Merged trunk up to rev41928

This commit is contained in:
Sergey Sharybin 2011-11-16 20:48:21 +00:00
commit 6e9fd309b8
851 changed files with 107836 additions and 18090 deletions

@ -171,6 +171,7 @@ option(WITH_MOD_DECIMATE "Enable Decimate Modifier" ON)
option(WITH_MOD_BOOLEAN "Enable Boolean Modifier" ON)
option(WITH_MOD_CLOTH_ELTOPO "Enable Experemental cloth solver" OFF)
mark_as_advanced(WITH_MOD_CLOTH_ELTOPO)
option(WITH_MOD_OCEANSIM "Enable Ocean Modifier" OFF)
# Image format support
option(WITH_IMAGE_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" ON)
@ -213,6 +214,13 @@ if(UNIX AND NOT APPLE)
endif()
option(WITH_PYTHON_INSTALL "Copy system python into the blender install folder" ON)
# Cycles
option(WITH_CYCLES "Enable cycles Render Engine" ON)
option(WITH_CYCLES_TEST "Build cycles test application" OFF)
option(WITH_CYCLES_CUDA_BINARIES "Build cycles CUDA binaries" OFF)
set(CYCLES_CUDA_BINARIES_ARCH sm_13 sm_20 sm_21 CACHE STRING "CUDA architectures to build binaries for")
mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
# disable for now, but plan to support on all platforms eventually
option(WITH_MEM_JEMALLOC "Enable malloc replacement (http://www.canonware.com/jemalloc)" OFF)
mark_as_advanced(WITH_MEM_JEMALLOC)
@ -279,11 +287,21 @@ if(WITH_CODEC_QUICKTIME AND MINGW)
"line if youre a developer who wants to add support.")
endif()
if(NOT WITH_FFTW3 AND WITH_MOD_OCEANSIM)
message(FATAL_ERROR "WITH_MOD_OCEANSIM requires WITH_FFTW3 to be ON")
endif()
# may as well build python module without a UI
if(WITH_PYTHON_MODULE)
set(WITH_HEADLESS ON)
endif()
# auto enable openimageio and boost for cycles
if(WITH_CYCLES)
set(WITH_OPENIMAGEIO ON)
set(WITH_BOOST ON)
endif()
TEST_SSE_SUPPORT(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG)
# don't store paths to libs for portable distrobution
@ -349,6 +367,19 @@ if(UNIX AND NOT APPLE)
set(CMAKE_LIBRARY_PATH "/usr/lib/x86_64-linux-gnu;${CMAKE_LIBRARY_PATH}")
endif()
# set lib directory if it exists
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/linux64)
else()
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/linux)
endif()
if(NOT EXISTS ${LIBDIR})
unset(LIBDIR)
endif()
endif()
find_package(JPEG REQUIRED)
find_package(PNG REQUIRED)
find_package(ZLIB REQUIRED)
@ -423,10 +454,17 @@ if(UNIX AND NOT APPLE)
endif()
if(WITH_CODEC_FFMPEG)
# use lib dir if available and nothing else specified
if(LIBDIR AND NOT FFMPEG)
set(FFMPEG ${LIBDIR}/ffmpeg CACHE PATH "FFMPEG Directory")
set(FFMPEG_LIBRARIES avformat avcodec avutil avdevice swscale dirac_encoder mp3lame ogg orc-0.4 schroedinger-1.0 theora theoraenc theoradec vorbis vorbisenc vpx x264 xvidcore faad asound CACHE STRING "FFMPEG Libraries")
else()
set(FFMPEG /usr CACHE PATH "FFMPEG Directory")
set(FFMPEG_LIBRARIES avformat avcodec avutil avdevice swscale CACHE STRING "FFMPEG Libraries")
endif()
mark_as_advanced(FFMPEG)
set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include)
set(FFMPEG_LIBRARIES avformat avcodec avutil avdevice swscale CACHE STRING "FFMPEG Libraries")
mark_as_advanced(FFMPEG_LIBRARIES)
set(FFMPEG_LIBPATH ${FFMPEG}/lib)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_CONSTANT_MACROS")
@ -491,6 +529,45 @@ if(UNIX AND NOT APPLE)
endif()
endif()
if(WITH_BOOST)
# uses in build instructions to override include and library variables
if(NOT BOOST_CUSTOM)
# use lib dir if available and nothing else specified
if(LIBDIR AND NOT BOOST_ROOT)
set(BOOST_ROOT ${LIBDIR}/boost)
set(Boost_USE_MULTITHREADED OFF)
else()
set(Boost_USE_MULTITHREADED ON)
endif()
find_package(Boost 1.34 COMPONENTS filesystem regex system thread)
mark_as_advanced(Boost_DIR) # why doesnt boost do this?
endif()
set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
set(BOOST_LIBRARIES ${Boost_LIBRARIES})
set(BOOST_LIBPATH ${Boost_LIBRARY_DIRS})
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
endif()
if(WITH_OPENIMAGEIO)
# use lib dir if available and nothing else specified
if(LIBDIR AND NOT OPENIMAGEIO_ROOT_DIR)
set(OPENIMAGEIO_ROOT_DIR ${LIBDIR}/oiio)
endif()
find_package(OpenImageIO)
set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARY} ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES} ${BOOST_LIBRARIES})
set(OPENIMAGEIO_LIBPATH) # TODO, remove and reference the absolute path everywhere
set(OPENIMAGEIO_DEFINITIONS)
if(NOT OPENIMAGEIO_FOUND)
set(WITH_OPENIMAGEIO OFF)
set(WITH_CYCLES OFF)
message(STATUS "OpenImageIO not found, disabling WITH_CYCLES")
endif()
endif()
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
set(PLATFORM_LINKLIBS "-lutil -lc -lm -lpthread -lstdc++")
@ -777,6 +854,28 @@ elseif(WIN32)
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
endif()
if(WITH_BOOST)
set(BOOST ${LIBDIR}/boost)
set(BOOST_INCLUDE_DIR ${BOOST}/include)
set(BOOST_POSTFIX "vc90-mt-s-1_47.lib")
set(BOOST_DEBUG_POSTFIX "vc90-mt-sgd-1_47.lib")
set(BOOST_LIBRARIES
optimized libboost_date_time-${BOOST_POSTFIX} libboost_filesystem-${BOOST_POSTFIX}
libboost_regex-${BOOST_POSTFIX} libboost_system-${BOOST_POSTFIX} libboost_thread-${BOOST_POSTFIX}
debug libboost_date_time-${BOOST_DEBUG_POSTFIX} libboost_filesystem-${BOOST_DEBUG_POSTFIX}
libboost_regex-${BOOST_DEBUG_POSTFIX} libboost_system-${BOOST_DEBUG_POSTFIX} libboost_thread-${BOOST_DEBUG_POSTFIX})
set(BOOST_LIBPATH ${BOOST}/lib)
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB")
endif()
if(WITH_OPENIMAGEIO)
set(OPENIMAGEIO ${LIBDIR}/openimageio)
set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
set(OPENIMAGEIO_LIBRARIES OpenImageIO)
set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
set(OPENIMAGEIO_DEFINITIONS)
endif()
set(PLATFORM_LINKFLAGS "/SUBSYSTEM:CONSOLE /STACK:2097152 /INCREMENTAL:NO /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcmrt.lib /NODEFAULTLIB:msvcurt.lib /NODEFAULTLIB:msvcrtd.lib")
# MSVC only, Mingw doesnt need
@ -791,7 +890,7 @@ elseif(WIN32)
else()
# keep GCC specific stuff here
if(CMAKE_COMPILER_IS_GNUCC)
set(PLATFORM_LINKLIBS "-lshell32 -lshfolder -lgdi32 -lmsvcrt -lwinmm -lmingw32 -lm -lws2_32 -lz -lstdc++ -lole32 -luuid -lwsock32")
set(PLATFORM_LINKLIBS "-lshell32 -lshfolder -lgdi32 -lmsvcrt -lwinmm -lmingw32 -lm -lws2_32 -lz -lstdc++ -lole32 -luuid -lwsock32 -lpsapi")
set(PLATFORM_CFLAGS "-pipe -funsigned-char -fno-strict-aliasing")
add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
@ -887,7 +986,29 @@ elseif(WIN32)
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
endif()
set(PLATFORM_LINKFLAGS "--stack,2097152")
if(WITH_BOOST)
set(BOOST ${LIBDIR}/boost)
set(BOOST_INCLUDE_DIR ${BOOST}/include)
set(BOOST_POSTFIX "mgw45-mt-s-1_47")
set(BOOST_DEBUG_POSTFIX "mgw45-mt-sd-1_47")
set(BOOST_LIBRARIES
optimized boost_date_time-${BOOST_POSTFIX} boost_filesystem-${BOOST_POSTFIX}
boost_regex-${BOOST_POSTFIX} boost_system-${BOOST_POSTFIX} boost_thread-${BOOST_POSTFIX}
debug boost_date_time-${BOOST_DEBUG_POSTFIX} boost_filesystem-${BOOST_DEBUG_POSTFIX}
boost_regex-${BOOST_DEBUG_POSTFIX} boost_system-${BOOST_DEBUG_POSTFIX} boost_thread-${BOOST_DEBUG_POSTFIX})
set(BOOST_LIBPATH ${BOOST}/lib/gcc)
set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB -DBOOST_THREAD_USE_LIB ")
endif()
if(WITH_OPENIMAGEIO)
set(OPENIMAGEIO ${LIBDIR}/gcc/openimageio)
set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
set(OPENIMAGEIO_LIBRARIES OpenImageIO)
set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib)
set(OPENIMAGEIO_DEFINITIONS)
endif()
set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152")
endif()
@ -1090,6 +1211,22 @@ elseif(APPLE)
# linker needs "-weak_framework 3DconnexionClient"
endif()
if(WITH_BOOST)
set(BOOST ${LIBDIR}/boost)
set(BOOST_INCLUDE_DIR ${BOOST}/include)
set(BOOST_LIBRARIES boost_date_time-mt boost_filesystem-mt boost_regex-mt boost_system-mt boost_thread-mt)
set(BOOST_LIBPATH ${BOOST}/lib)
set(BOOST_DEFINITIONS)
endif()
if(WITH_OPENIMAGEIO)
set(OPENIMAGEIO ${LIBDIR}/openimageio)
set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO}/include)
set(OPENIMAGEIO_LIBRARIES OpenImageIO ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARY} ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES})
set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib ${JPEG_LIBPATH} ${PNG_LIBPATH} ${TIFF_LIBPATH} ${OPENEXR_LIBPATH} ${ZLIB_LIBPATH})
set(OPENIMAGEIO_DEFINITIONS "-DOIIO_STATIC_BUILD")
endif()
set(EXETYPE MACOSX_BUNDLE)
set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
@ -1390,6 +1527,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_FFTW3)
info_cfg_option(WITH_INTERNATIONAL)
info_cfg_option(WITH_INPUT_NDOF)
info_cfg_option(WITH_CYCLES)
info_cfg_text("Compiler Options:")
info_cfg_option(WITH_BUILDINFO)
@ -1430,6 +1568,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_MOD_BOOLEAN)
info_cfg_option(WITH_MOD_DECIMATE)
info_cfg_option(WITH_MOD_FLUID)
info_cfg_option(WITH_MOD_OCEANSIM)
info_cfg_text("")

@ -34,7 +34,10 @@ OS_NCASE:=$(shell uname -s | tr '[A-Z]' '[a-z]')
# Source and Build DIR's
BLENDER_DIR:=$(shell pwd -P)
BUILD_TYPE:=Release
BUILD_CMAKE_ARGS:=
ifndef BUILD_CMAKE_ARGS
BUILD_CMAKE_ARGS:=
endif
ifndef BUILD_DIR
BUILD_DIR:=$(shell dirname $(BLENDER_DIR))/build/$(OS_NCASE)
@ -123,6 +126,7 @@ help:
@echo " * bpy - build as a python module which can be loaded from python directly"
@echo ""
@echo " Note, passing the argument 'BUILD_DIR=path' when calling make will override the default build dir."
@echo " Note, passing the argument 'BUILD_CMAKE_ARGS=args' lets you add cmake arguments."
@echo ""
@echo ""
@echo "Project Files for IDE's"

@ -254,6 +254,7 @@ if 'blenderlite' in B.targets:
target_env_defs['WITH_BF_BINRELOC'] = False
target_env_defs['BF_BUILDINFO'] = False
target_env_defs['WITH_BF_FLUID'] = False
target_env_defs['WITH_BF_OCEANSIM'] = False
target_env_defs['WITH_BF_DECIMATE'] = False
target_env_defs['WITH_BF_BOOLEAN'] = False
target_env_defs['WITH_BF_PYTHON'] = False
@ -329,6 +330,11 @@ if 'blendernogame' in B.targets:
if env['WITH_BF_FLUID'] == 1:
env['CPPFLAGS'].append('-DWITH_MOD_FLUID')
# build with ocean sim?
if env['WITH_BF_OCEANSIM'] == 1:
env['WITH_BF_FFTW3'] = 1 # ocean needs fftw3 so enable it
env['CPPFLAGS'].append('-DWITH_MOD_OCEANSIM')
if btools.ENDIAN == "big":
env['CPPFLAGS'].append('-D__BIG_ENDIAN__')
@ -435,12 +441,12 @@ B.init_lib_dict()
Export('env')
BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
SConscript(B.root_build_dir+'/source/SConscript')
BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
SConscript(B.root_build_dir+'/intern/SConscript')
BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
SConscript(B.root_build_dir+'/extern/SConscript')
BuildDir(B.root_build_dir+'/source', 'source', duplicate=0)
SConscript(B.root_build_dir+'/source/SConscript')
# now that we have read all SConscripts, we know what
# libraries will be built. Create list of
@ -526,6 +532,50 @@ if env['OURPLATFORM']!='darwin':
if len(source)==0:
env.Execute(Mkdir(dir))
scriptinstall.append(env.Install(dir=dir,source=source))
if env['WITH_BF_CYCLES']:
# cycles python code
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles')
source=os.listdir('intern/cycles/blender/addon')
if '.svn' in source: source.remove('.svn')
if '_svn' in source: source.remove('_svn')
if '__pycache__' in source: source.remove('__pycache__')
source=['intern/cycles/blender/addon/'+s for s in source]
scriptinstall.append(env.Install(dir=dir,source=source))
# cycles kernel code
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel')
source=os.listdir('intern/cycles/kernel')
if '.svn' in source: source.remove('.svn')
if '_svn' in source: source.remove('_svn')
if '__pycache__' in source: source.remove('__pycache__')
source.remove('kernel.cpp')
source.remove('CMakeLists.txt')
source.remove('svm')
source.remove('osl')
source=['intern/cycles/kernel/'+s for s in source]
source.append('intern/cycles/util/util_color.h')
source.append('intern/cycles/util/util_math.h')
source.append('intern/cycles/util/util_transform.h')
source.append('intern/cycles/util/util_types.h')
scriptinstall.append(env.Install(dir=dir,source=source))
# svm
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel', 'svm')
source=os.listdir('intern/cycles/kernel/svm')
if '.svn' in source: source.remove('.svn')
if '_svn' in source: source.remove('_svn')
if '__pycache__' in source: source.remove('__pycache__')
source=['intern/cycles/kernel/svm/'+s for s in source]
scriptinstall.append(env.Install(dir=dir,source=source))
# licenses
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'license')
source=os.listdir('intern/cycles/doc/license')
if '.svn' in source: source.remove('.svn')
if '_svn' in source: source.remove('_svn')
if '__pycache__' in source: source.remove('__pycache__')
source.remove('CMakeLists.txt')
source=['intern/cycles/doc/license/'+s for s in source]
scriptinstall.append(env.Install(dir=dir,source=source))
if env['WITH_BF_INTERNATIONAL']:
internationalpaths=['release' + os.sep + 'datafiles']
@ -696,6 +746,9 @@ if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
dllsources.append('${LCGDIR}/thumbhandler/lib/BlendThumb.dll')
dllsources.append('${LCGDIR}/thumbhandler/lib/BlendThumb64.dll')
if env['WITH_BF_OIIO']:
dllsources.append('${LCGDIR}/openimageio/bin/OpenImageIO.dll')
dllsources.append('#source/icons/blender.exe.manifest')
windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)

@ -34,7 +34,7 @@ BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/
# Don't depend on system's libstdc++
WITH_BF_STATICCXX = True
BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.3.2/libstdc++.a'
BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.3.4/libstdc++.a'
WITH_BF_OPENAL = True
WITH_BF_STATICOPENAL = True
@ -92,9 +92,27 @@ WITH_BF_STATICFFTW3 = True
# JACK
WITH_BF_JACK = True
# Cycles
WITH_BF_CYCLES = True
WITH_BF_OIIO = True
WITH_BF_STATICOIIO = True
BF_OIIO = '/opt/oiio'
BF_OIIO_INC = '${BF_OIIO}/include'
BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/libOpenImageIO.a ${BF_OPENEXR}/lib/libIlmImf.a'
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
WITH_BF_BOOST = True
WITH_BF_STATICBOOST = True
BF_BOOST = '/opt/boost'
BF_BOOST_INC = '${BF_BOOST}/include'
BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_system.a ${BF_BOOST_LIBPATH}/libboost_thread.a'
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
# Ocean Simulation
WITH_BF_OCEANSIM = True
# Compilation and optimization
BF_DEBUG = False
REL_CFLAGS = []
REL_CXXFLAGS = []
REL_CCFLAGS = ['-O2'] # C & C++
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib32']

@ -28,7 +28,7 @@ BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/
# Don't depend on system's libstdc++
WITH_BF_STATICCXX = True
BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.3.2/libstdc++.a'
BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.3.4/libstdc++.a'
WITH_BF_OPENAL = True
WITH_BF_STATICOPENAL = True
@ -83,9 +83,15 @@ BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib32'
# JACK
WITH_BF_JACK = True
# Motion Tracking
WITH_BF_LIBMV = False
# Ocean Simulation
WITH_BF_FFTW3 = True
WITH_BF_STATICFFTW3 = True
WITH_BF_OCEANSIM = True
# Compilation and optimization
BF_DEBUG = False
REL_CFLAGS = []
REL_CXXFLAGS = []
REL_CCFLAGS = ['-O2'] # C & C++
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib32']

@ -28,7 +28,7 @@ BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/
# Don't depend on system's libstdc++
WITH_BF_STATICCXX = True
BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.3.2/libstdc++.a'
BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.3.4/libstdc++.a'
WITH_BF_OPENAL = True
WITH_BF_STATICOPENAL = True
@ -83,9 +83,15 @@ BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib64'
# JACK
WITH_BF_JACK = True
# Motion Tracking
WITH_BF_LIBMV = False
# Ocean Simulation
WITH_BF_FFTW3 = True
WITH_BF_STATICFFTW3 = True
WITH_BF_OCEANSIM = True
# Compilation and optimization
BF_DEBUG = False
REL_CFLAGS = []
REL_CXXFLAGS = []
REL_CCFLAGS = ['-O2'] # C & C++
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib64']

@ -34,7 +34,7 @@ BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/
# Don't depend on system's libstdc++
WITH_BF_STATICCXX = True
BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.3.2/libstdc++.a'
BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.3.4/libstdc++.a'
WITH_BF_OPENAL = True
WITH_BF_STATICOPENAL = True
@ -92,9 +92,27 @@ WITH_BF_STATICFFTW3 = True
# JACK
WITH_BF_JACK = True
# Cycles
WITH_BF_CYCLES = True
WITH_BF_OIIO = True
WITH_BF_STATICOIIO = True
BF_OIIO = '/opt/oiio'
BF_OIIO_INC = '${BF_OIIO}/include'
BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/libOpenImageIO.a ${BF_OPENEXR}/lib/libIlmImf.a'
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
WITH_BF_BOOST = True
WITH_BF_STATICBOOST = True
BF_BOOST = '/opt/boost'
BF_BOOST_INC = '${BF_BOOST}/include'
BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_system.a ${BF_BOOST_LIBPATH}/libboost_thread.a'
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
# Ocean Simulation
WITH_BF_OCEANSIM = True
# Compilation and optimization
BF_DEBUG = False
REL_CFLAGS = []
REL_CXXFLAGS = []
REL_CCFLAGS = ['-O2'] # C & C++
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib64']

@ -0,0 +1,70 @@
# - Find OpenImageIO library
# Find the native OpenImageIO includes and library
# This module defines
# OPENIMAGEIO_INCLUDE_DIRS, where to find openimageio.h, Set when
# OPENIMAGEIO_INCLUDE_DIR is found.
# OPENIMAGEIO_LIBRARIES, libraries to link against to use OpenImageIO.
# OPENIMAGEIO_ROOT_DIR, The base directory to search for OpenImageIO.
# This can also be an environment variable.
# OPENIMAGEIO_FOUND, If false, do not try to use OpenImageIO.
#
# also defined, but not for general use are
# OPENIMAGEIO_LIBRARY, where to find the OpenImageIO library.
#=============================================================================
# Copyright 2011 Blender Foundation.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# If OPENIMAGEIO_ROOT_DIR was defined in the environment, use it.
IF(NOT OPENIMAGEIO_ROOT_DIR AND NOT $ENV{OPENIMAGEIO_ROOT_DIR} STREQUAL "")
SET(OPENIMAGEIO_ROOT_DIR $ENV{OPENIMAGEIO_ROOT_DIR})
ENDIF()
SET(_openimageio_SEARCH_DIRS
${OPENIMAGEIO_ROOT_DIR}
/usr/local
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
)
FIND_PATH(OPENIMAGEIO_INCLUDE_DIR
NAMES
OpenImageIO/imageio.h
HINTS
${_openimageio_SEARCH_DIRS}
PATH_SUFFIXES
include
)
FIND_LIBRARY(OPENIMAGEIO_LIBRARY
NAMES
OpenImageIO
HINTS
${_openimageio_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
# handle the QUIETLY and REQUIRED arguments and set OPENIMAGEIO_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenImageIO DEFAULT_MSG
OPENIMAGEIO_LIBRARY OPENIMAGEIO_INCLUDE_DIR)
IF(OPENIMAGEIO_FOUND)
SET(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARY})
SET(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO_INCLUDE_DIR})
ENDIF(OPENIMAGEIO_FOUND)
MARK_AS_ADVANCED(
OPENIMAGEIO_INCLUDE_DIR
OPENIMAGEIO_LIBRARY
)

@ -93,6 +93,9 @@ def cmake_get_src(f):
# print(f)
def is_definition(l, f, i, name):
if l.startswith("unset("):
return False
if ('set(%s' % name) in l or ('set(' in l and l.endswith(name)):
if len(l.split()) > 1:
raise Exception("strict formatting not kept 'set(%s*' %s:%d" % (name, f, i))
@ -172,6 +175,12 @@ def cmake_get_src(f):
pass
elif new_file.endswith(".def"):
pass
elif new_file.endswith(".cl"): # opencl
pass
elif new_file.endswith(".cu"): # cuda
pass
elif new_file.endswith(".osl"): # open shading language
pass
else:
raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file))

@ -39,6 +39,7 @@ from project_info import (SIMPLE_PROJECTFILE,
# is_py,
cmake_advanced_info,
cmake_compiler_defines,
project_name_get,
)
@ -59,7 +60,11 @@ def create_nb_project_main():
includes = list(set(includes) | set(dirname(f) for f in files if is_c_header(f)))
includes.sort()
if 0:
PROJECT_NAME = "Blender"
else:
# be tricky, get the project name from SVN if we can!
PROJECT_NAME = project_name_get(SOURCE_DIR)
# --------------- NB spesific
defines = [("%s=%s" % cdef) if cdef[1] else cdef[0] for cdef in defines]

@ -89,7 +89,7 @@ def create_qtc_project_main():
f = open(os.path.join(PROJECT_DIR, "%s.files" % FILE_NAME), 'w')
f.write("\n".join(files_rel))
f = open(os.path.join(PROJECT_DIR, "%s.includes" % FILE_NAME), 'w')
f = open(os.path.join(PROJECT_DIR, "%s.includes" % FILE_NAME), 'w', encoding='utf-8')
f.write("\n".join(sorted(includes)))
qtc_prj = os.path.join(PROJECT_DIR, "%s.creator" % FILE_NAME)
@ -104,7 +104,7 @@ def create_qtc_project_main():
defines_final += cmake_compiler_defines()
f.write("\n".join(defines_final))
print("Blender project file written to: %s" % qtc_prj)
print("Blender project file written to: %r" % qtc_prj)
# --- end
@ -133,7 +133,7 @@ def create_qtc_project_python():
f = open(qtc_cfg, 'w')
f.write("// ADD PREDEFINED MACROS HERE!\n")
print("Python project file written to: %s" % qtc_prj)
print("Python project file written to: %r" % qtc_prj)
def main():

@ -12,7 +12,9 @@ set(WITH_BUILTIN_GLEW OFF CACHE FORCE BOOL)
set(WITH_BULLET OFF CACHE FORCE BOOL)
set(WITH_CODEC_FFMPEG OFF CACHE FORCE BOOL)
set(WITH_CODEC_SNDFILE OFF CACHE FORCE BOOL)
set(WITH_CYCLES OFF CACHE FORCE BOOL)
set(WITH_FFTW3 OFF CACHE FORCE BOOL)
set(WITH_LIBMV OFF CACHE FORCE BOOL)
set(WITH_GAMEENGINE OFF CACHE FORCE BOOL)
set(WITH_IK_ITASC OFF CACHE FORCE BOOL)
set(WITH_IMAGE_CINEON OFF CACHE FORCE BOOL)
@ -32,6 +34,7 @@ set(WITH_MOD_BOOLEAN OFF CACHE FORCE BOOL)
set(WITH_MOD_DECIMATE OFF CACHE FORCE BOOL)
set(WITH_MOD_FLUID OFF CACHE FORCE BOOL)
set(WITH_MOD_SMOKE OFF CACHE FORCE BOOL)
set(WITH_MOD_OCEANSIM OFF CACHE FORCE BOOL)
set(WITH_AUDASPACE OFF CACHE FORCE BOOL)
set(WITH_OPENAL OFF CACHE FORCE BOOL)
set(WITH_OPENCOLLADA OFF CACHE FORCE BOOL)

@ -165,6 +165,12 @@ macro(SETUP_LIBDIRS)
if(WITH_IMAGE_TIFF)
link_directories(${TIFF_LIBPATH})
endif()
if(WITH_BOOST)
link_directories(${BOOST_LIBPATH})
endif()
if(WITH_OPENIMAGEIO)
link_directories(${OPENIMAGEIO_LIBPATH})
endif()
if(WITH_IMAGE_OPENJPEG AND UNIX AND NOT APPLE)
link_directories(${OPENJPEG_LIBPATH})
endif()
@ -259,8 +265,14 @@ macro(setup_liblinks
if(WITH_IMAGE_TIFF)
target_link_libraries(${target} ${TIFF_LIBRARY})
endif()
if(WITH_OPENIMAGEIO)
target_link_libraries(${target} ${OPENIMAGEIO_LIBRARIES})
endif()
if(WITH_BOOST)
target_link_libraries(${target} ${BOOST_LIBRARIES})
endif()
if(WITH_IMAGE_OPENEXR)
if(WIN32 AND NOT UNIX)
if(WIN32 AND NOT UNIX AND NOT CMAKE_COMPILER_IS_GNUCC)
file_list_suffix(OPENEXR_LIBRARIES_DEBUG "${OPENEXR_LIBRARIES}" "_d")
target_link_libraries_debug(${target} "${OPENEXR_LIBRARIES_DEBUG}")
target_link_libraries_optimized(${target} "${OPENEXR_LIBRARIES}")
@ -618,3 +630,38 @@ macro(blender_project_hack_post)
endif()
endmacro()
# pair of macros to allow libraries to be specify files to install, but to
# only install them at the end so the directories don't get cleared with
# the files in them. used by cycles to install addon.
macro(delayed_install
base
files
destination)
foreach(f ${files})
set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_FILES ${base}/${f})
set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_DESTINATIONS ${destination})
endforeach()
endmacro()
# note this is a function instead of a macro so that ${BUILD_TYPE} in targetdir
# does not get expanded in calling but is preserved
function(delayed_do_install
targetdir)
get_property(files GLOBAL PROPERTY DELAYED_INSTALL_FILES)
get_property(destinations GLOBAL PROPERTY DELAYED_INSTALL_DESTINATIONS)
if(files)
list(LENGTH files n)
math(EXPR n "${n}-1")
foreach(i RANGE ${n})
list(GET files ${i} f)
list(GET destinations ${i} d)
install(FILES ${f} DESTINATION ${targetdir}/${d})
endforeach()
endif()
endfunction()

@ -186,7 +186,7 @@ def cmake_advanced_info():
def cmake_cache_var(var):
cache_file = open(join(CMAKE_DIR, "CMakeCache.txt"))
cache_file = open(join(CMAKE_DIR, "CMakeCache.txt"), encoding='utf-8')
lines = [l_strip for l in cache_file for l_strip in (l.strip(),) if l_strip if not l_strip.startswith("//") if not l_strip.startswith("#")]
cache_file.close()

@ -217,6 +217,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
WITH_BF_GAMEENGINE = True
WITH_BF_PLAYER = True
WITH_BF_OCEANSIM = True
WITH_BF_BULLET = True
BF_BULLET = '#extern/bullet2/src'
@ -282,6 +283,21 @@ BF_PCRE_LIBPATH = '${BF_PCRE}/lib'
#BF_EXPAT_LIB = 'expat'
#BF_EXPAT_LIBPATH = '/usr/lib'
#Cycles
WITH_BF_CYCLES = True
WITH_BF_OIIO = True
BF_OIIO = LIBDIR + '/openimageio'
BF_OIIO_INC = BF_OIIO + '/include'
BF_OIIO_LIB = 'OpenImageIO'
BF_OIIO_LIBPATH = BF_OIIO + '/lib'
WITH_BF_BOOST = True
BF_BOOST = LIBDIR + '/boost'
BF_BOOST_INC = BF_BOOST + '/include'
BF_BOOST_LIB = 'boost_date_time-mt boost_filesystem-mt boost_regex-mt boost_system-mt boost_thread-mt'
BF_BOOST_LIBPATH = BF_BOOST + '/lib'
#Ray trace optimization
if MACOSX_ARCHITECTURE == 'x86_64' or MACOSX_ARCHITECTURE == 'i386':
WITH_BF_RAYOPTIMIZATION = True

@ -84,6 +84,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
WITH_BF_GAMEENGINE = False
WITH_BF_PLAYER = True
WITH_BF_OCEANSIM = True
WITH_BF_BULLET = True
BF_BULLET = '#extern/bullet2/src'

@ -84,6 +84,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
WITH_BF_GAMEENGINE = False
WITH_BF_PLAYER = True
WITH_BF_OCEANSIM = True
WITH_BF_BULLET = True
BF_BULLET = '#extern/bullet2/src'

@ -84,6 +84,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
WITH_BF_GAMEENGINE = False
WITH_BF_PLAYER = True
WITH_BF_OCEANSIM = True
WITH_BF_BULLET = True
BF_BULLET = '#extern/bullet2/src'

@ -1,5 +1,12 @@
LCGDIR = '../lib/linux'
LIBDIR = "${LCGDIR}"
# find library directory
import platform
import os
bitness = platform.architecture()[0]
if bitness == '64bit':
LCGDIR = '../lib/linux64'
else:
LCGDIR = '../lib/linux'
LIBDIR = "#${LCGDIR}"
BF_PYTHON_ABI_FLAGS = 'm' # Most common for linux distros
BF_PYTHON = '/usr'
@ -87,6 +94,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
WITH_BF_GAMEENGINE = True
WITH_BF_PLAYER = True
WITH_BF_OCEANSIM = True
WITH_BF_BULLET = True
BF_BULLET = '#extern/bullet2/src'
@ -113,7 +121,18 @@ WITH_BF_BINRELOC = True
# enable ffmpeg support
WITH_BF_FFMPEG = True # -DWITH_FFMPEG
BF_FFMPEG = '/usr'
BF_FFMPEG = LIBDIR + '/ffmpeg'
if os.path.exists(LCGDIR + '/ffmpeg'):
WITH_BF_STATICFFMPEG = True
BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/libswscale.a ' + \
'${BF_FFMPEG_LIBPATH}/libavcodec.a ${BF_FFMPEG_LIBPATH}/libavdevice.a ${BF_FFMPEG_LIBPATH}/libavutil.a ' + \
'${BF_FFMPEG_LIBPATH}/libxvidcore.a ${BF_FFMPEG_LIBPATH}/libx264.a ${BF_FFMPEG_LIBPATH}/libmp3lame.a ' + \
'${BF_FFMPEG_LIBPATH}/libvpx.a ${BF_FFMPEG_LIBPATH}/libvorbis.a ${BF_FFMPEG_LIBPATH}/libogg.a ' + \
'${BF_FFMPEG_LIBPATH}/libvorbisenc.a ${BF_FFMPEG_LIBPATH}/libtheora.a ' + \
'${BF_FFMPEG_LIBPATH}/libschroedinger-1.0.a ${BF_FFMPEG_LIBPATH}/liborc-0.4.a ${BF_FFMPEG_LIBPATH}/libdirac_encoder.a ' + \
'${BF_FFMPEG_LIBPATH}/libfaad.a'
else:
BF_FFMPEG = '/usr'
BF_FFMPEG_LIB = 'avformat avcodec swscale avutil avdevice'
BF_FFMPEG_INC = '${BF_FFMPEG}/include'
BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib'
@ -178,6 +197,28 @@ BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib'
BF_JEMALLOC_LIB = 'jemalloc'
BF_JEMALLOC_LIB_STATIC = '${BF_JEMALLOC_LIBPATH}/libjemalloc.a'
WITH_BF_OIIO = True
WITH_BF_STATICOIIO = False
BF_OIIO = LIBDIR + '/oiio'
if not os.path.exists(LCGDIR + '/oiio'):
WITH_BF_OIIO = False
BF_OIIO = '/usr'
BF_OIIO_INC = BF_OIIO + '/include'
BF_OIIO_LIB = 'OpenImageIO'
BF_OIIO_LIBPATH = BF_OIIO + '/lib'
WITH_BF_BOOST = True
WITH_BF_STATICBOOST = False
BF_BOOST = LIBDIR + '/boost'
if not os.path.exists(LCGDIR + '/boost'):
WITH_BF_BOOST = False
BF_BOOST = '/usr'
BF_BOOST_INC = BF_BOOST + '/include'
BF_BOOST_LIB = 'boost_date_time boost_filesystem boost_regex boost_system boost_thread'
BF_BOOST_LIBPATH = BF_BOOST + '/lib'
WITH_BF_CYCLES = WITH_BF_OIIO and WITH_BF_BOOST
WITH_BF_OPENMP = True
#Ray trace optimization
@ -186,6 +227,7 @@ BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
#SpaceNavigator and friends
WITH_BF_3DMOUSE = True
WITH_BF_STATIC3DMOUSE = False
BF_3DMOUSE = '/usr'
BF_3DMOUSE_INC = '${BF_3DMOUSE}/include'
BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib'

@ -90,6 +90,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
WITH_BF_GAMEENGINE = True
WITH_BF_PLAYER = False
WITH_BF_OCEANSIM = True
WITH_BF_BULLET = True
BF_BULLET = '#extern/bullet2/src'

