Cycles: svn merge -r41467:41531 ^/trunk/blender
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Fri, 4 Nov 2011 20:21:40 +0000 (20:21 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Fri, 4 Nov 2011 20:21:40 +0000 (20:21 +0000)
434 files changed:
CMakeLists.txt
build_files/cmake/Modules/FindOpenImageIO.cmake [new file with mode: 0644]
build_files/cmake/macros.cmake
intern/CMakeLists.txt
intern/cycles/CMakeLists.txt [new file with mode: 0644]
intern/cycles/app/CMakeLists.txt [new file with mode: 0644]
intern/cycles/app/cycles_server.cpp [new file with mode: 0644]
intern/cycles/app/cycles_test.cpp [new file with mode: 0644]
intern/cycles/app/cycles_xml.cpp [new file with mode: 0644]
intern/cycles/app/cycles_xml.h [new file with mode: 0644]
intern/cycles/blender/CMakeLists.txt [new file with mode: 0644]
intern/cycles/blender/addon/__init__.py [new file with mode: 0644]
intern/cycles/blender/addon/engine.py [new file with mode: 0644]
intern/cycles/blender/addon/enums.py [new file with mode: 0644]
intern/cycles/blender/addon/presets.py [new file with mode: 0644]
intern/cycles/blender/addon/properties.py [new file with mode: 0644]
intern/cycles/blender/addon/ui.py [new file with mode: 0644]
intern/cycles/blender/addon/xml.py [new file with mode: 0644]
intern/cycles/blender/blender_camera.cpp [new file with mode: 0644]
intern/cycles/blender/blender_mesh.cpp [new file with mode: 0644]
intern/cycles/blender/blender_object.cpp [new file with mode: 0644]
intern/cycles/blender/blender_python.cpp [new file with mode: 0644]
intern/cycles/blender/blender_session.cpp [new file with mode: 0644]
intern/cycles/blender/blender_session.h [new file with mode: 0644]
intern/cycles/blender/blender_shader.cpp [new file with mode: 0644]
intern/cycles/blender/blender_sync.cpp [new file with mode: 0644]
intern/cycles/blender/blender_sync.h [new file with mode: 0644]
intern/cycles/blender/blender_util.h [new file with mode: 0644]
intern/cycles/bvh/CMakeLists.txt [new file with mode: 0644]
intern/cycles/bvh/bvh.cpp [new file with mode: 0644]
intern/cycles/bvh/bvh.h [new file with mode: 0644]
intern/cycles/bvh/bvh_build.cpp [new file with mode: 0644]
intern/cycles/bvh/bvh_build.h [new file with mode: 0644]
intern/cycles/bvh/bvh_node.cpp [new file with mode: 0644]
intern/cycles/bvh/bvh_node.h [new file with mode: 0644]
intern/cycles/bvh/bvh_params.h [new file with mode: 0644]
intern/cycles/bvh/bvh_sort.cpp [new file with mode: 0644]
intern/cycles/bvh/bvh_sort.h [new file with mode: 0644]
intern/cycles/cmake/external_libs.cmake [new file with mode: 0644]
intern/cycles/device/CMakeLists.txt [new file with mode: 0644]
intern/cycles/device/device.cpp [new file with mode: 0644]
intern/cycles/device/device.h [new file with mode: 0644]
intern/cycles/device/device_cpu.cpp [new file with mode: 0644]
intern/cycles/device/device_cuda.cpp [new file with mode: 0644]
intern/cycles/device/device_intern.h [new file with mode: 0644]
intern/cycles/device/device_memory.h [new file with mode: 0644]
intern/cycles/device/device_multi.cpp [new file with mode: 0644]
intern/cycles/device/device_network.cpp [new file with mode: 0644]
intern/cycles/device/device_network.h [new file with mode: 0644]
intern/cycles/device/device_opencl.cpp [new file with mode: 0644]
intern/cycles/doc/CMakeLists.txt [new file with mode: 0644]
intern/cycles/doc/license/Apache_2.0.txt [new file with mode: 0644]
intern/cycles/doc/license/Blender.txt [new file with mode: 0644]
intern/cycles/doc/license/Boost.txt [new file with mode: 0644]
intern/cycles/doc/license/CMakeLists.txt [new file with mode: 0644]
intern/cycles/doc/license/GPL.txt [new file with mode: 0644]
intern/cycles/doc/license/ILM.txt [new file with mode: 0644]
intern/cycles/doc/license/NVidia.txt [new file with mode: 0644]
intern/cycles/doc/license/OSL.txt [new file with mode: 0644]
intern/cycles/doc/license/Sobol.txt [new file with mode: 0644]
intern/cycles/doc/license/readme.txt [new file with mode: 0644]
intern/cycles/kernel/CMakeLists.txt [new file with mode: 0644]
intern/cycles/kernel/kernel.cl [new file with mode: 0644]
intern/cycles/kernel/kernel.cpp [new file with mode: 0644]
intern/cycles/kernel/kernel.cu [new file with mode: 0644]
intern/cycles/kernel/kernel.h [new file with mode: 0644]
intern/cycles/kernel/kernel_bvh.h [new file with mode: 0644]
intern/cycles/kernel/kernel_camera.h [new file with mode: 0644]
intern/cycles/kernel/kernel_compat_cpu.h [new file with mode: 0644]
intern/cycles/kernel/kernel_compat_cuda.h [new file with mode: 0644]
intern/cycles/kernel/kernel_compat_opencl.h [new file with mode: 0644]
intern/cycles/kernel/kernel_differential.h [new file with mode: 0644]
intern/cycles/kernel/kernel_displace.h [new file with mode: 0644]
intern/cycles/kernel/kernel_emission.h [new file with mode: 0644]
intern/cycles/kernel/kernel_film.h [new file with mode: 0644]
intern/cycles/kernel/kernel_globals.h [new file with mode: 0644]
intern/cycles/kernel/kernel_light.h [new file with mode: 0644]
intern/cycles/kernel/kernel_math.h [new file with mode: 0644]
intern/cycles/kernel/kernel_mbvh.h [new file with mode: 0644]
intern/cycles/kernel/kernel_montecarlo.h [new file with mode: 0644]
intern/cycles/kernel/kernel_object.h [new file with mode: 0644]
intern/cycles/kernel/kernel_path.h [new file with mode: 0644]
intern/cycles/kernel/kernel_qbvh.h [new file with mode: 0644]
intern/cycles/kernel/kernel_random.h [new file with mode: 0644]
intern/cycles/kernel/kernel_shader.h [new file with mode: 0644]
intern/cycles/kernel/kernel_textures.h [new file with mode: 0644]
intern/cycles/kernel/kernel_triangle.h [new file with mode: 0644]
intern/cycles/kernel/kernel_types.h [new file with mode: 0644]
intern/cycles/kernel/osl/CMakeLists.txt [new file with mode: 0644]
intern/cycles/kernel/osl/background.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/bsdf_diffuse.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/bsdf_microfacet.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/bsdf_reflection.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/bsdf_refraction.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/bsdf_transparent.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/bsdf_ward.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/bsdf_westin.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/bssrdf.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/debug.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/emissive.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/CMakeLists.txt [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_add_closure.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_attribute.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_background.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_blend_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_blend_weight.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_bump.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_clouds_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_color.h [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_convert_from_color.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_convert_from_float.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_convert_from_normal.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_convert_from_point.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_convert_from_vector.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_distorted_noise_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_emission.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_environment_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_fresnel.h [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_fresnel.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_geometry.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_glass_bsdf.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_glossy_bsdf.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_holdout.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_image_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_light_path.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_magic_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_mapping.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_marble_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_math.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_mix.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_mix_closure.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_musgrave_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_noise_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_output_displacement.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_output_surface.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_output_volume.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_sky_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_stucci_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_texture.h [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_translucent_bsdf.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_transparent_bsdf.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_value.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_vector_math.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_velvet_bsdf.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_voronoi_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_ward_bsdf.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/node_wood_texture.osl [new file with mode: 0644]
intern/cycles/kernel/osl/nodes/stdosl.h [new file with mode: 0644]
intern/cycles/kernel/osl/osl_closures.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/osl_closures.h [new file with mode: 0644]
intern/cycles/kernel/osl/osl_globals.h [new file with mode: 0644]
intern/cycles/kernel/osl/osl_services.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/osl_services.h [new file with mode: 0644]
intern/cycles/kernel/osl/osl_shader.cpp [new file with mode: 0644]
intern/cycles/kernel/osl/osl_shader.h [new file with mode: 0644]
intern/cycles/kernel/osl/vol_subsurface.cpp [new file with mode: 0644]
intern/cycles/kernel/svm/bsdf.h [new file with mode: 0644]
intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h [new file with mode: 0644]
intern/cycles/kernel/svm/bsdf_diffuse.h [new file with mode: 0644]
intern/cycles/kernel/svm/bsdf_microfacet.h [new file with mode: 0644]
intern/cycles/kernel/svm/bsdf_reflection.h [new file with mode: 0644]
intern/cycles/kernel/svm/bsdf_refraction.h [new file with mode: 0644]
intern/cycles/kernel/svm/bsdf_transparent.h [new file with mode: 0644]
intern/cycles/kernel/svm/bsdf_ward.h [new file with mode: 0644]
intern/cycles/kernel/svm/bsdf_westin.h [new file with mode: 0644]
intern/cycles/kernel/svm/emissive.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_attribute.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_blend.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_bsdf.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_closure.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_clouds.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_convert.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_displace.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_distorted_noise.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_fresnel.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_geometry.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_image.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_light_path.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_magic.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_mapping.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_marble.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_math.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_mix.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_musgrave.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_noise.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_noisetex.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_sky.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_stucci.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_tex_coord.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_texture.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_types.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_value.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_voronoi.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_wood.h [new file with mode: 0644]
intern/cycles/kernel/svm/volume.h [new file with mode: 0644]
intern/cycles/render/CMakeLists.txt [new file with mode: 0644]
intern/cycles/render/attribute.cpp [new file with mode: 0644]
intern/cycles/render/attribute.h [new file with mode: 0644]
intern/cycles/render/background.cpp [new file with mode: 0644]
intern/cycles/render/background.h [new file with mode: 0644]
intern/cycles/render/buffers.cpp [new file with mode: 0644]
intern/cycles/render/buffers.h [new file with mode: 0644]
intern/cycles/render/camera.cpp [new file with mode: 0644]
intern/cycles/render/camera.h [new file with mode: 0644]
intern/cycles/render/film.cpp [new file with mode: 0644]
intern/cycles/render/film.h [new file with mode: 0644]
intern/cycles/render/filter.cpp [new file with mode: 0644]
intern/cycles/render/filter.h [new file with mode: 0644]
intern/cycles/render/graph.cpp [new file with mode: 0644]
intern/cycles/render/graph.h [new file with mode: 0644]
intern/cycles/render/image.cpp [new file with mode: 0644]
intern/cycles/render/image.h [new file with mode: 0644]
intern/cycles/render/integrator.cpp [new file with mode: 0644]
intern/cycles/render/integrator.h [new file with mode: 0644]
intern/cycles/render/light.cpp [new file with mode: 0644]
intern/cycles/render/light.h [new file with mode: 0644]
intern/cycles/render/mesh.cpp [new file with mode: 0644]
intern/cycles/render/mesh.h [new file with mode: 0644]
intern/cycles/render/mesh_displace.cpp [new file with mode: 0644]
intern/cycles/render/nodes.cpp [new file with mode: 0644]
intern/cycles/render/nodes.h [new file with mode: 0644]
intern/cycles/render/object.cpp [new file with mode: 0644]
intern/cycles/render/object.h [new file with mode: 0644]
intern/cycles/render/osl.cpp [new file with mode: 0644]
intern/cycles/render/osl.h [new file with mode: 0644]
intern/cycles/render/scene.cpp [new file with mode: 0644]
intern/cycles/render/scene.h [new file with mode: 0644]
intern/cycles/render/session.cpp [new file with mode: 0644]
intern/cycles/render/session.h [new file with mode: 0644]
intern/cycles/render/shader.cpp [new file with mode: 0644]
intern/cycles/render/shader.h [new file with mode: 0644]
intern/cycles/render/sobol.cpp [new file with mode: 0644]
intern/cycles/render/sobol.h [new file with mode: 0644]
intern/cycles/render/svm.cpp [new file with mode: 0644]
intern/cycles/render/svm.h [new file with mode: 0644]
intern/cycles/render/tile.cpp [new file with mode: 0644]
intern/cycles/render/tile.h [new file with mode: 0644]
intern/cycles/subd/CMakeLists.txt [new file with mode: 0644]
intern/cycles/subd/subd_build.cpp [new file with mode: 0644]
intern/cycles/subd/subd_build.h [new file with mode: 0644]
intern/cycles/subd/subd_dice.cpp [new file with mode: 0644]
intern/cycles/subd/subd_dice.h [new file with mode: 0644]
intern/cycles/subd/subd_edge.h [new file with mode: 0644]
intern/cycles/subd/subd_face.h [new file with mode: 0644]
intern/cycles/subd/subd_mesh.cpp [new file with mode: 0644]
intern/cycles/subd/subd_mesh.h [new file with mode: 0644]
intern/cycles/subd/subd_patch.cpp [new file with mode: 0644]
intern/cycles/subd/subd_patch.h [new file with mode: 0644]
intern/cycles/subd/subd_ring.cpp [new file with mode: 0644]
intern/cycles/subd/subd_ring.h [new file with mode: 0644]
intern/cycles/subd/subd_split.cpp [new file with mode: 0644]
intern/cycles/subd/subd_split.h [new file with mode: 0644]
intern/cycles/subd/subd_stencil.cpp [new file with mode: 0644]
intern/cycles/subd/subd_stencil.h [new file with mode: 0644]
intern/cycles/subd/subd_vert.h [new file with mode: 0644]
intern/cycles/util/CMakeLists.txt [new file with mode: 0644]
intern/cycles/util/util_algorithm.h [new file with mode: 0644]
intern/cycles/util/util_args.h [new file with mode: 0644]
intern/cycles/util/util_boundbox.h [new file with mode: 0644]
intern/cycles/util/util_cache.cpp [new file with mode: 0644]
intern/cycles/util/util_cache.h [new file with mode: 0644]
intern/cycles/util/util_color.h [new file with mode: 0644]
intern/cycles/util/util_cuda.cpp [new file with mode: 0644]
intern/cycles/util/util_cuda.h [new file with mode: 0644]
intern/cycles/util/util_debug.h [new file with mode: 0644]
intern/cycles/util/util_dynlib.cpp [new file with mode: 0644]
intern/cycles/util/util_dynlib.h [new file with mode: 0644]
intern/cycles/util/util_foreach.h [new file with mode: 0644]
intern/cycles/util/util_function.h [new file with mode: 0644]
intern/cycles/util/util_hash.h [new file with mode: 0644]
intern/cycles/util/util_image.h [new file with mode: 0644]
intern/cycles/util/util_list.h [new file with mode: 0644]
intern/cycles/util/util_map.h [new file with mode: 0644]
intern/cycles/util/util_math.h [new file with mode: 0644]
intern/cycles/util/util_md5.cpp [new file with mode: 0644]
intern/cycles/util/util_md5.h [new file with mode: 0644]
intern/cycles/util/util_memarena.cpp [new file with mode: 0644]
intern/cycles/util/util_memarena.h [new file with mode: 0644]
intern/cycles/util/util_opencl.c [new file with mode: 0755]
intern/cycles/util/util_opencl.h [new file with mode: 0755]
intern/cycles/util/util_opengl.h [new file with mode: 0644]
intern/cycles/util/util_param.h [new file with mode: 0644]
intern/cycles/util/util_path.cpp [new file with mode: 0644]
intern/cycles/util/util_path.h [new file with mode: 0644]
intern/cycles/util/util_progress.h [new file with mode: 0644]
intern/cycles/util/util_set.h [new file with mode: 0644]
intern/cycles/util/util_string.cpp [new file with mode: 0644]
intern/cycles/util/util_string.h [new file with mode: 0644]
intern/cycles/util/util_system.cpp [new file with mode: 0644]
intern/cycles/util/util_system.h [new file with mode: 0644]
intern/cycles/util/util_thread.h [new file with mode: 0644]
intern/cycles/util/util_time.cpp [new file with mode: 0644]
intern/cycles/util/util_time.h [new file with mode: 0644]
intern/cycles/util/util_transform.cpp [new file with mode: 0644]
intern/cycles/util/util_transform.h [new file with mode: 0644]
intern/cycles/util/util_types.h [new file with mode: 0644]
intern/cycles/util/util_vector.h [new file with mode: 0644]
intern/cycles/util/util_view.cpp [new file with mode: 0644]
intern/cycles/util/util_view.h [new file with mode: 0644]
intern/cycles/util/util_xml.h [new file with mode: 0644]
intern/ghost/GHOST_ISystem.h
intern/ghost/intern/GHOST_System.cpp
intern/ghost/intern/GHOST_System.h
release/scripts/presets/cycles/integrator/direct_light.py [new file with mode: 0644]
release/scripts/presets/cycles/integrator/full_global_illumination.py [new file with mode: 0644]
release/scripts/presets/cycles/integrator/limited_global_illumination.py [new file with mode: 0644]
release/scripts/startup/bl_ui/properties_particle.py
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/node.c
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/datafiles/startup.blend.c
source/blender/editors/include/ED_node.h
source/blender/editors/include/ED_uvedit.h
source/blender/editors/include/UI_interface.h
source/blender/editors/interface/CMakeLists.txt
source/blender/editors/interface/interface_draw.c
source/blender/editors/interface/interface_icons.c
source/blender/editors/interface/interface_intern.h
source/blender/editors/interface/interface_node.c [new file with mode: 0644]
source/blender/editors/interface/interface_panel.c
source/blender/editors/interface/interface_style.c
source/blender/editors/interface/interface_templates.c
source/blender/editors/interface/interface_widgets.c
source/blender/editors/mesh/mesh_data.c
source/blender/editors/object/object_add.c
source/blender/editors/screen/area.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/space_buttons/CMakeLists.txt
source/blender/editors/space_buttons/buttons_context.c
source/blender/editors/space_buttons/buttons_intern.h
source/blender/editors/space_buttons/buttons_texture.c [new file with mode: 0644]
source/blender/editors/space_buttons/space_buttons.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_node/CMakeLists.txt
source/blender/editors/space_node/SConscript
source/blender/editors/space_node/drawnode.c
source/blender/editors/space_node/node_draw.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_node/node_intern.h
source/blender/editors/space_node/node_layout.c [new file with mode: 0644]
source/blender/editors/space_node/node_ops.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/uvedit/uvedit_ops.c
source/blender/editors/uvedit/uvedit_unwrap_ops.c
source/blender/gpu/intern/gpu_draw.c
source/blender/gpu/intern/gpu_material.c
source/blender/gpu/intern/gpu_shader_material.glsl
source/blender/gpu/intern/gpu_shader_material.glsl.c
source/blender/imbuf/CMakeLists.txt
source/blender/imbuf/intern/IMB_filetype.h
source/blender/imbuf/intern/filetype.c
source/blender/imbuf/intern/openimageio.cpp [new file with mode: 0644]
source/blender/imbuf/intern/readimage.c
source/blender/imbuf/intern/util.c
source/blender/imbuf/intern/writeimage.c
source/blender/makesdna/DNA_node_types.h
source/blender/makesdna/DNA_space_types.h
source/blender/makesrna/intern/rna_nodetree.c
source/blender/makesrna/intern/rna_nodetree_types.h
source/blender/makesrna/intern/rna_object_api.c
source/blender/makesrna/intern/rna_render.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_ui_api.c
source/blender/nodes/CMakeLists.txt
source/blender/nodes/NOD_shader.h
source/blender/nodes/intern/node_socket.c
source/blender/nodes/shader/node_shader_tree.c
source/blender/nodes/shader/node_shader_util.c
source/blender/nodes/shader/node_shader_util.h
source/blender/nodes/shader/nodes/node_shader_add_shader.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_attribute.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_background.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_blend_weight.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_emission.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_fresnel.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_geom.c
source/blender/nodes/shader/nodes/node_shader_geometry.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_holdout.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_light_path.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_mapping.c
source/blender/nodes/shader/nodes/node_shader_math.c
source/blender/nodes/shader/nodes/node_shader_mixRgb.c
source/blender/nodes/shader/nodes/node_shader_mix_shader.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_noise.h [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_output_lamp.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_output_material.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_output_texture.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_output_world.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_rgb.c
source/blender/nodes/shader/nodes/node_shader_tex_blend.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_clouds.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_coord.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_distnoise.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_environment.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_image.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_magic.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_marble.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_noise.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_sky.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_stucci.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_tex_wood.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_valToRgb.c
source/blender/nodes/shader/nodes/node_shader_value.c
source/blender/nodes/shader/nodes/node_shader_vectMath.c
source/blender/nodes/shader/nodes/node_shader_volume_isotropic.c [new file with mode: 0644]
source/blender/nodes/shader/nodes/node_shader_volume_transparent.c [new file with mode: 0644]
source/blender/python/intern/CMakeLists.txt
source/blender/python/intern/bpy_interface.c
source/blender/render/extern/include/RE_engine.h
source/blender/render/intern/source/external_engine.c
source/blenderplayer/bad_level_call_stubs/stubs.c
source/creator/CMakeLists.txt
source/gameengine/GamePlayer/ghost/GPG_ghost.cpp

index 0e06f39e7187267081979e683737820a6e2aa42a..0230fb34d0c7a58cdf336467cdd17122f508ba93 100644 (file)
@@ -105,6 +105,7 @@ enable_testing()
 
 set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin CACHE INTERNAL "" FORCE )
 set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib CACHE INTERNAL "" FORCE )
+set(INCLUDE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/include CACHE INTERNAL "" FORCE )
 
 #-----------------------------------------------------------------------------
 # Set default config options
@@ -210,6 +211,15 @@ if(UNIX AND NOT APPLE)
 endif()
 option(WITH_PYTHON_INSTALL       "Copy system python into the blender install folder" ON)
 
+# Cycles
+option(WITH_CYCLES                     "Enable Cycles Render Engine" ON)
+OPTION(WITH_CYCLES_OSL         "Build with Open Shading Language support" OFF)
+OPTION(WITH_CYCLES_CUDA                "Build with CUDA binaries" OFF)
+OPTION(WITH_CYCLES_BLENDER     "Build Blender Python extension" ON)
+OPTION(WITH_CYCLES_PARTIO      "Build with Partio point cloud support (unfinished)" OFF)
+OPTION(WITH_CYCLES_NETWORK     "Build with network rendering support (unfinished)" OFF)
+OPTION(WITH_CYCLES_TEST                "Build cycles test application" OFF)
+
 # disable for now, but plan to support on all platforms eventually
 option(WITH_MEM_JEMALLOC   "Enable malloc replacement (http://www.canonware.com/jemalloc)" OFF)
 mark_as_advanced(WITH_MEM_JEMALLOC)
@@ -281,6 +291,16 @@ if(WITH_PYTHON_MODULE)
        set(WITH_HEADLESS ON)
 endif()
 
+# auto enable openimageio and boost for cycles
+if(WITH_CYCLES)
+       set(WITH_OPENIMAGEIO ON)
+       set(WITH_BOOST ON)
+endif()
+
+if(WITH_OPENIMAGEIO)
+       set(WITH_BOOST ON)
+endif()
+
 TEST_SSE_SUPPORT(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG)
 
 # don't store paths to libs for portable distrobution
@@ -488,6 +508,47 @@ if(UNIX AND NOT APPLE)
                endif()
        endif()
 
+       if(WITH_BOOST)
+               if(CYCLES_BOOST)
+                       set(BOOST ${CYCLES_BOOST} CACHE PATH "Boost Directory")
+                       unset(CYCLES_BOOST CACHE)
+               else()
+                       set(BOOST "/usr" CACHE PATH "Boost Directory")
+               endif()
+
+               if(NOT BOOST_CUSTOM)
+                       set(BOOST_ROOT ${BOOST})
+                       set(Boost_USE_MULTITHREADED ON)
+                       find_package(Boost 1.34 REQUIRED COMPONENTS filesystem regex system thread)
+               endif()
+
+               set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
+               set(BOOST_LIBRARIES ${Boost_LIBRARIES})
+               set(BOOST_LIBPATH ${Boost_LIBRARY_DIRS})
+               set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
+       endif()
+
+       if(WITH_OPENIMAGEIO)
+
+               # temp, update
+               if(CYCLES_OIIO)
+                       set(OPENIMAGEIO ${CYCLES_OIIO})
+                       unset(CYCLES_OIIO CACHE)
+               endif()
+
+               set(OPENIMAGEIO_ROOT_DIR ${OPENIMAGEIO})
+               find_package(OpenImageIO REQUIRED)
+
+               set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARY} ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES} ${BOOST_LIBRARIES})
+               set(OPENIMAGEIO_LIBPATH)  # TODO, remove and reference the absolute path everywhere
+               set(OPENIMAGEIO_DEFINITIONS)
+
+               if(NOT OPENIMAGEIO_FOUND)
+                       set(WITH_OPENIMAGEIO OFF)
+               endif()
+
+       endif()
+
        # OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
        set(PLATFORM_LINKLIBS "-lutil -lc -lm -lpthread -lstdc++")
 
@@ -774,6 +835,33 @@ elseif(WIN32)
                        set(PYTHON_LIBRARIES  "${PYTHON_LIBRARY}")
                endif()
 
+               if(WITH_BOOST)
+                       set(BOOST ${LIBDIR}/boost)
+                       set(BOOST_INCLUDE_DIR ${BOOST}/include)
+                       if(CMAKE_CL_64)
+                               set(BOOST_POSTFIX "vc90-mt-s-1_45.lib")
+                               set(BOOST_DEBUG_POSTFIX "vc90-mt-sgd-1_45.lib")
+                       else()
+                               set(BOOST_POSTFIX "vc90-mt-s-1_46_1.lib")
+                               set(BOOST_DEBUG_POSTFIX "vc90-mt-sgd-1_46_1.lib")
+                       endif()
+                       set(BOOST_LIBRARIES
+                               optimized libboost_date_time-${BOOST_POSTFIX} libboost_filesystem-${BOOST_POSTFIX}
+                               libboost_regex-${BOOST_POSTFIX} libboost_system-${BOOST_POSTFIX} libboost_thread-${BOOST_POSTFIX}
+                               debug libboost_date_time-${BOOST_DEBUG_POSTFIX} libboost_filesystem-${BOOST_DEBUG_POSTFIX}
+                               libboost_regex-${BOOST_DEBUG_POSTFIX} libboost_system-${BOOST_DEBUG_POSTFIX} libboost_thread-${BOOST_DEBUG_POSTFIX})
+                       set(BOOST_LIBPATH ${BOOST}/lib)
+                       set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
+               endif()
+                       
+               if(WITH_OPENIMAGEIO)
+                       set(OPENIMAGEIO ${LIBDIR}/openimageio)
+                       set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
+                       set(OPENIMAGEIO_LIBRARIES OpenImageIO)
+                       set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
+                       set(OPENIMAGEIO_DEFINITIONS)
+               endif()
+
                set(PLATFORM_LINKFLAGS "/SUBSYSTEM:CONSOLE /STACK:2097152 /INCREMENTAL:NO /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcmrt.lib /NODEFAULTLIB:msvcurt.lib /NODEFAULTLIB:msvcrtd.lib")
 
                # MSVC only, Mingw doesnt need
@@ -884,6 +972,28 @@ elseif(WIN32)
                        set(PYTHON_LIBRARIES  "${PYTHON_LIBRARY}")
                endif()
 
+               if(WITH_BOOST)
+                       set(BOOST ${LIBDIR}/boost)
+                       set(BOOST_INCLUDE_DIR ${BOOST}/include)
+                       set(BOOST_POSTFIX "vc90-mt-s-1_46_1")
+                       set(BOOST_DEBUG_POSTFIX "vc90-mt-sgd-1_46_1")
+                       set(BOOST_LIBRARIES
+                               optimized libboost_date_time-${BOOST_POSTFIX} libboost_filesystem-${BOOST_POSTFIX}
+                               libboost_regex-${BOOST_POSTFIX} libboost_system-${BOOST_POSTFIX} libboost_thread-${BOOST_POSTFIX}
+                               debug libboost_date_time-${BOOST_DEBUG_POSTFIX} libboost_filesystem-${BOOST_DEBUG_POSTFIX}
+                               libboost_regex-${BOOST_DEBUG_POSTFIX} libboost_system-${BOOST_DEBUG_POSTFIX} libboost_thread-${BOOST_DEBUG_POSTFIX})
+                       set(BOOST_LIBPATH ${BOOST}/lib)
+                       set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
+               endif()
+                       
+               if(WITH_OPENIMAGEIO)
+                       set(OPENIMAGEIO ${LIBDIR}/openimageio)
+                       set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
+                       set(OPENIMAGEIO_LIBRARIES OpenImageIO)
+                       set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
+                       set(OPENIMAGEIO_DEFINITIONS)
+               endif()
+
                set(PLATFORM_LINKFLAGS "--stack,2097152")
 
        endif()
@@ -1087,6 +1197,22 @@ elseif(APPLE)
                # linker needs "-weak_framework 3DconnexionClient"
        endif()
 
+       if(WITH_BOOST)
+               set(BOOST ${LIBDIR}/boost)
+               set(BOOST_INCLUDE_DIR ${BOOST}/include)
+               set(BOOST_LIBRARIES boost_date_time-mt boost_filesystem-mt boost_regex-mt boost_system-mt boost_thread-mt)
+               set(BOOST_LIBPATH ${BOOST}/lib)
+               set(BOOST_DEFINITIONS)
+       endif()
+
+       if(WITH_OPENIMAGEIO)
+               set(OPENIMAGEIO ${LIBDIR}/openimageio)
+               set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
+               set(OPENIMAGEIO_LIBRARIES OpenImageIO ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARY} ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES})
+               set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib ${JPEG_LIBPATH} ${PNG_LIBPATH} ${TIFF_LIBPATH} ${OPENEXR_LIBPATH} ${ZLIB_LIBPATH})
+               set(OPENIMAGEIO_DEFINITIONS "-DOIIO_STATIC_BUILD")
+       endif()
+
        set(EXETYPE MACOSX_BUNDLE)
 
        set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
