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