@ -17,7 +17,7 @@ BF_OPENAL_INC = '${BF_OPENAL}/include'
BF_OPENAL_LIB = 'wrap_oal'
BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib'
WITH_BF_FFMPEG = False
WITH_BF_FFMPEG = True
BF_FFMPEG_LIB = 'avformat-53 avcodec-53 avdevice-53 avutil-51 swscale-2'
BF_FFMPEG_LIBPATH = LIBDIR + '/ffmpeg/lib'
BF_FFMPEG_INC = LIBDIR + '/ffmpeg/include'
@ -46,11 +46,11 @@ BF_PTHREADS_INC = '${BF_PTHREADS}/include'
BF_PTHREADS_LIB = 'pthreadGC2'
BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib'
WITH_BF_OPENEXR = False # TODO, gives linking problems for the moment.
WITH_BF_OPENEXR = True
WITH_BF_STATICOPENEXR = False
BF_OPENEXR = LIBDIR + '/gcc/openexr'
BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/OpenEXR'
BF_OPENEXR_LIB = ' Half IlmImf Iex IlmThread '
BF_OPENEXR_LIB = 'Half IlmImf Imath IlmThread Iex'
BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
# Warning, this static lib configuration is untested! users of this OS please confirm.
BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
@ -94,14 +94,15 @@ BF_OPENJPEG_LIB = ''
BF_OPENJPEG_INC = '${BF_OPENJPEG}'
BF_OPENJPEG_LIBPATH='${BF_OPENJPEG}/lib'
WITH_BF_FFTW3 = False
WITH_BF_FFTW3 = True
BF_FFTW3 = LIBDIR + '/gcc/fftw3'
BF_FFTW3_INC = '${BF_FFTW3}/include'
BF_FFTW3_LIB = 'fftw3'
BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
WITH_BF_GAMEENGINE = False
WITH_BF_PLAYER = False
WITH_BF_GAMEENGINE = True
WITH_BF_PLAYER = True
WITH_BF_OCEANSIM = True
WITH_BF_BULLET = True
BF_BULLET = '#extern/bullet2/src'
@ -140,7 +141,7 @@ BF_OPENGL_LIB_STATIC = [ '${BF_OPENGL}/lib/libGL.a', '${BF_OPENGL}/lib/libGLU.a'
'${BF_OPENGL}/lib/libXmu.a', '${BF_OPENGL}/lib/libXext.a',
'${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.a' ]
WITH_BF_COLLADA = False # TODO, gives linking problems at the moment.
WITH_BF_COLLADA = True
BF_COLLADA = '#source/blender/collada'
BF_COLLADA_INC = '${BF_COLLADA}'
BF_COLLADA_LIB = 'bf_collada'
@ -150,8 +151,23 @@ BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include'
BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver expat pcre buffer ftoa'
BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib'
#Cycles
WITH_BF_CYCLES = True
WITH_BF_OIIO = True
BF_OIIO = LIBDIR + '/gcc/openimageio'
BF_OIIO_INC = '#../lib/windows/gcc/openimageio/include'
BF_OIIO_LIB = 'OpenImageIO'
BF_OIIO_LIBPATH = '#../lib/windows/gcc/openimageio/lib'
WITH_BF_BOOST = True
BF_BOOST = LIBDIR + '/boost'
BF_BOOST_INC = '#../lib/windows/boost/include'
BF_BOOST_LIB = 'boost_date_time-mgw45-mt-s-1_47 boost_filesystem-mgw45-mt-s-1_47 boost_regex-mgw45-mt-s-1_47 boost_system-mgw45-mt-s-1_47 boost_thread-mgw45-mt-s-1_47'
BF_BOOST_LIBPATH = '#../lib/windows/boost/lib/gcc'
#Ray trace optimization
WITH_BF_RAYOPTIMIZATION = False
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
##
@ -161,7 +177,7 @@ CXX = 'g++'
CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ]
CXXFLAGS = []
CPPFLAGS = ['-DWIN32', '-DFREE_WINDOWS', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE64_SOURCE']
CPPFLAGS = ['-DWIN32', '-DFREE_WINDOWS', '-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE64_SOURCE', '-DBOOST_ALL_NO_LIB', '-DBOOST_THREAD_USE_LIB', '-DGLEW_STATIC']
REL_CFLAGS = []
REL_CXXFLAGS = []
REL_CCFLAGS = ['-DNDEBUG', '-O2']
@ -170,9 +186,9 @@ C_WARN = ['-Wno-char-subscripts', '-Wdeclaration-after-statement', '-Wstrict-pro
CC_WARN = [ '-Wall' ]
LLIBS = ['-lshell32', '-lshfolder', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz', '-lstdc++','-lole32','-luuid', '-lwsock32']
LLIBS = ['-lshell32', '-lshfolder', '-lgdi32', '-lmsvcrt', '-lwinmm', '-lmingw32', '-lm', '-lws2_32', '-lz', '-lstdc++','-lole32','-luuid', '-lwsock32', '-lpsapi']
PLATFORM_LINKFLAGS = ['--stack,2097152']
PLATFORM_LINKFLAGS = ['-Xlinker', '--stack=2097152']
BF_DEBUG = False
BF_DEBUG_CCFLAGS= ['-g', '-D_DEBUG']

@ -96,6 +96,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
WITH_BF_GAMEENGINE = True
WITH_BF_PLAYER = True
WITH_BF_OCEANSIM = True
WITH_BF_BULLET = True
BF_BULLET = '#extern/bullet2/src'
@ -149,19 +150,20 @@ WITH_BF_3DMOUSE = True
WITH_BF_OPENMP = True
'''
#Cycles
WITH_BF_CYCLES = True
WITH_BF_OIIO = True
BF_OIIO = LIBDIR + '/openimageio'
BF_OIIO = '${LIBDIR}/openimageio'
BF_OIIO_INC = '${BF_OIIO}/include'
BF_OIIO_LIB = 'OpenImageIO'
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
WITH_BF_BOOST = True
BF_BOOST = LIBDIR + '/boost'
BF_BOOST = '${LIBDIR}/boost'
BF_BOOST_INC = '${BF_BOOST}/include'
BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_46_1 libboost_filesystem-vc90-mt-s-1_46_1 libboost_regex-vc90-mt-s-1_46_1 libboost_system-vc90-mt-s-1_46_1 libboost_thread-vc90-mt-s-1_46_1'
BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_47 libboost_filesystem-vc90-mt-s-1_47 libboost_regex-vc90-mt-s-1_47 libboost_system-vc90-mt-s-1_47 libboost_thread-vc90-mt-s-1_47'
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
'''
#Ray trace optimization
WITH_BF_RAYOPTIMIZATION = True

@ -100,6 +100,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
WITH_BF_GAMEENGINE = True
WITH_BF_PLAYER = True
WITH_BF_OCEANSIM = True
WITH_BF_BULLET = True
BF_BULLET = '#extern/bullet2/src'
@ -153,19 +154,20 @@ WITH_BF_3DMOUSE = True
WITH_BF_OPENMP = True
'''
WITH_BF_CYCLES = True
WITH_BF_OIIO = True
BF_OIIO = LIBDIR + '/openimageio'
BF_OIIO = '${LIBDIR}/openimageio'
BF_OIIO_INC = '${BF_OIIO}/include'
BF_OIIO_LIB = 'OpenImageIO'
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
WITH_BF_BOOST = True
BF_BOOST = LIBDIR + '/boost'
BF_BOOST = '${LIBDIR}/boost'
BF_BOOST_INC = '${BF_BOOST}/include'
BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_45 libboost_filesystem-vc90-mt-s-1_45 libboost_regex-vc90-mt-s-1_45 libboost_system-vc90-mt-s-1_45 libboost_thread-vc90-mt-s-1_45'
BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_47 libboost_filesystem-vc90-mt-s-1_47 libboost_regex-vc90-mt-s-1_47 libboost_system-vc90-mt-s-1_47 libboost_thread-vc90-mt-s-1_47'
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
'''
#Ray trace optimization
WITH_BF_RAYOPTIMIZATION = True

@ -195,8 +195,13 @@ def setup_staticlibs(lenv):
if lenv['WITH_BF_OIIO']:
libincs += Split(lenv['BF_OIIO_LIBPATH'])
if lenv['WITH_BF_STATICOIIO']:
statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
if lenv['WITH_BF_BOOST']:
libincs += Split(lenv['BF_BOOST_LIBPATH'])
if lenv['WITH_BF_STATICBOOST']:
statlibs += Split(lenv['BF_BOOST_LIB_STATIC'])
# setting this last so any overriding of manually libs could be handled
if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
@ -216,11 +221,7 @@ def setup_staticlibs(lenv):
return statlibs, libincs
def setup_syslibs(lenv):
syslibs = [
lenv['BF_JPEG_LIB'],
lenv['BF_PNG_LIB'],
]
syslibs = []
if not lenv['WITH_BF_FREETYPE_STATIC']:
syslibs += Split(lenv['BF_FREETYPE_LIB'])
@ -241,6 +242,10 @@ def setup_syslibs(lenv):
syslibs += ['gomp']
if lenv['WITH_BF_ICONV']:
syslibs += Split(lenv['BF_ICONV_LIB'])
if lenv['WITH_BF_OIIO']:
if not lenv['WITH_BF_STATICOIIO']:
syslibs += Split(lenv['BF_OIIO_LIB'])
if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
syslibs += Split(lenv['BF_OPENEXR_LIB'])
if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
@ -280,11 +285,12 @@ def setup_syslibs(lenv):
if not lenv['WITH_BF_STATIC3DMOUSE']:
syslibs += Split(lenv['BF_3DMOUSE_LIB'])
if lenv['WITH_BF_OIIO']:
syslibs += Split(lenv['BF_OIIO_LIB'])
if lenv['WITH_BF_BOOST']:
if lenv['WITH_BF_BOOST'] and not lenv['WITH_BF_STATICBOOST']:
syslibs += Split(lenv['BF_BOOST_LIB'])
syslibs += Split(lenv['BF_JPEG_LIB'])
syslibs += Split(lenv['BF_PNG_LIB'])
syslibs += lenv['LLIBS']
return syslibs
@ -550,10 +556,6 @@ def AppIt(target=None, source=None, env=None):
bldroot = env.Dir('.').abspath
binary = env['BINARYKIND']
if b=='verse':
print bc.OKBLUE+"no bundle for verse"+bc.ENDC
return 0
sourcedir = bldroot + '/source/darwin/%s.app'%binary
sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
targetinfo = installdir +'/' + "%s.app/Contents/Info.plist"%binary
@ -582,6 +584,23 @@ def AppIt(target=None, source=None, env=None):
cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
commands.getoutput(cmd)
if env['WITH_BF_CYCLES']:
croot = '%s/intern/cycles' % (bldroot)
cinstalldir = '%s/%s.app/Contents/MacOS/%s/scripts/addons/cycles' % (installdir,binary,VERSION)
cmd = 'mkdir %s' % (cinstalldir)
commands.getoutput(cmd)
cmd = 'mkdir %s/kernel' % (cinstalldir)
commands.getoutput(cmd)
cmd = 'cp -R %s/blender/addon/*.py %s/' % (croot, cinstalldir)
commands.getoutput(cmd)
cmd = 'cp -R %s/doc/license %s/license' % (croot, cinstalldir)
commands.getoutput(cmd)
cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
commands.getoutput(cmd)
cmd = 'cp -R %s/kernel/svm %s/util/util_color.h %s/util/util_math.h %s/util/util_transform.h %s/util/util_types.h %s/kernel/' % (croot, croot, croot, croot, croot, cinstalldir)
commands.getoutput(cmd)
if env['WITH_OSX_STATICPYTHON']:
cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
commands.getoutput(cmd)

@ -152,12 +152,14 @@ def validate_arguments(args, bc):
'WITH_BF_FLUID',
'WITH_BF_DECIMATE',
'WITH_BF_BOOLEAN',
'WITH_BF_OCEANSIM',
'WITH_BF_CXX_GUARDEDALLOC',
'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
'BUILDBOT_BRANCH',
'WITH_BF_3DMOUSE', 'WITH_BF_STATIC3DMOUSE', 'BF_3DMOUSE', 'BF_3DMOUSE_INC', 'BF_3DMOUSE_LIB', 'BF_3DMOUSE_LIBPATH', 'BF_3DMOUSE_LIB_STATIC',
'WITH_BF_OIIO', 'BF_OIIO', 'BF_OIIO_INC', 'BF_OIIO_LIB', 'BF_OIIO_LIBPATH',
'WITH_BF_BOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIBPATH'
'WITH_BF_CYCLES', 'WITH_BF_CYCLES_BINARIES' 'BF_CYCLES_BINARIES_ARCH',
'WITH_BF_OIIO', 'WITH_BF_STATICOIIO', 'BF_OIIO', 'BF_OIIO_INC', 'BF_OIIO_LIB', 'BF_OIIO_LIB_STATIC', 'BF_OIIO_LIBPATH',
'WITH_BF_BOOST', 'WITH_BF_STATICBOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIB_STATIC', 'BF_BOOST_LIBPATH'
]
# Have options here that scons expects to be lists
@ -239,6 +241,7 @@ def read_opts(env, cfg, args):
localopts = Variables.Variables(cfg, args)
localopts.AddVariables(
('LCGDIR', 'location of cvs lib dir'),
('LIBDIR', 'root dir of libs'),
(BoolVariable('WITH_BF_PYTHON', 'Compile with python', True)),
(BoolVariable('WITH_BF_PYTHON_SAFETY', 'Internal API error checking to track invalid data to prevent crash on access (at the expense of some effeciency)', False)),
('BF_PYTHON', 'Base path for python', ''),
@ -257,6 +260,7 @@ def read_opts(env, cfg, args):
(BoolVariable('WITH_BF_FLUID', 'Build with Fluid simulation (Elbeem)', True)),
(BoolVariable('WITH_BF_DECIMATE', 'Build with decimate modifier', True)),
(BoolVariable('WITH_BF_BOOLEAN', 'Build with boolean modifier', True)),
(BoolVariable('WITH_BF_OCEANSIM', 'Build with ocean simulation', False)),
('BF_PROFILE_FLAGS', 'Profiling compiler flags', ''),
(BoolVariable('WITH_BF_OPENAL', 'Use OpenAL if true', False)),
('BF_OPENAL', 'Base path for OpenAL', ''),
@ -536,16 +540,26 @@ def read_opts(env, cfg, args):
(BoolVariable('WITH_BF_CXX_GUARDEDALLOC', 'Enable GuardedAlloc for C++ memory allocation tracking.', False)),
('BUILDBOT_BRANCH', 'Buildbot branch name', ''),
) # end of opts.AddOptions()
localopts.AddVariables(
(BoolVariable('WITH_BF_CYCLES', 'Build with the Cycles engine', True)),
(BoolVariable('WITH_BF_OIIO', 'Build with OpenImageIO', False)),
(BoolVariable('WITH_BF_STATICOIIO', 'Staticly link to OpenImageIO', False)),
('BF_OIIO', 'OIIO root path', ''),
('BF_OIIO_INC', 'OIIO include path', ''),
('BF_OIIO_LIB', 'OIIO library', ''),
('BF_OIIO_LIBPATH', 'OIIO library path', ''),
('BF_OIIO_LIB_STATIC', 'OIIO static library', ''),
(BoolVariable('WITH_BF_BOOST', 'Build with Boost', False)),
(BoolVariable('WITH_BF_STATICBOOST', 'Staticly link to boost', False)),
('BF_BOOST', 'Boost root path', ''),
('BF_BOOST_INC', 'Boost include path', ''),
('BF_BOOST_LIB', 'Boost library', ''),
('BF_BOOST_LIBPATH', 'Boost library path', '')
('BF_BOOST_LIBPATH', 'Boost library path', ''),
('BF_BOOST_LIB_STATIC', 'Boost static library', '')
) # end of opts.AddOptions()
return localopts

@ -6,6 +6,7 @@ This script shows the most simple example of adding a handler.
import bpy
def my_handler(scene):
print("Frame Change", scene.frame_current)

@ -589,6 +589,7 @@ def pycontext2sphinx(BASEPATH):
"active_base": ("ObjectBase", False),
"active_bone": ("Bone", False),
"active_object": ("Object", False),
"active_operator": ("Operator", False),
"active_pose_bone": ("PoseBone", False),
"armature": ("Armature", False),
"bone": ("Bone", False),
@ -597,6 +598,7 @@ def pycontext2sphinx(BASEPATH):
"cloth": ("ClothModifier", False),
"collision": ("CollisionModifier", False),
"curve": ("Curve", False),
"dynamic_paint": ("DynamicPaintModifier", False),
"edit_bone": ("EditBone", False),
"edit_image": ("Image", False),
"edit_object": ("Object", False),
@ -635,6 +637,7 @@ def pycontext2sphinx(BASEPATH):
"speaker": ("Speaker", False),
"texture": ("Texture", False),
"texture_slot": ("MaterialTextureSlot", False),
"texture_user": ("ID", False),
"vertex_paint_object": ("Object", False),
"visible_bases": ("ObjectBase", True),
"visible_bones": ("Object", True),

@ -23,7 +23,7 @@
# ***** END GPL LICENSE BLOCK *****
set(INC
./Include
Include
)
set(INC_SYS
@ -34,7 +34,8 @@ set(SRC
Source/colamd.c
Source/colamd_global.c
Include//colamd.h
Include/colamd.h
Include/UFconfig.h
)
blender_add_lib(extern_colamd "${SRC}" "${INC}" "${INC_SYS}")

@ -25,8 +25,8 @@
set(INC
.
../Eigen3
./third_party/ssba
./third_party/ldl/Include
third_party/ssba
third_party/ldl/Include
../colamd/Include
)
@ -134,7 +134,7 @@ set(SRC
third_party/msinttypes/inttypes.h
)
IF(WIN32)
if(WIN32)
list(APPEND SRC
third_party/glog/src/logging.cc
third_party/glog/src/raw_logging.cc
@ -162,18 +162,23 @@ IF(WIN32)
)
list(APPEND INC
./third_party/glog/src/windows
./third_party/msinttypes
third_party/glog/src/windows
)
IF(MSVC)
if(NOT MINGW)
list(APPEND INC
third_party/msinttypes
)
endif()
if(MSVC)
set(MSVC_OFLAGS O1 O2 Ox)
foreach(FLAG )
string(REPLACE "" "Od" CMAKE_CXX_FLAGS_RELEASE "")
string(REPLACE "" "Od" CMAKE_C_FLAGS_RELWITHDEBINFO "")
endforeach()
ENDIF(MSVC)
ELSE(WIN32)
endif()
else(WIN32)
list(APPEND SRC
third_party/glog/src/utilities.cc
third_party/glog/src/symbolize.cc
@ -205,9 +210,9 @@ ELSE(WIN32)
)
list(APPEND INC
./third_party/glog/src
third_party/glog/src
)
ENDIF(WIN32)
endif()
add_definitions(-DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL=)

@ -30,7 +30,9 @@ incs += ' ' + env['BF_PNG_INC']
incs += ' ' + env['BF_ZLIB_INC']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog ./third_party/msinttypes'
incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog'
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
incs += ' ./third_party/msinttypes'
src += ['./third_party/glog/src/logging.cc', './third_party/glog/src/raw_logging.cc', './third_party/glog/src/utilities.cc', './third_party/glog/src/vlog_is_on.cc']
src += ['./third_party/glog/src/windows/port.cc']

@ -166,6 +166,16 @@ IF(WIN32)
third_party/glog/src/windows/config.h
)
list(APPEND INC
./third_party/glog/src/windows
)
IF(NOT MINGW)
list(APPEND INC
./third_party/msinttypes
)
ENDIF(MINGW)
list(APPEND INC
./third_party/glog/src/windows
./third_party/msinttypes
@ -219,7 +229,10 @@ incs += ' ' + env['BF_PNG_INC']
incs += ' ' + env['BF_ZLIB_INC']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog ./third_party/msinttypes'
incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog'
incs += ' ./third_party/glog/src/windows ./third_party/glog/src/windows/glog'
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
incs += ' ./third_party/msinttypes'
${win_src}
src += ['./third_party/glog/src/logging.cc', './third_party/glog/src/raw_logging.cc', './third_party/glog/src/utilities.cc', './third_party/glog/src/vlog_is_on.cc']
src += ['./third_party/glog/src/windows/port.cc']

@ -368,15 +368,12 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra
intrinsics->SetPrincipalPoint(principal_x, principal_y);
intrinsics->SetRadialDistortion(k1, k2, k3);
if(focal_length) {
/* do a lens undistortion if focal length is non-zero only */
for (int i = 0; i < markers.size(); ++i) {
intrinsics->InvertIntrinsics(markers[i].x,
markers[i].y,
&(markers[i].x),
&(markers[i].y));
}
}
libmv::Tracks normalized_tracks(markers);

@ -32,6 +32,8 @@
namespace libmv {
namespace euclidean_resection {
typedef unsigned int uint;
bool EuclideanResection(const Mat2X &x_camera,
const Mat3X &X_world,
Mat3 *R, Vec3 *t,

@ -18,6 +18,8 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
#define _USE_MATH_DEFINES
#include "libmv/tracking/esm_region_tracker.h"
#include "libmv/logging/logging.h"

@ -1,3 +1,16 @@
diff --git a/src/libmv/multiview/euclidean_resection.cc b/src/libmv/multiview/euclidean_resection.cc
index 6d918a1..9286251 100644
--- a/src/libmv/multiview/euclidean_resection.cc
+++ b/src/libmv/multiview/euclidean_resection.cc
@@ -32,6 +32,8 @@
namespace libmv {
namespace euclidean_resection {
+typedef unsigned int uint;
+
bool EuclideanResection(const Mat2X &x_camera,
const Mat3X &X_world,
Mat3 *R, Vec3 *t,
diff --git a/src/libmv/numeric/numeric.h b/src/libmv/numeric/numeric.h
index f39d126..21e0f06 100644
--- a/src/libmv/numeric/numeric.h
@ -11,3 +24,148 @@ index f39d126..21e0f06 100644
inline long lround(double d) {
return (long)(d>0 ? d+0.5 : ceil(d-0.5));
}
diff --git a/src/third_party/glog/src/config.h b/src/third_party/glog/src/config.h
index ed8d56e..06ed686 100644
--- a/src/third_party/glog/src/config.h
+++ b/src/third_party/glog/src/config.h
@@ -4,6 +4,8 @@
/* Namespace for Google classes */
#ifdef __APPLE__
#include "config_mac.h"
+#elif __MINGW32__
+ #include "windows/config.h"
#elif __GNUC__
#include "config_linux.h"
#elif _MSC_VER
diff --git a/src/third_party/glog/src/utilities.h b/src/third_party/glog/src/utilities.h
index ee54f94..c4ae256 100644
--- a/src/third_party/glog/src/utilities.h
+++ b/src/third_party/glog/src/utilities.h
@@ -101,7 +101,9 @@
// correctly when GetStackTrace() is called with max_depth == 0.
// Some code may do that.
-#if defined(HAVE_LIB_UNWIND)
+#if __MINGW32__
+# undef STACKTRACE_H
+#elif defined(HAVE_LIB_UNWIND)
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
#elif !defined(NO_FRAME_POINTER)
# if defined(__i386__) && __GNUC__ >= 2
diff --git a/src/third_party/glog/src/windows/glog/logging.h b/src/third_party/glog/src/windows/glog/logging.h
index 7a6df74..4257375 100755
--- a/src/third_party/glog/src/windows/glog/logging.h
+++ b/src/third_party/glog/src/windows/glog/logging.h
@@ -59,7 +59,7 @@
// Annoying stuff for windows -- makes sure clients can import these functions
#ifndef GOOGLE_GLOG_DLL_DECL
-# if defined(_WIN32) && !defined(__CYGWIN__)
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
# else
# define GOOGLE_GLOG_DLL_DECL
@@ -86,6 +86,15 @@
#include <gflags/gflags.h>
#endif
+#ifdef __MINGW32__
+# include <stdlib.h>
+# include <unistd.h>
+# include <stdint.h> // the normal place uint16_t is defined
+# include <sys/types.h> // the normal place u_int16_t is defined
+# include <inttypes.h> // a third place for uint16_t or u_int16_t
+# define _exit(x) exit(x)
+#endif
+
namespace google {
#if 0 // the C99 format
@@ -98,11 +107,16 @@ typedef int32_t int32;
typedef u_int32_t uint32;
typedef int64_t int64;
typedef u_int64_t uint64;
-#elif 1 // the windows (vc7) format
+#elif defined(_MSC_VER)
typedef __int32 int32;
typedef unsigned __int32 uint32;
typedef __int64 int64;
typedef unsigned __int64 uint64;
+#elif defined(__MINGW32__)
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
#else
#error Do not know how to define a 32-bit integer quantity on your system
#endif
diff --git a/src/third_party/glog/src/windows/port.h b/src/third_party/glog/src/windows/port.h
index d093bf5..d507812 100755
--- a/src/third_party/glog/src/windows/port.h
+++ b/src/third_party/glog/src/windows/port.h
@@ -59,14 +59,16 @@
* used by both C and C++ code, so we put all the C++ together.
*/
-/* 4244: otherwise we get problems when substracting two size_t's to an int
- * 4251: it's complaining about a private struct I've chosen not to dllexport
- * 4355: we use this in a constructor, but we do it safely
- * 4715: for some reason VC++ stopped realizing you can't return after abort()
- * 4800: we know we're casting ints/char*'s to bools, and we're ok with that
- * 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
- */
-#pragma warning(disable:4244 4251 4355 4715 4800 4996)
+#if _MSC_VER
+ /* 4244: otherwise we get problems when substracting two size_t's to an int
+ * 4251: it's complaining about a private struct I've chosen not to dllexport
+ * 4355: we use this in a constructor, but we do it safely
+ * 4715: for some reason VC++ stopped realizing you can't return after abort()
+ * 4800: we know we're casting ints/char*'s to bools, and we're ok with that
+ * 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
+ */
+# pragma warning(disable:4244 4251 4355 4715 4800 4996)
+#endif
/* file I/O */
#define PATH_MAX 1024
@@ -108,7 +110,9 @@ extern int snprintf(char *str, size_t size,
extern int safe_vsnprintf(char *str, size_t size,
const char *format, va_list ap);
#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
+#if !defined(__MINGW32__)
#define va_copy(dst, src) (dst) = (src)
+#endif
/* Windows doesn't support specifying the number of buckets as a
* hash_map constructor arg, so we leave this blank.
@@ -130,13 +134,30 @@ enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
inline struct tm* localtime_r(const time_t* timep, struct tm* result) {
+#if __MINGW32__
+ struct tm *local_result;
+ local_result = localtime (timep);
+
+ if (local_result == NULL || result == NULL)
+ return NULL;
+
+ memcpy (result, local_result, sizeof (result));
+
+ return result;
+#else
localtime_s(result, timep);
return result;
+#endif
}
inline char* strerror_r(int errnum, char* buf, size_t buflen) {
+#if __MINGW32__
+ strncpy(buf, "Not implemented yet", buflen);
+ return buf;
+#else
strerror_s(buf, buflen, errnum);
return buf;
+#endif
}
#ifndef __cplusplus

@ -4,6 +4,8 @@
/* Namespace for Google classes */
#ifdef __APPLE__
#include "config_mac.h"
#elif __MINGW32__
#include "windows/config.h"
#elif __GNUC__
#include "config_linux.h"
#elif _MSC_VER

@ -131,7 +131,7 @@
#define PACKAGE_VERSION "0.3.1"
/* How to access the PC from a struct ucontext */
#if defined(_M_X64) || defined(__amd64__)
#if defined(_M_X64) || defined(__amd64__) || defined(__x86_64__)
#define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP]
#else
#define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_EIP]

@ -101,7 +101,9 @@
// correctly when GetStackTrace() is called with max_depth == 0.
// Some code may do that.
#if defined(HAVE_LIB_UNWIND)
#if __MINGW32__
# undef STACKTRACE_H
#elif defined(HAVE_LIB_UNWIND)
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
#elif !defined(NO_FRAME_POINTER)
# if defined(__i386__) && __GNUC__ >= 2

@ -59,7 +59,7 @@
// Annoying stuff for windows -- makes sure clients can import these functions
#ifndef GOOGLE_GLOG_DLL_DECL
# if defined(_WIN32) && !defined(__CYGWIN__)
# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
# else
# define GOOGLE_GLOG_DLL_DECL
@ -86,6 +86,15 @@
#include "third_party/gflags/gflags.h"
#endif
#ifdef __MINGW32__
# include <stdlib.h>
# include <unistd.h>
# include <stdint.h> // the normal place uint16_t is defined
# include <sys/types.h> // the normal place u_int16_t is defined
# include <inttypes.h> // a third place for uint16_t or u_int16_t
# define _exit(x) exit(x)
#endif
namespace google {
#if 0 // the C99 format
@ -98,11 +107,16 @@ typedef int32_t int32;
typedef u_int32_t uint32;
typedef int64_t int64;
typedef u_int64_t uint64;
#elif 1 // the windows (vc7) format
#elif defined(_MSC_VER)
typedef __int32 int32;
typedef unsigned __int32 uint32;
typedef __int64 int64;
typedef unsigned __int64 uint64;
#elif defined(__MINGW32__)
typedef int32_t int32;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
#else
#error Do not know how to define a 32-bit integer quantity on your system
#endif

@ -59,14 +59,16 @@
* used by both C and C++ code, so we put all the C++ together.
*/
/* 4244: otherwise we get problems when substracting two size_t's to an int
#if _MSC_VER
/* 4244: otherwise we get problems when substracting two size_t's to an int
* 4251: it's complaining about a private struct I've chosen not to dllexport
* 4355: we use this in a constructor, but we do it safely
* 4715: for some reason VC++ stopped realizing you can't return after abort()
* 4800: we know we're casting ints/char*'s to bools, and we're ok with that
* 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
*/
#pragma warning(disable:4244 4251 4355 4715 4800 4996)
# pragma warning(disable:4244 4251 4355 4715 4800 4996)
#endif
/* file I/O */
#define PATH_MAX 1024
@ -108,7 +110,9 @@ extern int snprintf(char *str, size_t size,
extern int safe_vsnprintf(char *str, size_t size,
const char *format, va_list ap);
#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
#if !defined(__MINGW32__)
#define va_copy(dst, src) (dst) = (src)
#endif
/* Windows doesn't support specifying the number of buckets as a
* hash_map constructor arg, so we leave this blank.
@ -130,13 +134,30 @@ enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
inline struct tm* localtime_r(const time_t* timep, struct tm* result) {
#if __MINGW32__
struct tm *local_result;
local_result = localtime (timep);
if (local_result == NULL || result == NULL)
return NULL;
memcpy (result, local_result, sizeof (result));
return result;
#else
localtime_s(result, timep);
return result;
#endif
}
inline char* strerror_r(int errnum, char* buf, size_t buflen) {
#if __MINGW32__
strncpy(buf, "Not implemented yet", buflen);
return buf;
#else
strerror_s(buf, buflen, errnum);
return buf;
#endif
}
#ifndef __cplusplus

@ -57,3 +57,8 @@ endif()
if(WITH_IK_ITASC)
add_subdirectory(itasc)
endif()
if(WITH_CYCLES)
add_subdirectory(cycles)
endif()

@ -25,6 +25,9 @@ NEW_CSG='false'
if env['WITH_BF_FLUID']:
SConscript(['elbeem/SConscript'])
if env['WITH_BF_CYCLES']:
SConscript(['cycles/SConscript'])
if NEW_CSG=='false':
SConscript(['bsp/SConscript'])
else:

@ -98,7 +98,6 @@ set(SRC
intern/AUD_IWriter.h
intern/AUD_JOSResampleFactory.cpp
intern/AUD_JOSResampleFactory.h
intern/AUD_JOSResampleReaderCoeff.cpp
intern/AUD_JOSResampleReader.cpp
intern/AUD_JOSResampleReader.h
intern/AUD_LinearResampleFactory.cpp

@ -155,6 +155,9 @@ void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
m_cache_ok = true;
}
if(length == 0)
return;
for(int channel = 0; channel < m_channels; channel++)
{
for(int i = 0; i < length; i++)

@ -181,17 +181,19 @@ void BOP_Face2Face(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB)
if ((faceB->getTAG() != BROKEN) && (faceB->getTAG() != PHANTOM)) {
/* get (or create) bounding box for face B */
if( faceB->getBBox() == NULL )
if( faceB->getBBox() == NULL ) {
faceB->setBBox(mesh->getVertex(faceB->getVertex(0))->getPoint(),
mesh->getVertex(faceB->getVertex(1))->getPoint(),
mesh->getVertex(faceB->getVertex(2))->getPoint());
}
BOP_BBox *boxB = faceB->getBBox();
if (boxA->intersect(*boxB)) {
MT_Plane3 planeB = faceB->getPlane();
if (BOP_containsPoint(planeB,p1) &&
BOP_containsPoint(planeB,p2) &&
BOP_containsPoint(planeB,p3)) {
BOP_containsPoint(planeB,p3))
{
if (BOP_orientation(planeB,planeA)>0) {
BOP_intersectCoplanarFaces(mesh,facesB,faceA,faceB,false);
}
@ -656,7 +658,7 @@ void BOP_mergeSort(MT_Point3 *points, unsigned int *face, unsigned int &size, bo
* @param invert indicates if faceA has priority over faceB
* @param segmemts array of the output x-segments
*/
void BOP_createXS(BOP_Mesh* mesh,
void BOP_createXS(BOP_Mesh* mesh,
BOP_Face* faceA,
BOP_Face* faceB,
BOP_Segment sA,
@ -665,7 +667,7 @@ void BOP_mergeSort(MT_Point3 *points, unsigned int *face, unsigned int &size, bo
BOP_Segment* segments) {
BOP_createXS(mesh, faceA, faceB, faceA->getPlane(), faceB->getPlane(),
sA, sB, invert, segments);
}
}
/**
* Computes the x-segment of two segments (the shared interval). The segments needs to have sA.m_cfg1 > 0 && sB.m_cfg1 > 0 .
@ -1180,12 +1182,14 @@ void BOP_removeOverlappedFaces(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *f
if (faceJ->getTAG()!=BROKEN) {
MT_Plane3 planeJ = faceJ->getPlane();
if (BOP_containsPoint(planeJ,p1) && BOP_containsPoint(planeJ,p2)
&& BOP_containsPoint(planeJ,p3)) {
&& BOP_containsPoint(planeJ,p3))
{
MT_Point3 q1 = mesh->getVertex(faceJ->getVertex(0))->getPoint();
MT_Point3 q2 = mesh->getVertex(faceJ->getVertex(1))->getPoint();
MT_Point3 q3 = mesh->getVertex(faceJ->getVertex(2))->getPoint();
if (BOP_overlap(MT_Vector3(planeJ.x(),planeJ.y(),planeJ.z()),
p1,p2,p3,q1,q2,q3)) {
p1,p2,p3,q1,q2,q3))
{
facesB->erase(facesB->begin()+j,facesB->begin()+(j+1));
faceJ->setTAG(BROKEN);
overlapped = true;

@ -0,0 +1,75 @@
set(CYCLES_INSTALL_PATH "scripts/addons/cycles")
set(WITH_CYCLES_BLENDER ON)
# External Libraries
include(cmake/external_libs.cmake)
# Build Flags
if(WITH_RAYOPTIMIZATION AND SUPPORT_SSE_BUILD)
set(WITH_CYCLES_OPTIMIZED_KERNEL ON)
if(WIN32 AND MSVC)
set(CYCLES_OPTIMIZED_KERNEL_FLAGS "/Ox /Ot /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /EHsc /fp:fast")
elseif(CMAKE_COMPILER_IS_GNUCC)
set(CYCLES_OPTIMIZED_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -DGOGOGO")
endif()
endif()
# for OSL, not needed yet
# set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
# set(RTTI_DISABLE_FLAGS "/GR- -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
# Definitions and Includes
add_definitions(${BOOST_DEFINITIONS} ${OPENIMAGEIO_DEFINITIONS})
add_definitions(-DCCL_NAMESPACE_BEGIN=namespace\ ccl\ {)
add_definitions(-DCCL_NAMESPACE_END=})
if(WITH_CYCLES_OPTIMIZED_KERNEL)
add_definitions(-DWITH_OPTIMIZED_KERNEL)
endif()
if(WITH_CYCLES_NETWORK)
add_definitions(-DWITH_NETWORK)
endif()
if(WITH_CYCLES_OSL)
add_definitions(-DWITH_OSL)
endif()
if(WITH_CYCLES_PARTIO)
add_definitions(-DWITH_PARTIO)
endif()
if(WITH_CYCLES_CUDA_BINARIES)
add_definitions(-DWITH_CUDA_BINARIES)
endif()
add_definitions(-DWITH_OPENCL)
add_definitions(-DWITH_CUDA)
add_definitions(-DWITH_MULTI)
include_directories(
${BOOST_INCLUDE_DIR}
${OPENIMAGEIO_INCLUDE_DIRS}
${OPENIMAGEIO_INCLUDE_DIRS}/OpenImageIO)
# Subdirectories
if(WITH_CYCLES_BLENDER)
add_subdirectory(blender)
endif(WITH_CYCLES_BLENDER)
add_subdirectory(app)
add_subdirectory(bvh)
add_subdirectory(device)
add_subdirectory(doc)
add_subdirectory(kernel)
add_subdirectory(render)
add_subdirectory(subd)
add_subdirectory(util)

49
intern/cycles/SConscript Normal file

@ -0,0 +1,49 @@
#!/usr/bin/python
from os import path
Import('env')
cycles = env.Clone()
cycles.Depends('../../source/blender/makesrna/intern/RNA_blender_cpp.h', 'makesrna')
sources = cycles.Glob('bvh/*.cpp') + cycles.Glob('device/*.cpp') + cycles.Glob('kernel/*.cpp') + cycles.Glob('render/*.cpp') + cycles.Glob('subd/*.cpp') + cycles.Glob('util/*.cpp') + cycles.Glob('blender/*.cpp')
sources.remove(path.join('util', 'util_view.cpp'))
sources.remove(path.join('render', 'film_response.cpp'))
sources.remove(path.join('kernel', 'kernel_optimized.cpp'))
incs = []
defs = []
defs.append('CCL_NAMESPACE_BEGIN=namespace ccl {')
defs.append('CCL_NAMESPACE_END=}')
defs.append('WITH_OPENCL')
defs.append('WITH_MULTI')
defs.append('WITH_CUDA')
incs.extend('. bvh render device kernel kernel/osl kernel/svm util subd'.split())
incs.extend('#intern/guardedalloc #source/blender/makesrna #source/blender/makesdna'.split())
incs.extend('#source/blender/blenloader ../../source/blender/makesrna/intern'.split())
incs.extend('#extern/glew/include'.split())
incs.append(cycles['BF_OIIO_INC'])
incs.append(cycles['BF_BOOST_INC'])
incs.append(cycles['BF_PYTHON_INC'])
# optimized kernel
if env['WITH_BF_RAYOPTIMIZATION']:
optim_cxxflags = []
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
optim_cxxflags.append('/Ox /Ot /arch:SSE2 -D_CRT_SECURE_NO_WARNINGS /EHsc /fp:fast'.split())
else:
optim_cxxflags.append('-ffast-math -msse -msse2 -msse3'.split())
optim_defs = defs + ['WITH_OPTIMIZED_KERNEL']
optim_sources = [path.join('kernel', 'kernel_optimized.cpp')]
cycles_optim = cycles.Clone()
cycles_optim.BlenderLib('bf_intern_cycles_optimized', optim_sources, incs, optim_defs, libtype=['intern'], priority=[0], compileflags=[None], cxx_compileflags=optim_cxxflags)
cycles.BlenderLib('bf_intern_cycles', sources, incs, defs, libtype=['intern'], priority=[0], compileflags=[None])

@ -0,0 +1,69 @@
set(INC
.
../device
../kernel
../kernel/svm
../bvh
../util
../render
../subd
)
set(LIBRARIES
cycles_device
cycles_kernel
cycles_render
cycles_bvh
cycles_subd
cycles_util
${BOOST_LIBRARIES}
${OPENGL_LIBRARIES}
${CYCLES_GLEW_LIBRARY}
${OPENIMAGEIO_LIBRARIES}
)
link_directories(${OPENIMAGEIO_LIBPATH} ${BOOST_LIBPATH})
if(WITH_CYCLES_TEST)
list(APPEND LIBRARIES ${GLUT_LIBRARIES})
endif()
if(WITH_CYCLES_OSL)
list(APPEND LIBRARIES cycles_kernel_osl ${OSL_LIBRARIES})
endif()
if(WITH_CYCLES_PARTIO)
list(APPEND LIBRARIES ${PARTIO_LIBRARIES})
endif()
include_directories(${INC})
if(WITH_CYCLES_TEST)
set(SRC
cycles_test.cpp
cycles_xml.cpp
cycles_xml.h
)
add_executable(cycles_test ${SRC})
target_link_libraries(cycles_test ${LIBRARIES})
if(UNIX AND NOT APPLE)
set_target_properties(cycles_test PROPERTIES INSTALL_RPATH $ORIGIN/lib)
endif()
unset(SRC)
endif()
if(WITH_CYCLES_NETWORK)
set(SRC
cycles_server.cpp
)
add_executable(cycles_server ${SRC})
target_link_libraries(cycles_server ${LIBRARIES})
if(UNIX AND NOT APPLE)
set_target_properties(cycles_server PROPERTIES INSTALL_RPATH $ORIGIN/lib)
endif()
unset(SRC)
endif()

@ -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;
}

@ -0,0 +1,307 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include "buffers.h"
#include "camera.h"
#include "device.h"
#include "scene.h"
#include "session.h"
#include "util_args.h"
#include "util_foreach.h"
#include "util_function.h"
#include "util_path.h"
#include "util_progress.h"
#include "util_string.h"
#include "util_time.h"
#include "util_view.h"
#include "cycles_xml.h"
CCL_NAMESPACE_BEGIN
struct Options {
Session *session;
Scene *scene;
string filepath;
int width, height;
SceneParams scene_params;
SessionParams session_params;
bool quiet;
} options;
static void session_print(const string& str)
{
/* print with carriage return to overwrite previous */
printf("\r%s", str.c_str());
/* add spaces to overwrite longer previous print */
static int maxlen = 0;
int len = str.size();
maxlen = max(len, maxlen);
for(int i = len; i < maxlen; i++)
printf(" ");
/* flush because we don't write an end of line */
fflush(stdout);
}
static void session_print_status()
{
int sample;
double total_time, sample_time;
string status, substatus;
/* get status */
options.session->progress.get_sample(sample, total_time, sample_time);
options.session->progress.get_status(status, substatus);
if(substatus != "")
status += ": " + substatus;
/* print status */
status = string_printf("Sample %d %s", sample, status.c_str());
session_print(status);
}
static void session_init()
{
options.session = new Session(options.session_params);
options.session->reset(options.width, options.height, options.session_params.samples);
options.session->scene = options.scene;
if(options.session_params.background && !options.quiet)
options.session->progress.set_update_callback(function_bind(&session_print_status));
else
options.session->progress.set_update_callback(function_bind(&view_redraw));
options.session->start();
options.scene = NULL;
}
static void scene_init()
{
options.scene = new Scene(options.scene_params);
xml_read_file(options.scene, options.filepath.c_str());
options.width = options.scene->camera->width;
options.height = options.scene->camera->height;
}
static void session_exit()
{
if(options.session) {
delete options.session;
options.session = NULL;
}
if(options.scene) {
delete options.scene;
options.scene = NULL;
}
if(options.session_params.background && !options.quiet) {
session_print("Finished Rendering.");
printf("\n");
}
}
static void display_info(Progress& progress)
{
static double latency = 0.0;
static double last = 0;
double elapsed = time_dt();
string str;
latency = (elapsed - last);
last = elapsed;
int sample;
double total_time, sample_time;
string status, substatus;
progress.get_sample(sample, total_time, sample_time);
progress.get_status(status, substatus);
if(substatus != "")
status += ": " + substatus;
str = string_printf("latency: %.4f sample: %d total: %.4f average: %.4f %s",
latency, sample, total_time, sample_time, status.c_str());
view_display_info(str.c_str());
}
static void display()
{
options.session->draw(options.width, options.height);
display_info(options.session->progress);
}
static void resize(int width, int height)
{
options.width= width;
options.height= height;
if(options.session)
options.session->reset(options.width, options.height, options.session_params.samples);
}
void keyboard(unsigned char key)
{
if(key == 'r')
options.session->reset(options.width, options.height, options.session_params.samples);
else if(key == 27) // escape
options.session->progress.set_cancel("Cancelled");
}
static int files_parse(int argc, const char *argv[])
{
if(argc > 0)
options.filepath = argv[0];
return 0;
}
static void options_parse(int argc, const char **argv)
{
options.width= 1024;
options.height= 512;
options.filepath = "";
options.session = NULL;
options.quiet = false;
/* devices */
string devices = "";
string devicename = "cpu";
vector<DeviceType> types = Device::available_types();
foreach(DeviceType type, types) {
if(devices != "")
devices += ", ";
devices += Device::string_from_type(type);
}
/* shading system */
string ssname = "svm";
string shadingsystems = "Shading system to use: svm";
#ifdef WITH_OSL
shadingsystems += ", osl";
#endif
/* parse options */
ArgParse ap;
bool help = false;
ap.options ("Usage: cycles_test [options] file.xml",
"%*", files_parse, "",
"--device %s", &devicename, ("Devices to use: " + devices).c_str(),
"--shadingsys %s", &ssname, "Shading system to use: svm, osl",
"--background", &options.session_params.background, "Render in background, without user interface",
"--quiet", &options.quiet, "In background mode, don't print progress messages",
"--samples %d", &options.session_params.samples, "Number of samples to render",
"--output %s", &options.session_params.output_path, "File path to write output image",
"--threads %d", &options.session_params.threads, "CPU Rendering Threads",
"--help", &help, "Print help message",
NULL);
if(ap.parse(argc, argv) < 0) {
fprintf(stderr, "%s\n", ap.error_message().c_str());
ap.usage();
exit(EXIT_FAILURE);
}
else if(help || options.filepath == "") {
ap.usage();
exit(EXIT_SUCCESS);
}
options.session_params.device_type = Device::type_from_string(devicename.c_str());
if(ssname == "osl")
options.scene_params.shadingsystem = SceneParams::OSL;
else if(ssname == "svm")
options.scene_params.shadingsystem = SceneParams::SVM;
/* handle invalid configurations */
bool type_available = false;
foreach(DeviceType dtype, types)
if(options.session_params.device_type == dtype)
type_available = true;
if(options.session_params.device_type == DEVICE_NONE || !type_available) {
fprintf(stderr, "Unknown device: %s\n", devicename.c_str());
exit(EXIT_FAILURE);
}
#ifdef WITH_OSL
else if(!(ssname == "osl" || ssname == "svm")) {
#else
else if(!(ssname == "svm")) {
#endif
fprintf(stderr, "Unknown shading system: %s\n", ssname.c_str());
exit(EXIT_FAILURE);
}
else if(options.scene_params.shadingsystem == SceneParams::OSL && options.session_params.device_type != DEVICE_CPU) {
fprintf(stderr, "OSL shading system only works with CPU device\n");
exit(EXIT_FAILURE);
}
else if(options.session_params.samples < 0) {
fprintf(stderr, "Invalid number of samples: %d\n", options.session_params.samples);
exit(EXIT_FAILURE);
}
else if(options.filepath == "") {
fprintf(stderr, "No file path specified\n");
exit(EXIT_FAILURE);
}
/* load scene */
scene_init();
}
CCL_NAMESPACE_END
using namespace ccl;
int main(int argc, const char **argv)
{
path_init("../build/bin/2.59/scripts/addons/cycles/");
options_parse(argc, argv);
if(options.session_params.background) {
session_init();
options.session->wait();
session_exit();
}
else {
string title = "Cycles: " + path_filename(options.filepath);
/* init/exit are callback so they run while GL is initialized */
view_main_loop(title.c_str(), options.width, options.height,
session_init, session_exit, resize, display, keyboard);
}
return 0;
}

@ -0,0 +1,942 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <sstream>
#include <algorithm>
#include <iterator>
#include "camera.h"
#include "film.h"
#include "graph.h"
#include "integrator.h"
#include "light.h"
#include "mesh.h"
#include "nodes.h"
#include "object.h"
#include "shader.h"
#include "scene.h"
#include "subd_mesh.h"
#include "subd_patch.h"
#include "subd_split.h"
#include "util_debug.h"
#include "util_foreach.h"
#include "util_path.h"
#include "util_transform.h"
#include "util_xml.h"
#include "cycles_xml.h"
CCL_NAMESPACE_BEGIN
/* XML reading state */
struct XMLReadState {
Scene *scene; /* scene pointer */
Transform tfm; /* current transform state */
bool smooth; /* smooth normal state */
int shader; /* current shader */
string base; /* base path to current file*/
float dicing_rate; /* current dicing rate */
Mesh::DisplacementMethod displacement_method;
};
/* Attribute Reading */
static bool xml_read_bool(bool *value, pugi::xml_node node, const char *name)
{
pugi::xml_attribute attr = node.attribute(name);
if(attr) {
*value = (string_iequals(attr.value(), "true")) || (atoi(attr.value()) != 0);
return true;
}
return false;
}
static bool xml_read_int(int *value, pugi::xml_node node, const char *name)
{
pugi::xml_attribute attr = node.attribute(name);
if(attr) {
*value = atoi(attr.value());
return true;
}
return false;
}
static bool xml_read_int_array(vector<int>& value, pugi::xml_node node, const char *name)
{
pugi::xml_attribute attr = node.attribute(name);
if(attr) {
vector<string> tokens;
string_split(tokens, attr.value());
foreach(const string& token, tokens)
value.push_back(atoi(token.c_str()));
return true;
}
return false;
}
static bool xml_read_float(float *value, pugi::xml_node node, const char *name)
{
pugi::xml_attribute attr = node.attribute(name);
if(attr) {
*value = atof(attr.value());
return true;
}
return false;
}
static bool xml_read_float_array(vector<float>& value, pugi::xml_node node, const char *name)
{
pugi::xml_attribute attr = node.attribute(name);
if(attr) {
vector<string> tokens;
string_split(tokens, attr.value());
foreach(const string& token, tokens)
value.push_back(atof(token.c_str()));
return true;
}
return false;
}
static bool xml_read_float3(float3 *value, pugi::xml_node node, const char *name)
{
vector<float> array;
if(xml_read_float_array(array, node, name) && array.size() == 3) {
*value = make_float3(array[0], array[1], array[2]);
return true;
}
return false;
}
static bool xml_read_float3_array(vector<float3>& value, pugi::xml_node node, const char *name)
{
vector<float> array;
if(xml_read_float_array(array, node, name)) {
for(size_t i = 0; i < array.size(); i += 3)
value.push_back(make_float3(array[i+0], array[i+1], array[i+2]));
return true;
}
return false;
}
static bool xml_read_float4(float4 *value, pugi::xml_node node, const char *name)
{
vector<float> array;
if(xml_read_float_array(array, node, name) && array.size() == 4) {
*value = make_float4(array[0], array[1], array[2], array[3]);
return true;
}
return false;
}
static bool xml_read_string(string *str, pugi::xml_node node, const char *name)
{
pugi::xml_attribute attr = node.attribute(name);
if(attr) {
*str = attr.value();
return true;
}
return false;
}
static bool xml_read_ustring(ustring *str, pugi::xml_node node, const char *name)
{
pugi::xml_attribute attr = node.attribute(name);
if(attr) {
*str = ustring(attr.value());
return true;
}
return false;
}
static bool xml_equal_string(pugi::xml_node node, const char *name, const char *value)
{
pugi::xml_attribute attr = node.attribute(name);
if(attr)
return string_iequals(attr.value(), value);
return false;
}
static bool xml_read_enum(ustring *str, ShaderEnum& enm, pugi::xml_node node, const char *name)
{
pugi::xml_attribute attr = node.attribute(name);
if(attr) {
ustring ustr(attr.value());
if(enm.exists(ustr)) {
*str = ustr;
return true;
}
else
fprintf(stderr, "Unknown value \"%s\" for attribute \"%s\".\n", ustr.c_str(), name);
}
return false;
}
/* Film */
static void xml_read_film(const XMLReadState& state, pugi::xml_node node)
{
Camera *cam = state.scene->camera;
xml_read_int(&cam->width, node, "width");
xml_read_int(&cam->height, node, "height");
float aspect = (float)cam->width/(float)cam->height;
if(cam->width >= cam->height) {
cam->left = -aspect;
cam->right = aspect;
cam->bottom = -1.0f;
cam->top = 1.0f;
}
else {
cam->left = -1.0f;
cam->right = 1.0f;
cam->bottom = -1.0f/aspect;
cam->top = 1.0f/aspect;
}
cam->need_update = true;
cam->update();
}
/* Integrator */
static void xml_read_integrator(const XMLReadState& state, pugi::xml_node node)
{
Integrator *integrator = state.scene->integrator;
xml_read_int(&integrator->min_bounce, node, "min_bounce");
xml_read_int(&integrator->max_bounce, node, "max_bounce");
xml_read_bool(&integrator->no_caustics, node, "no_caustics");
xml_read_float(&integrator->blur_caustics, node, "blur_caustics");
}
/* Camera */
static void xml_read_camera(const XMLReadState& state, pugi::xml_node node)
{
Camera *cam = state.scene->camera;
if(xml_read_float(&cam->fov, node, "fov"))
cam->fov *= M_PI/180.0f;
xml_read_float(&cam->nearclip, node, "nearclip");
xml_read_float(&cam->farclip, node, "farclip");
xml_read_float(&cam->aperturesize, node, "aperturesize"); // 0.5*focallength/fstop
xml_read_float(&cam->focaldistance, node, "focaldistance");
xml_read_float(&cam->shutteropen, node, "shutteropen");
xml_read_float(&cam->shutterclose, node, "shutterclose");
if(xml_equal_string(node, "type", "orthographic"))
cam->ortho = true;
else if(xml_equal_string(node, "type", "perspective"))
cam->ortho = false;
cam->matrix = state.tfm;
cam->need_update = true;
cam->update();
}
/* Shader */
static string xml_socket_name(const char *name)
{
string sname = name;
size_t i;
while((i = sname.find(" ")) != string::npos)
sname.replace(i, 1, "");
return sname;
}
static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pugi::xml_node graph_node)
{
ShaderGraph *graph = new ShaderGraph();
map<string, ShaderNode*> nodemap;
nodemap["output"] = graph->output();
for(pugi::xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
ShaderNode *snode = NULL;
if(string_iequals(node.name(), "image_texture")) {
ImageTextureNode *img = new ImageTextureNode();
xml_read_string(&img->filename, node, "src");
img->filename = path_join(state.base, img->filename);
snode = img;
}
else if(string_iequals(node.name(), "environment_texture")) {
EnvironmentTextureNode *env = new EnvironmentTextureNode();
xml_read_string(&env->filename, node, "src");
env->filename = path_join(state.base, env->filename);
snode = env;
}
else if(string_iequals(node.name(), "sky_texture")) {
SkyTextureNode *sky = new SkyTextureNode();
xml_read_float3(&sky->sun_direction, node, "sun_direction");
xml_read_float(&sky->turbidity, node, "turbidity");
snode = sky;
}
else if(string_iequals(node.name(), "noise_texture")) {
snode = new NoiseTextureNode();
}
else if(string_iequals(node.name(), "blend_texture")) {
BlendTextureNode *blend = new BlendTextureNode();
xml_read_enum(&blend->progression, BlendTextureNode::progression_enum, node, "progression");
xml_read_enum(&blend->axis, BlendTextureNode::axis_enum, node, "axis");
snode = blend;
}
else if(string_iequals(node.name(), "clouds_texture")) {
CloudsTextureNode *clouds = new CloudsTextureNode();
xml_read_bool(&clouds->hard, node, "hard");
xml_read_int(&clouds->depth, node, "depth");
xml_read_enum(&clouds->basis, CloudsTextureNode::basis_enum, node, "basis");
snode = clouds;
}
else if(string_iequals(node.name(), "voronoi_texture")) {
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
xml_read_enum(&voronoi->distance_metric, VoronoiTextureNode::distance_metric_enum, node, "distance_metric");
xml_read_enum(&voronoi->coloring, VoronoiTextureNode::coloring_enum, node, "coloring");
snode = voronoi;
}
else if(string_iequals(node.name(), "musgrave_texture")) {
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
xml_read_enum(&musgrave->type, MusgraveTextureNode::type_enum, node, "type");
xml_read_enum(&musgrave->basis, MusgraveTextureNode::basis_enum, node, "basis");
snode = musgrave;
}
else if(string_iequals(node.name(), "marble_texture")) {
MarbleTextureNode *marble = new MarbleTextureNode();
xml_read_enum(&marble->type, MarbleTextureNode::type_enum, node, "type");
xml_read_enum(&marble->wave, MarbleTextureNode::wave_enum, node, "wave");
xml_read_enum(&marble->basis, MarbleTextureNode::basis_enum, node, "basis");
xml_read_bool(&marble->hard, node, "hard");
xml_read_int(&marble->depth, node, "depth");
snode = marble;
}
else if(string_iequals(node.name(), "magic_texture")) {
MagicTextureNode *magic = new MagicTextureNode();
xml_read_int(&magic->depth, node, "depth");
snode = magic;
}
else if(string_iequals(node.name(), "stucci_texture")) {
StucciTextureNode *stucci = new StucciTextureNode();
xml_read_enum(&stucci->type, StucciTextureNode::type_enum, node, "type");
xml_read_enum(&stucci->basis, StucciTextureNode::basis_enum, node, "basis");
xml_read_bool(&stucci->hard, node, "hard");
snode = stucci;
}
else if(string_iequals(node.name(), "distorted_noise_texture")) {
DistortedNoiseTextureNode *dist = new DistortedNoiseTextureNode();
xml_read_enum(&dist->basis, DistortedNoiseTextureNode::basis_enum, node, "basis");
xml_read_enum(&dist->distortion_basis, DistortedNoiseTextureNode::basis_enum, node, "distortion_basis");
snode = dist;
}
else if(string_iequals(node.name(), "wood_texture")) {
WoodTextureNode *wood = new WoodTextureNode();
xml_read_enum(&wood->type, WoodTextureNode::type_enum, node, "type");
xml_read_enum(&wood->wave, WoodTextureNode::wave_enum, node, "wave");
xml_read_enum(&wood->basis, WoodTextureNode::basis_enum, node, "basis");
xml_read_bool(&wood->hard, node, "hard");
snode = wood;
}
else if(string_iequals(node.name(), "mapping")) {
snode = new MappingNode();
}
else if(string_iequals(node.name(), "ward_bsdf")) {
snode = new WardBsdfNode();
}
else if(string_iequals(node.name(), "diffuse_bsdf")) {
snode = new DiffuseBsdfNode();
}
else if(string_iequals(node.name(), "translucent_bsdf")) {
snode = new TranslucentBsdfNode();
}
else if(string_iequals(node.name(), "transparent_bsdf")) {
snode = new TransparentBsdfNode();
}
else if(string_iequals(node.name(), "velvet_bsdf")) {
snode = new VelvetBsdfNode();
}
else if(string_iequals(node.name(), "glossy_bsdf")) {
GlossyBsdfNode *glossy = new GlossyBsdfNode();
xml_read_enum(&glossy->distribution, GlossyBsdfNode::distribution_enum, node, "distribution");
snode = glossy;
}
else if(string_iequals(node.name(), "glass_bsdf")) {
GlassBsdfNode *diel = new GlassBsdfNode();
xml_read_enum(&diel->distribution, GlassBsdfNode::distribution_enum, node, "distribution");
snode = diel;
}
else if(string_iequals(node.name(), "emission")) {
EmissionNode *emission = new EmissionNode();
xml_read_bool(&emission->total_power, node, "total_power");
snode = emission;
}
else if(string_iequals(node.name(), "background")) {
snode = new BackgroundNode();
}
else if(string_iequals(node.name(), "transparent_volume")) {
snode = new TransparentVolumeNode();
}
else if(string_iequals(node.name(), "isotropic_volume")) {
snode = new IsotropicVolumeNode();
}
else if(string_iequals(node.name(), "geometry")) {
snode = new GeometryNode();
}
else if(string_iequals(node.name(), "texture_coordinate")) {
snode = new TextureCoordinateNode();
}
else if(string_iequals(node.name(), "lightPath")) {
snode = new LightPathNode();
}
else if(string_iequals(node.name(), "value")) {
ValueNode *value = new ValueNode();
xml_read_float(&value->value, node, "value");
snode = value;
}
else if(string_iequals(node.name(), "color")) {
ColorNode *color = new ColorNode();
xml_read_float3(&color->value, node, "value");
snode = color;
}
else if(string_iequals(node.name(), "mix_closure")) {
snode = new MixClosureNode();
}
else if(string_iequals(node.name(), "add_closure")) {
snode = new AddClosureNode();
}
else if(string_iequals(node.name(), "mix")) {
MixNode *mix = new MixNode();
xml_read_enum(&mix->type, MixNode::type_enum, node, "type");
snode = mix;
}
else if(string_iequals(node.name(), "attribute")) {
AttributeNode *attr = new AttributeNode();
xml_read_ustring(&attr->attribute, node, "attribute");
snode = attr;
}
else if(string_iequals(node.name(), "fresnel")) {
snode = new FresnelNode();
}
else if(string_iequals(node.name(), "math")) {
MathNode *math = new MathNode();
xml_read_enum(&math->type, MathNode::type_enum, node, "type");
snode = math;
}
else if(string_iequals(node.name(), "vector_math")) {
VectorMathNode *vmath = new VectorMathNode();
xml_read_enum(&vmath->type, VectorMathNode::type_enum, node, "type");
snode = vmath;
}
else if(string_iequals(node.name(), "connect")) {
/* connect nodes */
vector<string> from_tokens, to_tokens;
string_split(from_tokens, node.attribute("from").value());
string_split(to_tokens, node.attribute("to").value());
if(from_tokens.size() == 2 && to_tokens.size() == 2) {
/* find nodes and sockets */
ShaderOutput *output = NULL;
ShaderInput *input = NULL;
if(nodemap.find(from_tokens[0]) != nodemap.end()) {
ShaderNode *fromnode = nodemap[from_tokens[0]];
foreach(ShaderOutput *out, fromnode->outputs)
if(string_iequals(xml_socket_name(out->name), from_tokens[1]))
output = out;
if(!output)
fprintf(stderr, "Unknown output socket name \"%s\" on \"%s\".\n", from_tokens[1].c_str(), from_tokens[0].c_str());
}
else
fprintf(stderr, "Unknown shader node name \"%s\".\n", from_tokens[0].c_str());
if(nodemap.find(to_tokens[0]) != nodemap.end()) {
ShaderNode *tonode = nodemap[to_tokens[0]];
foreach(ShaderInput *in, tonode->inputs)
if(string_iequals(xml_socket_name(in->name), to_tokens[1]))
input = in;
if(!input)
fprintf(stderr, "Unknown input socket name \"%s\" on \"%s\".\n", to_tokens[1].c_str(), to_tokens[0].c_str());
}
else
fprintf(stderr, "Unknown shader node name \"%s\".\n", to_tokens[0].c_str());
/* connect */
if(output && input)
graph->connect(output, input);
}
else
fprintf(stderr, "Invalid from or to value for connect node.\n");
}
else
fprintf(stderr, "Unknown shader node \"%s\".\n", node.name());
if(snode) {
/* add to graph */
graph->add(snode);
/* add to map for name lookups */
string name = "";
xml_read_string(&name, node, "name");
nodemap[name] = snode;
/* read input values */
for(pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute()) {
foreach(ShaderInput *in, snode->inputs) {
if(string_iequals(in->name, attr.name())) {
switch(in->type) {
case SHADER_SOCKET_FLOAT:
xml_read_float(&in->value.x, node, attr.name());
break;
case SHADER_SOCKET_COLOR:
case SHADER_SOCKET_VECTOR:
case SHADER_SOCKET_POINT:
case SHADER_SOCKET_NORMAL:
xml_read_float3(&in->value, node, attr.name());
break;
default:
break;
}
}
}
}
}
}
shader->set_graph(graph);
shader->tag_update(state.scene);
}
static void xml_read_shader(const XMLReadState& state, pugi::xml_node node)
{
Shader *shader = new Shader();
xml_read_string(&shader->name, node, "name");
xml_read_shader_graph(state, shader, node);
state.scene->shaders.push_back(shader);
}
/* Background */
static void xml_read_background(const XMLReadState& state, pugi::xml_node node)
{
Shader *shader = state.scene->shaders[state.scene->default_background];
xml_read_shader_graph(state, shader, node);
}
/* Mesh */
static Mesh *xml_add_mesh(Scene *scene, const Transform& tfm)
{
/* create mesh */
Mesh *mesh = new Mesh();
scene->meshes.push_back(mesh);
/* create object*/
Object *object = new Object();
object->mesh = mesh;
object->tfm = tfm;
scene->objects.push_back(object);
return mesh;
}
static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
{
/* add mesh */
Mesh *mesh = xml_add_mesh(state.scene, state.tfm);
mesh->used_shaders.push_back(state.shader);
/* read state */
int shader = state.shader;
bool smooth = state.smooth;
mesh->displacement_method = state.displacement_method;
/* read vertices and polygons, RIB style */
vector<float3> P;
vector<int> verts, nverts;
xml_read_float3_array(P, node, "P");
xml_read_int_array(verts, node, "verts");
xml_read_int_array(nverts, node, "nverts");
if(xml_equal_string(node, "subdivision", "catmull-clark")) {
/* create subd mesh */
SubdMesh sdmesh;
/* create subd vertices */
for(size_t i = 0; i < P.size(); i++)
sdmesh.add_vert(P[i]);
/* create subd faces */
int index_offset = 0;
for(size_t i = 0; i < nverts.size(); i++) {
if(nverts[i] == 4) {
int v0 = verts[index_offset + 0];
int v1 = verts[index_offset + 1];
int v2 = verts[index_offset + 2];
int v3 = verts[index_offset + 3];
sdmesh.add_face(v0, v1, v2, v3);
}
else {
for(int j = 0; j < nverts[i]-2; j++) {
int v0 = verts[index_offset];
int v1 = verts[index_offset + j + 1];
int v2 = verts[index_offset + j + 2];;
sdmesh.add_face(v0, v1, v2);
}
}
index_offset += nverts[i];
}
/* finalize subd mesh */
sdmesh.link_boundary();
/* subdivide */
DiagSplit dsplit;
//dsplit.camera = state.scene->camera;
//dsplit.dicing_rate = 5.0f;
dsplit.dicing_rate = state.dicing_rate;
xml_read_float(&dsplit.dicing_rate, node, "dicing_rate");
sdmesh.tesselate(&dsplit, false, mesh, shader, smooth);
}
else {
/* create vertices */
mesh->verts = P;
/* create triangles */
int index_offset = 0;
for(size_t i = 0; i < nverts.size(); i++) {
for(int j = 0; j < nverts[i]-2; j++) {
int v0 = verts[index_offset];
int v1 = verts[index_offset + j + 1];
int v2 = verts[index_offset + j + 2];
assert(v0 < (int)P.size());
assert(v1 < (int)P.size());
assert(v2 < (int)P.size());
mesh->add_triangle(v0, v1, v2, shader, smooth);
}
index_offset += nverts[i];
}
}
/* temporary for test compatibility */
mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
}
/* Patch */
static void xml_read_patch(const XMLReadState& state, pugi::xml_node node)
{
/* read patch */
Patch *patch = NULL;
vector<float3> P;
xml_read_float3_array(P, node, "P");
if(xml_equal_string(node, "type", "bilinear")) {
/* bilinear patch */
if(P.size() == 4) {
LinearQuadPatch *bpatch = new LinearQuadPatch();
for(int i = 0; i < 4; i++)
P[i] = transform(&state.tfm, P[i]);
memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
patch = bpatch;
}
else
fprintf(stderr, "Invalid number of control points for bilinear patch.\n");
}
else if(xml_equal_string(node, "type", "bicubic")) {
/* bicubic patch */
if(P.size() == 16) {
BicubicPatch *bpatch = new BicubicPatch();
for(int i = 0; i < 16; i++)
P[i] = transform(&state.tfm, P[i]);
memcpy(bpatch->hull, &P[0], sizeof(bpatch->hull));
patch = bpatch;
}
else
fprintf(stderr, "Invalid number of control points for bicubic patch.\n");
}
else
fprintf(stderr, "Unknown patch type.\n");
if(patch) {
/* add mesh */
Mesh *mesh = xml_add_mesh(state.scene, transform_identity());
mesh->used_shaders.push_back(state.shader);
/* split */
DiagSplit dsplit;
//dsplit.camera = state.scene->camera;
//dsplit.dicing_rate = 5.0f;
dsplit.dicing_rate = state.dicing_rate;
xml_read_float(&dsplit.dicing_rate, node, "dicing_rate");
dsplit.split_quad(mesh, patch, state.shader, state.smooth);
delete patch;
/* temporary for test compatibility */
mesh->attributes.remove(Attribute::STD_VERTEX_NORMAL);
}
}
/* Light */
static void xml_read_light(const XMLReadState& state, pugi::xml_node node)
{
Light *light = new Light();
light->shader = state.shader;
xml_read_float3(&light->co, node, "P");
light->co = transform(&state.tfm, light->co);
state.scene->lights.push_back(light);
}
/* Transform */
static void xml_read_transform(pugi::xml_node node, Transform& tfm)
{
if(node.attribute("matrix")) {
vector<float> matrix;
if(xml_read_float_array(matrix, node, "matrix") && matrix.size() == 16)
tfm = tfm * transform_transpose((*(Transform*)&matrix[0]));
}
if(node.attribute("translate")) {
float3 translate = make_float3(0.0f, 0.0f, 0.0f);
xml_read_float3(&translate, node, "translate");
tfm = tfm * transform_translate(translate);
}
if(node.attribute("rotate")) {
float4 rotate = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
xml_read_float4(&rotate, node, "rotate");
tfm = tfm * transform_rotate(rotate.x*M_PI/180.0f, make_float3(rotate.y, rotate.z, rotate.w));
}
if(node.attribute("scale")) {
float3 scale = make_float3(0.0f, 0.0f, 0.0f);
xml_read_float3(&scale, node, "scale");
tfm = tfm * transform_scale(scale);
}
}
/* State */
static void xml_read_state(XMLReadState& state, pugi::xml_node node)
{
/* read shader */
string shadername;
if(xml_read_string(&shadername, node, "shader")) {
int i = 0;
bool found = false;
foreach(Shader *shader, state.scene->shaders) {
if(shader->name == shadername) {
state.shader = i;
found = true;
break;
}
i++;
}
if(!found)
fprintf(stderr, "Unknown shader \"%s\".\n", shadername.c_str());
}
xml_read_float(&state.dicing_rate, node, "dicing_rate");
/* read smooth/flat */
if(xml_equal_string(node, "interpolation", "smooth"))
state.smooth = true;
else if(xml_equal_string(node, "interpolation", "flat"))
state.smooth = false;
/* read displacement method */
if(xml_equal_string(node, "displacement_method", "true"))
state.displacement_method = Mesh::DISPLACE_TRUE;
else if(xml_equal_string(node, "displacement_method", "bump"))
state.displacement_method = Mesh::DISPLACE_BUMP;
else if(xml_equal_string(node, "displacement_method", "both"))
state.displacement_method = Mesh::DISPLACE_BOTH;
}
/* Scene */
static void xml_read_include(const XMLReadState& state, const string& src);
static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
{
for(pugi::xml_node node = scene_node.first_child(); node; node = node.next_sibling()) {
if(string_iequals(node.name(), "film")) {
xml_read_film(state, node);
}
else if(string_iequals(node.name(), "integrator")) {
xml_read_integrator(state, node);
}
else if(string_iequals(node.name(), "camera")) {
xml_read_camera(state, node);
}
else if(string_iequals(node.name(), "shader")) {
xml_read_shader(state, node);
}
else if(string_iequals(node.name(), "background")) {
xml_read_background(state, node);
}
else if(string_iequals(node.name(), "mesh")) {
xml_read_mesh(state, node);
}
else if(string_iequals(node.name(), "patch")) {
xml_read_patch(state, node);
}
else if(string_iequals(node.name(), "light")) {
xml_read_light(state, node);
}
else if(string_iequals(node.name(), "transform")) {
XMLReadState substate = state;
xml_read_transform(node, substate.tfm);
xml_read_scene(substate, node);
}
else if(string_iequals(node.name(), "state")) {
XMLReadState substate = state;
xml_read_state(substate, node);
xml_read_scene(substate, node);
}
else if(string_iequals(node.name(), "include")) {
string src;
if(xml_read_string(&src, node, "src"))
xml_read_include(state, src);
}
else
fprintf(stderr, "Unknown node \"%s\".\n", node.name());
}
}
/* Include */
static void xml_read_include(const XMLReadState& state, const string& src)
{
/* open XML document */
pugi::xml_document doc;
pugi::xml_parse_result parse_result;
string path = path_join(state.base, src);
parse_result = doc.load_file(path.c_str());
if(parse_result) {
XMLReadState substate = state;
substate.base = path_dirname(path);
xml_read_scene(substate, doc);
}
else
fprintf(stderr, "%s read error: %s\n", src.c_str(), parse_result.description());
}
/* File */
void xml_read_file(Scene *scene, const char *filepath)
{
XMLReadState state;
state.scene = scene;
state.tfm = transform_identity();
state.shader = scene->default_surface;
state.smooth = false;
state.dicing_rate = 0.1f;
state.base = path_dirname(filepath);
xml_read_include(state, path_filename(filepath));
scene->params.bvh_type = SceneParams::BVH_STATIC;
}
CCL_NAMESPACE_END

@ -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__ */

@ -0,0 +1,47 @@
set(INC
../render
../device
../kernel
../kernel/svm
../util
../subd
)
set(INC_SYS
${BLENDER_INCLUDE_DIRS}
${PYTHON_INCLUDE_DIRS}
${GLEW_INCLUDE_PATH}
)
set(SRC
blender_camera.cpp
blender_mesh.cpp
blender_object.cpp
blender_python.cpp
blender_session.cpp
blender_shader.cpp
blender_sync.cpp
blender_sync.h
blender_session.h
blender_util.h
)
set(ADDON_FILES
addon/__init__.py
addon/engine.py
addon/enums.py
addon/presets.py
addon/properties.py
addon/ui.py
addon/xml.py
)
blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}")
add_dependencies(bf_intern_cycles bf_rna)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${ADDON_FILES}" ${CYCLES_INSTALL_PATH})

@ -0,0 +1,95 @@
#
# 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.
#
# <pep8 compliant>
bl_info = {
"name": "Cycles Render Engine",
"author": "",
"version": (0, 0),
"blender": (2, 6, 0),
"api": 41670,
"location": "Info header, render engine menu",
"description": "Cycles Render Engine integration.",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Dev:2.6/Source/Render/Cycles",
"tracker_url": "",
"support": 'OFFICIAL',
"category": "Render"}
import bpy
from cycles import ui
from cycles import properties
from cycles import xml
from cycles import engine
from cycles import presets
class CyclesRender(bpy.types.RenderEngine):
bl_idname = 'CYCLES'
bl_label = "Cycles"
bl_use_shading_nodes = True
def __init__(self):
engine.init()
self.session = None
def __del__(self):
engine.free(self)
# final render
def update(self, data, scene):
engine.create(self, data, scene)
engine.update(self, data, scene)
def render(self, scene):
engine.render(self)
# preview render
# def preview_update(self, context, id):
# pass
#
# def preview_render(self):
# pass
# viewport render
def view_update(self, context):
if not self.session:
engine.create(self, context.blend_data, context.scene,
context.region, context.space_data, context.region_data)
engine.update(self, context.blend_data, context.scene)
def view_draw(self, context):
engine.draw(self, context.region, context.space_data, context.region_data)
def register():
properties.register()
ui.register()
xml.register()
presets.register()
bpy.utils.register_module(__name__)
def unregister():
xml.unregister()
ui.unregister()
properties.unregister()
presets.unregister()
bpy.utils.unregister_module(__name__)

@ -0,0 +1,88 @@
#
# 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.
#
# <pep8 compliant>
import bpy
def init():
import bcycles
import os.path
path = os.path.dirname(__file__)
user_path = os.path.dirname(os.path.abspath(bpy.utils.user_resource('CONFIG', '')))
bcycles.init(path, user_path)
def create(engine, data, scene, region=0, v3d=0, rv3d=0):
import bcycles
data = data.as_pointer()
scene = scene.as_pointer()
if region:
region = region.as_pointer()
if v3d:
v3d = v3d.as_pointer()
if rv3d:
rv3d = rv3d.as_pointer()
engine.session = bcycles.create(engine.as_pointer(), data, scene, region, v3d, rv3d)
def free(engine):
if hasattr(engine, "session"):
if engine.session:
import bcycles
bcycles.free(engine.session)
del engine.session
def render(engine):
import bcycles
if "session" in dir(engine):
bcycles.render(engine.session)
def update(engine, data, scene):
import bcycles
if scene.render.use_border:
engine.report({'ERROR'}, "Border rendering not supported yet")
free(engine)
else:
bcycles.sync(engine.session)
def draw(engine, region, v3d, rv3d):
import bcycles
v3d = v3d.as_pointer()
rv3d = rv3d.as_pointer()
# draw render image
bcycles.draw(engine.session, v3d, rv3d)
def available_devices():
import bcycles
return bcycles.available_devices()
def with_osl():
import bcycles
return bcycles.with_osl()

@ -0,0 +1,66 @@
#
# 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.
#
# <pep8 compliant>
from cycles import engine
def get_gpu_device():
available_devices = engine.available_devices()
cuda = 'cuda' in available_devices
opencl = 'opencl' in available_devices
if cuda and opencl:
gpu_string = "GPU"
elif cuda and not opencl:
gpu_string = "CUDA GPU"
else:
gpu_string = "OpenCL GPU"
return gpu_string
devices = (
("CPU", "CPU", "Processor"),
("GPU", get_gpu_device(), "Graphics card"),
)
gpu_type = (
("CUDA", "CUDA", "NVidia only"),
("OPENCL", "OpenCL (incomplete)", ""),
)
shading_systems = (
("GPU_COMPATIBLE", "GPU Compatible", "Restricted shading system compatible with GPU rendering"),
("OSL", "Open Shading Language", "Open Shading Language shading system that only runs on the CPU"),
)
displacement_methods = (
("BUMP", "Bump", "Bump mapping to simulate the appearance of displacement"),
("TRUE", "True", "Use true displacement only, requires fine subdivision"),
("BOTH", "Both", "Combination of displacement and bump mapping"),
)
bvh_types = (
("DYNAMIC_BVH", "Dynamic BVH", "Objects can be individually updated, at the cost of slower render time"),
("STATIC_BVH", "Static BVH", "Any object modification requires a complete BVH rebuild, but renders faster"),
)
filter_types = (
("BOX", "Box", "Box filter"),
("GAUSSIAN", "Gaussian", "Gaussian filter"),
)

@ -0,0 +1,57 @@
#
# 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.
#
# <pep8 compliant>
from bl_operators.presets import AddPresetBase
from bpy.types import Operator
class AddPresetIntegrator(AddPresetBase, Operator):
'''Add an Integrator Preset'''
bl_idname = "render.cycles_integrator_preset_add"
bl_label = "Add Integrator Preset"
preset_menu = "CYCLES_MT_integrator_presets"
preset_defines = [
"cycles = bpy.context.scene.cycles"
]
preset_values = [
"cycles.max_bounces",
"cycles.min_bounces",
"cycles.no_caustics",
"cycles.diffuse_bounces",
"cycles.glossy_bounces",
"cycles.transmission_bounces",
"cycles.transparent_min_bounces",
"cycles.transparent_max_bounces"
]
preset_subdir = "cycles/integrator"
def register():
pass
def unregister():
pass
if __name__ == "__main__":
register()

@ -0,0 +1,211 @@
#
# 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.
#
# <pep8 compliant>
import bpy
from bpy.props import *
import math
from cycles import enums
class CyclesRenderSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
bpy.types.Scene.cycles = PointerProperty(type=cls, name="Cycles Render Settings", description="Cycles render settings")
cls.device = EnumProperty(name="Device", description="Device to use for rendering",
items=enums.devices, default="CPU")
cls.gpu_type = EnumProperty(name="GPU Type", description="Processing system to use on the GPU",
items=enums.gpu_type, default="CUDA")
cls.shading_system = EnumProperty(name="Shading System", description="Shading system to use for rendering",
items=enums.shading_systems, default="GPU_COMPATIBLE")
cls.samples = IntProperty(name="Samples", description="Number of samples to render for each pixel",
default=10, min=1, max=2147483647)
cls.preview_samples = IntProperty(name="Preview Samples", description="Number of samples to render in the viewport, unlimited if 0",
default=10, min=0, max=2147483647)
cls.preview_pause = BoolProperty(name="Pause Preview", description="Pause all viewport preview renders",
default=False)
cls.no_caustics = BoolProperty(name="No Caustics", description="Leave out caustics, resulting in a darker image with less noise",
default=False)
cls.blur_caustics = FloatProperty(name="Blur Caustics", description="Blur caustics to reduce noise",
default=0.0, min=0.0, max=1.0)
cls.min_bounces = IntProperty(name="Min Bounces", description="Minimum number of bounces, setting this lower than the maximum enables probalistic path termination (faster but noisier)",
default=3, min=0, max=1024)
cls.max_bounces = IntProperty(name="Max Bounces", description="Total maximum number of bounces",
default=8, min=0, max=1024)
cls.diffuse_bounces = IntProperty(name="Diffuse Bounces", description="Maximum number of diffuse reflection bounces, bounded by total maximum",
default=128, min=0, max=1024)
cls.glossy_bounces = IntProperty(name="Glossy Bounces", description="Maximum number of glossy reflection bounces, bounded by total maximum",
default=128, min=0, max=1024)
cls.transmission_bounces = IntProperty(name="Transmission Bounces", description="Maximum number of transmission bounces, bounded by total maximum",
default=128, min=0, max=1024)
cls.transparent_min_bounces = IntProperty(name="Transparent Min Bounces", description="Minimum number of transparent bounces, setting this lower than the maximum enables probalistic path termination (faster but noisier)",
default=8, min=0, max=1024)
cls.transparent_max_bounces = IntProperty(name="Transparent Max Bounces", description="Maximum number of transparent bounces",
default=8, min=0, max=1024)
cls.use_transparent_shadows = BoolProperty(name="Transparent Shadows", description="Use transparency of surfaces for rendering shadows",
default=True)
cls.film_exposure = FloatProperty(name="Exposure", description="Image brightness scale",
default=1.0, min=0.0, max=10.0)
cls.film_transparent = BoolProperty(name="Transparent", description="World background is transparent",
default=False)
cls.filter_type = EnumProperty(name="Filter Type", description="Pixel filter type",
items=enums.filter_types, default="GAUSSIAN")
cls.filter_width = FloatProperty(name="Filter Width", description="Pixel filter width",
default=1.5, min=0.01, max=10.0)
cls.seed = IntProperty(name="Seed", description="Seed value for integrator to get different noise patterns",
default=0, min=0, max=2147483647)
cls.debug_tile_size = IntProperty(name="Tile Size", description="",
default=1024, min=1, max=4096)
cls.debug_min_size = IntProperty(name="Min Size", description="",
default=64, min=1, max=4096)
cls.debug_reset_timeout = FloatProperty(name="Reset timeout", description="",
default=0.1, min=0.01, max=10.0)
cls.debug_cancel_timeout = FloatProperty(name="Cancel timeout", description="",
default=0.1, min=0.01, max=10.0)
cls.debug_text_timeout = FloatProperty(name="Text timeout", description="",
default=1.0, min=0.01, max=10.0)
cls.debug_bvh_type = EnumProperty(name="Viewport BVH Type", description="Choose between faster updates, or faster render",
items=enums.bvh_types, default="DYNAMIC_BVH")
cls.debug_use_spatial_splits = BoolProperty(name="Use Spatial Splits", description="Use BVH spatial splits: longer builder time, faster render",
default=False)
@classmethod
def unregister(cls):
del bpy.types.Scene.cycles
class CyclesCameraSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
bpy.types.Camera.cycles = PointerProperty(type=cls, name="Cycles Camera Settings", description="Cycles camera settings")
cls.aperture_size = FloatProperty(name="Aperture Size", description="Radius of the aperture for depth of field",
default=0.0, min=0.0, max=10.0)
cls.aperture_blades = IntProperty(name="Aperture Blades", description="Number of blades in aperture for polygonal bokeh (at least 3)",
default=0, min=0, max=100)
cls.aperture_rotation = FloatProperty(name="Aperture Rotation", description="Rotation of blades in aperture",
default=0, soft_min=-math.pi, soft_max=math.pi, subtype='ANGLE')
@classmethod
def unregister(cls):
del bpy.types.Camera.cycles
class CyclesMaterialSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
bpy.types.Material.cycles = PointerProperty(type=cls, name="Cycles Material Settings", description="Cycles material settings")
cls.sample_as_light = BoolProperty(name="Sample as Lamp", description="Use direct light sampling for this material, disabling may reduce overall noise for large objects that emit little light compared to other light sources", default=True)
cls.homogeneous_volume = BoolProperty(name="Homogeneous Volume", description="When using volume rendering, assume volume has the same density everywhere, for faster rendering", default=False)
@classmethod
def unregister(cls):
del bpy.types.Material.cycles
class CyclesLampSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
bpy.types.Lamp.cycles = PointerProperty(type=cls, name="Cycles Lamp Settings", description="Cycles lamp settings")
cls.cast_shadow = BoolProperty(name="Cast Shadow", description="Lamp casts shadows", default=True)
@classmethod
def unregister(cls):
del bpy.types.Lamp.cycles
class CyclesWorldSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
bpy.types.World.cycles = PointerProperty(type=cls, name="Cycles World Settings", description="Cycles world settings")
@classmethod
def unregister(cls):
del bpy.types.World.cycles
class CyclesVisibilitySettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
bpy.types.Object.cycles_visibility = PointerProperty(type=cls, name="Cycles Visibility Settings", description="Cycles visibility settings")
cls.camera = BoolProperty(name="Camera", description="Object visibility for camera rays", default=True)
cls.diffuse = BoolProperty(name="Diffuse", description="Object visibility for diffuse reflection rays", default=True)
cls.glossy = BoolProperty(name="Glossy", description="Object visibility for glossy reflection rays", default=True)
cls.transmission = BoolProperty(name="Transmission", description="Object visibility for transmission rays", default=True)
cls.shadow = BoolProperty(name="Shadow", description="Object visibility for shadow rays", default=True)
@classmethod
def unregister(cls):
del bpy.types.Object.cycles_visibility
class CyclesMeshSettings(bpy.types.PropertyGroup):
@classmethod
def register(cls):
bpy.types.Mesh.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
bpy.types.Curve.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
bpy.types.MetaBall.cycles = PointerProperty(type=cls, name="Cycles Mesh Settings", description="Cycles mesh settings")
cls.displacement_method = EnumProperty(name="Displacement Method", description="Method to use for the displacement",
items=enums.displacement_methods, default="BUMP")
cls.use_subdivision = BoolProperty(name="Use Subdivision", description="Subdivide mesh for rendering",
default=False)
cls.dicing_rate = FloatProperty(name="Dicing Rate", description="", default=1.0, min=0.001, max=1000.0)
@classmethod
def unregister(cls):
del bpy.types.Mesh.cycles
del bpy.types.Curve.cycles
del bpy.types.MetaBall.cycles
def register():
bpy.utils.register_class(CyclesRenderSettings)
bpy.utils.register_class(CyclesCameraSettings)
bpy.utils.register_class(CyclesMaterialSettings)
bpy.utils.register_class(CyclesLampSettings)
bpy.utils.register_class(CyclesWorldSettings)
bpy.utils.register_class(CyclesVisibilitySettings)
bpy.utils.register_class(CyclesMeshSettings)
def unregister():
bpy.utils.unregister_class(CyclesRenderSettings)
bpy.utils.unregister_class(CyclesCameraSettings)
bpy.utils.unregister_class(CyclesMaterialSettings)
bpy.utils.unregister_class(CyclesLampSettings)
bpy.utils.unregister_class(CyclesWorldSettings)
bpy.utils.unregister_class(CyclesMeshSettings)
bpy.utils.unregister_class(CyclesVisibilitySettings)

@ -0,0 +1,801 @@
#
# 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.
#
# <pep8 compliant>
import bpy
from bpy.types import Panel, Menu
from cycles import enums
from cycles import engine
class CYCLES_MT_integrator_presets(Menu):
bl_label = "Integrator Presets"
preset_subdir = "cycles/integrator"
preset_operator = "script.execute_preset"
COMPAT_ENGINES = {'CYCLES'}
draw = Menu.draw_preset
class CyclesButtonsPanel():
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
@classmethod
def poll(cls, context):
rd = context.scene.render
return rd.engine == 'CYCLES'
class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
bl_label = "Integrator"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
scene = context.scene
cscene = scene.cycles
row = layout.row(align=True)
row.menu("CYCLES_MT_integrator_presets", text=bpy.types.CYCLES_MT_integrator_presets.bl_label)
row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMIN")
row.operator("render.cycles_integrator_preset_add", text="", icon="ZOOMOUT").remove_active = True
split = layout.split()
col = split.column()
sub = col.column(align=True)
sub.label(text="Samples:")
sub.prop(cscene, "samples", text="Render")
sub.prop(cscene, "preview_samples", text="Preview")
sub.prop(cscene, "seed")
sub = col.column(align=True)
sub.label("Transparency:")
sub.prop(cscene, "transparent_max_bounces", text="Max")
sub.prop(cscene, "transparent_min_bounces", text="Min")
sub.prop(cscene, "use_transparent_shadows", text="Shadows")
col = split.column()
sub = col.column(align=True)
sub.label(text="Bounces:")
sub.prop(cscene, "max_bounces", text="Max")
sub.prop(cscene, "min_bounces", text="Min")
sub = col.column(align=True)
sub.label(text="Light Paths:")
sub.prop(cscene, "diffuse_bounces", text="Diffuse")
sub.prop(cscene, "glossy_bounces", text="Glossy")
sub.prop(cscene, "transmission_bounces", text="Transmission")
sub.prop(cscene, "no_caustics")
#row = col.row()
#row.prop(cscene, "blur_caustics")
#row.active = not cscene.no_caustics
class CyclesRender_PT_film(CyclesButtonsPanel, Panel):
bl_label = "Film"
def draw(self, context):
layout = self.layout
scene = context.scene
cscene = scene.cycles
split = layout.split()
col = split.column()
col.prop(cscene, "film_exposure")
col.prop(cscene, "film_transparent")
col = split.column()
sub = col.column(align=True)
sub.prop(cscene, "filter_type", text="")
if cscene.filter_type != 'BOX':
sub.prop(cscene, "filter_width", text="Width")
class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
bl_label = "Performance"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
scene = context.scene
rd = scene.render
cscene = scene.cycles
split = layout.split()
col = split.column(align=True)
col.label(text="Threads:")
col.row().prop(rd, "threads_mode", expand=True)
sub = col.column()
sub.enabled = rd.threads_mode == 'FIXED'
sub.prop(rd, "threads")
sub = col.column(align=True)
sub.label(text="Tiles:")
sub.prop(cscene, "debug_tile_size")
sub.prop(cscene, "debug_min_size")
col = split.column()
sub = col.column(align=True)
sub.label(text="Acceleration structure:")
sub.prop(cscene, "debug_bvh_type", text="")
sub.prop(cscene, "debug_use_spatial_splits")
class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
bl_label = "Layers"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
scene = context.scene
rd = scene.render
# row = layout.row()
# row.template_list(rd, "layers", rd.layers, "active_index", rows=2)
# col = row.column(align=True)
# col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
# col.operator("scene.render_layer_remove", icon='ZOOMOUT', text="")
row = layout.row()
# rl = rd.layers.active
rl = rd.layers[0]
row.prop(rl, "name")
#row.prop(rd, "use_single_layer", text="", icon_only=True)
split = layout.split()
col = split.column()
col.prop(scene, "layers", text="Scene")
col = split.column()
col.prop(rl, "layers", text="Layer")
layout.separator()
layout.prop(rl, "material_override", text="Material")
class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
bl_label = "Post Processing"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
rd = context.scene.render
split = layout.split()
col = split.column()
col.prop(rd, "use_compositing")
col.prop(rd, "use_sequencer")
col = split.column()
col.prop(rd, "dither_intensity", text="Dither", slider=True)
class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel):
bl_label = "Depth of Field"
bl_context = "data"
@classmethod
def poll(cls, context):
return context.camera and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
cam = context.camera
ccam = cam.cycles
split = layout.split()
col = split.column()
col.label("Focus:")
col.prop(cam, "dof_object", text="")
sub = col.row()
sub.active = cam.dof_object is None
sub.prop(cam, "dof_distance", text="Distance")
col = split.column()
col.label("Aperture:")
col.prop(ccam, "aperture_size", text="Size")
sub = col.column(align=True)
sub.prop(ccam, "aperture_blades", text="Blades")
sub.prop(ccam, "aperture_rotation", text="Rotation")
class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
bl_label = "Surface"
bl_context = "material"
bl_options = {'HIDE_HEADER'}
@classmethod
def poll(cls, context):
return (context.material or context.object) and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
mat = context.material
ob = context.object
slot = context.material_slot
space = context.space_data
if ob:
row = layout.row()
row.template_list(ob, "material_slots", ob, "active_material_index", rows=2)
col = row.column(align=True)
col.operator("object.material_slot_add", icon='ZOOMIN', text="")
col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
if ob.mode == 'EDIT':
row = layout.row(align=True)
row.operator("object.material_slot_assign", text="Assign")
row.operator("object.material_slot_select", text="Select")
row.operator("object.material_slot_deselect", text="Deselect")
split = layout.split(percentage=0.65)
if ob:
split.template_ID(ob, "active_material", new="material.new")
row = split.row()
if slot:
row.prop(slot, "link", text="")
else:
row.label()
elif mat:
split.template_ID(space, "pin_id")
split.separator()
class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
bl_label = "Displacement"
bl_context = "data"
@classmethod
def poll(cls, context):
return CyclesButtonsPanel.poll(context) and context.mesh or context.curve or context.meta_ball
def draw(self, context):
layout = self.layout
mesh = context.mesh
curve = context.curve
mball = context.meta_ball
if mesh:
cdata = mesh.cycles
elif curve:
cdata = curve.cycles
elif mball:
cdata = mball.cycles
layout.prop(cdata, "displacement_method", text="Method")
layout.prop(cdata, "use_subdivision")
layout.prop(cdata, "dicing_rate")
class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
bl_label = "Ray Visibility"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ob = context.object
return CyclesButtonsPanel.poll(context) and ob and ob.type in ('MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META') # todo: 'LAMP'
def draw(self, context):
layout = self.layout
ob = context.object
visibility = ob.cycles_visibility
split = layout.split()
col = split.column()
col.prop(visibility, "camera")
col.prop(visibility, "diffuse")
col.prop(visibility, "glossy")
col = split.column()
col.prop(visibility, "transmission")
col.prop(visibility, "shadow")
def find_node(material, nodetype):
if material and material.node_tree:
ntree = material.node_tree
for node in ntree.nodes:
if hasattr(node, 'type') and node.type == nodetype:
return node
return None
def find_node_input(node, name):
for input in node.inputs:
if input.name == name:
return input
return None
def panel_node_draw(layout, id, output_type, input_name):
if not id.node_tree:
layout.prop(id, "use_nodes", icon='NODETREE')
return False
ntree = id.node_tree
node = find_node(id, output_type)
if not node:
layout.label(text="No output node.")
else:
input = find_node_input(node, input_name)
layout.template_node_view(ntree, node, input)
return True
class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
bl_label = "Lamp"
bl_context = "data"
@classmethod
def poll(cls, context):
return context.lamp and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
lamp = context.lamp
clamp = lamp.cycles
layout.prop(lamp, "type", expand=True)
split = layout.split()
col = split.column(align=True)
if lamp.type in ('POINT', 'SUN', 'SPOT'):
col.prop(lamp, "shadow_soft_size", text="Size")
elif lamp.type == 'AREA':
col.prop(lamp, "shape", text="")
sub = col.column(align=True)
if lamp.shape == 'SQUARE':
sub.prop(lamp, "size")
elif lamp.shape == 'RECTANGLE':
sub.prop(lamp, "size", text="Size X")
sub.prop(lamp, "size_y", text="Size Y")
col = split.column()
col.prop(clamp, "cast_shadow")
if lamp.type == 'SPOT':
layout.label(text="Not supported, interpreted as point lamp.")
elif lamp.type == 'HEMI':
layout.label(text="Not supported, interpreted as sun lamp.")
class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel):
bl_label = "Nodes"
bl_context = "data"
@classmethod
def poll(cls, context):
return context.lamp and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
lamp = context.lamp
if not panel_node_draw(layout, lamp, 'OUTPUT_LAMP', 'Surface'):
layout.prop(lamp, "color")
class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel):
bl_label = "Surface"
bl_context = "world"
@classmethod
def poll(cls, context):
return context.world and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
world = context.world
if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'):
layout.prop(world, "horizon_color", text="Color")
class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel):
bl_label = "Volume"
bl_context = "world"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
world = context.world
return False # world and world.node_tree and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
layout.active = False
world = context.world
panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume')
class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel):
bl_label = "Surface"
bl_context = "material"
@classmethod
def poll(cls, context):
return context.material and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
mat = context.material
if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'):
layout.prop(mat, "diffuse_color")
class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel):
bl_label = "Volume"
bl_context = "material"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
mat = context.material
return False # mat and mat.node_tree and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
layout.active = False
mat = context.material
cmat = mat.cycles
panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
layout.prop(cmat, "homogeneous_volume")
class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel):
bl_label = "Displacement"
bl_context = "material"
@classmethod
def poll(cls, context):
mat = context.material
return mat and mat.node_tree and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
mat = context.material
panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
bl_label = "Settings"
bl_context = "material"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return context.material and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
mat = context.material
cmat = mat.cycles
split = layout.split()
col = split.column()
col.prop(mat, "diffuse_color", text="Viewport Color")
col = split.column()
col.prop(cmat, "sample_as_light")
class CyclesTexture_PT_context(CyclesButtonsPanel, Panel):
bl_label = ""
bl_context = "texture"
bl_options = {'HIDE_HEADER'}
COMPAT_ENGINES = {'CYCLES'}
def draw(self, context):
layout = self.layout
tex = context.texture
space = context.space_data
pin_id = space.pin_id
use_pin_id = space.use_pin_id
user = context.texture_user
node = context.texture_node
if not use_pin_id or not isinstance(pin_id, bpy.types.Texture):
pin_id = None
if not pin_id:
layout.template_texture_user()
if user:
layout.separator()
split = layout.split(percentage=0.65)
col = split.column()
if pin_id:
col.template_ID(space, "pin_id")
elif user:
col.template_ID(user, "texture", new="texture.new")
if tex:
row = split.row()
row.prop(tex, "use_nodes", icon="NODETREE", text="")
row.label()
if not tex.use_nodes:
split = layout.split(percentage=0.2)
split.label(text="Type:")
split.prop(tex, "type", text="")
class CyclesTexture_PT_nodes(CyclesButtonsPanel, Panel):
bl_label = "Nodes"
bl_context = "texture"
@classmethod
def poll(cls, context):
tex = context.texture
return (tex and tex.use_nodes) and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
tex = context.texture
panel_node_draw(layout, tex, 'OUTPUT_TEXTURE', 'Color')
class CyclesTexture_PT_node(CyclesButtonsPanel, Panel):
bl_label = "Node"
bl_context = "texture"
@classmethod
def poll(cls, context):
node = context.texture_node
return node and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
node = context.texture_node
ntree = node.id_data
layout.template_node_view(ntree, node, None)
class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel):
bl_label = "Mapping"
bl_context = "texture"
@classmethod
def poll(cls, context):
tex = context.texture
node = context.texture_node
return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
tex = context.texture
node = context.texture_node
mapping = node.texture_mapping
row = layout.row()
row.column().prop(mapping, "location")
row.column().prop(mapping, "rotation")
row.column().prop(mapping, "scale")
layout.label(text="Projection:")
row = layout.row()
row.prop(mapping, "mapping_x", text="")
row.prop(mapping, "mapping_y", text="")
row.prop(mapping, "mapping_z", text="")
class CyclesTexture_PT_colors(CyclesButtonsPanel, Panel):
bl_label = "Color"
bl_context = "texture"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
tex = context.texture
node = context.texture_node
return False
#return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout
tex = context.texture
node = context.texture_node
mapping = node.color_mapping
split = layout.split()
col = split.column()
col.label(text="Blend:")
col.prop(mapping, "blend_type", text="")
col.prop(mapping, "blend_factor", text="Factor")
col.prop(mapping, "blend_color", text="")
col = split.column()
col.label(text="Adjust:")
col.prop(mapping, "brightness")
col.prop(mapping, "contrast")
col.prop(mapping, "saturation")
layout.separator()
layout.prop(mapping, "use_color_ramp", text="Ramp")
if mapping.use_color_ramp:
layout.template_color_ramp(mapping, "color_ramp", expand=True)
def draw_device(self, context):
scene = context.scene
layout = self.layout
if scene.render.engine == "CYCLES":
cscene = scene.cycles
available_devices = engine.available_devices()
available_cuda = 'cuda' in available_devices
available_opencl = 'opencl' in available_devices
if available_cuda or available_opencl:
layout.prop(cscene, "device")
if cscene.device == 'GPU' and available_cuda and available_opencl:
layout.prop(cscene, "gpu_type")
if cscene.device == 'CPU' and engine.with_osl():
layout.prop(cscene, "shading_system")
def draw_pause(self, context):
layout = self.layout
scene = context.scene
if scene.render.engine == "CYCLES":
view = context.space_data
if view.viewport_shade == "RENDERED":
cscene = scene.cycles
layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
def get_panels():
return [
bpy.types.RENDER_PT_render,
bpy.types.RENDER_PT_output,
bpy.types.RENDER_PT_encoding,
bpy.types.RENDER_PT_dimensions,
bpy.types.RENDER_PT_stamp,
bpy.types.WORLD_PT_context_world,
bpy.types.DATA_PT_context_mesh,
bpy.types.DATA_PT_context_camera,
bpy.types.DATA_PT_context_lamp,
bpy.types.DATA_PT_texture_space,
bpy.types.DATA_PT_curve_texture_space,
bpy.types.DATA_PT_mball_texture_space,
bpy.types.DATA_PT_vertex_groups,
bpy.types.DATA_PT_shape_keys,
bpy.types.DATA_PT_uv_texture,
bpy.types.DATA_PT_vertex_colors,
bpy.types.DATA_PT_camera,
bpy.types.DATA_PT_camera_display,
bpy.types.DATA_PT_lens,
bpy.types.DATA_PT_custom_props_mesh,
bpy.types.DATA_PT_custom_props_camera,
bpy.types.DATA_PT_custom_props_lamp,
bpy.types.TEXTURE_PT_clouds,
bpy.types.TEXTURE_PT_wood,
bpy.types.TEXTURE_PT_marble,
bpy.types.TEXTURE_PT_magic,
bpy.types.TEXTURE_PT_blend,
bpy.types.TEXTURE_PT_stucci,
bpy.types.TEXTURE_PT_image,
bpy.types.TEXTURE_PT_image_sampling,
bpy.types.TEXTURE_PT_image_mapping,
bpy.types.TEXTURE_PT_musgrave,
bpy.types.TEXTURE_PT_voronoi,
bpy.types.TEXTURE_PT_distortednoise,
bpy.types.TEXTURE_PT_voxeldata,
bpy.types.TEXTURE_PT_pointdensity,
bpy.types.TEXTURE_PT_pointdensity_turbulence,
bpy.types.PARTICLE_PT_context_particles,
bpy.types.PARTICLE_PT_emission,
bpy.types.PARTICLE_PT_hair_dynamics,
bpy.types.PARTICLE_PT_cache,
bpy.types.PARTICLE_PT_velocity,
bpy.types.PARTICLE_PT_rotation,
bpy.types.PARTICLE_PT_physics,
bpy.types.PARTICLE_PT_boidbrain,
bpy.types.PARTICLE_PT_render,
bpy.types.PARTICLE_PT_draw,
bpy.types.PARTICLE_PT_children,
bpy.types.PARTICLE_PT_field_weights,
bpy.types.PARTICLE_PT_force_fields,
bpy.types.PARTICLE_PT_vertexgroups,
bpy.types.PARTICLE_PT_custom_props]
def register():
bpy.types.RENDER_PT_render.append(draw_device)
bpy.types.VIEW3D_HT_header.append(draw_pause)
for panel in get_panels():
panel.COMPAT_ENGINES.add('CYCLES')
def unregister():
bpy.types.RENDER_PT_render.remove(draw_device)
bpy.types.VIEW3D_HT_header.remove(draw_pause)
for panel in get_panels():
panel.COMPAT_ENGINES.remove('CYCLES')

@ -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.
#
# <pep8 compliant>
# XML exporter for generating test files, not intended for end users
import os
import bpy
from bpy_extras.io_utils import ExportHelper
import xml.etree.ElementTree as etree
import xml.dom.minidom as dom
def strip(root):
root.text = None
root.tail = None
for elem in root:
strip(elem)
def write(node, fname):
strip(node)
s = etree.tostring(node)
s = dom.parseString(s).toprettyxml()
f = open(fname, "w")
f.write(s)
class ExportCyclesXML(bpy.types.Operator, ExportHelper):
''''''
bl_idname = "export_mesh.cycles_xml"
bl_label = "Export Cycles XML"
filename_ext = ".xml"
@classmethod
def poll(cls, context):
return context.active_object != None
def execute(self, context):
filepath = bpy.path.ensure_ext(self.filepath, ".xml")
# get mesh
scene = context.scene
object = context.object
if not object:
raise Exception("No active object")
mesh = object.to_mesh(scene, True, 'PREVIEW')
if not mesh:
raise Exception("No mesh data in active object")
# generate mesh node
nverts = ""
verts = ""
P = ""
for v in mesh.vertices:
P += "%f %f %f " % (v.co[0], v.co[1], v.co[2])
for i, f in enumerate(mesh.faces):
nverts += str(len(f.vertices)) + " "
for v in f.vertices:
verts += str(v) + " "
verts += " "
node = etree.Element('mesh', attrib={'nverts': nverts, 'verts': verts, 'P': P})
# write to file
write(node, filepath)
return {'FINISHED'}
def register():
pass
def unregister():
pass
if __name__ == "__main__":
register()

@ -0,0 +1,290 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "camera.h"
#include "scene.h"
#include "blender_sync.h"
#include "blender_util.h"
CCL_NAMESPACE_BEGIN
/* Blender Camera Intermediate: we first convert both the offline and 3d view
* render camera to this, and from there convert to our native camera format. */
struct BlenderCamera {
float nearclip;
float farclip;
bool ortho;
float ortho_scale;
float lens;
float aperturesize;
uint apertureblades;
float aperturerotation;
float focaldistance;
float2 shift;
float2 offset;
float zoom;
float2 pixelaspect;
enum { AUTO, HORIZONTAL, VERTICAL } sensor_fit;
float sensor_width;
float sensor_height;
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);
bcam->sensor_width = 32.0f;
bcam->sensor_height = 18.0f;
bcam->sensor_fit = BlenderCamera::AUTO;
}
static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera)
{
BL::Object b_dof_object = b_camera.dof_object();
if(!b_dof_object)
return b_camera.dof_distance();
/* for dof object, return distance along camera direction. this is
* compatible with blender, but does it fit our dof model? */
Transform obmat = get_transform(b_ob.matrix_world());
Transform dofmat = get_transform(b_dof_object.matrix_world());
float3 cam_p = transform_get_column(&obmat, 3);
float3 cam_dir = normalize(transform_get_column(&obmat, 2));
float3 dof_p = transform_get_column(&dofmat, 3);
float3 proj_p = dot(dof_p, cam_dir) * cam_dir;
return len(proj_p - cam_p);
}
static void blender_camera_from_object(BlenderCamera *bcam, BL::Object b_ob)
{
BL::ID b_ob_data = b_ob.data();
if(b_ob_data.is_a(&RNA_Camera)) {
BL::Camera b_camera(b_ob_data);
PointerRNA ccamera = RNA_pointer_get(&b_camera.ptr, "cycles");
bcam->nearclip = b_camera.clip_start();
bcam->farclip = b_camera.clip_end();
bcam->ortho = (b_camera.type() == BL::Camera::type_ORTHO);
bcam->ortho_scale = b_camera.ortho_scale();
bcam->lens = b_camera.lens();
bcam->aperturesize = RNA_float_get(&ccamera, "aperture_size");
bcam->apertureblades = RNA_int_get(&ccamera, "aperture_blades");
bcam->aperturerotation = RNA_float_get(&ccamera, "aperture_rotation");
bcam->focaldistance = blender_camera_focal_distance(b_ob, b_camera);
bcam->shift.x = b_camera.shift_x();
bcam->shift.y = b_camera.shift_y();
bcam->sensor_width = b_camera.sensor_width();
bcam->sensor_height = b_camera.sensor_height();
if(b_camera.sensor_fit() == BL::Camera::sensor_fit_AUTO)
bcam->sensor_fit = BlenderCamera::AUTO;
else if(b_camera.sensor_fit() == BL::Camera::sensor_fit_HORIZONTAL)
bcam->sensor_fit = BlenderCamera::HORIZONTAL;
else
bcam->sensor_fit = BlenderCamera::VERTICAL;
}
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;
/* sensor fitting */
bool horizontal_fit;
float sensor_size;
if(bcam->sensor_fit == BlenderCamera::AUTO) {
horizontal_fit = (xratio > yratio);
sensor_size = bcam->sensor_width;
}
else if(bcam->sensor_fit == BlenderCamera::HORIZONTAL) {
horizontal_fit = true;
sensor_size = bcam->sensor_width;
}
else {
horizontal_fit = false;
sensor_size = bcam->sensor_height;
}
if(horizontal_fit) {
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((0.5f*sensor_size)/bcam->lens/aspectratio);
cam->focaldistance = bcam->focaldistance;
cam->aperturesize = bcam->aperturesize;
cam->blades = bcam->apertureblades;
cam->bladesrotation = bcam->aperturerotation;
/* transform, note the blender camera points along the negative z-axis */
cam->matrix = bcam->matrix * transform_scale(1.0f, 1.0f, -1.0f);
/* set update flag */
if(cam->modified(prevcam))
cam->tag_update();
}
/* Sync Render Camera */
void BlenderSync::sync_camera(int width, int height)
{
BlenderCamera bcam;
blender_camera_init(&bcam);
/* pixel aspect */
BL::RenderSettings r = b_scene.render();
bcam.pixelaspect.x = r.pixel_aspect_x();
bcam.pixelaspect.y = r.pixel_aspect_y();
/* camera object */
BL::Object b_ob = b_scene.camera();
if(b_ob) {
blender_camera_from_object(&bcam, b_ob);
bcam.matrix = get_transform(b_ob.matrix_world());
}
/* sync */
Camera *cam = scene->camera;
blender_camera_sync(cam, &bcam, width, height);
}
/* Sync 3D View Camera */
void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height)
{
BlenderCamera bcam;
blender_camera_init(&bcam);
/* 3d view parameters */
bcam.nearclip = b_v3d.clip_start();
bcam.farclip = b_v3d.clip_end();
bcam.lens = b_v3d.lens();
if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_CAMERA) {
/* camera view */
BL::Object b_ob = b_scene.camera();
if(b_ob) {
blender_camera_from_object(&bcam, b_ob);
/* magic zoom formula */
bcam.zoom = (float)b_rv3d.view_camera_zoom();
bcam.zoom = (1.41421f + bcam.zoom/50.0f);
bcam.zoom *= bcam.zoom;
bcam.zoom = 2.0f/bcam.zoom;
/* offset */
bcam.offset = get_float2(b_rv3d.view_camera_offset());
}
}
else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) {
/* orthographic view */
bcam.farclip *= 0.5;
bcam.nearclip = -bcam.farclip;
bcam.ortho = true;
bcam.ortho_scale = b_rv3d.view_distance();
}
bcam.zoom *= 2.0f;
/* 3d view transform */
bcam.matrix = transform_inverse(get_transform(b_rv3d.view_matrix()));
/* sync */
blender_camera_sync(scene->camera, &bcam, width, height);
}
CCL_NAMESPACE_END

@ -0,0 +1,321 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mesh.h"
#include "object.h"
#include "scene.h"
#include "blender_sync.h"
#include "blender_util.h"
#include "subd_mesh.h"
#include "subd_patch.h"
#include "subd_split.h"
#include "util_foreach.h"
CCL_NAMESPACE_BEGIN
/* Find/Add */
static bool mesh_need_attribute(Scene *scene, Mesh *mesh, Attribute::Standard std)
{
if(std == Attribute::STD_NONE)
return false;
foreach(uint shader, mesh->used_shaders)
if(scene->shaders[shader]->attributes.find(std))
return true;
return false;
}
static bool mesh_need_attribute(Scene *scene, Mesh *mesh, ustring name)
{
if(name == ustring())
return false;
foreach(uint shader, mesh->used_shaders)
if(scene->shaders[shader]->attributes.find(name))
return true;
return false;
}
static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
{
/* create vertices */
BL::Mesh::vertices_iterator v;
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
mesh->verts.push_back(get_float3(v->co()));
/* create vertex normals */
Attribute *attr_N = mesh->attributes.add(Attribute::STD_VERTEX_NORMAL);
float3 *N = attr_N->data_float3();
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v, ++N)
*N= get_float3(v->normal());
/* create faces */
BL::Mesh::faces_iterator f;
vector<int> nverts;
for(b_mesh.faces.begin(f); f != b_mesh.faces.end(); ++f) {
int4 vi = get_int4(f->vertices_raw());
int n= (vi[3] == 0)? 3: 4;
int shader = used_shaders[f->material_index()];
bool smooth = f->use_smooth();
mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth);
if(n == 4)
mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth);
nverts.push_back(n);
}
/* create generated coordinates. todo: we should actually get the orco
coordinates from modifiers, for now we use texspace loc/size which
is available in the api. */
if(mesh_need_attribute(scene, mesh, Attribute::STD_GENERATED)) {
Attribute *attr = mesh->attributes.add(Attribute::STD_GENERATED);
float3 loc = get_float3(b_mesh.texspace_location());
float3 size = get_float3(b_mesh.texspace_size());
if(size.x != 0.0f) size.x = 0.5f/size.x;
if(size.y != 0.0f) size.y = 0.5f/size.y;
if(size.z != 0.0f) size.z = 0.5f/size.z;
loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
float3 *fdata = attr->data_float3();
BL::Mesh::vertices_iterator v;
size_t i = 0;
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
fdata[i++] = get_float3(v->co())*size - loc;
}
/* create vertex color attributes */
{
BL::Mesh::vertex_colors_iterator l;
for(b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l) {
if(!mesh_need_attribute(scene, mesh, ustring(l->name().c_str())))
continue;
Attribute *attr = mesh->attributes.add(
ustring(l->name().c_str()), TypeDesc::TypeColor, Attribute::CORNER);
BL::MeshColorLayer::data_iterator c;
float3 *fdata = attr->data_float3();
size_t i = 0;
for(l->data.begin(c); c != l->data.end(); ++c, ++i) {
fdata[0] = color_srgb_to_scene_linear(get_float3(c->color1()));
fdata[1] = color_srgb_to_scene_linear(get_float3(c->color2()));
fdata[2] = color_srgb_to_scene_linear(get_float3(c->color3()));
if(nverts[i] == 4) {
fdata[3] = fdata[0];
fdata[4] = fdata[2];
fdata[5] = color_srgb_to_scene_linear(get_float3(c->color4()));
fdata += 6;
}
else
fdata += 3;
}
}
}
/* create uv layer attributes */
{
BL::Mesh::uv_textures_iterator l;
for(b_mesh.uv_textures.begin(l); l != b_mesh.uv_textures.end(); ++l) {
Attribute::Standard std = (l->active_render())? Attribute::STD_UV: Attribute::STD_NONE;
ustring name = ustring(l->name().c_str());
if(!(mesh_need_attribute(scene, mesh, name) || mesh_need_attribute(scene, mesh, std)))
continue;
Attribute *attr;
if(l->active_render())
attr = mesh->attributes.add(std, name);
else
attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER);
BL::MeshTextureFaceLayer::data_iterator t;
float3 *fdata = attr->data_float3();
size_t i = 0;
for(l->data.begin(t); t != l->data.end(); ++t, ++i) {
fdata[0] = get_float3(t->uv1());
fdata[1] = get_float3(t->uv2());
fdata[2] = get_float3(t->uv3());
fdata += 3;
if(nverts[i] == 4) {
fdata[0] = get_float3(t->uv1());
fdata[1] = get_float3(t->uv3());
fdata[2] = get_float3(t->uv4());
fdata += 3;
}
}
}
}
}
static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)
{
/* create subd mesh */
SubdMesh sdmesh;
/* create vertices */
BL::Mesh::vertices_iterator v;
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
sdmesh.add_vert(get_float3(v->co()));
/* create faces */
BL::Mesh::faces_iterator f;
for(b_mesh.faces.begin(f); f != b_mesh.faces.end(); ++f) {
int4 vi = get_int4(f->vertices_raw());
int n= (vi[3] == 0)? 3: 4;
//int shader = used_shaders[f->material_index()];
if(n == 4)
sdmesh.add_face(vi[0], vi[1], vi[2], vi[3]);
/*else
sdmesh.add_face(vi[0], vi[1], vi[2]);*/
}
/* finalize subd mesh */
sdmesh.link_boundary();
/* subdivide */
DiagSplit dsplit;
dsplit.camera = NULL;
dsplit.dicing_rate = RNA_float_get(cmesh, "dicing_rate");
sdmesh.tesselate(&dsplit, false, mesh, used_shaders[0], true);
}
/* Sync */
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated)
{
/* test if we can instance or if the object is modified */
BL::ID b_ob_data = b_ob.data();
BL::ID key = (object_is_modified(b_ob))? b_ob: b_ob_data;
/* find shader indices */
vector<uint> used_shaders;
BL::Object::material_slots_iterator slot;
for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) {
if(render_layer.material_override)
find_shader(render_layer.material_override, used_shaders);
else
find_shader(slot->material(), used_shaders);
}
if(used_shaders.size() == 0)
used_shaders.push_back(scene->default_surface);
/* test if we need to sync */
Mesh *mesh;
if(!mesh_map.sync(&mesh, key)) {
/* if transform was applied to mesh, need full update */
if(object_updated && mesh->transform_applied);
/* test if shaders changed, these can be object level so mesh
does not get tagged for recalc */
else if(mesh->used_shaders != used_shaders);
else {
/* even if not tagged for recalc, we may need to sync anyway
* because the shader needs different mesh attributes */
bool attribute_recalc = false;
foreach(uint shader, mesh->used_shaders)
if(scene->shaders[shader]->need_update_attributes)
attribute_recalc = true;
if(!attribute_recalc)
return mesh;
}
}
/* ensure we only sync instanced meshes once */
if(mesh_synced.find(mesh) != mesh_synced.end())
return mesh;
mesh_synced.insert(mesh);
/* create derived mesh */
BL::Mesh b_mesh = object_to_mesh(b_ob, b_scene, true, !preview);
PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
vector<Mesh::Triangle> oldtriangle = mesh->triangles;
mesh->clear();
mesh->used_shaders = used_shaders;
mesh->name = ustring(b_ob_data.name().c_str());
if(b_mesh) {
if(cmesh.data && RNA_boolean_get(&cmesh, "use_subdivision"))
create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders);
else
create_mesh(scene, mesh, b_mesh, used_shaders);
/* free derived mesh */
object_remove_mesh(b_data, b_mesh);
}
/* displacement method */
if(cmesh.data) {
int method = RNA_enum_get(&cmesh, "displacement_method");
if(method == 0)
mesh->displacement_method = Mesh::DISPLACE_BUMP;
else if(method == 1)
mesh->displacement_method = Mesh::DISPLACE_TRUE;
else
mesh->displacement_method = Mesh::DISPLACE_BOTH;
}
/* tag update */
bool rebuild = false;
if(oldtriangle.size() != mesh->triangles.size())
rebuild = true;
else if(oldtriangle.size()) {
if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0)
rebuild = true;
}
mesh->tag_update(scene, rebuild);
return mesh;
}
CCL_NAMESPACE_END

