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