Cycles: Pass Blender's C++ RNA structures by reference
[blender.git] / intern / cycles / blender / blender_util.h
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 "util_map.h"
21 #include "util_path.h"
22 #include "util_set.h"
23 #include "util_transform.h"
24 #include "util_types.h"
25 #include "util_vector.h"
26
27 /* Hacks to hook into Blender API
28  * todo: clean this up ... */
29
30 extern "C" {
31 size_t BLI_timecode_string_from_time_simple(char *str, size_t maxlen, double time_seconds);
32 void BKE_image_user_frame_calc(void *iuser, int cfra, int fieldnr);
33 void BKE_image_user_file_path(void *iuser, void *ima, char *path);
34 unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame);
35 float *BKE_image_get_float_pixels_for_frame(void *image, int frame);
36 }
37
38 CCL_NAMESPACE_BEGIN
39
40 void python_thread_state_save(void **python_thread_state);
41 void python_thread_state_restore(void **python_thread_state);
42
43 static inline BL::Mesh object_to_mesh(BL::BlendData& data,
44                                       BL::Object& object,
45                                       BL::Scene& scene,
46                                       bool apply_modifiers,
47                                       bool render,
48                                       bool calc_undeformed)
49 {
50         BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed);
51         if((bool)me) {
52                 if(me.use_auto_smooth()) {
53                         me.calc_normals_split();
54                 }
55                 me.calc_tessface(true);
56         }
57         return me;
58 }
59
60 static inline void colorramp_to_array(BL::ColorRamp& ramp,
61                                       float4 *data,
62                                       int size)
63 {
64         for(int i = 0; i < size; i++) {
65                 float color[4];
66
67                 ramp.evaluate((float)i/(float)(size-1), color);
68                 data[i] = make_float4(color[0], color[1], color[2], color[3]);
69         }
70 }
71
72 static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap& curve,
73                                          float *min_x,
74                                          float *max_x)
75 {
76         *min_x = min(*min_x, curve.points[0].location()[0]);
77         *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]);
78 }
79
80 static inline void curvemapping_minmax(/*const*/ BL::CurveMapping& cumap,
81                                        bool rgb_curve,
82                                        float *min_x,
83                                        float *max_x)
84 {
85         /* const int num_curves = cumap.curves.length(); */  /* Gives linking error so far. */
86         const int num_curves = rgb_curve? 4: 3;
87         *min_x = FLT_MAX;
88         *max_x = -FLT_MAX;
89         for(int i = 0; i < num_curves; ++i) {
90                 BL::CurveMap map(cumap.curves[i]);
91                 curvemap_minmax_curve(map, min_x, max_x);
92         }
93 }
94
95 static inline void curvemapping_to_array(BL::CurveMapping& cumap,
96                                          float *data,
97                                          int size)
98 {
99         cumap.update();
100         BL::CurveMap curve = cumap.curves[0];
101         for(int i = 0; i < size; i++) {
102                 float t = (float)i/(float)(size-1);
103                 data[i] = curve.evaluate(t);
104         }
105 }
106
107 static inline void curvemapping_color_to_array(BL::CurveMapping& cumap,
108                                                float4 *data,
109                                                int size,
110                                                bool rgb_curve)
111 {
112         float min_x = 0.0f, max_x = 1.0f;
113
114         /* TODO(sergey): There is no easy way to automatically guess what is
115          * the range to be used here for the case when mapping is applied on
116          * top of another mapping (i.e. R curve applied on top of common
117          * one).
118          *
119          * Using largest possible range form all curves works correct for the
120          * cases like vector curves and should be good enough heuristic for
121          * the color curves as well.
122          *
123          * There might be some better estimations here tho.
124          */
125         curvemapping_minmax(cumap, rgb_curve, &min_x, &max_x);
126
127         const float range_x = max_x - min_x;
128
129         cumap.update();
130
131         BL::CurveMap mapR = cumap.curves[0];
132         BL::CurveMap mapG = cumap.curves[1];
133         BL::CurveMap mapB = cumap.curves[2];
134
135         if(rgb_curve) {
136                 BL::CurveMap mapI = cumap.curves[3];
137
138                 for(int i = 0; i < size; i++) {
139                         float t = min_x + (float)i/(float)(size-1) * range_x;
140
141                         data[i][0] = mapR.evaluate(mapI.evaluate(t));
142                         data[i][1] = mapG.evaluate(mapI.evaluate(t));
143                         data[i][2] = mapB.evaluate(mapI.evaluate(t));
144                 }
145         }
146         else {
147                 for(int i = 0; i < size; i++) {
148                         float t = min_x + (float)i/(float)(size-1) * range_x;
149
150                         data[i][0] = mapR.evaluate(t);
151                         data[i][1] = mapG.evaluate(t);
152                         data[i][2] = mapB.evaluate(t);
153                 }
154         }
155 }
156
157 static inline bool BKE_object_is_modified(BL::Object& self,
158                                           BL::Scene& scene,
159                                           bool preview)
160 {
161         return self.is_modified(scene, (preview)? (1<<0): (1<<1))? true: false;
162 }
163
164 static inline bool BKE_object_is_deform_modified(BL::Object& self,
165                                                  BL::Scene& scene,
166                                                  bool preview)
167 {
168         return self.is_deform_modified(scene, (preview)? (1<<0): (1<<1))? true: false;
169 }
170
171 static inline int render_resolution_x(BL::RenderSettings& b_render)
172 {
173         return b_render.resolution_x()*b_render.resolution_percentage()/100;
174 }
175
176 static inline int render_resolution_y(BL::RenderSettings& b_render)
177 {
178         return b_render.resolution_y()*b_render.resolution_percentage()/100;
179 }
180
181 static inline string image_user_file_path(BL::ImageUser& iuser,
182                                           BL::Image& ima,
183                                           int cfra)
184 {
185         char filepath[1024];
186         BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
187         BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath);
188         return string(filepath);
189 }
190
191 static inline int image_user_frame_number(BL::ImageUser& iuser, int cfra)
192 {
193         BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
194         return iuser.frame_current();
195 }
196
197 static inline unsigned char *image_get_pixels_for_frame(BL::Image& image,
198                                                         int frame)
199 {
200         return BKE_image_get_pixels_for_frame(image.ptr.data, frame);
201 }
202
203 static inline float *image_get_float_pixels_for_frame(BL::Image& image,
204                                                       int frame)
205 {
206         return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame);
207 }
208
209 /* Utilities */
210
211 static inline Transform get_transform(const BL::Array<float, 16>& array)
212 {
213         Transform tfm;
214
215         /* we assume both types to be just 16 floats, and transpose because blender
216          * use column major matrix order while we use row major */
217         memcpy(&tfm, &array, sizeof(float)*16);
218         tfm = transform_transpose(tfm);
219
220         return tfm;
221 }
222
223 static inline float2 get_float2(const BL::Array<float, 2>& array)
224 {
225         return make_float2(array[0], array[1]);
226 }
227
228 static inline float3 get_float3(const BL::Array<float, 2>& array)
229 {
230         return make_float3(array[0], array[1], 0.0f);
231 }
232
233 static inline float3 get_float3(const BL::Array<float, 3>& array)
234 {
235         return make_float3(array[0], array[1], array[2]);
236 }
237
238 static inline float3 get_float3(const BL::Array<float, 4>& array)
239 {
240         return make_float3(array[0], array[1], array[2]);
241 }
242
243 static inline float4 get_float4(const BL::Array<float, 4>& array)
244 {
245         return make_float4(array[0], array[1], array[2], array[3]);
246 }
247
248 static inline int3 get_int3(const BL::Array<int, 3>& array)
249 {
250         return make_int3(array[0], array[1], array[2]);
251 }
252
253 static inline int4 get_int4(const BL::Array<int, 4>& array)
254 {
255         return make_int4(array[0], array[1], array[2], array[3]);
256 }
257
258 static inline uint get_layer(const BL::Array<int, 20>& array)
259 {
260         uint layer = 0;
261
262         for(uint i = 0; i < 20; i++)
263                 if(array[i])
264                         layer |= (1 << i);
265         
266         return layer;
267 }
268
269 static inline uint get_layer(const BL::Array<int, 20>& array,
270                              const BL::Array<int, 8>& local_array,
271                              bool use_local,
272                              bool is_light = false,
273                              uint scene_layers = (1 << 20) - 1)
274 {
275         uint layer = 0;
276
277         for(uint i = 0; i < 20; i++)
278                 if(array[i])
279                         layer |= (1 << i);
280
281         if(is_light) {
282                 /* Consider light is visible if it was visible without layer
283                  * override, which matches behavior of Blender Internal.
284                  */
285                 if(layer & scene_layers) {
286                         for(uint i = 0; i < 8; i++)
287                                 layer |= (1 << (20+i));
288                 }
289         }
290         else {
291                 for(uint i = 0; i < 8; i++)
292                         if(local_array[i])
293                                 layer |= (1 << (20+i));
294         }
295
296         /* we don't have spare bits for localview (normally 20-28) because
297          * PATH_RAY_LAYER_SHIFT uses 20-32. So - check if we have localview and if
298          * so, shift local view bits down to 1-8, since this is done for the view
299          * port only - it should be OK and not conflict with render layers. */
300         if(use_local)
301                 layer >>= 20;
302
303         return layer;
304 }
305
306 static inline float3 get_float3(PointerRNA& ptr, const char *name)
307 {
308         float3 f;
309         RNA_float_get_array(&ptr, name, &f.x);
310         return f;
311 }
312
313 static inline void set_float3(PointerRNA& ptr, const char *name, float3 value)
314 {
315         RNA_float_set_array(&ptr, name, &value.x);
316 }
317
318 static inline float4 get_float4(PointerRNA& ptr, const char *name)
319 {
320         float4 f;
321         RNA_float_get_array(&ptr, name, &f.x);
322         return f;
323 }
324
325 static inline void set_float4(PointerRNA& ptr, const char *name, float4 value)
326 {
327         RNA_float_set_array(&ptr, name, &value.x);
328 }
329
330 static inline bool get_boolean(PointerRNA& ptr, const char *name)
331 {
332         return RNA_boolean_get(&ptr, name)? true: false;
333 }
334
335 static inline void set_boolean(PointerRNA& ptr, const char *name, bool value)
336 {
337         RNA_boolean_set(&ptr, name, (int)value);
338 }
339
340 static inline float get_float(PointerRNA& ptr, const char *name)
341 {
342         return RNA_float_get(&ptr, name);
343 }
344
345 static inline void set_float(PointerRNA& ptr, const char *name, float value)
346 {
347         RNA_float_set(&ptr, name, value);
348 }
349
350 static inline int get_int(PointerRNA& ptr, const char *name)
351 {
352         return RNA_int_get(&ptr, name);
353 }
354
355 static inline void set_int(PointerRNA& ptr, const char *name, int value)
356 {
357         RNA_int_set(&ptr, name, value);
358 }
359
360 static inline int get_enum(PointerRNA& ptr, const char *name)
361 {
362         return RNA_enum_get(&ptr, name);
363 }
364
365 static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
366 {
367         PropertyRNA *prop = RNA_struct_find_property(&ptr, name);
368         const char *identifier = "";
369         int value = RNA_property_enum_get(&ptr, prop);
370
371         RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
372
373         return string(identifier);
374 }
375
376 static inline void set_enum(PointerRNA& ptr, const char *name, int value)
377 {
378         RNA_enum_set(&ptr, name, value);
379 }
380
381 static inline void set_enum(PointerRNA& ptr, const char *name, const string &identifier)
382 {
383         RNA_enum_set_identifier(NULL, &ptr, name, identifier.c_str());
384 }
385
386 static inline string get_string(PointerRNA& ptr, const char *name)
387 {
388         char cstrbuf[1024];
389         char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf));
390         string str(cstr);
391         if(cstr != cstrbuf)
392                 MEM_freeN(cstr);
393         
394         return str;
395 }
396
397 static inline void set_string(PointerRNA& ptr, const char *name, const string &value)
398 {
399         RNA_string_set(&ptr, name, value.c_str());
400 }
401
402 /* Relative Paths */
403
404 static inline string blender_absolute_path(BL::BlendData& b_data,
405                                            BL::ID& b_id,
406                                            const string& path)
407 {
408         if(path.size() >= 2 && path[0] == '/' && path[1] == '/') {
409                 string dirname;
410                 
411                 if(b_id.library()) {
412                         BL::ID b_library_id(b_id.library());
413                         dirname = blender_absolute_path(b_data,
414                                                         b_library_id,
415                                                         b_id.library().filepath());
416                 }
417                 else
418                         dirname = b_data.filepath();
419
420                 return path_join(path_dirname(dirname), path.substr(2));
421         }
422
423         return path;
424 }
425
426 /* Texture Space */
427
428 static inline void mesh_texture_space(BL::Mesh& b_mesh,
429                                       float3& loc,
430                                       float3& size)
431 {
432         loc = get_float3(b_mesh.texspace_location());
433         size = get_float3(b_mesh.texspace_size());
434
435         if(size.x != 0.0f) size.x = 0.5f/size.x;
436         if(size.y != 0.0f) size.y = 0.5f/size.y;
437         if(size.z != 0.0f) size.z = 0.5f/size.z;
438
439         loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
440 }
441
442 /* object used for motion blur */
443 static inline bool object_use_motion(BL::Object& b_parent, BL::Object& b_ob)
444 {
445         PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
446         bool use_motion = get_boolean(cobject, "use_motion_blur");
447         /* If motion blur is enabled for the object we also check
448          * whether it's enabled for the parent object as well.
449          *
450          * This way we can control motion blur from the dupligroup
451          * duplicator much easier.
452          */
453         if(use_motion && b_parent.ptr.data != b_ob.ptr.data) {
454                 PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
455                 use_motion &= get_boolean(parent_cobject, "use_motion_blur");
456         }
457         return use_motion;
458 }
459
460 /* object motion steps */
461 static inline uint object_motion_steps(BL::Object& b_ob)
462 {
463         PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
464         uint steps = get_int(cobject, "motion_steps");
465
466         /* use uneven number of steps so we get one keyframe at the current frame,
467          * and ue 2^(steps - 1) so objects with more/fewer steps still have samples
468          * at the same times, to avoid sampling at many different times */
469         return (2 << (steps - 1)) + 1;
470 }
471
472 /* object uses deformation motion blur */
473 static inline bool object_use_deform_motion(BL::Object& b_parent,
474                                             BL::Object& b_ob)
475 {
476         PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
477         bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
478         /* If motion blur is enabled for the object we also check
479          * whether it's enabled for the parent object as well.
480          *
481          * This way we can control motion blur from the dupligroup
482          * duplicator much easier.
483          */
484         if(use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
485                 PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
486                 use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
487         }
488         return use_deform_motion;
489 }
490
491 static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object& b_ob)
492 {
493         BL::Object::modifiers_iterator b_mod;
494
495         for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
496                 if(b_mod->is_a(&RNA_SmokeModifier)) {
497                         BL::SmokeModifier b_smd(*b_mod);
498
499                         if(b_smd.smoke_type() == BL::SmokeModifier::smoke_type_DOMAIN)
500                                 return b_smd.domain_settings();
501                 }
502         }
503         
504         return BL::SmokeDomainSettings(PointerRNA_NULL);
505 }
506
507 /* ID Map
508  *
509  * Utility class to keep in sync with blender data.
510  * Used for objects, meshes, lights and shaders. */
511
512 template<typename K, typename T>
513 class id_map {
514 public:
515         id_map(vector<T*> *scene_data_)
516         {
517                 scene_data = scene_data_;
518         }
519
520         T *find(const BL::ID& id)
521         {
522                 return find(id.ptr.id.data);
523         }
524
525         T *find(const K& key)
526         {
527                 if(b_map.find(key) != b_map.end()) {
528                         T *data = b_map[key];
529                         return data;
530                 }
531
532                 return NULL;
533         }
534
535         void set_recalc(const BL::ID& id)
536         {
537                 b_recalc.insert(id.ptr.data);
538         }
539
540         bool has_recalc()
541         {
542                 return !(b_recalc.empty());
543         }
544
545         void pre_sync()
546         {
547                 used_set.clear();
548         }
549
550         bool sync(T **r_data, const BL::ID& id)
551         {
552                 return sync(r_data, id, id, id.ptr.id.data);
553         }
554
555         bool sync(T **r_data, const BL::ID& id, const BL::ID& parent, const K& key)
556         {
557                 T *data = find(key);
558                 bool recalc;
559
560                 if(!data) {
561                         /* add data if it didn't exist yet */
562                         data = new T();
563                         scene_data->push_back(data);
564                         b_map[key] = data;
565                         recalc = true;
566                 }
567                 else {
568                         recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
569                         if(parent.ptr.data)
570                                 recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
571                 }
572
573                 used(data);
574
575                 *r_data = data;
576                 return recalc;
577         }
578
579         bool is_used(const K& key)
580         {
581                 T *data = find(key);
582                 return (data) ? used_set.find(data) != used_set.end() : false;
583         }
584
585         void used(T *data)
586         {
587                 /* tag data as still in use */
588                 used_set.insert(data);
589         }
590
591         void set_default(T *data)
592         {
593                 b_map[NULL] = data;
594         }
595
596         bool post_sync(bool do_delete = true)
597         {
598                 /* remove unused data */
599                 vector<T*> new_scene_data;
600                 typename vector<T*>::iterator it;
601                 bool deleted = false;
602
603                 for(it = scene_data->begin(); it != scene_data->end(); it++) {
604                         T *data = *it;
605
606                         if(do_delete && used_set.find(data) == used_set.end()) {
607                                 delete data;
608                                 deleted = true;
609                         }
610                         else
611                                 new_scene_data.push_back(data);
612                 }
613
614                 *scene_data = new_scene_data;
615
616                 /* update mapping */
617                 map<K, T*> new_map;
618                 typedef pair<const K, T*> TMapPair;
619                 typename map<K, T*>::iterator jt;
620
621                 for(jt = b_map.begin(); jt != b_map.end(); jt++) {
622                         TMapPair& pair = *jt;
623
624                         if(used_set.find(pair.second) != used_set.end())
625                                 new_map[pair.first] = pair.second;
626                 }
627
628                 used_set.clear();
629                 b_recalc.clear();
630                 b_map = new_map;
631
632                 return deleted;
633         }
634
635 protected:
636         vector<T*> *scene_data;
637         map<K, T*> b_map;
638         set<T*> used_set;
639         set<void*> b_recalc;
640 };
641
642 /* Object Key */
643
644 enum { OBJECT_PERSISTENT_ID_SIZE = 8 };
645
646 struct ObjectKey {
647         void *parent;
648         int id[OBJECT_PERSISTENT_ID_SIZE];
649         void *ob;
650
651         ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_)
652         : parent(parent_), ob(ob_)
653         {
654                 if(id_)
655                         memcpy(id, id_, sizeof(id));
656                 else
657                         memset(id, 0, sizeof(id));
658         }
659
660         bool operator<(const ObjectKey& k) const
661         {
662                 if(ob < k.ob) {
663                         return true;
664                 }
665                 else if(ob == k.ob) {
666                         if(parent < k.parent)
667                                 return true;
668                         else if(parent == k.parent)
669                                 return memcmp(id, k.id, sizeof(id)) < 0;
670                 }
671
672                 return false;
673         }
674 };
675
676 /* Particle System Key */
677
678 struct ParticleSystemKey {
679         void *ob;
680         int id[OBJECT_PERSISTENT_ID_SIZE];
681
682         ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE])
683         : ob(ob_)
684         {
685                 if(id_)
686                         memcpy(id, id_, sizeof(id));
687                 else
688                         memset(id, 0, sizeof(id));
689         }
690
691         bool operator<(const ParticleSystemKey& k) const
692         {
693                 /* first id is particle index, we don't compare that */
694                 if(ob < k.ob)
695                         return true;
696                 else if(ob == k.ob)
697                         return memcmp(id+1, k.id+1, sizeof(int)*(OBJECT_PERSISTENT_ID_SIZE-1)) < 0;
698
699                 return false;
700         }
701 };
702
703 CCL_NAMESPACE_END
704
705 #endif /* __BLENDER_UTIL_H__ */
706