Compositor: Cryptomatte compositing node.
This patch adds a new matte node that implements the Cryptomatte specification. It also incluces a custom eye dropper that works outside of a color picker. Cryptomatte export for the Cycles render engine will be in a separate patch. Reviewers: brecht Reviewed By: brecht Subscribers: brecht Tags: #compositing Differential Revision: https://developer.blender.org/D3531
This commit is contained in:
@@ -394,6 +394,7 @@ compositor_node_categories = [
|
|||||||
NodeItem("CompositorNodeChromaMatte"),
|
NodeItem("CompositorNodeChromaMatte"),
|
||||||
NodeItem("CompositorNodeColorMatte"),
|
NodeItem("CompositorNodeColorMatte"),
|
||||||
NodeItem("CompositorNodeDoubleEdgeMask"),
|
NodeItem("CompositorNodeDoubleEdgeMask"),
|
||||||
|
NodeItem("CompositorNodeCryptomatte"),
|
||||||
]),
|
]),
|
||||||
CompositorNodeCategory("CMP_DISTORT", "Distort", items=[
|
CompositorNodeCategory("CMP_DISTORT", "Distort", items=[
|
||||||
NodeItem("CompositorNodeScale"),
|
NodeItem("CompositorNodeScale"),
|
||||||
|
@@ -945,6 +945,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
|
|||||||
#define CMP_NODE_PLANETRACKDEFORM 320
|
#define CMP_NODE_PLANETRACKDEFORM 320
|
||||||
#define CMP_NODE_CORNERPIN 321
|
#define CMP_NODE_CORNERPIN 321
|
||||||
#define CMP_NODE_SWITCH_VIEW 322
|
#define CMP_NODE_SWITCH_VIEW 322
|
||||||
|
#define CMP_NODE_CRYPTOMATTE 323
|
||||||
|
|
||||||
/* channel toggles */
|
/* channel toggles */
|
||||||
#define CMP_CHAN_RGB 1
|
#define CMP_CHAN_RGB 1
|
||||||
@@ -997,6 +998,11 @@ void ntreeCompositOutputFileUniqueLayer(struct ListBase *list, struct bNodeSocke
|
|||||||
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
|
void ntreeCompositColorBalanceSyncFromLGG(bNodeTree *ntree, bNode *node);
|
||||||
void ntreeCompositColorBalanceSyncFromCDL(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);
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@@ -3528,6 +3528,7 @@ static void registerCompositNodes(void)
|
|||||||
register_node_type_cmp_doubleedgemask();
|
register_node_type_cmp_doubleedgemask();
|
||||||
register_node_type_cmp_keyingscreen();
|
register_node_type_cmp_keyingscreen();
|
||||||
register_node_type_cmp_keying();
|
register_node_type_cmp_keying();
|
||||||
|
register_node_type_cmp_cryptomatte();
|
||||||
|
|
||||||
register_node_type_cmp_translate();
|
register_node_type_cmp_translate();
|
||||||
register_node_type_cmp_rotate();
|
register_node_type_cmp_rotate();
|
||||||
|
40
source/blender/blenlib/BLI_hash_mm3.h
Normal file
40
source/blender/blenlib/BLI_hash_mm3.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BLI_HASH_MM3_H__
|
||||||
|
#define __BLI_HASH_MM3_H__
|
||||||
|
|
||||||
|
/** \file BLI_hash_mm3.h
|
||||||
|
* \ingroup bli
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BLI_sys_types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t BLI_hash_mm3(const unsigned char *data, size_t len, uint32_t seed);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __BLI_HASH_MM2A_H__ */
|
@@ -74,6 +74,7 @@ set(SRC
|
|||||||
intern/gsqueue.c
|
intern/gsqueue.c
|
||||||
intern/hash_md5.c
|
intern/hash_md5.c
|
||||||
intern/hash_mm2a.c
|
intern/hash_mm2a.c
|
||||||
|
intern/hash_mm3.c
|
||||||
intern/jitter_2d.c
|
intern/jitter_2d.c
|
||||||
intern/lasso_2d.c
|
intern/lasso_2d.c
|
||||||
intern/list_sort_impl.h
|
intern/list_sort_impl.h
|
||||||
@@ -159,6 +160,7 @@ set(SRC
|
|||||||
BLI_hash.h
|
BLI_hash.h
|
||||||
BLI_hash_md5.h
|
BLI_hash_md5.h
|
||||||
BLI_hash_mm2a.h
|
BLI_hash_mm2a.h
|
||||||
|
BLI_hash_mm3.h
|
||||||
BLI_heap.h
|
BLI_heap.h
|
||||||
BLI_jitter_2d.h
|
BLI_jitter_2d.h
|
||||||
BLI_kdopbvh.h
|
BLI_kdopbvh.h
|
||||||
|
147
source/blender/blenlib/intern/hash_mm3.c
Normal file
147
source/blender/blenlib/intern/hash_mm3.c
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Blender Foundation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file blender/blenlib/intern/hash_mm3.c
|
||||||
|
* \ingroup bli
|
||||||
|
*
|
||||||
|
* Functions to compute Murmur3 hash key.
|
||||||
|
*
|
||||||
|
* This Code is based on alShaders/Cryptomatte/MurmurHash3.h:
|
||||||
|
*
|
||||||
|
* MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||||
|
* domain. The author hereby disclaims copyright to this source code.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BLI_compiler_compat.h"
|
||||||
|
#include "BLI_compiler_attrs.h"
|
||||||
|
#include "BLI_hash_mm3.h" /* own include */
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# include <stdlib.h>
|
||||||
|
# define ROTL32(x,y) _rotl(x,y)
|
||||||
|
# define BIG_CONSTANT(x) (x)
|
||||||
|
|
||||||
|
/* Other compilers */
|
||||||
|
#else /* defined(_MSC_VER) */
|
||||||
|
static inline uint32_t rotl32(uint32_t x, int8_t r)
|
||||||
|
{
|
||||||
|
return (x << r) | (x >> (32 - r));
|
||||||
|
}
|
||||||
|
# define ROTL32(x,y) rotl32(x,y)
|
||||||
|
# define BIG_CONSTANT(x) (x##LLU)
|
||||||
|
#endif /* !defined(_MSC_VER) */
|
||||||
|
|
||||||
|
/* Block read - if your platform needs to do endian-swapping or can only
|
||||||
|
* handle aligned reads, do the conversion here
|
||||||
|
*/
|
||||||
|
|
||||||
|
BLI_INLINE uint32_t getblock32(const uint32_t * p, int i)
|
||||||
|
{
|
||||||
|
return p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_INLINE uint64_t getblock64(const uint64_t * p, int i)
|
||||||
|
{
|
||||||
|
return p[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalization mix - force all bits of a hash block to avalanche */
|
||||||
|
|
||||||
|
BLI_INLINE uint32_t fmix32(uint32_t h)
|
||||||
|
{
|
||||||
|
h ^= h >> 16;
|
||||||
|
h *= 0x85ebca6b;
|
||||||
|
h ^= h >> 13;
|
||||||
|
h *= 0xc2b2ae35;
|
||||||
|
h ^= h >> 16;
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLI_INLINE uint64_t fmix64(uint64_t k)
|
||||||
|
{
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
|
||||||
|
k ^= k >> 33;
|
||||||
|
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
|
||||||
|
k ^= k >> 33;
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t BLI_hash_mm3(const unsigned char *in, size_t len, uint32_t seed)
|
||||||
|
{
|
||||||
|
const uint8_t *data = (const uint8_t*)in;
|
||||||
|
const int nblocks = len / 4;
|
||||||
|
|
||||||
|
uint32_t h1 = seed;
|
||||||
|
|
||||||
|
const uint32_t c1 = 0xcc9e2d51;
|
||||||
|
const uint32_t c2 = 0x1b873593;
|
||||||
|
|
||||||
|
/* body */
|
||||||
|
|
||||||
|
const uint32_t *blocks = (const uint32_t *)(data + nblocks*4);
|
||||||
|
|
||||||
|
for (int i = -nblocks; i; i++) {
|
||||||
|
uint32_t k1 = getblock32(blocks,i);
|
||||||
|
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = ROTL32(k1,15);
|
||||||
|
k1 *= c2;
|
||||||
|
|
||||||
|
h1 ^= k1;
|
||||||
|
h1 = ROTL32(h1,13);
|
||||||
|
h1 = h1*5+0xe6546b64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tail */
|
||||||
|
|
||||||
|
const uint8_t *tail = (const uint8_t*)(data + nblocks*4);
|
||||||
|
|
||||||
|
uint32_t k1 = 0;
|
||||||
|
|
||||||
|
switch (len & 3) {
|
||||||
|
case 3:
|
||||||
|
k1 ^= tail[2] << 16;
|
||||||
|
ATTR_FALLTHROUGH;
|
||||||
|
case 2:
|
||||||
|
k1 ^= tail[1] << 8;
|
||||||
|
ATTR_FALLTHROUGH;
|
||||||
|
case 1:
|
||||||
|
k1 ^= tail[0];
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = ROTL32(k1,15);
|
||||||
|
k1 *= c2;
|
||||||
|
h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* finalization */
|
||||||
|
|
||||||
|
h1 ^= len;
|
||||||
|
|
||||||
|
h1 = fmix32(h1);
|
||||||
|
|
||||||
|
return h1;
|
||||||
|
}
|
@@ -3161,6 +3161,10 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
|
|||||||
direct_link_curvemapping(fd, node->storage);
|
direct_link_curvemapping(fd, node->storage);
|
||||||
else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
|
else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
|
||||||
((ImageUser *)node->storage)->ok = 1;
|
((ImageUser *)node->storage)->ok = 1;
|
||||||
|
else if (node->type==CMP_NODE_CRYPTOMATTE) {
|
||||||
|
NodeCryptomatte *nc = (NodeCryptomatte *) node->storage;
|
||||||
|
nc->matte_id = newdataadr(fd, nc->matte_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ( ntree->type==NTREE_TEXTURE) {
|
else if ( ntree->type==NTREE_TEXTURE) {
|
||||||
if (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME)
|
if (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME)
|
||||||
|
@@ -1077,6 +1077,13 @@ static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree)
|
|||||||
}
|
}
|
||||||
writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
|
writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
|
||||||
}
|
}
|
||||||
|
else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) {
|
||||||
|
NodeCryptomatte *nc = (NodeCryptomatte *)node->storage;
|
||||||
|
if (nc->matte_id) {
|
||||||
|
writedata(wd, DATA, strlen(nc->matte_id) + 1, nc->matte_id);
|
||||||
|
}
|
||||||
|
writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
|
writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage);
|
||||||
}
|
}
|
||||||
|
@@ -182,6 +182,11 @@ set(SRC
|
|||||||
operations/COM_SunBeamsOperation.cpp
|
operations/COM_SunBeamsOperation.cpp
|
||||||
operations/COM_SunBeamsOperation.h
|
operations/COM_SunBeamsOperation.h
|
||||||
|
|
||||||
|
nodes/COM_CryptomatteNode.cpp
|
||||||
|
nodes/COM_CryptomatteNode.h
|
||||||
|
operations/COM_CryptomatteOperation.cpp
|
||||||
|
operations/COM_CryptomatteOperation.h
|
||||||
|
|
||||||
nodes/COM_CornerPinNode.cpp
|
nodes/COM_CornerPinNode.cpp
|
||||||
nodes/COM_CornerPinNode.h
|
nodes/COM_CornerPinNode.h
|
||||||
nodes/COM_PlaneTrackDeformNode.cpp
|
nodes/COM_PlaneTrackDeformNode.cpp
|
||||||
|
@@ -55,6 +55,7 @@ extern "C" {
|
|||||||
#include "COM_Converter.h"
|
#include "COM_Converter.h"
|
||||||
#include "COM_CornerPinNode.h"
|
#include "COM_CornerPinNode.h"
|
||||||
#include "COM_CropNode.h"
|
#include "COM_CropNode.h"
|
||||||
|
#include "COM_CryptomatteNode.h"
|
||||||
#include "COM_DefocusNode.h"
|
#include "COM_DefocusNode.h"
|
||||||
#include "COM_DespeckleNode.h"
|
#include "COM_DespeckleNode.h"
|
||||||
#include "COM_DifferenceMatteNode.h"
|
#include "COM_DifferenceMatteNode.h"
|
||||||
@@ -406,6 +407,9 @@ Node *Converter::convert(bNode *b_node)
|
|||||||
case CMP_NODE_SUNBEAMS:
|
case CMP_NODE_SUNBEAMS:
|
||||||
node = new SunBeamsNode(b_node);
|
node = new SunBeamsNode(b_node);
|
||||||
break;
|
break;
|
||||||
|
case CMP_NODE_CRYPTOMATTE:
|
||||||
|
node = new CryptomatteNode(b_node);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
120
source/blender/compositor/nodes/COM_CryptomatteNode.cpp
Normal file
120
source/blender/compositor/nodes/COM_CryptomatteNode.cpp
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018, Blender Foundation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributor:
|
||||||
|
* Lukas Stockner
|
||||||
|
* Stefan Werner
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "COM_CryptomatteNode.h"
|
||||||
|
#include "COM_CryptomatteOperation.h"
|
||||||
|
#include "COM_SetAlphaOperation.h"
|
||||||
|
#include "COM_ConvertOperation.h"
|
||||||
|
#include "BLI_string.h"
|
||||||
|
#include "BLI_hash_mm3.h"
|
||||||
|
#include "BLI_assert.h"
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode)
|
||||||
|
{
|
||||||
|
/* pass */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is taken from the Cryptomatte specification 1.0. */
|
||||||
|
static inline float hash_to_float(uint32_t hash) {
|
||||||
|
uint32_t mantissa = hash & (( 1 << 23) - 1);
|
||||||
|
uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
|
||||||
|
exponent = max(exponent, (uint32_t) 1);
|
||||||
|
exponent = min(exponent, (uint32_t) 254);
|
||||||
|
exponent = exponent << 23;
|
||||||
|
uint32_t sign = (hash >> 31);
|
||||||
|
sign = sign << 31;
|
||||||
|
uint32_t float_bits = sign | exponent | mantissa;
|
||||||
|
float f;
|
||||||
|
/* Bit casting relies on equal size for both types. */
|
||||||
|
BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "float and uint32_t are not the same size")
|
||||||
|
::memcpy(&f, &float_bits, sizeof(float));
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CryptomatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
|
||||||
|
{
|
||||||
|
NodeInput *inputSocketImage = this->getInputSocket(0);
|
||||||
|
NodeOutput *outputSocketImage = this->getOutputSocket(0);
|
||||||
|
NodeOutput *outputSocketMatte = this->getOutputSocket(1);
|
||||||
|
NodeOutput *outputSocketPick = this->getOutputSocket(2);
|
||||||
|
|
||||||
|
bNode *node = this->getbNode();
|
||||||
|
NodeCryptomatte *cryptoMatteSettings = (NodeCryptomatte *)node->storage;
|
||||||
|
|
||||||
|
CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets()-1);
|
||||||
|
if (cryptoMatteSettings) {
|
||||||
|
if (cryptoMatteSettings->matte_id) {
|
||||||
|
/* Split the string by commas, ignoring white space. */
|
||||||
|
std::string input = cryptoMatteSettings->matte_id;
|
||||||
|
std::istringstream ss(input);
|
||||||
|
while (ss.good()) {
|
||||||
|
std::string token;
|
||||||
|
getline(ss, token, ',');
|
||||||
|
/* Ignore empty tokens. */
|
||||||
|
if (token.length() > 0) {
|
||||||
|
size_t first = token.find_first_not_of(' ');
|
||||||
|
size_t last = token.find_last_not_of(' ');
|
||||||
|
if (first == std::string::npos || last == std::string::npos) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
token = token.substr(first, (last - first + 1));
|
||||||
|
if (*token.begin() == '<' && *(--token.end()) == '>') {
|
||||||
|
operation->addObjectIndex(atof(token.substr(1, token.length() - 2).c_str()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uint32_t hash = BLI_hash_mm3((const unsigned char*)token.c_str(), token.length(), 0);
|
||||||
|
operation->addObjectIndex(hash_to_float(hash));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
converter.addOperation(operation);
|
||||||
|
|
||||||
|
for (int i = 0; i < getNumberOfInputSockets()-1; ++i) {
|
||||||
|
converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
SeparateChannelOperation *separateOperation = new SeparateChannelOperation;
|
||||||
|
separateOperation->setChannel(3);
|
||||||
|
converter.addOperation(separateOperation);
|
||||||
|
|
||||||
|
SetAlphaOperation *operationAlpha = new SetAlphaOperation();
|
||||||
|
converter.addOperation(operationAlpha);
|
||||||
|
|
||||||
|
converter.addLink(operation->getOutputSocket(0), separateOperation->getInputSocket(0));
|
||||||
|
converter.addLink(separateOperation->getOutputSocket(0), operationAlpha->getInputSocket(1));
|
||||||
|
|
||||||
|
SetAlphaOperation *clearAlphaOperation = new SetAlphaOperation();
|
||||||
|
converter.addOperation(clearAlphaOperation);
|
||||||
|
converter.addInputValue(clearAlphaOperation->getInputSocket(1), 1.0f);
|
||||||
|
|
||||||
|
converter.addLink(operation->getOutputSocket(0), clearAlphaOperation->getInputSocket(0));
|
||||||
|
|
||||||
|
converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
|
||||||
|
converter.mapOutputSocket(outputSocketMatte, separateOperation->getOutputSocket(0));
|
||||||
|
converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket(0));
|
||||||
|
converter.mapOutputSocket(outputSocketPick, clearAlphaOperation->getOutputSocket(0));
|
||||||
|
|
||||||
|
}
|
38
source/blender/compositor/nodes/COM_CryptomatteNode.h
Normal file
38
source/blender/compositor/nodes/COM_CryptomatteNode.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018, Blender Foundation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributor:
|
||||||
|
* Lukas Stockner
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _COM_CryptomatteNode_h_
|
||||||
|
#define _COM_CryptomatteNode_h_
|
||||||
|
|
||||||
|
#include "COM_Node.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CryptomatteNode
|
||||||
|
* @ingroup Node
|
||||||
|
*/
|
||||||
|
class CryptomatteNode : public Node {
|
||||||
|
public:
|
||||||
|
CryptomatteNode(bNode *editorNode);
|
||||||
|
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018, Blender Foundation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributor: Lukas Stockner, Stefan Werner
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "COM_CryptomatteOperation.h"
|
||||||
|
|
||||||
|
CryptomatteOperation::CryptomatteOperation(size_t num_inputs) : NodeOperation()
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < num_inputs; i++) {
|
||||||
|
this->addInputSocket(COM_DT_COLOR);
|
||||||
|
}
|
||||||
|
inputs.resize(num_inputs);
|
||||||
|
this->addOutputSocket(COM_DT_COLOR);
|
||||||
|
this->setComplex(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CryptomatteOperation::initExecution()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < inputs.size(); i++) {
|
||||||
|
inputs[i] = this->getInputSocketReader(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CryptomatteOperation::addObjectIndex(float objectIndex)
|
||||||
|
{
|
||||||
|
if (objectIndex != 0.0f) {
|
||||||
|
m_objectIndex.push_back(objectIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CryptomatteOperation::executePixel(float output[4],
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
float input[4];
|
||||||
|
output[0] = output[1] = output[2] = output[3] = 0.0f;
|
||||||
|
for (size_t i = 0; i < inputs.size(); i++) {
|
||||||
|
inputs[i]->read(input, x, y, data);
|
||||||
|
if (i == 0) {
|
||||||
|
/* Write the frontmost object as false color for picking. */
|
||||||
|
output[0] = input[0];
|
||||||
|
uint32_t m3hash;
|
||||||
|
::memcpy(&m3hash, &input[0], sizeof(uint32_t));
|
||||||
|
/* Since the red channel is likely to be out of display range,
|
||||||
|
* setting green and blue gives more meaningful images. */
|
||||||
|
output[1] = ((float) ((m3hash << 8)) / (float) UINT32_MAX);
|
||||||
|
output[2] = ((float) ((m3hash << 16)) / (float) UINT32_MAX);
|
||||||
|
}
|
||||||
|
for(size_t i = 0; i < m_objectIndex.size(); i++) {
|
||||||
|
if (m_objectIndex[i] == input[0]) {
|
||||||
|
output[3] += input[1];
|
||||||
|
}
|
||||||
|
if (m_objectIndex[i] == input[2]) {
|
||||||
|
output[3] += input[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018, Blender Foundation.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributor: Lukas Stockner, Stefan Werner
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _COM_CryptomatteOperation_h
|
||||||
|
#define _COM_CryptomatteOperation_h
|
||||||
|
#include "COM_NodeOperation.h"
|
||||||
|
|
||||||
|
|
||||||
|
class CryptomatteOperation : public NodeOperation {
|
||||||
|
private:
|
||||||
|
std::vector<float> m_objectIndex;
|
||||||
|
public:
|
||||||
|
std::vector<SocketReader *> inputs;
|
||||||
|
|
||||||
|
CryptomatteOperation(size_t num_inputs = 6);
|
||||||
|
|
||||||
|
void initExecution();
|
||||||
|
void executePixel(float output[4], int x, int y, void *data);
|
||||||
|
|
||||||
|
void addObjectIndex(float objectIndex);
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
@@ -969,6 +969,7 @@ void uiTemplateCurveMapping(
|
|||||||
bool levels, bool brush, bool neg_slope);
|
bool levels, bool brush, bool neg_slope);
|
||||||
void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool value_slider, bool lock, bool lock_luminosity, bool cubic);
|
void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool value_slider, bool lock, bool lock_luminosity, bool cubic);
|
||||||
void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool color);
|
void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool color);
|
||||||
|
void uiTemplateCryptoPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
|
||||||
void uiTemplateLayers(
|
void uiTemplateLayers(
|
||||||
uiLayout *layout, struct PointerRNA *ptr, const char *propname,
|
uiLayout *layout, struct PointerRNA *ptr, const char *propname,
|
||||||
PointerRNA *used_ptr, const char *used_propname, int active_layer);
|
PointerRNA *used_ptr, const char *used_propname, int active_layer);
|
||||||
|
@@ -82,6 +82,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
|
|||||||
/* assign to operators */
|
/* assign to operators */
|
||||||
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband");
|
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband");
|
||||||
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color");
|
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color");
|
||||||
|
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color_crypto");
|
||||||
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
|
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
|
||||||
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
|
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
|
||||||
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver");
|
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver");
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include "DNA_screen_types.h"
|
#include "DNA_screen_types.h"
|
||||||
|
|
||||||
#include "BLI_math_vector.h"
|
#include "BLI_math_vector.h"
|
||||||
|
#include "BLI_string.h"
|
||||||
|
|
||||||
#include "BKE_context.h"
|
#include "BKE_context.h"
|
||||||
#include "BKE_main.h"
|
#include "BKE_main.h"
|
||||||
@@ -72,6 +73,8 @@ typedef struct Eyedropper {
|
|||||||
bool accum_start; /* has mouse been pressed */
|
bool accum_start; /* has mouse been pressed */
|
||||||
float accum_col[3];
|
float accum_col[3];
|
||||||
int accum_tot;
|
int accum_tot;
|
||||||
|
|
||||||
|
bool accumulate; /* Color picking for cryptomatte, without accumulation. */
|
||||||
} Eyedropper;
|
} Eyedropper;
|
||||||
|
|
||||||
static bool eyedropper_init(bContext *C, wmOperator *op)
|
static bool eyedropper_init(bContext *C, wmOperator *op)
|
||||||
@@ -80,6 +83,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
|
|||||||
Eyedropper *eye;
|
Eyedropper *eye;
|
||||||
|
|
||||||
op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
|
op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
|
||||||
|
eye->accumulate = !STREQ(op->type->idname, "UI_OT_eyedropper_color_crypto");
|
||||||
|
|
||||||
UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
|
UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
|
||||||
|
|
||||||
@@ -207,29 +211,30 @@ static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3
|
|||||||
RNA_property_update(C, &eye->ptr, eye->prop);
|
RNA_property_update(C, &eye->ptr, eye->prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set sample from accumulated values */
|
|
||||||
static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye)
|
|
||||||
{
|
|
||||||
float col[3];
|
|
||||||
mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot);
|
|
||||||
eyedropper_color_set(C, eye, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* single point sample & set */
|
|
||||||
static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
|
static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
|
||||||
{
|
{
|
||||||
|
/* Accumulate color. */
|
||||||
float col[3];
|
float col[3];
|
||||||
eyedropper_color_sample_fl(C, mx, my, col);
|
eyedropper_color_sample_fl(C, mx, my, col);
|
||||||
eyedropper_color_set(C, eye, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my)
|
if (eye->accumulate) {
|
||||||
{
|
add_v3_v3(eye->accum_col, col);
|
||||||
float col[3];
|
eye->accum_tot++;
|
||||||
eyedropper_color_sample_fl(C, mx, my, col);
|
}
|
||||||
/* delay linear conversion */
|
else {
|
||||||
add_v3_v3(eye->accum_col, col);
|
copy_v3_v3(eye->accum_col, col);
|
||||||
eye->accum_tot++;
|
eye->accum_tot = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply to property. */
|
||||||
|
float accum_col[3];
|
||||||
|
if (eye->accum_tot > 1) {
|
||||||
|
mul_v3_v3fl(accum_col, eye->accum_col, 1.0f / (float)eye->accum_tot);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
copy_v3_v3(accum_col, eye->accum_col);
|
||||||
|
}
|
||||||
|
eyedropper_color_set(C, eye, accum_col);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eyedropper_cancel(bContext *C, wmOperator *op)
|
static void eyedropper_cancel(bContext *C, wmOperator *op)
|
||||||
@@ -254,29 +259,24 @@ static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
|||||||
if (eye->accum_tot == 0) {
|
if (eye->accum_tot == 0) {
|
||||||
eyedropper_color_sample(C, eye, event->x, event->y);
|
eyedropper_color_sample(C, eye, event->x, event->y);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
eyedropper_color_set_accum(C, eye);
|
|
||||||
}
|
|
||||||
eyedropper_exit(C, op);
|
eyedropper_exit(C, op);
|
||||||
return OPERATOR_FINISHED;
|
return OPERATOR_FINISHED;
|
||||||
case EYE_MODAL_SAMPLE_BEGIN:
|
case EYE_MODAL_SAMPLE_BEGIN:
|
||||||
/* enable accum and make first sample */
|
/* enable accum and make first sample */
|
||||||
eye->accum_start = true;
|
eye->accum_start = true;
|
||||||
eyedropper_color_sample_accum(C, eye, event->x, event->y);
|
eyedropper_color_sample(C, eye, event->x, event->y);
|
||||||
break;
|
break;
|
||||||
case EYE_MODAL_SAMPLE_RESET:
|
case EYE_MODAL_SAMPLE_RESET:
|
||||||
eye->accum_tot = 0;
|
eye->accum_tot = 0;
|
||||||
zero_v3(eye->accum_col);
|
zero_v3(eye->accum_col);
|
||||||
eyedropper_color_sample_accum(C, eye, event->x, event->y);
|
eyedropper_color_sample(C, eye, event->x, event->y);
|
||||||
eyedropper_color_set_accum(C, eye);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (event->type == MOUSEMOVE) {
|
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
|
||||||
if (eye->accum_start) {
|
if (eye->accum_start) {
|
||||||
/* button is pressed so keep sampling */
|
/* button is pressed so keep sampling */
|
||||||
eyedropper_color_sample_accum(C, eye, event->x, event->y);
|
eyedropper_color_sample(C, eye, event->x, event->y);
|
||||||
eyedropper_color_set_accum(C, eye);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,20 +321,9 @@ static int eyedropper_exec(bContext *C, wmOperator *op)
|
|||||||
|
|
||||||
static bool eyedropper_poll(bContext *C)
|
static bool eyedropper_poll(bContext *C)
|
||||||
{
|
{
|
||||||
PointerRNA ptr;
|
/* Actual test for active button happens later, since we don't
|
||||||
PropertyRNA *prop;
|
* know which one is active until mouse over. */
|
||||||
int index_dummy;
|
return (CTX_wm_window(C) != NULL);
|
||||||
uiBut *but;
|
|
||||||
|
|
||||||
/* Only color buttons */
|
|
||||||
if ((CTX_wm_window(C) != NULL) &&
|
|
||||||
(but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
|
|
||||||
(but->type == UI_BTYPE_COLOR))
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_OT_eyedropper_color(wmOperatorType *ot)
|
void UI_OT_eyedropper_color(wmOperatorType *ot)
|
||||||
@@ -353,6 +342,22 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
|
|||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
|
ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
|
||||||
|
}
|
||||||
/* properties */
|
|
||||||
|
void UI_OT_eyedropper_color_crypto(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
/* identifiers */
|
||||||
|
ot->name = "Cryptomatte Eyedropper";
|
||||||
|
ot->idname = "UI_OT_eyedropper_color_crypto";
|
||||||
|
ot->description = "Pick a color from Cryptomatte node Pick output image";
|
||||||
|
|
||||||
|
/* api callbacks */
|
||||||
|
ot->invoke = eyedropper_invoke;
|
||||||
|
ot->modal = eyedropper_modal;
|
||||||
|
ot->cancel = eyedropper_cancel;
|
||||||
|
ot->exec = eyedropper_exec;
|
||||||
|
ot->poll = eyedropper_poll;
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
|
||||||
}
|
}
|
||||||
|
@@ -763,6 +763,7 @@ struct wmKeyMap *eyedropper_colorband_modal_keymap(struct wmKeyConfig *keyconf);
|
|||||||
|
|
||||||
/* interface_eyedropper_color.c */
|
/* interface_eyedropper_color.c */
|
||||||
void UI_OT_eyedropper_color(struct wmOperatorType *ot);
|
void UI_OT_eyedropper_color(struct wmOperatorType *ot);
|
||||||
|
void UI_OT_eyedropper_color_crypto(struct wmOperatorType *ot);
|
||||||
|
|
||||||
/* interface_eyedropper_colorband.c */
|
/* interface_eyedropper_colorband.c */
|
||||||
void UI_OT_eyedropper_colorband(struct wmOperatorType *ot);
|
void UI_OT_eyedropper_colorband(struct wmOperatorType *ot);
|
||||||
|
@@ -1138,6 +1138,7 @@ void ED_operatortypes_ui(void)
|
|||||||
|
|
||||||
/* external */
|
/* external */
|
||||||
WM_operatortype_append(UI_OT_eyedropper_color);
|
WM_operatortype_append(UI_OT_eyedropper_color);
|
||||||
|
WM_operatortype_append(UI_OT_eyedropper_color_crypto);
|
||||||
WM_operatortype_append(UI_OT_eyedropper_colorband);
|
WM_operatortype_append(UI_OT_eyedropper_colorband);
|
||||||
WM_operatortype_append(UI_OT_eyedropper_colorband_point);
|
WM_operatortype_append(UI_OT_eyedropper_colorband_point);
|
||||||
WM_operatortype_append(UI_OT_eyedropper_id);
|
WM_operatortype_append(UI_OT_eyedropper_id);
|
||||||
|
@@ -2572,6 +2572,24 @@ void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uiTemplateCryptoPicker(uiLayout *layout, PointerRNA *ptr, const char *propname)
|
||||||
|
{
|
||||||
|
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
|
||||||
|
uiBlock *block;
|
||||||
|
uiBut *but;
|
||||||
|
|
||||||
|
if (!prop) {
|
||||||
|
RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = uiLayoutGetBlock(layout);
|
||||||
|
|
||||||
|
but = uiDefIconTextButO(block, UI_BTYPE_BUT, "UI_OT_eyedropper_color_crypto", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, RNA_property_ui_name(prop), 0, 0, UI_UNIT_X, UI_UNIT_Y, RNA_property_ui_description(prop));
|
||||||
|
but->rnapoin = *ptr;
|
||||||
|
but->rnaprop = prop;
|
||||||
|
but->rnaindex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
/********************* Layer Buttons Template ************************/
|
/********************* Layer Buttons Template ************************/
|
||||||
|
|
||||||
|
@@ -2544,6 +2544,25 @@ static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), P
|
|||||||
uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
|
uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void node_composit_buts_cryptomatte(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");
|
||||||
|
|
||||||
|
uiItemR(col, ptr, "matte_id", 0, "", ICON_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void node_composit_buts_cryptomatte_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
|
||||||
|
{
|
||||||
|
uiItemO(layout, IFACE_("Add Crypto Layer"), ICON_ZOOMIN, "NODE_OT_cryptomatte_layer_add");
|
||||||
|
uiItemO(layout, IFACE_("Remove Crypto Layer"), ICON_ZOOMOUT, "NODE_OT_cryptomatte_layer_remove");
|
||||||
|
}
|
||||||
|
|
||||||
static void node_composit_buts_brightcontrast(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
|
static void node_composit_buts_brightcontrast(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE);
|
uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE);
|
||||||
@@ -2776,6 +2795,10 @@ static void node_composit_set_butfunc(bNodeType *ntype)
|
|||||||
case CMP_NODE_SUNBEAMS:
|
case CMP_NODE_SUNBEAMS:
|
||||||
ntype->draw_buttons = node_composit_buts_sunbeams;
|
ntype->draw_buttons = node_composit_buts_sunbeams;
|
||||||
break;
|
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_BRIGHTCONTRAST:
|
case CMP_NODE_BRIGHTCONTRAST:
|
||||||
ntype->draw_buttons = node_composit_buts_brightcontrast;
|
ntype->draw_buttons = node_composit_buts_brightcontrast;
|
||||||
}
|
}
|
||||||
|
@@ -2611,3 +2611,93 @@ void NODE_OT_clear_viewer_border(wmOperatorType *ot)
|
|||||||
/* flags */
|
/* flags */
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ****************** Cryptomatte Add Socket ******************* */
|
||||||
|
|
||||||
|
static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
|
||||||
|
{
|
||||||
|
SpaceNode *snode = CTX_wm_space_node(C);
|
||||||
|
PointerRNA ptr = CTX_data_pointer_get(C, "node");
|
||||||
|
bNodeTree *ntree = NULL;
|
||||||
|
bNode *node = NULL;
|
||||||
|
|
||||||
|
if (ptr.data) {
|
||||||
|
node = ptr.data;
|
||||||
|
ntree = ptr.id.data;
|
||||||
|
}
|
||||||
|
else if (snode && snode->edittree) {
|
||||||
|
ntree = snode->edittree;
|
||||||
|
node = nodeGetActive(snode->edittree);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ntreeCompositCryptomatteAddSocket(ntree, node);
|
||||||
|
|
||||||
|
snode_notify(C, snode);
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
/* identifiers */
|
||||||
|
ot->name = "Add Cryptomatte Socket";
|
||||||
|
ot->description = "Add a new input layer to a Cryptomatte node";
|
||||||
|
ot->idname = "NODE_OT_cryptomatte_layer_add";
|
||||||
|
|
||||||
|
/* callbacks */
|
||||||
|
ot->exec = node_cryptomatte_add_socket_exec;
|
||||||
|
ot->poll = composite_node_editable;
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ****************** Cryptomatte Remove Socket ******************* */
|
||||||
|
|
||||||
|
static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(op))
|
||||||
|
{
|
||||||
|
SpaceNode *snode = CTX_wm_space_node(C);
|
||||||
|
PointerRNA ptr = CTX_data_pointer_get(C, "node");
|
||||||
|
bNodeTree *ntree = NULL;
|
||||||
|
bNode *node = NULL;
|
||||||
|
|
||||||
|
if (ptr.data) {
|
||||||
|
node = ptr.data;
|
||||||
|
ntree = ptr.id.data;
|
||||||
|
}
|
||||||
|
else if (snode && snode->edittree) {
|
||||||
|
ntree = snode->edittree;
|
||||||
|
node = nodeGetActive(snode->edittree);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node || node->type != CMP_NODE_CRYPTOMATTE) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ntreeCompositCryptomatteRemoveSocket(ntree, node)) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
snode_notify(C, snode);
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
/* identifiers */
|
||||||
|
ot->name = "Remove Cryptomatte Socket";
|
||||||
|
ot->description = "Remove layer from a Crytpomatte node";
|
||||||
|
ot->idname = "NODE_OT_cryptomatte_layer_remove";
|
||||||
|
|
||||||
|
/* callbacks */
|
||||||
|
ot->exec = node_cryptomatte_remove_socket_exec;
|
||||||
|
ot->poll = composite_node_editable;
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
}
|
||||||
|
@@ -222,6 +222,9 @@ void NODE_OT_shader_script_update(struct wmOperatorType *ot);
|
|||||||
void NODE_OT_viewer_border(struct wmOperatorType *ot);
|
void NODE_OT_viewer_border(struct wmOperatorType *ot);
|
||||||
void NODE_OT_clear_viewer_border(struct wmOperatorType *ot);
|
void NODE_OT_clear_viewer_border(struct wmOperatorType *ot);
|
||||||
|
|
||||||
|
void NODE_OT_cryptomatte_layer_add(struct wmOperatorType *ot);
|
||||||
|
void NODE_OT_cryptomatte_layer_remove(struct wmOperatorType *ot);
|
||||||
|
|
||||||
extern const char *node_context_dir[];
|
extern const char *node_context_dir[];
|
||||||
|
|
||||||
// XXXXXX
|
// XXXXXX
|
||||||
|
@@ -130,6 +130,9 @@ void node_operatortypes(void)
|
|||||||
WM_operatortype_append(NODE_OT_tree_socket_add);
|
WM_operatortype_append(NODE_OT_tree_socket_add);
|
||||||
WM_operatortype_append(NODE_OT_tree_socket_remove);
|
WM_operatortype_append(NODE_OT_tree_socket_remove);
|
||||||
WM_operatortype_append(NODE_OT_tree_socket_move);
|
WM_operatortype_append(NODE_OT_tree_socket_move);
|
||||||
|
|
||||||
|
WM_operatortype_append(NODE_OT_cryptomatte_layer_add);
|
||||||
|
WM_operatortype_append(NODE_OT_cryptomatte_layer_remove);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ED_operatormacros_node(void)
|
void ED_operatormacros_node(void)
|
||||||
|
@@ -907,6 +907,14 @@ typedef struct NodeSunBeams {
|
|||||||
float ray_length;
|
float ray_length;
|
||||||
} NodeSunBeams;
|
} NodeSunBeams;
|
||||||
|
|
||||||
|
typedef struct NodeCryptomatte {
|
||||||
|
float add[3];
|
||||||
|
float remove[3];
|
||||||
|
char *matte_id;
|
||||||
|
int num_inputs;
|
||||||
|
int pad;
|
||||||
|
} NodeCryptomatte;
|
||||||
|
|
||||||
/* script node mode */
|
/* script node mode */
|
||||||
#define NODE_SCRIPT_INTERNAL 0
|
#define NODE_SCRIPT_INTERNAL 0
|
||||||
#define NODE_SCRIPT_EXTERNAL 1
|
#define NODE_SCRIPT_EXTERNAL 1
|
||||||
|
@@ -2880,6 +2880,48 @@ static void rna_NodeColorBalance_update_cdl(Main *bmain, Scene *scene, PointerRN
|
|||||||
rna_Node_update(bmain, scene, ptr);
|
rna_Node_update(bmain, scene, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rna_NodeCryptomatte_matte_get(PointerRNA *ptr, char *value)
|
||||||
|
{
|
||||||
|
bNode *node = (bNode *)ptr->data;
|
||||||
|
NodeCryptomatte *nc = node->storage;
|
||||||
|
|
||||||
|
strcpy(value, (nc->matte_id) ? nc->matte_id : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rna_NodeCryptomatte_matte_length(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
bNode *node = (bNode *)ptr->data;
|
||||||
|
NodeCryptomatte *nc = node->storage;
|
||||||
|
|
||||||
|
return (nc->matte_id) ? strlen(nc->matte_id) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_NodeCryptomatte_matte_set(PointerRNA *ptr, const char *value)
|
||||||
|
{
|
||||||
|
bNode *node = (bNode *)ptr->data;
|
||||||
|
NodeCryptomatte *nc = node->storage;
|
||||||
|
|
||||||
|
if (nc->matte_id)
|
||||||
|
MEM_freeN(nc->matte_id);
|
||||||
|
|
||||||
|
if (value && value[0])
|
||||||
|
nc->matte_id = BLI_strdup(value);
|
||||||
|
else
|
||||||
|
nc->matte_id = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_NodeCryptomatte_update_add(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
ntreeCompositCryptomatteSyncFromAdd(ptr->id.data, ptr->data);
|
||||||
|
rna_Node_update(bmain, scene, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_NodeCryptomatte_update_remove(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
ntreeCompositCryptomatteSyncFromRemove(ptr->id.data, ptr->data);
|
||||||
|
rna_Node_update(bmain, scene, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
/* ******** Node Socket Types ******** */
|
/* ******** Node Socket Types ******** */
|
||||||
|
|
||||||
static PointerRNA rna_NodeOutputFile_slot_layer_get(CollectionPropertyIterator *iter)
|
static PointerRNA rna_NodeOutputFile_slot_layer_get(CollectionPropertyIterator *iter)
|
||||||
@@ -6977,6 +7019,32 @@ static void def_cmp_sunbeams(StructRNA *srna)
|
|||||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void def_cmp_cryptomatte(StructRNA *srna)
|
||||||
|
{
|
||||||
|
PropertyRNA *prop;
|
||||||
|
static float default_1[3] = {1.f, 1.f, 1.f};
|
||||||
|
|
||||||
|
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", "rna_NodeCryptomatte_matte_length",
|
||||||
|
"rna_NodeCryptomatte_matte_set");
|
||||||
|
RNA_def_property_ui_text(prop, "Matte Objects", "List of object and material crypto IDs to include in matte");
|
||||||
|
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_array_default(prop, default_1);
|
||||||
|
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
|
||||||
|
RNA_def_property_ui_text(prop, "Add", "Add object or material to matte, by picking a color from the Pick output");
|
||||||
|
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_array_default(prop, default_1);
|
||||||
|
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
|
||||||
|
RNA_def_property_ui_text(prop, "Remove", "Remove object or material from matte, by picking a color from the Pick output");
|
||||||
|
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeCryptomatte_update_remove");
|
||||||
|
}
|
||||||
|
|
||||||
/* -- Texture Nodes --------------------------------------------------------- */
|
/* -- Texture Nodes --------------------------------------------------------- */
|
||||||
|
|
||||||
static void def_tex_output(StructRNA *srna)
|
static void def_tex_output(StructRNA *srna)
|
||||||
|
@@ -59,6 +59,7 @@ set(SRC
|
|||||||
composite/nodes/node_composite_composite.c
|
composite/nodes/node_composite_composite.c
|
||||||
composite/nodes/node_composite_cornerpin.c
|
composite/nodes/node_composite_cornerpin.c
|
||||||
composite/nodes/node_composite_crop.c
|
composite/nodes/node_composite_crop.c
|
||||||
|
composite/nodes/node_composite_cryptomatte.c
|
||||||
composite/nodes/node_composite_curves.c
|
composite/nodes/node_composite_curves.c
|
||||||
composite/nodes/node_composite_despeckle.c
|
composite/nodes/node_composite_despeckle.c
|
||||||
composite/nodes/node_composite_doubleEdgeMask.c
|
composite/nodes/node_composite_doubleEdgeMask.c
|
||||||
|
@@ -109,6 +109,7 @@ void register_node_type_cmp_luma_matte(void);
|
|||||||
void register_node_type_cmp_doubleedgemask(void);
|
void register_node_type_cmp_doubleedgemask(void);
|
||||||
void register_node_type_cmp_keyingscreen(void);
|
void register_node_type_cmp_keyingscreen(void);
|
||||||
void register_node_type_cmp_keying(void);
|
void register_node_type_cmp_keying(void);
|
||||||
|
void register_node_type_cmp_cryptomatte(void);
|
||||||
|
|
||||||
void register_node_type_cmp_translate(void);
|
void register_node_type_cmp_translate(void);
|
||||||
void register_node_type_cmp_rotate(void);
|
void register_node_type_cmp_rotate(void);
|
||||||
|
@@ -219,6 +219,7 @@ DefNode( CompositorNode, CMP_NODE_PIXELATE, 0, "PIXEL
|
|||||||
DefNode( CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" )
|
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_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" )
|
||||||
DefNode( CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" )
|
DefNode( CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" )
|
||||||
|
DefNode( CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE", Cryptomatte, "Cryptomatte", "" )
|
||||||
|
|
||||||
DefNode( TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
|
DefNode( TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
|
||||||
DefNode( TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
|
DefNode( TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
|
||||||
|
@@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* The Original Code is Copyright (C) 2018 Blender Foundation.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* The Original Code is: all of this file.
|
||||||
|
*
|
||||||
|
* Contributor(s): Lukas Stockner, Stefan Werner
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file blender/nodes/composite/nodes/node_composite_cryptomatte.c
|
||||||
|
* \ingroup cmpnodes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "node_composite_util.h"
|
||||||
|
#include "BLI_dynstr.h"
|
||||||
|
#include "BLI_hash_mm3.h"
|
||||||
|
#include "BLI_assert.h"
|
||||||
|
|
||||||
|
#ifndef max
|
||||||
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef min
|
||||||
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* this is taken from the cryptomatte specification 1.0 */
|
||||||
|
|
||||||
|
static inline float hash_to_float(uint32_t hash)
|
||||||
|
{
|
||||||
|
uint32_t mantissa = hash & (( 1 << 23) - 1);
|
||||||
|
uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
|
||||||
|
exponent = max(exponent, (uint32_t) 1);
|
||||||
|
exponent = min(exponent, (uint32_t) 254);
|
||||||
|
exponent = exponent << 23;
|
||||||
|
uint32_t sign = (hash >> 31);
|
||||||
|
sign = sign << 31;
|
||||||
|
uint32_t float_bits = sign | exponent | mantissa;
|
||||||
|
float f;
|
||||||
|
/* Bit casting relies on equal size for both types. */
|
||||||
|
BLI_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "float and uint32_t are not the same size")
|
||||||
|
memcpy(&f, &float_bits, sizeof(float));
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cryptomatte_add(NodeCryptomatte* n, float f)
|
||||||
|
{
|
||||||
|
/* Turn the number into a string. */
|
||||||
|
char number[32];
|
||||||
|
BLI_snprintf(number, sizeof(number), "<%.9g>", f);
|
||||||
|
|
||||||
|
/* Search if we already have the number. */
|
||||||
|
if (n->matte_id && strlen(n->matte_id) != 0) {
|
||||||
|
size_t start = 0;
|
||||||
|
const size_t end = strlen(n->matte_id);
|
||||||
|
size_t token_len = 0;
|
||||||
|
while (start < end) {
|
||||||
|
/* Ignore leading whitespace. */
|
||||||
|
while (start < end && n->matte_id[start] == ' ') {
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the next seprator. */
|
||||||
|
char* token_end = strchr(n->matte_id+start, ',');
|
||||||
|
if (token_end == NULL || token_end == n->matte_id+start) {
|
||||||
|
token_end = n->matte_id+end;
|
||||||
|
}
|
||||||
|
/* Be aware that token_len still contains any trailing white space. */
|
||||||
|
token_len = token_end - (n->matte_id + start);
|
||||||
|
|
||||||
|
/* If this has a leading bracket, assume a raw floating point number and look for the closing bracket. */
|
||||||
|
if (n->matte_id[start] == '<') {
|
||||||
|
if (strncmp(n->matte_id+start, number, strlen(number)) == 0) {
|
||||||
|
/* This number is already there, so continue. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Remove trailing white space */
|
||||||
|
size_t name_len = token_len;
|
||||||
|
while (n->matte_id[start+name_len] == ' ' && name_len > 0) {
|
||||||
|
name_len--;
|
||||||
|
}
|
||||||
|
/* Calculate the hash of the token and compare. */
|
||||||
|
uint32_t hash = BLI_hash_mm3((const unsigned char*)(n->matte_id+start), name_len, 0);
|
||||||
|
if (f == hash_to_float(hash)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
start += token_len+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DynStr *new_matte = BLI_dynstr_new();
|
||||||
|
if (!new_matte) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n->matte_id) {
|
||||||
|
BLI_dynstr_append(new_matte, n->matte_id);
|
||||||
|
MEM_freeN(n->matte_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(BLI_dynstr_get_len(new_matte) > 0) {
|
||||||
|
BLI_dynstr_append(new_matte, ",");
|
||||||
|
}
|
||||||
|
BLI_dynstr_append(new_matte, number);
|
||||||
|
n->matte_id = BLI_dynstr_get_cstring(new_matte);
|
||||||
|
BLI_dynstr_free(new_matte);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cryptomatte_remove(NodeCryptomatte*n, float f)
|
||||||
|
{
|
||||||
|
if (n->matte_id == NULL || strlen(n->matte_id) == 0) {
|
||||||
|
/* Empty string, nothing to remove. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This will be the new string without the removed key. */
|
||||||
|
DynStr *new_matte = BLI_dynstr_new();
|
||||||
|
if (!new_matte) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn the number into a string. */
|
||||||
|
static char number[32];
|
||||||
|
BLI_snprintf(number, sizeof(number), "<%.9g>", f);
|
||||||
|
|
||||||
|
/* Search if we already have the number. */
|
||||||
|
size_t start = 0;
|
||||||
|
const size_t end = strlen(n->matte_id);
|
||||||
|
size_t token_len = 0;
|
||||||
|
bool is_first = true;
|
||||||
|
while (start < end) {
|
||||||
|
bool skip = false;
|
||||||
|
/* Ignore leading whitespace or commas. */
|
||||||
|
while (start < end && ((n->matte_id[start] == ' ') || (n->matte_id[start] == ','))) {
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the next seprator. */
|
||||||
|
char* token_end = strchr(n->matte_id+start+1, ',');
|
||||||
|
if (token_end == NULL || token_end == n->matte_id+start) {
|
||||||
|
token_end = n->matte_id+end;
|
||||||
|
}
|
||||||
|
/* Be aware that token_len still contains any trailing white space. */
|
||||||
|
token_len = token_end - (n->matte_id + start);
|
||||||
|
|
||||||
|
if (token_len == 1) {
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
/* If this has a leading bracket, assume a raw floating point number and look for the closing bracket. */
|
||||||
|
else if (n->matte_id[start] == '<') {
|
||||||
|
if (strncmp(n->matte_id+start, number, strlen(number)) == 0) {
|
||||||
|
/* This number is already there, so skip it. */
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Remove trailing white space */
|
||||||
|
size_t name_len = token_len;
|
||||||
|
while (n->matte_id[start+name_len] == ' ' && name_len > 0) {
|
||||||
|
name_len--;
|
||||||
|
}
|
||||||
|
/* Calculate the hash of the token and compare. */
|
||||||
|
uint32_t hash = BLI_hash_mm3((const unsigned char*)(n->matte_id+start), name_len, 0);
|
||||||
|
if (f == hash_to_float(hash)) {
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!skip) {
|
||||||
|
if (is_first) {
|
||||||
|
is_first = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BLI_dynstr_append(new_matte, ", ");
|
||||||
|
}
|
||||||
|
BLI_dynstr_nappend(new_matte, n->matte_id+start, token_len);
|
||||||
|
}
|
||||||
|
start += token_len+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n->matte_id) {
|
||||||
|
MEM_freeN(n->matte_id);
|
||||||
|
n->matte_id = NULL;
|
||||||
|
}
|
||||||
|
if(BLI_dynstr_get_len(new_matte) > 0) {
|
||||||
|
n->matte_id = BLI_dynstr_get_cstring(new_matte);
|
||||||
|
}
|
||||||
|
BLI_dynstr_free(new_matte);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bNodeSocketTemplate outputs[] = {
|
||||||
|
{ SOCK_RGBA, 0, N_("Image")},
|
||||||
|
{ SOCK_FLOAT, 0, N_("Matte")},
|
||||||
|
{ SOCK_RGBA, 0, N_("Pick")},
|
||||||
|
{ -1, 0, "" }
|
||||||
|
};
|
||||||
|
|
||||||
|
void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *UNUSED(ntree), bNode *node)
|
||||||
|
{
|
||||||
|
NodeCryptomatte *n = node->storage;
|
||||||
|
if (n->add[0] != 0.0f) {
|
||||||
|
cryptomatte_add(n, n->add[0]);
|
||||||
|
n->add[0] = 0.0f;
|
||||||
|
n->add[1] = 0.0f;
|
||||||
|
n->add[2] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *UNUSED(ntree), bNode *node)
|
||||||
|
{
|
||||||
|
NodeCryptomatte *n = node->storage;
|
||||||
|
if (n->remove[0] != 0.0f) {
|
||||||
|
cryptomatte_remove(n, n->remove[0]);
|
||||||
|
n->remove[0] = 0.0f;
|
||||||
|
n->remove[1] = 0.0f;
|
||||||
|
n->remove[2] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node)
|
||||||
|
{
|
||||||
|
NodeCryptomatte *n = 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, NULL, sockname);
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node)
|
||||||
|
{
|
||||||
|
NodeCryptomatte *n = node->storage;
|
||||||
|
if (n->num_inputs < 2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bNodeSocket *sock = node->inputs.last;
|
||||||
|
nodeRemoveSocket(ntree, node, sock);
|
||||||
|
n->num_inputs--;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init(bNodeTree *ntree, bNode *node)
|
||||||
|
{
|
||||||
|
NodeCryptomatte *user = MEM_callocN(sizeof(NodeCryptomatte), "cryptomatte user");
|
||||||
|
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_free_cryptomatte(bNode *node)
|
||||||
|
{
|
||||||
|
NodeCryptomatte *nc = node->storage;
|
||||||
|
|
||||||
|
if (nc) {
|
||||||
|
if (nc->matte_id) {
|
||||||
|
MEM_freeN(nc->matte_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
MEM_freeN(nc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node)
|
||||||
|
{
|
||||||
|
NodeCryptomatte *src_nc = src_node->storage;
|
||||||
|
NodeCryptomatte *dest_nc = MEM_dupallocN(src_nc);
|
||||||
|
|
||||||
|
if (src_nc->matte_id)
|
||||||
|
dest_nc->matte_id = MEM_dupallocN(src_nc->matte_id);
|
||||||
|
|
||||||
|
dest_node->storage = dest_nc;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, NULL, outputs);
|
||||||
|
node_type_init(&ntype, init);
|
||||||
|
node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
|
||||||
|
nodeRegisterType(&ntype);
|
||||||
|
}
|
Reference in New Issue
Block a user