forked from bartvdbraak/blender
021c40167d
Previous code was flipping the bits on a 32-bit number and doing a zero extension to cast to 64-bit, so mark the constant as long to begin with. This would also erase previously set bits in this part the flag.
829 lines
23 KiB
C++
829 lines
23 KiB
C++
/*
|
|
* Copyright 2011-2016 Blender Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "graph/node.h"
|
|
#include "graph/node_type.h"
|
|
|
|
#include "util/util_foreach.h"
|
|
#include "util/util_md5.h"
|
|
#include "util/util_param.h"
|
|
#include "util/util_transform.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/* Node Type */
|
|
|
|
NodeOwner::~NodeOwner()
|
|
{
|
|
}
|
|
|
|
Node::Node(const NodeType *type_, ustring name_) : name(name_), type(type_)
|
|
{
|
|
assert(type);
|
|
|
|
owner = nullptr;
|
|
tag_modified();
|
|
|
|
/* assign non-empty name, convenient for debugging */
|
|
if (name.empty()) {
|
|
name = type->name;
|
|
}
|
|
|
|
/* initialize default values */
|
|
foreach (const SocketType &socket, type->inputs) {
|
|
set_default_value(socket);
|
|
}
|
|
}
|
|
|
|
Node::~Node()
|
|
{
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
static bool is_socket_float3(const SocketType &socket)
|
|
{
|
|
return socket.type == SocketType::COLOR || socket.type == SocketType::POINT ||
|
|
socket.type == SocketType::VECTOR || socket.type == SocketType::NORMAL;
|
|
}
|
|
|
|
static bool is_socket_array_float3(const SocketType &socket)
|
|
{
|
|
return socket.type == SocketType::COLOR_ARRAY || socket.type == SocketType::POINT_ARRAY ||
|
|
socket.type == SocketType::VECTOR_ARRAY || socket.type == SocketType::NORMAL_ARRAY;
|
|
}
|
|
#endif
|
|
|
|
/* set values */
|
|
void Node::set(const SocketType &input, bool value)
|
|
{
|
|
assert(input.type == SocketType::BOOLEAN);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, int value)
|
|
{
|
|
assert((input.type == SocketType::INT || input.type == SocketType::ENUM));
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, uint value)
|
|
{
|
|
assert(input.type == SocketType::UINT);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, float value)
|
|
{
|
|
assert(input.type == SocketType::FLOAT);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, float2 value)
|
|
{
|
|
assert(input.type == SocketType::POINT2);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, float3 value)
|
|
{
|
|
assert(is_socket_float3(input));
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, const char *value)
|
|
{
|
|
set(input, ustring(value));
|
|
}
|
|
|
|
void Node::set(const SocketType &input, ustring value)
|
|
{
|
|
if (input.type == SocketType::STRING) {
|
|
set_if_different(input, value);
|
|
}
|
|
else if (input.type == SocketType::ENUM) {
|
|
const NodeEnum &enm = *input.enum_values;
|
|
if (enm.exists(value)) {
|
|
set_if_different(input, enm[value]);
|
|
}
|
|
else {
|
|
assert(0);
|
|
}
|
|
}
|
|
else {
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
void Node::set(const SocketType &input, const Transform &value)
|
|
{
|
|
assert(input.type == SocketType::TRANSFORM);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, Node *value)
|
|
{
|
|
assert(input.type == SocketType::NODE);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
/* set array values */
|
|
void Node::set(const SocketType &input, array<bool> &value)
|
|
{
|
|
assert(input.type == SocketType::BOOLEAN_ARRAY);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, array<int> &value)
|
|
{
|
|
assert(input.type == SocketType::INT_ARRAY);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, array<float> &value)
|
|
{
|
|
assert(input.type == SocketType::FLOAT_ARRAY);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, array<float2> &value)
|
|
{
|
|
assert(input.type == SocketType::POINT2_ARRAY);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, array<float3> &value)
|
|
{
|
|
assert(is_socket_array_float3(input));
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, array<ustring> &value)
|
|
{
|
|
assert(input.type == SocketType::STRING_ARRAY);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, array<Transform> &value)
|
|
{
|
|
assert(input.type == SocketType::TRANSFORM_ARRAY);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
void Node::set(const SocketType &input, array<Node *> &value)
|
|
{
|
|
assert(input.type == SocketType::NODE_ARRAY);
|
|
set_if_different(input, value);
|
|
}
|
|
|
|
/* get values */
|
|
bool Node::get_bool(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::BOOLEAN);
|
|
return get_socket_value<bool>(this, input);
|
|
}
|
|
|
|
int Node::get_int(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::INT || input.type == SocketType::ENUM);
|
|
return get_socket_value<int>(this, input);
|
|
}
|
|
|
|
uint Node::get_uint(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::UINT);
|
|
return get_socket_value<uint>(this, input);
|
|
}
|
|
|
|
float Node::get_float(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::FLOAT);
|
|
return get_socket_value<float>(this, input);
|
|
}
|
|
|
|
float2 Node::get_float2(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::POINT2);
|
|
return get_socket_value<float2>(this, input);
|
|
}
|
|
|
|
float3 Node::get_float3(const SocketType &input) const
|
|
{
|
|
assert(is_socket_float3(input));
|
|
return get_socket_value<float3>(this, input);
|
|
}
|
|
|
|
ustring Node::get_string(const SocketType &input) const
|
|
{
|
|
if (input.type == SocketType::STRING) {
|
|
return get_socket_value<ustring>(this, input);
|
|
}
|
|
else if (input.type == SocketType::ENUM) {
|
|
const NodeEnum &enm = *input.enum_values;
|
|
int intvalue = get_socket_value<int>(this, input);
|
|
return (enm.exists(intvalue)) ? enm[intvalue] : ustring();
|
|
}
|
|
else {
|
|
assert(0);
|
|
return ustring();
|
|
}
|
|
}
|
|
|
|
Transform Node::get_transform(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::TRANSFORM);
|
|
return get_socket_value<Transform>(this, input);
|
|
}
|
|
|
|
Node *Node::get_node(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::NODE);
|
|
return get_socket_value<Node *>(this, input);
|
|
}
|
|
|
|
/* get array values */
|
|
const array<bool> &Node::get_bool_array(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::BOOLEAN_ARRAY);
|
|
return get_socket_value<array<bool>>(this, input);
|
|
}
|
|
|
|
const array<int> &Node::get_int_array(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::INT_ARRAY);
|
|
return get_socket_value<array<int>>(this, input);
|
|
}
|
|
|
|
const array<float> &Node::get_float_array(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::FLOAT_ARRAY);
|
|
return get_socket_value<array<float>>(this, input);
|
|
}
|
|
|
|
const array<float2> &Node::get_float2_array(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::POINT2_ARRAY);
|
|
return get_socket_value<array<float2>>(this, input);
|
|
}
|
|
|
|
const array<float3> &Node::get_float3_array(const SocketType &input) const
|
|
{
|
|
assert(is_socket_array_float3(input));
|
|
return get_socket_value<array<float3>>(this, input);
|
|
}
|
|
|
|
const array<ustring> &Node::get_string_array(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::STRING_ARRAY);
|
|
return get_socket_value<array<ustring>>(this, input);
|
|
}
|
|
|
|
const array<Transform> &Node::get_transform_array(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::TRANSFORM_ARRAY);
|
|
return get_socket_value<array<Transform>>(this, input);
|
|
}
|
|
|
|
const array<Node *> &Node::get_node_array(const SocketType &input) const
|
|
{
|
|
assert(input.type == SocketType::NODE_ARRAY);
|
|
return get_socket_value<array<Node *>>(this, input);
|
|
}
|
|
|
|
/* generic value operations */
|
|
|
|
bool Node::has_default_value(const SocketType &input) const
|
|
{
|
|
const void *src = input.default_value;
|
|
void *dst = &get_socket_value<char>(this, input);
|
|
return memcmp(dst, src, input.size()) == 0;
|
|
}
|
|
|
|
void Node::set_default_value(const SocketType &socket)
|
|
{
|
|
const void *src = socket.default_value;
|
|
void *dst = ((char *)this) + socket.struct_offset;
|
|
if (socket.size() > 0) {
|
|
memcpy(dst, src, socket.size());
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
static void copy_array(const Node *node,
|
|
const SocketType &socket,
|
|
const Node *other,
|
|
const SocketType &other_socket)
|
|
{
|
|
const array<T> *src = (const array<T> *)(((char *)other) + other_socket.struct_offset);
|
|
array<T> *dst = (array<T> *)(((char *)node) + socket.struct_offset);
|
|
*dst = *src;
|
|
}
|
|
|
|
void Node::copy_value(const SocketType &socket, const Node &other, const SocketType &other_socket)
|
|
{
|
|
assert(socket.type == other_socket.type);
|
|
|
|
if (socket.is_array()) {
|
|
switch (socket.type) {
|
|
case SocketType::BOOLEAN_ARRAY:
|
|
copy_array<bool>(this, socket, &other, other_socket);
|
|
break;
|
|
case SocketType::FLOAT_ARRAY:
|
|
copy_array<float>(this, socket, &other, other_socket);
|
|
break;
|
|
case SocketType::INT_ARRAY:
|
|
copy_array<int>(this, socket, &other, other_socket);
|
|
break;
|
|
case SocketType::COLOR_ARRAY:
|
|
copy_array<float3>(this, socket, &other, other_socket);
|
|
break;
|
|
case SocketType::VECTOR_ARRAY:
|
|
copy_array<float3>(this, socket, &other, other_socket);
|
|
break;
|
|
case SocketType::POINT_ARRAY:
|
|
copy_array<float3>(this, socket, &other, other_socket);
|
|
break;
|
|
case SocketType::NORMAL_ARRAY:
|
|
copy_array<float3>(this, socket, &other, other_socket);
|
|
break;
|
|
case SocketType::POINT2_ARRAY:
|
|
copy_array<float2>(this, socket, &other, other_socket);
|
|
break;
|
|
case SocketType::STRING_ARRAY:
|
|
copy_array<ustring>(this, socket, &other, other_socket);
|
|
break;
|
|
case SocketType::TRANSFORM_ARRAY:
|
|
copy_array<Transform>(this, socket, &other, other_socket);
|
|
break;
|
|
case SocketType::NODE_ARRAY:
|
|
copy_array<void *>(this, socket, &other, other_socket);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
const void *src = ((char *)&other) + other_socket.struct_offset;
|
|
void *dst = ((char *)this) + socket.struct_offset;
|
|
memcpy(dst, src, socket.size());
|
|
}
|
|
}
|
|
|
|
void Node::set_value(const SocketType &socket, const Node &other, const SocketType &other_socket)
|
|
{
|
|
assert(socket.type == other_socket.type);
|
|
(void)other_socket;
|
|
|
|
if (socket.is_array()) {
|
|
switch (socket.type) {
|
|
case SocketType::BOOLEAN_ARRAY:
|
|
set(socket, get_socket_value<array<bool>>(&other, socket));
|
|
break;
|
|
case SocketType::FLOAT_ARRAY:
|
|
set(socket, get_socket_value<array<float>>(&other, socket));
|
|
break;
|
|
case SocketType::INT_ARRAY:
|
|
set(socket, get_socket_value<array<int>>(&other, socket));
|
|
break;
|
|
case SocketType::COLOR_ARRAY:
|
|
case SocketType::VECTOR_ARRAY:
|
|
case SocketType::POINT_ARRAY:
|
|
case SocketType::NORMAL_ARRAY:
|
|
set(socket, get_socket_value<array<float3>>(&other, socket));
|
|
break;
|
|
case SocketType::POINT2_ARRAY:
|
|
set(socket, get_socket_value<array<float2>>(&other, socket));
|
|
break;
|
|
case SocketType::STRING_ARRAY:
|
|
set(socket, get_socket_value<array<ustring>>(&other, socket));
|
|
break;
|
|
case SocketType::TRANSFORM_ARRAY:
|
|
set(socket, get_socket_value<array<Transform>>(&other, socket));
|
|
break;
|
|
case SocketType::NODE_ARRAY:
|
|
set(socket, get_socket_value<array<Node *>>(&other, socket));
|
|
break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
switch (socket.type) {
|
|
case SocketType::BOOLEAN:
|
|
set(socket, get_socket_value<bool>(&other, socket));
|
|
break;
|
|
case SocketType::FLOAT:
|
|
set(socket, get_socket_value<float>(&other, socket));
|
|
break;
|
|
case SocketType::INT:
|
|
set(socket, get_socket_value<int>(&other, socket));
|
|
break;
|
|
case SocketType::UINT:
|
|
set(socket, get_socket_value<uint>(&other, socket));
|
|
break;
|
|
case SocketType::COLOR:
|
|
case SocketType::VECTOR:
|
|
case SocketType::POINT:
|
|
case SocketType::NORMAL:
|
|
set(socket, get_socket_value<float3>(&other, socket));
|
|
break;
|
|
case SocketType::POINT2:
|
|
set(socket, get_socket_value<float2>(&other, socket));
|
|
break;
|
|
case SocketType::STRING:
|
|
set(socket, get_socket_value<ustring>(&other, socket));
|
|
break;
|
|
case SocketType::ENUM:
|
|
set(socket, get_socket_value<int>(&other, socket));
|
|
break;
|
|
case SocketType::TRANSFORM:
|
|
set(socket, get_socket_value<Transform>(&other, socket));
|
|
break;
|
|
case SocketType::NODE:
|
|
set(socket, get_socket_value<Node *>(&other, socket));
|
|
break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
static bool is_array_equal(const Node *node, const Node *other, const SocketType &socket)
|
|
{
|
|
const array<T> *a = (const array<T> *)(((char *)node) + socket.struct_offset);
|
|
const array<T> *b = (const array<T> *)(((char *)other) + socket.struct_offset);
|
|
return *a == *b;
|
|
}
|
|
|
|
template<typename T>
|
|
static bool is_value_equal(const Node *node, const Node *other, const SocketType &socket)
|
|
{
|
|
const T *a = (const T *)(((char *)node) + socket.struct_offset);
|
|
const T *b = (const T *)(((char *)other) + socket.struct_offset);
|
|
return *a == *b;
|
|
}
|
|
|
|
bool Node::equals_value(const Node &other, const SocketType &socket) const
|
|
{
|
|
switch (socket.type) {
|
|
case SocketType::BOOLEAN:
|
|
return is_value_equal<bool>(this, &other, socket);
|
|
case SocketType::FLOAT:
|
|
return is_value_equal<float>(this, &other, socket);
|
|
case SocketType::INT:
|
|
return is_value_equal<int>(this, &other, socket);
|
|
case SocketType::UINT:
|
|
return is_value_equal<uint>(this, &other, socket);
|
|
case SocketType::COLOR:
|
|
return is_value_equal<float3>(this, &other, socket);
|
|
case SocketType::VECTOR:
|
|
return is_value_equal<float3>(this, &other, socket);
|
|
case SocketType::POINT:
|
|
return is_value_equal<float3>(this, &other, socket);
|
|
case SocketType::NORMAL:
|
|
return is_value_equal<float3>(this, &other, socket);
|
|
case SocketType::POINT2:
|
|
return is_value_equal<float2>(this, &other, socket);
|
|
case SocketType::CLOSURE:
|
|
return true;
|
|
case SocketType::STRING:
|
|
return is_value_equal<ustring>(this, &other, socket);
|
|
case SocketType::ENUM:
|
|
return is_value_equal<int>(this, &other, socket);
|
|
case SocketType::TRANSFORM:
|
|
return is_value_equal<Transform>(this, &other, socket);
|
|
case SocketType::NODE:
|
|
return is_value_equal<void *>(this, &other, socket);
|
|
|
|
case SocketType::BOOLEAN_ARRAY:
|
|
return is_array_equal<bool>(this, &other, socket);
|
|
case SocketType::FLOAT_ARRAY:
|
|
return is_array_equal<float>(this, &other, socket);
|
|
case SocketType::INT_ARRAY:
|
|
return is_array_equal<int>(this, &other, socket);
|
|
case SocketType::COLOR_ARRAY:
|
|
return is_array_equal<float3>(this, &other, socket);
|
|
case SocketType::VECTOR_ARRAY:
|
|
return is_array_equal<float3>(this, &other, socket);
|
|
case SocketType::POINT_ARRAY:
|
|
return is_array_equal<float3>(this, &other, socket);
|
|
case SocketType::NORMAL_ARRAY:
|
|
return is_array_equal<float3>(this, &other, socket);
|
|
case SocketType::POINT2_ARRAY:
|
|
return is_array_equal<float2>(this, &other, socket);
|
|
case SocketType::STRING_ARRAY:
|
|
return is_array_equal<ustring>(this, &other, socket);
|
|
case SocketType::TRANSFORM_ARRAY:
|
|
return is_array_equal<Transform>(this, &other, socket);
|
|
case SocketType::NODE_ARRAY:
|
|
return is_array_equal<void *>(this, &other, socket);
|
|
|
|
case SocketType::UNDEFINED:
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* equals */
|
|
|
|
bool Node::equals(const Node &other) const
|
|
{
|
|
assert(type == other.type);
|
|
|
|
foreach (const SocketType &socket, type->inputs) {
|
|
if (!equals_value(other, socket))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Hash */
|
|
|
|
namespace {
|
|
|
|
template<typename T> void value_hash(const Node *node, const SocketType &socket, MD5Hash &md5)
|
|
{
|
|
md5.append(((uint8_t *)node) + socket.struct_offset, socket.size());
|
|
}
|
|
|
|
void float3_hash(const Node *node, const SocketType &socket, MD5Hash &md5)
|
|
{
|
|
/* Don't compare 4th element used for padding. */
|
|
md5.append(((uint8_t *)node) + socket.struct_offset, sizeof(float) * 3);
|
|
}
|
|
|
|
template<typename T> void array_hash(const Node *node, const SocketType &socket, MD5Hash &md5)
|
|
{
|
|
const array<T> &a = *(const array<T> *)(((char *)node) + socket.struct_offset);
|
|
for (size_t i = 0; i < a.size(); i++) {
|
|
md5.append((uint8_t *)&a[i], sizeof(T));
|
|
}
|
|
}
|
|
|
|
void float3_array_hash(const Node *node, const SocketType &socket, MD5Hash &md5)
|
|
{
|
|
/* Don't compare 4th element used for padding. */
|
|
const array<float3> &a = *(const array<float3> *)(((char *)node) + socket.struct_offset);
|
|
for (size_t i = 0; i < a.size(); i++) {
|
|
md5.append((uint8_t *)&a[i], sizeof(float) * 3);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void Node::hash(MD5Hash &md5)
|
|
{
|
|
md5.append(type->name.string());
|
|
|
|
foreach (const SocketType &socket, type->inputs) {
|
|
md5.append(socket.name.string());
|
|
|
|
switch (socket.type) {
|
|
case SocketType::BOOLEAN:
|
|
value_hash<bool>(this, socket, md5);
|
|
break;
|
|
case SocketType::FLOAT:
|
|
value_hash<float>(this, socket, md5);
|
|
break;
|
|
case SocketType::INT:
|
|
value_hash<int>(this, socket, md5);
|
|
break;
|
|
case SocketType::UINT:
|
|
value_hash<uint>(this, socket, md5);
|
|
break;
|
|
case SocketType::COLOR:
|
|
float3_hash(this, socket, md5);
|
|
break;
|
|
case SocketType::VECTOR:
|
|
float3_hash(this, socket, md5);
|
|
break;
|
|
case SocketType::POINT:
|
|
float3_hash(this, socket, md5);
|
|
break;
|
|
case SocketType::NORMAL:
|
|
float3_hash(this, socket, md5);
|
|
break;
|
|
case SocketType::POINT2:
|
|
value_hash<float2>(this, socket, md5);
|
|
break;
|
|
case SocketType::CLOSURE:
|
|
break;
|
|
case SocketType::STRING:
|
|
value_hash<ustring>(this, socket, md5);
|
|
break;
|
|
case SocketType::ENUM:
|
|
value_hash<int>(this, socket, md5);
|
|
break;
|
|
case SocketType::TRANSFORM:
|
|
value_hash<Transform>(this, socket, md5);
|
|
break;
|
|
case SocketType::NODE:
|
|
value_hash<void *>(this, socket, md5);
|
|
break;
|
|
|
|
case SocketType::BOOLEAN_ARRAY:
|
|
array_hash<bool>(this, socket, md5);
|
|
break;
|
|
case SocketType::FLOAT_ARRAY:
|
|
array_hash<float>(this, socket, md5);
|
|
break;
|
|
case SocketType::INT_ARRAY:
|
|
array_hash<int>(this, socket, md5);
|
|
break;
|
|
case SocketType::COLOR_ARRAY:
|
|
float3_array_hash(this, socket, md5);
|
|
break;
|
|
case SocketType::VECTOR_ARRAY:
|
|
float3_array_hash(this, socket, md5);
|
|
break;
|
|
case SocketType::POINT_ARRAY:
|
|
float3_array_hash(this, socket, md5);
|
|
break;
|
|
case SocketType::NORMAL_ARRAY:
|
|
float3_array_hash(this, socket, md5);
|
|
break;
|
|
case SocketType::POINT2_ARRAY:
|
|
array_hash<float2>(this, socket, md5);
|
|
break;
|
|
case SocketType::STRING_ARRAY:
|
|
array_hash<ustring>(this, socket, md5);
|
|
break;
|
|
case SocketType::TRANSFORM_ARRAY:
|
|
array_hash<Transform>(this, socket, md5);
|
|
break;
|
|
case SocketType::NODE_ARRAY:
|
|
array_hash<void *>(this, socket, md5);
|
|
break;
|
|
|
|
case SocketType::UNDEFINED:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
|
|
template<typename T> size_t array_size_in_bytes(const Node *node, const SocketType &socket)
|
|
{
|
|
const array<T> &a = *(const array<T> *)(((char *)node) + socket.struct_offset);
|
|
return a.size() * sizeof(T);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
size_t Node::get_total_size_in_bytes() const
|
|
{
|
|
size_t total_size = 0;
|
|
foreach (const SocketType &socket, type->inputs) {
|
|
switch (socket.type) {
|
|
case SocketType::BOOLEAN:
|
|
case SocketType::FLOAT:
|
|
case SocketType::INT:
|
|
case SocketType::UINT:
|
|
case SocketType::COLOR:
|
|
case SocketType::VECTOR:
|
|
case SocketType::POINT:
|
|
case SocketType::NORMAL:
|
|
case SocketType::POINT2:
|
|
case SocketType::CLOSURE:
|
|
case SocketType::STRING:
|
|
case SocketType::ENUM:
|
|
case SocketType::TRANSFORM:
|
|
case SocketType::NODE:
|
|
total_size += socket.size();
|
|
break;
|
|
|
|
case SocketType::BOOLEAN_ARRAY:
|
|
total_size += array_size_in_bytes<bool>(this, socket);
|
|
break;
|
|
case SocketType::FLOAT_ARRAY:
|
|
total_size += array_size_in_bytes<float>(this, socket);
|
|
break;
|
|
case SocketType::INT_ARRAY:
|
|
total_size += array_size_in_bytes<int>(this, socket);
|
|
break;
|
|
case SocketType::COLOR_ARRAY:
|
|
total_size += array_size_in_bytes<float3>(this, socket);
|
|
break;
|
|
case SocketType::VECTOR_ARRAY:
|
|
total_size += array_size_in_bytes<float3>(this, socket);
|
|
break;
|
|
case SocketType::POINT_ARRAY:
|
|
total_size += array_size_in_bytes<float3>(this, socket);
|
|
break;
|
|
case SocketType::NORMAL_ARRAY:
|
|
total_size += array_size_in_bytes<float3>(this, socket);
|
|
break;
|
|
case SocketType::POINT2_ARRAY:
|
|
total_size += array_size_in_bytes<float2>(this, socket);
|
|
break;
|
|
case SocketType::STRING_ARRAY:
|
|
total_size += array_size_in_bytes<ustring>(this, socket);
|
|
break;
|
|
case SocketType::TRANSFORM_ARRAY:
|
|
total_size += array_size_in_bytes<Transform>(this, socket);
|
|
break;
|
|
case SocketType::NODE_ARRAY:
|
|
total_size += array_size_in_bytes<void *>(this, socket);
|
|
break;
|
|
|
|
case SocketType::UNDEFINED:
|
|
break;
|
|
}
|
|
}
|
|
return total_size;
|
|
}
|
|
|
|
bool Node::is_a(const NodeType *type_)
|
|
{
|
|
for (const NodeType *base = type; base; base = base->base) {
|
|
if (base == type_) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const NodeOwner *Node::get_owner() const
|
|
{
|
|
return owner;
|
|
}
|
|
|
|
void Node::set_owner(const NodeOwner *owner_)
|
|
{
|
|
assert(owner_);
|
|
owner = owner_;
|
|
}
|
|
|
|
bool Node::socket_is_modified(const SocketType &input) const
|
|
{
|
|
return (socket_modified & input.modified_flag_bit) != 0;
|
|
}
|
|
|
|
bool Node::is_modified()
|
|
{
|
|
return socket_modified != 0;
|
|
}
|
|
|
|
void Node::tag_modified()
|
|
{
|
|
socket_modified = ~0ull;
|
|
}
|
|
|
|
void Node::clear_modified()
|
|
{
|
|
socket_modified = 0;
|
|
}
|
|
|
|
template<typename T> void Node::set_if_different(const SocketType &input, T value)
|
|
{
|
|
if (get_socket_value<T>(this, input) == value) {
|
|
return;
|
|
}
|
|
|
|
get_socket_value<T>(this, input) = value;
|
|
socket_modified |= input.modified_flag_bit;
|
|
}
|
|
|
|
template<typename T> void Node::set_if_different(const SocketType &input, array<T> &value)
|
|
{
|
|
if (!socket_is_modified(input)) {
|
|
if (get_socket_value<array<T>>(this, input) == value) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
get_socket_value<array<T>>(this, input).steal_data(value);
|
|
socket_modified |= input.modified_flag_bit;
|
|
}
|
|
|
|
void Node::print_modified_sockets() const
|
|
{
|
|
printf("Node : %s\n", name.c_str());
|
|
for (auto &socket : type->inputs) {
|
|
if (socket_is_modified(socket)) {
|
|
printf("-- socket modified : %s\n", socket.name.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|