Cycles: code refactoring, to do render layer visibility test a bit different,
[blender.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 "light.h"
20 #include "mesh.h"
21 #include "object.h"
22 #include "scene.h"
23
24 #include "blender_sync.h"
25 #include "blender_util.h"
26
27 #include "util_foreach.h"
28
29 CCL_NAMESPACE_BEGIN
30
31 /* Utilities */
32
33 bool BlenderSync::object_is_modified(BL::Object b_ob)
34 {
35         /* test if we can instance or if the object is modified */
36         if(ccl::object_is_modified(b_ob, b_scene, preview)) {
37                 /* modifiers */
38                 return true;
39         }
40         else {
41                 /* object level material links */
42                 BL::Object::material_slots_iterator slot;
43                 for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
44                         if(slot->link() == BL::MaterialSlot::link_OBJECT)
45                                 return true;
46         }
47
48         return false;
49 }
50
51 bool BlenderSync::object_is_mesh(BL::Object b_ob)
52 {
53         BL::ID b_ob_data = b_ob.data();
54
55         return (b_ob_data && (b_ob_data.is_a(&RNA_Mesh) ||
56                 b_ob_data.is_a(&RNA_Curve) || b_ob_data.is_a(&RNA_MetaBall)));
57 }
58
59 bool BlenderSync::object_is_light(BL::Object b_ob)
60 {
61         BL::ID b_ob_data = b_ob.data();
62
63         return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
64 }
65
66 static uint object_ray_visibility(BL::Object b_ob)
67 {
68         PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
69         uint flag = 0;
70
71         flag |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0;
72         flag |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0;
73         flag |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0;
74         flag |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0;
75         flag |= get_boolean(cvisibility, "shadow")? PATH_RAY_SHADOW: 0;
76
77         return flag;
78 }
79
80 /* Light */
81
82 void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm)
83 {
84         /* test if we need to sync */
85         Light *light;
86         ObjectKey key(b_parent, b_index, b_ob);
87
88         if(!light_map.sync(&light, b_ob, b_parent, key))
89                 return;
90         
91         BL::Lamp b_lamp(b_ob.data());
92
93         /* type */
94         switch(b_lamp.type()) {
95                 case BL::Lamp::type_POINT: {
96                         BL::PointLamp b_point_lamp(b_lamp);
97                         light->size = b_point_lamp.shadow_soft_size();
98                         light->type = LIGHT_POINT;
99                         break;
100                 }
101                 case BL::Lamp::type_SPOT: {
102                         BL::SpotLamp b_spot_lamp(b_lamp);
103                         light->size = b_spot_lamp.shadow_soft_size();
104                         light->type = LIGHT_POINT;
105                         break;
106                 }
107                 case BL::Lamp::type_HEMI: {
108                         light->type = LIGHT_DISTANT;
109                         light->size = 0.0f;
110                         break;
111                 }
112                 case BL::Lamp::type_SUN: {
113                         BL::SunLamp b_sun_lamp(b_lamp);
114                         light->size = b_sun_lamp.shadow_soft_size();
115                         light->type = LIGHT_DISTANT;
116                         break;
117                 }
118                 case BL::Lamp::type_AREA: {
119                         BL::AreaLamp b_area_lamp(b_lamp);
120                         light->size = 1.0f;
121                         light->axisu = make_float3(tfm.x.x, tfm.y.x, tfm.z.x);
122                         light->axisv = make_float3(tfm.x.y, tfm.y.y, tfm.z.y);
123                         light->sizeu = b_area_lamp.size();
124                         if(b_area_lamp.shape() == BL::AreaLamp::shape_RECTANGLE)
125                                 light->sizev = b_area_lamp.size_y();
126                         else
127                                 light->sizev = light->sizeu;
128                         light->type = LIGHT_AREA;
129                         break;
130                 }
131         }
132
133         /* location and (inverted!) direction */
134         light->co = make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
135         light->dir = -make_float3(tfm.x.z, tfm.y.z, tfm.z.z);
136
137         /* shader */
138         vector<uint> used_shaders;
139
140         find_shader(b_lamp, used_shaders, scene->default_light);
141
142         if(used_shaders.size() == 0)
143                 used_shaders.push_back(scene->default_light);
144
145         light->shader = used_shaders[0];
146
147         /* shadow */
148         PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
149         light->cast_shadow = get_boolean(clamp, "cast_shadow");
150
151         /* tag */
152         light->tag_update(scene);
153 }
154
155 /* Object */
156
157 void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint layer_flag)
158 {
159         /* light is handled separately */
160         if(object_is_light(b_ob)) {
161                 sync_light(b_parent, b_index, b_ob, tfm);
162                 return;
163         }
164
165         /* only interested in object that we can create meshes from */
166         if(!object_is_mesh(b_ob))
167                 return;
168
169         /* test if we need to sync */
170         ObjectKey key(b_parent, b_index, b_ob);
171         Object *object;
172         bool object_updated = false;
173
174         if(object_map.sync(&object, b_ob, b_parent, key))
175                 object_updated = true;
176         
177         /* mesh sync */
178         object->mesh = sync_mesh(b_ob, object_updated);
179
180         /* object sync */
181         if(object_updated || (object->mesh && object->mesh->need_update)) {
182                 object->name = b_ob.name().c_str();
183                 object->tfm = tfm;
184
185                 /* visibility flags for both parent */
186                 object->visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL;
187                 if(b_parent.ptr.data != b_ob.ptr.data)
188                         object->visibility &= object_ray_visibility(b_parent);
189
190                 /* camera flag is not actually used, instead is tested
191                    against render layer flags */
192                 if(object->visibility & PATH_RAY_CAMERA) {
193                         object->visibility |= layer_flag << PATH_RAY_LAYER_SHIFT;
194                         object->visibility &= ~PATH_RAY_CAMERA;
195                 }
196
197                 object->tag_update(scene);
198         }
199 }
200
201 /* Object Loop */
202
203 void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
204 {
205         /* layer data */
206         uint scene_layer = render_layer.scene_layer;
207         
208         /* prepare for sync */
209         light_map.pre_sync();
210         mesh_map.pre_sync();
211         object_map.pre_sync();
212         mesh_synced.clear();
213
214         /* object loop */
215         BL::Scene::objects_iterator b_ob;
216
217         for(b_scene.objects.begin(b_ob); b_ob != b_scene.objects.end(); ++b_ob) {
218                 bool hide = (b_v3d)? b_ob->hide(): b_ob->hide_render();
219                 uint ob_layer = get_layer(b_ob->layers());
220
221                 if(!hide && (ob_layer & scene_layer)) {
222                         if(b_ob->is_duplicator()) {
223                                 /* dupli objects */
224                                 object_create_duplilist(*b_ob, b_scene);
225
226                                 BL::Object::dupli_list_iterator b_dup;
227                                 int b_index = 0;
228
229                                 for(b_ob->dupli_list.begin(b_dup); b_dup != b_ob->dupli_list.end(); ++b_dup) {
230                                         Transform tfm = get_transform(b_dup->matrix());
231                                         sync_object(*b_ob, b_index, b_dup->object(), tfm, ob_layer);
232                                         b_index++;
233                                 }
234
235                                 object_free_duplilist(*b_ob);
236
237                                 /* check if we should render duplicator */
238                                 hide = true;
239                                 BL::Object::particle_systems_iterator b_psys;
240
241                                 for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
242                                         if(b_psys->settings().use_render_emitter())
243                                                 hide = false;
244                         }
245
246                         if(!hide) {
247                                 /* object itself */
248                                 Transform tfm = get_transform(b_ob->matrix_world());
249                                 sync_object(*b_ob, 0, *b_ob, tfm, ob_layer);
250                         }
251                 }
252         }
253
254         /* handle removed data and modified pointers */
255         if(light_map.post_sync())
256                 scene->light_manager->tag_update(scene);
257         if(mesh_map.post_sync())
258                 scene->mesh_manager->tag_update(scene);
259         if(object_map.post_sync())
260                 scene->object_manager->tag_update(scene);
261         mesh_synced.clear();
262 }
263
264 CCL_NAMESPACE_END
265