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