option(WITH_BULLET "Enable Bullet (Physics Engine)" ON)
option(WITH_GAMEENGINE "Enable Game Engine" ON)
option(WITH_PLAYER "Build Player" OFF)
+option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ON)
option(WITH_COMPOSITOR "Enable the tile based nodal compositor" ON)
# GHOST Windowing Library Options
endif()
# auto enable boost for cycles and carve
-if(WITH_CYCLES OR WITH_CARVE)
+if(WITH_CYCLES OR WITH_CARVE OR WITH_OPENCOLORIO)
set(WITH_BOOST ON)
endif()
endif()
endif()
+ if(WITH_OPENCOLORIO)
+ # use lib dir if available and nothing else specified
+ if(LIBDIR AND NOT OPENCOLORIO_ROOT_DIR)
+ set(OPENCOLORIO_ROOT_DIR ${LIBDIR}/ocio)
+ endif()
+
+ find_package(OpenColorIO)
+
+ set(OPENCOLORIO_LIBRARIES ${OPENCOLORIO_LIBRARIES})
+ set(OPENCOLORIO_LIBPATH) # TODO, remove and reference the absolute path everywhere
+ set(OPENCOLORIO_DEFINITIONS)
+
+ if(NOT OPENCOLORIO_FOUND)
+ set(WITH_OPENCOLORIO OFF)
+ message(STATUS "OpenColorIO not found")
+ endif()
+ endif()
+
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
set(PLATFORM_LINKLIBS "-lutil -lc -lm -lpthread -lstdc++")
set(OPENIMAGEIO_DEFINITIONS)
endif()
+ if(WITH_OPENCOLORIO)
+ set(OPENCOLORIO ${LIBDIR}/opencolorio)
+ set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO}/include)
+ set(OPENCOLORIO_LIBRARIES OpenColorIO)
+ set_lib_path(OPENCOLORIO_LIBPATH "opencolorio/lib")
+ set(OPENCOLORIO_DEFINITIONS)
+ endif()
+
set(PLATFORM_LINKFLAGS "/SUBSYSTEM:CONSOLE /STACK:2097152 /INCREMENTAL:NO /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcmrt.lib /NODEFAULTLIB:msvcurt.lib /NODEFAULTLIB:msvcrtd.lib")
# MSVC only, Mingw doesnt need
set(OPENIMAGEIO_DEFINITIONS)
endif()
+ if(WITH_OPENCOLORIO)
+ set(OPENCOLORIO ${LIBDIR}/opencolorio)
+ set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO}/include)
+ set(OPENCOLORIO_LIBRARIES OpenColorIO)
+ set(OPENCOLORIO_LIBPATH ${OPENCOLORIO}/lib)
+ set(OPENCOLORIO_DEFINITIONS)
+ endif()
+
set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152")
## DISABLE - causes linking errors
set(OPENIMAGEIO_DEFINITIONS "-DOIIO_STATIC_BUILD")
endif()
+ if(WITH_OPENCOLORIO)
+ set(OPENCOLORIO ${LIBDIR}/opencolorio)
+ set(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO}/include)
+ set(OPENCOLORIO_LIBRARIES OpenColorIO tinyxml yaml-cpp)
+ set(OPENCOLORIO_LIBPATH ${OPENCOLORIO}/lib)
+ set(OPENCOLORIO_DEFINITIONS "-DOCIO_STATIC_BUILD")
+ endif()
+
set(EXETYPE MACOSX_BUNDLE)
set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
info_cfg_option(WITH_INTERNATIONAL)
info_cfg_option(WITH_INPUT_NDOF)
info_cfg_option(WITH_CYCLES)
+ info_cfg_option(WITH_OPENCOLORIO)
info_cfg_text("Compiler Options:")
info_cfg_option(WITH_BUILDINFO)
kernel_build_dir = os.path.join(B.root_build_dir, 'intern/cycles/kernel')
cubin_file = os.path.join(kernel_build_dir, "kernel_%s.cubin" % arch)
scriptinstall.append(env.Install(dir=dir,source=cubin_file))
-
+
+ if env['WITH_BF_OCIO']:
+ colormanagement = os.path.join('release', 'datafiles', 'colormanagement')
+
+ for dp, dn, df in os.walk(colormanagement):
+ if '.svn' in dn:
+ dn.remove('.svn')
+ if '_svn' in dn:
+ dn.remove('_svn')
+
+ dir = os.path.join(env['BF_INSTALLDIR'], VERSION, 'datafiles')
+ dir += os.sep + os.path.basename(colormanagement) + dp[len(colormanagement):]
+
+ source = [os.path.join(dp, f) for f in df if not f.endswith(".pyc")]
+
+ # To ensure empty dirs are created too
+ if len(source) == 0:
+ env.Execute(Mkdir(dir))
+
+ scriptinstall.append(env.Install(dir=dir,source=source))
+
if env['WITH_BF_INTERNATIONAL']:
internationalpaths=['release' + os.sep + 'datafiles']
if env['WITH_BF_OIIO'] and env['OURPLATFORM'] != 'win32-mingw':
dllsources.append('${LCGDIR}/openimageio/bin/OpenImageIO.dll')
+ if env['WITH_BF_OCIO'] and env['OURPLATFORM'] != 'win32-mingw':
+ dllsources.append('${LCGDIR}/opencolorio/bin/OpenColorIO.dll')
+
dllsources.append('#source/icons/blender.exe.manifest')
windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
--- /dev/null
+# - Find OpenColorIO library
+# Find the native OpenColorIO includes and library
+# This module defines
+# OPENCOLORIO_INCLUDE_DIRS, where to find OpenColorIO.h, Set when
+# OPENCOLORIO_INCLUDE_DIR is found.
+# OPENCOLORIO_LIBRARIES, libraries to link against to use OpenColorIO.
+# OPENCOLORIO_ROOT_DIR, The base directory to search for OpenColorIO.
+# This can also be an environment variable.
+# OPENCOLORIO_FOUND, If false, do not try to use OpenColorIO.
+#
+# also defined, but not for general use are
+# OPENCOLORIO_LIBRARY, where to find the OpenColorIO library.
+
+#=============================================================================
+# Copyright 2012 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 OPENCOLORIO_ROOT_DIR was defined in the environment, use it.
+IF(NOT OPENCOLORIO_ROOT_DIR AND NOT $ENV{OPENCOLORIO_ROOT_DIR} STREQUAL "")
+ SET(OPENCOLORIO_ROOT_DIR $ENV{OPENCOLORIO_ROOT_DIR})
+ENDIF()
+
+SET(_opencolorio_SEARCH_DIRS
+ ${OPENCOLORIO_ROOT_DIR}
+ /usr/local
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+)
+
+FIND_PATH(OPENCOLORIO_INCLUDE_DIR
+ NAMES
+ OpenColorIO/OpenColorIO.h
+ HINTS
+ ${_opencolorio_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+FIND_LIBRARY(OPENCOLORIO_LIBRARY
+ NAMES
+ OCIO OpenColorIO
+ HINTS
+ ${_opencolorio_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib64 lib
+ )
+
+# handle the QUIETLY and REQUIRED arguments and set OPENCOLORIO_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenColorIO DEFAULT_MSG
+ OPENCOLORIO_LIBRARY OPENCOLORIO_INCLUDE_DIR)
+
+IF(OPENCOLORIO_FOUND)
+ SET(OPENCOLORIO_LIBRARIES ${OPENCOLORIO_LIBRARY})
+ SET(OPENCOLORIO_INCLUDE_DIRS ${OPENCOLORIO_INCLUDE_DIR})
+ENDIF(OPENCOLORIO_FOUND)
+
+MARK_AS_ADVANCED(
+ OPENCOLORIO_INCLUDE_DIR
+ OPENCOLORIO_LIBRARY
+)
+
if(WITH_OPENIMAGEIO)
link_directories(${OPENIMAGEIO_LIBPATH})
endif()
+ if(WITH_OPENCOLORIO)
+ link_directories(${OPENCOLORIO_LIBPATH})
+ endif()
if(WITH_IMAGE_OPENJPEG AND WITH_SYSTEM_OPENJPEG)
link_directories(${OPENJPEG_LIBPATH})
endif()
if(WITH_OPENIMAGEIO)
target_link_libraries(${target} ${OPENIMAGEIO_LIBRARIES})
endif()
+ if(WITH_OPENCOLORIO)
+ target_link_libraries(${target} ${OPENCOLORIO_LIBRARIES})
+ endif()
if(WITH_BOOST)
target_link_libraries(${target} ${BOOST_LIBRARIES})
endif()
BF_OIIO_LIB = 'OpenImageIO'
BF_OIIO_LIBPATH = BF_OIIO + '/lib'
+WITH_BF_OCIO = True
+BF_OCIO = LIBDIR + '/opencolorio'
+BF_OCIO_INC = BF_OCIO + '/include'
+BF_OCIO_LIB = 'OpenColorIO tinyxml yaml-cpp'
+BF_OCIO_LIBPATH = BF_OCIO + '/lib'
+
WITH_BF_BOOST = True
BF_BOOST = LIBDIR + '/boost'
BF_BOOST_INC = BF_BOOST + '/include'
BF_OIIO_LIB = 'OpenImageIO'
BF_OIIO_LIBPATH = BF_OIIO + '/lib'
+WITH_BF_OCIO = True
+WITH_BF_STATICOCIO = False
+BF_OCIO = LIBDIR + '/ocio'
+if not os.path.exists(LCGDIR + '/ocio'):
+ WITH_BF_OCIO = False
+ BF_OCIO = '/usr'
+BF_OCIO_INC = BF_OCIO + '/include'
+BF_OCIO_LIB = 'OpenColorIO yaml-cpp tinyxml'
+BF_OCIO_LIBPATH = BF_OCIO + '/lib'
+
WITH_BF_BOOST = True
WITH_BF_STATICBOOST = False
BF_BOOST = LIBDIR + '/boost'
BF_OIIO_LIB = 'OpenImageIO'
BF_OIIO_LIBPATH = BF_OIIO + '/lib'
+WITH_BF_OCIO = False
+BF_OCIO = LIBDIR + '/opencolorio'
+BF_OCIO_INC = BF_OCIO + '/include'
+BF_OCIO_LIB = 'OpenColorIO'
+BF_OCIO_LIBPATH = BF_OCIO + '/lib'
+
WITH_BF_BOOST = True
BF_BOOST = LIBDIR + '/boost'
BF_BOOST_INC = BF_BOOST + '/include'
BF_OIIO_LIB = 'OpenImageIO'
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
+WITH_BF_OCIO = True
+BF_OCIO = '${LIBDIR}/opencolorio'
+BF_OCIO_INC = '${BF_OCIO}/include'
+BF_OCIO_LIB = 'OpenColorIO'
+BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
+
WITH_BF_BOOST = True
BF_BOOST = '${LIBDIR}/boost'
BF_BOOST_INC = '${BF_BOOST}/include'
BF_OIIO_LIB = 'OpenImageIO'
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
+WITH_BF_OCIO = False
+BF_OCIO = LIBDIR + '/opencolorio'
+BF_OCIO_INC = '${BF_OCIO}/include'
+BF_OCIO_LIB = 'OpenColorIO'
+BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
+
WITH_BF_BOOST = True
BF_BOOST = LIBDIR + '/boost'
BF_BOOST_INC = BF_BOOST + '/include'
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
BF_OIIO_LIBPATH = '${BF_OIIO}/lib'
+WITH_BF_OCIO = True
+BF_OCIO = '${LIBDIR}/opencolorio'
+BF_OCIO_INC = '${BF_OCIO}/include'
+BF_OCIO_LIB = 'OpenColorIO'
+BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
+BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
+
WITH_BF_BOOST = True
BF_BOOST = '${LIBDIR}/boost'
BF_BOOST_INC = '${BF_BOOST}/include'
if lenv['WITH_BF_STATICOIIO']:
statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
+ if lenv['WITH_BF_OCIO']:
+ libincs += Split(lenv['BF_OCIO_LIBPATH'])
+ if lenv['WITH_BF_STATICOCIO']:
+ statlibs += Split(lenv['BF_OCIO_LIB_STATIC'])
+
if lenv['WITH_BF_BOOST']:
libincs += Split(lenv['BF_BOOST_LIBPATH'])
if lenv['WITH_BF_STATICBOOST']:
if not lenv['WITH_BF_STATICOIIO']:
syslibs += Split(lenv['BF_OIIO_LIB'])
+ if lenv['WITH_BF_OCIO']:
+ if not lenv['WITH_BF_STATICOCIO']:
+ syslibs += Split(lenv['BF_OCIO_LIB'])
+
if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
syslibs += Split(lenv['BF_OPENEXR_LIB'])
if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
commands.getoutput(cmd)
cmd = 'cp -R %s/release/datafiles/fonts %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
commands.getoutput(cmd)
+ if env['WITH_BF_OCIO']:
+ cmd = 'cp -R %s/release/datafiles/colormanagement %s/%s.app/Contents/MacOS/%s/datafiles/'%(bldroot,installdir,binary,VERSION)
+ commands.getoutput(cmd)
cmd = 'cp -R %s/release/scripts %s/%s.app/Contents/MacOS/%s/'%(bldroot,installdir,binary,VERSION)
commands.getoutput(cmd)
'WITH_BF_3DMOUSE', 'WITH_BF_STATIC3DMOUSE', 'BF_3DMOUSE', 'BF_3DMOUSE_INC', 'BF_3DMOUSE_LIB', 'BF_3DMOUSE_LIBPATH', 'BF_3DMOUSE_LIB_STATIC',
'WITH_BF_CYCLES', 'WITH_BF_CYCLES_CUDA_BINARIES', 'BF_CYCLES_CUDA_NVCC', 'BF_CYCLES_CUDA_NVCC', 'WITH_BF_CYCLES_CUDA_THREADED_COMPILE',
'WITH_BF_OIIO', 'WITH_BF_STATICOIIO', 'BF_OIIO', 'BF_OIIO_INC', 'BF_OIIO_LIB', 'BF_OIIO_LIB_STATIC', 'BF_OIIO_LIBPATH',
+ 'WITH_BF_OCIO', 'WITH_BF_STATICOCIO', 'BF_OCIO', 'BF_OCIO_INC', 'BF_OCIO_LIB', 'BF_OCIO_LIB_STATIC', 'BF_OCIO_LIBPATH',
'WITH_BF_BOOST', 'WITH_BF_STATICBOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIB_STATIC', 'BF_BOOST_LIBPATH',
'WITH_BF_LIBMV', 'WITH_BF_CARVE'
]
('BF_OIIO_LIBPATH', 'OIIO library path', ''),
('BF_OIIO_LIB_STATIC', 'OIIO static library', ''),
+ (BoolVariable('WITH_BF_OCIO', 'Build with OpenColorIO', False)),
+ (BoolVariable('WITH_BF_STATICOCIO', 'Staticly link to OpenColorIO', False)),
+ ('BF_OCIO', 'OCIO root path', ''),
+ ('BF_OCIO_INC', 'OCIO include path', ''),
+ ('BF_OCIO_LIB', 'OCIO library', ''),
+ ('BF_OCIO_LIBPATH', 'OCIO library path', ''),
+ ('BF_OCIO_LIB_STATIC', 'OCIO static library', ''),
+
(BoolVariable('WITH_BF_BOOST', 'Build with Boost', False)),
(BoolVariable('WITH_BF_STATICBOOST', 'Staticly link to boost', False)),
('BF_BOOST', 'Boost root path', ''),
if(WIN32)
add_subdirectory(utfconv)
endif()
+
+if(WITH_OPENCOLORIO)
+ add_subdirectory(opencolorio)
+endif()
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-mingw', 'linuxcross', 'win64-vc'):
SConscript(['utfconv/SConscript'])
+
+if env['WITH_BF_OCIO']:
+ SConscript(['opencolorio/SConscript'])
sub = col.column(align=True)
sub.label(text="Tiles:")
- sub.prop(cscene, "debug_tile_size")
- sub.prop(cscene, "debug_min_size")
+
+ sub.prop(rd, "parts_x", text="X")
+ sub.prop(rd, "parts_y", text="Y")
+
+ subsub = sub.column()
+ subsub.enabled = not rd.use_border
+ subsub.prop(rd, "use_save_buffers")
+
+ #sub.prop(cscene, "debug_tile_size")
+ #sub.prop(cscene, "debug_min_size")
col = split.column()
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
BL::BlendData b_data_, BL::Scene b_scene_)
: b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
- b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL),
- b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
+ b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL)
{
/* offline render */
- BL::RenderSettings r = b_scene.render();
- width = (int)(r.resolution_x()*r.resolution_percentage()/100);
- height = (int)(r.resolution_y()*r.resolution_percentage()/100);
+ width = b_engine.resolution_x();
+ height = b_engine.resolution_y();
+
background = true;
last_redraw_time = 0.0f;
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_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
- b_v3d(b_v3d_), b_rv3d(b_rv3d_), b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
+ b_v3d(b_v3d_), b_rv3d(b_rv3d_)
{
/* 3d view render */
width = width_;
void BlenderSession::create_session()
{
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
- SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
+ SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
/* reset status/progress */
last_status = "";
last_progress = -1.0f;
/* create scene */
- scene = new Scene(scene_params);
+ scene = new Scene(scene_params, session_params.device);
/* create sync */
- sync = new BlenderSync(b_data, b_scene, scene, !background);
+ sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background);
sync->sync_data(b_v3d, b_engine.camera_override());
if(b_rv3d)
return PASS_NONE;
}
+static BL::RenderResult begin_render_result(BL::RenderEngine b_engine, int x, int y, int w, int h, const char *layername)
+{
+ RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, x, y, w, h, layername);
+ PointerRNA rrptr;
+ RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr);
+ return BL::RenderResult(rrptr);
+}
+
+static void end_render_result(BL::RenderEngine b_engine, BL::RenderResult b_rr, bool cancel = false)
+{
+ RE_engine_end_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data, (int)cancel);
+}
+
+void BlenderSession::do_write_update_render_buffers(RenderBuffers *buffers, bool do_update_only)
+{
+ BufferParams& params = buffers->params;
+ int x = params.full_x - session->tile_manager.params.full_x;
+ int y = params.full_y - session->tile_manager.params.full_y;
+ int w = params.width;
+ int h = params.height;
+
+ /* get render result */
+ BL::RenderResult b_rr = begin_render_result(b_engine, x, y, w, h, b_rlay_name.c_str());
+
+ /* can happen if the intersected rectangle gives 0 width or height */
+ if (b_rr.ptr.data == NULL) {
+ return;
+ }
+
+ BL::RenderResult::layers_iterator b_single_rlay;
+ b_rr.layers.begin(b_single_rlay);
+ BL::RenderLayer b_rlay = *b_single_rlay;
+
+ if (do_update_only) {
+ /* update only needed */
+ update_render_result(b_rr, b_rlay, buffers);
+ end_render_result(b_engine, b_rr, true);
+ }
+ else {
+ /* write result */
+ write_render_result(b_rr, b_rlay, buffers);
+ end_render_result(b_engine, b_rr);
+ }
+}
+
+void BlenderSession::write_render_buffers(RenderBuffers *buffers)
+{
+ do_write_update_render_buffers(buffers, false);
+}
+
+void BlenderSession::update_render_buffers(RenderBuffers *buffers)
+{
+ do_write_update_render_buffers(buffers, true);
+}
+
void BlenderSession::render()
{
+ /* set callback to write out render results */
+ session->write_render_buffers_cb = function_bind(&BlenderSession::write_render_buffers, this, _1);
+ session->update_render_buffers_cb = function_bind(&BlenderSession::update_render_buffers, this, _1);
+
/* get buffer parameters */
- SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
+ SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, width, height);
- int w = buffer_params.width, h = buffer_params.height;
-
- /* create render result */
- RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, 0, 0, w, h);
- PointerRNA rrptr;
- RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr);
- b_rr = BL::RenderResult(rrptr);
+ /* render each layer */
BL::RenderSettings r = b_scene.render();
- BL::RenderResult::layers_iterator b_iter;
- BL::RenderLayers b_rr_layers(r.ptr);
+ BL::RenderSettings::layers_iterator b_iter;
- /* render each layer */
- for(b_rr.layers.begin(b_iter); b_iter != b_rr.layers.end(); ++b_iter) {
- /* set layer */
- b_rlay = *b_iter;
+ for(r.layers.begin(b_iter); b_iter != r.layers.end(); ++b_iter) {
+ b_rlay_name = b_iter->name();
+
+ /* temporary render result to find needed passes */
+ BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_rlay_name.c_str());
+ BL::RenderResult::layers_iterator b_single_rlay;
+ b_rr.layers.begin(b_single_rlay);
+
+ /* layer will be missing if it was disabled in the UI */
+ if(b_single_rlay == b_rr.layers.end()) {
+ end_render_result(b_engine, b_rr, true);
+ continue;
+ }
+
+ BL::RenderLayer b_rlay = *b_single_rlay;
/* add passes */
vector<Pass> passes;
Pass::add(PASS_COMBINED, passes);
if(session_params.device.advanced_shading) {
+
+ /* loop over passes */
BL::RenderLayer::passes_iterator b_pass_iter;
-
+
for(b_rlay.passes.begin(b_pass_iter); b_pass_iter != b_rlay.passes.end(); ++b_pass_iter) {
BL::RenderPass b_pass(*b_pass_iter);
PassType pass_type = get_pass_type(b_pass);
}
}
+ /* free result without merging */
+ end_render_result(b_engine, b_rr, true);
+
buffer_params.passes = passes;
scene->film->tag_passes_update(scene, passes);
scene->film->tag_update(scene);
scene->integrator->tag_update(scene);
/* update scene */
- sync->sync_data(b_v3d, b_engine.camera_override(), b_iter->name().c_str());
+ sync->sync_data(b_v3d, b_engine.camera_override(), b_rlay_name.c_str());
/* update session */
int samples = sync->get_layer_samples();
if(session->progress.get_cancel())
break;
-
- /* write result */
- write_render_result();
}
- /* delete render result */
- RE_engine_end_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data);
+ /* clear callback */
+ session->write_render_buffers_cb = NULL;
+ session->update_render_buffers_cb = NULL;
}
-void BlenderSession::write_render_result()
+void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderBuffers *buffers, bool do_update_only)
{
- /* get state */
- RenderBuffers *buffers = session->buffers;
-
/* copy data from device */
if(!buffers->copy_from_device())
return;
vector<float> pixels(params.width*params.height*4);
- /* copy each pass */
- BL::RenderLayer::passes_iterator b_iter;
-
- for(b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
- BL::RenderPass b_pass(*b_iter);
+ if (!do_update_only) {
+ /* copy each pass */
+ BL::RenderLayer::passes_iterator b_iter;
+
+ for(b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
+ BL::RenderPass b_pass(*b_iter);
- /* find matching pass type */
- PassType pass_type = get_pass_type(b_pass);
- int components = b_pass.channels();
+ /* find matching pass type */
+ PassType pass_type = get_pass_type(b_pass);
+ int components = b_pass.channels();
- /* copy pixels */
- if(buffers->get_pass(pass_type, exposure, sample, components, &pixels[0]))
- rna_RenderPass_rect_set(&b_pass.ptr, &pixels[0]);
+ /* copy pixels */
+ if(buffers->get_pass(pass_type, exposure, sample, components, &pixels[0]))
+ rna_RenderPass_rect_set(&b_pass.ptr, &pixels[0]);
+ }
}
/* copy combined pass */
RE_engine_update_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data);
}
+void BlenderSession::write_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderBuffers *buffers)
+{
+ do_write_update_render_result(b_rr, b_rlay, buffers, false);
+}
+
+void BlenderSession::update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderBuffers *buffers)
+{
+ do_write_update_render_result(b_rr, b_rlay, buffers, true);
+}
+
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_userpref, b_scene, background);
+ SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
if(session->params.modified(session_params) ||
scene->params.modified(scene_params))
/* reset if requested */
if(reset) {
- SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
+ SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, w, h);
session->reset(buffer_params, session_params.samples);
/* offline render, redraw if timeout passed */
if(time_dt() - last_redraw_time > 1.0) {
- write_render_result();
engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
last_redraw_time = time_dt();
}
class Scene;
class Session;
+class RenderBuffers;
class BlenderSession {
public:
/* offline render */
void render();
- void write_render_result();
+
+ void write_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderBuffers *buffers);
+ void write_render_buffers(RenderBuffers *buffers);
+
+ /* update functions are used to update display buffer only after sample was rendered
+ * only needed for better visual feedback
+ */
+ void update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderBuffers *buffers);
+ void update_render_buffers(RenderBuffers *buffers);
/* interactive updates */
void synchronize();
BL::Scene b_scene;
BL::SpaceView3D b_v3d;
BL::RegionView3D b_rv3d;
- BL::RenderResult b_rr;
- BL::RenderLayer b_rlay;
+ string b_rlay_name;
string last_status;
float last_progress;
int width, height;
+
+protected:
+ void do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderBuffers *buffers, bool do_update_only);
+ void do_write_update_render_buffers(RenderBuffers *buffers, bool do_update_only);
};
CCL_NAMESPACE_END
if(b_image)
image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
+ image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()];
+ image->projection_blend = b_image_node.projection_blend();
get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping());
node = image;
break;
/* Constructor */
-BlenderSync::BlenderSync(BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_)
-: b_data(b_data_), b_scene(b_scene_),
+BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_)
+: b_engine(b_engine_),
+ b_data(b_data_), b_scene(b_scene_),
shader_map(&scene_->shaders),
object_map(&scene_->objects),
mesh_map(&scene_->meshes),
return (background)? false: get_boolean(cscene, "preview_pause");
}
-SessionParams BlenderSync::get_session_params(BL::UserPreferences b_userpref, BL::Scene b_scene, bool background)
+SessionParams BlenderSync::get_session_params(BL::RenderEngine b_engine, BL::UserPreferences b_userpref, BL::Scene b_scene, bool background)
{
SessionParams params;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
}
}
+ /* tiles */
+ int tile_x = b_engine.tile_x();
+ int tile_y = b_engine.tile_y();
+
+ if(tile_x == 0 || tile_y == 0) {
+ tile_x = get_int(cscene, "debug_tile_size");
+ tile_y = tile_x;
+
+ params.tile_size = make_int2(tile_x, tile_y);
+ params.min_size = get_int(cscene, "debug_min_size");
+ }
+ else {
+ params.tile_size = make_int2(tile_x, tile_y);
+ params.min_size = min(tile_x, tile_y);
+ }
+
/* 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.progressive = false;
params.min_size = INT_MAX;
}
else
params.progressive = true;
- /* todo: multi device only works with single tiles now */
- if(params.device.type == DEVICE_MULTI)
- params.tile_size = INT_MAX;
-
return params;
}
class BlenderSync {
public:
- BlenderSync(BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_);
+ BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_);
~BlenderSync();
/* sync */
/* get parameters */
static SceneParams get_scene_params(BL::Scene b_scene, bool background);
- static SessionParams get_session_params(BL::UserPreferences b_userpref, BL::Scene b_scene, bool background);
+ static SessionParams get_session_params(BL::RenderEngine b_engine, BL::UserPreferences b_userpref, BL::Scene b_scene, bool background);
static bool get_session_pause(BL::Scene b_scene, bool background);
static BufferParams get_buffer_params(BL::Scene b_scene, Camera *cam, int width, int height);
int object_count_particles(BL::Object b_ob);
/* variables */
+ BL::RenderEngine b_engine;
BL::BlendData b_data;
BL::Scene b_scene;
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);
+struct RenderResult *RE_engine_begin_result(struct RenderEngine *engine, int x, int y, int w, int h, const char *layername);
void RE_engine_update_result(struct RenderEngine *engine, struct RenderResult *result);
-void RE_engine_end_result(struct RenderEngine *engine, struct RenderResult *result);
+void RE_engine_end_result(struct RenderEngine *engine, struct RenderResult *result, int cancel);
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);
device_multi.cpp
device_network.cpp
device_opencl.cpp
+ device_task.cpp
)
set(SRC_HEADERS
device_memory.h
device_intern.h
device_network.h
+ device_task.h
)
add_definitions(-DGLEW_STATIC)
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),
- shader_input(0), shader_output(0),
- shader_eval_type(0), shader_x(0), shader_w(0)
-{
-}
-
-void DeviceTask::split_max_size(list<DeviceTask>& tasks, int max_size)
-{
- int num;
-
- if(type == SHADER) {
- num = (shader_w + max_size - 1)/max_size;
- }
- else {
- max_size = max(1, max_size/w);
- num = (h + max_size - 1)/max_size;
- }
-
- split(tasks, num);
-}
-
-void DeviceTask::split(list<DeviceTask>& tasks, int num)
-{
- if(type == SHADER) {
- num = min(shader_w, num);
-
- for(int i = 0; i < num; i++) {
- int tx = shader_x + (shader_w/num)*i;
- int tw = (i == num-1)? shader_w - i*(shader_w/num): shader_w/num;
-
- DeviceTask task = *this;
-
- task.shader_x = tx;
- task.shader_w = tw;
-
- tasks.push_back(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_back(task);
- }
- }
-}
-
/* Device */
void Device::pixels_alloc(device_memory& mem)
#include <stdlib.h>
#include "device_memory.h"
+#include "device_task.h"
#include "util_list.h"
#include "util_string.h"
-#include "util_task.h"
#include "util_thread.h"
#include "util_types.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
class Progress;
+class RenderTile;
/* Device Types */
}
};
-/* Device Task */
-
-class DeviceTask : public Task {
-public:
- typedef enum { PATH_TRACE, TONEMAP, SHADER } Type;
- Type type;
-
- int x, y, w, h;
- device_ptr rng_state;
- device_ptr rgba;
- device_ptr buffer;
- int sample;
- int resolution;
- int offset, stride;
-
- device_ptr shader_input;
- device_ptr shader_output;
- int shader_eval_type;
- int shader_x, shader_w;
-
- DeviceTask(Type type = PATH_TRACE);
-
- void split(list<DeviceTask>& tasks, int num);
- void split_max_size(list<DeviceTask>& tasks, int max_size);
-};
-
/* Device */
class Device {
void server_run();
#endif
+ /* multi device */
+ virtual void map_tile(Device *sub_device, RenderTile& tile) {}
+ virtual int device_number(Device *sub_device) { return 0; }
+
/* static */
static Device *create(DeviceInfo& info, bool background = true, int threads = 0);
#include "osl_shader.h"
+#include "buffers.h"
+
#include "util_debug.h"
#include "util_foreach.h"
#include "util_function.h"
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, (float*)task.buffer, (unsigned int*)task.rng_state,
- task.sample, x, y, task.offset, task.stride);
+ RenderTile tile;
+
+ while(task.acquire_tile(this, tile)) {
+ float *render_buffer = (float*)tile.buffer;
+ uint *rng_state = (uint*)tile.rng_state;
+ int start_sample = tile.start_sample;
+ int end_sample = tile.start_sample + tile.num_samples;
- if(task_pool.cancelled())
- break;
+#ifdef WITH_OPTIMIZED_KERNEL
+ if(system_cpu_support_optimized()) {
+ for(int sample = start_sample; sample < end_sample; sample++) {
+ for(int y = tile.y; y < tile.y + tile.h; y++) {
+ for(int x = tile.x; x < tile.x + tile.w; x++) {
+ if (task.get_cancel())
+ break;
+
+ if(task_pool.cancelled())
+ break;
+
+ kernel_cpu_optimized_path_trace(kg, render_buffer, rng_state,
+ sample, x, y, tile.offset, tile.stride);
+ }
+ }
+
+ task.update_progress(tile);
+ }
}
- }
- else
+ 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, (float*)task.buffer, (unsigned int*)task.rng_state,
- task.sample, x, y, task.offset, task.stride);
+ {
+ for(int sample = start_sample; sample < end_sample; sample++) {
+ for(int y = tile.y; y < tile.y + tile.h; y++) {
+ for(int x = tile.x; x < tile.x + tile.w; x++) {
+ if (task.get_cancel()) {
+ break;
+ }
- if(task_pool.cancelled())
- break;
+ if(task_pool.cancelled())
+ break;
+
+ kernel_cpu_path_trace(kg, render_buffer, rng_state,
+ sample, x, y, tile.offset, tile.stride);
+
+ }
+ }
+
+ task.update_progress(tile);
+ }
}
+
+ task.release_tile(tile);
+
+ if(task_pool.cancelled())
+ break;
}
#ifdef WITH_OSL
/* split task into smaller ones, more than number of threads for uneven
* workloads where some parts of the image render slower than others */
list<DeviceTask> tasks;
-
- task.split(tasks, TaskScheduler::num_threads()*10);
+ task.split(tasks, TaskScheduler::num_threads()+1);
foreach(DeviceTask& task, tasks)
task_pool.push(new CPUDeviceTask(this, task));
#include "device.h"
#include "device_intern.h"
+#include "buffers.h"
+
#include "util_cuda.h"
#include "util_debug.h"
#include "util_map.h"
class CUDADevice : public Device
{
public:
+ TaskPool task_pool;
CUdevice cuDevice;
CUcontext cuContext;
CUmodule cuModule;
~CUDADevice()
{
+ task_pool.stop();
+
cuda_push_context();
cuda_assert(cuCtxDetach(cuContext))
}
}
}
- void path_trace(DeviceTask& task)
+ void path_trace(RenderTile& rtile, int sample)
{
cuda_push_context();
CUfunction cuPathTrace;
- CUdeviceptr d_buffer = cuda_device_ptr(task.buffer);
- CUdeviceptr d_rng_state = cuda_device_ptr(task.rng_state);
+ CUdeviceptr d_buffer = cuda_device_ptr(rtile.buffer);
+ CUdeviceptr d_rng_state = cuda_device_ptr(rtile.rng_state);
/* get kernel function */
cuda_assert(cuModuleGetFunction(&cuPathTrace, cuModule, "kernel_cuda_path_trace"))
cuda_assert(cuParamSetv(cuPathTrace, offset, &d_rng_state, sizeof(d_rng_state)))
offset += sizeof(d_rng_state);
- int sample = task.sample;
offset = align_up(offset, __alignof(sample));
- cuda_assert(cuParamSeti(cuPathTrace, offset, task.sample))
- offset += sizeof(task.sample);
+ cuda_assert(cuParamSeti(cuPathTrace, offset, sample))
+ offset += sizeof(sample);
- cuda_assert(cuParamSeti(cuPathTrace, offset, task.x))
- offset += sizeof(task.x);
+ cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.x))
+ offset += sizeof(rtile.x);
- cuda_assert(cuParamSeti(cuPathTrace, offset, task.y))
- offset += sizeof(task.y);
+ cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.y))
+ offset += sizeof(rtile.y);
- cuda_assert(cuParamSeti(cuPathTrace, offset, task.w))
- offset += sizeof(task.w);
+ cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.w))
+ offset += sizeof(rtile.w);
- cuda_assert(cuParamSeti(cuPathTrace, offset, task.h))
- offset += sizeof(task.h);
+ cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.h))
+ offset += sizeof(rtile.h);
- cuda_assert(cuParamSeti(cuPathTrace, offset, task.offset))
- offset += sizeof(task.offset);
+ cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.offset))
+ offset += sizeof(rtile.offset);
- cuda_assert(cuParamSeti(cuPathTrace, offset, task.stride))
- offset += sizeof(task.stride);
+ cuda_assert(cuParamSeti(cuPathTrace, offset, rtile.stride))
+ offset += sizeof(rtile.stride);
cuda_assert(cuParamSetSize(cuPathTrace, offset))
int xthreads = 8;
int ythreads = 8;
#endif
- int xblocks = (task.w + xthreads - 1)/xthreads;
- int yblocks = (task.h + ythreads - 1)/ythreads;
+ int xblocks = (rtile.w + xthreads - 1)/xthreads;
+ int yblocks = (rtile.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_assert(cuCtxSynchronize())
+
cuda_pop_context();
}
- void tonemap(DeviceTask& task)
+ void tonemap(DeviceTask& task, device_ptr buffer, device_ptr rgba)
{
cuda_push_context();
CUfunction cuFilmConvert;
- CUdeviceptr d_rgba = map_pixels(task.rgba);
- CUdeviceptr d_buffer = cuda_device_ptr(task.buffer);
+ CUdeviceptr d_rgba = map_pixels(rgba);
+ CUdeviceptr d_buffer = cuda_device_ptr(buffer);
/* get kernel function */
cuda_assert(cuModuleGetFunction(&cuFilmConvert, cuModule, "kernel_cuda_tonemap"))
Device::draw_pixels(mem, y, w, h, dy, width, height, transparent);
}
- void task_add(DeviceTask& task)
+ void thread_run(DeviceTask *task)
{
- if(task.type == DeviceTask::TONEMAP)
- tonemap(task);
- else if(task.type == DeviceTask::PATH_TRACE)
- path_trace(task);
- else if(task.type == DeviceTask::SHADER)
- shader(task);
+ if(task->type == DeviceTask::PATH_TRACE) {
+ RenderTile tile;
+
+ /* keep rendering tiles until done */
+ while(task->acquire_tile(this, tile)) {
+ int start_sample = tile.start_sample;
+ int end_sample = tile.start_sample + tile.num_samples;
+
+ for(int sample = start_sample; sample < end_sample; sample++) {
+ if (task->get_cancel()) {
+ break;
+ }
+
+ path_trace(tile, sample);
+ task->update_progress(tile);
+ }
+
+ task->release_tile(tile);
+ }
+ }
+ else if(task->type == DeviceTask::SHADER) {
+ shader(*task);
+
+ cuda_push_context();
+ cuda_assert(cuCtxSynchronize())
+ cuda_pop_context();
+ }
}
- void task_wait()
+ class CUDADeviceTask : public DeviceTask {
+ public:
+ CUDADeviceTask(CUDADevice *device, DeviceTask& task)
+ : DeviceTask(task)
+ {
+ run = function_bind(&CUDADevice::thread_run, device, this);
+ }
+ };
+
+ void task_add(DeviceTask& task)
{
- cuda_push_context();
+ if(task.type == DeviceTask::TONEMAP) {
+ /* must be done in main thread due to opengl access */
+ tonemap(task, task.buffer, task.rgba);
- cuda_assert(cuCtxSynchronize())
+ cuda_push_context();
+ cuda_assert(cuCtxSynchronize())
+ cuda_pop_context();
+ }
+ else {
+ task_pool.push(new CUDADeviceTask(this, task));
+ }
+ }
- cuda_pop_context();
+ void task_wait()
+ {
+ task_pool.wait_work();
}
void task_cancel()
{
+ task_pool.cancel();
}
};
#include "device_intern.h"
#include "device_network.h"
+#include "buffers.h"
+
#include "util_foreach.h"
#include "util_list.h"
#include "util_map.h"
rgba.device_pointer = tmp;
}
+ void map_tile(Device *sub_device, RenderTile& tile)
+ {
+ foreach(SubDevice& sub, devices) {
+ if(sub.device == sub_device) {
+ if(tile.buffer) tile.buffer = sub.ptr_map[tile.buffer];
+ if(tile.rng_state) tile.rng_state = sub.ptr_map[tile.rng_state];
+ if(tile.rgba) tile.rgba = sub.ptr_map[tile.rgba];
+ }
+ }
+ }
+
+ int device_number(Device *sub_device)
+ {
+ int i = 0;
+
+ foreach(SubDevice& sub, devices) {
+ if(sub.device == sub_device)
+ return i;
+ i++;
+ }
+
+ return -1;
+ }
+
void task_add(DeviceTask& task)
{
list<DeviceTask> tasks;
tasks.pop_front();
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.shader_input) subtask.shader_input = sub.ptr_map[task.shader_input];
if(task.shader_output) subtask.shader_output = sub.ptr_map[task.shader_output];
#include "device.h"
#include "device_intern.h"
+#include "buffers.h"
+
#include "util_foreach.h"
#include "util_map.h"
#include "util_math.h"
class OpenCLDevice : public Device
{
public:
+ TaskPool task_pool;
cl_context cxContext;
cl_command_queue cqCommandQueue;
cl_platform_id cpPlatform;
~OpenCLDevice()
{
+ task_pool.stop();
+
if(null_mem)
clReleaseMemObject(CL_MEM_PTR(null_mem));
return global_size + ((r == 0)? 0: group_size - r);
}
- void path_trace(DeviceTask& task)
+ void path_trace(RenderTile& rtile, int sample)
{
/* 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;
- cl_int d_offset = task.offset;
- cl_int d_stride = task.stride;
+ cl_mem d_buffer = CL_MEM_PTR(rtile.buffer);
+ cl_mem d_rng_state = CL_MEM_PTR(rtile.rng_state);
+ cl_int d_x = rtile.x;
+ cl_int d_y = rtile.y;
+ cl_int d_w = rtile.w;
+ cl_int d_h = rtile.h;
+ cl_int d_sample = sample;
+ cl_int d_offset = rtile.offset;
+ cl_int d_stride = rtile.stride;
/* sample arguments */
int narg = 0;
return err;
}
- void tonemap(DeviceTask& task)
+ void tonemap(DeviceTask& task, device_ptr buffer, device_ptr rgba)
{
/* 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_mem d_rgba = CL_MEM_PTR(rgba);
+ cl_mem d_buffer = CL_MEM_PTR(buffer);
cl_int d_x = task.x;
cl_int d_y = task.y;
cl_int d_w = task.w;
opencl_assert(clFinish(cqCommandQueue));
}
- void task_add(DeviceTask& maintask)
+ void thread_run(DeviceTask *task)
{
- list<DeviceTask> tasks;
-
- /* arbitrary limit to work around apple ATI opencl issue */
- if(platform_name == "Apple")
- maintask.split_max_size(tasks, 76800);
- else
- tasks.push_back(maintask);
+ if(task->type == DeviceTask::TONEMAP) {
+ tonemap(*task, task->buffer, task->rgba);
+ }
+ else if(task->type == DeviceTask::PATH_TRACE) {
+ RenderTile tile;
+
+ /* keep rendering tiles until done */
+ while(task->acquire_tile(this, tile)) {
+ int start_sample = tile.start_sample;
+ int end_sample = tile.start_sample + tile.num_samples;
+
+ for(int sample = start_sample; sample < end_sample; sample++)
+ path_trace(tile, sample);
+
+ task->release_tile(tile);
+ }
+ }
+ }
- foreach(DeviceTask& task, tasks) {
- if(task.type == DeviceTask::TONEMAP)
- tonemap(task);
- else if(task.type == DeviceTask::PATH_TRACE)
- path_trace(task);
+ class OpenCLDeviceTask : public DeviceTask {
+ public:
+ OpenCLDeviceTask(OpenCLDevice *device, DeviceTask& task)
+ : DeviceTask(task)
+ {
+ run = function_bind(&OpenCLDevice::thread_run, device, this);
}
+ };
+
+ void task_add(DeviceTask& task)
+ {
+ task_pool.push(new OpenCLDeviceTask(this, task));
}
void task_wait()
{
+ task_pool.wait_work();
}
void task_cancel()
{
+ task_pool.cancel();
}
};
--- /dev/null
+/*
+ * 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_task.h"
+
+#include "util_algorithm.h"
+#include "util_time.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Device Task */
+
+DeviceTask::DeviceTask(Type type_)
+: type(type_), x(0), y(0), w(0), h(0), rgba(0), buffer(0),
+ sample(0), num_samples(1), resolution(0),
+ shader_input(0), shader_output(0),
+ shader_eval_type(0), shader_x(0), shader_w(0)
+{
+ last_update_time = time_dt();
+}
+
+void DeviceTask::split_max_size(list<DeviceTask>& tasks, int max_size)
+{
+ int num;
+
+ if(type == SHADER) {
+ num = (shader_w + max_size - 1)/max_size;
+ }
+ else {
+ max_size = max(1, max_size/w);
+ num = (h + max_size - 1)/max_size;
+ }
+
+ split(tasks, num);
+}
+
+void DeviceTask::split(list<DeviceTask>& tasks, int num)
+{
+ if(type == SHADER) {
+ num = min(shader_w, num);
+
+ for(int i = 0; i < num; i++) {
+ int tx = shader_x + (shader_w/num)*i;
+ int tw = (i == num-1)? shader_w - i*(shader_w/num): shader_w/num;
+
+ DeviceTask task = *this;
+
+ task.shader_x = tx;
+ task.shader_w = tw;
+
+ tasks.push_back(task);
+ }
+ }
+ else if(type == PATH_TRACE) {
+ for(int i = 0; i < num; i++)
+ tasks.push_back(*this);
+ }
+ 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_back(task);
+ }
+ }
+}
+
+void DeviceTask::update_progress(RenderTile &rtile)
+{
+ if (type != PATH_TRACE)
+ return;
+
+ if (update_tile_sample) {
+ double current_time = time_dt();
+
+ if (current_time - last_update_time >= 1.0f) {
+ update_tile_sample(rtile);
+
+ last_update_time = current_time;
+ }
+ }
+}
+
+CCL_NAMESPACE_END
+
--- /dev/null
+/*
+ * 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_TASK_H__
+#define __DEVICE_TASK_H__
+
+#include "device_memory.h"
+
+#include "util_function.h"
+#include "util_list.h"
+#include "util_task.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Device Task */
+
+class Device;
+class RenderBuffers;
+class RenderTile;
+class Tile;
+
+class DeviceTask : public Task {
+public:
+ typedef enum { PATH_TRACE, TONEMAP, SHADER } Type;
+ Type type;
+
+ int x, y, w, h;
+ device_ptr rgba;
+ device_ptr buffer;
+ int sample;
+ int num_samples;
+ int resolution;
+ int offset, stride;
+
+ device_ptr shader_input;
+ device_ptr shader_output;
+ int shader_eval_type;
+ int shader_x, shader_w;
+
+ DeviceTask(Type type = PATH_TRACE);
+
+ void split(list<DeviceTask>& tasks, int num);
+ void split_max_size(list<DeviceTask>& tasks, int max_size);
+
+ void update_progress(RenderTile &rtile);
+
+ boost::function<bool(Device *device, RenderTile&)> acquire_tile;
+ boost::function<void(RenderTile&)> update_tile_sample;
+ boost::function<void(RenderTile&)> release_tile;
+ boost::function<bool(void)> get_cancel;
+
+protected:
+ double last_update_time;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __DEVICE_TASK_H__ */
+
else if(strstr(name, "__tex_image_float")) {
texture_image_float4 *tex = NULL;
int id = atoi(name + strlen("__tex_image_float_"));
+ int array_index = id;
- switch(id) {
- case 95: tex = &kg->__tex_image_float_095; break;
- case 96: tex = &kg->__tex_image_float_096; break;
- case 97: tex = &kg->__tex_image_float_097; break;
- case 98: tex = &kg->__tex_image_float_098; break;
- case 99: tex = &kg->__tex_image_float_099; break;
- default: break;
+ if (array_index >= 0 && array_index < MAX_FLOAT_IMAGES) {
+ tex = &kg->texture_float_images[array_index];
}
if(tex) {
else if(strstr(name, "__tex_image")) {
texture_image_uchar4 *tex = NULL;
int id = atoi(name + strlen("__tex_image_"));
+ int array_index = id - MAX_FLOAT_IMAGES;
- switch(id) {
- case 0: tex = &kg->__tex_image_000; break;
- case 1: tex = &kg->__tex_image_001; break;
- case 2: tex = &kg->__tex_image_002; break;
- case 3: tex = &kg->__tex_image_003; break;
- case 4: tex = &kg->__tex_image_004; break;
- case 5: tex = &kg->__tex_image_005; break;
- case 6: tex = &kg->__tex_image_006; break;
- case 7: tex = &kg->__tex_image_007; break;
- case 8: tex = &kg->__tex_image_008; break;
- case 9: tex = &kg->__tex_image_009; break;
- case 10: tex = &kg->__tex_image_010; break;
- case 11: tex = &kg->__tex_image_011; break;
- case 12: tex = &kg->__tex_image_012; break;
- case 13: tex = &kg->__tex_image_013; break;
- case 14: tex = &kg->__tex_image_014; break;
- case 15: tex = &kg->__tex_image_015; break;
- case 16: tex = &kg->__tex_image_016; break;
- case 17: tex = &kg->__tex_image_017; break;
- case 18: tex = &kg->__tex_image_018; break;
- case 19: tex = &kg->__tex_image_019; break;
- case 20: tex = &kg->__tex_image_020; break;
- case 21: tex = &kg->__tex_image_021; break;
- case 22: tex = &kg->__tex_image_022; break;
- case 23: tex = &kg->__tex_image_023; break;
- case 24: tex = &kg->__tex_image_024; break;
- case 25: tex = &kg->__tex_image_025; break;
- case 26: tex = &kg->__tex_image_026; break;
- case 27: tex = &kg->__tex_image_027; break;
- case 28: tex = &kg->__tex_image_028; break;
- case 29: tex = &kg->__tex_image_029; break;
- case 30: tex = &kg->__tex_image_030; break;
- case 31: tex = &kg->__tex_image_031; break;
- case 32: tex = &kg->__tex_image_032; break;
- case 33: tex = &kg->__tex_image_033; break;
- case 34: tex = &kg->__tex_image_034; break;
- case 35: tex = &kg->__tex_image_035; break;
- case 36: tex = &kg->__tex_image_036; break;
- case 37: tex = &kg->__tex_image_037; break;
- case 38: tex = &kg->__tex_image_038; break;
- case 39: tex = &kg->__tex_image_039; break;
- case 40: tex = &kg->__tex_image_040; break;
- case 41: tex = &kg->__tex_image_041; break;
- case 42: tex = &kg->__tex_image_042; break;
- case 43: tex = &kg->__tex_image_043; break;
- case 44: tex = &kg->__tex_image_044; break;
- case 45: tex = &kg->__tex_image_045; break;
- case 46: tex = &kg->__tex_image_046; break;
- case 47: tex = &kg->__tex_image_047; break;
- case 48: tex = &kg->__tex_image_048; break;
- case 49: tex = &kg->__tex_image_049; break;
- case 50: tex = &kg->__tex_image_050; break;
- case 51: tex = &kg->__tex_image_051; break;
- case 52: tex = &kg->__tex_image_052; break;
- case 53: tex = &kg->__tex_image_053; break;
- case 54: tex = &kg->__tex_image_054; break;
- case 55: tex = &kg->__tex_image_055; break;
- case 56: tex = &kg->__tex_image_056; break;
- case 57: tex = &kg->__tex_image_057; break;
- case 58: tex = &kg->__tex_image_058; break;
- case 59: tex = &kg->__tex_image_059; break;
- case 60: tex = &kg->__tex_image_060; break;
- case 61: tex = &kg->__tex_image_061; break;
- case 62: tex = &kg->__tex_image_062; break;
- case 63: tex = &kg->__tex_image_063; break;
- case 64: tex = &kg->__tex_image_064; break;
- case 65: tex = &kg->__tex_image_065; break;
- case 66: tex = &kg->__tex_image_066; break;
- case 67: tex = &kg->__tex_image_067; break;
- case 68: tex = &kg->__tex_image_068; break;
- case 69: tex = &kg->__tex_image_069; break;
- case 70: tex = &kg->__tex_image_070; break;
- case 71: tex = &kg->__tex_image_071; break;
- case 72: tex = &kg->__tex_image_072; break;
- case 73: tex = &kg->__tex_image_073; break;
- case 74: tex = &kg->__tex_image_074; break;
- case 75: tex = &kg->__tex_image_075; break;
- case 76: tex = &kg->__tex_image_076; break;
- case 77: tex = &kg->__tex_image_077; break;
- case 78: tex = &kg->__tex_image_078; break;
- case 79: tex = &kg->__tex_image_079; break;
- case 80: tex = &kg->__tex_image_080; break;
- case 81: tex = &kg->__tex_image_081; break;
- case 82: tex = &kg->__tex_image_082; break;
- case 83: tex = &kg->__tex_image_083; break;
- case 84: tex = &kg->__tex_image_084; break;
- case 85: tex = &kg->__tex_image_085; break;
- case 86: tex = &kg->__tex_image_086; break;
- case 87: tex = &kg->__tex_image_087; break;
- case 88: tex = &kg->__tex_image_088; break;
- case 89: tex = &kg->__tex_image_089; break;
- case 90: tex = &kg->__tex_image_090; break;
- case 91: tex = &kg->__tex_image_091; break;
- case 92: tex = &kg->__tex_image_092; break;
- case 93: tex = &kg->__tex_image_093; break;
- case 94: tex = &kg->__tex_image_094; break;
- default: break;
+ if (array_index >= 0 && array_index < MAX_BYTE_IMAGES) {
+ tex = &kg->texture_byte_images[array_index];
}
if(tex) {
#define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index))
#define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index))
#define kernel_tex_interp(tex, t, size) (kg->tex.interp(t, size))
-#define kernel_tex_image_interp(tex, x, y) (kg->tex.interp(x, y))
+#define kernel_tex_image_interp(tex, x, y) ((tex < MAX_FLOAT_IMAGES) ? kg->texture_float_images[tex].interp(x, y) : kg->texture_byte_images[tex - MAX_FLOAT_IMAGES].interp(x, y))
#define kernel_data (kg->__data)
#ifdef __KERNEL_CPU__
+#define MAX_BYTE_IMAGES 512
+#define MAX_FLOAT_IMAGES 5
+
typedef struct KernelGlobals {
+ texture_image_uchar4 texture_byte_images[MAX_BYTE_IMAGES];
+ texture_image_float4 texture_float_images[MAX_FLOAT_IMAGES];
#define KERNEL_TEX(type, ttype, name) ttype name;
-#define KERNEL_IMAGE_TEX(type, ttype, name) ttype name;
+#define KERNEL_IMAGE_TEX(type, ttype, name)
#include "kernel_textures.h"
KernelData __data;
/* sobol */
KERNEL_TEX(uint, texture_uint, __sobol_directions)
+/* full-float image */
+KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_000)
+KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_001)
+KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_002)
+KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_003)
+KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_004)
+
/* image */
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_000)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_001)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_002)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_003)
-KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_004)
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_005)
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_006)
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_007)
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_092)
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_093)
KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_094)
-
-/* full-float image */
-KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_095)
-KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_096)
-KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_097)
-KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_098)
-KERNEL_IMAGE_TEX(float4, texture_image_float4, __tex_image_float_099)
+KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_095)
+KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_096)
+KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_097)
+KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_098)
+KERNEL_IMAGE_TEX(uchar4, texture_image_uchar4, __tex_image_099)
/* packed image (opencl) */
KERNEL_TEX(uchar4, texture_uchar4, __tex_image_packed)
case NODE_TEX_IMAGE:
svm_node_tex_image(kg, sd, stack, node);
break;
+ case NODE_TEX_IMAGE_BOX:
+ svm_node_tex_image_box(kg, sd, stack, node);
+ break;
case NODE_TEX_ENVIRONMENT:
svm_node_tex_environment(kg, sd, stack, node);
break;
return x - (float)i;
}
-__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y)
+__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb)
{
uint4 info = kernel_tex_fetch(__tex_image_packed_info, id);
uint width = info.x;
r += ty*(1.0f - tx)*svm_image_texture_read(kg, offset + ix + niy*width);
r += ty*tx*svm_image_texture_read(kg, offset + nix + niy*width);
+ if(srgb) {
+ r.x = color_srgb_to_scene_linear(r.x);
+ r.y = color_srgb_to_scene_linear(r.y);
+ r.z = color_srgb_to_scene_linear(r.z);
+ }
+
return r;
}
#else
-__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y)
+__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb)
{
float4 r;
+#ifdef __KERNEL_CPU__
+ r = kernel_tex_image_interp(id, x, y);
+#else
/* not particularly proud of this massive switch, what are the
* alternatives?
* - use a single big 1D texture, and do our own lookup/filtering
* we still need some for other storage */
switch(id) {
- case 0: r = kernel_tex_image_interp(__tex_image_000, x, y); break;
- case 1: r = kernel_tex_image_interp(__tex_image_001, x, y); break;
- case 2: r = kernel_tex_image_interp(__tex_image_002, x, y); break;
- case 3: r = kernel_tex_image_interp(__tex_image_003, x, y); break;
- case 4: r = kernel_tex_image_interp(__tex_image_004, x, y); break;
+ case 0: r = kernel_tex_image_interp(__tex_image_float_000, x, y); break;
+ case 1: r = kernel_tex_image_interp(__tex_image_float_001, x, y); break;
+ case 2: r = kernel_tex_image_interp(__tex_image_float_002, x, y); break;
+ case 3: r = kernel_tex_image_interp(__tex_image_float_003, x, y); break;
+ case 4: r = kernel_tex_image_interp(__tex_image_float_004, x, y); break;
case 5: r = kernel_tex_image_interp(__tex_image_005, x, y); break;
case 6: r = kernel_tex_image_interp(__tex_image_006, x, y); break;
case 7: r = kernel_tex_image_interp(__tex_image_007, x, y); break;
case 92: r = kernel_tex_image_interp(__tex_image_092, x, y); break;
case 93: r = kernel_tex_image_interp(__tex_image_093, x, y); break;
case 94: r = kernel_tex_image_interp(__tex_image_094, x, y); break;
- case 95: r = kernel_tex_image_interp(__tex_image_float_095, x, y); break;
- case 96: r = kernel_tex_image_interp(__tex_image_float_096, x, y); break;
- case 97: r = kernel_tex_image_interp(__tex_image_float_097, x, y); break;
- case 98: r = kernel_tex_image_interp(__tex_image_float_098, x, y); break;
- case 99: r = kernel_tex_image_interp(__tex_image_float_099, x, y); break;
+ case 95: r = kernel_tex_image_interp(__tex_image_095, x, y); break;
+ case 96: r = kernel_tex_image_interp(__tex_image_096, x, y); break;
+ case 97: r = kernel_tex_image_interp(__tex_image_097, x, y); break;
+ case 98: r = kernel_tex_image_interp(__tex_image_098, x, y); break;
+ case 99: r = kernel_tex_image_interp(__tex_image_099, x, y); break;
default:
kernel_assert(0);
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
}
+#endif
+
+ if(srgb) {
+ r.x = color_srgb_to_scene_linear(r.x);
+ r.y = color_srgb_to_scene_linear(r.y);
+ r.z = color_srgb_to_scene_linear(r.z);
+ }
return r;
}
decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb);
float3 co = stack_load_float3(stack, co_offset);
- float4 f = svm_image_texture(kg, id, co.x, co.y);
- float3 r = make_float3(f.x, f.y, f.z);
+ float4 f = svm_image_texture(kg, id, co.x, co.y, srgb);
- if(srgb) {
- r.x = color_srgb_to_scene_linear(r.x);
- r.y = color_srgb_to_scene_linear(r.y);
- r.z = color_srgb_to_scene_linear(r.z);
+ if(stack_valid(out_offset))
+ stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
+ if(stack_valid(alpha_offset))
+ stack_store_float(stack, alpha_offset, f.w);
+}
+
+__device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
+{
+ /* get object space normal */
+ float3 N = sd->N;
+
+ N = sd->N;
+ if(sd->object != ~0)
+ object_inverse_normal_transform(kg, sd, &N);
+
+ /* project from direction vector to barycentric coordinates in triangles */
+ N.x = fabsf(N.x);
+ N.y = fabsf(N.y);
+ N.z = fabsf(N.z);
+
+ N /= (N.x + N.y + N.z);
+
+ /* basic idea is to think of this as a triangle, each corner representing
+ * one of the 3 faces of the cube. in the corners we have single textures,
+ * in between we blend between two textures, and in the middle we a blend
+ * between three textures.
+ *
+ * the Nxyz values are the barycentric coordinates in an equilateral
+ * triangle, which in case of blending in the middle has a smaller
+ * equilateral triangle where 3 textures blend. this divides things into
+ * 7 zones, with an if() test for each zone */
+
+ float3 weight = make_float3(0.0f, 0.0f, 0.0f);
+ float blend = __int_as_float(node.w);
+ float limit = 0.5f*(1.0f + blend);
+
+ /* first test for corners with single texture */
+ if(N.x > limit*(N.x + N.y) && N.x > limit*(N.x + N.z)) {
+ weight.x = 1.0f;
+ }
+ else if(N.y > limit*(N.x + N.y) && N.y > limit*(N.y + N.z)) {
+ weight.y = 1.0f;
}
+ else if(N.z > limit*(N.x + N.z) && N.z > limit*(N.y + N.z)) {
+ weight.z = 1.0f;
+ }
+ else if(blend > 0.0f) {
+ /* in case of blending, test for mixes between two textures */
+ if(N.z < (1.0f - limit)*(N.y + N.x)) {
+ weight.x = N.x/(N.x + N.y);
+ weight.x = clamp((weight.x - 0.5f*(1.0f - blend))/blend, 0.0f, 1.0f);
+ weight.y = 1.0f - weight.x;
+ }
+ else if(N.x < (1.0f - limit)*(N.y + N.z)) {
+ weight.y = N.y/(N.y + N.z);
+ weight.y = clamp((weight.y - 0.5f*(1.0f - blend))/blend, 0.0f, 1.0f);
+ weight.z = 1.0f - weight.y;
+ }
+ else if(N.y < (1.0f - limit)*(N.x + N.z)) {
+ weight.x = N.x/(N.x + N.z);
+ weight.x = clamp((weight.x - 0.5f*(1.0f - blend))/blend, 0.0f, 1.0f);
+ weight.z = 1.0f - weight.x;
+ }
+ else {
+ /* last case, we have a mix between three */
+ weight.x = ((2.0f - limit)*N.x + (limit - 1.0f))/(2.0f*limit - 1.0f);
+ weight.y = ((2.0f - limit)*N.y + (limit - 1.0f))/(2.0f*limit - 1.0f);
+ weight.z = ((2.0f - limit)*N.z + (limit - 1.0f))/(2.0f*limit - 1.0f);
+ }
+ }
+
+ /* now fetch textures */
+ uint co_offset, out_offset, alpha_offset, srgb;
+ decode_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &srgb);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ uint id = node.y;
+
+ float4 f = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ if(weight.x > 0.0f)
+ f += weight.x*svm_image_texture(kg, id, co.y, co.z, srgb);
+ if(weight.y > 0.0f)
+ f += weight.y*svm_image_texture(kg, id, co.x, co.z, srgb);
+ if(weight.z > 0.0f)
+ f += weight.z*svm_image_texture(kg, id, co.y, co.x, srgb);
if(stack_valid(out_offset))
- stack_store_float3(stack, out_offset, r);
+ stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
if(stack_valid(alpha_offset))
stack_store_float(stack, alpha_offset, f.w);
}
+
__device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
{
uint id = node.y;
else
uv = direction_to_mirrorball(co);
- float4 f = svm_image_texture(kg, id, uv.x, uv.y);
- float3 r = make_float3(f.x, f.y, f.z);
-
- if(srgb) {
- r.x = color_srgb_to_scene_linear(r.x);
- r.y = color_srgb_to_scene_linear(r.y);
- r.z = color_srgb_to_scene_linear(r.z);
- }
+ float4 f = svm_image_texture(kg, id, uv.x, uv.y, srgb);
if(stack_valid(out_offset))
- stack_store_float3(stack, out_offset, r);
+ stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
if(stack_valid(alpha_offset))
stack_store_float(stack, alpha_offset, f.w);
}
NODE_MIX_CLOSURE,
NODE_JUMP,
NODE_TEX_IMAGE,
+ NODE_TEX_IMAGE_BOX,
NODE_TEX_SKY,
NODE_GEOMETRY,
NODE_LIGHT_PATH,
return align_up(size, 4);
}
+/* Render Buffer Task */
+
+RenderTile::RenderTile()
+{
+ x = 0;
+ y = 0;
+ w = 0;
+ h = 0;
+
+ start_sample = 0;
+ num_samples = 0;
+ resolution = 0;
+
+ offset = 0;
+ stride = 0;
+
+ buffer = 0;
+ rng_state = 0;
+ rgba = 0;
+
+ buffers = NULL;
+}
+
/* Render Buffers */
RenderBuffers::RenderBuffers(Device *device_)
public:
/* buffer parameters */
BufferParams params;
+
/* float buffer */
device_vector<float> buffer;
/* random number generator state */
device_vector<uint> rng_state;
- /* mutex, must be locked manually by callers */
- thread_mutex mutex;
RenderBuffers(Device *device);
~RenderBuffers();
bool transparent;
/* byte buffer for tonemapped result */
device_vector<uchar4> rgba;
- /* mutex, must be locked manually by callers */
- thread_mutex mutex;
DisplayBuffer(Device *device);
~DisplayBuffer();
Device *device;
};
+/* Render Tile
+ * Rendering task on a buffer */
+
+class RenderTile {
+public:
+ int x, y, w, h;
+ int start_sample;
+ int num_samples;
+ int resolution;
+ int offset;
+ int stride;
+
+ device_ptr buffer;
+ device_ptr rng_state;
+ device_ptr rgba;
+
+ RenderBuffers *buffers;
+
+ RenderTile();
+};
+
CCL_NAMESPACE_END
#endif /* __BUFFERS_H__ */
need_update = true;
pack_images = false;
osl_texture_system = NULL;
+
+ tex_num_images = TEX_NUM_IMAGES;
+ tex_num_float_images = TEX_NUM_FLOAT_IMAGES;
+ tex_image_byte_start = TEX_IMAGE_BYTE_START;
}
ImageManager::~ImageManager()
osl_texture_system = texture_system;
}
+void ImageManager::set_extended_image_limits(void)
+{
+ tex_num_images = TEX_EXTENDED_NUM_IMAGES;
+ tex_num_float_images = TEX_EXTENDED_NUM_FLOAT_IMAGES;
+ tex_image_byte_start = TEX_EXTENDED_IMAGE_BYTE_START;
+}
+
static bool is_float_image(const string& filename)
{
ImageInput *in = ImageInput::create(filename);
for(slot = 0; slot < float_images.size(); slot++) {
if(float_images[slot] && float_images[slot]->filename == filename) {
float_images[slot]->users++;
- return slot+TEX_IMAGE_FLOAT_START;
+ return slot;
}
}
if(slot == float_images.size()) {
/* max images limit reached */
if(float_images.size() == TEX_NUM_FLOAT_IMAGES) {
- printf("ImageManager::add_image: byte image limit reached %d, skipping '%s'\n",
- TEX_NUM_IMAGES, filename.c_str());
+ printf("ImageManager::add_image: float image limit reached %d, skipping '%s'\n",
+ tex_num_float_images, filename.c_str());
return -1;
}
img->users = 1;
float_images[slot] = img;
- /* report slot out of total set of textures */
- slot += TEX_IMAGE_FLOAT_START;
}
else {
for(slot = 0; slot < images.size(); slot++) {
if(images[slot] && images[slot]->filename == filename) {
images[slot]->users++;
- return slot;
+ return slot+tex_image_byte_start;
}
}
if(slot == images.size()) {
/* max images limit reached */
- if(images.size() == TEX_NUM_IMAGES) {
+ if(images.size() == tex_num_images) {
printf("ImageManager::add_image: byte image limit reached %d, skipping '%s'\n",
- TEX_NUM_IMAGES, filename.c_str());
+ tex_num_images, filename.c_str());
return -1;
}
img->users = 1;
images[slot] = img;
+
+ slot += tex_image_byte_start;
}
need_update = true;
Image *img;
bool is_float;
- if(slot < TEX_IMAGE_FLOAT_START) {
- img = images[slot];
+ if(slot >= tex_image_byte_start) {
+ img = images[slot - tex_image_byte_start];
is_float = false;
}
else {
- img = float_images[slot - TEX_IMAGE_FLOAT_START];
+ img = float_images[slot];
is_float = true;
}
if(is_float) {
- string filename = path_filename(float_images[slot - TEX_IMAGE_FLOAT_START]->filename);
+ string filename = path_filename(float_images[slot]->filename);
progress->set_status("Updating Images", "Loading " + filename);
- device_vector<float4>& tex_img = dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START];
+ device_vector<float4>& tex_img = dscene->tex_float_image[slot];
if(tex_img.device_pointer)
device->tex_free(tex_img);
device->tex_alloc(name.c_str(), tex_img, true, true);
}
else {
- string filename = path_filename(images[slot]->filename);
+ string filename = path_filename(images[slot - tex_image_byte_start]->filename);
progress->set_status("Updating Images", "Loading " + filename);
- device_vector<uchar4>& tex_img = dscene->tex_image[slot];
+ device_vector<uchar4>& tex_img = dscene->tex_image[slot - tex_image_byte_start];
if(tex_img.device_pointer)
device->tex_free(tex_img);
Image *img;
bool is_float;
- if(slot < TEX_IMAGE_FLOAT_START) {
- img = images[slot];
+ if(slot >= tex_image_byte_start) {
+ img = images[slot - tex_image_byte_start];
is_float = false;
}
else {
- img = float_images[slot - TEX_IMAGE_FLOAT_START];
+ img = float_images[slot];
is_float = true;
}
#endif
}
else if(is_float) {
- device->tex_free(dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START]);
- dscene->tex_float_image[slot - TEX_IMAGE_FLOAT_START].clear();
+ device->tex_free(dscene->tex_float_image[slot]);
+ dscene->tex_float_image[slot].clear();
- delete float_images[slot - TEX_IMAGE_FLOAT_START];
- float_images[slot - TEX_IMAGE_FLOAT_START] = NULL;
+ delete float_images[slot];
+ float_images[slot] = NULL;
}
else {
- device->tex_free(dscene->tex_image[slot]);
- dscene->tex_image[slot].clear();
+ device->tex_free(dscene->tex_image[slot - tex_image_byte_start]);
+ dscene->tex_image[slot - tex_image_byte_start].clear();
- delete images[slot];
- images[slot] = NULL;
+ delete images[slot - tex_image_byte_start];
+ images[slot - tex_image_byte_start] = NULL;
}
}
}
continue;
if(images[slot]->users == 0) {
- device_free_image(device, dscene, slot);
+ device_free_image(device, dscene, slot + tex_image_byte_start);
}
else if(images[slot]->need_load) {
if(!osl_texture_system)
- pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot, &progress));
+ pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot + tex_image_byte_start, &progress));
}
}
continue;
if(float_images[slot]->users == 0) {
- device_free_image(device, dscene, slot + TEX_IMAGE_FLOAT_START);
+ device_free_image(device, dscene, slot);
}
else if(float_images[slot]->need_load) {
if(!osl_texture_system)
- pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot + TEX_IMAGE_FLOAT_START, &progress));
+ pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, slot, &progress));
}
}
void ImageManager::device_free(Device *device, DeviceScene *dscene)
{
for(size_t slot = 0; slot < images.size(); slot++)
- device_free_image(device, dscene, slot);
+ device_free_image(device, dscene, slot + tex_image_byte_start);
for(size_t slot = 0; slot < float_images.size(); slot++)
- device_free_image(device, dscene, slot + TEX_IMAGE_FLOAT_START);
+ device_free_image(device, dscene, slot);
device->tex_free(dscene->tex_image_packed);
dscene->tex_image_packed.clear();
#define TEX_NUM_FLOAT_IMAGES 5
#define TEX_NUM_IMAGES 95
-#define TEX_IMAGE_MAX (TEX_NUM_IMAGES + TEX_NUM_FLOAT_IMAGES)
-#define TEX_IMAGE_FLOAT_START TEX_NUM_IMAGES
+#define TEX_IMAGE_BYTE_START TEX_NUM_FLOAT_IMAGES
+
+#define TEX_EXTENDED_NUM_FLOAT_IMAGES 5
+#define TEX_EXTENDED_NUM_IMAGES 512
+#define TEX_EXTENDED_IMAGE_BYTE_START TEX_EXTENDED_NUM_FLOAT_IMAGES
/* color to use when textures are not found */
#define TEX_IMAGE_MISSING_R 1
void set_osl_texture_system(void *texture_system);
void set_pack_images(bool pack_images_);
+ void set_extended_image_limits(void);
+
bool need_update;
private:
+ int tex_num_images;
+ int tex_num_float_images;
+ int tex_image_byte_start;
+
struct Image {
string filename;
return enm;
}
+static ShaderEnum image_projection_init()
+{
+ ShaderEnum enm;
+
+ enm.insert("Flat", 0);
+ enm.insert("Box", 1);
+
+ return enm;
+}
+
ShaderEnum ImageTextureNode::color_space_enum = color_space_init();
+ShaderEnum ImageTextureNode::projection_enum = image_projection_init();
ImageTextureNode::ImageTextureNode()
: TextureNode("image_texture")
is_float = false;
filename = "";
color_space = ustring("Color");
+ projection = ustring("Flat");;
+ projection_blend = 0.0f;
add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_UV);
add_output("Color", SHADER_SOCKET_COLOR);
tex_mapping.compile(compiler, vector_in->stack_offset, vector_offset);
}
- compiler.add_node(NODE_TEX_IMAGE,
- slot,
- compiler.encode_uchar4(
- vector_offset,
- color_out->stack_offset,
- alpha_out->stack_offset,
- srgb));
+ if(projection == "Flat") {
+ compiler.add_node(NODE_TEX_IMAGE,
+ slot,
+ compiler.encode_uchar4(
+ vector_offset,
+ color_out->stack_offset,
+ alpha_out->stack_offset,
+ srgb));
+ }
+ else {
+ compiler.add_node(NODE_TEX_IMAGE_BOX,
+ slot,
+ compiler.encode_uchar4(
+ vector_offset,
+ color_out->stack_offset,
+ alpha_out->stack_offset,
+ srgb),
+ __float_as_int(projection_blend));
+ }
if(vector_offset != vector_in->stack_offset)
compiler.stack_clear_offset(vector_in->type, vector_offset);
/* Environment Texture */
-static ShaderEnum projection_init()
+static ShaderEnum env_projection_init()
{
ShaderEnum enm;
}
ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init();
-ShaderEnum EnvironmentTextureNode::projection_enum = projection_init();
+ShaderEnum EnvironmentTextureNode::projection_enum = env_projection_init();
EnvironmentTextureNode::EnvironmentTextureNode()
: TextureNode("environment_texture")
bool is_float;
string filename;
ustring color_space;
+ ustring projection;
+ float projection_blend;
static ShaderEnum color_space_enum;
+ static ShaderEnum projection_enum;
};
class EnvironmentTextureNode : public TextureNode {
CCL_NAMESPACE_BEGIN
-Scene::Scene(const SceneParams& params_)
+Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
: params(params_)
{
device = NULL;
integrator = new Integrator();
image_manager = new ImageManager();
shader_manager = ShaderManager::create(this);
+
+ if (device_info_.type == DEVICE_CPU)
+ image_manager->set_extended_image_limits();
}
Scene::~Scene()
class Background;
class Camera;
class Device;
+class DeviceInfo;
class Film;
class Filter;
class Integrator;
device_vector<uint> sobol_directions;
/* images */
- device_vector<uchar4> tex_image[TEX_NUM_IMAGES];
- device_vector<float4> tex_float_image[TEX_NUM_FLOAT_IMAGES];
+ device_vector<uchar4> tex_image[TEX_EXTENDED_NUM_IMAGES];
+ device_vector<float4> tex_float_image[TEX_EXTENDED_NUM_FLOAT_IMAGES];
/* opencl images */
device_vector<uchar4> tex_image_packed;
/* mutex must be locked manually by callers */
thread_mutex mutex;
- Scene(const SceneParams& params);
+ Scene(const SceneParams& params, const DeviceInfo& device_info);
~Scene();
void device_update(Device *device, Progress& progress);
#include "util_foreach.h"
#include "util_function.h"
+#include "util_math.h"
#include "util_opengl.h"
#include "util_task.h"
#include "util_time.h"
Session::Session(const SessionParams& params_)
: params(params_),
- tile_manager(params.progressive, params.samples, params.tile_size, params.min_size)
+ tile_manager(params.progressive, params.samples, params.tile_size, params.min_size,
+ (params.background)? 1: max(params.device.multi_devices.size(), 1))
{
device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background);
TaskScheduler::init(params.threads);
device = Device::create(params.device, params.background, params.threads);
- buffers = new RenderBuffers(device);
- display = new DisplayBuffer(device);
+
+ if(params.background) {
+ buffers = NULL;
+ display = NULL;
+ }
+ else {
+ buffers = new RenderBuffers(device);
+ display = new DisplayBuffer(device);
+ }
session_thread = NULL;
scene = NULL;
wait();
}
- if(params.output_path != "") {
+ if(display && params.output_path != "") {
tonemap();
progress.set_status("Writing Image", params.output_path);
/* block for buffer acces and reset immediately. we can't do this
* in the thread, because we need to allocate an OpenGL buffer, and
* that only works in the main thread */
- thread_scoped_lock display_lock(display->mutex);
- thread_scoped_lock buffers_lock(buffers->mutex);
+ thread_scoped_lock display_lock(display_mutex);
+ thread_scoped_lock buffers_lock(buffers_mutex);
display_outdated = true;
reset_time = time_dt();
bool Session::draw_gpu(BufferParams& buffer_params)
{
/* block for buffer access */
- thread_scoped_lock display_lock(display->mutex);
+ thread_scoped_lock display_lock(display_mutex);
/* first check we already rendered something */
if(gpu_draw_ready) {
/* for CUDA we need to do tonemapping still, since we can
* only access GL buffers from the main thread */
if(gpu_need_tonemap) {
- thread_scoped_lock buffers_lock(buffers->mutex);
+ thread_scoped_lock buffers_lock(buffers_mutex);
tonemap();
gpu_need_tonemap = false;
gpu_need_tonemap_cond.notify_all();
/* buffers mutex is locked entirely while rendering each
* sample, and released/reacquired on each iteration to allow
* reset and draw in between */
- thread_scoped_lock buffers_lock(buffers->mutex);
+ thread_scoped_lock buffers_lock(buffers_mutex);
/* update status and timing */
update_status_time();
/* path trace */
- foreach(Tile& tile, tile_manager.state.tiles) {
- path_trace(tile);
+ path_trace();
- device->task_wait();
+ device->task_wait();
- if(device->error_message() != "")
- progress.set_cancel(device->error_message());
-
- if(progress.get_cancel())
- break;
- }
+ if(device->error_message() != "")
+ progress.set_cancel(device->error_message());
/* update status and timing */
update_status_time();
bool Session::draw_cpu(BufferParams& buffer_params)
{
- thread_scoped_lock display_lock(display->mutex);
+ thread_scoped_lock display_lock(display_mutex);
/* first check we already rendered something */
if(display->draw_ready()) {
return false;
}
+bool Session::acquire_tile(Device *tile_device, RenderTile& rtile)
+{
+ if(progress.get_cancel())
+ return false;
+
+ thread_scoped_lock tile_lock(tile_mutex);
+
+ /* get next tile from manager */
+ Tile tile;
+ int device_num = device->device_number(tile_device);
+
+ if(!tile_manager.next_tile(tile, device_num))
+ return false;
+
+ /* fill render tile */
+ rtile.x = tile_manager.state.buffer.full_x + tile.x;
+ rtile.y = tile_manager.state.buffer.full_y + tile.y;
+ rtile.w = tile.w;
+ rtile.h = tile.h;
+ rtile.start_sample = tile_manager.state.sample;
+ rtile.num_samples = tile_manager.state.num_samples;
+ rtile.resolution = tile_manager.state.resolution;
+
+ tile_lock.unlock();
+
+ /* in case of a permant buffer, return it, otherwise we will allocate
+ * a new temporary buffer */
+ if(!write_render_buffers_cb) {
+ tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride);
+
+ rtile.buffer = buffers->buffer.device_pointer;
+ rtile.rng_state = buffers->rng_state.device_pointer;
+ rtile.rgba = display->rgba.device_pointer;
+ rtile.buffers = buffers;
+
+ device->map_tile(tile_device, rtile);
+
+ return true;
+ }
+
+ /* fill buffer parameters */
+ BufferParams buffer_params = tile_manager.params;
+ buffer_params.full_x = rtile.x;
+ buffer_params.full_y = rtile.y;
+ buffer_params.width = rtile.w;
+ buffer_params.height = rtile.h;
+
+ buffer_params.get_offset_stride(rtile.offset, rtile.stride);
+
+ /* allocate buffers */
+ RenderBuffers *tilebuffers = new RenderBuffers(tile_device);
+ tilebuffers->reset(tile_device, buffer_params);
+
+ rtile.buffer = tilebuffers->buffer.device_pointer;
+ rtile.rng_state = tilebuffers->rng_state.device_pointer;
+ rtile.rgba = 0;
+ rtile.buffers = tilebuffers;
+
+ return true;
+}
+
+void Session::update_tile_sample(RenderTile& rtile)
+{
+ thread_scoped_lock tile_lock(tile_mutex);
+
+ if(update_render_buffers_cb) {
+ /* todo: optimize this by making it thread safe and removing lock */
+
+ if(!progress.get_cancel())
+ update_render_buffers_cb(rtile.buffers);
+ }
+
+ update_status_time();
+}
+
+void Session::release_tile(RenderTile& rtile)
+{
+ thread_scoped_lock tile_lock(tile_mutex);
+
+ if(write_render_buffers_cb) {
+ /* todo: optimize this by making it thread safe and removing lock */
+ if(!progress.get_cancel())
+ write_render_buffers_cb(rtile.buffers);
+ delete rtile.buffers;
+ }
+
+ update_status_time();
+}
+
void Session::run_cpu()
{
{
/* reset once to start */
thread_scoped_lock reset_lock(delayed_reset.mutex);
- thread_scoped_lock buffers_lock(buffers->mutex);
- thread_scoped_lock display_lock(display->mutex);
+ thread_scoped_lock buffers_lock(buffers_mutex);
+ thread_scoped_lock display_lock(display_mutex);
reset_(delayed_reset.params, delayed_reset.samples);
delayed_reset.do_reset = false;
/* buffers mutex is locked entirely while rendering each
* sample, and released/reacquired on each iteration to allow
* reset and draw in between */
- thread_scoped_lock buffers_lock(buffers->mutex);
+ thread_scoped_lock buffers_lock(buffers_mutex);
/* update scene */
update_scene();
update_status_time();
/* path trace */
- foreach(Tile& tile, tile_manager.state.tiles)
- path_trace(tile);
+ path_trace();
/* update status and timing */
update_status_time();
{
thread_scoped_lock reset_lock(delayed_reset.mutex);
- thread_scoped_lock buffers_lock(buffers->mutex);
- thread_scoped_lock display_lock(display->mutex);
+ thread_scoped_lock buffers_lock(buffers_mutex);
+ thread_scoped_lock display_lock(display_mutex);
if(delayed_reset.do_reset) {
/* reset rendering if request from main thread */
void Session::reset_(BufferParams& buffer_params, int samples)
{
- if(buffer_params.modified(buffers->params)) {
- gpu_draw_ready = false;
- buffers->reset(device, buffer_params);
- display->reset(device, buffer_params);
+ if(buffers) {
+ if(buffer_params.modified(buffers->params)) {
+ gpu_draw_ready = false;
+ buffers->reset(device, buffer_params);
+ display->reset(device, buffer_params);
+ }
}
tile_manager.reset(buffer_params, samples);
{
thread_scoped_lock scene_lock(scene->mutex);
- progress.set_status("Updating Scene");
-
/* update camera if dimensions changed for progressive render. the camera
* knows nothing about progressive or cropped rendering, it just gets the
* image dimensions passed in */
}
/* update scene */
- if(scene->need_update())
+ if(scene->need_update()) {
+ progress.set_status("Updating Scene");
scene->device_update(device, progress);
+ }
}
void Session::update_status_time(bool show_pause, bool show_done)
{
int sample = tile_manager.state.sample;
+ int num_samples = tile_manager.state.num_samples;
int resolution = tile_manager.state.resolution;
+ int num_tiles = tile_manager.state.num_tiles;
+ int tile = num_tiles - tile_manager.state.tiles.size();
/* update status */
string status, substatus;
if(!params.progressive)
- substatus = "Path Tracing";
+ substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles);
else if(params.samples == INT_MAX)
substatus = string_printf("Path Tracing Sample %d", sample+1);
else
/* negative can happen when we pause a bit before rendering, can discard that */
if(preview_time < 0.0) preview_time = 0.0;
- progress.set_sample(sample + 1, sample_time);
+ progress.set_sample(sample + num_samples, sample_time);
}
-void Session::path_trace(Tile& tile)
+void Session::path_trace()
{
/* add path trace task */
DeviceTask task(DeviceTask::PATH_TRACE);
-
- task.x = tile_manager.state.buffer.full_x + tile.x;
- task.y = tile_manager.state.buffer.full_y + tile.y;
- task.w = tile.w;
- task.h = tile.h;
- task.buffer = buffers->buffer.device_pointer;
- task.rng_state = buffers->rng_state.device_pointer;
- task.sample = tile_manager.state.sample;
- task.resolution = tile_manager.state.resolution;
- tile_manager.state.buffer.get_offset_stride(task.offset, task.stride);
+
+ task.acquire_tile = function_bind(&Session::acquire_tile, this, _1, _2);
+ task.release_tile = function_bind(&Session::release_tile, this, _1);
+ task.get_cancel = function_bind(&Progress::get_cancel, &this->progress);
+ task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1);
device->task_add(task);
}
bool progressive;
bool experimental;
int samples;
- int tile_size;
+ int2 tile_size;
int min_size;
int threads;
progressive = false;
experimental = false;
samples = INT_MAX;
- tile_size = 64;
+ tile_size = make_int2(64, 64);
min_size = 64;
threads = 0;
DisplayBuffer *display;
Progress progress;
SessionParams params;
+ TileManager tile_manager;
int sample;
+ boost::function<void(RenderBuffers*)> write_render_buffers_cb;
+ boost::function<void(RenderBuffers*)> update_render_buffers_cb;
+
Session(const SessionParams& params);
~Session();
void update_status_time(bool show_pause = false, bool show_done = false);
void tonemap();
- void path_trace(Tile& tile);
+ void path_trace();
void reset_(BufferParams& params, int samples);
void run_cpu();
bool draw_gpu(BufferParams& params);
void reset_gpu(BufferParams& params, int samples);
- TileManager tile_manager;
+ bool acquire_tile(Device *tile_device, RenderTile& tile);
+ void update_tile_sample(RenderTile& tile);
+ void release_tile(RenderTile& tile);
+
bool device_use_gl;
thread *session_thread;
bool pause;
thread_condition_variable pause_cond;
thread_mutex pause_mutex;
+ thread_mutex tile_mutex;
+ thread_mutex buffers_mutex;
+ thread_mutex display_mutex;
bool kernels_loaded;
#include "tile.h"
#include "util_algorithm.h"
+#include "util_types.h"
CCL_NAMESPACE_BEGIN
-TileManager::TileManager(bool progressive_, int samples_, int tile_size_, int min_size_)
+TileManager::TileManager(bool progressive_, int num_samples_, int2 tile_size_, int min_size_, int num_devices_)
{
progressive = progressive_;
tile_size = tile_size_;
min_size = min_size_;
+ num_devices = num_devices_;
BufferParams buffer_params;
reset(buffer_params, 0);
{
}
-void TileManager::reset(BufferParams& params_, int samples_)
+void TileManager::reset(BufferParams& params_, int num_samples_)
{
params = params_;
}
}
- samples = samples_;
+ num_samples = num_samples_;
state.buffer = BufferParams();
state.sample = -1;
+ state.num_tiles = 0;
+ state.num_samples = 0;
state.resolution = start_resolution;
state.tiles.clear();
}
-void TileManager::set_samples(int samples_)
+void TileManager::set_samples(int num_samples_)
{
- samples = samples_;
+ num_samples = num_samples_;
}
void TileManager::set_tiles()
int resolution = state.resolution;
int image_w = max(1, params.width/resolution);
int image_h = max(1, params.height/resolution);
- int tile_w = (tile_size >= image_w)? 1: (image_w + tile_size - 1)/tile_size;
- int tile_h = (tile_size >= image_h)? 1: (image_h + tile_size - 1)/tile_size;
- int sub_w = image_w/tile_w;
- int sub_h = image_h/tile_h;
state.tiles.clear();
- for(int tile_y = 0; tile_y < tile_h; tile_y++) {
- for(int tile_x = 0; tile_x < tile_w; tile_x++) {
- int x = tile_x * sub_w;
- int y = tile_y * sub_h;
- int w = (tile_x == tile_w-1)? image_w - x: sub_w;
- int h = (tile_y == tile_h-1)? image_h - y: sub_h;
+ int num = min(image_h, num_devices);
- state.tiles.push_back(Tile(x, y, w, h));
+ for(int device = 0; device < num; device++) {
+ int device_y = (image_h/num)*device;
+ int device_h = (device == num-1)? image_h - device*(image_h/num): image_h/num;
+
+ int tile_w = (tile_size.x >= image_w)? 1: (image_w + tile_size.x - 1)/tile_size.x;
+ int tile_h = (tile_size.y >= device_h)? 1: (device_h + tile_size.y - 1)/tile_size.y;
+ int sub_w = (image_w + tile_w - 1)/tile_w;
+ int sub_h = (device_h + tile_h - 1)/tile_h;
+
+ for(int tile_y = 0; tile_y < tile_h; tile_y++) {
+ for(int tile_x = 0; tile_x < tile_w; tile_x++) {
+ int x = tile_x * sub_w;
+ int y = tile_y * sub_h;
+ int w = (tile_x == tile_w-1)? image_w - x: sub_w;
+ int h = (tile_y == tile_h-1)? device_h - y: sub_h;
+
+ state.tiles.push_back(Tile(x, y + device_y, w, h, device));
+ }
}
}
+ state.num_tiles = state.tiles.size();
+
state.buffer.width = image_w;
state.buffer.height = image_h;
state.buffer.full_height = max(1, params.full_height/resolution);
}
+bool TileManager::next_tile(Tile& tile, int device)
+{
+ list<Tile>::iterator iter, best = state.tiles.end();
+
+ int resolution = state.resolution;
+ int image_w = max(1, params.width/resolution);
+ int image_h = max(1, params.height/resolution);
+
+ int num = min(image_h, num_devices);
+
+ int device_y = (image_h / num) * device;
+ int device_h = (device == num - 1) ? image_h - device * (image_h / num) : image_h / num;
+
+ int64_t centx = image_w / 2, centy = device_h / 2, tot = 1;
+ int64_t mindist = (int64_t) image_w * (int64_t) device_h;
+
+ /* find center of rendering tiles, image center counts for 1 too */
+ for(iter = state.tiles.begin(); iter != state.tiles.end(); iter++) {
+ if(iter->device == device && iter->rendering) {
+ Tile &cur_tile = *iter;
+ centx += cur_tile.x + cur_tile.w / 2;
+ centy += cur_tile.y + cur_tile.h / 2;
+ tot++;
+ }
+ }
+
+ centx /= tot;
+ centy /= tot;
+
+ /* closest of the non-rendering tiles */
+ for(iter = state.tiles.begin(); iter != state.tiles.end(); iter++) {
+ if(iter->device == device && iter->rendering == false) {
+ Tile &cur_tile = *iter;
+
+ int64_t distx = centx - (cur_tile.x + cur_tile.w / 2);
+ int64_t disty = centy - (cur_tile.y + cur_tile.h / 2);
+ distx = (int64_t) sqrt((double)distx * distx + disty * disty);
+
+ if (distx < mindist) {
+ best = iter;
+ mindist = distx;
+ }
+ }
+ }
+
+ if (best != state.tiles.end()) {
+ best->rendering = true;
+ tile = *best;
+
+ return true;
+ }
+
+ return false;
+}
+
bool TileManager::done()
{
- return (state.sample+1 >= samples && state.resolution == 1);
+ return (state.sample+state.num_samples >= num_samples && state.resolution == 1);
}
bool TileManager::next()
if(progressive && state.resolution > 1) {
state.sample = 0;
state.resolution /= 2;
+ state.num_samples = 1;
set_tiles();
}
else {
state.sample++;
+
+ if(progressive)
+ state.num_samples = 1;
+ else
+ state.num_samples = num_samples;
+
state.resolution = 1;
set_tiles();
}
class Tile {
public:
int x, y, w, h;
+ int device;
+ bool rendering;
- Tile(int x_, int y_, int w_, int h_)
- : x(x_), y(y_), w(w_), h(h_) {}
+ Tile()
+ {}
+
+ Tile(int x_, int y_, int w_, int h_, int device_)
+ : x(x_), y(y_), w(w_), h(h_), device(device_), rendering(false) {}
};
/* Tile Manager */
struct State {
BufferParams buffer;
int sample;
+ int num_samples;
int resolution;
+ int num_tiles;
list<Tile> tiles;
} state;
- TileManager(bool progressive, int samples, int tile_size, int min_size);
+ TileManager(bool progressive, int num_samples, int2 tile_size, int min_size, int num_devices = 1);
~TileManager();
- void reset(BufferParams& params, int samples);
- void set_samples(int samples);
+ void reset(BufferParams& params, int num_samples);
+ void set_samples(int num_samples);
bool next();
+ bool next_tile(Tile& tile, int device = 0);
bool done();
protected:
void set_tiles();
bool progressive;
- int samples;
- int tile_size;
+ int num_samples;
+ int2 tile_size;
int min_size;
+ int num_devices;
int start_resolution;
};
#ifndef __KERNEL_OPENCL__
+__device_inline bool operator==(const int2 a, const int2 b)
+{
+ return (a.x == b.x && a.y == b.y);
+}
+
__device_inline float len(const float2 a)
{
return sqrtf(dot(a, a));
--- /dev/null
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# 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.
+#
+# The Original Code is Copyright (C) 2012, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Sergey Sharybin.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ${OPENCOLORIO_INCLUDE_DIRS}
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ ocio_capi.cpp
+ ocio_capi.h
+)
+
+add_definitions(
+)
+
+if(WIN32 AND NOT MINGW)
+ list(APPEND INC
+ ${BOOST_INCLUDE_DIR}
+ )
+endif()
+
+blender_add_lib(bf_intern_opencolorio "${SRC}" "${INC}" "${INC_SYS}")
--- /dev/null
+#!/usr/bin/python
+
+Import('env')
+
+sources = env.Glob('*.cpp')
+
+incs = '.'
+incs += ' ' + env['BF_OCIO_INC']
+
+if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
+ incs += ' ' + env['BF_BOOST_INC']
+
+env.BlenderLib( 'bf_intern_opencolorio', sources, Split(incs), [], libtype=['extern','player'], priority=[10, 185])
--- /dev/null
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2012 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Xavier Thomas
+ * Lukas Toene
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <iostream>
+
+#include <OpenColorIO/OpenColorIO.h>
+
+
+#define OCIO_CAPI_IMPLEMENTATION
+#include "ocio_capi.h"
+
+#ifdef NDEBUG
+# define OCIO_abort()
+#else
+# include <stdlib.h>
+# define OCIO_abort() abort()
+#endif
+
+static void OCIO_reportError(const char *err)
+{
+ std::cerr << "OpenColorIO Error: " << err << std::endl;
+
+ OCIO_abort();
+}
+
+static void OCIO_reportException(Exception &exception)
+{
+ OCIO_reportError(exception.what());
+}
+
+ConstConfigRcPtr *OCIO_getCurrentConfig(void)
+{
+ ConstConfigRcPtr *config = new ConstConfigRcPtr();
+ try {
+ *config = GetCurrentConfig();
+
+ if(*config)
+ return config;
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+void OCIO_setCurrentConfig(const ConstConfigRcPtr *config)
+{
+ try {
+ SetCurrentConfig(*config);
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+}
+
+ConstConfigRcPtr *OCIO_configCreateFromEnv(void)
+{
+ ConstConfigRcPtr *config = new ConstConfigRcPtr();
+
+ try {
+ *config = Config::CreateFromEnv();
+
+ if (*config)
+ return config;
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+
+ConstConfigRcPtr *OCIO_configCreateFromFile(const char *filename)
+{
+ ConstConfigRcPtr *config = new ConstConfigRcPtr();
+
+ try {
+ *config = Config::CreateFromFile(filename);
+
+ if (*config)
+ return config;
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+void OCIO_configRelease(ConstConfigRcPtr *config)
+{
+ delete config;
+}
+
+int OCIO_configGetNumColorSpaces(ConstConfigRcPtr *config)
+{
+ try {
+ return (*config)->getNumColorSpaces();
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return 0;
+}
+
+const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index)
+{
+ try {
+ return (*config)->getColorSpaceNameByIndex(index);
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *config, const char *name)
+{
+ ConstColorSpaceRcPtr *cs = new ConstColorSpaceRcPtr();
+
+ try {
+ *cs = (*config)->getColorSpace(name);
+
+ if (*cs)
+ return cs;
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ delete cs;
+ }
+
+ return NULL;
+}
+
+int OCIO_configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name)
+{
+ try {
+ return (*config)->getIndexForColorSpace(name);
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return -1;
+}
+
+const char *OCIO_configGetDefaultDisplay(ConstConfigRcPtr *config)
+{
+ try {
+ return (*config)->getDefaultDisplay();
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+int OCIO_configGetNumDisplays(ConstConfigRcPtr* config)
+{
+ try {
+ return (*config)->getNumDisplays();
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return 0;
+}
+
+const char *OCIO_configGetDisplay(ConstConfigRcPtr *config, int index)
+{
+ try {
+ return (*config)->getDisplay(index);
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+const char *OCIO_configGetDefaultView(ConstConfigRcPtr *config, const char *display)
+{
+ try {
+ return (*config)->getDefaultView(display);
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+int OCIO_configGetNumViews(ConstConfigRcPtr *config, const char *display)
+{
+ try {
+ return (*config)->getNumViews(display);
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return 0;
+}
+
+const char *OCIO_configGetView(ConstConfigRcPtr *config, const char *display, int index)
+{
+ try {
+ return (*config)->getView(display, index);
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+const char *OCIO_configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view)
+{
+ try {
+ return (*config)->getDisplayColorSpaceName(display, view);
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+void OCIO_colorSpaceRelease(ConstColorSpaceRcPtr *cs)
+{
+ delete cs;
+}
+
+ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName)
+{
+ ConstProcessorRcPtr *p = new ConstProcessorRcPtr();
+
+ try {
+ *p = (*config)->getProcessor(srcName, dstName);
+
+ if (*p)
+ return p;
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return 0;
+}
+
+ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform)
+{
+ ConstProcessorRcPtr *p = new ConstProcessorRcPtr();
+
+ try {
+ *p = (*config)->getProcessor(*transform);
+
+ if (*p)
+ return p;
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img)
+{
+ try {
+ (*processor)->apply(*img);
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+}
+
+void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel)
+{
+ (*processor)->applyRGB(pixel);
+}
+
+void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel)
+{
+ (*processor)->applyRGBA(pixel);
+}
+
+void OCIO_processorRelease(ConstProcessorRcPtr *p)
+{
+ delete p;
+}
+
+const char *OCIO_colorSpaceGetName(ConstColorSpaceRcPtr *cs)
+{
+ return (*cs)->getName();
+}
+
+const char *OCIO_colorSpaceGetDescription(ConstColorSpaceRcPtr *cs)
+{
+ return (*cs)->getDescription();
+}
+
+const char *OCIO_colorSpaceGetFamily(ConstColorSpaceRcPtr *cs)
+{
+ return (*cs)->getFamily();
+}
+
+DisplayTransformRcPtr *OCIO_createDisplayTransform(void)
+{
+ DisplayTransformRcPtr *dt = new DisplayTransformRcPtr();
+
+ *dt = DisplayTransform::Create();
+
+ return dt;
+}
+
+void OCIO_displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name)
+{
+ (*dt)->setInputColorSpaceName(name);
+}
+
+void OCIO_displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name)
+{
+ (*dt)->setDisplay(name);
+}
+
+void OCIO_displayTransformSetView(DisplayTransformRcPtr *dt, const char *name)
+{
+ (*dt)->setView(name);
+}
+
+void OCIO_displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t)
+{
+ (*dt)->setDisplayCC(*t);
+}
+
+void OCIO_displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *t)
+{
+ (*dt)->setLinearCC(*t);
+}
+
+void OCIO_displayTransformRelease(DisplayTransformRcPtr *dt)
+{
+ delete dt;
+ dt = NULL;
+}
+
+PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height, long numChannels,
+ long chanStrideBytes, long xStrideBytes, long yStrideBytes)
+{
+ try {
+ PackedImageDesc *id = new PackedImageDesc(data, width, height, numChannels, chanStrideBytes, xStrideBytes, yStrideBytes);
+
+ return id;
+ }
+ catch (Exception &exception) {
+ OCIO_reportException(exception);
+ }
+
+ return NULL;
+}
+
+void OCIO_packedImageDescRelease(PackedImageDesc* id)
+{
+ delete id;
+ id = NULL;
+}
+
+ExponentTransformRcPtr *OCIO_createExponentTransform(void)
+{
+ ExponentTransformRcPtr *et = new ExponentTransformRcPtr();
+
+ *et = ExponentTransform::Create();
+
+ return et;
+}
+
+void OCIO_exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent)
+{
+ (*et)->setValue(exponent);
+}
+
+void OCIO_exponentTransformRelease(ExponentTransformRcPtr *et)
+{
+ delete et;
+}
+
+MatrixTransformRcPtr *OCIO_createMatrixTransform(void)
+{
+ MatrixTransformRcPtr *mt = new MatrixTransformRcPtr();
+
+ *mt = MatrixTransform::Create();
+
+ return mt;
+}
+
+void OCIO_matrixTransformSetValue(MatrixTransformRcPtr *mt, const float *m44, const float *offset4)
+{
+ (*mt)->setValue(m44, offset4);
+}
+
+void OCIO_matrixTransformRelease(MatrixTransformRcPtr *mt)
+{
+ delete mt;
+}
+
+void OCIO_matrixTransformScale(float * m44, float * offset4, const float *scale4f)
+{
+ MatrixTransform::Scale(m44, offset4, scale4f);
+}
--- /dev/null
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2012 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Xavier Thomas
+ * Lukas Toene
+ * Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __OCIO_CAPI_H__
+#define __OCIO_CAPI_H__
+
+
+
+#ifdef __cplusplus
+using namespace OCIO_NAMESPACE;
+extern "C" {
+#endif
+
+#define OCIO_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
+
+
+#ifndef OCIO_CAPI_IMPLEMENTATION
+ #define OCIO_ROLE_SCENE_LINEAR "scene_linear"
+ #define OCIO_ROLE_COLOR_PICKING "color_picking"
+ #define OCIO_ROLE_TEXTURE_PAINT "texture_paint"
+
+ OCIO_DECLARE_HANDLE(ConstConfigRcPtr);
+ OCIO_DECLARE_HANDLE(ConstColorSpaceRcPtr);
+ OCIO_DECLARE_HANDLE(ConstProcessorRcPtr);
+ OCIO_DECLARE_HANDLE(ConstContextRcPtr);
+ OCIO_DECLARE_HANDLE(PackedImageDesc);
+ OCIO_DECLARE_HANDLE(DisplayTransformRcPtr);
+ OCIO_DECLARE_HANDLE(ConstTransformRcPtr);
+ OCIO_DECLARE_HANDLE(ExponentTransformRcPtr);
+ OCIO_DECLARE_HANDLE(MatrixTransformRcPtr);
+#endif
+
+
+ConstConfigRcPtr *OCIO_getCurrentConfig(void);
+void OCIO_setCurrentConfig(const ConstConfigRcPtr *config);
+
+ConstConfigRcPtr *OCIO_configCreateFromEnv(void);
+ConstConfigRcPtr *OCIO_configCreateFromFile(const char* filename);
+
+void OCIO_configRelease(ConstConfigRcPtr *config);
+
+int OCIO_configGetNumColorSpaces(ConstConfigRcPtr *config);
+const char *OCIO_configGetColorSpaceNameByIndex(ConstConfigRcPtr *config, int index);
+ConstColorSpaceRcPtr *OCIO_configGetColorSpace(ConstConfigRcPtr *config, const char *name);
+int OCIO_configGetIndexForColorSpace(ConstConfigRcPtr *config, const char *name);
+
+void OCIO_colorSpaceRelease(ConstColorSpaceRcPtr *cs);
+
+const char *OCIO_configGetDefaultDisplay(ConstConfigRcPtr *config);
+int OCIO_configGetNumDisplays(ConstConfigRcPtr *config);
+const char *OCIO_configGetDisplay(ConstConfigRcPtr *config, int index);
+const char *OCIO_configGetDefaultView(ConstConfigRcPtr *config, const char *display);
+int OCIO_configGetNumViews(ConstConfigRcPtr *config, const char *display);
+const char *OCIO_configGetView(ConstConfigRcPtr *config, const char *display, int index);
+const char *OCIO_configGetDisplayColorSpaceName(ConstConfigRcPtr *config, const char *display, const char *view);
+
+ConstProcessorRcPtr *OCIO_configGetProcessorWithNames(ConstConfigRcPtr *config, const char *srcName, const char *dstName);
+ConstProcessorRcPtr *OCIO_configGetProcessor(ConstConfigRcPtr *config, ConstTransformRcPtr *transform);
+
+void OCIO_processorApply(ConstProcessorRcPtr *processor, PackedImageDesc *img);
+void OCIO_processorApplyRGB(ConstProcessorRcPtr *processor, float *pixel);
+void OCIO_processorApplyRGBA(ConstProcessorRcPtr *processor, float *pixel);
+
+void OCIO_processorRelease(ConstProcessorRcPtr *p);
+
+const char *OCIO_colorSpaceGetName(ConstColorSpaceRcPtr *cs);
+const char *OCIO_colorSpaceGetDescription(ConstColorSpaceRcPtr *cs);
+const char *OCIO_colorSpaceGetFamily(ConstColorSpaceRcPtr *cs);
+
+DisplayTransformRcPtr *OCIO_createDisplayTransform(void);
+void OCIO_displayTransformSetInputColorSpaceName(DisplayTransformRcPtr *dt, const char *name);
+void OCIO_displayTransformSetDisplay(DisplayTransformRcPtr *dt, const char *name);
+void OCIO_displayTransformSetView(DisplayTransformRcPtr *dt, const char *name);
+void OCIO_displayTransformSetDisplayCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et);
+void OCIO_displayTransformSetLinearCC(DisplayTransformRcPtr *dt, ConstTransformRcPtr *et);
+void OCIO_displayTransformRelease(DisplayTransformRcPtr *dt);
+
+PackedImageDesc *OCIO_createPackedImageDesc(float *data, long width, long height, long numChannels,
+ long chanStrideBytes, long xStrideBytes, long yStrideBytes);
+
+void OCIO_packedImageDescRelease(PackedImageDesc *p);
+
+ExponentTransformRcPtr *OCIO_createExponentTransform(void);
+void OCIO_exponentTransformSetValue(ExponentTransformRcPtr *et, const float *exponent);
+void OCIO_exponentTransformRelease(ExponentTransformRcPtr *et);
+
+MatrixTransformRcPtr *OCIO_createMatrixTransform(void);
+void OCIO_matrixTransformSetValue(MatrixTransformRcPtr *et, const float *m44, const float *offset4);
+void OCIO_matrixTransformRelease(MatrixTransformRcPtr *mt);
+
+void OCIO_matrixTransformScale(float * m44, float * offset4, const float * scale4);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //OCIO_CAPI_H
--- /dev/null
+ocio_profile_version: 1
+
+search_path: luts
+strictparsing: true
+luma: [0.2126, 0.7152, 0.0722]
+
+description: RRT version ut33
+
+roles:
+ color_picking: raw
+ color_timing: adx10
+ compositing_log: adx10
+ data: raw
+ default: raw
+ matte_paint: raw
+ reference: aces
+ scene_linear: rec709
+ texture_paint: raw
+
+displays:
+ p3dci:
+ - !<View> {name: Raw, colorspace: raw}
+ - !<View> {name: Log, colorspace: adx10}
+ - !<View> {name: RRT, colorspace: rrt_p3dci}
+ sRGB:
+ - !<View> {name: Raw, colorspace: raw}
+ - !<View> {name: Log, colorspace: adx10}
+ - !<View> {name: RRT, colorspace: rrt_srgb}
+ - !<View> {name: SPI Film, colorspace: srgb8}
+ - !<View> {name: SPI Log, colorspace: lg10}
+ - !<View> {name: Nuke rec709, colorspace: nuke_rec709}
+ xyz:
+ - !<View> {name: Raw, colorspace: raw}
+ - !<View> {name: Log, colorspace: adx10}
+ - !<View> {name: RRT, colorspace: rrt_xyz}
+
+active_displays: [sRGB, p3dci, xyz]
+active_views: [RRT, Log, SPI Film, SPI Log, Raw]
+
+colorspaces:
+ - !<ColorSpace>
+ name: aces
+ family: aces
+ equalitygroup:
+ bitdepth: 32f
+ isdata: false
+ allocation: lg2
+ allocationvars: [-8.5, 5]
+
+ - !<ColorSpace>
+ name: raw
+ family: raw
+ equalitygroup:
+ bitdepth: 32f
+ isdata: true
+ allocation: uniform
+ allocationvars: [0, 1]
+
+ - !<ColorSpace>
+ name: adx10
+ family: adx
+ equalitygroup:
+ bitdepth: 10ui
+ description: |
+ Film Scan, using the 10-bit Academy Density Encoding
+
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ to_reference: !<GroupTransform>
+ children:
+ - !<FileTransform> {src: adx_adx10_to_cdd.spimtx}
+ - !<FileTransform> {src: adx_cdd_to_cid.spimtx}
+ - !<FileTransform> {src: adx_cid_to_rle.spi1d, interpolation: linear}
+ - !<LogTransform> {base: 10, direction: inverse}
+ - !<FileTransform> {src: adx_exp_to_aces.spimtx}
+
+ - !<ColorSpace>
+ name: adx16
+ family: adx
+ equalitygroup:
+ bitdepth: 16ui
+ description: |
+ Film Scan, using the 16-bit Academy Density Encoding
+
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ to_reference: !<GroupTransform>
+ children:
+ - !<FileTransform> {src: adx_adx16_to_cdd.spimtx}
+ - !<FileTransform> {src: adx_cdd_to_cid.spimtx}
+ - !<FileTransform> {src: adx_cid_to_rle.spi1d, interpolation: linear}
+ - !<LogTransform> {base: 10, direction: inverse}
+ - !<FileTransform> {src: adx_exp_to_aces.spimtx}
+
+ - !<ColorSpace>
+ name: slogf35
+ family: sony
+ equalitygroup:
+ bitdepth: 10ui
+ description: |
+ Sony 10-bit S-Log, with f35 color primaries
+
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ to_reference: !<GroupTransform>
+ children:
+ - !<FileTransform> {src: slog10.spi1d, interpolation: linear}
+ - !<FileTransform> {src: slogf35_to_aces.spimtx, interpolation: linear}
+
+ - !<ColorSpace>
+ name: slogf65_3200
+ family: sony
+ equalitygroup:
+ bitdepth: 10ui
+ description: |
+ Sony 10-bit S-Log, with f65 color primaries
+
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ to_reference: !<GroupTransform>
+ children:
+ - !<FileTransform> {src: slog10.spi1d, interpolation: linear}
+ - !<FileTransform> {src: slogf65_to_aces_3200.spimtx, interpolation: linear}
+
+ - !<ColorSpace>
+ name: slogf65_5500
+ family: sony
+ equalitygroup:
+ bitdepth: 10ui
+ description: |
+ Sony 10-bit S-Log, with f65 color primaries
+
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ to_reference: !<GroupTransform>
+ children:
+ - !<FileTransform> {src: slog10.spi1d, interpolation: linear}
+ - !<FileTransform> {src: slogf65_to_aces_5500.spimtx, interpolation: linear}
+
+ - !<ColorSpace>
+ name: logc
+ family: arri
+ equalitygroup:
+ bitdepth: 10ui
+ description: |
+ Arri Alexa LogC, V3, Exposure Index 800
+
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ to_reference: !<GroupTransform>
+ children:
+ - !<FileTransform> {src: logc800.spi1d, interpolation: linear}
+ - !<FileTransform> {src: logc_to_aces.spimtx}
+
+ - !<ColorSpace>
+ name: log
+ family: log
+ equalitygroup:
+ bitdepth: 32f
+ description: |
+ A mathematically idealized log space, which spans the dynamic range
+ currently being utilized by the ACES RRT. Note: this does not correspond
+ to scanned plates, adx10 is preferred for that purpose.
+
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ from_reference: !<GroupTransform>
+ children:
+ - !<AllocationTransform> {allocation: lg2, vars: [-8.5, 5]}
+
+ - !<ColorSpace>
+ name: rec709
+ family: ""
+ equalitygroup: ""
+ bitdepth: 32f
+ description: |
+ Rec. 709 (Full Range), Blender native internal space
+ isdata: false
+ allocation: uniform
+ allocationvars: [-0.125, 1.125]
+ to_reference: !<FileTransform> {src: rec709_to_aces.spimtx, interpolation: nearest}
+
+ - !<ColorSpace>
+ name: rrt_srgb
+ family: rrt
+ equalitygroup:
+ bitdepth: 32f
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ from_reference: !<GroupTransform>
+ children:
+ - !<AllocationTransform> {allocation: lg2, vars: [-8.5, 5]}
+ - !<FileTransform> {src: rrt_ut33_sRGB.spi3d, interpolation: tetrahedral}
+
+ - !<ColorSpace>
+ name: rrt_rec709
+ family: rrt
+ equalitygroup:
+ bitdepth: 32f
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ from_reference: !<GroupTransform>
+ children:
+ - !<AllocationTransform> {allocation: lg2, vars: [-8.5, 5]}
+ - !<FileTransform> {src: rrt_ut33_rec709.spi3d, interpolation: tetrahedral}
+
+ - !<ColorSpace>
+ name: rrt_p3dci
+ family: rrt
+ equalitygroup:
+ bitdepth: 32f
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ from_reference: !<GroupTransform>
+ children:
+ - !<AllocationTransform> {allocation: lg2, vars: [-8.5, 5]}
+ - !<FileTransform> {src: rrt_ut33_p3dci.spi3d, interpolation: tetrahedral}
+
+ - !<ColorSpace>
+ name: rrt_p3d60
+ family: rrt
+ equalitygroup:
+ bitdepth: 32f
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ from_reference: !<GroupTransform>
+ children:
+ - !<AllocationTransform> {allocation: lg2, vars: [-8.5, 5]}
+ - !<FileTransform> {src: rrt_ut33_p3d60.spi3d, interpolation: tetrahedral}
+
+ - !<ColorSpace>
+ name: rrt_xyz
+ family: rrt
+ equalitygroup:
+ bitdepth: 32f
+ isdata: false
+ allocation: uniform
+ allocationvars: [0, 1]
+ from_reference: !<GroupTransform>
+ children:
+ - !<AllocationTransform> {allocation: lg2, vars: [-8.5, 5]}
+ - !<FileTransform> {src: rrt_ut33_dcdm.spi3d, interpolation: tetrahedral}
+
+ # spi-vfx
+ - !<ColorSpace>
+ name: lg10
+ family: lg
+ equalitygroup:
+ bitdepth: 10ui
+ description: |
+ lg10 : conversion from film log
+ isdata: false
+ allocation: uniform
+ to_reference: !<GroupTransform>
+ children:
+ - !<FileTransform> {src: lg10.spi1d, interpolation: nearest}
+ - !<FileTransform> {src: rec709_to_aces.spimtx, interpolation: nearest}
+
+ - !<ColorSpace>
+ name: srgb8
+ family: srgb
+ equalitygroup:
+ bitdepth: 8ui
+ description: |
+ srgb8 :rgb display space for the srgb standard.
+ isdata: false
+ allocation: uniform
+ from_reference: !<GroupTransform>
+ children:
+ - !<ColorSpaceTransform> {src: aces, dst: lg10}
+ - !<FileTransform> {src: spi_ocio_srgb_test.spi3d, interpolation: linear}
+
+ # nuke-default
+ - !<ColorSpace>
+ name: nuke_rec709
+ family: ""
+ equalitygroup: ""
+ bitdepth: 32f
+ description: |
+ Rec. 709 (Full Range) Display Space
+ isdata: false
+ allocation: uniform
+ allocationvars: [-0.125, 1.125]
+ to_reference: !<GroupTransform>
+ children:
+ - !<FileTransform> {src: rec709.spi1d, interpolation: linear}
+ - !<FileTransform> {src: rec709_to_aces.spimtx, interpolation: nearest}
--- /dev/null
+2.046 0.0 0.0 -12451.65
+0.0 2.046 0.0 -12451.65
+0.0 0.0 2.046 -12451.65
+
--- /dev/null
+8.191875 0.0 0.0 -12451.65
+0.0 8.191875 0.0 -12451.65
+0.0 0.0 8.191875 -12451.65
+
--- /dev/null
+0.75573 0.22197 0.02230 0
+0.05901 0.96928 -0.02829 0
+0.16134 0.07406 0.76460 0
+
--- /dev/null
+#!/usr/bin/env python
+
+import math, numpy
+
+"""
+
+const float REF_PT = (7120.0 - 1520.0) / 8000.0 * (100.0 / 55.0) - log10(0.18);
+
+const float LUT_1D[11][2] = {
+ {-0.190000000000000, -6.000000000000000},
+ { 0.010000000000000, -2.721718645000000},
+ { 0.028000000000000, -2.521718645000000},
+ { 0.054000000000000, -2.321718645000000},
+ { 0.095000000000000, -2.121718645000000},
+ { 0.145000000000000, -1.921718645000000},
+ { 0.220000000000000, -1.721718645000000},
+ { 0.300000000000000, -1.521718645000000},
+ { 0.400000000000000, -1.321718645000000},
+ { 0.500000000000000, -1.121718645000000},
+ { 0.600000000000000, -0.926545676714876}
+};
+
+ // Convert Channel Independent Density values to Relative Log Exposure values
+ float logE[3];
+ if ( cid[0] <= 0.6) logE[0] = interpolate1D( LUT_1D, cid[0]);
+ if ( cid[1] <= 0.6) logE[1] = interpolate1D( LUT_1D, cid[1]);
+ if ( cid[2] <= 0.6) logE[2] = interpolate1D( LUT_1D, cid[2]);
+
+ if ( cid[0] > 0.6) logE[0] = ( 100.0 / 55.0) * cid[0] - REF_PT;
+ if ( cid[1] > 0.6) logE[1] = ( 100.0 / 55.0) * cid[1] - REF_PT;
+ if ( cid[2] > 0.6) logE[2] = ( 100.0 / 55.0) * cid[2] - REF_PT;
+"""
+
+
+def interpolate1D(x, xp, fp):
+ return numpy.interp(x, xp, fp)
+
+LUT_1D_xp = [-0.190000000000000,
+ 0.010000000000000,
+ 0.028000000000000,
+ 0.054000000000000,
+ 0.095000000000000,
+ 0.145000000000000,
+ 0.220000000000000,
+ 0.300000000000000,
+ 0.400000000000000,
+ 0.500000000000000,
+ 0.600000000000000]
+
+LUT_1D_fp = [-6.000000000000000,
+ -2.721718645000000,
+ -2.521718645000000,
+ -2.321718645000000,
+ -2.121718645000000,
+ -1.921718645000000,
+ -1.721718645000000,
+ -1.521718645000000,
+ -1.321718645000000,
+ -1.121718645000000,
+ -0.926545676714876]
+
+REF_PT = (7120.0 - 1520.0) / 8000.0 * (100.0 / 55.0) - math.log(0.18, 10.0)
+
+def cid_to_rle(x):
+ if x <= 0.6:
+ return interpolate1D(x, LUT_1D_xp, LUT_1D_fp)
+ return (100.0 / 55.0) * x - REF_PT
+
+def WriteSPI1D(filename, fromMin, fromMax, data):
+ f = file(filename,'w')
+ f.write("Version 1\n")
+ f.write("From %s %s\n" % (fromMin, fromMax))
+ f.write("Length %d\n" % len(data))
+ f.write("Components 1\n")
+ f.write("{\n")
+ for value in data:
+ f.write(" %s\n" % value)
+ f.write("}\n")
+ f.close()
+
+def Fit(value, fromMin, fromMax, toMin, toMax):
+ if fromMin == fromMax:
+ raise ValueError("fromMin == fromMax")
+ return (value - fromMin) / (fromMax - fromMin) * (toMax - toMin) + toMin
+
+NUM_SAMPLES = 2**12
+RANGE = (-0.19, 3.0)
+data = []
+for i in xrange(NUM_SAMPLES):
+ x = i/(NUM_SAMPLES-1.0)
+ x = Fit(x, 0.0, 1.0, RANGE[0], RANGE[1])
+ data.append(cid_to_rle(x))
+
+WriteSPI1D('adx_cid_to_rle.spi1d', RANGE[0], RANGE[1], data)
+
--- /dev/null
+Version 1
+From -0.19 3.0
+Length 4096
+Components 1
+{
+ -6.0
+ -5.98723111414
+ -5.97446222827
+ -5.96169334241
+ -5.94892445654
+ -5.93615557068
+ -5.92338668482
+ -5.91061779895
+ -5.89784891309
+ -5.88508002723
+ -5.87231114136
+ -5.8595422555
+ -5.84677336963
+ -5.83400448377
+ -5.82123559791
+ -5.80846671204
+ -5.79569782618
+ -5.78292894032
+ -5.77016005445
+ -5.75739116859
+ -5.74462228272
+ -5.73185339686
+ -5.719084511
+ -5.70631562513
+ -5.69354673927
+ -5.68077785341
+ -5.66800896754
+ -5.65524008168
+ -5.64247119581
+ -5.62970230995
+ -5.61693342409
+ -5.60416453822
+ -5.59139565236
+ -5.57862676649
+ -5.56585788063
+ -5.55308899477
+ -5.5403201089
+ -5.52755122304
+ -5.51478233718
+ -5.50201345131
+ -5.48924456545
+ -5.47647567958
+ -5.46370679372
+ -5.45093790786
+ -5.43816902199
+ -5.42540013613
+ -5.41263125027
+ -5.3998623644
+ -5.38709347854
+ -5.37432459267
+ -5.36155570681
+ -5.34878682095
+ -5.33601793508
+ -5.32324904922
+ -5.31048016335
+ -5.29771127749
+ -5.28494239163
+ -5.27217350576
+ -5.2594046199
+ -5.24663573404
+ -5.23386684817
+ -5.22109796231
+ -5.20832907644
+ -5.19556019058
+ -5.18279130472
+ -5.17002241885
+ -5.15725353299
+ -5.14448464713
+ -5.13171576126
+ -5.1189468754
+ -5.10617798953
+ -5.09340910367
+ -5.08064021781
+ -5.06787133194
+ -5.05510244608
+ -5.04233356022
+ -5.02956467435
+ -5.01679578849
+ -5.00402690262
+ -4.99125801676
+ -4.9784891309
+ -4.96572024503
+ -4.95295135917
+ -4.9401824733
+ -4.92741358744
+ -4.91464470158
+ -4.90187581571
+ -4.88910692985
+ -4.87633804399
+ -4.86356915812
+ -4.85080027226
+ -4.83803138639
+ -4.82526250053
+ -4.81249361467
+ -4.7997247288
+ -4.78695584294
+ -4.77418695708
+ -4.76141807121
+ -4.74864918535
+ -4.73588029948
+ -4.72311141362
+ -4.71034252776
+ -4.69757364189
+ -4.68480475603
+ -4.67203587017
+ -4.6592669843
+ -4.64649809844
+ -4.63372921257
+ -4.62096032671
+ -4.60819144085
+ -4.59542255498
+ -4.58265366912
+ -4.56988478325
+ -4.55711589739
+ -4.54434701153
+ -4.53157812566
+ -4.5188092398
+ -4.50604035394
+ -4.49327146807
+ -4.48050258221
+ -4.46773369634
+ -4.45496481048
+ -4.44219592462
+ -4.42942703875
+ -4.41665815289
+ -4.40388926703
+ -4.39112038116
+ -4.3783514953
+ -4.36558260943
+ -4.35281372357
+ -4.34004483771
+ -4.32727595184
+ -4.31450706598
+ -4.30173818011
+ -4.28896929425
+ -4.27620040839
+ -4.26343152252
+ -4.25066263666
+ -4.2378937508
+ -4.22512486493
+ -4.21235597907
+ -4.1995870932
+ -4.18681820734
+ -4.17404932148
+ -4.16128043561
+ -4.14851154975
+ -4.13574266389
+ -4.12297377802
+ -4.11020489216
+ -4.09743600629
+ -4.08466712043
+ -4.07189823457
+ -4.0591293487
+ -4.04636046284
+ -4.03359157698
+ -4.02082269111
+ -4.00805380525
+ -3.99528491938
+ -3.98251603352
+ -3.96974714766
+ -3.95697826179
+ -3.94420937593
+ -3.93144049006
+ -3.9186716042
+ -3.90590271834
+ -3.89313383247
+ -3.88036494661
+ -3.86759606075
+ -3.85482717488
+ -3.84205828902
+ -3.82928940315
+ -3.81652051729
+ -3.80375163143
+ -3.79098274556
+ -3.7782138597
+ -3.76544497384
+ -3.75267608797
+ -3.73990720211
+ -3.72713831624
+ -3.71436943038
+ -3.70160054452
+ -3.68883165865
+ -3.67606277279
+ -3.66329388693
+ -3.65052500106
+ -3.6377561152
+ -3.62498722933
+ -3.61221834347
+ -3.59944945761
+ -3.58668057174
+ -3.57391168588
+ -3.56114280001
+ -3.54837391415
+ -3.53560502829
+ -3.52283614242
+ -3.51006725656
+ -3.4972983707
+ -3.48452948483
+ -3.47176059897
+ -3.4589917131
+ -3.44622282724
+ -3.43345394138
+ -3.42068505551
+ -3.40791616965
+ -3.39514728379
+ -3.38237839792
+ -3.36960951206
+ -3.35684062619
+ -3.34407174033
+ -3.33130285447
+ -3.3185339686
+ -3.30576508274
+ -3.29299619687
+ -3.28022731101
+ -3.26745842515
+ -3.25468953928
+ -3.24192065342
+ -3.22915176756
+ -3.21638288169
+ -3.20361399583
+ -3.19084510996
+ -3.1780762241
+ -3.16530733824
+ -3.15253845237
+ -3.13976956651
+ -3.12700068065
+ -3.11423179478
+ -3.10146290892
+ -3.08869402305
+ -3.07592513719
+ -3.06315625133
+ -3.05038736546
+ -3.0376184796
+ -3.02484959374
+ -3.01208070787
+ -2.99931182201
+ -2.98654293614
+ -2.97377405028
+ -2.96100516442
+ -2.94823627855
+ -2.93546739269
+ -2.92269850682
+ -2.90992962096
+ -2.8971607351
+ -2.88439184923
+ -2.87162296337
+ -2.85885407751
+ -2.84608519164
+ -2.83331630578
+ -2.82054741991
+ -2.80777853405
+ -2.79500964819
+ -2.78224076232
+ -2.76947187646
+ -2.7567029906
+ -2.74393410473
+ -2.73116521887
+ -2.71946657608
+ -2.71081103409
+ -2.7021554921
+ -2.69349995011
+ -2.68484440813
+ -2.67618886614
+ -2.66753332415
+ -2.65887778216
+ -2.65022224017
+ -2.64156669818
+ -2.63291115619
+ -2.6242556142
+ -2.61560007221
+ -2.60694453023
+ -2.59828898824
+ -2.58963344625
+ -2.58097790426
+ -2.57232236227
+ -2.56366682028
+ -2.55501127829
+ -2.5463557363
+ -2.53770019431
+ -2.52904465233
+ -2.52079819793
+ -2.51480589963
+ -2.50881360133
+ -2.50282130303
+ -2.49682900473
+ -2.49083670643
+ -2.48484440813
+ -2.47885210983
+ -2.47285981153
+ -2.46686751323
+ -2.46087521493
+ -2.45488291663
+ -2.44889061833
+ -2.44289832003
+ -2.43690602173
+ -2.43091372343
+ -2.42492142513
+ -2.41892912683
+ -2.41293682853
+ -2.40694453023
+ -2.40095223193
+ -2.39495993363
+ -2.38896763533
+ -2.38297533703
+ -2.37698303873
+ -2.37099074043
+ -2.36499844213
+ -2.35900614383
+ -2.35301384553
+ -2.34702154723
+ -2.34102924893
+ -2.33503695063
+ -2.32904465233
+ -2.32305235403
+ -2.31876441766
+ -2.31496442361
+ -2.31116442957
+ -2.30736443552
+ -2.30356444148
+ -2.29976444744
+ -2.29596445339
+ -2.29216445935
+ -2.2883644653
+ -2.28456447126
+ -2.28076447722
+ -2.27696448317
+ -2.27316448913
+ -2.26936449508
+ -2.26556450104
+ -2.261764507
+ -2.25796451295
+ -2.25416451891
+ -2.25036452487
+ -2.24656453082
+ -2.24276453678
+ -2.23896454273
+ -2.23516454869
+ -2.23136455465
+ -2.2275645606
+ -2.22376456656
+ -2.21996457251
+ -2.21616457847
+ -2.21236458443
+ -2.20856459038
+ -2.20476459634
+ -2.20096460229
+ -2.19716460825
+ -2.19336461421
+ -2.18956462016
+ -2.18576462612
+ -2.18196463208
+ -2.17816463803
+ -2.17436464399
+ -2.17056464994
+ -2.1667646559
+ -2.16296466186
+ -2.15916466781
+ -2.15536467377
+ -2.15156467972
+ -2.14776468568
+ -2.14396469164
+ -2.14016469759
+ -2.13636470355
+ -2.1325647095
+ -2.12876471546
+ -2.12496472142
+ -2.12126443255
+ -2.11814843743
+ -2.11503244231
+ -2.1119164472
+ -2.10880045208
+ -2.10568445697
+ -2.10256846185
+ -2.09945246673
+ -2.09633647162
+ -2.0932204765
+ -2.09010448139
+ -2.08698848627
+ -2.08387249115
+ -2.08075649604
+ -2.07764050092
+ -2.07452450581
+ -2.07140851069
+ -2.06829251557
+ -2.06517652046
+ -2.06206052534
+ -2.05894453023
+ -2.05582853511
+ -2.05271253999
+ -2.04959654488
+ -2.04648054976
+ -2.04336455465
+ -2.04024855953
+ -2.03713256441
+ -2.0340165693
+ -2.03090057418
+ -2.02778457907
+ -2.02466858395
+ -2.02155258883
+ -2.01843659372
+ -2.0153205986
+ -2.01220460349
+ -2.00908860837
+ -2.00597261325
+ -2.00285661814
+ -1.99974062302
+ -1.99662462791
+ -1.99350863279
+ -1.99039263767
+ -1.98727664256
+ -1.98416064744
+ -1.98104465233
+ -1.97792865721
+ -1.97481266209
+ -1.97169666698
+ -1.96858067186
+ -1.96546467675
+ -1.96234868163
+ -1.95923268651
+ -1.9561166914
+ -1.95300069628
+ -1.94988470117
+ -1.94676870605
+ -1.94365271093
+ -1.94053671582
+ -1.9374207207
+ -1.93430472559
+ -1.93118873047
+ -1.92807273535
+ -1.92495674024
+ -1.92184074512
+ -1.919722715
+ -1.91764538493
+ -1.91556805485
+ -1.91349072477
+ -1.91141339469
+ -1.90933606462
+ -1.90725873454
+ -1.90518140446
+ -1.90310407439
+ -1.90102674431
+ -1.89894941423
+ -1.89687208415
+ -1.89479475408
+ -1.892717424
+ -1.89064009392
+ -1.88856276384
+ -1.88648543377
+ -1.88440810369
+ -1.88233077361
+ -1.88025344353
+ -1.87817611346
+ -1.87609878338
+ -1.8740214533
+ -1.87194412323
+ -1.86986679315
+ -1.86778946307
+ -1.86571213299
+ -1.86363480292
+ -1.86155747284
+ -1.85948014276
+ -1.85740281268
+ -1.85532548261
+ -1.85324815253
+ -1.85117082245
+ -1.84909349237
+ -1.8470161623
+ -1.84493883222
+ -1.84286150214
+ -1.84078417207
+ -1.83870684199
+ -1.83662951191
+ -1.83455218183
+ -1.83247485176
+ -1.83039752168
+ -1.8283201916
+ -1.82624286152
+ -1.82416553145
+ -1.82208820137
+ -1.82001087129
+ -1.81793354121
+ -1.81585621114
+ -1.81377888106
+ -1.81170155098
+ -1.80962422091
+ -1.80754689083
+ -1.80546956075
+ -1.80339223067
+ -1.8013149006
+ -1.79923757052
+ -1.79716024044
+ -1.79508291036
+ -1.79300558029
+ -1.79092825021
+ -1.78885092013
+ -1.78677359005
+ -1.78469625998
+ -1.7826189299
+ -1.78054159982
+ -1.77846426975
+ -1.77638693967
+ -1.77430960959
+ -1.77223227951
+ -1.77015494944
+ -1.76807761936
+ -1.76600028928
+ -1.7639229592
+ -1.76184562913
+ -1.75976829905
+ -1.75769096897
+ -1.75561363889
+ -1.75353630882
+ -1.75145897874
+ -1.74938164866
+ -1.74730431859
+ -1.74522698851
+ -1.74314965843
+ -1.74107232835
+ -1.73899499828
+ -1.7369176682
+ -1.73484033812
+ -1.73276300804
+ -1.73068567797
+ -1.72860834789
+ -1.72653101781
+ -1.72445368774
+ -1.72237635766
+ -1.72038775367
+ -1.71844025672
+ -1.71649275977
+ -1.71454526283
+ -1.71259776588
+ -1.71065026893
+ -1.70870277198
+ -1.70675527504
+ -1.70480777809
+ -1.70286028114
+ -1.70091278419
+ -1.69896528725
+ -1.6970177903
+ -1.69507029335
+ -1.6931227964
+ -1.69117529946
+ -1.68922780251
+ -1.68728030556
+ -1.68533280861
+ -1.68338531167
+ -1.68143781472
+ -1.67949031777
+ -1.67754282082
+ -1.67559532388
+ -1.67364782693
+ -1.67170032998
+ -1.66975283303
+ -1.66780533609
+ -1.66585783914
+ -1.66391034219
+ -1.66196284524
+ -1.6600153483
+ -1.65806785135
+ -1.6561203544
+ -1.65417285745
+ -1.65222536051
+ -1.65027786356
+ -1.64833036661
+ -1.64638286966
+ -1.64443537272
+ -1.64248787577
+ -1.64054037882
+ -1.63859288187
+ -1.63664538493
+ -1.63469788798
+ -1.63275039103
+ -1.63080289408
+ -1.62885539714
+ -1.62690790019
+ -1.62496040324
+ -1.62301290629
+ -1.62106540935
+ -1.6191179124
+ -1.61717041545
+ -1.6152229185
+ -1.61327542156
+ -1.61132792461
+ -1.60938042766
+ -1.60743293071
+ -1.60548543377
+ -1.60353793682
+ -1.60159043987
+ -1.59964294292
+ -1.59769544598
+ -1.59574794903
+ -1.59380045208
+ -1.59185295513
+ -1.58990545819
+ -1.58795796124
+ -1.58601046429
+ -1.58406296734
+ -1.5821154704
+ -1.58016797345
+ -1.5782204765
+ -1.57627297955
+ -1.57432548261
+ -1.57237798566
+ -1.57043048871
+ -1.56848299176
+ -1.56653549482
+ -1.56458799787
+ -1.56264050092
+ -1.56069300397
+ -1.55874550703
+ -1.55679801008
+ -1.55485051313
+ -1.55290301618
+ -1.55095551924
+ -1.54900802229
+ -1.54706052534
+ -1.54511302839
+ -1.54316553145
+ -1.5412180345
+ -1.53927053755
+ -1.5373230406
+ -1.53537554366
+ -1.53342804671
+ -1.53148054976
+ -1.52953305281
+ -1.52758555587
+ -1.52563805892
+ -1.52369056197
+ -1.52174306502
+ -1.52018018346
+ -1.5186221859
+ -1.51706418835
+ -1.51550619079
+ -1.51394819323
+ -1.51239019567
+ -1.51083219811
+ -1.50927420056
+ -1.507716203
+ -1.50615820544
+ -1.50460020788
+ -1.50304221032
+ -1.50148421277
+ -1.49992621521
+ -1.49836821765
+ -1.49681022009
+ -1.49525222253
+ -1.49369422498
+ -1.49213622742
+ -1.49057822986
+ -1.4890202323
+ -1.48746223474
+ -1.48590423719
+ -1.48434623963
+ -1.48278824207
+ -1.48123024451
+ -1.47967224695
+ -1.4781142494
+ -1.47655625184
+ -1.47499825428
+ -1.47344025672
+ -1.47188225916
+ -1.47032426161
+ -1.46876626405
+ -1.46720826649
+ -1.46565026893
+ -1.46409227137
+ -1.46253427382
+ -1.46097627626
+ -1.4594182787
+ -1.45786028114
+ -1.45630228358
+ -1.45474428603
+ -1.45318628847
+ -1.45162829091
+ -1.45007029335
+ -1.44851229579
+ -1.44695429824
+ -1.44539630068
+ -1.44383830312
+ -1.44228030556
+ -1.440722308
+ -1.43916431045
+ -1.43760631289
+ -1.43604831533
+ -1.43449031777
+ -1.43293232021
+ -1.43137432266
+ -1.4298163251
+ -1.42825832754
+ -1.42670032998
+ -1.42514233242
+ -1.42358433487
+ -1.42202633731
+ -1.42046833975
+ -1.41891034219
+ -1.41735234463
+ -1.41579434708
+ -1.41423634952
+ -1.41267835196
+ -1.4111203544
+ -1.40956235684
+ -1.40800435929
+ -1.40644636173
+ -1.40488836417
+ -1.40333036661
+ -1.40177236905
+ -1.4002143715
+ -1.39865637394
+ -1.39709837638
+ -1.39554037882
+ -1.39398238126
+ -1.39242438371
+ -1.39086638615
+ -1.38930838859
+ -1.38775039103
+ -1.38619239347
+ -1.38463439592
+ -1.38307639836
+ -1.3815184008
+ -1.37996040324
+ -1.37840240568
+ -1.37684440813
+ -1.37528641057
+ -1.37372841301
+ -1.37217041545
+ -1.37061241789
+ -1.36905442034
+ -1.36749642278
+ -1.36593842522
+ -1.36438042766
+ -1.3628224301
+ -1.36126443255
+ -1.35970643499
+ -1.35814843743
+ -1.35659043987
+ -1.35503244231
+ -1.35347444476
+ -1.3519164472
+ -1.35035844964
+ -1.34880045208
+ -1.34724245452
+ -1.34568445697
+ -1.34412645941
+ -1.34256846185
+ -1.34101046429
+ -1.33945246673
+ -1.33789446918
+ -1.33633647162
+ -1.33477847406
+ -1.3332204765
+ -1.33166247894
+ -1.33010448139
+ -1.32854648383
+ -1.32698848627
+ -1.32543048871
+ -1.32387249115
+ -1.3223144936
+ -1.32075649604
+ -1.31919849848
+ -1.31764050092
+ -1.31608250336
+ -1.31452450581
+ -1.31296650825
+ -1.31140851069
+ -1.30985051313
+ -1.30829251557
+ -1.30673451802
+ -1.30517652046
+ -1.3036185229
+ -1.30206052534
+ -1.30050252778
+ -1.29894453023
+ -1.29738653267
+ -1.29582853511
+ -1.29427053755
+ -1.29271253999
+ -1.29115454244
+ -1.28959654488
+ -1.28803854732
+ -1.28648054976
+ -1.2849225522
+ -1.28336455465
+ -1.28180655709
+ -1.28024855953
+ -1.27869056197
+ -1.27713256441
+ -1.27557456686
+ -1.2740165693
+ -1.27245857174
+ -1.27090057418
+ -1.26934257662
+ -1.26778457907
+ -1.26622658151
+ -1.26466858395
+ -1.26311058639
+ -1.26155258883
+ -1.25999459128
+ -1.25843659372
+ -1.25687859616
+ -1.2553205986
+ -1.25376260104
+ -1.25220460349
+ -1.25064660593
+ -1.24908860837
+ -1.24753061081
+ -1.24597261325
+ -1.2444146157
+ -1.24285661814
+ -1.24129862058
+ -1.23974062302
+ -1.23818262546
+ -1.23662462791
+ -1.23506663035
+ -1.23350863279
+ -1.23195063523
+ -1.23039263767
+ -1.22883464012
+ -1.22727664256
+ -1.225718645
+ -1.22416064744
+ -1.22260264988
+ -1.22104465233
+ -1.21948665477
+ -1.21792865721
+ -1.21637065965
+ -1.21481266209
+ -1.21325466454
+ -1.21169666698
+ -1.21013866942
+ -1.20858067186
+ -1.2070226743
+ -1.20546467675
+ -1.20390667919
+ -1.20234868163
+ -1.20079068407
+ -1.19923268651
+ -1.19767468896
+ -1.1961166914
+ -1.19455869384
+ -1.19300069628
+ -1.19144269872
+ -1.18988470117
+ -1.18832670361
+ -1.18676870605
+ -1.18521070849
+ -1.18365271093
+ -1.18209471338
+ -1.18053671582
+ -1.17897871826
+ -1.1774207207
+ -1.17586272314
+ -1.17430472559
+ -1.17274672803
+ -1.17118873047
+ -1.16963073291
+ -1.16807273535
+ -1.1665147378
+ -1.16495674024
+ -1.16339874268
+ -1.16184074512
+ -1.16028274756
+ -1.15872475001
+ -1.15716675245
+ -1.15560875489
+ -1.15405075733
+ -1.15249275977
+ -1.15093476222
+ -1.14937676466
+ -1.1478187671
+ -1.14626076954
+ -1.14470277198
+ -1.14314477443
+ -1.14158677687
+ -1.14002877931
+ -1.13847078175
+ -1.13691278419
+ -1.13535478664
+ -1.13379678908
+ -1.13223879152
+ -1.13068079396
+ -1.1291227964
+ -1.12756479885
+ -1.12600680129
+ -1.12444880373
+ -1.12289080617
+ -1.12134212084
+ -1.1198217258
+ -1.11830133076
+ -1.11678093572
+ -1.11526054068
+ -1.11374014564
+ -1.1122197506
+ -1.11069935556
+ -1.10917896052
+ -1.10765856548
+ -1.10613817044
+ -1.1046177754
+ -1.10309738036
+ -1.10157698532
+ -1.10005659028
+ -1.09853619524
+ -1.0970158002
+ -1.09549540516
+ -1.09397501012
+ -1.09245461508
+ -1.09093422004
+ -1.089413825
+ -1.08789342996
+ -1.08637303492
+ -1.08485263988
+ -1.08333224484
+ -1.0818118498
+ -1.08029145476
+ -1.07877105972
+ -1.07725066468
+ -1.07573026964
+ -1.0742098746
+ -1.07268947956
+ -1.07116908452
+ -1.06964868948
+ -1.06812829444
+ -1.0666078994
+ -1.06508750436
+ -1.06356710932
+ -1.06204671428
+ -1.06052631924
+ -1.0590059242
+ -1.05748552916
+ -1.05596513412
+ -1.05444473908
+ -1.05292434404
+ -1.051403949
+ -1.04988355396
+ -1.04836315892
+ -1.04684276388
+ -1.04532236884
+ -1.0438019738
+ -1.04228157876
+ -1.04076118372
+ -1.03924078868
+ -1.03772039364
+ -1.0361999986
+ -1.03467960356
+ -1.03315920852
+ -1.03163881348
+ -1.03011841844
+ -1.0285980234
+ -1.02707762836
+ -1.02555723332
+ -1.02403683828
+ -1.02251644324
+ -1.0209960482
+ -1.01947565316
+ -1.01795525812
+ -1.01643486309
+ -1.01491446805
+ -1.01339407301
+ -1.01187367797
+ -1.01035328293
+ -1.00883288789
+ -1.00731249285
+ -1.00579209781
+ -1.00427170277
+ -1.00275130773
+ -1.00123091269
+ -0.999710517646
+ -0.998190122606
+ -0.996669727567
+ -0.995149332527
+ -0.993628937487
+ -0.992108542447
+ -0.990588147407
+ -0.989067752367
+ -0.987547357327
+ -0.986026962287
+ -0.984506567248
+ -0.982986172208
+ -0.981465777168
+ -0.979945382128
+ -0.978424987088
+ -0.976904592048
+ -0.975384197008
+ -0.973863801968
+ -0.972343406929
+ -0.970823011889
+ -0.969302616849
+ -0.967782221809
+ -0.966261826769
+ -0.964741431729
+ -0.963221036689
+ -0.961700641649
+ -0.96018024661
+ -0.95865985157
+ -0.95713945653
+ -0.95561906149
+ -0.95409866645
+ -0.95257827141
+ -0.95105787637
+ -0.94953748133
+ -0.948017086291
+ -0.946496691251
+ -0.944976296211
+ -0.943455901171
+ -0.941935506131
+ -0.940415111091
+ -0.938894716051
+ -0.937374321011
+ -0.935853925972
+ -0.934333530932
+ -0.932813135892
+ -0.931292740852
+ -0.929772345812
+ -0.928251950772
+ -0.926731555732
+ -0.925302475472
+ -0.923886114055
+ -0.922469752639
+ -0.921053391223
+ -0.919637029806
+ -0.91822066839
+ -0.916804306974
+ -0.915387945557
+ -0.913971584141
+ -0.912555222724
+ -0.911138861308
+ -0.909722499892
+ -0.908306138475
+ -0.906889777059
+ -0.905473415643
+ -0.904057054226
+ -0.90264069281
+ -0.901224331394
+ -0.899807969977
+ -0.898391608561
+ -0.896975247144
+ -0.895558885728
+ -0.894142524312
+ -0.892726162895
+ -0.891309801479
+ -0.889893440063
+ -0.888477078646
+ -0.88706071723
+ -0.885644355814
+ -0.884227994397
+ -0.882811632981
+ -0.881395271564
+ -0.879978910148
+ -0.878562548732
+ -0.877146187315
+ -0.875729825899
+ -0.874313464483
+ -0.872897103066
+ -0.87148074165
+ -0.870064380234
+ -0.868648018817
+ -0.867231657401
+ -0.865815295984
+ -0.864398934568
+ -0.862982573152
+ -0.861566211735
+ -0.860149850319
+ -0.858733488903
+ -0.857317127486
+ -0.85590076607
+ -0.854484404654
+ -0.853068043237
+ -0.851651681821
+ -0.850235320405
+ -0.848818958988
+ -0.847402597572
+ -0.845986236155
+ -0.844569874739
+ -0.843153513323
+ -0.841737151906
+ -0.84032079049
+ -0.838904429074
+ -0.837488067657
+ -0.836071706241
+ -0.834655344825
+ -0.833238983408
+ -0.831822621992
+ -0.830406260575
+ -0.828989899159
+ -0.827573537743
+ -0.826157176326
+ -0.82474081491
+ -0.823324453494
+ -0.821908092077
+ -0.820491730661
+ -0.819075369245
+ -0.817659007828
+ -0.816242646412
+ -0.814826284995
+ -0.813409923579
+ -0.811993562163
+ -0.810577200746
+ -0.80916083933
+ -0.807744477914
+ -0.806328116497
+ -0.804911755081
+ -0.803495393665
+ -0.802079032248
+ -0.800662670832
+ -0.799246309416
+ -0.797829947999
+ -0.796413586583
+ -0.794997225166
+ -0.79358086375
+ -0.792164502334
+ -0.790748140917
+ -0.789331779501
+ -0.787915418085
+ -0.786499056668
+ -0.785082695252
+ -0.783666333836
+ -0.782249972419
+ -0.780833611003
+ -0.779417249586
+ -0.77800088817
+ -0.776584526754
+ -0.775168165337
+ -0.773751803921
+ -0.772335442505
+ -0.770919081088
+ -0.769502719672
+ -0.768086358256
+ -0.766669996839
+ -0.765253635423
+ -0.763837274006
+ -0.76242091259
+ -0.761004551174
+ -0.759588189757
+ -0.758171828341
+ -0.756755466925
+ -0.755339105508
+ -0.753922744092
+ -0.752506382676
+ -0.751090021259
+ -0.749673659843
+ -0.748257298426
+ -0.74684093701
+ -0.745424575594
+ -0.744008214177
+ -0.742591852761
+ -0.741175491345
+ -0.739759129928
+ -0.738342768512
+ -0.736926407096
+ -0.735510045679
+ -0.734093684263
+ -0.732677322847
+ -0.73126096143
+ -0.729844600014
+ -0.728428238597
+ -0.727011877181
+ -0.725595515765
+ -0.724179154348
+ -0.722762792932
+ -0.721346431516
+ -0.719930070099
+ -0.718513708683
+ -0.717097347267
+ -0.71568098585
+ -0.714264624434
+ -0.712848263017
+ -0.711431901601
+ -0.710015540185
+ -0.708599178768
+ -0.707182817352
+ -0.705766455936
+ -0.704350094519
+ -0.702933733103
+ -0.701517371687
+ -0.70010101027
+ -0.698684648854
+ -0.697268287437
+ -0.695851926021
+ -0.694435564605
+ -0.693019203188
+ -0.691602841772
+ -0.690186480356
+ -0.688770118939
+ -0.687353757523
+ -0.685937396107
+ -0.68452103469
+ -0.683104673274
+ -0.681688311858
+ -0.680271950441
+ -0.678855589025
+ -0.677439227608
+ -0.676022866192
+ -0.674606504776
+ -0.673190143359
+ -0.671773781943
+ -0.670357420527
+ -0.66894105911
+ -0.667524697694
+ -0.666108336278
+ -0.664691974861
+ -0.663275613445
+ -0.661859252028
+ -0.660442890612
+ -0.659026529196
+ -0.657610167779
+ -0.656193806363
+ -0.654777444947
+ -0.65336108353
+ -0.651944722114
+ -0.650528360698
+ -0.649111999281
+ -0.647695637865
+ -0.646279276448
+ -0.644862915032
+ -0.643446553616
+ -0.642030192199
+ -0.640613830783
+ -0.639197469367
+ -0.63778110795
+ -0.636364746534
+ -0.634948385118
+ -0.633532023701
+ -0.632115662285
+ -0.630699300868
+ -0.629282939452
+ -0.627866578036
+ -0.626450216619
+ -0.625033855203
+ -0.623617493787
+ -0.62220113237
+ -0.620784770954
+ -0.619368409538
+ -0.617952048121
+ -0.616535686705
+ -0.615119325289
+ -0.613702963872
+ -0.612286602456
+ -0.610870241039
+ -0.609453879623
+ -0.608037518207
+ -0.60662115679
+ -0.605204795374
+ -0.603788433958
+ -0.602372072541
+ -0.600955711125
+ -0.599539349709
+ -0.598122988292
+ -0.596706626876
+ -0.595290265459
+ -0.593873904043
+ -0.592457542627
+ -0.59104118121
+ -0.589624819794
+ -0.588208458378
+ -0.586792096961
+ -0.585375735545
+ -0.583959374129
+ -0.582543012712
+ -0.581126651296
+ -0.579710289879
+ -0.578293928463
+ -0.576877567047
+ -0.57546120563
+ -0.574044844214
+ -0.572628482798
+ -0.571212121381
+ -0.569795759965
+ -0.568379398549
+ -0.566963037132
+ -0.565546675716
+ -0.5641303143
+ -0.562713952883
+ -0.561297591467
+ -0.55988123005
+ -0.558464868634
+ -0.557048507218
+ -0.555632145801
+ -0.554215784385
+ -0.552799422969
+ -0.551383061552
+ -0.549966700136
+ -0.54855033872
+ -0.547133977303
+ -0.545717615887
+ -0.54430125447
+ -0.542884893054
+ -0.541468531638
+ -0.540052170221
+ -0.538635808805
+ -0.537219447389
+ -0.535803085972
+ -0.534386724556
+ -0.53297036314
+ -0.531554001723
+ -0.530137640307
+ -0.52872127889
+ -0.527304917474
+ -0.525888556058
+ -0.524472194641
+ -0.523055833225
+ -0.521639471809
+ -0.520223110392
+ -0.518806748976
+ -0.51739038756
+ -0.515974026143
+ -0.514557664727
+ -0.513141303311
+ -0.511724941894
+ -0.510308580478
+ -0.508892219061
+ -0.507475857645
+ -0.506059496229
+ -0.504643134812
+ -0.503226773396
+ -0.50181041198
+ -0.500394050563
+ -0.498977689147
+ -0.497561327731
+ -0.496144966314
+ -0.494728604898
+ -0.493312243481
+ -0.491895882065
+ -0.490479520649
+ -0.489063159232
+ -0.487646797816
+ -0.4862304364
+ -0.484814074983
+ -0.483397713567
+ -0.481981352151
+ -0.480564990734
+ -0.479148629318
+ -0.477732267901
+ -0.476315906485
+ -0.474899545069
+ -0.473483183652
+ -0.472066822236
+ -0.47065046082
+ -0.469234099403
+ -0.467817737987
+ -0.466401376571
+ -0.464985015154
+ -0.463568653738
+ -0.462152292321
+ -0.460735930905
+ -0.459319569489
+ -0.457903208072
+ -0.456486846656
+ -0.45507048524
+ -0.453654123823
+ -0.452237762407
+ -0.450821400991
+ -0.449405039574
+ -0.447988678158
+ -0.446572316742
+ -0.445155955325
+ -0.443739593909
+ -0.442323232492
+ -0.440906871076
+ -0.43949050966
+ -0.438074148243
+ -0.436657786827
+ -0.435241425411
+ -0.433825063994
+ -0.432408702578
+ -0.430992341162
+ -0.429575979745
+ -0.428159618329
+ -0.426743256912
+ -0.425326895496
+ -0.42391053408
+ -0.422494172663
+ -0.421077811247
+ -0.419661449831
+ -0.418245088414
+ -0.416828726998
+ -0.415412365582
+ -0.413996004165
+ -0.412579642749
+ -0.411163281332
+ -0.409746919916
+ -0.4083305585
+ -0.406914197083
+ -0.405497835667
+ -0.404081474251
+ -0.402665112834
+ -0.401248751418
+ -0.399832390002
+ -0.398416028585
+ -0.396999667169
+ -0.395583305753
+ -0.394166944336
+ -0.39275058292
+ -0.391334221503
+ -0.389917860087
+ -0.388501498671
+ -0.387085137254
+ -0.385668775838
+ -0.384252414422
+ -0.382836053005
+ -0.381419691589
+ -0.380003330173
+ -0.378586968756
+ -0.37717060734
+ -0.375754245923
+ -0.374337884507
+ -0.372921523091
+ -0.371505161674
+ -0.370088800258
+ -0.368672438842
+ -0.367256077425
+ -0.365839716009
+ -0.364423354593
+ -0.363006993176
+ -0.36159063176
+ -0.360174270343
+ -0.358757908927
+ -0.357341547511
+ -0.355925186094
+ -0.354508824678
+ -0.353092463262
+ -0.351676101845
+ -0.350259740429
+ -0.348843379013
+ -0.347427017596
+ -0.34601065618
+ -0.344594294763
+ -0.343177933347
+ -0.341761571931
+ -0.340345210514
+ -0.338928849098
+ -0.337512487682
+ -0.336096126265
+ -0.334679764849
+ -0.333263403433
+ -0.331847042016
+ -0.3304306806
+ -0.329014319184
+ -0.327597957767
+ -0.326181596351
+ -0.324765234934
+ -0.323348873518
+ -0.321932512102
+ -0.320516150685
+ -0.319099789269
+ -0.317683427853
+ -0.316267066436
+ -0.31485070502
+ -0.313434343604
+ -0.312017982187
+ -0.310601620771
+ -0.309185259354
+ -0.307768897938
+ -0.306352536522
+ -0.304936175105
+ -0.303519813689
+ -0.302103452273
+ -0.300687090856
+ -0.29927072944
+ -0.297854368024
+ -0.296438006607
+ -0.295021645191
+ -0.293605283774
+ -0.292188922358
+ -0.290772560942
+ -0.289356199525
+ -0.287939838109
+ -0.286523476693
+ -0.285107115276
+ -0.28369075386
+ -0.282274392444
+ -0.280858031027
+ -0.279441669611
+ -0.278025308195
+ -0.276608946778
+ -0.275192585362
+ -0.273776223945
+ -0.272359862529
+ -0.270943501113
+ -0.269527139696
+ -0.26811077828
+ -0.266694416864
+ -0.265278055447
+ -0.263861694031
+ -0.262445332615
+ -0.261028971198
+ -0.259612609782
+ -0.258196248365
+ -0.256779886949
+ -0.255363525533
+ -0.253947164116
+ -0.2525308027
+ -0.251114441284
+ -0.249698079867
+ -0.248281718451
+ -0.246865357035
+ -0.245448995618
+ -0.244032634202
+ -0.242616272785
+ -0.241199911369
+ -0.239783549953
+ -0.238367188536
+ -0.23695082712
+ -0.235534465704
+ -0.234118104287
+ -0.232701742871
+ -0.231285381455
+ -0.229869020038
+ -0.228452658622
+ -0.227036297205
+ -0.225619935789
+ -0.224203574373
+ -0.222787212956
+ -0.22137085154
+ -0.219954490124
+ -0.218538128707
+ -0.217121767291
+ -0.215705405875
+ -0.214289044458
+ -0.212872683042
+ -0.211456321626
+ -0.210039960209
+ -0.208623598793
+ -0.207207237376
+ -0.20579087596
+ -0.204374514544
+ -0.202958153127
+ -0.201541791711
+ -0.200125430295
+ -0.198709068878
+ -0.197292707462
+ -0.195876346046
+ -0.194459984629
+ -0.193043623213
+ -0.191627261796
+ -0.19021090038
+ -0.188794538964
+ -0.187378177547
+ -0.185961816131
+ -0.184545454715
+ -0.183129093298
+ -0.181712731882
+ -0.180296370466
+ -0.178880009049
+ -0.177463647633
+ -0.176047286216
+ -0.1746309248
+ -0.173214563384
+ -0.171798201967
+ -0.170381840551
+ -0.168965479135
+ -0.167549117718
+ -0.166132756302
+ -0.164716394886
+ -0.163300033469
+ -0.161883672053
+ -0.160467310637
+ -0.15905094922
+ -0.157634587804
+ -0.156218226387
+ -0.154801864971
+ -0.153385503555
+ -0.151969142138
+ -0.150552780722
+ -0.149136419306
+ -0.147720057889
+ -0.146303696473
+ -0.144887335057
+ -0.14347097364
+ -0.142054612224
+ -0.140638250807
+ -0.139221889391
+ -0.137805527975
+ -0.136389166558
+ -0.134972805142
+ -0.133556443726
+ -0.132140082309
+ -0.130723720893
+ -0.129307359477
+ -0.12789099806
+ -0.126474636644
+ -0.125058275227
+ -0.123641913811
+ -0.122225552395
+ -0.120809190978
+ -0.119392829562
+ -0.117976468146
+ -0.116560106729
+ -0.115143745313
+ -0.113727383897
+ -0.11231102248
+ -0.110894661064
+ -0.109478299647
+ -0.108061938231
+ -0.106645576815
+ -0.105229215398
+ -0.103812853982
+ -0.102396492566
+ -0.100980131149
+ -0.099563769733
+ -0.0981474083166
+ -0.0967310469002
+ -0.0953146854839
+ -0.0938983240675
+ -0.0924819626512
+ -0.0910656012348
+ -0.0896492398184
+ -0.0882328784021
+ -0.0868165169857
+ -0.0854001555694
+ -0.083983794153
+ -0.0825674327366
+ -0.0811510713203
+ -0.0797347099039
+ -0.0783183484875
+ -0.0769019870712
+ -0.0754856256548
+ -0.0740692642385
+ -0.0726529028221
+ -0.0712365414057
+ -0.0698201799894
+ -0.068403818573
+ -0.0669874571567
+ -0.0655710957403
+ -0.0641547343239
+ -0.0627383729076
+ -0.0613220114912
+ -0.0599056500748
+ -0.0584892886585
+ -0.0570729272421
+ -0.0556565658258
+ -0.0542402044094
+ -0.052823842993
+ -0.0514074815767
+ -0.0499911201603
+ -0.048574758744
+ -0.0471583973276
+ -0.0457420359112
+ -0.0443256744949
+ -0.0429093130785
+ -0.0414929516622
+ -0.0400765902458
+ -0.0386602288294
+ -0.0372438674131
+ -0.0358275059967
+ -0.0344111445803
+ -0.032994783164
+ -0.0315784217476
+ -0.0301620603313
+ -0.0287456989149
+ -0.0273293374985
+ -0.0259129760822
+ -0.0244966146658
+ -0.0230802532495
+ -0.0216638918331
+ -0.0202475304167
+ -0.0188311690004
+ -0.017414807584
+ -0.0159984461676
+ -0.0145820847513
+ -0.0131657233349
+ -0.0117493619186
+ -0.0103330005022
+ -0.00891663908584
+ -0.00750027766948
+ -0.00608391625311
+ -0.00466755483675
+ -0.00325119342039
+ -0.00183483200403
+ -0.00041847058767
+ 0.000997890828692
+ 0.00241425224505
+ 0.00383061366141
+ 0.00524697507778
+ 0.00666333649414
+ 0.0080796979105
+ 0.00949605932686
+ 0.0109124207432
+ 0.0123287821596
+ 0.0137451435759
+ 0.0151615049923
+ 0.0165778664087
+ 0.017994227825
+ 0.0194105892414
+ 0.0208269506578
+ 0.0222433120741
+ 0.0236596734905
+ 0.0250760349068
+ 0.0264923963232
+ 0.0279087577396
+ 0.0293251191559
+ 0.0307414805723
+ 0.0321578419886
+ 0.033574203405
+ 0.0349905648214
+ 0.0364069262377
+ 0.0378232876541
+ 0.0392396490705
+ 0.0406560104868
+ 0.0420723719032
+ 0.0434887333195
+ 0.0449050947359
+ 0.0463214561523
+ 0.0477378175686
+ 0.049154178985
+ 0.0505705404013
+ 0.0519869018177
+ 0.0534032632341
+ 0.0548196246504
+ 0.0562359860668
+ 0.0576523474831
+ 0.0590687088995
+ 0.0604850703159
+ 0.0619014317322
+ 0.0633177931486
+ 0.064734154565
+ 0.0661505159813
+ 0.0675668773977
+ 0.068983238814
+ 0.0703996002304
+ 0.0718159616468
+ 0.0732323230631
+ 0.0746486844795
+ 0.0760650458958
+ 0.0774814073122
+ 0.0788977687286
+ 0.0803141301449
+ 0.0817304915613
+ 0.0831468529777
+ 0.084563214394
+ 0.0859795758104
+ 0.0873959372267
+ 0.0888122986431
+ 0.0902286600595
+ 0.0916450214758
+ 0.0930613828922
+ 0.0944777443085
+ 0.0958941057249
+ 0.0973104671413
+ 0.0987268285576
+ 0.100143189974
+ 0.10155955139
+ 0.102975912807
+ 0.104392274223
+ 0.105808635639
+ 0.107224997056
+ 0.108641358472
+ 0.110057719889
+ 0.111474081305
+ 0.112890442721
+ 0.114306804138
+ 0.115723165554
+ 0.11713952697
+ 0.118555888387
+ 0.119972249803
+ 0.121388611219
+ 0.122804972636
+ 0.124221334052
+ 0.125637695468
+ 0.127054056885
+ 0.128470418301
+ 0.129886779718
+ 0.131303141134
+ 0.13271950255
+ 0.134135863967
+ 0.135552225383
+ 0.136968586799
+ 0.138384948216
+ 0.139801309632
+ 0.141217671048
+ 0.142634032465
+ 0.144050393881
+ 0.145466755298
+ 0.146883116714
+ 0.14829947813
+ 0.149715839547
+ 0.151132200963
+ 0.152548562379
+ 0.153964923796
+ 0.155381285212
+ 0.156797646628
+ 0.158214008045
+ 0.159630369461
+ 0.161046730878
+ 0.162463092294
+ 0.16387945371
+ 0.165295815127
+ 0.166712176543
+ 0.168128537959
+ 0.169544899376
+ 0.170961260792
+ 0.172377622208
+ 0.173793983625
+ 0.175210345041
+ 0.176626706458
+ 0.178043067874
+ 0.17945942929
+ 0.180875790707
+ 0.182292152123
+ 0.183708513539
+ 0.185124874956
+ 0.186541236372
+ 0.187957597788
+ 0.189373959205
+ 0.190790320621
+ 0.192206682037
+ 0.193623043454
+ 0.19503940487
+ 0.196455766287
+ 0.197872127703
+ 0.199288489119
+ 0.200704850536
+ 0.202121211952
+ 0.203537573368
+ 0.204953934785
+ 0.206370296201
+ 0.207786657617
+ 0.209203019034
+ 0.21061938045
+ 0.212035741867
+ 0.213452103283
+ 0.214868464699
+ 0.216284826116
+ 0.217701187532
+ 0.219117548948
+ 0.220533910365
+ 0.221950271781
+ 0.223366633197
+ 0.224782994614
+ 0.22619935603
+ 0.227615717447
+ 0.229032078863
+ 0.230448440279
+ 0.231864801696
+ 0.233281163112
+ 0.234697524528
+ 0.236113885945
+ 0.237530247361
+ 0.238946608777
+ 0.240362970194
+ 0.24177933161
+ 0.243195693026
+ 0.244612054443
+ 0.246028415859
+ 0.247444777276
+ 0.248861138692
+ 0.250277500108
+ 0.251693861525
+ 0.253110222941
+ 0.254526584357
+ 0.255942945774
+ 0.25735930719
+ 0.258775668606
+ 0.260192030023
+ 0.261608391439
+ 0.263024752856
+ 0.264441114272
+ 0.265857475688
+ 0.267273837105
+ 0.268690198521
+ 0.270106559937
+ 0.271522921354
+ 0.27293928277
+ 0.274355644186
+ 0.275772005603
+ 0.277188367019
+ 0.278604728436
+ 0.280021089852
+ 0.281437451268
+ 0.282853812685
+ 0.284270174101
+ 0.285686535517
+ 0.287102896934
+ 0.28851925835
+ 0.289935619766
+ 0.291351981183
+ 0.292768342599
+ 0.294184704016
+ 0.295601065432
+ 0.297017426848
+ 0.298433788265
+ 0.299850149681
+ 0.301266511097
+ 0.302682872514
+ 0.30409923393
+ 0.305515595346
+ 0.306931956763
+ 0.308348318179
+ 0.309764679595
+ 0.311181041012
+ 0.312597402428
+ 0.314013763845
+ 0.315430125261
+ 0.316846486677
+ 0.318262848094
+ 0.31967920951
+ 0.321095570926
+ 0.322511932343
+ 0.323928293759
+ 0.325344655175
+ 0.326761016592
+ 0.328177378008
+ 0.329593739425
+ 0.331010100841
+ 0.332426462257
+ 0.333842823674
+ 0.33525918509
+ 0.336675546506
+ 0.338091907923
+ 0.339508269339
+ 0.340924630755
+ 0.342340992172
+ 0.343757353588
+ 0.345173715005
+ 0.346590076421
+ 0.348006437837
+ 0.349422799254
+ 0.35083916067
+ 0.352255522086
+ 0.353671883503
+ 0.355088244919
+ 0.356504606335
+ 0.357920967752
+ 0.359337329168
+ 0.360753690584
+ 0.362170052001
+ 0.363586413417
+ 0.365002774834
+ 0.36641913625
+ 0.367835497666
+ 0.369251859083
+ 0.370668220499
+ 0.372084581915
+ 0.373500943332
+ 0.374917304748
+ 0.376333666164
+ 0.377750027581
+ 0.379166388997
+ 0.380582750414
+ 0.38199911183
+ 0.383415473246
+ 0.384831834663
+ 0.386248196079
+ 0.387664557495
+ 0.389080918912
+ 0.390497280328
+ 0.391913641744
+ 0.393330003161
+ 0.394746364577
+ 0.396162725994
+ 0.39757908741
+ 0.398995448826
+ 0.400411810243
+ 0.401828171659
+ 0.403244533075
+ 0.404660894492
+ 0.406077255908
+ 0.407493617324
+ 0.408909978741
+ 0.410326340157
+ 0.411742701574
+ 0.41315906299
+ 0.414575424406
+ 0.415991785823
+ 0.417408147239
+ 0.418824508655
+ 0.420240870072
+ 0.421657231488
+ 0.423073592904
+ 0.424489954321
+ 0.425906315737
+ 0.427322677153
+ 0.42873903857
+ 0.430155399986
+ 0.431571761403
+ 0.432988122819
+ 0.434404484235
+ 0.435820845652
+ 0.437237207068
+ 0.438653568484
+ 0.440069929901
+ 0.441486291317
+ 0.442902652733
+ 0.44431901415
+ 0.445735375566
+ 0.447151736983
+ 0.448568098399
+ 0.449984459815
+ 0.451400821232
+ 0.452817182648
+ 0.454233544064
+ 0.455649905481
+ 0.457066266897
+ 0.458482628313
+ 0.45989898973
+ 0.461315351146
+ 0.462731712563
+ 0.464148073979
+ 0.465564435395
+ 0.466980796812
+ 0.468397158228
+ 0.469813519644
+ 0.471229881061
+ 0.472646242477
+ 0.474062603893
+ 0.47547896531
+ 0.476895326726
+ 0.478311688142
+ 0.479728049559
+ 0.481144410975
+ 0.482560772392
+ 0.483977133808
+ 0.485393495224
+ 0.486809856641
+ 0.488226218057
+ 0.489642579473
+ 0.49105894089
+ 0.492475302306
+ 0.493891663722
+ 0.495308025139
+ 0.496724386555
+ 0.498140747972
+ 0.499557109388
+ 0.500973470804
+ 0.502389832221
+ 0.503806193637
+ 0.505222555053
+ 0.50663891647
+ 0.508055277886
+ 0.509471639302
+ 0.510888000719
+ 0.512304362135
+ 0.513720723552
+ 0.515137084968
+ 0.516553446384
+ 0.517969807801
+ 0.519386169217
+ 0.520802530633
+ 0.52221889205
+ 0.523635253466
+ 0.525051614882
+ 0.526467976299
+ 0.527884337715
+ 0.529300699132
+ 0.530717060548
+ 0.532133421964
+ 0.533549783381
+ 0.534966144797
+ 0.536382506213
+ 0.53779886763
+ 0.539215229046
+ 0.540631590462
+ 0.542047951879
+ 0.543464313295
+ 0.544880674711
+ 0.546297036128
+ 0.547713397544
+ 0.549129758961
+ 0.550546120377
+ 0.551962481793
+ 0.55337884321
+ 0.554795204626
+ 0.556211566042
+ 0.557627927459
+ 0.559044288875
+ 0.560460650291
+ 0.561877011708
+ 0.563293373124
+ 0.564709734541
+ 0.566126095957
+ 0.567542457373
+ 0.56895881879
+ 0.570375180206
+ 0.571791541622
+ 0.573207903039
+ 0.574624264455
+ 0.576040625871
+ 0.577456987288
+ 0.578873348704
+ 0.580289710121
+ 0.581706071537
+ 0.583122432953
+ 0.58453879437
+ 0.585955155786
+ 0.587371517202
+ 0.588787878619
+ 0.590204240035
+ 0.591620601451
+ 0.593036962868
+ 0.594453324284
+ 0.5958696857
+ 0.597286047117
+ 0.598702408533
+ 0.60011876995
+ 0.601535131366
+ 0.602951492782
+ 0.604367854199
+ 0.605784215615
+ 0.607200577031
+ 0.608616938448
+ 0.610033299864
+ 0.61144966128
+ 0.612866022697
+ 0.614282384113
+ 0.61569874553
+ 0.617115106946
+ 0.618531468362
+ 0.619947829779
+ 0.621364191195
+ 0.622780552611
+ 0.624196914028
+ 0.625613275444
+ 0.62702963686
+ 0.628445998277
+ 0.629862359693
+ 0.63127872111
+ 0.632695082526
+ 0.634111443942
+ 0.635527805359
+ 0.636944166775
+ 0.638360528191
+ 0.639776889608
+ 0.641193251024
+ 0.64260961244
+ 0.644025973857
+ 0.645442335273
+ 0.646858696689
+ 0.648275058106
+ 0.649691419522
+ 0.651107780939
+ 0.652524142355
+ 0.653940503771
+ 0.655356865188
+ 0.656773226604
+ 0.65818958802
+ 0.659605949437
+ 0.661022310853
+ 0.662438672269
+ 0.663855033686
+ 0.665271395102
+ 0.666687756519
+ 0.668104117935
+ 0.669520479351
+ 0.670936840768
+ 0.672353202184
+ 0.6737695636
+ 0.675185925017
+ 0.676602286433
+ 0.678018647849
+ 0.679435009266
+ 0.680851370682
+ 0.682267732099
+ 0.683684093515
+ 0.685100454931
+ 0.686516816348
+ 0.687933177764
+ 0.68934953918
+ 0.690765900597
+ 0.692182262013
+ 0.693598623429
+ 0.695014984846
+ 0.696431346262
+ 0.697847707679
+ 0.699264069095
+ 0.700680430511
+ 0.702096791928
+ 0.703513153344
+ 0.70492951476
+ 0.706345876177
+ 0.707762237593
+ 0.709178599009
+ 0.710594960426
+ 0.712011321842
+ 0.713427683258
+ 0.714844044675
+ 0.716260406091
+ 0.717676767508
+ 0.719093128924
+ 0.72050949034
+ 0.721925851757
+ 0.723342213173
+ 0.724758574589
+ 0.726174936006
+ 0.727591297422
+ 0.729007658838
+ 0.730424020255
+ 0.731840381671
+ 0.733256743088
+ 0.734673104504
+ 0.73608946592
+ 0.737505827337
+ 0.738922188753
+ 0.740338550169
+ 0.741754911586
+ 0.743171273002
+ 0.744587634418
+ 0.746003995835
+ 0.747420357251
+ 0.748836718668
+ 0.750253080084
+ 0.7516694415
+ 0.753085802917
+ 0.754502164333
+ 0.755918525749
+ 0.757334887166
+ 0.758751248582
+ 0.760167609998
+ 0.761583971415
+ 0.763000332831
+ 0.764416694247
+ 0.765833055664
+ 0.76724941708
+ 0.768665778497
+ 0.770082139913
+ 0.771498501329
+ 0.772914862746
+ 0.774331224162
+ 0.775747585578
+ 0.777163946995
+ 0.778580308411
+ 0.779996669827
+ 0.781413031244
+ 0.78282939266
+ 0.784245754077
+ 0.785662115493
+ 0.787078476909
+ 0.788494838326
+ 0.789911199742
+ 0.791327561158
+ 0.792743922575
+ 0.794160283991
+ 0.795576645407
+ 0.796993006824
+ 0.79840936824
+ 0.799825729657
+ 0.801242091073
+ 0.802658452489
+ 0.804074813906
+ 0.805491175322
+ 0.806907536738
+ 0.808323898155
+ 0.809740259571
+ 0.811156620987
+ 0.812572982404
+ 0.81398934382
+ 0.815405705237
+ 0.816822066653
+ 0.818238428069
+ 0.819654789486
+ 0.821071150902
+ 0.822487512318
+ 0.823903873735
+ 0.825320235151
+ 0.826736596567
+ 0.828152957984
+ 0.8295693194
+ 0.830985680816
+ 0.832402042233
+ 0.833818403649
+ 0.835234765066
+ 0.836651126482
+ 0.838067487898
+ 0.839483849315
+ 0.840900210731
+ 0.842316572147
+ 0.843732933564
+ 0.84514929498
+ 0.846565656396
+ 0.847982017813
+ 0.849398379229
+ 0.850814740646
+ 0.852231102062
+ 0.853647463478
+ 0.855063824895
+ 0.856480186311
+ 0.857896547727
+ 0.859312909144
+ 0.86072927056
+ 0.862145631976
+ 0.863561993393
+ 0.864978354809
+ 0.866394716226
+ 0.867811077642
+ 0.869227439058
+ 0.870643800475
+ 0.872060161891
+ 0.873476523307
+ 0.874892884724
+ 0.87630924614
+ 0.877725607556
+ 0.879141968973
+ 0.880558330389
+ 0.881974691805
+ 0.883391053222
+ 0.884807414638
+ 0.886223776055
+ 0.887640137471
+ 0.889056498887
+ 0.890472860304
+ 0.89188922172
+ 0.893305583136
+ 0.894721944553
+ 0.896138305969
+ 0.897554667385
+ 0.898971028802
+ 0.900387390218
+ 0.901803751635
+ 0.903220113051
+ 0.904636474467
+ 0.906052835884
+ 0.9074691973
+ 0.908885558716
+ 0.910301920133
+ 0.911718281549
+ 0.913134642965
+ 0.914551004382
+ 0.915967365798
+ 0.917383727215
+ 0.918800088631
+ 0.920216450047
+ 0.921632811464
+ 0.92304917288
+ 0.924465534296
+ 0.925881895713
+ 0.927298257129
+ 0.928714618545
+ 0.930130979962
+ 0.931547341378
+ 0.932963702795
+ 0.934380064211
+ 0.935796425627
+ 0.937212787044
+ 0.93862914846
+ 0.940045509876
+ 0.941461871293
+ 0.942878232709
+ 0.944294594125
+ 0.945710955542
+ 0.947127316958
+ 0.948543678374
+ 0.949960039791
+ 0.951376401207
+ 0.952792762624
+ 0.95420912404
+ 0.955625485456
+ 0.957041846873
+ 0.958458208289
+ 0.959874569705
+ 0.961290931122
+ 0.962707292538
+ 0.964123653954
+ 0.965540015371
+ 0.966956376787
+ 0.968372738204
+ 0.96978909962
+ 0.971205461036
+ 0.972621822453
+ 0.974038183869
+ 0.975454545285
+ 0.976870906702
+ 0.978287268118
+ 0.979703629534
+ 0.981119990951
+ 0.982536352367
+ 0.983952713784
+ 0.9853690752
+ 0.986785436616
+ 0.988201798033
+ 0.989618159449
+ 0.991034520865
+ 0.992450882282
+ 0.993867243698
+ 0.995283605114
+ 0.996699966531
+ 0.998116327947
+ 0.999532689363
+ 1.00094905078
+ 1.0023654122
+ 1.00378177361
+ 1.00519813503
+ 1.00661449645
+ 1.00803085786
+ 1.00944721928
+ 1.01086358069
+ 1.01227994211
+ 1.01369630353
+ 1.01511266494
+ 1.01652902636
+ 1.01794538778
+ 1.01936174919
+ 1.02077811061
+ 1.02219447203
+ 1.02361083344
+ 1.02502719486
+ 1.02644355627
+ 1.02785991769
+ 1.02927627911
+ 1.03069264052
+ 1.03210900194
+ 1.03352536336
+ 1.03494172477
+ 1.03635808619
+ 1.03777444761
+ 1.03919080902
+ 1.04060717044
+ 1.04202353185
+ 1.04343989327
+ 1.04485625469
+ 1.0462726161
+ 1.04768897752
+ 1.04910533894
+ 1.05052170035
+ 1.05193806177
+ 1.05335442319
+ 1.0547707846
+ 1.05618714602
+ 1.05760350743
+ 1.05901986885
+ 1.06043623027
+ 1.06185259168
+ 1.0632689531
+ 1.06468531452
+ 1.06610167593
+ 1.06751803735
+ 1.06893439877
+ 1.07035076018
+ 1.0717671216
+ 1.07318348301
+ 1.07459984443
+ 1.07601620585
+ 1.07743256726
+ 1.07884892868
+ 1.0802652901
+ 1.08168165151
+ 1.08309801293
+ 1.08451437435
+ 1.08593073576
+ 1.08734709718
+ 1.08876345859
+ 1.09017982001
+ 1.09159618143
+ 1.09301254284
+ 1.09442890426
+ 1.09584526568
+ 1.09726162709
+ 1.09867798851
+ 1.10009434993
+ 1.10151071134
+ 1.10292707276
+ 1.10434343417
+ 1.10575979559
+ 1.10717615701
+ 1.10859251842
+ 1.11000887984
+ 1.11142524126
+ 1.11284160267
+ 1.11425796409
+ 1.11567432551
+ 1.11709068692
+ 1.11850704834
+ 1.11992340975
+ 1.12133977117
+ 1.12275613259
+ 1.124172494
+ 1.12558885542
+ 1.12700521684
+ 1.12842157825
+ 1.12983793967
+ 1.13125430109
+ 1.1326706625
+ 1.13408702392
+ 1.13550338533
+ 1.13691974675
+ 1.13833610817
+ 1.13975246958
+ 1.141168831
+ 1.14258519242
+ 1.14400155383
+ 1.14541791525
+ 1.14683427667
+ 1.14825063808
+ 1.1496669995
+ 1.15108336091
+ 1.15249972233
+ 1.15391608375
+ 1.15533244516
+ 1.15674880658
+ 1.158165168
+ 1.15958152941
+ 1.16099789083
+ 1.16241425225
+ 1.16383061366
+ 1.16524697508
+ 1.16666333649
+ 1.16807969791
+ 1.16949605933
+ 1.17091242074
+ 1.17232878216
+ 1.17374514358
+ 1.17516150499
+ 1.17657786641
+ 1.17799422783
+ 1.17941058924
+ 1.18082695066
+ 1.18224331207
+ 1.18365967349
+ 1.18507603491
+ 1.18649239632
+ 1.18790875774
+ 1.18932511916
+ 1.19074148057
+ 1.19215784199
+ 1.19357420341
+ 1.19499056482
+ 1.19640692624
+ 1.19782328765
+ 1.19923964907
+ 1.20065601049
+ 1.2020723719
+ 1.20348873332
+ 1.20490509474
+ 1.20632145615
+ 1.20773781757
+ 1.20915417898
+ 1.2105705404
+ 1.21198690182
+ 1.21340326323
+ 1.21481962465
+ 1.21623598607
+ 1.21765234748
+ 1.2190687089
+ 1.22048507032
+ 1.22190143173
+ 1.22331779315
+ 1.22473415456
+ 1.22615051598
+ 1.2275668774
+ 1.22898323881
+ 1.23039960023
+ 1.23181596165
+ 1.23323232306
+ 1.23464868448
+ 1.2360650459
+ 1.23748140731
+ 1.23889776873
+ 1.24031413014
+ 1.24173049156
+ 1.24314685298
+ 1.24456321439
+ 1.24597957581
+ 1.24739593723
+ 1.24881229864
+ 1.25022866006
+ 1.25164502148
+ 1.25306138289
+ 1.25447774431
+ 1.25589410572
+ 1.25731046714
+ 1.25872682856
+ 1.26014318997
+ 1.26155955139
+ 1.26297591281
+ 1.26439227422
+ 1.26580863564
+ 1.26722499706
+ 1.26864135847
+ 1.27005771989
+ 1.2714740813
+ 1.27289044272
+ 1.27430680414
+ 1.27572316555
+ 1.27713952697
+ 1.27855588839
+ 1.2799722498
+ 1.28138861122
+ 1.28280497264
+ 1.28422133405
+ 1.28563769547
+ 1.28705405688
+ 1.2884704183
+ 1.28988677972
+ 1.29130314113
+ 1.29271950255
+ 1.29413586397
+ 1.29555222538
+ 1.2969685868
+ 1.29838494822
+ 1.29980130963
+ 1.30121767105
+ 1.30263403246
+ 1.30405039388
+ 1.3054667553
+ 1.30688311671
+ 1.30829947813
+ 1.30971583955
+ 1.31113220096
+ 1.31254856238
+ 1.3139649238
+ 1.31538128521
+ 1.31679764663
+ 1.31821400804
+ 1.31963036946
+ 1.32104673088
+ 1.32246309229
+ 1.32387945371
+ 1.32529581513
+ 1.32671217654
+ 1.32812853796
+ 1.32954489938
+ 1.33096126079
+ 1.33237762221
+ 1.33379398362
+ 1.33521034504
+ 1.33662670646
+ 1.33804306787
+ 1.33945942929
+ 1.34087579071
+ 1.34229215212
+ 1.34370851354
+ 1.34512487496
+ 1.34654123637
+ 1.34795759779
+ 1.3493739592
+ 1.35079032062
+ 1.35220668204
+ 1.35362304345
+ 1.35503940487
+ 1.35645576629
+ 1.3578721277
+ 1.35928848912
+ 1.36070485054
+ 1.36212121195
+ 1.36353757337
+ 1.36495393478
+ 1.3663702962
+ 1.36778665762
+ 1.36920301903
+ 1.37061938045
+ 1.37203574187
+ 1.37345210328
+ 1.3748684647
+ 1.37628482612
+ 1.37770118753
+ 1.37911754895
+ 1.38053391036
+ 1.38195027178
+ 1.3833666332
+ 1.38478299461
+ 1.38619935603
+ 1.38761571745
+ 1.38903207886
+ 1.39044844028
+ 1.3918648017
+ 1.39328116311
+ 1.39469752453
+ 1.39611388594
+ 1.39753024736
+ 1.39894660878
+ 1.40036297019
+ 1.40177933161
+ 1.40319569303
+ 1.40461205444
+ 1.40602841586
+ 1.40744477728
+ 1.40886113869
+ 1.41027750011
+ 1.41169386152
+ 1.41311022294
+ 1.41452658436
+ 1.41594294577
+ 1.41735930719
+ 1.41877566861
+ 1.42019203002
+ 1.42160839144
+ 1.42302475286
+ 1.42444111427
+ 1.42585747569
+ 1.4272738371
+ 1.42869019852
+ 1.43010655994
+ 1.43152292135
+ 1.43293928277
+ 1.43435564419
+ 1.4357720056
+ 1.43718836702
+ 1.43860472844
+ 1.44002108985
+ 1.44143745127
+ 1.44285381268
+ 1.4442701741
+ 1.44568653552
+ 1.44710289693
+ 1.44851925835
+ 1.44993561977
+ 1.45135198118
+ 1.4527683426
+ 1.45418470402
+ 1.45560106543
+ 1.45701742685
+ 1.45843378826
+ 1.45985014968
+ 1.4612665111
+ 1.46268287251
+ 1.46409923393
+ 1.46551559535
+ 1.46693195676
+ 1.46834831818
+ 1.4697646796
+ 1.47118104101
+ 1.47259740243
+ 1.47401376384
+ 1.47543012526
+ 1.47684648668
+ 1.47826284809
+ 1.47967920951
+ 1.48109557093
+ 1.48251193234
+ 1.48392829376
+ 1.48534465518
+ 1.48676101659
+ 1.48817737801
+ 1.48959373942
+ 1.49101010084
+ 1.49242646226
+ 1.49384282367
+ 1.49525918509
+ 1.49667554651
+ 1.49809190792
+ 1.49950826934
+ 1.50092463076
+ 1.50234099217
+ 1.50375735359
+ 1.505173715
+ 1.50659007642
+ 1.50800643784
+ 1.50942279925
+ 1.51083916067
+ 1.51225552209
+ 1.5136718835
+ 1.51508824492
+ 1.51650460634
+ 1.51792096775
+ 1.51933732917
+ 1.52075369058
+ 1.522170052
+ 1.52358641342
+ 1.52500277483
+ 1.52641913625
+ 1.52783549767
+ 1.52925185908
+ 1.5306682205
+ 1.53208458192
+ 1.53350094333
+ 1.53491730475
+ 1.53633366616
+ 1.53775002758
+ 1.539166389
+ 1.54058275041
+ 1.54199911183
+ 1.54341547325
+ 1.54483183466
+ 1.54624819608
+ 1.5476645575
+ 1.54908091891
+ 1.55049728033
+ 1.55191364174
+ 1.55333000316
+ 1.55474636458
+ 1.55616272599
+ 1.55757908741
+ 1.55899544883
+ 1.56041181024
+ 1.56182817166
+ 1.56324453308
+ 1.56466089449
+ 1.56607725591
+ 1.56749361732
+ 1.56890997874
+ 1.57032634016
+ 1.57174270157
+ 1.57315906299
+ 1.57457542441
+ 1.57599178582
+ 1.57740814724
+ 1.57882450866
+ 1.58024087007
+ 1.58165723149
+ 1.5830735929
+ 1.58448995432
+ 1.58590631574
+ 1.58732267715
+ 1.58873903857
+ 1.59015539999
+ 1.5915717614
+ 1.59298812282
+ 1.59440448424
+ 1.59582084565
+ 1.59723720707
+ 1.59865356848
+ 1.6000699299
+ 1.60148629132
+ 1.60290265273
+ 1.60431901415
+ 1.60573537557
+ 1.60715173698
+ 1.6085680984
+ 1.60998445982
+ 1.61140082123
+ 1.61281718265
+ 1.61423354406
+ 1.61564990548
+ 1.6170662669
+ 1.61848262831
+ 1.61989898973
+ 1.62131535115
+ 1.62273171256
+ 1.62414807398
+ 1.6255644354
+ 1.62698079681
+ 1.62839715823
+ 1.62981351964
+ 1.63122988106
+ 1.63264624248
+ 1.63406260389
+ 1.63547896531
+ 1.63689532673
+ 1.63831168814
+ 1.63972804956
+ 1.64114441098
+ 1.64256077239
+ 1.64397713381
+ 1.64539349522
+ 1.64680985664
+ 1.64822621806
+ 1.64964257947
+ 1.65105894089
+ 1.65247530231
+ 1.65389166372
+ 1.65530802514
+ 1.65672438656
+ 1.65814074797
+ 1.65955710939
+ 1.6609734708
+ 1.66238983222
+ 1.66380619364
+ 1.66522255505
+ 1.66663891647
+ 1.66805527789
+ 1.6694716393
+ 1.67088800072
+ 1.67230436214
+ 1.67372072355
+ 1.67513708497
+ 1.67655344638
+ 1.6779698078
+ 1.67938616922
+ 1.68080253063
+ 1.68221889205
+ 1.68363525347
+ 1.68505161488
+ 1.6864679763
+ 1.68788433772
+ 1.68930069913
+ 1.69071706055
+ 1.69213342196
+ 1.69354978338
+ 1.6949661448
+ 1.69638250621
+ 1.69779886763
+ 1.69921522905
+ 1.70063159046
+ 1.70204795188
+ 1.7034643133
+ 1.70488067471
+ 1.70629703613
+ 1.70771339754
+ 1.70912975896
+ 1.71054612038
+ 1.71196248179
+ 1.71337884321
+ 1.71479520463
+ 1.71621156604
+ 1.71762792746
+ 1.71904428888
+ 1.72046065029
+ 1.72187701171
+ 1.72329337312
+ 1.72470973454
+ 1.72612609596
+ 1.72754245737
+ 1.72895881879
+ 1.73037518021
+ 1.73179154162
+ 1.73320790304
+ 1.73462426446
+ 1.73604062587
+ 1.73745698729
+ 1.7388733487
+ 1.74028971012
+ 1.74170607154
+ 1.74312243295
+ 1.74453879437
+ 1.74595515579
+ 1.7473715172
+ 1.74878787862
+ 1.75020424004
+ 1.75162060145
+ 1.75303696287
+ 1.75445332428
+ 1.7558696857
+ 1.75728604712
+ 1.75870240853
+ 1.76011876995
+ 1.76153513137
+ 1.76295149278
+ 1.7643678542
+ 1.76578421562
+ 1.76720057703
+ 1.76861693845
+ 1.77003329986
+ 1.77144966128
+ 1.7728660227
+ 1.77428238411
+ 1.77569874553
+ 1.77711510695
+ 1.77853146836
+ 1.77994782978
+ 1.78136419119
+ 1.78278055261
+ 1.78419691403
+ 1.78561327544
+ 1.78702963686
+ 1.78844599828
+ 1.78986235969
+ 1.79127872111
+ 1.79269508253
+ 1.79411144394
+ 1.79552780536
+ 1.79694416677
+ 1.79836052819
+ 1.79977688961
+ 1.80119325102
+ 1.80260961244
+ 1.80402597386
+ 1.80544233527
+ 1.80685869669
+ 1.80827505811
+ 1.80969141952
+ 1.81110778094
+ 1.81252414235
+ 1.81394050377
+ 1.81535686519
+ 1.8167732266
+ 1.81818958802
+ 1.81960594944
+ 1.82102231085
+ 1.82243867227
+ 1.82385503369
+ 1.8252713951
+ 1.82668775652
+ 1.82810411793
+ 1.82952047935
+ 1.83093684077
+ 1.83235320218
+ 1.8337695636
+ 1.83518592502
+ 1.83660228643
+ 1.83801864785
+ 1.83943500927
+ 1.84085137068
+ 1.8422677321
+ 1.84368409351
+ 1.84510045493
+ 1.84651681635
+ 1.84793317776
+ 1.84934953918
+ 1.8507659006
+ 1.85218226201
+ 1.85359862343
+ 1.85501498485
+ 1.85643134626
+ 1.85784770768
+ 1.85926406909
+ 1.86068043051
+ 1.86209679193
+ 1.86351315334
+ 1.86492951476
+ 1.86634587618
+ 1.86776223759
+ 1.86917859901
+ 1.87059496043
+ 1.87201132184
+ 1.87342768326
+ 1.87484404467
+ 1.87626040609
+ 1.87767676751
+ 1.87909312892
+ 1.88050949034
+ 1.88192585176
+ 1.88334221317
+ 1.88475857459
+ 1.88617493601
+ 1.88759129742
+ 1.88900765884
+ 1.89042402025
+ 1.89184038167
+ 1.89325674309
+ 1.8946731045
+ 1.89608946592
+ 1.89750582734
+ 1.89892218875
+ 1.90033855017
+ 1.90175491159
+ 1.903171273
+ 1.90458763442
+ 1.90600399583
+ 1.90742035725
+ 1.90883671867
+ 1.91025308008
+ 1.9116694415
+ 1.91308580292
+ 1.91450216433
+ 1.91591852575
+ 1.91733488717
+ 1.91875124858
+ 1.92016761
+ 1.92158397141
+ 1.92300033283
+ 1.92441669425
+ 1.92583305566
+ 1.92724941708
+ 1.9286657785
+ 1.93008213991
+ 1.93149850133
+ 1.93291486275
+ 1.93433122416
+ 1.93574758558
+ 1.93716394699
+ 1.93858030841
+ 1.93999666983
+ 1.94141303124
+ 1.94282939266
+ 1.94424575408
+ 1.94566211549
+ 1.94707847691
+ 1.94849483833
+ 1.94991119974
+ 1.95132756116
+ 1.95274392257
+ 1.95416028399
+ 1.95557664541
+ 1.95699300682
+ 1.95840936824
+ 1.95982572966
+ 1.96124209107
+ 1.96265845249
+ 1.96407481391
+ 1.96549117532
+