@@ -1406,6 +1532,7 @@ if(FIRST_RUN)
        info_cfg_option(WITH_IMAGE_OPENJPEG)
        info_cfg_option(WITH_IMAGE_REDCODE)
        info_cfg_option(WITH_IMAGE_TIFF)
+       info_cfg_option(WITH_OPENIMAGEIO)
 
        info_cfg_text("Audio:")
        info_cfg_option(WITH_OPENAL)
diff --git a/build_files/cmake/Modules/FindOpenImageIO.cmake b/build_files/cmake/Modules/FindOpenImageIO.cmake
new file mode 100644 (file)
index 0000000..7512b93
--- /dev/null
@@ -0,0 +1,70 @@
+# - Find OpenImageIO library
+# Find the native OpenImageIO includes and library
+# This module defines
+#  OPENIMAGEIO_INCLUDE_DIRS, where to find openimageio.h, Set when
+#                            OPENIMAGEIO_INCLUDE_DIR is found.
+#  OPENIMAGEIO_LIBRARIES, libraries to link against to use OpenImageIO.
+#  OPENIMAGEIO_ROOT_DIR, The base directory to search for OpenImageIO.
+#                        This can also be an environment variable.
+#  OPENIMAGEIO_FOUND, If false, do not try to use OpenImageIO.
+#
+# also defined, but not for general use are
+#  OPENIMAGEIO_LIBRARY, where to find the OpenImageIO library.
+
+#=============================================================================
+# Copyright 2011 Blender Foundation.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+
+# If OPENIMAGEIO_ROOT_DIR was defined in the environment, use it.
+IF(NOT OPENIMAGEIO_ROOT_DIR AND NOT $ENV{OPENIMAGEIO_ROOT_DIR} STREQUAL "")
+  SET(OPENIMAGEIO_ROOT_DIR $ENV{OPENIMAGEIO_ROOT_DIR})
+ENDIF()
+
+SET(_openimageio_SEARCH_DIRS
+  ${OPENIMAGEIO_ROOT_DIR}
+  /usr/local
+  /sw # Fink
+  /opt/local # DarwinPorts
+  /opt/csw # Blastwave
+)
+
+FIND_PATH(OPENIMAGEIO_INCLUDE_DIR
+  NAMES
+    OpenImageIO/imageio.h
+  HINTS
+    ${_openimageio_SEARCH_DIRS}
+  PATH_SUFFIXES
+    include
+)
+
+FIND_LIBRARY(OPENIMAGEIO_LIBRARY
+  NAMES
+    OpenImageIO
+  HINTS
+    ${_openimageio_SEARCH_DIRS}
+  PATH_SUFFIXES
+    lib64 lib
+  )
+
+# handle the QUIETLY and REQUIRED arguments and set OPENIMAGEIO_FOUND to TRUE if 
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenImageIO DEFAULT_MSG
+    OPENIMAGEIO_LIBRARY OPENIMAGEIO_INCLUDE_DIR)
+
+IF(OPENIMAGEIO_FOUND)
+  SET(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARY})
+  SET(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO_INCLUDE_DIR})
+ENDIF(OPENIMAGEIO_FOUND)
+
+MARK_AS_ADVANCED(
+  OPENIMAGEIO_INCLUDE_DIR
+  OPENIMAGEIO_LIBRARY
+)
index 10f89797754c13b7092c7f1ed0058f08a9a90cd3..c9a04f87148280fd97d9360c0d0a05f3b6d1a1c5 100644 (file)
@@ -165,6 +165,12 @@ macro(SETUP_LIBDIRS)
        if(WITH_IMAGE_TIFF)
                link_directories(${TIFF_LIBPATH})
        endif()
+       if(WITH_BOOST)
+               link_directories(${BOOST_LIBPATH})
+       endif()
+       if(WITH_OPENIMAGEIO)
+               link_directories(${OPENIMAGEIO_LIBPATH})
+       endif()
        if(WITH_IMAGE_OPENJPEG AND UNIX AND NOT APPLE)
                link_directories(${OPENJPEG_LIBPATH})
        endif()
@@ -259,6 +265,12 @@ macro(setup_liblinks
        if(WITH_IMAGE_TIFF)
                target_link_libraries(${target} ${TIFF_LIBRARY})
        endif()
+       if(WITH_OPENIMAGEIO)
+               target_link_libraries(${target} ${OPENIMAGEIO_LIBRARIES})
+       endif()
+       if(WITH_BOOST)
+               target_link_libraries(${target} ${BOOST_LIBRARIES})
+       endif()
        if(WITH_IMAGE_OPENEXR)
                if(WIN32 AND NOT UNIX)
                        file_list_suffix(OPENEXR_LIBRARIES_DEBUG "${OPENEXR_LIBRARIES}" "_d")
@@ -618,3 +630,38 @@ macro(blender_project_hack_post)
        endif()
 
 endmacro()
+
+# pair of macros to allow libraries to be specify files to install, but to
+# only install them at the end so the directories don't get cleared with
+# the files in them. used by cycles to install addon.
+macro(delayed_install
+       base
+       files
+       destination)
+
+       foreach(f ${files})
+               set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_FILES ${base}/${f})
+               set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_DESTINATIONS ${destination})
+       endforeach()
+endmacro()
+
+# note this is a function instead of a macro so that ${BUILD_TYPE} in targetdir
+# does not get expanded in calling but is preserved
+function(delayed_do_install
+       targetdir)
+
+       get_property(files GLOBAL PROPERTY DELAYED_INSTALL_FILES)
+       get_property(destinations GLOBAL PROPERTY DELAYED_INSTALL_DESTINATIONS)
+
+       if(files)
+               list(LENGTH files n)
+               math(EXPR n "${n}-1")
+
+               foreach(i RANGE ${n})
+                       list(GET files ${i} f)
+                       list(GET destinations ${i} d)
+                       install(FILES ${f} DESTINATION ${targetdir}/${d})
+               endforeach()
+       endif()
+endfunction()
+
index 7a663ec9335dbdbf3d0b17fd093dc4cfcbe6fd57..0f7672595d75058c99bcdbae220a06b2ef144b6b 100644 (file)
@@ -57,3 +57,8 @@ endif()
 if(WITH_IK_ITASC)
        add_subdirectory(itasc)
 endif()