@ -0,0 +1,263 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "light.h"
#include "mesh.h"
#include "object.h"
#include "scene.h"
#include "blender_sync.h"
#include "blender_util.h"
#include "util_foreach.h"
CCL_NAMESPACE_BEGIN
/* Utilities */
bool BlenderSync::object_is_modified(BL::Object b_ob)
{
/* test if we can instance or if the object is modified */
if(ccl::object_is_modified(b_ob, b_scene, preview)) {
/* modifiers */
return true;
}
else {
/* object level material links */
BL::Object::material_slots_iterator slot;
for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot)
if(slot->link() == BL::MaterialSlot::link_OBJECT)
return true;
}
return false;
}
bool BlenderSync::object_is_mesh(BL::Object b_ob)
{
BL::ID b_ob_data = b_ob.data();
return (b_ob_data && (b_ob_data.is_a(&RNA_Mesh) ||
b_ob_data.is_a(&RNA_Curve) || b_ob_data.is_a(&RNA_MetaBall)));
}
bool BlenderSync::object_is_light(BL::Object b_ob)
{
BL::ID b_ob_data = b_ob.data();
return (b_ob_data && b_ob_data.is_a(&RNA_Lamp));
}
static uint object_ray_visibility(BL::Object b_ob)
{
PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
uint flag = 0;
flag |= get_boolean(cvisibility, "camera")? PATH_RAY_CAMERA: 0;
flag |= get_boolean(cvisibility, "diffuse")? PATH_RAY_DIFFUSE: 0;
flag |= get_boolean(cvisibility, "glossy")? PATH_RAY_GLOSSY: 0;
flag |= get_boolean(cvisibility, "transmission")? PATH_RAY_TRANSMIT: 0;
flag |= get_boolean(cvisibility, "shadow")? PATH_RAY_SHADOW: 0;
return flag;
}
/* Light */
void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm)
{
/* test if we need to sync */
Light *light;
ObjectKey key(b_parent, b_index, b_ob);
if(!light_map.sync(&light, b_ob, b_parent, key))
return;
BL::Lamp b_lamp(b_ob.data());
/* type */
switch(b_lamp.type()) {
case BL::Lamp::type_POINT: {
BL::PointLamp b_point_lamp(b_lamp);
light->size = b_point_lamp.shadow_soft_size();
light->type = LIGHT_POINT;
break;
}
case BL::Lamp::type_SPOT: {
BL::SpotLamp b_spot_lamp(b_lamp);
light->size = b_spot_lamp.shadow_soft_size();
light->type = LIGHT_POINT;
break;
}
case BL::Lamp::type_HEMI: {
light->type = LIGHT_DISTANT;
light->size = 0.0f;
break;
}
case BL::Lamp::type_SUN: {
BL::SunLamp b_sun_lamp(b_lamp);
light->size = b_sun_lamp.shadow_soft_size();
light->type = LIGHT_DISTANT;
break;
}
case BL::Lamp::type_AREA: {
BL::AreaLamp b_area_lamp(b_lamp);
light->size = 1.0f;
light->axisu = make_float3(tfm.x.x, tfm.y.x, tfm.z.x);
light->axisv = make_float3(tfm.x.y, tfm.y.y, tfm.z.y);
light->sizeu = b_area_lamp.size();
if(b_area_lamp.shape() == BL::AreaLamp::shape_RECTANGLE)
light->sizev = b_area_lamp.size_y();
else
light->sizev = light->sizeu;
light->type = LIGHT_AREA;
break;
}
}
/* location and (inverted!) direction */
light->co = make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
light->dir = -make_float3(tfm.x.z, tfm.y.z, tfm.z.z);
/* shader */
vector<uint> used_shaders;
find_shader(b_lamp, used_shaders);
if(used_shaders.size() == 0)
used_shaders.push_back(scene->default_light);
light->shader = used_shaders[0];
/* shadow */
PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
light->cast_shadow = get_boolean(clamp, "cast_shadow");
/* tag */
light->tag_update(scene);
}
/* Object */
void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint visibility)
{
/* light is handled separately */
if(object_is_light(b_ob)) {
sync_light(b_parent, b_index, b_ob, tfm);
return;
}
/* only interested in object that we can create meshes from */
if(!object_is_mesh(b_ob))
return;
/* test if we need to sync */
ObjectKey key(b_parent, b_index, b_ob);
Object *object;
bool object_updated = false;
if(object_map.sync(&object, b_ob, b_parent, key))
object_updated = true;
/* mesh sync */
object->mesh = sync_mesh(b_ob, object_updated);
/* object sync */
if(object_updated || (object->mesh && object->mesh->need_update)) {
object->name = b_ob.name().c_str();
object->tfm = tfm;
object->visibility = object_ray_visibility(b_ob) & visibility;
if(b_parent.ptr.data != b_ob.ptr.data)
object->visibility &= object_ray_visibility(b_parent);
object->tag_update(scene);
}
}
/* Object Loop */
void BlenderSync::sync_objects(BL::SpaceView3D b_v3d)
{
/* layer data */
uint scene_layer = render_layer.scene_layer;
uint layer = render_layer.layer;
/* prepare for sync */
light_map.pre_sync();
mesh_map.pre_sync();
object_map.pre_sync();
mesh_synced.clear();
/* object loop */
BL::Scene::objects_iterator b_ob;
for(b_scene.objects.begin(b_ob); b_ob != b_scene.objects.end(); ++b_ob) {
bool hide = (b_v3d)? b_ob->hide(): b_ob->hide_render();
uint ob_layer = get_layer(b_ob->layers());
if(!hide && (ob_layer & scene_layer)) {
uint visibility = PATH_RAY_ALL;
if(!(ob_layer & layer))
visibility &= ~PATH_RAY_CAMERA;
if(b_ob->is_duplicator()) {
/* dupli objects */
object_create_duplilist(*b_ob, b_scene);
BL::Object::dupli_list_iterator b_dup;
int b_index = 0;
for(b_ob->dupli_list.begin(b_dup); b_dup != b_ob->dupli_list.end(); ++b_dup) {
Transform tfm = get_transform(b_dup->matrix());
sync_object(*b_ob, b_index, b_dup->object(), tfm, visibility);
b_index++;
}
object_free_duplilist(*b_ob);
/* check if we should render duplicator */
hide = true;
BL::Object::particle_systems_iterator b_psys;
for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys)
if(b_psys->settings().use_render_emitter())
hide = false;
}
if(!hide) {
/* object itself */
Transform tfm = get_transform(b_ob->matrix_world());
sync_object(*b_ob, 0, *b_ob, tfm, visibility);
}
}
}
/* handle removed data and modified pointers */
if(light_map.post_sync())
scene->light_manager->tag_update(scene);
if(mesh_map.post_sync())
scene->mesh_manager->tag_update(scene);
if(object_map.post_sync())
scene->object_manager->tag_update(scene);
mesh_synced.clear();
}
CCL_NAMESPACE_END

