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