Cycles render engine, initial commit. This is the engine itself, blender modification...
authorTon Roosendaal <ton@blender.org>
Wed, 27 Apr 2011 11:58:34 +0000 (11:58 +0000)
committerTon Roosendaal <ton@blender.org>
Wed, 27 Apr 2011 11:58:34 +0000 (11:58 +0000)
Cycles uses code from some great open source projects, many thanks them:

* BVH building and traversal code from NVidia's "Understanding the Efficiency of Ray Traversal on GPUs":
http://code.google.com/p/understanding-the-efficiency-of-ray-traversal-on-gpus/
* Open Shading Language for a large part of the shading system:
http://code.google.com/p/openshadinglanguage/
* Blender for procedural textures and a few other nodes.
* Approximate Catmull Clark subdivision from NVidia Mesh tools:
http://code.google.com/p/nvidia-mesh-tools/
* Sobol direction vectors from:
http://web.maths.unsw.edu.au/~fkuo/sobol/
* Film response functions from:
http://www.cs.columbia.edu/CAVE/software/softlib/dorf.php

291 files changed:
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/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/create_dmg.py [new file with mode: 0755]
intern/cycles/cmake/external_libs.cmake [new file with mode: 0644]
intern/cycles/cmake/platforms.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/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_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_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_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_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_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]

diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
new file mode 100644 (file)
index 0000000..406b4e6
--- /dev/null
@@ -0,0 +1,59 @@
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(cycles)
+SET(CYCLES_VERSION_MAJOR 0)
+SET(CYCLES_VERSION_MINOR 0)
+SET(CYCLES_VERSION ${CYCLES_VERSION_MAJOR}.${CYCLES_VERSION_MINOR})
+
+# Options
+
+OPTION(WITH_OSL "Build with Open Shading Language support" OFF)
+OPTION(WITH_CUDA "Build with CUDA support" OFF)
+OPTION(WITH_OPENCL "Build with OpenCL support (not working)" OFF)
+OPTION(WITH_BLENDER "Build Blender Python extension" OFF)
+OPTION(WITH_PARTIO "Build with Partio point cloud support (unfinished)" OFF)
+OPTION(WITH_NETWORK "Build with network rendering support (unfinished)" OFF)
+OPTION(WITH_MULTI "Build with network rendering support (unfinished)" OFF)
+OPTION(WITH_DOCS "Build html documentation" OFF)
+
+# Flags
+SET(CUDA_ARCH sm_10 sm_11 sm_12 sm_13 sm_20 sm_21 CACHE STRING "CUDA architectures to build for")
+SET(CUDA_MAXREG 24 CACHE STRING "CUDA maximum number of register to use")
+
+# Paths
+
+SET(OSL_PATH "" CACHE PATH "Path to OpenShadingLanguage installation")
+SET(OIIO_PATH "" CACHE PATH "Path to OpenImageIO installation")
+SET(BOOST_PATH "/usr" CACHE PATH "Path to Boost installation")
+SET(CUDA_PATH "/usr/local/cuda" CACHE PATH "Path to CUDA installation")
+SET(OPENCL_PATH "" CACHE PATH "Path to OpenCL installation")
+SET(PYTHON_PATH "" CACHE PATH "Path to Python installation")
+SET(BLENDER_PATH "" CACHE PATH "Path to Blender installation")
+SET(PARTIO_PATH "" CACHE PATH "Path to Partio installation")
+SET(GLEW_PATH "" CACHE PATH "Path to GLEW installation")
+SET(GLUT_PATH "" CACHE PATH "Path to GLUT installation")
+SET(INSTALL_PATH "${CMAKE_BINARY_DIR}/install" CACHE PATH "Path to install to")
+
+# External Libraries
+
+INCLUDE(cmake/external_libs.cmake)
+
+# Platforms
+
+INCLUDE(cmake/platforms.cmake)
+
+# Subdirectories
+
+IF(WITH_BLENDER)
+       ADD_SUBDIRECTORY(blender)
+ENDIF(WITH_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..b1f73ed
--- /dev/null
@@ -0,0 +1,48 @@
+
+INCLUDE_DIRECTORIES(. ../device ../kernel ../kernel/svm ../bvh ../util ../render ../subd)
+
+SET(LIBRARIES
+       device
+       kernel
+       render
+       bvh
+       subd
+       util
+       ${Boost_LIBRARIES}
+       ${OPENGL_LIBRARIES}
+       ${GLEW_LIBRARIES}
+       ${OPENIMAGEIO_LIBRARY}
+       ${GLUT_LIBRARIES})
+
+IF(WITH_OSL)
+       LIST(APPEND LIBRARIES kernel_osl ${OSL_LIBRARIES})
+ENDIF(WITH_OSL)
+
+IF(WITH_PARTIO)
+       LIST(APPEND LIBRARIES ${PARTIO_LIBRARIES})
+ENDIF(WITH_PARTIO)
+
+IF(WITH_OPENCL)
+       LIST(APPEND LIBRARIES ${OPENCL_LIBRARIES})
+ENDIF(WITH_OPENCL)
+
+ADD_EXECUTABLE(cycles_test cycles_test.cpp cycles_xml.cpp cycles_xml.h)
+TARGET_LINK_LIBRARIES(cycles_test ${LIBRARIES})
+INSTALL(TARGETS cycles_test DESTINATION ${INSTALL_PATH}/cycles)
+
+IF(UNIX AND NOT APPLE)
+       SET_TARGET_PROPERTIES(cycles_test PROPERTIES INSTALL_RPATH $ORIGIN/lib)
+ENDIF()
+
+IF(WITH_NETWORK)
+       ADD_EXECUTABLE(cycles_server cycles_server.cpp)
+       TARGET_LINK_LIBRARIES(cycles_server ${LIBRARIES})
+       INSTALL(TARGETS cycles_server DESTINATION ${INSTALL_PATH}/cycles)
+
+       IF(UNIX AND NOT APPLE)
+               SET_TARGET_PROPERTIES(cycles_server PROPERTIES INSTALL_RPATH $ORIGIN/lib)
+       ENDIF()
+ENDIF()
+
+INSTALL(CODE "FILE(MAKE_DIRECTORY ${INSTALL_PATH}/cycles/cache)")
+
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..96072ac
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * 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 pass;
+       double total_time, pass_time;
+       string status, substatus;
+
+       /* get status */
+       options.session->progress.get_pass(pass, total_time, pass_time);
+       options.session->progress.get_status(status, substatus);
+
+       if(substatus != "")
+               status += ": " + substatus;
+
+       /* print status */
+       status = string_printf("Pass %d   %s", pass, 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->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 pass;
+       double total_time, pass_time;
+       string status, substatus;
+
+       progress.get_pass(pass, total_time, pass_time);
+       progress.get_status(status, substatus);
+
+       if(substatus != "")
+               status += ": " + substatus;
+
+       str = string_printf("latency: %.4f        pass: %d        total: %.4f        average: %.4f        %s",
+               latency, pass, total_time, pass_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);
+}
+
+void keyboard(unsigned char key)
+{
+       if(key == 'r')
+               options.session->reset(options.width, options.height);
+       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 = path_get("../../../test/models/elephants.xml");
+       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",
+               "--passes %d", &options.session_params.passes, "Number of passes to render",
+               "--output %s", &options.session_params.output_path, "File path to write output image",
+               "--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.passes < 0) {
+               fprintf(stderr, "Invalid number of passes: %d\n", options.session_params.passes);
+               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();
+
+       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..0e80cd8
--- /dev/null
@@ -0,0 +1,936 @@
+/*
+ * 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->minbounce, node, "min_bounce");
+       xml_read_int(&integrator->maxbounce, 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->lensradius, node, "lensradius"); // 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(), "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..a75f729
--- /dev/null
@@ -0,0 +1,72 @@
+
+SET(sources
+       blender_camera.cpp
+       blender_mesh.cpp
+       blender_object.cpp
+       blender_python.cpp
+       blender_session.cpp
+       blender_shader.cpp
+       blender_sync.cpp)
+
+SET(headers
+       blender_sync.h
+       blender_session.h
+       blender_util.h)
+
+SET(addonfiles
+       addon/__init__.py
+       addon/engine.py 
+       addon/enums.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})
+
+SET(LIBRARIES
+       render
+       bvh
+       device
+       kernel
+       util
+       subd
+       ${Boost_LIBRARIES}
+       ${OPENGL_LIBRARIES}
+       ${OPENIMAGEIO_LIBRARY}
+       ${PYTHON_LIBRARIES}
+       ${GLUT_LIBRARIES}
+       ${GLEW_LIBRARIES}
+       ${BLENDER_LIBRARIES})
+
+IF(WITH_OSL)
+       LIST(APPEND LIBRARIES kernel_osl ${OSL_LIBRARIES})
+ENDIF(WITH_OSL)
+
+IF(WITH_PARTIO)
+       LIST(APPEND LIBRARIES ${PARTIO_LIBRARIES})
+ENDIF(WITH_PARTIO)
+
+IF(WITH_OPENCL)
+       LIST(APPEND LIBRARIES ${OPENCL_LIBRARIES})
+ENDIF(WITH_OPENCL)
+
+SET(CMAKE_MODULE_LINKER_FLAGS ${PYTHON_MODULE_FLAGS})
+
+ADD_LIBRARY(cycles_blender MODULE ${sources} ${headers})
+TARGET_LINK_LIBRARIES(cycles_blender ${LIBRARIES})
+
+INSTALL(FILES ${addonfiles} DESTINATION ${INSTALL_PATH}/cycles)
+INSTALL(TARGETS cycles_blender LIBRARY DESTINATION ${INSTALL_PATH}/cycles)
+
+IF(UNIX AND NOT APPLE)
+       SET_TARGET_PROPERTIES(cycles_blender PROPERTIES INSTALL_RPATH $ORIGIN/lib)
+ENDIF()
+
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
new file mode 100644 (file)
index 0000000..0a2e5ce
--- /dev/null
@@ -0,0 +1,73 @@
+#
+# 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
+
+class CyclesRender(bpy.types.RenderEngine):
+       bl_idname = 'CYCLES'
+       bl_label = "Cycles"
+
+       def __init__(self):
+               engine.init()
+               self.session = None
+       
+       def __del__(self):
+               engine.free(self)
+
+       def render(self, scene):
+               engine.create(self, scene, True)
+               engine.render(self, scene)
+
+       def draw(self, scene):
+               if not self.session:
+                       engine.create(self, scene, False)
+               engine.draw(self, scene)
+
+       def update(self, scene):
+               engine.update(self, scene)
+
+def register():
+       properties.register()
+       ui.register()
+       xml.register()
+       bpy.utils.register_module(__name__)
+
+def unregister():
+       xml.unregister()
+       ui.unregister()
+       properties.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..fb98068
--- /dev/null
@@ -0,0 +1,107 @@
+#
+# 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():
+       from cycles import libcycles_blender as lib
+       import os.path
+       lib.init(os.path.dirname(__file__))
+
+def create(engine, scene, offline):
+       from cycles import libcycles_blender as lib
+       data = bpy.data.as_pointer()
+       scene = scene.as_pointer()
+
+       if not offline and bpy.context.area.type == 'VIEW_3D':
+               region = bpy.context.region.as_pointer()
+               v3d = bpy.context.space_data.as_pointer()
+               rv3d = bpy.context.region_data.as_pointer()
+       else:
+               region = 0
+               v3d = 0
+               rv3d = 0
+
+       engine.session = lib.create(engine.as_pointer(), data, scene, region, v3d, rv3d)
+
+def free(engine):
+       if "session" in dir(engine):
+               if engine.session:
+                       from cycles import libcycles_blender as lib
+                       lib.free(engine.session)
+               del engine.session
+
+def render(engine, scene):
+       from cycles import libcycles_blender as lib
+       lib.render(engine.session)
+
+def update(engine, scene):
+       from cycles import libcycles_blender as lib
+       lib.sync(engine.session)
+
+def draw(engine, scene):
+       from cycles import libcycles_blender as lib
+       v3d = bpy.context.space_data.as_pointer()
+       rv3d = bpy.context.region_data.as_pointer()
+       region = bpy.context.region
+
+       # draw render image
+       status, substatus = lib.draw(engine.session, v3d, rv3d)
+
+       # draw text over image
+       if status != "":
+               import blf
+               import bgl
+
+               fontid = 0 # todo, find out how to set this
+               dim = blf.dimensions(fontid, status)
+               dim_sub = blf.dimensions(fontid, substatus)
+
+               padding = 5
+
+               x = (region.width - max(dim[0], dim_sub[0]))*0.5 - padding
+               y = (region.height - (dim[1] + dim_sub[1] + padding))*0.5 - padding
+
+               bgl.glColor4f(0.0, 0.0, 0.0, 0.5)
+               bgl.glEnable(bgl.GL_BLEND)
+               bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA)
+               bgl.glRectf(x, y, x+max(dim[0], dim_sub[0])+padding+padding, y+dim[1]+dim_sub[1]+padding+padding+2)
+               bgl.glDisable(bgl.GL_BLEND)
+
+               x = (region.width - dim[0])*0.5
+               y = (region.height - (dim[1] + dim_sub[1] + padding))*0.5 + dim_sub[1] + padding
+
+               bgl.glColor3f(0.8, 0.8, 0.8)
+               blf.position(fontid, x, y, 0)
+               blf.draw(fontid, status)
+
+               x = (region.width - dim_sub[0])*0.5
+               y = (region.height - (dim[1] + dim_sub[1] + padding))*0.5
+
+               bgl.glColor3f(0.6, 0.6, 0.6)
+               blf.position(fontid, x, y, 0)
+               blf.draw(fontid, substatus)
+
+def available_devices():
+       from cycles import libcycles_blender as lib
+       return lib.available_devices()
+
+def with_osl():
+       from cycles 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..fd12fa6
--- /dev/null
@@ -0,0 +1,113 @@
+#
+# 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.
+#
+
+devices = (
+("CPU", "CPU", "Processor"),
+("GPU", "GPU", "Graphics card (NVidia only)"))
+
+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"))
+
+response_curves = (
+("None", "None", ""),
+("", "Agfa", ""),
+("Agfacolor Futura 100", "Futura 100", ""),
+("Agfacolor Futura 200", "Futura 200", ""),
+("Agfacolor Futura 400", "Futura 400", ""),
+("Agfacolor Futura II 100", "Futura II 100", ""),
+("Agfacolor Futura II 200", "Futura II 200", ""),
+("Agfacolor Futura II 400", "Futura II 400", ""),
+("Agfacolor HDC 100 plus", "HDC 100 plus", ""),
+("Agfacolor HDC 400 plus", "HDC 400 plus", ""),
+("Agfacolor HDC 200 plus", "HDC 200 plus", ""),
+("Agfacolor Optima II 100", "Optima II 100", ""),
+("Agfacolor Optima II 200", "Optima II 200", ""),
+("Agfacolor Ultra 050", "Ultra 050", ""),
+("", "Agfa", ""),
+("Agfacolor Vista 100", "Vista 100", ""),
+("Agfacolor Vista 200", "Vista 200", ""),
+("Agfacolor Vista 400", "Vista 400", ""),
+("Agfacolor Vista 800", "Vista 800", ""),
+("Agfachrome CT Precisa 100", "CT Precisa 100", ""),
+("Agfachrome CT Precisa 200", "CT Precisa 200", ""),
+("Agfachrome RSX2 050", "Agfachrome RSX2 050", ""),
+("Agfachrome RSX2 100", "Agfachrome RSX2 100", ""),
+("Agfachrome RSX2 200", "Agfachrome RSX2 200", ""),
+("Advantix 100", "Advantix 100", ""),
+("Advantix 200", "Advantix 200", ""),
+("Advantix 400", "Advantix 400", ""),
+("", "Kodak", ""),
+("Gold 100", "Gold 100", ""),
+("Gold 200", "Gold 200", ""),
+("Max Zoom 800", "Max Zoom 800", ""),
+("Portra 100T", "Portra 100T", ""),
+("Portra 160NC", "Portra 160NC", ""),
+("Portra 160VC", "Portra 160VC", ""),
+("Portra 800", "Portra 800", ""),
+("Portra 400VC", "Portra 400VC", ""),
+("Portra 400NC", "Portra 400NC", ""),
+("", "Kodak", ""),
+("Ektachrome 100 plus", "Ektachrome 100 plus", ""),
+("Ektachrome 320T", "Ektachrome 320T", ""),
+("Ektachrome 400X", "Ektachrome 400X", ""),
+("Ektachrome 64", "Ektachrome 64", ""),
+("Ektachrome 64T", "Ektachrome 64T", ""),
+("Ektachrome E100S", "Ektachrome E100S", ""),
+("Ektachrome 100", "Ektachrome 100", ""),
+("Kodachrome 200", "Kodachrome 200", ""),
+("Kodachrome 25", "Kodachrome 25", ""),
+("Kodachrome 64", "Kodachrome 64", ""),
+#("DSCS 3151", "DSCS 3151", ""),
+#("DSCS 3152", "DSCS 3152", ""),
+#("DSCS 3153", "DSCS 3153", ""),
+#("DSCS 3154", "DSCS 3154", ""),
+#("DSCS 3155", "DSCS 3155", ""),
+#("DSCS 3156", "DSCS 3156", ""),
+#("KAI-0311", "KAI-0311", ""),
+#("KAF-2001", "KAF-2001", ""),
+#("KAF-3000", "KAF-3000", ""),
+#("KAI-0372", "KAI-0372", ""),
+#("KAI-1010", "KAI-1010", ""),
+("", "Fujifilm", ""),
+("F-125", "F-125", ""),
+("F-250", "F-250", ""),
+("F-400", "F-400", ""),
+("FCI", "FCI", ""),
+("FP2900Z", "FP2900Z", ""),
+("", "Eastman", ""),
+("Double X Neg 12min", "Double X Neg 12min", ""),
+("Double X Neg 6min", "Double X Neg 6min", ""),
+("Double X Neg 5min", "Double X Neg 5min", ""),
+("Double X Neg 4min", "Double X Neg 4min", ""),
+("", "Canon", ""),
+("Optura 981111", "Optura 981111", ""),
+("Optura 981113", "Optura 981113", ""),
+("Optura 981114", "Optura 981114", ""),
+("Optura 981111.SLRR", "Optura 981111.SLRR", "")
+)
+
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
new file mode 100644 (file)
index 0000000..3ec0587
--- /dev/null
@@ -0,0 +1,120 @@
+#
+# 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 *
+
+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.shading_system = EnumProperty(name="Shading System", description="Shading system to use for rendering",
+                       items=enums.shading_systems, default="GPU_COMPATIBLE")
+
+               cls.passes = IntProperty(name="Passes", description="Number of passes to render",
+                       default=10, min=1, max=2147483647)
+               cls.min_bounces = IntProperty(name="Min Bounces", description="Minimum number of bounces",
+                       default=3, min=0, max=1024)
+               cls.max_bounces = IntProperty(name="Max Bounces", description="Maximum number of bounces",
+                       default=8, min=0, max=1024)
+               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.exposure = FloatProperty(name="Exposure", description="Image brightness scale",
+                       default=1.0, min=0.0, max=10.0)
+               cls.response_curve = EnumProperty(name="Response Curve", description="Measured camera film response",
+                       items=enums.response_curves, default="Advantix 400")
+
+               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="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.lens_radius = FloatProperty(name="Lens radius", description="Lens radius for depth of field",
+                       default=0.0, min=0.0, max=10.0)
+       
+       @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")
+
+       @classmethod
+       def unregister(cls):
+               del bpy.types.Material.cycles
+
+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
+
+def register():
+       bpy.utils.register_class(CyclesRenderSettings)
+       bpy.utils.register_class(CyclesCameraSettings)
+       bpy.utils.register_class(CyclesMaterialSettings)
+       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(CyclesMeshSettings)
+
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
new file mode 100644 (file)
index 0000000..2c4f24d
--- /dev/null
@@ -0,0 +1,388 @@
+#
+# 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 cycles import enums
+from cycles import engine
+
+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, bpy.types.Panel):
+       bl_label = "Integrator"
+
+       def draw(self, context):
+               layout = self.layout
+
+               scene = context.scene
+               cycles = scene.cycles
+
+               split = layout.split()
+
+               col = split.column()
+               col.prop(cycles, "passes")
+               col.prop(cycles, "no_caustics")
+
+               col = split.column()
+               col = col.column(align=True)
+               col.prop(cycles, "max_bounces")
+               col.prop(cycles, "min_bounces")
+
+               #row = col.row()
+               #row.prop(cycles, "blur_caustics")
+               #row.active = not cycles.no_caustics
+
+class CyclesRender_PT_film(CyclesButtonsPanel, bpy.types.Panel):
+       bl_label = "Film"
+
+       def draw(self, context):
+               layout = self.layout
+
+               scene = context.scene
+               cycles = scene.cycles
+
+               split = layout.split()
+
+               split.prop(cycles, "exposure")
+               split.prop(cycles, "response_curve", text="")
+
+class CyclesRender_PT_debug(CyclesButtonsPanel, bpy.types.Panel):
+       bl_label = "Debug"
+       bl_options = {'DEFAULT_CLOSED'}
+
+       def draw(self, context):
+               layout = self.layout
+
+               scene = context.scene
+               cycles = scene.cycles
+
+               split = layout.split()
+
+               col = split.column()
+
+               sub = col.column(align=True)
+               sub.prop(cycles, "debug_bvh_type", text="")
+               sub.prop(cycles, "debug_use_spatial_splits")
+
+               sub = col.column(align=True)
+               sub.prop(cycles, "debug_tile_size")
+               sub.prop(cycles, "debug_min_size")
+
+               col = split.column(align=True)
+               col.prop(cycles, "debug_cancel_timeout")
+               col.prop(cycles, "debug_reset_timeout")
+               col.prop(cycles, "debug_text_timeout")
+
+class Cycles_PT_post_processing(CyclesButtonsPanel, bpy.types.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 Cycles_PT_camera(CyclesButtonsPanel, bpy.types.Panel):
+       bl_label = "Cycles"
+       bl_context = "data"
+
+       @classmethod
+       def poll(cls, context):
+               return context.camera
+
+       def draw(self, context):
+               layout = self.layout
+
+               camera = context.camera
+               cycles = camera.cycles
+
+               layout.prop(cycles, "lens_radius")
+
+class Cycles_PT_context_material(CyclesButtonsPanel, bpy.types.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, bpy.types.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:
+                       cycles = mesh.cycles
+               elif curve:
+                       cycles = curve.cycles
+               elif mball:
+                       cycles = mball.cycles
+
+               layout.prop(cycles, "displacement_method", text="Method")
+               layout.prop(cycles, "use_subdivision");
+               layout.prop(cycles, "dicing_rate");
+
+def find_node(material, nodetype):
+       if material and material.node_tree:
+               ntree = material.node_tree
+
+               for node in ntree.nodes:
+                       if type(node) is not bpy.types.NodeGroup 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")
+               return
+
+       ntree = id.node_tree
+
+       node = find_node(id, output_type)
+       if not node:
+               layout.label(text="No output node.")
+
+       input = find_node_input(node, input_name)
+       layout.template_node_view(id, ntree, node, input);
+
+class CyclesLamp_PT_lamp(CyclesButtonsPanel, bpy.types.Panel):
+       bl_label = "Surface"
+       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, bpy.types.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, bpy.types.Panel):
+       bl_label = "Volume"
+       bl_context = "world"
+
+       @classmethod
+       def poll(cls, context):
+               return context.world and CyclesButtonsPanel.poll(context)
+
+       def draw(self, context):
+               layout = self.layout
+               layout.active = False
+
+               mat = context.world
+               panel_node_draw(layout, mat, 'OUTPUT_WORLD', 'Volume')
+
+class CyclesMaterial_PT_surface(CyclesButtonsPanel, bpy.types.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, bpy.types.Panel):
+       bl_label = "Volume"
+       bl_context = "material"
+
+       @classmethod
+       def poll(cls, context):
+               return context.material and CyclesButtonsPanel.poll(context)
+
+       def draw(self, context):
+               layout = self.layout
+               layout.active = False
+
+               mat = context.material
+               panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
+
+class CyclesMaterial_PT_displacement(CyclesButtonsPanel, bpy.types.Panel):
+       bl_label = "Displacement"
+       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', 'Displacement')
+
+class CyclesMaterial_PT_settings(CyclesButtonsPanel, bpy.types.Panel):
+       bl_label = "Settings"
+       bl_context = "material"
+       bl_options = {'DEFAULT_CLOSED'}
+
+       @classmethod
+       def poll(cls, context):
+               # return context.material and CyclesButtonsPanel.poll(context)
+               return False
+
+       def draw(self, context):
+               layout = self.layout
+
+               mat = context.material
+       
+               row = layout.row()
+               row.label(text="Light Group:")
+               row.prop(mat, "light_group", text="")
+       
+def draw_device(self, context):
+       scene = context.scene
+       layout = self.layout
+
+       if scene.render.engine == "CYCLES":
+               cycles = scene.cycles
+
+               if 'cuda' in engine.available_devices():
+                       layout.prop(cycles, "device")
+               if cycles.device == 'CPU' and engine.with_osl():
+                       layout.prop(cycles, "shading_system")
+
+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_vertex_groups,
+               bpy.types.DATA_PT_shape_keys,
+               bpy.types.DATA_PT_uv_texture,
+               bpy.types.DATA_PT_vertex_colors,
+               bpy.types.DATA_PT_custom_props_mesh,
+               bpy.types.DATA_PT_context_camera,
+               bpy.types.DATA_PT_camera,
+               bpy.types.DATA_PT_camera_display,
+               bpy.types.DATA_PT_custom_props_camera,
+               bpy.types.DATA_PT_context_lamp,
+               bpy.types.DATA_PT_custom_props_lamp,
+               bpy.types.TEXTURE_PT_context_texture]
+
+def register():
+       bpy.types.RENDER_PT_render.append(draw_device)
+
+       for panel in get_panels():
+               panel.COMPAT_ENGINES.add('CYCLES')
+       
+def unregister():
+       bpy.types.RENDER_PT_render.remove(draw_device)
+
+       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..4d1b43d
--- /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
+import io_utils
+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, io_utils.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.create_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..cc4cfda
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * 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 lensradius;
+       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->lensradius = RNA_float_get(&ccamera, "lens_radius");
+               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->lensradius = bcam->lensradius;
+
+       /* 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 = 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..e18a67b
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * 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(v = b_mesh.vertices.begin(); v != b_mesh.vertices.end(); ++v)
+               mesh->verts.push_back(get_float3(v->co()));
+
+       /* create faces */
+       BL::Mesh::faces_iterator f;
+       vector<int> nverts;
+
+       for(f = b_mesh.faces.begin(); 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(v = b_mesh.vertices.begin(); 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(l = b_mesh.vertex_colors.begin(); l != b_mesh.vertex_colors.end(); ++l) {
+                       if(!mesh_need_attribute(scene, mesh, ustring(l->name())))
+                               continue;
+
+                       Attribute *attr = mesh->attributes.add(
+                               ustring(l->name()), TypeDesc::TypeColor, Attribute::CORNER);
+
+                       BL::MeshColorLayer::data_iterator c;
+                       float3 *fdata = attr->data_float3();
+                       size_t i = 0;
+
+                       for(c = l->data.begin(); c != l->data.end(); ++c, ++i) {
+                               fdata[0] =  get_float3(c->color1());
+                               fdata[1] =  get_float3(c->color2());
+                               fdata[2] =  get_float3(c->color3());
+                               fdata += 3;
+
+                               if(nverts[i] == 4) {
+                                       fdata[0] =  get_float3(c->color1());
+                                       fdata[1] =  get_float3(c->color3());
+                                       fdata[2] =  get_float3(c->color4());
+                                       fdata += 3;
+                               }
+                       }
+               }
+       }
+
+       /* create uv layer attributes */
+       {
+               BL::Mesh::uv_textures_iterator l;
+
+               for(l = b_mesh.uv_textures.begin(); l != b_mesh.uv_textures.end(); ++l) {
+                       Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
+                       ustring name = ustring(l->name());
+
+                       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(t = l->data.begin(); 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(v = b_mesh.vertices.begin(); v != b_mesh.vertices.end(); ++v)
+               sdmesh.add_vert(get_float3(v->co()));
+
+       /* create faces */
+       BL::Mesh::faces_iterator f;
+
+       for(f = b_mesh.faces.begin(); 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(slot = b_ob.material_slots.begin(); slot != b_ob.material_slots.end(); ++slot)
+               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;
+               }
+       }
+
+       /* create derived mesh */
+       BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
+       /* todo: this will crash on non-mesh types! */
+       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());
+
+       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(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..51fd743
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * 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(slot = b_ob.material_slots.begin(); 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));
+}
+
+/* Light */
+
+void BlenderSync::sync_light(BL::Object b_ob, Transform& tfm)
+{
+       /* test if we need to sync */
+       Light *light;
+
+       /* todo: account for instancing */
+       if(!light_map.sync(&light, b_ob))
+               return;
+
+       /* location */
+       light->co = make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
+
+       /* shader */
+       BL::Lamp b_lamp(b_ob.data());
+       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];
+
+       /* tag */
+       light->tag_update(scene);
+}
+
+/* Object */
+
+void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm)
+{
+       /* light is handled separately */
+       if(object_is_light(b_ob)) {
+               sync_light(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, key)) {
+               object->name = b_ob.name();
+               object->tfm = tfm;
+               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 layer;
+       
+       if(b_v3d)
+               layer = get_layer(b_v3d.layers());
+       else
+               layer = get_layer(b_scene.layers());
+       
+       /* prepare for sync */
+       light_map.pre_sync();
+       mesh_map.pre_sync();
+       object_map.pre_sync();
+
+       /* object loop */
+       BL::Scene::objects_iterator b_ob;
+
+       for(b_ob = b_scene.objects.begin(); b_ob != b_scene.objects.end(); ++b_ob) {
+               bool hide = (b_v3d)? b_ob->hide(): b_ob->hide_render();
+
+               if(!hide && get_layer(b_ob->layers()) & layer) {
+                       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_dup = b_ob->dupli_list.begin(); 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);
+                                       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);
+                       }
+               }
+       }
+
+       /* 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);
+}
+
+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..7c5bdf0
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * 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;
+
+       if(!PyArg_ParseTuple(args, "s", &path))
+               return NULL;
+       
+       path_init(path);
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *create_func(PyObject *self, PyObject *args)
+{
+       Py_ssize_t pyengine, pydata, pyscene, pyregion, pyv3d, pyrv3d;
+
+       if(!PyArg_ParseTuple(args, "nnnnnn", &pyengine, &pydata, &pyscene, &pyregion, &pyv3d, &pyrv3d))
+               return NULL;
+
+       /* RNA */
+       PointerRNA engineptr;
+       RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)pyengine, &engineptr);
+       BL::RenderEngine engine(engineptr);
+
+       PointerRNA dataptr;
+       RNA_id_pointer_create((ID*)pydata, &dataptr);
+       BL::BlendData data(dataptr);
+
+       PointerRNA sceneptr;
+       RNA_id_pointer_create((ID*)pyscene, &sceneptr);
+       BL::Scene scene(sceneptr);
+
+       PointerRNA regionptr;
+       RNA_id_pointer_create((ID*)pyregion, &regionptr);
+       BL::Region region(regionptr);
+
+       PointerRNA v3dptr;
+       RNA_id_pointer_create((ID*)pyv3d, &v3dptr);
+       BL::SpaceView3D v3d(v3dptr);
+
+       PointerRNA rv3dptr;
+       RNA_id_pointer_create((ID*)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)
+{
+       Py_ssize_t pysession;
+
+       if(!PyArg_ParseTuple(args, "n", &pysession))
+               return NULL;
+
+       delete (BlenderSession*)pysession;
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *render_func(PyObject *self, PyObject *args)
+{
+       Py_ssize_t pysession;
+
+       if(!PyArg_ParseTuple(args, "n", &pysession))
+               return NULL;
+       
+       Py_BEGIN_ALLOW_THREADS
+
+       BlenderSession *session = (BlenderSession*)pysession;
+       session->render();
+
+       Py_END_ALLOW_THREADS
+
+       Py_INCREF(Py_None);
+       return Py_None;
+}
+
+static PyObject *draw_func(PyObject *self, PyObject *args)
+{
+       Py_ssize_t pysession, pyv3d, pyrv3d;
+
+       if(!PyArg_ParseTuple(args, "nnn", &pysession, &pyv3d, &pyrv3d))
+               return NULL;
+       
+       BlenderSession *session = (BlenderSession*)pysession;
+
+       bool draw_text = false;
+
+       if(pyrv3d) {
+               /* 3d view drawing */
+               int viewport[4];
+               glGetIntegerv(GL_VIEWPORT, viewport);
+
+               draw_text = session->draw(viewport[2], viewport[3]);
+       }
+       else {
+               /* image editor drawing */
+               draw_text = session->draw();
+       }
+
+       /* draw */
+       PyObject *ret = PyTuple_New(2);
+
+       if(!draw_text) {
+               PyTuple_SetItem(ret, 0, PyUnicode_FromString(""));
+               PyTuple_SetItem(ret, 1, PyUnicode_FromString(""));
+       }
+       else {
+               string status, substatus;
+
+               session->get_status(status, substatus);
+
+               PyTuple_SetItem(ret, 0, PyUnicode_FromString(status.c_str()));
+               PyTuple_SetItem(ret, 1, PyUnicode_FromString(substatus.c_str()));
+       }
+
+       return ret;
+}
+
+static PyObject *sync_func(PyObject *self, PyObject *args)
+{
+       Py_ssize_t pysession;
+
+       if(!PyArg_ParseTuple(args, "n", &pysession))
+               return NULL;
+
+       BlenderSession *session = (BlenderSession*)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},
+};
+
+static struct PyModuleDef module = {
+       PyModuleDef_HEAD_INIT,
+       "libcycles_blender",
+       "Blender RNA to render exporter",
+       -1,
+       methods
+};
+
+CCL_NAMESPACE_END
+
+PyMODINIT_FUNC PyInit_libcycles_blender() 
+{
+       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..8e8bba4
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * 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 "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);
+       SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
+
+       /* 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));
+
+       /* start rendering */
+       session->reset(width, height);
+       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 */
+       DisplayBuffer *display = session->display;
+       Device *device = session->device;
+
+       if(!display->rgba.device_pointer)
+               return;
+
+       /* todo: get float buffer */
+       device->pixels_copy_from(display->rgba, 0, width, height);
+       uchar4 *rgba = (uchar4*)display->rgba.data_pointer;
+
+       vector<float4> buffer(width*height);
+       float fac = 1.0f/255.0f;
+
+       /* normalize */
+       for(int i = width*height - 1; i >= 0; i--) {
+               uchar4 f = rgba[i];
+               float r = color_srgb_to_scene_linear(f.x*fac);
+               float g = color_srgb_to_scene_linear(f.y*fac);
+               float b = color_srgb_to_scene_linear(f.z*fac);
+               buffer[i] = make_float4(r, g, b, 1.0f);
+       }
+
+       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);
+
+       rna_RenderLayer_rect_set(&rr.layers.begin()->ptr, (float*)&buffer[0]);
+
+       RE_engine_end_result((RenderEngine*)b_engine.ptr.data, rrp);
+}
+
+void BlenderSession::synchronize()
+{
+       /* on session/scene parameter changes, we recreate session entirely */
+       SceneParams scene_params = BlenderSync::get_scene_params(b_scene);
+       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;
+       }
+
+       /* 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);
+
+       /* reset if needed */
+       if(scene->need_reset())
+               session->reset(width, height);
+
+       /* unlock */
+       session->scene->mutex.unlock();
+}
+
+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)
+                       session->reset(width, height);
+       }
+
+       /* draw */
+       return !session->draw(width, height);
+}
+
+bool BlenderSession::draw()
+{
+       return !session->draw(width, height);
+}
+
+void BlenderSession::get_status(string& status, string& substatus)
+{
+       session->progress.get_status(status, substatus);
+}
+
+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) {
+               /* offline render, set stats and redraw if timeout passed */
+               string status, substatus;
+               get_status(status, substatus);
+
+               if(substatus.size() > 0)
+                       status += " | " + substatus;
+
+               RE_engine_update_stats((RenderEngine*)b_engine.ptr.data, "", status.c_str());
+
+               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..8bc5d3d
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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();
+       bool draw(int w, int h);
+       void tag_redraw();
+       void tag_update();
+       void get_status(string& status, string& substatus);
+       void test_cancel();
+
+       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;
+
+       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..c6dbfc6
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * 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::Node b_node, const string& name)
+{
+       BL::Node::inputs_iterator b_in;
+
+       for(b_in = b_node.inputs.begin(); b_in != b_node.inputs.end(); ++b_in) {
+               if(b_in->name() == name) {
+                       if(b_group_node) {
+
+                               BL::NodeTree b_ntree = BL::NodeGroup(*b_group_node).node_tree();
+                               BL::NodeTree::links_iterator b_link;
+
+                               for(b_link = b_ntree.links.begin(); 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_gin = b_group_node->inputs.begin(); 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;
+               }
+       }
+
+       assert(0);
+
+       return *b_in;
+}
+
+static BL::NodeSocket get_node_output(BL::Node b_node, const string& name)
+{
+       BL::Node::outputs_iterator b_out;
+
+       for(b_out = b_node.outputs.begin(); 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::RGBANodeSocket 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::ValueNodeSocket sock(get_node_output(b_node, name));
+       return sock.default_value()[0];
+}
+
+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();
+                       mapping->translation = get_float3(b_mapping_node.location());
+                       mapping->rotation = get_float3(b_mapping_node.rotation());
+                       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_ADD_CLOSURE: {
+                       node = new AddClosureNode();
+                       break;
+               }
+               case BL::ShaderNode::type_MIX_CLOSURE: {
+                       node = new MixClosureNode();
+                       break;
+               }
+               case BL::ShaderNode::type_ATTRIBUTE: {
+                       AttributeNode *attr = new AttributeNode();
+                       attr->attribute = "";
+                       node = attr;
+                       break;
+               }
+               case BL::ShaderNode::type_BACKGROUND: {
+                       node = new BackgroundNode();
+                       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_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());
+                       node = image;
+                       break;
+               }
+               case BL::ShaderNode::type_TEX_ENVIRONMENT: {
+                       BL::ShaderNodeTexEnvironment b_environment_node(b_node);
+                       BL::Image b_image(b_environment_node.image());
+                       EnvironmentTextureNode *env = new EnvironmentTextureNode();
+                       if(b_image)
+                               env->filename = blender_absolute_path(b_data, b_image, b_image.filepath());
+                       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 != graph->output())
+               graph->add(node);
+
+       return node;
+}
+
+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_node = b_ntree.nodes.begin(); 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_input = b_node->inputs.begin(); b_input != b_node->inputs.end(); ++b_input) {
+                                       ShaderInput *input = node->input(b_input->name().c_str());
+                                       BL::NodeSocket sock(get_node_input(b_group_node, *b_node, b_input->name()));
+
+                                       assert(input);
+
+                                       /* copy values for non linked inputs */
+                                       switch(input->type) {
+                                               case SHADER_SOCKET_FLOAT: {
+                                                       BL::ValueNodeSocket value_sock(sock);
+                                                       input->set(value_sock.default_value()[0]);
+                                                       break;
+                                               }
+                                               case SHADER_SOCKET_COLOR: {
+                                                       BL::RGBANodeSocket 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::VectorNodeSocket 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_link = b_ntree.links.begin(); 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] =
+                                       SocketPair(node_map[b_to_node.ptr.data], b_to_sock.name());
+
+                               continue;
+                       }
+                       else if(!b_to_node) {
+                               sockets_map[b_to_sock.ptr.data] =
+                                       SocketPair(node_map[b_from_node.ptr.data], b_from_sock.name());
+
+                               continue;
+                       }
+               }
+
+               ShaderNode *from_node, *to_node;
+               string from_name, to_name;
+
+               /* from sock */
+               if(b_from_node.is_a(&RNA_NodeGroup)) {
+                       /* group node */
+                       BL::NodeSocket group_sock = b_from_sock.group_socket();
+                       SocketPair& pair = node_groups[b_from_node.ptr.data][group_sock.ptr.data];
+
+                       from_node = pair.first;
+                       from_name = pair.second;
+               }
+               else {
+                       /* regular node */
+                       from_node = node_map[b_from_node.ptr.data];
+                       from_name = b_from_sock.name();
+               }
+
+               /* to sock */
+               if(b_to_node.is_a(&RNA_NodeGroup)) {
+                       /* group node */
+                       BL::NodeSocket group_sock = b_to_sock.group_socket();
+                       SocketPair& pair = node_groups[b_to_node.ptr.data][group_sock.ptr.data];
+
+                       to_node = pair.first;
+                       to_name = pair.second;
+               }
+               else {
+                       /* regular node */
+                       to_node = node_map[b_to_node.ptr.data];
+                       to_name = b_to_sock.name();
+               }
+
+               graph->connect(from_node->output(from_name.c_str()), to_node->input(to_name.c_str()));
+       }
+}
+
+/* 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_mat = b_data.materials.begin(); 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();
+
+                       /* create nodes */
+                       if(b_mat && b_mat->node_tree()) {
+                               shader->name = b_mat->name();
+
+                               PtrSockMap sock_to_node;
+                               BL::ShaderNodeTree b_ntree(b_mat->node_tree());
+
+                               add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
+                       }
+
+                       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.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);
+               }
+
+               shader->set_graph(graph);
+               shader->tag_update(scene);
+       }
+
+       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_lamp = b_data.lamps.begin(); 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 && b_lamp->node_tree()) {
+                               shader->name = b_lamp->name();
+
+                               PtrSockMap sock_to_node;
+                               BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
+
+                               add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
+                       }
+
+                       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..1bf85f1
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * 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 "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()
+{
+       BL::BlendData::materials_iterator b_mat;
+
+       for(b_mat = b_data.materials.begin(); b_mat != b_data.materials.end(); ++b_mat)
+               if(b_mat->recalc())
+                       shader_map.set_recalc(*b_mat);
+
+       BL::BlendData::lamps_iterator b_lamp;
+
+       for(b_lamp = b_data.lamps.begin(); b_lamp != b_data.lamps.end(); ++b_lamp)
+               if(b_lamp->recalc())
+                       shader_map.set_recalc(*b_lamp);
+
+       BL::BlendData::objects_iterator b_ob;
+
+       for(b_ob = b_data.objects.begin(); b_ob != b_data.objects.end(); ++b_ob) {
+               if(b_ob->recalc()) {
+                       object_map.set_recalc(*b_ob);
+                       light_map.set_recalc(*b_ob);
+               }
+               if(object_is_mesh(*b_ob)) {
+                       if(b_ob->recalc_data() || b_ob->data().recalc()) {
+                               BL::ID key = object_is_modified(*b_ob)? *b_ob: b_ob->data();
+                               mesh_map.set_recalc(key);
+                       }
+               }
+       }
+
+       BL::BlendData::meshes_iterator b_mesh;
+
+       for(b_mesh = b_data.meshes.begin(); b_mesh != b_data.meshes.end(); ++b_mesh)
+               if(b_mesh->recalc())
+                       mesh_map.set_recalc(*b_mesh);
+
+       BL::BlendData::worlds_iterator b_world;
+
+       for(b_world = b_data.worlds.begin(); b_world != b_data.worlds.end(); ++b_world)
+               if(world_map == b_world->ptr.data && b_world->recalc())
+                       world_recalc = true;
+
+       bool recalc =
+               shader_map.has_recalc() ||
+               object_map.has_recalc() ||
+               light_map.has_recalc() ||
+               mesh_map.has_recalc() ||
+               world_recalc;
+
+       return recalc;
+}
+
+void BlenderSync::sync_data(BL::SpaceView3D b_v3d)
+{
+       sync_integrator();
+       sync_film();
+       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->minbounce = get_int(cscene, "min_bounces");
+       integrator->maxbounce = get_int(cscene, "max_bounces");
+       integrator->no_caustics = get_boolean(cscene, "no_caustics");
+       integrator->blur_caustics = get_float(cscene, "blur_caustics");
+
+       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, "exposure");
+       film->response = get_enum_identifier(cscene, "response_curve");
+
+       if(film->modified(prevfilm))
+               film->tag_update(scene);
+}
+
+/* Scene Parameters */
+
+SceneParams BlenderSync::get_scene_params(BL::Scene b_scene)
+{
+       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;
+       
+       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 */
+
+SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
+{
+       SessionParams params;
+       PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
+
+       /* device type */
+       DeviceType dtype = (RNA_enum_get(&cscene, "device") == 1)? DEVICE_CUDA: DEVICE_CPU;
+
+       params.device_type = DEVICE_CPU;
+       vector<DeviceType> types = Device::available_types();
+
+       foreach(DeviceType dt, types)
+               if(dt == dtype)
+                       params.device_type = dtype;
+
+       /* other parameters */
+       params.background = background;
+       params.passes = (background)? get_int(cscene, "passes"): INT_MAX;
+       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..f1fce37
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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);
+       static SessionParams get_session_params(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_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);
+       void sync_light(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<void*, Light> light_map;
+       void *world_map;
+       bool world_recalc;
+
+       Scene *scene;
+       bool preview;
+};
+
+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..9da1c1d
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * 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 engine_tag_redraw(void *engine);
+void engine_tag_update(void *engine);
+int rna_Object_is_modified(void *ob, void *scene, int settings);
+
+}
+
+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);
+       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));
+}
+
+/* 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);
+}
+
+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.ptr.id.data);
+       }
+
+       bool sync(T **r_data, BL::ID id, 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());
+
+               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..c934cde
--- /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(bvh ${sources} ${headers})
+
diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp
new file mode 100644 (file)
index 0000000..ab23079
--- /dev/null
@@ -0,0 +1,661 @@
+/*
+ * 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_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)
+       : node(n), idx(i)
+       {
+       }
+
+       int encodeIdx() const
+       {
+               return (node->is_leaf())? ~idx: idx;
+       }
+};
+
+/* BVH */
+
+BVH::BVH(const BVHParams& params_, const vector<Object*>& objects_)
+: params(params_), objects(objects_)
+{
+}
+
+BVH *BVH::create(const BVHParams& params, const vector<Object*>& objects)
+{
+       if(params.use_qbvh)
+               return new QBVH(params, objects);
+       else
+               return new RegularBVH(params, objects);
+}
+
+/* Cache */
+
+bool BVH::cache_read(CacheData& key)
+{
+       key.add(&params, sizeof(params));
+
+       foreach(Object *ob, objects) {
+               key.add(ob->mesh->verts);
+               key.add(ob->mesh->triangles);
+       }
+
+       CacheData value;
+
+       if(Cache::global.lookup(key, value)) {
+               value.read(pack.root_index);
+
+               value.read(pack.nodes);
+               value.read(pack.object_node);
+               value.read(pack.tri_woop);
+               value.read(pack.prim_index);
+               value.read(pack.prim_object);
+               value.read(pack.is_leaf);
+
+               return true;
+       }
+
+       return false;
+}
+
+void BVH::cache_write(CacheData& key)
+{
+       CacheData value;
+
+       value.add(pack.root_index);
+
+       value.add(pack.nodes);
+       value.add(pack.object_node);
+       value.add(pack.tri_woop);
+       value.add(pack.prim_index);
+       value.add(pack.prim_object);
+       value.add(pack.is_leaf);
+
+       Cache::global.insert(key, value);
+}
+
+/* Building */
+
+void BVH::build(Progress& progress)
+{
+       progress.set_substatus("Building BVH");
+
+       /* cache read */
+       CacheData key("bvh");
+
+       if(params.use_cache) {
+               progress.set_substatus("Looking in BVH cache");
+
+               if(cache_read(key))
+                       return;
+       }
+
+       /* build nodes */
+       vector<int> prim_index;
+       vector<int> prim_object;
+
+       BVHBuild bvh_build(objects, prim_index, prim_object, params, progress);
+       BVHNode *root = bvh_build.run();
+
+       if(progress.get_cancel()) {
+               if(root) root->deleteSubtree();
+               return;
+       }
+
+       /* todo: get rid of this copy */
+       pack.prim_index = prim_index;
+       pack.prim_object = prim_object;
+
+       /* compute SAH */
+       if(!params.top_level)
+               pack.SAH = root->computeSubtreeSAHCost(params);
+
+       if(progress.get_cancel()) {
+               root->deleteSubtree();
+               return;
+       }
+
+       /* pack triangles */
+       progress.set_substatus("Packing BVH triangles");
+       pack_triangles();
+
+       if(progress.get_cancel()) {
+               root->deleteSubtree();
+               return;
+       }
+
+       /* pack nodes */
+       progress.set_substatus("Packing BVH nodes");
+       array<int> tmp_prim_object = pack.prim_object;
+       pack_nodes(tmp_prim_object, root);
+       
+       /* free build nodes */
+       root->deleteSubtree();
+
+       if(progress.get_cancel()) return;
+
+       /* cache write */
+       if(params.use_cache) {
+               progress.set_substatus("Writing BVH cache");
+               cache_write(key);
+       }
+}
+
+/* Refitting */
+
+void BVH::refit(Progress& progress)
+{
+       progress.set_substatus("Packing BVH triangles");
+       pack_triangles();
+
+       if(progress.get_cancel()) return;
+
+       progress.set_substatus("Refitting BVH nodes");
+       refit_nodes();
+}
+
+/* Triangles */
+
+void BVH::pack_triangle(int idx, float4 woop[3])
+{
+       /* create Woop triangle */
+       int tob = pack.prim_object[idx];
+       const Mesh *mesh = objects[tob]->mesh;
+       int tidx = pack.prim_index[idx];
+       const int *vidx = mesh->triangles[tidx].v;
+       const float3* vpos = &mesh->verts[0];
+       float3 v0 = vpos[vidx[0]];
+       float3 v1 = vpos[vidx[1]];
+       float3 v2 = vpos[vidx[2]];
+
+       float3 r0 = v0 - v2;
+       float3 r1 = v1 - v2;
+       float3 r2 = cross(r0, r1);
+
+       if(dot(r0, r0) == 0.0f || dot(r1, r1) == 0.0f || dot(r2, r2) == 0.0f) {
+               /* degenerate */
+               woop[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+               woop[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+               woop[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+       }
+       else {
+               Transform t = make_transform(
+                       r0.x, r1.x, r2.x, v2.x,
+                       r0.y, r1.y, r2.y, v2.y,
+                       r0.z, r1.z, r2.z, v2.z,
+                       0.0f, 0.0f, 0.0f, 1.0f);
+
+               t = transform_inverse(t);
+
+               woop[0] = make_float4(t.z.x, t.z.y, t.z.z, -t.z.w);
+               woop[1] = make_float4(t.x.x, t.x.y, t.x.z, t.x.w);
+               woop[2] = make_float4(t.y.x, t.y.y, t.y.z, t.y.w);
+       }
+}
+
+void BVH::pack_triangles()
+{
+       int nsize = TRI_NODE_SIZE;
+       size_t tidx_size = pack.prim_index.size();
+
+       pack.tri_woop.clear();
+       pack.tri_woop.resize(tidx_size * nsize);
+
+       for(unsigned int i = 0; i < tidx_size; i++) {
+               if(pack.prim_index[i] != -1) {
+                       float4 woop[3];
+
+                       pack_triangle(i, woop);
+                       memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
+               }
+       }
+}
+
+/* Pack Instances */
+
+void BVH::pack_instances(size_t nodes_size)
+{
+       /* The BVH's for instances are built separately, but for traversal all
+          BVH's are stored in global arrays. This function merges them into the
+          top level BVH, adjusting indexes and offsets where appropriate. */
+       bool use_qbvh = params.use_qbvh;
+       size_t nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE;
+
+       /* adjust primitive index to point to the triangle in the global array, for
+          meshes with transform applied and already in the top level BVH */
+       for(size_t i = 0; i < pack.prim_index.size(); i++)
+               if(pack.prim_index[i] != -1)
+                       pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset;
+
+       /* track offsets of instanced BVH data in global array */
+       size_t tri_offset = pack.prim_index.size();
+       size_t nodes_offset = nodes_size;
+
+       /* clear array that gives the node indexes for instanced objects */
+       pack.object_node.clear();
+
+       /* reserve */
+       size_t prim_index_size = pack.prim_index.size();
+       size_t tri_woop_size = pack.tri_woop.size();
+
+       size_t pack_prim_index_offset = prim_index_size;
+       size_t pack_tri_woop_offset = tri_woop_size;
+       size_t pack_nodes_offset = nodes_size;
+       size_t object_offset = 0;
+
+       foreach(Object *ob, objects) {
+               Mesh *mesh = ob->mesh;
+               BVH *bvh = mesh->bvh;
+
+               if(!mesh->transform_applied) {
+                       prim_index_size += bvh->pack.prim_index.size();
+                       tri_woop_size += bvh->pack.tri_woop.size();
+                       nodes_size += bvh->pack.nodes.size()*nsize;
+               }
+       }
+
+       pack.prim_index.resize(prim_index_size);
+       pack.prim_object.resize(prim_index_size);
+       pack.tri_woop.resize(tri_woop_size);
+       pack.nodes.resize(nodes_size);
+       pack.object_node.resize(objects.size());
+
+       int *pack_prim_index = &pack.prim_index[0];
+       int *pack_prim_object = &pack.prim_object[0];
+       float4 *pack_tri_woop = &pack.tri_woop[0];
+       int4 *pack_nodes = &pack.nodes[0];
+
+       /* merge */
+       foreach(Object *ob, objects) {
+               Mesh *mesh = ob->mesh;
+
+               /* if mesh transform is applied, that means it's already in the top
+                  level BVH, and we don't need to merge it in */
+               if(mesh->transform_applied) {
+                       pack.object_node[object_offset++] = 0;
+                       continue;
+               }
+
+               BVH *bvh = mesh->bvh;
+
+               int noffset = nodes_offset/nsize;
+               int mesh_tri_offset = mesh->tri_offset;
+
+               /* fill in node indexes for instances */
+               if(bvh->pack.is_leaf[0])
+                       pack.object_node[object_offset++] = -noffset-1;
+               else
+                       pack.object_node[object_offset++] = noffset;
+
+               /* merge primitive and object indexes */
+               {
+                       size_t bvh_prim_index_size = bvh->pack.prim_index.size();
+                       int *bvh_prim_index = &bvh->pack.prim_index[0];
+
+                       for(size_t i = 0; i < bvh_prim_index_size; i++) {
+                               pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset;
+                               pack_prim_object[pack_prim_index_offset] = 0;  // unused for instances
+                               pack_prim_index_offset++;
+                       }
+               }
+
+               /* merge triangle intersection data */
+               {
+                       memcpy(pack_tri_woop+pack_tri_woop_offset, &bvh->pack.tri_woop[0],
+                               bvh->pack.tri_woop.size()*sizeof(float4));
+                       pack_tri_woop_offset += bvh->pack.tri_woop.size();
+               }
+
+               /* merge nodes */
+               {
+                       size_t nsize_bbox = (use_qbvh)? nsize-2: nsize-1;
+                       int4 *bvh_nodes = &bvh->pack.nodes[0];
+                       size_t bvh_nodes_size = bvh->pack.nodes.size(); 
+                       int *bvh_is_leaf = &bvh->pack.is_leaf[0];
+
+                       for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) {
+                               memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4));
+
+                               /* modify offsets into arrays */
+                               int4 data = bvh_nodes[i + nsize_bbox];
+
+                               if(bvh_is_leaf[j]) {
+                                       data.x += tri_offset;
+                                       data.y += tri_offset;
+                               }
+                               else {
+                                       data.x += (data.x < 0)? -noffset: noffset;
+                                       data.y += (data.y < 0)? -noffset: noffset;
+
+                                       if(use_qbvh) {
+                                               data.z += (data.z < 0)? -noffset: noffset;
+                                               data.w += (data.w < 0)? -noffset: noffset;
+                                       }
+                               }
+
+                               pack_nodes[pack_nodes_offset + nsize_bbox] = data;
+
+                               if(use_qbvh)
+                                       pack_nodes[pack_nodes_offset + nsize_bbox+1] = bvh_nodes[i + nsize_bbox+1];
+
+                               pack_nodes_offset += nsize;
+                       }
+               }
+
+               nodes_offset += bvh->pack.nodes.size();
+               tri_offset += bvh->pack.prim_index.size();
+       }
+}
+
+/* Regular BVH */
+
+RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_)
+: BVH(params_, objects_)
+{
+}
+
+void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
+{
+       if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1)
+               /* object */
+               pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, ~(leaf->m_lo), 0);
+       else
+               /* triangle */
+               pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, leaf->m_lo, leaf->m_hi);
+}
+
+void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1)
+{
+       pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx());
+}
+
+void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1)
+{
+       int4 data[BVH_NODE_SIZE] =
+       {
+               make_int4(__float_as_int(b0.min.x), __float_as_int(b0.max.x), __float_as_int(b0.min.y), __float_as_int(b0.max.y)),
+               make_int4(__float_as_int(b1.min.x), __float_as_int(b1.max.x), __float_as_int(b1.min.y), __float_as_int(b1.max.y)),
+               make_int4(__float_as_int(b0.min.z), __float_as_int(b0.max.z), __float_as_int(b1.min.z), __float_as_int(b1.max.z)),
+               make_int4(c0, c1, 0, 0)
+       };
+
+       memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE);
+}
+
+void RegularBVH::pack_nodes(const array<int>& prims, const BVHNode *root)
+{
+       size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
+
+       /* resize arrays */
+       pack.nodes.clear();
+       pack.is_leaf.clear();
+       pack.is_leaf.resize(node_size);
+
+       /* for top level BVH, first merge existing BVH's so we know the offsets */
+       if(params.top_level)
+               pack_instances(node_size*BVH_NODE_SIZE);
+       else
+               pack.nodes.resize(node_size*BVH_NODE_SIZE);
+
+       int nextNodeIdx = 0;
+
+       vector<BVHStackEntry> stack;
+       stack.push_back(BVHStackEntry(root, nextNodeIdx++));
+
+       while(stack.size()) {
+               BVHStackEntry e = stack.back();
+               stack.pop_back();
+
+               pack.is_leaf[e.idx] = e.node->is_leaf();
+
+               if(e.node->is_leaf()) {
+                       /* leaf node */
+                       const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
+                       pack_leaf(e, leaf);
+               }
+               else {
+                       /* innner node */
+                       stack.push_back(BVHStackEntry(e.node->get_child(0), nextNodeIdx++));
+                       stack.push_back(BVHStackEntry(e.node->get_child(1), nextNodeIdx++));
+
+                       pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]);
+               }
+       }
+
+       /* root index to start traversal at, to handle case of single leaf node */
+       pack.root_index = (pack.is_leaf[0])? -1: 0;
+}
+
+void RegularBVH::refit_nodes()
+{
+       assert(!params.top_level);
+
+       BoundBox bbox;
+       refit_node(0, pack.is_leaf[0], bbox);
+}
+
+void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox)
+{
+       int4 *data = &pack.nodes[idx*4];
+
+       int c0 = data[3].x;
+       int c1 = data[3].y;
+
+       if(leaf) {
+               /* refit leaf node */
+               for(int tri = c0; tri < c1; tri++) {
+                       int tidx = pack.prim_index[tri];
+                       int tob = pack.prim_object[tri];
+                       Object *ob = objects[tob];
+
+                       if(tidx == -1) {
+                               /* object instance */
+                               bbox.grow(ob->bounds);
+                       }
+                       else {
+                               /* triangles */
+                               const Mesh *mesh = ob->mesh;
+                               int tri_offset = (params.top_level)? mesh->tri_offset: 0;
+                               const int *vidx = mesh->triangles[tidx - tri_offset].v;
+                               const float3 *vpos = &mesh->verts[0];
+
+                               bbox.grow(vpos[vidx[0]]);
+                               bbox.grow(vpos[vidx[1]]);
+                               bbox.grow(vpos[vidx[2]]);
+                       }
+               }
+
+               pack_node(idx, bbox, bbox, c0, c1);
+       }
+       else {
+               /* refit inner node, set bbox from children */
+               BoundBox bbox0, bbox1;
+
+               refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0);
+               refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1);
+
+               bbox.grow(bbox0);
+               bbox.grow(bbox1);
+
+               pack_node(idx, bbox0, bbox1, c0, c1);
+       }
+}
+
+/* QBVH */
+
+QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_)
+: BVH(params_, objects_)
+{
+       params.use_qbvh = true;
+}
+
+void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf)
+{
+       float4 data[BVH_QNODE_SIZE];
+
+       memset(data, 0, sizeof(data));
+
+       if(leaf->num_triangles() == 1 && pack.prim_index[leaf->m_lo] == -1) {
+               /* object */
+               data[6].x = __int_as_float(~(leaf->m_lo));
+               data[6].y = __int_as_float(0);
+       }
+       else {
+               /* triangle */
+               data[6].x = __int_as_float(leaf->m_lo);
+               data[6].y = __int_as_float(leaf->m_hi);
+       }
+
+       memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
+}
+
+void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num)
+{
+       float4 data[BVH_QNODE_SIZE];
+
+       for(int i = 0; i < num; i++) {
+               float3 bb_min = en[i].node->m_bounds.min;
+               float3 bb_max = en[i].node->m_bounds.max;
+
+               data[0][i] = bb_min.x;
+               data[1][i] = bb_max.x;
+               data[2][i] = bb_min.y;
+               data[3][i] = bb_max.y;
+               data[4][i] = bb_min.z;
+               data[5][i] = bb_max.z;
+
+               data[6][i] = __int_as_float(en[i].encodeIdx());
+               data[7][i] = 0.0f;
+       }
+
+       for(int i = num; i < 4; i++) {
+               data[0][i] = 0.0f;
+               data[1][i] = 0.0f;
+               data[2][i] = 0.0f;
+
+               data[3][i] = 0.0f;
+               data[4][i] = 0.0f;
+               data[5][i] = 0.0f;
+
+               data[6][i] = __int_as_float(0);
+               data[7][i] = 0.0f;
+       }
+
+       memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE);
+}
+
+/* Quad SIMD Nodes */
+
+void QBVH::pack_nodes(const array<int>& prims, const BVHNode *root)
+{
+       size_t node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT);
+
+       /* resize arrays */
+       pack.nodes.clear();
+       pack.is_leaf.clear();
+       pack.is_leaf.resize(node_size);
+
+       /* for top level BVH, first merge existing BVH's so we know the offsets */
+       if(params.top_level)
+               pack_instances(node_size*BVH_QNODE_SIZE);
+       else
+               pack.nodes.resize(node_size*BVH_QNODE_SIZE);
+
+       int nextNodeIdx = 0;
+
+       vector<BVHStackEntry> stack;
+       stack.push_back(BVHStackEntry(root, nextNodeIdx++));
+
+       while(stack.size()) {
+               BVHStackEntry e = stack.back();
+               stack.pop_back();
+
+               pack.is_leaf[e.idx] = e.node->is_leaf();
+
+               if(e.node->is_leaf()) {
+                       /* leaf node */
+                       const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node);
+                       pack_leaf(e, leaf);
+               }
+               else {
+                       /* inner node */
+                       const BVHNode *node = e.node;
+                       const BVHNode *node0 = node->get_child(0);
+                       const BVHNode *node1 = node->get_child(1);
+
+                       /* collect nodes */
+                       const BVHNode *nodes[4];
+                       int numnodes = 0;
+
+                       if(node0->is_leaf()) {
+                               nodes[numnodes++] = node0;
+                       }
+                       else {
+                               nodes[numnodes++] = node0->get_child(0);
+                               nodes[numnodes++] = node0->get_child(1);
+                       }
+
+                       if(node1->is_leaf()) {
+                               nodes[numnodes++] = node1;
+                       }
+                       else {
+                               nodes[numnodes++] = node1->get_child(0);
+                               nodes[numnodes++] = node1->get_child(1);
+                       }
+
+                       /* push entries on the stack */
+                       for(int i = 0; i < numnodes; i++)
+                               stack.push_back(BVHStackEntry(nodes[i], nextNodeIdx++));
+
+                       /* set node */
+                       pack_inner(e, &stack[stack.size()-numnodes], numnodes);
+               }
+       }
+
+       /* root index to start traversal at, to handle case of single leaf node */
+       pack.root_index = (pack.is_leaf[0])? -1: 0;
+}
+
+void QBVH::refit_nodes()
+{
+       assert(0); /* todo */
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h
new file mode 100644 (file)
index 0000000..acc2529
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#ifndef __BVH_H__
+#define __BVH_H__
+
+#include "bvh_params.h"
+
+#include "util_types.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BVHNode;
+class BVHStackEntry;
+class BVHParams;
+class BoundBox;
+class CacheData;
+class LeafNode;
+class Object;
+class Progress;
+
+#define BVH_NODE_SIZE  4
+#define BVH_QNODE_SIZE 8
+#define BVH_ALIGN              4096
+#define TRI_NODE_SIZE  3
+
+/* Packed BVH
+ *
+ * BVH stored as it will be used for traversal on the rendering device. */
+
+struct PackedBVH {
+       /* BVH nodes storage, one node is 4x int4, and contains two bounding boxes,
+          and child, triangle or object indexes dependening on the node type */
+       array<int4> nodes; 
+       /* object index to BVH node index mapping for instances */
+       array<int> object_node; 
+       /* precomputed triangle intersection data, one triangle is 4x float4 */
+       array<float4> tri_woop; 
+       /* mapping from BVH primitive index to true primitive index, as primitives
+          may be duplicated due to spatial splits. -1 for instances. */
+       array<int> prim_index;
+       /* mapping from BVH primitive index, to the object id of that primitive. */
+       array<int> prim_object;
+       /* quick array to lookup if a node is a leaf, not used for traversal, only
+          for instance BVH merging  */
+       array<int> is_leaf;
+
+       /* index of the root node. */
+       int root_index;
+
+       /* surface area heuristic, for building top level BVH */
+       float SAH;
+
+       PackedBVH()
+       {
+               root_index = 0;
+               SAH = 0.0f;
+       }
+};
+
+/* BVH */
+
+class BVH
+{
+public:
+       PackedBVH pack;
+       BVHParams params;
+       vector<Object*> objects;
+
+       static BVH *create(const BVHParams& params, const vector<Object*>& objects);
+
+       void build(Progress& progress);
+       void refit(Progress& progress);
+
+protected:
+       BVH(const BVHParams& params, const vector<Object*>& objects);
+
+       /* cache */
+       bool cache_read(CacheData& key);
+       void cache_write(CacheData& key);
+
+       /* triangles */
+       void pack_triangles();
+       void pack_triangle(int idx, float4 woop[3]);
+
+       /* merge instance BVH's */
+       void pack_instances(size_t nodes_size);
+
+       /* for subclasses to implement */
+       virtual void pack_nodes(const array<int>& prims, const BVHNode *root) = 0;
+       virtual void refit_nodes() = 0;
+};
+
+/* Regular BVH
+ *
+ * Typical BVH with each node having two children. */
+
+class RegularBVH : public BVH {
+protected:
+       /* constructor */
+       friend class BVH;
+       RegularBVH(const BVHParams& params, const vector<Object*>& objects);
+
+       /* pack */
+       void pack_nodes(const array<int>& prims, const BVHNode *root);
+       void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
+       void pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1);
+       void pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1);
+
+       /* refit */
+       void refit_nodes();
+       void refit_node(int idx, bool leaf, BoundBox& bbox);
+};
+
+/* QBVH
+ *
+ * Quad BVH, with each node having four children, to use with SIMD instructions. */
+
+class QBVH : public BVH {
+protected:
+       /* constructor */
+       friend class BVH;
+       QBVH(const BVHParams& params, const vector<Object*>& objects);
+
+       /* pack */
+       void pack_nodes(const array<int>& prims, const BVHNode *root);
+       void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf);
+       void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num);
+
+       /* refit */
+       void refit_nodes();
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_H__ */
+
diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp
new file mode 100644 (file)
index 0000000..6a9cc91
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * 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 "bvh_build.h"
+#include "bvh_node.h"
+#include "bvh_params.h"
+#include "bvh_sort.h"
+
+#include "mesh.h"
+#include "object.h"
+#include "scene.h"
+
+#include "util_algorithm.h"
+#include "util_foreach.h"
+#include "util_progress.h"
+#include "util_time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Constructor / Destructor */
+
+BVHBuild::BVHBuild(const vector<Object*>& objects_,
+       vector<int>& prim_index_, vector<int>& prim_object_,
+       const BVHParams& params_, Progress& progress_)
+: objects(objects_),
+  prim_index(prim_index_),
+  prim_object(prim_object_),
+  params(params_),
+  progress(progress_),
+  progress_start_time(0.0)
+{
+       spatial_min_overlap = 0.0f;
+       progress_num_duplicates = 0;
+}
+
+BVHBuild::~BVHBuild()
+{
+}
+
+/* Adding References */
+
+void BVHBuild::add_reference_mesh(NodeSpec& root, Mesh *mesh, int i)
+{
+       for(uint j = 0; j < mesh->triangles.size(); j++) {
+               Mesh::Triangle t = mesh->triangles[j];
+               Reference ref;
+
+               ref.prim_index = j;
+               ref.prim_object = i;
+
+               for(int k = 0; k < 3; k++) {
+                       float3 pt = mesh->verts[t.v[k]];
+                       ref.bounds.grow(pt);
+               }
+
+               references.push_back(ref);
+               root.bounds.grow(ref.bounds);
+       }
+}
+
+void BVHBuild::add_reference_object(NodeSpec& root, Object *ob, int i)
+{
+       Reference ref;
+
+       ref.prim_index = -1;
+       ref.prim_object = i;
+       ref.bounds = ob->bounds;
+
+       references.push_back(ref);
+       root.bounds.grow(ref.bounds);
+}
+
+void BVHBuild::add_references(NodeSpec& root)
+{
+       /* init root spec */
+       root.num = 0;
+       root.bounds = BoundBox();
+
+       /* add objects */
+       int i = 0;
+
+       foreach(Object *ob, objects) {
+               if(params.top_level) {
+                       if(ob->mesh->transform_applied)
+                               add_reference_mesh(root, ob->mesh, i);
+                       else
+                               add_reference_object(root, ob, i);
+               }
+               else
+                       add_reference_mesh(root, ob->mesh, i);
+
+               i++;
+
+               if(progress.get_cancel()) return;
+       }
+
+       /* happens mostly on empty meshes */
+       if(!root.bounds.valid())
+               root.bounds.grow(make_float3(0.0f, 0.0f, 0.0f));
+
+       root.num = references.size();
+}
+
+/* Build */
+
+BVHNode* BVHBuild::run()
+{
+       NodeSpec root;
+
+       /* add references */
+       add_references(root);
+
+       if(progress.get_cancel()) return NULL;
+
+       /* init spatial splits */
+       if(params.top_level) /* todo: get rid of this */
+               params.use_spatial_split = false;
+
+       spatial_min_overlap = root.bounds.area() * params.spatial_split_alpha;
+       spatial_right_bounds.clear();
+       spatial_right_bounds.resize(max(root.num, (int)BVHParams::NUM_SPATIAL_BINS) - 1);
+
+       /* init progress updates */
+       progress_num_duplicates = 0;
+       progress_start_time = time_dt();
+
+       /* build recursively */
+       return build_node(root, 0, 0.0f, 1.0f);
+}
+
+void BVHBuild::progress_update(float progress_start, float progress_end)
+{
+       if(time_dt() - progress_start_time < 0.25f)
+               return;
+
+       float duplicates = (float)progress_num_duplicates/(float)references.size();
+       string msg = string_printf("Building BVH %.0f%%, duplicates %.0f%%",
+               progress_start*100.0f, duplicates*100.0f);
+
+       progress.set_substatus(msg);
+       progress_start_time = time_dt();
+}
+
+BVHNode* BVHBuild::build_node(const NodeSpec& spec, int level, float progress_start, float progress_end)
+{
+       /* progress update */
+       progress_update(progress_start, progress_end);
+       if(progress.get_cancel()) return NULL;
+
+       /* small enough or too deep => create leaf. */
+       if(spec.num <= params.min_leaf_size || level >= BVHParams::MAX_DEPTH)
+               return create_leaf_node(spec);
+
+       /* find split candidates. */
+       float area = spec.bounds.area();
+       float leafSAH = area * params.triangle_cost(spec.num);
+       float nodeSAH = area * params.node_cost(2);
+       ObjectSplit object = find_object_split(spec, nodeSAH);
+       SpatialSplit spatial;
+
+       if(params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) {
+               BoundBox overlap = object.left_bounds;
+               overlap.intersect(object.right_bounds);
+
+               if(overlap.area() >= spatial_min_overlap)
+                       spatial = find_spatial_split(spec, nodeSAH);
+       }
+
+       /* leaf SAH is the lowest => create leaf. */
+       float minSAH = min(min(leafSAH, object.sah), spatial.sah);
+
+       if(minSAH == leafSAH && spec.num <= params.max_leaf_size)
+               return create_leaf_node(spec);
+
+       /* perform split. */
+       NodeSpec left, right;
+
+       if(params.use_spatial_split && minSAH == spatial.sah)
+               do_spatial_split(left, right, spec, spatial);
+       if(!left.num || !right.num)
+               do_object_split(left, right, spec, object);
+
+       /* create inner node. */
+       progress_num_duplicates += left.num + right.num - spec.num;
+
+       float progress_mid = lerp(progress_start, progress_end, (float)right.num / (float)(left.num + right.num));
+
+       BVHNode* rightNode = build_node(right, level + 1, progress_start, progress_mid);
+       if(progress.get_cancel()) {
+               if(rightNode) rightNode->deleteSubtree();
+               return NULL;
+       }
+
+       BVHNode* leftNode = build_node(left, level + 1, progress_mid, progress_end);
+       if(progress.get_cancel()) {
+               if(leftNode) leftNode->deleteSubtree();
+               return NULL;
+       }
+
+       return new InnerNode(spec.bounds, leftNode, rightNode);
+}
+
+BVHNode *BVHBuild::create_object_leaf_nodes(const Reference *ref, int num)
+{
+       if(num == 0) {
+               BoundBox bounds;
+               return new LeafNode(bounds, 0, 0);
+       }
+       else if(num == 1) {
+               prim_index.push_back(ref[0].prim_index);
+               prim_object.push_back(ref[0].prim_object);
+               return new LeafNode(ref[0].bounds, prim_index.size()-1, prim_index.size());
+       }
+       else {
+               int mid = num/2;
+               BVHNode *leaf0 = create_object_leaf_nodes(ref, mid); 
+               BVHNode *leaf1 = create_object_leaf_nodes(ref+mid, num-mid); 
+
+               BoundBox bounds;
+               bounds.grow(leaf0->m_bounds);
+               bounds.grow(leaf1->m_bounds);
+
+               return new InnerNode(bounds, leaf0, leaf1);
+       }
+}
+
+BVHNode* BVHBuild::create_leaf_node(const NodeSpec& spec)
+{
+       vector<int>& p_index = prim_index;
+       vector<int>& p_object = prim_object;
+       BoundBox bounds;
+       int num = 0;
+
+       for(int i = 0; i < spec.num; i++) {
+               if(references.back().prim_index != -1) {
+                       p_index.push_back(references.back().prim_index);
+                       p_object.push_back(references.back().prim_object);
+                       bounds.grow(references.back().bounds);
+                       references.pop_back();
+                       num++;
+               }
+       }
+
+       BVHNode *leaf = NULL;
+       
+       if(num > 0) {
+               leaf = new LeafNode(bounds, p_index.size() - num, p_index.size());
+
+               if(num == spec.num)
+                       return leaf;
+       }
+
+       /* while there may be multiple triangles in a leaf, for object primitives
+        * we want them to be the only one, so we  */
+       int ob_num = spec.num - num;
+       BVHNode *oleaf = create_object_leaf_nodes(&references.back() - (ob_num - 1), ob_num);
+       for(int i = 0; i < ob_num; i++)
+               references.pop_back();
+       
+       if(leaf)
+               return new InnerNode(spec.bounds, leaf, oleaf);
+       else
+               return oleaf;
+}
+
+/* Object Split */
+
+BVHBuild::ObjectSplit BVHBuild::find_object_split(const NodeSpec& spec, float nodeSAH)
+{
+       ObjectSplit split;
+       const Reference *ref_ptr = &references[references.size() - spec.num];
+
+       for(int dim = 0; dim < 3; dim++) {
+               /* sort references */
+               bvh_reference_sort(references.size() - spec.num, references.size(), &references[0], dim);
+
+               /* sweep right to left and determine bounds. */
+               BoundBox right_bounds;
+
+               for(int i = spec.num - 1; i > 0; i--) {
+                       right_bounds.grow(ref_ptr[i].bounds);
+                       spatial_right_bounds[i - 1] = right_bounds;
+               }
+
+               /* sweep left to right and select lowest SAH. */
+               BoundBox left_bounds;
+
+               for(int i = 1; i < spec.num; i++) {
+                       left_bounds.grow(ref_ptr[i - 1].bounds);
+                       right_bounds = spatial_right_bounds[i - 1];
+
+                       float sah = nodeSAH +
+                               left_bounds.area() * params.triangle_cost(i) +
+                               right_bounds.area() * params.triangle_cost(spec.num - i);
+
+                       if(sah < split.sah) {
+                               split.sah = sah;
+                               split.dim = dim;
+                               split.num_left = i;
+                               split.left_bounds = left_bounds;
+                               split.right_bounds = right_bounds;
+                       }
+               }
+       }
+
+       return split;
+}
+
+void BVHBuild::do_object_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const ObjectSplit& split)
+{
+       /* sort references according to split */
+       int start = references.size() - spec.num;
+       int end = references.size(); /* todo: is this right? */
+
+       bvh_reference_sort(start, end, &references[0], split.dim);
+
+       /* split node specs */
+       left.num = split.num_left;
+       left.bounds = split.left_bounds;
+       right.num = spec.num - split.num_left;
+       right.bounds = split.right_bounds;
+}
+
+/* Spatial Split */
+
+BVHBuild::SpatialSplit BVHBuild::find_spatial_split(const NodeSpec& spec, float nodeSAH)
+{
+       /* initialize bins. */
+       float3 origin = spec.bounds.min;
+       float3 binSize = (spec.bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS);
+       float3 invBinSize = 1.0f / binSize;
+
+       for(int dim = 0; dim < 3; dim++) {
+               for(int i = 0; i < BVHParams::NUM_SPATIAL_BINS; i++) {
+                       SpatialBin& bin = spatial_bins[dim][i];
+
+                       bin.bounds = BoundBox();
+                       bin.enter = 0;
+                       bin.exit = 0;
+               }
+       }
+
+       /* chop references into bins. */
+       for(unsigned int refIdx = references.size() - spec.num; refIdx < references.size(); refIdx++) {
+               const Reference& ref = references[refIdx];
+               float3 firstBinf = (ref.bounds.min - origin) * invBinSize;
+               float3 lastBinf = (ref.bounds.max - origin) * invBinSize;
+               int3 firstBin = make_int3(firstBinf.x, firstBinf.y, firstBinf.z);
+               int3 lastBin = make_int3(lastBinf.x, lastBinf.y, lastBinf.z);
+
+               firstBin = clamp(firstBin, 0, BVHParams::NUM_SPATIAL_BINS - 1);
+               lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1);
+
+               for(int dim = 0; dim < 3; dim++) {
+                       Reference currRef = ref;
+
+                       for(int i = firstBin[dim]; i < lastBin[dim]; i++) {
+                               Reference leftRef, rightRef;
+
+                               split_reference(leftRef, rightRef, currRef, dim, origin[dim] + binSize[dim] * (float)(i + 1));
+                               spatial_bins[dim][i].bounds.grow(leftRef.bounds);
+                               currRef = rightRef;
+                       }
+
+                       spatial_bins[dim][lastBin[dim]].bounds.grow(currRef.bounds);
+                       spatial_bins[dim][firstBin[dim]].enter++;
+                       spatial_bins[dim][lastBin[dim]].exit++;
+               }
+       }
+
+       /* select best split plane. */
+       SpatialSplit split;
+
+       for(int dim = 0; dim < 3; dim++) {
+               /* sweep right to left and determine bounds. */
+               BoundBox right_bounds;
+
+               for(int i = BVHParams::NUM_SPATIAL_BINS - 1; i > 0; i--) {
+                       right_bounds.grow(spatial_bins[dim][i].bounds);
+                       spatial_right_bounds[i - 1] = right_bounds;
+               }
+
+               /* sweep left to right and select lowest SAH. */
+               BoundBox left_bounds;
+               int leftNum = 0;
+               int rightNum = spec.num;
+
+               for(int i = 1; i < BVHParams::NUM_SPATIAL_BINS; i++) {
+                       left_bounds.grow(spatial_bins[dim][i - 1].bounds);
+                       leftNum += spatial_bins[dim][i - 1].enter;
+                       rightNum -= spatial_bins[dim][i - 1].exit;
+
+                       float sah = nodeSAH +
+                               left_bounds.area() * params.triangle_cost(leftNum) +
+                               spatial_right_bounds[i - 1].area() * params.triangle_cost(rightNum);
+
+                       if(sah < split.sah) {
+                               split.sah = sah;
+                               split.dim = dim;
+                               split.pos = origin[dim] + binSize[dim] * (float)i;
+                       }
+               }
+       }
+
+       return split;
+}
+
+void BVHBuild::do_spatial_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const SpatialSplit& split)
+{
+       /* Categorize references and compute bounds.
+        *
+        * Left-hand side:                      [left_start, left_end[
+        * Uncategorized/split:         [left_end, right_start[
+        * Right-hand side:                     [right_start, refs.size()[ */
+
+       vector<Reference>& refs = references;
+       int left_start = refs.size() - spec.num;
+       int left_end = left_start;
+       int right_start = refs.size();
+
+       left.bounds = right.bounds = BoundBox();
+
+       for(int i = left_end; i < right_start; i++) {
+               if(refs[i].bounds.max[split.dim] <= split.pos) {
+                       /* entirely on the left-hand side */
+                       left.bounds.grow(refs[i].bounds);
+                       swap(refs[i], refs[left_end++]);
+               }
+               else if(refs[i].bounds.min[split.dim] >= split.pos) {
+                       /* entirely on the right-hand side */
+                       right.bounds.grow(refs[i].bounds);
+                       swap(refs[i--], refs[--right_start]);
+               }
+       }
+
+       /* duplicate or unsplit references intersecting both sides. */
+       while(left_end < right_start) {
+               /* split reference. */
+               Reference lref, rref;
+
+               split_reference(lref, rref, refs[left_end], split.dim, split.pos);
+
+               /* compute SAH for duplicate/unsplit candidates. */
+               BoundBox lub = left.bounds;             // Unsplit to left:             new left-hand bounds.
+               BoundBox rub = right.bounds;    // Unsplit to right:    new right-hand bounds.
+               BoundBox ldb = left.bounds;             // Duplicate:                   new left-hand bounds.
+               BoundBox rdb = right.bounds;    // Duplicate:                   new right-hand bounds.
+
+               lub.grow(refs[left_end].bounds);
+               rub.grow(refs[left_end].bounds);
+               ldb.grow(lref.bounds);
+               rdb.grow(rref.bounds);
+
+               float lac = params.triangle_cost(left_end - left_start);
+               float rac = params.triangle_cost(refs.size() - right_start);
+               float lbc = params.triangle_cost(left_end - left_start + 1);
+               float rbc = params.triangle_cost(refs.size() - right_start + 1);
+
+               float unsplitLeftSAH = lub.area() * lbc + right.bounds.area() * rac;
+               float unsplitRightSAH = left.bounds.area() * lac + rub.area() * rbc;
+               float duplicateSAH = ldb.area() * lbc + rdb.area() * rbc;
+               float minSAH = min(min(unsplitLeftSAH, unsplitRightSAH), duplicateSAH);
+
+               if(minSAH == unsplitLeftSAH) {
+                       /* unsplit to left */
+                       left.bounds = lub;
+                       left_end++;
+               }
+               else if(minSAH == unsplitRightSAH) {
+                       /* unsplit to right */
+                       right.bounds = rub;
+                       swap(refs[left_end], refs[--right_start]);
+               }
+               else {
+                       /* duplicate */
+                       left.bounds = ldb;
+                       right.bounds = rdb;
+                       refs[left_end++] = lref;
+                       refs.push_back(rref);
+               }
+       }
+
+       left.num = left_end - left_start;
+       right.num = refs.size() - right_start;
+}
+
+void BVHBuild::split_reference(Reference& left, Reference& right, const Reference& ref, int dim, float pos)
+{
+       /* initialize references. */
+       left.prim_index = right.prim_index = ref.prim_index;
+       left.prim_object = right.prim_object = ref.prim_object;
+       left.bounds = right.bounds = BoundBox();
+
+       /* loop over vertices/edges. */
+       Object *ob = objects[ref.prim_object];
+       const Mesh *mesh = ob->mesh;
+       const int *inds = mesh->triangles[ref.prim_index].v;
+       const float3 *verts = &mesh->verts[0];
+       const float3* v1 = &verts[inds[2]];
+
+       for(int i = 0; i < 3; i++) {
+               const float3* v0 = v1;
+               int vindex = inds[i];
+               v1 = &verts[vindex];
+               float v0p = (*v0)[dim];
+               float v1p = (*v1)[dim];
+
+               /* insert vertex to the boxes it belongs to. */
+               if(v0p <= pos)
+                       left.bounds.grow(*v0);
+
+               if(v0p >= pos)
+                       right.bounds.grow(*v0);
+
+               /* edge intersects the plane => insert intersection to both boxes. */
+               if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) {
+                       float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f));
+                       left.bounds.grow(t);
+                       right.bounds.grow(t);
+               }
+       }
+
+       /* intersect with original bounds. */
+       left.bounds.max[dim] = pos;
+       right.bounds.min[dim] = pos;
+       left.bounds.intersect(ref.bounds);
+       right.bounds.intersect(ref.bounds);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h
new file mode 100644 (file)
index 0000000..1fa1951
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+#ifndef __BVH_BUILD_H__
+#define __BVH_BUILD_H__
+
+#include <float.h>
+
+#include "bvh.h"
+
+#include "util_boundbox.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class BVHParams;
+class Mesh;
+class Object;
+class Progress;
+
+/* BVH Builder */
+
+class BVHBuild
+{
+public:
+       struct Reference
+       {
+               int prim_index;
+               int prim_object;
+               BoundBox bounds;
+
+               Reference()
+               {
+               }
+       };
+
+       struct NodeSpec
+       {
+               int num;
+               BoundBox bounds;
+
+               NodeSpec()
+               {
+                       num = 0;
+               }
+       };
+
+       BVHBuild(
+               const vector<Object*>& objects,
+               vector<int>& prim_index,
+               vector<int>& prim_object,
+               const BVHParams& params,
+               Progress& progress);
+       ~BVHBuild();
+
+       BVHNode *run();
+
+protected:
+       /* adding references */
+       void add_reference_mesh(NodeSpec& root, Mesh *mesh, int i);
+       void add_reference_object(NodeSpec& root, Object *ob, int i);
+       void add_references(NodeSpec& root);
+
+       /* building */
+       BVHNode *build_node(const NodeSpec& spec, int level, float progress_start, float progress_end);
+       BVHNode *create_leaf_node(const NodeSpec& spec);
+       BVHNode *create_object_leaf_nodes(const Reference *ref, int num);
+
+       void progress_update(float progress_start, float progress_end);
+
+       /* object splits */
+       struct ObjectSplit
+       {
+               float sah;
+               int dim;
+               int num_left;
+               BoundBox left_bounds;
+               BoundBox right_bounds;
+
+               ObjectSplit()
+               : sah(FLT_MAX), dim(0), num_left(0)
+               {
+               }
+       };
+
+       ObjectSplit find_object_split(const NodeSpec& spec, float nodeSAH);
+       void do_object_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const ObjectSplit& split);
+
+       /* spatial splits */
+       struct SpatialSplit
+       {
+               float sah;
+               int dim;
+               float pos;
+
+               SpatialSplit()
+               : sah(FLT_MAX), dim(0), pos(0.0f)
+               {
+               }
+       };
+
+       struct SpatialBin
+       {
+               BoundBox bounds;
+               int enter;
+               int exit;
+       };
+
+       SpatialSplit find_spatial_split(const NodeSpec& spec, float nodeSAH);
+       void do_spatial_split(NodeSpec& left, NodeSpec& right, const NodeSpec& spec, const SpatialSplit& split);
+       void split_reference(Reference& left, Reference& right, const Reference& ref, int dim, float pos);
+
+       /* objects and primitive references */
+       vector<Object*> objects;
+       vector<Reference> references;
+
+       /* output primitive indexes and objects */
+       vector<int>& prim_index;
+       vector<int>& prim_object;
+
+       /* build parameters */
+       BVHParams params;
+
+       /* progress reporting */
+       Progress& progress;
+       double progress_start_time;
+       int progress_num_duplicates;
+
+       /* spatial splitting */
+       float spatial_min_overlap;
+       vector<BoundBox> spatial_right_bounds;
+       SpatialBin spatial_bins[3][BVHParams::NUM_SPATIAL_BINS];
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_BUILD_H__ */
+
diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp
new file mode 100644 (file)
index 0000000..63683ba
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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 "bvh.h"
+#include "bvh_build.h"
+#include "bvh_node.h"
+
+#include "util_debug.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+int BVHNode::getSubtreeSize(BVH_STAT stat) const
+{
+       int cnt = 0;
+
+       switch(stat)
+       {
+               case BVH_STAT_NODE_COUNT:
+                       cnt = 1;
+                       break;
+               case BVH_STAT_LEAF_COUNT:
+                       cnt = is_leaf() ? 1 : 0;
+                       break;
+               case BVH_STAT_INNER_COUNT:
+                       cnt = is_leaf() ? 0 : 1;
+                       break;
+               case BVH_STAT_TRIANGLE_COUNT:
+                       cnt = is_leaf() ? reinterpret_cast<const LeafNode*>(this)->num_triangles() : 0;
+                       break;
+               case BVH_STAT_CHILDNODE_COUNT:
+                       cnt = num_children();
+                       break;
+               default:
+                       assert(0); /* unknown mode */
+       }
+
+       if(!is_leaf())
+               for(int i=0;i<num_children();i++)
+                       cnt += get_child(i)->getSubtreeSize(stat);
+
+       return cnt;
+}
+
+void BVHNode::deleteSubtree()
+{
+       for(int i=0;i<num_children();i++)
+               get_child(i)->deleteSubtree();
+
+       delete this;
+}
+
+float BVHNode::computeSubtreeSAHCost(const BVHParams& p, float probability) const
+{
+       float SAH = probability * p.cost(num_children(), num_triangles());
+
+       for(int i=0;i<num_children();i++) {
+               BVHNode *child = get_child(i);
+               SAH += child->computeSubtreeSAHCost(p, probability * child->m_bounds.area()/m_bounds.area());
+       }
+
+       return SAH;
+}
+
+void InnerNode::print(int depth) const
+{
+       for(int i = 0; i < depth; i++)
+               printf("  ");
+       
+       printf("inner node %p\n", (void*)this);
+
+       if(children[0])
+               children[0]->print(depth+1);
+       if(children[1])
+               children[1]->print(depth+1);
+}
+
+void LeafNode::print(int depth) const
+{
+       for(int i = 0; i < depth; i++)
+               printf("  ");
+       
+       printf("leaf node %d to %d\n", m_lo, m_hi);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h
new file mode 100644 (file)
index 0000000..d83c006
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#ifndef __BVH_NODE_H__
+#define __BVH_NODE_H__
+
+#include "util_boundbox.h"
+#include "util_debug.h"
+#include "util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+enum BVH_STAT
+{
+       BVH_STAT_NODE_COUNT,
+       BVH_STAT_INNER_COUNT,
+       BVH_STAT_LEAF_COUNT,
+       BVH_STAT_TRIANGLE_COUNT,
+       BVH_STAT_CHILDNODE_COUNT
+};
+
+class BVHParams;
+
+class BVHNode
+{
+public:
+       BVHNode()
+       {
+       }
+
+       virtual bool is_leaf() const = 0;
+       virtual int num_children() const = 0;
+       virtual BVHNode *get_child(int i) const = 0;
+       virtual int num_triangles() const { return 0; }
+       virtual void print(int depth = 0) const = 0;
+
+       float getArea() const { return m_bounds.area(); }
+
+       BoundBox m_bounds;
+
+       // Subtree functions
+       int getSubtreeSize(BVH_STAT stat=BVH_STAT_NODE_COUNT) const;
+       float computeSubtreeSAHCost(const BVHParams& p, float probability = 1.0f) const;        
+       void deleteSubtree();
+};
+
+class InnerNode : public BVHNode
+{
+public:
+       InnerNode(const BoundBox& bounds, BVHNode* child0, BVHNode* child1)
+       {
+               m_bounds = bounds;
+               children[0] = child0;
+               children[1] = child1;
+       }
+
+       bool is_leaf() const { return false; }
+       int num_children() const { return 2; }
+       BVHNode *get_child(int i) const{ assert(i>=0 && i<2); return children[i]; }
+       void print(int depth) const;
+
+       BVHNode *children[2];
+};
+
+class LeafNode : public BVHNode
+{
+public:
+       LeafNode(const BoundBox& bounds, int lo, int hi) 
+       {
+               m_bounds = bounds;
+               m_lo = lo;
+               m_hi = hi;
+       }
+
+       LeafNode(const LeafNode& s)
+       : BVHNode()
+       {
+               *this = s;
+       }
+
+       bool is_leaf() const { return true; }
+       int num_children() const { return 0; }
+       BVHNode *get_child(int) const { return NULL; }
+       int num_triangles() const { return m_hi - m_lo; }
+       void print(int depth) const;
+
+       int m_lo;
+       int m_hi;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_NODE_H__ */
+
diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h
new file mode 100644 (file)
index 0000000..b38e40c
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef __BVH_PARAMS_H__
+#define __BVH_PARAMS_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* BVH Parameters */
+
+class BVHParams
+{
+public:
+       /* spatial split area threshold */
+       bool use_spatial_split;
+       float spatial_split_alpha;
+
+       /* SAH costs */
+       float sah_node_cost;
+       float sah_triangle_cost;
+
+       /* number of triangles in leaf */
+       int min_leaf_size;
+       int max_leaf_size;
+
+       /* object or mesh level bvh */
+       bool top_level;
+
+       /* disk cache */
+       bool use_cache;
+
+       /* QBVH */
+       bool use_qbvh;
+
+       /* fixed parameters */
+       enum {
+               MAX_DEPTH = 64,
+               MAX_SPATIAL_DEPTH = 48,
+               NUM_SPATIAL_BINS = 32
+       };
+
+       BVHParams()
+       {
+               use_spatial_split = true;
+               spatial_split_alpha = 1e-5f;
+
+               sah_node_cost = 1.0f;
+               sah_triangle_cost = 1.0f;
+
+               min_leaf_size = 1;
+               max_leaf_size = 0x7FFFFFF;
+
+               top_level = false;
+               use_cache = false;
+               use_qbvh = false;
+       }
+
+       /* SAH costs */
+       float cost(int num_nodes, int num_tris) const
+       { return node_cost(num_nodes) + triangle_cost(num_tris); }
+
+       float triangle_cost(int n) const
+       { return n*sah_triangle_cost; }
+
+       float node_cost(int n) const
+       { return n*sah_node_cost; }
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_PARAMS_H__ */
+
diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp
new file mode 100644 (file)
index 0000000..ee4531a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 "bvh_build.h"
+#include "bvh_sort.h"
+
+#include "util_algorithm.h"
+#include "util_debug.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct BVHReferenceCompare {
+public:
+       int dim;
+
+       BVHReferenceCompare(int dim_)
+       {
+               dim = dim_;
+       }
+
+       bool operator()(const BVHBuild::Reference& ra, const BVHBuild::Reference& rb)
+       {
+               float ca = ra.bounds.min[dim] + ra.bounds.max[dim];
+               float cb = rb.bounds.min[dim] + rb.bounds.max[dim];
+
+               if(ca < cb) return true;
+               else if(ca > cb) return false;
+               else if(ra.prim_object < rb.prim_object) return true;
+               else if(ra.prim_object > rb.prim_object) return false;
+               else if(ra.prim_index < rb.prim_index) return true;
+               else if(ra.prim_index > rb.prim_index) return false;
+
+               return false;
+       }
+};
+
+void bvh_reference_sort(int start, int end, BVHBuild::Reference *data, int dim)
+{
+       sort(data+start, data+end, BVHReferenceCompare(dim));
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/bvh/bvh_sort.h b/intern/cycles/bvh/bvh_sort.h
new file mode 100644 (file)
index 0000000..f067694
--- /dev/null
@@ -0,0 +1,28 @@
+ /*
+ * 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.
+ */
+
+#ifndef __BVH_SORT_H__
+#define __BVH_SORT_H__
+
+CCL_NAMESPACE_BEGIN
+
+void bvh_reference_sort(int start, int end, BVHBuild::Reference *data, int dim);
+
+CCL_NAMESPACE_END
+
+#endif /* __BVH_SORT_H__ */
+
diff --git a/intern/cycles/cmake/create_dmg.py b/intern/cycles/cmake/create_dmg.py
new file mode 100755 (executable)
index 0000000..bba7f8d
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/python 
+
+import os
+import string
+import sys
+
+name = string.replace(sys.argv[1], ".zip", "")
+
+os.system("rm -f %s.dmg" % (name))
+os.system("mkdir -p /tmp/cycles_dmg")
+os.system("rm /tmp/cycles_dmg/*")
+os.system("cp %s.zip /tmp/cycles_dmg/" % (name))
+os.system("/usr/bin/hdiutil create -fs HFS+ -srcfolder /tmp/cycles_dmg -volname %s %s.dmg" % (name, name))
+
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
new file mode 100644 (file)
index 0000000..6f6f00e
--- /dev/null
@@ -0,0 +1,210 @@
+###########################################################################
+# Boost setup
+
+MESSAGE(STATUS "BOOST_PATH ${BOOST_PATH}")
+SET(BOOST_ROOT ${BOOST_PATH})
+
+SET(Boost_ADDITIONAL_VERSIONS "1.45" "1.44" 
+                               "1.43" "1.43.0" "1.42" "1.42.0" 
+                               "1.41" "1.41.0" "1.40" "1.40.0"
+                               "1.39" "1.39.0" "1.38" "1.38.0"
+                               "1.37" "1.37.0" "1.34.1" "1_34_1")
+IF(LINKSTATIC)
+       SET(Boost_USE_STATIC_LIBS ON)
+ENDIF()
+
+SET(Boost_USE_MULTITHREADED ON)
+
+FIND_PACKAGE(Boost 1.34 REQUIRED COMPONENTS filesystem regex system serialization thread)
+
+MESSAGE(STATUS "Boost found ${Boost_FOUND}")
+MESSAGE(STATUS "Boost version ${Boost_VERSION}")
+MESSAGE(STATUS "Boost include dirs ${Boost_INCLUDE_DIRS}")
+MESSAGE(STATUS "Boost library dirs ${Boost_LIBRARY_DIRS}")
+MESSAGE(STATUS "Boost libraries ${Boost_LIBRARIES}")
+
+INCLUDE_DIRECTORIES("${Boost_INCLUDE_DIRS}")
+LINK_DIRECTORIES("${Boost_LIBRARY_DIRS}")
+
+IF(WITH_NETWORK)
+       ADD_DEFINITIONS(-DWITH_NETWORK)
+ENDIF()
+
+IF(WITH_MULTI)
+       ADD_DEFINITIONS(-DWITH_MULTI)
+ENDIF()
+
+###########################################################################
+# OpenImageIO
+
+MESSAGE(STATUS "OIIO_PATH = ${OIIO_PATH}")
+
+FIND_LIBRARY(OPENIMAGEIO_LIBRARY NAMES OpenImageIO PATHS ${OIIO_PATH}/lib)
+FIND_PATH(OPENIMAGEIO_INCLUDES OpenImageIO/imageio.h ${OIIO_PATH}/include)
+FIND_PROGRAM(OPENIMAGEIO_IDIFF NAMES idiff PATHS ${OIIO_PATH}/bin)
+
+IF(OPENIMAGEIO_INCLUDES AND OPENIMAGEIO_LIBRARY)
+       SET(OPENIMAGEIO_FOUND TRUE)
+       MESSAGE(STATUS "OpenImageIO includes = ${OPENIMAGEIO_INCLUDES}")
+       MESSAGE(STATUS "OpenImageIO library = ${OPENIMAGEIO_LIBRARY}")
+ELSE()
+       MESSAGE(STATUS "OpenImageIO not found")
+ENDIF()
+
+ADD_DEFINITIONS(-DWITH_OIIO)
+INCLUDE_DIRECTORIES(${OPENIMAGEIO_INCLUDES} ${OPENIMAGEIO_INCLUDES}/OpenImageIO)
+
+###########################################################################
+# OpenGL
+
+FIND_PACKAGE(OpenGL)
+MESSAGE(STATUS "OPENGL_FOUND=${OPENGL_FOUND}")
+
+INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR})
+
+###########################################################################
+# GLUT
+
+SET(GLUT_ROOT_PATH ${GLUT_PATH})
+
+FIND_PACKAGE(GLUT)
+MESSAGE(STATUS "GLUT_FOUND=${GLUT_FOUND}")
+
+INCLUDE_DIRECTORIES(${GLUT_INCLUDE_DIR})
+
+###########################################################################
+# GLEW
+
+SET(GLEW_VERSION 1.5.1)
+FIND_LIBRARY(GLEW_LIBRARIES NAMES GLEW PATHS ${GLEW_PATH}/lib)
+FIND_PATH(GLEW_INCLUDES NAMES glew.h PATH_SUFFIXES GL PATHS ${GLEW_PATH}/include)
+
+IF(GLEW_INCLUDES AND GLEW_LIBRARIES)
+       MESSAGE(STATUS "GLEW includes = ${GLEW_INCLUDES}")
+       MESSAGE(STATUS "GLEW library = ${GLEW_LIBRARIES}")
+ELSE()
+       MESSAGE(STATUS "GLEW not found")
+ENDIF()
+
+INCLUDE_DIRECTORIES("${GLEW_INCLUDES}")
+
+###########################################################################
+# OpenShadingLanguage
+
+IF(WITH_OSL)
+
+       MESSAGE(STATUS "OSL_PATH = ${OSL_PATH}")
+
+       FIND_LIBRARY(OSL_LIBRARIES NAMES oslexec oslcomp oslquery PATHS ${OSL_PATH}/lib)
+       FIND_PATH(OSL_INCLUDES OSL/oslclosure.h ${OSL_PATH}/include)
+       FIND_PROGRAM(OSL_COMPILER NAMES oslc PATHS ${OSL_PATH}/bin)
+
+       IF(OSL_INCLUDES AND OSL_LIBRARIES AND OSL_COMPILER)
+               SET(OSL_FOUND TRUE)
+               MESSAGE(STATUS "OSL includes = ${OSL_INCLUDES}")
+               MESSAGE(STATUS "OSL library = ${OSL_LIBRARIES}")
+               MESSAGE(STATUS "OSL compiler = ${OSL_COMPILER}")
+       ELSE()
+               MESSAGE(STATUS "OSL not found")
+       ENDIF()
+
+       ADD_DEFINITIONS(-DWITH_OSL)
+       INCLUDE_DIRECTORIES(${OSL_INCLUDES} ${OSL_INCLUDES}/OSL ${OSL_INCLUDES}/../../../src/liboslexec)
+
+ENDIF()
+
+###########################################################################
+# Partio
+
+IF(WITH_PARTIO)
+
+       MESSAGE(STATUS "PARTIO_PATH = ${PARTIO_PATH}")
+
+       FIND_LIBRARY(PARTIO_LIBRARIES NAMES partio PATHS ${PARTIO_PATH}/lib)
+       FIND_PATH(PARTIO_INCLUDES Partio.h ${PARTIO_PATH}/include)
+
+       FIND_PACKAGE(ZLIB)
+
+       IF(PARTIO_INCLUDES AND PARTIO_LIBRARIES AND ZLIB_LIBRARIES)
+               LIST(APPEND PARTIO_LIBRARIES ${ZLIB_LIBRARIES})
+               SET(PARTIO_FOUND TRUE)
+               MESSAGE(STATUS "PARTIO includes = ${PARTIO_INCLUDES}")
+               MESSAGE(STATUS "PARTIO library = ${PARTIO_LIBRARIES}")
+       ELSE()
+               MESSAGE(STATUS "PARTIO not found")
+       ENDIF()
+
+       ADD_DEFINITIONS(-DWITH_PARTIO)
+       INCLUDE_DIRECTORIES(${PARTIO_INCLUDES})
+
+ENDIF()
+
+###########################################################################
+# Python
+
+IF(WITH_BLENDER)
+
+       FIND_PATH(PYTHON_INCLUDE_DIRS Python.h PATHS ${PYTHON_PATH} ${PYTHON_PATH}/include ${PYTHON_PATH}/include/python3.1 ${PYTHON_PATH}/include/python3.2 NO_DEFAULT_PATH)
+       IF(WIN32)
+               FIND_LIBRARY(PYTHON_LIBRARIES NAMES python31 PATHS ${PYTHON_PATH}/lib)
+       ENDIF()
+
+ENDIF()
+
+###########################################################################
+# Blender
+
+IF(WITH_BLENDER)
+       FIND_PATH(BLENDER_INCLUDE_DIRS RNA_blender.h PATHS ${BLENDER_PATH}/include)
+       IF(WIN32)
+               SET(BLENDER_LIBRARIES ${BLENDER_PATH}/bin/Release/blender.lib)
+       ENDIF()
+ENDIF()
+
+###########################################################################
+# CUDA
+
+IF(WITH_CUDA)
+
+       FIND_LIBRARY(CUDA_LIBRARIES NAMES cuda PATHS ${CUDA_PATH}/lib ${CUDA_PATH}/lib/Win32 NO_DEFAULT_PATH)
+       FIND_PATH(CUDA_INCLUDES cuda.h ${CUDA_PATH}/include NO_DEFAULT_PATH)
+       FIND_PROGRAM(CUDA_NVCC NAMES nvcc PATHS ${CUDA_PATH}/bin NO_DEFAULT_PATH)
+
+       IF(CUDA_INCLUDES AND CUDA_LIBRARIES AND CUDA_NVCC)
+               MESSAGE(STATUS "CUDA includes = ${CUDA_INCLUDES}")
+               MESSAGE(STATUS "CUDA library = ${CUDA_LIBRARIES}")
+               MESSAGE(STATUS "CUDA nvcc = ${CUDA_NVCC}")
+       ELSE()
+               MESSAGE(STATUS "CUDA not found")
+       ENDIF()
+
+       ADD_DEFINITIONS(-DWITH_CUDA)
+       INCLUDE_DIRECTORIES(${CUDA_INCLUDES})
+
+ENDIF()
+
+###########################################################################
+# OpenCL
+
+IF(WITH_OPENCL)
+
+       IF(APPLE)
+               SET(OPENCL_INCLUDES "/System/Library/Frameworks/OpenCL.framework/Headers")
+               SET(OPENCL_LIBRARIES "-framework OpenCL")
+       ENDIF()
+
+       IF(WIN32)
+               SET(OPENCL_INCLUDES "")
+               SET(OPENCL_LIRBARIES "OpenCL")
+       ENDIF()
+
+       IF(UNIX AND NOT APPLE)
+               SET(OPENCL_INCLUDES ${OPENCL_PATH})
+               SET(OPENCL_LIRBARIES "OpenCL")
+       ENDIF()
+
+       ADD_DEFINITIONS(-DWITH_OPENCL)
+       INCLUDE_DIRECTORIES(${OPENCL_INCLUDES})
+
+ENDIF()
+
diff --git a/intern/cycles/cmake/platforms.cmake b/intern/cycles/cmake/platforms.cmake
new file mode 100644 (file)
index 0000000..ebc4b01
--- /dev/null
@@ -0,0 +1,27 @@
+
+# Platform specific build flags
+
+SET(GCC_WARNING_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-long-long") # -pedantic
+SET(GCC_OPTIM_FLAGS "-ffast-math -fPIC -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")
+       SET(PYTHON_MODULE_FLAGS "-undefined dynamic_lookup")
+ENDIF(APPLE)
+
+IF(WIN32)
+       SET(CMAKE_CXX_FLAGS "-D_CRT_SECURE_NO_WARNINGS /EHsc /fp:fast")
+       SET(RTTI_DISABLE_FLAGS "/GR- -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
+       SET(PYTHON_MODULE_FLAGS "-DLL")
+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")
+       SET(PYTHON_MODULE_FLAGS "-fPIC")
+ENDIF(UNIX AND NOT APPLE)
+
+ADD_DEFINITIONS(-DCCL_NAMESPACE_BEGIN=namespace\ ccl\ {)
+ADD_DEFINITIONS(-DCCL_NAMESPACE_END=})
+
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ab72548
--- /dev/null
@@ -0,0 +1,18 @@
+
+INCLUDE_DIRECTORIES(. ../kernel ../kernel/svm ../kernel/osl ../util ../render)
+
+SET(sources
+       device.cpp
+       device_cpu.cpp
+       device_cuda.cpp
+       device_multi.cpp
+       device_network.cpp
+       device_opencl.cpp)
+
+SET(headers
+       device.h
+       device_intern.h
+       device_network.h)
+
+ADD_LIBRARY(device ${sources} ${headers})
+
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
new file mode 100644 (file)
index 0000000..4fae931
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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,
+ * bu