@ -0,0 +1,212 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <Python.h>
#include "blender_sync.h"
#include "blender_session.h"
#include "util_opengl.h"
#include "util_path.h"
CCL_NAMESPACE_BEGIN
static PyObject *init_func(PyObject *self, PyObject *args)
{
const char *path, *user_path;
if(!PyArg_ParseTuple(args, "ss", &path, &user_path))
return NULL;
path_init(path, user_path);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *create_func(PyObject *self, PyObject *args)
{
PyObject *pyengine, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
if(!PyArg_ParseTuple(args, "OOOOOO", &pyengine, &pydata, &pyscene, &pyregion, &pyv3d, &pyrv3d))
return NULL;
/* RNA */
PointerRNA engineptr;
RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)PyLong_AsVoidPtr(pyengine), &engineptr);
BL::RenderEngine engine(engineptr);
PointerRNA dataptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydata), &dataptr);
BL::BlendData data(dataptr);
PointerRNA sceneptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
BL::Scene scene(sceneptr);
PointerRNA regionptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyregion), &regionptr);
BL::Region region(regionptr);
PointerRNA v3dptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyv3d), &v3dptr);
BL::SpaceView3D v3d(v3dptr);
PointerRNA rv3dptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyrv3d), &rv3dptr);
BL::RegionView3D rv3d(rv3dptr);
/* create session */
BlenderSession *session;
if(rv3d) {
/* interactive session */
int width = region.width();
int height = region.height();
session = new BlenderSession(engine, data, scene, v3d, rv3d, width, height);
}
else {
/* offline session */
session = new BlenderSession(engine, data, scene);
}
return PyLong_FromVoidPtr(session);
}
static PyObject *free_func(PyObject *self, PyObject *args)
{
PyObject *pysession;
if(!PyArg_ParseTuple(args, "O", &pysession))
return NULL;
delete (BlenderSession*)PyLong_AsVoidPtr(pysession);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *render_func(PyObject *self, PyObject *args)
{
PyObject *pysession;
if(!PyArg_ParseTuple(args, "O", &pysession))
return NULL;
Py_BEGIN_ALLOW_THREADS
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
session->render();
Py_END_ALLOW_THREADS
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *draw_func(PyObject *self, PyObject *args)
{
PyObject *pysession, *pyv3d, *pyrv3d;
if(!PyArg_ParseTuple(args, "OOO", &pysession, &pyv3d, &pyrv3d))
return NULL;
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
if(PyLong_AsVoidPtr(pyrv3d)) {
/* 3d view drawing */
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
session->draw(viewport[2], viewport[3]);
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *sync_func(PyObject *self, PyObject *args)
{
PyObject *pysession;
if(!PyArg_ParseTuple(args, "O", &pysession))
return NULL;
BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
session->synchronize();
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *available_devices_func(PyObject *self, PyObject *args)
{
vector<DeviceType> types = Device::available_types();
PyObject *ret = PyTuple_New(types.size());
for(size_t i = 0; i < types.size(); i++) {
string name = Device::string_from_type(types[i]);
PyTuple_SetItem(ret, i, PyUnicode_FromString(name.c_str()));
}
return ret;
}
static PyObject *with_osl_func(PyObject *self, PyObject *args)
{
#ifdef WITH_OSL
PyObject *ret = Py_True;
#else
PyObject *ret = Py_False;
#endif
return Py_INCREF(ret), ret;
}
static PyMethodDef methods[] = {
{"init", init_func, METH_VARARGS, ""},
{"create", create_func, METH_VARARGS, ""},
{"free", free_func, METH_VARARGS, ""},
{"render", render_func, METH_VARARGS, ""},
{"draw", draw_func, METH_VARARGS, ""},
{"sync", sync_func, METH_VARARGS, ""},
{"available_devices", available_devices_func, METH_NOARGS, ""},
{"with_osl", with_osl_func, METH_NOARGS, ""},
{NULL, NULL, 0, NULL},
};
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT,
"bcycles",
"Blender cycles render integration",
-1,
methods,
NULL, NULL, NULL, NULL
};
CCL_NAMESPACE_END
extern "C" PyObject *CYCLES_initPython();
PyObject *CYCLES_initPython()
{
return PyModule_Create(&ccl::module);
}

@ -0,0 +1,316 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "background.h"
#include "buffers.h"
#include "camera.h"
#include "device.h"
#include "integrator.h"
#include "film.h"
#include "light.h"
#include "scene.h"
#include "session.h"
#include "shader.h"
#include "util_color.h"
#include "util_foreach.h"
#include "util_function.h"
#include "util_progress.h"
#include "util_time.h"
#include "blender_sync.h"
#include "blender_session.h"
#include "blender_util.h"
CCL_NAMESPACE_BEGIN
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_)
: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL)
{
/* offline render */
BL::RenderSettings r = b_scene.render();
width = (int)(r.resolution_x()*r.resolution_percentage()*0.01f);
height = (int)(r.resolution_y()*r.resolution_percentage()*0.01f);
background = true;
last_redraw_time = 0.0f;
create_session();
}
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_,
BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(b_v3d_), b_rv3d(b_rv3d_)
{
/* 3d view render */
width = width_;
height = height_;
background = false;
last_redraw_time = 0.0f;
create_session();
}
BlenderSession::~BlenderSession()
{
free_session();
}
void BlenderSession::create_session()
{
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
/* reset status/progress */
last_status= "";
last_progress= -1.0f;
/* create scene */
scene = new Scene(scene_params);
/* create sync */
sync = new BlenderSync(b_data, b_scene, scene, !background);
sync->sync_data(b_v3d);
if(b_rv3d)
sync->sync_view(b_v3d, b_rv3d, width, height);
else
sync->sync_camera(width, height);
/* create session */
session = new Session(session_params);
session->scene = scene;
session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
/* start rendering */
session->reset(width, height, session_params.samples);
session->start();
}
void BlenderSession::free_session()
{
delete sync;
delete session;
}
void BlenderSession::render()
{
session->wait();
if(session->progress.get_cancel())
return;
/* write result */
write_render_result();
}
void BlenderSession::write_render_result()
{
/* get result */
RenderBuffers *buffers = session->buffers;
float exposure = scene->film->exposure;
double total_time, sample_time;
int sample;
session->progress.get_sample(sample, total_time, sample_time);
float4 *pixels = buffers->copy_from_device(exposure, sample);
if(!pixels)
return;
struct RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, 0, 0, width, height);
PointerRNA rrptr;
RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr);
BL::RenderResult rr(rrptr);
BL::RenderResult::layers_iterator layer;
rr.layers.begin(layer);
rna_RenderLayer_rect_set(&layer->ptr, (float*)pixels);
RE_engine_end_result((RenderEngine*)b_engine.ptr.data, rrp);
delete [] pixels;
}
void BlenderSession::synchronize()
{
/* on session/scene parameter changes, we recreate session entirely */
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
if(session->params.modified(session_params) ||
scene->params.modified(scene_params)) {
free_session();
create_session();
return;
}
/* increase samples, but never decrease */
session->set_samples(session_params.samples);
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
/* copy recalc flags, outside of mutex so we can decide to do the real
synchronization at a later time to not block on running updates */
sync->sync_recalc();
/* try to acquire mutex. if we don't want to or can't, come back later */
if(!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
tag_update();
return;
}
/* data and camera synchronize */
sync->sync_data(b_v3d);
if(b_rv3d)
sync->sync_view(b_v3d, b_rv3d, width, height);
else
sync->sync_camera(width, height);
/* unlock */
session->scene->mutex.unlock();
/* reset if needed */
if(scene->need_reset())
session->reset(width, height, session_params.samples);
}
bool BlenderSession::draw(int w, int h)
{
/* before drawing, we verify camera and viewport size changes, because
we do not get update callbacks for those, we must detect them here */
if(session->ready_to_reset()) {
bool reset = false;
/* try to acquire mutex. if we can't, come back later */
if(!session->scene->mutex.try_lock()) {
tag_update();
}
else {
/* update camera from 3d view */
bool need_update = scene->camera->need_update;
sync->sync_view(b_v3d, b_rv3d, w, h);
if(scene->camera->need_update && !need_update)
reset = true;
session->scene->mutex.unlock();
}
/* if dimensions changed, reset */
if(width != w || height != h) {
width = w;
height = h;
reset = true;
}
/* reset if requested */
if(reset) {
SessionParams session_params = BlenderSync::get_session_params(b_scene, background);
session->reset(width, height, session_params.samples);
}
}
/* update status and progress for 3d view draw */
update_status_progress();
/* draw */
return !session->draw(width, height);
}
void BlenderSession::get_status(string& status, string& substatus)
{
session->progress.get_status(status, substatus);
}
void BlenderSession::get_progress(float& progress, double& total_time)
{
double sample_time;
int sample;
session->progress.get_sample(sample, total_time, sample_time);
progress = ((float)sample/(float)session->params.samples);
}
void BlenderSession::update_status_progress()
{
string status, substatus;
float progress;
double total_time;
char time_str[128];
get_status(status, substatus);
get_progress(progress, total_time);
if(!background) {
BLI_timestr(total_time, time_str);
status = "Time: " + string(time_str) + " | " + status;
}
if(substatus.size() > 0)
status += " | " + substatus;
if(status != last_status) {
RE_engine_update_stats((RenderEngine*)b_engine.ptr.data, "", status.c_str());
last_status = status;
}
if(progress != last_progress) {
RE_engine_update_progress((RenderEngine*)b_engine.ptr.data, progress);
last_progress = progress;
}
}
void BlenderSession::tag_update()
{
/* tell blender that we want to get another update callback */
engine_tag_update((RenderEngine*)b_engine.ptr.data);
}
void BlenderSession::tag_redraw()
{
if(background) {
/* update stats and progress, only for background here because
in 3d view we do it in draw for thread safety reasons */
update_status_progress();
/* offline render, redraw if timeout passed */
if(time_dt() - last_redraw_time > 1.0f) {
write_render_result();
engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
last_redraw_time = time_dt();
}
}
else {
/* tell blender that we want to redraw */
engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
}
}
void BlenderSession::test_cancel()
{
/* test if we need to cancel rendering */
if(background)
if(RE_engine_test_break((RenderEngine*)b_engine.ptr.data))
session->progress.set_cancel("Cancelled");
}
CCL_NAMESPACE_END

