Cryptomatte: Data structure in compositor node
This changes the way how the mattes are stored in the compositor node. This used to be a single string what was decoded/encoded when needed. The new data structure stores all entries in `CryptomatteEntry` and is converted to the old `matte_id` property on the fly. This is done for some future changes in the workflow where a more structured approach leads to less confusing and easier to read code.
This commit is contained in:
parent
07ce9910f7
commit
f4df036bc4
Notes:
blender-bot
2023-02-14 04:24:05 +01:00
Referenced by commit 35368e8bfc
, Fix: mattes of cryptomatte node lost after write
Referenced by issue #86026, 2.92 crashes when reopening file [Cryptomatte related].
Referenced by issue #83792, Crash when opening a file containing a cryptomatte node with a `matte_id`
|
@ -25,18 +25,28 @@
|
|||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include "DNA_layer_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Object;
|
||||
struct Material;
|
||||
struct ID;
|
||||
struct Main;
|
||||
|
||||
uint32_t BKE_cryptomatte_hash(const char *name, int name_len);
|
||||
uint32_t BKE_cryptomatte_object_hash(const struct Object *object);
|
||||
uint32_t BKE_cryptomatte_material_hash(const struct Material *material);
|
||||
uint32_t BKE_cryptomatte_asset_hash(const struct Object *object);
|
||||
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash);
|
||||
|
||||
char *BKE_cryptomatte_entries_to_matte_id(struct NodeCryptomatte *node_storage);
|
||||
void BKE_cryptomatte_matte_id_to_entries(const struct Main *bmain,
|
||||
struct NodeCryptomatte *node_storage,
|
||||
const char *matte_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -101,7 +101,7 @@ set(SRC
|
|||
intern/constraint.c
|
||||
intern/context.c
|
||||
intern/crazyspace.c
|
||||
intern/cryptomatte.c
|
||||
intern/cryptomatte.cc
|
||||
intern/curve.c
|
||||
intern/curve_bevel.c
|
||||
intern/curve_decimate.c
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* 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) 2008 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "BKE_cryptomatte.h"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_hash_mm3.h"
|
||||
#include "BLI_string.h"
|
||||
#include <string.h>
|
||||
|
||||
static uint32_t cryptomatte_hash(const ID *id)
|
||||
{
|
||||
const char *name = &id->name[2];
|
||||
const int len = BLI_strnlen(name, MAX_NAME - 2);
|
||||
uint32_t cryptohash_int = BLI_hash_mm3((const unsigned char *)name, len, 0);
|
||||
return cryptohash_int;
|
||||
}
|
||||
|
||||
uint32_t BKE_cryptomatte_object_hash(const Object *object)
|
||||
{
|
||||
return cryptomatte_hash(&object->id);
|
||||
}
|
||||
|
||||
uint32_t BKE_cryptomatte_material_hash(const Material *material)
|
||||
{
|
||||
if (material == NULL) {
|
||||
return 0.0f;
|
||||
}
|
||||
return cryptomatte_hash(&material->id);
|
||||
}
|
||||
|
||||
uint32_t BKE_cryptomatte_asset_hash(const Object *object)
|
||||
{
|
||||
const Object *asset_object = object;
|
||||
while (asset_object->parent != NULL) {
|
||||
asset_object = asset_object->parent;
|
||||
}
|
||||
return cryptomatte_hash(&asset_object->id);
|
||||
}
|
||||
|
||||
/* Convert a cryptomatte hash to a float.
|
||||
*
|
||||
* Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
|
||||
* cryptomatte specification. See Floating point conversion section in
|
||||
* https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
|
||||
*
|
||||
* The conversion uses as many 32 bit floating point values as possible to minimize hash
|
||||
* collisions. Unfortunately not all 32 bits can be as NaN and Inf can be problematic.
|
||||
*
|
||||
* Note that this conversion assumes to be running on a L-endian system. */
|
||||
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
|
||||
{
|
||||
uint32_t mantissa = cryptomatte_hash & ((1 << 23) - 1);
|
||||
uint32_t exponent = (cryptomatte_hash >> 23) & ((1 << 8) - 1);
|
||||
exponent = MAX2(exponent, (uint32_t)1);
|
||||
exponent = MIN2(exponent, (uint32_t)254);
|
||||
exponent = exponent << 23;
|
||||
uint32_t sign = (cryptomatte_hash >> 31);
|
||||
sign = sign << 31;
|
||||
uint32_t float_bits = sign | exponent | mantissa;
|
||||
float f;
|
||||
memcpy(&f, &float_bits, sizeof(uint32_t));
|
||||
return f;
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* 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) 2020 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "BKE_cryptomatte.h"
|
||||
#include "BKE_main.h"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_node_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_dynstr.h"
|
||||
#include "BLI_hash_mm3.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
static uint32_t cryptomatte_hash(const ID *id)
|
||||
{
|
||||
const char *name = &id->name[2];
|
||||
const int name_len = BLI_strnlen(name, MAX_NAME);
|
||||
uint32_t cryptohash_int = BKE_cryptomatte_hash(name, name_len);
|
||||
return cryptohash_int;
|
||||
}
|
||||
|
||||
uint32_t BKE_cryptomatte_hash(const char *name, int name_len)
|
||||
{
|
||||
uint32_t cryptohash_int = BLI_hash_mm3((const unsigned char *)name, name_len, 0);
|
||||
return cryptohash_int;
|
||||
}
|
||||
|
||||
uint32_t BKE_cryptomatte_object_hash(const Object *object)
|
||||
{
|
||||
return cryptomatte_hash(&object->id);
|
||||
}
|
||||
|
||||
uint32_t BKE_cryptomatte_material_hash(const Material *material)
|
||||
{
|
||||
if (material == nullptr) {
|
||||
return 0.0f;
|
||||
}
|
||||
return cryptomatte_hash(&material->id);
|
||||
}
|
||||
|
||||
uint32_t BKE_cryptomatte_asset_hash(const Object *object)
|
||||
{
|
||||
const Object *asset_object = object;
|
||||
while (asset_object->parent != nullptr) {
|
||||
asset_object = asset_object->parent;
|
||||
}
|
||||
return cryptomatte_hash(&asset_object->id);
|
||||
}
|
||||
|
||||
/* Convert a cryptomatte hash to a float.
|
||||
*
|
||||
* Cryptomatte hashes are stored in float textures and images. The conversion is taken from the
|
||||
* cryptomatte specification. See Floating point conversion section in
|
||||
* https://github.com/Psyop/Cryptomatte/blob/master/specification/cryptomatte_specification.pdf.
|
||||
*
|
||||
* The conversion uses as many 32 bit floating point values as possible to minimize hash
|
||||
* collisions. Unfortunately not all 32 bits can be as NaN and Inf can be problematic.
|
||||
*
|
||||
* Note that this conversion assumes to be running on a L-endian system. */
|
||||
float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash)
|
||||
{
|
||||
uint32_t mantissa = cryptomatte_hash & ((1 << 23) - 1);
|
||||
uint32_t exponent = (cryptomatte_hash >> 23) & ((1 << 8) - 1);
|
||||
exponent = MAX2(exponent, (uint32_t)1);
|
||||
exponent = MIN2(exponent, (uint32_t)254);
|
||||
exponent = exponent << 23;
|
||||
uint32_t sign = (cryptomatte_hash >> 31);
|
||||
sign = sign << 31;
|
||||
uint32_t float_bits = sign | exponent | mantissa;
|
||||
float f;
|
||||
memcpy(&f, &float_bits, sizeof(uint32_t));
|
||||
return f;
|
||||
}
|
||||
|
||||
static ID *cryptomatte_find_id(const ListBase *ids, const float encoded_hash)
|
||||
{
|
||||
LISTBASE_FOREACH (ID *, id, ids) {
|
||||
uint32_t hash = BKE_cryptomatte_hash((id->name + 2), BLI_strnlen(id->name + 2, MAX_NAME));
|
||||
if (BKE_cryptomatte_hash_to_float(hash) == encoded_hash) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Find an ID in the given main that matches the given encoded float. */
|
||||
static struct ID *BKE_cryptomatte_find_id(const Main *bmain, const float encoded_hash)
|
||||
{
|
||||
ID *result;
|
||||
result = cryptomatte_find_id(&bmain->objects, encoded_hash);
|
||||
if (result == nullptr) {
|
||||
result = cryptomatte_find_id(&bmain->materials, encoded_hash);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage)
|
||||
{
|
||||
DynStr *matte_id = BLI_dynstr_new();
|
||||
bool first = true;
|
||||
LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) {
|
||||
if (!first) {
|
||||
BLI_dynstr_append(matte_id, ",");
|
||||
}
|
||||
if (BLI_strnlen(entry->name, sizeof(entry->name)) != 0) {
|
||||
BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name));
|
||||
}
|
||||
else {
|
||||
BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
char *result = BLI_dynstr_get_cstring(matte_id);
|
||||
BLI_dynstr_free(matte_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
void BKE_cryptomatte_matte_id_to_entries(const Main *bmain,
|
||||
NodeCryptomatte *node_storage,
|
||||
const char *matte_id)
|
||||
{
|
||||
BLI_freelistN(&node_storage->entries);
|
||||
|
||||
std::istringstream ss(matte_id);
|
||||
while (ss.good()) {
|
||||
CryptomatteEntry *entry = nullptr;
|
||||
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()) == '>') {
|
||||
float encoded_hash = atof(token.substr(1, token.length() - 2).c_str());
|
||||
entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
|
||||
entry->encoded_hash = encoded_hash;
|
||||
if (bmain) {
|
||||
ID *id = BKE_cryptomatte_find_id(bmain, encoded_hash);
|
||||
if (id != nullptr) {
|
||||
BLI_strncpy(entry->name, id->name + 2, sizeof(entry->name));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const char *name = token.c_str();
|
||||
int name_len = token.length();
|
||||
entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
|
||||
BLI_strncpy(entry->name, name, sizeof(entry->name));
|
||||
uint32_t hash = BKE_cryptomatte_hash(name, name_len);
|
||||
entry->encoded_hash = BKE_cryptomatte_hash_to_float(hash);
|
||||
}
|
||||
}
|
||||
if (entry != nullptr) {
|
||||
BLI_addtail(&node_storage->entries, entry);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,6 +52,7 @@
|
|||
#include "BKE_armature.h"
|
||||
#include "BKE_collection.h"
|
||||
#include "BKE_colortools.h"
|
||||
#include "BKE_cryptomatte.h"
|
||||
#include "BKE_fcurve.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_lib_id.h"
|
||||
|
@ -1280,5 +1281,24 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert `NodeCryptomatte->storage->matte_id` to `NodeCryptomatte->storage->entries` */
|
||||
if (!DNA_struct_find(fd->filesdna, "CryptomatteEntry")) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
if (scene->nodetree) {
|
||||
LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) {
|
||||
if (node->type == CMP_NODE_CRYPTOMATTE) {
|
||||
NodeCryptomatte *storage = (NodeCryptomatte *)node->storage;
|
||||
char *matte_id = storage->matte_id;
|
||||
if (matte_id == NULL || strlen(storage->matte_id) == 0) {
|
||||
continue;
|
||||
}
|
||||
BKE_cryptomatte_matte_id_to_entries(NULL, storage, storage->matte_id);
|
||||
MEM_SAFE_FREE(storage->matte_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,15 @@
|
|||
*/
|
||||
|
||||
#include "COM_CryptomatteNode.h"
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_hash_mm3.h"
|
||||
#include "BLI_string.h"
|
||||
#include "COM_ConvertOperation.h"
|
||||
#include "COM_CryptomatteOperation.h"
|
||||
#include "COM_SetAlphaOperation.h"
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_hash_mm3.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode)
|
||||
|
@ -30,24 +33,6 @@ 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
|
||||
{
|
||||
|
@ -61,30 +46,8 @@ void CryptomatteNode::convertToOperations(NodeConverter &converter,
|
|||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptoMatteSettings->entries) {
|
||||
operation->addObjectIndex(cryptomatte_entry->encoded_hash);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1052,10 +1052,20 @@ typedef struct NodeSunBeams {
|
|||
float ray_length;
|
||||
} NodeSunBeams;
|
||||
|
||||
typedef struct CryptomatteEntry {
|
||||
struct CryptomatteEntry *next, *prev;
|
||||
float encoded_hash;
|
||||
/** MAX_NAME. */
|
||||
char name[64];
|
||||
char _pad[4];
|
||||
} CryptomatteEntry;
|
||||
|
||||
typedef struct NodeCryptomatte {
|
||||
float add[3];
|
||||
float remove[3];
|
||||
char *matte_id;
|
||||
char *matte_id DNA_DEPRECATED;
|
||||
/* Contains `CryptomatteEntry`. */
|
||||
ListBase entries;
|
||||
int num_inputs;
|
||||
char _pad[4];
|
||||
} NodeCryptomatte;
|
||||
|
|
|
@ -202,6 +202,7 @@ extern StructRNA RNA_CopyRotationConstraint;
|
|||
extern StructRNA RNA_CopyScaleConstraint;
|
||||
extern StructRNA RNA_CopyTransformsConstraint;
|
||||
extern StructRNA RNA_CorrectiveSmoothModifier;
|
||||
extern StructRNA RNA_CryptomatteEntry;
|
||||
extern StructRNA RNA_Curve;
|
||||
extern StructRNA RNA_CurveMap;
|
||||
extern StructRNA RNA_CurveMapPoint;
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_cryptomatte.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_texture.h"
|
||||
|
@ -3626,33 +3627,26 @@ 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 : "");
|
||||
char *matte_id = BKE_cryptomatte_entries_to_matte_id(nc);
|
||||
strcpy(value, matte_id);
|
||||
MEM_freeN(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;
|
||||
char *matte_id = BKE_cryptomatte_entries_to_matte_id(nc);
|
||||
int result = strlen(matte_id);
|
||||
MEM_freeN(matte_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
BKE_cryptomatte_matte_id_to_entries(NULL, nc, value);
|
||||
}
|
||||
|
||||
static void rna_NodeCryptomatte_update_add(Main *bmain, Scene *scene, PointerRNA *ptr)
|
||||
|
@ -8205,6 +8199,24 @@ static void def_cmp_sunbeams(StructRNA *srna)
|
|||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_cmp_cryptomatte_entry(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "CryptomatteEntry", NULL);
|
||||
RNA_def_struct_sdna(srna, "CryptomatteEntry");
|
||||
|
||||
prop = RNA_def_property(srna, "encoded_hash", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "encoded_hash");
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Name", "");
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
}
|
||||
|
||||
static void def_cmp_cryptomatte(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
@ -8494,6 +8506,8 @@ static void rna_def_compositor_node(BlenderRNA *brna)
|
|||
/* compositor node need_exec flag */
|
||||
func = RNA_def_function(srna, "tag_need_exec", "rna_CompositorNode_tag_need_exec");
|
||||
RNA_def_function_ui_description(func, "Tag the node for compositor update");
|
||||
|
||||
def_cmp_cryptomatte_entry(brna);
|
||||
}
|
||||
|
||||
static void rna_def_texture_node(BlenderRNA *brna)
|
||||
|
|
|
@ -27,172 +27,36 @@
|
|||
#include "BLI_utildefines.h"
|
||||
#include "node_composite_util.h"
|
||||
|
||||
/* this is taken from the cryptomatte specification 1.0 */
|
||||
|
||||
BLI_INLINE float hash_to_float(uint32_t hash)
|
||||
static CryptomatteEntry *cryptomatte_find(NodeCryptomatte *n, float encoded_hash)
|
||||
{
|
||||
uint32_t mantissa = hash & ((1 << 23) - 1);
|
||||
uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
|
||||
exponent = MAX2(exponent, (uint32_t)1);
|
||||
exponent = MIN2(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;
|
||||
LISTBASE_FOREACH (CryptomatteEntry *, entry, &n->entries) {
|
||||
if (entry->encoded_hash == encoded_hash) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 separator. */
|
||||
char *token_end = strchr(n->matte_id + start, ',');
|
||||
if (ELEM(token_end, NULL, 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) {
|
||||
/* Check if entry already exist. */
|
||||
if (cryptomatte_find(n, f) != NULL) {
|
||||
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);
|
||||
CryptomatteEntry *entry = MEM_callocN(sizeof(CryptomatteEntry), __func__);
|
||||
entry->encoded_hash = f;
|
||||
BLI_addtail(&n->entries, entry);
|
||||
}
|
||||
|
||||
static void cryptomatte_remove(NodeCryptomatte *n, float f)
|
||||
{
|
||||
if (n->matte_id == NULL || strlen(n->matte_id) == 0) {
|
||||
/* Empty string, nothing to remove. */
|
||||
CryptomatteEntry *entry = cryptomatte_find(n, f);
|
||||
if (entry == NULL) {
|
||||
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 separator. */
|
||||
char *token_end = strchr(n->matte_id + start + 1, ',');
|
||||
if (ELEM(token_end, NULL, 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);
|
||||
BLI_remlink(&n->entries, entry);
|
||||
MEM_freeN(entry);
|
||||
}
|
||||
|
||||
static bNodeSocketTemplate outputs[] = {
|
||||
|
@ -265,10 +129,7 @@ static void node_free_cryptomatte(bNode *node)
|
|||
NodeCryptomatte *nc = node->storage;
|
||||
|
||||
if (nc) {
|
||||
if (nc->matte_id) {
|
||||
MEM_freeN(nc->matte_id);
|
||||
}
|
||||
|
||||
BLI_freelistN(&nc->entries);
|
||||
MEM_freeN(nc);
|
||||
}
|
||||
}
|
||||
|
@ -280,10 +141,7 @@ static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree),
|
|||
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);
|
||||
}
|
||||
|
||||
BLI_duplicatelist(&dest_nc->entries, &src_nc->entries);
|
||||
dest_node->storage = dest_nc;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue