RNA C++: fixes for lookup_int/lookup_string which were not working in some cases,
[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);
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 }
37
38 CCL_NAMESPACE_BEGIN
39
40 static inline BL::Mesh object_to_mesh(BL::Object self, BL::Scene scene, bool apply_modifiers, bool render)
41 {
42         return self.to_mesh(scene, apply_modifiers, (render)? 2: 1);
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 object_remove_mesh(BL::BlendData data, BL::Mesh mesh)
56 {
57         /* TODO: BlendData.meshes ideally should be also a subclass of BlendDataMeshes */
58         BL::BlendDataMeshes mesh_data(data.ptr);
59
60         mesh_data.remove(mesh);
61 }
62
63 static inline void object_create_duplilist(BL::Object self, BL::Scene scene)
64 {
65         self.dupli_list_create(scene, 2);
66 }
67
68 static inline void object_free_duplilist(BL::Object self)
69 {
70         self.dupli_list_clear();
71 }
72
73 static inline bool BKE_object_is_modified(BL::Object self, BL::Scene scene, bool preview)
74 {
75         return self.is_modified(scene, (preview)? (1<<0): (1<<1))? true: false;
76 }
77
78 static inline bool BKE_object_is_deform_modified(BL::Object self, BL::Scene scene, bool preview)
79 {
80         return self.is_deform_modified(scene, (preview)? (1<<0): (1<<1))? true: false;
81 }
82
83 static inline string image_user_file_path(BL::ImageUser iuser, BL::Image ima, int cfra)
84 {
85         char filepath[1024];
86         BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
87         BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath);
88         return string(filepath);
89 }
90
91 static inline void scene_frame_set(BL::Scene scene, int frame)
92 {
93         scene.frame_set(frame, 0.0f);
94 }
95
96 /* Utilities */
97
98 static inline Transform get_transform(BL::Array<float, 16> array)
99 {
100         Transform tfm;
101
102         /* we assume both types to be just 16 floats, and transpose because blender
103          * use column major matrix order while we use row major */
104         memcpy(&tfm, &array, sizeof(float)*16);
105         tfm = transform_transpose(tfm);
106
107         return tfm;
108 }
109
110 static inline float2 get_float2(BL::Array<float, 2> array)
111 {
112         return make_float2(array[0], array[1]);
113 }
114
115 static inline float3 get_float3(BL::Array<float, 2> array)
116 {
117         return make_float3(array[0], array[1], 0.0f);
118 }
119
120 static inline float3 get_float3(BL::Array<float, 3> array)
121 {
122         return make_float3(array[0], array[1], array[2]);
123 }
124
125 static inline float3 get_float3(BL::Array<float, 4> array)
126 {
127         return make_float3(array[0], array[1], array[2]);
128 }
129
130 static inline float4 get_float4(BL::Array<float, 4> array)
131 {
132         return make_float4(array[0], array[1], array[2], array[3]);
133 }
134
135 static inline int4 get_int4(BL::Array<int, 4> array)
136 {
137         return make_int4(array[0], array[1], array[2], array[3]);
138 }
139
140 static inline uint get_layer(BL::Array<int, 20> array)
141 {
142         uint layer = 0;
143
144         for(uint i = 0; i < 20; i++)
145                 if(array[i])
146                         layer |= (1 << i);
147         
148         return layer;
149 }
150
151 static inline uint get_layer(BL::Array<int, 20> array, BL::Array<int, 8> local_array, bool use_local, bool is_light = false)
152 {
153         uint layer = 0;
154
155         for(uint i = 0; i < 20; i++)
156                 if(array[i])
157                         layer |= (1 << i);
158
159         if(is_light) {
160                 /* consider lamps on all local view layers */
161                 for(uint i = 0; i < 8; i++)
162                         layer |= (1 << (20+i));
163         }
164         else {
165                 for(uint i = 0; i < 8; i++)
166                         if(local_array[i])
167                                 layer |= (1 << (20+i));
168         }
169
170         /* we don't have spare bits for localview (normally 20-28) because
171          * PATH_RAY_LAYER_SHIFT uses 20-32. So - check if we have localview and if
172          * so, shift local view bits down to 1-8, since this is done for the view
173          * port only - it should be OK and not conflict with render layers. */
174         if(use_local)
175                 layer >>= 20;
176
177         return layer;
178 }
179
180 #if 0
181 static inline float3 get_float3(PointerRNA& ptr, const char *name)
182 {
183         float3 f;
184         RNA_float_get_array(&ptr, name, &f.x);
185         return f;
186 }
187 #endif
188
189 static inline bool get_boolean(PointerRNA& ptr, const char *name)
190 {
191         return RNA_boolean_get(&ptr, name)? true: false;
192 }
193
194 static inline float get_float(PointerRNA& ptr, const char *name)
195 {
196         return RNA_float_get(&ptr, name);
197 }
198
199 static inline int get_int(PointerRNA& ptr, const char *name)
200 {
201         return RNA_int_get(&ptr, name);
202 }
203
204 static inline int get_enum(PointerRNA& ptr, const char *name)
205 {
206         return RNA_enum_get(&ptr, name);
207 }
208
209 static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
210 {
211         PropertyRNA *prop = RNA_struct_find_property(&ptr, name);
212         const char *identifier = "";
213         int value = RNA_property_enum_get(&ptr, prop);
214
215         RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
216
217         return string(identifier);
218 }
219
220 /* Relative Paths */
221
222 static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, const string& path)
223 {
224         if(path.size() >= 2 && path[0] == '/' && path[1] == '/') {
225                 string dirname;
226                 
227                 if(b_id.library())
228                         dirname = blender_absolute_path(b_data, b_id.library(), b_id.library().filepath());
229                 else
230                         dirname = b_data.filepath();
231
232                 return path_join(path_dirname(dirname), path.substr(2));
233         }
234
235         return path;
236 }
237
238 /* ID Map
239  *
240  * Utility class to keep in sync with blender data.
241  * Used for objects, meshes, lights and shaders. */
242
243 template<typename K, typename T>
244 class id_map {
245 public:
246         id_map(vector<T*> *scene_data_)
247         {
248                 scene_data = scene_data_;
249         }
250
251         T *find(BL::ID id)
252         {
253                 return find(id.ptr.id.data);
254         }
255
256         T *find(const K& key)
257         {
258                 if(b_map.find(key) != b_map.end()) {
259                         T *data = b_map[key];
260                         return data;
261                 }
262
263                 return NULL;
264         }
265
266         void set_recalc(BL::ID id)
267         {
268                 b_recalc.insert(id.ptr.data);
269         }
270
271         bool has_recalc()
272         {
273                 return !(b_recalc.empty());
274         }
275
276         void pre_sync()
277         {
278                 used_set.clear();
279         }
280
281         bool sync(T **r_data, BL::ID id)
282         {
283                 return sync(r_data, id, id, id.ptr.id.data);
284         }
285
286         bool sync(T **r_data, BL::ID id, BL::ID parent, const K& key)
287         {
288                 T *data = find(key);
289                 bool recalc;
290
291                 if(!data) {
292                         /* add data if it didn't exist yet */
293                         data = new T();
294                         scene_data->push_back(data);
295                         b_map[key] = data;
296                         recalc = true;
297                 }
298                 else {
299                         recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
300                         if(parent.ptr.data)
301                                 recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
302                 }
303
304                 used(data);
305
306                 *r_data = data;
307                 return recalc;
308         }
309
310         void used(T *data)
311         {
312                 /* tag data as still in use */
313                 used_set.insert(data);
314         }
315
316         void set_default(T *data)
317         {
318                 b_map[NULL] = data;
319         }
320
321         bool post_sync(bool do_delete = true)
322         {
323                 /* remove unused data */
324                 vector<T*> new_scene_data;
325                 typename vector<T*>::iterator it;
326                 bool deleted = false;
327
328                 for(it = scene_data->begin(); it != scene_data->end(); it++) {
329                         T *data = *it;
330
331                         if(do_delete && used_set.find(data) == used_set.end()) {
332                                 delete data;
333                                 deleted = true;
334                         }
335                         else
336                                 new_scene_data.push_back(data);
337                 }
338
339                 *scene_data = new_scene_data;
340
341                 /* update mapping */
342                 map<K, T*> new_map;
343                 typedef pair<const K, T*> TMapPair;
344                 typename map<K, T*>::iterator jt;
345
346                 for(jt = b_map.begin(); jt != b_map.end(); jt++) {
347                         TMapPair& pair = *jt;
348
349                         if(used_set.find(pair.second) != used_set.end())
350                                 new_map[pair.first] = pair.second;
351                 }
352
353                 used_set.clear();
354                 b_recalc.clear();
355                 b_map = new_map;
356
357                 return deleted;
358         }
359
360 protected:
361         vector<T*> *scene_data;
362         map<K, T*> b_map;
363         set<T*> used_set;
364         set<void*> b_recalc;
365 };
366
367 /* Object Key */
368
369 struct ObjectKey {
370         void *parent;
371         int index;
372         void *ob;
373
374         ObjectKey(void *parent_, int index_, void *ob_)
375         : parent(parent_), index(index_), ob(ob_) {}
376
377         bool operator<(const ObjectKey& k) const
378         { return (parent < k.parent || (parent == k.parent && (index < k.index || (index == k.index && ob < k.ob)))); }
379 };
380
381 struct ParticleSystemKey {
382         void *ob;
383         void *psys;
384
385         ParticleSystemKey(void *ob_, void *psys_)
386         : ob(ob_), psys(psys_) {}
387
388         bool operator<(const ParticleSystemKey& k) const
389         { return (ob < k.ob && psys < k.psys); }
390 };
391
392 CCL_NAMESPACE_END
393
394 #endif /* __BLENDER_UTIL_H__ */
395