Code cleanup: Add -Werror=float-conversion to Cycles
[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 void BLI_timestr(double _time, char *str, size_t maxlen);
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, BL::Object object, BL::Scene scene, bool apply_modifiers, bool render, bool calc_undeformed)
44 {
45         BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed);
46         if ((bool)me) {
47                 if (me.use_auto_smooth()) {
48                         me.calc_normals_split(me.auto_smooth_angle());
49                 }
50                 me.calc_tessface();
51         }
52         return me;
53 }
54
55 static inline void colorramp_to_array(BL::ColorRamp ramp, float4 *data, int size)
56 {
57         for(int i = 0; i < size; i++) {
58                 float color[4];
59
60                 ramp.evaluate((float)i/(float)(size-1), color);
61                 data[i] = make_float4(color[0], color[1], color[2], color[3]);
62         }
63 }
64
65 static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *data, int size, bool rgb_curve)
66 {
67         cumap.update();
68
69         BL::CurveMap mapR = cumap.curves[0];
70         BL::CurveMap mapG = cumap.curves[1];
71         BL::CurveMap mapB = cumap.curves[2];
72
73         if(rgb_curve) {
74                 BL::CurveMap mapI = cumap.curves[3];
75
76                 for(int i = 0; i < size; i++) {
77                         float t = (float)i/(float)(size-1);
78
79                         data[i][0] = mapR.evaluate(mapI.evaluate(t));
80                         data[i][1] = mapG.evaluate(mapI.evaluate(t));
81                         data[i][2] = mapB.evaluate(mapI.evaluate(t));
82                 }
83         }
84         else {
85                 for(int i = 0; i < size; i++) {
86                         float t = (float)i/(float)(size-1);
87
88                         data[i][0] = mapR.evaluate(t);
89                         data[i][1] = mapG.evaluate(t);
90                         data[i][2] = mapB.evaluate(t);
91                 }
92         }
93 }
94
95 static inline bool BKE_object_is_modified(BL::Object self, BL::Scene scene, bool preview)
96 {
97         return self.is_modified(scene, (preview)? (1<<0): (1<<1))? true: false;
98 }
99
100 static inline bool BKE_object_is_deform_modified(BL::Object self, BL::Scene scene, bool preview)
101 {
102         return self.is_deform_modified(scene, (preview)? (1<<0): (1<<1))? true: false;
103 }
104
105 static inline int render_resolution_x(BL::RenderSettings b_render)
106 {
107         return b_render.resolution_x()*b_render.resolution_percentage()/100;
108 }
109
110 static inline int render_resolution_y(BL::RenderSettings b_render)
111 {
112         return b_render.resolution_y()*b_render.resolution_percentage()/100;
113 }
114
115 static inline string image_user_file_path(BL::ImageUser iuser, BL::Image ima, int cfra)
116 {
117         char filepath[1024];
118         BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
119         BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath);
120         return string(filepath);
121 }
122
123 static inline int image_user_frame_number(BL::ImageUser iuser, int cfra)
124 {
125         BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
126         return iuser.frame_current();
127 }
128
129 static inline unsigned char *image_get_pixels_for_frame(BL::Image image, int frame)
130 {
131         return BKE_image_get_pixels_for_frame(image.ptr.data, frame);
132 }
133
134 static inline float *image_get_float_pixels_for_frame(BL::Image image, int frame)
135 {
136         return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame);
137 }
138
139 /* Utilities */
140
141 static inline Transform get_transform(BL::Array<float, 16> array)
142 {
143         Transform tfm;
144
145         /* we assume both types to be just 16 floats, and transpose because blender
146          * use column major matrix order while we use row major */
147         memcpy(&tfm, &array, sizeof(float)*16);
148         tfm = transform_transpose(tfm);
149
150         return tfm;
151 }
152
153 static inline float2 get_float2(BL::Array<float, 2> array)
154 {
155         return make_float2(array[0], array[1]);
156 }
157
158 static inline float3 get_float3(BL::Array<float, 2> array)
159 {
160         return make_float3(array[0], array[1], 0.0f);
161 }
162
163 static inline float3 get_float3(BL::Array<float, 3> array)
164 {
165         return make_float3(array[0], array[1], array[2]);
166 }
167
168 static inline float3 get_float3(BL::Array<float, 4> array)
169 {
170         return make_float3(array[0], array[1], array[2]);
171 }
172
173 static inline float4 get_float4(BL::Array<float, 4> array)
174 {
175         return make_float4(array[0], array[1], array[2], array[3]);
176 }
177
178 static inline int3 get_int3(BL::Array<int, 3> array)
179 {
180         return make_int3(array[0], array[1], array[2]);
181 }
182
183 static inline int4 get_int4(BL::Array<int, 4> array)
184 {
185         return make_int4(array[0], array[1], array[2], array[3]);
186 }
187
188 static inline uint get_layer(BL::Array<int, 20> array)
189 {
190         uint layer = 0;
191
192         for(uint i = 0; i < 20; i++)
193                 if(array[i])
194                         layer |= (1 << i);
195         
196         return layer;
197 }
198
199 static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_array, bool use_local, bool is_light = false)
200 {
201         uint layer = 0;
202
203         for(uint i = 0; i < 20; i++)
204                 if(array[i])
205                         layer |= (1 << i);
206
207         if(is_light) {
208                 /* consider lamps on all local view layers */
209                 for(uint i = 0; i < 8; i++)
210                         layer |= (1 << (20+i));
211         }
212         else {
213                 for(uint i = 0; i < 8; i++)
214                         if(local_array[i])
215                                 layer |= (1 << (20+i));
216         }
217
218         /* we don't have spare bits for localview (normally 20-28) because
219          * PATH_RAY_LAYER_SHIFT uses 20-32. So - check if we have localview and if
220          * so, shift local view bits down to 1-8, since this is done for the view
221          * port only - it should be OK and not conflict with render layers. */
222         if(use_local)
223                 layer >>= 20;
224
225         return layer;
226 }
227
228 static inline float3 get_float3(PointerRNA& ptr, const char *name)
229 {
230         float3 f;
231         RNA_float_get_array(&ptr, name, &f.x);
232         return f;
233 }
234
235 static inline void set_float3(PointerRNA& ptr, const char *name, float3 value)
236 {
237         RNA_float_set_array(&ptr, name, &value.x);
238 }
239
240 static inline float4 get_float4(PointerRNA& ptr, const char *name)
241 {
242         float4 f;
243         RNA_float_get_array(&ptr, name, &f.x);
244         return f;
245 }
246
247 static inline void set_float4(PointerRNA& ptr, const char *name, float4 value)
248 {
249         RNA_float_set_array(&ptr, name, &value.x);
250 }
251
252 static inline bool get_boolean(PointerRNA& ptr, const char *name)
253 {
254         return RNA_boolean_get(&ptr, name)? true: false;
255 }
256
257 static inline void set_boolean(PointerRNA& ptr, const char *name, bool value)
258 {
259         RNA_boolean_set(&ptr, name, (int)value);
260 }
261
262 static inline float get_float(PointerRNA& ptr, const char *name)
263 {
264         return RNA_float_get(&ptr, name);
265 }
266
267 static inline void set_float(PointerRNA& ptr, const char *name, float value)
268 {
269         RNA_float_set(&ptr, name, value);
270 }
271
272 static inline int get_int(PointerRNA& ptr, const char *name)
273 {
274         return RNA_int_get(&ptr, name);
275 }
276
277 static inline void set_int(PointerRNA& ptr, const char *name, int value)
278 {
279         RNA_int_set(&ptr, name, value);
280 }
281
282 static inline int get_enum(PointerRNA& ptr, const char *name)
283 {
284         return RNA_enum_get(&ptr, name);
285 }
286
287 static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
288 {
289         PropertyRNA *prop = RNA_struct_find_property(&ptr, name);
290         const char *identifier = "";
291         int value = RNA_property_enum_get(&ptr, prop);
292
293         RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
294
295         return string(identifier);
296 }
297
298 static inline void set_enum(PointerRNA& ptr, const char *name, int value)
299 {
300         RNA_enum_set(&ptr, name, value);
301 }
302
303 static inline void set_enum(PointerRNA& ptr, const char *name, const string &identifier)
304 {
305         RNA_enum_set_identifier(&ptr, name, identifier.c_str());
306 }
307
308 static inline string get_string(PointerRNA& ptr, const char *name)
309 {
310         char cstrbuf[1024];
311         char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf));
312         string str(cstr);
313         if (cstr != cstrbuf)
314                 MEM_freeN(cstr);
315         
316         return str;
317 }
318
319 static inline void set_string(PointerRNA& ptr, const char *name, const string &value)
320 {
321         RNA_string_set(&ptr, name, value.c_str());
322 }
323
324 /* Relative Paths */
325
326 static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, const string& path)
327 {
328         if(path.size() >= 2 && path[0] == '/' && path[1] == '/') {
329                 string dirname;
330                 
331                 if(b_id.library())
332                         dirname = blender_absolute_path(b_data, b_id.library(), b_id.library().filepath());
333                 else
334                         dirname = b_data.filepath();
335
336                 return path_join(path_dirname(dirname), path.substr(2));
337         }
338
339         return path;
340 }
341
342 /* Texture Space */
343
344 static inline void mesh_texture_space(BL::Mesh b_mesh, float3& loc, float3& size)
345 {
346         loc = get_float3(b_mesh.texspace_location());
347         size = get_float3(b_mesh.texspace_size());
348
349         if(size.x != 0.0f) size.x = 0.5f/size.x;
350         if(size.y != 0.0f) size.y = 0.5f/size.y;
351         if(size.z != 0.0f) size.z = 0.5f/size.z;
352
353         loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
354 }
355
356 /* object used for motion blur */
357 static inline bool object_use_motion(BL::Object b_ob)
358 {
359         PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
360         bool use_motion = get_boolean(cobject, "use_motion_blur");
361         
362         return use_motion;
363 }
364
365 /* object motion steps */
366 static inline uint object_motion_steps(BL::Object b_ob)
367 {
368         PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
369         uint steps = get_int(cobject, "motion_steps");
370
371         /* use uneven number of steps so we get one keyframe at the current frame,
372          * and ue 2^(steps - 1) so objects with more/fewer steps still have samples
373          * at the same times, to avoid sampling at many different times */
374         return (2 << (steps - 1)) + 1;
375 }
376
377 /* object uses deformation motion blur */
378 static inline bool object_use_deform_motion(BL::Object b_ob)
379 {
380         PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
381         bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
382         
383         return use_deform_motion;
384 }
385
386 static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object b_ob)
387 {
388         BL::Object::modifiers_iterator b_mod;
389
390         for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
391                 if (b_mod->is_a(&RNA_SmokeModifier)) {
392                         BL::SmokeModifier b_smd(*b_mod);
393
394                         if(b_smd.smoke_type() == BL::SmokeModifier::smoke_type_DOMAIN)
395                                 return b_smd.domain_settings();
396                 }
397         }
398         
399         return BL::SmokeDomainSettings(PointerRNA_NULL);
400 }
401
402 /* ID Map
403  *
404  * Utility class to keep in sync with blender data.
405  * Used for objects, meshes, lights and shaders. */
406
407 template<typename K, typename T>
408 class id_map {
409 public:
410         id_map(vector<T*> *scene_data_)
411         {
412                 scene_data = scene_data_;
413         }
414
415         T *find(BL::ID id)
416         {
417                 return find(id.ptr.id.data);
418         }
419
420         T *find(const K& key)
421         {
422                 if(b_map.find(key) != b_map.end()) {
423                         T *data = b_map[key];
424                         return data;
425                 }
426
427                 return NULL;
428         }
429
430         void set_recalc(BL::ID id)
431         {
432                 b_recalc.insert(id.ptr.data);
433         }
434
435         bool has_recalc()
436         {
437                 return !(b_recalc.empty());
438         }
439
440         void pre_sync()
441         {
442                 used_set.clear();
443         }
444
445         bool sync(T **r_data, BL::ID id)
446         {
447                 return sync(r_data, id, id, id.ptr.id.data);
448         }
449
450         bool sync(T **r_data, BL::ID id, BL::ID parent, const K& key)
451         {
452                 T *data = find(key);
453                 bool recalc;
454
455                 if(!data) {
456                         /* add data if it didn't exist yet */
457                         data = new T();
458                         scene_data->push_back(data);
459                         b_map[key] = data;
460                         recalc = true;
461                 }
462                 else {
463                         recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
464                         if(parent.ptr.data)
465                                 recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
466                 }
467
468                 used(data);
469
470                 *r_data = data;
471                 return recalc;
472         }
473
474         bool is_used(const K& key)
475         {
476                 T *data = find(key);
477                 return (data) ? used_set.find(data) != used_set.end() : false;
478         }
479
480         void used(T *data)
481         {
482                 /* tag data as still in use */
483                 used_set.insert(data);
484         }
485
486         void set_default(T *data)
487         {
488                 b_map[NULL] = data;
489         }
490
491         bool post_sync(bool do_delete = true)
492         {
493                 /* remove unused data */
494                 vector<T*> new_scene_data;
495                 typename vector<T*>::iterator it;
496                 bool deleted = false;
497
498                 for(it = scene_data->begin(); it != scene_data->end(); it++) {
499                         T *data = *it;
500
501                         if(do_delete && used_set.find(data) == used_set.end()) {
502                                 delete data;
503                                 deleted = true;
504                         }
505                         else
506                                 new_scene_data.push_back(data);
507                 }
508
509                 *scene_data = new_scene_data;
510
511                 /* update mapping */
512                 map<K, T*> new_map;
513                 typedef pair<const K, T*> TMapPair;
514                 typename map<K, T*>::iterator jt;
515
516                 for(jt = b_map.begin(); jt != b_map.end(); jt++) {
517                         TMapPair& pair = *jt;
518
519                         if(used_set.find(pair.second) != used_set.end())
520                                 new_map[pair.first] = pair.second;
521                 }
522
523                 used_set.clear();
524                 b_recalc.clear();
525                 b_map = new_map;
526
527                 return deleted;
528         }
529
530 protected:
531         vector<T*> *scene_data;
532         map<K, T*> b_map;
533         set<T*> used_set;
534         set<void*> b_recalc;
535 };
536
537 /* Object Key */
538
539 enum { OBJECT_PERSISTENT_ID_SIZE = 8 };
540
541 struct ObjectKey {
542         void *parent;
543         int id[OBJECT_PERSISTENT_ID_SIZE];
544         void *ob;
545
546         ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_)
547         : parent(parent_), ob(ob_)
548         {
549                 if(id_)
550                         memcpy(id, id_, sizeof(id));
551                 else
552                         memset(id, 0, sizeof(id));
553         }
554
555         bool operator<(const ObjectKey& k) const
556         {
557                 if(ob < k.ob) {
558                         return true;
559                 }
560                 else if(ob == k.ob) {
561                         if(parent < k.parent)
562                                 return true;
563                         else if(parent == k.parent)
564                                 return memcmp(id, k.id, sizeof(id)) < 0;
565                 }
566
567                 return false;
568         }
569 };
570
571 /* Particle System Key */
572
573 struct ParticleSystemKey {
574         void *ob;
575         int id[OBJECT_PERSISTENT_ID_SIZE];
576
577         ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE])
578         : ob(ob_)
579         {
580                 if(id_)
581                         memcpy(id, id_, sizeof(id));
582                 else
583                         memset(id, 0, sizeof(id));
584         }
585
586         bool operator<(const ParticleSystemKey& k) const
587         {
588                 /* first id is particle index, we don't compare that */
589                 if(ob < k.ob)
590                         return true;
591                 else if(ob == k.ob)
592                         return memcmp(id+1, k.id+1, sizeof(int)*(OBJECT_PERSISTENT_ID_SIZE-1)) < 0;
593
594                 return false;
595         }
596 };
597
598 CCL_NAMESPACE_END
599
600 #endif /* __BLENDER_UTIL_H__ */
601