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