@ -0,0 +1,81 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __BLENDER_SESSION_H__
#define __BLENDER_SESSION_H__
#include "device.h"
#include "scene.h"
#include "session.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
class Scene;
class Session;
class BlenderSession {
public:
BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene);
BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene,
BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
~BlenderSession();
/* session */
void create_session();
void free_session();
/* offline render */
void render();
void write_render_result();
/* interactive updates */
void synchronize();
/* drawing */
bool draw(int w, int h);
void tag_redraw();
void tag_update();
void get_status(string& status, string& substatus);
void get_progress(float& progress, double& total_time);
void test_cancel();
void update_status_progress();
bool background;
Session *session;
Scene *scene;
BlenderSync *sync;
double last_redraw_time;
BL::RenderEngine b_engine;
BL::BlendData b_data;
BL::Scene b_scene;
BL::SpaceView3D b_v3d;
BL::RegionView3D b_rv3d;
string last_status;
float last_progress;
int width, height;
};
CCL_NAMESPACE_END
#endif /* __BLENDER_SESSION_H__ */

@ -0,0 +1,709 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "background.h"
#include "graph.h"
#include "light.h"
#include "nodes.h"
#include "scene.h"
#include "shader.h"
#include "blender_sync.h"
#include "blender_util.h"
#include "util_debug.h"
CCL_NAMESPACE_BEGIN
typedef map<void*, ShaderNode*> PtrNodeMap;
typedef pair<ShaderNode*, std::string> SocketPair;
typedef map<void*, SocketPair> PtrSockMap;
/* Find */
void BlenderSync::find_shader(BL::ID id, vector<uint>& used_shaders)
{
Shader *shader = shader_map.find(id);
for(size_t i = 0; i < scene->shaders.size(); i++) {
if(scene->shaders[i] == shader) {
used_shaders.push_back(i);
break;
}
}
}
/* Graph */
static BL::NodeSocket get_node_input(BL::Node *b_group_node, BL::NodeSocket b_in)
{
if(b_group_node) {
BL::NodeTree b_ntree = BL::NodeGroup(*b_group_node).node_tree();
BL::NodeTree::links_iterator b_link;
for(b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
if(b_link->to_socket().ptr.data == b_in.ptr.data) {
BL::Node::inputs_iterator b_gin;
for(b_group_node->inputs.begin(b_gin); b_gin != b_group_node->inputs.end(); ++b_gin)
if(b_gin->group_socket().ptr.data == b_link->from_socket().ptr.data)
return *b_gin;
}
}
}
return b_in;
}
static BL::NodeSocket get_node_output(BL::Node b_node, const string& name)
{
BL::Node::outputs_iterator b_out;
for(b_node.outputs.begin(b_out); b_out != b_node.outputs.end(); ++b_out)
if(b_out->name() == name)
return *b_out;
assert(0);
return *b_out;
}
static float3 get_node_output_rgba(BL::Node b_node, const string& name)
{
BL::NodeSocketRGBA sock(get_node_output(b_node, name));
return get_float3(sock.default_value());
}
static float get_node_output_value(BL::Node b_node, const string& name)
{
BL::NodeSocketFloatNone sock(get_node_output(b_node, name));
return sock.default_value();
}
static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping b_mapping)
{
mapping->translation = get_float3(b_mapping.location());
mapping->rotation = get_float3(b_mapping.rotation());
mapping->scale = get_float3(b_mapping.scale());
mapping->x_mapping = (TextureMapping::Mapping)b_mapping.mapping_x();
mapping->y_mapping = (TextureMapping::Mapping)b_mapping.mapping_y();
mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z();
}
static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping b_mapping)
{
mapping->translation = get_float3(b_mapping.location());
mapping->rotation = get_float3(b_mapping.rotation());
mapping->scale = get_float3(b_mapping.scale());
}
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_GEOMETRY: 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();
get_tex_mapping(&mapping->tex_mapping, b_mapping_node);
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_LAYER_WEIGHT: {
node = new LayerWeightNode();
break;
}
case BL::ShaderNode::type_ADD_SHADER: {
node = new AddClosureNode();
break;
}
case BL::ShaderNode::type_MIX_SHADER: {
node = new MixClosureNode();
break;
}
case BL::ShaderNode::type_ATTRIBUTE: {
BL::ShaderNodeAttribute b_attr_node(b_node);
AttributeNode *attr = new AttributeNode();
attr->attribute = b_attr_node.attribute_name();
node = attr;
break;
}
case BL::ShaderNode::type_BACKGROUND: {
node = new BackgroundNode();
break;
}
case BL::ShaderNode::type_HOLDOUT: {
node = new HoldoutNode();
break;
}
case BL::ShaderNode::type_BSDF_DIFFUSE: {
node = new DiffuseBsdfNode();
break;
}
case BL::ShaderNode::type_BSDF_GLOSSY: {
BL::ShaderNodeBsdfGlossy b_glossy_node(b_node);
GlossyBsdfNode *glossy = new GlossyBsdfNode();
switch(b_glossy_node.distribution()) {
case BL::ShaderNodeBsdfGlossy::distribution_SHARP:
glossy->distribution = ustring("Sharp");
break;
case BL::ShaderNodeBsdfGlossy::distribution_BECKMANN:
glossy->distribution = ustring("Beckmann");
break;
case BL::ShaderNodeBsdfGlossy::distribution_GGX:
glossy->distribution = ustring("GGX");
break;
}
node = glossy;
break;
}
case BL::ShaderNode::type_BSDF_GLASS: {
BL::ShaderNodeBsdfGlass b_glass_node(b_node);
GlassBsdfNode *glass = new GlassBsdfNode();
switch(b_glass_node.distribution()) {
case BL::ShaderNodeBsdfGlass::distribution_SHARP:
glass->distribution = ustring("Sharp");
break;
case BL::ShaderNodeBsdfGlass::distribution_BECKMANN:
glass->distribution = ustring("Beckmann");
break;
case BL::ShaderNodeBsdfGlass::distribution_GGX:
glass->distribution = ustring("GGX");
break;
}
node = glass;
break;
}
case BL::ShaderNode::type_BSDF_TRANSLUCENT: {
node = new TranslucentBsdfNode();
break;
}
case BL::ShaderNode::type_BSDF_TRANSPARENT: {
node = new TransparentBsdfNode();
break;
}
case BL::ShaderNode::type_BSDF_VELVET: {
node = new VelvetBsdfNode();
break;
}
case BL::ShaderNode::type_EMISSION: {
node = new EmissionNode();
break;
}
case BL::ShaderNode::type_VOLUME_ISOTROPIC: {
node = new IsotropicVolumeNode();
break;
}
case BL::ShaderNode::type_VOLUME_TRANSPARENT: {
node = new TransparentVolumeNode();
break;
}
case BL::ShaderNode::type_NEW_GEOMETRY: {
node = new GeometryNode();
break;
}
case BL::ShaderNode::type_LIGHT_PATH: {
node = new LightPathNode();
break;
}
case BL::ShaderNode::type_TEX_IMAGE: {
BL::ShaderNodeTexImage b_image_node(b_node);
BL::Image b_image(b_image_node.image());
ImageTextureNode *image = new ImageTextureNode();
/* todo: handle generated/builtin images */
if(b_image)
image->filename = blender_absolute_path(b_data, b_image, b_image.filepath());
image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
node = image;
break;
}
case BL::ShaderNode::type_TEX_ENVIRONMENT: {
BL::ShaderNodeTexEnvironment b_env_node(b_node);
BL::Image b_image(b_env_node.image());
EnvironmentTextureNode *env = new EnvironmentTextureNode();
if(b_image)
env->filename = blender_absolute_path(b_data, b_image, b_image.filepath());
env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
get_tex_mapping(&env->tex_mapping, b_env_node.texture_mapping());
node = env;
break;
}
case BL::ShaderNode::type_TEX_GRADIENT: {
BL::ShaderNodeTexGradient b_gradient_node(b_node);
GradientTextureNode *gradient = new GradientTextureNode();
gradient->type = GradientTextureNode::type_enum[(int)b_gradient_node.gradient_type()];
get_tex_mapping(&gradient->tex_mapping, b_gradient_node.texture_mapping());
node = gradient;
break;
}
case BL::ShaderNode::type_TEX_VORONOI: {
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
voronoi->coloring = VoronoiTextureNode::coloring_enum[(int)b_voronoi_node.coloring()];
get_tex_mapping(&voronoi->tex_mapping, b_voronoi_node.texture_mapping());
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();
get_tex_mapping(&magic->tex_mapping, b_magic_node.texture_mapping());
node = magic;
break;
}
case BL::ShaderNode::type_TEX_WAVE: {
BL::ShaderNodeTexWave b_wave_node(b_node);
WaveTextureNode *wave = new WaveTextureNode();
wave->type = WaveTextureNode::type_enum[(int)b_wave_node.wave_type()];
get_tex_mapping(&wave->tex_mapping, b_wave_node.texture_mapping());
node = wave;
break;
}
case BL::ShaderNode::type_TEX_NOISE: {
BL::ShaderNodeTexNoise b_noise_node(b_node);
NoiseTextureNode *noise = new NoiseTextureNode();
get_tex_mapping(&noise->tex_mapping, b_noise_node.texture_mapping());
node = noise;
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()];
get_tex_mapping(&musgrave->tex_mapping, b_musgrave_node.texture_mapping());
node = musgrave;
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();
get_tex_mapping(&sky->tex_mapping, b_sky_node.texture_mapping());
node = sky;
break;
}
}
if(node && node != graph->output())
graph->add(node);
return node;
}
static SocketPair node_socket_map_pair(PtrNodeMap& node_map, BL::Node b_node, BL::NodeSocket b_socket)
{
BL::Node::inputs_iterator b_input;
BL::Node::outputs_iterator b_output;
string name = b_socket.name();
bool found = false;
int counter = 0, total = 0;
/* find in inputs */
for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
if(b_input->name() == name) {
if(!found)
counter++;
total++;
}
if(b_input->ptr.data == b_socket.ptr.data)
found = true;
}
if(!found) {
/* find in outputs */
found = false;
counter = 0;
total = 0;
for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
if(b_output->name() == name) {
if(!found)
counter++;
total++;
}
if(b_output->ptr.data == b_socket.ptr.data)
found = true;
}
}
/* rename if needed */
if(name == "Shader")
name = "Closure";
if(total > 1)
name = string_printf("%s%d", name.c_str(), counter);
return SocketPair(node_map[b_node.ptr.data], name);
}
static void add_nodes(BL::BlendData b_data, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, BL::Node *b_group_node, PtrSockMap& sockets_map)
{
/* add nodes */
BL::ShaderNodeTree::nodes_iterator b_node;
PtrNodeMap node_map;
map<void*, PtrSockMap> node_groups;
for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) {
if(b_node->is_a(&RNA_NodeGroup)) {
BL::NodeGroup b_gnode(*b_node);
BL::ShaderNodeTree b_group_ntree(b_gnode.node_tree());
node_groups[b_node->ptr.data] = PtrSockMap();
add_nodes(b_data, graph, b_group_ntree, &b_gnode, node_groups[b_node->ptr.data]);
}
else {
ShaderNode *node = add_node(b_data, graph, b_group_node, BL::ShaderNode(*b_node));
if(node) {
BL::Node::inputs_iterator b_input;
BL::Node::outputs_iterator b_output;
node_map[b_node->ptr.data] = node;
for(b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
SocketPair pair = node_socket_map_pair(node_map, *b_node, *b_input);
ShaderInput *input = pair.first->input(pair.second.c_str());
BL::NodeSocket sock(get_node_input(b_group_node, *b_input));
assert(input);
/* copy values for non linked inputs */
switch(input->type) {
case SHADER_SOCKET_FLOAT: {
BL::NodeSocketFloatNone value_sock(sock);
input->set(value_sock.default_value());
break;
}
case SHADER_SOCKET_COLOR: {
BL::NodeSocketRGBA rgba_sock(sock);
input->set(get_float3(rgba_sock.default_value()));
break;
}
case SHADER_SOCKET_NORMAL:
case SHADER_SOCKET_POINT:
case SHADER_SOCKET_VECTOR: {
BL::NodeSocketVectorNone vec_sock(sock);
input->set(get_float3(vec_sock.default_value()));
break;
}
case SHADER_SOCKET_CLOSURE:
break;
}
}
}
}
}
/* connect nodes */
BL::NodeTree::links_iterator b_link;
for(b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
/* get blender link data */
BL::Node b_from_node = b_link->from_node();
BL::Node b_to_node = b_link->to_node();
BL::NodeSocket b_from_sock = b_link->from_socket();
BL::NodeSocket b_to_sock = b_link->to_socket();
/* if link with group socket, add to map so we can connect it later */
if(b_group_node) {
if(!b_from_node) {
sockets_map[b_from_sock.ptr.data] =
node_socket_map_pair(node_map, b_to_node, b_to_sock);
continue;
}
else if(!b_to_node) {
sockets_map[b_to_sock.ptr.data] =
node_socket_map_pair(node_map, b_from_node, b_from_sock);
continue;
}
}
SocketPair from_pair, to_pair;
/* from sock */
if(b_from_node.is_a(&RNA_NodeGroup)) {
/* group node */
BL::NodeSocket group_sock = b_from_sock.group_socket();
from_pair = node_groups[b_from_node.ptr.data][group_sock.ptr.data];
}
else {
/* regular node */
from_pair = node_socket_map_pair(node_map, b_from_node, b_from_sock);
}
/* to sock */
if(b_to_node.is_a(&RNA_NodeGroup)) {
/* group node */
BL::NodeSocket group_sock = b_to_sock.group_socket();
to_pair = node_groups[b_to_node.ptr.data][group_sock.ptr.data];
}
else {
/* regular node */
to_pair = node_socket_map_pair(node_map, b_to_node, b_to_sock);
}
/* in case of groups there may not actually be a node inside the group
that the group socket connects to, so from_node or to_node may be NULL */
if(from_pair.first && to_pair.first) {
ShaderOutput *output = from_pair.first->output(from_pair.second.c_str());
ShaderInput *input = to_pair.first->input(to_pair.second.c_str());
graph->connect(output, input);
}
}
}
/* Sync Materials */
void BlenderSync::sync_materials()
{
shader_map.set_default(scene->shaders[scene->default_surface]);
/* material loop */
BL::BlendData::materials_iterator b_mat;
for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) {
Shader *shader;
/* test if we need to sync */
if(shader_map.sync(&shader, *b_mat)) {
ShaderGraph *graph = new ShaderGraph();
shader->name = b_mat->name().c_str();
/* create nodes */
if(b_mat->use_nodes() && b_mat->node_tree()) {
PtrSockMap sock_to_node;
BL::ShaderNodeTree b_ntree(b_mat->node_tree());
add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
}
else {
ShaderNode *closure, *out;
closure = graph->add(new DiffuseBsdfNode());
closure->input("Color")->value = get_float3(b_mat->diffuse_color());
out = graph->output();
graph->connect(closure->output("BSDF"), out->input("Surface"));
}
/* settings */
PointerRNA cmat = RNA_pointer_get(&b_mat->ptr, "cycles");
shader->sample_as_light = get_boolean(cmat, "sample_as_light");
shader->homogeneous_volume = get_boolean(cmat, "homogeneous_volume");
shader->set_graph(graph);
shader->tag_update(scene);
}
}
}
/* Sync World */
void BlenderSync::sync_world()
{
Background *background = scene->background;
Background prevbackground = *background;
BL::World b_world = b_scene.world();
if(world_recalc || b_world.ptr.data != world_map) {
Shader *shader = scene->shaders[scene->default_background];
ShaderGraph *graph = new ShaderGraph();
/* create nodes */
if(b_world && b_world.use_nodes() && b_world.node_tree()) {
PtrSockMap sock_to_node;
BL::ShaderNodeTree b_ntree(b_world.node_tree());
add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
}
else if(b_world) {
ShaderNode *closure, *out;
closure = graph->add(new BackgroundNode());
closure->input("Color")->value = get_float3(b_world.horizon_color());
out = graph->output();
graph->connect(closure->output("Background"), out->input("Surface"));
}
shader->set_graph(graph);
shader->tag_update(scene);
}
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
background->transparent = get_boolean(cscene, "film_transparent");
if(background->modified(prevbackground))
background->tag_update(scene);
world_map = b_world.ptr.data;
world_recalc = false;
}
/* Sync Lamps */
void BlenderSync::sync_lamps()
{
shader_map.set_default(scene->shaders[scene->default_light]);
/* lamp loop */
BL::BlendData::lamps_iterator b_lamp;
for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp) {
Shader *shader;
/* test if we need to sync */
if(shader_map.sync(&shader, *b_lamp)) {
ShaderGraph *graph = new ShaderGraph();
/* create nodes */
if(b_lamp->use_nodes() && b_lamp->node_tree()) {
shader->name = b_lamp->name().c_str();
PtrSockMap sock_to_node;
BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
add_nodes(b_data, graph, b_ntree, NULL, sock_to_node);
}
else {
ShaderNode *closure, *out;
float strength = 1.0f;
if(b_lamp->type() == BL::Lamp::type_POINT ||
b_lamp->type() == BL::Lamp::type_SPOT ||
b_lamp->type() == BL::Lamp::type_AREA)
strength = 100.0f;
closure = graph->add(new EmissionNode());
closure->input("Color")->value = get_float3(b_lamp->color());
closure->input("Strength")->value.x = strength;
out = graph->output();
graph->connect(closure->output("Emission"), out->input("Surface"));
}
shader->set_graph(graph);
shader->tag_update(scene);
}
}
}
void BlenderSync::sync_shaders()
{
shader_map.pre_sync();
sync_world();
sync_lamps();
sync_materials();
/* false = don't delete unused shaders, not supported */
shader_map.post_sync(false);
}
CCL_NAMESPACE_END

