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