Cycles: merge of changes from tomato branch.
[blender-staging.git] / intern / cycles / blender / blender_object.cpp
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 #include "camera.h"
20 #include "graph.h"
21 #include "light.h"
22 #include "mesh.h"
23 #include "object.h"
24 #include "scene.h"
25 #include "nodes.h"
26 #include "shader.h"
27
28 #include "blender_sync.h"
29 #include "blender_util.h"
30
31 #include "util_foreach.h"
32 #include "util_hash.h"
33
34 CCL_NAMESPACE_BEGIN
35
36 /* Utilities */
37
38 bool BlenderSync::BKE_object_is_modified(BL::Object b_ob)
39 {
40         /* test if we can instance or if the object is modified */
41         if(ccl::BKE_object_is_modified(b_ob, b_scene, preview)) {
42                 /* modifiers */
43                 return true;
44         }
45         else {
46                 /* object level material links */
47                 BL::Object::material_slots_iterator slot;
48                 for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
49                         if(slot->link() == BL::MaterialSlot::link_OBJECT)
50                                 return true;
51         }
52
53         return false;
54 }
55
56 bool BlenderSync::object_is_mesh(BL::Object b_ob)
57 {
58         BL::ID b_ob_data = b_ob.data();
59
60         return (b_ob_data && (b_ob_data.is_a(&RNA_Mesh) ||
61                 b_ob_data.is_a(&RNA_Curve) || b_ob_data.is_a(&RNA_MetaBall)));
62 }
63
64 bool BlenderSync::object_is_light(BL::Object b_ob)
65 {
66         BL::ID b_ob_data = b_ob.data();
67
68         return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
69 }
70
71 static uint object_ray_visibility(BL::Object b_ob)
72 {
73         PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
74         uint flag = 0;
75
76         flag |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0;
77         flag |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0;
78         flag |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0;
79         flag |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0;
80         flag |= get_boolean(cvisibility, "shadow")? PATH_RAY_SHADOW: 0;
81
82         return flag;
83 }
84
85 /* Light */
86
87 void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm)
88 {
89         /* test if we need to sync */
90         Light *light;
91         ObjectKey key(b_parent, b_index, b_ob);
92
93         if(!light_map.sync(&light, b_ob, b_parent, key))
94                 return;
95         
96         BL::Lamp b_lamp(b_ob.data());
97
98         /* type */
99         switch(b_lamp.type()) {
100                 case BL::Lamp::type_POINT: {
101                         BL::PointLamp b_point_lamp(b_lamp);
102                         light->size = b_point_lamp.shadow_soft_size();
103                         light->type = LIGHT_POINT;
104                         break;
105                 }
106                 case BL::Lamp::type_SPOT: {
107                         BL::SpotLamp b_spot_lamp(b_lamp);
108                         light->size = b_spot_lamp.shadow_soft_size();
109                         light->type = LIGHT_SPOT;
110                         light->spot_angle = b_spot_lamp.spot_size();
111                         light->spot_smooth = b_spot_lamp.spot_blend();
112                         break;
113                 }
114                 case BL::Lamp::type_HEMI: {
115                         light->type = LIGHT_DISTANT;
116                         light->size = 0.0f;
117                         break;
118                 }
119                 case BL::Lamp::type_SUN: {
120                         BL::SunLamp b_sun_lamp(b_lamp);
121                         light->size = b_sun_lamp.shadow_soft_size();
122                         light->type = LIGHT_DISTANT;
123                         break;
124                 }
125                 case BL::Lamp::type_AREA: {
126                         BL::AreaLamp b_area_lamp(b_lamp);
127                         light->size = 1.0f;
128                         light->axisu = make_float3(tfm.x.x, tfm.y.x, tfm.z.x);
129                         light->axisv = make_float3(tfm.x.y, tfm.y.y, tfm.z.y);
130                         light->sizeu = b_area_lamp.size();
131                         if(b_area_lamp.shape() == BL::AreaLamp::shape_RECTANGLE)
132                                 light->sizev = b_area_lamp.size_y();
133                         else
134                                 light->sizev = light->sizeu;
135                         light->type = LIGHT_AREA;
136                         break;
137                 }
138         }
139
140         /* location and (inverted!) direction */
141         light->co = make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
142         light->dir = -make_float3(tfm.x.z, tfm.y.z, tfm.z.z);
143
144         /* shader */
145         vector<uint> used_shaders;
146
147         find_shader(b_lamp, used_shaders, scene->default_light);
148
149         if(used_shaders.size() == 0)
150                 used_shaders.push_back(scene->default_light);
151
152         light->shader = used_shaders[0];
153
154         /* shadow */
155         PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
156         light->cast_shadow = get_boolean(clamp, "cast_shadow");
157         light->samples = get_int(clamp, "samples");
158
159         /* tag */
160         light->tag_update(scene);
161 }
162
163 void BlenderSync::sync_background_light()
164 {
165         BL::World b_world = b_scene.world();
166
167         if(b_world) {
168                 PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
169                 bool sample_as_light = get_boolean(cworld, "sample_as_light");
170
171                 if(sample_as_light) {
172                         /* test if we need to sync */
173                         Light *light;
174                         ObjectKey key(b_world, 0, b_world);
175
176                         if(light_map.sync(&light, b_world, b_world, key) ||
177                            world_recalc ||
178                            b_world.ptr.data != world_map)
179                         {
180                                 light->type = LIGHT_BACKGROUND;
181                                 light->map_resolution  = get_int(cworld, "sample_map_resolution");
182                                 light->samples  = get_int(cworld, "samples");
183                                 light->shader = scene->default_background;
184
185                                 light->tag_update(scene);
186                                 light_map.set_recalc(b_world);
187                         }
188                 }
189         }
190
191         world_map = b_world.ptr.data;
192         world_recalc = false;
193 }
194
195 /* Object */
196
197 void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint layer_flag, int motion, int particle_id)
198 {
199         /* light is handled separately */
200         if(object_is_light(b_ob)) {
201                 if(!motion)
202                         sync_light(b_parent, b_index, b_ob, tfm);
203                 return;
204         }
205
206         /* only interested in object that we can create meshes from */
207         if(!object_is_mesh(b_ob))
208                 return;
209
210         /* key to lookup object */
211         ObjectKey key(b_parent, b_index, b_ob);
212         Object *object;
213
214         /* motion vector case */
215         if(motion) {
216                 object = object_map.find(key);
217
218                 if(object) {
219                         if(tfm != object->tfm) {
220                                 if(motion == -1)
221                                         object->motion.pre = tfm;
222                                 else
223                                         object->motion.post = tfm;
224
225                                 object->use_motion = true;
226                         }
227
228                         sync_mesh_motion(b_ob, object->mesh, motion);
229                 }
230
231                 return;
232         }
233
234         /* test if we need to sync */
235         bool object_updated = false;
236
237         if(object_map.sync(&object, b_ob, b_parent, key))
238                 object_updated = true;
239         
240         bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
241         
242         /* mesh sync */
243         object->mesh = sync_mesh(b_ob, object_updated);
244
245         if(use_holdout != object->use_holdout) {
246                 object->use_holdout = use_holdout;
247                 scene->object_manager->tag_update(scene);
248         }
249
250         /* object sync */
251         /* transform comparison should not be needed, but duplis don't work perfect
252          * in the depsgraph and may not signal changes, so this is a workaround */
253         if(object_updated || (object->mesh && object->mesh->need_update) || tfm != object->tfm) {
254                 object->name = b_ob.name().c_str();
255                 object->pass_id = b_ob.pass_index();
256                 object->tfm = tfm;
257                 object->motion.pre = tfm;
258                 object->motion.post = tfm;
259                 object->use_motion = false;
260
261                 object->random_id = hash_int_2d(hash_string(object->name.c_str()), b_index);
262
263                 /* visibility flags for both parent */
264                 object->visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL;
265                 if(b_parent.ptr.data != b_ob.ptr.data) {
266                         object->visibility &= object_ray_visibility(b_parent);
267                         object->random_id ^= hash_int(hash_string(b_parent.name().c_str()));
268                 }
269
270                 /* camera flag is not actually used, instead is tested
271                  * against render layer flags */
272                 if(object->visibility & PATH_RAY_CAMERA) {
273                         object->visibility |= layer_flag << PATH_RAY_LAYER_SHIFT;
274                         object->visibility &= ~PATH_RAY_CAMERA;
275                 }
276
277                 object->particle_id = particle_id;
278
279                 object->tag_update(scene);
280         }
281 }
282
283 /* Object Loop */
284
285 void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion)
286 {
287         /* layer data */
288         uint scene_layer = render_layer.scene_layer;
289         
290         if(!motion) {
291                 /* prepare for sync */
292                 light_map.pre_sync();
293                 mesh_map.pre_sync();
294                 object_map.pre_sync();
295                 mesh_synced.clear();
296         }
297
298         /* object loop */
299         BL::Scene::objects_iterator b_ob;
300         BL::Scene b_sce = b_scene;
301         int particle_offset = 1;        /* first particle is dummy for regular, non-instanced objects */
302
303         bool cancel = false;
304
305         for(; b_sce && !cancel; b_sce = b_sce.background_set()) {
306                 for(b_sce.objects.begin(b_ob); b_ob != b_sce.objects.end() && !cancel; ++b_ob) {
307                         bool hide = (render_layer.use_viewport_visibility)? b_ob->hide(): b_ob->hide_render();
308                         uint ob_layer = get_layer(b_ob->layers(), b_ob->layers_local_view(), render_layer.use_localview, object_is_light(*b_ob));
309                         hide = hide || !(ob_layer & scene_layer);
310
311                         if(!hide) {
312                                 progress.set_status("Synchronizing object", (*b_ob).name());
313
314                                 int num_particles = object_count_particles(*b_ob);
315
316                                 if(b_ob->is_duplicator()) {
317                                         hide = true;    /* duplicators hidden by default */
318
319                                         /* dupli objects */
320                                         object_create_duplilist(*b_ob, b_scene);
321
322                                         BL::Object::dupli_list_iterator b_dup;
323                                         int b_index = 0;
324
325                                         for(b_ob->dupli_list.begin(b_dup); b_dup != b_ob->dupli_list.end(); ++b_dup) {
326                                                 Transform tfm = get_transform(b_dup->matrix());
327                                                 BL::Object b_dup_ob = b_dup->object();
328                                                 bool dup_hide = (b_v3d)? b_dup_ob.hide(): b_dup_ob.hide_render();
329
330                                                 if(!(b_dup->hide() || dup_hide)) {
331                                                         sync_object(*b_ob, b_index, b_dup_ob, tfm, ob_layer, motion, b_dup->particle_index() + particle_offset);
332                                                 }
333                                                 
334                                                 ++b_index;
335                                         }
336
337                                         object_free_duplilist(*b_ob);
338                                 }
339
340                                 /* check if we should render or hide particle emitter */
341                                 BL::Object::particle_systems_iterator b_psys;
342                                 for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
343                                         if(b_psys->settings().use_render_emitter())
344                                                 hide = false;
345
346                                 if(!hide) {
347                                         /* object itself */
348                                         Transform tfm = get_transform(b_ob->matrix_world());
349                                         sync_object(*b_ob, 0, *b_ob, tfm, ob_layer, motion, 0);
350                                 }
351
352                                 particle_offset += num_particles;
353                         }
354
355                         cancel = progress.get_cancel();
356                 }
357         }
358
359         if(!cancel && !motion) {
360                 sync_background_light();
361
362                 /* handle removed data and modified pointers */
363                 if(light_map.post_sync())
364                         scene->light_manager->tag_update(scene);
365                 if(mesh_map.post_sync())
366                         scene->mesh_manager->tag_update(scene);
367                 if(object_map.post_sync())
368                         scene->object_manager->tag_update(scene);
369                 mesh_synced.clear();
370         }
371 }
372
373 void BlenderSync::sync_motion(BL::SpaceView3D b_v3d, BL::Object b_override)
374 {
375         if(scene->need_motion() == Scene::MOTION_NONE)
376                 return;
377
378         /* get camera object here to deal with camera switch */
379         BL::Object b_cam = b_scene.camera();
380         if(b_override)
381                 b_cam = b_override;
382
383         /* go back and forth one frame */
384         int frame = b_scene.frame_current();
385
386         for(int motion = -1; motion <= 1; motion += 2) {
387                 scene_frame_set(b_scene, frame + motion);
388
389                 /* camera object */
390                 if(b_cam)
391                         sync_camera_motion(b_cam, motion);
392
393                 /* mesh objects */
394                 sync_objects(b_v3d, motion);
395         }
396
397         scene_frame_set(b_scene, frame);
398 }
399
400 CCL_NAMESPACE_END
401