@ -0,0 +1,303 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "background.h"
#include "film.h"
#include "../render/filter.h"
#include "graph.h"
#include "integrator.h"
#include "light.h"
#include "mesh.h"
#include "nodes.h"
#include "object.h"
#include "scene.h"
#include "shader.h"
#include "device.h"
#include "blender_sync.h"
#include "blender_util.h"
#include "util_debug.h"
#include "util_foreach.h"
CCL_NAMESPACE_BEGIN
/* Constructor */
BlenderSync::BlenderSync(BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_)
: b_data(b_data_), b_scene(b_scene_),
shader_map(&scene_->shaders),
object_map(&scene_->objects),
mesh_map(&scene_->meshes),
light_map(&scene_->lights),
world_map(NULL),
world_recalc(false)
{
scene = scene_;
preview = preview_;
}
BlenderSync::~BlenderSync()
{
}
/* Sync */
bool BlenderSync::sync_recalc()
{
/* sync recalc flags from blender to cycles. actual update is done separate,
so we can do it later on if doing it immediate is not suitable */
BL::BlendData::materials_iterator b_mat;
for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat)
if(b_mat->is_updated())
shader_map.set_recalc(*b_mat);
BL::BlendData::lamps_iterator b_lamp;
for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp)
if(b_lamp->is_updated())
shader_map.set_recalc(*b_lamp);
BL::BlendData::objects_iterator b_ob;
for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) {
if(b_ob->is_updated()) {
object_map.set_recalc(*b_ob);
light_map.set_recalc(*b_ob);
}
if(object_is_mesh(*b_ob)) {
if(b_ob->is_updated_data() || b_ob->data().is_updated()) {
BL::ID key = object_is_modified(*b_ob)? *b_ob: b_ob->data();
mesh_map.set_recalc(key);
}
}
else if(object_is_light(*b_ob)) {
if(b_ob->is_updated_data() || b_ob->data().is_updated())
light_map.set_recalc(*b_ob);
}
}
BL::BlendData::meshes_iterator b_mesh;
for(b_data.meshes.begin(b_mesh); b_mesh != b_data.meshes.end(); ++b_mesh)
if(b_mesh->is_updated())
mesh_map.set_recalc(*b_mesh);
BL::BlendData::worlds_iterator b_world;
for(b_data.worlds.begin(b_world); b_world != b_data.worlds.end(); ++b_world)
if(world_map == b_world->ptr.data && b_world->is_updated())
world_recalc = true;
bool recalc =
shader_map.has_recalc() ||
object_map.has_recalc() ||
light_map.has_recalc() ||
mesh_map.has_recalc() ||
BlendDataObjects_is_updated_get(&b_data.ptr) ||
world_recalc;
return recalc;
}
void BlenderSync::sync_data(BL::SpaceView3D b_v3d)
{
sync_integrator();
sync_film();
sync_render_layer(b_v3d);
sync_shaders();
sync_objects(b_v3d);
}
/* Integrator */
void BlenderSync::sync_integrator()
{
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
Integrator *integrator = scene->integrator;
Integrator previntegrator = *integrator;
integrator->min_bounce = get_int(cscene, "min_bounces");
integrator->max_bounce = get_int(cscene, "max_bounces");
integrator->max_diffuse_bounce = get_int(cscene, "diffuse_bounces");
integrator->max_glossy_bounce = get_int(cscene, "glossy_bounces");
integrator->max_transmission_bounce = get_int(cscene, "transmission_bounces");
integrator->transparent_max_bounce = get_int(cscene, "transparent_max_bounces");
integrator->transparent_min_bounce = get_int(cscene, "transparent_min_bounces");
integrator->transparent_shadows = get_boolean(cscene, "use_transparent_shadows");
integrator->no_caustics = get_boolean(cscene, "no_caustics");
integrator->blur_caustics = get_float(cscene, "blur_caustics");
integrator->seed = get_int(cscene, "seed");
if(integrator->modified(previntegrator))
integrator->tag_update(scene);
}
/* Film */
void BlenderSync::sync_film()
{
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
Film *film = scene->film;
Film prevfilm = *film;
film->exposure = get_float(cscene, "film_exposure");
if(film->modified(prevfilm))
film->tag_update(scene);
Filter *filter = scene->filter;
Filter prevfilter = *filter;
filter->filter_type = (FilterType)RNA_enum_get(&cscene, "filter_type");
filter->filter_width = (filter->filter_type == FILTER_BOX)? 1.0f: get_float(cscene, "filter_width");
if(filter->modified(prevfilter))
filter->tag_update(scene);
}
/* Render Layer */
void BlenderSync::sync_render_layer(BL::SpaceView3D b_v3d)
{
if(b_v3d) {
render_layer.scene_layer = get_layer(b_v3d.layers());
render_layer.layer = render_layer.scene_layer;
render_layer.material_override = PointerRNA_NULL;
}
else {
BL::RenderSettings r = b_scene.render();
BL::RenderSettings::layers_iterator b_rlay;
bool first = true;
for(r.layers.begin(b_rlay); b_rlay != r.layers.end(); ++b_rlay) {
/* single layer for now */
if(first) {
render_layer.scene_layer = get_layer(b_scene.layers());
render_layer.layer = get_layer(b_rlay->layers());
render_layer.material_override = b_rlay->material_override();
first = false;
}
}
}
}
/* Scene Parameters */
SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background)
{
SceneParams params;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
int shadingsystem = RNA_enum_get(&cscene, "shading_system");
if(shadingsystem == 0)
params.shadingsystem = SceneParams::SVM;
else if(shadingsystem == 1)
params.shadingsystem = SceneParams::OSL;
if(background)
params.bvh_type = SceneParams::BVH_STATIC;
else
params.bvh_type = (SceneParams::BVHType)RNA_enum_get(&cscene, "debug_bvh_type");
params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits");
return params;
}
/* Session Parameters */
bool BlenderSync::get_session_pause(BL::Scene b_scene, bool background)
{
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
return (background)? false: get_boolean(cscene, "preview_pause");
}
static bool device_type_available(vector<DeviceType>& types, DeviceType dtype)
{
foreach(DeviceType dt, types)
if(dt == dtype)
return true;
return false;
}
SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
{
SessionParams params;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
/* device type */
params.device_type = DEVICE_CPU;
if(RNA_enum_get(&cscene, "device") != 0) {
vector<DeviceType> types = Device::available_types();
DeviceType dtype = (RNA_enum_get(&cscene, "gpu_type") == 0)? DEVICE_CUDA: DEVICE_OPENCL;
if(device_type_available(types, dtype))
params.device_type = dtype;
else if(device_type_available(types, DEVICE_OPENCL))
params.device_type = DEVICE_OPENCL;
else if(device_type_available(types, DEVICE_CUDA))
params.device_type = DEVICE_CUDA;
}
/* Background */
params.background = background;
/* samples */
if(background) {
params.samples = get_int(cscene, "samples");
}
else {
params.samples = get_int(cscene, "preview_samples");
if(params.samples == 0)
params.samples = INT_MAX;
}
/* other parameters */
params.threads = b_scene.render().threads();
params.tile_size = get_int(cscene, "debug_tile_size");
params.min_size = get_int(cscene, "debug_min_size");
params.cancel_timeout = get_float(cscene, "debug_cancel_timeout");
params.reset_timeout = get_float(cscene, "debug_reset_timeout");
params.text_timeout = get_float(cscene, "debug_text_timeout");
if(background) {
params.progressive = true;
params.min_size = INT_MAX;
}
else
params.progressive = true;
return params;
}
CCL_NAMESPACE_END

@ -0,0 +1,119 @@
/*
* Copyright 2011, Blender Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __BLENDER_SYNC_H__
#define __BLENDER_SYNC_H__
#include "MEM_guardedalloc.h"
#include "RNA_types.h"
#include "RNA_access.h"
#include "RNA_blender_cpp.h"
#include "blender_util.h"
#include "scene.h"
#include "session.h"
#include "util_map.h"
#include "util_set.h"
#include "util_transform.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
class Background;
class Camera;
class Film;
class Light;
class Mesh;
class Object;
class Scene;
class Shader;
class ShaderGraph;
class ShaderNode;
class BlenderSync {
public:
BlenderSync(BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_);
~BlenderSync();
/* sync */
bool sync_recalc();
void sync_data(BL::SpaceView3D b_v3d);
void sync_camera(int width, int height);
void sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
/* get parameters */
static SceneParams get_scene_params(BL::Scene b_scene, bool background);
static SessionParams get_session_params(BL::Scene b_scene, bool background);
static bool get_session_pause(BL::Scene b_scene, bool background);
private:
/* sync */
void sync_lamps();
void sync_materials();
void sync_objects(BL::SpaceView3D b_v3d);
void sync_film();
void sync_integrator();
void sync_view();
void sync_world();
void sync_render_layer(BL::SpaceView3D b_v3d);
void sync_shaders();
void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
Mesh *sync_mesh(BL::Object b_ob, bool object_updated);
void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint visibility);
void sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm);
/* util */
void find_shader(BL::ID id, vector<uint>& used_shaders);
bool object_is_modified(BL::Object b_ob);
bool object_is_mesh(BL::Object b_ob);
bool object_is_light(BL::Object b_ob);
/* variables */
BL::BlendData b_data;
BL::Scene b_scene;
id_map<void*, Shader> shader_map;
id_map<ObjectKey, Object> object_map;
id_map<void*, Mesh> mesh_map;
id_map<ObjectKey, Light> light_map;
set<Mesh*> mesh_synced;
void *world_map;
bool world_recalc;
Scene *scene;
bool preview;
struct RenderLayerInfo {
RenderLayerInfo()
: scene_layer(0), layer(0),
material_override(PointerRNA_NULL)
{}
uint scene_layer;
uint layer;
BL::Material material_override;
} render_layer;
};
CCL_NAMESPACE_END
#endif /* __BLENDER_SYNC_H__ */

@ -0,0 +1,332 @@
/*
* 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
todo: clean this up ... */
extern "C" {
struct RenderEngine;
struct RenderResult;
ID *rna_Object_to_mesh(void *_self, void *reports, void *scene, int apply_modifiers, int settings);
void rna_Main_meshes_remove(void *bmain, void *reports, void *mesh);
void rna_Object_create_duplilist(void *ob, void *reports, void *sce);
void rna_Object_free_duplilist(void *ob, void *reports);
void rna_RenderLayer_rect_set(PointerRNA *ptr, const float *values);
void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values);
struct RenderResult *RE_engine_begin_result(struct RenderEngine *engine, int x, int y, int w, int h);
void RE_engine_update_result(struct RenderEngine *engine, struct RenderResult *result);
void RE_engine_end_result(struct RenderEngine *engine, struct RenderResult *result);
int RE_engine_test_break(struct RenderEngine *engine);
void RE_engine_update_stats(struct RenderEngine *engine, const char *stats, const char *info);
void RE_engine_update_progress(struct RenderEngine *engine, float progress);
void engine_tag_redraw(void *engine);
void engine_tag_update(void *engine);
int rna_Object_is_modified(void *ob, void *scene, int settings);
void BLI_timestr(double _time, char *str);
}
CCL_NAMESPACE_BEGIN
static inline BL::Mesh object_to_mesh(BL::Object self, BL::Scene scene, bool apply_modifiers, bool render)
{
ID *data = rna_Object_to_mesh(self.ptr.data, NULL, scene.ptr.data, apply_modifiers, (render)? 2: 1);
PointerRNA ptr;
RNA_id_pointer_create(data, &ptr);
return BL::Mesh(ptr);
}
static inline void object_remove_mesh(BL::BlendData data, BL::Mesh mesh)
{
rna_Main_meshes_remove(data.ptr.data, NULL, mesh.ptr.data);
}
static inline void object_create_duplilist(BL::Object self, BL::Scene scene)
{
rna_Object_create_duplilist(self.ptr.data, NULL, scene.ptr.data);
}
static inline void object_free_duplilist(BL::Object self)
{
rna_Object_free_duplilist(self.ptr.data, NULL);
}
static inline bool object_is_modified(BL::Object self, BL::Scene scene, bool preview)
{
return rna_Object_is_modified(self.ptr.data, scene.ptr.data, (preview)? (1<<0): (1<<1))? true: false;
}
/* Utilities */
static inline Transform get_transform(BL::Array<float, 16> array)
{
Transform tfm;
/* we assume both types to be just 16 floats, and transpose because blender
use column major matrix order while we use row major */
memcpy(&tfm, &array, sizeof(float)*16);
tfm = transform_transpose(tfm);
return tfm;
}
static inline float2 get_float2(BL::Array<float, 2> array)
{
return make_float2(array[0], array[1]);
}
static inline float3 get_float3(BL::Array<float, 2> array)
{
return make_float3(array[0], array[1], 0.0f);
}
static inline float3 get_float3(BL::Array<float, 3> array)
{
return make_float3(array[0], array[1], array[2]);
}
static inline float3 get_float3(BL::Array<float, 4> array)
{
return make_float3(array[0], array[1], array[2]);
}
static inline int4 get_int4(BL::Array<int, 4> array)
{
return make_int4(array[0], array[1], array[2], array[3]);
}
static inline uint get_layer(BL::Array<int, 20> array)
{
uint layer = 0;
for(uint i = 0; i < 20; i++)
if(array[i])
layer |= (1 << i);
return layer;
}
/*static inline float3 get_float3(PointerRNA& ptr, const char *name)
{
float3 f;
RNA_float_get_array(&ptr, name, &f.x);
return f;
}*/
static inline bool get_boolean(PointerRNA& ptr, const char *name)
{
return RNA_boolean_get(&ptr, name)? true: false;
}
static inline float get_float(PointerRNA& ptr, const char *name)
{
return RNA_float_get(&ptr, name);
}
static inline int get_int(PointerRNA& ptr, const char *name)
{
return RNA_int_get(&ptr, name);
}
static inline int get_enum(PointerRNA& ptr, const char *name)
{
return RNA_enum_get(&ptr, name);
}
static inline string get_enum_identifier(PointerRNA& ptr, const char *name)
{
PropertyRNA *prop = RNA_struct_find_property(&ptr, name);
const char *identifier = "";
int value = RNA_property_enum_get(&ptr, prop);
RNA_property_enum_identifier(NULL, &ptr, prop, value, &identifier);
return string(identifier);
}
/* Relative Paths */
static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, const string& path)
{
if(path.size() >= 2 && path[0] == '/' && path[1] == '/') {
string dirname = (b_id.library())? b_id.library().filepath(): b_data.filepath();
return path_join(path_dirname(dirname), path.substr(2));
}
return path;
}
/* ID Map
*
* Utility class to keep in sync with blender data.
* Used for objects, meshes, lights and shaders. */
template<typename K, typename T>
class id_map {
public:
id_map(vector<T*> *scene_data_)
{
scene_data = scene_data_;
}
T *find(BL::ID id)
{
return find(id.ptr.id.data);
}
T *find(const K& key)
{
if(b_map.find(key) != b_map.end()) {
T *data = b_map[key];
return data;
}
return NULL;
}
void set_recalc(BL::ID id)
{
b_recalc.insert(id.ptr.data);
}
bool has_recalc()
{
return !(b_recalc.empty());
}
void pre_sync()
{
used_set.clear();
}
bool sync(T **r_data, BL::ID id)
{
return sync(r_data, id, id, id.ptr.id.data);
}
bool sync(T **r_data, BL::ID id, BL::ID parent, const K& key)
{
T *data = find(key);
bool recalc;
if(!data) {
/* add data if it didn't exist yet */
data = new T();
scene_data->push_back(data);
b_map[key] = data;
recalc = true;
}
else {
recalc = (b_recalc.find(id.ptr.data) != b_recalc.end());
if(parent.ptr.data)
recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end());
}
used(data);
*r_data = data;
return recalc;
}
void used(T *data)
{
/* tag data as still in use */
used_set.insert(data);
}
void set_default(T *data)
{
b_map[NULL] = data;
}
bool post_sync(bool do_delete = true)
{
/* remove unused data */
vector<T*> new_scene_data;
typename vector<T*>::iterator it;
bool deleted = false;
for(it = scene_data->begin(); it != scene_data->end(); it++) {
T *data = *it;
if(do_delete && used_set.find(data) == used_set.end()) {
delete data;
deleted = true;
}
else
new_scene_data.push_back(data);
}
*scene_data = new_scene_data;
/* update mapping */
map<K, T*> new_map;
typedef pair<const K, T*> TMapPair;
typename map<K, T*>::iterator jt;
for(jt = b_map.begin(); jt != b_map.end(); jt++) {
TMapPair& pair = *jt;
if(used_set.find(pair.second) != used_set.end())
new_map[pair.first] = pair.second;
}
used_set.clear();
b_recalc.clear();
b_map = new_map;
return deleted;
}
protected:
vector<T*> *scene_data;
map<K, T*> b_map;
set<T*> used_set;
set<void*> b_recalc;
};
/* Object Key */
struct ObjectKey {
void *parent;
int index;
void *ob;
ObjectKey(void *parent_, int index_, void *ob_)
: parent(parent_), index(index_), ob(ob_) {}
bool operator<(const ObjectKey& k) const
{ return (parent < k.parent || (parent == k.parent && (index < k.index || (index == k.index && ob < k.ob)))); }
};
CCL_NAMESPACE_END
#endif /* __BLENDER_UTIL_H__ */

@ -0,0 +1,28 @@
set(INC
.
../kernel
../kernel/svm
../render
../util
../device
)
set(SRC
bvh.cpp
bvh_build.cpp
bvh_node.cpp
bvh_sort.cpp
)
set(SRC_HEADERS
bvh.h
bvh_build.h
bvh_node.h
bvh_params.h
bvh_sort.h
)
include_directories(${INC})
add_library(cycles_bvh ${SRC} ${SRC_HEADERS})

701
intern/cycles/bvh/bvh.cpp Normal file

@ -0,0 +1,701 @@
/*
* Adapted from code copyright 2009-2010 NVIDIA Corporation
* Modifications Copyright 2011, Blender Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mesh.h"
#include "object.h"
#include "scene.h"
#include "bvh.h"
#include "bvh_build.h"
#include "bvh_node.h"
#include "bvh_params.h"
#include "util_cache.h"
#include "util_debug.h"
#include "util_foreach.h"
#include "util_map.h"
#include "util_progress.h"
#include "util_types.h"
CCL_NAMESPACE_BEGIN
/* Pack Utility */
struct BVHStackEntry
{
const BVHNode *node;
int idx;
BVHStackEntry(const BVHNode* n = 0, int i = 0)
: 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_visibility);
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_visibility);
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);
pack.prim_visibility.clear();
pack.prim_visibility.resize(tidx_size);
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);
int tob = pack.prim_object[i];
Object *ob = objects[tob];
pack.prim_visibility[i] = ob->visibility;
}
}
}
/* 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;
map<Mesh*, int> mesh_map;
foreach(Object *ob, objects) {
Mesh *mesh = ob->mesh;
BVH *bvh = mesh->bvh;
if(!mesh->transform_applied) {
if(mesh_map.find(mesh) == mesh_map.end()) {
prim_index_size += bvh->pack.prim_index.size();
tri_woop_size += bvh->pack.tri_woop.size();
nodes_size += bvh->pack.nodes.size()*nsize;
mesh_map[mesh] = 1;
}
}
}
mesh_map.clear();
pack.prim_index.resize(prim_index_size);
pack.prim_object.resize(prim_index_size);
pack.prim_visibility.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.size())? &pack.prim_index[0]: NULL;
int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL;
uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL;
float4 *pack_tri_woop = (pack.tri_woop.size())? &pack.tri_woop[0]: NULL;
int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL;
/* 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;
}
/* if mesh already added once, don't add it again, but used set
node offset for this object */
map<Mesh*, int>::iterator it = mesh_map.find(mesh);
if(mesh_map.find(mesh) != mesh_map.end()) {
int noffset = it->second;
pack.object_node[object_offset++] = noffset;
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;
mesh_map[mesh] = pack.object_node[object_offset-1];
/* merge primitive and object indexes */
if(bvh->pack.prim_index.size()) {
size_t bvh_prim_index_size = bvh->pack.prim_index.size();
int *bvh_prim_index = &bvh->pack.prim_index[0];
uint *bvh_prim_visibility = &bvh->pack.prim_visibility[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_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
pack_prim_index_offset++;
}
}
/* merge triangle intersection data */
if(bvh->pack.tri_woop.size()) {
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 */
if( bvh->pack.nodes.size()) {
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, leaf->m_visibility, leaf->m_visibility);
else
/* triangle */
pack_node(e.idx, leaf->m_bounds, leaf->m_bounds, leaf->m_lo, leaf->m_hi, leaf->m_visibility, leaf->m_visibility);
}
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(), e0.node->m_visibility, e1.node->m_visibility);
}
void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1)
{
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, visibility0, visibility1)
};
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;
uint visibility = 0;
refit_node(0, (pack.is_leaf[0])? true: false, bbox, visibility);
}
void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility)
{
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]]);
}
visibility |= ob->visibility;
}
pack_node(idx, bbox, bbox, c0, c1, visibility, visibility);
}
else {
/* refit inner node, set bbox from children */
BoundBox bbox0, bbox1;
uint visibility0 = 0, visibility1 = 0;
refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0);
refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1);
pack_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1);
bbox.grow(bbox0);
bbox.grow(bbox1);
visibility = visibility0|visibility1;
}
}
/* QBVH */
QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_)
: BVH(params_, objects_)
{
params.use_qbvh = true;
/* todo: use visibility */
}
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

155
intern/cycles/bvh/bvh.h Normal file

@ -0,0 +1,155 @@
/*
* 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;
struct 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;
/* visibility visibilitys for primitives */
array<uint> prim_visibility;
/* 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);
virtual ~BVH() {}
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, uint visibility0, uint visibility1);
/* refit */
void refit_nodes();
void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility);
};
/* 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__ */

@ -0,0 +1,549 @@
/*
* 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, 0);
}
else if(num == 1) {
prim_index.push_back(ref[0].prim_index);
prim_object.push_back(ref[0].prim_object);
uint visibility = objects[ref[0].prim_object]->visibility;
return new LeafNode(ref[0].bounds, visibility, 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;
uint visibility = 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);
visibility |= objects[references.back().prim_object]->visibility;
references.pop_back();
num++;
}
}
BVHNode *leaf = NULL;
if(num > 0) {
leaf = new LeafNode(bounds, visibility, 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;
const Reference *ref = (ob_num)? &references.back() - (ob_num - 1): NULL;
BVHNode *oleaf = create_object_leaf_nodes(ref, 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((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z);
int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)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

@ -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__ */

@ -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

@ -0,0 +1,112 @@
/*
* 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 ~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;
uint m_visibility;
// 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;
m_visibility = child0->m_visibility|child1->m_visibility;
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, uint visibility, int lo, int hi)
{
m_bounds = bounds;
m_visibility = visibility;
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__ */

@ -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__ */

@ -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

@ -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__ */