+
+if(WITH_CYCLES)
+       add_subdirectory(cycles)
+endif()
+
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d0b24c8
--- /dev/null
@@ -0,0 +1,79 @@
+
+set(CYCLES_INSTALL_PATH "scripts/addons/cycles")
+
+# External Libraries
+
+include(cmake/external_libs.cmake)
+
+# Build Flags
+
+set(GCC_WARNING_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-long-long")
+set(GCC_OPTIM_FLAGS "-ffast-math -msse -msse2 -msse3 -mtune=native")
+
+if(APPLE)
+       set(CMAKE_CXX_FLAGS "${GCC_WARNING_FLAGS} ${GCC_OPTIM_FLAGS}")
+       set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
+endif(APPLE)
+
+if(WIN32)
+       if(MSVC)
+               set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Ox /Ot /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /EHsc /fp:fast")
+               set(RTTI_DISABLE_FLAGS "/GR- -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
+       elseif(CMAKE_COMPILER_IS_GNUCC)
+               set(CMAKE_CXX_FLAGS "${GCC_WARNING_FLAGS} ${GCC_OPTIM_FLAGS}")
+               set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
+       endif()
+endif(WIN32)
+
+if(UNIX AND NOT APPLE)
+       set(CMAKE_CXX_FLAGS "${GCC_WARNING_FLAGS} ${GCC_OPTIM_FLAGS}")
+       set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
+endif(UNIX AND NOT APPLE)
+
+# Definitions and Includes
+
+add_definitions(${BOOST_DEFINITIONS} ${OPENIMAGEIO_DEFINITIONS})
+
+add_definitions(-DCCL_NAMESPACE_BEGIN=namespace\ ccl\ {)
+add_definitions(-DCCL_NAMESPACE_END=})
+
+if(WITH_CYCLES_NETWORK)
+  add_definitions(-DWITH_NETWORK)
+endif()
+
+if(WITH_CYCLES_CUDA)
+  add_definitions(-DWITH_CUDA_BINARIES)
+endif()
+
+if(WITH_CYCLES_OSL)
+  add_definitions(-DWITH_OSL)
+endif()
+
+if(WITH_CYCLES_PARTIO)
+  add_definitions(-DWITH_PARTIO)
+endif()
+
+add_definitions(-DWITH_OPENCL)
+add_definitions(-DWITH_CUDA)
+add_definitions(-DWITH_MULTI)
+
+include_directories(
+       ${BOOST_INCLUDE_DIR}
+       ${OPENIMAGEIO_INCLUDE_DIRS}
+       ${OPENIMAGEIO_INCLUDE_DIRS}/OpenImageIO)
+
+# Subdirectories
+
+if(WITH_CYCLES_BLENDER)
+       add_subdirectory(blender)
+endif(WITH_CYCLES_BLENDER)
+
+add_subdirectory(app)
+add_subdirectory(bvh)
+add_subdirectory(device)
+add_subdirectory(doc)
+add_subdirectory(kernel)
+add_subdirectory(render)
+add_subdirectory(subd)
+add_subdirectory(util)
+
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ef6a80f
--- /dev/null
@@ -0,0 +1,55 @@
+
+include_directories(
+       .
+       ../device
+       ../kernel
+       ../kernel/svm
+       ../bvh
+       ../util
+       ../render
+       ../subd)
+
+set(LIBRARIES
+       cycles_device
+       cycles_kernel
+       cycles_render
+       cycles_bvh
+       cycles_subd
+       cycles_util
+       ${BOOST_LIBRARIES}
+       ${OPENGL_LIBRARIES}
+       ${CYCLES_GLEW_LIBRARY}
+       ${OPENIMAGEIO_LIBRARIES})
+
+link_directories(${OPENIMAGEIO_LIBPATH} ${BOOST_LIBPATH})
+
+if(WITH_CYCLES_TEST)
+       list(APPEND LIBRARIES ${GLUT_LIBRARIES})
+endif()
+
+if(WITH_CYCLES_OSL)
+       list(APPEND LIBRARIES cycles_kernel_osl ${OSL_LIBRARIES})
+endif()
+
+if(WITH_CYCLES_PARTIO)
+       list(APPEND LIBRARIES ${PARTIO_LIBRARIES})
+endif()
+
+if(WITH_CYCLES_TEST)
+       add_executable(cycles_test cycles_test.cpp cycles_xml.cpp cycles_xml.h)
+       target_link_libraries(cycles_test ${LIBRARIES})
+
+       if(UNIX AND NOT APPLE)
+               set_target_properties(cycles_test PROPERTIES INSTALL_RPATH $ORIGIN/lib)
+       endif()
+endif()
+
+if(WITH_CYCLES_NETWORK)
+       add_executable(cycles_server cycles_server.cpp)
+       target_link_libraries(cycles_server ${LIBRARIES})
+
+       if(UNIX AND NOT APPLE)
+               set_target_properties(cycles_server PROPERTIES INSTALL_RPATH $ORIGIN/lib)
+       endif()
+endif()
+
diff --git a/intern/cycles/app/cycles_server.cpp b/intern/cycles/app/cycles_server.cpp
new file mode 100644 (file)
index 0000000..bcf4d3e
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+
+#include "device.h"
+
+#include "util_args.h"
+#include "util_foreach.h"
+#include "util_path.h"
+#include "util_string.h"
+
+using namespace ccl;
+
+int main(int argc, const char **argv)
+{
+       path_init();
+
+       /* device types */
+       string devices = "";
+       string devicename = "cpu";
+
+       vector<DeviceType> types = Device::available_types();
+
+       foreach(DeviceType type, types) {
+               if(devices != "")
+                       devices += ", ";
+
+               devices += Device::string_from_type(type);
+       }
+
+       /* parse options */
+       ArgParse ap;
+
+       ap.options ("Usage: cycles_server [options]",
+               "--device %s", &devicename, ("Devices to use: " + devices).c_str(),
+               NULL);
+
+       if(ap.parse(argc, argv) < 0) {
+               fprintf(stderr, "%s\n", ap.error_message().c_str());
+               ap.usage();
+               exit(EXIT_FAILURE);
+       }
+
+       DeviceType dtype = Device::type_from_string(devicename.c_str());
+
+       while(1) {
+               Device *device = Device::create(dtype);
+               printf("Cycles Server with device: %s\n", device->description().c_str());
+               device->server_run();
+               delete device;
+       }
+
+       return 0;
+}
+
diff --git a/intern/cycles/app/cycles_test.cpp b/intern/cycles/app/cycles_test.cpp
new file mode 100644 (file)
index 0000000..27e53de
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+
+#include "buffers.h"
+#include "camera.h"
+#include "device.h"
+#include "scene.h"
+#include "session.h"
+
+#include "util_args.h"
+#include "util_foreach.h"
+#include "util_function.h"
+#include "util_path.h"
+#include "util_progress.h"
+#include "util_string.h"
+#include "util_time.h"
+#include "util_view.h"
+
+#include "cycles_xml.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct Options {
+       Session *session;
+       Scene *scene;
+       string filepath;
+       int width, height;
+       SceneParams scene_params;
+       SessionParams session_params;
+       bool quiet;
+} options;
+
+static void session_print(const string& str)
+{
+       /* print with carriage return to overwrite previous */
+       printf("\r%s", str.c_str());
+
+       /* add spaces to overwrite longer previous print */
+       static int maxlen = 0;
+       int len = str.size();
+       maxlen = max(len, maxlen);
+
+       for(int i = len; i < maxlen; i++)
+               printf(" ");
+
+       /* flush because we don't write an end of line */
+       fflush(stdout);
+}
+
+static void session_print_status()
+{
+       int sample;
+       double total_time, sample_time;
+       string status, substatus;
+
+       /* get status */
+       options.session->progress.get_sample(sample, total_time, sample_time);
+       options.session->progress.get_status(status, substatus);
+
+       if(substatus != "")
+               status += ": " + substatus;
+
+       /* print status */
+       status = string_printf("Sample %d   %s", sample, status.c_str());
+       session_print(status);
+}
+
+static void session_init()
+{
+       options.session = new Session(options.session_params);
+       options.session->reset(options.width, options.height, options.session_params.samples);
+       options.session->scene = options.scene;
+       
+       if(options.session_params.background && !options.quiet)
+               options.session->progress.set_update_callback(function_bind(&session_print_status));
+       else
+               options.session->progress.set_update_callback(function_bind(&view_redraw));
+
+       options.session->start();
+
+       options.scene = NULL;
+}
+
+static void scene_init()
+{
+       options.scene = new Scene(options.scene_params);
+       xml_read_file(options.scene, options.filepath.c_str());
+       options.width = options.scene->camera->width;
+       options.height = options.scene->camera->height;
+}
+
+static void session_exit()
+{
+       if(options.session) {
+               delete options.session;
+               options.session = NULL;
+       }
+       if(options.scene) {
+               delete options.scene;
+               options.scene = NULL;
+       }
+
+       if(options.session_params.background && !options.quiet) {
+               session_print("Finished Rendering.");
+               printf("\n");
+       }
+}
+
+static void display_info(Progress& progress)
+{
+       static double latency = 0.0;
+       static double last = 0;
+       double elapsed = time_dt();
+       string str;
+
+       latency = (elapsed - last);
+       last = elapsed;
+
+       int sample;
+       double total_time, sample_time;
+       string status, substatus;
+
+       progress.get_sample(sample, total_time, sample_time);
+       progress.get_status(status, substatus);
+
+       if(substatus != "")
+               status += ": " + substatus;
+
+       str = string_printf("latency: %.4f        sample: %d        total: %.4f        average: %.4f        %s",
+               latency, sample, total_time, sample_time, status.c_str());
+
+       view_display_info(str.c_str());
+}
+
+static void display()
+{
+       options.session->draw(options.width, options.height);
+
+       display_info(options.session->progress);
+}
+
+static void resize(int width, int height)
+{
+       options.width= width;
+       options.height= height;
+
+       if(options.session)
+               options.session->reset(options.width, options.height, options.session_params.samples);
+}
+
+void keyboard(unsigned char key)
+{
+       if(key == 'r')
+               options.session->reset(options.width, options.height, options.session_params.samples);
+       else if(key == 27) // escape
+               options.session->progress.set_cancel("Cancelled");
+}
+
+static int files_parse(int argc, const char *argv[])
+{
+       if(argc > 0)
+               options.filepath = argv[0];
+
+       return 0;
+}
+
+static void options_parse(int argc, const char **argv)
+{
+       options.width= 1024;
+       options.height= 512;
+       options.filepath = "";
+       options.session = NULL;
+       options.quiet = false;
+
+       /* devices */
+       string devices = "";
+       string devicename = "cpu";
+
+       vector<DeviceType> types = Device::available_types();
+
+       foreach(DeviceType type, types) {
+               if(devices != "")
+                       devices += ", ";
+
+               devices += Device::string_from_type(type);
+       }
+
+       /* shading system */
+       string ssname = "svm";
+       string shadingsystems = "Shading system to use: svm";
+
+#ifdef WITH_OSL
+       shadingsystems += ", osl"; 
+#endif
+
+       /* parse options */
+       ArgParse ap;
+       bool help = false;
+
+       ap.options ("Usage: cycles_test [options] file.xml",
+               "%*", files_parse, "",
+               "--device %s", &devicename, ("Devices to use: " + devices).c_str(),
+               "--shadingsys %s", &ssname, "Shading system to use: svm, osl",
+               "--background", &options.session_params.background, "Render in background, without user interface",
+               "--quiet", &options.quiet, "In background mode, don't print progress messages",
+               "--samples %d", &options.session_params.samples, "Number of samples to render",
+               "--output %s", &options.session_params.output_path, "File path to write output image",
+               "--threads %d", &options.session_params.threads, "CPU Rendering Threads",
+               "--help", &help, "Print help message",
+               NULL);
+       
+       if(ap.parse(argc, argv) < 0) {
+               fprintf(stderr, "%s\n", ap.error_message().c_str());
+               ap.usage();
+               exit(EXIT_FAILURE);
+       }
+       else if(help || options.filepath == "") {
+               ap.usage();
+               exit(EXIT_SUCCESS);
+       }
+
+       options.session_params.device_type = Device::type_from_string(devicename.c_str());
+
+       if(ssname == "osl")
+               options.scene_params.shadingsystem = SceneParams::OSL;
+       else if(ssname == "svm")
+               options.scene_params.shadingsystem = SceneParams::SVM;
+
+       /* handle invalid configurations */
+       bool type_available = false;
+
+       foreach(DeviceType dtype, types)
+               if(options.session_params.device_type == dtype)
+                       type_available = true;
+
+       if(options.session_params.device_type == DEVICE_NONE || !type_available) {
+               fprintf(stderr, "Unknown device: %s\n", devicename.c_str());
+               exit(EXIT_FAILURE);
+       }
+#ifdef WITH_OSL
+       else if(!(ssname == "osl" || ssname == "svm")) {
+#else
+       else if(!(ssname == "svm")) {
+#endif
+               fprintf(stderr, "Unknown shading system: %s\n", ssname.c_str());
+               exit(EXIT_FAILURE);
+       }
+       else if(options.scene_params.shadingsystem == SceneParams::OSL && options.session_params.device_type != DEVICE_CPU) {
+               fprintf(stderr, "OSL shading system only works with CPU device\n");
+               exit(EXIT_FAILURE);
+       }
+       else if(options.session_params.samples < 0) {
+               fprintf(stderr, "Invalid number of samples: %d\n", options.session_params.samples);
+               exit(EXIT_FAILURE);
+       }
+       else if(options.filepath == "") {
+               fprintf(stderr, "No file path specified\n");
+               exit(EXIT_FAILURE);
+       }
+
+       /* load scene */
+       scene_init();
+}
+
+CCL_NAMESPACE_END
+
+using namespace ccl;
+
+int main(int argc, const char **argv)
+{
+       path_init("../build/bin/2.59/scripts/addons/cycles/");
+
+       options_parse(argc, argv);
+
+       if(options.session_params.background) {
+               session_init();
+               options.session->wait();
+               session_exit();
+       }
+       else {
+               string title = "Cycles: " + path_filename(options.filepath);
+
+               /* init/exit are callback so they run while GL is initialized */
+               view_main_loop(title.c_str(), options.width, options.height,
+                       session_init, session_exit, resize, display, keyboard);
+       }
+
+       return 0;
+}
+
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
new file mode 100644 (file)
index 0000000..5f9e1d7
--- /dev/null
@@ -0,0 +1,942 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdio.h>
+
+#include <sstream>
+#include <algorithm>
+#include <iterator>
+
+#include "camera.h"
+#include "film.h"
+#include "graph.h"
+#include "integrator.h"
+#include "light.h"
+#include "mesh.h"
+#include "nodes.h"
+#include "object.h"
+#include "shader.h"
+#include "scene.h"
+
+#include "subd_mesh.h"
+#include "subd_patch.h"
+#include "subd_split.h"
+
+#include "util_debug.h"
+#include "util_foreach.h"
+#include "util_path.h"
+#include "util_transform.h"
+#include "util_xml.h"
+
+#include "cycles_xml.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* XML reading state */
+
+struct XMLReadState {
+       Scene *scene;           /* scene pointer */
+       Transform tfm;          /* current transform state */
+       bool smooth;            /* smooth normal state */
+       int shader;                     /* current shader */
+       string base;            /* base path to current file*/
+       float dicing_rate;      /* current dicing rate */
+       Mesh::DisplacementMethod displacement_method;
+};
+
+/* Attribute Reading */
+
+static bool xml_read_bool(bool *value, pugi::xml_node node, const char *name)
+{
+       pugi::xml_attribute attr = node.attribute(name);
+
+       if(attr) {
+               *value = (string_iequals(attr.value(), "true")) || (atoi(attr.value()) != 0);
+               return true;
+       }
+
+       return false;
+}
+
+static bool xml_read_int(int *value, pugi::xml_node node, const char *name)
+{
+       pugi::xml_attribute attr = node.attribute(name);
+
+       if(attr) {
+               *value = atoi(attr.value());
+               return true;
+       }
+
+       return false;
+}
+
+static bool xml_read_int_array(vector<int>& value, pugi::xml_node node, const char *name)
+{
+       pugi::xml_attribute attr = node.attribute(name);
+
+       if(attr) {
+               vector<string> tokens;
+               string_split(tokens, attr.value());
+
+               foreach(const string& token, tokens)
+                       value.push_back(atoi(token.c_str()));
+
+               return true;
+       }
+
+       return false;
+}
+
+static bool xml_read_float(float *value, pugi::xml_node node, const char *name)
+{
+       pugi::xml_attribute attr = node.attribute(name);
+
+       if(attr) {
+               *value = atof(attr.value());
+               return true;
+       }
+
+       return false;
+}
+
+static bool xml_read_float_array(vector<float>& value, pugi::xml_node node, const char *name)
+{
+       pugi::xml_attribute attr = node.attribute(name);
+
+       if(attr) {
+               vector<string> tokens;
+               string_split(tokens, attr.value());
+
+               foreach(const string& token, tokens)
+                       value.push_back(atof(token.c_str()));
+
+               return true;
+       }
+
+       return false;
+}
+
+static bool xml_read_float3(float3 *value, pugi::xml_node node, const char *name)
+{
+       vector<float> array;
+
+       if(xml_read_float_array(array, node, name) && array.size() == 3) {
+               *value = make_float3(array[0], array[1], array[2]);
+               return true;
+       }
+
+       return false;
+}
+
+static bool xml_read_float3_array(vector<float3>& value, pugi::xml_node node, const char *name)
+{
+       vector<float> array;
+
+       if(xml_read_float_array(array, node, name)) {
+               for(size_t i = 0; i < array.size(); i += 3)
+                       value.push_back(make_float3(array[i+0], array[i+1], array[i+2]));
+
+               return true;
+       }
+
+       return false;
+}
+
+static bool xml_read_float4(float4 *value, pugi::xml_node node, const char *name)
+{
+       vector<float> array;
+
+       if(xml_read_float_array(array, node, name) && array.size() == 4) {
+               *value = make_float4(array[0], array[1], array[2], array[3]);
+               return true;
+       }
+
+       return false;
+}
+
+static bool xml_read_string(string *str, pugi::xml_node node, const char *name)
+{
+       pugi::xml_attribute attr = node.attribute(name);
+
+       if(attr) {
+               *str = attr.value();
+               return true;
+       }
+
+       return false;
+}
+
+static bool xml_read_ustring(ustring *str, pugi::xml_node node, const char *name)
+{
+       pugi::xml_attribute attr = node.attribute(name);
+
+       if(attr) {
+               *str = ustring(attr.value());
+               return true;
+       }
+
+       return false;
+}
+
+static bool xml_equal_string(pugi::xml_node node, const char *name, const char *value)
+{
+       pugi::xml_attribute attr = node.attribute(name);
+
+       if(attr)
+               return string_iequals(attr.value(), value);
+       
+       return false;
+}
+
+static bool xml_read_enum(ustring *str, ShaderEnum& enm, pugi::xml_node node, const char *name)
+{
+       pugi::xml_attribute attr = node.attribute(name);
+
+       if(attr) {
+               ustring ustr(attr.value());
+
+               if(enm.exists(ustr)) {
+                       *str = ustr;
+                       return true;
+               }
+               else
+                       fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", ustr.c_str(), name);
+       }
+
+       return false;
+}
+
+/* Film */
+
+static void xml_read_film(const XMLReadState& state, pugi::xml_node node)
+{
+       Camera *cam = state.scene->camera;
+
+       xml_read_int(&cam->width, node, "width");
+       xml_read_int(&cam->height, node, "height");
+
+       float aspect = (float)cam->width/(float)cam->height;
+
+       if(cam->width >= cam->height) {
+               cam->left = -aspect;
+               cam->right = aspect;
+               cam->bottom = -1.0f;
+               cam->top = 1.0f;
+       }
+       else {
+               cam->left = -1.0f;
+               cam->right = 1.0f;
+               cam->bottom = -1.0f/aspect;
+               cam->top = 1.0f/aspect;
+       }
+
+       cam->need_update = true;
+       cam->update();
+}
+
+/* Integrator */
+
+static void xml_read_integrator(const XMLReadState& state, pugi::xml_node node)
+{
+       Integrator *integrator = state.scene->integrator;
+
+       xml_read_int(&integrator->min_bounce, node, "min_bounce");
+       xml_read_int(&integrator->max_bounce, node, "max_bounce");
+       xml_read_bool(&integrator->no_caustics, node, "no_caustics");
+       xml_read_float(&integrator->blur_caustics, node, "blur_caustics");
+}
+
+/* Camera */
+
+static void xml_read_camera(const XMLReadState& state, pugi::xml_node node)
+{
+       Camera *cam = state.scene->camera;
+
+       if(xml_read_float(&cam->fov, node, "fov"))
+               cam->fov *= M_PI/180.0f;
+
+       xml_read_float(&cam->nearclip, node, "nearclip");
+       xml_read_float(&cam->farclip, node, "farclip");
+       xml_read_float(&cam->aperturesize, node, "aperturesize"); // 0.5*focallength/fstop
+       xml_read_float(&cam->focaldistance, node, "focaldistance");
+       xml_read_float(&cam->shutteropen, node, "shutteropen");
+       xml_read_float(&cam->shutterclose, node, "shutterclose");
+
+       if(xml_equal_string(node, "type", "orthographic"))
+               cam->ortho = true;
+       else if(xml_equal_string(node, "type", "perspective"))
+               cam->ortho = false;
+
+       cam->matrix = state.tfm;
+
+       cam->need_update = true;
+       cam->update();
+}
+
+/* Shader */
+
+static string xml_socket_name(const char *name)
+{
+       string sname = name;
+       size_t i;
+
+       while((i = sname.find(" ")) != string::npos)
+               sname.replace(i, 1, "");
+       
+       return sname;
+}
+
+static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pugi::xml_node graph_node)
+{
+       ShaderGraph *graph = new ShaderGraph();
+
+       map<string, ShaderNode*> nodemap;
+
+       nodemap["output"] = graph->output();
+
+       for(pugi::xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
+               ShaderNode *snode = NULL;
+
+               if(string_iequals(node.name(), "image_texture")) {
+                       ImageTextureNode *img = new ImageTextureNode();
+
+                       xml_read_string(&img->filename, node, "src");
+                       img->filename = path_join(state.base, img->filename);
+
+                       snode = img;
+               }
+               else if(string_iequals(node.name(), "environment_texture")) {
+                       EnvironmentTextureNode *env = new EnvironmentTextureNode();
+
+                       xml_read_string(&env->filename, node, "src");
+                       env->filename = path_join(state.base, env->filename);
+
+                       snode = env;
+               }
+               else if(string_iequals(node.name(), "sky_texture")) {
+                       SkyTextureNode *sky = new SkyTextureNode();
+
+                       xml_read_float3(&sky->sun_direction, node, "sun_direction");
+                       xml_read_float(&sky->turbidity, node, "turbidity");
+                       
+                       snode = sky;
+               }
+               else if(string_iequals(node.name(), "noise_texture")) {
+                       snode = new NoiseTextureNode();
+               }
+               else if(string_iequals(node.name(), "blend_texture")) {
+                       BlendTextureNode *blend = new BlendTextureNode();
+                       xml_read_enum(&blend->progression, BlendTextureNode::progression_enum, node, "progression");
+                       xml_read_enum(&blend->axis, BlendTextureNode::axis_enum, node, "axis");
+                       snode = blend;
+               }
+               else if(string_iequals(node.name(), "clouds_texture")) {
+                       CloudsTextureNode *clouds = new CloudsTextureNode();
+                       xml_read_bool(&clouds->hard, node, "hard");
+                       xml_read_int(&clouds->depth, node, "depth");
+                       xml_read_enum(&clouds->basis, CloudsTextureNode::basis_enum, node, "basis");
+                       snode = clouds;
+               }
+               else if(string_iequals(node.name(), "voronoi_texture")) {
+                       VoronoiTextureNode *voronoi = new VoronoiTextureNode();
+                       xml_read_enum(&voronoi->distance_metric, VoronoiTextureNode::distance_metric_enum, node, "distance_metric");
+                       xml_read_enum(&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring");
+                       snode = voronoi;
+               }
+               else if(string_iequals(node.name(), "musgrave_texture")) {
+                       MusgraveTextureNode *musgrave = new MusgraveTextureNode();
+                       xml_read_enum(&musgrave->type, MusgraveTextureNode::type_enum, node, "type");
+                       xml_read_enum(&musgrave->basis, MusgraveTextureNode::basis_enum, node, "basis");
+                       snode = musgrave;
+               }
+               else if(string_iequals(node.name(), "marble_texture")) {
+                       MarbleTextureNode *marble = new MarbleTextureNode();
+                       xml_read_enum(&marble->type, MarbleTextureNode::type_enum, node, "type");
+                       xml_read_enum(&marble->wave, MarbleTextureNode::wave_enum, node, "wave");
+                       xml_read_enum(&marble->basis, MarbleTextureNode::basis_enum, node, "basis");
+                       xml_read_bool(&marble->hard, node, "hard");
+                       xml_read_int(&marble->depth, node, "depth");
+                       snode = marble;
+               }
+               else if(string_iequals(node.name(), "magic_texture")) {
+                       MagicTextureNode *magic = new MagicTextureNode();
+                       xml_read_int(&magic->depth, node, "depth");
+                       snode = magic;
+               }
+               else if(string_iequals(node.name(), "stucci_texture")) {
+                       StucciTextureNode *stucci = new StucciTextureNode();
+                       xml_read_enum(&stucci->type, StucciTextureNode::type_enum, node, "type");
+                       xml_read_enum(&stucci->basis, StucciTextureNode::basis_enum, node, "basis");
+                       xml_read_bool(&stucci->hard, node, "hard");
+                       snode = stucci;
+               }
+               else if(string_iequals(node.name(), "distorted_noise_texture")) {
+                       DistortedNoiseTextureNode *dist = new DistortedNoiseTextureNode();
+                       xml_read_enum(&dist->basis, DistortedNoiseTextureNode::basis_enum, node, "basis");
+                       xml_read_enum(&dist->distortion_basis, DistortedNoiseTextureNode::basis_enum, node, "distortion_basis");
+                       snode = dist;
+               }
+               else if(string_iequals(node.name(), "wood_texture")) {
+                       WoodTextureNode *wood = new WoodTextureNode();
+                       xml_read_enum(&wood->type, WoodTextureNode::type_enum, node, "type");
+                       xml_read_enum(&wood->wave, WoodTextureNode::wave_enum, node, "wave");
+                       xml_read_enum(&wood->basis, WoodTextureNode::basis_enum, node, "basis");
+                       xml_read_bool(&wood->hard, node, "hard");
+                       snode = wood;
+               }
+               else if(string_iequals(node.name(), "mapping")) {
+                       snode = new MappingNode();
+               }
+               else if(string_iequals(node.name(), "ward_bsdf")) {
+                       snode = new WardBsdfNode();
+               }
+               else if(string_iequals(node.name(), "diffuse_bsdf")) {
+                       snode = new DiffuseBsdfNode();
+               }
+               else if(string_iequals(node.name(), "translucent_bsdf")) {
+                       snode = new TranslucentBsdfNode();
+               }
+               else if(string_iequals(node.name(), "transparent_bsdf")) {
+                       snode = new TransparentBsdfNode();
+               }
+               else if(string_iequals(node.name(), "velvet_bsdf")) {
+                       snode = new VelvetBsdfNode();
+               }
+               else if(string_iequals(node.name(), "glossy_bsdf")) {
+                       GlossyBsdfNode *glossy = new GlossyBsdfNode();
+                       xml_read_enum(&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution");
+                       snode = glossy;
+               }
+               else if(string_iequals(node.name(), "glass_bsdf")) {
+                       GlassBsdfNode *diel = new GlassBsdfNode();
+                       xml_read_enum(&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution");
+                       snode = diel;
+               }
+               else if(string_iequals(node.name(), "emission")) {
+                       EmissionNode *emission = new EmissionNode();
+                       xml_read_bool(&emission->total_power, node, "total_power");
+                       snode = emission;
+               }
+               else if(string_iequals(node.name(), "background")) {
+                       snode = new BackgroundNode();
+               }
+               else if(string_iequals(node.name(), "transparent_volume")) {
+                       snode = new TransparentVolumeNode();
+               }
+               else if(string_iequals(node.name(), "isotropic_volume")) {
+                       snode = new IsotropicVolumeNode();
+               }
+               else if(string_iequals(node.name(), "geometry")) {
+                       snode = new GeometryNode();
+               }
+               else if(string_iequals(node.name(), "texture_coordinate")) {
+                       snode = new TextureCoordinateNode();
+               }
+               else if(string_iequals(node.name(), "lightPath")) {
+                       snode = new LightPathNode();
+               }
+               else if(string_iequals(node.name(), "value")) {
+                       ValueNode *value = new ValueNode();
+                       xml_read_float(&value->value, node, "value");
+                       snode = value;
+               }
+               else if(string_iequals(node.name(), "color")) {
+                       ColorNode *color = new ColorNode();
+                       xml_read_float3(&color->value, node, "value");
+                       snode = color;
+               }
+               else if(string_iequals(node.name(), "mix_closure")) {
+                       snode = new MixClosureNode();
+               }
+               else if(string_iequals(node.name(), "add_closure")) {
+                       snode = new AddClosureNode();
+               }
+               else if(string_iequals(node.name(), "mix")) {
+                       MixNode *mix = new MixNode();
+                       xml_read_enum(&mix->type, MixNode::type_enum, node, "type");
+                       snode = mix;
+               }
+               else if(string_iequals(node.name(), "attribute")) {
+                       AttributeNode *attr = new AttributeNode();
+                       xml_read_ustring(&attr->attribute, node, "attribute");
+                       snode = attr;
+               }
+               else if(string_iequals(node.name(), "fresnel")) {
+                       snode = new FresnelNode();
+               }
+               else if(string_iequals(node.name(), "math")) {
+                       MathNode *math = new MathNode();
+                       xml_read_enum(&math->type, MathNode::type_enum, node, "type");
+                       snode = math;
+               }
+               else if(string_iequals(node.name(), "vector_math")) {
+                       VectorMathNode *vmath = new VectorMathNode();
+                       xml_read_enum(&vmath->type, VectorMathNode::type_enum, node, "type");
+                       snode = vmath;
+               }
+               else if(string_iequals(node.name(), "connect")) {
+                       /* connect nodes */
+                       vector<string> from_tokens, to_tokens;
+
+                       string_split(from_tokens, node.attribute("from").value());
+                       string_split(to_tokens, node.attribute("to").value());
+
+                       if(from_tokens.size() == 2 && to_tokens.size() == 2) {
+                               /* find nodes and sockets */
+                               ShaderOutput *output = NULL;
+                               ShaderInput *input = NULL;
+
+                               if(nodemap.find(from_tokens[0]) != nodemap.end()) {
+                                       ShaderNode *fromnode = nodemap[from_tokens[0]];
+
+                                       foreach(ShaderOutput *out, fromnode->outputs)
+                                               if(string_iequals(xml_socket_name(out->name), from_tokens[1]))
+                                                       output = out;
+
+                                       if(!output)
+                                               fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_tokens[1].c_str(), from_tokens[0].c_str());
+                               }
+                               else
+                                       fprintf(stderr, "Unknown shader node name \"%s\".\n", from_tokens[0].c_str());
+
+                               if(nodemap.find(to_tokens[0]) != nodemap.end()) {
+                                       ShaderNode *tonode = nodemap[to_tokens[0]];
+
+                                       foreach(ShaderInput *in, tonode->inputs)
+                                               if(string_iequals(xml_socket_name(in->name), to_tokens[1]))
+                                                       input = in;
+
+                                       if(!input)
+                                               fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_tokens[1].c_str(), to_tokens[0].c_str());
+                               }
+                               else
+                                       fprintf(stderr, "Unknown shader node name \"%s\".\n", to_tokens[0].c_str());
+
+                               /* connect */
+                               if(output && input)
+                                       graph->connect(output, input);
+                       }
+                       else
+                               fprintf(stderr, "Invalid from or to value for connect node.\n");
+               }
+               else
+                       fprintf(stderr, "Unknown shader node \"%s\".\n", node.name());
+
+               if(snode) {
+                       /* add to graph */
+                       graph->add(snode);
+
+                       /* add to map for name lookups */
+                       string name = "";
+                       xml_read_string(&name, node, "name");
+
+                       nodemap[name] = snode;
+
+                       /* read input values */
+                       for(pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) {
+                               foreach(ShaderInput *in, snode->inputs) {
+                                       if(string_iequals(in->name, attr.name())) {
+                                               switch(in->type) {
+                                                       case SHADER_SOCKET_FLOAT:
+                                                               xml_read_float(&in->value.x, node, attr.name());
+                                                               break;
+                                                       case SHADER_SOCKET_COLOR:
+                                                       case SHADER_SOCKET_VECTOR:
+                                                       case SHADER_SOCKET_POINT:
+                                                       case SHADER_SOCKET_NORMAL:
+                                                               xml_read_float3(&in->value, node, attr.name());
+                                                               break;
+                                                       default:
+                                                               break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       shader->set_graph(graph);
+       shader->tag_update(state.scene);
+}
+
+static void xml_read_shader(const XMLReadState& state, pugi::xml_node node)
+{
+       Shader *shader = new Shader();
+       xml_read_string(&shader->name, node, "name");
+       xml_read_shader_graph(state, shader, node);
+       state.scene->shaders.push_back(shader);
+}
+
+/* Background */
+
+static void xml_read_background(const XMLReadState& state, pugi::xml_node node)
+{
+       Shader *shader = state.scene->shaders[state.scene->default_background];
+
+       xml_read_shader_graph(state, shader, node);
+}
+
+/* Mesh */
+
+static Mesh *xml_add_mesh(Scene *scene, const Transform& tfm)
+{
+       /* create mesh */
+       Mesh *mesh = new Mesh();
+       scene->meshes.push_back(mesh);
+
+       /* create object*/
+       Object *object = new Object();
+       object->mesh = mesh;
+       object->tfm = tfm;
+       scene->objects.push_back(object);
+
+       return mesh;
+}
+
+static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
+{
+       /* add mesh */
+       Mesh *mesh = xml_add_mesh(state.scene, state.tfm);
+       mesh->used_shaders.push_back(state.shader);
+
+       /* read state */
+       int shader = state.shader;
+       bool smooth = state.smooth;
+
+       mesh->displacement_method = state.displacement_method;
+
+       /* read vertices and polygons, RIB style */
+       vector<float3> P;
+       vector<int> verts, nverts;
+
+       xml_read_float3_array(P, node, "P");
+       xml_read_int_array(verts, node, "verts");
+       xml_read_int_array(nverts, node, "nverts");
+
+       if(xml_equal_string(node, "subdivision", "catmull-clark")) {
+               /* create subd mesh */
+               SubdMesh sdmesh;
+
+               /* create subd vertices */
+               for(size_t i = 0; i < P.size(); i++)
+                       sdmesh.add_vert(P[i]);
+
+               /* create subd faces */
+               int index_offset = 0;
+
+               for(size_t i = 0; i < nverts.size(); i++) {
+                       if(nverts[i] == 4) {
+                               int v0 = verts[index_offset + 0];
+                               int v1 = verts[index_offset + 1];
+                               int v2 = verts[index_offset + 2];
+                               int v3 = verts[index_offset + 3];
+
+                               sdmesh.add_face(v0, v1, v2, v3);
+                       }
+                       else {
+                               for(int j = 0; j < nverts[i]-2; j++) {
+                                       int v0 = verts[index_offset];
+                                       int v1 = verts[index_offset + j + 1];
+                                       int v2 = verts[index_offset + j + 2];;
+
+                                       sdmesh.add_face(v0, v1, v2);
+                               }
+                       }
+
+                       index_offset += nverts[i];
+               }
+
+               /* finalize subd mesh */
+               sdmesh.link_boundary();
+
+               /* subdivide */
+               DiagSplit dsplit;
+               //dsplit.camera = state.scene->camera;
+               //dsplit.dicing_rate = 5.0f;
+               dsplit.dicing_rate = state.dicing_rate;
+               xml_read_float(&dsplit.dicing_rate, node, "dicing_rate");
+               sdmesh.tesselate(&dsplit, false, mesh, shader, smooth);
+       }
+       else {
+               /* create vertices */
+               mesh->verts = P;
+
+               /* create triangles */
+               int index_offset = 0;
+
+               for(size_t i = 0; i < nverts.size(); i++) {
+                       for(int j = 0; j < nverts[i]-2; j++) {
+                               int v0 = verts[index_offset];
+                               int v1 = verts[index_offset + j + 1];
+                               int v2 = verts[index_offset + j + 2];
+
+                               assert(v0 < (int)P.size());
+                               assert(v1 < (int)P.size());
+                               assert(v2 < (int)P.size());
+
+                               mesh->add_triangle(v0, v1, v2, shader, smooth);
+                       }
+
+                       index_offset += nverts[i];
+               }
+       }
+
+       /* temporary for test compatibility */
+       mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
+}
+
+/* Patch */
+
+static void xml_read_patch(const XMLReadState& state, pugi::xml_node node)
+{
+       /* read patch */
+       Patch *patch = NULL;
+
+       vector<float3> P;
+       xml_read_float3_array(P, node, "P");
+
+       if(xml_equal_string(node, "type", "bilinear")) {
+               /* bilinear patch */
+               if(P.size() == 4) {
+                       LinearQuadPatch *bpatch = new LinearQuadPatch();
+
+                       for(int i = 0; i < 4; i++)
+                               P[i] = transform(&state.tfm, P[i]);
+                       memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
+
+                       patch = bpatch;
+               }
+               else
+                       fprintf(stderr, "Invalid number of control points for bilinear patch.\n");
+       }
+       else if(xml_equal_string(node, "type", "bicubic")) {
+               /* bicubic patch */
+               if(P.size() == 16) {
+                       BicubicPatch *bpatch = new BicubicPatch();
+
+                       for(int i = 0; i < 16; i++)
+                               P[i] = transform(&state.tfm, P[i]);
+                       memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
+
+                       patch = bpatch;
+               }
+               else
+                       fprintf(stderr, "Invalid number of control points for bicubic patch.\n");
+       }
+       else
+               fprintf(stderr, "Unknown patch type.\n");
+
+       if(patch) {
+               /* add mesh */
+               Mesh *mesh = xml_add_mesh(state.scene, transform_identity());
+
+               mesh->used_shaders.push_back(state.shader);
+
+               /* split */
+               DiagSplit dsplit;
+               //dsplit.camera = state.scene->camera;
+               //dsplit.dicing_rate = 5.0f;
+               dsplit.dicing_rate = state.dicing_rate;
+               xml_read_float(&dsplit.dicing_rate, node, "dicing_rate");
+               dsplit.split_quad(mesh, patch, state.shader, state.smooth);
+
+               delete patch;
+
+               /* temporary for test compatibility */
+               mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
+       }
+}
+
+/* Light */
+
+static void xml_read_light(const XMLReadState& state, pugi::xml_node node)
+{
+       Light *light = new Light();
+       light->shader = state.shader;
+       xml_read_float3(&light->co, node, "P");
+       light->co = transform(&state.tfm, light->co);
+
+       state.scene->lights.push_back(light);
+}
+
+/* Transform */
+
+static void xml_read_transform(pugi::xml_node node, Transform& tfm)
+{
+       if(node.attribute("matrix")) {
+               vector<float> matrix;
+               if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16)
+                       tfm = tfm * transform_transpose((*(Transform*)&matrix[0]));
+       }
+
+       if(node.attribute("translate")) {
+               float3 translate = make_float3(0.0f, 0.0f, 0.0f);
+               xml_read_float3(&translate, node, "translate");
+               tfm = tfm * transform_translate(translate);
+       }
+
+       if(node.attribute("rotate")) {
+               float4 rotate = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+               xml_read_float4(&rotate, node, "rotate");
+               tfm = tfm * transform_rotate(rotate.x*M_PI/180.0f, make_float3(rotate.y, rotate.z, rotate.w));
+       }
+
+       if(node.attribute("scale")) {
+               float3 scale = make_float3(0.0f, 0.0f, 0.0f);
+               xml_read_float3(&scale, node, "scale");
+               tfm = tfm * transform_scale(scale);
+       }
+}
+
+/* State */
+
+static void xml_read_state(XMLReadState& state, pugi::xml_node node)
+{
+       /* read shader */
+       string shadername;
+
+       if(xml_read_string(&shadername, node, "shader")) {
+               int i = 0;
+               bool found = false;
+
+               foreach(Shader *shader, state.scene->shaders) {
+                       if(shader->name == shadername) {
+                               state.shader = i;
+                               found = true;
+                               break;
+                       }
+
+                       i++;
+               }
+
+               if(!found)
+                       fprintf(stderr, "Unknown shader \"%s\".\n", shadername.c_str());
+       }
+
+       xml_read_float(&state.dicing_rate, node, "dicing_rate");
+
+       /* read smooth/flat */
+       if(xml_equal_string(node, "interpolation", "smooth"))
+               state.smooth = true;
+       else if(xml_equal_string(node, "interpolation", "flat"))
+               state.smooth = false;
+
+       /* read displacement method */
+       if(xml_equal_string(node, "displacement_method", "true"))
+               state.displacement_method = Mesh::DISPLACE_TRUE;
+       else if(xml_equal_string(node, "displacement_method", "bump"))
+               state.displacement_method = Mesh::DISPLACE_BUMP;
+       else if(xml_equal_string(node, "displacement_method", "both"))
+               state.displacement_method = Mesh::DISPLACE_BOTH;
+}
+
+/* Scene */
+
+static void xml_read_include(const XMLReadState& state, const string& src);
+
+static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
+{
+       for(pugi::xml_node node = scene_node.first_child(); node; node = node.next_sibling()) {
+               if(string_iequals(node.name(), "film")) {
+                       xml_read_film(state, node);
+               }
+               else if(string_iequals(node.name(), "integrator")) {
+                       xml_read_integrator(state, node);
+               }
+               else if(string_iequals(node.name(), "camera")) {
+                       xml_read_camera(state, node);
+               }
+               else if(string_iequals(node.name(), "shader")) {
+                       xml_read_shader(state, node);
+               }
+               else if(string_iequals(node.name(), "background")) {
+                       xml_read_background(state, node);
+               }
+               else if(string_iequals(node.name(), "mesh")) {
+                       xml_read_mesh(state, node);
+               }
+               else if(string_iequals(node.name(), "patch")) {
+                       xml_read_patch(state, node);
+               }
+               else if(string_iequals(node.name(), "light")) {
+                       xml_read_light(state, node);
+               }
+               else if(string_iequals(node.name(), "transform")) {
+                       XMLReadState substate = state;
+
+                       xml_read_transform(node, substate.tfm);
+                       xml_read_scene(substate, node);
+               }
+               else if(string_iequals(node.name(), "state")) {
+                       XMLReadState substate = state;
+
+                       xml_read_state(substate, node);
+                       xml_read_scene(substate, node);
+               }
+               else if(string_iequals(node.name(), "include")) {
+                       string src;
+
+                       if(xml_read_string(&src, node, "src"))
+                               xml_read_include(state, src);
+               }
+               else
+                       fprintf(stderr, "Unknown node \"%s\".\n", node.name());
+       }
+}
+
+/* Include */
+
+static void xml_read_include(const XMLReadState& state, const string& src)
+{
+       /* open XML document */
+       pugi::xml_document doc;
+       pugi::xml_parse_result parse_result;
+
+       string path = path_join(state.base, src);
+       parse_result = doc.load_file(path.c_str());
+
+       if(parse_result) {
+               XMLReadState substate = state;
+               substate.base = path_dirname(path);
+
+               xml_read_scene(substate, doc);
+       }
+       else
+               fprintf(stderr, "%s read error: %s\n", src.c_str(), parse_result.description());
+}
+
+/* File */
+
+void xml_read_file(Scene *scene, const char *filepath)
+{
+       XMLReadState state;
+
+       state.scene = scene;
+       state.tfm = transform_identity();
+       state.shader = scene->default_surface;
+       state.smooth = false;
+       state.dicing_rate = 0.1f;
+       state.base = path_dirname(filepath);
+
+       xml_read_include(state, path_filename(filepath));
+
+       scene->params.bvh_type = SceneParams::BVH_STATIC;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/app/cycles_xml.h b/intern/cycles/app/cycles_xml.h
new file mode 100644 (file)
index 0000000..90ec529
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __CYCLES_XML__
+#define __CYCLES_XML__
+
+CCL_NAMESPACE_BEGIN
+
+class Scene;
+
+void xml_read_file(Scene *scene, const char *filepath);
+
+CCL_NAMESPACE_END
+
+#endif /* __CYCLES_XML__ */
+
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a4f290f
--- /dev/null
@@ -0,0 +1,39 @@
+
+set(sources
+       blender_camera.cpp
+       blender_mesh.cpp
+       blender_object.cpp
+       blender_python.cpp
+       blender_session.cpp
+       blender_shader.cpp
+       blender_sync.cpp
+
+       blender_sync.h
+       blender_session.h
+       blender_util.h)
+
+set(addonfiles
+       addon/__init__.py
+       addon/engine.py 
+       addon/enums.py
+       addon/presets.py
+       addon/properties.py
+       addon/ui.py
+       addon/xml.py)
+
+include_directories(
+       ../render
+       ../device
+       ../kernel
+       ../kernel/svm
+       ../util
+       ../subd
+       ${BLENDER_INCLUDE_DIRS}
+       ${PYTHON_INCLUDE_DIRS}
+       ${GLEW_INCLUDE_PATH})
+
+blender_add_lib(bf_intern_cycles "${sources}" "" "")
+add_dependencies(bf_intern_cycles bf_rna)
+
+delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${addonfiles}" ${CYCLES_INSTALL_PATH})
+
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
new file mode 100644 (file)
index 0000000..979e3e8
--- /dev/null
@@ -0,0 +1,90 @@
+#
+# Copyright 2011, Blender Foundation.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+bl_info = {
+    "name": "Cycles Render Engine",
+    "author": "",
+    "version": (0,0),
+    "blender": (2, 5, 6),
+    "api": 34462,
+    "location": "Info header, render engine menu",
+    "description": "Cycles Render Engine integration.",
+    "warning": "",
+    "wiki_url": "",
+    "tracker_url": "",
+    "category": "Render"}
+
+import bpy
+
+from cycles import ui
+from cycles import properties
+from cycles import xml
+from cycles import engine
+from cycles import presets
+
+class CyclesRender(bpy.types.RenderEngine):
+    bl_idname = 'CYCLES'
+    bl_label = "Cycles"
+    bl_use_shading_nodes = True
+
+    def __init__(self):
+        engine.init()
+        self.session = None
+    
+    def __del__(self):
+        engine.free(self)
+
+    # final render
+    def update(self, data, scene):
+        engine.create(self, data, scene)
+        engine.update(self, data, scene)
+
+    def render(self, scene):
+        engine.render(self)
+
+    # preview render
+    # def preview_update(self, context, id):
+    #    pass
+    #
+    # def preview_render(self):
+    #    pass
+    
+    # viewport render
+    def view_update(self, context):
+        if not self.session:
+            engine.create(self, context.blend_data, context.scene,
+                context.region, context.space_data, context.region_data)
+        engine.update(self, context.blend_data, context.scene)
+
+    def view_draw(self, context):
+        engine.draw(self, context.region, context.space_data, context.region_data)
+
+def register():
+    properties.register()
+    ui.register()
+    xml.register()
+    presets.register()
+    bpy.utils.register_module(__name__)
+
+def unregister():
+    xml.unregister()
+    ui.unregister()
+    properties.unregister()
+    presets.unregister()
+    bpy.utils.unregister_module(__name__)
+
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
new file mode 100644 (file)
index 0000000..8cd7be5
--- /dev/null
@@ -0,0 +1,74 @@
+#
+# Copyright 2011, Blender Foundation.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+import bpy
+
+def init():
+    import libcycles_blender as lib
+    import os.path
+
+    path = os.path.dirname(__file__)
+    user_path = os.path.dirname(os.path.abspath(bpy.utils.user_resource('CONFIG', '')))
+
+    lib.init(path, user_path)
+
+def create(engine, data, scene, region = 0, v3d = 0, rv3d = 0):
+    import libcycles_blender as lib
+
+    data = data.as_pointer()
+    scene = scene.as_pointer()
+    if region:
+        region = region.as_pointer()
+    if v3d:
+        v3d = v3d.as_pointer()
+    if rv3d:
+        rv3d = rv3d.as_pointer()
+
+    engine.session = lib.create(engine.as_pointer(), data, scene, region, v3d, rv3d)
+
+def free(engine):
+    if "session" in dir(engine):
+        if engine.session:
+            import libcycles_blender as lib
+            lib.free(engine.session)
+        del engine.session
+
+def render(engine):
+    import libcycles_blender as lib
+    lib.render(engine.session)
+
+def update(engine, data, scene):
+    import libcycles_blender as lib
+    lib.sync(engine.session)
+
+def draw(engine, region, v3d, rv3d):
+    import libcycles_blender as lib
+    v3d = v3d.as_pointer()
+    rv3d = rv3d.as_pointer()
+
+    # draw render image
+    lib.draw(engine.session, v3d, rv3d)
+
+def available_devices():
+    import libcycles_blender as lib
+    return lib.available_devices()
+
+def with_osl():
+    import libcycles_blender as lib
+    return lib.with_osl()
+
diff --git a/intern/cycles/blender/addon/enums.py b/intern/cycles/blender/addon/enums.py
new file mode 100644 (file)
index 0000000..4aef255
--- /dev/null
@@ -0,0 +1,59 @@
+#
+# Copyright 2011, Blender Foundation.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+from cycles import engine
+
+def get_gpu_device():
+    available_devices = engine.available_devices()
+    cuda = 'cuda' in available_devices
+    opencl = 'opencl' in available_devices
+    if cuda and opencl:
+        gpu_string = "GPU"
+    elif cuda and not opencl:
+        gpu_string = "CUDA GPU"
+    else:
+        gpu_string = "OpenCL GPU"
+    
+    return gpu_string
+
+devices = (
+("CPU", "CPU", "Processor"),
+("GPU", get_gpu_device(), "Graphics card"))
+
+gpu_type = (
+("CUDA", "CUDA", "NVidia only"),
+("OPENCL", "OpenCL (incomplete)", ""))
+
+shading_systems = (
+("GPU_COMPATIBLE", "GPU Compatible", "Restricted shading system compatible with GPU rendering"),
+("OSL", "Open Shading Language", "Open Shading Language shading system that only runs on the CPU"))
+
+displacement_methods = (
+("BUMP", "Bump", "Bump mapping to simulate the appearance of displacement"),
+("TRUE", "True", "Use true displacement only, requires fine subdivision"),
+("BOTH", "Both", "Combination of displacement and bump mapping"))
+
+bvh_types = (
+("DYNAMIC_BVH", "Dynamic BVH", "Objects can be individually updated, at the cost of slower render time"),
+("STATIC_BVH", "Static BVH", "Any object modification requires a complete BVH rebuild, but renders faster"))
+
+filter_types = (
+("BOX", "Box", "Box filter"),
+("GAUSSIAN", "Gaussian", "Gaussian filter"))
+
+
diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py
new file mode 100644 (file)
index 0000000..e5243b6
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# Copyright 2011, Blender Foundation.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+from bl_operators.presets import AddPresetBase
+from bpy.types import Operator
+
+class AddPresetIntegrator(AddPresetBase, Operator):
+    '''Add an Integrator Preset'''
+    bl_idname = "render.cycles_integrator_preset_add"
+    bl_label = "Add Integrator Preset"
+    preset_menu = "CYCLES_MT_integrator_presets"
+
+    preset_defines = [
+        "cycles = bpy.context.scene.cycles"
+    ]
+
+    preset_values = [
+        "cycles.max_bounces",
+        "cycles.min_bounces",
+        "cycles.no_caustics",
+        "cycles.diffuse_bounces",
+        "cycles.glossy_bounces",
+        "cycles.transmission_bounces",
+        "cycles.transparent_min_bounces",
+        "cycles.transparent_max_bounces"
+    ]
+
+    preset_subdir = "cycles/integrator"
+    
+def register():
+    pass
+
+def unregister():
+    pass
+    
+if __name__ == "__main__":
+    register()
+
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
new file mode 100644 (file)
index 0000000..a58e4df
--- /dev/null
@@ -0,0 +1,201 @@
+#
+# Copyright 2011, Blender Foundation.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+import bpy
+from bpy.props import *
+
+import math
+
+from cycles import enums
+
+class CyclesRenderSettings(bpy.types.PropertyGroup):
+    @classmethod
+    def register(cls):
+        bpy.types.Scene.cycles = PointerProperty(type=cls, name="Cycles Render Settings", description="Cycles render settings")
+
+        cls.device = EnumProperty(name="Device", description="Device to use for rendering",
+            items=enums.devices, default="CPU")
+            
+        cls.gpu_type = EnumProperty(name="GPU Type", description="Processing system to use on the GPU",
+            items=enums.gpu_type, default="CUDA")
+
+        cls.shading_system = EnumProperty(name="Shading System", description="Shading system to use for rendering",
+            items=enums.shading_systems, default="GPU_COMPATIBLE")
+
+        cls.samples = IntProperty(name="Samples", description="Number of samples to render for each pixel",
+            default=10, min=1, max=2147483647)
+        cls.preview_samples = IntProperty(name="Preview Samples", description="Number of samples to render in the viewport, unlimited if 0",
+            default=0, min=0, max=2147483647)
+        cls.preview_pause = BoolProperty(name="Pause Preview", description="Pause all viewport preview renders",
+            default=False)
+
+        cls.no_caustics = BoolProperty(name="No Caustics", description="Leave out caustics, resulting in a darker image with less noise",
+            default=False)
+        cls.blur_caustics = FloatProperty(name="Blur Caustics", description="Blur caustics to reduce noise",
+            default=0.0, min=0.0, max=1.0)
+
+        cls.min_bounces = IntProperty(name="Min Bounces", description="Minimum number of bounces, setting this lower than the maximum enables probalistic path termination (faster but noisier)",
+            default=3, min=0, max=1024)
+        cls.max_bounces = IntProperty(name="Max Bounces", description="Total maximum number of bounces",
+            default=8, min=0, max=1024)
+
+        cls.diffuse_bounces = IntProperty(name="Diffuse Bounces", description="Maximum number of diffuse reflection bounces, bounded by total maximum",
+            default=128, min=0, max=1024)
+        cls.glossy_bounces = IntProperty(name="Glossy Bounces", description="Maximum number of glossy reflection bounces, bounded by total maximum",
+            default=128, min=0, max=1024)
+        cls.transmission_bounces = IntProperty(name="Transmission Bounces", description="Maximum number of transmission bounces, bounded by total maximum",
+            default=128, min=0, max=1024)
+
+        cls.transparent_min_bounces = IntProperty(name="Transparent Min Bounces", description="Minimum number of transparent bounces, setting this lower than the maximum enables probalistic path termination (faster but noisier)",
+            default=8, min=0, max=1024)
+        cls.transparent_max_bounces = IntProperty(name="Transparent Max Bounces", description="Maximum number of transparent bounces",
+            default=8, min=0, max=1024)
+        cls.use_transparent_shadows = BoolProperty(name="Transparent Shadows", description="Use transparency of surfaces for rendering shadows",
+            default=True)
+
+        cls.film_exposure = FloatProperty(name="Exposure", description="Image brightness scale",
+            default=1.0, min=0.0, max=10.0)
+        cls.film_transparent = BoolProperty(name="Transparent", description="World background is transparent",
+            default=False)
+
+        cls.filter_type = EnumProperty(name="Filter Type", description="Pixel filter type",
+            items=enums.filter_types, default="GAUSSIAN")
+        cls.filter_width = FloatProperty(name="Filter Width", description="Pixel filter width",
+            default=1.5, min=0.01, max=10.0)
+
+        cls.seed = IntProperty(name="Seed", description="Seed value for integrator to get different noise patterns",
+            default=0, min=0, max=2147483647)
+
+        cls.debug_tile_size = IntProperty(name="Tile Size", description="",
+            default=1024, min=1, max=4096)
+        cls.debug_min_size = IntProperty(name="Min Size", description="",
+            default=64, min=1, max=4096)
+        cls.debug_reset_timeout = FloatProperty(name="Reset timeout", description="",
+            default=0.1, min=0.01, max=10.0)
+        cls.debug_cancel_timeout = FloatProperty(name="Cancel timeout", description="",
+            default=0.1, min=0.01, max=10.0)
+        cls.debug_text_timeout = FloatProperty(name="Text timeout", description="",
+            default=1.0, min=0.01, max=10.0)
+
+        cls.debug_bvh_type = EnumProperty(name="Viewport BVH Type", description="Choose between faster updates, or faster render",
+            items=enums.bvh_types, default="DYNAMIC_BVH")
+        cls.debug_use_spatial_splits = BoolProperty(name="Use Spatial Splits", description="Use BVH spatial splits: longer builder time, faster render",
+            default=False)
+
+    @classmethod
+    def unregister(cls):
+        del bpy.types.Scene.cycles
+
+class CyclesCameraSettings(bpy.types.PropertyGroup):
+    @classmethod
+    def register(cls):
+        bpy.types.Camera.cycles = PointerProperty(type=cls, name="Cycles Camera Settings", description="Cycles camera settings")
+
+        cls.aperture_size = FloatProperty(name="Aperture Size", description="Radius of the aperture for depth of field",
+            default=0.0, min=0.0, max=10.0)
+        cls.aperture_blades = IntProperty(name="Aperture Blades", description="Number of blades in aperture for polygonal bokeh (need 3 or more)",
+            default=0, min=0, max=100)
+        cls.aperture_rotation = FloatProperty(name="Aperture Rotation", description="Rotation of blades in aperture",
+            default=0, soft_min=-math.pi, soft_max=math.pi, subtype='ANGLE')
+    
+    @classmethod
+    def unregister(cls):
+        del bpy.types.Camera.cycles
+
+class CyclesMaterialSettings(bpy.types.PropertyGroup):
+    @classmethod
+    def register(cls):
+        bpy.types.Material.cycles = PointerProperty(type=cls, name="Cycles Material Settings", description="Cycles material settings")
+        cls.sample_as_light = BoolProperty(name="Sample as Light", description="Use direct light sampling, to reduce noise for small or strong emitting materials", default=True)
+        cls.homogeneous_volume = BoolProperty(name="Homogeneous Volume", description="When using volume rendering, assume volume has the same density everywhere, for faster rendering", default=False)
+
+    @classmethod
+    def unregister(cls):
+        del bpy.types.Material.cycles
+
+class CyclesLampSettings(bpy.types.PropertyGroup):
+    @classmethod
+    def register(cls):
+        bpy.types.Lamp.cycles = PointerProperty(type=cls, name="Cycles Lamp Settings", description="Cycles lamp settings")
+        cls.cast_shadow = BoolProperty(name="Cast Shadow", description="Lamp casts shadows", default=True)
+
+    @classmethod
+    def unregister(cls):
+        del bpy.types.Lamp.cycles
+
+class CyclesWorldSettings(bpy.types.PropertyGroup):
+    @classmethod
+    def register(cls):
+        bpy.types.World.cycles = PointerProperty(type=cls, name="Cycles World Settings", description="Cycles world settings")
+
+    @classmethod
+    def unregister(cls):
+        del bpy.types.World.cycles
+
+class CyclesVisibilitySettings(bpy.types.PropertyGroup):
+    @classmethod
+    def register(cls):
+        bpy.types.Object.cycles_visibility = PointerProperty(type=cls, name="Cycles Visibility Settings", description="Cycles visibility settings")
+
+        cls.camera = BoolProperty(name="Camera", description="Object visibility for camera rays", default=True)
+        cls.diffuse = BoolProperty(name="Diffuse", description="Object visibility for diffuse reflection rays", default=True)
+        cls.glossy = BoolProperty(name="Glossy", description="Object visibility for glossy reflection rays", default=True)
+        cls.transmission = BoolProperty(name="Transmission", description="Object visibility for transmission rays", default=True)
+        cls.shadow = BoolProperty(name="Shadow", description="Object visibility for shadow rays", default=True)
+
+    @classmethod
+    def unregister(cls):
+        del bpy.types.Object.cycles_visibility
+
+class CyclesMeshSettings(bpy.types.PropertyGroup):
+    @classmethod
+    def register(cls):
+        bpy.types.Mesh.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
+        bpy.types.Curve.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
+        bpy.types.MetaBall.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
+
+        cls.displacement_method = EnumProperty(name="Displacement Method", description="Method to use for the displacement",
+            items=enums.displacement_methods, default="BUMP")
+        cls.use_subdivision = BoolProperty(name="Use Subdivision", description="Subdivide mesh for rendering",
+            default=False)
+        cls.dicing_rate = FloatProperty(name="Dicing Rate", description="", default=1.0, min=0.001, max=1000.0)
+
+    @classmethod
+    def unregister(cls):
+        del bpy.types.Mesh.cycles
+        del bpy.types.Curve.cycles
+        del bpy.types.MetaBall.cycles
+
+def register():
+    bpy.utils.register_class(CyclesRenderSettings)
+    bpy.utils.register_class(CyclesCameraSettings)
+    bpy.utils.register_class(CyclesMaterialSettings)
+    bpy.utils.register_class(CyclesLampSettings)
+    bpy.utils.register_class(CyclesWorldSettings)
+    bpy.utils.register_class(CyclesVisibilitySettings)
+    bpy.utils.register_class(CyclesMeshSettings)
+    
+def unregister():
+    bpy.utils.unregister_class(CyclesRenderSettings)
+    bpy.utils.unregister_class(CyclesCameraSettings)
+    bpy.utils.unregister_class(CyclesMaterialSettings)
+    bpy.utils.unregister_class(CyclesLampSettings)
+    bpy.utils.unregister_class(CyclesWorldSettings)
+    bpy.utils.unregister_class(CyclesMeshSettings)
+    bpy.utils.unregister_class(CyclesVisibilitySettings)
+
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
new file mode 100644 (file)
index 0000000..ca077a5
--- /dev/null
@@ -0,0 +1,706 @@
+#
+# Copyright 2011, Blender Foundation.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+import bpy
+
+from bpy.types import Panel, Menu
+
+from cycles import enums
+from cycles import engine
+
+class CYCLES_MT_integrator_presets(Menu):
+    bl_label = "Integrator Presets"
+    preset_subdir = "cycles/integrator"
+    preset_operator = "script.execute_preset"
+    COMPAT_ENGINES = {'CYCLES'}
+    draw = Menu.draw_preset
+
+class CyclesButtonsPanel():
+    bl_space_type = "PROPERTIES"
+    bl_region_type = "WINDOW"
+    bl_context = "render"
+    
+    @classmethod
+    def poll(cls, context):
+        rd = context.scene.render
+        return rd.engine == 'CYCLES'
+
+class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
+    bl_label = "Integrator"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+        cscene = scene.cycles
+        
+        row = layout.row(align=True)
+        row.menu("CYCLES_MT_integrator_presets", text=bpy.types.CYCLES_MT_integrator_presets.bl_label)
+        row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMIN")
+        row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMOUT").remove_active = True
+
+        split = layout.split()
+
+        col = split.column()
+        sub = col.column(align=True)
+        sub.label(text="Samples:")
+        sub.prop(cscene, "samples", text="Render")
+        sub.prop(cscene, "preview_samples", text="Preview")
+        sub.prop(cscene, "seed")
+
+        sub = col.column(align=True)
+        sub.label("Transparency:")
+        sub.prop(cscene, "transparent_max_bounces", text="Max")
+        sub.prop(cscene, "transparent_min_bounces", text="Min")
+        sub.prop(cscene, "use_transparent_shadows", text="Shadows")
+
+        col = split.column()
+
+        sub = col.column(align=True)
+        sub.label(text="Bounces:")
+        sub.prop(cscene, "max_bounces", text="Max")
+        sub.prop(cscene, "min_bounces", text="Min")
+
+        sub = col.column(align=True)
+        sub.label(text="Light Paths:")
+        sub.prop(cscene, "diffuse_bounces", text="Diffuse")
+        sub.prop(cscene, "glossy_bounces", text="Glossy")
+        sub.prop(cscene, "transmission_bounces", text="Transmission")
+        sub.prop(cscene, "no_caustics")
+
+        #row = col.row()
+        #row.prop(cscene, "blur_caustics")
+        #row.active = not cscene.no_caustics
+        
+class CyclesRender_PT_film(CyclesButtonsPanel, Panel):
+    bl_label = "Film"
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+        cscene = scene.cycles
+
+        split = layout.split()
+
+        col = split.column();
+        col.prop(cscene, "film_exposure")
+        col.prop(cscene, "film_transparent")
+
+        col = split.column()
+        sub = col.column(align=True)
+        sub.prop(cscene, "filter_type", text="")
+        if cscene.filter_type != 'BOX':
+            sub.prop(cscene, "filter_width", text="Width")
+
+class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
+    bl_label = "Performance"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+        rd = scene.render
+        cscene = scene.cycles
+
+        split = layout.split()
+
+        col = split.column(align=True)
+
+        col.label(text="Threads:")
+        col.row().prop(rd, "threads_mode", expand=True)
+        sub = col.column()
+        sub.enabled = rd.threads_mode == 'FIXED'
+        sub.prop(rd, "threads")
+
+        sub = col.column(align=True)
+        sub.label(text="Tiles:")
+        sub.prop(cscene, "debug_tile_size")
+        sub.prop(cscene, "debug_min_size")
+
+        col = split.column()
+
+        sub = col.column(align=True)
+        sub.label(text="Acceleration structure:")
+        sub.prop(cscene, "debug_bvh_type", text="")
+        sub.prop(cscene, "debug_use_spatial_splits")
+
+class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
+    bl_label = "Layers"
+    bl_options = {'DEFAULT_CLOSED'}
+    COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+        rd = scene.render
+
+        # row = layout.row()
+        # row.template_list(rd, "layers", rd.layers, "active_index", rows=2)
+
+        # col = row.column(align=True)
+        # col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
+        # col.operator("scene.render_layer_remove", icon='ZOOMOUT', text="")
+
+        row = layout.row()
+        # rl = rd.layers.active
+        rl = rd.layers[0]
+        row.prop(rl, "name")
+        #row.prop(rd, "use_single_layer", text="", icon_only=True)
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(scene, "layers", text="Scene")
+
+        col = split.column()
+        col.prop(rl, "layers", text="Layer")
+
+        layout.separator()
+
+        layout.prop(rl, "material_override", text="Material")
+
+class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
+    bl_label = "Post Processing"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        rd = context.scene.render
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(rd, "use_compositing")
+        col.prop(rd, "use_sequencer")
+
+        col = split.column()
+        col.prop(rd, "dither_intensity", text="Dither", slider=True)
+
+class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel):
+    bl_label = "Depth of Field"
+    bl_context = "data"
+
+    @classmethod
+    def poll(cls, context):
+        return context.camera and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+
+        cam = context.camera
+        ccam = cam.cycles
+
+        split = layout.split()
+
+        col = split.column()
+        col.label("Focus:")
+        col.prop(cam, "dof_object", text="")
+
+        sub = col.row()
+        sub.active = cam.dof_object is None
+        sub.prop(cam, "dof_distance", text="Distance")
+
+        col = split.column()
+
+        col.label("Aperture:")
+        col.prop(ccam, "aperture_size", text="Size")
+
+        sub = col.column(align=True)
+        sub.prop(ccam, "aperture_blades", text="Blades")
+        sub.prop(ccam, "aperture_rotation", text="Rotation")
+
+class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
+    bl_label = "Surface"
+    bl_context = "material"
+    bl_options = {'HIDE_HEADER'}
+
+    @classmethod
+    def poll(cls, context):
+        return (context.material or context.object) and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+
+        mat = context.material
+        ob = context.object
+        slot = context.material_slot
+        space = context.space_data
+
+        if ob:
+            row = layout.row()
+
+            row.template_list(ob, "material_slots", ob, "active_material_index", rows=2)
+
+            col = row.column(align=True)
+            col.operator("object.material_slot_add", icon='ZOOMIN', text="")
+            col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
+
+            col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
+
+            if ob.mode == 'EDIT':
+                row = layout.row(align=True)
+                row.operator("object.material_slot_assign", text="Assign")
+                row.operator("object.material_slot_select", text="Select")
+                row.operator("object.material_slot_deselect", text="Deselect")
+
+        split = layout.split(percentage=0.65)
+
+        if ob:
+            split.template_ID(ob, "active_material", new="material.new")
+            row = split.row()
+
+            if slot:
+                row.prop(slot, "link", text="")
+            else:
+                row.label()
+        elif mat:
+            split.template_ID(space, "pin_id")
+            split.separator()
+
+class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
+    bl_label = "Displacement"
+    bl_context = "data"
+
+    @classmethod
+    def poll(cls, context):
+        return context.mesh or context.curve or context.meta_ball
+
+    def draw(self, context):
+        layout = self.layout
+
+        mesh = context.mesh
+        curve = context.curve
+        mball = context.meta_ball
+
+        if mesh:
+            cdata = mesh.cycles
+        elif curve:
+            cdata = curve.cycles
+        elif mball:
+            cdata = mball.cycles
+
+        layout.prop(cdata, "displacement_method", text="Method")
+        layout.prop(cdata, "use_subdivision");
+        layout.prop(cdata, "dicing_rate");
+
+class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
+    bl_label = "Ray Visibility"
+    bl_context = "object"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        ob = context.object
+        return ob and ob.type in ('MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META') # todo: 'LAMP'
+
+    def draw(self, context):
+        layout = self.layout
+
+        ob = context.object
+        visibility = ob.cycles_visibility
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(visibility, "camera")
+        col.prop(visibility, "diffuse")
+        col.prop(visibility, "glossy")
+
+        col = split.column()
+        col.prop(visibility, "transmission")
+        col.prop(visibility, "shadow")
+
+def find_node(material, nodetype):
+    if material and material.node_tree:
+        ntree = material.node_tree
+
+        for node in ntree.nodes:
+            if hasattr(node, 'type') and node.type == nodetype:
+                return node
+    
+    return None
+
+def find_node_input(node, name):
+    for input in node.inputs:
+        if input.name == name:
+            return input
+    
+    return None
+
+def panel_node_draw(layout, id, output_type, input_name):
+    if not id.node_tree:
+        layout.prop(id, "use_nodes", icon='NODETREE')
+        return
+
+    ntree = id.node_tree
+
+    node = find_node(id, output_type)
+    if not node:
+        layout.label(text="No output node.")
+    else:
+        input = find_node_input(node, input_name)
+        layout.template_node_view(ntree, node, input);
+
+class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
+    bl_label = "Lamp"
+    bl_context = "data"
+
+    @classmethod
+    def poll(cls, context):
+        return context.lamp and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+
+        lamp = context.lamp
+        clamp = lamp.cycles
+
+        layout.prop(lamp, "type", expand=True)
+
+        split = layout.split()
+        col = split.column(align=True)
+
+        if lamp.type in ('POINT', 'SUN', 'SPOT'):
+            col.prop(lamp, "shadow_soft_size", text="Size")
+        elif lamp.type == 'AREA':
+            col.prop(lamp, "shape", text="")
+            sub = col.column(align=True)
+
+            if lamp.shape == 'SQUARE':
+                sub.prop(lamp, "size")
+            elif lamp.shape == 'RECTANGLE':
+                sub.prop(lamp, "size", text="Size X")
+                sub.prop(lamp, "size_y", text="Size Y")
+
+        col = split.column()
+        col.prop(clamp, "cast_shadow")
+
+        if lamp.type == 'SPOT':
+            layout.label(text="Not supported, interpreted as point lamp.")
+        elif lamp.type == 'HEMI':
+            layout.label(text="Not supported, interpreted as sun lamp.")
+   
+class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
+    bl_label = "Nodes"
+    bl_context = "data"
+
+    @classmethod
+    def poll(cls, context):
+        return context.lamp and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+
+        mat = context.lamp
+        panel_node_draw(layout, mat, 'OUTPUT_LAMP', 'Surface')
+
+class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel):
+    bl_label = "Surface"
+    bl_context = "world"
+
+    @classmethod
+    def poll(cls, context):
+        return context.world and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+
+        mat = context.world
+        panel_node_draw(layout, mat, 'OUTPUT_WORLD', 'Surface')
+
+class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel):
+    bl_label = "Volume"
+    bl_context = "world"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        world = context.world
+        return world and world.node_tree and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+        layout.active = False
+
+        world = context.world
+        panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
+
+class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel):
+    bl_label = "Surface"
+    bl_context = "material"
+
+    @classmethod
+    def poll(cls, context):
+        return context.material and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+
+        mat = context.material
+        panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface')
+
+class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel):
+    bl_label = "Volume"
+    bl_context = "material"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        mat = context.material
+        return mat and mat.node_tree and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+        layout.active = False
+
+        mat = context.material
+        cmat = mat.cycles
+
+        panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
+
+        layout.prop(cmat, "homogeneous_volume")
+
+class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
+    bl_label = "Displacement"
+    bl_context = "material"
+
+    @classmethod
+    def poll(cls, context):
+        mat = context.material
+        return mat and mat.node_tree and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+
+        mat = context.material
+        panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
+
+class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
+    bl_label = "Settings"
+    bl_context = "material"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    @classmethod
+    def poll(cls, context):
+        return context.material and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+
+        mat = context.material
+        cmat = mat.cycles
+
+        split = layout.split()
+
+        col = split.column()
+        col.prop(mat, "diffuse_color", text="Viewport Color")
+
+        col = split.column()
+        col.prop(cmat, "sample_as_light")
+
+class CyclesTexture_PT_context(CyclesButtonsPanel, Panel):
+    bl_label = ""
+    bl_context = "texture"
+    bl_options = {'HIDE_HEADER'}
+    COMPAT_ENGINES = {'CYCLES'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        tex = context.texture
+        space = context.space_data
+        pin_id = space.pin_id
+        use_pin_id = space.use_pin_id;
+        user = context.texture_user
+        node = context.texture_node
+
+        if not use_pin_id or not isinstance(pin_id, bpy.types.Texture):
+            pin_id = None
+
+        if not pin_id:
+            layout.template_texture_user()
+
+        if user:
+            layout.separator()
+
+            split = layout.split(percentage=0.65)
+            col = split.column()
+
+            if pin_id:
+                col.template_ID(space, "pin_id")
+            elif user:
+                col.template_ID(user, "texture", new="texture.new")
+            
+            if tex:
+                row = split.row()
+                row.prop(tex, "use_nodes", icon="NODETREE", text="")
+                row.label()
+
+                if not tex.use_nodes:
+                    split = layout.split(percentage=0.2)
+                    split.label(text="Type:")
+                    split.prop(tex, "type", text="")
+
+class CyclesTexture_PT_nodes(CyclesButtonsPanel, Panel):
+    bl_label = "Nodes"
+    bl_context = "texture"
+
+    @classmethod
+    def poll(cls, context):
+        tex = context.texture
+        return (tex and tex.use_nodes) and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+
+        tex = context.texture
+        panel_node_draw(layout, tex, 'OUTPUT_TEXTURE', 'Color')
+
+class CyclesTexture_PT_node(CyclesButtonsPanel, Panel):
+    bl_label = "Node"
+    bl_context = "texture"
+
+    @classmethod
+    def poll(cls, context):
+        node = context.texture_node
+        return node and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+
+        node = context.texture_node
+        ntree = node.id_data
+        layout.template_node_view(ntree, node, None)
+
+class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel):
+    bl_label = "Mapping"
+    bl_context = "texture"
+
+    @classmethod
+    def poll(cls, context):
+        tex = context.texture
+        node = context.texture_node
+        return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+        layout.label("Texture coordinate mapping goes here.");
+        layout.label("Translate, rotate, scale, projection, XYZ.")
+
+class CyclesTexture_PT_color(CyclesButtonsPanel, Panel):
+    bl_label = "Color"
+    bl_context = "texture"
+
+    @classmethod
+    def poll(cls, context):
+        tex = context.texture
+        node = context.texture_node
+        return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
+
+    def draw(self, context):
+        layout = self.layout
+        layout.label("Color modification options go here.");
+        layout.label("Ramp, brightness, contrast, saturation.")
+
+def draw_device(self, context):
+    scene = context.scene
+    layout = self.layout
+
+    if scene.render.engine == "CYCLES":
+        cscene = scene.cycles
+
+        available_devices = engine.available_devices()
+        available_cuda = 'cuda' in available_devices
+        available_opencl = 'opencl' in available_devices
+
+        if available_cuda or available_opencl:
+            layout.prop(cscene, "device")
+            if cscene.device == 'GPU' and available_cuda and available_opencl:
+                layout.prop(cscene, "gpu_type")
+        if cscene.device == 'CPU' and engine.with_osl():
+            layout.prop(cscene, "shading_system")
+
+def draw_pause(self, context):
+    layout = self.layout
+    scene = context.scene
+
+    if scene.render.engine == "CYCLES":
+        view = context.space_data
+
+        if view.viewport_shade == "RENDERED":
+            cscene = scene.cycles
+            layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
+
+def get_panels():
+    return [
+        bpy.types.RENDER_PT_render,
+        bpy.types.RENDER_PT_output,
+        bpy.types.RENDER_PT_encoding,
+        bpy.types.RENDER_PT_dimensions,
+        bpy.types.RENDER_PT_stamp,
+        bpy.types.WORLD_PT_context_world,
+        bpy.types.DATA_PT_context_mesh,
+        bpy.types.DATA_PT_context_camera,
+        bpy.types.DATA_PT_context_lamp,
+        bpy.types.DATA_PT_texture_space,
+        bpy.types.DATA_PT_curve_texture_space,
+        bpy.types.DATA_PT_mball_texture_space,
+        bpy.types.DATA_PT_vertex_groups,
+        bpy.types.DATA_PT_shape_keys,
+        bpy.types.DATA_PT_uv_texture,
+        bpy.types.DATA_PT_vertex_colors,
+        bpy.types.DATA_PT_camera,
+        bpy.types.DATA_PT_camera_display,
+        bpy.types.DATA_PT_custom_props_mesh,
+        bpy.types.DATA_PT_custom_props_camera,
+        bpy.types.DATA_PT_custom_props_lamp,
+        bpy.types.TEXTURE_PT_clouds,
+        bpy.types.TEXTURE_PT_wood,
+        bpy.types.TEXTURE_PT_marble,
+        bpy.types.TEXTURE_PT_magic,
+        bpy.types.TEXTURE_PT_blend,
+        bpy.types.TEXTURE_PT_stucci,
+        bpy.types.TEXTURE_PT_image,
+        bpy.types.TEXTURE_PT_image_sampling,
+        bpy.types.TEXTURE_PT_image_mapping,
+        bpy.types.TEXTURE_PT_musgrave,
+        bpy.types.TEXTURE_PT_voronoi,
+        bpy.types.TEXTURE_PT_distortednoise,
+        bpy.types.TEXTURE_PT_voxeldata,
+        bpy.types.TEXTURE_PT_pointdensity,
+        bpy.types.TEXTURE_PT_pointdensity_turbulence]
+
+def register():
+    bpy.types.RENDER_PT_render.append(draw_device)
+    bpy.types.VIEW3D_HT_header.append(draw_pause)
+
+    for panel in get_panels():
+        panel.COMPAT_ENGINES.add('CYCLES')
+    
+def unregister():
+    bpy.types.RENDER_PT_render.remove(draw_device)
+    bpy.types.VIEW3D_HT_header.remove(draw_pause)
+
+    for panel in get_panels():
+        panel.COMPAT_ENGINES.remove('CYCLES')
+
diff --git a/intern/cycles/blender/addon/xml.py b/intern/cycles/blender/addon/xml.py
new file mode 100644 (file)
index 0000000..3713da0
--- /dev/null
@@ -0,0 +1,99 @@
+#
+# Copyright 2011, Blender Foundation.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+# XML exporter for generating test files, not intended for end users
+
+import os
+import bpy
+from bpy_extras.io_utils import ExportHelper
+import xml.etree.ElementTree as etree
+import xml.dom.minidom as dom
+
+def strip(root):
+    root.text = None
+    root.tail = None
+
+    for elem in root:
+        strip(elem)
+
+def write(node, fname):
+    strip(node)
+
+    s = etree.tostring(node)
+    s = dom.parseString(s).toprettyxml()
+
+    f = open(fname, "w")
+    f.write(s)
+
+class ExportCyclesXML(bpy.types.Operator, ExportHelper):
+    ''''''
+    bl_idname = "export_mesh.cycles_xml"
+    bl_label = "Export Cycles XML"
+
+    filename_ext = ".xml"
+
+    @classmethod
+    def poll(cls, context):
+        return context.active_object != None
+
+    def execute(self, context):
+        filepath = bpy.path.ensure_ext(self.filepath, ".xml")
+
+        # get mesh
+        scene = context.scene
+        object = context.object
+
+        if not object:
+            raise Exception("No active object")
+
+        mesh = object.to_mesh(scene, True, 'PREVIEW')
+
+        if not mesh:
+            raise Exception("No mesh data in active object")
+
+        # generate mesh node
+        nverts = ""
+        verts = ""
+        P = ""
+
+        for v in mesh.vertices:
+            P += "%f %f %f  " % (v.co[0], v.co[1], v.co[2])
+
+        for i, f in enumerate(mesh.faces):
+            nverts += str(len(f.vertices)) + " "
+
+            for v in f.vertices:
+                verts += str(v) + " "
+            verts += " "
+
+        node = etree.Element('mesh', attrib={'nverts': nverts, 'verts': verts, 'P': P})
+        
+        # write to file
+        write(node, filepath)
+
+        return {'FINISHED'}
+
+def register():
+    pass
+
+def unregister():
+    pass
+
+if __name__ == "__main__":
+    register()
+
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
new file mode 100644 (file)
index 0000000..e3b0fbd
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "camera.h"
+#include "scene.h"
+
+#include "blender_sync.h"
+#include "blender_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Blender Camera Intermediate: we first convert both the offline and 3d view
+ * render camera to this, and from there convert to our native camera format. */
+
+struct BlenderCamera {
+       float nearclip;
+       float farclip;
+
+       bool ortho;
+       float ortho_scale;
+
+       float lens;
+
+       float aperturesize;
+       uint apertureblades;
+       float aperturerotation;
+       float focaldistance;
+
+       float2 shift;
+       float2 offset;
+       float zoom;
+
+       float2 pixelaspect;
+
+       Transform matrix;
+};
+
+static void blender_camera_init(BlenderCamera *bcam)
+{
+       memset(bcam, 0, sizeof(BlenderCamera));
+
+       bcam->zoom = 1.0f;
+       bcam->pixelaspect = make_float2(1.0f, 1.0f);
+}
+
+static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
+{
+       BL::Object b_dof_object = b_camera.dof_object();
+
+       if(!b_dof_object)
+               return b_camera.dof_distance();
+       
+       /* for dof object, return distance along camera direction. this is
+        * compatible with blender, but does it fit our dof model? */
+       Transform obmat = get_transform(b_ob.matrix_world());
+       Transform dofmat = get_transform(b_dof_object.matrix_world());
+
+       float3 cam_p = transform_get_column(&obmat, 3);
+       float3 cam_dir = normalize(transform_get_column(&obmat, 2));
+       float3 dof_p = transform_get_column(&dofmat, 3);
+       float3 proj_p = dot(dof_p, cam_dir) * cam_dir;
+
+       return len(proj_p - cam_p);
+}
+
+static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob)
+{
+       BL::ID b_ob_data = b_ob.data();
+
+       if(b_ob_data.is_a(&RNA_Camera)) {
+               BL::Camera b_camera(b_ob_data);
+               PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
+
+               bcam->nearclip = b_camera.clip_start();
+               bcam->farclip = b_camera.clip_end();
+
+               bcam->ortho = (b_camera.type() == BL::Camera::type_ORTHO);
+               bcam->ortho_scale = b_camera.ortho_scale();
+
+               bcam->lens = b_camera.lens();
+               bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size");
+               bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
+               bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
+               bcam->focaldistance = blender_camera_focal_distance(b_ob, b_camera);
+
+               bcam->shift.x = b_camera.shift_x();
+               bcam->shift.y = b_camera.shift_y();
+       }
+       else {
+               /* from lamp not implemented yet */
+       }
+}
+
+static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int height)
+{
+       /* copy camera to compare later */
+       Camera prevcam = *cam;
+
+       /* dimensions */
+       float xratio = width*bcam->pixelaspect.x;
+       float yratio = height*bcam->pixelaspect.y;
+
+       /* compute x/y aspect and ratio */
+       float aspectratio, xaspect, yaspect;
+
+       if(xratio > yratio) {
+               aspectratio= xratio/yratio;
+               xaspect= aspectratio;
+               yaspect= 1.0f;
+       }
+       else {
+               aspectratio= yratio/xratio;
+               xaspect= 1.0f;
+               yaspect= aspectratio;
+       }
+
+       /* modify aspect for orthographic scale */
+       if(bcam->ortho) {
+               xaspect = xaspect*bcam->ortho_scale/(aspectratio*2.0f);
+               yaspect = yaspect*bcam->ortho_scale/(aspectratio*2.0f);
+               aspectratio = bcam->ortho_scale/2.0f;
+       }
+
+       /* set viewplane */
+       cam->left = -xaspect;
+       cam->right = xaspect;
+       cam->bottom = -yaspect;
+       cam->top = yaspect;
+
+       /* zoom for 3d camera view */
+       cam->left *= bcam->zoom;
+       cam->right *= bcam->zoom;
+       cam->bottom *= bcam->zoom;
+       cam->top *= bcam->zoom;
+
+       /* modify viewplane with camera shift and 3d camera view offset */
+       float dx = 2.0f*(aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f);
+       float dy = 2.0f*(aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f);
+
+       cam->left += dx;
+       cam->right += dx;
+       cam->bottom += dy;
+       cam->top += dy;
+
+       /* clipping distances */
+       cam->nearclip = bcam->nearclip;
+       cam->farclip = bcam->farclip;
+
+       /* orthographic */
+       cam->ortho = bcam->ortho;
+
+       /* perspective */
+       cam->fov = 2.0f*atan(16.0f/bcam->lens/aspectratio);
+       cam->focaldistance = bcam->focaldistance;
+       cam->aperturesize = bcam->aperturesize;
+       cam->blades = bcam->apertureblades;
+       cam->bladesrotation = bcam->aperturerotation;
+
+       /* transform, note the blender camera points along the negative z-axis */
+       cam->matrix = bcam->matrix * transform_scale(1.0f, 1.0f, -1.0f);
+
+       /* set update flag */
+       if(cam->modified(prevcam))
+               cam->tag_update();
+}
+
+/* Sync Render Camera */
+
+void BlenderSync::sync_camera(int width, int height)
+{
+       BlenderCamera bcam;
+       blender_camera_init(&bcam);
+
+       /* pixel aspect */
+       BL::RenderSettings r = b_scene.render();
+
+       bcam.pixelaspect.x = r.pixel_aspect_x();
+       bcam.pixelaspect.y = r.pixel_aspect_y();
+
+       /* camera object */
+       BL::Object b_ob = b_scene.camera();
+
+       if(b_ob) {
+               blender_camera_from_object(&bcam, b_ob);
+               bcam.matrix = get_transform(b_ob.matrix_world());
+       }
+
+       /* sync */
+       Camera *cam = scene->camera;
+       blender_camera_sync(cam, &bcam, width, height);
+}
+
+/* Sync 3D View Camera */
+
+void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
+{
+       BlenderCamera bcam;
+       blender_camera_init(&bcam);
+
+       /* 3d view parameters */
+       bcam.nearclip = b_v3d.clip_start();
+       bcam.farclip = b_v3d.clip_end();
+       bcam.lens = b_v3d.lens();
+
+       if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
+               /* camera view */
+               BL::Object b_ob = b_scene.camera();
+
+               if(b_ob) {
+                       blender_camera_from_object(&bcam, b_ob);
+
+                       /* magic zoom formula */
+                       bcam.zoom = (float)b_rv3d.view_camera_zoom();
+                       bcam.zoom = (1.41421f + bcam.zoom/50.0f);
+                       bcam.zoom *= bcam.zoom;
+                       bcam.zoom = 2.0f/bcam.zoom;
+
+                       /* offset */
+                       bcam.offset = get_float2(b_rv3d.view_camera_offset());
+               }
+       }
+       else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
+               /* orthographic view */
+               bcam.farclip *= 0.5;
+               bcam.nearclip = -bcam.farclip;
+
+               bcam.ortho = true;
+               bcam.ortho_scale = b_rv3d.view_distance();
+       }
+
+       bcam.zoom *= 2.0f;
+
+       /* 3d view transform */
+       bcam.matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
+
+       /* sync */
+       blender_camera_sync(scene->camera, &bcam, width, height);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
new file mode 100644 (file)
index 0000000..3bf83fa
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "mesh.h"
+#include "object.h"
+#include "scene.h"
+
+#include "blender_sync.h"
+#include "blender_util.h"
+
+#include "subd_mesh.h"
+#include "subd_patch.h"
+#include "subd_split.h"
+
+#include "util_foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Find/Add */
+
+static bool mesh_need_attribute(Scene *scene, Mesh *mesh, Attribute::Standard std)
+{
+       if(std == Attribute::STD_NONE)
+               return false;
+
+       foreach(uint shader, mesh->used_shaders)
+               if(scene->shaders[shader]->attributes.find(std))
+                       return true;
+       
+       return false;
+}
+
+static bool mesh_need_attribute(Scene *scene, Mesh *mesh, ustring name)
+{
+       if(name == ustring())
+               return false;
+
+       foreach(uint shader, mesh->used_shaders)
+               if(scene->shaders[shader]->attributes.find(name))
+                       return true;
+       
+       return false;
+}
+
+static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
+{
+       /* create vertices */
+       BL::Mesh::vertices_iterator v;
+
+       for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
+               mesh->verts.push_back(get_float3(v->co()));
+
+       /* create vertex normals */
+       Attribute *attr_N = mesh->attributes.add(Attribute::STD_VERTEX_NORMAL);
+       float3 *N = attr_N->data_float3();
+
+       for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
+               *N= get_float3(v->normal());
+
+       /* create faces */
+       BL::Mesh::faces_iterator f;
+       vector<int> nverts;
+
+       for(b_mesh.faces.begin(f); f != b_mesh.faces.end(); ++f) {
+               int4 vi = get_int4(f->vertices_raw());
+               int n= (vi[3] == 0)? 3: 4;
+               int shader = used_shaders[f->material_index()];
+               bool smooth = f->use_smooth();
+
+               mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
+
+               if(n == 4)
+                       mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
+
+               nverts.push_back(n);
+       }
+
+       /* create generated coordinates. todo: we should actually get the orco
+          coordinates from modifiers, for now we use texspace loc/size which
+          is available in the api. */
+       if(mesh_need_attribute(scene, mesh, Attribute::STD_GENERATED)) {
+               Attribute *attr = mesh->attributes.add(Attribute::STD_GENERATED);
+               float3 loc = get_float3(b_mesh.texspace_location());
+               float3 size = get_float3(b_mesh.texspace_size());
+
+               if(size.x != 0.0f) size.x = 0.5f/size.x;
+               if(size.y != 0.0f) size.y = 0.5f/size.y;
+               if(size.z != 0.0f) size.z = 0.5f/size.z;
+
+               loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
+
+               float3 *fdata = attr->data_float3();
+               BL::Mesh::vertices_iterator v;
+               size_t i = 0;
+
+               for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
+                       fdata[i++] = get_float3(v->co())*size - loc;
+       }
+
+       /* create vertex color attributes */
+       {
+               BL::Mesh::vertex_colors_iterator l;
+
+               for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) {
+                       if(!mesh_need_attribute(scene, mesh, ustring(l->name().c_str())))
+                               continue;
+
+                       Attribute *attr = mesh->attributes.add(
+                               ustring(l->name().c_str()), TypeDesc::TypeColor, Attribute::CORNER);
+
+                       BL::MeshColorLayer::data_iterator c;
+                       float3 *fdata = attr->data_float3();
+                       size_t i = 0;
+
+                       for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
+                               fdata[0] = color_srgb_to_scene_linear(get_float3(c->color1()));
+                               fdata[1] = color_srgb_to_scene_linear(get_float3(c->color2()));
+                               fdata[2] = color_srgb_to_scene_linear(get_float3(c->color3()));
+
+                               if(nverts[i] == 4) {
+                                       fdata[3] = fdata[0];
+                                       fdata[4] = fdata[2];
+                                       fdata[5] = color_srgb_to_scene_linear(get_float3(c->color4()));
+                                       fdata += 6;
+                               }
+                               else
+                                       fdata += 3;
+                       }
+               }
+       }
+
+       /* create uv layer attributes */
+       {
+               BL::Mesh::uv_textures_iterator l;
+
+               for(b_mesh.uv_textures.begin(l); l != b_mesh.uv_textures.end(); ++l) {
+                       Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
+                       ustring name = ustring(l->name().c_str());
+
+                       if(!(mesh_need_attribute(scene, mesh, name) || mesh_need_attribute(scene, mesh, std)))
+                               continue;
+
+                       Attribute *attr;
+
+                       if(l->active_render())
+                               attr = mesh->attributes.add(std, name);
+                       else
+                               attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);
+
+                       BL::MeshTextureFaceLayer::data_iterator t;
+                       float3 *fdata = attr->data_float3();
+                       size_t i = 0;
+
+                       for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
+                               fdata[0] =  get_float3(t->uv1());
+                               fdata[1] =  get_float3(t->uv2());
+                               fdata[2] =  get_float3(t->uv3());
+                               fdata += 3;
+
+                               if(nverts[i] == 4) {
+                                       fdata[0] =  get_float3(t->uv1());
+                                       fdata[1] =  get_float3(t->uv3());
+                                       fdata[2] =  get_float3(t->uv4());
+                                       fdata += 3;
+                               }
+                       }
+               }
+       }
+}
+
+static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
+{
+       /* create subd mesh */
+       SubdMesh sdmesh;
+
+       /* create vertices */
+       BL::Mesh::vertices_iterator v;
+
+       for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
+               sdmesh.add_vert(get_float3(v->co()));
+
+       /* create faces */
+       BL::Mesh::faces_iterator f;
+
+       for(b_mesh.faces.begin(f); f != b_mesh.faces.end(); ++f) {
+               int4 vi = get_int4(f->vertices_raw());
+               int n= (vi[3] == 0)? 3: 4;
+               //int shader = used_shaders[f->material_index()];
+
+               if(n == 4)
+                       sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
+               /*else
+                       sdmesh.add_face(vi[0], vi[1], vi[2]);*/
+       }
+
+       /* finalize subd mesh */
+       sdmesh.link_boundary();
+
+       /* subdivide */
+       DiagSplit dsplit;
+       dsplit.camera = NULL;
+       dsplit.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
+
+       sdmesh.tesselate(&dsplit, false, mesh, used_shaders[0], true);
+}
+
+/* Sync */
+
+Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
+{
+       /* test if we can instance or if the object is modified */
+       BL::ID b_ob_data = b_ob.data();
+       BL::ID key = (object_is_modified(b_ob))? b_ob: b_ob_data;
+
+       /* find shader indices */
+       vector<uint> used_shaders;
+
+       BL::Object::material_slots_iterator slot;
+       for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
+               if(render_layer.material_override)
+                       find_shader(render_layer.material_override, used_shaders);
+               else
+                       find_shader(slot->material(), used_shaders);
+       }
+
+       if(used_shaders.size() == 0)
+               used_shaders.push_back(scene->default_surface);
+       
+       /* test if we need to sync */
+       Mesh *mesh;
+
+       if(!mesh_map.sync(&mesh, key)) {
+               /* if transform was applied to mesh, need full update */
+               if(object_updated && mesh->transform_applied);
+               /* test if shaders changed, these can be object level so mesh
+                  does not get tagged for recalc */
+               else if(mesh->used_shaders != used_shaders);
+               else {
+                       /* even if not tagged for recalc, we may need to sync anyway
+                        * because the shader needs different mesh attributes */
+                       bool attribute_recalc = false;
+
+                       foreach(uint shader, mesh->used_shaders)
+                               if(scene->shaders[shader]->need_update_attributes)
+                                       attribute_recalc = true;
+
+                       if(!attribute_recalc)
+                               return mesh;
+               }
+       }
+
+       /* ensure we only sync instanced meshes once */
+       if(mesh_synced.find(mesh) != mesh_synced.end())
+               return mesh;
+       
+       mesh_synced.insert(mesh);
+
+       /* create derived mesh */
+       BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
+       PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
+
+       vector<Mesh::Triangle> oldtriangle = mesh->triangles;
+
+
+       mesh->clear();
+       mesh->used_shaders = used_shaders;
+       mesh->name = ustring(b_ob_data.name().c_str());
+
+       if(b_mesh) {
+               if(cmesh.data && RNA_boolean_get(&cmesh, "use_subdivision"))
+                       create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
+               else
+                       create_mesh(scene, mesh, b_mesh, used_shaders);
+
+               /* free derived mesh */
+               object_remove_mesh(b_data, b_mesh);
+       }
+
+       /* displacement method */
+       if(cmesh.data) {
+               int method = RNA_enum_get(&cmesh, "displacement_method");
+
+               if(method == 0)
+                       mesh->displacement_method = Mesh::DISPLACE_BUMP;
+               else if(method == 1)
+                       mesh->displacement_method = Mesh::DISPLACE_TRUE;
+               else
+                       mesh->displacement_method = Mesh::DISPLACE_BOTH;
+       }
+
+       /* tag update */
+       bool rebuild = false;
+
+       if(oldtriangle.size() != mesh->triangles.size())
+               rebuild = true;
+       else if(oldtriangle.size()) {
+               if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
+                       rebuild = true;
+       }
+       
+       mesh->tag_update(scene, rebuild);
+
+       return mesh;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
new file mode 100644 (file)
index 0000000..1095a3e
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "light.h"
+#include "mesh.h"
+#include "object.h"
+#include "scene.h"
+
+#include "blender_sync.h"
+#include "blender_util.h"
+
+#include "util_foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Utilities */
+
+bool BlenderSync::object_is_modified(BL::Object b_ob)
+{
+       /* test if we can instance or if the object is modified */
+       if(ccl::object_is_modified(b_ob, b_scene, preview)) {
+               /* modifiers */
+               return true;
+       }
+       else {
+               /* object level material links */
+               BL::Object::material_slots_iterator slot;
+               for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
+                       if(slot->link() == BL::MaterialSlot::link_OBJECT)
+                               return true;
+       }
+
+       return false;
+}
+
+bool BlenderSync::object_is_mesh(BL::Object b_ob)
+{
+       BL::ID b_ob_data = b_ob.data();
+
+       return (b_ob_data && (b_ob_data.is_a(&RNA_Mesh) ||
+               b_ob_data.is_a(&RNA_Curve) || b_ob_data.is_a(&RNA_MetaBall)));
+}
+
+bool BlenderSync::object_is_light(BL::Object b_ob)
+{
+       BL::ID b_ob_data = b_ob.data();
+
+       return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
+}
+
+static uint object_ray_visibility(BL::Object b_ob)
+{
+       PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
+       uint flag = 0;
+
+       flag |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0;
+       flag |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0;
+       flag |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0;
+       flag |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0;
+       flag |= get_boolean(cvisibility, "shadow")? PATH_RAY_SHADOW: 0;
+
+       return flag;
+}
+
+/* Light */
+
+void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm)
+{
+       /* test if we need to sync */
+       Light *light;
+       ObjectKey key(b_parent, b_index, b_ob);
+
+       if(!light_map.sync(&light, b_ob, b_parent, key))
+               return;
+       
+       BL::Lamp b_lamp(b_ob.data());
+
+       /* type */
+       switch(b_lamp.type()) {
+               case BL::Lamp::type_POINT: {
+                       BL::PointLamp b_point_lamp(b_lamp);
+                       light->size = b_point_lamp.shadow_soft_size();
+                       light->type = LIGHT_POINT;
+                       break;
+               }
+               case BL::Lamp::type_SPOT: {
+                       BL::SpotLamp b_spot_lamp(b_lamp);
+                       light->size = b_spot_lamp.shadow_soft_size();
+                       light->type = LIGHT_POINT;
+                       break;
+               }
+               case BL::Lamp::type_HEMI: {
+                       light->type = LIGHT_DISTANT;
+                       light->size = 0.0f;
+                       break;
+               }
+               case BL::Lamp::type_SUN: {
+                       BL::SunLamp b_sun_lamp(b_lamp);
+                       light->size = b_sun_lamp.shadow_soft_size();
+                       light->type = LIGHT_DISTANT;
+                       break;
+               }
+               case BL::Lamp::type_AREA: {
+                       BL::AreaLamp b_area_lamp(b_lamp);
+                       light->size = 1.0f;
+                       light->axisu = make_float3(tfm.x.x, tfm.y.x, tfm.z.x);
+                       light->axisv = make_float3(tfm.x.y, tfm.y.y, tfm.z.y);
+                       light->sizeu = b_area_lamp.size();
+                       if(b_area_lamp.shape() == BL::AreaLamp::shape_RECTANGLE)
+                               light->sizev = b_area_lamp.size_y();
+                       else
+                               light->sizev = light->sizeu;
+                       light->type = LIGHT_AREA;
+                       break;
+               }
+       }
+
+       /* location and (inverted!) direction */
+       light->co = make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
+       light->dir = -make_float3(tfm.x.z, tfm.y.z, tfm.z.z);
+
+       /* shader */
+       vector<uint> used_shaders;
+
+       find_shader(b_lamp, used_shaders);
+
+       if(used_shaders.size() == 0)
+               used_shaders.push_back(scene->default_light);
+
+       light->shader = used_shaders[0];
+
+       /* shadow */
+       PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
+       light->cast_shadow = get_boolean(clamp, "cast_shadow");
+
+       /* tag */
+       light->tag_update(scene);
+}
+
+/* Object */
+
+void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint visibility)
+{
+       /* light is handled separately */
+       if(object_is_light(b_ob)) {
+               sync_light(b_parent, b_index, b_ob, tfm);
+               return;
+       }
+
+       /* only interested in object that we can create meshes from */
+       if(!object_is_mesh(b_ob))
+               return;
+
+       /* test if we need to sync */
+       ObjectKey key(b_parent, b_index, b_ob);
+       Object *object;
+       bool object_updated = false;
+
+       /* object sync */
+       if(object_map.sync(&object, b_ob, b_parent, key)) {
+               object->name = b_ob.name().c_str();
+               object->tfm = tfm;
+               
+               object->visibility = object_ray_visibility(b_ob) & visibility;
+               if(b_parent.ptr.data != b_ob.ptr.data)
+                       object->visibility &= object_ray_visibility(b_parent);
+
+               object->tag_update(scene);
+               object_updated = true;
+       }
+
+       /* mesh sync */
+       object->mesh = sync_mesh(b_ob, object_updated);
+}
+
+/* Object Loop */
+
+void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
+{
+       /* layer data */
+       uint scene_layer = render_layer.scene_layer;
+       uint layer = render_layer.layer;
+       
+       /* prepare for sync */
+       light_map.pre_sync();
+       mesh_map.pre_sync();
+       object_map.pre_sync();
+       mesh_synced.clear();
+
+       /* object loop */
+       BL::Scene::objects_iterator b_ob;
+
+       for(b_scene.objects.begin(b_ob); b_ob != b_scene.objects.end(); ++b_ob) {
+               bool hide = (b_v3d)? b_ob->hide(): b_ob->hide_render();
+               uint ob_layer = get_layer(b_ob->layers());
+
+               if(!hide && (ob_layer & scene_layer)) {
+                       uint visibility = PATH_RAY_ALL;
+                       
+                       if(!(ob_layer & layer))
+                               visibility &= ~PATH_RAY_CAMERA;
+
+                       if(b_ob->is_duplicator()) {
+                               /* dupli objects */
+                               object_create_duplilist(*b_ob, b_scene);
+
+                               BL::Object::dupli_list_iterator b_dup;
+                               int b_index = 0;
+
+                               for(b_ob->dupli_list.begin(b_dup); b_dup != b_ob->dupli_list.end(); ++b_dup) {
+                                       Transform tfm = get_transform(b_dup->matrix());
+                                       sync_object(*b_ob, b_index, b_dup->object(), tfm, visibility);
+                                       b_index++;
+                               }
+
+                               object_free_duplilist(*b_ob);
+                       }
+                       else {
+                               /* object itself */
+                               Transform tfm = get_transform(b_ob->matrix_world());
+                               sync_object(*b_ob, 0, *b_ob, tfm, visibility);
+                       }
+               }
+       }
+
+       /* handle removed data and modified pointers */
+       if(light_map.post_sync())
+               scene->light_manager->tag_update(scene);
+       if(mesh_map.post_sync())
+               scene->mesh_manager->tag_update(scene);
+       if(object_map.post_sync())
+               scene->object_manager->tag_update(scene);
+       mesh_synced.clear();
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
new file mode 100644 (file)
index 0000000..1026d42
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <Python.h>
+
+#include "blender_sync.h"
+#include "blender_session.h"
+
+#include "util_opengl.h"
+#include "util_path.h"
+
+CCL_NAMESPACE_BEGIN
+
+static PyObject *init_func(PyObject *self, PyObject *args)
+{
+       const char *path, *user_path;
+
+       if(!PyArg_ParseTuple(args, "ss", &path, &user_path))
+               return NULL;
+       
+       path_init(path, user_path);
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *create_func(PyObject *self, PyObject *args)
+{
+       PyObject *pyengine, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
+
+       if(!PyArg_ParseTuple(args, "OOOOOO", &pyengine, &pydata, &pyscene, &pyregion, &pyv3d, &pyrv3d))
+               return NULL;
+
+       /* RNA */
+       PointerRNA engineptr;
+       RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)PyLong_AsVoidPtr(pyengine), &engineptr);
+       BL::RenderEngine engine(engineptr);
+
+       PointerRNA dataptr;
+       RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydata), &dataptr);
+       BL::BlendData data(dataptr);
+
+       PointerRNA sceneptr;
+       RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
+       BL::Scene scene(sceneptr);
+
+       PointerRNA regionptr;
+       RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyregion), &regionptr);
+       BL::Region region(regionptr);
+
+       PointerRNA v3dptr;
+       RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyv3d), &v3dptr);
+       BL::SpaceView3D v3d(v3dptr);
+
+       PointerRNA rv3dptr;
+       RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyrv3d), &rv3dptr);
+       BL::RegionView3D rv3d(rv3dptr);
+
+       /* create session */
+       BlenderSession *session;
+
+       if(rv3d) {
+               /* interactive session */
+               int width = region.width();
+               int height = region.height();
+
+               session = new BlenderSession(engine, data, scene, v3d, rv3d, width, height);
+       }
+       else {
+               /* offline session */
+               session = new BlenderSession(engine, data, scene);
+       }
+       
+       return PyLong_FromVoidPtr(session);
+}
+
+static PyObject *free_func(PyObject *self, PyObject *args)
+{
+       PyObject *pysession;
+
+       if(!PyArg_ParseTuple(args, "O", &pysession))
+               return NULL;
+
+       delete (BlenderSession*)PyLong_AsVoidPtr(pysession);
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *render_func(PyObject *self, PyObject *args)
+{
+       PyObject *pysession;
+
+       if(!PyArg_ParseTuple(args, "O", &pysession))
+               return NULL;
+       
+       Py_BEGIN_ALLOW_THREADS
+
+       BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
+       session->render();
+
+       Py_END_ALLOW_THREADS
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *draw_func(PyObject *self, PyObject *args)
+{
+       PyObject *pysession, *pyv3d, *pyrv3d;
+
+       if(!PyArg_ParseTuple(args, "OOO", &pysession, &pyv3d, &pyrv3d))
+               return NULL;
+       
+       BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
+
+       if(PyLong_AsVoidPtr(pyrv3d)) {
+               /* 3d view drawing */
+               int viewport[4];
+               glGetIntegerv(GL_VIEWPORT, viewport);
+
+               session->draw(viewport[2], viewport[3]);
+       }
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *sync_func(PyObject *self, PyObject *args)
+{
+       PyObject *pysession;
+
+       if(!PyArg_ParseTuple(args, "O", &pysession))
+               return NULL;
+
+       BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
+       session->synchronize();
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *available_devices_func(PyObject *self, PyObject *args)
+{
+       vector<DeviceType> types = Device::available_types();
+
+       PyObject *ret = PyTuple_New(types.size());
+
+       for(size_t i = 0; i < types.size(); i++) {
+               string name = Device::string_from_type(types[i]);
+               PyTuple_SetItem(ret, i, PyUnicode_FromString(name.c_str()));
+       }
+
+       return ret;
+}
+
+static PyObject *with_osl_func(PyObject *self, PyObject *args)
+{
+#ifdef WITH_OSL
+       PyObject *ret = Py_True;
+#else
+       PyObject *ret = Py_False;
+#endif
+
+       return Py_INCREF(ret), ret;
+}
+
+static PyMethodDef methods[] = {
+       {"init", init_func, METH_VARARGS, ""},
+       {"create", create_func, METH_VARARGS, ""},
+       {"free", free_func, METH_VARARGS, ""},
+       {"render", render_func, METH_VARARGS, ""},
+       {"draw", draw_func, METH_VARARGS, ""},
+       {"sync", sync_func, METH_VARARGS, ""},
+       {"available_devices", available_devices_func, METH_NOARGS, ""},
+       {"with_osl", with_osl_func, METH_NOARGS, ""},
+       {NULL, NULL, 0, NULL},
+};
+
+static struct PyModuleDef module = {
+       PyModuleDef_HEAD_INIT,
+       "libcycles_blender",
+       "Blender RNA to render exporter",
+       -1,
+       methods,
+       NULL, NULL, NULL, NULL
+};
+
+CCL_NAMESPACE_END
+
+extern "C" PyObject *CYCLES_initPython();
+
+PyObject *CYCLES_initPython()
+{
+       return PyModule_Create(&ccl::module);
+}
+
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
new file mode 100644 (file)
index 0000000..4433b1e
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "background.h"
+#include "buffers.h"
+#include "camera.h"
+#include "device.h"
+#include "integrator.h"
+#include "film.h"
+#include "light.h"
+#include "scene.h"
+#include "session.h"
+#include "shader.h"
+
+#include "util_color.h"
+#include "util_foreach.h"
+#include "util_function.h"
+#include "util_progress.h"
+#include "util_time.h"
+
+#include "blender_sync.h"
+#include "blender_session.h"
+#include "blender_util.h"
+
+CCL_NAMESPACE_BEGIN
+
+BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_)
+: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL)
+{
+       /* offline render */
+       BL::RenderSettings r = b_scene.render();
+
+       width = (int)(r.resolution_x()*r.resolution_percentage()*0.01f);
+       height = (int)(r.resolution_y()*r.resolution_percentage()*0.01f);
+       background = true;
+       last_redraw_time = 0.0f;
+
+       create_session();
+}
+
+BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_,
+       BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
+: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(b_v3d_), b_rv3d(b_rv3d_)
+{
+       /* 3d view render */
+       width = width_;
+       height = height_;
+       background = false;
+       last_redraw_time = 0.0f;
+
+       create_session();
+}
+
+BlenderSession::~BlenderSession()
+{
+       free_session();
+}
+
+void BlenderSession::create_session()
+{
+       SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
+       SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
+
+       /* reset status/progress */
+       last_status= "";
+       last_progress= -1.0f;
+
+       /* create scene */
+       scene = new Scene(scene_params);
+
+       /* create sync */
+       sync = new BlenderSync(b_data, b_scene, scene, !background);
+       sync->sync_data(b_v3d);
+
+       if(b_rv3d)
+               sync->sync_view(b_v3d, b_rv3d, width, height);
+       else
+               sync->sync_camera(width, height);
+
+       /* create session */
+       session = new Session(session_params);
+       session->scene = scene;
+       session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
+       session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
+       session->set_pause(BlenderSync::get_session_pause(b_scene, background));
+
+       /* start rendering */
+       session->reset(width, height, session_params.samples);
+       session->start();
+}
+
+void BlenderSession::free_session()
+{
+       delete sync;
+       delete session;
+}
+
+void BlenderSession::render()
+{
+       session->wait();
+
+       if(session->progress.get_cancel())
+               return;
+
+       /* write result */
+       write_render_result();
+}
+
+void BlenderSession::write_render_result()
+{
+       /* get result */
+       RenderBuffers *buffers = session->buffers;
+       float exposure = scene->film->exposure;
+       double total_time, sample_time;
+       int sample;
+       session->progress.get_sample(sample, total_time, sample_time);
+
+       float4 *pixels = buffers->copy_from_device(exposure, sample);
+
+       if(!pixels)
+               return;
+
+       struct RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, 0, 0, width, height);
+       PointerRNA rrptr;
+       RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr);
+       BL::RenderResult rr(rrptr);
+
+       BL::RenderResult::layers_iterator layer;
+       rr.layers.begin(layer);
+       rna_RenderLayer_rect_set(&layer->ptr, (float*)pixels);
+
+       RE_engine_end_result((RenderEngine*)b_engine.ptr.data, rrp);
+
+       delete [] pixels;
+}
+
+void BlenderSession::synchronize()
+{
+       /* on session/scene parameter changes, we recreate session entirely */
+       SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
+       SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
+
+       if(session->params.modified(session_params) ||
+          scene->params.modified(scene_params)) {
+               free_session();
+               create_session();
+               return;
+       }
+
+       /* increase samples, but never decrease */
+       session->set_samples(session_params.samples);
+       session->set_pause(BlenderSync::get_session_pause(b_scene, background));
+
+       /* copy recalc flags, outside of mutex so we can decide to do the real
+          synchronization at a later time to not block on running updates */
+       sync->sync_recalc();
+
+       /* try to acquire mutex. if we don't want to or can't, come back later */
+       if(!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
+               tag_update();
+               return;
+       }
+
+       /* data and camera synchronize */
+       sync->sync_data(b_v3d);
+
+       if(b_rv3d)
+               sync->sync_view(b_v3d, b_rv3d, width, height);
+       else
+               sync->sync_camera(width, height);
+
+       /* unlock */
+       session->scene->mutex.unlock();
+
+       /* reset if needed */
+       if(scene->need_reset())
+               session->reset(width, height, session_params.samples);
+}
+
+bool BlenderSession::draw(int w, int h)
+{
+       /* before drawing, we verify camera and viewport size changes, because
+          we do not get update callbacks for those, we must detect them here */
+       if(session->ready_to_reset()) {
+               bool reset = false;
+
+               /* try to acquire mutex. if we can't, come back later */
+               if(!session->scene->mutex.try_lock()) {
+                       tag_update();
+               }
+               else {
+                       /* update camera from 3d view */
+                       bool need_update = scene->camera->need_update;
+
+                       sync->sync_view(b_v3d, b_rv3d, w, h);
+
+                       if(scene->camera->need_update && !need_update)
+                               reset = true;
+
+                       session->scene->mutex.unlock();
+               }
+
+               /* if dimensions changed, reset */
+               if(width != w || height != h) {
+                       width = w;
+                       height = h;
+                       reset = true;
+               }
+
+               /* reset if requested */
+               if(reset) {
+                       SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
+                       session->reset(width, height, session_params.samples);
+               }
+       }
+
+       /* update status and progress for 3d view draw */
+       update_status_progress();
+
+       /* draw */
+       return !session->draw(width, height);
+}
+
+void BlenderSession::get_status(string& status, string& substatus)
+{
+       session->progress.get_status(status, substatus);
+}
+
+void BlenderSession::get_progress(float& progress, double& total_time)
+{
+       double sample_time;
+       int sample;
+
+       session->progress.get_sample(sample, total_time, sample_time);
+       progress = ((float)sample/(float)session->params.samples);
+}
+
+void BlenderSession::update_status_progress()
+{
+       string status, substatus;
+       float progress;
+       double total_time;
+       char time_str[128];
+
+       get_status(status, substatus);
+       get_progress(progress, total_time);
+
+       if(!background) {
+               BLI_timestr(total_time, time_str);
+               status = "Time: " + string(time_str) + " | " + status;
+       }
+
+       if(substatus.size() > 0)
+               status += " | " + substatus;
+
+       if(status != last_status) {
+               RE_engine_update_stats((RenderEngine*)b_engine.ptr.data, "", status.c_str());
+               last_status = status;
+       }
+       if(progress != last_progress) {
+               RE_engine_update_progress((RenderEngine*)b_engine.ptr.data, progress);
+               last_progress = progress;
+       }
+}
+
+void BlenderSession::tag_update()
+{
+       /* tell blender that we want to get another update callback */
+       engine_tag_update((RenderEngine*)b_engine.ptr.data);
+}
+
+void BlenderSession::tag_redraw()
+{
+       if(background) {
+               /* update stats and progress, only for background here because
+                  in 3d view we do it in draw for thread safety reasons */
+               update_status_progress();
+
+               /* offline render, redraw if timeout passed */
+               if(time_dt() - last_redraw_time > 1.0f) {
+                       write_render_result();
+                       engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
+                       last_redraw_time = time_dt();
+               }
+       }
+       else {
+               /* tell blender that we want to redraw */
+               engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
+       }
+}
+
+void BlenderSession::test_cancel()
+{
+       /* test if we need to cancel rendering */
+       if(background)
+               if(RE_engine_test_break((RenderEngine*)b_engine.ptr.data))
+                       session->progress.set_cancel("Cancelled");
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
new file mode 100644 (file)
index 0000000..e30b60c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLENDER_SESSION_H__
+#define __BLENDER_SESSION_H__
+
+#include "device.h"
+#include "scene.h"
+#include "session.h"
+
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Scene;
+class Session;
+
+class BlenderSession {
+public:
+       BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene);
+       BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene,
+               BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
+
+       ~BlenderSession();
+
+       /* session */
+       void create_session();
+       void free_session();
+
+       /* offline render */
+       void render();
+       void write_render_result();
+
+       /* interactive updates */
+       void synchronize();
+
+       /* drawing */
+       bool draw(int w, int h);
+       void tag_redraw();
+       void tag_update();
+       void get_status(string& status, string& substatus);
+       void get_progress(float& progress, double& total_time);
+       void test_cancel();
+       void update_status_progress();
+
+       bool background;
+       Session *session;
+       Scene *scene;
+       BlenderSync *sync;
+       double last_redraw_time;
+
+       BL::RenderEngine b_engine;
+       BL::BlendData b_data;
+       BL::Scene b_scene;
+       BL::SpaceView3D b_v3d;
+       BL::RegionView3D b_rv3d;
+
+       string last_status;
+       float last_progress;
+
+       int width, height;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_SESSION_H__ */
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
new file mode 100644 (file)
index 0000000..ed84777
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "background.h"
+#include "graph.h"
+#include "light.h"
+#include "nodes.h"
+#include "scene.h"
+#include "shader.h"
+
+#include "blender_sync.h"
+#include "blender_util.h"
+
+#include "util_debug.h"
+
+CCL_NAMESPACE_BEGIN
+
+typedef map<void*, ShaderNode*> PtrNodeMap;
+typedef pair<ShaderNode*, std::string> SocketPair;
+typedef map<void*, SocketPair> PtrSockMap;
+
+/* Find */
+
+void BlenderSync::find_shader(BL::ID id, vector<uint>& used_shaders)
+{
+       Shader *shader = shader_map.find(id);
+
+       for(size_t i = 0; i < scene->shaders.size(); i++) {
+               if(scene->shaders[i] == shader) {
+                       used_shaders.push_back(i);
+                       break;
+               }
+       }
+}
+
+/* Graph */
+
+static BL::NodeSocket get_node_input(BL::Node *b_group_node, BL::NodeSocket b_in)
+{
+       if(b_group_node) {
+
+               BL::NodeTree b_ntree = BL::NodeGroup(*b_group_node).node_tree();
+               BL::NodeTree::links_iterator b_link;
+
+               for(b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
+                       if(b_link->to_socket().ptr.data == b_in.ptr.data) {
+                               BL::Node::inputs_iterator b_gin;
+
+                               for(b_group_node->inputs.begin(b_gin); b_gin != b_group_node->inputs.end(); ++b_gin)
+                                       if(b_gin->group_socket().ptr.data == b_link->from_socket().ptr.data)
+                                               return *b_gin;
+
+                       }
+               }
+       }
+
+       return b_in;
+}
+
+static BL::NodeSocket get_node_output(BL::Node b_node, const string& name)
+{
+       BL::Node::outputs_iterator b_out;
+
+       for(b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out)
+               if(b_out->name() == name)
+                       return *b_out;
+
+       assert(0);
+
+       return *b_out;
+}
+
+static float3 get_node_output_rgba(BL::Node b_node, const string& name)
+{
+       BL::NodeSocketRGBA sock(get_node_output(b_node, name));
+       return get_float3(sock.default_value());
+}
+
+static float get_node_output_value(BL::Node b_node, const string& name)
+{
+       BL::NodeSocketFloatNone sock(get_node_output(b_node, name));
+       return sock.default_value();
+}
+
+static ShaderNode *add_node(BL::BlendData b_data, ShaderGraph *graph, BL::Node *b_group_node, BL::ShaderNode b_node)
+{
+       ShaderNode *node = NULL;
+
+       switch(b_node.type()) {
+               /* not supported */
+               case BL::ShaderNode::type_CAMERA: break;
+               case BL::ShaderNode::type_COMBRGB: break;
+               case BL::ShaderNode::type_CURVE_RGB: break;
+               case BL::ShaderNode::type_CURVE_VEC: break;
+               case BL::ShaderNode::type_GEOM: break;
+               case BL::ShaderNode::type_HUE_SAT: break;
+               case BL::ShaderNode::type_INVERT: break;
+               case BL::ShaderNode::type_MATERIAL: break;
+               case BL::ShaderNode::type_MATERIAL_EXT: break;
+               case BL::ShaderNode::type_NORMAL: break;
+               case BL::ShaderNode::type_OUTPUT: break;
+               case BL::ShaderNode::type_SCRIPT: break;
+               case BL::ShaderNode::type_SEPRGB: break;
+               case BL::ShaderNode::type_SQUEEZE: break;
+               case BL::ShaderNode::type_TEXTURE: break;
+               case BL::ShaderNode::type_VALTORGB: break;
+               /* handled outside this function */
+               case BL::ShaderNode::type_GROUP: break;
+               /* existing blender nodes */
+               case BL::ShaderNode::type_RGB: {
+                       ColorNode *color = new ColorNode();
+                       color->value = get_node_output_rgba(b_node, "Color");
+                       node = color;
+                       break;
+               }
+               case BL::ShaderNode::type_VALUE: {
+                       ValueNode *value = new ValueNode();
+                       value->value = get_node_output_value(b_node, "Value");
+                       node = value;
+                       break;
+               }
+               case BL::ShaderNode::type_MIX_RGB: {
+                       BL::ShaderNodeMixRGB b_mix_node(b_node);
+                       MixNode *mix = new MixNode();
+                       mix->type = MixNode::type_enum[b_mix_node.blend_type()];
+                       node = mix;
+                       break;
+               }
+               case BL::ShaderNode::type_RGBTOBW: {
+                       node = new ConvertNode(SHADER_SOCKET_COLOR, SHADER_SOCKET_FLOAT);
+                       break;
+               }
+               case BL::ShaderNode::type_MATH: {
+                       BL::ShaderNodeMath b_math_node(b_node);
+                       MathNode *math = new MathNode();
+                       math->type = MathNode::type_enum[b_math_node.operation()];
+                       node = math;
+                       break;
+               }
+               case BL::ShaderNode::type_VECT_MATH: {
+                       BL::ShaderNodeVectorMath b_vector_math_node(b_node);
+                       VectorMathNode *vmath = new VectorMathNode();
+                       vmath->type = VectorMathNode::type_enum[b_vector_math_node.operation()];
+                       node = vmath;
+                       break;
+               }
+               case BL::ShaderNode::type_MAPPING: {
+                       BL::ShaderNodeMapping b_mapping_node(b_node);
+                       MappingNode *mapping = new MappingNode();
+
+                       TextureMapping *tex_mapping = &mapping->tex_mapping;
+                       tex_mapping->translation = get_float3(b_mapping_node.location());
+                       tex_mapping->rotation = get_float3(b_mapping_node.rotation());
+                       tex_mapping->scale = get_float3(b_mapping_node.scale());
+
+                       node = mapping;
+                       break;
+               }
+
+               /* new nodes */
+               case BL::ShaderNode::type_OUTPUT_MATERIAL:
+               case BL::ShaderNode::type_OUTPUT_WORLD:
+               case BL::ShaderNode::type_OUTPUT_LAMP: {
+                       node = graph->output();
+                       break;
+               }
+               case BL::ShaderNode::type_FRESNEL: {
+                       node = new FresnelNode();
+                       break;
+               }
+               case BL::ShaderNode::type_BLEND_WEIGHT: {
+                       node = new BlendWeightNode();
+                       break;
+               }
+               case BL::ShaderNode::type_ADD_SHADER: {
+                       node = new AddClosureNode();
+                       break;
+               }
+               case BL::ShaderNode::type_MIX_SHADER: {
+                       node = new MixClosureNode();
+                       break;
+               }
+               case BL::ShaderNode::type_ATTRIBUTE: {
+                       BL::ShaderNodeAttribute b_attr_node(b_node);
+                       AttributeNode *attr = new AttributeNode();
+                       attr->attribute = b_attr_node.attribute_name();
+                       node = attr;
+                       break;
+               }
+               case BL::ShaderNode::type_BACKGROUND: {
+                       node = new BackgroundNode();
+                       break;
+               }
+               case BL::ShaderNode::type_HOLDOUT: {
+                       node = new HoldoutNode();
+                       break;
+               }
+               case BL::ShaderNode::type_BSDF_ANISOTROPIC: {
+                       node = new WardBsdfNode();
+                       break;
+               }
+               case BL::ShaderNode::type_BSDF_DIFFUSE: {
+                       node = new DiffuseBsdfNode();
+                       break;
+               }
+               case BL::ShaderNode::type_BSDF_GLOSSY: {
+                       BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
+                       GlossyBsdfNode *glossy = new GlossyBsdfNode();
+
+                       switch(b_glossy_node.distribution()) {
+                               case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
+                                       glossy->distribution = ustring("Sharp");
+                                       break;
+                               case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
+                                       glossy->distribution = ustring("Beckmann");
+                                       break;
+                               case BL::ShaderNodeBsdfGlossy::distribution_GGX:
+                                       glossy->distribution = ustring("GGX");
+                                       break;
+                       }
+                       node = glossy;
+                       break;
+               }
+               case BL::ShaderNode::type_BSDF_GLASS: {
+                       BL::ShaderNodeBsdfGlass b_glass_node(b_node);
+                       GlassBsdfNode *glass = new GlassBsdfNode();
+                       switch(b_glass_node.distribution()) {
+                               case BL::ShaderNodeBsdfGlass::distribution_SHARP:
+                                       glass->distribution = ustring("Sharp");
+                                       break;
+                               case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
+                                       glass->distribution = ustring("Beckmann");
+                                       break;
+                               case BL::ShaderNodeBsdfGlass::distribution_GGX:
+                                       glass->distribution = ustring("GGX");
+                                       break;
+                       }
+                       node = glass;
+                       break;
+               }
+               case BL::ShaderNode::type_BSDF_TRANSLUCENT: {
+                       node = new TranslucentBsdfNode();
+                       break;
+               }
+               case BL::ShaderNode::type_BSDF_TRANSPARENT: {
+                       node = new TransparentBsdfNode();
+                       break;
+               }
+               case BL::ShaderNode::type_BSDF_VELVET: {
+                       node = new VelvetBsdfNode();
+                       break;
+               }
+               case BL::ShaderNode::type_EMISSION: {
+                       node = new EmissionNode();
+                       break;
+               }
+               case BL::ShaderNode::type_VOLUME_ISOTROPIC: {
+                       node = new IsotropicVolumeNode();
+                       break;
+               }
+               case BL::ShaderNode::type_VOLUME_TRANSPARENT: {
+                       node = new TransparentVolumeNode();
+                       break;
+               }
+               case BL::ShaderNode::type_GEOMETRY: {
+                       node = new GeometryNode();
+                       break;
+               }
+               case BL::ShaderNode::type_LIGHT_PATH: {
+                       node = new LightPathNode();
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_IMAGE: {
+                       BL::ShaderNodeTexImage b_image_node(b_node);
+                       BL::Image b_image(b_image_node.image());
+                       ImageTextureNode *image = new ImageTextureNode();
+                       /* todo: handle generated/builtin images */
+                       if(b_image)
+                               image->filename = blender_absolute_path(b_data, b_image, b_image.filepath());
+                       image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
+                       node = image;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_ENVIRONMENT: {
+                       BL::ShaderNodeTexEnvironment b_env_node(b_node);
+                       BL::Image b_image(b_env_node.image());
+                       EnvironmentTextureNode *env = new EnvironmentTextureNode();
+                       if(b_image)
+                               env->filename = blender_absolute_path(b_data, b_image, b_image.filepath());
+                       env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
+                       node = env;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_NOISE: {
+                       node = new NoiseTextureNode();
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_BLEND: {
+                       BL::ShaderNodeTexBlend b_blend_node(b_node);
+                       BlendTextureNode *blend = new BlendTextureNode();
+                       blend->progression = BlendTextureNode::progression_enum[(int)b_blend_node.progression()];
+                       blend->axis = BlendTextureNode::axis_enum[(int)b_blend_node.axis()];
+                       node = blend;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_VORONOI: {
+                       BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
+                       VoronoiTextureNode *voronoi = new VoronoiTextureNode();
+                       voronoi->distance_metric = VoronoiTextureNode::distance_metric_enum[(int)b_voronoi_node.distance_metric()];
+                       voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
+                       node = voronoi;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_MAGIC: {
+                       BL::ShaderNodeTexMagic b_magic_node(b_node);
+                       MagicTextureNode *magic = new MagicTextureNode();
+                       magic->depth = b_magic_node.turbulence_depth();
+                       node = magic;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_MARBLE: {
+                       BL::ShaderNodeTexMarble b_marble_node(b_node);
+                       MarbleTextureNode *marble = new MarbleTextureNode();
+                       marble->depth = b_marble_node.turbulence_depth();
+                       marble->basis = MarbleTextureNode::basis_enum[(int)b_marble_node.noise_basis()];
+                       marble->type = MarbleTextureNode::type_enum[(int)b_marble_node.marble_type()];
+                       marble->wave = MarbleTextureNode::wave_enum[(int)b_marble_node.wave_type()];
+                       marble->hard = b_marble_node.noise_type() == BL::ShaderNodeTexMarble::noise_type_HARD;
+                       node = marble;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_CLOUDS: {
+                       BL::ShaderNodeTexClouds b_clouds_node(b_node);
+                       CloudsTextureNode *clouds = new CloudsTextureNode();
+                       clouds->depth = b_clouds_node.turbulence_depth();
+                       clouds->basis = CloudsTextureNode::basis_enum[(int)b_clouds_node.noise_basis()];
+                       clouds->hard = b_clouds_node.noise_type() == BL::ShaderNodeTexClouds::noise_type_HARD;
+                       node = clouds;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_WOOD: {
+                       BL::ShaderNodeTexWood b_wood_node(b_node);
+                       WoodTextureNode *wood = new WoodTextureNode();
+                       wood->type = WoodTextureNode::type_enum[(int)b_wood_node.wood_type()];
+                       wood->basis = WoodTextureNode::basis_enum[(int)b_wood_node.noise_basis()];
+                       wood->hard = b_wood_node.noise_type() == BL::ShaderNodeTexWood::noise_type_HARD;
+                       wood->wave = WoodTextureNode::wave_enum[(int)b_wood_node.wave_type()];
+                       node = wood;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_MUSGRAVE: {
+                       BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
+                       MusgraveTextureNode *musgrave = new MusgraveTextureNode();
+                       musgrave->type = MusgraveTextureNode::type_enum[(int)b_musgrave_node.musgrave_type()];
+                       musgrave->basis = MusgraveTextureNode::basis_enum[(int)b_musgrave_node.noise_basis()];
+                       node = musgrave;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_STUCCI: {
+                       BL::ShaderNodeTexStucci b_stucci_node(b_node);
+                       StucciTextureNode *stucci = new StucciTextureNode();
+                       stucci->type = StucciTextureNode::type_enum[(int)b_stucci_node.stucci_type()];
+                       stucci->basis = StucciTextureNode::basis_enum[(int)b_stucci_node.noise_basis()];
+                       stucci->hard = b_stucci_node.noise_type() == BL::ShaderNodeTexStucci::noise_type_HARD;
+                       node = stucci;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_DISTORTED_NOISE: {
+                       BL::ShaderNodeTexDistortedNoise b_distnoise_node(b_node);
+                       DistortedNoiseTextureNode *distnoise = new DistortedNoiseTextureNode();
+                       distnoise->basis = DistortedNoiseTextureNode::basis_enum[(int)b_distnoise_node.noise_basis()];
+                       distnoise->distortion_basis = DistortedNoiseTextureNode::basis_enum[(int)b_distnoise_node.noise_distortion()];
+                       node = distnoise;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_COORD: {
+                       node = new TextureCoordinateNode();;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_SKY: {
+                       BL::ShaderNodeTexSky b_sky_node(b_node);
+                       SkyTextureNode *sky = new SkyTextureNode();
+                       sky->sun_direction = get_float3(b_sky_node.sun_direction());
+                       sky->turbidity = b_sky_node.turbidity();
+                       node = sky;
+                       break;
+               }
+       }
+
+       if(node && node != graph->output())
+               graph->add(node);
+
+       return node;
+}
+
+static SocketPair node_socket_map_pair(PtrNodeMap& node_map, BL::Node b_node, BL::NodeSocket b_socket)
+{
+       BL::Node::inputs_iterator b_input;
+       BL::Node::outputs_iterator b_output;
+       string name = b_socket.name();
+       bool found = false;
+       int counter = 0, total = 0;
+
+       /* find in inputs */
+       for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
+               if(b_input->name() == name) {
+                       if(!found)
+                               counter++;
+                       total++;
+               }
+
+               if(b_input->ptr.data == b_socket.ptr.data)
+                       found = true;
+       }
+
+       if(!found) {
+               /* find in outputs */
+               found = false;
+               counter = 0;
+               total = 0;
+
+               for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
+                       if(b_output->name() == name) {
+                               if(!found)
+                                       counter++;
+                               total++;
+                       }
+
+                       if(b_output->ptr.data == b_socket.ptr.data)
+                               found = true;
+               }
+       }
+
+       /* rename if needed */
+       if(name == "Shader")
+               name = "Closure";
+
+       if(total > 1)
+               name = string_printf("%s%d", name.c_str(), counter);
+
+       return SocketPair(node_map[b_node.ptr.data], name);
+}
+
+static void add_nodes(BL::BlendData b_data, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, BL::Node *b_group_node, PtrSockMap& sockets_map)
+{
+       /* add nodes */
+       BL::ShaderNodeTree::nodes_iterator b_node;
+       PtrNodeMap node_map;
+       map<void*, PtrSockMap> node_groups;
+
+       for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
+               if(b_node->is_a(&RNA_NodeGroup)) {
+                       BL::NodeGroup b_gnode(*b_node);
+                       BL::ShaderNodeTree b_group_ntree(b_gnode.node_tree());
+
+                       node_groups[b_node->ptr.data] = PtrSockMap();
+                       add_nodes(b_data, graph, b_group_ntree, &b_gnode, node_groups[b_node->ptr.data]);
+               }
+               else {
+                       ShaderNode *node = add_node(b_data, graph, b_group_node, BL::ShaderNode(*b_node));
+
+                       if(node) {
+                               BL::Node::inputs_iterator b_input;
+                               BL::Node::outputs_iterator b_output;
+
+                               node_map[b_node->ptr.data] = node;
+
+                               for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
+                                       SocketPair pair = node_socket_map_pair(node_map, *b_node, *b_input);
+                                       ShaderInput *input = pair.first->input(pair.second.c_str());
+                                       BL::NodeSocket sock(get_node_input(b_group_node, *b_input));
+
+                                       assert(input);
+
+                                       /* copy values for non linked inputs */
+                                       switch(input->type) {
+                                               case SHADER_SOCKET_FLOAT: {
+                                                       BL::NodeSocketFloatNone value_sock(sock);
+                                                       input->set(value_sock.default_value());
+                                                       break;
+                                               }
+                                               case SHADER_SOCKET_COLOR: {
+                                                       BL::NodeSocketRGBA rgba_sock(sock);
+                                                       input->set(get_float3(rgba_sock.default_value()));
+                                                       break;
+                                               }
+                                               case SHADER_SOCKET_NORMAL:
+                                               case SHADER_SOCKET_POINT:
+                                               case SHADER_SOCKET_VECTOR: {
+                                                       BL::NodeSocketVectorNone vec_sock(sock);
+                                                       input->set(get_float3(vec_sock.default_value()));
+                                                       break;
+                                               }
+                                               case SHADER_SOCKET_CLOSURE:
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* connect nodes */
+       BL::NodeTree::links_iterator b_link;
+
+       for(b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
+               /* get blender link data */
+               BL::Node b_from_node = b_link->from_node();
+               BL::Node b_to_node = b_link->to_node();
+
+               BL::NodeSocket b_from_sock = b_link->from_socket();
+               BL::NodeSocket b_to_sock = b_link->to_socket();
+
+               /* if link with group socket, add to map so we can connect it later */
+               if(b_group_node) {
+                       if(!b_from_node) {
+                               sockets_map[b_from_sock.ptr.data] =
+                                       node_socket_map_pair(node_map, b_to_node, b_to_sock);
+
+                               continue;
+                       }
+                       else if(!b_to_node) {
+                               sockets_map[b_to_sock.ptr.data] =
+                                       node_socket_map_pair(node_map, b_from_node, b_from_sock);
+
+                               continue;
+                       }
+               }
+
+               SocketPair from_pair, to_pair;
+
+               /* from sock */
+               if(b_from_node.is_a(&RNA_NodeGroup)) {
+                       /* group node */
+                       BL::NodeSocket group_sock = b_from_sock.group_socket();
+                       from_pair = node_groups[b_from_node.ptr.data][group_sock.ptr.data];
+               }
+               else {
+                       /* regular node */
+                       from_pair = node_socket_map_pair(node_map, b_from_node, b_from_sock);
+               }
+
+               /* to sock */
+               if(b_to_node.is_a(&RNA_NodeGroup)) {
+                       /* group node */
+                       BL::NodeSocket group_sock = b_to_sock.group_socket();
+                       to_pair = node_groups[b_to_node.ptr.data][group_sock.ptr.data];
+               }
+               else {
+                       /* regular node */
+                       to_pair = node_socket_map_pair(node_map, b_to_node, b_to_sock);
+               }
+
+               /* in case of groups there may not actually be a node inside the group
+                  that the group socket connects to, so from_node or to_node may be NULL */
+               if(from_pair.first && to_pair.first) {
+                       ShaderOutput *output = from_pair.first->output(from_pair.second.c_str());
+                       ShaderInput *input = to_pair.first->input(to_pair.second.c_str());
+
+                       graph->connect(output, input);
+               }
+       }
+}
+
+/* Sync Materials */
+
+void BlenderSync::sync_materials()
+{
+       shader_map.set_default(scene->shaders[scene->default_surface]);
+
+       /* material loop */
+       BL::BlendData::materials_iterator b_mat;
+
+       for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) {
+               Shader *shader;
+               
+               /* test if we need to sync */
+               if(shader_map.sync(&shader, *b_mat)) {
+                       ShaderGraph *graph = new ShaderGraph();
+
+                       shader->name = b_mat->name().c_str();
+
+                       /* create nodes */
+                       if(b_mat->use_nodes() && b_mat->node_tree()) {
+                               PtrSockMap sock_to_node;
+                               BL::ShaderNodeTree b_ntree(b_mat->node_tree());
+
+                               add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
+                       }
+                       else {
+                               ShaderNode *closure, *out;
+
+                               closure = graph->add(new DiffuseBsdfNode());
+                               closure->input("Color")->value = get_float3(b_mat->diffuse_color());
+                               out = graph->output();
+
+                               graph->connect(closure->output("BSDF"), out->input("Surface"));
+                       }
+
+                       /* settings */
+                       PointerRNA cmat = RNA_pointer_get(&b_mat->ptr, "cycles");
+                       shader->sample_as_light = get_boolean(cmat, "sample_as_light");
+                       shader->homogeneous_volume = get_boolean(cmat, "homogeneous_volume");
+
+                       shader->set_graph(graph);
+                       shader->tag_update(scene);
+               }
+       }
+}
+
+/* Sync World */
+
+void BlenderSync::sync_world()
+{
+       Background *background = scene->background;
+       Background prevbackground = *background;
+
+       BL::World b_world = b_scene.world();
+
+       if(world_recalc || b_world.ptr.data != world_map) {
+               Shader *shader = scene->shaders[scene->default_background];
+               ShaderGraph *graph = new ShaderGraph();
+
+               /* create nodes */
+               if(b_world && b_world.use_nodes() && b_world.node_tree()) {
+                       PtrSockMap sock_to_node;
+                       BL::ShaderNodeTree b_ntree(b_world.node_tree());
+
+                       add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
+               }
+               else if(b_world) {
+                       ShaderNode *closure, *out;
+
+                       closure = graph->add(new BackgroundNode());
+                       closure->input("Color")->value = get_float3(b_world.horizon_color());
+                       out = graph->output();
+
+                       graph->connect(closure->output("Background"), out->input("Surface"));
+               }
+
+               shader->set_graph(graph);
+               shader->tag_update(scene);
+       }
+
+       PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+       background->transparent = get_boolean(cscene, "film_transparent");
+
+       if(background->modified(prevbackground))
+               background->tag_update(scene);
+
+       world_map = b_world.ptr.data;
+       world_recalc = false;
+}
+
+/* Sync Lamps */
+
+void BlenderSync::sync_lamps()
+{
+       shader_map.set_default(scene->shaders[scene->default_light]);
+
+       /* lamp loop */
+       BL::BlendData::lamps_iterator b_lamp;
+
+       for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp) {
+               Shader *shader;
+               
+               /* test if we need to sync */
+               if(shader_map.sync(&shader, *b_lamp)) {
+                       ShaderGraph *graph = new ShaderGraph();
+
+                       /* create nodes */
+                       if(b_lamp->use_nodes() && b_lamp->node_tree()) {
+                               shader->name = b_lamp->name().c_str();
+
+                               PtrSockMap sock_to_node;
+                               BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
+
+                               add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
+                       }
+                       else {
+                               ShaderNode *closure, *out;
+
+                               closure = graph->add(new EmissionNode());
+                               closure->input("Color")->value = get_float3(b_lamp->color());
+                               closure->input("Strength")->value.x = b_lamp->energy()*10.0f;
+                               out = graph->output();
+
+                               graph->connect(closure->output("Emission"), out->input("Surface"));
+                       }
+
+                       shader->set_graph(graph);
+                       shader->tag_update(scene);
+               }
+       }
+}
+
+void BlenderSync::sync_shaders()
+{
+       shader_map.pre_sync();
+
+       sync_world();
+       sync_lamps();
+       sync_materials();
+
+       /* false = don't delete unused shaders, not supported */
+       shader_map.post_sync(false);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
new file mode 100644 (file)
index 0000000..36cf29d
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "background.h"
+#include "film.h"
+#include "../render/filter.h"
+#include "graph.h"
+#include "integrator.h"
+#include "light.h"
+#include "mesh.h"
+#include "nodes.h"
+#include "object.h"
+#include "scene.h"
+#include "shader.h"
+
+#include "device.h"
+
+#include "blender_sync.h"
+#include "blender_util.h"
+
+#include "util_debug.h"
+#include "util_foreach.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Constructor */
+
+BlenderSync::BlenderSync(BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_)
+: b_data(b_data_), b_scene(b_scene_),
+  shader_map(&scene_->shaders),
+  object_map(&scene_->objects),
+  mesh_map(&scene_->meshes),
+  light_map(&scene_->lights),
+  world_map(NULL),
+  world_recalc(false)
+{
+       scene = scene_;
+       preview = preview_;
+}
+
+BlenderSync::~BlenderSync()
+{
+}
+
+/* Sync */
+
+bool BlenderSync::sync_recalc()
+{
+       /* sync recalc flags from blender to cycles. actual update is done separate,
+          so we can do it later on if doing it immediate is not suitable */
+
+       BL::BlendData::materials_iterator b_mat;
+
+       for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat)
+               if(b_mat->is_updated())
+                       shader_map.set_recalc(*b_mat);
+
+       BL::BlendData::lamps_iterator b_lamp;
+
+       for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp)
+               if(b_lamp->is_updated())
+                       shader_map.set_recalc(*b_lamp);
+
+       BL::BlendData::objects_iterator b_ob;
+
+       for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
+               if(b_ob->is_updated()) {
+                       object_map.set_recalc(*b_ob);
+                       light_map.set_recalc(*b_ob);
+               }
+
+               if(object_is_mesh(*b_ob)) {
+                       if(b_ob->is_updated_data() || b_ob->data().is_updated()) {
+                               BL::ID key = object_is_modified(*b_ob)? *b_ob: b_ob->data();
+                               mesh_map.set_recalc(key);
+                       }
+               }
+               else if(object_is_light(*b_ob)) {
+                       if(b_ob->is_updated_data() || b_ob->data().is_updated())
+                               light_map.set_recalc(*b_ob);
+               }
+       }
+
+       BL::BlendData::meshes_iterator b_mesh;
+
+       for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh)
+               if(b_mesh->is_updated())
+                       mesh_map.set_recalc(*b_mesh);
+
+       BL::BlendData::worlds_iterator b_world;
+
+       for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world)
+               if(world_map == b_world->ptr.data && b_world->is_updated())
+                       world_recalc = true;
+
+       bool recalc =
+               shader_map.has_recalc() ||
+               object_map.has_recalc() ||
+               light_map.has_recalc() ||
+               mesh_map.has_recalc() ||
+               BlendDataObjects_is_updated_get(&b_data.ptr) ||
+               world_recalc;
+
+       return recalc;
+}
+
+void BlenderSync::sync_data(BL::SpaceView3D b_v3d)
+{
+       sync_integrator();
+       sync_film();
+       sync_render_layer(b_v3d);
+       sync_shaders();
+       sync_objects(b_v3d);
+}
+
+/* Integrator */
+
+void BlenderSync::sync_integrator()
+{
+       PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+       Integrator *integrator = scene->integrator;
+       Integrator previntegrator = *integrator;
+
+       integrator->min_bounce = get_int(cscene, "min_bounces");
+       integrator->max_bounce = get_int(cscene, "max_bounces");
+
+       integrator->max_diffuse_bounce = get_int(cscene, "diffuse_bounces");
+       integrator->max_glossy_bounce = get_int(cscene, "glossy_bounces");
+       integrator->max_transmission_bounce = get_int(cscene, "transmission_bounces");
+
+       integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces");
+       integrator->transparent_min_bounce = get_int(cscene, "transparent_min_bounces");
+       integrator->transparent_shadows = get_boolean(cscene, "use_transparent_shadows");
+
+       integrator->no_caustics = get_boolean(cscene, "no_caustics");
+       integrator->blur_caustics = get_float(cscene, "blur_caustics");
+
+       integrator->seed = get_int(cscene, "seed");
+
+       if(integrator->modified(previntegrator))
+               integrator->tag_update(scene);
+}
+
+/* Film */
+
+void BlenderSync::sync_film()
+{
+       PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+       Film *film = scene->film;
+       Film prevfilm = *film;
+
+       film->exposure = get_float(cscene, "film_exposure");
+
+       if(film->modified(prevfilm))
+               film->tag_update(scene);
+
+       Filter *filter = scene->filter;
+       Filter prevfilter = *filter;
+
+       filter->filter_type = (FilterType)RNA_enum_get(&cscene, "filter_type");
+       filter->filter_width = (filter->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width");
+
+       if(filter->modified(prevfilter))
+               filter->tag_update(scene);
+}
+
+/* Render Layer */
+
+void BlenderSync::sync_render_layer(BL::SpaceView3D b_v3d)
+{
+       if(b_v3d) {
+               render_layer.scene_layer = get_layer(b_v3d.layers());
+               render_layer.layer = render_layer.scene_layer;
+               render_layer.material_override = PointerRNA_NULL;
+       }
+       else {
+               BL::RenderSettings r = b_scene.render();
+               BL::RenderSettings::layers_iterator b_rlay;
+               bool first = true;
+
+               for(r.layers.begin(b_rlay); b_rlay != r.layers.end(); ++b_rlay) {
+                       /* single layer for now */
+                       if(first) {
+                               render_layer.scene_layer = get_layer(b_scene.layers());
+                               render_layer.layer = get_layer(b_rlay->layers());
+                               render_layer.material_override = b_rlay->material_override();
+
+                               first = false;
+                       }
+               }
+       }
+}
+
+/* Scene Parameters */
+
+SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background)
+{
+       SceneParams params;
+       PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+       int shadingsystem = RNA_enum_get(&cscene, "shading_system");
+
+       if(shadingsystem == 0)
+               params.shadingsystem = SceneParams::SVM;
+       else if(shadingsystem == 1)
+               params.shadingsystem = SceneParams::OSL;
+       
+       if(background)
+               params.bvh_type = SceneParams::BVH_STATIC;
+       else
+               params.bvh_type = (SceneParams::BVHType)RNA_enum_get(&cscene, "debug_bvh_type");
+
+       params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
+
+       return params;
+}
+
+/* Session Parameters */
+
+bool BlenderSync::get_session_pause(BL::Scene b_scene, bool background)
+{
+       PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+       return (background)? false: get_boolean(cscene, "preview_pause");
+}
+
+static bool device_type_available(vector<DeviceType>& types, DeviceType dtype)
+{
+       foreach(DeviceType dt, types)
+               if(dt == dtype)
+                       return true;
+
+       return false;
+}
+
+SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
+{
+       SessionParams params;
+       PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+       /* device type */
+       params.device_type = DEVICE_CPU;
+
+       if(RNA_enum_get(&cscene, "device") != 0) {
+               vector<DeviceType> types = Device::available_types();
+               DeviceType dtype = (RNA_enum_get(&cscene, "gpu_type") == 0)? DEVICE_CUDA: DEVICE_OPENCL;
+
+               if(device_type_available(types, dtype))
+                       params.device_type = dtype;
+               else if(device_type_available(types, DEVICE_OPENCL))
+                       params.device_type = DEVICE_OPENCL;
+               else if(device_type_available(types, DEVICE_CUDA))
+                       params.device_type = DEVICE_CUDA;
+       }
+                       
+       /* Background */
+       params.background = background;
+                       
+       /* samples */
+       if(background) {
+               params.samples = get_int(cscene, "samples");
+       }
+       else {
+               params.samples = get_int(cscene, "preview_samples");
+               if(params.samples == 0)
+                       params.samples = INT_MAX;
+       }
+
+       /* other parameters */
+       params.threads = b_scene.render().threads();
+       params.tile_size = get_int(cscene, "debug_tile_size");
+       params.min_size = get_int(cscene, "debug_min_size");
+       params.cancel_timeout = get_float(cscene, "debug_cancel_timeout");
+       params.reset_timeout = get_float(cscene, "debug_reset_timeout");
+       params.text_timeout = get_float(cscene, "debug_text_timeout");
+
+       if(background) {
+               params.progressive = true;
+               params.min_size = INT_MAX;
+       }
+       else
+               params.progressive = true;
+
+       return params;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h
new file mode 100644 (file)
index 0000000..2e7b8ed
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLENDER_SYNC_H__
+#define __BLENDER_SYNC_H__
+
+#include "MEM_guardedalloc.h"
+#include "RNA_types.h"
+#include "RNA_access.h"
+#include "RNA_blender_cpp.h"
+
+#include "blender_util.h"
+
+#include "scene.h"
+#include "session.h"
+
+#include "util_map.h"
+#include "util_set.h"
+#include "util_transform.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Background;
+class Camera;
+class Film;
+class Light;
+class Mesh;
+class Object;
+class Scene;
+class Shader;
+class ShaderGraph;
+class ShaderNode;
+
+class BlenderSync {
+public:
+       BlenderSync(BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_);
+       ~BlenderSync();
+
+       /* sync */
+       bool sync_recalc();
+       void sync_data(BL::SpaceView3D b_v3d);
+       void sync_camera(int width, int height);
+       void sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
+
+       /* get parameters */
+       static SceneParams get_scene_params(BL::Scene b_scene, bool background);
+       static SessionParams get_session_params(BL::Scene b_scene, bool background);
+       static bool get_session_pause(BL::Scene b_scene, bool background);
+
+private:
+       /* sync */
+       void sync_lamps();
+       void sync_materials();
+       void sync_objects(BL::SpaceView3D b_v3d);
+       void sync_film();
+       void sync_integrator();
+       void sync_view();
+       void sync_world();
+       void sync_render_layer(BL::SpaceView3D b_v3d);
+       void sync_shaders();
+
+       void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
+       Mesh *sync_mesh(BL::Object b_ob, bool object_updated);
+       void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint visibility);
+       void sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm);
+
+       /* util */
+       void find_shader(BL::ID id, vector<uint>& used_shaders);
+       bool object_is_modified(BL::Object b_ob);
+       bool object_is_mesh(BL::Object b_ob);
+       bool object_is_light(BL::Object b_ob);
+
+       /* variables */
+       BL::BlendData b_data;
+       BL::Scene b_scene;
+
+       id_map<void*, Shader> shader_map;
+       id_map<ObjectKey, Object> object_map;
+       id_map<void*, Mesh> mesh_map;
+       id_map<ObjectKey, Light> light_map;
+       set<Mesh*> mesh_synced;
+       void *world_map;
+       bool world_recalc;
+
+       Scene *scene;
+       bool preview;
+
+       struct RenderLayerInfo {
+               RenderLayerInfo()
+               : scene_layer(0), layer(0),
+                 material_override(PointerRNA_NULL)
+               {}
+
+               uint scene_layer;
+               uint layer;
+               BL::Material material_override;
+       } render_layer;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_SYNC_H__ */
+
diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h
new file mode 100644 (file)
index 0000000..bcca028
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __BLENDER_UTIL_H__
+#define __BLENDER_UTIL_H__
+
+#include "util_map.h"
+#include "util_path.h"
+#include "util_set.h"
+#include "util_transform.h"
+#include "util_types.h"
+#include "util_vector.h"
+
+/* Hacks to hook into Blender API */
+
+extern "C" {
+
+struct RenderEngine;
+struct RenderResult;
+
+ID *rna_Object_to_mesh(void *_self, void *reports, void *scene, int apply_modifiers, int settings);
+void rna_Main_meshes_remove(void *bmain, void *reports, void *mesh);
+void rna_Object_create_duplilist(void *ob, void *reports, void *sce);
+void rna_Object_free_duplilist(void *ob, void *reports);
+void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values);
+void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values);
+struct RenderResult *RE_engine_begin_result(struct RenderEngine *engine, int x, int y, int w, int h);
+void RE_engine_update_result(struct RenderEngine *engine, struct RenderResult *result);
+void RE_engine_end_result(struct RenderEngine *engine, struct RenderResult *result);
+int RE_engine_test_break(struct RenderEngine *engine);
+void RE_engine_update_stats(struct RenderEngine *engine, const char *stats, const char *info);
+void RE_engine_update_progress(struct RenderEngine *engine, float progress);
+void engine_tag_redraw(void *engine);
+void engine_tag_update(void *engine);
+int rna_Object_is_modified(void *ob, void *scene, int settings);
+void BLI_timestr(double _time, char *str);
+
+}
+
+CCL_NAMESPACE_BEGIN
+
+static inline BL::Mesh object_to_mesh(BL::Object self, BL::Scene scene, bool apply_modifiers, bool render)
+{
+       ID *data = rna_Object_to_mesh(self.ptr.data, NULL, scene.ptr.data, apply_modifiers, (render)? 2: 1);
+       PointerRNA ptr;
+       RNA_id_pointer_create(data, &ptr);
+       return BL::Mesh(ptr);
+}
+
+static inline void object_remove_mesh(BL::BlendData data, BL::Mesh mesh)
+{
+       rna_Main_meshes_remove(data.ptr.data, NULL, mesh.ptr.data);
+}
+
+static inline void object_create_duplilist(BL::Object self, BL::Scene scene)
+{
+       rna_Object_create_duplilist(self.ptr.data, NULL, scene.ptr.data);
+}
+
+static inline void object_free_duplilist(BL::Object self)
+{
+       rna_Object_free_duplilist(self.ptr.data, NULL);
+}
+
+static inline bool object_is_modified(BL::Object self, BL::Scene scene, bool preview)
+{
+       return rna_Object_is_modified(self.ptr.data, scene.ptr.data, (preview)? (1<<0): (1<<1))? true: false;
+}
+
+/* Utilities */
+
+static inline Transform get_transform(BL::Array<float, 16> array)
+{
+       Transform tfm;
+
+       /* we assume both types to be just 16 floats, and transpose because blender
+          use column major matrix order while we use row major */
+       memcpy(&tfm, &array, sizeof(float)*16);
+       tfm = transform_transpose(tfm);
+
+       return tfm;
+}
+
+static inline float2 get_float2(BL::Array<float, 2> array)
+{
+       return make_float2(array[0], array[1]);
+}
+
+static inline float3 get_float3(BL::Array<float, 2> array)
+{
+       return make_float3(array[0], array[1], 0.0f);
+}
+
+static inline float3 get_float3(BL::Array<float, 3> array)
+{
+       return make_float3(array[0], array[1], array[2]);
+}
+
+static inline float3 get_float3(BL::Array<float, 4> array)
+{
+       return make_float3(array[0], array[1], array[2]);
+}
+
+static inline int4 get_int4(BL::Array<int, 4> array)
+{
+       return make_int4(array[0], array[1], array[2], array[3]);
+}
+
+static inline uint get_layer(BL::Array<int, 20> array)
+{
+       uint layer = 0;
+
+       for(uint i = 0; i < 20; i++)
+               if(array[i])
+                       layer |= (1 << i);
+       
+       return layer;
+}
+
+/*static inline float3 get_float3(PointerRNA& ptr, const char *name)
+{
+       float3 f;
+       RNA_float_get_array(&ptr, name, &f.x);
+       return f;
+}*/
+
+static inline bool get_boolean(PointerRNA& ptr, const char *name)
+{
+       return RNA_boolean_get(&ptr, name)? true: false;
+}
+
+static inline float get_float(PointerRNA& ptr, const char *name)
+{
+       return RNA_float_get(&ptr, name);
+}
+
+static inline int get_int(PointerRNA& ptr, const char *name)
+{
+       return RNA_int_get(&ptr, name);
+}
+
+static inline int get_enum(PointerRNA& ptr, const char *name)
+{
+       return RNA_enum_get(&ptr, name);
+}
+
+static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
+{
+       PropertyRNA *prop = RNA_struct_find_property(&ptr, name);
+       const char *identifier = "";
+       int value = RNA_property_enum_get(&ptr, prop);
+
+       RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
+
+       return string(identifier);
+}
+
+/* Relative Paths */
+
+static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, const string& path)
+{
+       if(path.size() >= 2 && path[0] == '/' && path[1] == '/') {
+               string dirname = (b_id.library())? b_id.library().filepath(): b_data.filepath();
+               return path_join(path_dirname(dirname), path.substr(2));
+       }
+
+       return path;
+}
+
+/* ID Map
+ *
+ * Utility class to keep in sync with blender data.
+ * Used for objects, meshes, lights and shaders. */
+
+template<typename K, typename T>
+class id_map {
+public:
+       id_map(vector<T*> *scene_data_)
+       {
+               scene_data = scene_data_;
+       }
+
+       T *find(BL::ID id)
+       {
+               return find(id.ptr.id.data);
+       }
+
+       T *find(const K& key)
+       {
+               if(b_map.find(key) != b_map.end()) {
+                       T *data = b_map[key];
+                       return data;
+               }
+
+               return NULL;
+       }
+
+       void set_recalc(BL::ID id)
+       {
+               b_recalc.insert(id.ptr.data);
+       }
+
+       bool has_recalc()
+       {
+               return !(b_recalc.empty());
+       }
+
+       void pre_sync()
+       {
+               used_set.clear();
+       }
+
+       bool sync(T **r_data, BL::ID id)
+       {
+               return sync(r_data, id, id, id.ptr.id.data);
+       }
+
+       bool sync(T **r_data, BL::ID id, BL::ID parent, const K& key)
+       {
+               T *data = find(key);
+               bool recalc;
+
+               if(!data) {
+                       /* add data if it didn't exist yet */
+                       data = new T();
+                       scene_data->push_back(data);
+                       b_map[key] = data;
+                       recalc = true;
+               }
+               else {
+                       recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
+                       if(parent.ptr.data)
+                               recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
+               }
+
+               used(data);
+
+               *r_data = data;
+               return recalc;
+       }
+
+       void used(T *data)
+       {
+               /* tag data as still in use */
+               used_set.insert(data);
+       }
+
+       void set_default(T *data)
+       {
+               b_map[NULL] = data;
+       }
+
+       bool post_sync(bool do_delete = true)
+       {
+               /* remove unused data */
+               vector<T*> new_scene_data;
+               typename vector<T*>::iterator it;
+               bool deleted = false;
+
+               for(it = scene_data->begin(); it != scene_data->end(); it++) {
+                       T *data = *it;
+
+                       if(do_delete && used_set.find(data) == used_set.end()) {
+                               delete data;
+                               deleted = true;
+                       }
+                       else
+                               new_scene_data.push_back(data);
+               }
+
+               *scene_data = new_scene_data;
+
+               /* update mapping */
+               map<K, T*> new_map;
+               typedef pair<const K, T*> TMapPair;
+               typename map<K, T*>::iterator jt;
+
+               for(jt = b_map.begin(); jt != b_map.end(); jt++) {
+                       TMapPair& pair = *jt;
+
+                       if(used_set.find(pair.second) != used_set.end())
+                               new_map[pair.first] = pair.second;
+               }
+
+               used_set.clear();
+               b_recalc.clear();
+               b_map = new_map;
+
+               return deleted;
+       }
+
+protected:
+       vector<T*> *scene_data;
+       map<K, T*> b_map;
+       set<T*> used_set;
+       set<void*> b_recalc;
+};
+
+/* Object Key */
+
+struct ObjectKey {
+       void *parent;
+       int index;
+       void *ob;
+
+       ObjectKey(void *parent_, int index_, void *ob_)
+       : parent(parent_), index(index_), ob(ob_) {}
+
+       bool operator<(const ObjectKey& k) const
+       { return (parent < k.parent || (parent == k.parent && (index < k.index || (index == k.index && ob < k.ob)))); }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BLENDER_UTIL_H__ */
+
diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b35c20b
--- /dev/null
@@ -0,0 +1,18 @@
+
+include_directories(. ../kernel ../kernel/svm ../render ../util ../device)
+
+set(sources
+       bvh.cpp
+       bvh_build.cpp
+       bvh_node.cpp
+       bvh_sort.cpp)
+
+set(headers
+       bvh.h
+       bvh_build.h
+       bvh_node.h
+       bvh_params.h
+       bvh_sort.h)
+
+add_library(cycles_bvh ${sources} ${headers})
+
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
new file mode 100644 (file)
index 0000000..cd3ad70
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * Adapted from code copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mesh.h"
+#include "object.h"
+#include "scene.h"
+
+#include "bvh.h"
+#include "bvh_build.h"
+#include "bvh_node.h"
+#include "bvh_params.h"
+
+#include "util_cache.h"
+#include "util_debug.h"
+#include "util_foreach.h"
+#include "util_map.h"
+#include "util_progress.h"
+#include "util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Pack Utility */
+
+struct BVHStackEntry
+{
+       const BVHNode *node;
+       int idx;
+
+       BVHStackEntry(const BVHNode* n = 0, int i = 0)