forked from bartvdbraak/blender
Merged trunk up to rev41928
This commit is contained in:
commit
6e9fd309b8
147
CMakeLists.txt
147
CMakeLists.txt
@ -171,6 +171,7 @@ option(WITH_MOD_DECIMATE "Enable Decimate Modifier" ON)
|
|||||||
option(WITH_MOD_BOOLEAN "Enable Boolean Modifier" ON)
|
option(WITH_MOD_BOOLEAN "Enable Boolean Modifier" ON)
|
||||||
option(WITH_MOD_CLOTH_ELTOPO "Enable Experemental cloth solver" OFF)
|
option(WITH_MOD_CLOTH_ELTOPO "Enable Experemental cloth solver" OFF)
|
||||||
mark_as_advanced(WITH_MOD_CLOTH_ELTOPO)
|
mark_as_advanced(WITH_MOD_CLOTH_ELTOPO)
|
||||||
|
option(WITH_MOD_OCEANSIM "Enable Ocean Modifier" OFF)
|
||||||
|
|
||||||
# Image format support
|
# Image format support
|
||||||
option(WITH_IMAGE_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" ON)
|
option(WITH_IMAGE_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" ON)
|
||||||
@ -213,6 +214,13 @@ if(UNIX AND NOT APPLE)
|
|||||||
endif()
|
endif()
|
||||||
option(WITH_PYTHON_INSTALL "Copy system python into the blender install folder" ON)
|
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
|
# disable for now, but plan to support on all platforms eventually
|
||||||
option(WITH_MEM_JEMALLOC "Enable malloc replacement (http://www.canonware.com/jemalloc)" OFF)
|
option(WITH_MEM_JEMALLOC "Enable malloc replacement (http://www.canonware.com/jemalloc)" OFF)
|
||||||
mark_as_advanced(WITH_MEM_JEMALLOC)
|
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.")
|
"line if youre a developer who wants to add support.")
|
||||||
endif()
|
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
|
# may as well build python module without a UI
|
||||||
if(WITH_PYTHON_MODULE)
|
if(WITH_PYTHON_MODULE)
|
||||||
set(WITH_HEADLESS ON)
|
set(WITH_HEADLESS ON)
|
||||||
endif()
|
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)
|
TEST_SSE_SUPPORT(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG)
|
||||||
|
|
||||||
# don't store paths to libs for portable distrobution
|
# 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}")
|
set(CMAKE_LIBRARY_PATH "/usr/lib/x86_64-linux-gnu;${CMAKE_LIBRARY_PATH}")
|
||||||
endif()
|
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(JPEG REQUIRED)
|
||||||
find_package(PNG REQUIRED)
|
find_package(PNG REQUIRED)
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
@ -423,10 +454,17 @@ if(UNIX AND NOT APPLE)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_CODEC_FFMPEG)
|
if(WITH_CODEC_FFMPEG)
|
||||||
set(FFMPEG /usr CACHE PATH "FFMPEG Directory")
|
# 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)
|
mark_as_advanced(FFMPEG)
|
||||||
set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include)
|
set(FFMPEG_INCLUDE_DIRS ${FFMPEG}/include)
|
||||||
set(FFMPEG_LIBRARIES avformat avcodec avutil avdevice swscale CACHE STRING "FFMPEG Libraries")
|
|
||||||
mark_as_advanced(FFMPEG_LIBRARIES)
|
mark_as_advanced(FFMPEG_LIBRARIES)
|
||||||
set(FFMPEG_LIBPATH ${FFMPEG}/lib)
|
set(FFMPEG_LIBPATH ${FFMPEG}/lib)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_CONSTANT_MACROS")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_CONSTANT_MACROS")
|
||||||
@ -491,6 +529,45 @@ if(UNIX AND NOT APPLE)
|
|||||||
endif()
|
endif()
|
||||||
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
|
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
|
||||||
set(PLATFORM_LINKLIBS "-lutil -lc -lm -lpthread -lstdc++")
|
set(PLATFORM_LINKLIBS "-lutil -lc -lm -lpthread -lstdc++")
|
||||||
|
|
||||||
@ -777,6 +854,28 @@ elseif(WIN32)
|
|||||||
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
|
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
|
||||||
endif()
|
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")
|
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
|
# MSVC only, Mingw doesnt need
|
||||||
@ -791,7 +890,7 @@ elseif(WIN32)
|
|||||||
else()
|
else()
|
||||||
# keep GCC specific stuff here
|
# keep GCC specific stuff here
|
||||||
if(CMAKE_COMPILER_IS_GNUCC)
|
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")
|
set(PLATFORM_CFLAGS "-pipe -funsigned-char -fno-strict-aliasing")
|
||||||
|
|
||||||
add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
|
add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE)
|
||||||
@ -887,7 +986,29 @@ elseif(WIN32)
|
|||||||
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
|
set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}")
|
||||||
endif()
|
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()
|
endif()
|
||||||
|
|
||||||
@ -1090,6 +1211,22 @@ elseif(APPLE)
|
|||||||
# linker needs "-weak_framework 3DconnexionClient"
|
# linker needs "-weak_framework 3DconnexionClient"
|
||||||
endif()
|
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(EXETYPE MACOSX_BUNDLE)
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
|
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_FFTW3)
|
||||||
info_cfg_option(WITH_INTERNATIONAL)
|
info_cfg_option(WITH_INTERNATIONAL)
|
||||||
info_cfg_option(WITH_INPUT_NDOF)
|
info_cfg_option(WITH_INPUT_NDOF)
|
||||||
|
info_cfg_option(WITH_CYCLES)
|
||||||
|
|
||||||
info_cfg_text("Compiler Options:")
|
info_cfg_text("Compiler Options:")
|
||||||
info_cfg_option(WITH_BUILDINFO)
|
info_cfg_option(WITH_BUILDINFO)
|
||||||
@ -1430,6 +1568,7 @@ if(FIRST_RUN)
|
|||||||
info_cfg_option(WITH_MOD_BOOLEAN)
|
info_cfg_option(WITH_MOD_BOOLEAN)
|
||||||
info_cfg_option(WITH_MOD_DECIMATE)
|
info_cfg_option(WITH_MOD_DECIMATE)
|
||||||
info_cfg_option(WITH_MOD_FLUID)
|
info_cfg_option(WITH_MOD_FLUID)
|
||||||
|
info_cfg_option(WITH_MOD_OCEANSIM)
|
||||||
|
|
||||||
info_cfg_text("")
|
info_cfg_text("")
|
||||||
|
|
||||||
|
@ -34,7 +34,10 @@ OS_NCASE:=$(shell uname -s | tr '[A-Z]' '[a-z]')
|
|||||||
# Source and Build DIR's
|
# Source and Build DIR's
|
||||||
BLENDER_DIR:=$(shell pwd -P)
|
BLENDER_DIR:=$(shell pwd -P)
|
||||||
BUILD_TYPE:=Release
|
BUILD_TYPE:=Release
|
||||||
BUILD_CMAKE_ARGS:=
|
|
||||||
|
ifndef BUILD_CMAKE_ARGS
|
||||||
|
BUILD_CMAKE_ARGS:=
|
||||||
|
endif
|
||||||
|
|
||||||
ifndef BUILD_DIR
|
ifndef BUILD_DIR
|
||||||
BUILD_DIR:=$(shell dirname $(BLENDER_DIR))/build/$(OS_NCASE)
|
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 " * bpy - build as a python module which can be loaded from python directly"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo " Note, passing the argument 'BUILD_DIR=path' when calling make will override the default build dir."
|
@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 ""
|
@echo ""
|
||||||
@echo "Project Files for IDE's"
|
@echo "Project Files for IDE's"
|
||||||
|
59
SConstruct
59
SConstruct
@ -162,7 +162,7 @@ if cxx:
|
|||||||
|
|
||||||
if sys.platform=='win32':
|
if sys.platform=='win32':
|
||||||
if env['CC'] in ['cl', 'cl.exe']:
|
if env['CC'] in ['cl', 'cl.exe']:
|
||||||
platform = 'win64-vc' if bitness == 64 else 'win32-vc'
|
platform = 'win64-vc' if bitness == 64 else 'win32-vc'
|
||||||
elif env['CC'] in ['gcc']:
|
elif env['CC'] in ['gcc']:
|
||||||
platform = 'win32-mingw'
|
platform = 'win32-mingw'
|
||||||
|
|
||||||
@ -254,6 +254,7 @@ if 'blenderlite' in B.targets:
|
|||||||
target_env_defs['WITH_BF_BINRELOC'] = False
|
target_env_defs['WITH_BF_BINRELOC'] = False
|
||||||
target_env_defs['BF_BUILDINFO'] = False
|
target_env_defs['BF_BUILDINFO'] = False
|
||||||
target_env_defs['WITH_BF_FLUID'] = 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_DECIMATE'] = False
|
||||||
target_env_defs['WITH_BF_BOOLEAN'] = False
|
target_env_defs['WITH_BF_BOOLEAN'] = False
|
||||||
target_env_defs['WITH_BF_PYTHON'] = False
|
target_env_defs['WITH_BF_PYTHON'] = False
|
||||||
@ -329,6 +330,11 @@ if 'blendernogame' in B.targets:
|
|||||||
if env['WITH_BF_FLUID'] == 1:
|
if env['WITH_BF_FLUID'] == 1:
|
||||||
env['CPPFLAGS'].append('-DWITH_MOD_FLUID')
|
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":
|
if btools.ENDIAN == "big":
|
||||||
env['CPPFLAGS'].append('-D__BIG_ENDIAN__')
|
env['CPPFLAGS'].append('-D__BIG_ENDIAN__')
|
||||||
@ -435,12 +441,12 @@ B.init_lib_dict()
|
|||||||
|
|
||||||
Export('env')
|
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)
|
BuildDir(B.root_build_dir+'/intern', 'intern', duplicate=0)
|
||||||
SConscript(B.root_build_dir+'/intern/SConscript')
|
SConscript(B.root_build_dir+'/intern/SConscript')
|
||||||
BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
|
BuildDir(B.root_build_dir+'/extern', 'extern', duplicate=0)
|
||||||
SConscript(B.root_build_dir+'/extern/SConscript')
|
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
|
# now that we have read all SConscripts, we know what
|
||||||
# libraries will be built. Create list of
|
# libraries will be built. Create list of
|
||||||
@ -526,6 +532,50 @@ if env['OURPLATFORM']!='darwin':
|
|||||||
if len(source)==0:
|
if len(source)==0:
|
||||||
env.Execute(Mkdir(dir))
|
env.Execute(Mkdir(dir))
|
||||||
scriptinstall.append(env.Install(dir=dir,source=source))
|
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']:
|
if env['WITH_BF_INTERNATIONAL']:
|
||||||
internationalpaths=['release' + os.sep + 'datafiles']
|
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/BlendThumb.dll')
|
||||||
dllsources.append('${LCGDIR}/thumbhandler/lib/BlendThumb64.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')
|
dllsources.append('#source/icons/blender.exe.manifest')
|
||||||
|
|
||||||
windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
|
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++
|
# Don't depend on system's libstdc++
|
||||||
WITH_BF_STATICCXX = True
|
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_OPENAL = True
|
||||||
WITH_BF_STATICOPENAL = True
|
WITH_BF_STATICOPENAL = True
|
||||||
@ -92,9 +92,27 @@ WITH_BF_STATICFFTW3 = True
|
|||||||
# JACK
|
# JACK
|
||||||
WITH_BF_JACK = True
|
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
|
# Compilation and optimization
|
||||||
BF_DEBUG = False
|
BF_DEBUG = False
|
||||||
REL_CFLAGS = []
|
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
|
||||||
REL_CXXFLAGS = []
|
|
||||||
REL_CCFLAGS = ['-O2'] # C & C++
|
|
||||||
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib32']
|
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++
|
# Don't depend on system's libstdc++
|
||||||
WITH_BF_STATICCXX = True
|
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_OPENAL = True
|
||||||
WITH_BF_STATICOPENAL = True
|
WITH_BF_STATICOPENAL = True
|
||||||
@ -83,9 +83,15 @@ BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib32'
|
|||||||
# JACK
|
# JACK
|
||||||
WITH_BF_JACK = True
|
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
|
# Compilation and optimization
|
||||||
BF_DEBUG = False
|
BF_DEBUG = False
|
||||||
REL_CFLAGS = []
|
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
|
||||||
REL_CXXFLAGS = []
|
|
||||||
REL_CCFLAGS = ['-O2'] # C & C++
|
|
||||||
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib32']
|
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++
|
# Don't depend on system's libstdc++
|
||||||
WITH_BF_STATICCXX = True
|
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_OPENAL = True
|
||||||
WITH_BF_STATICOPENAL = True
|
WITH_BF_STATICOPENAL = True
|
||||||
@ -83,9 +83,15 @@ BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib64'
|
|||||||
# JACK
|
# JACK
|
||||||
WITH_BF_JACK = True
|
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
|
# Compilation and optimization
|
||||||
BF_DEBUG = False
|
BF_DEBUG = False
|
||||||
REL_CFLAGS = []
|
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
|
||||||
REL_CXXFLAGS = []
|
|
||||||
REL_CCFLAGS = ['-O2'] # C & C++
|
|
||||||
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib64']
|
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++
|
# Don't depend on system's libstdc++
|
||||||
WITH_BF_STATICCXX = True
|
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_OPENAL = True
|
||||||
WITH_BF_STATICOPENAL = True
|
WITH_BF_STATICOPENAL = True
|
||||||
@ -92,9 +92,27 @@ WITH_BF_STATICFFTW3 = True
|
|||||||
# JACK
|
# JACK
|
||||||
WITH_BF_JACK = True
|
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
|
# Compilation and optimization
|
||||||
BF_DEBUG = False
|
BF_DEBUG = False
|
||||||
REL_CFLAGS = []
|
REL_CCFLAGS = ['-O2', '-msse', '-msse2'] # C & C++
|
||||||
REL_CXXFLAGS = []
|
|
||||||
REL_CCFLAGS = ['-O2'] # C & C++
|
|
||||||
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib64']
|
PLATFORM_LINKFLAGS = ['-L/home/sources/staticlibs/lib64']
|
||||||
|
70
build_files/cmake/Modules/FindOpenImageIO.cmake
Normal file
70
build_files/cmake/Modules/FindOpenImageIO.cmake
Normal file
@ -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)
|
# print(f)
|
||||||
|
|
||||||
def is_definition(l, f, i, name):
|
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 ('set(%s' % name) in l or ('set(' in l and l.endswith(name)):
|
||||||
if len(l.split()) > 1:
|
if len(l.split()) > 1:
|
||||||
raise Exception("strict formatting not kept 'set(%s*' %s:%d" % (name, f, i))
|
raise Exception("strict formatting not kept 'set(%s*' %s:%d" % (name, f, i))
|
||||||
@ -172,6 +175,12 @@ def cmake_get_src(f):
|
|||||||
pass
|
pass
|
||||||
elif new_file.endswith(".def"):
|
elif new_file.endswith(".def"):
|
||||||
pass
|
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:
|
else:
|
||||||
raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file))
|
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,
|
# is_py,
|
||||||
cmake_advanced_info,
|
cmake_advanced_info,
|
||||||
cmake_compiler_defines,
|
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 = list(set(includes) | set(dirname(f) for f in files if is_c_header(f)))
|
||||||
includes.sort()
|
includes.sort()
|
||||||
|
|
||||||
PROJECT_NAME = "Blender"
|
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
|
# --------------- NB spesific
|
||||||
defines = [("%s=%s" % cdef) if cdef[1] else cdef[0] for cdef in defines]
|
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 = open(os.path.join(PROJECT_DIR, "%s.files" % FILE_NAME), 'w')
|
||||||
f.write("\n".join(files_rel))
|
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)))
|
f.write("\n".join(sorted(includes)))
|
||||||
|
|
||||||
qtc_prj = os.path.join(PROJECT_DIR, "%s.creator" % FILE_NAME)
|
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()
|
defines_final += cmake_compiler_defines()
|
||||||
f.write("\n".join(defines_final))
|
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
|
# --- end
|
||||||
|
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ def create_qtc_project_python():
|
|||||||
f = open(qtc_cfg, 'w')
|
f = open(qtc_cfg, 'w')
|
||||||
f.write("// ADD PREDEFINED MACROS HERE!\n")
|
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():
|
def main():
|
||||||
|
@ -12,7 +12,9 @@ set(WITH_BUILTIN_GLEW OFF CACHE FORCE BOOL)
|
|||||||
set(WITH_BULLET OFF CACHE FORCE BOOL)
|
set(WITH_BULLET OFF CACHE FORCE BOOL)
|
||||||
set(WITH_CODEC_FFMPEG OFF CACHE FORCE BOOL)
|
set(WITH_CODEC_FFMPEG OFF CACHE FORCE BOOL)
|
||||||
set(WITH_CODEC_SNDFILE 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_FFTW3 OFF CACHE FORCE BOOL)
|
||||||
|
set(WITH_LIBMV OFF CACHE FORCE BOOL)
|
||||||
set(WITH_GAMEENGINE OFF CACHE FORCE BOOL)
|
set(WITH_GAMEENGINE OFF CACHE FORCE BOOL)
|
||||||
set(WITH_IK_ITASC OFF CACHE FORCE BOOL)
|
set(WITH_IK_ITASC OFF CACHE FORCE BOOL)
|
||||||
set(WITH_IMAGE_CINEON 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_DECIMATE OFF CACHE FORCE BOOL)
|
||||||
set(WITH_MOD_FLUID OFF CACHE FORCE BOOL)
|
set(WITH_MOD_FLUID OFF CACHE FORCE BOOL)
|
||||||
set(WITH_MOD_SMOKE 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_AUDASPACE OFF CACHE FORCE BOOL)
|
||||||
set(WITH_OPENAL OFF CACHE FORCE BOOL)
|
set(WITH_OPENAL OFF CACHE FORCE BOOL)
|
||||||
set(WITH_OPENCOLLADA OFF CACHE FORCE BOOL)
|
set(WITH_OPENCOLLADA OFF CACHE FORCE BOOL)
|
||||||
|
@ -165,6 +165,12 @@ macro(SETUP_LIBDIRS)
|
|||||||
if(WITH_IMAGE_TIFF)
|
if(WITH_IMAGE_TIFF)
|
||||||
link_directories(${TIFF_LIBPATH})
|
link_directories(${TIFF_LIBPATH})
|
||||||
endif()
|
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)
|
if(WITH_IMAGE_OPENJPEG AND UNIX AND NOT APPLE)
|
||||||
link_directories(${OPENJPEG_LIBPATH})
|
link_directories(${OPENJPEG_LIBPATH})
|
||||||
endif()
|
endif()
|
||||||
@ -259,8 +265,14 @@ macro(setup_liblinks
|
|||||||
if(WITH_IMAGE_TIFF)
|
if(WITH_IMAGE_TIFF)
|
||||||
target_link_libraries(${target} ${TIFF_LIBRARY})
|
target_link_libraries(${target} ${TIFF_LIBRARY})
|
||||||
endif()
|
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(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")
|
file_list_suffix(OPENEXR_LIBRARIES_DEBUG "${OPENEXR_LIBRARIES}" "_d")
|
||||||
target_link_libraries_debug(${target} "${OPENEXR_LIBRARIES_DEBUG}")
|
target_link_libraries_debug(${target} "${OPENEXR_LIBRARIES_DEBUG}")
|
||||||
target_link_libraries_optimized(${target} "${OPENEXR_LIBRARIES}")
|
target_link_libraries_optimized(${target} "${OPENEXR_LIBRARIES}")
|
||||||
@ -618,3 +630,38 @@ macro(blender_project_hack_post)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
endmacro()
|
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):
|
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("#")]
|
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()
|
cache_file.close()
|
||||||
|
|
||||||
|
@ -217,6 +217,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
|
|||||||
|
|
||||||
WITH_BF_GAMEENGINE = True
|
WITH_BF_GAMEENGINE = True
|
||||||
WITH_BF_PLAYER = True
|
WITH_BF_PLAYER = True
|
||||||
|
WITH_BF_OCEANSIM = True
|
||||||
|
|
||||||
WITH_BF_BULLET = True
|
WITH_BF_BULLET = True
|
||||||
BF_BULLET = '#extern/bullet2/src'
|
BF_BULLET = '#extern/bullet2/src'
|
||||||
@ -282,6 +283,21 @@ BF_PCRE_LIBPATH = '${BF_PCRE}/lib'
|
|||||||
#BF_EXPAT_LIB = 'expat'
|
#BF_EXPAT_LIB = 'expat'
|
||||||
#BF_EXPAT_LIBPATH = '/usr/lib'
|
#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
|
#Ray trace optimization
|
||||||
if MACOSX_ARCHITECTURE == 'x86_64' or MACOSX_ARCHITECTURE == 'i386':
|
if MACOSX_ARCHITECTURE == 'x86_64' or MACOSX_ARCHITECTURE == 'i386':
|
||||||
WITH_BF_RAYOPTIMIZATION = True
|
WITH_BF_RAYOPTIMIZATION = True
|
||||||
|
@ -84,6 +84,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
|
|||||||
|
|
||||||
WITH_BF_GAMEENGINE = False
|
WITH_BF_GAMEENGINE = False
|
||||||
WITH_BF_PLAYER = True
|
WITH_BF_PLAYER = True
|
||||||
|
WITH_BF_OCEANSIM = True
|
||||||
|
|
||||||
WITH_BF_BULLET = True
|
WITH_BF_BULLET = True
|
||||||
BF_BULLET = '#extern/bullet2/src'
|
BF_BULLET = '#extern/bullet2/src'
|
||||||
|
@ -84,6 +84,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
|
|||||||
|
|
||||||
WITH_BF_GAMEENGINE = False
|
WITH_BF_GAMEENGINE = False
|
||||||
WITH_BF_PLAYER = True
|
WITH_BF_PLAYER = True
|
||||||
|
WITH_BF_OCEANSIM = True
|
||||||
|
|
||||||
WITH_BF_BULLET = True
|
WITH_BF_BULLET = True
|
||||||
BF_BULLET = '#extern/bullet2/src'
|
BF_BULLET = '#extern/bullet2/src'
|
||||||
|
@ -84,6 +84,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
|
|||||||
|
|
||||||
WITH_BF_GAMEENGINE = False
|
WITH_BF_GAMEENGINE = False
|
||||||
WITH_BF_PLAYER = True
|
WITH_BF_PLAYER = True
|
||||||
|
WITH_BF_OCEANSIM = True
|
||||||
|
|
||||||
WITH_BF_BULLET = True
|
WITH_BF_BULLET = True
|
||||||
BF_BULLET = '#extern/bullet2/src'
|
BF_BULLET = '#extern/bullet2/src'
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
LCGDIR = '../lib/linux'
|
# find library directory
|
||||||
LIBDIR = "${LCGDIR}"
|
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_ABI_FLAGS = 'm' # Most common for linux distros
|
||||||
BF_PYTHON = '/usr'
|
BF_PYTHON = '/usr'
|
||||||
@ -87,6 +94,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
|
|||||||
|
|
||||||
WITH_BF_GAMEENGINE = True
|
WITH_BF_GAMEENGINE = True
|
||||||
WITH_BF_PLAYER = True
|
WITH_BF_PLAYER = True
|
||||||
|
WITH_BF_OCEANSIM = True
|
||||||
|
|
||||||
WITH_BF_BULLET = True
|
WITH_BF_BULLET = True
|
||||||
BF_BULLET = '#extern/bullet2/src'
|
BF_BULLET = '#extern/bullet2/src'
|
||||||
@ -113,7 +121,18 @@ WITH_BF_BINRELOC = True
|
|||||||
|
|
||||||
# enable ffmpeg support
|
# enable ffmpeg support
|
||||||
WITH_BF_FFMPEG = True # -DWITH_FFMPEG
|
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_LIB = 'avformat avcodec swscale avutil avdevice'
|
||||||
BF_FFMPEG_INC = '${BF_FFMPEG}/include'
|
BF_FFMPEG_INC = '${BF_FFMPEG}/include'
|
||||||
BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib'
|
BF_FFMPEG_LIBPATH='${BF_FFMPEG}/lib'
|
||||||
@ -178,6 +197,28 @@ BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib'
|
|||||||
BF_JEMALLOC_LIB = 'jemalloc'
|
BF_JEMALLOC_LIB = 'jemalloc'
|
||||||
BF_JEMALLOC_LIB_STATIC = '${BF_JEMALLOC_LIBPATH}/libjemalloc.a'
|
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
|
WITH_BF_OPENMP = True
|
||||||
|
|
||||||
#Ray trace optimization
|
#Ray trace optimization
|
||||||
@ -186,6 +227,7 @@ BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
|
|||||||
|
|
||||||
#SpaceNavigator and friends
|
#SpaceNavigator and friends
|
||||||
WITH_BF_3DMOUSE = True
|
WITH_BF_3DMOUSE = True
|
||||||
|
WITH_BF_STATIC3DMOUSE = False
|
||||||
BF_3DMOUSE = '/usr'
|
BF_3DMOUSE = '/usr'
|
||||||
BF_3DMOUSE_INC = '${BF_3DMOUSE}/include'
|
BF_3DMOUSE_INC = '${BF_3DMOUSE}/include'
|
||||||
BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib'
|
BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib'
|
||||||
|
@ -90,6 +90,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
|
|||||||
|
|
||||||
WITH_BF_GAMEENGINE = True
|
WITH_BF_GAMEENGINE = True
|
||||||
WITH_BF_PLAYER = False
|
WITH_BF_PLAYER = False
|
||||||
|
WITH_BF_OCEANSIM = True
|
||||||
|
|
||||||
WITH_BF_BULLET = True
|
WITH_BF_BULLET = True
|
||||||
BF_BULLET = '#extern/bullet2/src'
|
BF_BULLET = '#extern/bullet2/src'
|
||||||
|
@ -17,7 +17,7 @@ BF_OPENAL_INC = '${BF_OPENAL}/include'
|
|||||||
BF_OPENAL_LIB = 'wrap_oal'
|
BF_OPENAL_LIB = 'wrap_oal'
|
||||||
BF_OPENAL_LIBPATH = '${BF_OPENAL}/lib'
|
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_LIB = 'avformat-53 avcodec-53 avdevice-53 avutil-51 swscale-2'
|
||||||
BF_FFMPEG_LIBPATH = LIBDIR + '/ffmpeg/lib'
|
BF_FFMPEG_LIBPATH = LIBDIR + '/ffmpeg/lib'
|
||||||
BF_FFMPEG_INC = LIBDIR + '/ffmpeg/include'
|
BF_FFMPEG_INC = LIBDIR + '/ffmpeg/include'
|
||||||
@ -46,11 +46,11 @@ BF_PTHREADS_INC = '${BF_PTHREADS}/include'
|
|||||||
BF_PTHREADS_LIB = 'pthreadGC2'
|
BF_PTHREADS_LIB = 'pthreadGC2'
|
||||||
BF_PTHREADS_LIBPATH = '${BF_PTHREADS}/lib'
|
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
|
WITH_BF_STATICOPENEXR = False
|
||||||
BF_OPENEXR = LIBDIR + '/gcc/openexr'
|
BF_OPENEXR = LIBDIR + '/gcc/openexr'
|
||||||
BF_OPENEXR_INC = '${BF_OPENEXR}/include ${BF_OPENEXR}/include/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'
|
BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
|
||||||
# Warning, this static lib configuration is untested! users of this OS please confirm.
|
# 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'
|
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_INC = '${BF_OPENJPEG}'
|
||||||
BF_OPENJPEG_LIBPATH='${BF_OPENJPEG}/lib'
|
BF_OPENJPEG_LIBPATH='${BF_OPENJPEG}/lib'
|
||||||
|
|
||||||
WITH_BF_FFTW3 = False
|
WITH_BF_FFTW3 = True
|
||||||
BF_FFTW3 = LIBDIR + '/gcc/fftw3'
|
BF_FFTW3 = LIBDIR + '/gcc/fftw3'
|
||||||
BF_FFTW3_INC = '${BF_FFTW3}/include'
|
BF_FFTW3_INC = '${BF_FFTW3}/include'
|
||||||
BF_FFTW3_LIB = 'fftw3'
|
BF_FFTW3_LIB = 'fftw3'
|
||||||
BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
|
BF_FFTW3_LIBPATH = '${BF_FFTW3}/lib'
|
||||||
|
|
||||||
WITH_BF_GAMEENGINE = False
|
WITH_BF_GAMEENGINE = True
|
||||||
WITH_BF_PLAYER = False
|
WITH_BF_PLAYER = True
|
||||||
|
WITH_BF_OCEANSIM = True
|
||||||
|
|
||||||
WITH_BF_BULLET = True
|
WITH_BF_BULLET = True
|
||||||
BF_BULLET = '#extern/bullet2/src'
|
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/libXmu.a', '${BF_OPENGL}/lib/libXext.a',
|
||||||
'${BF_OPENGL}/lib/libX11.a', '${BF_OPENGL}/lib/libXi.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 = '#source/blender/collada'
|
||||||
BF_COLLADA_INC = '${BF_COLLADA}'
|
BF_COLLADA_INC = '${BF_COLLADA}'
|
||||||
BF_COLLADA_LIB = '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_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver expat pcre buffer ftoa'
|
||||||
BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib'
|
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
|
#Ray trace optimization
|
||||||
WITH_BF_RAYOPTIMIZATION = False
|
WITH_BF_RAYOPTIMIZATION = True
|
||||||
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
|
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
|
||||||
|
|
||||||
##
|
##
|
||||||
@ -161,7 +177,7 @@ CXX = 'g++'
|
|||||||
CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ]
|
CCFLAGS = [ '-pipe', '-funsigned-char', '-fno-strict-aliasing' ]
|
||||||
CXXFLAGS = []
|
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_CFLAGS = []
|
||||||
REL_CXXFLAGS = []
|
REL_CXXFLAGS = []
|
||||||
REL_CCFLAGS = ['-DNDEBUG', '-O2']
|
REL_CCFLAGS = ['-DNDEBUG', '-O2']
|
||||||
@ -170,9 +186,9 @@ C_WARN = ['-Wno-char-subscripts', '-Wdeclaration-after-statement', '-Wstrict-pro
|
|||||||
|
|
||||||
CC_WARN = [ '-Wall' ]
|
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 = False
|
||||||
BF_DEBUG_CCFLAGS= ['-g', '-D_DEBUG']
|
BF_DEBUG_CCFLAGS= ['-g', '-D_DEBUG']
|
||||||
|
@ -96,6 +96,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
|
|||||||
|
|
||||||
WITH_BF_GAMEENGINE = True
|
WITH_BF_GAMEENGINE = True
|
||||||
WITH_BF_PLAYER = True
|
WITH_BF_PLAYER = True
|
||||||
|
WITH_BF_OCEANSIM = True
|
||||||
|
|
||||||
WITH_BF_BULLET = True
|
WITH_BF_BULLET = True
|
||||||
BF_BULLET = '#extern/bullet2/src'
|
BF_BULLET = '#extern/bullet2/src'
|
||||||
@ -149,19 +150,20 @@ WITH_BF_3DMOUSE = True
|
|||||||
|
|
||||||
WITH_BF_OPENMP = True
|
WITH_BF_OPENMP = True
|
||||||
|
|
||||||
'''
|
#Cycles
|
||||||
|
WITH_BF_CYCLES = True
|
||||||
|
|
||||||
WITH_BF_OIIO = True
|
WITH_BF_OIIO = True
|
||||||
BF_OIIO = LIBDIR + '/openimageio'
|
BF_OIIO = '${LIBDIR}/openimageio'
|
||||||
BF_OIIO_INC = '${BF_OIIO}/include'
|
BF_OIIO_INC = '${BF_OIIO}/include'
|
||||||
BF_OIIO_LIB = 'OpenImageIO'
|
BF_OIIO_LIB = 'OpenImageIO'
|
||||||
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
||||||
|
|
||||||
WITH_BF_BOOST = True
|
WITH_BF_BOOST = True
|
||||||
BF_BOOST = LIBDIR + '/boost'
|
BF_BOOST = '${LIBDIR}/boost'
|
||||||
BF_BOOST_INC = '${BF_BOOST}/include'
|
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'
|
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
||||||
'''
|
|
||||||
|
|
||||||
#Ray trace optimization
|
#Ray trace optimization
|
||||||
WITH_BF_RAYOPTIMIZATION = True
|
WITH_BF_RAYOPTIMIZATION = True
|
||||||
|
@ -100,6 +100,7 @@ BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib'
|
|||||||
|
|
||||||
WITH_BF_GAMEENGINE = True
|
WITH_BF_GAMEENGINE = True
|
||||||
WITH_BF_PLAYER = True
|
WITH_BF_PLAYER = True
|
||||||
|
WITH_BF_OCEANSIM = True
|
||||||
|
|
||||||
WITH_BF_BULLET = True
|
WITH_BF_BULLET = True
|
||||||
BF_BULLET = '#extern/bullet2/src'
|
BF_BULLET = '#extern/bullet2/src'
|
||||||
@ -153,19 +154,20 @@ WITH_BF_3DMOUSE = True
|
|||||||
|
|
||||||
WITH_BF_OPENMP = True
|
WITH_BF_OPENMP = True
|
||||||
|
|
||||||
'''
|
WITH_BF_CYCLES = True
|
||||||
|
|
||||||
WITH_BF_OIIO = True
|
WITH_BF_OIIO = True
|
||||||
BF_OIIO = LIBDIR + '/openimageio'
|
BF_OIIO = '${LIBDIR}/openimageio'
|
||||||
BF_OIIO_INC = '${BF_OIIO}/include'
|
BF_OIIO_INC = '${BF_OIIO}/include'
|
||||||
BF_OIIO_LIB = 'OpenImageIO'
|
BF_OIIO_LIB = 'OpenImageIO'
|
||||||
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
||||||
|
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
|
||||||
|
|
||||||
WITH_BF_BOOST = True
|
WITH_BF_BOOST = True
|
||||||
BF_BOOST = LIBDIR + '/boost'
|
BF_BOOST = '${LIBDIR}/boost'
|
||||||
BF_BOOST_INC = '${BF_BOOST}/include'
|
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'
|
BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
||||||
'''
|
|
||||||
|
|
||||||
#Ray trace optimization
|
#Ray trace optimization
|
||||||
WITH_BF_RAYOPTIMIZATION = True
|
WITH_BF_RAYOPTIMIZATION = True
|
||||||
|
@ -195,8 +195,13 @@ def setup_staticlibs(lenv):
|
|||||||
|
|
||||||
if lenv['WITH_BF_OIIO']:
|
if lenv['WITH_BF_OIIO']:
|
||||||
libincs += Split(lenv['BF_OIIO_LIBPATH'])
|
libincs += Split(lenv['BF_OIIO_LIBPATH'])
|
||||||
|
if lenv['WITH_BF_STATICOIIO']:
|
||||||
|
statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
|
||||||
|
|
||||||
if lenv['WITH_BF_BOOST']:
|
if lenv['WITH_BF_BOOST']:
|
||||||
libincs += Split(lenv['BF_BOOST_LIBPATH'])
|
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
|
# setting this last so any overriding of manually libs could be handled
|
||||||
if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
|
if lenv['OURPLATFORM'] not in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
|
||||||
@ -216,11 +221,7 @@ def setup_staticlibs(lenv):
|
|||||||
return statlibs, libincs
|
return statlibs, libincs
|
||||||
|
|
||||||
def setup_syslibs(lenv):
|
def setup_syslibs(lenv):
|
||||||
syslibs = [
|
syslibs = []
|
||||||
|
|
||||||
lenv['BF_JPEG_LIB'],
|
|
||||||
lenv['BF_PNG_LIB'],
|
|
||||||
]
|
|
||||||
|
|
||||||
if not lenv['WITH_BF_FREETYPE_STATIC']:
|
if not lenv['WITH_BF_FREETYPE_STATIC']:
|
||||||
syslibs += Split(lenv['BF_FREETYPE_LIB'])
|
syslibs += Split(lenv['BF_FREETYPE_LIB'])
|
||||||
@ -241,6 +242,10 @@ def setup_syslibs(lenv):
|
|||||||
syslibs += ['gomp']
|
syslibs += ['gomp']
|
||||||
if lenv['WITH_BF_ICONV']:
|
if lenv['WITH_BF_ICONV']:
|
||||||
syslibs += Split(lenv['BF_ICONV_LIB'])
|
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']:
|
if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
|
||||||
syslibs += Split(lenv['BF_OPENEXR_LIB'])
|
syslibs += Split(lenv['BF_OPENEXR_LIB'])
|
||||||
if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
|
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']:
|
if not lenv['WITH_BF_STATIC3DMOUSE']:
|
||||||
syslibs += Split(lenv['BF_3DMOUSE_LIB'])
|
syslibs += Split(lenv['BF_3DMOUSE_LIB'])
|
||||||
|
|
||||||
if lenv['WITH_BF_OIIO']:
|
if lenv['WITH_BF_BOOST'] and not lenv['WITH_BF_STATICBOOST']:
|
||||||
syslibs += Split(lenv['BF_OIIO_LIB'])
|
|
||||||
if lenv['WITH_BF_BOOST']:
|
|
||||||
syslibs += Split(lenv['BF_BOOST_LIB'])
|
syslibs += Split(lenv['BF_BOOST_LIB'])
|
||||||
|
|
||||||
|
syslibs += Split(lenv['BF_JPEG_LIB'])
|
||||||
|
syslibs += Split(lenv['BF_PNG_LIB'])
|
||||||
|
|
||||||
syslibs += lenv['LLIBS']
|
syslibs += lenv['LLIBS']
|
||||||
|
|
||||||
return syslibs
|
return syslibs
|
||||||
@ -550,10 +556,6 @@ def AppIt(target=None, source=None, env=None):
|
|||||||
bldroot = env.Dir('.').abspath
|
bldroot = env.Dir('.').abspath
|
||||||
binary = env['BINARYKIND']
|
binary = env['BINARYKIND']
|
||||||
|
|
||||||
if b=='verse':
|
|
||||||
print bc.OKBLUE+"no bundle for verse"+bc.ENDC
|
|
||||||
return 0
|
|
||||||
|
|
||||||
sourcedir = bldroot + '/source/darwin/%s.app'%binary
|
sourcedir = bldroot + '/source/darwin/%s.app'%binary
|
||||||
sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
|
sourceinfo = bldroot + "/source/darwin/%s.app/Contents/Info.plist"%binary
|
||||||
targetinfo = installdir +'/' + "%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)
|
cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
|
||||||
commands.getoutput(cmd)
|
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']:
|
if env['WITH_OSX_STATICPYTHON']:
|
||||||
cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
|
cmd = 'mkdir %s/%s.app/Contents/MacOS/%s/python/'%(installdir,binary, VERSION)
|
||||||
commands.getoutput(cmd)
|
commands.getoutput(cmd)
|
||||||
|
@ -152,12 +152,14 @@ def validate_arguments(args, bc):
|
|||||||
'WITH_BF_FLUID',
|
'WITH_BF_FLUID',
|
||||||
'WITH_BF_DECIMATE',
|
'WITH_BF_DECIMATE',
|
||||||
'WITH_BF_BOOLEAN',
|
'WITH_BF_BOOLEAN',
|
||||||
|
'WITH_BF_OCEANSIM',
|
||||||
'WITH_BF_CXX_GUARDEDALLOC',
|
'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',
|
'WITH_BF_JEMALLOC', 'WITH_BF_STATICJEMALLOC', 'BF_JEMALLOC', 'BF_JEMALLOC_INC', 'BF_JEMALLOC_LIBPATH', 'BF_JEMALLOC_LIB', 'BF_JEMALLOC_LIB_STATIC',
|
||||||
'BUILDBOT_BRANCH',
|
'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_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_CYCLES', 'WITH_BF_CYCLES_BINARIES' 'BF_CYCLES_BINARIES_ARCH',
|
||||||
'WITH_BF_BOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIBPATH'
|
'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
|
# 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 = Variables.Variables(cfg, args)
|
||||||
localopts.AddVariables(
|
localopts.AddVariables(
|
||||||
('LCGDIR', 'location of cvs lib dir'),
|
('LCGDIR', 'location of cvs lib dir'),
|
||||||
|
('LIBDIR', 'root dir of libs'),
|
||||||
(BoolVariable('WITH_BF_PYTHON', 'Compile with python', True)),
|
(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)),
|
(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', ''),
|
('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_FLUID', 'Build with Fluid simulation (Elbeem)', True)),
|
||||||
(BoolVariable('WITH_BF_DECIMATE', 'Build with decimate modifier', True)),
|
(BoolVariable('WITH_BF_DECIMATE', 'Build with decimate modifier', True)),
|
||||||
(BoolVariable('WITH_BF_BOOLEAN', 'Build with boolean 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', ''),
|
('BF_PROFILE_FLAGS', 'Profiling compiler flags', ''),
|
||||||
(BoolVariable('WITH_BF_OPENAL', 'Use OpenAL if true', False)),
|
(BoolVariable('WITH_BF_OPENAL', 'Use OpenAL if true', False)),
|
||||||
('BF_OPENAL', 'Base path for OpenAL', ''),
|
('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)),
|
(BoolVariable('WITH_BF_CXX_GUARDEDALLOC', 'Enable GuardedAlloc for C++ memory allocation tracking.', False)),
|
||||||
|
|
||||||
('BUILDBOT_BRANCH', 'Buildbot branch name', ''),
|
('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_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_INC', 'OIIO include path', ''),
|
||||||
('BF_OIIO_LIB', 'OIIO library', ''),
|
('BF_OIIO_LIB', 'OIIO library', ''),
|
||||||
('BF_OIIO_LIBPATH', 'OIIO library path', ''),
|
('BF_OIIO_LIBPATH', 'OIIO library path', ''),
|
||||||
|
('BF_OIIO_LIB_STATIC', 'OIIO static library', ''),
|
||||||
|
|
||||||
(BoolVariable('WITH_BF_BOOST', 'Build with Boost', False)),
|
(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_INC', 'Boost include path', ''),
|
||||||
('BF_BOOST_LIB', 'Boost library', ''),
|
('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()
|
) # end of opts.AddOptions()
|
||||||
|
|
||||||
return localopts
|
return localopts
|
||||||
|
@ -49,198 +49,198 @@ CSuffixes = ['.c', '.C']
|
|||||||
CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
|
CXXSuffixes = ['.cc', '.cpp', '.cxx', '.c++', '.C++']
|
||||||
|
|
||||||
def get_msvctoolkit_paths():
|
def get_msvctoolkit_paths():
|
||||||
"""Return a 4-tuple of (INCLUDE, LIB, PATH, TOOLKIT) as the values of those
|
"""Return a 4-tuple of (INCLUDE, LIB, PATH, TOOLKIT) as the values of those
|
||||||
three environment variables that should be set in order to execute
|
three environment variables that should be set in order to execute
|
||||||
the MSVC .NET tools properly, if the information wasn't available
|
the MSVC .NET tools properly, if the information wasn't available
|
||||||
from the registry."""
|
from the registry."""
|
||||||
|
|
||||||
MSToolkitDir = None
|
MSToolkitDir = None
|
||||||
paths = {}
|
paths = {}
|
||||||
exe_path = ''
|
exe_path = ''
|
||||||
lib_path = ''
|
lib_path = ''
|
||||||
include_path = ''
|
include_path = ''
|
||||||
|
|
||||||
# First, we get the shell folder for this user:
|
# First, we get the shell folder for this user:
|
||||||
if not SCons.Util.can_read_reg:
|
if not SCons.Util.can_read_reg:
|
||||||
raise SCons.Errors.InternalError, "No Windows registry module was found"
|
raise SCons.Errors.InternalError, "No Windows registry module was found"
|
||||||
|
|
||||||
# look for toolkit
|
# look for toolkit
|
||||||
if os.environ.has_key('VCToolkitInstallDir'):
|
if os.environ.has_key('VCToolkitInstallDir'):
|
||||||
MSToolkitDir = os.path.normpath(os.environ['VCToolkitInstallDir'])
|
MSToolkitDir = os.path.normpath(os.environ['VCToolkitInstallDir'])
|
||||||
else:
|
else:
|
||||||
# last resort -- default install location
|
# last resort -- default install location
|
||||||
MSToolkitDir = r'C:\Program Files\Microsoft Visual C++ Toolkit 2003'
|
MSToolkitDir = r'C:\Program Files\Microsoft Visual C++ Toolkit 2003'
|
||||||
|
|
||||||
# look for platform sdk
|
# look for platform sdk
|
||||||
if os.environ.has_key('MSSdk'):
|
if os.environ.has_key('MSSdk'):
|
||||||
PlatformSDKDir = os.path.normpath(os.environ['MSSdk'])
|
PlatformSDKDir = os.path.normpath(os.environ['MSSdk'])
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
PlatformSDKDir = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\MicrosoftSDK\Directories\Install Dir')[0]
|
PlatformSDKDir = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\MicrosoftSDK\Directories\Install Dir')[0]
|
||||||
PlatformSDKDir = str(PlatformSDKDir)
|
PlatformSDKDir = str(PlatformSDKDir)
|
||||||
except SCons.Util.RegError:
|
except SCons.Util.RegError:
|
||||||
raise SCons.Errors.InternalError, "The Platform SDK directory was not found in the registry or in the `MSSdk` environment variable."
|
raise SCons.Errors.InternalError, "The Platform SDK directory was not found in the registry or in the `MSSdk` environment variable."
|
||||||
|
|
||||||
# look for DX Sdk (expecting DX9)
|
# look for DX Sdk (expecting DX9)
|
||||||
# dxsdk docs have a directory key, look for it, extract path
|
# dxsdk docs have a directory key, look for it, extract path
|
||||||
#dxsdkdocs = ""
|
#dxsdkdocs = ""
|
||||||
DXsdkDir = ""
|
DXsdkDir = ""
|
||||||
#try:
|
#try:
|
||||||
# dxsdkdocs = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\DirectX SDK\DX9SDK Doc Path')
|
# dxsdkdocs = SCons.Util.RegGetValue(SCons.Util.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\DirectX SDK\DX9SDK Doc Path')
|
||||||
#except SCons.Util.RegError:
|
#except SCons.Util.RegError:
|
||||||
# raise SCons.Errors.InternalError, "The DXSDK directory was not found in the registry."
|
# raise SCons.Errors.InternalError, "The DXSDK directory was not found in the registry."
|
||||||
if os.environ.has_key('DXSDK_DIR'):
|
if os.environ.has_key('DXSDK_DIR'):
|
||||||
DXsdkDir = os.path.normpath(os.environ['DXSDK_DIR'])
|
DXsdkDir = os.path.normpath(os.environ['DXSDK_DIR'])
|
||||||
|
|
||||||
#DXsdkDir = os.path.split(dxsdkdocs[0])[0]
|
#DXsdkDir = os.path.split(dxsdkdocs[0])[0]
|
||||||
DXsdkDir = os.path.split(DXsdkDir)[0]
|
DXsdkDir = os.path.split(DXsdkDir)[0]
|
||||||
|
|
||||||
include_path = r'%s\include;%s\include;%s\include' % (MSToolkitDir, PlatformSDKDir, DXsdkDir)
|
include_path = r'%s\include;%s\include;%s\include' % (MSToolkitDir, PlatformSDKDir, DXsdkDir)
|
||||||
lib_path = r'%s\lib;%s\lib;%s\lib' % (MSToolkitDir, PlatformSDKDir, DXsdkDir)
|
lib_path = r'%s\lib;%s\lib;%s\lib' % (MSToolkitDir, PlatformSDKDir, DXsdkDir)
|
||||||
exe_path = r'%s\bin;%s\bin\win95;%s\bin' % (MSToolkitDir, PlatformSDKDir, PlatformSDKDir)
|
exe_path = r'%s\bin;%s\bin\win95;%s\bin' % (MSToolkitDir, PlatformSDKDir, PlatformSDKDir)
|
||||||
return (include_path, lib_path, exe_path, PlatformSDKDir)
|
return (include_path, lib_path, exe_path, PlatformSDKDir)
|
||||||
|
|
||||||
def validate_vars(env):
|
def validate_vars(env):
|
||||||
"""Validate the PDB, PCH, and PCHSTOP construction variables."""
|
"""Validate the PDB, PCH, and PCHSTOP construction variables."""
|
||||||
if env.has_key('PCH') and env['PCH']:
|
if env.has_key('PCH') and env['PCH']:
|
||||||
if not env.has_key('PCHSTOP'):
|
if not env.has_key('PCHSTOP'):
|
||||||
raise SCons.Errors.UserError, "The PCHSTOP construction must be defined if PCH is defined."
|
raise SCons.Errors.UserError, "The PCHSTOP construction must be defined if PCH is defined."
|
||||||
if not SCons.Util.is_String(env['PCHSTOP']):
|
if not SCons.Util.is_String(env['PCHSTOP']):
|
||||||
raise SCons.Errors.UserError, "The PCHSTOP construction variable must be a string: %r"%env['PCHSTOP']
|
raise SCons.Errors.UserError, "The PCHSTOP construction variable must be a string: %r"%env['PCHSTOP']
|
||||||
|
|
||||||
def pch_emitter(target, source, env):
|
def pch_emitter(target, source, env):
|
||||||
"""Sets up the PDB dependencies for a pch file, and adds the object
|
"""Sets up the PDB dependencies for a pch file, and adds the object
|
||||||
file target."""
|
file target."""
|
||||||
|
|
||||||
validate_vars(env)
|
validate_vars(env)
|
||||||
|
|
||||||
pch = None
|
pch = None
|
||||||
obj = None
|
obj = None
|
||||||
|
|
||||||
for t in target:
|
for t in target:
|
||||||
if SCons.Util.splitext(str(t))[1] == '.pch':
|
if SCons.Util.splitext(str(t))[1] == '.pch':
|
||||||
pch = t
|
pch = t
|
||||||
if SCons.Util.splitext(str(t))[1] == '.obj':
|
if SCons.Util.splitext(str(t))[1] == '.obj':
|
||||||
obj = t
|
obj = t
|
||||||
|
|
||||||
if not obj:
|
if not obj:
|
||||||
obj = SCons.Util.splitext(str(pch))[0]+'.obj'
|
obj = SCons.Util.splitext(str(pch))[0]+'.obj'
|
||||||
|
|
||||||
target = [pch, obj] # pch must be first, and obj second for the PCHCOM to work
|
target = [pch, obj] # pch must be first, and obj second for the PCHCOM to work
|
||||||
|
|
||||||
if env.has_key('PDB') and env['PDB']:
|
if env.has_key('PDB') and env['PDB']:
|
||||||
env.SideEffect(env['PDB'], target)
|
env.SideEffect(env['PDB'], target)
|
||||||
env.Precious(env['PDB'])
|
env.Precious(env['PDB'])
|
||||||
|
|
||||||
return (target, source)
|
return (target, source)
|
||||||
|
|
||||||
def object_emitter(target, source, env, parent_emitter):
|
def object_emitter(target, source, env, parent_emitter):
|
||||||
"""Sets up the PDB and PCH dependencies for an object file."""
|
"""Sets up the PDB and PCH dependencies for an object file."""
|
||||||
|
|
||||||
validate_vars(env)
|
validate_vars(env)
|
||||||
|
|
||||||
parent_emitter(target, source, env)
|
parent_emitter(target, source, env)
|
||||||
|
|
||||||
if env.has_key('PDB') and env['PDB']:
|
if env.has_key('PDB') and env['PDB']:
|
||||||
env.SideEffect(env['PDB'], target)
|
env.SideEffect(env['PDB'], target)
|
||||||
env.Precious(env['PDB'])
|
env.Precious(env['PDB'])
|
||||||
|
|
||||||
if env.has_key('PCH') and env['PCH']:
|
if env.has_key('PCH') and env['PCH']:
|
||||||
env.Depends(target, env['PCH'])
|
env.Depends(target, env['PCH'])
|
||||||
|
|
||||||
return (target, source)
|
return (target, source)
|
||||||
|
|
||||||
def static_object_emitter(target, source, env):
|
def static_object_emitter(target, source, env):
|
||||||
return object_emitter(target, source, env,
|
return object_emitter(target, source, env,
|
||||||
SCons.Defaults.StaticObjectEmitter)
|
SCons.Defaults.StaticObjectEmitter)
|
||||||
|
|
||||||
def shared_object_emitter(target, source, env):
|
def shared_object_emitter(target, source, env):
|
||||||
return object_emitter(target, source, env,
|
return object_emitter(target, source, env,
|
||||||
SCons.Defaults.SharedObjectEmitter)
|
SCons.Defaults.SharedObjectEmitter)
|
||||||
|
|
||||||
pch_builder = SCons.Builder.Builder(action='$PCHCOM', suffix='.pch', emitter=pch_emitter)
|
pch_builder = SCons.Builder.Builder(action='$PCHCOM', suffix='.pch', emitter=pch_emitter)
|
||||||
res_builder = SCons.Builder.Builder(action='$RCCOM', suffix='.res')
|
res_builder = SCons.Builder.Builder(action='$RCCOM', suffix='.res')
|
||||||
|
|
||||||
def pdbGenerator(env, target, source, for_signature):
|
def pdbGenerator(env, target, source, for_signature):
|
||||||
if target and env.has_key('PDB') and env['PDB']:
|
if target and env.has_key('PDB') and env['PDB']:
|
||||||
return ['/PDB:%s'%target[0].File(env['PDB']).get_string(for_signature),
|
return ['/PDB:%s'%target[0].File(env['PDB']).get_string(for_signature),
|
||||||
'/DEBUG']
|
'/DEBUG']
|
||||||
|
|
||||||
def win32ShlinkTargets(target, source, env, for_signature):
|
def win32ShlinkTargets(target, source, env, for_signature):
|
||||||
listCmd = []
|
listCmd = []
|
||||||
dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
|
dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
|
||||||
if dll: listCmd.append("/out:%s"%dll.get_string(for_signature))
|
if dll: listCmd.append("/out:%s"%dll.get_string(for_signature))
|
||||||
|
|
||||||
implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX')
|
implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX')
|
||||||
if implib: listCmd.append("/implib:%s"%implib.get_string(for_signature))
|
if implib: listCmd.append("/implib:%s"%implib.get_string(for_signature))
|
||||||
|
|
||||||
return listCmd
|
return listCmd
|
||||||
|
|
||||||
def win32ShlinkSources(target, source, env, for_signature):
|
def win32ShlinkSources(target, source, env, for_signature):
|
||||||
listCmd = []
|
listCmd = []
|
||||||
|
|
||||||
deffile = env.FindIxes(source, "WIN32DEFPREFIX", "WIN32DEFSUFFIX")
|
deffile = env.FindIxes(source, "WIN32DEFPREFIX", "WIN32DEFSUFFIX")
|
||||||
for src in source:
|
for src in source:
|
||||||
if src == deffile:
|
if src == deffile:
|
||||||
# Treat this source as a .def file.
|
# Treat this source as a .def file.
|
||||||
listCmd.append("/def:%s" % src.get_string(for_signature))
|
listCmd.append("/def:%s" % src.get_string(for_signature))
|
||||||
else:
|
else:
|
||||||
# Just treat it as a generic source file.
|
# Just treat it as a generic source file.
|
||||||
listCmd.append(src)
|
listCmd.append(src)
|
||||||
return listCmd
|
return listCmd
|
||||||
|
|
||||||
def win32LibEmitter(target, source, env):
|
def win32LibEmitter(target, source, env):
|
||||||
# SCons.Tool.msvc.validate_vars(env)
|
# SCons.Tool.msvc.validate_vars(env)
|
||||||
|
|
||||||
dll = env.FindIxes(target, "SHLIBPREFIX", "SHLIBSUFFIX")
|
dll = env.FindIxes(target, "SHLIBPREFIX", "SHLIBSUFFIX")
|
||||||
no_import_lib = env.get('no_import_lib', 0)
|
no_import_lib = env.get('no_import_lib', 0)
|
||||||
|
|
||||||
if not dll:
|
if not dll:
|
||||||
raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")
|
raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")
|
||||||
|
|
||||||
if env.get("WIN32_INSERT_DEF", 0) and \
|
if env.get("WIN32_INSERT_DEF", 0) and \
|
||||||
not env.FindIxes(source, "WIN32DEFPREFIX", "WIN32DEFSUFFIX"):
|
not env.FindIxes(source, "WIN32DEFPREFIX", "WIN32DEFSUFFIX"):
|
||||||
|
|
||||||
# append a def file to the list of sources
|
# append a def file to the list of sources
|
||||||
source.append(env.ReplaceIxes(dll,
|
source.append(env.ReplaceIxes(dll,
|
||||||
"SHLIBPREFIX", "SHLIBSUFFIX",
|
"SHLIBPREFIX", "SHLIBSUFFIX",
|
||||||
"WIN32DEFPREFIX", "WIN32DEFSUFFIX"))
|
"WIN32DEFPREFIX", "WIN32DEFSUFFIX"))
|
||||||
|
|
||||||
if env.has_key('PDB') and env['PDB']:
|
if env.has_key('PDB') and env['PDB']:
|
||||||
env.SideEffect(env['PDB'], target)
|
env.SideEffect(env['PDB'], target)
|
||||||
env.Precious(env['PDB'])
|
env.Precious(env['PDB'])
|
||||||
|
|
||||||
if not no_import_lib and \
|
if not no_import_lib and \
|
||||||
not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"):
|
not env.FindIxes(target, "LIBPREFIX", "LIBSUFFIX"):
|
||||||
# Append an import library to the list of targets.
|
# Append an import library to the list of targets.
|
||||||
target.append(env.ReplaceIxes(dll,
|
target.append(env.ReplaceIxes(dll,
|
||||||
"SHLIBPREFIX", "SHLIBSUFFIX",
|
"SHLIBPREFIX", "SHLIBSUFFIX",
|
||||||
"LIBPREFIX", "LIBSUFFIX"))
|
"LIBPREFIX", "LIBSUFFIX"))
|
||||||
# and .exp file is created if there are exports from a DLL
|
# and .exp file is created if there are exports from a DLL
|
||||||
target.append(env.ReplaceIxes(dll,
|
target.append(env.ReplaceIxes(dll,
|
||||||
"SHLIBPREFIX", "SHLIBSUFFIX",
|
"SHLIBPREFIX", "SHLIBSUFFIX",
|
||||||
"WIN32EXPPREFIX", "WIN32EXPSUFFIX"))
|
"WIN32EXPPREFIX", "WIN32EXPSUFFIX"))
|
||||||
|
|
||||||
return (target, source)
|
return (target, source)
|
||||||
|
|
||||||
def prog_emitter(target, source, env):
|
def prog_emitter(target, source, env):
|
||||||
#SCons.Tool.msvc.validate_vars(env)
|
#SCons.Tool.msvc.validate_vars(env)
|
||||||
|
|
||||||
if env.has_key('PDB') and env['PDB']:
|
if env.has_key('PDB') and env['PDB']:
|
||||||
env.SideEffect(env['PDB'], target)
|
env.SideEffect(env['PDB'], target)
|
||||||
env.Precious(env['PDB'])
|
env.Precious(env['PDB'])
|
||||||
|
|
||||||
return (target,source)
|
return (target,source)
|
||||||
|
|
||||||
def RegServerFunc(target, source, env):
|
def RegServerFunc(target, source, env):
|
||||||
if env.has_key('register') and env['register']:
|
if env.has_key('register') and env['register']:
|
||||||
ret = regServerAction([target[0]], [source[0]], env)
|
ret = regServerAction([target[0]], [source[0]], env)
|
||||||
if ret:
|
if ret:
|
||||||
raise SCons.Errors.UserError, "Unable to register %s" % target[0]
|
raise SCons.Errors.UserError, "Unable to register %s" % target[0]
|
||||||
else:
|
else:
|
||||||
print "Registered %s sucessfully" % target[0]
|
print "Registered %s sucessfully" % target[0]
|
||||||
return ret
|
return ret
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
regServerAction = SCons.Action.Action("$REGSVRCOM")
|
regServerAction = SCons.Action.Action("$REGSVRCOM")
|
||||||
regServerCheck = SCons.Action.Action(RegServerFunc, None)
|
regServerCheck = SCons.Action.Action(RegServerFunc, None)
|
||||||
@ -248,106 +248,106 @@ shlibLinkAction = SCons.Action.Action('${TEMPFILE("$SHLINK $SHLINKFLAGS $_SHLINK
|
|||||||
compositeLinkAction = shlibLinkAction + regServerCheck
|
compositeLinkAction = shlibLinkAction + regServerCheck
|
||||||
|
|
||||||
def generate(env):
|
def generate(env):
|
||||||
"""Add Builders and construction variables for MSVC++ to an Environment."""
|
"""Add Builders and construction variables for MSVC++ to an Environment."""
|
||||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||||
|
|
||||||
for suffix in CSuffixes:
|
for suffix in CSuffixes:
|
||||||
static_obj.add_action(suffix, SCons.Defaults.CAction)
|
static_obj.add_action(suffix, SCons.Defaults.CAction)
|
||||||
shared_obj.add_action(suffix, SCons.Defaults.ShCAction)
|
shared_obj.add_action(suffix, SCons.Defaults.ShCAction)
|
||||||
|
|
||||||
for suffix in CXXSuffixes:
|
for suffix in CXXSuffixes:
|
||||||
static_obj.add_action(suffix, SCons.Defaults.CXXAction)
|
static_obj.add_action(suffix, SCons.Defaults.CXXAction)
|
||||||
shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction)
|
shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction)
|
||||||
|
|
||||||
SCons.Tool.createStaticLibBuilder(env)
|
SCons.Tool.createStaticLibBuilder(env)
|
||||||
SCons.Tool.createSharedLibBuilder(env)
|
SCons.Tool.createSharedLibBuilder(env)
|
||||||
SCons.Tool.createProgBuilder(env)
|
SCons.Tool.createProgBuilder(env)
|
||||||
|
|
||||||
env['CCPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Zi /Fd%s"%File(PDB)) or ""}'])
|
env['CCPDBFLAGS'] = SCons.Util.CLVar(['${(PDB and "/Zi /Fd%s"%File(PDB)) or ""}'])
|
||||||
env['CCPCHFLAGS'] = SCons.Util.CLVar(['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}'])
|
env['CCPCHFLAGS'] = SCons.Util.CLVar(['${(PCH and "/Yu%s /Fp%s"%(PCHSTOP or "",File(PCH))) or ""}'])
|
||||||
env['CCCOMFLAGS'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS'
|
env['CCCOMFLAGS'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET $CCPCHFLAGS $CCPDBFLAGS'
|
||||||
env['CC'] = 'cl'
|
env['CC'] = 'cl'
|
||||||
env['CCFLAGS'] = SCons.Util.CLVar('/nologo')
|
env['CCFLAGS'] = SCons.Util.CLVar('/nologo')
|
||||||
env['CCCOM'] = '$CC $CCFLAGS $CCCOMFLAGS'
|
env['CCCOM'] = '$CC $CCFLAGS $CCCOMFLAGS'
|
||||||
env['SHCC'] = '$CC'
|
env['SHCC'] = '$CC'
|
||||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
||||||
env['SHCCCOM'] = '$SHCC $SHCCFLAGS $CCCOMFLAGS'
|
env['SHCCCOM'] = '$SHCC $SHCCFLAGS $CCCOMFLAGS'
|
||||||
env['CXX'] = '$CC'
|
env['CXX'] = '$CC'
|
||||||
env['CXXFLAGS'] = SCons.Util.CLVar('$CCFLAGS $( /TP $)')
|
env['CXXFLAGS'] = SCons.Util.CLVar('$CCFLAGS $( /TP $)')
|
||||||
env['CXXCOM'] = '$CXX $CXXFLAGS $CCCOMFLAGS'
|
env['CXXCOM'] = '$CXX $CXXFLAGS $CCCOMFLAGS'
|
||||||
env['SHCXX'] = '$CXX'
|
env['SHCXX'] = '$CXX'
|
||||||
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
|
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
|
||||||
env['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CCCOMFLAGS'
|
env['SHCXXCOM'] = '$SHCXX $SHCXXFLAGS $CCCOMFLAGS'
|
||||||
env['CPPDEFPREFIX'] = '/D'
|
env['CPPDEFPREFIX'] = '/D'
|
||||||
env['CPPDEFSUFFIX'] = ''
|
env['CPPDEFSUFFIX'] = ''
|
||||||
env['INCPREFIX'] = '/I'
|
env['INCPREFIX'] = '/I'
|
||||||
env['INCSUFFIX'] = ''
|
env['INCSUFFIX'] = ''
|
||||||
env['OBJEMITTER'] = static_object_emitter
|
env['OBJEMITTER'] = static_object_emitter
|
||||||
env['SHOBJEMITTER'] = shared_object_emitter
|
env['SHOBJEMITTER'] = shared_object_emitter
|
||||||
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
|
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
|
||||||
|
|
||||||
env['RC'] = 'rc'
|
env['RC'] = 'rc'
|
||||||
env['RCFLAGS'] = SCons.Util.CLVar('')
|
env['RCFLAGS'] = SCons.Util.CLVar('')
|
||||||
env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
|
env['RCCOM'] = '$RC $_CPPDEFFLAGS $_CPPINCFLAGS $RCFLAGS /fo$TARGET $SOURCES'
|
||||||
CScan = env.get_scanner('.c')
|
CScan = env.get_scanner('.c')
|
||||||
if CScan:
|
if CScan:
|
||||||
CScan.add_skey('.rc')
|
CScan.add_skey('.rc')
|
||||||
env['BUILDERS']['RES'] = res_builder
|
env['BUILDERS']['RES'] = res_builder
|
||||||
|
|
||||||
include_path, lib_path, exe_path, sdk_path = get_msvctoolkit_paths()
|
include_path, lib_path, exe_path, sdk_path = get_msvctoolkit_paths()
|
||||||
env.PrependENVPath('INCLUDE', include_path)
|
env.PrependENVPath('INCLUDE', include_path)
|
||||||
env.PrependENVPath('LIB', lib_path)
|
env.PrependENVPath('LIB', lib_path)
|
||||||
env.PrependENVPath('PATH', exe_path)
|
env.PrependENVPath('PATH', exe_path)
|
||||||
|
|
||||||
env['ENV']['CPU'] = 'i386'
|
env['ENV']['CPU'] = 'i386'
|
||||||
env['ENV']['MSSDK'] = sdk_path
|
env['ENV']['MSSDK'] = sdk_path
|
||||||
env['ENV']['BkOffice'] = sdk_path
|
env['ENV']['BkOffice'] = sdk_path
|
||||||
env['ENV']['Basemake'] = sdk_path + "\\Include\\BKOffice.Mak"
|
env['ENV']['Basemake'] = sdk_path + "\\Include\\BKOffice.Mak"
|
||||||
env['ENV']['INETSDK'] = sdk_path
|
env['ENV']['INETSDK'] = sdk_path
|
||||||
env['ENV']['MSSDK'] = sdk_path
|
env['ENV']['MSSDK'] = sdk_path
|
||||||
env['ENV']['MSTOOLS'] = sdk_path
|
env['ENV']['MSTOOLS'] = sdk_path
|
||||||
env['ENV']['TARGETOS'] = 'WINNT'
|
env['ENV']['TARGETOS'] = 'WINNT'
|
||||||
env['ENV']['APPVER'] = '5.0'
|
env['ENV']['APPVER'] = '5.0'
|
||||||
|
|
||||||
env['CFILESUFFIX'] = '.c'
|
env['CFILESUFFIX'] = '.c'
|
||||||
env['CXXFILESUFFIX'] = '.cc'
|
env['CXXFILESUFFIX'] = '.cc'
|
||||||
|
|
||||||
env['PCHCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo${TARGETS[1]} /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS'
|
env['PCHCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo${TARGETS[1]} /Yc$PCHSTOP /Fp${TARGETS[0]} $CCPDBFLAGS'
|
||||||
env['BUILDERS']['PCH'] = pch_builder
|
env['BUILDERS']['PCH'] = pch_builder
|
||||||
|
|
||||||
env['AR'] = 'lib.exe' #'"' +sdk_path + '\\bin\\Win64\\lib.exe"'
|
env['AR'] = 'lib.exe' #'"' +sdk_path + '\\bin\\Win64\\lib.exe"'
|
||||||
env['ARFLAGS'] = SCons.Util.CLVar('/nologo')
|
env['ARFLAGS'] = SCons.Util.CLVar('/nologo')
|
||||||
env['ARCOM'] = "${TEMPFILE('$AR $ARFLAGS /OUT:$TARGET $SOURCES')}"
|
env['ARCOM'] = "${TEMPFILE('$AR $ARFLAGS /OUT:$TARGET $SOURCES')}"
|
||||||
|
|
||||||
env['SHLINK'] = '$LINK'
|
env['SHLINK'] = '$LINK'
|
||||||
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS /dll')
|
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS /dll')
|
||||||
env['_SHLINK_TARGETS'] = win32ShlinkTargets
|
env['_SHLINK_TARGETS'] = win32ShlinkTargets
|
||||||
env['_SHLINK_SOURCES'] = win32ShlinkSources
|
env['_SHLINK_SOURCES'] = win32ShlinkSources
|
||||||
env['SHLINKCOM'] = compositeLinkAction
|
env['SHLINKCOM'] = compositeLinkAction
|
||||||
env['SHLIBEMITTER']= win32LibEmitter
|
env['SHLIBEMITTER']= win32LibEmitter
|
||||||
env['LINK'] = 'link.exe' #'"' +sdk_path + '\\bin\\Win64\\' + 'link.exe"'
|
env['LINK'] = 'link.exe' #'"' +sdk_path + '\\bin\\Win64\\' + 'link.exe"'
|
||||||
env['LINKFLAGS'] = SCons.Util.CLVar('/nologo')
|
env['LINKFLAGS'] = SCons.Util.CLVar('/nologo')
|
||||||
env['_PDB'] = pdbGenerator
|
env['_PDB'] = pdbGenerator
|
||||||
env["TEMPFILE"] = SCons.Platform.win32.TempFileMunge
|
env["TEMPFILE"] = SCons.Platform.win32.TempFileMunge
|
||||||
env['LINKCOM'] = '${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET $( $_LIBDIRFLAGS $) $_LIBFLAGS $_PDB $SOURCES")}'
|
env['LINKCOM'] = '${TEMPFILE("$LINK $LINKFLAGS /OUT:$TARGET $( $_LIBDIRFLAGS $) $_LIBFLAGS $_PDB $SOURCES")}'
|
||||||
env['PROGEMITTER'] = prog_emitter
|
env['PROGEMITTER'] = prog_emitter
|
||||||
env['LIBDIRPREFIX']='/LIBPATH:'
|
env['LIBDIRPREFIX']='/LIBPATH:'
|
||||||
env['LIBDIRSUFFIX']=''
|
env['LIBDIRSUFFIX']=''
|
||||||
env['LIBLINKPREFIX']=''
|
env['LIBLINKPREFIX']=''
|
||||||
env['LIBLINKSUFFIX']='$LIBSUFFIX'
|
env['LIBLINKSUFFIX']='$LIBSUFFIX'
|
||||||
|
|
||||||
env['WIN32DEFPREFIX'] = ''
|
env['WIN32DEFPREFIX'] = ''
|
||||||
env['WIN32DEFSUFFIX'] = '.def'
|
env['WIN32DEFSUFFIX'] = '.def'
|
||||||
env['WIN32_INSERT_DEF'] = 0
|
env['WIN32_INSERT_DEF'] = 0
|
||||||
|
|
||||||
env['WIN32EXPPREFIX'] = ''
|
env['WIN32EXPPREFIX'] = ''
|
||||||
env['WIN32EXPSUFFIX'] = '.exp'
|
env['WIN32EXPSUFFIX'] = '.exp'
|
||||||
|
|
||||||
env['REGSVRACTION'] = regServerCheck
|
env['REGSVRACTION'] = regServerCheck
|
||||||
env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32')
|
env['REGSVR'] = os.path.join(SCons.Platform.win32.get_system_root(),'System32','regsvr32')
|
||||||
env['REGSVRFLAGS'] = '/s '
|
env['REGSVRFLAGS'] = '/s '
|
||||||
env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS $TARGET'
|
env['REGSVRCOM'] = '$REGSVR $REGSVRFLAGS $TARGET'
|
||||||
|
|
||||||
|
|
||||||
def exists(env):
|
def exists(env):
|
||||||
return env.Detect('cl')
|
return env.Detect('cl')
|
||||||
|
@ -15,6 +15,6 @@ from bpy.app.handlers import persistent
|
|||||||
|
|
||||||
@persistent
|
@persistent
|
||||||
def load_handler(dummy):
|
def load_handler(dummy):
|
||||||
print("Load Handler:", bpy.data.filepath)
|
print("Load Handler:", bpy.data.filepath)
|
||||||
|
|
||||||
bpy.app.handlers.load_post.append(load_handler)
|
bpy.app.handlers.load_post.append(load_handler)
|
||||||
|
@ -6,7 +6,8 @@ This script shows the most simple example of adding a handler.
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
|
|
||||||
def my_handler(scene):
|
def my_handler(scene):
|
||||||
print("Frame Change", scene.frame_current)
|
print("Frame Change", scene.frame_current)
|
||||||
|
|
||||||
bpy.app.handlers.frame_change_pre.append(my_handler)
|
bpy.app.handlers.frame_change_pre.append(my_handler)
|
@ -589,6 +589,7 @@ def pycontext2sphinx(BASEPATH):
|
|||||||
"active_base": ("ObjectBase", False),
|
"active_base": ("ObjectBase", False),
|
||||||
"active_bone": ("Bone", False),
|
"active_bone": ("Bone", False),
|
||||||
"active_object": ("Object", False),
|
"active_object": ("Object", False),
|
||||||
|
"active_operator": ("Operator", False),
|
||||||
"active_pose_bone": ("PoseBone", False),
|
"active_pose_bone": ("PoseBone", False),
|
||||||
"armature": ("Armature", False),
|
"armature": ("Armature", False),
|
||||||
"bone": ("Bone", False),
|
"bone": ("Bone", False),
|
||||||
@ -597,6 +598,7 @@ def pycontext2sphinx(BASEPATH):
|
|||||||
"cloth": ("ClothModifier", False),
|
"cloth": ("ClothModifier", False),
|
||||||
"collision": ("CollisionModifier", False),
|
"collision": ("CollisionModifier", False),
|
||||||
"curve": ("Curve", False),
|
"curve": ("Curve", False),
|
||||||
|
"dynamic_paint": ("DynamicPaintModifier", False),
|
||||||
"edit_bone": ("EditBone", False),
|
"edit_bone": ("EditBone", False),
|
||||||
"edit_image": ("Image", False),
|
"edit_image": ("Image", False),
|
||||||
"edit_object": ("Object", False),
|
"edit_object": ("Object", False),
|
||||||
@ -635,6 +637,7 @@ def pycontext2sphinx(BASEPATH):
|
|||||||
"speaker": ("Speaker", False),
|
"speaker": ("Speaker", False),
|
||||||
"texture": ("Texture", False),
|
"texture": ("Texture", False),
|
||||||
"texture_slot": ("MaterialTextureSlot", False),
|
"texture_slot": ("MaterialTextureSlot", False),
|
||||||
|
"texture_user": ("ID", False),
|
||||||
"vertex_paint_object": ("Object", False),
|
"vertex_paint_object": ("Object", False),
|
||||||
"visible_bases": ("ObjectBase", True),
|
"visible_bases": ("ObjectBase", True),
|
||||||
"visible_bones": ("Object", True),
|
"visible_bones": ("Object", True),
|
||||||
|
5
extern/colamd/CMakeLists.txt
vendored
5
extern/colamd/CMakeLists.txt
vendored
@ -23,7 +23,7 @@
|
|||||||
# ***** END GPL LICENSE BLOCK *****
|
# ***** END GPL LICENSE BLOCK *****
|
||||||
|
|
||||||
set(INC
|
set(INC
|
||||||
./Include
|
Include
|
||||||
)
|
)
|
||||||
|
|
||||||
set(INC_SYS
|
set(INC_SYS
|
||||||
@ -34,7 +34,8 @@ set(SRC
|
|||||||
Source/colamd.c
|
Source/colamd.c
|
||||||
Source/colamd_global.c
|
Source/colamd_global.c
|
||||||
|
|
||||||
Include//colamd.h
|
Include/colamd.h
|
||||||
|
Include/UFconfig.h
|
||||||
)
|
)
|
||||||
|
|
||||||
blender_add_lib(extern_colamd "${SRC}" "${INC}" "${INC_SYS}")
|
blender_add_lib(extern_colamd "${SRC}" "${INC}" "${INC_SYS}")
|
||||||
|
25
extern/libmv/CMakeLists.txt
vendored
25
extern/libmv/CMakeLists.txt
vendored
@ -25,8 +25,8 @@
|
|||||||
set(INC
|
set(INC
|
||||||
.
|
.
|
||||||
../Eigen3
|
../Eigen3
|
||||||
./third_party/ssba
|
third_party/ssba
|
||||||
./third_party/ldl/Include
|
third_party/ldl/Include
|
||||||
../colamd/Include
|
../colamd/Include
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ set(SRC
|
|||||||
third_party/msinttypes/inttypes.h
|
third_party/msinttypes/inttypes.h
|
||||||
)
|
)
|
||||||
|
|
||||||
IF(WIN32)
|
if(WIN32)
|
||||||
list(APPEND SRC
|
list(APPEND SRC
|
||||||
third_party/glog/src/logging.cc
|
third_party/glog/src/logging.cc
|
||||||
third_party/glog/src/raw_logging.cc
|
third_party/glog/src/raw_logging.cc
|
||||||
@ -162,18 +162,23 @@ IF(WIN32)
|
|||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND INC
|
list(APPEND INC
|
||||||
./third_party/glog/src/windows
|
third_party/glog/src/windows
|
||||||
./third_party/msinttypes
|
|
||||||
)
|
)
|
||||||
|
|
||||||
IF(MSVC)
|
if(NOT MINGW)
|
||||||
|
list(APPEND INC
|
||||||
|
third_party/msinttypes
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
set(MSVC_OFLAGS O1 O2 Ox)
|
set(MSVC_OFLAGS O1 O2 Ox)
|
||||||
foreach(FLAG )
|
foreach(FLAG )
|
||||||
string(REPLACE "" "Od" CMAKE_CXX_FLAGS_RELEASE "")
|
string(REPLACE "" "Od" CMAKE_CXX_FLAGS_RELEASE "")
|
||||||
string(REPLACE "" "Od" CMAKE_C_FLAGS_RELWITHDEBINFO "")
|
string(REPLACE "" "Od" CMAKE_C_FLAGS_RELWITHDEBINFO "")
|
||||||
endforeach()
|
endforeach()
|
||||||
ENDIF(MSVC)
|
endif()
|
||||||
ELSE(WIN32)
|
else(WIN32)
|
||||||
list(APPEND SRC
|
list(APPEND SRC
|
||||||
third_party/glog/src/utilities.cc
|
third_party/glog/src/utilities.cc
|
||||||
third_party/glog/src/symbolize.cc
|
third_party/glog/src/symbolize.cc
|
||||||
@ -205,9 +210,9 @@ ELSE(WIN32)
|
|||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND INC
|
list(APPEND INC
|
||||||
./third_party/glog/src
|
third_party/glog/src
|
||||||
)
|
)
|
||||||
ENDIF(WIN32)
|
endif()
|
||||||
|
|
||||||
add_definitions(-DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL=)
|
add_definitions(-DV3DLIB_ENABLE_SUITESPARSE -DGOOGLE_GLOG_DLL_DECL=)
|
||||||
|
|
||||||
|
4
extern/libmv/SConscript
vendored
4
extern/libmv/SConscript
vendored
@ -30,7 +30,9 @@ incs += ' ' + env['BF_PNG_INC']
|
|||||||
incs += ' ' + env['BF_ZLIB_INC']
|
incs += ' ' + env['BF_ZLIB_INC']
|
||||||
|
|
||||||
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
|
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/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']
|
src += ['./third_party/glog/src/windows/port.cc']
|
||||||
|
15
extern/libmv/bundle.sh
vendored
15
extern/libmv/bundle.sh
vendored
@ -166,6 +166,16 @@ IF(WIN32)
|
|||||||
third_party/glog/src/windows/config.h
|
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
|
list(APPEND INC
|
||||||
./third_party/glog/src/windows
|
./third_party/glog/src/windows
|
||||||
./third_party/msinttypes
|
./third_party/msinttypes
|
||||||
@ -219,7 +229,10 @@ incs += ' ' + env['BF_PNG_INC']
|
|||||||
incs += ' ' + env['BF_ZLIB_INC']
|
incs += ' ' + env['BF_ZLIB_INC']
|
||||||
|
|
||||||
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
|
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}
|
${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/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']
|
src += ['./third_party/glog/src/windows/port.cc']
|
||||||
|
13
extern/libmv/libmv-capi.cpp
vendored
13
extern/libmv/libmv-capi.cpp
vendored
@ -368,14 +368,11 @@ libmv_Reconstruction *libmv_solveReconstruction(libmv_Tracks *tracks, int keyfra
|
|||||||
intrinsics->SetPrincipalPoint(principal_x, principal_y);
|
intrinsics->SetPrincipalPoint(principal_x, principal_y);
|
||||||
intrinsics->SetRadialDistortion(k1, k2, k3);
|
intrinsics->SetRadialDistortion(k1, k2, k3);
|
||||||
|
|
||||||
if(focal_length) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
/* do a lens undistortion if focal length is non-zero only */
|
intrinsics->InvertIntrinsics(markers[i].x,
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
markers[i].y,
|
||||||
intrinsics->InvertIntrinsics(markers[i].x,
|
&(markers[i].x),
|
||||||
markers[i].y,
|
&(markers[i].y));
|
||||||
&(markers[i].x),
|
|
||||||
&(markers[i].y));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
libmv::Tracks normalized_tracks(markers);
|
libmv::Tracks normalized_tracks(markers);
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
namespace libmv {
|
namespace libmv {
|
||||||
namespace euclidean_resection {
|
namespace euclidean_resection {
|
||||||
|
|
||||||
|
typedef unsigned int uint;
|
||||||
|
|
||||||
bool EuclideanResection(const Mat2X &x_camera,
|
bool EuclideanResection(const Mat2X &x_camera,
|
||||||
const Mat3X &X_world,
|
const Mat3X &X_world,
|
||||||
Mat3 *R, Vec3 *t,
|
Mat3 *R, Vec3 *t,
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
|
||||||
#include "libmv/tracking/esm_region_tracker.h"
|
#include "libmv/tracking/esm_region_tracker.h"
|
||||||
|
|
||||||
#include "libmv/logging/logging.h"
|
#include "libmv/logging/logging.h"
|
||||||
|
158
extern/libmv/patches/mingw.patch
vendored
158
extern/libmv/patches/mingw.patch
vendored
@ -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
|
diff --git a/src/libmv/numeric/numeric.h b/src/libmv/numeric/numeric.h
|
||||||
index f39d126..21e0f06 100644
|
index f39d126..21e0f06 100644
|
||||||
--- a/src/libmv/numeric/numeric.h
|
--- a/src/libmv/numeric/numeric.h
|
||||||
@ -11,3 +24,148 @@ index f39d126..21e0f06 100644
|
|||||||
inline long lround(double d) {
|
inline long lround(double d) {
|
||||||
return (long)(d>0 ? d+0.5 : ceil(d-0.5));
|
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
|
||||||
|
2
extern/libmv/third_party/glog/src/config.h
vendored
2
extern/libmv/third_party/glog/src/config.h
vendored
@ -4,6 +4,8 @@
|
|||||||
/* Namespace for Google classes */
|
/* Namespace for Google classes */
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include "config_mac.h"
|
#include "config_mac.h"
|
||||||
|
#elif __MINGW32__
|
||||||
|
#include "windows/config.h"
|
||||||
#elif __GNUC__
|
#elif __GNUC__
|
||||||
#include "config_linux.h"
|
#include "config_linux.h"
|
||||||
#elif _MSC_VER
|
#elif _MSC_VER
|
||||||
|
@ -131,7 +131,7 @@
|
|||||||
#define PACKAGE_VERSION "0.3.1"
|
#define PACKAGE_VERSION "0.3.1"
|
||||||
|
|
||||||
/* How to access the PC from a struct ucontext */
|
/* 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]
|
#define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_RIP]
|
||||||
#else
|
#else
|
||||||
#define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_EIP]
|
#define PC_FROM_UCONTEXT uc_mcontext.gregs[REG_EIP]
|
||||||
|
@ -101,7 +101,9 @@
|
|||||||
// correctly when GetStackTrace() is called with max_depth == 0.
|
// correctly when GetStackTrace() is called with max_depth == 0.
|
||||||
// Some code may do that.
|
// 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"
|
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
|
||||||
#elif !defined(NO_FRAME_POINTER)
|
#elif !defined(NO_FRAME_POINTER)
|
||||||
# if defined(__i386__) && __GNUC__ >= 2
|
# if defined(__i386__) && __GNUC__ >= 2
|
||||||
|
@ -59,7 +59,7 @@
|
|||||||
|
|
||||||
// Annoying stuff for windows -- makes sure clients can import these functions
|
// Annoying stuff for windows -- makes sure clients can import these functions
|
||||||
#ifndef GOOGLE_GLOG_DLL_DECL
|
#ifndef GOOGLE_GLOG_DLL_DECL
|
||||||
# if defined(_WIN32) && !defined(__CYGWIN__)
|
# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
|
||||||
# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
|
# define GOOGLE_GLOG_DLL_DECL __declspec(dllimport)
|
||||||
# else
|
# else
|
||||||
# define GOOGLE_GLOG_DLL_DECL
|
# define GOOGLE_GLOG_DLL_DECL
|
||||||
@ -86,6 +86,15 @@
|
|||||||
#include "third_party/gflags/gflags.h"
|
#include "third_party/gflags/gflags.h"
|
||||||
#endif
|
#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 {
|
namespace google {
|
||||||
|
|
||||||
#if 0 // the C99 format
|
#if 0 // the C99 format
|
||||||
@ -98,11 +107,16 @@ typedef int32_t int32;
|
|||||||
typedef u_int32_t uint32;
|
typedef u_int32_t uint32;
|
||||||
typedef int64_t int64;
|
typedef int64_t int64;
|
||||||
typedef u_int64_t uint64;
|
typedef u_int64_t uint64;
|
||||||
#elif 1 // the windows (vc7) format
|
#elif defined(_MSC_VER)
|
||||||
typedef __int32 int32;
|
typedef __int32 int32;
|
||||||
typedef unsigned __int32 uint32;
|
typedef unsigned __int32 uint32;
|
||||||
typedef __int64 int64;
|
typedef __int64 int64;
|
||||||
typedef unsigned __int64 uint64;
|
typedef unsigned __int64 uint64;
|
||||||
|
#elif defined(__MINGW32__)
|
||||||
|
typedef int32_t int32;
|
||||||
|
typedef uint32_t uint32;
|
||||||
|
typedef int64_t int64;
|
||||||
|
typedef uint64_t uint64;
|
||||||
#else
|
#else
|
||||||
#error Do not know how to define a 32-bit integer quantity on your system
|
#error Do not know how to define a 32-bit integer quantity on your system
|
||||||
#endif
|
#endif
|
||||||
|
37
extern/libmv/third_party/glog/src/windows/port.h
vendored
37
extern/libmv/third_party/glog/src/windows/port.h
vendored
@ -59,14 +59,16 @@
|
|||||||
* used by both C and C++ code, so we put all the C++ together.
|
* 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
|
||||||
* 4251: it's complaining about a private struct I've chosen not to dllexport
|
/* 4244: otherwise we get problems when substracting two size_t's to an int
|
||||||
* 4355: we use this in a constructor, but we do it safely
|
* 4251: it's complaining about a private struct I've chosen not to dllexport
|
||||||
* 4715: for some reason VC++ stopped realizing you can't return after abort()
|
* 4355: we use this in a constructor, but we do it safely
|
||||||
* 4800: we know we're casting ints/char*'s to bools, and we're ok with that
|
* 4715: for some reason VC++ stopped realizing you can't return after abort()
|
||||||
* 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
|
* 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 */
|
/* file I/O */
|
||||||
#define PATH_MAX 1024
|
#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,
|
extern int safe_vsnprintf(char *str, size_t size,
|
||||||
const char *format, va_list ap);
|
const char *format, va_list ap);
|
||||||
#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
|
#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
|
||||||
|
#if !defined(__MINGW32__)
|
||||||
#define va_copy(dst, src) (dst) = (src)
|
#define va_copy(dst, src) (dst) = (src)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Windows doesn't support specifying the number of buckets as a
|
/* Windows doesn't support specifying the number of buckets as a
|
||||||
* hash_map constructor arg, so we leave this blank.
|
* 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))
|
#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) {
|
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);
|
localtime_s(result, timep);
|
||||||
return result;
|
return result;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline char* strerror_r(int errnum, char* buf, size_t buflen) {
|
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);
|
strerror_s(buf, buflen, errnum);
|
||||||
return buf;
|
return buf;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
|
@ -57,3 +57,8 @@ endif()
|
|||||||
if(WITH_IK_ITASC)
|
if(WITH_IK_ITASC)
|
||||||
add_subdirectory(itasc)
|
add_subdirectory(itasc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CYCLES)
|
||||||
|
add_subdirectory(cycles)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
@ -25,6 +25,9 @@ NEW_CSG='false'
|
|||||||
if env['WITH_BF_FLUID']:
|
if env['WITH_BF_FLUID']:
|
||||||
SConscript(['elbeem/SConscript'])
|
SConscript(['elbeem/SConscript'])
|
||||||
|
|
||||||
|
if env['WITH_BF_CYCLES']:
|
||||||
|
SConscript(['cycles/SConscript'])
|
||||||
|
|
||||||
if NEW_CSG=='false':
|
if NEW_CSG=='false':
|
||||||
SConscript(['bsp/SConscript'])
|
SConscript(['bsp/SConscript'])
|
||||||
else:
|
else:
|
||||||
|
@ -98,7 +98,6 @@ set(SRC
|
|||||||
intern/AUD_IWriter.h
|
intern/AUD_IWriter.h
|
||||||
intern/AUD_JOSResampleFactory.cpp
|
intern/AUD_JOSResampleFactory.cpp
|
||||||
intern/AUD_JOSResampleFactory.h
|
intern/AUD_JOSResampleFactory.h
|
||||||
intern/AUD_JOSResampleReaderCoeff.cpp
|
|
||||||
intern/AUD_JOSResampleReader.cpp
|
intern/AUD_JOSResampleReader.cpp
|
||||||
intern/AUD_JOSResampleReader.h
|
intern/AUD_JOSResampleReader.h
|
||||||
intern/AUD_LinearResampleFactory.cpp
|
intern/AUD_LinearResampleFactory.cpp
|
||||||
|
@ -395,7 +395,7 @@ void AUD_FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
|
|||||||
{
|
{
|
||||||
data_size = AUD_MIN(pkgbuf_pos, left * sample_size);
|
data_size = AUD_MIN(pkgbuf_pos, left * sample_size);
|
||||||
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(),
|
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(),
|
||||||
data_size / AUD_FORMAT_SIZE(m_specs.format));
|
data_size / AUD_FORMAT_SIZE(m_specs.format));
|
||||||
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
|
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
|
||||||
left -= data_size/sample_size;
|
left -= data_size/sample_size;
|
||||||
}
|
}
|
||||||
|
@ -73,5 +73,5 @@ void AUD_ConverterReader::read(int& length, bool& eos, sample_t* buffer)
|
|||||||
m_reader->read(length, eos, m_buffer.getBuffer());
|
m_reader->read(length, eos, m_buffer.getBuffer());
|
||||||
|
|
||||||
m_convert((data_t*)buffer, (data_t*)m_buffer.getBuffer(),
|
m_convert((data_t*)buffer, (data_t*)m_buffer.getBuffer(),
|
||||||
length * specs.channels);
|
length * specs.channels);
|
||||||
}
|
}
|
||||||
|
@ -155,6 +155,9 @@ void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
|
|||||||
m_cache_ok = true;
|
m_cache_ok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
for(int channel = 0; channel < m_channels; channel++)
|
for(int channel = 0; channel < m_channels; channel++)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < length; i++)
|
for(int i = 0; i < length; i++)
|
||||||
|
@ -167,39 +167,41 @@ void BOP_Face2Face(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB)
|
|||||||
MT_Point3 p2 = mesh->getVertex(faceA->getVertex(1))->getPoint();
|
MT_Point3 p2 = mesh->getVertex(faceA->getVertex(1))->getPoint();
|
||||||
MT_Point3 p3 = mesh->getVertex(faceA->getVertex(2))->getPoint();
|
MT_Point3 p3 = mesh->getVertex(faceA->getVertex(2))->getPoint();
|
||||||
|
|
||||||
/* get (or create) bounding box for face A */
|
/* get (or create) bounding box for face A */
|
||||||
if( faceA->getBBox() == NULL )
|
if( faceA->getBBox() == NULL )
|
||||||
faceA->setBBox(p1,p2,p3);
|
faceA->setBBox(p1,p2,p3);
|
||||||
BOP_BBox *boxA = faceA->getBBox();
|
BOP_BBox *boxA = faceA->getBBox();
|
||||||
|
|
||||||
/* start checking B faces with the previously stored split index */
|
/* start checking B faces with the previously stored split index */
|
||||||
|
|
||||||
for(unsigned int idxFaceB=faceA->getSplit();
|
for(unsigned int idxFaceB=faceA->getSplit();
|
||||||
idxFaceB<facesB->size() && (faceA->getTAG() != BROKEN) && (faceA->getTAG() != PHANTOM);) {
|
idxFaceB<facesB->size() && (faceA->getTAG() != BROKEN) && (faceA->getTAG() != PHANTOM);) {
|
||||||
BOP_Face *faceB = (*facesB)[idxFaceB];
|
BOP_Face *faceB = (*facesB)[idxFaceB];
|
||||||
faceA->setSplit(idxFaceB);
|
faceA->setSplit(idxFaceB);
|
||||||
if ((faceB->getTAG() != BROKEN) && (faceB->getTAG() != PHANTOM)) {
|
if ((faceB->getTAG() != BROKEN) && (faceB->getTAG() != PHANTOM)) {
|
||||||
|
|
||||||
/* get (or create) bounding box for face B */
|
/* get (or create) bounding box for face B */
|
||||||
if( faceB->getBBox() == NULL )
|
if( faceB->getBBox() == NULL ) {
|
||||||
faceB->setBBox(mesh->getVertex(faceB->getVertex(0))->getPoint(),
|
faceB->setBBox(mesh->getVertex(faceB->getVertex(0))->getPoint(),
|
||||||
mesh->getVertex(faceB->getVertex(1))->getPoint(),
|
mesh->getVertex(faceB->getVertex(1))->getPoint(),
|
||||||
mesh->getVertex(faceB->getVertex(2))->getPoint());
|
mesh->getVertex(faceB->getVertex(2))->getPoint());
|
||||||
BOP_BBox *boxB = faceB->getBBox();
|
}
|
||||||
|
BOP_BBox *boxB = faceB->getBBox();
|
||||||
|
|
||||||
if (boxA->intersect(*boxB)) {
|
if (boxA->intersect(*boxB)) {
|
||||||
MT_Plane3 planeB = faceB->getPlane();
|
MT_Plane3 planeB = faceB->getPlane();
|
||||||
if (BOP_containsPoint(planeB,p1) &&
|
if (BOP_containsPoint(planeB,p1) &&
|
||||||
BOP_containsPoint(planeB,p2) &&
|
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);
|
if (BOP_orientation(planeB,planeA)>0) {
|
||||||
}
|
BOP_intersectCoplanarFaces(mesh,facesB,faceA,faceB,false);
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
BOP_intersectNonCoplanarFaces(mesh,facesA,facesB,faceA,faceB);
|
else {
|
||||||
}
|
BOP_intersectNonCoplanarFaces(mesh,facesA,facesB,faceA,faceB);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
idxFaceB++;
|
idxFaceB++;
|
||||||
}
|
}
|
||||||
@ -656,16 +658,16 @@ void BOP_mergeSort(MT_Point3 *points, unsigned int *face, unsigned int &size, bo
|
|||||||
* @param invert indicates if faceA has priority over faceB
|
* @param invert indicates if faceA has priority over faceB
|
||||||
* @param segmemts array of the output x-segments
|
* @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* faceA,
|
||||||
BOP_Face* faceB,
|
BOP_Face* faceB,
|
||||||
BOP_Segment sA,
|
BOP_Segment sA,
|
||||||
BOP_Segment sB,
|
BOP_Segment sB,
|
||||||
bool invert,
|
bool invert,
|
||||||
BOP_Segment* segments) {
|
BOP_Segment* segments) {
|
||||||
BOP_createXS(mesh, faceA, faceB, faceA->getPlane(), faceB->getPlane(),
|
BOP_createXS(mesh, faceA, faceB, faceA->getPlane(), faceB->getPlane(),
|
||||||
sA, sB, invert, segments);
|
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 .
|
* Computes the x-segment of two segments (the shared interval). The segments needs to have sA.m_cfg1 > 0 && sB.m_cfg1 > 0 .
|
||||||
@ -1178,21 +1180,23 @@ void BOP_removeOverlappedFaces(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *f
|
|||||||
for(unsigned int j=0;j<facesB->size();) {
|
for(unsigned int j=0;j<facesB->size();) {
|
||||||
BOP_Face *faceJ = (*facesB)[j];
|
BOP_Face *faceJ = (*facesB)[j];
|
||||||
if (faceJ->getTAG()!=BROKEN) {
|
if (faceJ->getTAG()!=BROKEN) {
|
||||||
MT_Plane3 planeJ = faceJ->getPlane();
|
MT_Plane3 planeJ = faceJ->getPlane();
|
||||||
if (BOP_containsPoint(planeJ,p1) && BOP_containsPoint(planeJ,p2)
|
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 q1 = mesh->getVertex(faceJ->getVertex(0))->getPoint();
|
||||||
MT_Point3 q3 = mesh->getVertex(faceJ->getVertex(2))->getPoint();
|
MT_Point3 q2 = mesh->getVertex(faceJ->getVertex(1))->getPoint();
|
||||||
if (BOP_overlap(MT_Vector3(planeJ.x(),planeJ.y(),planeJ.z()),
|
MT_Point3 q3 = mesh->getVertex(faceJ->getVertex(2))->getPoint();
|
||||||
p1,p2,p3,q1,q2,q3)) {
|
if (BOP_overlap(MT_Vector3(planeJ.x(),planeJ.y(),planeJ.z()),
|
||||||
facesB->erase(facesB->begin()+j,facesB->begin()+(j+1));
|
p1,p2,p3,q1,q2,q3))
|
||||||
faceJ->setTAG(BROKEN);
|
{
|
||||||
overlapped = true;
|
facesB->erase(facesB->begin()+j,facesB->begin()+(j+1));
|
||||||
}
|
faceJ->setTAG(BROKEN);
|
||||||
else j++;
|
overlapped = true;
|
||||||
}
|
}
|
||||||
else j++;
|
else j++;
|
||||||
|
}
|
||||||
|
else j++;
|
||||||
}else j++;
|
}else j++;
|
||||||
}
|
}
|
||||||
if (overlapped) faceI->setTAG(OVERLAPPED);
|
if (overlapped) faceI->setTAG(OVERLAPPED);
|
||||||
|
@ -46,23 +46,23 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
BoolOpState BOP_intersectionBoolOp(BOP_Mesh* meshC,
|
BoolOpState BOP_intersectionBoolOp(BOP_Mesh* meshC,
|
||||||
BOP_Faces* facesA,
|
BOP_Faces* facesA,
|
||||||
BOP_Faces* facesB,
|
BOP_Faces* facesB,
|
||||||
bool invertMeshA,
|
bool invertMeshA,
|
||||||
bool invertMeshB);
|
bool invertMeshB);
|
||||||
BOP_Face3* BOP_createFace(BOP_Mesh* mesh,
|
BOP_Face3* BOP_createFace(BOP_Mesh* mesh,
|
||||||
BOP_Index vertex1,
|
BOP_Index vertex1,
|
||||||
BOP_Index vertex2,
|
BOP_Index vertex2,
|
||||||
BOP_Index vertex3,
|
BOP_Index vertex3,
|
||||||
BOP_Index origFace);
|
BOP_Index origFace);
|
||||||
void BOP_addMesh(BOP_Mesh* mesh,
|
void BOP_addMesh(BOP_Mesh* mesh,
|
||||||
BOP_Faces* meshFacesId,
|
BOP_Faces* meshFacesId,
|
||||||
CSG_FaceIteratorDescriptor& face_it,
|
CSG_FaceIteratorDescriptor& face_it,
|
||||||
CSG_VertexIteratorDescriptor& vertex_it,
|
CSG_VertexIteratorDescriptor& vertex_it,
|
||||||
bool invert);
|
bool invert);
|
||||||
BSP_CSGMesh* BOP_newEmptyMesh();
|
BSP_CSGMesh* BOP_newEmptyMesh();
|
||||||
BSP_CSGMesh* BOP_exportMesh(BOP_Mesh* inputMesh,
|
BSP_CSGMesh* BOP_exportMesh(BOP_Mesh* inputMesh,
|
||||||
bool invert);
|
bool invert);
|
||||||
void BOP_meshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp);
|
void BOP_meshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp);
|
||||||
void BOP_simplifiedMeshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp, bool inverted);
|
void BOP_simplifiedMeshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp, bool inverted);
|
||||||
void BOP_meshClassify(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp);
|
void BOP_meshClassify(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp);
|
||||||
|
@ -788,20 +788,20 @@ BOP_Index BOP_Mesh::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex)
|
|||||||
|
|
||||||
bool BOP_Mesh::isClosedMesh()
|
bool BOP_Mesh::isClosedMesh()
|
||||||
{
|
{
|
||||||
for(unsigned int i=0; i<m_edges.size(); i++) {
|
for(unsigned int i=0; i<m_edges.size(); i++) {
|
||||||
BOP_Edge *edge = m_edges[i];
|
BOP_Edge *edge = m_edges[i];
|
||||||
BOP_Indexs faces = edge->getFaces();
|
BOP_Indexs faces = edge->getFaces();
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
const BOP_IT_Indexs facesEnd = faces.end();
|
const BOP_IT_Indexs facesEnd = faces.end();
|
||||||
for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) {
|
for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) {
|
||||||
if (m_faces[*it]->getTAG()!=BROKEN)
|
if (m_faces[*it]->getTAG()!=BROKEN)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((count%2)!=0) return false;
|
if ((count%2)!=0) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,14 +91,14 @@ CSG_PerformBooleanOperation(
|
|||||||
|
|
||||||
switch( op_type ) {
|
switch( op_type ) {
|
||||||
case e_csg_union:
|
case e_csg_union:
|
||||||
boolType = BOP_UNION;
|
boolType = BOP_UNION;
|
||||||
break;
|
break;
|
||||||
case e_csg_difference:
|
case e_csg_difference:
|
||||||
boolType = BOP_DIFFERENCE;
|
boolType = BOP_DIFFERENCE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
boolType = BOP_INTERSECTION;
|
boolType = BOP_INTERSECTION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoolOpState boolOpResult;
|
BoolOpState boolOpResult;
|
||||||
|
@ -229,7 +229,7 @@ private:
|
|||||||
Parent(
|
Parent(
|
||||||
unsigned int i
|
unsigned int i
|
||||||
) {
|
) {
|
||||||
return (i-1) >> 1;
|
return (i-1) >> 1;
|
||||||
}
|
}
|
||||||
int
|
int
|
||||||
Left(
|
Left(
|
||||||
|
75
intern/cycles/CMakeLists.txt
Normal file
75
intern/cycles/CMakeLists.txt
Normal file
@ -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
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])
|
||||||
|
|
69
intern/cycles/app/CMakeLists.txt
Normal file
69
intern/cycles/app/CMakeLists.txt
Normal file
@ -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()
|
||||||
|
|
71
intern/cycles/app/cycles_server.cpp
Normal file
71
intern/cycles/app/cycles_server.cpp
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
307
intern/cycles/app/cycles_test.cpp
Normal file
307
intern/cycles/app/cycles_test.cpp
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
942
intern/cycles/app/cycles_xml.cpp
Normal file
942
intern/cycles/app/cycles_xml.cpp
Normal file
@ -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
|
||||||
|
|
31
intern/cycles/app/cycles_xml.h
Normal file
31
intern/cycles/app/cycles_xml.h
Normal file
@ -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__ */
|
||||||
|
|
47
intern/cycles/blender/CMakeLists.txt
Normal file
47
intern/cycles/blender/CMakeLists.txt
Normal file
@ -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})
|
||||||
|
|
95
intern/cycles/blender/addon/__init__.py
Normal file
95
intern/cycles/blender/addon/__init__.py
Normal file
@ -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__)
|
88
intern/cycles/blender/addon/engine.py
Normal file
88
intern/cycles/blender/addon/engine.py
Normal file
@ -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()
|
66
intern/cycles/blender/addon/enums.py
Normal file
66
intern/cycles/blender/addon/enums.py
Normal file
@ -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"),
|
||||||
|
)
|
57
intern/cycles/blender/addon/presets.py
Normal file
57
intern/cycles/blender/addon/presets.py
Normal file
@ -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()
|
211
intern/cycles/blender/addon/properties.py
Normal file
211
intern/cycles/blender/addon/properties.py
Normal file
@ -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)
|
801
intern/cycles/blender/addon/ui.py
Normal file
801
intern/cycles/blender/addon/ui.py
Normal file
@ -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')
|
105
intern/cycles/blender/addon/xml.py
Normal file
105
intern/cycles/blender/addon/xml.py
Normal file
@ -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()
|
290
intern/cycles/blender/blender_camera.cpp
Normal file
290
intern/cycles/blender/blender_camera.cpp
Normal file
@ -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
|
||||||
|
|
321
intern/cycles/blender/blender_mesh.cpp
Normal file
321
intern/cycles/blender/blender_mesh.cpp
Normal file
@ -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
|
||||||
|
|
263
intern/cycles/blender/blender_object.cpp
Normal file
263
intern/cycles/blender/blender_object.cpp
Normal file
@ -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
|
||||||
|
|
212
intern/cycles/blender/blender_python.cpp
Normal file
212
intern/cycles/blender/blender_python.cpp
Normal file
@ -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), ®ionptr);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
316
intern/cycles/blender/blender_session.cpp
Normal file
316
intern/cycles/blender/blender_session.cpp
Normal file
@ -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
|
||||||
|
|
81
intern/cycles/blender/blender_session.h
Normal file
81
intern/cycles/blender/blender_session.h
Normal file
@ -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__ */
|
709
intern/cycles/blender/blender_shader.cpp
Normal file
709
intern/cycles/blender/blender_shader.cpp
Normal file
@ -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
|
||||||
|
|
303
intern/cycles/blender/blender_sync.cpp
Normal file
303
intern/cycles/blender/blender_sync.cpp
Normal file
@ -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
|
||||||
|
|
119
intern/cycles/blender/blender_sync.h
Normal file
119
intern/cycles/blender/blender_sync.h
Normal file
@ -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__ */
|
||||||
|
|
332
intern/cycles/blender/blender_util.h
Normal file
332
intern/cycles/blender/blender_util.h
Normal file
@ -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__ */
|
||||||
|
|
28
intern/cycles/bvh/CMakeLists.txt
Normal file
28
intern/cycles/bvh/CMakeLists.txt
Normal file
@ -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
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(¶ms, 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
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__ */
|
||||||
|
|
549
intern/cycles/bvh/bvh_build.cpp
Normal file
549
intern/cycles/bvh/bvh_build.cpp
Normal file
@ -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
|
||||||
|
|
152
intern/cycles/bvh/bvh_build.h
Normal file
152
intern/cycles/bvh/bvh_build.h
Normal file
@ -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__ */
|
||||||
|
|
101
intern/cycles/bvh/bvh_node.cpp
Normal file
101
intern/cycles/bvh/bvh_node.cpp
Normal file
@ -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
|
||||||
|
|
112
intern/cycles/bvh/bvh_node.h
Normal file
112
intern/cycles/bvh/bvh_node.h
Normal file
@ -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__ */
|
||||||
|
|
86
intern/cycles/bvh/bvh_params.h
Normal file
86
intern/cycles/bvh/bvh_params.h
Normal file
@ -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__ */
|
||||||
|
|
57
intern/cycles/bvh/bvh_sort.cpp
Normal file
57
intern/cycles/bvh/bvh_sort.cpp
Normal file
@ -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
|
||||||
|
|
28
intern/cycles/bvh/bvh_sort.h
Normal file
28
intern/cycles/bvh/bvh_sort.h
Normal file
@ -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__ */
|
||||||
|
|
100
intern/cycles/cmake/external_libs.cmake
Normal file
100
intern/cycles/cmake/external_libs.cmake
Normal file
@ -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()
|
||||||
|
|
33
intern/cycles/device/CMakeLists.txt
Normal file
33
intern/cycles/device/CMakeLists.txt
Normal file
@ -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})
|
222
intern/cycles/device/device.cpp
Normal file
222
intern/cycles/device/device.cpp
Normal file
@ -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
|
||||||
|
|
140
intern/cycles/device/device.h
Normal file
140
intern/cycles/device/device.h
Normal file
@ -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__ */
|
||||||
|
|
263
intern/cycles/device/device_cpu.cpp
Normal file
263
intern/cycles/device/device_cpu.cpp
Normal file
@ -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
|
||||||
|
|
809
intern/cycles/device/device_cuda.cpp
Normal file
809
intern/cycles/device/device_cuda.cpp
Normal file
@ -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(¶m, 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(¶m))
|
||||||
|
}
|
||||||
|
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
|
||||||
|
|
35
intern/cycles/device/device_intern.h
Normal file
35
intern/cycles/device/device_intern.h
Normal file
@ -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__ */
|
||||||
|
|
244
intern/cycles/device/device_memory.h
Normal file
244
intern/cycles/device/device_memory.h
Normal file
@ -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__ */
|
||||||
|
|
336
intern/cycles/device/device_multi.cpp
Normal file
336
intern/cycles/device/device_multi.cpp
Normal file
@ -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
|
||||||
|
|
391
intern/cycles/device/device_network.cpp
Normal file
391
intern/cycles/device/device_network.cpp
Normal file
@ -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
|
||||||
|
|
308
intern/cycles/device/device_network.h
Normal file
308
intern/cycles/device/device_network.h
Normal file
@ -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__ */
|
||||||
|
|
663
intern/cycles/device/device_opencl.cpp
Normal file
663
intern/cycles/device/device_opencl.cpp
Normal file
@ -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 */
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user