@ -0,0 +1,100 @@
###########################################################################
# GLUT
if(WITH_CYCLES_TEST)
set(GLUT_ROOT_PATH ${CYCLES_GLUT})
find_package(GLUT)
message(STATUS "GLUT_FOUND=${GLUT_FOUND}")
include_directories(${GLUT_INCLUDE_DIR})
endif()
if(WITH_BUILTIN_GLEW)
set(CYCLES_GLEW_LIBRARY extern_glew)
else()
set(CYCLES_GLEW_LIBRARY ${GLEW_LIBRARY})
endif()
###########################################################################
# OpenShadingLanguage
if(WITH_CYCLES_OSL)
set(CYCLES_OSL "" CACHE PATH "Path to OpenShadingLanguage installation")
message(STATUS "CYCLES_OSL = ${CYCLES_OSL}")
find_library(OSL_LIBRARIES NAMES oslexec oslcomp oslquery PATHS ${CYCLES_OSL}/lib ${CYCLES_OSL}/dist)
find_path(OSL_INCLUDES OSL/oslclosure.h PATHS ${CYCLES_OSL}/include ${CYCLES_OSL}/dist)
find_program(OSL_COMPILER NAMES oslc PATHS ${CYCLES_OSL}/bin ${CYCLES_OSL}/dist)
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()
include_directories(${OSL_INCLUDES} ${OSL_INCLUDES}/OSL ${OSL_INCLUDES}/../../../src/liboslexec)
endif()
###########################################################################
# Partio
if(WITH_CYCLES_PARTIO)
set(CYCLES_PARTIO "" CACHE PATH "Path to Partio installation")
message(STATUS "CYCLES_PARTIO = ${CYCLES_PARTIO}")
find_library(PARTIO_LIBRARIES NAMES partio PATHS ${CYCLES_PARTIO}/lib)
find_path(PARTIO_INCLUDES Partio.h ${CYCLES_PARTIO}/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()
include_directories(${PARTIO_INCLUDES})
endif()
###########################################################################
# Blender
if(WITH_CYCLES_BLENDER)
set(BLENDER_INCLUDE_DIRS
${CMAKE_SOURCE_DIR}/intern/guardedalloc
${CMAKE_SOURCE_DIR}/source/blender/makesdna
${CMAKE_SOURCE_DIR}/source/blender/makesrna
${CMAKE_SOURCE_DIR}/source/blender/blenloader
${CMAKE_BINARY_DIR}/source/blender/makesrna/intern)
add_definitions(-DBLENDER_PLUGIN)
endif()
###########################################################################
# CUDA
if(WITH_CYCLES_CUDA_BINARIES)
find_package(CUDA) # Try to auto locate CUDA toolkit
if(CUDA_FOUND)
message(STATUS "CUDA nvcc = ${CUDA_NVCC_EXECUTABLE}")
else()
message(STATUS "CUDA compiler not found, disabling WITH_CYCLES_CUDA_BINARIES")
set(WITH_CYCLES_CUDA_BINARIES OFF)
endif()
endif()

@ -0,0 +1,33 @@
set(INC
.
../kernel
../kernel/svm
../kernel/osl
../util
../render
${OPENGL_INCLUDE_DIR}
${GLEW_INCLUDE_PATH}
)
set(SRC
device.cpp
device_cpu.cpp
device_cuda.cpp
device_multi.cpp
device_network.cpp
device_opencl.cpp
)
set(SRC_HEADERS
device.h
device_memory.h
device_intern.h
device_network.h
)
add_definitions(-DGLEW_STATIC)
include_directories(${INC})
add_library(cycles_device ${SRC} ${SRC_HEADERS})

@ -0,0 +1,222 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include "device.h"
#include "device_intern.h"
#include "util_cuda.h"
#include "util_debug.h"
#include "util_math.h"
#include "util_opencl.h"
#include "util_opengl.h"
#include "util_types.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
/* Device Task */
DeviceTask::DeviceTask(Type type_)
: type(type_), x(0), y(0), w(0), h(0), rng_state(0), rgba(0), buffer(0),
sample(0), resolution(0),
displace_input(0), displace_offset(0), displace_x(0), displace_w(0)
{
}
void DeviceTask::split(ThreadQueue<DeviceTask>& tasks, int num)
{
if(type == DISPLACE) {
num = min(displace_w, num);
for(int i = 0; i < num; i++) {
int tx = displace_x + (displace_w/num)*i;
int tw = (i == num-1)? displace_w - i*(displace_w/num): displace_w/num;
DeviceTask task = *this;
task.displace_x = tx;
task.displace_w = tw;
tasks.push(task);
}
}
else {
num = min(h, num);
for(int i = 0; i < num; i++) {
int ty = y + (h/num)*i;
int th = (i == num-1)? h - i*(h/num): h/num;
DeviceTask task = *this;
task.y = ty;
task.h = th;
tasks.push(task);
}
}
}
/* Device */
void Device::pixels_alloc(device_memory& mem)
{
mem_alloc(mem, MEM_READ_WRITE);
}
void Device::pixels_copy_from(device_memory& mem, int y, int w, int h)
{
mem_copy_from(mem, sizeof(uint8_t)*4*y*w, sizeof(uint8_t)*4*w*h);
}
void Device::pixels_free(device_memory& mem)
{
mem_free(mem);
}
void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int width, int height, bool transparent)
{
pixels_copy_from(rgba, y, w, h);
if(transparent) {
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
glPixelZoom((float)width/(float)w, (float)height/(float)h);
glRasterPos2f(0, y);
uint8_t *pixels = (uint8_t*)rgba.data_pointer;
/* for multi devices, this assumes the ineffecient method that we allocate
all pixels on the device even though we only render to a subset */
pixels += 4*y*w;
glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glRasterPos2f(0.0f, 0.0f);
glPixelZoom(1.0f, 1.0f);
if(transparent)
glDisable(GL_BLEND);
}
Device *Device::create(DeviceType type, bool background, int threads)
{
Device *device;
switch(type) {
case DEVICE_CPU:
device = device_cpu_create(threads);
break;
#ifdef WITH_CUDA
case DEVICE_CUDA:
if(cuLibraryInit())
device = device_cuda_create(background);
else
device = NULL;
break;
#endif
#ifdef WITH_MULTI
case DEVICE_MULTI:
device = device_multi_create(background);
break;
#endif
#ifdef WITH_NETWORK
case DEVICE_NETWORK:
device = device_network_create("127.0.0.1");
break;
#endif
#ifdef WITH_OPENCL
case DEVICE_OPENCL:
if(clLibraryInit())
device = device_opencl_create(background);
else
device = NULL;
break;
#endif
default:
return NULL;
}
return device;
}
DeviceType Device::type_from_string(const char *name)
{
if(strcmp(name, "cpu") == 0)
return DEVICE_CPU;
else if(strcmp(name, "cuda") == 0)
return DEVICE_CUDA;
else if(strcmp(name, "opencl") == 0)
return DEVICE_OPENCL;
else if(strcmp(name, "network") == 0)
return DEVICE_NETWORK;
else if(strcmp(name, "multi") == 0)
return DEVICE_MULTI;
return DEVICE_NONE;
}
string Device::string_from_type(DeviceType type)
{
if(type == DEVICE_CPU)
return "cpu";
else if(type == DEVICE_CUDA)
return "cuda";
else if(type == DEVICE_OPENCL)
return "opencl";
else if(type == DEVICE_NETWORK)
return "network";
else if(type == DEVICE_MULTI)
return "multi";
return "";
}
vector<DeviceType> Device::available_types()
{
vector<DeviceType> types;
types.push_back(DEVICE_CPU);
#ifdef WITH_CUDA
if(cuLibraryInit())
types.push_back(DEVICE_CUDA);
#endif
#ifdef WITH_OPENCL
if(clLibraryInit())
types.push_back(DEVICE_OPENCL);
#endif
#ifdef WITH_NETWORK
types.push_back(DEVICE_NETWORK);
#endif
#ifdef WITH_MULTI
types.push_back(DEVICE_MULTI);
#endif
return types;
}
CCL_NAMESPACE_END

@ -0,0 +1,140 @@
/*
* 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 __DEVICE_H__
#define __DEVICE_H__
#include <stdlib.h>
#include "device_memory.h"
#include "util_string.h"
#include "util_thread.h"
#include "util_types.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
class Progress;
enum DeviceType {
DEVICE_NONE,
DEVICE_CPU,
DEVICE_OPENCL,
DEVICE_CUDA,
DEVICE_NETWORK,
DEVICE_MULTI
};
enum MemoryType {
MEM_READ_ONLY,
MEM_WRITE_ONLY,
MEM_READ_WRITE
};
/* Device Task */
class DeviceTask {
public:
typedef enum { PATH_TRACE, TONEMAP, DISPLACE } Type;
Type type;
int x, y, w, h;
device_ptr rng_state;
device_ptr rgba;
device_ptr buffer;
int sample;
int resolution;
device_ptr displace_input;
device_ptr displace_offset;
int displace_x, displace_w;
DeviceTask(Type type = PATH_TRACE);
void split(ThreadQueue<DeviceTask>& tasks, int num);
};
/* Device */
class Device {
protected:
Device() {}
bool background;
public:
virtual ~Device() {}
virtual bool support_full_kernel() = 0;
/* info */
virtual string description() = 0;
/* regular memory */
virtual void mem_alloc(device_memory& mem, MemoryType type) = 0;
virtual void mem_copy_to(device_memory& mem) = 0;
virtual void mem_copy_from(device_memory& mem,
size_t offset, size_t size) = 0;
virtual void mem_zero(device_memory& mem) = 0;
virtual void mem_free(device_memory& mem) = 0;
/* constant memory */
virtual void const_copy_to(const char *name, void *host, size_t size) = 0;
/* texture memory */
virtual void tex_alloc(const char *name, device_memory& mem,
bool interpolation = false, bool periodic = false) {};
virtual void tex_free(device_memory& mem) {};
/* pixel memory */
virtual void pixels_alloc(device_memory& mem);
virtual void pixels_copy_from(device_memory& mem, int y, int w, int h);
virtual void pixels_free(device_memory& mem);
/* open shading language, only for CPU device */
virtual void *osl_memory() { return NULL; }
/* load/compile kernels, must be called before adding tasks */
virtual bool load_kernels() { return true; }
/* tasks */
virtual void task_add(DeviceTask& task) = 0;
virtual void task_wait() = 0;
virtual void task_cancel() = 0;
/* opengl drawing */
virtual void draw_pixels(device_memory& mem, int y, int w, int h,
int width, int height, bool transparent);
#ifdef WITH_NETWORK
/* networking */
void server_run();
#endif
/* static */
static Device *create(DeviceType type, bool background = true, int threads = 0);
static DeviceType type_from_string(const char *name);
static string string_from_type(DeviceType type);
static vector<DeviceType> available_types();
};
CCL_NAMESPACE_END
#endif /* __DEVICE_H__ */

@ -0,0 +1,263 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include "device.h"
#include "device_intern.h"
#include "kernel.h"
#include "kernel_types.h"
#include "osl_shader.h"
#include "util_debug.h"
#include "util_foreach.h"
#include "util_function.h"
#include "util_opengl.h"
#include "util_progress.h"
#include "util_system.h"
#include "util_thread.h"
CCL_NAMESPACE_BEGIN
class CPUDevice : public Device
{
public:
vector<thread*> threads;
ThreadQueue<DeviceTask> tasks;
KernelGlobals *kg;
CPUDevice(int threads_num)
{
kg = kernel_globals_create();
/* do now to avoid thread issues */
system_cpu_support_optimized();
if(threads_num == 0)
threads_num = system_cpu_thread_count();
threads.resize(threads_num);
for(size_t i = 0; i < threads.size(); i++)
threads[i] = new thread(function_bind(&CPUDevice::thread_run, this, i));
}
~CPUDevice()
{
tasks.stop();
foreach(thread *t, threads) {
t->join();
delete t;
}
kernel_globals_free(kg);
}
bool support_full_kernel()
{
return true;
}
string description()
{
return system_cpu_brand_string();
}
void mem_alloc(device_memory& mem, MemoryType type)
{
mem.device_pointer = mem.data_pointer;
}
void mem_copy_to(device_memory& mem)
{
/* no-op */
}
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
{
/* no-op */
}
void mem_zero(device_memory& mem)
{
memset((void*)mem.device_pointer, 0, mem.memory_size());
}
void mem_free(device_memory& mem)
{
mem.device_pointer = 0;
}
void const_copy_to(const char *name, void *host, size_t size)
{
kernel_const_copy(kg, name, host, size);
}
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
{
kernel_tex_copy(kg, name, mem.data_pointer, mem.data_width, mem.data_height);
mem.device_pointer = mem.data_pointer;
}
void tex_free(device_memory& mem)
{
mem.device_pointer = 0;
}
void *osl_memory()
{
#ifdef WITH_OSL
return kernel_osl_memory(kg);
#else
return NULL;
#endif
}
void thread_run(int t)
{
DeviceTask task;
while(tasks.worker_wait_pop(task)) {
if(task.type == DeviceTask::PATH_TRACE)
thread_path_trace(task);
else if(task.type == DeviceTask::TONEMAP)
thread_tonemap(task);
else if(task.type == DeviceTask::DISPLACE)
thread_displace(task);
tasks.worker_done();
}
}
void thread_path_trace(DeviceTask& task)
{
if(tasks.worker_cancel())
return;
#ifdef WITH_OSL
if(kernel_osl_use(kg))
OSLShader::thread_init(kg);
#endif
#ifdef WITH_OPTIMIZED_KERNEL
if(system_cpu_support_optimized()) {
for(int y = task.y; y < task.y + task.h; y++) {
for(int x = task.x; x < task.x + task.w; x++)
kernel_cpu_optimized_path_trace(kg, (float4*)task.buffer, (unsigned int*)task.rng_state, task.sample, x, y);
if(tasks.worker_cancel())
break;
}
}
else
#endif
{
for(int y = task.y; y < task.y + task.h; y++) {
for(int x = task.x; x < task.x + task.w; x++)
kernel_cpu_path_trace(kg, (float4*)task.buffer, (unsigned int*)task.rng_state, task.sample, x, y);
if(tasks.worker_cancel())
break;
}
}
#ifdef WITH_OSL
if(kernel_osl_use(kg))
OSLShader::thread_free(kg);
#endif
}
void thread_tonemap(DeviceTask& task)
{
#ifdef WITH_OPTIMIZED_KERNEL
if(system_cpu_support_optimized()) {
for(int y = task.y; y < task.y + task.h; y++)
for(int x = task.x; x < task.x + task.w; x++)
kernel_cpu_optimized_tonemap(kg, (uchar4*)task.rgba, (float4*)task.buffer, task.sample, task.resolution, x, y);
}
else
#endif
{
for(int y = task.y; y < task.y + task.h; y++)
for(int x = task.x; x < task.x + task.w; x++)
kernel_cpu_tonemap(kg, (uchar4*)task.rgba, (float4*)task.buffer, task.sample, task.resolution, x, y);
}
}
void thread_displace(DeviceTask& task)
{
#ifdef WITH_OSL
if(kernel_osl_use(kg))
OSLShader::thread_init(kg);
#endif
#ifdef WITH_OPTIMIZED_KERNEL
if(system_cpu_support_optimized()) {
for(int x = task.displace_x; x < task.displace_x + task.displace_w; x++) {
kernel_cpu_optimized_displace(kg, (uint4*)task.displace_input, (float3*)task.displace_offset, x);
if(tasks.worker_cancel())
break;
}
}
else
#endif
{
for(int x = task.displace_x; x < task.displace_x + task.displace_w; x++) {
kernel_cpu_displace(kg, (uint4*)task.displace_input, (float3*)task.displace_offset, x);
if(tasks.worker_cancel())
break;
}
}
#ifdef WITH_OSL
if(kernel_osl_use(kg))
OSLShader::thread_free(kg);
#endif
}
void task_add(DeviceTask& task)
{
/* split task into smaller ones, more than number of threads for uneven
workloads where some parts of the image render slower than others */
task.split(tasks, threads.size()*10);
}
void task_wait()
{
tasks.wait_done();
}
void task_cancel()
{
tasks.cancel();
}
};
Device *device_cpu_create(int threads)
{
return new CPUDevice(threads);
}
CCL_NAMESPACE_END

@ -0,0 +1,809 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include "device.h"
#include "device_intern.h"
#include "util_cuda.h"
#include "util_debug.h"
#include "util_map.h"
#include "util_opengl.h"
#include "util_path.h"
#include "util_system.h"
#include "util_types.h"
#include "util_time.h"
CCL_NAMESPACE_BEGIN
class CUDADevice : public Device
{
public:
CUdevice cuDevice;
CUcontext cuContext;
CUmodule cuModule;
map<device_ptr, bool> tex_interp_map;
int cuDevId;
struct PixelMem {
GLuint cuPBO;
CUgraphicsResource cuPBOresource;
GLuint cuTexId;
int w, h;
};
map<device_ptr, PixelMem> pixel_mem_map;
CUdeviceptr cuda_device_ptr(device_ptr mem)
{
return (CUdeviceptr)mem;
}
const char *cuda_error_string(CUresult result)
{
switch(result) {
case CUDA_SUCCESS: return "No errors";
case CUDA_ERROR_INVALID_VALUE: return "Invalid value";
case CUDA_ERROR_OUT_OF_MEMORY: return "Out of memory";
case CUDA_ERROR_NOT_INITIALIZED: return "Driver not initialized";
case CUDA_ERROR_DEINITIALIZED: return "Driver deinitialized";
case CUDA_ERROR_NO_DEVICE: return "No CUDA-capable device available";
case CUDA_ERROR_INVALID_DEVICE: return "Invalid device";
case CUDA_ERROR_INVALID_IMAGE: return "Invalid kernel image";
case CUDA_ERROR_INVALID_CONTEXT: return "Invalid context";
case CUDA_ERROR_CONTEXT_ALREADY_CURRENT: return "Context already current";
case CUDA_ERROR_MAP_FAILED: return "Map failed";
case CUDA_ERROR_UNMAP_FAILED: return "Unmap failed";
case CUDA_ERROR_ARRAY_IS_MAPPED: return "Array is mapped";
case CUDA_ERROR_ALREADY_MAPPED: return "Already mapped";
case CUDA_ERROR_NO_BINARY_FOR_GPU: return "No binary for GPU";
case CUDA_ERROR_ALREADY_ACQUIRED: return "Already acquired";
case CUDA_ERROR_NOT_MAPPED: return "Not mapped";
case CUDA_ERROR_NOT_MAPPED_AS_ARRAY: return "Mapped resource not available for access as an array";
case CUDA_ERROR_NOT_MAPPED_AS_POINTER: return "Mapped resource not available for access as a pointer";
case CUDA_ERROR_ECC_UNCORRECTABLE: return "Uncorrectable ECC error detected";
case CUDA_ERROR_UNSUPPORTED_LIMIT: return "CUlimit not supported by device";
case CUDA_ERROR_INVALID_SOURCE: return "Invalid source";
case CUDA_ERROR_FILE_NOT_FOUND: return "File not found";
case CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND: return "Link to a shared object failed to resolve";
case CUDA_ERROR_SHARED_OBJECT_INIT_FAILED: return "Shared object initialization failed";
case CUDA_ERROR_INVALID_HANDLE: return "Invalid handle";
case CUDA_ERROR_NOT_FOUND: return "Not found";
case CUDA_ERROR_NOT_READY: return "CUDA not ready";
case CUDA_ERROR_LAUNCH_FAILED: return "Launch failed";
case CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES: return "Launch exceeded resources";
case CUDA_ERROR_LAUNCH_TIMEOUT: return "Launch exceeded timeout";
case CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING: return "Launch with incompatible texturing";
case CUDA_ERROR_UNKNOWN: return "Unknown error";
default: return "Unknown CUDA error value";
}
}
static int cuda_align_up(int& offset, int alignment)
{
return (offset + alignment - 1) & ~(alignment - 1);
}
#ifdef NDEBUG
#define cuda_abort()
#else
#define cuda_abort() abort()
#endif
#define cuda_assert(stmt) \
{ \
CUresult result = stmt; \
\
if(result != CUDA_SUCCESS) { \
fprintf(stderr, "CUDA error: %s in %s\n", cuda_error_string(result), #stmt); \
cuda_abort(); \
} \
}
bool cuda_error(CUresult result)
{
if(result == CUDA_SUCCESS)
return false;
fprintf(stderr, "CUDA error: %s\n", cuda_error_string(result));
return true;
}
void cuda_push_context()
{
cuda_assert(cuCtxSetCurrent(cuContext))
}
void cuda_pop_context()
{
cuda_assert(cuCtxSetCurrent(NULL));
}
CUDADevice(bool background_)
{
background = background_;
cuDevId = 0;
cuDevice = 0;
cuContext = 0;
/* intialize */
if(cuda_error(cuInit(0)))
return;
/* setup device and context */
if(cuda_error(cuDeviceGet(&cuDevice, cuDevId)))
return;
CUresult result;
if(background)
result = cuCtxCreate(&cuContext, 0, cuDevice);
else
result = cuGLCtxCreate(&cuContext, 0, cuDevice);
if(cuda_error(result))
return;
cuda_pop_context();
}
~CUDADevice()
{
cuda_push_context();
cuda_assert(cuCtxDetach(cuContext))
}
bool support_full_kernel()
{
int major, minor;
cuDeviceComputeCapability(&major, &minor, cuDevId);
return (major >= 2);
}
string description()
{
/* print device information */
char deviceName[100];
cuda_push_context();
cuDeviceGetName(deviceName, 256, cuDevId);
cuda_pop_context();
return string("CUDA ") + deviceName;
}
string compile_kernel()
{
/* compute cubin name */
int major, minor;
cuDeviceComputeCapability(&major, &minor, cuDevId);
/* attempt to use kernel provided with blender */
string cubin = path_get(string_printf("lib/kernel_sm_%d%d.cubin", major, minor));
if(path_exists(cubin))
return cubin;
/* not found, try to use locally compiled kernel */
string kernel_path = path_get("kernel");
string md5 = path_files_md5_hash(kernel_path);
cubin = string_printf("cycles_kernel_sm%d%d_%s.cubin", major, minor, md5.c_str());;
cubin = path_user_get(path_join("cache", cubin));
/* if exists already, use it */
if(path_exists(cubin))
return cubin;
#ifdef WITH_CUDA_BINARIES
fprintf(stderr, "CUDA binary kernel for this graphics card not found.\n");
return "";
#else
/* if not, find CUDA compiler */
string nvcc = cuCompilerPath();
if(nvcc == "") {
fprintf(stderr, "CUDA nvcc compiler not found. Install CUDA toolkit in default location.\n");
return "";
}
/* compile */
string kernel = path_join(kernel_path, "kernel.cu");
string include = kernel_path;
const int machine = system_cpu_bits();
const int maxreg = 24;
double starttime = time_dt();
printf("Compiling CUDA kernel ...\n");
path_create_directories(cubin);
string command = string_printf("\"%s\" -arch=sm_%d%d -m%d --cubin \"%s\" --use_fast_math "
"-o \"%s\" --ptxas-options=\"-v\" --maxrregcount=%d --opencc-options -OPT:Olimit=0 -I\"%s\" -DNVCC",
nvcc.c_str(), major, minor, machine, kernel.c_str(), cubin.c_str(), maxreg, include.c_str());
if(system(command.c_str()) == -1) {
fprintf(stderr, "Failed to execute compilation command.\n");
return "";
}
/* verify if compilation succeeded */
if(!path_exists(cubin)) {
fprintf(stderr, "CUDA kernel compilation failed.\n");
return "";
}
printf("Kernel compilation finished in %.2lfs.\n", time_dt() - starttime);
return cubin;
#endif
}
bool load_kernels()
{
/* check if cuda init succeeded */
if(cuContext == 0)
return false;
/* get kernel */
string cubin = compile_kernel();
if(cubin == "")
return false;
/* open module */
cuda_push_context();
CUresult result = cuModuleLoad(&cuModule, cubin.c_str());
if(cuda_error(result))
fprintf(stderr, "Failed loading CUDA kernel %s.\n", cubin.c_str());
cuda_pop_context();
return (result == CUDA_SUCCESS);
}
void mem_alloc(device_memory& mem, MemoryType type)
{
cuda_push_context();
CUdeviceptr device_pointer;
cuda_assert(cuMemAlloc(&device_pointer, mem.memory_size()))
mem.device_pointer = (device_ptr)device_pointer;
cuda_pop_context();
}
void mem_copy_to(device_memory& mem)
{
cuda_push_context();
cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size()))
cuda_pop_context();
}
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
{
/* todo: offset is ignored */
cuda_push_context();
cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset,
(CUdeviceptr)((uchar*)mem.device_pointer + offset), size))
cuda_pop_context();
}
void mem_zero(device_memory& mem)
{
memset((void*)mem.data_pointer, 0, mem.memory_size());
cuda_push_context();
cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size()))
cuda_pop_context();
}
void mem_free(device_memory& mem)
{
if(mem.device_pointer) {
cuda_push_context();
cuda_assert(cuMemFree(cuda_device_ptr(mem.device_pointer)))
cuda_pop_context();
mem.device_pointer = 0;
}
}
void const_copy_to(const char *name, void *host, size_t size)
{
CUdeviceptr mem;
size_t bytes;
cuda_push_context();
cuda_assert(cuModuleGetGlobal(&mem, &bytes, cuModule, name))
//assert(bytes == size);
cuda_assert(cuMemcpyHtoD(mem, host, size))
cuda_pop_context();
}
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
{
/* determine format */
CUarray_format_enum format;
size_t dsize = datatype_size(mem.data_type);
size_t size = mem.memory_size();
switch(mem.data_type) {
case TYPE_UCHAR: format = CU_AD_FORMAT_UNSIGNED_INT8; break;
case TYPE_UINT: format = CU_AD_FORMAT_UNSIGNED_INT32; break;
case TYPE_INT: format = CU_AD_FORMAT_SIGNED_INT32; break;
case TYPE_FLOAT: format = CU_AD_FORMAT_FLOAT; break;
default: assert(0); return;
}
CUtexref texref;
cuda_push_context();
cuda_assert(cuModuleGetTexRef(&texref, cuModule, name))
if(interpolation) {
CUarray handle;
CUDA_ARRAY_DESCRIPTOR desc;
desc.Width = mem.data_width;
desc.Height = mem.data_height;
desc.Format = format;
desc.NumChannels = mem.data_elements;
cuda_assert(cuArrayCreate(&handle, &desc))
if(mem.data_height > 1) {
CUDA_MEMCPY2D param;
memset(&param, 0, sizeof(param));
param.dstMemoryType = CU_MEMORYTYPE_ARRAY;
param.dstArray = handle;
param.srcMemoryType = CU_MEMORYTYPE_HOST;
param.srcHost = (void*)mem.data_pointer;
param.srcPitch = mem.data_width*dsize*mem.data_elements;
param.WidthInBytes = param.srcPitch;
param.Height = mem.data_height;
cuda_assert(cuMemcpy2D(&param))
}
else
cuda_assert(cuMemcpyHtoA(handle, 0, (void*)mem.data_pointer, size))
cuda_assert(cuTexRefSetArray(texref, handle, CU_TRSA_OVERRIDE_FORMAT))
cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_LINEAR))
cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_NORMALIZED_COORDINATES))
mem.device_pointer = (device_ptr)handle;
}
else {
cuda_pop_context();
mem_alloc(mem, MEM_READ_ONLY);
mem_copy_to(mem);
cuda_push_context();
cuda_assert(cuTexRefSetAddress(NULL, texref, cuda_device_ptr(mem.device_pointer), size))
cuda_assert(cuTexRefSetFilterMode(texref, CU_TR_FILTER_MODE_POINT))
cuda_assert(cuTexRefSetFlags(texref, CU_TRSF_READ_AS_INTEGER))
}
if(periodic) {
cuda_assert(cuTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_WRAP))
cuda_assert(cuTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_WRAP))
}
else {
cuda_assert(cuTexRefSetAddressMode(texref, 0, CU_TR_ADDRESS_MODE_CLAMP))
cuda_assert(cuTexRefSetAddressMode(texref, 1, CU_TR_ADDRESS_MODE_CLAMP))
}
cuda_assert(cuTexRefSetFormat(texref, format, mem.data_elements))
cuda_pop_context();
tex_interp_map[mem.device_pointer] = interpolation;
}
void tex_free(device_memory& mem)
{
if(mem.device_pointer) {
if(tex_interp_map[mem.device_pointer]) {
cuda_push_context();
cuArrayDestroy((CUarray)mem.device_pointer);
cuda_pop_context();
tex_interp_map.erase(tex_interp_map.find(mem.device_pointer));
mem.device_pointer = 0;
}
else {
tex_interp_map.erase(tex_interp_map.find(mem.device_pointer));
mem_free(mem);
}
}
}
void path_trace(DeviceTask& task)
{
cuda_push_context();
CUfunction cuPathTrace;
CUdeviceptr d_buffer = cuda_device_ptr(task.buffer);
CUdeviceptr d_rng_state = cuda_device_ptr(task.rng_state);
/* get kernel function */
cuda_assert(cuModuleGetFunction(&cuPathTrace, cuModule, "kernel_cuda_path_trace"))
/* pass in parameters */
int offset = 0;
cuda_assert(cuParamSetv(cuPathTrace, offset, &d_buffer, sizeof(d_buffer)))
offset += sizeof(d_buffer);
cuda_assert(cuParamSetv(cuPathTrace, offset, &d_rng_state, sizeof(d_rng_state)))
offset += sizeof(d_rng_state);
int sample = task.sample;
offset = cuda_align_up(offset, __alignof(sample));
cuda_assert(cuParamSeti(cuPathTrace, offset, task.sample))
offset += sizeof(task.sample);
cuda_assert(cuParamSeti(cuPathTrace, offset, task.x))
offset += sizeof(task.x);
cuda_assert(cuParamSeti(cuPathTrace, offset, task.y))
offset += sizeof(task.y);
cuda_assert(cuParamSeti(cuPathTrace, offset, task.w))
offset += sizeof(task.w);
cuda_assert(cuParamSeti(cuPathTrace, offset, task.h))
offset += sizeof(task.h);
cuda_assert(cuParamSetSize(cuPathTrace, offset))
/* launch kernel: todo find optimal size, cache config for fermi */
#ifndef __APPLE__
int xthreads = 16;
int ythreads = 16;
#else
int xthreads = 8;
int ythreads = 8;
#endif
int xblocks = (task.w + xthreads - 1)/xthreads;
int yblocks = (task.h + ythreads - 1)/ythreads;
cuda_assert(cuFuncSetCacheConfig(cuPathTrace, CU_FUNC_CACHE_PREFER_L1))
cuda_assert(cuFuncSetBlockShape(cuPathTrace, xthreads, ythreads, 1))
cuda_assert(cuLaunchGrid(cuPathTrace, xblocks, yblocks))
cuda_pop_context();
}
void tonemap(DeviceTask& task)
{
cuda_push_context();
CUfunction cuFilmConvert;
CUdeviceptr d_rgba = map_pixels(task.rgba);
CUdeviceptr d_buffer = cuda_device_ptr(task.buffer);
/* get kernel function */
cuda_assert(cuModuleGetFunction(&cuFilmConvert, cuModule, "kernel_cuda_tonemap"))
/* pass in parameters */
int offset = 0;
cuda_assert(cuParamSetv(cuFilmConvert, offset, &d_rgba, sizeof(d_rgba)))
offset += sizeof(d_rgba);
cuda_assert(cuParamSetv(cuFilmConvert, offset, &d_buffer, sizeof(d_buffer)))
offset += sizeof(d_buffer);
int sample = task.sample;
offset = cuda_align_up(offset, __alignof(sample));
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.sample))
offset += sizeof(task.sample);
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.resolution))
offset += sizeof(task.resolution);
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.x))
offset += sizeof(task.x);
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.y))
offset += sizeof(task.y);
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.w))
offset += sizeof(task.w);
cuda_assert(cuParamSeti(cuFilmConvert, offset, task.h))
offset += sizeof(task.h);
cuda_assert(cuParamSetSize(cuFilmConvert, offset))
/* launch kernel: todo find optimal size, cache config for fermi */
#ifndef __APPLE__
int xthreads = 16;
int ythreads = 16;
#else
int xthreads = 8;
int ythreads = 8;
#endif
int xblocks = (task.w + xthreads - 1)/xthreads;
int yblocks = (task.h + ythreads - 1)/ythreads;
cuda_assert(cuFuncSetCacheConfig(cuFilmConvert, CU_FUNC_CACHE_PREFER_L1))
cuda_assert(cuFuncSetBlockShape(cuFilmConvert, xthreads, ythreads, 1))
cuda_assert(cuLaunchGrid(cuFilmConvert, xblocks, yblocks))
unmap_pixels(task.rgba);
cuda_pop_context();
}
void displace(DeviceTask& task)
{
cuda_push_context();
CUfunction cuDisplace;
CUdeviceptr d_input = cuda_device_ptr(task.displace_input);
CUdeviceptr d_offset = cuda_device_ptr(task.displace_offset);
/* get kernel function */
cuda_assert(cuModuleGetFunction(&cuDisplace, cuModule, "kernel_cuda_displace"))
/* pass in parameters */
int offset = 0;
cuda_assert(cuParamSetv(cuDisplace, offset, &d_input, sizeof(d_input)))
offset += sizeof(d_input);
cuda_assert(cuParamSetv(cuDisplace, offset, &d_offset, sizeof(d_offset)))
offset += sizeof(d_offset);
int displace_x = task.displace_x;
offset = cuda_align_up(offset, __alignof(displace_x));
cuda_assert(cuParamSeti(cuDisplace, offset, task.displace_x))
offset += sizeof(task.displace_x);
cuda_assert(cuParamSetSize(cuDisplace, offset))
/* launch kernel: todo find optimal size, cache config for fermi */
#ifndef __APPLE__
int xthreads = 16;
#else
int xthreads = 8;
#endif
int xblocks = (task.displace_w + xthreads - 1)/xthreads;
cuda_assert(cuFuncSetCacheConfig(cuDisplace, CU_FUNC_CACHE_PREFER_L1))
cuda_assert(cuFuncSetBlockShape(cuDisplace, xthreads, 1, 1))
cuda_assert(cuLaunchGrid(cuDisplace, xblocks, 1))
cuda_pop_context();
}
CUdeviceptr map_pixels(device_ptr mem)
{
if(!background) {
PixelMem pmem = pixel_mem_map[mem];
CUdeviceptr buffer;
size_t bytes;
cuda_assert(cuGraphicsMapResources(1, &pmem.cuPBOresource, 0))
cuda_assert(cuGraphicsResourceGetMappedPointer(&buffer, &bytes, pmem.cuPBOresource))
return buffer;
}
return cuda_device_ptr(mem);
}
void unmap_pixels(device_ptr mem)
{
if(!background) {
PixelMem pmem = pixel_mem_map[mem];
cuda_assert(cuGraphicsUnmapResources(1, &pmem.cuPBOresource, 0))
}
}
void pixels_alloc(device_memory& mem)
{
if(!background) {
PixelMem pmem;
pmem.w = mem.data_width;
pmem.h = mem.data_height;
cuda_push_context();
glGenBuffers(1, &pmem.cuPBO);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
glBufferData(GL_PIXEL_UNPACK_BUFFER, pmem.w*pmem.h*sizeof(GLfloat)*3, NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glGenTextures(1, &pmem.cuTexId);
glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pmem.w, pmem.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
cuda_assert(cuGraphicsGLRegisterBuffer(&pmem.cuPBOresource, pmem.cuPBO, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE))
cuda_pop_context();
mem.device_pointer = pmem.cuTexId;
pixel_mem_map[mem.device_pointer] = pmem;
return;
}
Device::pixels_alloc(mem);
}
void pixels_copy_from(device_memory& mem, int y, int w, int h)
{
if(!background) {
PixelMem pmem = pixel_mem_map[mem.device_pointer];
cuda_push_context();
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO);
uchar *pixels = (uchar*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_ONLY);
size_t offset = sizeof(uchar)*4*y*w;
memcpy((uchar*)mem.data_pointer + offset, pixels + offset, sizeof(uchar)*4*w*h);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
cuda_pop_context();
return;
}
Device::pixels_copy_from(mem, y, w, h);
}
void pixels_free(device_memory& mem)
{
if(mem.device_pointer) {
if(!background) {
PixelMem pmem = pixel_mem_map[mem.device_pointer];
cuda_push_context();
cuda_assert(cuGraphicsUnregisterResource(pmem.cuPBOresource))
glDeleteBuffers(1, &pmem.cuPBO);
glDeleteTextures(1, &pmem.cuTexId);
cuda_pop_context();
pixel_mem_map.erase(pixel_mem_map.find(mem.device_pointer));
mem.device_pointer = 0;
return;
}
Device::pixels_free(mem);
}
}
void draw_pixels(device_memory& mem, int y, int w, int h, int width, int height, bool transparent)
{
if(!background) {
PixelMem pmem = pixel_mem_map[mem.device_pointer];
cuda_push_context();
/* for multi devices, this assumes the ineffecient method that we allocate
all pixels on the device even though we only render to a subset */
size_t offset = sizeof(uint8_t)*4*y*w;
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pmem.cuPBO);
glBindTexture(GL_TEXTURE_2D, pmem.cuTexId);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)offset);
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
glEnable(GL_TEXTURE_2D);
if(transparent) {
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
glColor3f(1.0f, 1.0f, 1.0f);
glPushMatrix();
glTranslatef(0.0f, (float)y, 0.0f);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, 0.0f);
glTexCoord2f((float)w/(float)pmem.w, 0.0f);
glVertex2f((float)width, 0.0f);
glTexCoord2f((float)w/(float)pmem.w, (float)h/(float)pmem.h);
glVertex2f((float)width, (float)height);
glTexCoord2f(0.0f, (float)h/(float)pmem.h);
glVertex2f(0.0f, (float)height);
glEnd();
glPopMatrix();
if(transparent)
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
cuda_pop_context();
return;
}
Device::draw_pixels(mem, y, w, h, width, height, transparent);
}
void task_add(DeviceTask& task)
{
if(task.type == DeviceTask::TONEMAP)
tonemap(task);
else if(task.type == DeviceTask::PATH_TRACE)
path_trace(task);
else if(task.type == DeviceTask::DISPLACE)
displace(task);
}
void task_wait()
{
cuda_push_context();
cuda_assert(cuCtxSynchronize())
cuda_pop_context();
}
void task_cancel()
{
}
};
Device *device_cuda_create(bool background)
{
return new CUDADevice(background);
}
CCL_NAMESPACE_END

@ -0,0 +1,35 @@
/*
* 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 __DEVICE_INTERN_H__
#define __DEVICE_INTERN_H__
CCL_NAMESPACE_BEGIN
class Device;
Device *device_cpu_create(int threads);
Device *device_opencl_create(bool background);
Device *device_cuda_create(bool background);
Device *device_network_create(const char *address);
Device *device_multi_create(bool background);
CCL_NAMESPACE_END
#endif /* __DEVICE_INTERN_H__ */

@ -0,0 +1,244 @@
/*
* 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 __DEVICE_MEMORY_H__
#define __DEVICE_MEMORY_H__
/* Device Memory
*
* This file defines data types that can be used in device memory arrays, and
* a device_vector<T> type to store such arrays.
*
* device_vector<T> contains an STL vector, metadata about the data type,
* dimensions, elements, and a device pointer. For the CPU device this is just
* a pointer to the STL vector data, as no copying needs to take place. For
* other devices this is a pointer to device memory, where we will copy memory
* to and from. */
#include "util_debug.h"
#include "util_types.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
/* Supported Data Types */
enum DataType {
TYPE_UCHAR,
TYPE_UINT,
TYPE_INT,
TYPE_FLOAT
};
static inline size_t datatype_size(DataType datatype)
{
switch(datatype) {
case TYPE_UCHAR: return sizeof(uchar);
case TYPE_FLOAT: return sizeof(float);
case TYPE_UINT: return sizeof(uint);
case TYPE_INT: return sizeof(int);
default: return 0;
}
}
/* Traits for data types */
template<typename T> struct device_type_traits {
static const DataType data_type = TYPE_UCHAR;
static const int num_elements = 0;
};
template<> struct device_type_traits<uchar> {
static const DataType data_type = TYPE_UCHAR;
static const int num_elements = 1;
};
template<> struct device_type_traits<uchar2> {
static const DataType data_type = TYPE_UCHAR;
static const int num_elements = 2;
};
template<> struct device_type_traits<uchar3> {
static const DataType data_type = TYPE_UCHAR;
static const int num_elements = 3;
};
template<> struct device_type_traits<uchar4> {
static const DataType data_type = TYPE_UCHAR;
static const int num_elements = 4;
};
template<> struct device_type_traits<uint> {
static const DataType data_type = TYPE_UINT;
static const int num_elements = 1;
};
template<> struct device_type_traits<uint2> {
static const DataType data_type = TYPE_UINT;
static const int num_elements = 2;
};
template<> struct device_type_traits<uint3> {
static const DataType data_type = TYPE_UINT;
static const int num_elements = 3;
};
template<> struct device_type_traits<uint4> {
static const DataType data_type = TYPE_UINT;
static const int num_elements = 4;
};
template<> struct device_type_traits<int> {
static const DataType data_type = TYPE_INT;
static const int num_elements = 1;
};
template<> struct device_type_traits<int2> {
static const DataType data_type = TYPE_INT;
static const int num_elements = 2;
};
template<> struct device_type_traits<int3> {
static const DataType data_type = TYPE_INT;
static const int num_elements = 3;
};
template<> struct device_type_traits<int4> {
static const DataType data_type = TYPE_INT;
static const int num_elements = 4;
};
template<> struct device_type_traits<float> {
static const DataType data_type = TYPE_FLOAT;
static const int num_elements = 1;
};
template<> struct device_type_traits<float2> {
static const DataType data_type = TYPE_FLOAT;
static const int num_elements = 2;
};
template<> struct device_type_traits<float3> {
static const DataType data_type = TYPE_FLOAT;
static const int num_elements = 3;
};
template<> struct device_type_traits<float4> {
static const DataType data_type = TYPE_FLOAT;
static const int num_elements = 4;
};
/* Device Memory */
class device_memory
{
public:
size_t memory_size() { return data_size*data_elements*datatype_size(data_type); }
/* data information */
DataType data_type;
int data_elements;
device_ptr data_pointer;
size_t data_size;
size_t data_width;
size_t data_height;
/* device pointer */
device_ptr device_pointer;
protected:
device_memory() {}
virtual ~device_memory() { assert(!device_pointer); }
/* no copying */
device_memory(const device_memory&);
device_memory& operator = (const device_memory&);
};
/* Device Vector */
template<typename T> class device_vector : public device_memory
{
public:
device_vector()
{
data_type = device_type_traits<T>::data_type;
data_elements = device_type_traits<T>::num_elements;
data_pointer = 0;
data_size = 0;
data_width = 0;
data_height = 0;
assert(data_elements > 0);
device_pointer = 0;
}
virtual ~device_vector() {}
/* vector functions */
T *resize(size_t width, size_t height = 0)
{
data_size = (height == 0)? width: width*height;
data.resize(data_size);
data_pointer = (device_ptr)&data[0];
data_width = width;
data_height = height;
return &data[0];
}
T *copy(T *ptr, size_t width, size_t height = 0)
{
T *mem = resize(width, height);
memcpy(mem, ptr, memory_size());
return mem;
}
void reference(T *ptr, size_t width, size_t height = 0)
{
data.clear();
data_size = (height == 0)? width: width*height;
data_pointer = (device_ptr)ptr;
data_width = width;
data_height = height;
}
void clear()
{
data.clear();
data_pointer = 0;
data_width = 0;
data_height = 0;
data_size = 0;
}
size_t size()
{
return data.size();
}
private:
array<T> data;
bool referenced;
};
CCL_NAMESPACE_END
#endif /* __DEVICE_MEMORY_H__ */

@ -0,0 +1,336 @@
/*
* 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 <stdlib.h>
#include <sstream>
#include "device.h"
#include "device_intern.h"
#include "device_network.h"
#include "util_foreach.h"
#include "util_list.h"
#include "util_map.h"
#include "util_time.h"
CCL_NAMESPACE_BEGIN
class MultiDevice : public Device
{
public:
struct SubDevice {
SubDevice(Device *device_)
: device(device_) {}
Device *device;
map<device_ptr, device_ptr> ptr_map;
};
list<SubDevice> devices;
device_ptr unique_ptr;
MultiDevice(bool background_)
: unique_ptr(1)
{
Device *device;
/* add CPU device */
device = Device::create(DEVICE_CPU, background);
devices.push_back(SubDevice(device));
#ifdef WITH_CUDA
/* try to add GPU device */
device = Device::create(DEVICE_CUDA, background);
if(device) {
devices.push_back(SubDevice(device));
}
else
#endif
{
#ifdef WITH_OPENCL
device = Device::create(DEVICE_OPENCL, background);
if(device)
devices.push_back(SubDevice(device));
#endif
}
#ifdef WITH_NETWORK
/* try to add network devices */
ServerDiscovery discovery(true);
time_sleep(1.0);
list<string> servers = discovery.get_server_list();
foreach(string& server, servers) {
device = device_network_create(server.c_str());
if(device)
devices.push_back(SubDevice(device));
}
#endif
}
~MultiDevice()
{
foreach(SubDevice& sub, devices)
delete sub.device;
}
bool support_full_kernel()
{
foreach(SubDevice& sub, devices) {
if(!sub.device->support_full_kernel())
return false;
}
return true;
}
string description()
{
/* create map to find duplicate descriptions */
map<string, int> dupli_map;
map<string, int>::iterator dt;
foreach(SubDevice& sub, devices) {
string key = sub.device->description();
if(dupli_map.find(key) == dupli_map.end())
dupli_map[key] = 1;
else
dupli_map[key]++;
}
/* generate string */
stringstream desc;
bool first = true;
for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
if(!first) desc << ", ";
first = false;
if(dt->second > 1)
desc << dt->second << "x " << dt->first;
else
desc << dt->first;
}
return desc.str();
}
bool load_kernels()
{
foreach(SubDevice& sub, devices)
if(!sub.device->load_kernels())
return false;
return true;
}
void mem_alloc(device_memory& mem, MemoryType type)
{
foreach(SubDevice& sub, devices) {
mem.device_pointer = 0;
sub.device->mem_alloc(mem, type);
sub.ptr_map[unique_ptr] = mem.device_pointer;
}
mem.device_pointer = unique_ptr++;
}
void mem_copy_to(device_memory& mem)
{
device_ptr tmp = mem.device_pointer;
foreach(SubDevice& sub, devices) {
mem.device_pointer = sub.ptr_map[tmp];
sub.device->mem_copy_to(mem);
}
mem.device_pointer = tmp;
}
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
{
device_ptr tmp = mem.device_pointer;
/* todo: how does this work? */
foreach(SubDevice& sub, devices) {
mem.device_pointer = sub.ptr_map[tmp];
sub.device->mem_copy_from(mem, offset, size);
break;
}
mem.device_pointer = tmp;
}
void mem_zero(device_memory& mem)
{
device_ptr tmp = mem.device_pointer;
foreach(SubDevice& sub, devices) {
mem.device_pointer = sub.ptr_map[tmp];
sub.device->mem_zero(mem);
}
mem.device_pointer = tmp;
}
void mem_free(device_memory& mem)
{
device_ptr tmp = mem.device_pointer;
foreach(SubDevice& sub, devices) {
mem.device_pointer = sub.ptr_map[tmp];
sub.device->mem_free(mem);
sub.ptr_map.erase(sub.ptr_map.find(tmp));
}
mem.device_pointer = 0;
}
void const_copy_to(const char *name, void *host, size_t size)
{
foreach(SubDevice& sub, devices)
sub.device->const_copy_to(name, host, size);
}
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
{
foreach(SubDevice& sub, devices) {
mem.device_pointer = 0;
sub.device->tex_alloc(name, mem, interpolation, periodic);
sub.ptr_map[unique_ptr] = mem.device_pointer;
}
mem.device_pointer = unique_ptr++;
}
void tex_free(device_memory& mem)
{
device_ptr tmp = mem.device_pointer;
foreach(SubDevice& sub, devices) {
mem.device_pointer = sub.ptr_map[tmp];
sub.device->tex_free(mem);
sub.ptr_map.erase(sub.ptr_map.find(tmp));
}
mem.device_pointer = 0;
}
void pixels_alloc(device_memory& mem)
{
foreach(SubDevice& sub, devices) {
mem.device_pointer = 0;
sub.device->pixels_alloc(mem);
sub.ptr_map[unique_ptr] = mem.device_pointer;
}
mem.device_pointer = unique_ptr++;
}
void pixels_free(device_memory& mem)
{
device_ptr tmp = mem.device_pointer;
foreach(SubDevice& sub, devices) {
mem.device_pointer = sub.ptr_map[tmp];
sub.device->pixels_free(mem);
sub.ptr_map.erase(sub.ptr_map.find(tmp));
}
mem.device_pointer = 0;
}
void pixels_copy_from(device_memory& mem, int y, int w, int h)
{
device_ptr tmp = mem.device_pointer;
int i = 0, sub_h = h/devices.size();
foreach(SubDevice& sub, devices) {
int sy = y + i*sub_h;
int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
mem.device_pointer = sub.ptr_map[tmp];
sub.device->pixels_copy_from(mem, sy, w, sh);
i++;
}
mem.device_pointer = tmp;
}
void draw_pixels(device_memory& rgba, int y, int w, int h, int width, int height, bool transparent)
{
device_ptr tmp = rgba.device_pointer;
int i = 0, sub_h = h/devices.size();
int sub_height = height/devices.size();
foreach(SubDevice& sub, devices) {
int sy = y + i*sub_h;
int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
int sheight = (i == (int)devices.size() - 1)? height - sub_height*i: sub_height;
/* adjust math for w/width */
rgba.device_pointer = sub.ptr_map[tmp];
sub.device->draw_pixels(rgba, sy, w, sh, width, sheight, transparent);
i++;
}
rgba.device_pointer = tmp;
}
void task_add(DeviceTask& task)
{
ThreadQueue<DeviceTask> tasks;
task.split(tasks, devices.size());
foreach(SubDevice& sub, devices) {
DeviceTask subtask;
if(tasks.worker_wait_pop(subtask)) {
if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
if(task.rng_state) subtask.rng_state = sub.ptr_map[task.rng_state];
if(task.rgba) subtask.rgba = sub.ptr_map[task.rgba];
if(task.displace_input) subtask.displace_input = sub.ptr_map[task.displace_input];
if(task.displace_offset) subtask.displace_offset = sub.ptr_map[task.displace_offset];
sub.device->task_add(subtask);
}
}
}
void task_wait()
{
foreach(SubDevice& sub, devices)
sub.device->task_wait();
}
void task_cancel()
{
foreach(SubDevice& sub, devices)
sub.device->task_cancel();
}
};
Device *device_multi_create(bool background)
{
return new MultiDevice(background);
}
CCL_NAMESPACE_END

