Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <jeroen@blender.org>2021-03-16 09:37:30 +0300
committerJeroen Bakker <jeroen@blender.org>2021-03-16 09:43:17 +0300
commitd49e7b82da67885aac5933e094ee217ff777ac03 (patch)
tree6ef994837bc165e76bd17aacb1f5296033f31c09
parent269536d47ec5684a1c6018353120559be0ba2961 (diff)
Compositor: Redesign Cryptomatte node for better usability
In the current implementation, cryptomatte passes are connected to the node and elements are picked by using the eyedropper tool on a special pick channel. This design has two disadvantages - both connecting all passes individually and always having to switch to the picker channel are tedious. With the new design, the user selects the RenderLayer or Image from which the Cryptomatte layers are directly loaded (the type of pass is determined by an enum). This allows the node to automatically detect all relevant passes. Then, when using the eyedropper tool, the operator looks up the selected coordinates from the picked Image, Node backdrop or Clip and reads the picked object directly from the Renderlayer/Image, therefore allowing to pick in any context (e.g. by clicking on the Combined pass in the Image Viewer). The sampled color is looked up in the metadata and the actual name is stored in the cryptomatte node. This also allows to remove a hash by just removing the name from the matte id. Technically there is some loss of flexibility because the Cryptomatte pass inputs can no longer be connected to other nodes, but since any compositing done on them is likely to break the Cryptomatte system anyways, this isn't really a concern in practise. In the future, this would also allow to automatically translate values to names by looking up the value in the associated metadata of the input, or to get a better visualization of overlapping areas in the Pick output since we could blend colors now that the output doesn't have to contain the exact value. Idea + Original patch: Lucas Stockner Reviewed By: Brecht van Lommel Differential Revision: https://developer.blender.org/D3959
-rw-r--r--release/scripts/startup/nodeitems_builtins.py1
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.h9
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.hh5
-rw-r--r--source/blender/blenkernel/BKE_node.h20
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc58
-rw-r--r--source/blender/blenkernel/intern/node.cc9
-rw-r--r--source/blender/blenkernel/intern/scene.c5
-rw-r--r--source/blender/blenloader/intern/versioning_290.c2
-rw-r--r--source/blender/compositor/intern/COM_Converter.cc3
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.cc255
-rw-r--r--source/blender/compositor/nodes/COM_CryptomatteNode.h62
-rw-r--r--source/blender/editors/include/ED_clip.h4
-rw-r--r--source/blender/editors/include/ED_image.h4
-rw-r--r--source/blender/editors/include/ED_node.h5
-rw-r--r--source/blender/editors/include/UI_interface.h5
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c179
-rw-r--r--source/blender/editors/interface/interface_templates.c8
-rw-r--r--source/blender/editors/space_clip/clip_editor.c17
-rw-r--r--source/blender/editors/space_image/image_ops.c17
-rw-r--r--source/blender/editors/space_node/drawnode.c81
-rw-r--r--source/blender/editors/space_node/node_edit.c10
-rw-r--r--source/blender/editors/space_node/node_view.c26
-rw-r--r--source/blender/makesdna/DNA_node_types.h30
-rw-r--r--source/blender/makesrna/RNA_access.h2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c215
-rw-r--r--source/blender/nodes/NOD_composite.h1
-rw-r--r--source/blender/nodes/NOD_static_types.h3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc271
29 files changed, 1166 insertions, 142 deletions
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index e6e2c25e383..fefb266e591 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -390,6 +390,7 @@ compositor_node_categories = [
NodeItem("CompositorNodeColorMatte"),
NodeItem("CompositorNodeDoubleEdgeMask"),
NodeItem("CompositorNodeCryptomatte"),
+ NodeItem("CompositorNodeCryptomatteV2"),
]),
CompositorNodeCategory("CMP_DISTORT", "Distort", items=[
NodeItem("CompositorNodeScale"),
diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h
index 7d295929e77..576a2c1effd 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.h
+++ b/source/blender/blenkernel/BKE_cryptomatte.h
@@ -30,14 +30,17 @@
extern "C" {
#endif
+/* Forward declarations. */
struct CryptomatteSession;
struct Material;
struct Object;
struct RenderResult;
+struct Scene;
struct CryptomatteSession *BKE_cryptomatte_init(void);
struct CryptomatteSession *BKE_cryptomatte_init_from_render_result(
const struct RenderResult *render_result);
+struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *scene);
void BKE_cryptomatte_free(struct CryptomatteSession *session);
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name);
@@ -52,6 +55,10 @@ uint32_t BKE_cryptomatte_asset_hash(struct CryptomatteSession *session,
const char *layer_name,
const struct Object *object);
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash);
+bool BKE_cryptomatte_find_name(const struct CryptomatteSession *session,
+ const float encoded_hash,
+ char *r_name,
+ int name_len);
char *BKE_cryptomatte_entries_to_matte_id(struct NodeCryptomatte *node_storage);
void BKE_cryptomatte_matte_id_to_entries(struct NodeCryptomatte *node_storage,
@@ -63,4 +70,4 @@ void BKE_cryptomatte_store_metadata(const struct CryptomatteSession *session,
#ifdef __cplusplus
}
-#endif
+#endif \ No newline at end of file
diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index 98fdfc965bc..9e205d01765 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -26,6 +26,8 @@
#include <optional>
#include <string>
+#include "BKE_cryptomatte.h"
+
#include "BLI_map.hh"
#include "BLI_string_ref.hh"
@@ -105,6 +107,9 @@ struct CryptomatteStampDataCallbackData {
static void extract_layer_manifest(void *_data, const char *propname, char *propvalue, int len);
};
+const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(
+ const CryptomatteSession &session);
+
struct CryptomatteSessionDeleter {
void operator()(CryptomatteSession *session)
{
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 0379dea9e8c..42022cce5a5 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -47,6 +47,7 @@ struct BlendLibReader;
struct BlendWriter;
struct ColorManagedDisplaySettings;
struct ColorManagedViewSettings;
+struct CryptomatteSession;
struct FreestyleLineStyle;
struct GPUMaterial;
struct GPUNodeStack;
@@ -1204,9 +1205,10 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_NODE_PLANETRACKDEFORM 320
#define CMP_NODE_CORNERPIN 321
#define CMP_NODE_SWITCH_VIEW 322
-#define CMP_NODE_CRYPTOMATTE 323
+#define CMP_NODE_CRYPTOMATTE_LEGACY 323
#define CMP_NODE_DENOISE 324
#define CMP_NODE_EXPOSURE 325
+#define CMP_NODE_CRYPTOMATTE 326
/* channel toggles */
#define CMP_CHAN_RGB 1
@@ -1236,6 +1238,10 @@ void ntreeGPUMaterialNodes(struct bNodeTree *localtree,
#define CMP_TRACKPOS_RELATIVE_FRAME 2
#define CMP_TRACKPOS_ABSOLUTE_FRAME 3
+/* Cryptomatte source. */
+#define CMP_CRYPTOMATTE_SRC_RENDER 0
+#define CMP_CRYPTOMATTE_SRC_IMAGE 1
+
/* API */
void ntreeCompositExecTree(struct Scene *scene,
struct bNodeTree *ntree,
@@ -1278,11 +1284,15 @@ void ntreeCompositOutputFileUniqueLayer(struct ListBase *list,
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *ntree, bNode *node);
-void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *ntree, bNode *node);
-void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *ntree, bNode *node);
-struct bNodeSocket *ntreeCompositCryptomatteAddSocket(struct bNodeTree *ntree, struct bNode *node);
-int ntreeCompositCryptomatteRemoveSocket(struct bNodeTree *ntree, struct bNode *node);
+void ntreeCompositCryptomatteSyncFromAdd(bNode *node);
+void ntreeCompositCryptomatteSyncFromRemove(bNode *node);
+bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node);
+int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node);
+void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len);
+/* Update the runtime layer names with the cryptomatte layer names of the references
+ * render layer or image. */
+void ntreeCompositCryptomatteUpdateLayerNames(bNode *node);
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index 55426f738ff..74576b8bbbb 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -30,6 +30,7 @@
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_compiler_attrs.h"
#include "BLI_dynstr.h"
@@ -50,10 +51,13 @@
struct CryptomatteSession {
blender::Map<std::string, blender::bke::cryptomatte::CryptomatteLayer> layers;
+ /* Layer names in order of creation. */
+ blender::Vector<std::string> layer_names;
CryptomatteSession();
CryptomatteSession(const Main *bmain);
CryptomatteSession(StampData *stamp_data);
+ CryptomatteSession(const Scene *scene);
blender::bke::cryptomatte::CryptomatteLayer &add_layer(std::string layer_name);
std::optional<std::string> operator[](float encoded_hash) const;
@@ -99,8 +103,32 @@ CryptomatteSession::CryptomatteSession(StampData *stamp_data)
false);
}
+CryptomatteSession::CryptomatteSession(const Scene *scene)
+{
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ eViewLayerCryptomatteFlags cryptoflags = static_cast<eViewLayerCryptomatteFlags>(
+ view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ALL);
+ if (cryptoflags == 0) {
+ cryptoflags = static_cast<eViewLayerCryptomatteFlags>(VIEW_LAYER_CRYPTOMATTE_ALL);
+ }
+
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_OBJECT) {
+ add_layer(blender::StringRefNull(view_layer->name) + ".CryptoObject");
+ }
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_ASSET) {
+ add_layer(blender::StringRefNull(view_layer->name) + ".CryptoAsset");
+ }
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_MATERIAL) {
+ add_layer(blender::StringRefNull(view_layer->name) + ".CryptoMaterial");
+ }
+ }
+}
+
blender::bke::cryptomatte::CryptomatteLayer &CryptomatteSession::add_layer(std::string layer_name)
{
+ if (!layer_names.contains(layer_name)) {
+ layer_names.append(layer_name);
+ }
return layers.lookup_or_add_default(layer_name);
}
@@ -128,6 +156,12 @@ struct CryptomatteSession *BKE_cryptomatte_init_from_render_result(
return session;
}
+struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *scene)
+{
+ CryptomatteSession *session = new CryptomatteSession(scene);
+ return session;
+}
+
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name)
{
session->add_layer(layer_name);
@@ -182,6 +216,21 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
return blender::bke::cryptomatte::CryptomatteHash(cryptomatte_hash).float_encoded();
}
+/* Find an ID in the given main that matches the given encoded float. */
+bool BKE_cryptomatte_find_name(const CryptomatteSession *session,
+ const float encoded_hash,
+ char *r_name,
+ int name_len)
+{
+ std::optional<std::string> name = (*session)[encoded_hash];
+ if (!name) {
+ return false;
+ }
+
+ BLI_strncpy(r_name, name->c_str(), name_len);
+ return true;
+}
+
char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
{
DynStr *matte_id = BLI_dynstr_new();
@@ -213,7 +262,8 @@ void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const ch
}
/* Update the matte_id so the files can be opened in versions that don't
* use `CryptomatteEntry`. */
- if (matte_id != node_storage->matte_id && STREQ(node_storage->matte_id, matte_id)) {
+ if (matte_id != node_storage->matte_id && node_storage->matte_id &&
+ STREQ(node_storage->matte_id, matte_id)) {
MEM_SAFE_FREE(node_storage->matte_id);
node_storage->matte_id = static_cast<char *>(MEM_dupallocN(matte_id));
}
@@ -599,4 +649,10 @@ void CryptomatteStampDataCallbackData::extract_layer_manifest(void *_data,
blender::bke::cryptomatte::manifest::from_manifest(layer, propvalue);
}
+const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(
+ const CryptomatteSession &session)
+{
+ return session.layer_names;
+}
+
} // namespace blender::bke::cryptomatte
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index b6f02128353..66c0e724fdf 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -538,7 +538,8 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
}
- else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) {
+ else if ((ntree->type == NTREE_COMPOSIT) &&
+ (ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY))) {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
BLO_write_string(writer, nc->matte_id);
LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) {
@@ -703,10 +704,12 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
iuser->scene = nullptr;
break;
}
+ case CMP_NODE_CRYPTOMATTE_LEGACY:
case CMP_NODE_CRYPTOMATTE: {
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
BLO_read_data_address(reader, &nc->matte_id);
BLO_read_list(reader, &nc->entries);
+ BLI_listbase_clear(&nc->runtime.layers);
break;
}
case TEX_NODE_IMAGE: {
@@ -903,7 +906,8 @@ void ntreeBlendReadExpand(BlendExpander *expander, bNodeTree *ntree)
}
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id && node->type != CMP_NODE_R_LAYERS) {
+ if (node->id && !(node->type == CMP_NODE_R_LAYERS) &&
+ !(node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER)) {
BLO_expand(expander, node->id);
}
@@ -4607,6 +4611,7 @@ static void registerCompositNodes()
register_node_type_cmp_keyingscreen();
register_node_type_cmp_keying();
register_node_type_cmp_cryptomatte();
+ register_node_type_cmp_cryptomatte_legacy();
register_node_type_cmp_translate();
register_node_type_cmp_rotate();
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 3633dff8690..de3e1023b08 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -1377,9 +1377,10 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
/* patch for missing scene IDs, can't be in do-versions */
static void composite_patch(bNodeTree *ntree, Scene *scene)
{
-
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id == NULL && node->type == CMP_NODE_R_LAYERS) {
+ if (node->id == NULL &&
+ ((node->type == CMP_NODE_R_LAYERS) ||
+ (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER))) {
node->id = &scene->id;
}
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 05762c479ff..06bafb20c35 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1482,7 +1482,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->nodetree) {
LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) {
- if (node->type == CMP_NODE_CRYPTOMATTE) {
+ if (node->type == CMP_NODE_CRYPTOMATTE_LEGACY) {
NodeCryptomatte *storage = (NodeCryptomatte *)node->storage;
char *matte_id = storage->matte_id;
if (matte_id == NULL || strlen(storage->matte_id) == 0) {
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc
index 7d897d29576..91439f54710 100644
--- a/source/blender/compositor/intern/COM_Converter.cc
+++ b/source/blender/compositor/intern/COM_Converter.cc
@@ -406,6 +406,9 @@ Node *COM_convert_bnode(bNode *b_node)
case CMP_NODE_SUNBEAMS:
node = new SunBeamsNode(b_node);
break;
+ case CMP_NODE_CRYPTOMATTE_LEGACY:
+ node = new CryptomatteLegacyNode(b_node);
+ break;
case CMP_NODE_CRYPTOMATTE:
node = new CryptomatteNode(b_node);
break;
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
index 27ef98af8f3..4c698b5609f 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.cc
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc
@@ -17,64 +17,247 @@
*/
#include "COM_CryptomatteNode.h"
-#include "COM_ConvertOperation.h"
-#include "COM_CryptomatteOperation.h"
-
+#include "BKE_node.h"
#include "BLI_assert.h"
#include "BLI_hash_mm3.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
-
+#include "COM_ConvertOperation.h"
+#include "COM_CryptomatteOperation.h"
+#include "COM_MultilayerImageOperation.h"
+#include "COM_RenderLayersProg.h"
#include "COM_SetAlphaMultiplyOperation.h"
+#include "COM_SetColorOperation.h"
#include <iterator>
+#include <string>
+
+/** \name Cryptomatte base
+ * \{ */
-CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode)
+void CryptomatteBaseNode::convertToOperations(NodeConverter &converter,
+ const CompositorContext &context) const
{
- /* pass */
+ NodeOutput *output_image_socket = this->getOutputSocket(0);
+
+ bNode *node = this->getbNode();
+ NodeCryptomatte *cryptomatte_settings = static_cast<NodeCryptomatte *>(node->storage);
+
+ CryptomatteOperation *cryptomatte_operation = create_cryptomatte_operation(
+ converter, context, *node, cryptomatte_settings);
+ converter.addOperation(cryptomatte_operation);
+
+ NodeOutput *output_matte_socket = this->getOutputSocket(1);
+ SeparateChannelOperation *extract_mask_operation = new SeparateChannelOperation;
+ extract_mask_operation->setChannel(3);
+ converter.addOperation(extract_mask_operation);
+ converter.addLink(cryptomatte_operation->getOutputSocket(0),
+ extract_mask_operation->getInputSocket(0));
+ converter.mapOutputSocket(output_matte_socket, extract_mask_operation->getOutputSocket(0));
+
+ NodeInput *input_image_socket = this->getInputSocket(0);
+ SetAlphaMultiplyOperation *apply_mask_operation = new SetAlphaMultiplyOperation();
+ converter.mapInputSocket(input_image_socket, apply_mask_operation->getInputSocket(0));
+ converter.addOperation(apply_mask_operation);
+ converter.addLink(extract_mask_operation->getOutputSocket(0),
+ apply_mask_operation->getInputSocket(1));
+ converter.mapOutputSocket(output_image_socket, apply_mask_operation->getOutputSocket(0));
+
+ NodeOutput *output_pick_socket = this->getOutputSocket(2);
+ SetAlphaMultiplyOperation *extract_pick_operation = new SetAlphaMultiplyOperation();
+ converter.addOperation(extract_pick_operation);
+ converter.addInputValue(extract_pick_operation->getInputSocket(1), 1.0f);
+ converter.addLink(cryptomatte_operation->getOutputSocket(0),
+ extract_pick_operation->getInputSocket(0));
+ converter.mapOutputSocket(output_pick_socket, extract_pick_operation->getOutputSocket(0));
}
-void CryptomatteNode::convertToOperations(NodeConverter &converter,
- const CompositorContext & /*context*/) const
+/* \} */
+
+/** \name Cryptomatte V2
+ * \{ */
+static std::string prefix_from_node(const bNode &node)
{
- NodeInput *inputSocketImage = this->getInputSocket(0);
- NodeOutput *outputSocketImage = this->getOutputSocket(0);
- NodeOutput *outputSocketMatte = this->getOutputSocket(1);
- NodeOutput *outputSocketPick = this->getOutputSocket(2);
+ char prefix[MAX_NAME];
+ ntreeCompositCryptomatteLayerPrefix(&node, prefix, sizeof(prefix));
+ return std::string(prefix, BLI_strnlen(prefix, sizeof(prefix)));
+}
- bNode *node = this->getbNode();
- NodeCryptomatte *cryptoMatteSettings = (NodeCryptomatte *)node->storage;
+static std::string combined_layer_pass_name(RenderLayer *render_layer, RenderPass *render_pass)
+{
+ if (render_layer->name[0] == '\0') {
+ return std::string(render_pass->name,
+ BLI_strnlen(render_pass->name, sizeof(render_pass->name)));
+ }
- CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets() - 1);
- if (cryptoMatteSettings) {
- LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptoMatteSettings->entries) {
- operation->addObjectIndex(cryptomatte_entry->encoded_hash);
+ std::string combined_name =
+ blender::StringRef(render_layer->name,
+ BLI_strnlen(render_layer->name, sizeof(render_layer->name))) +
+ "." +
+ blender::StringRef(render_pass->name,
+ BLI_strnlen(render_pass->name, sizeof(render_pass->name)));
+ return combined_name;
+}
+
+void CryptomatteNode::input_operations_from_render_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations)
+{
+ Scene *scene = (Scene *)node.id;
+ if (!scene) {
+ return;
+ }
+
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+ Render *render = RE_GetSceneRender(scene);
+ RenderResult *render_result = render ? RE_AcquireResultRead(render) : nullptr;
+
+ if (!render_result) {
+ return;
+ }
+
+ const short cryptomatte_layer_id = 0;
+ const std::string prefix = prefix_from_node(node);
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name);
+ if (render_layer) {
+ LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
+ const std::string combined_name = combined_layer_pass_name(render_layer, render_pass);
+ if (blender::StringRef(combined_name).startswith(prefix)) {
+ RenderLayersProg *op = new RenderLayersProg(
+ render_pass->name, COM_DT_COLOR, render_pass->channels);
+ op->setScene(scene);
+ op->setLayerId(cryptomatte_layer_id);
+ op->setRenderData(context.getRenderData());
+ op->setViewName(context.getViewName());
+ r_input_operations.append(op);
+ }
+ }
}
}
+ RE_ReleaseResult(render);
+}
- converter.addOperation(operation);
+void CryptomatteNode::input_operations_from_image_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations)
+{
+ NodeCryptomatte *cryptomatte_settings = (NodeCryptomatte *)node.storage;
+ Image *image = (Image *)node.id;
+ if (!image) {
+ return;
+ }
- for (int i = 0; i < getNumberOfInputSockets() - 1; i++) {
- converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
+ BLI_assert(GS(image->id.name) == ID_IM);
+ if (image->type != IMA_TYPE_MULTILAYER) {
+ return;
}
- SeparateChannelOperation *separateOperation = new SeparateChannelOperation;
- separateOperation->setChannel(3);
- converter.addOperation(separateOperation);
+ ImageUser *iuser = &cryptomatte_settings->iuser;
+ BKE_image_user_frame_calc(image, iuser, context.getFramenumber());
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
- SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation();
- converter.addOperation(operationAlpha);
+ if (image->rr) {
+ int view = 0;
+ if (BLI_listbase_count_at_most(&image->rr->views, 2) > 1) {
+ if (iuser->view == 0) {
+ /* Heuristic to match image name with scene names, check if the view name exists in the
+ * image. */
+ view = BLI_findstringindex(
+ &image->rr->views, context.getViewName(), offsetof(RenderView, name));
+ if (view == -1) {
+ view = 0;
+ }
+ }
+ else {
+ view = iuser->view - 1;
+ }
+ }
- converter.addLink(operation->getOutputSocket(0), separateOperation->getInputSocket(0));
- converter.addLink(separateOperation->getOutputSocket(0), operationAlpha->getInputSocket(1));
+ const std::string prefix = prefix_from_node(node);
+ LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) {
+ LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
+ const std::string combined_name = combined_layer_pass_name(render_layer, render_pass);
+ if (blender::StringRef(combined_name).startswith(prefix)) {
+ MultilayerColorOperation *op = new MultilayerColorOperation(
+ render_layer, render_pass, view);
+ op->setImage(image);
+ op->setImageUser(iuser);
+ op->setFramenumber(context.getFramenumber());
+ r_input_operations.append(op);
+ }
+ }
+ }
+ }
+ BKE_image_release_ibuf(image, ibuf, nullptr);
+}
- SetAlphaMultiplyOperation *clearAlphaOperation = new SetAlphaMultiplyOperation();
- converter.addOperation(clearAlphaOperation);
- converter.addInputValue(clearAlphaOperation->getInputSocket(1), 1.0f);
+blender::Vector<NodeOperation *> CryptomatteNode::create_input_operations(
+ const CompositorContext &context, const bNode &node)
+{
+ blender::Vector<NodeOperation *> input_operations;
+ switch (node.custom1) {
+ case CMP_CRYPTOMATTE_SRC_RENDER:
+ input_operations_from_render_source(context, node, input_operations);
+ break;
+ case CMP_CRYPTOMATTE_SRC_IMAGE:
+ input_operations_from_image_source(context, node, input_operations);
+ break;
+ }
- converter.addLink(operation->getOutputSocket(0), clearAlphaOperation->getInputSocket(0));
+ if (input_operations.is_empty()) {
+ SetColorOperation *op = new SetColorOperation();
+ op->setChannel1(0.0f);
+ op->setChannel2(1.0f);
+ op->setChannel3(0.0f);
+ op->setChannel4(0.0f);
+ input_operations.append(op);
+ }
+ return input_operations;
+}
+CryptomatteOperation *CryptomatteNode::create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const
+{
+ blender::Vector<NodeOperation *> input_operations = create_input_operations(context, node);
+ CryptomatteOperation *operation = new CryptomatteOperation(input_operations.size());
+ LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) {
+ operation->addObjectIndex(cryptomatte_entry->encoded_hash);
+ }
+ for (int i = 0; i < input_operations.size(); ++i) {
+ converter.addOperation(input_operations[i]);
+ converter.addLink(input_operations[i]->getOutputSocket(), operation->getInputSocket(i));
+ }
+ return operation;
+}
+
+/* \} */
+
+/** \name Cryptomatte legacy
+ * \{ */
- converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
- converter.mapOutputSocket(outputSocketMatte, separateOperation->getOutputSocket(0));
- converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket(0));
- converter.mapOutputSocket(outputSocketPick, clearAlphaOperation->getOutputSocket(0));
+CryptomatteOperation *CryptomatteLegacyNode::create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &UNUSED(context),
+ const bNode &UNUSED(node),
+ const NodeCryptomatte *cryptomatte_settings) const
+{
+ const int num_inputs = getNumberOfInputSockets() - 1;
+ CryptomatteOperation *operation = new CryptomatteOperation(num_inputs);
+ if (cryptomatte_settings) {
+ LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) {
+ operation->addObjectIndex(cryptomatte_entry->encoded_hash);
+ }
+ }
+
+ for (int i = 0; i < num_inputs; i++) {
+ converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
+ }
+
+ return operation;
}
+
+/* \} */ \ No newline at end of file
diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.h b/source/blender/compositor/nodes/COM_CryptomatteNode.h
index 1fb8893efa0..e99a104c914 100644
--- a/source/blender/compositor/nodes/COM_CryptomatteNode.h
+++ b/source/blender/compositor/nodes/COM_CryptomatteNode.h
@@ -18,14 +18,72 @@
#pragma once
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "COM_CryptomatteOperation.h"
#include "COM_Node.h"
/**
* \brief CryptomatteNode
* \ingroup Node
*/
-class CryptomatteNode : public Node {
+class CryptomatteBaseNode : public Node {
+ protected:
+ CryptomatteBaseNode(bNode *editor_node) : Node(editor_node)
+ {
+ /* pass */
+ }
+
public:
- CryptomatteNode(bNode *editorNode);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+
+ protected:
+ virtual CryptomatteOperation *create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const = 0;
+};
+
+class CryptomatteNode : public CryptomatteBaseNode {
+ public:
+ CryptomatteNode(bNode *editor_node) : CryptomatteBaseNode(editor_node)
+ {
+ /* pass */
+ }
+
+ protected:
+ CryptomatteOperation *create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const override;
+
+ private:
+ static blender::Vector<NodeOperation *> create_input_operations(const CompositorContext &context,
+ const bNode &node);
+ static void input_operations_from_render_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations);
+ static void input_operations_from_image_source(
+ const CompositorContext &context,
+ const bNode &node,
+ blender::Vector<NodeOperation *> &r_input_operations);
+};
+
+class CryptomatteLegacyNode : public CryptomatteBaseNode {
+ public:
+ CryptomatteLegacyNode(bNode *editor_node) : CryptomatteBaseNode(editor_node)
+ {
+ /* pass */
+ }
+
+ protected:
+ CryptomatteOperation *create_cryptomatte_operation(
+ NodeConverter &converter,
+ const CompositorContext &context,
+ const bNode &node,
+ const NodeCryptomatte *cryptomatte_settings) const override;
};
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 56494f87bfe..21d8a28e2c9 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -64,6 +64,10 @@ struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc,
float *scale,
float *angle);
+bool ED_space_clip_get_position(struct SpaceClip *sc,
+ struct ARegion *ar,
+ int mval[2],
+ float fpos[2]);
bool ED_space_clip_color_sample(struct SpaceClip *sc,
struct ARegion *region,
int mval[2],
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index b139b0765a3..ec525806b81 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -53,6 +53,10 @@ void ED_space_image_auto_set(const struct bContext *C, struct SpaceImage *sima);
struct Mask *ED_space_image_get_mask(struct SpaceImage *sima);
void ED_space_image_set_mask(struct bContext *C, struct SpaceImage *sima, struct Mask *mask);
+bool ED_space_image_get_position(struct SpaceImage *sima,
+ struct ARegion *region,
+ int mval[2],
+ float fpos[2]);
bool ED_space_image_color_sample(
struct SpaceImage *sima, struct ARegion *region, int mval[2], float r_col[3], bool *r_is_data);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **r_lock, int tile);
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index ea2383457c2..67a50b83bd6 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -121,6 +121,11 @@ void ED_node_composite_job(const struct bContext *C,
void ED_operatormacros_node(void);
/* node_view.c */
+bool ED_space_node_get_position(struct Main *bmain,
+ struct SpaceNode *snode,
+ struct ARegion *region,
+ const int mval[2],
+ float fpos[2]);
bool ED_space_node_color_sample(struct Main *bmain,
struct SpaceNode *snode,
struct ARegion *region,
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 5620d39ab16..d23daf7f0e3 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2078,7 +2078,10 @@ void uiTemplatePalette(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
bool colors);
-void uiTemplateCryptoPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
+void uiTemplateCryptoPicker(uiLayout *layout,
+ struct PointerRNA *ptr,
+ const char *propname,
+ int icon);
void uiTemplateLayers(uiLayout *layout,
struct PointerRNA *ptr,
const char *propname,
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 82bcd5d7eb4..421019bebb8 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../../makesdna
../../makesrna
../../python
+ ../../render
../../windowmanager
../../../../intern/glew-mx
../../../../intern/guardedalloc
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 5af290db037..349086132dc 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -31,10 +31,14 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_string.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_node.h"
#include "BKE_screen.h"
#include "RNA_access.h"
@@ -42,6 +46,7 @@
#include "UI_interface.h"
#include "IMB_colormanagement.h"
+#include "IMB_imbuf_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -54,6 +59,8 @@
#include "ED_image.h"
#include "ED_node.h"
+#include "RE_pipeline.h"
+
#include "interface_eyedropper_intern.h"
typedef struct Eyedropper {
@@ -71,13 +78,12 @@ typedef struct Eyedropper {
float accum_col[3];
int accum_tot;
- bool use_accum;
+ bNode *crypto_node;
} Eyedropper;
static bool eyedropper_init(bContext *C, wmOperator *op)
{
Eyedropper *eye = MEM_callocN(sizeof(Eyedropper), __func__);
- eye->use_accum = RNA_boolean_get(op->ptr, "use_accumulate");
uiBut *but = UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
const enum PropertySubType prop_subtype = eye->prop ? RNA_property_subtype(eye->prop) : 0;
@@ -96,6 +102,13 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
float col[4];
RNA_property_float_get_array(&eye->ptr, eye->prop, col);
+ if (ELEM(eye->ptr.type, &RNA_CompositorNodeCryptomatteV2, &RNA_CompositorNodeCryptomatte)) {
+ eye->crypto_node = (bNode *)eye->ptr.data;
+ }
+ else {
+ eye->crypto_node = NULL;
+ }
+
if (prop_subtype != PROP_COLOR) {
Scene *scene = CTX_data_scene(C);
const char *display_device;
@@ -125,6 +138,150 @@ static void eyedropper_exit(bContext *C, wmOperator *op)
/* *** eyedropper_color_ helper functions *** */
+static bool eyedropper_cryptomatte_sample_renderlayer_fl(RenderLayer *render_layer,
+ const char *prefix,
+ const float fpos[2],
+ float r_col[3])
+{
+ if (!render_layer) {
+ return false;
+ }
+
+ const int render_layer_name_len = BLI_strnlen(render_layer->name, sizeof(render_layer->name));
+ if (strncmp(prefix, render_layer->name, render_layer_name_len) != 0) {
+ return false;
+ }
+
+ const int prefix_len = strlen(prefix);
+ if (prefix_len <= render_layer_name_len + 1) {
+ return false;
+ }
+
+ /* RenderResult from images can have no render layer name. */
+ const char *render_pass_name_prefix = render_layer_name_len ?
+ prefix + 1 + render_layer_name_len :
+ prefix;
+
+ LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) {
+ if (STRPREFIX(render_pass->name, render_pass_name_prefix) &&
+ !STREQLEN(render_pass->name, render_pass_name_prefix, sizeof(render_pass->name))) {
+ BLI_assert(render_pass->channels == 4);
+ const int x = (int)(fpos[0] * render_pass->rectx);
+ const int y = (int)(fpos[1] * render_pass->recty);
+ const int offset = 4 * (y * render_pass->rectx + x);
+ zero_v3(r_col);
+ r_col[0] = render_pass->rect[offset];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool eyedropper_cryptomatte_sample_fl(
+ bContext *C, Eyedropper *eye, int mx, int my, float r_col[3])
+{
+ bNode *node = eye->crypto_node;
+ NodeCryptomatte *crypto = node ? ((NodeCryptomatte *)node->storage) : NULL;
+
+ if (!crypto) {
+ return false;
+ }
+
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ if (!sa || !ELEM(sa->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
+ return false;
+ }
+
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (!ar) {
+ return false;
+ }
+
+ int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
+ float fpos[2] = {-1.0f, -1.0};
+ switch (sa->spacetype) {
+ case SPACE_IMAGE: {
+ SpaceImage *sima = sa->spacedata.first;
+ ED_space_image_get_position(sima, ar, mval, fpos);
+ break;
+ }
+ case SPACE_NODE: {
+ Main *bmain = CTX_data_main(C);
+ SpaceNode *snode = sa->spacedata.first;
+ ED_space_node_get_position(bmain, snode, ar, mval, fpos);
+ break;
+ }
+ case SPACE_CLIP: {
+ SpaceClip *sc = sa->spacedata.first;
+ ED_space_clip_get_position(sc, ar, mval, fpos);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ if (fpos[0] < 0.0f || fpos[1] < 0.0f || fpos[0] >= 1.0f || fpos[1] >= 1.0f) {
+ return false;
+ }
+
+ /* CMP_CRYPTOMATTE_SRC_RENDER and CMP_CRYPTOMATTE_SRC_IMAGE require a referenced image/scene to
+ * work properly. */
+ if (!node->id) {
+ return false;
+ }
+
+ bool success = false;
+ /* TODO(jbakker): Migrate this file to cc and use std::string as return param. */
+ char prefix[MAX_NAME + 1];
+ ntreeCompositCryptomatteLayerPrefix(node, prefix, sizeof(prefix) - 1);
+ prefix[MAX_NAME] = '\0';
+
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) {
+ Scene *scene = (Scene *)node->id;
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+ Render *re = RE_GetSceneRender(scene);
+
+ if (re) {
+ RenderResult *rr = RE_AcquireResultRead(re);
+ if (rr) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
+ RenderLayer *render_layer = RE_GetRenderLayer(rr, view_layer->name);
+ success = eyedropper_cryptomatte_sample_renderlayer_fl(
+ render_layer, prefix, fpos, r_col);
+ if (success) {
+ break;
+ }
+ }
+ }
+ RE_ReleaseResult(re);
+ }
+ }
+ else if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) {
+ Image *image = (Image *)node->id;
+ BLI_assert(GS(image->id.name) == ID_IM);
+ ImageUser *iuser = &crypto->iuser;
+
+ if (image && image->type == IMA_TYPE_MULTILAYER) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, NULL);
+ if (image->rr) {
+ LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) {
+ success = eyedropper_cryptomatte_sample_renderlayer_fl(
+ render_layer, prefix, fpos, r_col);
+ if (success) {
+ break;
+ }
+ }
+ }
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ }
+
+ return success;
+}
+
/**
* \brief get the color from the screen.
*
@@ -230,9 +387,16 @@ static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my
{
/* Accumulate color. */
float col[3];
- eyedropper_color_sample_fl(C, mx, my, col);
+ if (eye->crypto_node) {
+ if (!eyedropper_cryptomatte_sample_fl(C, eye, mx, my, col)) {
+ return;
+ }
+ }
+ else {
+ eyedropper_color_sample_fl(C, mx, my, col);
+ }
- if (eye->use_accum) {
+ if (!eye->crypto_node) {
add_v3_v3(eye->accum_col, col);
eye->accum_tot++;
}
@@ -360,11 +524,4 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_INTERNAL;
-
- /* properties */
- PropertyRNA *prop;
-
- /* Needed for color picking with crypto-matte. */
- prop = RNA_def_boolean(ot->srna, "use_accumulate", true, "Accumulate", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index fed011d78d7..08895564a26 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -5485,7 +5485,7 @@ void uiTemplatePalette(uiLayout *layout,
}
}
-void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname)
+void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, int icon)
{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
@@ -5500,7 +5500,7 @@ void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propn
UI_BTYPE_BUT,
"UI_OT_eyedropper_color",
WM_OP_INVOKE_DEFAULT,
- ICON_EYEDROPPER,
+ icon,
RNA_property_ui_name(prop),
0,
0,
@@ -5510,10 +5510,6 @@ void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propn
but->rnapoin = *ptr;
but->rnaprop = prop;
but->rnaindex = -1;
-
- PointerRNA *opptr = UI_but_operator_ptr_get(but);
- /* Important for crypto-matte operation. */
- RNA_boolean_set(opptr, "use_accumulate", false);
}
/** \} */
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index e1172458f67..36375ad1ef3 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -269,6 +269,23 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale
return NULL;
}
+bool ED_space_clip_get_position(struct SpaceClip *sc,
+ struct ARegion *ar,
+ int mval[2],
+ float fpos[2])
+{
+ ImBuf *ibuf = ED_space_clip_get_buffer(sc);
+ if (!ibuf) {
+ return false;
+ }
+
+ /* map the mouse coords to the backdrop image space */
+ ED_clip_mouse_pos(sc, ar, mval, fpos);
+
+ IMB_freeImBuf(ibuf);
+ return true;
+}
+
/* Returns color in linear space, matching ED_space_image_color_sample(). */
bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], float r_col[3])
{
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index fc3619f01b9..72405a51aca 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -3147,6 +3147,23 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
/** \name Sample Image Operator
* \{ */
+/* Returns mouse position in image space. */
+bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[2], float fpos[2])
+{
+ void *lock;
+ ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0);
+
+ if (ibuf == NULL) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ return false;
+ }
+
+ UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fpos[0], &fpos[1]);
+
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ return true;
+}
+
/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(
SpaceImage *sima, ARegion *region, int mval[2], float r_col[3], bool *r_is_data)
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 75ea5b9a1bf..0f2b2b435bc 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -643,7 +643,8 @@ static void node_buts_image_user(uiLayout *layout,
PointerRNA *ptr,
PointerRNA *imaptr,
PointerRNA *iuserptr,
- bool compositor)
+ const bool show_layer_selection,
+ const bool show_color_management)
{
if (!imaptr->data) {
return;
@@ -677,20 +678,22 @@ static void node_buts_image_user(uiLayout *layout,
uiItemR(col, ptr, "use_auto_refresh", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- if (compositor && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
+ if (show_layer_selection && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
RNA_boolean_get(ptr, "has_layers")) {
col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "layer", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiLayout *split = uiLayoutSplit(layout, 0.5f, true);
- PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings");
- uiItemL(split, IFACE_("Color Space"), ICON_NONE);
- uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
+ if (show_color_management) {
+ uiLayout *split = uiLayoutSplit(layout, 0.5f, true);
+ PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings");
+ uiItemL(split, IFACE_("Color Space"), ICON_NONE);
+ uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
- /* Avoid losing changes image is painted. */
- if (BKE_image_is_dirty(imaptr->data)) {
- uiLayoutSetEnabled(split, false);
+ /* Avoid losing changes image is painted. */
+ if (BKE_image_is_dirty(imaptr->data)) {
+ uiLayoutSetEnabled(split, false);
+ }
}
}
@@ -756,7 +759,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
/* note: image user properties used directly here, unlike compositor image node,
* which redefines them in the node struct RNA to get proper updates.
*/
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false, true);
}
static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -785,7 +788,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE);
uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE);
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false, true);
}
static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1374,7 +1377,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
PointerRNA imaptr = RNA_pointer_get(ptr, "image");
- node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true);
+ node_buts_image_user(layout, C, ptr, &imaptr, &iuserptr, true, true);
node_buts_image_views(layout, C, ptr, &imaptr);
}
@@ -2665,27 +2668,64 @@ static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), P
uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
-static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+static void node_composit_buts_cryptomatte_legacy(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
{
uiLayout *col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Matte Objects:"), ICON_NONE);
uiLayout *row = uiLayoutRow(col, true);
- uiTemplateCryptoPicker(row, ptr, "add");
- uiTemplateCryptoPicker(row, ptr, "remove");
+ uiTemplateCryptoPicker(row, ptr, "add", ICON_ADD);
+ uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE);
uiItemR(col, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE);
}
-static void node_composit_buts_cryptomatte_ex(uiLayout *layout,
- bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr))
+static void node_composit_buts_cryptomatte_legacy_ex(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr))
{
uiItemO(layout, IFACE_("Add Crypto Layer"), ICON_ADD, "NODE_OT_cryptomatte_layer_add");
uiItemO(layout, IFACE_("Remove Crypto Layer"), ICON_REMOVE, "NODE_OT_cryptomatte_layer_remove");
}
+static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ bNode *node = ptr->data;
+
+ uiLayout *row = uiLayoutRow(layout, true);
+ uiItemR(row, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ uiLayout *col = uiLayoutColumn(layout, false);
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) {
+ uiTemplateID(col, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
+ }
+ else {
+ uiTemplateID(
+ col, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
+
+ NodeCryptomatte *crypto = (NodeCryptomatte *)node->storage;
+ PointerRNA imaptr = RNA_pointer_get(ptr, "image");
+ PointerRNA iuserptr;
+ RNA_pointer_create((ID *)ptr->owner_id, &RNA_ImageUser, &crypto->iuser, &iuserptr);
+ uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
+
+ node_buts_image_user(col, C, ptr, &imaptr, &iuserptr, false, false);
+ node_buts_image_views(col, C, ptr, &imaptr);
+ }
+
+ col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "layer_name", 0, "", ICON_NONE);
+ uiItemL(col, IFACE_("Matte ID:"), ICON_NONE);
+
+ row = uiLayoutRow(col, true);
+ uiItemR(row, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE);
+ uiTemplateCryptoPicker(row, ptr, "add", ICON_ADD);
+ uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE);
+}
+
static void node_composit_buts_brightcontrast(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
@@ -2938,7 +2978,10 @@ static void node_composit_set_butfunc(bNodeType *ntype)
break;
case CMP_NODE_CRYPTOMATTE:
ntype->draw_buttons = node_composit_buts_cryptomatte;
- ntype->draw_buttons_ex = node_composit_buts_cryptomatte_ex;
+ break;
+ case CMP_NODE_CRYPTOMATTE_LEGACY:
+ ntype->draw_buttons = node_composit_buts_cryptomatte_legacy;
+ ntype->draw_buttons_ex = node_composit_buts_cryptomatte_legacy_ex;
break;
case CMP_NODE_BRIGHTCONTRAST:
ntype->draw_buttons = node_composit_buts_brightcontrast;
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index afdc9efb78b..b72a6503749 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -1404,8 +1404,12 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
}
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
- if (node->type == CMP_NODE_R_LAYERS) {
+ if ((node->type == CMP_NODE_R_LAYERS) ||
+ (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER)) {
ID *id = node->id;
+ if (id == NULL) {
+ continue;
+ }
if (id->tag & LIB_TAG_DOIT) {
RE_ReadRenderResult(curscene, (Scene *)id);
ntreeCompositTagRender((Scene *)id);
@@ -2742,7 +2746,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
node = nodeGetActive(snode->edittree);
}
- if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
+ if (!node || node->type != CMP_NODE_CRYPTOMATTE_LEGACY) {
return OPERATOR_CANCELLED;
}
@@ -2786,7 +2790,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o
node = nodeGetActive(snode->edittree);
}
- if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
+ if (!node || node->type != CMP_NODE_CRYPTOMATTE_LEGACY) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 8f1dc3c8c3e..8ecab92aa26 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -443,6 +443,32 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
}
}
+/* Returns mouse position in image space. */
+bool ED_space_node_get_position(
+ Main *bmain, SpaceNode *snode, struct ARegion *ar, const int mval[2], float fpos[2])
+{
+ if (!ED_node_is_compositor(snode) || (snode->flag & SNODE_BACKDRAW) == 0) {
+ return false;
+ }
+
+ void *lock;
+ Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
+ if (!ibuf) {
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ return false;
+ }
+
+ /* map the mouse coords to the backdrop image space */
+ float bufx = ibuf->x * snode->zoom;
+ float bufy = ibuf->y * snode->zoom;
+ fpos[0] = (bufx > 0.0f ? ((float)mval[0] - 0.5f * ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
+ fpos[1] = (bufy > 0.0f ? ((float)mval[1] - 0.5f * ar->winy - snode->yof) / bufy + 0.5f : 0.0f);
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ return true;
+}
+
/* Returns color in linear space, matching ED_space_image_color_sample().
* And here we've got recursion in the comments tips...
*/
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index ad1def0f3ec..967258f1b81 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1066,15 +1066,39 @@ typedef struct CryptomatteEntry {
char _pad[4];
} CryptomatteEntry;
-typedef struct NodeCryptomatte {
+typedef struct CryptomatteLayer {
+ struct CryptomatteEntry *next, *prev;
+ char name[64];
+} CryptomatteLayer;
+
+typedef struct NodeCryptomatte_Runtime {
+ /* Contains `CryptomatteLayer`. */
+ ListBase layers;
+ /* Temp storage for the cryptomatte picker. */
float add[3];
float remove[3];
- /* Stores `entries` as a string for opening in 2.80-2.91. */
- char *matte_id;
+} NodeCryptomatte_Runtime;
+
+typedef struct NodeCryptomatte {
+ /* iuser needs to be first element due to RNA limitations.
+ * When we define the ImageData properties, we can't define them from
+ * storage->iuser, so storage needs to be casted to ImageUser directly. */
+ ImageUser iuser;
+
/* Contains `CryptomatteEntry`. */
ListBase entries;
+
+ /* MAX_NAME */
+ char layer_name[64];
+ /* Stores `entries` as a string for opening in 2.80-2.91. */
+ char *matte_id;
+
+ /** Legacy attributes */
+ /* Number of input sockets. */
int num_inputs;
+
char _pad[4];
+ NodeCryptomatte_Runtime runtime;
} NodeCryptomatte;
typedef struct NodeDenoise {
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index d41220eb22c..a9125c78229 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -142,6 +142,8 @@ extern StructRNA RNA_CompositorNodeCombYUVA;
extern StructRNA RNA_CompositorNodeComposite;
extern StructRNA RNA_CompositorNodeCornerPin;
extern StructRNA RNA_CompositorNodeCrop;
+extern StructRNA RNA_CompositorNodeCryptomatte;
+extern StructRNA RNA_CompositorNodeCryptomatteV2;
extern StructRNA RNA_CompositorNodeCurveRGB;
extern StructRNA RNA_CompositorNodeCurveVec;
extern StructRNA RNA_CompositorNodeDBlur;
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 622460979e7..35c319c2f79 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -398,6 +398,12 @@ static const EnumPropertyItem prop_shader_output_target_items[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem node_cryptomatte_layer_name_items[] = {
+ {0, "CryptoObject", 0, "Object", "Use Object layer"},
+ {1, "CryptoMaterial", 0, "Material", "Use Material layer"},
+ {2, "CryptoAsset", 0, "Asset", "Use Asset layer"},
+ {0, NULL, 0, NULL, NULL}};
+
#endif
#define ITEM_ATTRIBUTE \
@@ -3444,6 +3450,10 @@ static void rna_Node_image_layer_update(Main *bmain, Scene *scene, PointerRNA *p
Image *ima = (Image *)node->id;
ImageUser *iuser = node->storage;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return;
+ }
+
BKE_image_multilayer_index(ima->rr, iuser);
BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_SRC_CHANGE);
@@ -3490,6 +3500,10 @@ static const EnumPropertyItem *rna_Node_image_layer_itemf(bContext *UNUSED(C),
const EnumPropertyItem *item = NULL;
RenderLayer *rl;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return DummyRNA_NULL_items;
+ }
+
if (ima == NULL || ima->rr == NULL) {
*r_free = false;
return DummyRNA_NULL_items;
@@ -3508,8 +3522,12 @@ static bool rna_Node_image_has_layers_get(PointerRNA *ptr)
bNode *node = (bNode *)ptr->data;
Image *ima = (Image *)node->id;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return false;
+ }
+
if (!ima || !(ima->rr)) {
- return 0;
+ return false;
}
return RE_layers_have_name(ima->rr);
@@ -3520,8 +3538,12 @@ static bool rna_Node_image_has_views_get(PointerRNA *ptr)
bNode *node = (bNode *)ptr->data;
Image *ima = (Image *)node->id;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return false;
+ }
+
if (!ima || !(ima->rr)) {
- return 0;
+ return false;
}
return BLI_listbase_count_at_most(&ima->rr->views, 2) > 1;
@@ -3566,6 +3588,10 @@ static const EnumPropertyItem *rna_Node_image_view_itemf(bContext *UNUSED(C),
const EnumPropertyItem *item = NULL;
RenderView *rv;
+ if (node->type == CMP_NODE_CRYPTOMATTE && node->custom1 != CMP_CRYPTOMATTE_SRC_IMAGE) {
+ return DummyRNA_NULL_items;
+ }
+
if (ima == NULL || ima->rr == NULL) {
*r_free = false;
return DummyRNA_NULL_items;
@@ -3722,6 +3748,115 @@ static void rna_NodeColorBalance_update_cdl(Main *bmain, Scene *scene, PointerRN
rna_Node_update(bmain, scene, ptr);
}
+static void rna_NodeCryptomatte_source_set(PointerRNA *ptr, int value)
+{
+ bNode *node = (bNode *)ptr->data;
+ if (node->id && node->custom1 != value) {
+ id_us_min((ID *)node->id);
+ node->id = NULL;
+ }
+ node->custom1 = value;
+}
+
+static int rna_NodeCryptomatte_layer_name_get(PointerRNA *ptr)
+{
+ int index = 0;
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *storage = node->storage;
+ LISTBASE_FOREACH_INDEX (CryptomatteLayer *, layer, &storage->runtime.layers, index) {
+ if (STREQLEN(storage->layer_name, layer->name, sizeof(storage->layer_name))) {
+ return index;
+ }
+ }
+ return 0;
+}
+
+static void rna_NodeCryptomatte_layer_name_set(PointerRNA *ptr, int new_value)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *storage = node->storage;
+
+ CryptomatteLayer *layer = BLI_findlink(&storage->runtime.layers, new_value);
+ if (layer) {
+ STRNCPY(storage->layer_name, layer->name);
+ }
+}
+
+static const EnumPropertyItem *rna_NodeCryptomatte_layer_name_itemf(bContext *UNUSED(C),
+ PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ bNode *node = (bNode *)ptr->data;
+ NodeCryptomatte *storage = node->storage;
+ EnumPropertyItem *item = NULL;
+ EnumPropertyItem template = {0, "", 0, "", ""};
+ int totitem = 0;
+
+ ntreeCompositCryptomatteUpdateLayerNames(node);
+ int layer_index;
+ LISTBASE_FOREACH_INDEX (CryptomatteLayer *, layer, &storage->runtime.layers, layer_index) {
+ template.value = layer_index;
+ template.identifier = layer->name;
+ template.name = layer->name;
+ RNA_enum_item_add(&item, &totitem, &template);
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
+static PointerRNA rna_NodeCryptomatte_scene_get(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ Scene *scene = (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) ? (Scene *)node->id : NULL;
+ return rna_pointer_inherit_refine(ptr, &RNA_Scene, scene);
+}
+
+static void rna_NodeCryptomatte_scene_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *reports)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_RENDER) {
+ rna_Node_scene_set(ptr, value, reports);
+ }
+}
+
+static PointerRNA rna_NodeCryptomatte_image_get(PointerRNA *ptr)
+{
+ bNode *node = (bNode *)ptr->data;
+
+ Image *image = (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) ? (Image *)node->id : NULL;
+ return rna_pointer_inherit_refine(ptr, &RNA_Image, image);
+}
+
+static void rna_NodeCryptomatte_image_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *UNUSED(reports))
+{
+ bNode *node = (bNode *)ptr->data;
+
+ if (node->custom1 == CMP_CRYPTOMATTE_SRC_IMAGE) {
+ if (node->id)
+ id_us_min((ID *)node->id);
+ if (value.data)
+ id_us_plus((ID *)value.data);
+
+ node->id = value.data;
+ }
+}
+
+static bool rna_NodeCryptomatte_image_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
+{
+ Image *image = (Image *)value.owner_id;
+ return image->type == IMA_TYPE_MULTILAYER;
+}
+
static void rna_NodeCryptomatte_matte_get(PointerRNA *ptr, char *value)
{
bNode *node = (bNode *)ptr->data;
@@ -3750,13 +3885,13 @@ static void rna_NodeCryptomatte_matte_set(PointerRNA *ptr, const char *value)
static void rna_NodeCryptomatte_update_add(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- ntreeCompositCryptomatteSyncFromAdd((bNodeTree *)ptr->owner_id, ptr->data);
+ ntreeCompositCryptomatteSyncFromAdd(ptr->data);
rna_Node_update(bmain, scene, ptr);
}
static void rna_NodeCryptomatte_update_remove(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- ntreeCompositCryptomatteSyncFromRemove((bNodeTree *)ptr->owner_id, ptr->data);
+ ntreeCompositCryptomatteSyncFromRemove(ptr->data);
rna_Node_update(bmain, scene, ptr);
}
@@ -8409,12 +8544,11 @@ static void def_cmp_cryptomatte_entry(BlenderRNA *brna)
RNA_def_struct_name_property(srna, prop);
}
-static void def_cmp_cryptomatte(StructRNA *srna)
+static void def_cmp_cryptomatte_common(StructRNA *srna)
{
PropertyRNA *prop;
static float default_1[3] = {1.0f, 1.0f, 1.0f};
- RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage");
prop = RNA_def_property(srna, "matte_id", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop,
"rna_NodeCryptomatte_matte_get",
@@ -8425,6 +8559,7 @@ static void def_cmp_cryptomatte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "add", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "runtime.add");
RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(
@@ -8432,6 +8567,7 @@ static void def_cmp_cryptomatte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_add");
prop = RNA_def_property(srna, "remove", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "runtime.remove");
RNA_def_property_float_array_default(prop, default_1);
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_text(
@@ -8441,6 +8577,73 @@ static void def_cmp_cryptomatte(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_remove");
}
+static void def_cmp_cryptomatte_legacy(StructRNA *srna)
+{
+ RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage");
+ def_cmp_cryptomatte_common(srna);
+}
+
+static void def_cmp_cryptomatte(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static const EnumPropertyItem cryptomatte_source_items[] = {
+ {CMP_CRYPTOMATTE_SRC_RENDER, "RENDER", 0, "Render", "Use Cryptomatte passes from a render"},
+ {CMP_CRYPTOMATTE_SRC_IMAGE, "IMAGE", 0, "Image", "Use Cryptomatte passes from an image"},
+ {0, NULL, 0, NULL, NULL}};
+
+ prop = RNA_def_property(srna, "source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, cryptomatte_source_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_NodeCryptomatte_source_set", NULL);
+ RNA_def_property_ui_text(prop, "Source", "Where the Cryptomatte passes are loaded from");
+
+ prop = RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(
+ prop, "rna_NodeCryptomatte_scene_get", "rna_NodeCryptomatte_scene_set", NULL, NULL);
+ RNA_def_property_struct_type(prop, "Scene");
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
+ RNA_def_property_ui_text(prop, "Scene", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_funcs(prop,
+ "rna_NodeCryptomatte_image_get",
+ "rna_NodeCryptomatte_image_set",
+ NULL,
+ "rna_NodeCryptomatte_image_poll");
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Image", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "NodeCryptomatte", "storage");
+ def_cmp_cryptomatte_common(srna);
+
+ prop = RNA_def_property(srna, "layer_name", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, node_cryptomatte_layer_name_items);
+ RNA_def_property_enum_funcs(prop,
+ "rna_NodeCryptomatte_layer_name_get",
+ "rna_NodeCryptomatte_layer_name_set",
+ "rna_NodeCryptomatte_layer_name_itemf");
+ RNA_def_property_ui_text(prop, "Cryptomatte Layer", "What Cryptomatte layer is used");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "entries", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "entries", NULL);
+ RNA_def_property_struct_type(prop, "CryptomatteEntry");
+ RNA_def_property_ui_text(prop, "Mattes", "");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ /* Included here instead of defining image_user as a property of the node,
+ * see def_cmp_image for details.
+ * As mentioned in DNA_node_types.h, iuser is the first member of the Cryptomatte
+ * storage type, so we can cast node->storage to ImageUser.
+ * That is required since we can't define the properties from storage->iuser directly... */
+ RNA_def_struct_sdna_from(srna, "ImageUser", "storage");
+ def_node_image_user(srna);
+}
+
static void def_cmp_denoise(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 6ad02986010..b0dd0edeec5 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -106,6 +106,7 @@ void register_node_type_cmp_doubleedgemask(void);
void register_node_type_cmp_keyingscreen(void);
void register_node_type_cmp_keying(void);
void register_node_type_cmp_cryptomatte(void);
+void register_node_type_cmp_cryptomatte_legacy(void);
void register_node_type_cmp_translate(void);
void register_node_type_cmp_rotate(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 493aaa05675..e9983d7e92c 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -220,7 +220,8 @@ DefNode(CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELA
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", "" )
-DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE", Cryptomatte, "Cryptomatte", "" )
+DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE_V2", CryptomatteV2, "Cryptomatte", "" )
+DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE_LEGACY, def_cmp_cryptomatte_legacy, "CRYPTOMATTE", Cryptomatte, "Cryptomatte (Legacy)", "" )
DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOISE", Denoise, "Denoise", "" )
DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" )
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index 84cd84e41c7..d81076c2fa6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -21,11 +21,84 @@
* \ingroup cmpnodes
*/
+#include "node_composite_util.h"
+
#include "BLI_assert.h"
#include "BLI_dynstr.h"
#include "BLI_hash_mm3.h"
+#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"
-#include "node_composite_util.h"
+
+#include "BKE_context.h"
+#include "BKE_cryptomatte.hh"
+#include "BKE_global.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+
+#include <optional>
+
+/** \name Cryptomatte
+ * \{ */
+
+static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node(
+ const bNode &node, const int frame_number, const bool use_meta_data)
+{
+ blender::bke::cryptomatte::CryptomatteSessionPtr session;
+ if (node.type != CMP_NODE_CRYPTOMATTE) {
+ return session;
+ }
+
+ NodeCryptomatte *node_cryptomatte = static_cast<NodeCryptomatte *>(node.storage);
+ switch (node.custom1) {
+ case CMP_CRYPTOMATTE_SRC_RENDER: {
+ Scene *scene = (Scene *)node.id;
+ if (!scene) {
+ return session;
+ }
+ BLI_assert(GS(scene->id.name) == ID_SCE);
+
+ if (use_meta_data) {
+ Render *render = (scene) ? RE_GetSceneRender(scene) : nullptr;
+ RenderResult *render_result = render ? RE_AcquireResultRead(render) : nullptr;
+ if (render_result) {
+ session = blender::bke::cryptomatte::CryptomatteSessionPtr(
+ BKE_cryptomatte_init_from_render_result(render_result));
+ }
+ if (render) {
+ RE_ReleaseResult(render);
+ }
+ }
+
+ if (session == nullptr) {
+ session = blender::bke::cryptomatte::CryptomatteSessionPtr(
+ BKE_cryptomatte_init_from_scene(scene));
+ }
+
+ break;
+ }
+
+ case CMP_CRYPTOMATTE_SRC_IMAGE: {
+ Image *image = (Image *)node.id;
+ BLI_assert(!image || GS(image->id.name) == ID_IM);
+ if (!image || image->type != IMA_TYPE_MULTILAYER) {
+ break;
+ }
+
+ ImageUser *iuser = &node_cryptomatte->iuser;
+ BKE_image_user_frame_calc(image, iuser, frame_number);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr);
+ RenderResult *render_result = image->rr;
+ if (render_result) {
+ session = blender::bke::cryptomatte::CryptomatteSessionPtr(
+ BKE_cryptomatte_init_from_render_result(render_result));
+ }
+ BKE_image_release_ibuf(image, ibuf, nullptr);
+ break;
+ }
+ }
+ return session;
+}
extern "C" {
static CryptomatteEntry *cryptomatte_find(const NodeCryptomatte &n, float encoded_hash)
@@ -38,21 +111,29 @@ static CryptomatteEntry *cryptomatte_find(const NodeCryptomatte &n, float encode
return nullptr;
}
-static void cryptomatte_add(NodeCryptomatte &n, float f)
+static void cryptomatte_add(bNode &node, NodeCryptomatte &node_cryptomatte, float encoded_hash)
{
/* Check if entry already exist. */
- if (cryptomatte_find(n, f)) {
+ if (cryptomatte_find(node_cryptomatte, encoded_hash)) {
return;
}
+
CryptomatteEntry *entry = static_cast<CryptomatteEntry *>(
MEM_callocN(sizeof(CryptomatteEntry), __func__));
- entry->encoded_hash = f;
- BLI_addtail(&n.entries, entry);
+ entry->encoded_hash = encoded_hash;
+ /* TODO(jbakker): Get current frame from scene. */
+ blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
+ node, 0, true);
+ if (session) {
+ BKE_cryptomatte_find_name(session.get(), encoded_hash, entry->name, sizeof(entry->name));
+ }
+
+ BLI_addtail(&node_cryptomatte.entries, entry);
}
-static void cryptomatte_remove(NodeCryptomatte &n, float f)
+static void cryptomatte_remove(NodeCryptomatte &n, float encoded_hash)
{
- CryptomatteEntry *entry = cryptomatte_find(n, f);
+ CryptomatteEntry *entry = cryptomatte_find(n, encoded_hash);
if (!entry) {
return;
}
@@ -60,73 +141,104 @@ static void cryptomatte_remove(NodeCryptomatte &n, float f)
MEM_freeN(entry);
}
-static bNodeSocketTemplate outputs[] = {
+static bNodeSocketTemplate cmp_node_cryptomatte_in[] = {
+ {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, {-1, ""}};
+
+static bNodeSocketTemplate cmp_node_cryptomatte_out[] = {
{SOCK_RGBA, N_("Image")},
{SOCK_FLOAT, N_("Matte")},
{SOCK_RGBA, N_("Pick")},
{-1, ""},
};
-void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *UNUSED(ntree), bNode *node)
+void ntreeCompositCryptomatteSyncFromAdd(bNode *node)
{
+ BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
- if (n->add[0] != 0.0f) {
- cryptomatte_add(*n, n->add[0]);
- zero_v3(n->add);
+ if (n->runtime.add[0] != 0.0f) {
+ cryptomatte_add(*node, *n, n->runtime.add[0]);
+ zero_v3(n->runtime.add);
}
}
-void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *UNUSED(ntree), bNode *node)
+void ntreeCompositCryptomatteSyncFromRemove(bNode *node)
{
+ BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
- if (n->remove[0] != 0.0f) {
- cryptomatte_remove(*n, n->remove[0]);
- zero_v3(n->remove);
+ if (n->runtime.remove[0] != 0.0f) {
+ cryptomatte_remove(*n, n->runtime.remove[0]);
+ zero_v3(n->runtime.remove);
}
}
-
-bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
+void ntreeCompositCryptomatteUpdateLayerNames(bNode *node)
{
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
- char sockname[32];
- n->num_inputs++;
- BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1);
- bNodeSocket *sock = nodeAddStaticSocket(
- ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, sockname);
- return sock;
+ BLI_freelistN(&n->runtime.layers);
+
+ blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
+ *node, 0, false);
+
+ if (session) {
+ for (blender::StringRef layer_name :
+ blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) {
+ CryptomatteLayer *layer = static_cast<CryptomatteLayer *>(
+ MEM_callocN(sizeof(CryptomatteLayer), __func__));
+ layer_name.copy(layer->name);
+ BLI_addtail(&n->runtime.layers, layer);
+ }
+ }
}
-int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
+void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len)
{
- NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
- if (n->num_inputs < 2) {
- return 0;
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
+ NodeCryptomatte *node_cryptomatte = (NodeCryptomatte *)node->storage;
+ blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
+ *node, 0, false);
+ std::string first_layer_name;
+
+ if (session) {
+ for (blender::StringRef layer_name :
+ blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) {
+ if (first_layer_name.empty()) {
+ first_layer_name = layer_name;
+ }
+
+ if (layer_name == node_cryptomatte->layer_name) {
+ BLI_strncpy(r_prefix, node_cryptomatte->layer_name, prefix_len);
+ return;
+ }
+ }
}
- bNodeSocket *sock = static_cast<bNodeSocket *>(node->inputs.last);
- nodeRemoveSocket(ntree, node, sock);
- n->num_inputs--;
- return 1;
+
+ const char *cstr = first_layer_name.c_str();
+ BLI_strncpy(r_prefix, cstr, prefix_len);
}
-static void init(bNodeTree *ntree, bNode *node)
+static void node_init_cryptomatte(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeCryptomatte *user = static_cast<NodeCryptomatte *>(
MEM_callocN(sizeof(NodeCryptomatte), __func__));
node->storage = user;
+}
- nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
-
- /* Add three inputs by default, as recommended by the Cryptomatte specification. */
- ntreeCompositCryptomatteAddSocket(ntree, node);
- ntreeCompositCryptomatteAddSocket(ntree, node);
- ntreeCompositCryptomatteAddSocket(ntree, node);
+static void node_init_api_cryptomatte(const bContext *C, PointerRNA *ptr)
+{
+ Scene *scene = CTX_data_scene(C);
+ bNode *node = static_cast<bNode *>(ptr->data);
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE);
+ node->id = &scene->id;
+ id_us_plus(node->id);
}
static void node_free_cryptomatte(bNode *node)
{
+ BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY));
NodeCryptomatte *nc = static_cast<NodeCryptomatte *>(node->storage);
if (nc) {
+ BLI_freelistN(&nc->runtime.layers);
BLI_freelistN(&nc->entries);
MEM_freeN(nc);
}
@@ -140,17 +252,92 @@ static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree),
NodeCryptomatte *dest_nc = static_cast<NodeCryptomatte *>(MEM_dupallocN(src_nc));
BLI_duplicatelist(&dest_nc->entries, &src_nc->entries);
+ BLI_listbase_clear(&dest_nc->runtime.layers);
dest_node->storage = dest_nc;
}
+static bool node_poll_cryptomatte(bNodeType *UNUSED(ntype), bNodeTree *ntree)
+{
+ if (STREQ(ntree->idname, "CompositorNodeTree")) {
+ Scene *scene;
+
+ /* See node_composit_poll_rlayers. */
+ for (scene = static_cast<Scene *>(G.main->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
+ if (scene->nodetree == ntree) {
+ break;
+ }
+ }
+
+ return scene != nullptr;
+ }
+ return false;
+}
+
void register_node_type_cmp_cryptomatte(void)
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_CONVERTOR, 0);
- node_type_socket_templates(&ntype, nullptr, outputs);
- node_type_init(&ntype, init);
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE, 0);
+ node_type_socket_templates(&ntype, cmp_node_cryptomatte_in, cmp_node_cryptomatte_out);
+ node_type_init(&ntype, node_init_cryptomatte);
+ ntype.initfunc_api = node_init_api_cryptomatte;
+ ntype.poll = node_poll_cryptomatte;
+ node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
+ nodeRegisterType(&ntype);
+}
+
+/** \} */
+
+/** \name Cryptomatte Legacy
+ * \{ */
+static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node)
+{
+ node_init_cryptomatte(ntree, node);
+
+ nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image");
+
+ /* Add three inputs by default, as recommended by the Cryptomatte specification. */
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+ ntreeCompositCryptomatteAddSocket(ntree, node);
+}
+
+bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
+{
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE_LEGACY);
+ NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
+ char sockname[32];
+ n->num_inputs++;
+ BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1);
+ bNodeSocket *sock = nodeAddStaticSocket(
+ ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, sockname);
+ return sock;
+}
+
+int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
+{
+ BLI_assert(node->type == CMP_NODE_CRYPTOMATTE_LEGACY);
+ NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage);
+ if (n->num_inputs < 2) {
+ return 0;
+ }
+ bNodeSocket *sock = static_cast<bNodeSocket *>(node->inputs.last);
+ nodeRemoveSocket(ntree, node, sock);
+ n->num_inputs--;
+ return 1;
+}
+
+void register_node_type_cmp_cryptomatte_legacy(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE, 0);
+ node_type_socket_templates(&ntype, nullptr, cmp_node_cryptomatte_out);
+ node_type_init(&ntype, node_init_cryptomatte_legacy);
node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
nodeRegisterType(&ntype);
}
+
+/** \} */
}