Alembic: quiet compilation warnings on Windows.
[blender.git] / intern / cycles / blender / blender_object.cpp
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 #include "camera.h"
18 #include "integrator.h"
19 #include "graph.h"
20 #include "light.h"
21 #include "mesh.h"
22 #include "object.h"
23 #include "scene.h"
24 #include "nodes.h"
25 #include "particles.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 #include "util_logging.h"
34
35 CCL_NAMESPACE_BEGIN
36
37 /* Utilities */
38
39 bool BlenderSync::BKE_object_is_modified(BL::Object& b_ob)
40 {
41         /* test if we can instance or if the object is modified */
42         if(b_ob.type() == BL::Object::type_META) {
43                 /* multi-user and dupli metaballs are fused, can't instance */
44                 return true;
45         }
46         else if(ccl::BKE_object_is_modified(b_ob, b_scene, preview)) {
47                 /* modifiers */
48                 return true;
49         }
50         else {
51                 /* object level material links */
52                 BL::Object::material_slots_iterator slot;
53                 for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
54                         if(slot->link() == BL::MaterialSlot::link_OBJECT)
55                                 return true;
56         }
57
58         return false;
59 }
60
61 bool BlenderSync::object_is_mesh(BL::Object& b_ob)
62 {
63         BL::ID b_ob_data = b_ob.data();
64
65         return (b_ob_data && (b_ob_data.is_a(&RNA_Mesh) ||
66                 b_ob_data.is_a(&RNA_Curve) || b_ob_data.is_a(&RNA_MetaBall)));
67 }
68
69 bool BlenderSync::object_is_light(BL::Object& b_ob)
70 {
71         BL::ID b_ob_data = b_ob.data();
72
73         return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
74 }
75
76 static uint object_ray_visibility(BL::Object& b_ob)
77 {
78         PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
79         uint flag = 0;
80
81         flag |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0;
82         flag |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0;
83         flag |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0;
84         flag |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0;
85         flag |= get_boolean(cvisibility, "shadow")? PATH_RAY_SHADOW: 0;
86         flag |= get_boolean(cvisibility, "scatter")? PATH_RAY_VOLUME_SCATTER: 0;
87
88         return flag;
89 }
90
91 /* Culling */
92
93 class BlenderObjectCulling
94 {
95 public:
96         BlenderObjectCulling(Scene *scene, BL::Scene& b_scene)
97         : use_scene_camera_cull(false),
98           use_camera_cull(false),
99           camera_cull_margin(0.0f),
100           use_scene_distance_cull(false),
101           use_distance_cull(false),
102           distance_cull_margin(0.0f)
103         {
104                 if(b_scene.render().use_simplify()) {
105                         PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
106
107                         use_scene_camera_cull = scene->camera->type != CAMERA_PANORAMA &&
108                                                                         !b_scene.render().use_multiview() &&
109                                                                         get_boolean(cscene, "use_camera_cull");
110                         use_scene_distance_cull = scene->camera->type != CAMERA_PANORAMA &&
111                                                                           !b_scene.render().use_multiview() &&
112                                                                           get_boolean(cscene, "use_distance_cull");
113
114                         camera_cull_margin = get_float(cscene, "camera_cull_margin");
115                         distance_cull_margin = get_float(cscene, "distance_cull_margin");
116
117                         if (distance_cull_margin == 0.0f) {
118                                 use_scene_distance_cull = false;
119                         }
120                 }
121         }
122
123         void init_object(Scene *scene, BL::Object& b_ob)
124         {
125                 if(!use_scene_camera_cull && !use_scene_distance_cull) {
126                         return;
127                 }
128
129                 PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
130
131                 use_camera_cull = use_scene_camera_cull && get_boolean(cobject, "use_camera_cull");
132                 use_distance_cull = use_scene_distance_cull && get_boolean(cobject, "use_distance_cull");
133
134                 if(use_camera_cull || use_distance_cull) {
135                         /* Need to have proper projection matrix. */
136                         scene->camera->update();
137                 }
138         }
139
140         bool test(Scene *scene, BL::Object& b_ob, Transform& tfm)
141         {
142                 if(!use_camera_cull && !use_distance_cull) {
143                         return false;
144                 }
145
146                 /* Compute world space bounding box corners. */
147                 float3 bb[8];
148                 BL::Array<float, 24> boundbox = b_ob.bound_box();
149                 for(int i = 0; i < 8; ++i) {
150                         float3 p = make_float3(boundbox[3 * i + 0],
151                                                                    boundbox[3 * i + 1],
152                                                                    boundbox[3 * i + 2]);
153                         bb[i] = transform_point(&tfm, p);
154                 }
155
156                 bool camera_culled = use_camera_cull && test_camera(scene, bb);
157                 bool distance_culled = use_distance_cull && test_distance(scene, bb);
158
159                 return ((camera_culled && distance_culled) ||
160                         (camera_culled && !use_distance_cull) ||
161                         (distance_culled && !use_camera_cull));
162         }
163
164 private:
165         /* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order
166          * to reduce number of objects which are wrongly considered visible.
167          */
168         bool test_camera(Scene *scene, float3 bb[8])
169         {
170                 Camera *cam = scene->camera;
171                 Transform& worldtondc = cam->worldtondc;
172                 float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
173                            bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
174                 bool all_behind = true;
175                 for(int i = 0; i < 8; ++i) {
176                         float3 p = bb[i];
177                         float4 b = make_float4(p.x, p.y, p.z, 1.0f);
178                         float4 c = make_float4(dot(worldtondc.x, b),
179                                                dot(worldtondc.y, b),
180                                                dot(worldtondc.z, b),
181                                                dot(worldtondc.w, b));
182                         p = float4_to_float3(c / c.w);
183                         if(c.z < 0.0f) {
184                                 p.x = 1.0f - p.x;
185                                 p.y = 1.0f - p.y;
186                         }
187                         if(c.z >= -camera_cull_margin) {
188                                 all_behind = false;
189                         }
190                         bb_min = min(bb_min, p);
191                         bb_max = max(bb_max, p);
192                 }
193                 if(all_behind) {
194                         return true;
195                 }
196                 return (bb_min.x >= 1.0f + camera_cull_margin ||
197                         bb_min.y >= 1.0f + camera_cull_margin ||
198                         bb_max.x <= -camera_cull_margin ||
199                         bb_max.y <= -camera_cull_margin);
200         }
201
202         bool test_distance(Scene *scene, float3 bb[8])
203         {
204                 float3 camera_position = transform_get_column(&scene->camera->matrix, 3);
205                 float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
206                            bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
207
208                 /* Find min & max points for x & y & z on bounding box */
209                 for(int i = 0; i < 8; ++i) {
210                         float3 p = bb[i];
211                         bb_min = min(bb_min, p);
212                         bb_max = max(bb_max, p);
213                 }
214
215                 float3 closest_point = max(min(bb_max,camera_position),bb_min);
216                 return (len_squared(camera_position - closest_point) >
217                         distance_cull_margin * distance_cull_margin);
218         }
219
220         bool use_scene_camera_cull;
221         bool use_camera_cull;
222         float camera_cull_margin;
223         bool use_scene_distance_cull;
224         bool use_distance_cull;
225         float distance_cull_margin;
226 };
227
228 /* Light */
229
230 void BlenderSync::sync_light(BL::Object& b_parent,
231                              int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
232                              BL::Object& b_ob,
233                              Transform& tfm,
234                              bool *use_portal)
235 {
236         /* test if we need to sync */
237         Light *light;
238         ObjectKey key(b_parent, persistent_id, b_ob);
239
240         if(!light_map.sync(&light, b_ob, b_parent, key)) {
241                 if(light->is_portal)
242                         *use_portal = true;
243                 return;
244         }
245         
246         BL::Lamp b_lamp(b_ob.data());
247
248         /* type */
249         switch(b_lamp.type()) {
250                 case BL::Lamp::type_POINT: {
251                         BL::PointLamp b_point_lamp(b_lamp);
252                         light->size = b_point_lamp.shadow_soft_size();
253                         light->type = LIGHT_POINT;
254                         break;
255                 }
256                 case BL::Lamp::type_SPOT: {
257                         BL::SpotLamp b_spot_lamp(b_lamp);
258                         light->size = b_spot_lamp.shadow_soft_size();
259                         light->type = LIGHT_SPOT;
260                         light->spot_angle = b_spot_lamp.spot_size();
261                         light->spot_smooth = b_spot_lamp.spot_blend();
262                         break;
263                 }
264                 case BL::Lamp::type_HEMI: {
265                         light->type = LIGHT_DISTANT;
266                         light->size = 0.0f;
267                         break;
268                 }
269                 case BL::Lamp::type_SUN: {
270                         BL::SunLamp b_sun_lamp(b_lamp);
271                         light->size = b_sun_lamp.shadow_soft_size();
272                         light->type = LIGHT_DISTANT;
273                         break;
274                 }
275                 case BL::Lamp::type_AREA: {
276                         BL::AreaLamp b_area_lamp(b_lamp);
277                         light->size = 1.0f;
278                         light->axisu = transform_get_column(&tfm, 0);
279                         light->axisv = transform_get_column(&tfm, 1);
280                         light->sizeu = b_area_lamp.size();
281                         if(b_area_lamp.shape() == BL::AreaLamp::shape_RECTANGLE)
282                                 light->sizev = b_area_lamp.size_y();
283                         else
284                                 light->sizev = light->sizeu;
285                         light->type = LIGHT_AREA;
286                         break;
287                 }
288         }
289
290         /* location and (inverted!) direction */
291         light->co = transform_get_column(&tfm, 3);
292         light->dir = -transform_get_column(&tfm, 2);
293         light->tfm = tfm;
294
295         /* shader */
296         vector<Shader*> used_shaders;
297         find_shader(b_lamp, used_shaders, scene->default_light);
298         light->shader = used_shaders[0];
299
300         /* shadow */
301         PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
302         PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
303         light->cast_shadow = get_boolean(clamp, "cast_shadow");
304         light->use_mis = get_boolean(clamp, "use_multiple_importance_sampling");
305         
306         int samples = get_int(clamp, "samples");
307         if(get_boolean(cscene, "use_square_samples"))
308                 light->samples = samples * samples;
309         else
310                 light->samples = samples;
311
312         light->max_bounces = get_int(clamp, "max_bounces");
313
314         if(light->type == LIGHT_AREA)
315                 light->is_portal = get_boolean(clamp, "is_portal");
316         else
317                 light->is_portal = false;
318
319         if(light->is_portal)
320                 *use_portal = true;
321
322         /* visibility */
323         uint visibility = object_ray_visibility(b_ob);
324         light->use_diffuse = (visibility & PATH_RAY_DIFFUSE) != 0;
325         light->use_glossy = (visibility & PATH_RAY_GLOSSY) != 0;
326         light->use_transmission = (visibility & PATH_RAY_TRANSMIT) != 0;
327         light->use_scatter = (visibility & PATH_RAY_VOLUME_SCATTER) != 0;
328
329         /* tag */
330         light->tag_update(scene);
331 }
332
333 void BlenderSync::sync_background_light(bool use_portal)
334 {
335         BL::World b_world = b_scene.world();
336
337         if(b_world) {
338                 PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
339                 PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
340                 bool sample_as_light = get_boolean(cworld, "sample_as_light");
341
342                 if(sample_as_light || use_portal) {
343                         /* test if we need to sync */
344                         Light *light;
345                         ObjectKey key(b_world, 0, b_world);
346
347                         if(light_map.sync(&light, b_world, b_world, key) ||
348                             world_recalc ||
349                             b_world.ptr.data != world_map)
350                         {
351                                 light->type = LIGHT_BACKGROUND;
352                                 light->map_resolution  = get_int(cworld, "sample_map_resolution");
353                                 light->shader = scene->default_background;
354                                 light->use_mis = sample_as_light;
355                                 light->max_bounces = get_int(cworld, "max_bounces");
356
357                                 int samples = get_int(cworld, "samples");
358                                 if(get_boolean(cscene, "use_square_samples"))
359                                         light->samples = samples * samples;
360                                 else
361                                         light->samples = samples;
362
363                                 light->tag_update(scene);
364                                 light_map.set_recalc(b_world);
365                         }
366                 }
367         }
368
369         world_map = b_world.ptr.data;
370         world_recalc = false;
371 }
372
373 /* Object */
374
375 Object *BlenderSync::sync_object(BL::Object& b_parent,
376                                  int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
377                                  BL::DupliObject& b_dupli_ob,
378                                  Transform& tfm,
379                                  uint layer_flag,
380                                  float motion_time,
381                                  bool hide_tris,
382                                  BlenderObjectCulling& culling,
383                                  bool *use_portal)
384 {
385         BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
386         bool motion = motion_time != 0.0f;
387         
388         /* light is handled separately */
389         if(object_is_light(b_ob)) {
390                 /* don't use lamps for excluded layers used as mask layer */
391                 if(!motion && !((layer_flag & render_layer.holdout_layer) && (layer_flag & render_layer.exclude_layer)))
392                         sync_light(b_parent, persistent_id, b_ob, tfm, use_portal);
393
394                 return NULL;
395         }
396
397         /* only interested in object that we can create meshes from */
398         if(!object_is_mesh(b_ob)) {
399                 return NULL;
400         }
401
402         /* Perform object culling. */
403         if(culling.test(scene, b_ob, tfm)) {
404                 return NULL;
405         }
406
407         /* key to lookup object */
408         ObjectKey key(b_parent, persistent_id, b_ob);
409         Object *object;
410
411         /* motion vector case */
412         if(motion) {
413                 object = object_map.find(key);
414
415                 if(object && (scene->need_motion() == Scene::MOTION_PASS ||
416                               object_use_motion(b_parent, b_ob)))
417                 {
418                         /* object transformation */
419                         if(tfm != object->tfm) {
420                                 VLOG(1) << "Object " << b_ob.name() << " motion detected.";
421                                 if(motion_time == -1.0f || motion_time == 1.0f) {
422                                         object->use_motion = true;
423                                 }
424                         }
425
426                         if(motion_time == -1.0f) {
427                                 object->motion.pre = tfm;
428                         }
429                         else if(motion_time == 1.0f) {
430                                 object->motion.post = tfm;
431                         }
432
433                         /* mesh deformation */
434                         if(object->mesh)
435                                 sync_mesh_motion(b_ob, object, motion_time);
436                 }
437
438                 return object;
439         }
440
441         /* test if we need to sync */
442         bool object_updated = false;
443
444         if(object_map.sync(&object, b_ob, b_parent, key))
445                 object_updated = true;
446         
447         bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
448         
449         /* mesh sync */
450         object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
451
452         /* special case not tracked by object update flags */
453
454         /* holdout */
455         if(use_holdout != object->use_holdout) {
456                 object->use_holdout = use_holdout;
457                 scene->object_manager->tag_update(scene);
458                 object_updated = true;
459         }
460
461         /* visibility flags for both parent and child */
462         uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY;
463         if(b_parent.ptr.data != b_ob.ptr.data) {
464                 visibility &= object_ray_visibility(b_parent);
465         }
466
467         /* make holdout objects on excluded layer invisible for non-camera rays */
468         if(use_holdout && (layer_flag & render_layer.exclude_layer)) {
469                 visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA);
470         }
471
472         /* hide objects not on render layer from camera rays */
473         if(!(layer_flag & render_layer.layer)) {
474                 visibility &= ~PATH_RAY_CAMERA;
475         }
476
477         if(visibility != object->visibility) {
478                 object->visibility = visibility;
479                 object_updated = true;
480         }
481
482         /* object sync
483          * transform comparison should not be needed, but duplis don't work perfect
484          * in the depsgraph and may not signal changes, so this is a workaround */
485         if(object_updated || (object->mesh && object->mesh->need_update) || tfm != object->tfm) {
486                 object->name = b_ob.name().c_str();
487                 object->pass_id = b_ob.pass_index();
488                 object->tfm = tfm;
489                 object->motion.pre = transform_empty();
490                 object->motion.post = transform_empty();
491                 object->use_motion = false;
492
493                 /* motion blur */
494                 if(scene->need_motion() == Scene::MOTION_BLUR && object->mesh) {
495                         Mesh *mesh = object->mesh;
496
497                         mesh->use_motion_blur = false;
498
499                         if(object_use_motion(b_parent, b_ob)) {
500                                 if(object_use_deform_motion(b_parent, b_ob)) {
501                                         mesh->motion_steps = object_motion_steps(b_ob);
502                                         mesh->use_motion_blur = true;
503                                 }
504
505                                 vector<float> times = object->motion_times();
506                                 foreach(float time, times)
507                                         motion_times.insert(time);
508                         }
509                 }
510
511                 /* random number */
512                 object->random_id = hash_string(object->name.c_str());
513
514                 if(persistent_id) {
515                         for(int i = 0; i < OBJECT_PERSISTENT_ID_SIZE; i++)
516                                 object->random_id = hash_int_2d(object->random_id, persistent_id[i]);
517                 }
518                 else
519                         object->random_id = hash_int_2d(object->random_id, 0);
520
521                 if(b_parent.ptr.data != b_ob.ptr.data)
522                         object->random_id ^= hash_int(hash_string(b_parent.name().c_str()));
523
524                 /* dupli texture coordinates */
525                 if(b_dupli_ob) {
526                         object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f);
527                         object->dupli_uv = get_float2(b_dupli_ob.uv());
528                 }
529                 else {
530                         object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f);
531                         object->dupli_uv = make_float2(0.0f, 0.0f);
532                 }
533
534                 object->tag_update(scene);
535         }
536
537         return object;
538 }
539
540 static bool object_render_hide_original(BL::Object::type_enum ob_type,
541                                         BL::Object::dupli_type_enum dupli_type)
542 {
543         /* metaball exception, they duplicate self */
544         if(ob_type == BL::Object::type_META)
545                 return false;
546
547         return (dupli_type == BL::Object::dupli_type_VERTS ||
548                 dupli_type == BL::Object::dupli_type_FACES ||
549                 dupli_type == BL::Object::dupli_type_FRAMES);
550 }
551
552 static bool object_render_hide(BL::Object& b_ob,
553                                bool top_level,
554                                bool parent_hide,
555                                bool& hide_triangles)
556 {
557         /* check if we should render or hide particle emitter */
558         BL::Object::particle_systems_iterator b_psys;
559
560         bool hair_present = false;
561         bool show_emitter = false;
562         bool hide_emitter = false;
563         bool hide_as_dupli_parent = false;
564         bool hide_as_dupli_child_original = false;
565
566         for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) {
567                 if((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) &&
568                    (b_psys->settings().type()==BL::ParticleSettings::type_HAIR))
569                         hair_present = true;
570
571                 if(b_psys->settings().use_render_emitter())
572                         show_emitter = true;
573                 else
574                         hide_emitter = true;
575         }
576
577         if(show_emitter)
578                 hide_emitter = false;
579
580         /* duplicators hidden by default, except dupliframes which duplicate self */
581         if(b_ob.is_duplicator())
582                 if(top_level || b_ob.dupli_type() != BL::Object::dupli_type_FRAMES)
583                         hide_as_dupli_parent = true;
584
585         /* hide original object for duplis */
586         BL::Object parent = b_ob.parent();
587         while(parent) {
588                 if(object_render_hide_original(b_ob.type(),
589                                                parent.dupli_type()))
590                 {
591                         if(parent_hide) {
592                                 hide_as_dupli_child_original = true;
593                                 break;
594                         }
595                 }
596                 parent = parent.parent();
597         }
598         
599         hide_triangles = hide_emitter;
600
601         if(show_emitter) {
602                 return false;
603         }
604         else if(hair_present) {
605                 return hide_as_dupli_child_original;
606         }
607         else {
608                 return (hide_as_dupli_parent || hide_as_dupli_child_original);
609         }
610 }
611
612 static bool object_render_hide_duplis(BL::Object& b_ob)
613 {
614         BL::Object parent = b_ob.parent();
615
616         return (parent && object_render_hide_original(b_ob.type(), parent.dupli_type()));
617 }
618
619 /* Object Loop */
620
621 void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time)
622 {
623         /* layer data */
624         uint scene_layer = render_layer.scene_layer;
625         bool motion = motion_time != 0.0f;
626         
627         if(!motion) {
628                 /* prepare for sync */
629                 light_map.pre_sync();
630                 mesh_map.pre_sync();
631                 object_map.pre_sync();
632                 particle_system_map.pre_sync();
633                 motion_times.clear();
634         }
635         else {
636                 mesh_motion_synced.clear();
637         }
638
639         /* initialize culling */
640         BlenderObjectCulling culling(scene, b_scene);
641
642         /* object loop */
643         BL::Scene::object_bases_iterator b_base;
644         BL::Scene b_sce = b_scene;
645         /* modifier result type (not exposed as enum in C++ API)
646          * 1 : DAG_EVAL_PREVIEW
647          * 2 : DAG_EVAL_RENDER
648          */
649         int dupli_settings = preview ? 1 : 2;
650
651         bool cancel = false;
652         bool use_portal = false;
653
654         uint layer_override = get_layer(b_engine.layer_override());
655         for(; b_sce && !cancel; b_sce = b_sce.background_set()) {
656                 /* Render layer's scene_layer is affected by local view already,
657                  * which is not a desired behavior here.
658                  */
659                 uint scene_layers = layer_override ? layer_override : get_layer(b_scene.layers());
660                 for(b_sce.object_bases.begin(b_base); b_base != b_sce.object_bases.end() && !cancel; ++b_base) {
661                         BL::Object b_ob = b_base->object();
662                         bool hide = (render_layer.use_viewport_visibility)? b_ob.hide(): b_ob.hide_render();
663                         uint ob_layer = get_layer(b_base->layers(),
664                                                   b_base->layers_local_view(),
665                                                   object_is_light(b_ob),
666                                                   scene_layers);
667                         hide = hide || !(ob_layer & scene_layer);
668
669                         if(!hide) {
670                                 progress.set_sync_status("Synchronizing object", b_ob.name());
671
672                                 /* load per-object culling data */
673                                 culling.init_object(scene, b_ob);
674
675                                 if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) {
676                                         /* dupli objects */
677                                         b_ob.dupli_list_create(b_scene, dupli_settings);
678
679                                         BL::Object::dupli_list_iterator b_dup;
680
681                                         for(b_ob.dupli_list.begin(b_dup); b_dup != b_ob.dupli_list.end(); ++b_dup) {
682                                                 Transform tfm = get_transform(b_dup->matrix());
683                                                 BL::Object b_dup_ob = b_dup->object();
684                                                 bool dup_hide = (b_v3d)? b_dup_ob.hide(): b_dup_ob.hide_render();
685                                                 bool in_dupli_group = (b_dup->type() == BL::DupliObject::type_GROUP);
686                                                 bool hide_tris;
687
688                                                 if(!(b_dup->hide() || dup_hide || object_render_hide(b_dup_ob, false, in_dupli_group, hide_tris))) {
689                                                         /* the persistent_id allows us to match dupli objects
690                                                          * between frames and updates */
691                                                         BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
692
693                                                         /* sync object and mesh or light data */
694                                                         Object *object = sync_object(b_ob,
695                                                                                      persistent_id.data,
696                                                                                      *b_dup,
697                                                                                      tfm,
698                                                                                      ob_layer,
699                                                                                      motion_time,
700                                                                                      hide_tris,
701                                                                                      culling,
702                                                                                      &use_portal);
703
704                                                         /* sync possible particle data, note particle_id
705                                                          * starts counting at 1, first is dummy particle */
706                                                         if(!motion && object) {
707                                                                 sync_dupli_particle(b_ob, *b_dup, object);
708                                                         }
709
710                                                 }
711                                         }
712
713                                         b_ob.dupli_list_clear();
714                                 }
715
716                                 /* test if object needs to be hidden */
717                                 bool hide_tris;
718
719                                 if(!object_render_hide(b_ob, true, true, hide_tris)) {
720                                         /* object itself */
721                                         Transform tfm = get_transform(b_ob.matrix_world());
722                                         BL::DupliObject b_empty_dupli_ob(PointerRNA_NULL);
723                                         sync_object(b_ob,
724                                                     NULL,
725                                                     b_empty_dupli_ob,
726                                                     tfm,
727                                                     ob_layer,
728                                                     motion_time,
729                                                     hide_tris,
730                                                     culling,
731                                                     &use_portal);
732                                 }
733                         }
734
735                         cancel = progress.get_cancel();
736                 }
737         }
738
739         progress.set_sync_status("");
740
741         if(!cancel && !motion) {
742                 sync_background_light(use_portal);
743
744                 /* handle removed data and modified pointers */
745                 if(light_map.post_sync())
746                         scene->light_manager->tag_update(scene);
747                 if(mesh_map.post_sync())
748                         scene->mesh_manager->tag_update(scene);
749                 if(object_map.post_sync())
750                         scene->object_manager->tag_update(scene);
751                 if(particle_system_map.post_sync())
752                         scene->particle_system_manager->tag_update(scene);
753         }
754
755         if(motion)
756                 mesh_motion_synced.clear();
757 }
758
759 void BlenderSync::sync_motion(BL::RenderSettings& b_render,
760                               BL::SpaceView3D& b_v3d,
761                               BL::Object& b_override,
762                               int width, int height,
763                               void **python_thread_state)
764 {
765         if(scene->need_motion() == Scene::MOTION_NONE)
766                 return;
767
768         /* get camera object here to deal with camera switch */
769         BL::Object b_cam = b_scene.camera();
770         if(b_override)
771                 b_cam = b_override;
772
773         Camera prevcam = *(scene->camera);
774
775         int frame_center = b_scene.frame_current();
776         float subframe_center = b_scene.frame_subframe();
777         float frame_center_delta = 0.0f;
778
779         if(scene->need_motion() != Scene::MOTION_PASS &&
780            scene->camera->motion_position != Camera::MOTION_POSITION_CENTER)
781         {
782                 float shuttertime = scene->camera->shuttertime;
783                 if(scene->camera->motion_position == Camera::MOTION_POSITION_END) {
784                         frame_center_delta = -shuttertime * 0.5f;
785                 }
786                 else {
787                         assert(scene->camera->motion_position == Camera::MOTION_POSITION_START);
788                         frame_center_delta = shuttertime * 0.5f;
789                 }
790                 float time = frame_center + subframe_center + frame_center_delta;
791                 int frame = (int)floorf(time);
792                 float subframe = time - frame;
793                 python_thread_state_restore(python_thread_state);
794                 b_engine.frame_set(frame, subframe);
795                 python_thread_state_save(python_thread_state);
796                 sync_camera_motion(b_render, b_cam, width, height, 0.0f);
797                 sync_objects(b_v3d, 0.0f);
798         }
799
800         /* always sample these times for camera motion */
801         motion_times.insert(-1.0f);
802         motion_times.insert(1.0f);
803
804         /* note iteration over motion_times set happens in sorted order */
805         foreach(float relative_time, motion_times) {
806                 VLOG(1) << "Synchronizing motion for the relative time "
807                         << relative_time << ".";
808
809                 /* fixed shutter time to get previous and next frame for motion pass */
810                 float shuttertime = scene->motion_shutter_time();
811
812                 /* compute frame and subframe time */
813                 float time = frame_center + subframe_center + frame_center_delta + relative_time * shuttertime * 0.5f;
814                 int frame = (int)floorf(time);
815                 float subframe = time - frame;
816
817                 /* change frame */
818                 python_thread_state_restore(python_thread_state);
819                 b_engine.frame_set(frame, subframe);
820                 python_thread_state_save(python_thread_state);
821
822                 /* sync camera, only supports two times at the moment */
823                 if(relative_time == -1.0f || relative_time == 1.0f) {
824                         sync_camera_motion(b_render,
825                                            b_cam,
826                                            width, height,
827                                            relative_time);
828                 }
829
830                 /* sync object */
831                 sync_objects(b_v3d, relative_time);
832         }
833
834         /* we need to set the python thread state again because this
835          * function assumes it is being executed from python and will
836          * try to save the thread state */
837         python_thread_state_restore(python_thread_state);
838         b_engine.frame_set(frame_center, subframe_center);
839         python_thread_state_save(python_thread_state);
840
841         /* tag camera for motion update */
842         if(scene->camera->motion_modified(prevcam))
843                 scene->camera->tag_update();
844 }
845
846 CCL_NAMESPACE_END
847