@ -0,0 +1,391 @@
/*
* 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 "device.h"
#include "device_intern.h"
#include "device_network.h"
#include "util_foreach.h"
CCL_NAMESPACE_BEGIN
#ifdef WITH_NETWORK
class NetworkDevice : public Device
{
public:
boost::asio::io_service io_service;
tcp::socket socket;
NetworkDevice(const char *address)
: socket(io_service)
{
stringstream portstr;
portstr << SERVER_PORT;
tcp::resolver resolver(io_service);
tcp::resolver::query query(address, portstr.str());
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;
boost::system::error_code error = boost::asio::error::host_not_found;
while(error && endpoint_iterator != end)
{
socket.close();
socket.connect(*endpoint_iterator++, error);
}
if(error)
throw boost::system::system_error(error);
}
~NetworkDevice()
{
}
bool support_full_kernel()
{
return false;
}
string description()
{
RPCSend snd(socket, "description");
snd.write();
RPCReceive rcv(socket);
string desc_string;
*rcv.archive & desc_string;
return desc_string + " (remote)";
}
void mem_alloc(device_memory& mem, MemoryType type)
{
#if 0
RPCSend snd(socket, "mem_alloc");
snd.archive & size & type;
snd.write();
RPCReceive rcv(socket);
device_ptr mem;
*rcv.archive & mem;
return mem;
#endif
}
void mem_copy_to(device_memory& mem)
{
#if 0
RPCSend snd(socket, "mem_copy_to");
snd.archive & mem & size;
snd.write();
snd.write_buffer(host, size);
#endif
}
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
{
#if 0
RPCSend snd(socket, "mem_copy_from");
snd.archive & mem & offset & size;
snd.write();
RPCReceive rcv(socket);
rcv.read_buffer(host, size);
#endif
}
void mem_zero(device_memory& mem)
{
#if 0
RPCSend snd(socket, "mem_zero");
snd.archive & mem & size;
snd.write();
#endif
}
void mem_free(device_memory& mem)
{
#if 0
if(mem) {
RPCSend snd(socket, "mem_free");
snd.archive & mem;
snd.write();
}
#endif
}
void const_copy_to(const char *name, void *host, size_t size)
{
RPCSend snd(socket, "const_copy_to");
string name_string(name);
snd.archive & name_string & size;
snd.write();
snd.write_buffer(host, size);
}
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
{
#if 0
RPCSend snd(socket, "tex_alloc");
string name_string(name);
snd.archive & name_string & width & height & datatype & components & interpolation;
snd.write();
size_t size = width*height*components*datatype_size(datatype);
snd.write_buffer(host, size);
RPCReceive rcv(socket);
device_ptr mem;
*rcv.archive & mem;
return mem;
#endif
}
void tex_free(device_memory& mem)
{
#if 0
if(mem) {
RPCSend snd(socket, "tex_free");
snd.archive & mem;
snd.write();
}
#endif
}
void path_trace(int x, int y, int w, int h, device_ptr buffer, device_ptr rng_state, int sample)
{
#if 0
RPCSend snd(socket, "path_trace");
snd.archive & x & y & w & h & buffer & rng_state & sample;
snd.write();
#endif
}
void tonemap(int x, int y, int w, int h, device_ptr rgba, device_ptr buffer, int sample, int resolution)
{
#if 0
RPCSend snd(socket, "tonemap");
snd.archive & x & y & w & h & rgba & buffer & sample & resolution;
snd.write();
#endif
}
void task_add(DeviceTask& task)
{
if(task.type == DeviceTask::TONEMAP)
tonemap(task.x, task.y, task.w, task.h, task.rgba, task.buffer, task.sample, task.resolution);
else if(task.type == DeviceTask::PATH_TRACE)
path_trace(task.x, task.y, task.w, task.h, task.buffer, task.rng_state, task.sample);
}
void task_wait()
{
}
void task_cancel()
{
}
};
Device *device_network_create(const char *address)
{
return new NetworkDevice(address);
}
void Device::server_run()
{
try
{
/* starts thread that responds to discovery requests */
ServerDiscovery discovery;
for(;;)
{
/* accept connection */
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), SERVER_PORT));
tcp::socket socket(io_service);
acceptor.accept(socket);
/* receive remote function calls */
for(;;) {
RPCReceive rcv(socket);
if(rcv.name == "description") {
string desc = description();
RPCSend snd(socket);
snd.archive & desc;
snd.write();
}
else if(rcv.name == "mem_alloc") {
#if 0
MemoryType type;
size_t size;
device_ptr mem;
*rcv.archive & size & type;
mem = mem_alloc(size, type);
RPCSend snd(socket);
snd.archive & mem;
snd.write();
#endif
}
else if(rcv.name == "mem_copy_to") {
#if 0
device_ptr mem;
size_t size;
*rcv.archive & mem & size;
vector<char> host_vector(size);
rcv.read_buffer(&host_vector[0], size);
mem_copy_to(mem, &host_vector[0], size);
#endif
}
else if(rcv.name == "mem_copy_from") {
#if 0
device_ptr mem;
size_t offset, size;
*rcv.archive & mem & offset & size;
vector<char> host_vector(size);
mem_copy_from(&host_vector[0], mem, offset, size);
RPCSend snd(socket);
snd.write();
snd.write_buffer(&host_vector[0], size);
#endif
}
else if(rcv.name == "mem_zero") {
#if 0
device_ptr mem;
size_t size;
*rcv.archive & mem & size;
mem_zero(mem, size);
#endif
}
else if(rcv.name == "mem_free") {
#if 0
device_ptr mem;
*rcv.archive & mem;
mem_free(mem);
#endif
}
else if(rcv.name == "const_copy_to") {
string name_string;
size_t size;
*rcv.archive & name_string & size;
vector<char> host_vector(size);
rcv.read_buffer(&host_vector[0], size);
const_copy_to(name_string.c_str(), &host_vector[0], size);
}
else if(rcv.name == "tex_alloc") {
#if 0
string name_string;
DataType datatype;
device_ptr mem;
size_t width, height;
int components;
bool interpolation;
*rcv.archive & name_string & width & height & datatype & components & interpolation;
size_t size = width*height*components*datatype_size(datatype);
vector<char> host_vector(size);
rcv.read_buffer(&host_vector[0], size);
mem = tex_alloc(name_string.c_str(), &host_vector[0], width, height, datatype, components, interpolation);
RPCSend snd(socket);
snd.archive & mem;
snd.write();
#endif
}
else if(rcv.name == "tex_free") {
#if 0
device_ptr mem;
*rcv.archive & mem;
tex_free(mem);
#endif
}
else if(rcv.name == "path_trace") {
#if 0
device_ptr buffer, rng_state;
int x, y, w, h;
int sample;
*rcv.archive & x & y & w & h & buffer & rng_state & sample;
path_trace(x, y, w, h, buffer, rng_state, sample);
#endif
}
else if(rcv.name == "tonemap") {
#if 0
device_ptr rgba, buffer;
int x, y, w, h;
int sample, resolution;
*rcv.archive & x & y & w & h & rgba & buffer & sample & resolution;
tonemap(x, y, w, h, rgba, buffer, sample, resolution);
#endif
}
}
}
}
catch(exception& e)
{
cerr << "Network server exception: " << e.what() << endl;
}
}
#endif
CCL_NAMESPACE_END

@ -0,0 +1,308 @@
/*
* 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 __DEVICE_NETWORK_H__
#define __DEVICE_NETWORK_H__
#ifdef WITH_NETWORK
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/thread.hpp>
#include <iostream>
#include "util_foreach.h"
#include "util_list.h"
#include "util_string.h"
CCL_NAMESPACE_BEGIN
using std::cout;
using std::cerr;
using std::endl;
using std::hex;
using std::setw;
using std::exception;
using boost::asio::ip::tcp;
static const int SERVER_PORT = 5120;
static const int DISCOVER_PORT = 5121;
static const string DISCOVER_REQUEST_MSG = "REQUEST_RENDER_SERVER_IP";
static const string DISCOVER_REPLY_MSG = "REPLY_RENDER_SERVER_IP";
typedef struct RPCSend {
RPCSend(tcp::socket& socket_, const string& name_ = "")
: name(name_), socket(socket_), archive(archive_stream)
{
archive & name_;
}
void write()
{
boost::system::error_code error;
/* get string from stream */
string archive_str = archive_stream.str();
/* first send fixed size header with size of following data */
ostringstream header_stream;
header_stream << setw(8) << hex << archive_str.size();
string header_str = header_stream.str();
boost::asio::write(socket,
boost::asio::buffer(header_str),
boost::asio::transfer_all(), error);
if(error.value())
cout << "Network send error: " << error.message() << "\n";
/* then send actual data */
boost::asio::write(socket,
boost::asio::buffer(archive_str),
boost::asio::transfer_all(), error);
if(error.value())
cout << "Network send error: " << error.message() << "\n";
}
void write_buffer(void *buffer, size_t size)
{
boost::system::error_code error;
boost::asio::write(socket,
boost::asio::buffer(buffer, size),
boost::asio::transfer_all(), error);
if(error.value())
cout << "Network send error: " << error.message() << "\n";
}
string name;
tcp::socket& socket;
ostringstream archive_stream;
boost::archive::text_oarchive archive;
} RPCSend;
typedef struct RPCReceive {
RPCReceive(tcp::socket& socket_)
: socket(socket_), archive_stream(NULL), archive(NULL)
{
/* read head with fixed size */
vector<char> header(8);
size_t len = boost::asio::read(socket, boost::asio::buffer(header));
/* verify if we got something */
if(len == header.size()) {
/* decode header */
string header_str(&header[0], header.size());
istringstream header_stream(header_str);
size_t data_size;
if((header_stream >> hex >> data_size)) {
vector<char> data(data_size);
size_t len = boost::asio::read(socket, boost::asio::buffer(data));
if(len == data_size) {
archive_str = (data.size())? string(&data[0], data.size()): string("");
/*istringstream archive_stream(archive_str);
boost::archive::text_iarchive archive(archive_stream);*/
archive_stream = new istringstream(archive_str);
archive = new boost::archive::text_iarchive(*archive_stream);
*archive & name;
}
else
cout << "Network receive error: data size doens't match header\n";
}
else
cout << "Network receive error: can't decode data size from header\n";
}
else
cout << "Network receive error: invalid header size\n";
}
~RPCReceive()
{
delete archive;
delete archive_stream;
}
void read_buffer(void *buffer, size_t size)
{
size_t len = boost::asio::read(socket, boost::asio::buffer(buffer, size));
if(len != size)
cout << "Network receive error: buffer size doesn't match expected size\n";
}
string name;
tcp::socket& socket;
string archive_str;
istringstream *archive_stream;
boost::archive::text_iarchive *archive;
} RPCReceive;
class ServerDiscovery {
public:
ServerDiscovery(bool discover = false)
: listen_socket(io_service), collect_servers(false)
{
/* setup listen socket */
listen_endpoint.address(boost::asio::ip::address_v4::any());
listen_endpoint.port(DISCOVER_PORT);
listen_socket.open(listen_endpoint.protocol());
boost::asio::socket_base::reuse_address option(true);
listen_socket.set_option(option);
listen_socket.bind(listen_endpoint);
/* setup receive callback */
async_receive();
/* start server discovery */
if(discover) {
collect_servers = true;
servers.clear();
broadcast_message(DISCOVER_REQUEST_MSG);
}
/* start thread */
work = new boost::asio::io_service::work(io_service);
thread = new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service));
}
~ServerDiscovery()
{
io_service.stop();
thread->join();
delete thread;
delete work;
}
list<string> get_server_list()
{
list<string> result;
mutex.lock();
result = servers;
mutex.unlock();
return result;
}
private:
void handle_receive_from(const boost::system::error_code& error, size_t size)
{
if(error) {
cout << "Server discovery receive error: " << error.message() << "\n";
return;
}
if(size > 0) {
string msg = string(receive_buffer, size);
/* handle incoming message */
if(collect_servers) {
if(msg == DISCOVER_REPLY_MSG) {
string address = receive_endpoint.address().to_string();
mutex.lock();
/* add address if it's not already in the list */
bool found = false;
foreach(string& server, servers)
if(server == address)
found = true;
if(!found)
servers.push_back(address);
mutex.unlock();
}
}
else {
/* reply to request */
if(msg == DISCOVER_REQUEST_MSG)
broadcast_message(DISCOVER_REPLY_MSG);
}
}
async_receive();
}
void async_receive()
{
listen_socket.async_receive_from(
boost::asio::buffer(receive_buffer), receive_endpoint,
boost::bind(&ServerDiscovery::handle_receive_from, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void broadcast_message(const string& msg)
{
/* setup broadcast socket */
boost::asio::ip::udp::socket socket(io_service);
socket.open(boost::asio::ip::udp::v4());
boost::asio::socket_base::broadcast option(true);
socket.set_option(option);
boost::asio::ip::udp::endpoint broadcast_endpoint(
boost::asio::ip::address::from_string("255.255.255.255"), DISCOVER_PORT);
/* broadcast message */
socket.send_to(boost::asio::buffer(msg), broadcast_endpoint);
}
/* network service and socket */
boost::asio::io_service io_service;
boost::asio::ip::udp::endpoint listen_endpoint;
boost::asio::ip::udp::socket listen_socket;
/* threading */
boost::thread *thread;
boost::asio::io_service::work *work;
boost::mutex mutex;
/* buffer and endpoint for receiving messages */
char receive_buffer[256];
boost::asio::ip::udp::endpoint receive_endpoint;
/* collection of server addresses in list */
bool collect_servers;
list<string> servers;
};
CCL_NAMESPACE_END
#endif
#endif /* __DEVICE_NETWORK_H__ */

@ -0,0 +1,663 @@
/*
* 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.
*/
#ifdef WITH_OPENCL
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "device.h"
#include "device_intern.h"
#include "util_map.h"
#include "util_math.h"
#include "util_md5.h"
#include "util_opencl.h"
#include "util_opengl.h"
#include "util_path.h"
#include "util_time.h"
CCL_NAMESPACE_BEGIN
#define CL_MEM_PTR(p) ((cl_mem)(unsigned long)(p))
class OpenCLDevice : public Device
{
public:
cl_context cxContext;
cl_command_queue cqCommandQueue;
cl_platform_id cpPlatform;
cl_device_id cdDevice;
cl_program cpProgram;
cl_kernel ckPathTraceKernel;
cl_kernel ckFilmConvertKernel;
cl_int ciErr;
map<string, device_vector<uchar>*> const_mem_map;
map<string, device_memory*> mem_map;
device_ptr null_mem;
bool device_initialized;
const char *opencl_error_string(cl_int err)
{
switch (err) {
case CL_SUCCESS: return "Success!";
case CL_DEVICE_NOT_FOUND: return "Device not found.";
case CL_DEVICE_NOT_AVAILABLE: return "Device not available";
case CL_COMPILER_NOT_AVAILABLE: return "Compiler not available";
case CL_MEM_OBJECT_ALLOCATION_FAILURE: return "Memory object allocation failure";
case CL_OUT_OF_RESOURCES: return "Out of resources";
case CL_OUT_OF_HOST_MEMORY: return "Out of host memory";
case CL_PROFILING_INFO_NOT_AVAILABLE: return "Profiling information not available";
case CL_MEM_COPY_OVERLAP: return "Memory copy overlap";
case CL_IMAGE_FORMAT_MISMATCH: return "Image format mismatch";
case CL_IMAGE_FORMAT_NOT_SUPPORTED: return "Image format not supported";
case CL_BUILD_PROGRAM_FAILURE: return "Program build failure";
case CL_MAP_FAILURE: return "Map failure";
case CL_INVALID_VALUE: return "Invalid value";
case CL_INVALID_DEVICE_TYPE: return "Invalid device type";
case CL_INVALID_PLATFORM: return "Invalid platform";
case CL_INVALID_DEVICE: return "Invalid device";
case CL_INVALID_CONTEXT: return "Invalid context";
case CL_INVALID_QUEUE_PROPERTIES: return "Invalid queue properties";
case CL_INVALID_COMMAND_QUEUE: return "Invalid command queue";
case CL_INVALID_HOST_PTR: return "Invalid host pointer";
case CL_INVALID_MEM_OBJECT: return "Invalid memory object";
case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: return "Invalid image format descriptor";
case CL_INVALID_IMAGE_SIZE: return "Invalid image size";
case CL_INVALID_SAMPLER: return "Invalid sampler";
case CL_INVALID_BINARY: return "Invalid binary";
case CL_INVALID_BUILD_OPTIONS: return "Invalid build options";
case CL_INVALID_PROGRAM: return "Invalid program";
case CL_INVALID_PROGRAM_EXECUTABLE: return "Invalid program executable";
case CL_INVALID_KERNEL_NAME: return "Invalid kernel name";
case CL_INVALID_KERNEL_DEFINITION: return "Invalid kernel definition";
case CL_INVALID_KERNEL: return "Invalid kernel";
case CL_INVALID_ARG_INDEX: return "Invalid argument index";
case CL_INVALID_ARG_VALUE: return "Invalid argument value";
case CL_INVALID_ARG_SIZE: return "Invalid argument size";
case CL_INVALID_KERNEL_ARGS: return "Invalid kernel arguments";
case CL_INVALID_WORK_DIMENSION: return "Invalid work dimension";
case CL_INVALID_WORK_GROUP_SIZE: return "Invalid work group size";
case CL_INVALID_WORK_ITEM_SIZE: return "Invalid work item size";
case CL_INVALID_GLOBAL_OFFSET: return "Invalid global offset";
case CL_INVALID_EVENT_WAIT_LIST: return "Invalid event wait list";
case CL_INVALID_EVENT: return "Invalid event";
case CL_INVALID_OPERATION: return "Invalid operation";
case CL_INVALID_GL_OBJECT: return "Invalid OpenGL object";
case CL_INVALID_BUFFER_SIZE: return "Invalid buffer size";
case CL_INVALID_MIP_LEVEL: return "Invalid mip-map level";
default: return "Unknown";
}
}
bool opencl_error(cl_int err)
{
if(err != CL_SUCCESS) {
fprintf(stderr, "OpenCL error (%d): %s\n", err, opencl_error_string(err));
return true;
}
return false;
}
void opencl_assert(cl_int err)
{
if(err != CL_SUCCESS) {
fprintf(stderr, "OpenCL error (%d): %s\n", err, opencl_error_string(err));
#ifndef NDEBUG
abort();
#endif
}
}
OpenCLDevice(bool background_)
{
background = background_;
cpPlatform = NULL;
cxContext = NULL;
cqCommandQueue = NULL;
cpProgram = NULL;
ckPathTraceKernel = NULL;
ckFilmConvertKernel = NULL;
null_mem = 0;
device_initialized = false;
vector<cl_platform_id> platform_ids;
cl_uint num_platforms;
/* setup device */
ciErr = clGetPlatformIDs(0, NULL, &num_platforms);
if(opencl_error(ciErr))
return;
if(num_platforms == 0) {
fprintf(stderr, "OpenCL: no platforms found.\n");
return;
}
platform_ids.resize(num_platforms);
ciErr = clGetPlatformIDs(num_platforms, &platform_ids[0], NULL);
if(opencl_error(ciErr))
return;
cpPlatform = platform_ids[0]; /* todo: pick specified platform && device */
ciErr = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU|CL_DEVICE_TYPE_ACCELERATOR, 1, &cdDevice, NULL);
if(opencl_error(ciErr))
return;
cxContext = clCreateContext(0, 1, &cdDevice, NULL, NULL, &ciErr);
if(opencl_error(ciErr))
return;
cqCommandQueue = clCreateCommandQueue(cxContext, cdDevice, 0, &ciErr);
if(opencl_error(ciErr))
return;
null_mem = (device_ptr)clCreateBuffer(cxContext, CL_MEM_READ_ONLY, 1, NULL, &ciErr);
device_initialized = true;
}
bool opencl_version_check()
{
char version[256];
int major, minor, req_major = 1, req_minor = 1;
clGetPlatformInfo(cpPlatform, CL_PLATFORM_VERSION, sizeof(version), &version, NULL);
if(sscanf(version, "OpenCL %d.%d", &major, &minor) < 2) {
fprintf(stderr, "OpenCL: failed to parse platform version string (%s).", version);
return false;
}
if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
fprintf(stderr, "OpenCL: platform version 1.1 or later required, found %d.%d\n", major, minor);
return false;
}
clGetDeviceInfo(cdDevice, CL_DEVICE_OPENCL_C_VERSION, sizeof(version), &version, NULL);
if(sscanf(version, "OpenCL C %d.%d", &major, &minor) < 2) {
fprintf(stderr, "OpenCL: failed to parse OpenCL C version string (%s).", version);
return false;
}
if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
fprintf(stderr, "OpenCL: C version 1.1 or later required, found %d.%d\n", major, minor);
return false;
}
/* we don't check CL_DEVICE_VERSION since for e.g. nvidia sm 1.3 cards this is
1.0 even if the language features are there, just limited shared memory */
return true;
}
bool load_binary(const string& kernel_path, const string& clbin)
{
/* read binary into memory */
vector<uint8_t> binary;
if(!path_read_binary(clbin, binary)) {
fprintf(stderr, "OpenCL failed to read cached binary %s.\n", clbin.c_str());
return false;
}
/* create program */
cl_int status;
size_t size = binary.size();
const uint8_t *bytes = &binary[0];
cpProgram = clCreateProgramWithBinary(cxContext, 1, &cdDevice,
&size, &bytes, &status, &ciErr);
if(opencl_error(status) || opencl_error(ciErr)) {
fprintf(stderr, "OpenCL failed create program from cached binary %s.\n", clbin.c_str());
return false;
}
if(!build_kernel(kernel_path))
return false;
return true;
}
bool save_binary(const string& clbin)
{
size_t size = 0;
clGetProgramInfo(cpProgram, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &size, NULL);
if(!size)
return false;
vector<uint8_t> binary(size);
uint8_t *bytes = &binary[0];
clGetProgramInfo(cpProgram, CL_PROGRAM_BINARIES, sizeof(uint8_t*), &bytes, NULL);
if(!path_write_binary(clbin, binary)) {
fprintf(stderr, "OpenCL failed to write cached binary %s.\n", clbin.c_str());
return false;
}
return true;
}
bool build_kernel(const string& kernel_path)
{
string build_options = "";
build_options += "-I " + kernel_path + ""; /* todo: escape path */
build_options += " -cl-fast-relaxed-math ";
/* Full Shading only on NVIDIA cards at the moment */
char vendor[256];
clGetPlatformInfo(cpPlatform, CL_PLATFORM_NAME, sizeof(vendor), &vendor, NULL);
string name = vendor;
if (name == "NVIDIA CUDA") {
build_options += "-D __SVM__ ";
build_options += "-D __EMISSION__ ";
build_options += "-D __TEXTURES__ ";
build_options += "-D __HOLDOUT__ ";
build_options += "-D __MULTI_CLOSURE__ ";
}
ciErr = clBuildProgram(cpProgram, 0, NULL, build_options.c_str(), NULL, NULL);
if(ciErr != CL_SUCCESS) {
/* show build errors */
char *build_log;
size_t ret_val_size;
clGetProgramBuildInfo(cpProgram, cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
build_log = new char[ret_val_size+1];
clGetProgramBuildInfo(cpProgram, cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
build_log[ret_val_size] = '\0';
fprintf(stderr, "OpenCL build failed:\n %s\n", build_log);
delete[] build_log;
return false;
}
return true;
}
bool compile_kernel(const string& kernel_path, const string& kernel_md5)
{
/* we compile kernels consisting of many files. unfortunately opencl
kernel caches do not seem to recognize changes in included files.
so we force recompile on changes by adding the md5 hash of all files */
string source = "#include \"kernel.cl\" // " + kernel_md5 + "\n";
size_t source_len = source.size();
const char *source_str = source.c_str();
cpProgram = clCreateProgramWithSource(cxContext, 1, &source_str, &source_len, &ciErr);
if(opencl_error(ciErr))
return false;
double starttime = time_dt();
printf("Compiling OpenCL kernel ...\n");
if(!build_kernel(kernel_path))
return false;
printf("Kernel compilation finished in %.2lfs.\n", time_dt() - starttime);
return true;
}
string device_md5_hash()
{
MD5Hash md5;
char version[256], driver[256], name[256], vendor[256];
clGetPlatformInfo(cpPlatform, CL_PLATFORM_VENDOR, sizeof(vendor), &vendor, NULL);
clGetDeviceInfo(cdDevice, CL_DEVICE_VERSION, sizeof(version), &version, NULL);
clGetDeviceInfo(cdDevice, CL_DEVICE_NAME, sizeof(name), &name, NULL);
clGetDeviceInfo(cdDevice, CL_DRIVER_VERSION, sizeof(driver), &driver, NULL);
md5.append((uint8_t*)vendor, strlen(vendor));
md5.append((uint8_t*)version, strlen(version));
md5.append((uint8_t*)name, strlen(name));
md5.append((uint8_t*)driver, strlen(driver));
return md5.get_hex();
}
bool load_kernels()
{
/* verify if device was initialized */
if(!device_initialized) {
fprintf(stderr, "OpenCL: failed to initialize device.\n");
return false;
}
/* verify we have right opencl version */
if(!opencl_version_check())
return false;
/* md5 hash to detect changes */
string kernel_path = path_get("kernel");
string kernel_md5 = path_files_md5_hash(kernel_path);
string device_md5 = device_md5_hash();
/* try to use cache binary */
string clbin = string_printf("cycles_kernel_%s_%s.clbin", device_md5.c_str(), kernel_md5.c_str());;
clbin = path_user_get(path_join("cache", clbin));
if(path_exists(clbin)) {
/* if exists already, try use it */
if(!load_binary(kernel_path, clbin))
return false;
}
else {
/* compile kernel */
if(!compile_kernel(kernel_path, kernel_md5))
return false;
/* save binary for reuse */
save_binary(clbin);
}
/* find kernels */
ckPathTraceKernel = clCreateKernel(cpProgram, "kernel_ocl_path_trace", &ciErr);
if(opencl_error(ciErr))
return false;
ckFilmConvertKernel = clCreateKernel(cpProgram, "kernel_ocl_tonemap", &ciErr);
if(opencl_error(ciErr))
return false;
return true;
}
~OpenCLDevice()
{
if(null_mem)
clReleaseMemObject(CL_MEM_PTR(null_mem));
map<string, device_vector<uchar>*>::iterator mt;
for(mt = const_mem_map.begin(); mt != const_mem_map.end(); mt++) {
mem_free(*(mt->second));
delete mt->second;
}
if(ckPathTraceKernel)
clReleaseKernel(ckPathTraceKernel);
if(ckFilmConvertKernel)
clReleaseKernel(ckFilmConvertKernel);
if(cpProgram)
clReleaseProgram(cpProgram);
if(cqCommandQueue)
clReleaseCommandQueue(cqCommandQueue);
if(cxContext)
clReleaseContext(cxContext);
}
bool support_full_kernel()
{
return false;
}
string description()
{
char name[1024];
clGetDeviceInfo(cdDevice, CL_DEVICE_NAME, sizeof(name), &name, NULL);
return string("OpenCL ") + name;
}
void mem_alloc(device_memory& mem, MemoryType type)
{
size_t size = mem.memory_size();
if(type == MEM_READ_ONLY)
mem.device_pointer = (device_ptr)clCreateBuffer(cxContext, CL_MEM_READ_ONLY, size, NULL, &ciErr);
else if(type == MEM_WRITE_ONLY)
mem.device_pointer = (device_ptr)clCreateBuffer(cxContext, CL_MEM_WRITE_ONLY, size, NULL, &ciErr);
else
mem.device_pointer = (device_ptr)clCreateBuffer(cxContext, CL_MEM_READ_WRITE, size, NULL, &ciErr);
opencl_assert(ciErr);
}
void mem_copy_to(device_memory& mem)
{
/* this is blocking */
size_t size = mem.memory_size();
ciErr = clEnqueueWriteBuffer(cqCommandQueue, CL_MEM_PTR(mem.device_pointer), CL_TRUE, 0, size, (void*)mem.data_pointer, 0, NULL, NULL);
opencl_assert(ciErr);
}
void mem_copy_from(device_memory& mem, size_t offset, size_t size)
{
ciErr = clEnqueueReadBuffer(cqCommandQueue, CL_MEM_PTR(mem.device_pointer), CL_TRUE, offset, size, (uchar*)mem.data_pointer + offset, 0, NULL, NULL);
opencl_assert(ciErr);
}
void mem_zero(device_memory& mem)
{
if(mem.device_pointer) {
memset((void*)mem.data_pointer, 0, mem.memory_size());
mem_copy_to(mem);
}
}
void mem_free(device_memory& mem)
{
if(mem.device_pointer) {
ciErr = clReleaseMemObject(CL_MEM_PTR(mem.device_pointer));
mem.device_pointer = 0;
opencl_assert(ciErr);
}
}
void const_copy_to(const char *name, void *host, size_t size)
{
if(const_mem_map.find(name) == const_mem_map.end()) {
device_vector<uchar> *data = new device_vector<uchar>();
data->copy((uchar*)host, size);
mem_alloc(*data, MEM_READ_ONLY);
const_mem_map[name] = data;
}
else {
device_vector<uchar> *data = const_mem_map[name];
data->copy((uchar*)host, size);
}
mem_copy_to(*const_mem_map[name]);
}
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
{
mem_alloc(mem, MEM_READ_ONLY);
mem_copy_to(mem);
mem_map[name] = &mem;
}
void tex_free(device_memory& mem)
{
if(mem.data_pointer)
mem_free(mem);
}
size_t global_size_round_up(int group_size, int global_size)
{
int r = global_size % group_size;
return global_size + ((r == 0)? 0: group_size - r);
}
void path_trace(DeviceTask& task)
{
/* cast arguments to cl types */
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
cl_mem d_buffer = CL_MEM_PTR(task.buffer);
cl_mem d_rng_state = CL_MEM_PTR(task.rng_state);
cl_int d_x = task.x;
cl_int d_y = task.y;
cl_int d_w = task.w;
cl_int d_h = task.h;
cl_int d_sample = task.sample;
/* sample arguments */
int narg = 0;
ciErr = 0;
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_data), (void*)&d_data);
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_buffer), (void*)&d_buffer);
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_rng_state), (void*)&d_rng_state);
#define KERNEL_TEX(type, ttype, name) \
ciErr |= set_kernel_arg_mem(ckPathTraceKernel, &narg, #name);
#include "kernel_textures.h"
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_sample), (void*)&d_sample);
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_x), (void*)&d_x);
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_y), (void*)&d_y);
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_w), (void*)&d_w);
ciErr |= clSetKernelArg(ckPathTraceKernel, narg++, sizeof(d_h), (void*)&d_h);
opencl_assert(ciErr);
size_t workgroup_size;
clGetKernelWorkGroupInfo(ckPathTraceKernel, cdDevice,
CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroup_size, NULL);
workgroup_size = max(sqrt((double)workgroup_size), 1.0);
size_t local_size[2] = {workgroup_size, workgroup_size};
size_t global_size[2] = {global_size_round_up(local_size[0], d_w), global_size_round_up(local_size[1], d_h)};
/* run kernel */
ciErr = clEnqueueNDRangeKernel(cqCommandQueue, ckPathTraceKernel, 2, NULL, global_size, local_size, 0, NULL, NULL);
opencl_assert(ciErr);
opencl_assert(clFinish(cqCommandQueue));
}
cl_int set_kernel_arg_mem(cl_kernel kernel, int *narg, const char *name)
{
cl_mem ptr;
cl_int size, err = 0;
if(mem_map.find(name) != mem_map.end()) {
device_memory *mem = mem_map[name];
ptr = CL_MEM_PTR(mem->device_pointer);
size = mem->data_width;
}
else {
/* work around NULL not working, even though the spec says otherwise */
ptr = CL_MEM_PTR(null_mem);
size = 1;
}
err |= clSetKernelArg(kernel, (*narg)++, sizeof(ptr), (void*)&ptr);
opencl_assert(err);
err |= clSetKernelArg(kernel, (*narg)++, sizeof(size), (void*)&size);
opencl_assert(err);
return err;
}
void tonemap(DeviceTask& task)
{
/* cast arguments to cl types */
cl_mem d_data = CL_MEM_PTR(const_mem_map["__data"]->device_pointer);
cl_mem d_rgba = CL_MEM_PTR(task.rgba);
cl_mem d_buffer = CL_MEM_PTR(task.buffer);
cl_int d_x = task.x;
cl_int d_y = task.y;
cl_int d_w = task.w;
cl_int d_h = task.h;
cl_int d_sample = task.sample;
cl_int d_resolution = task.resolution;
/* sample arguments */
int narg = 0;
ciErr = 0;
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_data), (void*)&d_data);
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_rgba), (void*)&d_rgba);
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_buffer), (void*)&d_buffer);
#define KERNEL_TEX(type, ttype, name) \
ciErr |= set_kernel_arg_mem(ckFilmConvertKernel, &narg, #name);
#include "kernel_textures.h"
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_sample), (void*)&d_sample);
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_resolution), (void*)&d_resolution);
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_x), (void*)&d_x);
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_y), (void*)&d_y);
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_w), (void*)&d_w);
ciErr |= clSetKernelArg(ckFilmConvertKernel, narg++, sizeof(d_h), (void*)&d_h);
opencl_assert(ciErr);
size_t workgroup_size;
clGetKernelWorkGroupInfo(ckFilmConvertKernel, cdDevice,
CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &workgroup_size, NULL);
workgroup_size = max(sqrt((double)workgroup_size), 1.0);
size_t local_size[2] = {workgroup_size, workgroup_size};
size_t global_size[2] = {global_size_round_up(local_size[0], d_w), global_size_round_up(local_size[1], d_h)};
/* run kernel */
ciErr = clEnqueueNDRangeKernel(cqCommandQueue, ckFilmConvertKernel, 2, NULL, global_size, local_size, 0, NULL, NULL);
opencl_assert(ciErr);
opencl_assert(clFinish(cqCommandQueue));
}
void task_add(DeviceTask& task)
{
if(task.type == DeviceTask::TONEMAP)
tonemap(task);
else if(task.type == DeviceTask::PATH_TRACE)
path_trace(task);
}
void task_wait()
{
}
void task_cancel()
{
}
};
Device *device_opencl_create(bool background)
{
return new OpenCLDevice(background);
}
CCL_NAMESPACE_END
#endif /* WITH_OPENCL */

@ -0,0 +1,2 @@
add_subdirectory(license)

@ -0,0 +1,203 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

@ -0,0 +1,17 @@
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.
Contributor(s): Alfredo de Greef, Blender Foundation

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

@ -0,0 +1,13 @@
set(LICENSES
Apache_2.0.txt
Blender.txt
GPL.txt
ILM.txt
NVidia.txt
OSL.txt
Sobol.txt
readme.txt
)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${LICENSES}" ${CYCLES_INSTALL_PATH}/license)

@ -0,0 +1,342 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

@ -0,0 +1,29 @@
Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
Digital Ltd. LLC. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Industrial Light & Magic nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -0,0 +1,36 @@
Copyright 2006, NVIDIA Corporation Ignacio Castano <icastano@nvidia.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright 2009-2010 NVIDIA Corporation
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.

Some files were not shown because too many files have changed in this diff Show More