Fix Cycles warning in release builds.
[blender.git] / intern / cycles / graph / node.cpp
1 /*
2  * Copyright 2011-2016 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "node.h"
18 #include "node_type.h"
19
20 #include "util_foreach.h"
21 #include "util_param.h"
22 #include "util_transform.h"
23
24 CCL_NAMESPACE_BEGIN
25
26 /* Node Type */
27
28 Node::Node(const NodeType *type_, ustring name_)
29 : name(name_), type(type_)
30 {
31         assert(type);
32
33         /* assign non-empty name, convenient for debugging */
34         if(name.empty()) {
35                 name = type->name;
36         }
37
38         /* initialize default values */
39         typedef unordered_map<ustring, SocketType, ustringHash> map_type;
40         foreach(const map_type::value_type& it, type->inputs) {
41                 const SocketType& socket = it.second;
42                 const void *src = socket.default_value;
43                 void *dst = ((char*)this) + socket.struct_offset;
44                 memcpy(dst, src, socket.size());
45         }
46 }
47
48 Node::~Node()
49 {
50 }
51
52 template<typename T>
53 static T& get_socket_value(const Node *node, const SocketType& socket)
54 {
55         return (T&)*(((char*)node) + socket.struct_offset);
56 }
57
58 #ifndef NDEBUG
59 static bool is_socket_float3(const SocketType& socket)
60 {
61         return socket.type == SocketType::COLOR ||
62                socket.type == SocketType::POINT ||
63                    socket.type == SocketType::VECTOR ||
64                    socket.type == SocketType::NORMAL;
65 }
66
67 static bool is_socket_array_float3(const SocketType& socket)
68 {
69         return socket.type == SocketType::COLOR_ARRAY ||
70                socket.type == SocketType::POINT_ARRAY ||
71                    socket.type == SocketType::VECTOR_ARRAY ||
72                    socket.type == SocketType::NORMAL_ARRAY;
73 }
74 #endif
75
76 /* set values */
77 void Node::set(const SocketType& input, bool value)
78 {
79         assert(input.type == SocketType::BOOLEAN);
80         get_socket_value<bool>(this, input) = value;
81 }
82
83 void Node::set(const SocketType& input, int value)
84 {
85         assert((input.type == SocketType::INT || input.type == SocketType::ENUM));
86         get_socket_value<int>(this, input) = value;
87 }
88
89 void Node::set(const SocketType& input, float value)
90 {
91         assert(input.type == SocketType::FLOAT);
92         get_socket_value<float>(this, input) = value;
93 }
94
95 void Node::set(const SocketType& input, float2 value)
96 {
97         assert(input.type == SocketType::FLOAT);
98         get_socket_value<float2>(this, input) = value;
99 }
100
101 void Node::set(const SocketType& input, float3 value)
102 {
103         assert(is_socket_float3(input));
104         get_socket_value<float3>(this, input) = value;
105 }
106
107 void Node::set(const SocketType& input, ustring value)
108 {
109         if(input.type == SocketType::STRING) {
110                 get_socket_value<ustring>(this, input) = value;
111         }
112         else if(input.type == SocketType::ENUM) {
113                 const NodeEnum& enm = *input.enum_values;
114                 if(enm.exists(value)) {
115                         get_socket_value<int>(this, input) = enm[value];
116                 }
117                 else {
118                         assert(0);
119                 }
120         }
121         else {
122                 assert(0);
123         }
124 }
125
126 void Node::set(const SocketType& input, const Transform& value)
127 {
128         assert(input.type == SocketType::TRANSFORM);
129         get_socket_value<Transform>(this, input) = value;
130 }
131
132 void Node::set(const SocketType& input, Node *value)
133 {
134         assert(input.type == SocketType::TRANSFORM);
135         get_socket_value<Node*>(this, input) = value;
136 }
137
138 /* set array values */
139 void Node::set(const SocketType& input, array<bool>& value)
140 {
141         assert(input.type == SocketType::BOOLEAN_ARRAY);
142         get_socket_value<array<bool> >(this, input).steal_data(value);
143 }
144
145 void Node::set(const SocketType& input, array<int>& value)
146 {
147         assert(input.type == SocketType::INT_ARRAY);
148         get_socket_value<array<int> >(this, input).steal_data(value);
149 }
150
151 void Node::set(const SocketType& input, array<float>& value)
152 {
153         assert(input.type == SocketType::FLOAT_ARRAY);
154         get_socket_value<array<float> >(this, input).steal_data(value);
155 }
156
157 void Node::set(const SocketType& input, array<float2>& value)
158 {
159         assert(input.type == SocketType::FLOAT_ARRAY);
160         get_socket_value<array<float2> >(this, input).steal_data(value);
161 }
162
163 void Node::set(const SocketType& input, array<float3>& value)
164 {
165         assert(is_socket_array_float3(input));
166         get_socket_value<array<float3> >(this, input).steal_data(value);
167 }
168
169 void Node::set(const SocketType& input, array<ustring>& value)
170 {
171         assert(input.type == SocketType::STRING_ARRAY);
172         get_socket_value<array<ustring> >(this, input).steal_data(value);
173 }
174
175 void Node::set(const SocketType& input, array<Transform>& value)
176 {
177         assert(input.type == SocketType::TRANSFORM_ARRAY);
178         get_socket_value<array<Transform> >(this, input).steal_data(value);
179 }
180
181 void Node::set(const SocketType& input, array<Node*>& value)
182 {
183         assert(input.type == SocketType::TRANSFORM_ARRAY);
184         get_socket_value<array<Node*> >(this, input).steal_data(value);
185 }
186
187 /* get values */
188 bool Node::get_bool(const SocketType& input) const
189 {
190         assert(input.type == SocketType::BOOLEAN);
191         return get_socket_value<bool>(this, input);
192 }
193
194 int Node::get_int(const SocketType& input) const
195 {
196         assert(input.type == SocketType::INT || input.type == SocketType::ENUM);
197         return get_socket_value<int>(this, input);
198 }
199
200 float Node::get_float(const SocketType& input) const
201 {
202         assert(input.type == SocketType::FLOAT);
203         return get_socket_value<float>(this, input);
204 }
205
206 float2 Node::get_float2(const SocketType& input) const
207 {
208         assert(input.type == SocketType::FLOAT);
209         return get_socket_value<float2>(this, input);
210 }
211
212 float3 Node::get_float3(const SocketType& input) const
213 {
214         assert(is_socket_float3(input));
215         return get_socket_value<float3>(this, input);
216 }
217
218 ustring Node::get_string(const SocketType& input) const
219 {
220         if(input.type == SocketType::STRING) {
221                 return get_socket_value<ustring>(this, input);
222         }
223         else if(input.type == SocketType::ENUM) {
224                 const NodeEnum& enm = *input.enum_values;
225                 int intvalue = get_socket_value<int>(this, input);
226                 return (enm.exists(intvalue)) ? enm[intvalue] : ustring();
227         }
228         else {
229                 assert(0);
230                 return ustring();
231         }
232 }
233
234 Transform Node::get_transform(const SocketType& input) const
235 {
236         assert(input.type == SocketType::TRANSFORM);
237         return get_socket_value<Transform>(this, input);
238 }
239
240 Node *Node::get_node(const SocketType& input) const
241 {
242         assert(input.type == SocketType::NODE);
243         return get_socket_value<Node*>(this, input);
244 }
245
246 /* get array values */
247 const array<bool>& Node::get_bool_array(const SocketType& input) const
248 {
249         assert(input.type == SocketType::BOOLEAN_ARRAY);
250         return get_socket_value<array<bool> >(this, input);
251 }
252
253 const array<int>& Node::get_int_array(const SocketType& input) const
254 {
255         assert(input.type == SocketType::INT_ARRAY);
256         return get_socket_value<array<int> >(this, input);
257 }
258
259 const array<float>& Node::get_float_array(const SocketType& input) const
260 {
261         assert(input.type == SocketType::FLOAT_ARRAY);
262         return get_socket_value<array<float> >(this, input);
263 }
264
265 const array<float2>& Node::get_float2_array(const SocketType& input) const
266 {
267         assert(input.type == SocketType::FLOAT_ARRAY);
268         return get_socket_value<array<float2> >(this, input);
269 }
270
271 const array<float3>& Node::get_float3_array(const SocketType& input) const
272 {
273         assert(is_socket_array_float3(input));
274         return get_socket_value<array<float3> >(this, input);
275 }
276
277 const array<ustring>& Node::get_string_array(const SocketType& input) const
278 {
279         assert(input.type == SocketType::STRING_ARRAY);
280         return get_socket_value<array<ustring> >(this, input);
281 }
282
283 const array<Transform>& Node::get_transform_array(const SocketType& input) const
284 {
285         assert(input.type == SocketType::TRANSFORM_ARRAY);
286         return get_socket_value<array<Transform> >(this, input);
287 }
288
289 const array<Node*>& Node::get_node_array(const SocketType& input) const
290 {
291         assert(input.type == SocketType::NODE_ARRAY);
292         return get_socket_value<array<Node*> >(this, input);
293 }
294
295 /* default values */
296 bool Node::has_default_value(const SocketType& input) const
297 {
298         const void *src = input.default_value;
299         void *dst = &get_socket_value<char>(this, input);
300         return memcmp(dst, src, input.size()) == 0;
301 }
302
303 template<typename T>
304 static bool is_array_equal(const Node *node, const Node *other, const SocketType& socket)
305 {
306         const array<T>* a = (const array<T>*)(((char*)node) + socket.struct_offset);
307         const array<T>* b = (const array<T>*)(((char*)other) + socket.struct_offset);
308         return *a == *b;
309 }
310
311 /* modified */
312 bool Node::modified(const Node& other)
313 {
314         assert(type == other.type);
315
316         typedef unordered_map<ustring, SocketType, ustringHash> map_type;
317         foreach(const map_type::value_type& it, type->inputs) {
318                 const SocketType& socket = it.second;
319
320                 if(socket.is_array()) {
321                         bool equal = true;
322
323                         switch(socket.type)
324                         {
325                                 case SocketType::BOOLEAN_ARRAY: equal = is_array_equal<bool>(this, &other, socket); break;
326                                 case SocketType::FLOAT_ARRAY: equal = is_array_equal<float>(this, &other, socket); break;
327                                 case SocketType::INT_ARRAY: equal = is_array_equal<int>(this, &other, socket); break;
328                                 case SocketType::COLOR_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
329                                 case SocketType::VECTOR_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
330                                 case SocketType::POINT_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
331                                 case SocketType::NORMAL_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
332                                 case SocketType::POINT2_ARRAY: equal = is_array_equal<float2>(this, &other, socket); break;
333                                 case SocketType::STRING_ARRAY: equal = is_array_equal<ustring>(this, &other, socket); break;
334                                 case SocketType::TRANSFORM_ARRAY: equal = is_array_equal<Transform>(this, &other, socket); break;
335                                 case SocketType::NODE_ARRAY: equal = is_array_equal<void*>(this, &other, socket); break;
336                                 default: assert(0); break;
337                         }
338
339                         if(!equal) {
340                                 return true;
341                         }
342                 }
343                 else {
344                         const void *a = ((char*)this) + socket.struct_offset;
345                         const void *b = ((char*)&other) + socket.struct_offset;
346                         if(memcmp(a, b, socket.size()) != 0) {
347                                 return true;
348                         }
349                 }
350         }
351
352         return false;
353 }
354
355 CCL_NAMESPACE_END
356