1 /*
2 * Copyright 2011-2013 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 #ifndef __BLENDER_UTIL_H__
18 #define __BLENDER_UTIL_H__
19
20 #include "render/mesh.h"
21
22 #include "util/util_algorithm.h"
23 #include "util/util_array.h"
24 #include "util/util_map.h"
25 #include "util/util_path.h"
26 #include "util/util_set.h"
27 #include "util/util_transform.h"
28 #include "util/util_types.h"
29 #include "util/util_vector.h"
30
31 /* Hacks to hook into Blender API
32 * todo: clean this up ... */
33
34 extern "C" {
35 void BKE_image_user_frame_calc(void *ima, void *iuser, int cfra);
36 void BKE_image_user_file_path(void *iuser, void *ima, char *path);
37 unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame, int tile);
38 float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
39 }
40
41 CCL_NAMESPACE_BEGIN
42
43 void python_thread_state_save(void **python_thread_state);
44 void python_thread_state_restore(void **python_thread_state);
45
object_to_mesh(BL::BlendData &,BL::Object & object,BL::Depsgraph &,bool,Mesh::SubdivisionType subdivision_type)46 static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
47 BL::Object &object,
48 BL::Depsgraph & /*depsgraph*/,
49 bool /*calc_undeformed*/,
50 Mesh::SubdivisionType subdivision_type)
51 {
52 /* TODO: make this work with copy-on-write, modifiers are already evaluated. */
53 #if 0
54 bool subsurf_mod_show_render = false;
55 bool subsurf_mod_show_viewport = false;
56
57 if (subdivision_type != Mesh::SUBDIVISION_NONE) {
58 BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1];
59
60 subsurf_mod_show_render = subsurf_mod.show_render();
61 subsurf_mod_show_viewport = subsurf_mod.show_viewport();
62
63 subsurf_mod.show_render(false);
64 subsurf_mod.show_viewport(false);
65 }
66 #endif
67
68 BL::Mesh mesh(PointerRNA_NULL);
69 if (object.type() == BL::Object::type_MESH) {
70 /* TODO: calc_undeformed is not used. */
71 mesh = BL::Mesh(object.data());
72
73 /* Make a copy to split faces if we use autosmooth, otherwise not needed.
74 * Also in edit mode do we need to make a copy, to ensure data layers like
75 * UV are not empty. */
76 if (mesh.is_editmode() ||
77 (mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) {
78 BL::Depsgraph depsgraph(PointerRNA_NULL);
79 mesh = object.to_mesh(false, depsgraph);
80 }
81 }
82 else {
83 BL::Depsgraph depsgraph(PointerRNA_NULL);
84 mesh = object.to_mesh(false, depsgraph);
85 }
86
87 #if 0
88 if (subdivision_type != Mesh::SUBDIVISION_NONE) {
89 BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length() - 1];
90
91 subsurf_mod.show_render(subsurf_mod_show_render);
92 subsurf_mod.show_viewport(subsurf_mod_show_viewport);
93 }
94 #endif
95
96 if ((bool)mesh && subdivision_type == Mesh::SUBDIVISION_NONE) {
97 if (mesh.use_auto_smooth()) {
98 mesh.split_faces(false);
99 }
100
101 mesh.calc_loop_triangles();
102 }
103
104 return mesh;
105 }
106
free_object_to_mesh(BL::BlendData &,BL::Object & object,BL::Mesh & mesh)107 static inline void free_object_to_mesh(BL::BlendData & /*data*/,
108 BL::Object &object,
109 BL::Mesh &mesh)
110 {
111 /* Free mesh if we didn't just use the existing one. */
112 if (object.data().ptr.data != mesh.ptr.data) {
113 object.to_mesh_clear();
114 }
115 }
116
colorramp_to_array(BL::ColorRamp & ramp,array<float3> & ramp_color,array<float> & ramp_alpha,int size)117 static inline void colorramp_to_array(BL::ColorRamp &ramp,
118 array<float3> &ramp_color,
119 array<float> &ramp_alpha,
120 int size)
121 {
122 ramp_color.resize(size);
123 ramp_alpha.resize(size);
124
125 for (int i = 0; i < size; i++) {
126 float color[4];
127
128 ramp.evaluate((float)i / (float)(size - 1), color);
129 ramp_color[i] = make_float3(color[0], color[1], color[2]);
130 ramp_alpha[i] = color[3];
131 }
132 }
133
curvemap_minmax_curve(BL::CurveMap & curve,float * min_x,float * max_x)134 static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap &curve, float *min_x, float *max_x)
135 {
136 *min_x = min(*min_x, curve.points[0].location()[0]);
137 *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]);
138 }
139
curvemapping_minmax(BL::CurveMapping & cumap,bool rgb_curve,float * min_x,float * max_x)140 static inline void curvemapping_minmax(/*const*/ BL::CurveMapping &cumap,
141 bool rgb_curve,
142 float *min_x,
143 float *max_x)
144 {
145 /* const int num_curves = cumap.curves.length(); */ /* Gives linking error so far. */
146 const int num_curves = rgb_curve ? 4 : 3;
147 *min_x = FLT_MAX;
148 *max_x = -FLT_MAX;
149 for (int i = 0; i < num_curves; ++i) {
150 BL::CurveMap map(cumap.curves[i]);
151 curvemap_minmax_curve(map, min_x, max_x);
152 }
153 }
154
curvemapping_to_array(BL::CurveMapping & cumap,array<float> & data,int size)155 static inline void curvemapping_to_array(BL::CurveMapping &cumap, array<float> &data, int size)
156 {
157 cumap.update();
158 BL::CurveMap curve = cumap.curves[0];
159 data.resize(size);
160 for (int i = 0; i < size; i++) {
161 float t = (float)i / (float)(size - 1);
162 data[i] = cumap.evaluate(curve, t);
163 }
164 }
165
curvemapping_color_to_array(BL::CurveMapping & cumap,array<float3> & data,int size,bool rgb_curve)166 static inline void curvemapping_color_to_array(BL::CurveMapping &cumap,
167 array<float3> &data,
168 int size,
169 bool rgb_curve)
170 {
171 float min_x = 0.0f, max_x = 1.0f;
172
173 /* TODO(sergey): There is no easy way to automatically guess what is
174 * the range to be used here for the case when mapping is applied on
175 * top of another mapping (i.e. R curve applied on top of common
176 * one).
177 *
178 * Using largest possible range form all curves works correct for the
179 * cases like vector curves and should be good enough heuristic for
180 * the color curves as well.
181 *
182 * There might be some better estimations here tho.
183 */
184 curvemapping_minmax(cumap, rgb_curve, &min_x, &max_x);
185
186 const float range_x = max_x - min_x;
187
188 cumap.update();
189
190 BL::CurveMap mapR = cumap.curves[0];
191 BL::CurveMap mapG = cumap.curves[1];
192 BL::CurveMap mapB = cumap.curves[2];
193
194 data.resize(size);
195
196 if (rgb_curve) {
197 BL::CurveMap mapI = cumap.curves[3];
198 for (int i = 0; i < size; i++) {
199 const float t = min_x + (float)i / (float)(size - 1) * range_x;
200 data[i] = make_float3(cumap.evaluate(mapR, cumap.evaluate(mapI, t)),
201 cumap.evaluate(mapG, cumap.evaluate(mapI, t)),
202 cumap.evaluate(mapB, cumap.evaluate(mapI, t)));
203 }
204 }
205 else {
206 for (int i = 0; i < size; i++) {
207 float t = min_x + (float)i / (float)(size - 1) * range_x;
208 data[i] = make_float3(
209 cumap.evaluate(mapR, t), cumap.evaluate(mapG, t), cumap.evaluate(mapB, t));
210 }
211 }
212 }
213
BKE_object_is_modified(BL::Object & self,BL::Scene & scene,bool preview)214 static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bool preview)
215 {
216 return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
217 }
218
BKE_object_is_deform_modified(BL::Object & self,BL::Scene & scene,bool preview)219 static inline bool BKE_object_is_deform_modified(BL::Object &self, BL::Scene &scene, bool preview)
220 {
221 return self.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
222 }
223
render_resolution_x(BL::RenderSettings & b_render)224 static inline int render_resolution_x(BL::RenderSettings &b_render)
225 {
226 return b_render.resolution_x() * b_render.resolution_percentage() / 100;
227 }
228
render_resolution_y(BL::RenderSettings & b_render)229 static inline int render_resolution_y(BL::RenderSettings &b_render)
230 {
231 return b_render.resolution_y() * b_render.resolution_percentage() / 100;
232 }
233
image_user_file_path(BL::ImageUser & iuser,BL::Image & ima,int cfra,bool load_tiled)234 static inline string image_user_file_path(BL::ImageUser &iuser,
235 BL::Image &ima,
236 int cfra,
237 bool load_tiled)
238 {
239 char filepath[1024];
240 iuser.tile(0);
241 BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra);
242 BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath);
243
244 string filepath_str = string(filepath);
245 if (load_tiled && ima.source() == BL::Image::source_TILED) {
246 string_replace(filepath_str, "1001", "<UDIM>");
247 }
248 return filepath_str;
249 }
250
image_user_frame_number(BL::ImageUser & iuser,BL::Image & ima,int cfra)251 static inline int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, int cfra)
252 {
253 BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra);
254 return iuser.frame_current();
255 }
256
image_get_pixels_for_frame(BL::Image & image,int frame,int tile)257 static inline unsigned char *image_get_pixels_for_frame(BL::Image &image, int frame, int tile)
258 {
259 return BKE_image_get_pixels_for_frame(image.ptr.data, frame, tile);
260 }
261
image_get_float_pixels_for_frame(BL::Image & image,int frame,int tile)262 static inline float *image_get_float_pixels_for_frame(BL::Image &image, int frame, int tile)
263 {
264 return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame, tile);
265 }
266
render_add_metadata(BL::RenderResult & b_rr,string name,string value)267 static inline void render_add_metadata(BL::RenderResult &b_rr, string name, string value)
268 {
269 b_rr.stamp_data_add_field(name.c_str(), value.c_str());
270 }
271
272 /* Utilities */
273
get_transform(const BL::Array<float,16> & array)274 static inline Transform get_transform(const BL::Array<float, 16> &array)
275 {
276 ProjectionTransform projection;
277
278 /* We assume both types to be just 16 floats, and transpose because blender
279 * use column major matrix order while we use row major. */
280 memcpy((void *)&projection, &array, sizeof(float) * 16);
281 projection = projection_transpose(projection);
282
283 /* Drop last row, matrix is assumed to be affine transform. */
284 return projection_to_transform(projection);
285 }
286
get_float2(const BL::Array<float,2> & array)287 static inline float2 get_float2(const BL::Array<float, 2> &array)
288 {
289 return make_float2(array[0], array[1]);
290 }
291
get_float3(const BL::Array<float,2> & array)292 static inline float3 get_float3(const BL::Array<float, 2> &array)
293 {
294 return make_float3(array[0], array[1], 0.0f);
295 }
296
get_float3(const BL::Array<float,3> & array)297 static inline float3 get_float3(const BL::Array<float, 3> &array)
298 {
299 return make_float3(array[0], array[1], array[2]);
300 }
301
get_float3(const BL::Array<float,4> & array)302 static inline float3 get_float3(const BL::Array<float, 4> &array)
303 {
304 return make_float3(array[0], array[1], array[2]);
305 }
306
get_float4(const BL::Array<float,4> & array)307 static inline float4 get_float4(const BL::Array<float, 4> &array)
308 {
309 return make_float4(array[0], array[1], array[2], array[3]);
310 }
311
get_int3(const BL::Array<int,3> & array)312 static inline int3 get_int3(const BL::Array<int, 3> &array)
313 {
314 return make_int3(array[0], array[1], array[2]);
315 }
316
get_int4(const BL::Array<int,4> & array)317 static inline int4 get_int4(const BL::Array<int, 4> &array)
318 {
319 return make_int4(array[0], array[1], array[2], array[3]);
320 }
321
get_float3(PointerRNA & ptr,const char * name)322 static inline float3 get_float3(PointerRNA &ptr, const char *name)
323 {
324 float3 f;
325 RNA_float_get_array(&ptr, name, &f.x);
326 return f;
327 }
328
set_float3(PointerRNA & ptr,const char * name,float3 value)329 static inline void set_float3(PointerRNA &ptr, const char *name, float3 value)
330 {
331 RNA_float_set_array(&ptr, name, &value.x);
332 }
333
get_float4(PointerRNA & ptr,const char * name)334 static inline float4 get_float4(PointerRNA &ptr, const char *name)
335 {
336 float4 f;
337 RNA_float_get_array(&ptr, name, &f.x);
338 return f;
339 }
340
set_float4(PointerRNA & ptr,const char * name,float4 value)341 static inline void set_float4(PointerRNA &ptr, const char *name, float4 value)
342 {
343 RNA_float_set_array(&ptr, name, &value.x);
344 }
345
get_boolean(PointerRNA & ptr,const char * name)346 static inline bool get_boolean(PointerRNA &ptr, const char *name)
347 {
348 return RNA_boolean_get(&ptr, name) ? true : false;
349 }
350
set_boolean(PointerRNA & ptr,const char * name,bool value)351 static inline void set_boolean(PointerRNA &ptr, const char *name, bool value)
352 {
353 RNA_boolean_set(&ptr, name, (int)value);
354 }
355
get_float(PointerRNA & ptr,const char * name)356 static inline float get_float(PointerRNA &ptr, const char *name)
357 {
358 return RNA_float_get(&ptr, name);
359 }
360
set_float(PointerRNA & ptr,const char * name,float value)361 static inline void set_float(PointerRNA &ptr, const char *name, float value)
362 {
363 RNA_float_set(&ptr, name, value);
364 }
365
get_int(PointerRNA & ptr,const char * name)366 static inline int get_int(PointerRNA &ptr, const char *name)
367 {
368 return RNA_int_get(&ptr, name);
369 }
370
set_int(PointerRNA & ptr,const char * name,int value)371 static inline void set_int(PointerRNA &ptr, const char *name, int value)
372 {
373 RNA_int_set(&ptr, name, value);
374 }
375
376 /* Get a RNA enum value with sanity check: if the RNA value is above num_values
377 * the function will return a fallback default value.
378 *
379 * NOTE: This function assumes that RNA enum values are a continuous sequence
380 * from 0 to num_values-1. Be careful to use it with enums where some values are
381 * deprecated!
382 */
383 static inline int get_enum(PointerRNA &ptr,
384 const char *name,
385 int num_values = -1,
386 int default_value = -1)
387 {
388 int value = RNA_enum_get(&ptr, name);
389 if (num_values != -1 && value >= num_values) {
390 assert(default_value != -1);
391 value = default_value;
392 }
393 return value;
394 }
395
get_enum_identifier(PointerRNA & ptr,const char * name)396 static inline string get_enum_identifier(PointerRNA &ptr, const char *name)
397 {
398 PropertyRNA *prop = RNA_struct_find_property(&ptr, name);
399 const char *identifier = "";
400 int value = RNA_property_enum_get(&ptr, prop);
401
402 RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
403
404 return string(identifier);
405 }
406
set_enum(PointerRNA & ptr,const char * name,int value)407 static inline void set_enum(PointerRNA &ptr, const char *name, int value)
408 {
409 RNA_enum_set(&ptr, name, value);
410 }
411
set_enum(PointerRNA & ptr,const char * name,const string & identifier)412 static inline void set_enum(PointerRNA &ptr, const char *name, const string &identifier)
413 {
414 RNA_enum_set_identifier(NULL, &ptr, name, identifier.c_str());
415 }
416
get_string(PointerRNA & ptr,const char * name)417 static inline string get_string(PointerRNA &ptr, const char *name)
418 {
419 char cstrbuf[1024];
420 char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf));
421 string str(cstr);
422 if (cstr != cstrbuf)
423 MEM_freeN(cstr);
424
425 return str;
426 }
427
set_string(PointerRNA & ptr,const char * name,const string & value)428 static inline void set_string(PointerRNA &ptr, const char *name, const string &value)
429 {
430 RNA_string_set(&ptr, name, value.c_str());
431 }
432
433 /* Relative Paths */
434
blender_absolute_path(BL::BlendData & b_data,BL::ID & b_id,const string & path)435 static inline string blender_absolute_path(BL::BlendData &b_data, BL::ID &b_id, const string &path)
436 {
437 if (path.size() >= 2 && path[0] == '/' && path[1] == '/') {
438 string dirname;
439
440 if (b_id.library()) {
441 BL::ID b_library_id(b_id.library());
442 dirname = blender_absolute_path(b_data, b_library_id, b_id.library().filepath());
443 }
444 else
445 dirname = b_data.filepath();
446
447 return path_join(path_dirname(dirname), path.substr(2));
448 }
449
450 return path;
451 }
452
get_text_datablock_content(const PointerRNA & ptr)453 static inline string get_text_datablock_content(const PointerRNA &ptr)
454 {
455 if (ptr.data == NULL) {
456 return "";
457 }
458
459 string content;
460 BL::Text::lines_iterator iter;
461 for (iter.begin(ptr); iter; ++iter) {
462 content += iter->body() + "\n";
463 }
464
465 return content;
466 }
467
468 /* Texture Space */
469
mesh_texture_space(BL::Mesh & b_mesh,float3 & loc,float3 & size)470 static inline void mesh_texture_space(BL::Mesh &b_mesh, float3 &loc, float3 &size)
471 {
472 loc = get_float3(b_mesh.texspace_location());
473 size = get_float3(b_mesh.texspace_size());
474
475 if (size.x != 0.0f)
476 size.x = 0.5f / size.x;
477 if (size.y != 0.0f)
478 size.y = 0.5f / size.y;
479 if (size.z != 0.0f)
480 size.z = 0.5f / size.z;
481
482 loc = loc * size - make_float3(0.5f, 0.5f, 0.5f);
483 }
484
485 /* Object motion steps, returns 0 if no motion blur needed. */
486 static inline uint object_motion_steps(BL::Object &b_parent,
487 BL::Object &b_ob,
488 const int max_steps = INT_MAX)
489 {
490 /* Get motion enabled and steps from object itself. */
491 PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
492 bool use_motion = get_boolean(cobject, "use_motion_blur");
493 if (!use_motion) {
494 return 0;
495 }
496
497 int steps = max(1, get_int(cobject, "motion_steps"));
498
499 /* Also check parent object, so motion blur and steps can be
500 * controlled by dupligroup duplicator for linked groups. */
501 if (b_parent.ptr.data != b_ob.ptr.data) {
502 PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
503 use_motion &= get_boolean(parent_cobject, "use_motion_blur");
504
505 if (!use_motion) {
506 return 0;
507 }
508
509 steps = max(steps, get_int(parent_cobject, "motion_steps"));
510 }
511
512 /* Use uneven number of steps so we get one keyframe at the current frame,
513 * and use 2^(steps - 1) so objects with more/fewer steps still have samples
514 * at the same times, to avoid sampling at many different times. */
515 return min((2 << (steps - 1)) + 1, max_steps);
516 }
517
518 /* object uses deformation motion blur */
object_use_deform_motion(BL::Object & b_parent,BL::Object & b_ob)519 static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_ob)
520 {
521 PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
522 bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
523 /* If motion blur is enabled for the object we also check
524 * whether it's enabled for the parent object as well.
525 *
526 * This way we can control motion blur from the dupligroup
527 * duplicator much easier.
528 */
529 if (use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
530 PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
531 use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
532 }
533 return use_deform_motion;
534 }
535
object_fluid_liquid_domain_find(BL::Object & b_ob)536 static inline BL::FluidDomainSettings object_fluid_liquid_domain_find(BL::Object &b_ob)
537 {
538 BL::Object::modifiers_iterator b_mod;
539
540 for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
541 if (b_mod->is_a(&RNA_FluidModifier)) {
542 BL::FluidModifier b_mmd(*b_mod);
543
544 if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
545 b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_LIQUID) {
546 return b_mmd.domain_settings();
547 }
548 }
549 }
550
551 return BL::FluidDomainSettings(PointerRNA_NULL);
552 }
553
object_fluid_gas_domain_find(BL::Object & b_ob)554 static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
555 {
556 BL::Object::modifiers_iterator b_mod;
557
558 for (b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
559 if (b_mod->is_a(&RNA_FluidModifier)) {
560 BL::FluidModifier b_mmd(*b_mod);
561
562 if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
563 b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_GAS) {
564 return b_mmd.domain_settings();
565 }
566 }
567 }
568
569 return BL::FluidDomainSettings(PointerRNA_NULL);
570 }
571
object_subdivision_type(BL::Object & b_ob,bool preview,bool experimental)572 static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
573 bool preview,
574 bool experimental)
575 {
576 PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
577
578 if (cobj.data && b_ob.modifiers.length() > 0 && experimental) {
579 BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
580 bool enabled = preview ? mod.show_viewport() : mod.show_render();
581
582 if (enabled && mod.type() == BL::Modifier::type_SUBSURF &&
583 RNA_boolean_get(&cobj, "use_adaptive_subdivision")) {
584 BL::SubsurfModifier subsurf(mod);
585
586 if (subsurf.subdivision_type() == BL::SubsurfModifier::subdivision_type_CATMULL_CLARK) {
587 return Mesh::SUBDIVISION_CATMULL_CLARK;
588 }
589 else {
590 return Mesh::SUBDIVISION_LINEAR;
591 }
592 }
593 }
594
595 return Mesh::SUBDIVISION_NONE;
596 }
597
object_ray_visibility(BL::Object & b_ob)598 static inline uint object_ray_visibility(BL::Object &b_ob)
599 {
600 PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
601 uint flag = 0;
602
603 flag |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0;
604 flag |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0;
605 flag |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0;
606 flag |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0;
607 flag |= get_boolean(cvisibility, "shadow") ? PATH_RAY_SHADOW : 0;
608 flag |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0;
609
610 return flag;
611 }
612
613 class EdgeMap {
614 public:
EdgeMap()615 EdgeMap()
616 {
617 }
618
clear()619 void clear()
620 {
621 edges_.clear();
622 }
623
insert(int v0,int v1)624 void insert(int v0, int v1)
625 {
626 get_sorted_verts(v0, v1);
627 edges_.insert(std::pair<int, int>(v0, v1));
628 }
629
exists(int v0,int v1)630 bool exists(int v0, int v1)
631 {
632 get_sorted_verts(v0, v1);
633 return edges_.find(std::pair<int, int>(v0, v1)) != edges_.end();
634 }
635
636 protected:
get_sorted_verts(int & v0,int & v1)637 void get_sorted_verts(int &v0, int &v1)
638 {
639 if (v0 > v1) {
640 swap(v0, v1);
641 }
642 }
643
644 set<std::pair<int, int>> edges_;
645 };
646
647 CCL_NAMESPACE_END
648
649 #endif /* __BLENDER_UTIL_H__ */
650