diff options
Diffstat (limited to 'source')
28 files changed, 1165 insertions, 142 deletions
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); } + +/** \} */ } |