Merged changes in the trunk up to revision 54110.
Conflicts resolved: source/blender/blenfont/SConscript source/blender/blenkernel/intern/subsurf_ccg.c source/blender/makesdna/intern/makesdna.c source/blender/makesrna/intern/rna_scene.c
@@ -135,7 +135,6 @@ 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)
 | 
			
		||||
option(WITH_COMPOSITOR_LEGACY "Enable legacy compositor" OFF)
 | 
			
		||||
 | 
			
		||||
# GHOST Windowing Library Options
 | 
			
		||||
option(WITH_GHOST_DEBUG   "Enable debugging output for the GHOST library" OFF)
 | 
			
		||||
@@ -1330,6 +1329,11 @@ elseif(WIN32)
 | 
			
		||||
					optimized boost_locale-${BOOST_POSTFIX}
 | 
			
		||||
					debug boost_locale-${BOOST_DEBUG_POSTFIX}) 
 | 
			
		||||
			endif()
 | 
			
		||||
			if(WITH_CYCLES_OSL)
 | 
			
		||||
				set(BOOST_LIBRARIES ${BOOST_LIBRARIES}
 | 
			
		||||
					optimized boost_wave-${BOOST_POSTFIX}
 | 
			
		||||
					debug boost_wave-${BOOST_DEBUG_POSTFIX}) 
 | 
			
		||||
			endif()
 | 
			
		||||
			set(BOOST_LIBPATH ${BOOST}/lib)
 | 
			
		||||
			set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB -DBOOST_THREAD_USE_LIB ")
 | 
			
		||||
		endif()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								SConstruct
									
									
									
									
									
								
							
							
						
						@@ -575,6 +575,23 @@ data_to_c_simple("release/datafiles/brushicons/thumb.png")
 | 
			
		||||
data_to_c_simple("release/datafiles/brushicons/twist.png")
 | 
			
		||||
data_to_c_simple("release/datafiles/brushicons/vertexdraw.png")
 | 
			
		||||
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc01.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc02.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc03.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc04.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc05.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc06.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc07.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc08.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc09.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc10.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc11.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc12.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc13.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc14.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc15.jpg")
 | 
			
		||||
data_to_c_simple("release/datafiles/matcaps/mc16.jpg")
 | 
			
		||||
 | 
			
		||||
##### END DATAFILES ##########
 | 
			
		||||
 | 
			
		||||
Help(opts.GenerateHelpText(env))
 | 
			
		||||
 
 | 
			
		||||
@@ -28,8 +28,8 @@ c['slavePortnum'] = 9989
 | 
			
		||||
from buildbot.changes.svnpoller import SVNPoller
 | 
			
		||||
 | 
			
		||||
c['change_source'] = SVNPoller(
 | 
			
		||||
       'https://svn.blender.org/svnroot/bf-blender/trunk/',
 | 
			
		||||
       pollinterval=1200)
 | 
			
		||||
    'https://svn.blender.org/svnroot/bf-blender/trunk/',
 | 
			
		||||
    pollinterval=1200)
 | 
			
		||||
 | 
			
		||||
# BUILDERS
 | 
			
		||||
#
 | 
			
		||||
@@ -74,9 +74,11 @@ def svn_step(branch=''):
 | 
			
		||||
    else:
 | 
			
		||||
        return SVN(baseURL='https://svn.blender.org/svnroot/bf-blender/%%BRANCH%%/blender', mode='update', defaultBranch='trunk', workdir='blender')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def lib_svn_step(dir):
 | 
			
		||||
    return SVN(name='lib svn', baseURL='https://svn.blender.org/svnroot/bf-blender/%%BRANCH%%/lib/' + dir, mode='update', defaultBranch='trunk', workdir='lib/' + dir)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def rsync_step(id, branch, rsync_script):
 | 
			
		||||
    return ShellCommand(name='rsync', command=['python', rsync_script, id, branch], description='uploading', descriptionDone='uploaded', workdir='install')
 | 
			
		||||
 | 
			
		||||
@@ -155,9 +157,9 @@ for i in range(0, schedule_cycle):
 | 
			
		||||
 | 
			
		||||
    print(names)
 | 
			
		||||
    c['schedulers'].append(timed.Nightly(name='nightly' + str(i),
 | 
			
		||||
        builderNames=names,
 | 
			
		||||
        hour=3+i,
 | 
			
		||||
        minute=0))
 | 
			
		||||
                                         builderNames=names,
 | 
			
		||||
                                         hour=3 + i,
 | 
			
		||||
                                         minute=0))
 | 
			
		||||
 | 
			
		||||
# STATUS TARGETS
 | 
			
		||||
#
 | 
			
		||||
 
 | 
			
		||||
@@ -41,5 +41,3 @@ print(command)
 | 
			
		||||
 | 
			
		||||
ret = os.system(command)
 | 
			
		||||
sys.exit(ret)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ def main():
 | 
			
		||||
    check_commands = []
 | 
			
		||||
    for c, inc_dirs, defs in source_info:
 | 
			
		||||
        cmd = ([CHECKER_BIN] +
 | 
			
		||||
                CHECKER_ARGS +
 | 
			
		||||
               CHECKER_ARGS +
 | 
			
		||||
               [c] +
 | 
			
		||||
               [("-I%s" % i) for i in inc_dirs] +
 | 
			
		||||
               [("-D%s" % d) for d in defs]
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,7 @@ def main():
 | 
			
		||||
    check_commands = []
 | 
			
		||||
    for c, inc_dirs, defs in source_info:
 | 
			
		||||
        cmd = ([CHECKER_BIN] +
 | 
			
		||||
                CHECKER_ARGS +
 | 
			
		||||
               CHECKER_ARGS +
 | 
			
		||||
               [c] +
 | 
			
		||||
               [("-I%s" % i) for i in inc_dirs] +
 | 
			
		||||
               [("-D%s" % d) for d in defs]
 | 
			
		||||
 
 | 
			
		||||
@@ -41,6 +41,7 @@ import os
 | 
			
		||||
 | 
			
		||||
USE_QUIET = (os.environ.get("QUIET", None) is not None)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    source_info = project_source_info.build_info(use_cxx=False, ignore_prefix_list=CHECKER_IGNORE_PREFIX)
 | 
			
		||||
 | 
			
		||||
@@ -48,7 +49,7 @@ def main():
 | 
			
		||||
    for c, inc_dirs, defs in source_info:
 | 
			
		||||
 | 
			
		||||
        cmd = ([CHECKER_BIN] +
 | 
			
		||||
                CHECKER_ARGS +
 | 
			
		||||
               CHECKER_ARGS +
 | 
			
		||||
               [c] +
 | 
			
		||||
               [("-I%s" % i) for i in inc_dirs] +
 | 
			
		||||
               [("-D%s" % d) for d in defs]
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ def main():
 | 
			
		||||
    for c, inc_dirs, defs in source_info:
 | 
			
		||||
 | 
			
		||||
        cmd = ([CHECKER_BIN] +
 | 
			
		||||
                CHECKER_ARGS +
 | 
			
		||||
               CHECKER_ARGS +
 | 
			
		||||
               [c] +
 | 
			
		||||
               [("-I%s" % i) for i in inc_dirs] +
 | 
			
		||||
               [("-D%s" % d) for d in defs]
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ def main():
 | 
			
		||||
    check_commands = []
 | 
			
		||||
    for c, inc_dirs, defs in source_info:
 | 
			
		||||
        cmd = ([CHECKER_BIN] +
 | 
			
		||||
                CHECKER_ARGS +
 | 
			
		||||
               CHECKER_ARGS +
 | 
			
		||||
               [c] +
 | 
			
		||||
               [("-I%s" % i) for i in inc_dirs] +
 | 
			
		||||
               [("-D%s" % d) for d in defs]
 | 
			
		||||
 
 | 
			
		||||
@@ -141,7 +141,7 @@ def cmake_advanced_info():
 | 
			
		||||
        if sys.platform == "win32":
 | 
			
		||||
            cmd = 'cmake "%s" -G"Eclipse CDT4 - MinGW Makefiles"' % CMAKE_DIR
 | 
			
		||||
        else:
 | 
			
		||||
            if make_exe_basename.startswith("make"):
 | 
			
		||||
            if make_exe_basename.startswith(("make", "gmake")):
 | 
			
		||||
                cmd = 'cmake "%s" -G"Eclipse CDT4 - Unix Makefiles"' % CMAKE_DIR
 | 
			
		||||
            elif make_exe_basename.startswith("ninja"):
 | 
			
		||||
                cmd = 'cmake "%s" -G"Eclipse CDT4 - Ninja"' % CMAKE_DIR
 | 
			
		||||
@@ -151,7 +151,6 @@ def cmake_advanced_info():
 | 
			
		||||
        os.system(cmd)
 | 
			
		||||
        return join(CMAKE_DIR, ".cproject")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    includes = []
 | 
			
		||||
    defines = []
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -86,15 +86,15 @@ def makefile_log():
 | 
			
		||||
    make_exe = cmake_cache_var("CMAKE_MAKE_PROGRAM")
 | 
			
		||||
    make_exe_basename = os.path.basename(make_exe)
 | 
			
		||||
 | 
			
		||||
    if make_exe_basename.startswith("make"):
 | 
			
		||||
    if make_exe_basename.startswith(("make", "gmake")):
 | 
			
		||||
        print("running 'make' with --dry-run ...")
 | 
			
		||||
        process = subprocess.Popen([make_exe, "--always-make", "--dry-run", "--keep-going", "VERBOSE=1"],
 | 
			
		||||
                                    stdout=subprocess.PIPE,
 | 
			
		||||
                                   stdout=subprocess.PIPE,
 | 
			
		||||
                                   )
 | 
			
		||||
    elif make_exe_basename.startswith("ninja"):
 | 
			
		||||
        print("running 'ninja' with -t commands ...")
 | 
			
		||||
        process = subprocess.Popen([make_exe, "-t", "commands"],
 | 
			
		||||
                                    stdout=subprocess.PIPE,
 | 
			
		||||
                                   stdout=subprocess.PIPE,
 | 
			
		||||
                                   )
 | 
			
		||||
 | 
			
		||||
    while process.poll():
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,13 @@ def FindPython():
 | 
			
		||||
            abi_flags = cur_flags
 | 
			
		||||
            break
 | 
			
		||||
 | 
			
		||||
    # Find config.h. In some distros, such as ubuntu 12.10 they are not in standard include dir.
 | 
			
		||||
    incconf64 = os.path.join(include, "x86_64-linux-gnu", "python" + version + cur_flags, "pyconfig.h")
 | 
			
		||||
    if os.path.exists(incconf64):
 | 
			
		||||
        incconf = os.path.join(include, "x86_64-linux-gnu", "python" + version + cur_flags)
 | 
			
		||||
    else:
 | 
			
		||||
        incconf = ''
 | 
			
		||||
 | 
			
		||||
    # Determine whether python is in /usr/lib or /usr/lib64
 | 
			
		||||
    lib32 = os.path.join(python, "lib", "python" + version, "sysconfig.py")
 | 
			
		||||
    lib64 = os.path.join(python, "lib64", "python" + version, "sysconfig.py")
 | 
			
		||||
@@ -29,4 +36,5 @@ def FindPython():
 | 
			
		||||
    return {'PYTHON': python,
 | 
			
		||||
            "VERSION": version,
 | 
			
		||||
            'LIBPATH': libpath,
 | 
			
		||||
            'ABI_FLAGS': abi_flags}
 | 
			
		||||
            'ABI_FLAGS': abi_flags,
 | 
			
		||||
            'CONFIG': incconf}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,10 @@ py = FindPython()
 | 
			
		||||
BF_PYTHON_ABI_FLAGS = py['ABI_FLAGS']
 | 
			
		||||
BF_PYTHON = py['PYTHON']
 | 
			
		||||
BF_PYTHON_LIBPATH = py['LIBPATH']
 | 
			
		||||
BF_PYTHON_CONFIG = py['CONFIG']
 | 
			
		||||
BF_PYTHON_VERSION = py['VERSION']
 | 
			
		||||
WITH_BF_STATICPYTHON = False
 | 
			
		||||
BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}${BF_PYTHON_ABI_FLAGS}'
 | 
			
		||||
BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}${BF_PYTHON_ABI_FLAGS} ' + BF_PYTHON_CONFIG
 | 
			
		||||
BF_PYTHON_BINARY = '${BF_PYTHON}/bin/python${BF_PYTHON_VERSION}'
 | 
			
		||||
BF_PYTHON_LIB = 'python${BF_PYTHON_VERSION}${BF_PYTHON_ABI_FLAGS}'  # BF_PYTHON+'/lib/python'+BF_PYTHON_VERSION+'/config/libpython'+BF_PYTHON_VERSION+'.a'
 | 
			
		||||
BF_PYTHON_LINKFLAGS = ['-Xlinker', '-export-dynamic']
 | 
			
		||||
@@ -193,7 +194,7 @@ BF_OCIO_LIB = 'OpenColorIO yaml-cpp tinyxml'
 | 
			
		||||
BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/libOpenColorIO.a ${BF_OCIO_LIBPATH}/libtinyxml.a ${BF_OCIO_LIBPATH}/libyaml-cpp.a'
 | 
			
		||||
BF_OCIO_LIBPATH = '${BF_OCIO}/lib'
 | 
			
		||||
 | 
			
		||||
WITH_BF_BOOST = False
 | 
			
		||||
WITH_BF_BOOST = True
 | 
			
		||||
WITH_BF_STATICBOOST = False
 | 
			
		||||
BF_BOOST = '/usr'
 | 
			
		||||
BF_BOOST_INC = '${BF_BOOST}/include'
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ def validate_arguments(args, bc):
 | 
			
		||||
            'WITH_BF_STATICFFMPEG', 'BF_FFMPEG_LIB_STATIC',
 | 
			
		||||
            'WITH_BF_OGG', 'BF_OGG', 'BF_OGG_LIB',
 | 
			
		||||
            'WITH_BF_FRAMESERVER',
 | 
			
		||||
            'WITH_BF_COMPOSITOR', 'WITH_BF_COMPOSITOR_LEGACY',
 | 
			
		||||
            'WITH_BF_COMPOSITOR',
 | 
			
		||||
            'WITH_BF_JPEG', 'BF_JPEG', 'BF_JPEG_INC', 'BF_JPEG_LIB', 'BF_JPEG_LIBPATH', 'WITH_BF_STATICJPEG', 'BF_JPEG_LIB_STATIC',
 | 
			
		||||
            'WITH_BF_OPENJPEG', 'BF_OPENJPEG', 'BF_OPENJPEG_INC', 'BF_OPENJPEG_LIB', 'BF_OPENJPEG_LIBPATH',
 | 
			
		||||
            'WITH_BF_REDCODE', 'BF_REDCODE', 'BF_REDCODE_INC', 'BF_REDCODE_LIB', 'BF_REDCODE_LIBPATH',
 | 
			
		||||
@@ -602,7 +602,6 @@ def read_opts(env, cfg, args):
 | 
			
		||||
        ('BF_BOOST_LIB_STATIC', 'Boost static library', ''),
 | 
			
		||||
 | 
			
		||||
        (BoolVariable('WITH_GHOST_XDND', 'Build with drag-n-drop support on Linux platforms using XDND protocol', True)),
 | 
			
		||||
        (BoolVariable('WITH_BF_COMPOSITOR_LEGACY', 'Enable the legacy compositor', False)),
 | 
			
		||||
 | 
			
		||||
        (BoolVariable('WITH_BF_CYCLES_OSL', 'Build with OSL sypport in Cycles', False)),
 | 
			
		||||
        (BoolVariable('WITH_BF_STATICOSL', 'Staticly link to OSL', False)),
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ import bpy
 | 
			
		||||
def get_float(self):
 | 
			
		||||
    return self["testprop"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_float(self, value):
 | 
			
		||||
    self["testprop"] = value
 | 
			
		||||
 | 
			
		||||
@@ -36,6 +37,7 @@ bpy.types.Scene.test_date = bpy.props.StringProperty(get=get_date)
 | 
			
		||||
def get_array(self):
 | 
			
		||||
    return (True, self["somebool"])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_array(self, values):
 | 
			
		||||
    self["somebool"] = values[0] and values[1]
 | 
			
		||||
 | 
			
		||||
@@ -51,10 +53,12 @@ test_items = [
 | 
			
		||||
    ("YELLOW", "Red", "", 4),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_enum(self):
 | 
			
		||||
    import random
 | 
			
		||||
    return random.randint(1, 4)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_enum(self, value):
 | 
			
		||||
    print("setting value", value)
 | 
			
		||||
 | 
			
		||||
@@ -66,16 +70,16 @@ bpy.types.Scene.test_enum = bpy.props.EnumProperty(items=test_items, get=get_enu
 | 
			
		||||
scene = bpy.context.scene
 | 
			
		||||
 | 
			
		||||
scene.test_float = 12.34
 | 
			
		||||
print (scene.test_float)
 | 
			
		||||
print(scene.test_float)
 | 
			
		||||
 | 
			
		||||
scene.test_array = (True, False)
 | 
			
		||||
print ([x for x in scene.test_array])
 | 
			
		||||
print([x for x in scene.test_array])
 | 
			
		||||
 | 
			
		||||
#scene.test_date = "blah"   # this would fail, property is read-only
 | 
			
		||||
print (scene.test_date)
 | 
			
		||||
print(scene.test_date)
 | 
			
		||||
 | 
			
		||||
scene.test_enum = 'BLUE'
 | 
			
		||||
print (scene.test_enum)
 | 
			
		||||
print(scene.test_enum)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# >>> 12.34000015258789
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,8 @@ from bpy.props import StringProperty, IntProperty, BoolProperty
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExampleAddonPreferences(AddonPreferences):
 | 
			
		||||
    # this must match the addon name, use '__package__'
 | 
			
		||||
    # when defining this in a submodule of a python package.
 | 
			
		||||
    bl_idname = __name__
 | 
			
		||||
 | 
			
		||||
    filepath = StringProperty(
 | 
			
		||||
 
 | 
			
		||||
@@ -486,16 +486,14 @@ using :kbd:`Ctrl-Shift-Space` as the key shortcut to activate it.
 | 
			
		||||
       kmi = km.keymap_items.new(ObjectCursorArray.bl_idname, 'SPACE', 'PRESS', ctrl=True, shift=True)
 | 
			
		||||
       kmi.properties.total = 4
 | 
			
		||||
 | 
			
		||||
       addon_keymaps.append(km)
 | 
			
		||||
       addon_keymaps.append((km, kmi))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   def unregister():
 | 
			
		||||
 | 
			
		||||
       # handle the keymap
 | 
			
		||||
       wm = bpy.context.window_manager
 | 
			
		||||
       for km in addon_keymaps:
 | 
			
		||||
           wm.keyconfigs.addon.keymaps.remove(km)
 | 
			
		||||
       # clear the list
 | 
			
		||||
       for km, kmi in addon_keymaps:
 | 
			
		||||
           km.keymap_items.remove(kmi)
 | 
			
		||||
       addon_keymaps.clear()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -568,18 +566,16 @@ Bringing it all together
 | 
			
		||||
       km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
 | 
			
		||||
       kmi = km.keymap_items.new(ObjectCursorArray.bl_idname, 'SPACE', 'PRESS', ctrl=True, shift=True)
 | 
			
		||||
       kmi.properties.total = 4
 | 
			
		||||
       addon_keymaps.append(km)
 | 
			
		||||
       addon_keymaps.append((km, kmi))
 | 
			
		||||
 | 
			
		||||
   def unregister():
 | 
			
		||||
       bpy.utils.unregister_class(ObjectCursorArray)
 | 
			
		||||
       bpy.types.VIEW3D_MT_object.remove(menu_func)
 | 
			
		||||
 | 
			
		||||
       # handle the keymap
 | 
			
		||||
       wm = bpy.context.window_manager
 | 
			
		||||
       for km in addon_keymaps:
 | 
			
		||||
           wm.keyconfigs.addon.keymaps.remove(km)
 | 
			
		||||
       # clear the list
 | 
			
		||||
       del addon_keymaps[:]
 | 
			
		||||
       for km, kmi in addon_keymaps:
 | 
			
		||||
           km.keymap_items.remove(kmi)
 | 
			
		||||
       addon_keymaps.clear()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   if __name__ == "__main__":
 | 
			
		||||
 
 | 
			
		||||
@@ -113,7 +113,6 @@ def main():
 | 
			
		||||
    fsrc.close()
 | 
			
		||||
    del fsrc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
   # namespace hack
 | 
			
		||||
    vars = (
 | 
			
		||||
        "BMO_OP_SLOT_ELEMENT_BUF",
 | 
			
		||||
@@ -191,7 +190,6 @@ def main():
 | 
			
		||||
        # print(global_namespace["result"])
 | 
			
		||||
        blocks_py.append((comment, global_namespace["result"]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # ---------------------
 | 
			
		||||
    # Now convert into rst.
 | 
			
		||||
    fout = open(OUT_RST, 'w', encoding="utf-8")
 | 
			
		||||
@@ -236,7 +234,6 @@ def main():
 | 
			
		||||
        fw("\n")
 | 
			
		||||
        # -- done
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        # get the args
 | 
			
		||||
        def get_args_wash(args, args_index, is_ret):
 | 
			
		||||
            args_wash = []
 | 
			
		||||
@@ -306,9 +303,12 @@ def main():
 | 
			
		||||
                    assert(tp_sub is not None)
 | 
			
		||||
 | 
			
		||||
                    ls = []
 | 
			
		||||
                    if tp_sub & BM_VERT: ls.append(":class:`bmesh.types.BMVert`")
 | 
			
		||||
                    if tp_sub & BM_EDGE: ls.append(":class:`bmesh.types.BMEdge`")
 | 
			
		||||
                    if tp_sub & BM_FACE: ls.append(":class:`bmesh.types.BMFace`")
 | 
			
		||||
                    if tp_sub & BM_VERT:
 | 
			
		||||
                        ls.append(":class:`bmesh.types.BMVert`")
 | 
			
		||||
                    if tp_sub & BM_EDGE:
 | 
			
		||||
                        ls.append(":class:`bmesh.types.BMEdge`")
 | 
			
		||||
                    if tp_sub & BM_FACE:
 | 
			
		||||
                        ls.append(":class:`bmesh.types.BMFace`")
 | 
			
		||||
                    assert(ls)  # must be at least one
 | 
			
		||||
 | 
			
		||||
                    if tp_sub & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE:
 | 
			
		||||
 
 | 
			
		||||
@@ -992,6 +992,7 @@ context_type_map = {
 | 
			
		||||
    "world": ("World", False),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def pycontext2sphinx(basepath):
 | 
			
		||||
    # Only use once. very irregular
 | 
			
		||||
 | 
			
		||||
@@ -1019,7 +1020,6 @@ def pycontext2sphinx(basepath):
 | 
			
		||||
        "sequencer_context_dir",
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    unique = set()
 | 
			
		||||
    blend_cdll = ctypes.CDLL("")
 | 
			
		||||
    for ctx_str in context_strings:
 | 
			
		||||
 
 | 
			
		||||
@@ -107,7 +107,7 @@ void AUD_FFMPEGReader::init()
 | 
			
		||||
	m_position = 0;
 | 
			
		||||
	m_pkgbuf_left = 0;
 | 
			
		||||
 | 
			
		||||
	if(av_find_stream_info(m_formatCtx)<0)
 | 
			
		||||
	if(avformat_find_stream_info(m_formatCtx, NULL) < 0)
 | 
			
		||||
		AUD_THROW(AUD_ERROR_FFMPEG, streaminfo_error);
 | 
			
		||||
 | 
			
		||||
	// find audio stream and codec
 | 
			
		||||
@@ -133,7 +133,7 @@ void AUD_FFMPEGReader::init()
 | 
			
		||||
	if(!aCodec)
 | 
			
		||||
		AUD_THROW(AUD_ERROR_FFMPEG, nodecoder_error);
 | 
			
		||||
 | 
			
		||||
	if(avcodec_open(m_codecCtx, aCodec)<0)
 | 
			
		||||
	if(avcodec_open2(m_codecCtx, aCodec, NULL) < 0)
 | 
			
		||||
		AUD_THROW(AUD_ERROR_FFMPEG, codecopen_error);
 | 
			
		||||
 | 
			
		||||
	// XXX this prints file information to stdout:
 | 
			
		||||
@@ -236,14 +236,7 @@ AUD_FFMPEGReader::AUD_FFMPEGReader(boost::shared_ptr<AUD_Buffer> buffer) :
 | 
			
		||||
AUD_FFMPEGReader::~AUD_FFMPEGReader()
 | 
			
		||||
{
 | 
			
		||||
	avcodec_close(m_codecCtx);
 | 
			
		||||
 | 
			
		||||
	if(m_aviocontext)
 | 
			
		||||
	{
 | 
			
		||||
		avformat_close_input(&m_formatCtx);
 | 
			
		||||
		av_free(m_aviocontext);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		av_close_input_file(m_formatCtx);
 | 
			
		||||
	avformat_close_input(&m_formatCtx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int AUD_FFMPEGReader::read_packet(void* opaque, uint8_t* buf, int buf_size)
 | 
			
		||||
 
 | 
			
		||||
@@ -55,10 +55,15 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
 | 
			
		||||
{
 | 
			
		||||
	static const char* formats[] = { NULL, "ac3", "flac", "matroska", "mp2", "mp3", "ogg", "wav" };
 | 
			
		||||
 | 
			
		||||
	if(avformat_alloc_output_context2(&m_formatCtx, NULL, formats[format], filename.c_str()))
 | 
			
		||||
		AUD_THROW(AUD_ERROR_FFMPEG, context_error);
 | 
			
		||||
	m_formatCtx = avformat_alloc_context();
 | 
			
		||||
	if (!m_formatCtx) AUD_THROW(AUD_ERROR_FFMPEG, context_error);
 | 
			
		||||
 | 
			
		||||
	m_outputFmt = m_formatCtx->oformat;
 | 
			
		||||
	strcpy(m_formatCtx->filename, filename.c_str());
 | 
			
		||||
	m_outputFmt = m_formatCtx->oformat = av_guess_format(formats[format], filename.c_str(), NULL);
 | 
			
		||||
	if (!m_outputFmt) {
 | 
			
		||||
		avformat_free_context(m_formatCtx);
 | 
			
		||||
		AUD_THROW(AUD_ERROR_FFMPEG, context_error);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch(codec)
 | 
			
		||||
	{
 | 
			
		||||
@@ -116,7 +121,7 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
 | 
			
		||||
		if(m_outputFmt->audio_codec == CODEC_ID_NONE)
 | 
			
		||||
			AUD_THROW(AUD_ERROR_SPECS, codec_error);
 | 
			
		||||
 | 
			
		||||
		m_stream = av_new_stream(m_formatCtx, 0);
 | 
			
		||||
		m_stream = avformat_new_stream(m_formatCtx, NULL);
 | 
			
		||||
		if(!m_stream)
 | 
			
		||||
			AUD_THROW(AUD_ERROR_FFMPEG, stream_error);
 | 
			
		||||
 | 
			
		||||
@@ -164,7 +169,7 @@ AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs,
 | 
			
		||||
			if(!codec)
 | 
			
		||||
				AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
 | 
			
		||||
 | 
			
		||||
			if(avcodec_open(m_codecCtx, codec))
 | 
			
		||||
			if(avcodec_open2(m_codecCtx, codec, NULL))
 | 
			
		||||
				AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
 | 
			
		||||
 | 
			
		||||
			m_output_buffer.resize(FF_MIN_BUFFER_SIZE);
 | 
			
		||||
 
 | 
			
		||||
@@ -47,10 +47,6 @@ if(WITH_CYCLES_OSL)
 | 
			
		||||
	include_directories(${OSL_INCLUDES})
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(WITH_CYCLES_CUDA_BINARIES)
 | 
			
		||||
	add_definitions(-DWITH_CUDA_BINARIES)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
add_definitions(-DWITH_OPENCL)
 | 
			
		||||
add_definitions(-DWITH_CUDA)
 | 
			
		||||
add_definitions(-DWITH_MULTI)
 | 
			
		||||
 
 | 
			
		||||
@@ -53,9 +53,6 @@ if env['WITH_BF_CYCLES_OSL']:
 | 
			
		||||
    defs.append('WITH_OSL')
 | 
			
		||||
    incs.append(cycles['BF_OSL_INC'])
 | 
			
		||||
 | 
			
		||||
if env['WITH_BF_CYCLES_CUDA_BINARIES']:
 | 
			
		||||
    defs.append('WITH_CUDA_BINARIES')
 | 
			
		||||
 | 
			
		||||
incs.extend('. bvh render device kernel kernel/osl kernel/svm util subd'.split())
 | 
			
		||||
incs.extend('#intern/guardedalloc #source/blender/makesrna #source/blender/makesdna'.split())
 | 
			
		||||
incs.extend('#source/blender/blenloader ../../source/blender/makesrna/intern'.split())
 | 
			
		||||
 
 | 
			
		||||
@@ -233,16 +233,16 @@ static void xml_read_film(const XMLReadState& state, pugi::xml_node node)
 | 
			
		||||
	float aspect = (float)cam->width/(float)cam->height;
 | 
			
		||||
 | 
			
		||||
	if(cam->width >= cam->height) {
 | 
			
		||||
		cam->left = -aspect;
 | 
			
		||||
		cam->right = aspect;
 | 
			
		||||
		cam->bottom = -1.0f;
 | 
			
		||||
		cam->top = 1.0f;
 | 
			
		||||
		cam->viewplane.left = -aspect;
 | 
			
		||||
		cam->viewplane.right = aspect;
 | 
			
		||||
		cam->viewplane.bottom = -1.0f;
 | 
			
		||||
		cam->viewplane.top = 1.0f;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		cam->left = -1.0f;
 | 
			
		||||
		cam->right = 1.0f;
 | 
			
		||||
		cam->bottom = -1.0f/aspect;
 | 
			
		||||
		cam->top = 1.0f/aspect;
 | 
			
		||||
		cam->viewplane.left = -1.0f;
 | 
			
		||||
		cam->viewplane.right = 1.0f;
 | 
			
		||||
		cam->viewplane.bottom = -1.0f/aspect;
 | 
			
		||||
		cam->viewplane.top = 1.0f/aspect;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cam->need_update = true;
 | 
			
		||||
 
 | 
			
		||||
@@ -34,13 +34,13 @@ import bpy
 | 
			
		||||
 | 
			
		||||
from . import engine
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CyclesRender(bpy.types.RenderEngine):
 | 
			
		||||
    bl_idname = 'CYCLES'
 | 
			
		||||
    bl_label = "Cycles Render"
 | 
			
		||||
    bl_use_shading_nodes = True
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        engine.init()
 | 
			
		||||
        self.session = None
 | 
			
		||||
 | 
			
		||||
    def __del__(self):
 | 
			
		||||
@@ -69,7 +69,7 @@ class CyclesRender(bpy.types.RenderEngine):
 | 
			
		||||
    def view_update(self, context):
 | 
			
		||||
        if not self.session:
 | 
			
		||||
            engine.create(self, context.blend_data, context.scene,
 | 
			
		||||
                context.region, context.space_data, context.region_data)
 | 
			
		||||
                          context.region, context.space_data, context.region_data)
 | 
			
		||||
        engine.update(self, context.blend_data, context.scene)
 | 
			
		||||
 | 
			
		||||
    def view_draw(self, context):
 | 
			
		||||
@@ -88,6 +88,8 @@ def register():
 | 
			
		||||
    from . import properties
 | 
			
		||||
    from . import presets
 | 
			
		||||
 | 
			
		||||
    engine.init()
 | 
			
		||||
 | 
			
		||||
    properties.register()
 | 
			
		||||
    ui.register()
 | 
			
		||||
    presets.register()
 | 
			
		||||
@@ -103,4 +105,3 @@ def unregister():
 | 
			
		||||
    properties.unregister()
 | 
			
		||||
    presets.unregister()
 | 
			
		||||
    bpy.utils.unregister_module(__name__)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@
 | 
			
		||||
 | 
			
		||||
# <pep8 compliant>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def init():
 | 
			
		||||
    import bpy
 | 
			
		||||
    import _cycles
 | 
			
		||||
@@ -89,4 +90,3 @@ def available_devices():
 | 
			
		||||
def with_osl():
 | 
			
		||||
    import _cycles
 | 
			
		||||
    return _cycles.with_osl
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,13 @@
 | 
			
		||||
 | 
			
		||||
# <pep8 compliant>
 | 
			
		||||
 | 
			
		||||
import bpy, _cycles, os, tempfile
 | 
			
		||||
import bpy
 | 
			
		||||
import _cycles
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# compile .osl file with given filepath to temporary .oso file
 | 
			
		||||
def osl_compile(input_path, report):
 | 
			
		||||
    """compile .osl file with given filepath to temporary .oso file"""
 | 
			
		||||
    import tempfile
 | 
			
		||||
    output_file = tempfile.NamedTemporaryFile(mode='w', suffix=".oso", delete=False)
 | 
			
		||||
    output_path = output_file.name
 | 
			
		||||
    output_file.close()
 | 
			
		||||
@@ -33,9 +36,12 @@ def osl_compile(input_path, report):
 | 
			
		||||
 | 
			
		||||
    return ok, output_path
 | 
			
		||||
 | 
			
		||||
# compile and update shader script node
 | 
			
		||||
 | 
			
		||||
def update_script_node(node, report):
 | 
			
		||||
    import os, shutil
 | 
			
		||||
    """compile and update shader script node"""
 | 
			
		||||
    import os
 | 
			
		||||
    import shutil
 | 
			
		||||
    import tempfile
 | 
			
		||||
 | 
			
		||||
    if node.mode == 'EXTERNAL':
 | 
			
		||||
        # compile external script file
 | 
			
		||||
@@ -125,4 +131,3 @@ def update_script_node(node, report):
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
    return ok
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -74,13 +74,14 @@ enum_curve_presets = (
 | 
			
		||||
enum_curve_primitives = (
 | 
			
		||||
    ('TRIANGLES', "Triangles", "Create triangle geometry around strands"),
 | 
			
		||||
    ('LINE_SEGMENTS', "Line Segments", "Use line segment primitives"),
 | 
			
		||||
    ('CURVE_SEGMENTS', "?Curve Segments?", "Use curve segment primitives (not implemented)"),
 | 
			
		||||
    ('CURVE_SEGMENTS', "Curve Segments", "Use segmented cardinal curve primitives"),
 | 
			
		||||
    ('CURVE_RIBBONS', "Curve Ribbons", "Use smooth cardinal curve ribbon primitives"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
enum_triangle_curves = (
 | 
			
		||||
    ('CAMERA', "Planes", "Create individual triangles forming planes that face camera"),
 | 
			
		||||
    ('RIBBONS', "Ribbons", "Create individual triangles forming ribbon"),
 | 
			
		||||
    ('TESSELLATED', "Tessellated", "Create mesh surrounding each strand"),
 | 
			
		||||
    ('CAMERA_TRIANGLES', "Planes", "Create individual triangles forming planes that face camera"),
 | 
			
		||||
    ('RIBBON_TRIANGLES', "Ribbons", "Create individual triangles forming ribbon"),
 | 
			
		||||
    ('TESSELLATED_TRIANGLES', "Tessellated", "Create mesh surrounding each strand"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
enum_line_curves = (
 | 
			
		||||
@@ -104,6 +105,7 @@ enum_tile_order = (
 | 
			
		||||
    ('BOTTOM_TO_TOP', "Bottom to Top", "Render from bottom to top"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CyclesRenderSettings(bpy.types.PropertyGroup):
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def register(cls):
 | 
			
		||||
@@ -619,6 +621,7 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
 | 
			
		||||
        del bpy.types.Curve.cycles
 | 
			
		||||
        del bpy.types.MetaBall.cycles
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def register(cls):
 | 
			
		||||
@@ -643,7 +646,7 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
 | 
			
		||||
                name="Mesh Geometry",
 | 
			
		||||
                description="Method for creating triangle geometry",
 | 
			
		||||
                items=enum_triangle_curves,
 | 
			
		||||
                default='CAMERA',
 | 
			
		||||
                default='CAMERA_TRIANGLES',
 | 
			
		||||
                )
 | 
			
		||||
        cls.line_method = EnumProperty(
 | 
			
		||||
                name="Intersection Method",
 | 
			
		||||
@@ -682,10 +685,6 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
 | 
			
		||||
                description="Correct the tangent normal for the strand's slope",
 | 
			
		||||
                default=False,
 | 
			
		||||
                )
 | 
			
		||||
        cls.use_cache = BoolProperty(
 | 
			
		||||
                name="Export Cached data",
 | 
			
		||||
                default=True,
 | 
			
		||||
                )
 | 
			
		||||
        cls.use_parents = BoolProperty(
 | 
			
		||||
                name="Use parent strands",
 | 
			
		||||
                description="Use parents with children",
 | 
			
		||||
@@ -730,11 +729,18 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
 | 
			
		||||
                min=0, max=100.0,
 | 
			
		||||
                default=1.01,
 | 
			
		||||
                )
 | 
			
		||||
        cls.subdivisions = IntProperty(
 | 
			
		||||
                name="Subdivisions",
 | 
			
		||||
                description="Number of subdivisions used in Cardinal curve intersection (power of 2)",
 | 
			
		||||
                min=0, max=24,
 | 
			
		||||
                default=3,
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def unregister(cls):
 | 
			
		||||
        del bpy.types.Scene.cycles_curves
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CyclesCurveSettings(bpy.types.PropertyGroup):
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def register(cls):
 | 
			
		||||
@@ -771,6 +777,7 @@ class CyclesCurveSettings(bpy.types.PropertyGroup):
 | 
			
		||||
    def unregister(cls):
 | 
			
		||||
        del bpy.types.ParticleSettings.cycles
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def register():
 | 
			
		||||
    bpy.utils.register_class(CyclesRenderSettings)
 | 
			
		||||
    bpy.utils.register_class(CyclesCameraSettings)
 | 
			
		||||
 
 | 
			
		||||
@@ -976,62 +976,71 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel):
 | 
			
		||||
            slot = part.texture_slots[part.active_texture_index]
 | 
			
		||||
            layout.template_ID(slot, "texture", new="texture.new")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel):
 | 
			
		||||
    bl_label = "Cycles Hair Rendering"
 | 
			
		||||
    bl_context = "particle"
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def poll(cls, context):
 | 
			
		||||
        scene = context.scene
 | 
			
		||||
        cscene = scene.cycles
 | 
			
		||||
        psys = context.particle_system
 | 
			
		||||
        device_type = context.user_preferences.system.compute_device_type
 | 
			
		||||
        experimental = context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE')
 | 
			
		||||
        experimental = ((cscene.feature_set == 'EXPERIMENTAL') and (cscene.device == 'CPU' or device_type == 'NONE'))
 | 
			
		||||
        return CyclesButtonsPanel.poll(context) and experimental and psys
 | 
			
		||||
 | 
			
		||||
    def draw_header(self, context):
 | 
			
		||||
        cscene = context.scene.cycles_curves
 | 
			
		||||
        self.layout.prop(cscene, "use_curves", text="")
 | 
			
		||||
        ccscene = context.scene.cycles_curves
 | 
			
		||||
        self.layout.prop(ccscene, "use_curves", text="")
 | 
			
		||||
 | 
			
		||||
    def draw(self, context):
 | 
			
		||||
        layout = self.layout
 | 
			
		||||
 | 
			
		||||
        scene = context.scene
 | 
			
		||||
        cscene = scene.cycles_curves
 | 
			
		||||
        ccscene = scene.cycles_curves
 | 
			
		||||
 | 
			
		||||
        layout.active = cscene.use_curves
 | 
			
		||||
        layout.active = ccscene.use_curves
 | 
			
		||||
 | 
			
		||||
        layout.prop(cscene, "preset", text="Mode")
 | 
			
		||||
        layout.prop(ccscene, "preset", text="Mode")
 | 
			
		||||
 | 
			
		||||
        if cscene.preset == 'CUSTOM':
 | 
			
		||||
            layout.prop(cscene, "primitive", text="Primitive")
 | 
			
		||||
        if ccscene.preset == 'CUSTOM':
 | 
			
		||||
            layout.prop(ccscene, "primitive", text="Primitive")
 | 
			
		||||
 | 
			
		||||
            if cscene.primitive == 'TRIANGLES':
 | 
			
		||||
                layout.prop(cscene, "triangle_method", text="Method")
 | 
			
		||||
                if cscene.triangle_method == 'TESSELLATED':
 | 
			
		||||
                    layout.prop(cscene, "resolution", text="Resolution")
 | 
			
		||||
                layout.prop(cscene, "use_smooth", text="Smooth")
 | 
			
		||||
            elif cscene.primitive == 'LINE_SEGMENTS':
 | 
			
		||||
                layout.prop(cscene, "use_backfacing", text="Check back-faces")
 | 
			
		||||
            if ccscene.primitive == 'TRIANGLES':
 | 
			
		||||
                layout.prop(ccscene, "triangle_method", text="Method")
 | 
			
		||||
                if ccscene.triangle_method == 'TESSELLATED_TRIANGLES':
 | 
			
		||||
                    layout.prop(ccscene, "resolution", text="Resolution")
 | 
			
		||||
                layout.prop(ccscene, "use_smooth", text="Smooth")
 | 
			
		||||
            elif ccscene.primitive == 'LINE_SEGMENTS':
 | 
			
		||||
                layout.prop(ccscene, "use_backfacing", text="Check back-faces")
 | 
			
		||||
 | 
			
		||||
                row = layout.row()
 | 
			
		||||
                row.prop(cscene, "use_encasing", text="Exclude encasing")
 | 
			
		||||
                row.prop(ccscene, "use_encasing", text="Exclude encasing")
 | 
			
		||||
                sub = row.row()
 | 
			
		||||
                sub.active = cscene.use_encasing
 | 
			
		||||
                sub.prop(cscene, "encasing_ratio", text="Ratio for encasing")
 | 
			
		||||
                sub.active = ccscene.use_encasing
 | 
			
		||||
                sub.prop(ccscene, "encasing_ratio", text="Ratio for encasing")
 | 
			
		||||
 | 
			
		||||
                layout.prop(cscene, "line_method", text="Method")
 | 
			
		||||
                layout.prop(cscene, "use_tangent_normal", text="Use tangent normal as default")
 | 
			
		||||
                layout.prop(cscene, "use_tangent_normal_geometry", text="Use tangent normal geometry")
 | 
			
		||||
                layout.prop(cscene, "use_tangent_normal_correction", text="Correct tangent normal for slope")
 | 
			
		||||
                layout.prop(cscene, "interpolation", text="Interpolation")
 | 
			
		||||
                layout.prop(ccscene, "line_method", text="Method")
 | 
			
		||||
                layout.prop(ccscene, "use_tangent_normal", text="Use tangent normal as default")
 | 
			
		||||
                layout.prop(ccscene, "use_tangent_normal_geometry", text="Use tangent normal geometry")
 | 
			
		||||
                layout.prop(ccscene, "use_tangent_normal_correction", text="Correct tangent normal for slope")
 | 
			
		||||
                layout.prop(ccscene, "interpolation", text="Interpolation")
 | 
			
		||||
 | 
			
		||||
                row = layout.row()
 | 
			
		||||
                row.prop(cscene, "segments", text="Segments")
 | 
			
		||||
                row.prop(cscene, "normalmix", text="Ray Mix")
 | 
			
		||||
                row.prop(ccscene, "segments", text="Segments")
 | 
			
		||||
                row.prop(ccscene, "normalmix", text="Ray Mix")
 | 
			
		||||
            elif ccscene.primitive in {'CURVE_SEGMENTS', 'CURVE_RIBBONS'}:
 | 
			
		||||
                layout.prop(ccscene, "subdivisions", text="Curve subdivisions")
 | 
			
		||||
                layout.prop(ccscene, "use_backfacing", text="Check back-faces")
 | 
			
		||||
 | 
			
		||||
                layout.prop(ccscene, "interpolation", text="Interpolation")
 | 
			
		||||
                row = layout.row()
 | 
			
		||||
                row.prop(ccscene, "segments", text="Segments")
 | 
			
		||||
 | 
			
		||||
            row = layout.row()
 | 
			
		||||
            row.prop(cscene, "use_cache", text="Export cache with children")
 | 
			
		||||
            if cscene.use_cache:
 | 
			
		||||
                row.prop(cscene, "use_parents", text="Include parents")  
 | 
			
		||||
            row.prop(ccscene, "use_parents", text="Include parents")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
 | 
			
		||||
    bl_label = "Cycles Hair Settings"
 | 
			
		||||
@@ -1039,9 +1048,12 @@ class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel):
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def poll(cls, context):
 | 
			
		||||
        use_curves = context.scene.cycles_curves.use_curves and context.particle_system
 | 
			
		||||
        scene = context.scene
 | 
			
		||||
        cscene = scene.cycles
 | 
			
		||||
        ccscene = scene.cycles_curves
 | 
			
		||||
        use_curves = ccscene.use_curves and context.particle_system
 | 
			
		||||
        device_type = context.user_preferences.system.compute_device_type
 | 
			
		||||
        experimental = context.scene.cycles.feature_set == 'EXPERIMENTAL' and (context.scene.cycles.device == 'CPU' or device_type == 'NONE')
 | 
			
		||||
        experimental = cscene.feature_set == 'EXPERIMENTAL' and (cscene.device == 'CPU' or device_type == 'NONE')
 | 
			
		||||
        return CyclesButtonsPanel.poll(context) and experimental and use_curves
 | 
			
		||||
 | 
			
		||||
    def draw(self, context):
 | 
			
		||||
@@ -1120,74 +1132,79 @@ def draw_pause(self, context):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_panels():
 | 
			
		||||
    types = bpy.types
 | 
			
		||||
    return (
 | 
			
		||||
        bpy.types.RENDER_PT_render,
 | 
			
		||||
        bpy.types.RENDER_PT_output,
 | 
			
		||||
        bpy.types.RENDER_PT_encoding,
 | 
			
		||||
        bpy.types.RENDER_PT_dimensions,
 | 
			
		||||
        bpy.types.RENDER_PT_stamp,
 | 
			
		||||
        bpy.types.SCENE_PT_scene,
 | 
			
		||||
        bpy.types.SCENE_PT_audio,
 | 
			
		||||
        bpy.types.SCENE_PT_unit,
 | 
			
		||||
        bpy.types.SCENE_PT_keying_sets,
 | 
			
		||||
        bpy.types.SCENE_PT_keying_set_paths,
 | 
			
		||||
        bpy.types.SCENE_PT_physics,
 | 
			
		||||
        bpy.types.WORLD_PT_context_world,
 | 
			
		||||
        bpy.types.DATA_PT_context_mesh,
 | 
			
		||||
        bpy.types.DATA_PT_context_camera,
 | 
			
		||||
        bpy.types.DATA_PT_context_lamp,
 | 
			
		||||
        bpy.types.DATA_PT_context_speaker,
 | 
			
		||||
        bpy.types.DATA_PT_texture_space,
 | 
			
		||||
        bpy.types.DATA_PT_curve_texture_space,
 | 
			
		||||
        bpy.types.DATA_PT_mball_texture_space,
 | 
			
		||||
        bpy.types.DATA_PT_vertex_groups,
 | 
			
		||||
        bpy.types.DATA_PT_shape_keys,
 | 
			
		||||
        bpy.types.DATA_PT_uv_texture,
 | 
			
		||||
        bpy.types.DATA_PT_vertex_colors,
 | 
			
		||||
        bpy.types.DATA_PT_camera,
 | 
			
		||||
        bpy.types.DATA_PT_camera_display,
 | 
			
		||||
        bpy.types.DATA_PT_lens,
 | 
			
		||||
        bpy.types.DATA_PT_speaker,
 | 
			
		||||
        bpy.types.DATA_PT_distance,
 | 
			
		||||
        bpy.types.DATA_PT_cone,
 | 
			
		||||
        bpy.types.DATA_PT_customdata,
 | 
			
		||||
        bpy.types.DATA_PT_custom_props_mesh,
 | 
			
		||||
        bpy.types.DATA_PT_custom_props_camera,
 | 
			
		||||
        bpy.types.DATA_PT_custom_props_lamp,
 | 
			
		||||
        bpy.types.DATA_PT_custom_props_speaker,
 | 
			
		||||
        bpy.types.TEXTURE_PT_clouds,
 | 
			
		||||
        bpy.types.TEXTURE_PT_wood,
 | 
			
		||||
        bpy.types.TEXTURE_PT_marble,
 | 
			
		||||
        bpy.types.TEXTURE_PT_magic,
 | 
			
		||||
        bpy.types.TEXTURE_PT_blend,
 | 
			
		||||
        bpy.types.TEXTURE_PT_stucci,
 | 
			
		||||
        bpy.types.TEXTURE_PT_image,
 | 
			
		||||
        bpy.types.TEXTURE_PT_image_sampling,
 | 
			
		||||
        bpy.types.TEXTURE_PT_image_mapping,
 | 
			
		||||
        bpy.types.TEXTURE_PT_musgrave,
 | 
			
		||||
        bpy.types.TEXTURE_PT_voronoi,
 | 
			
		||||
        bpy.types.TEXTURE_PT_distortednoise,
 | 
			
		||||
        bpy.types.TEXTURE_PT_voxeldata,
 | 
			
		||||
        bpy.types.TEXTURE_PT_pointdensity,
 | 
			
		||||
        bpy.types.TEXTURE_PT_pointdensity_turbulence,
 | 
			
		||||
        bpy.types.TEXTURE_PT_mapping,
 | 
			
		||||
        bpy.types.TEXTURE_PT_influence,
 | 
			
		||||
        bpy.types.TEXTURE_PT_colors,
 | 
			
		||||
        bpy.types.PARTICLE_PT_context_particles,
 | 
			
		||||
        bpy.types.PARTICLE_PT_emission,
 | 
			
		||||
        bpy.types.PARTICLE_PT_hair_dynamics,
 | 
			
		||||
        bpy.types.PARTICLE_PT_cache,
 | 
			
		||||
        bpy.types.PARTICLE_PT_velocity,
 | 
			
		||||
        bpy.types.PARTICLE_PT_rotation,
 | 
			
		||||
        bpy.types.PARTICLE_PT_physics,
 | 
			
		||||
        bpy.types.PARTICLE_PT_boidbrain,
 | 
			
		||||
        bpy.types.PARTICLE_PT_render,
 | 
			
		||||
        bpy.types.PARTICLE_PT_draw,
 | 
			
		||||
        bpy.types.PARTICLE_PT_children,
 | 
			
		||||
        bpy.types.PARTICLE_PT_field_weights,
 | 
			
		||||
        bpy.types.PARTICLE_PT_force_fields,
 | 
			
		||||
        bpy.types.PARTICLE_PT_vertexgroups,
 | 
			
		||||
        bpy.types.PARTICLE_PT_custom_props,
 | 
			
		||||
        types.RENDER_PT_render,
 | 
			
		||||
        types.RENDER_PT_output,
 | 
			
		||||
        types.RENDER_PT_encoding,
 | 
			
		||||
        types.RENDER_PT_dimensions,
 | 
			
		||||
        types.RENDER_PT_stamp,
 | 
			
		||||
        types.SCENE_PT_scene,
 | 
			
		||||
        types.SCENE_PT_color_management,
 | 
			
		||||
        types.SCENE_PT_audio,
 | 
			
		||||
        types.SCENE_PT_unit,
 | 
			
		||||
        types.SCENE_PT_keying_sets,
 | 
			
		||||
        types.SCENE_PT_keying_set_paths,
 | 
			
		||||
        types.SCENE_PT_physics,
 | 
			
		||||
        types.WORLD_PT_context_world,
 | 
			
		||||
        types.DATA_PT_context_mesh,
 | 
			
		||||
        types.DATA_PT_context_camera,
 | 
			
		||||
        types.DATA_PT_context_lamp,
 | 
			
		||||
        types.DATA_PT_context_speaker,
 | 
			
		||||
        types.DATA_PT_texture_space,
 | 
			
		||||
        types.DATA_PT_curve_texture_space,
 | 
			
		||||
        types.DATA_PT_mball_texture_space,
 | 
			
		||||
        types.DATA_PT_vertex_groups,
 | 
			
		||||
        types.DATA_PT_shape_keys,
 | 
			
		||||
        types.DATA_PT_uv_texture,
 | 
			
		||||
        types.DATA_PT_vertex_colors,
 | 
			
		||||
        types.DATA_PT_camera,
 | 
			
		||||
        types.DATA_PT_camera_display,
 | 
			
		||||
        types.DATA_PT_lens,
 | 
			
		||||
        types.DATA_PT_speaker,
 | 
			
		||||
        types.DATA_PT_distance,
 | 
			
		||||
        types.DATA_PT_cone,
 | 
			
		||||
        types.DATA_PT_customdata,
 | 
			
		||||
        types.DATA_PT_custom_props_mesh,
 | 
			
		||||
        types.DATA_PT_custom_props_camera,
 | 
			
		||||
        types.DATA_PT_custom_props_lamp,
 | 
			
		||||
        types.DATA_PT_custom_props_speaker,
 | 
			
		||||
        types.TEXTURE_PT_clouds,
 | 
			
		||||
        types.TEXTURE_PT_wood,
 | 
			
		||||
        types.TEXTURE_PT_marble,
 | 
			
		||||
        types.TEXTURE_PT_magic,
 | 
			
		||||
        types.TEXTURE_PT_blend,
 | 
			
		||||
        types.TEXTURE_PT_stucci,
 | 
			
		||||
        types.TEXTURE_PT_image,
 | 
			
		||||
        types.TEXTURE_PT_image_sampling,
 | 
			
		||||
        types.TEXTURE_PT_image_mapping,
 | 
			
		||||
        types.TEXTURE_PT_musgrave,
 | 
			
		||||
        types.TEXTURE_PT_voronoi,
 | 
			
		||||
        types.TEXTURE_PT_distortednoise,
 | 
			
		||||
        types.TEXTURE_PT_voxeldata,
 | 
			
		||||
        types.TEXTURE_PT_pointdensity,
 | 
			
		||||
        types.TEXTURE_PT_pointdensity_turbulence,
 | 
			
		||||
        types.TEXTURE_PT_mapping,
 | 
			
		||||
        types.TEXTURE_PT_influence,
 | 
			
		||||
        types.TEXTURE_PT_colors,
 | 
			
		||||
        types.PARTICLE_PT_context_particles,
 | 
			
		||||
        types.PARTICLE_PT_emission,
 | 
			
		||||
        types.PARTICLE_PT_hair_dynamics,
 | 
			
		||||
        types.PARTICLE_PT_cache,
 | 
			
		||||
        types.PARTICLE_PT_velocity,
 | 
			
		||||
        types.PARTICLE_PT_rotation,
 | 
			
		||||
        types.PARTICLE_PT_physics,
 | 
			
		||||
        types.SCENE_PT_rigid_body_world,
 | 
			
		||||
        types.SCENE_PT_rigid_body_cache,
 | 
			
		||||
        types.SCENE_PT_rigid_body_field_weights,
 | 
			
		||||
        types.PARTICLE_PT_boidbrain,
 | 
			
		||||
        types.PARTICLE_PT_render,
 | 
			
		||||
        types.PARTICLE_PT_draw,
 | 
			
		||||
        types.PARTICLE_PT_children,
 | 
			
		||||
        types.PARTICLE_PT_field_weights,
 | 
			
		||||
        types.PARTICLE_PT_force_fields,
 | 
			
		||||
        types.PARTICLE_PT_vertexgroups,
 | 
			
		||||
        types.PARTICLE_PT_custom_props,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -37,8 +37,7 @@ void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, floa
 | 
			
		||||
void interp_weights(float t, float data[4], int type);
 | 
			
		||||
float shaperadius(float shape, float root, float tip, float time);
 | 
			
		||||
void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation);
 | 
			
		||||
bool ObtainParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData);
 | 
			
		||||
bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents);
 | 
			
		||||
bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int uv_num);
 | 
			
		||||
bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int vcol_num);
 | 
			
		||||
bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents);
 | 
			
		||||
void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam);
 | 
			
		||||
@@ -152,93 +151,6 @@ void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyl
 | 
			
		||||
		curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ObtainParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	int curvenum = 0;
 | 
			
		||||
	int keyno = 0;
 | 
			
		||||
 | 
			
		||||
	if(!(mesh && b_mesh && b_ob && CData))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	BL::Object::modifiers_iterator b_mod;
 | 
			
		||||
	for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
 | 
			
		||||
		if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
 | 
			
		||||
 | 
			
		||||
			BL::ParticleSystemModifier psmd(b_mod->ptr);
 | 
			
		||||
 | 
			
		||||
			BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
 | 
			
		||||
 | 
			
		||||
			BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
 | 
			
		||||
 | 
			
		||||
			if((b_psys.settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys.settings().type()==BL::ParticleSettings::type_HAIR)) {
 | 
			
		||||
 | 
			
		||||
				int mi = clamp(b_psys.settings().material()-1, 0, mesh->used_shaders.size()-1);
 | 
			
		||||
				int shader = mesh->used_shaders[mi];
 | 
			
		||||
 | 
			
		||||
				int totcurves = b_psys.particles.length();
 | 
			
		||||
 | 
			
		||||
				if(totcurves == 0)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
 | 
			
		||||
 | 
			
		||||
				CData->psys_firstcurve.push_back(curvenum);
 | 
			
		||||
				CData->psys_curvenum.push_back(totcurves);
 | 
			
		||||
				CData->psys_shader.push_back(shader);
 | 
			
		||||
 | 
			
		||||
				float radius = b_psys.settings().particle_size() * 0.5f;
 | 
			
		||||
	
 | 
			
		||||
				CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
 | 
			
		||||
				CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
 | 
			
		||||
				CData->psys_shape.push_back(get_float(cpsys, "shape"));
 | 
			
		||||
				CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
 | 
			
		||||
 | 
			
		||||
				BL::ParticleSystem::particles_iterator b_pa;
 | 
			
		||||
				for(b_psys.particles.begin(b_pa); b_pa != b_psys.particles.end(); ++b_pa) {
 | 
			
		||||
					CData->curve_firstkey.push_back(keyno);
 | 
			
		||||
 | 
			
		||||
					int keylength = b_pa->hair_keys.length();
 | 
			
		||||
					CData->curve_keynum.push_back(keylength);
 | 
			
		||||
 | 
			
		||||
					float curve_length = 0.0f;
 | 
			
		||||
					float3 pcKey;
 | 
			
		||||
					int step_no = 0;
 | 
			
		||||
					BL::Particle::hair_keys_iterator b_cKey;
 | 
			
		||||
					for(b_pa->hair_keys.begin(b_cKey); b_cKey != b_pa->hair_keys.end(); ++b_cKey) {
 | 
			
		||||
						float nco[3];
 | 
			
		||||
						b_cKey->co_object( *b_ob, psmd, *b_pa, nco);
 | 
			
		||||
						float3 cKey = make_float3(nco[0],nco[1],nco[2]);
 | 
			
		||||
						if(step_no > 0)
 | 
			
		||||
							curve_length += len(cKey - pcKey);
 | 
			
		||||
						CData->curvekey_co.push_back(cKey);
 | 
			
		||||
						CData->curvekey_time.push_back(curve_length);
 | 
			
		||||
						pcKey = cKey;
 | 
			
		||||
						keyno++;
 | 
			
		||||
						step_no++;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					CData->curve_length.push_back(curve_length);
 | 
			
		||||
					/*add uvs*/
 | 
			
		||||
					BL::Mesh::tessface_uv_textures_iterator l;
 | 
			
		||||
					b_mesh->tessface_uv_textures.begin(l);
 | 
			
		||||
 | 
			
		||||
					float3 uv = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
					if(b_mesh->tessface_uv_textures.length())
 | 
			
		||||
						b_pa->uv_on_emitter(psmd,&uv.x);
 | 
			
		||||
					CData->curve_uv.push_back(uv);
 | 
			
		||||
 | 
			
		||||
					curvenum++;
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
@@ -328,7 +240,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents)
 | 
			
		||||
bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int uv_num)
 | 
			
		||||
{
 | 
			
		||||
#if 0
 | 
			
		||||
	int keyno = 0;
 | 
			
		||||
@@ -342,6 +254,8 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti
 | 
			
		||||
	Transform itfm = transform_quick_inverse(tfm);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	CData->curve_uv.clear();
 | 
			
		||||
 | 
			
		||||
	BL::Object::modifiers_iterator b_mod;
 | 
			
		||||
	for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
 | 
			
		||||
		if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
 | 
			
		||||
@@ -384,7 +298,7 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti
 | 
			
		||||
 | 
			
		||||
					float3 uv = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
					if(b_mesh->tessface_uv_textures.length())
 | 
			
		||||
						b_psys.uv_on_emitter(psmd, *b_pa, pa_no, &uv.x);
 | 
			
		||||
						b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
 | 
			
		||||
					CData->curve_uv.push_back(uv);
 | 
			
		||||
 | 
			
		||||
					if(pa_no < totparts && b_pa != b_psys.particles.end())
 | 
			
		||||
@@ -413,6 +327,8 @@ bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par
 | 
			
		||||
	Transform itfm = transform_quick_inverse(tfm);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	CData->curve_vcol.clear();
 | 
			
		||||
 | 
			
		||||
	BL::Object::modifiers_iterator b_mod;
 | 
			
		||||
	for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
 | 
			
		||||
		if ((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (b_mod->show_viewport()) && (b_mod->show_render())) {
 | 
			
		||||
@@ -782,10 +698,8 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa
 | 
			
		||||
	if(!(mesh->curves.empty() && mesh->curve_keys.empty()))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	Attribute *attr_uv = NULL, *attr_intercept = NULL;
 | 
			
		||||
	Attribute *attr_intercept = NULL;
 | 
			
		||||
	
 | 
			
		||||
	if(mesh->need_attribute(scene, ATTR_STD_UV))
 | 
			
		||||
		attr_uv = mesh->curve_attributes.add(ATTR_STD_UV);
 | 
			
		||||
	if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT))
 | 
			
		||||
		attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT);
 | 
			
		||||
 | 
			
		||||
@@ -831,9 +745,6 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			mesh->add_curve(num_keys, num_curve_keys, CData->psys_shader[sys]);
 | 
			
		||||
			if(attr_uv)
 | 
			
		||||
				attr_uv->add(CData->curve_uv[curve]);
 | 
			
		||||
 | 
			
		||||
			num_keys += num_curve_keys;
 | 
			
		||||
			num_curves++;
 | 
			
		||||
		}
 | 
			
		||||
@@ -929,11 +840,11 @@ void BlenderSync::sync_curve_settings()
 | 
			
		||||
		curve_system_manager->resolution = get_int(csscene, "resolution");
 | 
			
		||||
		curve_system_manager->segments = get_int(csscene, "segments");
 | 
			
		||||
		curve_system_manager->use_smooth = get_boolean(csscene, "use_smooth");
 | 
			
		||||
		curve_system_manager->subdivisions = get_int(csscene, "subdivisions");
 | 
			
		||||
 | 
			
		||||
		curve_system_manager->normalmix = get_float(csscene, "normalmix");
 | 
			
		||||
		curve_system_manager->encasing_ratio = get_float(csscene, "encasing_ratio");
 | 
			
		||||
 | 
			
		||||
		curve_system_manager->use_cache = get_boolean(csscene, "use_cache");
 | 
			
		||||
		curve_system_manager->use_parents = get_boolean(csscene, "use_parents");
 | 
			
		||||
		curve_system_manager->use_encasing = get_boolean(csscene, "use_encasing");
 | 
			
		||||
		curve_system_manager->use_backfacing = get_boolean(csscene, "use_backfacing");
 | 
			
		||||
@@ -947,7 +858,6 @@ void BlenderSync::sync_curve_settings()
 | 
			
		||||
		curve_system_manager->interpolation = CURVE_CARDINAL;
 | 
			
		||||
		curve_system_manager->normalmix = 1.0f;
 | 
			
		||||
		curve_system_manager->encasing_ratio = 1.01f;
 | 
			
		||||
		curve_system_manager->use_cache = true;
 | 
			
		||||
		curve_system_manager->use_parents = false;
 | 
			
		||||
		curve_system_manager->segments = 1;
 | 
			
		||||
		curve_system_manager->use_joined = false;
 | 
			
		||||
@@ -1028,7 +938,6 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
 | 
			
		||||
	int resolution = scene->curve_system_manager->resolution;
 | 
			
		||||
	int segments = scene->curve_system_manager->segments;
 | 
			
		||||
	bool use_smooth = scene->curve_system_manager->use_smooth;
 | 
			
		||||
	bool use_cache = scene->curve_system_manager->use_cache;
 | 
			
		||||
	bool use_parents = scene->curve_system_manager->use_parents;
 | 
			
		||||
	bool export_tgs = scene->curve_system_manager->use_joined;
 | 
			
		||||
 | 
			
		||||
@@ -1036,12 +945,7 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
 | 
			
		||||
 | 
			
		||||
	ParticleCurveData CData;
 | 
			
		||||
 | 
			
		||||
	if(use_cache) {
 | 
			
		||||
		ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, use_parents);
 | 
			
		||||
		ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		ObtainParticleData(mesh, &b_mesh, &b_ob, &CData);
 | 
			
		||||
	ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, use_parents);
 | 
			
		||||
 | 
			
		||||
	/* attach strands to mesh */
 | 
			
		||||
	BL::Object b_CamOb = b_scene.camera();
 | 
			
		||||
@@ -1055,11 +959,12 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
 | 
			
		||||
 | 
			
		||||
	if(primitive == CURVE_TRIANGLES){
 | 
			
		||||
		int vert_num = mesh->triangles.size() * 3;
 | 
			
		||||
		if(triangle_method == CURVE_CAMERA) {
 | 
			
		||||
		ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents, 0);
 | 
			
		||||
		if(triangle_method == CURVE_CAMERA_TRIANGLES) {
 | 
			
		||||
			ExportCurveTrianglePlanes(mesh, &CData, interpolation, use_smooth, segments, RotCam);
 | 
			
		||||
			ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1);
 | 
			
		||||
		}
 | 
			
		||||
		else if(triangle_method == CURVE_RIBBONS) {
 | 
			
		||||
		else if(triangle_method == CURVE_RIBBON_TRIANGLES) {
 | 
			
		||||
			ExportCurveTriangleRibbons(mesh, &CData, interpolation, use_smooth, segments);
 | 
			
		||||
			ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1);
 | 
			
		||||
		}
 | 
			
		||||
@@ -1088,44 +993,74 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool
 | 
			
		||||
 | 
			
		||||
		/* generated coordinates from first key. we should ideally get this from
 | 
			
		||||
		 * blender to handle deforming objects */
 | 
			
		||||
		if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
 | 
			
		||||
			float3 loc, size;
 | 
			
		||||
			mesh_texture_space(b_mesh, loc, size);
 | 
			
		||||
		{
 | 
			
		||||
			if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
 | 
			
		||||
				float3 loc, size;
 | 
			
		||||
				mesh_texture_space(b_mesh, loc, size);
 | 
			
		||||
 | 
			
		||||
			Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
 | 
			
		||||
			float3 *generated = attr_generated->data_float3();
 | 
			
		||||
			size_t i = 0;
 | 
			
		||||
				Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED);
 | 
			
		||||
				float3 *generated = attr_generated->data_float3();
 | 
			
		||||
				size_t i = 0;
 | 
			
		||||
 | 
			
		||||
			foreach(Mesh::Curve& curve, mesh->curves) {
 | 
			
		||||
				float3 co = mesh->curve_keys[curve.first_key].co;
 | 
			
		||||
				generated[i++] = co*size - loc;
 | 
			
		||||
				foreach(Mesh::Curve& curve, mesh->curves) {
 | 
			
		||||
					float3 co = mesh->curve_keys[curve.first_key].co;
 | 
			
		||||
					generated[i++] = co*size - loc;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* create vertex color attributes */
 | 
			
		||||
		BL::Mesh::tessface_vertex_colors_iterator l;
 | 
			
		||||
		int vcol_num = 0;
 | 
			
		||||
		{
 | 
			
		||||
			BL::Mesh::tessface_vertex_colors_iterator l;
 | 
			
		||||
			int vcol_num = 0;
 | 
			
		||||
 | 
			
		||||
		for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
 | 
			
		||||
			if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
 | 
			
		||||
				continue;
 | 
			
		||||
			for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
 | 
			
		||||
				if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
			/*error occurs with more than one vertex colour attribute so avoided*/
 | 
			
		||||
			if(vcol_num!=0)
 | 
			
		||||
				break;
 | 
			
		||||
				Attribute *attr_vcol = mesh->curve_attributes.add(
 | 
			
		||||
					ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
 | 
			
		||||
 | 
			
		||||
			Attribute *attr_vcol = mesh->curve_attributes.add(
 | 
			
		||||
				ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
 | 
			
		||||
				ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, use_parents, vcol_num);
 | 
			
		||||
 | 
			
		||||
			ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, use_parents, 0);
 | 
			
		||||
				float3 *vcol = attr_vcol->data_float3();
 | 
			
		||||
 | 
			
		||||
			float3 *vcol = attr_vcol->data_float3();
 | 
			
		||||
 | 
			
		||||
			if(vcol) {
 | 
			
		||||
				for(size_t curve = 0; curve < CData.curve_vcol.size() ;curve++)
 | 
			
		||||
					vcol[curve] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
 | 
			
		||||
				if(vcol) {
 | 
			
		||||
					for(size_t curve = 0; curve < CData.curve_vcol.size() ;curve++)
 | 
			
		||||
						vcol[curve] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* create uv map attributes */
 | 
			
		||||
		{
 | 
			
		||||
			BL::Mesh::tessface_uv_textures_iterator l;
 | 
			
		||||
			int uv_num = 0;
 | 
			
		||||
 | 
			
		||||
			for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
 | 
			
		||||
				bool active_render = l->active_render();
 | 
			
		||||
				AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
 | 
			
		||||
				ustring name = ustring(l->name().c_str());
 | 
			
		||||
 | 
			
		||||
				/* UV map */
 | 
			
		||||
				if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
 | 
			
		||||
					Attribute *attr;
 | 
			
		||||
 | 
			
		||||
					if(active_render)
 | 
			
		||||
						attr = mesh->curve_attributes.add(std, name);
 | 
			
		||||
					else
 | 
			
		||||
						attr = mesh->curve_attributes.add(name, TypeDesc::TypePoint,  ATTR_ELEMENT_CURVE);
 | 
			
		||||
 | 
			
		||||
					ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, use_parents, uv_num);
 | 
			
		||||
 | 
			
		||||
					float3 *uv = attr->data_float3();
 | 
			
		||||
 | 
			
		||||
					if(uv) {
 | 
			
		||||
						for(size_t curve = 0; curve < CData.curve_uv.size() ;curve++)
 | 
			
		||||
							uv[curve] = CData.curve_uv[curve];
 | 
			
		||||
					}
 | 
			
		||||
				}			
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -109,6 +109,11 @@ void BlenderSession::create_session()
 | 
			
		||||
	session->reset(buffer_params, session_params.samples);
 | 
			
		||||
 | 
			
		||||
	b_engine.use_highlight_tiles(session_params.progressive_refine == false);
 | 
			
		||||
 | 
			
		||||
	/* setup callbacks for builtin image support */
 | 
			
		||||
	scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5);
 | 
			
		||||
	scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2);
 | 
			
		||||
	scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
 | 
			
		||||
@@ -607,5 +612,124 @@ void BlenderSession::test_cancel()
 | 
			
		||||
			session->progress.set_cancel("Cancelled");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* builtin image file name is actually an image datablock name with
 | 
			
		||||
 * absolute sequence frame number concatenated via '@' character
 | 
			
		||||
 *
 | 
			
		||||
 * this function splits image id name and frame number from a
 | 
			
		||||
 * builtin image name
 | 
			
		||||
 */
 | 
			
		||||
void BlenderSession::builtin_name_split(const string &builtin_name, string &name, int &frame)
 | 
			
		||||
{
 | 
			
		||||
	int last = builtin_name.find_last_of('@');
 | 
			
		||||
	name = builtin_name.substr(0, last);
 | 
			
		||||
	frame = atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BlenderSession::builtin_image_info(const string &builtin_name, bool &is_float, int &width, int &height, int &channels)
 | 
			
		||||
{
 | 
			
		||||
	string name;
 | 
			
		||||
	int frame;
 | 
			
		||||
	builtin_name_split(builtin_name, name, frame);
 | 
			
		||||
 | 
			
		||||
	BL::Image b_image = b_data.images[name];
 | 
			
		||||
 | 
			
		||||
	if(b_image) {
 | 
			
		||||
		is_float = b_image.is_float();
 | 
			
		||||
		width = b_image.size()[0];
 | 
			
		||||
		height = b_image.size()[1];
 | 
			
		||||
		channels = b_image.channels();
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		is_float = false;
 | 
			
		||||
		width = 0;
 | 
			
		||||
		height = 0;
 | 
			
		||||
		channels = 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool BlenderSession::builtin_image_pixels(const string &builtin_name, unsigned char *pixels)
 | 
			
		||||
{
 | 
			
		||||
	string name;
 | 
			
		||||
	int frame;
 | 
			
		||||
	builtin_name_split(builtin_name, name, frame);
 | 
			
		||||
 | 
			
		||||
	BL::Image b_image = b_data.images[name];
 | 
			
		||||
 | 
			
		||||
	if(b_image) {
 | 
			
		||||
		int width = b_image.size()[0];
 | 
			
		||||
		int height = b_image.size()[1];
 | 
			
		||||
		int channels = b_image.channels();
 | 
			
		||||
 | 
			
		||||
		unsigned char *image_pixels;
 | 
			
		||||
		image_pixels = image_get_pixels_for_frame(b_image, frame);
 | 
			
		||||
 | 
			
		||||
		if(image_pixels) {
 | 
			
		||||
			memcpy(pixels, image_pixels, width * height * channels * sizeof(unsigned char));
 | 
			
		||||
			MEM_freeN(image_pixels);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			if(channels == 1) {
 | 
			
		||||
				memset(pixels, 0, width * height * sizeof(unsigned char));
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				unsigned char *cp = pixels;
 | 
			
		||||
				for(int i = 0; i < width * height; i++, cp += channels) {
 | 
			
		||||
					cp[0] = 255;
 | 
			
		||||
					cp[1] = 0;
 | 
			
		||||
					cp[2] = 255;
 | 
			
		||||
					if(channels == 4)
 | 
			
		||||
						cp[3] = 255;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, float *pixels)
 | 
			
		||||
{
 | 
			
		||||
	string name;
 | 
			
		||||
	int frame;
 | 
			
		||||
	builtin_name_split(builtin_name, name, frame);
 | 
			
		||||
 | 
			
		||||
	BL::Image b_image = b_data.images[name];
 | 
			
		||||
 | 
			
		||||
	if(b_image) {
 | 
			
		||||
		int width = b_image.size()[0];
 | 
			
		||||
		int height = b_image.size()[1];
 | 
			
		||||
		int channels = b_image.channels();
 | 
			
		||||
 | 
			
		||||
		float *image_pixels;
 | 
			
		||||
		image_pixels = image_get_float_pixels_for_frame(b_image, frame);
 | 
			
		||||
 | 
			
		||||
		if(image_pixels) {
 | 
			
		||||
			memcpy(pixels, image_pixels, width * height * channels * sizeof(float));
 | 
			
		||||
			MEM_freeN(image_pixels);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			if(channels == 1) {
 | 
			
		||||
				memset(pixels, 0, width * height * sizeof(float));
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				float *fp = pixels;
 | 
			
		||||
				for(int i = 0; i < width * height; i++, fp += channels) {
 | 
			
		||||
					fp[0] = 1.0f;
 | 
			
		||||
					fp[1] = 0.0f;
 | 
			
		||||
					fp[2] = 1.0f;
 | 
			
		||||
					if(channels == 4)
 | 
			
		||||
						fp[3] = 1.0f;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CCL_NAMESPACE_END
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -93,6 +93,11 @@ public:
 | 
			
		||||
protected:
 | 
			
		||||
	void do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only);
 | 
			
		||||
	void do_write_update_render_tile(RenderTile& rtile, bool do_update_only);
 | 
			
		||||
 | 
			
		||||
	void builtin_name_split(const string &builtin_name, string &name, int &frame);
 | 
			
		||||
	void builtin_image_info(const string &builtin_name, bool &is_float, int &width, int &height, int &channels);
 | 
			
		||||
	bool builtin_image_pixels(const string &builtin_name, unsigned char *pixels);
 | 
			
		||||
	bool builtin_image_float_pixels(const string &builtin_name, float *pixels);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
CCL_NAMESPACE_END
 | 
			
		||||
 
 | 
			
		||||
@@ -511,9 +511,31 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
 | 
			
		||||
			BL::ShaderNodeTexImage b_image_node(b_node);
 | 
			
		||||
			BL::Image b_image(b_image_node.image());
 | 
			
		||||
			ImageTextureNode *image = new ImageTextureNode();
 | 
			
		||||
			/* todo: handle generated/builtin images */
 | 
			
		||||
			if(b_image && b_image.source() != BL::Image::source_MOVIE) {
 | 
			
		||||
				image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
 | 
			
		||||
			if(b_image) {
 | 
			
		||||
				/* builtin images will use callback-based reading because
 | 
			
		||||
				 * they could only be loaded correct from blender side
 | 
			
		||||
				 */
 | 
			
		||||
				bool is_builtin = b_image.packed_file() ||
 | 
			
		||||
				                  b_image.source() == BL::Image::source_GENERATED ||
 | 
			
		||||
				                  b_image.source() == BL::Image::source_MOVIE;
 | 
			
		||||
 | 
			
		||||
				if(is_builtin) {
 | 
			
		||||
					/* for builtin images we're using image datablock name to find an image to
 | 
			
		||||
					 * read pixels from later
 | 
			
		||||
					 *
 | 
			
		||||
					 * also store frame number as well, so there's no differences in handling
 | 
			
		||||
					 * builtin names for packed images and movies
 | 
			
		||||
					 */
 | 
			
		||||
					int scene_frame = b_scene.frame_current();
 | 
			
		||||
					int image_frame = image_user_frame_number(b_image_node.image_user(), scene_frame);
 | 
			
		||||
					image->filename = b_image.name() + "@" + string_printf("%d", image_frame);
 | 
			
		||||
					image->is_builtin = true;
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					image->filename = image_user_file_path(b_image_node.image_user(), b_image, b_scene.frame_current());
 | 
			
		||||
					image->is_builtin = false;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				image->animated = b_image_node.image_user().use_auto_refresh();
 | 
			
		||||
			}
 | 
			
		||||
			image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()];
 | 
			
		||||
@@ -527,9 +549,21 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
 | 
			
		||||
			BL::ShaderNodeTexEnvironment b_env_node(b_node);
 | 
			
		||||
			BL::Image b_image(b_env_node.image());
 | 
			
		||||
			EnvironmentTextureNode *env = new EnvironmentTextureNode();
 | 
			
		||||
			if(b_image && b_image.source() != BL::Image::source_MOVIE) {
 | 
			
		||||
				env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
 | 
			
		||||
				env->animated = b_env_node.image_user().use_auto_refresh();
 | 
			
		||||
			if(b_image) {
 | 
			
		||||
				bool is_builtin = b_image.packed_file() ||
 | 
			
		||||
				                  b_image.source() == BL::Image::source_GENERATED ||
 | 
			
		||||
				                  b_image.source() == BL::Image::source_MOVIE;
 | 
			
		||||
 | 
			
		||||
				if(is_builtin) {
 | 
			
		||||
					int scene_frame = b_scene.frame_current();
 | 
			
		||||
					int image_frame = image_user_frame_number(b_env_node.image_user(), scene_frame);
 | 
			
		||||
					env->filename = b_image.name() + "@" + string_printf("%d", image_frame);
 | 
			
		||||
					env->is_builtin = true;
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					env->filename = image_user_file_path(b_env_node.image_user(), b_image, b_scene.frame_current());
 | 
			
		||||
					env->animated = b_env_node.image_user().use_auto_refresh();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()];
 | 
			
		||||
			env->projection = EnvironmentTextureNode::projection_enum[(int)b_env_node.projection()];
 | 
			
		||||
 
 | 
			
		||||
@@ -359,22 +359,22 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine b_engine, BL::Use
 | 
			
		||||
	params.background = background;
 | 
			
		||||
 | 
			
		||||
	/* samples */
 | 
			
		||||
	if(get_boolean(cscene, "progressive")) {
 | 
			
		||||
	if(get_boolean(cscene, "progressive") == 0 && params.device.type == DEVICE_CPU){
 | 
			
		||||
		if(background) {
 | 
			
		||||
			params.samples = get_int(cscene, "samples");
 | 
			
		||||
			params.samples = get_int(cscene, "aa_samples");
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			params.samples = get_int(cscene, "preview_samples");
 | 
			
		||||
			params.samples = get_int(cscene, "preview_aa_samples");
 | 
			
		||||
			if(params.samples == 0)
 | 
			
		||||
				params.samples = INT_MAX;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		if(background) {
 | 
			
		||||
			params.samples = get_int(cscene, "aa_samples");
 | 
			
		||||
			params.samples = get_int(cscene, "samples");
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			params.samples = get_int(cscene, "preview_aa_samples");
 | 
			
		||||
			params.samples = get_int(cscene, "preview_samples");
 | 
			
		||||
			if(params.samples == 0)
 | 
			
		||||
				params.samples = INT_MAX;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,8 @@ extern "C" {
 | 
			
		||||
void BLI_timestr(double _time, char *str);
 | 
			
		||||
void BKE_image_user_frame_calc(void *iuser, int cfra, int fieldnr);
 | 
			
		||||
void BKE_image_user_file_path(void *iuser, void *ima, char *path);
 | 
			
		||||
unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame);
 | 
			
		||||
float *BKE_image_get_float_pixels_for_frame(void *image, int frame);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CCL_NAMESPACE_BEGIN
 | 
			
		||||
@@ -100,6 +102,22 @@ static inline string image_user_file_path(BL::ImageUser iuser, BL::Image ima, in
 | 
			
		||||
	return string(filepath);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int image_user_frame_number(BL::ImageUser iuser, int cfra)
 | 
			
		||||
{
 | 
			
		||||
	BKE_image_user_frame_calc(iuser.ptr.data, cfra, 0);
 | 
			
		||||
	return iuser.frame_current();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned char *image_get_pixels_for_frame(BL::Image image, int frame)
 | 
			
		||||
{
 | 
			
		||||
	return BKE_image_get_pixels_for_frame(image.ptr.data, frame);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline float *image_get_float_pixels_for_frame(BL::Image image, int frame)
 | 
			
		||||
{
 | 
			
		||||
	return BKE_image_get_float_pixels_for_frame(image.ptr.data, frame);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Utilities */
 | 
			
		||||
 | 
			
		||||
static inline Transform get_transform(BL::Array<float, 16> array)
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@
 | 
			
		||||
#include "mesh.h"
 | 
			
		||||
#include "object.h"
 | 
			
		||||
#include "scene.h"
 | 
			
		||||
#include "curves.h"
 | 
			
		||||
 | 
			
		||||
#include "bvh.h"
 | 
			
		||||
#include "bvh_build.h"
 | 
			
		||||
@@ -631,8 +632,19 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility
 | 
			
		||||
					int k0 = mesh->curves[pidx - str_offset].first_key + pack.prim_segment[prim]; // XXX!
 | 
			
		||||
					int k1 = k0 + 1;
 | 
			
		||||
 | 
			
		||||
					bbox.grow(mesh->curve_keys[k0].co, mesh->curve_keys[k0].radius);
 | 
			
		||||
					bbox.grow(mesh->curve_keys[k1].co, mesh->curve_keys[k1].radius);
 | 
			
		||||
					float3 p[4];
 | 
			
		||||
					p[0] = mesh->curve_keys[max(k0 - 1,mesh->curves[pidx - str_offset].first_key)].co;
 | 
			
		||||
					p[1] = mesh->curve_keys[k0].co;
 | 
			
		||||
					p[2] = mesh->curve_keys[k1].co;
 | 
			
		||||
					p[3] = mesh->curve_keys[min(k1 + 1,mesh->curves[pidx - str_offset].first_key + mesh->curves[pidx - str_offset].num_keys - 1)].co;
 | 
			
		||||
					float3 lower;
 | 
			
		||||
					float3 upper;
 | 
			
		||||
					curvebounds(&lower.x, &upper.x, p, 0);
 | 
			
		||||
					curvebounds(&lower.y, &upper.y, p, 1);
 | 
			
		||||
					curvebounds(&lower.z, &upper.z, p, 2);
 | 
			
		||||
					float mr = max(mesh->curve_keys[k0].radius,mesh->curve_keys[k1].radius);
 | 
			
		||||
					bbox.grow(lower, mr);
 | 
			
		||||
					bbox.grow(upper, mr);
 | 
			
		||||
				}
 | 
			
		||||
				else {
 | 
			
		||||
					/* triangles */
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include "mesh.h"
 | 
			
		||||
#include "object.h"
 | 
			
		||||
#include "scene.h"
 | 
			
		||||
#include "curves.h"
 | 
			
		||||
 | 
			
		||||
#include "util_debug.h"
 | 
			
		||||
#include "util_foreach.h"
 | 
			
		||||
@@ -91,11 +92,20 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh,
 | 
			
		||||
		for(int k = 0; k < curve.num_keys - 1; k++) {
 | 
			
		||||
			BoundBox bounds = BoundBox::empty;
 | 
			
		||||
 | 
			
		||||
			float3 co0 = mesh->curve_keys[curve.first_key + k].co;
 | 
			
		||||
			float3 co1 = mesh->curve_keys[curve.first_key + k + 1].co;
 | 
			
		||||
			float3 co[4];
 | 
			
		||||
			co[0] = mesh->curve_keys[max(curve.first_key + k - 1,curve.first_key)].co;
 | 
			
		||||
			co[1] = mesh->curve_keys[curve.first_key + k].co;
 | 
			
		||||
			co[2] = mesh->curve_keys[curve.first_key + k + 1].co;
 | 
			
		||||
			co[3] = mesh->curve_keys[min(curve.first_key + k + 2, curve.first_key + curve.num_keys - 1)].co;
 | 
			
		||||
 | 
			
		||||
			bounds.grow(co0, mesh->curve_keys[curve.first_key + k].radius);
 | 
			
		||||
			bounds.grow(co1, mesh->curve_keys[curve.first_key + k + 1].radius);
 | 
			
		||||
			float3 lower;
 | 
			
		||||
			float3 upper;
 | 
			
		||||
			curvebounds(&lower.x, &upper.x, co, 0);
 | 
			
		||||
			curvebounds(&lower.y, &upper.y, co, 1);
 | 
			
		||||
			curvebounds(&lower.z, &upper.z, co, 2);
 | 
			
		||||
			float mr = max(mesh->curve_keys[curve.first_key + k].radius, mesh->curve_keys[curve.first_key + k + 1].radius);
 | 
			
		||||
			bounds.grow(lower, mr);
 | 
			
		||||
			bounds.grow(upper, mr);
 | 
			
		||||
 | 
			
		||||
			if(bounds.valid()) {
 | 
			
		||||
				references.push_back(BVHReference(bounds, j, i, k));
 | 
			
		||||
 
 | 
			
		||||
@@ -238,13 +238,16 @@ public:
 | 
			
		||||
		if(path_exists(cubin))
 | 
			
		||||
			return cubin;
 | 
			
		||||
 | 
			
		||||
#if defined(WITH_CUDA_BINARIES) && defined(_WIN32)
 | 
			
		||||
		if(major <= 1 && minor <= 2)
 | 
			
		||||
			cuda_error(string_printf("CUDA device supported only compute capability 1.3 or up, found %d.%d.", major, minor));
 | 
			
		||||
		else
 | 
			
		||||
			cuda_error(string_printf("CUDA binary kernel for this graphics card compute capability (%d.%d) not found.", major, minor));
 | 
			
		||||
		return "";
 | 
			
		||||
#else
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
		if(cuHavePrecompiledKernels()) {
 | 
			
		||||
			if(major <= 1 && minor <= 2)
 | 
			
		||||
				cuda_error(string_printf("CUDA device requires compute capability 1.3 or up, found %d.%d. Your GPU is not supported.", major, minor));
 | 
			
		||||
			else
 | 
			
		||||
				cuda_error(string_printf("CUDA binary kernel for this graphics card compute capability (%d.%d) not found.", major, minor));
 | 
			
		||||
			return "";
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		/* if not, find CUDA compiler */
 | 
			
		||||
		string nvcc = cuCompilerPath();
 | 
			
		||||
 | 
			
		||||
@@ -282,7 +285,6 @@ public:
 | 
			
		||||
		printf("Kernel compilation finished in %.2lfs.\n", time_dt() - starttime);
 | 
			
		||||
 | 
			
		||||
		return cubin;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool load_kernels(bool experimental)
 | 
			
		||||
 
 | 
			
		||||
@@ -303,7 +303,7 @@ public:
 | 
			
		||||
		string build_options = " -cl-fast-relaxed-math ";
 | 
			
		||||
		
 | 
			
		||||
		if(platform_name == "NVIDIA CUDA")
 | 
			
		||||
			build_options += "-D__KERNEL_SHADING__ -D__KERNEL_OPENCL_NVIDIA__ -cl-nv-maxrregcount=24 -cl-nv-verbose ";
 | 
			
		||||
			build_options += "-D__KERNEL_OPENCL_NVIDIA__ -cl-nv-maxrregcount=24 -cl-nv-verbose ";
 | 
			
		||||
 | 
			
		||||
		else if(platform_name == "Apple")
 | 
			
		||||
			build_options += "-D__CL_NO_FLOAT3__ -D__KERNEL_OPENCL_APPLE__ ";
 | 
			
		||||
 
 | 
			
		||||
@@ -133,6 +133,10 @@ __device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
 | 
			
		||||
		L->indirect_glossy = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
		L->indirect_transmission = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
		L->path_diffuse = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
		L->path_glossy = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
		L->path_transmission = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
		L->emission = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
		L->background = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
		L->ao = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
@@ -156,11 +160,11 @@ __device_inline void path_radiance_bsdf_bounce(PathRadiance *L, float3 *throughp
 | 
			
		||||
			/* first on directly visible surface */
 | 
			
		||||
			float3 value = *throughput*inverse_pdf;
 | 
			
		||||
 | 
			
		||||
			L->indirect_diffuse = bsdf_eval->diffuse*value;
 | 
			
		||||
			L->indirect_glossy = bsdf_eval->glossy*value;
 | 
			
		||||
			L->indirect_transmission = bsdf_eval->transmission*value;
 | 
			
		||||
			L->path_diffuse = bsdf_eval->diffuse*value;
 | 
			
		||||
			L->path_glossy = bsdf_eval->glossy*value;
 | 
			
		||||
			L->path_transmission = bsdf_eval->transmission*value;
 | 
			
		||||
 | 
			
		||||
			*throughput = L->indirect_diffuse + L->indirect_glossy + L->indirect_transmission;
 | 
			
		||||
			*throughput = L->path_diffuse + L->path_glossy + L->path_transmission;
 | 
			
		||||
			
 | 
			
		||||
			L->direct_throughput = *throughput;
 | 
			
		||||
		}
 | 
			
		||||
@@ -266,22 +270,45 @@ __device_inline void path_radiance_accum_background(PathRadiance *L, float3 thro
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__device_inline void path_radiance_sum_indirect(PathRadiance *L)
 | 
			
		||||
{
 | 
			
		||||
#ifdef __PASSES__
 | 
			
		||||
	/* this division is a bit ugly, but means we only have to keep track of
 | 
			
		||||
	 * only a single throughput further along the path, here we recover just
 | 
			
		||||
	 * the indirect parth that is not influenced by any particular BSDF type */
 | 
			
		||||
	if(L->use_light_pass) {
 | 
			
		||||
		L->direct_emission = safe_divide_color(L->direct_emission, L->direct_throughput);
 | 
			
		||||
		L->direct_diffuse += L->path_diffuse*L->direct_emission;
 | 
			
		||||
		L->direct_glossy += L->path_glossy*L->direct_emission;
 | 
			
		||||
		L->direct_transmission += L->path_transmission*L->direct_emission;
 | 
			
		||||
 | 
			
		||||
		L->indirect = safe_divide_color(L->indirect, L->direct_throughput);
 | 
			
		||||
		L->indirect_diffuse += L->path_diffuse*L->indirect;
 | 
			
		||||
		L->indirect_glossy += L->path_glossy*L->indirect;
 | 
			
		||||
		L->indirect_transmission += L->path_transmission*L->indirect;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__device_inline void path_radiance_reset_indirect(PathRadiance *L)
 | 
			
		||||
{
 | 
			
		||||
#ifdef __PASSES__
 | 
			
		||||
	if(L->use_light_pass) {
 | 
			
		||||
		L->path_diffuse = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
		L->path_glossy = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
		L->path_transmission = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
		L->direct_emission = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
		L->indirect = make_float3(0.0f, 0.0f, 0.0f);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__device_inline float3 path_radiance_sum(KernelGlobals *kg, PathRadiance *L)
 | 
			
		||||
{
 | 
			
		||||
#ifdef __PASSES__
 | 
			
		||||
	if(L->use_light_pass) {
 | 
			
		||||
		/* this division is a bit ugly, but means we only have to keep track of
 | 
			
		||||
		 * only a single throughput further along the path, here we recover just
 | 
			
		||||
		 * the indirect parth that is not influenced by any particular BSDF type */
 | 
			
		||||
		L->direct_emission = safe_divide_color(L->direct_emission, L->direct_throughput);
 | 
			
		||||
		L->direct_diffuse += L->indirect_diffuse*L->direct_emission;
 | 
			
		||||
		L->direct_glossy += L->indirect_glossy*L->direct_emission;
 | 
			
		||||
		L->direct_transmission += L->indirect_transmission*L->direct_emission;
 | 
			
		||||
 | 
			
		||||
		L->indirect = safe_divide_color(L->indirect, L->direct_throughput);
 | 
			
		||||
		L->indirect_diffuse *= L->indirect;
 | 
			
		||||
		L->indirect_glossy *= L->indirect;
 | 
			
		||||
		L->indirect_transmission *= L->indirect;
 | 
			
		||||
		path_radiance_sum_indirect(L);
 | 
			
		||||
 | 
			
		||||
		float3 L_sum = L->emission
 | 
			
		||||
			+ L->direct_diffuse + L->direct_glossy + L->direct_transmission
 | 
			
		||||
 
 | 
			
		||||
@@ -206,6 +206,317 @@ __device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *ise
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __HAIR__
 | 
			
		||||
__device_inline void curvebounds(float *lower, float *upper, float *extremta, float *extrema, float *extremtb, float *extremb, float p0, float p1, float p2, float p3)
 | 
			
		||||
{
 | 
			
		||||
	float halfdiscroot = (p2 * p2 - 3 * p3 * p1);
 | 
			
		||||
	float ta = -1.0f;
 | 
			
		||||
	float tb = -1.0f;
 | 
			
		||||
	*extremta = -1.0f;
 | 
			
		||||
	*extremtb = -1.0f;
 | 
			
		||||
	*upper = p0;
 | 
			
		||||
	*lower = p0 + p1 + p2 + p3;
 | 
			
		||||
	*extrema = *upper;
 | 
			
		||||
	*extremb = *lower;
 | 
			
		||||
	if(*lower >= *upper) {
 | 
			
		||||
		*upper = *lower;
 | 
			
		||||
		*lower = p0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(halfdiscroot >= 0) {
 | 
			
		||||
		halfdiscroot = sqrt(halfdiscroot);
 | 
			
		||||
		ta = (-p2 - halfdiscroot) / (3 * p3);
 | 
			
		||||
		tb = (-p2 + halfdiscroot) / (3 * p3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	float t2;
 | 
			
		||||
	float t3;
 | 
			
		||||
	if(ta > 0.0f && ta < 1.0f) {
 | 
			
		||||
		t2 = ta * ta;
 | 
			
		||||
		t3 = t2 * ta;
 | 
			
		||||
		*extremta = ta;
 | 
			
		||||
		*extrema = p3 * t3 + p2 * t2 + p1 * ta + p0;
 | 
			
		||||
		if(*extrema > *upper) {
 | 
			
		||||
			*upper = *extrema;
 | 
			
		||||
		}
 | 
			
		||||
		if(*extrema < *lower) {
 | 
			
		||||
			*lower = *extrema;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if(tb > 0.0f && tb < 1.0f) {
 | 
			
		||||
		t2 = tb * tb;
 | 
			
		||||
		t3 = t2 * tb;
 | 
			
		||||
		*extremtb = tb;
 | 
			
		||||
		*extremb = p3 * t3 + p2 * t2 + p1 * tb + p0;
 | 
			
		||||
		if(*extremb >= *upper) {
 | 
			
		||||
			*upper = *extremb;
 | 
			
		||||
		}
 | 
			
		||||
		if(*extremb <= *lower) {
 | 
			
		||||
			*lower = *extremb;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__device_inline void bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersection *isect,
 | 
			
		||||
	float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment)
 | 
			
		||||
{
 | 
			
		||||
	int depth = kernel_data.curve_kernel_data.subdivisions;
 | 
			
		||||
 | 
			
		||||
	/* curve Intersection check */
 | 
			
		||||
	float3 dir = 1.0f/idir;
 | 
			
		||||
	
 | 
			
		||||
	int flags = kernel_data.curve_kernel_data.curveflags;
 | 
			
		||||
 | 
			
		||||
	int prim = kernel_tex_fetch(__prim_index, curveAddr);
 | 
			
		||||
 | 
			
		||||
	float3 curve_coef[4];
 | 
			
		||||
	float r_st,r_en;
 | 
			
		||||
 | 
			
		||||
	/*obtain curve parameters*/
 | 
			
		||||
	{
 | 
			
		||||
		/*ray transform created - this shold be created at beginning of intersection loop*/
 | 
			
		||||
		Transform htfm;
 | 
			
		||||
		float d = sqrtf(dir.x * dir.x + dir.z * dir.z);
 | 
			
		||||
		htfm = make_transform(
 | 
			
		||||
			dir.z / d, 0, -dir.x /d, 0,
 | 
			
		||||
			-dir.x * dir.y /d, d, -dir.y * dir.z /d, 0,
 | 
			
		||||
			dir.x, dir.y, dir.z, 0,
 | 
			
		||||
			0, 0, 0, 1) * make_transform(
 | 
			
		||||
			1, 0, 0, -P.x,
 | 
			
		||||
			0, 1, 0, -P.y,
 | 
			
		||||
			0, 0, 1, -P.z,
 | 
			
		||||
			0, 0, 0, 1);
 | 
			
		||||
 | 
			
		||||
		float4 v00 = kernel_tex_fetch(__curves, prim);
 | 
			
		||||
 | 
			
		||||
		int k0 = __float_as_int(v00.x) + segment;
 | 
			
		||||
		int k1 = k0 + 1;
 | 
			
		||||
 | 
			
		||||
		int ka = max(k0 - 1,__float_as_int(v00.x));
 | 
			
		||||
		int kb = min(k1 + 1,__float_as_int(v00.x) + __float_as_int(v00.y) - 1);
 | 
			
		||||
 | 
			
		||||
		float4 P0 = kernel_tex_fetch(__curve_keys, ka);
 | 
			
		||||
		float4 P1 = kernel_tex_fetch(__curve_keys, k0);
 | 
			
		||||
		float4 P2 = kernel_tex_fetch(__curve_keys, k1);
 | 
			
		||||
		float4 P3 = kernel_tex_fetch(__curve_keys, kb);
 | 
			
		||||
 | 
			
		||||
		float3 p0 = transform_point(&htfm, float4_to_float3(P0));
 | 
			
		||||
		float3 p1 = transform_point(&htfm, float4_to_float3(P1));
 | 
			
		||||
		float3 p2 = transform_point(&htfm, float4_to_float3(P2));
 | 
			
		||||
		float3 p3 = transform_point(&htfm, float4_to_float3(P3));
 | 
			
		||||
 | 
			
		||||
		float fc = 0.71f;
 | 
			
		||||
		curve_coef[0] = p1;
 | 
			
		||||
		curve_coef[1] = -fc*p0 + fc*p2;
 | 
			
		||||
		curve_coef[2] = 2.0f * fc * p0 + (fc - 3.0f) * p1 + (3.0f - 2.0f * fc) * p2 - fc * p3;
 | 
			
		||||
		curve_coef[3] = -fc * p0 + (2.0f - fc) * p1 + (fc - 2.0f) * p2 + fc * p3;
 | 
			
		||||
		r_st = P1.w;
 | 
			
		||||
		r_en = P2.w;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	float r_curr = max(r_st, r_en);
 | 
			
		||||
 | 
			
		||||
	/*find bounds - this is slow for cubic curves*/
 | 
			
		||||
	float upper,lower;
 | 
			
		||||
	float xextrem[4];
 | 
			
		||||
	curvebounds(&lower, &upper, &xextrem[0], &xextrem[1], &xextrem[2], &xextrem[3], curve_coef[0].x, curve_coef[1].x, curve_coef[2].x, curve_coef[3].x);
 | 
			
		||||
	if(lower > r_curr || upper < -r_curr)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	float yextrem[4];
 | 
			
		||||
	curvebounds(&lower, &upper, &yextrem[0], &yextrem[1], &yextrem[2], &yextrem[3], curve_coef[0].y, curve_coef[1].y, curve_coef[2].y, curve_coef[3].y);
 | 
			
		||||
	if(lower > r_curr || upper < -r_curr)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	float zextrem[4];
 | 
			
		||||
	curvebounds(&lower, &upper, &zextrem[0], &zextrem[1], &zextrem[2], &zextrem[3], curve_coef[0].z, curve_coef[1].z, curve_coef[2].z, curve_coef[3].z);
 | 
			
		||||
	if(lower - r_curr > isect->t || upper + r_curr < 0.0f)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/*setup recurrent loop*/
 | 
			
		||||
	int level = 1 << depth;
 | 
			
		||||
	int tree = 0;
 | 
			
		||||
	float resol = 1.0f / (float)level;
 | 
			
		||||
 | 
			
		||||
	/*begin loop*/
 | 
			
		||||
	while(!(tree >> (depth))) {
 | 
			
		||||
		float i_st = tree * resol;
 | 
			
		||||
		float i_en = i_st + (level * resol);
 | 
			
		||||
		float3 p_st = ((curve_coef[3] * i_st + curve_coef[2]) * i_st + curve_coef[1]) * i_st + curve_coef[0];
 | 
			
		||||
		float3 p_en = ((curve_coef[3] * i_en + curve_coef[2]) * i_en + curve_coef[1]) * i_en + curve_coef[0];
 | 
			
		||||
		
 | 
			
		||||
		float bminx = min(p_st.x, p_en.x);
 | 
			
		||||
		float bmaxx = max(p_st.x, p_en.x);
 | 
			
		||||
		float bminy = min(p_st.y, p_en.y);
 | 
			
		||||
		float bmaxy = max(p_st.y, p_en.y);
 | 
			
		||||
		float bminz = min(p_st.z, p_en.z);
 | 
			
		||||
		float bmaxz = max(p_st.z, p_en.z);
 | 
			
		||||
 | 
			
		||||
		if(xextrem[0] >= i_st && xextrem[0] <= i_en) {
 | 
			
		||||
			bminx = min(bminx,xextrem[1]);
 | 
			
		||||
			bmaxx = max(bmaxx,xextrem[1]);
 | 
			
		||||
		}
 | 
			
		||||
		if(xextrem[2] >= i_st && xextrem[2] <= i_en) {
 | 
			
		||||
			bminx = min(bminx,xextrem[3]);
 | 
			
		||||
			bmaxx = max(bmaxx,xextrem[3]);
 | 
			
		||||
		}
 | 
			
		||||
		if(yextrem[0] >= i_st && yextrem[0] <= i_en) {
 | 
			
		||||
			bminy = min(bminy,yextrem[1]);
 | 
			
		||||
			bmaxy = max(bmaxy,yextrem[1]);
 | 
			
		||||
		}
 | 
			
		||||
		if(yextrem[2] >= i_st && yextrem[2] <= i_en) {
 | 
			
		||||
			bminy = min(bminy,yextrem[3]);
 | 
			
		||||
			bmaxy = max(bmaxy,yextrem[3]);
 | 
			
		||||
		}
 | 
			
		||||
		if(zextrem[0] >= i_st && zextrem[0] <= i_en) {
 | 
			
		||||
			bminz = min(bminz,zextrem[1]);
 | 
			
		||||
			bmaxz = max(bmaxz,zextrem[1]);
 | 
			
		||||
		}
 | 
			
		||||
		if(zextrem[2] >= i_st && zextrem[2] <= i_en) {
 | 
			
		||||
			bminz = min(bminz,zextrem[3]);
 | 
			
		||||
			bmaxz = max(bmaxz,zextrem[3]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		float r1 = r_st + (r_en - r_st) * i_st;
 | 
			
		||||
		float r2 = r_st + (r_en - r_st) * i_en;
 | 
			
		||||
		r_curr = max(r1, r2);
 | 
			
		||||
 | 
			
		||||
		if (bminz - r_curr > isect->t || bmaxz + r_curr < 0.0f|| bminx > r_curr || bmaxx < -r_curr || bminy > r_curr || bmaxy < -r_curr) {
 | 
			
		||||
			/* the bounding box does not overlap the square centered at O.*/
 | 
			
		||||
			tree += level;
 | 
			
		||||
			level = tree & -tree;
 | 
			
		||||
		}
 | 
			
		||||
		else if (level == 1) {
 | 
			
		||||
 | 
			
		||||
			/* the maximum recursion depth is reached.
 | 
			
		||||
			* check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0.
 | 
			
		||||
			* dP* is reversed if necessary.*/
 | 
			
		||||
			float t = isect->t;
 | 
			
		||||
			float u = 0.0f;
 | 
			
		||||
			if(flags & CURVE_KN_RIBBONS) {
 | 
			
		||||
				float3 tg = (p_en - p_st);
 | 
			
		||||
				float w = tg.x * tg.x + tg.y * tg.y;
 | 
			
		||||
				if (w == 0) {
 | 
			
		||||
					tree++;
 | 
			
		||||
					level = tree & -tree;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				w = -(p_st.x * tg.x + p_st.y * tg.y) / w;
 | 
			
		||||
				w = clamp((float)w, 0.0f, 1.0f);
 | 
			
		||||
 | 
			
		||||
				/* compute u on the curve segment.*/
 | 
			
		||||
				u = i_st * (1 - w) + i_en * w;
 | 
			
		||||
				r_curr = r_st + (r_en - r_st) * u;
 | 
			
		||||
				/* compare x-y distances.*/
 | 
			
		||||
				float3 p_curr = ((curve_coef[3] * u + curve_coef[2]) * u + curve_coef[1]) * u + curve_coef[0];
 | 
			
		||||
 | 
			
		||||
				float3 dp_st = (3 * curve_coef[3] * i_st + 2 * curve_coef[2]) * i_st + curve_coef[1];
 | 
			
		||||
				if (dot(tg, dp_st)< 0)
 | 
			
		||||
					dp_st *= -1;
 | 
			
		||||
				if (dot(dp_st, -p_st) + p_curr.z * dp_st.z < 0) {
 | 
			
		||||
					tree++;
 | 
			
		||||
					level = tree & -tree;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				float3 dp_en = (3 * curve_coef[3] * i_en + 2 * curve_coef[2]) * i_en + curve_coef[1];
 | 
			
		||||
				if (dot(tg, dp_en) < 0)
 | 
			
		||||
					dp_en *= -1;
 | 
			
		||||
				if (dot(dp_en, p_en) - p_curr.z * dp_en.z < 0) {
 | 
			
		||||
					tree++;
 | 
			
		||||
					level = tree & -tree;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				if (p_curr.x * p_curr.x + p_curr.y * p_curr.y >= r_curr * r_curr || p_curr.z <= 0.0f) {
 | 
			
		||||
					tree++;
 | 
			
		||||
					level = tree & -tree;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				/* compare z distances.*/
 | 
			
		||||
				if (isect->t < p_curr.z) {
 | 
			
		||||
					tree++;
 | 
			
		||||
					level = tree & -tree;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				t = p_curr.z;
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				float l = len(p_en - p_st);
 | 
			
		||||
				float3 tg = (p_en - p_st) / l;
 | 
			
		||||
				float gd = (r2 - r1) / l;
 | 
			
		||||
				float difz = -dot(p_st,tg);
 | 
			
		||||
				float cyla = 1.0f - (tg.z * tg.z * (1 + gd*gd));
 | 
			
		||||
				float halfb = (-p_st.z - tg.z*(difz + gd*(difz*gd + r1)));
 | 
			
		||||
				float tcentre = -halfb/cyla;
 | 
			
		||||
				float zcentre = difz + (tg.z * tcentre);
 | 
			
		||||
				float3 tdif = - p_st;
 | 
			
		||||
				tdif.z += tcentre;
 | 
			
		||||
				float tdifz = dot(tdif,tg);
 | 
			
		||||
				float tb = 2*(tdif.z - tg.z*(tdifz + gd*(tdifz*gd + r1)));
 | 
			
		||||
				float tc = dot(tdif,tdif) - tdifz * tdifz * (1 + gd*gd) - r1*r1 - 2*r1*tdifz*gd;
 | 
			
		||||
				float td = tb*tb - 4*cyla*tc;
 | 
			
		||||
				if (td < 0.0f){
 | 
			
		||||
					tree++;
 | 
			
		||||
					level = tree & -tree;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				
 | 
			
		||||
				float rootd = sqrtf(td);
 | 
			
		||||
				float correction = ((-tb - rootd)/(2*cyla));
 | 
			
		||||
				t = tcentre + correction;
 | 
			
		||||
				float w = (zcentre + (tg.z * correction))/l;
 | 
			
		||||
 | 
			
		||||
				float3 dp_st = (3 * curve_coef[3] * i_st + 2 * curve_coef[2]) * i_st + curve_coef[1];
 | 
			
		||||
				if (dot(tg, dp_st)< 0)
 | 
			
		||||
					dp_st *= -1;
 | 
			
		||||
				float3 dp_en = (3 * curve_coef[3] * i_en + 2 * curve_coef[2]) * i_en + curve_coef[1];
 | 
			
		||||
				if (dot(tg, dp_en) < 0)
 | 
			
		||||
					dp_en *= -1;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
				if(flags & CURVE_KN_BACKFACING && (dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f)) {
 | 
			
		||||
					correction = ((-tb + rootd)/(2*cyla));
 | 
			
		||||
					t = tcentre + correction;
 | 
			
		||||
					w = (zcentre + (tg.z * correction))/l;
 | 
			
		||||
				}			
 | 
			
		||||
 | 
			
		||||
				if (dot(dp_st, -p_st) + t * dp_st.z < 0 || dot(dp_en, p_en) - t * dp_en.z < 0 || isect->t < t || t <= 0.0f) {
 | 
			
		||||
					tree++;
 | 
			
		||||
					level = tree & -tree;
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				w = clamp((float)w, 0.0f, 1.0f);
 | 
			
		||||
				/* compute u on the curve segment.*/
 | 
			
		||||
				u = i_st * (1 - w) + i_en * w;	
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			/* we found a new intersection.*/
 | 
			
		||||
#ifdef __VISIBILITY_FLAG__
 | 
			
		||||
			/* visibility flag test. we do it here under the assumption
 | 
			
		||||
			 * that most triangles are culled by node flags */
 | 
			
		||||
			if(kernel_tex_fetch(__prim_visibility, curveAddr) & visibility)
 | 
			
		||||
#endif
 | 
			
		||||
			{
 | 
			
		||||
				/* record intersection */
 | 
			
		||||
				isect->prim = curveAddr;
 | 
			
		||||
				isect->segment = segment;
 | 
			
		||||
				isect->object = object;
 | 
			
		||||
				isect->u = u;
 | 
			
		||||
				isect->v = 0.0f;
 | 
			
		||||
				isect->t = t;
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			tree++;
 | 
			
		||||
			level = tree & -tree;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			/* split the curve into two curves and process */
 | 
			
		||||
			level = level >> 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
 | 
			
		||||
	float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment)
 | 
			
		||||
{
 | 
			
		||||
@@ -222,7 +533,6 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
 | 
			
		||||
	float4 P1 = kernel_tex_fetch(__curve_keys, k0);
 | 
			
		||||
	float4 P2 = kernel_tex_fetch(__curve_keys, k1);
 | 
			
		||||
 | 
			
		||||
	float l = len(P2 - P1);
 | 
			
		||||
	float r1 = P1.w;
 | 
			
		||||
	float r2 = P2.w;
 | 
			
		||||
	float mr = max(r1,r2);
 | 
			
		||||
@@ -230,6 +540,7 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
 | 
			
		||||
	float3 p2 = float4_to_float3(P2);
 | 
			
		||||
	float3 dif = P - p1;
 | 
			
		||||
	float3 dir = 1.0f/idir;
 | 
			
		||||
	float l = len(p2 - p1);
 | 
			
		||||
 | 
			
		||||
	float sp_r = mr + 0.5f * l;
 | 
			
		||||
	float3 sphere_dif = P - ((p1 + p2) * 0.5f);
 | 
			
		||||
@@ -344,7 +655,7 @@ __device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect,
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
__device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
 | 
			
		||||
__device bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
 | 
			
		||||
{
 | 
			
		||||
	/* traversal stack in CUDA thread-local memory */
 | 
			
		||||
	int traversalStack[BVH_STACK_SIZE];
 | 
			
		||||
@@ -425,8 +736,12 @@ __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint
 | 
			
		||||
						/* intersect ray against primitive */
 | 
			
		||||
#ifdef __HAIR__
 | 
			
		||||
						uint segment = kernel_tex_fetch(__prim_segment, primAddr);
 | 
			
		||||
						if(segment != ~0)
 | 
			
		||||
							bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
 | 
			
		||||
						if(segment != ~0) {
 | 
			
		||||
							if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_INTERPOLATE) 
 | 
			
		||||
								bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
 | 
			
		||||
							else
 | 
			
		||||
								bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
 | 
			
		||||
						}
 | 
			
		||||
						else
 | 
			
		||||
#endif
 | 
			
		||||
							bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
 | 
			
		||||
@@ -470,7 +785,7 @@ __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __OBJECT_MOTION__
 | 
			
		||||
__device_inline bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
 | 
			
		||||
__device bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect)
 | 
			
		||||
{
 | 
			
		||||
	/* traversal stack in CUDA thread-local memory */
 | 
			
		||||
	int traversalStack[BVH_STACK_SIZE];
 | 
			
		||||
@@ -551,8 +866,12 @@ __device_inline bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, con
 | 
			
		||||
						/* intersect ray against primitive */
 | 
			
		||||
#ifdef __HAIR__
 | 
			
		||||
						uint segment = kernel_tex_fetch(__prim_segment, primAddr);
 | 
			
		||||
						if(segment != ~0)
 | 
			
		||||
							bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
 | 
			
		||||
						if(segment != ~0) {
 | 
			
		||||
							if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_INTERPOLATE) 
 | 
			
		||||
								bvh_cardinal_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
 | 
			
		||||
							else
 | 
			
		||||
								bvh_curve_intersect(kg, isect, P, idir, visibility, object, primAddr, segment);
 | 
			
		||||
						}
 | 
			
		||||
						else
 | 
			
		||||
#endif
 | 
			
		||||
							bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr);
 | 
			
		||||
@@ -610,7 +929,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng)
 | 
			
		||||
	const float epsilon_f = 1e-5f;
 | 
			
		||||
	/* ideally this should match epsilon_f, but instancing/mblur
 | 
			
		||||
	 * precision makes it problematic */
 | 
			
		||||
	const float epsilon_test = 1e-1f;
 | 
			
		||||
	const float epsilon_test = 1.0f;
 | 
			
		||||
	const int epsilon_i = 32;
 | 
			
		||||
 | 
			
		||||
	float3 res;
 | 
			
		||||
@@ -697,6 +1016,32 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, co
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __HAIR__
 | 
			
		||||
 | 
			
		||||
__device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3)
 | 
			
		||||
{
 | 
			
		||||
	float fc = 0.71f;
 | 
			
		||||
	float data[4];
 | 
			
		||||
	float t2 = t * t;
 | 
			
		||||
    data[0] = -3.0f * fc          * t2  + 4.0f * fc * t                  - fc;
 | 
			
		||||
    data[1] =  3.0f * (2.0f - fc) * t2  + 2.0f * (fc - 3.0f) * t;
 | 
			
		||||
    data[2] =  3.0f * (fc - 2.0f) * t2  + 2.0f * (3.0f - 2.0f * fc) * t  + fc;
 | 
			
		||||
    data[3] =  3.0f * fc          * t2  - 2.0f * fc * t;
 | 
			
		||||
	return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__device_inline float3 curvepoint(float t, float3 p0, float3 p1, float3 p2, float3 p3)
 | 
			
		||||
{
 | 
			
		||||
	float data[4];
 | 
			
		||||
	float fc = 0.71f;
 | 
			
		||||
	float t2 = t * t;
 | 
			
		||||
	float t3 = t2 * t;
 | 
			
		||||
	data[0] = -fc          * t3  + 2.0f * fc          * t2 - fc * t;
 | 
			
		||||
	data[1] =  (2.0f - fc) * t3  + (fc - 3.0f)        * t2 + 1.0f;
 | 
			
		||||
	data[2] =  (fc - 2.0f) * t3  + (3.0f - 2.0f * fc) * t2 + fc * t;
 | 
			
		||||
	data[3] =  fc          * t3  - fc * t2;
 | 
			
		||||
	return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float t)
 | 
			
		||||
{
 | 
			
		||||
	int flag = kernel_data.curve_kernel_data.curveflags;
 | 
			
		||||
@@ -723,64 +1068,92 @@ __device_inline float3 bvh_curve_refine(KernelGlobals *kg, ShaderData *sd, const
 | 
			
		||||
 | 
			
		||||
	float4 P1 = kernel_tex_fetch(__curve_keys, k0);
 | 
			
		||||
	float4 P2 = kernel_tex_fetch(__curve_keys, k1);
 | 
			
		||||
	float l = len(P2 - P1);
 | 
			
		||||
	float l = 1.0f;
 | 
			
		||||
	float3 tg = normalize_len(float4_to_float3(P2 - P1),&l);
 | 
			
		||||
	float r1 = P1.w;
 | 
			
		||||
	float r2 = P2.w;
 | 
			
		||||
	float3 tg = float4_to_float3(P2 - P1) / l;
 | 
			
		||||
	float3 dif = P - float4_to_float3(P1) + t * D;
 | 
			
		||||
	float gd = ((r2 - r1)/l);
 | 
			
		||||
	
 | 
			
		||||
	P = P + D*t;
 | 
			
		||||
 | 
			
		||||
	dif = P - float4_to_float3(P1);
 | 
			
		||||
	if(flag & CURVE_KN_INTERPOLATE) {
 | 
			
		||||
		int ka = max(k0 - 1,__float_as_int(v00.x));
 | 
			
		||||
		int kb = min(k1 + 1,__float_as_int(v00.x) + __float_as_int(v00.y) - 1);
 | 
			
		||||
 | 
			
		||||
	#ifdef __UV__
 | 
			
		||||
	sd->u = dot(dif,tg)/l;
 | 
			
		||||
	sd->v = 0.0f;
 | 
			
		||||
	#endif
 | 
			
		||||
		float4 P0 = kernel_tex_fetch(__curve_keys, ka);
 | 
			
		||||
		float4 P3 = kernel_tex_fetch(__curve_keys, kb);
 | 
			
		||||
 | 
			
		||||
	if (flag & CURVE_KN_TRUETANGENTGNORMAL) {
 | 
			
		||||
		sd->Ng = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
 | 
			
		||||
		sd->Ng = normalize(sd->Ng);
 | 
			
		||||
		if (flag & CURVE_KN_NORMALCORRECTION)
 | 
			
		||||
		{
 | 
			
		||||
			//sd->Ng = normalize(sd->Ng);
 | 
			
		||||
		float3 p[4];
 | 
			
		||||
		p[0] = float4_to_float3(P0);
 | 
			
		||||
		p[1] = float4_to_float3(P1);
 | 
			
		||||
		p[2] = float4_to_float3(P2);
 | 
			
		||||
		p[3] = float4_to_float3(P3);
 | 
			
		||||
 | 
			
		||||
		tg = normalize(curvetangent(isect->u,p[0],p[1],p[2],p[3]));
 | 
			
		||||
		float3 p_curr = curvepoint(isect->u,p[0],p[1],p[2],p[3]);
 | 
			
		||||
 | 
			
		||||
#ifdef __UV__
 | 
			
		||||
		sd->u = isect->u;
 | 
			
		||||
		sd->v = 0.0f;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_RIBBONS)
 | 
			
		||||
			sd->Ng = normalize(-(D - tg * (dot(tg,D))));
 | 
			
		||||
		else {
 | 
			
		||||
			sd->Ng = normalize(P - p_curr);
 | 
			
		||||
			sd->Ng = sd->Ng - gd * tg;
 | 
			
		||||
			sd->Ng = normalize(sd->Ng);
 | 
			
		||||
		}
 | 
			
		||||
		sd->N = sd->Ng;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		sd->Ng = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
 | 
			
		||||
		if (gd != 0.0f) {
 | 
			
		||||
			sd->Ng = sd->Ng - gd * tg ;
 | 
			
		||||
		float3 dif = P - float4_to_float3(P1);
 | 
			
		||||
 | 
			
		||||
#ifdef __UV__
 | 
			
		||||
		sd->u = dot(dif,tg)/l;
 | 
			
		||||
		sd->v = 0.0f;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		if (flag & CURVE_KN_TRUETANGENTGNORMAL) {
 | 
			
		||||
			sd->Ng = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
 | 
			
		||||
			sd->Ng = normalize(sd->Ng);
 | 
			
		||||
			if (flag & CURVE_KN_NORMALCORRECTION) {
 | 
			
		||||
				sd->Ng = sd->Ng - gd * tg;
 | 
			
		||||
				sd->Ng = normalize(sd->Ng);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			sd->Ng = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
 | 
			
		||||
			if (gd != 0.0f) {
 | 
			
		||||
				sd->Ng = sd->Ng - gd * tg ;
 | 
			
		||||
				sd->Ng = normalize(sd->Ng);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sd->N = sd->Ng;
 | 
			
		||||
		sd->N = sd->Ng;
 | 
			
		||||
 | 
			
		||||
	if (flag & CURVE_KN_TANGENTGNORMAL && !(flag & CURVE_KN_TRUETANGENTGNORMAL)) {
 | 
			
		||||
		sd->N = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
 | 
			
		||||
		sd->N = normalize(sd->N);
 | 
			
		||||
		if (flag & CURVE_KN_NORMALCORRECTION) {
 | 
			
		||||
			//sd->N = normalize(sd->N);
 | 
			
		||||
			sd->N = sd->N - gd * tg;
 | 
			
		||||
		if (flag & CURVE_KN_TANGENTGNORMAL && !(flag & CURVE_KN_TRUETANGENTGNORMAL)) {
 | 
			
		||||
			sd->N = -(D - tg * (dot(tg,D) * kernel_data.curve_kernel_data.normalmix));
 | 
			
		||||
			sd->N = normalize(sd->N);
 | 
			
		||||
			if (flag & CURVE_KN_NORMALCORRECTION) {
 | 
			
		||||
				sd->N = sd->N - gd * tg;
 | 
			
		||||
				sd->N = normalize(sd->N);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!(flag & CURVE_KN_TANGENTGNORMAL) && flag & CURVE_KN_TRUETANGENTGNORMAL) {
 | 
			
		||||
		sd->N = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
 | 
			
		||||
		if (gd != 0.0f) {
 | 
			
		||||
			sd->N = sd->N - gd * tg ;
 | 
			
		||||
			sd->N = normalize(sd->N);
 | 
			
		||||
		if (!(flag & CURVE_KN_TANGENTGNORMAL) && flag & CURVE_KN_TRUETANGENTGNORMAL) {
 | 
			
		||||
			sd->N = (dif - tg * sd->u * l) / (P1.w + sd->u * l * gd);
 | 
			
		||||
			if (gd != 0.0f) {
 | 
			
		||||
				sd->N = sd->N - gd * tg ;
 | 
			
		||||
				sd->N = normalize(sd->N);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#ifdef __DPDU__
 | 
			
		||||
#ifdef __DPDU__
 | 
			
		||||
	/* dPdu/dPdv */
 | 
			
		||||
	sd->dPdu = tg;
 | 
			
		||||
	sd->dPdv = cross(tg,sd->Ng);
 | 
			
		||||
	#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if(isect->object != ~0) {
 | 
			
		||||
#ifdef __OBJECT_MOTION__
 | 
			
		||||
 
 | 
			
		||||
@@ -213,7 +213,7 @@ __device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, flo
 | 
			
		||||
 | 
			
		||||
#ifdef __CAMERA_MOTION__
 | 
			
		||||
	/* motion blur */
 | 
			
		||||
	if(kernel_data.cam.shuttertime == 0.0f)
 | 
			
		||||
	if(kernel_data.cam.shuttertime == -1.0f)
 | 
			
		||||
		ray->time = TIME_INVALID;
 | 
			
		||||
	else
 | 
			
		||||
		ray->time = 0.5f + 0.5f*(time - 0.5f)*kernel_data.cam.shuttertime;
 | 
			
		||||
 
 | 
			
		||||
@@ -233,8 +233,10 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
 | 
			
		||||
 | 
			
		||||
		if(radius > 0.0f)
 | 
			
		||||
			D = distant_light_sample(D, radius, randu, randv);
 | 
			
		||||
#ifdef __LAMP_MIS__
 | 
			
		||||
		else
 | 
			
		||||
			ls->use_mis = false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		ls->P = D;
 | 
			
		||||
		ls->Ng = D;
 | 
			
		||||
@@ -255,6 +257,9 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
 | 
			
		||||
		ls->D = -D;
 | 
			
		||||
		ls->t = FLT_MAX;
 | 
			
		||||
		ls->eval_fac = 1.0f;
 | 
			
		||||
#ifndef __LAMP_MIS__
 | 
			
		||||
		ls->use_mis = true;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	else {
 | 
			
		||||
@@ -266,8 +271,10 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
 | 
			
		||||
			if(radius > 0.0f)
 | 
			
		||||
				/* sphere light */
 | 
			
		||||
				ls->P += sphere_light_sample(P, ls->P, radius, randu, randv);
 | 
			
		||||
#ifdef __LAMP_MIS__
 | 
			
		||||
			else
 | 
			
		||||
				ls->use_mis = false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
			ls->D = normalize_len(ls->P - P, &ls->t);
 | 
			
		||||
			ls->Ng = -ls->D;
 | 
			
		||||
@@ -298,7 +305,9 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
 | 
			
		||||
			float invarea = data2.x;
 | 
			
		||||
 | 
			
		||||
			if(invarea == 0.0f) {
 | 
			
		||||
#ifdef __LAMP_MIS__
 | 
			
		||||
				ls->use_mis = false;
 | 
			
		||||
#endif
 | 
			
		||||
				invarea = 1.0f;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -949,6 +949,11 @@ __device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sam
 | 
			
		||||
				kernel_path_indirect(kg, rng, sample*num_samples + j, bsdf_ray, buffer,
 | 
			
		||||
					tp*num_samples_inv, num_samples,
 | 
			
		||||
					min_ray_pdf, bsdf_pdf, ps, rng_offset+PRNG_BOUNCE_NUM, &L);
 | 
			
		||||
 | 
			
		||||
				/* for render passes, sum and reset indirect light pass variables
 | 
			
		||||
				 * for the next samples */
 | 
			
		||||
				path_radiance_sum_indirect(&L);
 | 
			
		||||
				path_radiance_reset_indirect(&L);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -106,7 +106,7 @@ __device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
 | 
			
		||||
		float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
 | 
			
		||||
		data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
 | 
			
		||||
		object_normal_transform(kg, sd, &data);
 | 
			
		||||
		return cross(sd->N, normalize(cross(data, sd->N)));;
 | 
			
		||||
		return cross(sd->N, normalize(cross(data, sd->N)));
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		/* otherwise use surface derivatives */
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ __device_noinline void shader_setup_object_transforms(KernelGlobals *kg, ShaderD
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
__device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
 | 
			
		||||
__device void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
 | 
			
		||||
	const Intersection *isect, const Ray *ray)
 | 
			
		||||
{
 | 
			
		||||
#ifdef __INSTANCING__
 | 
			
		||||
 
 | 
			
		||||
@@ -43,12 +43,12 @@ CCL_NAMESPACE_BEGIN
 | 
			
		||||
#ifdef __KERNEL_CPU__
 | 
			
		||||
#define __KERNEL_SHADING__
 | 
			
		||||
#define __KERNEL_ADV_SHADING__
 | 
			
		||||
#define __NON_PROGRESSIVE__
 | 
			
		||||
#define __LAMP_MIS__
 | 
			
		||||
#define __HAIR__
 | 
			
		||||
#ifdef WITH_OSL
 | 
			
		||||
#define __OSL__
 | 
			
		||||
#endif
 | 
			
		||||
#define __NON_PROGRESSIVE__
 | 
			
		||||
#define __HAIR__
 | 
			
		||||
#define __LAMP_MIS__
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __KERNEL_CUDA__
 | 
			
		||||
@@ -56,6 +56,9 @@ CCL_NAMESPACE_BEGIN
 | 
			
		||||
#if __CUDA_ARCH__ >= 200
 | 
			
		||||
#define __KERNEL_ADV_SHADING__
 | 
			
		||||
#endif
 | 
			
		||||
#if __CUDA_ARCH__ >= 210
 | 
			
		||||
#define __LAMP_MIS__
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __KERNEL_OPENCL__
 | 
			
		||||
@@ -114,8 +117,8 @@ CCL_NAMESPACE_BEGIN
 | 
			
		||||
#define __PASSES__
 | 
			
		||||
#define __BACKGROUND_MIS__
 | 
			
		||||
#define __AO__
 | 
			
		||||
#define __CAMERA_MOTION__
 | 
			
		||||
#define __ANISOTROPIC__
 | 
			
		||||
#define __CAMERA_MOTION__
 | 
			
		||||
#define __OBJECT_MOTION__
 | 
			
		||||
#endif
 | 
			
		||||
//#define __SOBOL_FULL_SCREEN__
 | 
			
		||||
@@ -255,6 +258,10 @@ typedef struct PathRadiance {
 | 
			
		||||
	float3 indirect_glossy;
 | 
			
		||||
	float3 indirect_transmission;
 | 
			
		||||
 | 
			
		||||
	float3 path_diffuse;
 | 
			
		||||
	float3 path_glossy;
 | 
			
		||||
	float3 path_transmission;
 | 
			
		||||
 | 
			
		||||
	float4 shadow;
 | 
			
		||||
} PathRadiance;
 | 
			
		||||
 | 
			
		||||
@@ -696,6 +703,7 @@ typedef enum CurveFlag {
 | 
			
		||||
	CURVE_KN_NORMALCORRECTION = 128,		/* correct tangent normal for slope? */
 | 
			
		||||
	CURVE_KN_TRUETANGENTGNORMAL = 256,		/* use tangent normal for geometry? */
 | 
			
		||||
	CURVE_KN_TANGENTGNORMAL = 512,			/* use tangent normal for shader? */
 | 
			
		||||
	CURVE_KN_RIBBONS = 1024,				/* use flat curve ribbons */
 | 
			
		||||
} CurveFlag;
 | 
			
		||||
 | 
			
		||||
typedef struct KernelCurves {
 | 
			
		||||
@@ -703,7 +711,7 @@ typedef struct KernelCurves {
 | 
			
		||||
	float normalmix;
 | 
			
		||||
	float encasing_ratio;
 | 
			
		||||
	int curveflags;
 | 
			
		||||
	int pad;
 | 
			
		||||
	int subdivisions;
 | 
			
		||||
 | 
			
		||||
} KernelCurves;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -31,15 +31,23 @@ shader node_normal_map(
 | 
			
		||||
 | 
			
		||||
	if (space == "Tangent") {
 | 
			
		||||
		vector tangent;
 | 
			
		||||
		vector ninterp;
 | 
			
		||||
		float tangent_sign;
 | 
			
		||||
 | 
			
		||||
		getattribute(attr_name, tangent);
 | 
			
		||||
		getattribute(attr_sign_name, tangent_sign);
 | 
			
		||||
		// get _unnormalized_ interpolated normal and tangent
 | 
			
		||||
		if(!getattribute(attr_name, tangent) ||
 | 
			
		||||
		   !getattribute(attr_sign_name, tangent_sign) ||
 | 
			
		||||
		   !getattribute("geom:N", ninterp)) {
 | 
			
		||||
			Normal = normal(0, 0, 0);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			// apply normal map
 | 
			
		||||
			vector B = tangent_sign * cross(ninterp, tangent);
 | 
			
		||||
			Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * ninterp);
 | 
			
		||||
 | 
			
		||||
		tangent = transform("object", "world", tangent);
 | 
			
		||||
 | 
			
		||||
		vector B = tangent_sign * cross(NormalIn, tangent);
 | 
			
		||||
		Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * NormalIn);
 | 
			
		||||
			// transform to world space
 | 
			
		||||
			Normal = normalize(transform("object", "world", Normal));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (space == "Object")
 | 
			
		||||
		Normal = normalize(transform("object", "world", vector(mcolor)));
 | 
			
		||||
 
 | 
			
		||||
@@ -248,24 +248,27 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* first try to get tangent attribute */
 | 
			
		||||
		AttributeElement attr_elem, attr_sign_elem;
 | 
			
		||||
		AttributeElement attr_elem, attr_sign_elem, attr_normal_elem;
 | 
			
		||||
		int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
 | 
			
		||||
		int attr_sign_offset = find_attribute(kg, sd, node.w, &attr_sign_elem);
 | 
			
		||||
		int attr_normal_offset = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL, &attr_normal_elem);
 | 
			
		||||
 | 
			
		||||
		if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND) {
 | 
			
		||||
		if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND || attr_normal_offset == ATTR_STD_NOT_FOUND) {
 | 
			
		||||
			stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* ensure orthogonal and normalized (interpolation breaks it) */
 | 
			
		||||
		/* get _unnormalized_ interpolated normal and tangent */
 | 
			
		||||
		float3 tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
 | 
			
		||||
		float sign = primitive_attribute_float(kg, sd, attr_sign_elem, attr_sign_offset, NULL, NULL);
 | 
			
		||||
		float3 normal = primitive_attribute_float3(kg, sd, attr_normal_elem, attr_normal_offset, NULL, NULL);
 | 
			
		||||
 | 
			
		||||
		object_normal_transform(kg, sd, &tangent);
 | 
			
		||||
		tangent = cross(sd->N, normalize(cross(tangent, sd->N)));;
 | 
			
		||||
		/* apply normal map */
 | 
			
		||||
		float3 B = sign * cross(normal, tangent);
 | 
			
		||||
		N = normalize(color.x * tangent + color.y * B + color.z * normal);
 | 
			
		||||
 | 
			
		||||
		float3 B = sign * cross(sd->N, tangent);
 | 
			
		||||
		N = normalize(color.x * tangent + color.y * B + color.z * sd->N);
 | 
			
		||||
		/* transform to world space */
 | 
			
		||||
		object_normal_transform(kg, sd, &N);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		/* object, world space */
 | 
			
		||||
 
 | 
			
		||||
@@ -216,9 +216,9 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
 | 
			
		||||
 | 
			
		||||
	/* motion blur */
 | 
			
		||||
#ifdef __CAMERA_MOTION__
 | 
			
		||||
	kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime: 0.0f;
 | 
			
		||||
	kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime: -1.0f;
 | 
			
		||||
#else
 | 
			
		||||
	kcam->shuttertime = 0.0f;
 | 
			
		||||
	kcam->shuttertime = -1.0f;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* type */
 | 
			
		||||
 
 | 
			
		||||
@@ -90,7 +90,7 @@ public:
 | 
			
		||||
	Transform worldtocamera;
 | 
			
		||||
 | 
			
		||||
	Transform rastertocamera;
 | 
			
		||||
	Transform cameratoraster;;
 | 
			
		||||
	Transform cameratoraster;
 | 
			
		||||
 | 
			
		||||
	float3 dx;
 | 
			
		||||
	float3 dy;
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,52 @@
 | 
			
		||||
 | 
			
		||||
CCL_NAMESPACE_BEGIN
 | 
			
		||||
 | 
			
		||||
/* Curve functions */
 | 
			
		||||
 | 
			
		||||
void curvebounds(float *lower, float *upper, float3 *p, int dim)
 | 
			
		||||
{
 | 
			
		||||
	float *p0 = &p[0].x;
 | 
			
		||||
	float *p1 = &p[1].x;
 | 
			
		||||
	float *p2 = &p[2].x;
 | 
			
		||||
	float *p3 = &p[3].x;
 | 
			
		||||
	float fc = 0.71f;
 | 
			
		||||
	float curve_coef[4];
 | 
			
		||||
	curve_coef[0] = p1[dim];
 | 
			
		||||
	curve_coef[1] = -fc*p0[dim] + fc*p2[dim];
 | 
			
		||||
	curve_coef[2] = 2.0f * fc * p0[dim] + (fc - 3.0f) * p1[dim] + (3.0f - 2.0f * fc) * p2[dim] - fc * p3[dim];
 | 
			
		||||
	curve_coef[3] = -fc * p0[dim] + (2.0f - fc) * p1[dim] + (fc - 2.0f) * p2[dim] + fc * p3[dim];
 | 
			
		||||
	float discroot = curve_coef[2] * curve_coef[2] - 3 * curve_coef[3] * curve_coef[1];
 | 
			
		||||
	float ta = -1.0f;
 | 
			
		||||
	float tb = -1.0f;
 | 
			
		||||
	if(discroot >= 0) {
 | 
			
		||||
		discroot = sqrt(discroot);
 | 
			
		||||
		ta = (-curve_coef[2] - discroot) / (3 * curve_coef[3]);
 | 
			
		||||
		tb = (-curve_coef[2] + discroot) / (3 * curve_coef[3]);
 | 
			
		||||
		ta = (ta > 1.0f || ta < 0.0f) ? -1.0f : ta;
 | 
			
		||||
		tb = (tb > 1.0f || tb < 0.0f) ? -1.0f : tb;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*upper = max(p1[dim],p2[dim]);
 | 
			
		||||
	*lower = min(p1[dim],p2[dim]);
 | 
			
		||||
	float exa = p1[dim];
 | 
			
		||||
	float exb = p2[dim];
 | 
			
		||||
	float t2;
 | 
			
		||||
	float t3;
 | 
			
		||||
	if(ta >= 0.0f) {
 | 
			
		||||
		t2 = ta * ta;
 | 
			
		||||
		t3 = t2 * ta;
 | 
			
		||||
		exa = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * ta + curve_coef[0];
 | 
			
		||||
	}
 | 
			
		||||
	if(tb >= 0.0f) {
 | 
			
		||||
		t2 = tb * tb;
 | 
			
		||||
		t3 = t2 * tb;
 | 
			
		||||
		exb = curve_coef[3] * t3 + curve_coef[2] * t2 + curve_coef[1] * tb + curve_coef[0];
 | 
			
		||||
	}
 | 
			
		||||
	*upper = max(*upper, max(exa,exb));
 | 
			
		||||
	*lower = min(*lower, min(exa,exb));
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Hair System Manager */
 | 
			
		||||
 | 
			
		||||
CurveSystemManager::CurveSystemManager()
 | 
			
		||||
@@ -36,16 +82,16 @@ CurveSystemManager::CurveSystemManager()
 | 
			
		||||
	primitive = CURVE_LINE_SEGMENTS;
 | 
			
		||||
	line_method = CURVE_CORRECTED;
 | 
			
		||||
	interpolation = CURVE_CARDINAL;
 | 
			
		||||
	triangle_method = CURVE_CAMERA;
 | 
			
		||||
	triangle_method = CURVE_CAMERA_TRIANGLES;
 | 
			
		||||
	resolution = 3;
 | 
			
		||||
	segments = 1;
 | 
			
		||||
	subdivisions = 3;
 | 
			
		||||
 | 
			
		||||
	normalmix = 1.0f;
 | 
			
		||||
	encasing_ratio = 1.01f;
 | 
			
		||||
 | 
			
		||||
	use_curves = true;
 | 
			
		||||
	use_smooth = true;
 | 
			
		||||
	use_cache = true;
 | 
			
		||||
	use_parents = false;
 | 
			
		||||
	use_encasing = true;
 | 
			
		||||
	use_backfacing = false;
 | 
			
		||||
@@ -75,31 +121,36 @@ void CurveSystemManager::device_update(Device *device, DeviceScene *dscene, Scen
 | 
			
		||||
 | 
			
		||||
	kcurve->curveflags = 0;
 | 
			
		||||
 | 
			
		||||
	if(primitive == CURVE_SEGMENTS)
 | 
			
		||||
		kcurve->curveflags |= CURVE_KN_INTERPOLATE;
 | 
			
		||||
	if(use_curves) {
 | 
			
		||||
		if(primitive == CURVE_SEGMENTS || primitive == CURVE_RIBBONS)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_INTERPOLATE;
 | 
			
		||||
		if(primitive == CURVE_RIBBONS)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_RIBBONS;
 | 
			
		||||
 | 
			
		||||
	if(line_method == CURVE_ACCURATE)
 | 
			
		||||
		kcurve->curveflags |= CURVE_KN_ACCURATE;
 | 
			
		||||
	if(line_method == CURVE_CORRECTED)
 | 
			
		||||
		kcurve->curveflags |= CURVE_KN_INTERSECTCORRECTION;
 | 
			
		||||
	if(line_method == CURVE_POSTCORRECTED)
 | 
			
		||||
		kcurve->curveflags |= CURVE_KN_POSTINTERSECTCORRECTION;
 | 
			
		||||
		if(line_method == CURVE_ACCURATE)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_ACCURATE;
 | 
			
		||||
		if(line_method == CURVE_CORRECTED)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_INTERSECTCORRECTION;
 | 
			
		||||
		if(line_method == CURVE_POSTCORRECTED)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_POSTINTERSECTCORRECTION;
 | 
			
		||||
 | 
			
		||||
	if(use_tangent_normal)
 | 
			
		||||
		kcurve->curveflags |= CURVE_KN_TANGENTGNORMAL;
 | 
			
		||||
	if(use_tangent_normal_correction)
 | 
			
		||||
		kcurve->curveflags |= CURVE_KN_NORMALCORRECTION;
 | 
			
		||||
	if(use_tangent_normal_geometry)
 | 
			
		||||
		kcurve->curveflags |= CURVE_KN_TRUETANGENTGNORMAL;
 | 
			
		||||
	if(use_joined)
 | 
			
		||||
		kcurve->curveflags |= CURVE_KN_CURVEDATA;
 | 
			
		||||
	if(use_backfacing)
 | 
			
		||||
		kcurve->curveflags |= CURVE_KN_BACKFACING;
 | 
			
		||||
	if(use_encasing)
 | 
			
		||||
		kcurve->curveflags |= CURVE_KN_ENCLOSEFILTER;
 | 
			
		||||
		if(use_tangent_normal)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_TANGENTGNORMAL;
 | 
			
		||||
		if(use_tangent_normal_correction)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_NORMALCORRECTION;
 | 
			
		||||
		if(use_tangent_normal_geometry)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_TRUETANGENTGNORMAL;
 | 
			
		||||
		if(use_joined)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_CURVEDATA;
 | 
			
		||||
		if(use_backfacing)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_BACKFACING;
 | 
			
		||||
		if(use_encasing)
 | 
			
		||||
			kcurve->curveflags |= CURVE_KN_ENCLOSEFILTER;
 | 
			
		||||
 | 
			
		||||
	kcurve->normalmix = normalmix;
 | 
			
		||||
	kcurve->encasing_ratio = encasing_ratio;
 | 
			
		||||
		kcurve->normalmix = normalmix;
 | 
			
		||||
		kcurve->encasing_ratio = encasing_ratio;
 | 
			
		||||
		kcurve->subdivisions = subdivisions;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(progress.get_cancel()) return;
 | 
			
		||||
 | 
			
		||||
@@ -123,14 +174,14 @@ bool CurveSystemManager::modified(const CurveSystemManager& CurveSystemManager)
 | 
			
		||||
		encasing_ratio == CurveSystemManager.encasing_ratio &&
 | 
			
		||||
		use_backfacing == CurveSystemManager.use_backfacing &&
 | 
			
		||||
		normalmix == CurveSystemManager.normalmix &&
 | 
			
		||||
		use_cache == CurveSystemManager.use_cache &&
 | 
			
		||||
		use_smooth == CurveSystemManager.use_smooth &&
 | 
			
		||||
		triangle_method == CurveSystemManager.triangle_method &&
 | 
			
		||||
		resolution == CurveSystemManager.resolution &&
 | 
			
		||||
		use_curves == CurveSystemManager.use_curves &&
 | 
			
		||||
		use_joined == CurveSystemManager.use_joined &&
 | 
			
		||||
		segments == CurveSystemManager.segments &&
 | 
			
		||||
		use_parents == CurveSystemManager.use_parents);
 | 
			
		||||
		use_parents == CurveSystemManager.use_parents &&
 | 
			
		||||
		subdivisions == CurveSystemManager.subdivisions);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CurveSystemManager::modified_mesh(const CurveSystemManager& CurveSystemManager)
 | 
			
		||||
@@ -143,8 +194,7 @@ bool CurveSystemManager::modified_mesh(const CurveSystemManager& CurveSystemMana
 | 
			
		||||
		resolution == CurveSystemManager.resolution &&
 | 
			
		||||
		use_curves == CurveSystemManager.use_curves &&
 | 
			
		||||
		use_joined == CurveSystemManager.use_joined &&
 | 
			
		||||
		segments == CurveSystemManager.segments &&
 | 
			
		||||
		use_cache == CurveSystemManager.use_cache);
 | 
			
		||||
		segments == CurveSystemManager.segments);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CurveSystemManager::tag_update(Scene *scene)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,8 @@ class DeviceScene;
 | 
			
		||||
class Progress;
 | 
			
		||||
class Scene;
 | 
			
		||||
 | 
			
		||||
void curvebounds(float *lower, float *upper, float3 *p, int dim);
 | 
			
		||||
 | 
			
		||||
typedef enum curve_presets {
 | 
			
		||||
	CURVE_CUSTOM,
 | 
			
		||||
	CURVE_TANGENT_SHADING,
 | 
			
		||||
@@ -39,13 +41,14 @@ typedef enum curve_presets {
 | 
			
		||||
typedef enum curve_primitives {
 | 
			
		||||
	CURVE_TRIANGLES,
 | 
			
		||||
	CURVE_LINE_SEGMENTS,
 | 
			
		||||
	CURVE_SEGMENTS
 | 
			
		||||
	CURVE_SEGMENTS,
 | 
			
		||||
	CURVE_RIBBONS
 | 
			
		||||
} curve_primitives;
 | 
			
		||||
 | 
			
		||||
typedef enum curve_triangles {
 | 
			
		||||
	CURVE_CAMERA,
 | 
			
		||||
	CURVE_RIBBONS,
 | 
			
		||||
	CURVE_TESSELATED
 | 
			
		||||
	CURVE_CAMERA_TRIANGLES,
 | 
			
		||||
	CURVE_RIBBON_TRIANGLES,
 | 
			
		||||
	CURVE_TESSELATED_TRIANGLES
 | 
			
		||||
} curve_triangles;
 | 
			
		||||
 | 
			
		||||
typedef enum curve_lines {
 | 
			
		||||
@@ -98,13 +101,13 @@ public:
 | 
			
		||||
	int triangle_method;
 | 
			
		||||
	int resolution;
 | 
			
		||||
	int segments;
 | 
			
		||||
	int subdivisions;
 | 
			
		||||
 | 
			
		||||
	float normalmix;
 | 
			
		||||
	float encasing_ratio;
 | 
			
		||||
 | 
			
		||||
	bool use_curves;
 | 
			
		||||
	bool use_smooth;
 | 
			
		||||
	bool use_cache;
 | 
			
		||||
	bool use_parents;
 | 
			
		||||
	bool use_encasing;
 | 
			
		||||
	bool use_backfacing;
 | 
			
		||||
 
 | 
			
		||||
@@ -708,7 +708,8 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
 | 
			
		||||
				value2_in->value.x = 1.0f;
 | 
			
		||||
 | 
			
		||||
			weight_out = math_node->output("Value");
 | 
			
		||||
			disconnect(weight_in);
 | 
			
		||||
			if(weight_in->link)
 | 
			
		||||
				disconnect(weight_in);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* connected to closure mix weight */
 | 
			
		||||
 
 | 
			
		||||
@@ -85,11 +85,21 @@ bool ImageManager::set_animation_frame_update(int frame)
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ImageManager::is_float_image(const string& filename)
 | 
			
		||||
bool ImageManager::is_float_image(const string& filename, bool is_builtin)
 | 
			
		||||
{
 | 
			
		||||
	ImageInput *in = ImageInput::create(filename);
 | 
			
		||||
	bool is_float = false;
 | 
			
		||||
 | 
			
		||||
	if(is_builtin) {
 | 
			
		||||
		if(builtin_image_info_cb) {
 | 
			
		||||
			int width, height, channels;
 | 
			
		||||
			builtin_image_info_cb(filename, is_float, width, height, channels);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return is_float;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ImageInput *in = ImageInput::create(filename);
 | 
			
		||||
 | 
			
		||||
	if(in) {
 | 
			
		||||
		ImageSpec spec;
 | 
			
		||||
 | 
			
		||||
@@ -113,13 +123,13 @@ bool ImageManager::is_float_image(const string& filename)
 | 
			
		||||
	return is_float;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ImageManager::add_image(const string& filename, bool animated, bool& is_float)
 | 
			
		||||
int ImageManager::add_image(const string& filename, bool is_builtin, bool animated, bool& is_float)
 | 
			
		||||
{
 | 
			
		||||
	Image *img;
 | 
			
		||||
	size_t slot;
 | 
			
		||||
 | 
			
		||||
	/* load image info and find out if we need a float texture */
 | 
			
		||||
	is_float = (pack_images)? false: is_float_image(filename);
 | 
			
		||||
	is_float = (pack_images)? false: is_float_image(filename, is_builtin);
 | 
			
		||||
 | 
			
		||||
	if(is_float) {
 | 
			
		||||
		/* find existing image */
 | 
			
		||||
@@ -150,6 +160,7 @@ int ImageManager::add_image(const string& filename, bool animated, bool& is_floa
 | 
			
		||||
		/* add new image */
 | 
			
		||||
		img = new Image();
 | 
			
		||||
		img->filename = filename;
 | 
			
		||||
		img->is_builtin = is_builtin;
 | 
			
		||||
		img->need_load = true;
 | 
			
		||||
		img->animated = animated;
 | 
			
		||||
		img->users = 1;
 | 
			
		||||
@@ -184,6 +195,7 @@ int ImageManager::add_image(const string& filename, bool animated, bool& is_floa
 | 
			
		||||
		/* add new image */
 | 
			
		||||
		img = new Image();
 | 
			
		||||
		img->filename = filename;
 | 
			
		||||
		img->is_builtin = is_builtin;
 | 
			
		||||
		img->need_load = true;
 | 
			
		||||
		img->animated = animated;
 | 
			
		||||
		img->users = 1;
 | 
			
		||||
@@ -197,12 +209,12 @@ int ImageManager::add_image(const string& filename, bool animated, bool& is_floa
 | 
			
		||||
	return slot;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ImageManager::remove_image(const string& filename)
 | 
			
		||||
void ImageManager::remove_image(const string& filename, bool is_builtin)
 | 
			
		||||
{
 | 
			
		||||
	size_t slot;
 | 
			
		||||
 | 
			
		||||
	for(slot = 0; slot < images.size(); slot++) {
 | 
			
		||||
		if(images[slot] && images[slot]->filename == filename) {
 | 
			
		||||
		if(images[slot] && images[slot]->filename == filename && images[slot]->is_builtin == is_builtin) {
 | 
			
		||||
			/* decrement user count */
 | 
			
		||||
			images[slot]->users--;
 | 
			
		||||
			assert(images[slot]->users >= 0);
 | 
			
		||||
@@ -220,7 +232,7 @@ void ImageManager::remove_image(const string& filename)
 | 
			
		||||
	if(slot == images.size()) {
 | 
			
		||||
		/* see if it's in a float texture slot */
 | 
			
		||||
		for(slot = 0; slot < float_images.size(); slot++) {
 | 
			
		||||
			if(float_images[slot] && float_images[slot]->filename == filename) {
 | 
			
		||||
			if(float_images[slot] && float_images[slot]->filename == filename && float_images[slot]->is_builtin == is_builtin) {
 | 
			
		||||
				/* decrement user count */
 | 
			
		||||
				float_images[slot]->users--;
 | 
			
		||||
				assert(float_images[slot]->users >= 0);
 | 
			
		||||
@@ -242,27 +254,43 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
 | 
			
		||||
	if(img->filename == "")
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	/* load image from file through OIIO */
 | 
			
		||||
	ImageInput *in = ImageInput::create(img->filename);
 | 
			
		||||
	ImageInput *in = NULL;
 | 
			
		||||
	int width, height, components;
 | 
			
		||||
 | 
			
		||||
	if(!in)
 | 
			
		||||
		return false;
 | 
			
		||||
	if(!img->is_builtin) {
 | 
			
		||||
		/* load image from file through OIIO */
 | 
			
		||||
		in = ImageInput::create(img->filename);
 | 
			
		||||
 | 
			
		||||
	ImageSpec spec;
 | 
			
		||||
		if(!in)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
	if(!in->open(img->filename, spec)) {
 | 
			
		||||
		delete in;
 | 
			
		||||
		return false;
 | 
			
		||||
		ImageSpec spec;
 | 
			
		||||
 | 
			
		||||
		if(!in->open(img->filename, spec)) {
 | 
			
		||||
			delete in;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		width = spec.width;
 | 
			
		||||
		height = spec.height;
 | 
			
		||||
		components = spec.nchannels;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		/* load image using builtin images callbacks */
 | 
			
		||||
		if(!builtin_image_info_cb || !builtin_image_pixels_cb)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		bool is_float;
 | 
			
		||||
		builtin_image_info_cb(img->filename, is_float, width, height, components);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* we only handle certain number of components */
 | 
			
		||||
	int width = spec.width;
 | 
			
		||||
	int height = spec.height;
 | 
			
		||||
	int components = spec.nchannels;
 | 
			
		||||
 | 
			
		||||
	if(!(components == 1 || components == 3 || components == 4)) {
 | 
			
		||||
		in->close();
 | 
			
		||||
		delete in;
 | 
			
		||||
		if(in) {
 | 
			
		||||
			in->close();
 | 
			
		||||
			delete in;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -270,14 +298,19 @@ bool ImageManager::file_load_image(Image *img, device_vector<uchar4>& tex_img)
 | 
			
		||||
	uchar *pixels = (uchar*)tex_img.resize(width, height);
 | 
			
		||||
	int scanlinesize = width*components*sizeof(uchar);
 | 
			
		||||
 | 
			
		||||
	in->read_image(TypeDesc::UINT8,
 | 
			
		||||
		(uchar*)pixels + (height-1)*scanlinesize,
 | 
			
		||||
		AutoStride,
 | 
			
		||||
		-scanlinesize,
 | 
			
		||||
		AutoStride);
 | 
			
		||||
	if(in) {
 | 
			
		||||
		in->read_image(TypeDesc::UINT8,
 | 
			
		||||
			(uchar*)pixels + (height-1)*scanlinesize,
 | 
			
		||||
			AutoStride,
 | 
			
		||||
			-scanlinesize,
 | 
			
		||||
			AutoStride);
 | 
			
		||||
 | 
			
		||||
	in->close();
 | 
			
		||||
	delete in;
 | 
			
		||||
		in->close();
 | 
			
		||||
		delete in;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		builtin_image_pixels_cb(img->filename, pixels);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(components == 3) {
 | 
			
		||||
		for(int i = width*height-1; i >= 0; i--) {
 | 
			
		||||
@@ -304,27 +337,42 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
 | 
			
		||||
	if(img->filename == "")
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	/* load image from file through OIIO */
 | 
			
		||||
	ImageInput *in = ImageInput::create(img->filename);
 | 
			
		||||
	ImageInput *in = NULL;
 | 
			
		||||
	int width, height, components;
 | 
			
		||||
 | 
			
		||||
	if(!in)
 | 
			
		||||
		return false;
 | 
			
		||||
	if(!img->is_builtin) {
 | 
			
		||||
		/* load image from file through OIIO */
 | 
			
		||||
		in = ImageInput::create(img->filename);
 | 
			
		||||
 | 
			
		||||
	ImageSpec spec;
 | 
			
		||||
		if(!in)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
	if(!in->open(img->filename, spec)) {
 | 
			
		||||
		delete in;
 | 
			
		||||
		return false;
 | 
			
		||||
		ImageSpec spec;
 | 
			
		||||
 | 
			
		||||
		if(!in->open(img->filename, spec)) {
 | 
			
		||||
			delete in;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* we only handle certain number of components */
 | 
			
		||||
		width = spec.width;
 | 
			
		||||
		height = spec.height;
 | 
			
		||||
		components = spec.nchannels;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		/* load image using builtin images callbacks */
 | 
			
		||||
		if(!builtin_image_info_cb || !builtin_image_float_pixels_cb)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		bool is_float;
 | 
			
		||||
		builtin_image_info_cb(img->filename, is_float, width, height, components);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* we only handle certain number of components */
 | 
			
		||||
	int width = spec.width;
 | 
			
		||||
	int height = spec.height;
 | 
			
		||||
	int components = spec.nchannels;
 | 
			
		||||
 | 
			
		||||
	if(!(components == 1 || components == 3 || components == 4)) {
 | 
			
		||||
		in->close();
 | 
			
		||||
		delete in;
 | 
			
		||||
		if(in) {
 | 
			
		||||
			in->close();
 | 
			
		||||
			delete in;
 | 
			
		||||
		}
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -332,14 +380,19 @@ bool ImageManager::file_load_float_image(Image *img, device_vector<float4>& tex_
 | 
			
		||||
	float *pixels = (float*)tex_img.resize(width, height);
 | 
			
		||||
	int scanlinesize = width*components*sizeof(float);
 | 
			
		||||
 | 
			
		||||
	in->read_image(TypeDesc::FLOAT,
 | 
			
		||||
		(uchar*)pixels + (height-1)*scanlinesize,
 | 
			
		||||
		AutoStride,
 | 
			
		||||
		-scanlinesize,
 | 
			
		||||
		AutoStride);
 | 
			
		||||
	if(in) {
 | 
			
		||||
		in->read_image(TypeDesc::FLOAT,
 | 
			
		||||
			(uchar*)pixels + (height-1)*scanlinesize,
 | 
			
		||||
			AutoStride,
 | 
			
		||||
			-scanlinesize,
 | 
			
		||||
			AutoStride);
 | 
			
		||||
 | 
			
		||||
	in->close();
 | 
			
		||||
	delete in;
 | 
			
		||||
		in->close();
 | 
			
		||||
		delete in;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		builtin_image_float_pixels_cb(img->filename, pixels);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(components == 3) {
 | 
			
		||||
		for(int i = width*height-1; i >= 0; i--) {
 | 
			
		||||
 
 | 
			
		||||
@@ -51,9 +51,9 @@ public:
 | 
			
		||||
	ImageManager();
 | 
			
		||||
	~ImageManager();
 | 
			
		||||
 | 
			
		||||
	int add_image(const string& filename, bool animated, bool& is_float);
 | 
			
		||||
	void remove_image(const string& filename);
 | 
			
		||||
	bool is_float_image(const string& filename);
 | 
			
		||||
	int add_image(const string& filename, bool is_builtin, bool animated, bool& is_float);
 | 
			
		||||
	void remove_image(const string& filename, bool is_builtin);
 | 
			
		||||
	bool is_float_image(const string& filename, bool is_builtin);
 | 
			
		||||
 | 
			
		||||
	void device_update(Device *device, DeviceScene *dscene, Progress& progress);
 | 
			
		||||
	void device_free(Device *device, DeviceScene *dscene);
 | 
			
		||||
@@ -65,6 +65,9 @@ public:
 | 
			
		||||
 | 
			
		||||
	bool need_update;
 | 
			
		||||
 | 
			
		||||
	boost::function<void(const string &filename, bool &is_float, int &width, int &height, int &channels)> builtin_image_info_cb;
 | 
			
		||||
	boost::function<bool(const string &filename, unsigned char *pixels)> builtin_image_pixels_cb;
 | 
			
		||||
	boost::function<bool(const string &filename, float *pixels)> builtin_image_float_pixels_cb;
 | 
			
		||||
private:
 | 
			
		||||
	int tex_num_images;
 | 
			
		||||
	int tex_num_float_images;
 | 
			
		||||
@@ -74,6 +77,7 @@ private:
 | 
			
		||||
 | 
			
		||||
	struct Image {
 | 
			
		||||
		string filename;
 | 
			
		||||
		bool is_builtin;
 | 
			
		||||
 | 
			
		||||
		bool need_load;
 | 
			
		||||
		bool animated;
 | 
			
		||||
 
 | 
			
		||||
@@ -198,8 +198,10 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
 | 
			
		||||
		bool have_emission = false;
 | 
			
		||||
 | 
			
		||||
		/* skip if we are not visible for BSDFs */
 | 
			
		||||
		if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT)))
 | 
			
		||||
		if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) {
 | 
			
		||||
			j++;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* skip if we have no emission shaders */
 | 
			
		||||
		foreach(uint sindex, mesh->used_shaders) {
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,7 @@ Mesh::Mesh()
 | 
			
		||||
	need_update = true;
 | 
			
		||||
	transform_applied = false;
 | 
			
		||||
	transform_negative_scaled = false;
 | 
			
		||||
	transform_normal = transform_identity();
 | 
			
		||||
	displacement_method = DISPLACE_BUMP;
 | 
			
		||||
	bounds = BoundBox::empty;
 | 
			
		||||
 | 
			
		||||
@@ -94,6 +95,7 @@ void Mesh::clear()
 | 
			
		||||
 | 
			
		||||
	transform_applied = false;
 | 
			
		||||
	transform_negative_scaled = false;
 | 
			
		||||
	transform_normal = transform_identity();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
 | 
			
		||||
@@ -181,6 +183,14 @@ void Mesh::add_face_normals()
 | 
			
		||||
				fN[i] = -fN[i];
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* expected to be in local space */
 | 
			
		||||
	if(transform_applied) {
 | 
			
		||||
		Transform ntfm = transform_inverse(transform_normal);
 | 
			
		||||
 | 
			
		||||
		for(size_t i = 0; i < triangles_size; i++)
 | 
			
		||||
			fN[i] = normalize(transform_direction(&ntfm, fN[i]));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mesh::add_vertex_normals()
 | 
			
		||||
@@ -232,10 +242,18 @@ void Mesh::pack_normals(Scene *scene, float4 *normal, float4 *vnormal)
 | 
			
		||||
	size_t triangles_size = triangles.size();
 | 
			
		||||
	uint *shader_ptr = (shader.size())? &shader[0]: NULL;
 | 
			
		||||
 | 
			
		||||
	bool do_transform = transform_applied;
 | 
			
		||||
	Transform ntfm = transform_normal;
 | 
			
		||||
 | 
			
		||||
	for(size_t i = 0; i < triangles_size; i++) {
 | 
			
		||||
		normal[i].x = fN[i].x;
 | 
			
		||||
		normal[i].y = fN[i].y;
 | 
			
		||||
		normal[i].z = fN[i].z;
 | 
			
		||||
		float3 fNi = fN[i];
 | 
			
		||||
 | 
			
		||||
		if(do_transform)
 | 
			
		||||
			fNi = normalize(transform_direction(&ntfm, fNi));
 | 
			
		||||
 | 
			
		||||
		normal[i].x = fNi.x;
 | 
			
		||||
		normal[i].y = fNi.y;
 | 
			
		||||
		normal[i].z = fNi.z;
 | 
			
		||||
 | 
			
		||||
		/* stuff shader id in here too */
 | 
			
		||||
		if(shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
 | 
			
		||||
@@ -249,8 +267,14 @@ void Mesh::pack_normals(Scene *scene, float4 *normal, float4 *vnormal)
 | 
			
		||||
 | 
			
		||||
	size_t verts_size = verts.size();
 | 
			
		||||
 | 
			
		||||
	for(size_t i = 0; i < verts_size; i++)
 | 
			
		||||
		vnormal[i] = make_float4(vN[i].x, vN[i].y, vN[i].z, 0.0f);
 | 
			
		||||
	for(size_t i = 0; i < verts_size; i++) {
 | 
			
		||||
		float3 vNi = vN[i];
 | 
			
		||||
 | 
			
		||||
		if(do_transform)
 | 
			
		||||
			vNi = normalize(transform_direction(&ntfm, vNi));
 | 
			
		||||
 | 
			
		||||
		vnormal[i] = make_float4(vNi.x, vNi.y, vNi.z, 0.0f);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset)
 | 
			
		||||
 
 | 
			
		||||
@@ -90,6 +90,7 @@ public:
 | 
			
		||||
	BoundBox bounds;
 | 
			
		||||
	bool transform_applied;
 | 
			
		||||
	bool transform_negative_scaled;
 | 
			
		||||
	Transform transform_normal;
 | 
			
		||||
	DisplacementMethod displacement_method;
 | 
			
		||||
 | 
			
		||||
	/* Update Flags */
 | 
			
		||||
 
 | 
			
		||||
@@ -142,8 +142,9 @@ ImageTextureNode::ImageTextureNode()
 | 
			
		||||
	slot = -1;
 | 
			
		||||
	is_float = -1;
 | 
			
		||||
	filename = "";
 | 
			
		||||
	is_builtin = false;
 | 
			
		||||
	color_space = ustring("Color");
 | 
			
		||||
	projection = ustring("Flat");;
 | 
			
		||||
	projection = ustring("Flat");
 | 
			
		||||
	projection_blend = 0.0f;
 | 
			
		||||
	animated = false;
 | 
			
		||||
 | 
			
		||||
@@ -155,7 +156,7 @@ ImageTextureNode::ImageTextureNode()
 | 
			
		||||
ImageTextureNode::~ImageTextureNode()
 | 
			
		||||
{
 | 
			
		||||
	if(image_manager)
 | 
			
		||||
		image_manager->remove_image(filename);
 | 
			
		||||
		image_manager->remove_image(filename, is_builtin);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ShaderNode *ImageTextureNode::clone() const
 | 
			
		||||
@@ -176,7 +177,7 @@ void ImageTextureNode::compile(SVMCompiler& compiler)
 | 
			
		||||
	image_manager = compiler.image_manager;
 | 
			
		||||
	if(is_float == -1) {
 | 
			
		||||
		bool is_float_bool;
 | 
			
		||||
		slot = image_manager->add_image(filename, animated, is_float_bool);
 | 
			
		||||
		slot = image_manager->add_image(filename, is_builtin, animated, is_float_bool);
 | 
			
		||||
		is_float = (int)is_float_bool;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -237,7 +238,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler)
 | 
			
		||||
	tex_mapping.compile(compiler);
 | 
			
		||||
 | 
			
		||||
	if(is_float == -1)
 | 
			
		||||
		is_float = (int)image_manager->is_float_image(filename);
 | 
			
		||||
		is_float = (int)image_manager->is_float_image(filename, false);
 | 
			
		||||
 | 
			
		||||
	compiler.parameter("filename", filename.c_str());
 | 
			
		||||
	if(is_float || color_space != "Color")
 | 
			
		||||
@@ -271,6 +272,7 @@ EnvironmentTextureNode::EnvironmentTextureNode()
 | 
			
		||||
	slot = -1;
 | 
			
		||||
	is_float = -1;
 | 
			
		||||
	filename = "";
 | 
			
		||||
	is_builtin = false;
 | 
			
		||||
	color_space = ustring("Color");
 | 
			
		||||
	projection = ustring("Equirectangular");
 | 
			
		||||
	animated = false;
 | 
			
		||||
@@ -283,7 +285,7 @@ EnvironmentTextureNode::EnvironmentTextureNode()
 | 
			
		||||
EnvironmentTextureNode::~EnvironmentTextureNode()
 | 
			
		||||
{
 | 
			
		||||
	if(image_manager)
 | 
			
		||||
		image_manager->remove_image(filename);
 | 
			
		||||
		image_manager->remove_image(filename, is_builtin);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ShaderNode *EnvironmentTextureNode::clone() const
 | 
			
		||||
@@ -304,7 +306,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler)
 | 
			
		||||
	image_manager = compiler.image_manager;
 | 
			
		||||
	if(slot == -1) {
 | 
			
		||||
		bool is_float_bool;
 | 
			
		||||
		slot = image_manager->add_image(filename, animated, is_float_bool);
 | 
			
		||||
		slot = image_manager->add_image(filename, is_builtin, animated, is_float_bool);
 | 
			
		||||
		is_float = (int)is_float_bool;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -354,7 +356,7 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler)
 | 
			
		||||
	tex_mapping.compile(compiler);
 | 
			
		||||
 | 
			
		||||
	if(is_float == -1)
 | 
			
		||||
		is_float = (int)image_manager->is_float_image(filename);
 | 
			
		||||
		is_float = (int)image_manager->is_float_image(filename, false);
 | 
			
		||||
 | 
			
		||||
	compiler.parameter("filename", filename.c_str());
 | 
			
		||||
	compiler.parameter("projection", projection);
 | 
			
		||||
@@ -3255,6 +3257,8 @@ void NormalMapNode::attributes(AttributeRequestSet *attributes)
 | 
			
		||||
			attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
 | 
			
		||||
			attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		attributes->add(ATTR_STD_VERTEX_NORMAL);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	ShaderNode::attributes(attributes);
 | 
			
		||||
 
 | 
			
		||||
@@ -70,6 +70,7 @@ public:
 | 
			
		||||
	int slot;
 | 
			
		||||
	int is_float;
 | 
			
		||||
	string filename;
 | 
			
		||||
	bool is_builtin;
 | 
			
		||||
	ustring color_space;
 | 
			
		||||
	ustring projection;
 | 
			
		||||
	float projection_blend;
 | 
			
		||||
@@ -89,6 +90,7 @@ public:
 | 
			
		||||
	int slot;
 | 
			
		||||
	int is_float;
 | 
			
		||||
	string filename;
 | 
			
		||||
	bool is_builtin;
 | 
			
		||||
	ustring color_space;
 | 
			
		||||
	ustring projection;
 | 
			
		||||
	bool animated;
 | 
			
		||||
 
 | 
			
		||||
@@ -91,38 +91,16 @@ void Object::apply_transform()
 | 
			
		||||
	for(size_t i = 0; i < mesh->curve_keys.size(); i++)
 | 
			
		||||
		mesh->curve_keys[i].co = transform_point(&tfm, mesh->curve_keys[i].co);
 | 
			
		||||
 | 
			
		||||
	Attribute *attr_tangent = mesh->curve_attributes.find(ATTR_STD_CURVE_TANGENT);
 | 
			
		||||
	Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
 | 
			
		||||
	Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
 | 
			
		||||
 | 
			
		||||
	Transform ntfm = transform_transpose(transform_inverse(tfm));
 | 
			
		||||
	/* store matrix to transform later. when accessing these as attributes we
 | 
			
		||||
	 * do not want the transform to be applied for consistency between static
 | 
			
		||||
	 * and dynamic BVH, so we do it on packing. */
 | 
			
		||||
	mesh->transform_normal = transform_transpose(transform_inverse(tfm));
 | 
			
		||||
 | 
			
		||||
	/* we keep normals pointing in same direction on negative scale, notify
 | 
			
		||||
	 * mesh about this in it (re)calculates normals */
 | 
			
		||||
	if(transform_negative_scale(tfm))
 | 
			
		||||
		mesh->transform_negative_scaled = true;
 | 
			
		||||
 | 
			
		||||
	if(attr_fN) {
 | 
			
		||||
		float3 *fN = attr_fN->data_float3();
 | 
			
		||||
 | 
			
		||||
		for(size_t i = 0; i < mesh->triangles.size(); i++)
 | 
			
		||||
			fN[i] = transform_direction(&ntfm, fN[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(attr_vN) {
 | 
			
		||||
		float3 *vN = attr_vN->data_float3();
 | 
			
		||||
 | 
			
		||||
		for(size_t i = 0; i < mesh->verts.size(); i++)
 | 
			
		||||
			vN[i] = transform_direction(&ntfm, vN[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(attr_tangent) {
 | 
			
		||||
		float3 *tangent = attr_tangent->data_float3();
 | 
			
		||||
 | 
			
		||||
		for(size_t i = 0; i < mesh->curve_keys.size(); i++)
 | 
			
		||||
			tangent[i] = transform_direction(&tfm, tangent[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(bounds.valid()) {
 | 
			
		||||
		mesh->compute_bounds();
 | 
			
		||||
		compute_bounds(false, 0.0f);
 | 
			
		||||
 
 | 
			
		||||
@@ -376,21 +376,23 @@ bool cuLibraryInit()
 | 
			
		||||
	/* cuda 4.0 */
 | 
			
		||||
	CUDA_LIBRARY_FIND(cuCtxSetCurrent);
 | 
			
		||||
 | 
			
		||||
#ifndef WITH_CUDA_BINARIES
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	return false; /* runtime build doesn't work at the moment */
 | 
			
		||||
#else
 | 
			
		||||
	if(cuCompilerPath() == "")
 | 
			
		||||
		return false;
 | 
			
		||||
	if(cuHavePrecompiledKernels())
 | 
			
		||||
		result = true;
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
	else if(cuCompilerPath() != "")
 | 
			
		||||
		result = true;
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* success */
 | 
			
		||||
	result = true;
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cuHavePrecompiledKernels()
 | 
			
		||||
{
 | 
			
		||||
	string cubins_path = path_get("lib");
 | 
			
		||||
 | 
			
		||||
	return path_exists(cubins_path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
string cuCompilerPath()
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ CCL_NAMESPACE_BEGIN
 | 
			
		||||
 * matrixMulDynlinkJIT in the CUDA SDK. */
 | 
			
		||||
 | 
			
		||||
bool cuLibraryInit();
 | 
			
		||||
bool cuHavePrecompiledKernels();
 | 
			
		||||
string cuCompilerPath();
 | 
			
		||||
 | 
			
		||||
CCL_NAMESPACE_END
 | 
			
		||||
 
 | 
			
		||||
@@ -152,7 +152,6 @@ void TaskPool::num_increase()
 | 
			
		||||
thread_mutex TaskScheduler::mutex;
 | 
			
		||||
int TaskScheduler::users = 0;
 | 
			
		||||
vector<thread*> TaskScheduler::threads;
 | 
			
		||||
vector<int> TaskScheduler::thread_level;
 | 
			
		||||
volatile bool TaskScheduler::do_exit = false;
 | 
			
		||||
 | 
			
		||||
list<TaskScheduler::Entry> TaskScheduler::queue;
 | 
			
		||||
@@ -179,12 +178,9 @@ void TaskScheduler::init(int num_threads)
 | 
			
		||||
 | 
			
		||||
		/* launch threads that will be waiting for work */
 | 
			
		||||
		threads.resize(num_threads);
 | 
			
		||||
		thread_level.resize(num_threads);
 | 
			
		||||
 | 
			
		||||
		for(size_t i = 0; i < threads.size(); i++) {
 | 
			
		||||
		for(size_t i = 0; i < threads.size(); i++)
 | 
			
		||||
			threads[i] = new thread(function_bind(&TaskScheduler::thread_run, i));
 | 
			
		||||
			thread_level[i] = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	users++;
 | 
			
		||||
@@ -208,7 +204,6 @@ void TaskScheduler::exit()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		threads.clear();
 | 
			
		||||
		thread_level.clear();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,6 @@ protected:
 | 
			
		||||
	static thread_mutex mutex;
 | 
			
		||||
	static int users;
 | 
			
		||||
	static vector<thread*> threads;
 | 
			
		||||
	static vector<int> thread_level;
 | 
			
		||||
	static volatile bool do_exit;
 | 
			
		||||
 | 
			
		||||
	static list<Entry> queue;
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,8 @@
 | 
			
		||||
class VirtualMemoryAllocator
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
virtual ~VirtualMemoryAllocator() {}
 | 
			
		||||
 | 
			
		||||
virtual void *allocate( ) = 0;
 | 
			
		||||
virtual void deallocate(void *obj) = 0;
 | 
			
		||||
virtual void destroy( ) = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@
 | 
			
		||||
#include <libavcodec/avcodec.h>
 | 
			
		||||
#include <libavutil/rational.h>
 | 
			
		||||
#include <libavutil/opt.h>
 | 
			
		||||
#include <libavutil/mathematics.h>
 | 
			
		||||
 | 
			
		||||
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || ((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 101))
 | 
			
		||||
#define FFMPEG_HAVE_PARSE_UTILS 1
 | 
			
		||||
@@ -75,10 +76,68 @@
 | 
			
		||||
#define FFMPEG_FFV1_ALPHA_SUPPORTED
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ((LIBAVUTIL_VERSION_MAJOR < 51) || (LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR < 22))
 | 
			
		||||
static inline
 | 
			
		||||
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
 | 
			
		||||
{
 | 
			
		||||
	const AVOption *rv = NULL;
 | 
			
		||||
	av_set_string3(obj, name, val, 1, &rv);
 | 
			
		||||
	return rv != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline
 | 
			
		||||
int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
 | 
			
		||||
{
 | 
			
		||||
	const AVOption *rv = NULL;
 | 
			
		||||
	rv = av_set_int(obj, name, val);
 | 
			
		||||
	return rv != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline
 | 
			
		||||
int av_opt_set_double(void *obj, const char *name, double val, int search_flags)
 | 
			
		||||
{
 | 
			
		||||
	const AVOption *rv = NULL;
 | 
			
		||||
	rv = av_set_double(obj, name, val);
 | 
			
		||||
	return rv != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define AV_OPT_TYPE_INT     FF_OPT_TYPE_INT
 | 
			
		||||
#define AV_OPT_TYPE_INT64   FF_OPT_TYPE_INT64
 | 
			
		||||
#define AV_OPT_TYPE_STRING  FF_OPT_TYPE_STRING
 | 
			
		||||
#define AV_OPT_TYPE_CONST   FF_OPT_TYPE_CONST
 | 
			
		||||
#define AV_OPT_TYPE_DOUBLE  FF_OPT_TYPE_DOUBLE
 | 
			
		||||
#define AV_OPT_TYPE_FLOAT   FF_OPT_TYPE_FLOAT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ((LIBAVFORMAT_VERSION_MAJOR < 53) || ((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR < 24)) || ((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR < 24) && (LIBAVFORMAT_VERSION_MICRO < 2)))
 | 
			
		||||
#define avformat_close_input(x) av_close_input_file(*(x))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ((LIBAVCODEC_VERSION_MAJOR < 53) || (LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR < 35))
 | 
			
		||||
static inline
 | 
			
		||||
int avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVDictionary **options)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: no options are taking into account */
 | 
			
		||||
	return avcodec_open(avctx, codec);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ((LIBAVFORMAT_VERSION_MAJOR < 53) || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR < 21))
 | 
			
		||||
static inline
 | 
			
		||||
AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: no codec is taking into account */
 | 
			
		||||
	return av_new_stream(s, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline
 | 
			
		||||
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: no options are taking into account */
 | 
			
		||||
	return av_find_stream_info(ic);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ((LIBAVFORMAT_VERSION_MAJOR > 53) || ((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR > 32)) || ((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR == 24) && (LIBAVFORMAT_VERSION_MICRO >= 100)))
 | 
			
		||||
static inline
 | 
			
		||||
void my_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
 | 
			
		||||
 
 | 
			
		||||
@@ -860,7 +860,7 @@ extern int GHOST_UseNativePixels(void);
 | 
			
		||||
/**
 | 
			
		||||
 * If window was opened using native pixel size, it returns scaling factor.
 | 
			
		||||
 */
 | 
			
		||||
extern float GHOST_GetNativePixelSize(void);
 | 
			
		||||
extern float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 
 | 
			
		||||
@@ -297,10 +297,8 @@ public:
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
	 * Native pixel size support (MacBook 'retina').
 | 
			
		||||
	 * \return The pixel size in float.
 | 
			
		||||
	 */
 | 
			
		||||
	virtual bool useNativePixel(void) = 0;
 | 
			
		||||
	virtual float getNativePixelSize(void) = 0;
 | 
			
		||||
 | 
			
		||||
	/***************************************************************************************
 | 
			
		||||
	 * Event management functionality
 | 
			
		||||
 
 | 
			
		||||
@@ -305,6 +305,10 @@ public:
 | 
			
		||||
	 */
 | 
			
		||||
	virtual GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode, GHOST_Rect *bounds, GHOST_TInt32 mouse_ungrab_xy[2]) { return GHOST_kSuccess; }
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	virtual float getNativePixelSize(void) = 0;
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
#ifdef WITH_CXX_GUARDEDALLOC
 | 
			
		||||
	MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_IWindow")
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -183,6 +183,7 @@ typedef enum {
 | 
			
		||||
	GHOST_kEventDraggingDropDone,
 | 
			
		||||
	
 | 
			
		||||
	GHOST_kEventOpenMainFile, // Needed for Cocoa to open double-clicked .blend file at startup
 | 
			
		||||
	GHOST_kEventNativeResolutionChange, // Needed for Cocoa when window moves to other display
 | 
			
		||||
 | 
			
		||||
	GHOST_kEventTimer,
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -885,9 +885,11 @@ int GHOST_UseNativePixels(void)
 | 
			
		||||
	return system->useNativePixel();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float GHOST_GetNativePixelSize(void)
 | 
			
		||||
float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle)
 | 
			
		||||
{
 | 
			
		||||
	GHOST_ISystem *system = GHOST_ISystem::getSystem();
 | 
			
		||||
	return system->getNativePixelSize();
 | 
			
		||||
	GHOST_IWindow *window = (GHOST_IWindow *) windowhandle;
 | 
			
		||||
	if (window)
 | 
			
		||||
		return window->getNativePixelSize();
 | 
			
		||||
	return 1.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -58,12 +58,23 @@
 | 
			
		||||
#  define GHOST_PRINTF(x, ...)
 | 
			
		||||
#endif // GHOST_DEBUG
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef GHOST_DEBUG
 | 
			
		||||
#ifdef WITH_ASSERT_ABORT
 | 
			
		||||
#  include <stdio.h>  //for fprintf()
 | 
			
		||||
#  include <stdlib.h> //for abort()
 | 
			
		||||
#  define GHOST_ASSERT(x, info)                                               \
 | 
			
		||||
	{                                                                         \
 | 
			
		||||
		if (!(x)) {                                                           \
 | 
			
		||||
			fprintf(stderr, "GHOST_ASSERT failed: ");                         \
 | 
			
		||||
			fprintf(stderr, info);                                            \
 | 
			
		||||
			fprintf(stderr, "\n");                                            \
 | 
			
		||||
			abort();                                                          \
 | 
			
		||||
		}                                                                     \
 | 
			
		||||
	} (void)0
 | 
			
		||||
#elif defined(GHOST_DEBUG)
 | 
			
		||||
#  define GHOST_ASSERT(x, info)                                               \
 | 
			
		||||
	{                                                                         \
 | 
			
		||||
	    if (!(x)) {                                                           \
 | 
			
		||||
	        GHOST_PRINT("assertion failed: ");                                \
 | 
			
		||||
	        GHOST_PRINT("GHOST_ASSERT failed: ");                             \
 | 
			
		||||
	        GHOST_PRINT(info);                                                \
 | 
			
		||||
	        GHOST_PRINT("\n");                                                \
 | 
			
		||||
	    }                                                                     \
 | 
			
		||||
 
 | 
			
		||||
@@ -52,11 +52,15 @@ GHOST_DisplayManagerWin32::GHOST_DisplayManagerWin32(void)
 | 
			
		||||
 | 
			
		||||
GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplays(GHOST_TUns8& numDisplays) const
 | 
			
		||||
{
 | 
			
		||||
	// We do not support multiple monitors at the moment
 | 
			
		||||
	numDisplays = ::GetSystemMetrics(SM_CMONITORS);
 | 
			
		||||
	return numDisplays > 0 ? GHOST_kSuccess : GHOST_kFailure;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BOOL get_dd(DWORD d, DISPLAY_DEVICE* dd)
 | 
			
		||||
{
 | 
			
		||||
	dd->cb = sizeof(DISPLAY_DEVICE);
 | 
			
		||||
	return ::EnumDisplayDevices(NULL, d, dd, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * When you call EnumDisplaySettings with iModeNum set to zero, the operating system 
 | 
			
		||||
@@ -67,10 +71,12 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplays(GHOST_TUns8& numDisplay
 | 
			
		||||
 */
 | 
			
		||||
GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplaySettings(GHOST_TUns8 display, GHOST_TInt32& numSettings) const
 | 
			
		||||
{
 | 
			
		||||
	GHOST_ASSERT((display == kMainDisplay), "GHOST_DisplayManagerWin32::getNumDisplaySettings(): only main displlay is supported");
 | 
			
		||||
	DISPLAY_DEVICE display_device;
 | 
			
		||||
	if (!get_dd(display, &display_device)) return GHOST_kFailure;
 | 
			
		||||
 | 
			
		||||
	numSettings = 0;
 | 
			
		||||
	DEVMODE dm;
 | 
			
		||||
	while (::EnumDisplaySettings(NULL, numSettings, &dm)) {
 | 
			
		||||
	while (::EnumDisplaySettings(display_device.DeviceName, numSettings, &dm)) {
 | 
			
		||||
		numSettings++;
 | 
			
		||||
	}
 | 
			
		||||
	return GHOST_kSuccess;
 | 
			
		||||
@@ -79,10 +85,12 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getNumDisplaySettings(GHOST_TUns8 disp
 | 
			
		||||
 | 
			
		||||
GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display, GHOST_TInt32 index, GHOST_DisplaySetting& setting) const
 | 
			
		||||
{
 | 
			
		||||
	GHOST_ASSERT((display == kMainDisplay), "GHOST_DisplayManagerWin32::getDisplaySetting(): only main display is supported");
 | 
			
		||||
	DISPLAY_DEVICE display_device;
 | 
			
		||||
	if (!get_dd(display, &display_device)) return GHOST_kFailure;
 | 
			
		||||
 | 
			
		||||
	GHOST_TSuccess success;
 | 
			
		||||
	DEVMODE dm;
 | 
			
		||||
	if (::EnumDisplaySettings(NULL, index, &dm)) {
 | 
			
		||||
	if (::EnumDisplaySettings(display_device.DeviceName, index, &dm)) {
 | 
			
		||||
#ifdef GHOST_DEBUG
 | 
			
		||||
		printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n", dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency);
 | 
			
		||||
#endif // GHOST_DEBUG
 | 
			
		||||
@@ -112,23 +120,23 @@ GHOST_TSuccess GHOST_DisplayManagerWin32::getDisplaySetting(GHOST_TUns8 display,
 | 
			
		||||
 | 
			
		||||
GHOST_TSuccess GHOST_DisplayManagerWin32::getCurrentDisplaySetting(GHOST_TUns8 display, GHOST_DisplaySetting& setting) const
 | 
			
		||||
{
 | 
			
		||||
	GHOST_ASSERT((display == kMainDisplay), "GHOST_DisplayManagerWin32::getCurrentDisplaySetting(): only main display is supported");
 | 
			
		||||
	return getDisplaySetting(kMainDisplay, ENUM_CURRENT_SETTINGS, setting);
 | 
			
		||||
	return getDisplaySetting(display, ENUM_CURRENT_SETTINGS, setting);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GHOST_TSuccess GHOST_DisplayManagerWin32::setCurrentDisplaySetting(GHOST_TUns8 display, const GHOST_DisplaySetting& setting)
 | 
			
		||||
{
 | 
			
		||||
	GHOST_ASSERT((display == kMainDisplay), "GHOST_DisplayManagerWin32::setCurrentDisplaySetting(): only main display is supported");
 | 
			
		||||
	DISPLAY_DEVICE display_device;
 | 
			
		||||
	if (!get_dd(display, &display_device)) return GHOST_kFailure;
 | 
			
		||||
 | 
			
		||||
	GHOST_DisplaySetting match;
 | 
			
		||||
	findMatch(display, setting, match);
 | 
			
		||||
	DEVMODE dm;
 | 
			
		||||
	int i = 0;
 | 
			
		||||
	while (::EnumDisplaySettings(NULL, i++, &dm)) {
 | 
			
		||||
		if ((dm.dmBitsPerPel == match.bpp) &&
 | 
			
		||||
		    (dm.dmPelsWidth == match.xPixels) &&
 | 
			
		||||
		    (dm.dmPelsHeight == match.yPixels) &&
 | 
			
		||||
	while (::EnumDisplaySettings(display_device.DeviceName, i++, &dm)) {
 | 
			
		||||
		if ((dm.dmBitsPerPel       == match.bpp    ) &&
 | 
			
		||||
		    (dm.dmPelsWidth        == match.xPixels) &&
 | 
			
		||||
		    (dm.dmPelsHeight       == match.yPixels) &&
 | 
			
		||||
		    (dm.dmDisplayFrequency == match.frequency))
 | 
			
		||||
		{
 | 
			
		||||
			break;
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,6 @@
 | 
			
		||||
 | 
			
		||||
GHOST_System::GHOST_System()
 | 
			
		||||
	: m_nativePixel(false),
 | 
			
		||||
	m_nativePixelSize(1),
 | 
			
		||||
	m_displayManager(0),
 | 
			
		||||
	m_timerManager(0),
 | 
			
		||||
	m_windowManager(0),
 | 
			
		||||
@@ -382,9 +381,3 @@ bool GHOST_System::useNativePixel(void)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float GHOST_System::getNativePixelSize(void)
 | 
			
		||||
{
 | 
			
		||||
	if (m_nativePixel)
 | 
			
		||||
		return m_nativePixelSize;
 | 
			
		||||
	return 1.0f;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -175,9 +175,6 @@ public:
 | 
			
		||||
	virtual bool useNativePixel(void);
 | 
			
		||||
	bool m_nativePixel;
 | 
			
		||||
 | 
			
		||||
	virtual float getNativePixelSize(void);
 | 
			
		||||
	float m_nativePixelSize;
 | 
			
		||||
 | 
			
		||||
	/***************************************************************************************
 | 
			
		||||
	 * Event management functionality
 | 
			
		||||
	 ***************************************************************************************/
 | 
			
		||||
 
 | 
			
		||||
@@ -1038,6 +1038,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
 | 
			
		||||
				pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) );
 | 
			
		||||
				break;
 | 
			
		||||
			case GHOST_kEventWindowUpdate:
 | 
			
		||||
				if (m_nativePixel) {
 | 
			
		||||
					window->setNativePixelSize();
 | 
			
		||||
					pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventNativeResolutionChange, window) );
 | 
			
		||||
				}
 | 
			
		||||
				pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
 | 
			
		||||
				break;
 | 
			
		||||
			case GHOST_kEventWindowMove:
 | 
			
		||||
@@ -1054,6 +1058,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
 | 
			
		||||
					//m_ignoreWindowSizedMessages = true;
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
			case GHOST_kEventNativeResolutionChange:
 | 
			
		||||
				
 | 
			
		||||
				if (m_nativePixel) {
 | 
			
		||||
					window->setNativePixelSize();
 | 
			
		||||
					pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventNativeResolutionChange, window) );
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				return GHOST_kFailure;
 | 
			
		||||
				break;
 | 
			
		||||
@@ -1592,7 +1603,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
			
 | 
			
		||||
			/* these events only happen on swiping trackpads */
 | 
			
		||||
			/* these events only happen on swiping trackpads or tablets */
 | 
			
		||||
			/* warning: using tablet + trackpad at same time frustrates this static variable */
 | 
			
		||||
		case NSEventTypeBeginGesture:
 | 
			
		||||
			m_hasMultiTouchTrackpad = 1;
 | 
			
		||||
			break;
 | 
			
		||||
@@ -1626,10 +1638,18 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
 | 
			
		||||
					double dy;
 | 
			
		||||
					
 | 
			
		||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
 | 
			
		||||
					int phase = [event phase];
 | 
			
		||||
					
 | 
			
		||||
					/* with 10.7 nice scrolling deltas are supported */
 | 
			
		||||
					dx = [event scrollingDeltaX];
 | 
			
		||||
					dy = [event scrollingDeltaY];
 | 
			
		||||
					
 | 
			
		||||
					/* however, wacom tablet (intuos5) needs old deltas, it then has momentum and phase at zero */
 | 
			
		||||
					if (phase == 0 && momentum==NULL) {
 | 
			
		||||
						dx = [event deltaX];
 | 
			
		||||
						dy = [event deltaY];
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
					/* trying to pretend you have nice scrolls... */
 | 
			
		||||
					dx = [event deltaX];
 | 
			
		||||
 
 | 
			
		||||
@@ -783,8 +783,8 @@ GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType,
 | 
			
		||||
 | 
			
		||||
void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO *minmax)
 | 
			
		||||
{
 | 
			
		||||
	minmax->ptMinTrackSize.x = 640;
 | 
			
		||||
	minmax->ptMinTrackSize.y = 480;
 | 
			
		||||
	minmax->ptMinTrackSize.x = 320;
 | 
			
		||||
	minmax->ptMinTrackSize.y = 240;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_INPUT_NDOF
 | 
			
		||||
 
 | 
			
		||||
@@ -69,8 +69,10 @@
 | 
			
		||||
#include <stdio.h> /* for fprintf only */
 | 
			
		||||
#include <cstdlib> /* for exit */
 | 
			
		||||
 | 
			
		||||
static GHOST_TKey
 | 
			
		||||
convertXKey(KeySym key);
 | 
			
		||||
/* for debugging - so we can breakpoint X11 errors */
 | 
			
		||||
// #define USE_X11_ERROR_HANDLERS
 | 
			
		||||
 | 
			
		||||
static GHOST_TKey convertXKey(KeySym key);
 | 
			
		||||
 | 
			
		||||
/* these are for copy and select copy */
 | 
			
		||||
static char *txt_cut_buffer = NULL;
 | 
			
		||||
@@ -91,6 +93,11 @@ GHOST_SystemX11(
 | 
			
		||||
		abort(); /* was return before, but this would just mean it will crash later */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef USE_X11_ERROR_HANDLERS
 | 
			
		||||
	(void) XSetErrorHandler(GHOST_X11_ApplicationErrorHandler);
 | 
			
		||||
	(void) XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
 | 
			
		||||
	/* note -- don't open connection to XIM server here, because the locale
 | 
			
		||||
	 * has to be set before opening the connection but setlocale() has not
 | 
			
		||||
@@ -146,6 +153,12 @@ GHOST_SystemX11(
 | 
			
		||||
		XkbSetDetectableAutoRepeat(m_display, true, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	/* initialize incase X11 fails to load */
 | 
			
		||||
	memset(&m_xtablet, 0, sizeof(m_xtablet));
 | 
			
		||||
 | 
			
		||||
	initXInputDevices();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GHOST_SystemX11::
 | 
			
		||||
@@ -157,6 +170,15 @@ GHOST_SystemX11::
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	/* close tablet devices */
 | 
			
		||||
	if (m_xtablet.StylusDevice)
 | 
			
		||||
		XCloseDevice(m_display, m_xtablet.StylusDevice);
 | 
			
		||||
	
 | 
			
		||||
	if (m_xtablet.EraserDevice)
 | 
			
		||||
		XCloseDevice(m_display, m_xtablet.EraserDevice);
 | 
			
		||||
#endif /* WITH_X11_XINPUT */
 | 
			
		||||
 | 
			
		||||
	XCloseDisplay(m_display);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -494,12 +516,52 @@ processEvents(
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
/* set currently using tablet mode (stylus or eraser) depending on device ID */
 | 
			
		||||
static void setTabletMode(GHOST_WindowX11 *window, XID deviceid)
 | 
			
		||||
static void setTabletMode(GHOST_SystemX11 *system, GHOST_WindowX11 *window, XID deviceid)
 | 
			
		||||
{
 | 
			
		||||
	if (deviceid == window->GetXTablet().StylusID)
 | 
			
		||||
		window->GetXTablet().CommonData.Active = GHOST_kTabletModeStylus;
 | 
			
		||||
	else if (deviceid == window->GetXTablet().EraserID)
 | 
			
		||||
		window->GetXTablet().CommonData.Active = GHOST_kTabletModeEraser;
 | 
			
		||||
	if (deviceid == system->GetXTablet().StylusID)
 | 
			
		||||
		window->GetTabletData()->Active = GHOST_kTabletModeStylus;
 | 
			
		||||
	else if (deviceid == system->GetXTablet().EraserID)
 | 
			
		||||
		window->GetTabletData()->Active = GHOST_kTabletModeEraser;
 | 
			
		||||
}
 | 
			
		||||
#endif /* WITH_X11_XINPUT */
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
static bool checkTabletProximity(Display *display, XDevice *device)
 | 
			
		||||
{
 | 
			
		||||
	/* we could have true/false/not-found return value, but for now false is OK */
 | 
			
		||||
 | 
			
		||||
	/* see: state.c from xinput, to get more data out of the device */
 | 
			
		||||
	XDeviceState *state;
 | 
			
		||||
 | 
			
		||||
	if (device == NULL) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	state = XQueryDeviceState(display, device);
 | 
			
		||||
 | 
			
		||||
	if (state) {
 | 
			
		||||
		XInputClass *cls = state->data;
 | 
			
		||||
		// printf("%d class%s :\n", state->num_classes,
 | 
			
		||||
		//       (state->num_classes > 1) ? "es" : "");
 | 
			
		||||
		for (int loop = 0; loop < state->num_classes; loop++) {
 | 
			
		||||
			switch (cls->c_class) {
 | 
			
		||||
				case ValuatorClass:
 | 
			
		||||
					XValuatorState *val_state = (XValuatorState *)cls;
 | 
			
		||||
					// printf("ValuatorClass Mode=%s Proximity=%s\n",
 | 
			
		||||
					//        val_state->mode & 1 ? "Absolute" : "Relative",
 | 
			
		||||
					//        val_state->mode & 2 ? "Out" : "In");
 | 
			
		||||
 | 
			
		||||
					if ((val_state->mode & 2) == 0) {
 | 
			
		||||
						XFreeDeviceState(state);
 | 
			
		||||
						return true;
 | 
			
		||||
					}
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
			cls = (XInputClass *) ((char *)cls + cls->length);
 | 
			
		||||
		}
 | 
			
		||||
		XFreeDeviceState(state);
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
#endif /* WITH_X11_XINPUT */
 | 
			
		||||
 | 
			
		||||
@@ -513,6 +575,22 @@ GHOST_SystemX11::processEvent(XEvent *xe)
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	/* Proximity-Out Events are not reliable, if the tablet is active - check on each event
 | 
			
		||||
	 * this adds a little overhead but only while the tablet is in use.
 | 
			
		||||
	 * in the futire we could have a ghost call window->CheckTabletProximity()
 | 
			
		||||
	 * but for now enough parts of the code are checking 'Active'
 | 
			
		||||
	 * - campbell */
 | 
			
		||||
	if (window->GetTabletData()->Active != GHOST_kTabletModeNone) {
 | 
			
		||||
		if (checkTabletProximity(xe->xany.display, m_xtablet.StylusDevice) == false &&
 | 
			
		||||
		    checkTabletProximity(xe->xany.display, m_xtablet.EraserDevice) == false)
 | 
			
		||||
		{
 | 
			
		||||
			// printf("proximity disable\n");
 | 
			
		||||
			window->GetTabletData()->Active = GHOST_kTabletModeNone;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif /* WITH_X11_XINPUT */
 | 
			
		||||
 | 
			
		||||
	switch (xe->type) {
 | 
			
		||||
		case Expose:
 | 
			
		||||
		{
 | 
			
		||||
@@ -537,7 +615,7 @@ GHOST_SystemX11::processEvent(XEvent *xe)
 | 
			
		||||
			XMotionEvent &xme = xe->xmotion;
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
			bool is_tablet = window->GetXTablet().CommonData.Active != GHOST_kTabletModeNone;
 | 
			
		||||
			bool is_tablet = window->GetTabletData()->Active != GHOST_kTabletModeNone;
 | 
			
		||||
#else
 | 
			
		||||
			bool is_tablet = false;
 | 
			
		||||
#endif
 | 
			
		||||
@@ -983,31 +1061,31 @@ GHOST_SystemX11::processEvent(XEvent *xe)
 | 
			
		||||
		
 | 
			
		||||
		default: {
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
			if (xe->type == window->GetXTablet().MotionEvent) {
 | 
			
		||||
			if (xe->type == m_xtablet.MotionEvent) {
 | 
			
		||||
				XDeviceMotionEvent *data = (XDeviceMotionEvent *)xe;
 | 
			
		||||
 | 
			
		||||
				/* stroke might begin without leading ProxyIn event,
 | 
			
		||||
				 * this happens when window is opened when stylus is already hovering
 | 
			
		||||
				 * around tablet surface */
 | 
			
		||||
				setTabletMode(window, data->deviceid);
 | 
			
		||||
				setTabletMode(this, window, data->deviceid);
 | 
			
		||||
 | 
			
		||||
				window->GetXTablet().CommonData.Pressure =
 | 
			
		||||
				        data->axis_data[2] / ((float)window->GetXTablet().PressureLevels);
 | 
			
		||||
				window->GetTabletData()->Pressure =
 | 
			
		||||
				        data->axis_data[2] / ((float)m_xtablet.PressureLevels);
 | 
			
		||||
 | 
			
		||||
				/* the (short) cast and the &0xffff is bizarre and unexplained anywhere,
 | 
			
		||||
				 * but I got garbage data without it. Found it in the xidump.c source --matt */
 | 
			
		||||
				window->GetXTablet().CommonData.Xtilt =
 | 
			
		||||
				        (short)(data->axis_data[3] & 0xffff) / ((float)window->GetXTablet().XtiltLevels);
 | 
			
		||||
				window->GetXTablet().CommonData.Ytilt =
 | 
			
		||||
				        (short)(data->axis_data[4] & 0xffff) / ((float)window->GetXTablet().YtiltLevels);
 | 
			
		||||
				window->GetTabletData()->Xtilt =
 | 
			
		||||
				        (short)(data->axis_data[3] & 0xffff) / ((float)m_xtablet.XtiltLevels);
 | 
			
		||||
				window->GetTabletData()->Ytilt =
 | 
			
		||||
				        (short)(data->axis_data[4] & 0xffff) / ((float)m_xtablet.YtiltLevels);
 | 
			
		||||
			}
 | 
			
		||||
			else if (xe->type == window->GetXTablet().ProxInEvent) {
 | 
			
		||||
			else if (xe->type == m_xtablet.ProxInEvent) {
 | 
			
		||||
				XProximityNotifyEvent *data = (XProximityNotifyEvent *)xe;
 | 
			
		||||
 | 
			
		||||
				setTabletMode(window, data->deviceid);
 | 
			
		||||
				setTabletMode(this, window, data->deviceid);
 | 
			
		||||
			}
 | 
			
		||||
			else if (xe->type == window->GetXTablet().ProxOutEvent) {
 | 
			
		||||
				window->GetXTablet().CommonData.Active = GHOST_kTabletModeNone;
 | 
			
		||||
			else if (xe->type == m_xtablet.ProxOutEvent) {
 | 
			
		||||
				window->GetTabletData()->Active = GHOST_kTabletModeNone;
 | 
			
		||||
			}
 | 
			
		||||
#endif // WITH_X11_XINPUT
 | 
			
		||||
			break;
 | 
			
		||||
@@ -1648,3 +1726,197 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
 | 
			
		||||
	                         );
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
/* 
 | 
			
		||||
 * Dummy function to get around IO Handler exiting if device invalid
 | 
			
		||||
 * Basically it will not crash blender now if you have a X device that
 | 
			
		||||
 * is configured but not plugged in.
 | 
			
		||||
 */
 | 
			
		||||
int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n",
 | 
			
		||||
	        theEvent->error_code, theEvent->request_code);
 | 
			
		||||
 | 
			
		||||
	/* No exit! - but keep lint happy */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int GHOST_X11_ApplicationIOErrorHandler(Display *display)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "Ignoring Xlib error: error IO\n");
 | 
			
		||||
 | 
			
		||||
	/* No exit! - but keep lint happy */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* These C functions are copied from Wine 1.1.13's wintab.c */
 | 
			
		||||
#define BOOL int
 | 
			
		||||
#define TRUE 1
 | 
			
		||||
#define FALSE 0
 | 
			
		||||
 | 
			
		||||
static bool match_token(const char *haystack, const char *needle)
 | 
			
		||||
{
 | 
			
		||||
	const char *p, *q;
 | 
			
		||||
	for (p = haystack; *p; )
 | 
			
		||||
	{
 | 
			
		||||
		while (*p && isspace(*p))
 | 
			
		||||
			p++;
 | 
			
		||||
		if (!*p)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		for (q = needle; *q && *p && tolower(*p) == tolower(*q); q++)
 | 
			
		||||
			p++;
 | 
			
		||||
		if (!*q && (isspace(*p) || !*p))
 | 
			
		||||
			return TRUE;
 | 
			
		||||
 | 
			
		||||
		while (*p && !isspace(*p))
 | 
			
		||||
			p++;
 | 
			
		||||
	}
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Determining if an X device is a Tablet style device is an imperfect science.
 | 
			
		||||
 * We rely on common conventions around device names as well as the type reported
 | 
			
		||||
 * by Wacom tablets.  This code will likely need to be expanded for alternate tablet types
 | 
			
		||||
 *
 | 
			
		||||
 * Wintab refers to any device that interacts with the tablet as a cursor,
 | 
			
		||||
 * (stylus, eraser, tablet mouse, airbrush, etc)
 | 
			
		||||
 * this is not to be confused with wacom x11 configuration "cursor" device.
 | 
			
		||||
 * Wacoms x11 config "cursor" refers to its device slot (which we mirror with
 | 
			
		||||
 * our gSysCursors) for puck like devices (tablet mice essentially).
 | 
			
		||||
 */
 | 
			
		||||
#if 0 // unused
 | 
			
		||||
static BOOL is_tablet_cursor(const char *name, const char *type)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	static const char *tablet_cursor_whitelist[] = {
 | 
			
		||||
		"wacom",
 | 
			
		||||
		"wizardpen",
 | 
			
		||||
		"acecad",
 | 
			
		||||
		"tablet",
 | 
			
		||||
		"cursor",
 | 
			
		||||
		"stylus",
 | 
			
		||||
		"eraser",
 | 
			
		||||
		"pad",
 | 
			
		||||
		NULL
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	for (i = 0; tablet_cursor_whitelist[i] != NULL; i++) {
 | 
			
		||||
		if (name && match_token(name, tablet_cursor_whitelist[i]))
 | 
			
		||||
			return TRUE;
 | 
			
		||||
		if (type && match_token(type, tablet_cursor_whitelist[i]))
 | 
			
		||||
			return TRUE;
 | 
			
		||||
	}
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
static BOOL is_stylus(const char *name, const char *type)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	static const char *tablet_stylus_whitelist[] = {
 | 
			
		||||
		"stylus",
 | 
			
		||||
		"wizardpen",
 | 
			
		||||
		"acecad",
 | 
			
		||||
		NULL
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	for (i = 0; tablet_stylus_whitelist[i] != NULL; i++) {
 | 
			
		||||
		if (name && match_token(name, tablet_stylus_whitelist[i]))
 | 
			
		||||
			return TRUE;
 | 
			
		||||
		if (type && match_token(type, tablet_stylus_whitelist[i]))
 | 
			
		||||
			return TRUE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BOOL is_eraser(const char *name, const char *type)
 | 
			
		||||
{
 | 
			
		||||
	if (name && match_token(name, "eraser"))
 | 
			
		||||
		return TRUE;
 | 
			
		||||
	if (type && match_token(type, "eraser"))
 | 
			
		||||
		return TRUE;
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
#undef BOOL
 | 
			
		||||
#undef TRUE
 | 
			
		||||
#undef FALSE
 | 
			
		||||
/* end code copied from wine */
 | 
			
		||||
 | 
			
		||||
void GHOST_SystemX11::initXInputDevices()
 | 
			
		||||
{
 | 
			
		||||
	static XErrorHandler   old_handler = (XErrorHandler) 0;
 | 
			
		||||
	static XIOErrorHandler old_handler_io = (XIOErrorHandler) 0;
 | 
			
		||||
 | 
			
		||||
	XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
 | 
			
		||||
 | 
			
		||||
	if (version && (version != (XExtensionVersion *)NoSuchExtension)) {
 | 
			
		||||
		if (version->present) {
 | 
			
		||||
			int device_count;
 | 
			
		||||
			XDeviceInfo *device_info = XListInputDevices(m_display, &device_count);
 | 
			
		||||
			m_xtablet.StylusDevice = NULL;
 | 
			
		||||
			m_xtablet.EraserDevice = NULL;
 | 
			
		||||
 | 
			
		||||
			/* Install our error handler to override Xlib's termination behavior */
 | 
			
		||||
			old_handler = XSetErrorHandler(GHOST_X11_ApplicationErrorHandler);
 | 
			
		||||
			old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
 | 
			
		||||
 | 
			
		||||
			for (int i = 0; i < device_count; ++i) {
 | 
			
		||||
				char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) : NULL;
 | 
			
		||||
				
 | 
			
		||||
//				printf("Tablet type:'%s', name:'%s', index:%d\n", device_type, device_info[i].name, i);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
				if (m_xtablet.StylusDevice == NULL && is_stylus(device_info[i].name, device_type)) {
 | 
			
		||||
//					printf("\tfound stylus\n");
 | 
			
		||||
					m_xtablet.StylusID = device_info[i].id;
 | 
			
		||||
					m_xtablet.StylusDevice = XOpenDevice(m_display, m_xtablet.StylusID);
 | 
			
		||||
 | 
			
		||||
					if (m_xtablet.StylusDevice != NULL) {
 | 
			
		||||
						/* Find how many pressure levels tablet has */
 | 
			
		||||
						XAnyClassPtr ici = device_info[i].inputclassinfo;
 | 
			
		||||
						for (int j = 0; j < m_xtablet.StylusDevice->num_classes; ++j) {
 | 
			
		||||
							if (ici->c_class == ValuatorClass) {
 | 
			
		||||
//								printf("\t\tfound ValuatorClass\n");
 | 
			
		||||
								XValuatorInfo *xvi = (XValuatorInfo *)ici;
 | 
			
		||||
								m_xtablet.PressureLevels = xvi->axes[2].max_value;
 | 
			
		||||
							
 | 
			
		||||
								/* this is assuming that the tablet has the same tilt resolution in both
 | 
			
		||||
								 * positive and negative directions. It would be rather weird if it didn't.. */
 | 
			
		||||
								m_xtablet.XtiltLevels = xvi->axes[3].max_value;
 | 
			
		||||
								m_xtablet.YtiltLevels = xvi->axes[4].max_value;
 | 
			
		||||
								break;
 | 
			
		||||
							}
 | 
			
		||||
						
 | 
			
		||||
							ici = (XAnyClassPtr)(((char *)ici) + ici->length);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						m_xtablet.StylusID = 0;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else if (m_xtablet.EraserDevice == NULL && is_eraser(device_info[i].name, device_type)) {
 | 
			
		||||
//					printf("\tfound eraser\n");
 | 
			
		||||
					m_xtablet.EraserID = device_info[i].id;
 | 
			
		||||
					m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID);
 | 
			
		||||
					if (m_xtablet.EraserDevice == NULL) m_xtablet.EraserID = 0;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (device_type) {
 | 
			
		||||
					XFree((void *)device_type);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* Restore handler */
 | 
			
		||||
			(void) XSetErrorHandler(old_handler);
 | 
			
		||||
			(void) XSetIOErrorHandler(old_handler_io);
 | 
			
		||||
 | 
			
		||||
			XFreeDeviceList(device_info);
 | 
			
		||||
		}
 | 
			
		||||
		XFree(version);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* WITH_X11_XINPUT */
 | 
			
		||||
 
 | 
			
		||||
@@ -39,11 +39,19 @@
 | 
			
		||||
#include "GHOST_System.h"
 | 
			
		||||
#include "../GHOST_Types.h"
 | 
			
		||||
 | 
			
		||||
// For tablets
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
#  include <X11/extensions/XInput.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
 | 
			
		||||
#  define GHOST_X11_RES_NAME  "Blender" /* res_name */
 | 
			
		||||
#  define GHOST_X11_RES_CLASS "Blender" /* res_class */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* generic error handlers */
 | 
			
		||||
int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent);
 | 
			
		||||
int GHOST_X11_ApplicationIOErrorHandler(Display *display);
 | 
			
		||||
 | 
			
		||||
class GHOST_WindowX11;
 | 
			
		||||
 | 
			
		||||
@@ -284,6 +292,27 @@ public:
 | 
			
		||||
	Atom m_incr;
 | 
			
		||||
	Atom m_utf8_string;
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	typedef struct GHOST_TabletX11 {
 | 
			
		||||
		XDevice *StylusDevice;
 | 
			
		||||
		XDevice *EraserDevice;
 | 
			
		||||
 | 
			
		||||
		XID StylusID, EraserID;
 | 
			
		||||
 | 
			
		||||
		int MotionEvent;
 | 
			
		||||
		int ProxInEvent;
 | 
			
		||||
		int ProxOutEvent;
 | 
			
		||||
 | 
			
		||||
		int PressureLevels;
 | 
			
		||||
		int XtiltLevels, YtiltLevels;
 | 
			
		||||
	} GHOST_TabletX11;
 | 
			
		||||
 | 
			
		||||
	GHOST_TabletX11 &GetXTablet()
 | 
			
		||||
	{
 | 
			
		||||
		return m_xtablet;
 | 
			
		||||
	}
 | 
			
		||||
#endif // WITH_X11_XINPUT
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
	Display *m_display;
 | 
			
		||||
@@ -291,6 +320,11 @@ private:
 | 
			
		||||
	XIM m_xim;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	/* Tablet devices */
 | 
			
		||||
	GHOST_TabletX11 m_xtablet;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/// The vector of windows that need to be updated.
 | 
			
		||||
	std::vector<GHOST_WindowX11 *> m_dirty_windows;
 | 
			
		||||
 | 
			
		||||
@@ -313,6 +347,10 @@ private:
 | 
			
		||||
	bool openX11_IM();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	void initXInputDevices();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	GHOST_WindowX11 *
 | 
			
		||||
	findGhostWindow(
 | 
			
		||||
	    Window xwind
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,8 @@ GHOST_Window::GHOST_Window(
 | 
			
		||||
	m_cursorGrabAccumPos[0] = 0;
 | 
			
		||||
	m_cursorGrabAccumPos[1] = 0;
 | 
			
		||||
	
 | 
			
		||||
	m_nativePixelSize = 1.0f;
 | 
			
		||||
 | 
			
		||||
	m_fullScreen = state == GHOST_kWindowStateFullScreen;
 | 
			
		||||
	if (m_fullScreen) {
 | 
			
		||||
		m_fullScreenWidth = width;
 | 
			
		||||
@@ -194,3 +196,4 @@ bool GHOST_Window::getModifiedState()
 | 
			
		||||
{
 | 
			
		||||
	return m_isUnsavedChanges;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -258,6 +258,13 @@ public:
 | 
			
		||||
		m_userData = userData;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	virtual float getNativePixelSize(void)
 | 
			
		||||
	{
 | 
			
		||||
		if (m_nativePixelSize > 0.0f)
 | 
			
		||||
			return m_nativePixelSize;
 | 
			
		||||
		return 1.0f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tries to install a rendering context in this window.
 | 
			
		||||
@@ -351,6 +358,9 @@ protected:
 | 
			
		||||
	GHOST_TUns32 m_fullScreenWidth;
 | 
			
		||||
	/** Full-screen height */
 | 
			
		||||
	GHOST_TUns32 m_fullScreenHeight;
 | 
			
		||||
	
 | 
			
		||||
	/* OSX only, retina screens */
 | 
			
		||||
	float m_nativePixelSize;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -182,7 +182,8 @@ GHOST_WindowCarbon::GHOST_WindowCarbon(
 | 
			
		||||
		    (SInt32) this);                     // Store a pointer to the class in the refCon
 | 
			
		||||
#endif
 | 
			
		||||
		//GHOST_PRINT("GHOST_WindowCarbon::GHOST_WindowCarbon(): creating full-screen OpenGL context\n");
 | 
			
		||||
		setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);; installDrawingContext(GHOST_kDrawingContextTypeOpenGL);
 | 
			
		||||
		setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);
 | 
			
		||||
		installDrawingContext(GHOST_kDrawingContextTypeOpenGL);
 | 
			
		||||
		updateDrawingContext();
 | 
			
		||||
		activateDrawingContext();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -262,6 +262,11 @@ public:
 | 
			
		||||
	 * Hides the progress bar icon
 | 
			
		||||
	 */
 | 
			
		||||
	virtual GHOST_TSuccess endProgressBar();
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	virtual void setNativePixelSize(void);
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
protected:
 | 
			
		||||
	/**
 | 
			
		||||
	 * Tries to install a rendering context in this window.
 | 
			
		||||
 
 | 
			
		||||
@@ -74,8 +74,10 @@ extern "C" {
 | 
			
		||||
- (void)windowDidMove:(NSNotification *)notification;
 | 
			
		||||
- (void)windowWillMove:(NSNotification *)notification;
 | 
			
		||||
- (BOOL)windowShouldClose:(id)sender;	
 | 
			
		||||
- (void)windowDidChangeBackingProperties:(NSNotification *)notification;
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@implementation CocoaWindowDelegate : NSObject
 | 
			
		||||
- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa
 | 
			
		||||
{
 | 
			
		||||
@@ -128,6 +130,11 @@ extern "C" {
 | 
			
		||||
	}*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)windowDidChangeBackingProperties:(NSNotification *)notification
 | 
			
		||||
{
 | 
			
		||||
	systemCocoa->handleWindowEvent(GHOST_kEventNativeResolutionChange, associatedWindow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)windowShouldClose:(id)sender;
 | 
			
		||||
{
 | 
			
		||||
	//Let Blender close the window rather than closing immediately
 | 
			
		||||
@@ -481,8 +488,8 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
 | 
			
		||||
	[m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
 | 
			
		||||
	
 | 
			
		||||
	//Forbid to resize the window below the blender defined minimum one
 | 
			
		||||
	minSize.width = 640;
 | 
			
		||||
	minSize.height = 480;
 | 
			
		||||
	minSize.width = 320;
 | 
			
		||||
	minSize.height = 240;
 | 
			
		||||
	[m_window setContentMinSize:minSize];
 | 
			
		||||
	
 | 
			
		||||
	setTitle(title);
 | 
			
		||||
@@ -593,7 +600,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(
 | 
			
		||||
			[m_openGLView setWantsBestResolutionOpenGLSurface:YES];
 | 
			
		||||
		
 | 
			
		||||
			NSRect backingBounds = [m_openGLView convertRectToBacking:[m_openGLView bounds]];
 | 
			
		||||
			m_systemCocoa->m_nativePixelSize = (float)backingBounds.size.width / (float)rect.size.width;
 | 
			
		||||
			m_nativePixelSize = (float)backingBounds.size.width / (float)rect.size.width;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
@@ -911,6 +918,19 @@ NSScreen* GHOST_WindowCocoa::getScreen()
 | 
			
		||||
	return [m_window screen];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* called for event, when window leaves monitor to another */
 | 
			
		||||
void GHOST_WindowCocoa::setNativePixelSize(void)
 | 
			
		||||
{
 | 
			
		||||
	/* make sure 10.6 keeps running */
 | 
			
		||||
	if ([m_openGLView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
 | 
			
		||||
		NSRect backingBounds = [m_openGLView convertRectToBacking:[m_openGLView bounds]];
 | 
			
		||||
		
 | 
			
		||||
		GHOST_Rect rect;
 | 
			
		||||
		getClientBounds(rect);
 | 
			
		||||
 | 
			
		||||
		m_nativePixelSize = (float)backingBounds.size.width / (float)rect.getWidth();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \note Fullscreen switch is not actual fullscreen with display capture.
 | 
			
		||||
@@ -1029,7 +1049,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
 | 
			
		||||
				[tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
 | 
			
		||||
												   NSStringPboardType, NSTIFFPboardType, nil]];
 | 
			
		||||
				//Forbid to resize the window below the blender defined minimum one
 | 
			
		||||
				[tmpWindow setContentMinSize:NSMakeSize(640, 480)];
 | 
			
		||||
				[tmpWindow setContentMinSize:NSMakeSize(320, 240)];
 | 
			
		||||
				
 | 
			
		||||
				//Assign the openGL view to the new window
 | 
			
		||||
				[tmpWindow setContentView:m_openGLView];
 | 
			
		||||
 
 | 
			
		||||
@@ -186,11 +186,6 @@ GHOST_WindowX11(
 | 
			
		||||
	int natom;
 | 
			
		||||
	int glxVersionMajor, glxVersionMinor; /* As in GLX major.minor */
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	/* initialize incase X11 fails to load */
 | 
			
		||||
	memset(&m_xtablet, 0, sizeof(m_xtablet));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	m_visual = NULL;
 | 
			
		||||
 | 
			
		||||
	if (!glXQueryVersion(m_display, &glxVersionMajor, &glxVersionMinor)) {
 | 
			
		||||
@@ -363,8 +358,8 @@ GHOST_WindowX11(
 | 
			
		||||
	xsizehints->y = top;
 | 
			
		||||
	xsizehints->width = width;
 | 
			
		||||
	xsizehints->height = height;
 | 
			
		||||
	xsizehints->min_width = 640;     /* size hints, could be made apart of the ghost api */
 | 
			
		||||
	xsizehints->min_height = 480;    /* limits are also arbitrary, but should not allow 1x1 window */
 | 
			
		||||
	xsizehints->min_width = 320;     /* size hints, could be made apart of the ghost api */
 | 
			
		||||
	xsizehints->min_height = 240;    /* limits are also arbitrary, but should not allow 1x1 window */
 | 
			
		||||
	xsizehints->max_width = 65535;
 | 
			
		||||
	xsizehints->max_height = 65535;
 | 
			
		||||
	XSetWMNormalHints(m_display, m_window, xsizehints);
 | 
			
		||||
@@ -461,6 +456,8 @@ GHOST_WindowX11(
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	initXInputDevices();
 | 
			
		||||
 | 
			
		||||
	m_tabletData.Active = GHOST_kTabletModeNone;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* now set up the rendering context. */
 | 
			
		||||
@@ -517,200 +514,30 @@ bool GHOST_WindowX11::createX11_XIC()
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
/* 
 | 
			
		||||
 * Dummy function to get around IO Handler exiting if device invalid
 | 
			
		||||
 * Basically it will not crash blender now if you have a X device that
 | 
			
		||||
 * is configured but not plugged in.
 | 
			
		||||
 */
 | 
			
		||||
static int ApplicationErrorHandler(Display *display, XErrorEvent *theEvent)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n",
 | 
			
		||||
	        theEvent->error_code, theEvent->request_code);
 | 
			
		||||
 | 
			
		||||
	/* No exit! - but keep lint happy */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* These C functions are copied from Wine 1.1.13's wintab.c */
 | 
			
		||||
#define BOOL int
 | 
			
		||||
#define TRUE 1
 | 
			
		||||
#define FALSE 0
 | 
			
		||||
 | 
			
		||||
static bool match_token(const char *haystack, const char *needle)
 | 
			
		||||
{
 | 
			
		||||
	const char *p, *q;
 | 
			
		||||
	for (p = haystack; *p; )
 | 
			
		||||
	{
 | 
			
		||||
		while (*p && isspace(*p))
 | 
			
		||||
			p++;
 | 
			
		||||
		if (!*p)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		for (q = needle; *q && *p && tolower(*p) == tolower(*q); q++)
 | 
			
		||||
			p++;
 | 
			
		||||
		if (!*q && (isspace(*p) || !*p))
 | 
			
		||||
			return TRUE;
 | 
			
		||||
 | 
			
		||||
		while (*p && !isspace(*p))
 | 
			
		||||
			p++;
 | 
			
		||||
	}
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Determining if an X device is a Tablet style device is an imperfect science.
 | 
			
		||||
 * We rely on common conventions around device names as well as the type reported
 | 
			
		||||
 * by Wacom tablets.  This code will likely need to be expanded for alternate tablet types
 | 
			
		||||
 *
 | 
			
		||||
 * Wintab refers to any device that interacts with the tablet as a cursor,
 | 
			
		||||
 * (stylus, eraser, tablet mouse, airbrush, etc)
 | 
			
		||||
 * this is not to be confused with wacom x11 configuration "cursor" device.
 | 
			
		||||
 * Wacoms x11 config "cursor" refers to its device slot (which we mirror with
 | 
			
		||||
 * our gSysCursors) for puck like devices (tablet mice essentially).
 | 
			
		||||
 */
 | 
			
		||||
#if 0 // unused
 | 
			
		||||
static BOOL is_tablet_cursor(const char *name, const char *type)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	static const char *tablet_cursor_whitelist[] = {
 | 
			
		||||
		"wacom",
 | 
			
		||||
		"wizardpen",
 | 
			
		||||
		"acecad",
 | 
			
		||||
		"tablet",
 | 
			
		||||
		"cursor",
 | 
			
		||||
		"stylus",
 | 
			
		||||
		"eraser",
 | 
			
		||||
		"pad",
 | 
			
		||||
		NULL
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	for (i = 0; tablet_cursor_whitelist[i] != NULL; i++) {
 | 
			
		||||
		if (name && match_token(name, tablet_cursor_whitelist[i]))
 | 
			
		||||
			return TRUE;
 | 
			
		||||
		if (type && match_token(type, tablet_cursor_whitelist[i]))
 | 
			
		||||
			return TRUE;
 | 
			
		||||
	}
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
static BOOL is_stylus(const char *name, const char *type)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	static const char *tablet_stylus_whitelist[] = {
 | 
			
		||||
		"stylus",
 | 
			
		||||
		"wizardpen",
 | 
			
		||||
		"acecad",
 | 
			
		||||
		NULL
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	for (i = 0; tablet_stylus_whitelist[i] != NULL; i++) {
 | 
			
		||||
		if (name && match_token(name, tablet_stylus_whitelist[i]))
 | 
			
		||||
			return TRUE;
 | 
			
		||||
		if (type && match_token(type, tablet_stylus_whitelist[i]))
 | 
			
		||||
			return TRUE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BOOL is_eraser(const char *name, const char *type)
 | 
			
		||||
{
 | 
			
		||||
	if (name && match_token(name, "eraser"))
 | 
			
		||||
		return TRUE;
 | 
			
		||||
	if (type && match_token(type, "eraser"))
 | 
			
		||||
		return TRUE;
 | 
			
		||||
	return FALSE;
 | 
			
		||||
}
 | 
			
		||||
#undef BOOL
 | 
			
		||||
#undef TRUE
 | 
			
		||||
#undef FALSE
 | 
			
		||||
/* end code copied from wine */
 | 
			
		||||
 | 
			
		||||
void GHOST_WindowX11::initXInputDevices()
 | 
			
		||||
{
 | 
			
		||||
	static XErrorHandler old_handler = (XErrorHandler) 0;
 | 
			
		||||
	XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
 | 
			
		||||
 | 
			
		||||
	if (version && (version != (XExtensionVersion *)NoSuchExtension)) {
 | 
			
		||||
		if (version->present) {
 | 
			
		||||
			int device_count;
 | 
			
		||||
			XDeviceInfo *device_info = XListInputDevices(m_display, &device_count);
 | 
			
		||||
			m_xtablet.StylusDevice = NULL;
 | 
			
		||||
			m_xtablet.EraserDevice = NULL;
 | 
			
		||||
			m_xtablet.CommonData.Active = GHOST_kTabletModeNone;
 | 
			
		||||
 | 
			
		||||
			/* Install our error handler to override Xlib's termination behavior */
 | 
			
		||||
			old_handler = XSetErrorHandler(ApplicationErrorHandler);
 | 
			
		||||
 | 
			
		||||
			for (int i = 0; i < device_count; ++i) {
 | 
			
		||||
				char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) : NULL;
 | 
			
		||||
				
 | 
			
		||||
//				printf("Tablet type:'%s', name:'%s', index:%d\n", device_type, device_info[i].name, i);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
				if (m_xtablet.StylusDevice == NULL && is_stylus(device_info[i].name, device_type)) {
 | 
			
		||||
//					printf("\tfound stylus\n");
 | 
			
		||||
					m_xtablet.StylusID = device_info[i].id;
 | 
			
		||||
					m_xtablet.StylusDevice = XOpenDevice(m_display, m_xtablet.StylusID);
 | 
			
		||||
 | 
			
		||||
					if (m_xtablet.StylusDevice != NULL) {
 | 
			
		||||
						/* Find how many pressure levels tablet has */
 | 
			
		||||
						XAnyClassPtr ici = device_info[i].inputclassinfo;
 | 
			
		||||
						for (int j = 0; j < m_xtablet.StylusDevice->num_classes; ++j) {
 | 
			
		||||
							if (ici->c_class == ValuatorClass) {
 | 
			
		||||
//								printf("\t\tfound ValuatorClass\n");
 | 
			
		||||
								XValuatorInfo *xvi = (XValuatorInfo *)ici;
 | 
			
		||||
								m_xtablet.PressureLevels = xvi->axes[2].max_value;
 | 
			
		||||
							
 | 
			
		||||
								/* this is assuming that the tablet has the same tilt resolution in both
 | 
			
		||||
								 * positive and negative directions. It would be rather weird if it didn't.. */
 | 
			
		||||
								m_xtablet.XtiltLevels = xvi->axes[3].max_value;
 | 
			
		||||
								m_xtablet.YtiltLevels = xvi->axes[4].max_value;
 | 
			
		||||
								break;
 | 
			
		||||
							}
 | 
			
		||||
						
 | 
			
		||||
							ici = (XAnyClassPtr)(((char *)ici) + ici->length);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					else {
 | 
			
		||||
						m_xtablet.StylusID = 0;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				else if (m_xtablet.EraserDevice == NULL && is_eraser(device_info[i].name, device_type)) {
 | 
			
		||||
//					printf("\tfound eraser\n");
 | 
			
		||||
					m_xtablet.EraserID = device_info[i].id;
 | 
			
		||||
					m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID);
 | 
			
		||||
					if (m_xtablet.EraserDevice == NULL) m_xtablet.EraserID = 0;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (device_type) {
 | 
			
		||||
					XFree((void *)device_type);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* Restore handler */
 | 
			
		||||
			(void) XSetErrorHandler(old_handler);
 | 
			
		||||
 | 
			
		||||
			XFreeDeviceList(device_info);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
			GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet();
 | 
			
		||||
			XEventClass xevents[10], ev;
 | 
			
		||||
			int dcount = 0;
 | 
			
		||||
 | 
			
		||||
			if (m_xtablet.StylusDevice) {
 | 
			
		||||
				DeviceMotionNotify(m_xtablet.StylusDevice, m_xtablet.MotionEvent, ev);
 | 
			
		||||
			if (xtablet.StylusDevice) {
 | 
			
		||||
				DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev);
 | 
			
		||||
				if (ev) xevents[dcount++] = ev;
 | 
			
		||||
				ProximityIn(m_xtablet.StylusDevice, m_xtablet.ProxInEvent, ev);
 | 
			
		||||
				ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev);
 | 
			
		||||
				if (ev) xevents[dcount++] = ev;
 | 
			
		||||
				ProximityOut(m_xtablet.StylusDevice, m_xtablet.ProxOutEvent, ev);
 | 
			
		||||
				ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev);
 | 
			
		||||
				if (ev) xevents[dcount++] = ev;
 | 
			
		||||
			}
 | 
			
		||||
			if (m_xtablet.EraserDevice) {
 | 
			
		||||
				DeviceMotionNotify(m_xtablet.EraserDevice, m_xtablet.MotionEvent, ev);
 | 
			
		||||
			if (xtablet.EraserDevice) {
 | 
			
		||||
				DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEvent, ev);
 | 
			
		||||
				if (ev) xevents[dcount++] = ev;
 | 
			
		||||
				ProximityIn(m_xtablet.EraserDevice, m_xtablet.ProxInEvent, ev);
 | 
			
		||||
				ProximityIn(xtablet.EraserDevice, xtablet.ProxInEvent, ev);
 | 
			
		||||
				if (ev) xevents[dcount++] = ev;
 | 
			
		||||
				ProximityOut(m_xtablet.EraserDevice, m_xtablet.ProxOutEvent, ev);
 | 
			
		||||
				ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEvent, ev);
 | 
			
		||||
				if (ev) xevents[dcount++] = ev;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@@ -1341,15 +1168,6 @@ GHOST_WindowX11::
 | 
			
		||||
		XFreeCursor(m_display, m_custom_cursor);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	/* close tablet devices */
 | 
			
		||||
	if (m_xtablet.StylusDevice)
 | 
			
		||||
		XCloseDevice(m_display, m_xtablet.StylusDevice);
 | 
			
		||||
	
 | 
			
		||||
	if (m_xtablet.EraserDevice)
 | 
			
		||||
		XCloseDevice(m_display, m_xtablet.EraserDevice);
 | 
			
		||||
#endif /* WITH_X11_XINPUT */
 | 
			
		||||
 | 
			
		||||
	if (m_context != s_firstContext) {
 | 
			
		||||
		glXDestroyContext(m_display, m_context);
 | 
			
		||||
	}
 | 
			
		||||
@@ -1392,6 +1210,15 @@ installDrawingContext(
 | 
			
		||||
	GHOST_TSuccess success;
 | 
			
		||||
	switch (type) {
 | 
			
		||||
		case GHOST_kDrawingContextTypeOpenGL:
 | 
			
		||||
		{
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
			/* use our own event handlers to avoid exiting blender,
 | 
			
		||||
			 * this would happen for eg:
 | 
			
		||||
			 * if you open blender, unplug a tablet, then open a new window. */
 | 
			
		||||
			XErrorHandler old_handler      = XSetErrorHandler(GHOST_X11_ApplicationErrorHandler);
 | 
			
		||||
			XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
			m_context = glXCreateContext(m_display, m_visual, s_firstContext, True);
 | 
			
		||||
			if (m_context != NULL) {
 | 
			
		||||
				if (!s_firstContext) {
 | 
			
		||||
@@ -1406,12 +1233,18 @@ installDrawingContext(
 | 
			
		||||
				success = GHOST_kFailure;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
			/* Restore handler */
 | 
			
		||||
			(void) XSetErrorHandler(old_handler);
 | 
			
		||||
			(void) XSetIOErrorHandler(old_handler_io);
 | 
			
		||||
#endif
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		case GHOST_kDrawingContextTypeNone:
 | 
			
		||||
		{
 | 
			
		||||
			success = GHOST_kSuccess;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		default:
 | 
			
		||||
			success = GHOST_kFailure;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -196,32 +196,9 @@ public:
 | 
			
		||||
	getXWindow(
 | 
			
		||||
	    );
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	class XTablet
 | 
			
		||||
	GHOST_TabletData *GetTabletData()
 | 
			
		||||
	{
 | 
			
		||||
public:
 | 
			
		||||
		GHOST_TabletData CommonData;
 | 
			
		||||
 | 
			
		||||
		XDevice *StylusDevice;
 | 
			
		||||
		XDevice *EraserDevice;
 | 
			
		||||
 | 
			
		||||
		XID StylusID, EraserID;
 | 
			
		||||
 | 
			
		||||
		int MotionEvent;
 | 
			
		||||
		int ProxInEvent;
 | 
			
		||||
		int ProxOutEvent;
 | 
			
		||||
 | 
			
		||||
		int PressureLevels;
 | 
			
		||||
		int XtiltLevels, YtiltLevels;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	XTablet& GetXTablet()
 | 
			
		||||
	{
 | 
			
		||||
		return m_xtablet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const GHOST_TabletData *GetTabletData()
 | 
			
		||||
	{
 | 
			
		||||
		return &m_xtablet.CommonData;
 | 
			
		||||
		return &m_tabletData;
 | 
			
		||||
	}
 | 
			
		||||
#else // WITH_X11_XINPUT
 | 
			
		||||
	const GHOST_TabletData *GetTabletData()
 | 
			
		||||
@@ -387,8 +364,7 @@ private:
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_X11_XINPUT
 | 
			
		||||
	/* Tablet devices */
 | 
			
		||||
	XTablet m_xtablet;
 | 
			
		||||
	GHOST_TabletData m_tabletData;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
 | 
			
		||||
 
 | 
			
		||||
@@ -68,6 +68,17 @@
 | 
			
		||||
 | 
			
		||||
//#define DEBUG_MEMCOUNTER
 | 
			
		||||
 | 
			
		||||
/* Only for debugging:
 | 
			
		||||
 * defining DEBUG_THREADS will enable check whether memory manager
 | 
			
		||||
 * is locked with a mutex when allocation is called from non-main
 | 
			
		||||
 * thread.
 | 
			
		||||
 *
 | 
			
		||||
 * This helps troubleshooting memory issues caused by the fact
 | 
			
		||||
 * guarded allocator is not thread-safe, however this check will
 | 
			
		||||
 * fail to check allocations from openmp threads.
 | 
			
		||||
 */
 | 
			
		||||
//#define DEBUG_THREADS
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_MEMCOUNTER
 | 
			
		||||
   /* set this to the value that isn't being freed */
 | 
			
		||||
#  define DEBUG_MEMCOUNTER_ERROR_VAL 0
 | 
			
		||||
@@ -122,6 +133,12 @@ typedef struct MemHead {
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_THREADS
 | 
			
		||||
#  include <assert.h>
 | 
			
		||||
#  include <pthread.h>
 | 
			
		||||
static pthread_t mainid;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct MemTail {
 | 
			
		||||
	int tag3, pad;
 | 
			
		||||
} MemTail;
 | 
			
		||||
@@ -206,6 +223,20 @@ static void print_error(const char *str, ...)
 | 
			
		||||
 | 
			
		||||
static void mem_lock_thread(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef DEBUG_THREADS
 | 
			
		||||
	static int initialized = 0;
 | 
			
		||||
 | 
			
		||||
	if (initialized == 0) {
 | 
			
		||||
		/* assume first allocation happens from main thread */
 | 
			
		||||
		mainid = pthread_self();
 | 
			
		||||
		initialized = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!pthread_equal(pthread_self(), mainid) && thread_lock_callback == NULL) {
 | 
			
		||||
		assert(!"Memory function is called from non-main thread without lock");
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_OMP_MALLOC
 | 
			
		||||
	assert(omp_in_parallel() == 0);
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@
 | 
			
		||||
 | 
			
		||||
static std::string messages_path;
 | 
			
		||||
static std::string default_domain;
 | 
			
		||||
static std::string locale_str;
 | 
			
		||||
 | 
			
		||||
void bl_locale_init(const char *_messages_path, const char *_default_domain)
 | 
			
		||||
{
 | 
			
		||||
@@ -52,6 +53,7 @@ void bl_locale_init(const char *_messages_path, const char *_default_domain)
 | 
			
		||||
void bl_locale_set(const char *locale)
 | 
			
		||||
{
 | 
			
		||||
	boost::locale::generator gen;
 | 
			
		||||
	std::locale _locale;
 | 
			
		||||
	// Specify location of dictionaries.
 | 
			
		||||
	gen.add_messages_path(messages_path);
 | 
			
		||||
	gen.add_messages_domain(default_domain);
 | 
			
		||||
@@ -59,7 +61,8 @@ void bl_locale_set(const char *locale)
 | 
			
		||||
 | 
			
		||||
	try {
 | 
			
		||||
		if (locale && locale[0]) {
 | 
			
		||||
			std::locale::global(gen(locale));
 | 
			
		||||
			_locale = gen(locale);
 | 
			
		||||
			std::locale::global(_locale);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
#ifdef __APPLE__
 | 
			
		||||
@@ -85,9 +88,11 @@ void bl_locale_set(const char *locale)
 | 
			
		||||
			if (locale_osx == "")
 | 
			
		||||
				fprintf(stderr, "Locale set: failed to read AppleLocale read from defaults\n");
 | 
			
		||||
 | 
			
		||||
			std::locale::global(gen(locale_osx.c_str()));
 | 
			
		||||
			_locale = gen(locale_osx.c_str());
 | 
			
		||||
			std::locale::global(_locale);
 | 
			
		||||
#else
 | 
			
		||||
			std::locale::global(gen(""));
 | 
			
		||||
			_locale = gen("");
 | 
			
		||||
			std::locale::global(_locale);
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
		// Note: boost always uses "C" LC_NUMERIC by default!
 | 
			
		||||
@@ -95,6 +100,22 @@ void bl_locale_set(const char *locale)
 | 
			
		||||
	catch(std::exception const &e) {
 | 
			
		||||
		std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Generate the locale string (useful to know which locale we are actually using in case of "default" one). */
 | 
			
		||||
#define LOCALE_INFO std::use_facet<boost::locale::info>(_locale)
 | 
			
		||||
 | 
			
		||||
	locale_str = LOCALE_INFO.language();
 | 
			
		||||
	if (LOCALE_INFO.country() != "") {
 | 
			
		||||
		locale_str += "_" + LOCALE_INFO.country();
 | 
			
		||||
	}
 | 
			
		||||
	if (LOCALE_INFO.variant() != "") {
 | 
			
		||||
		locale_str += "@" + LOCALE_INFO.variant();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *bl_locale_get(void)
 | 
			
		||||
{
 | 
			
		||||
	return locale_str.c_str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *bl_locale_pgettext(const char *msgctxt, const char *msgid)
 | 
			
		||||
@@ -116,4 +137,3 @@ const char *bl_locale_pgettext(const char *msgctxt, const char *msgid)
 | 
			
		||||
		return msgid;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,8 @@ extern "C" {
 | 
			
		||||
 | 
			
		||||
void bl_locale_init(const char *messages_path, const char *default_domain);
 | 
			
		||||
void bl_locale_set(const char *locale);
 | 
			
		||||
const char* bl_locale_pgettext(const char *msgctxt, const char *msgid);
 | 
			
		||||
const char *bl_locale_get(void);
 | 
			
		||||
const char *bl_locale_pgettext(const char *msgctxt, const char *msgid);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 3.9 MiB After Width: | Height: | Size: 4.1 MiB  | 
| 
		 Before Width: | Height: | Size: 226 KiB After Width: | Height: | Size: 233 KiB  | 
| 
		 Before Width: | Height: | Size: 563 KiB After Width: | Height: | Size: 586 KiB  | 
							
								
								
									
										3
									
								
								release/datafiles/matcaps/license.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,3 @@
 | 
			
		||||
These matcap images are licensed as GNU GPL 2 or later, like the rest of Blender's code.
 | 
			
		||||
 | 
			
		||||
Thanks to Kent Trammell and Aidy Burrows and John Herreno for making the pictures.
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								release/datafiles/matcaps/mc01.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 21 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								release/datafiles/matcaps/mc02.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 39 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								release/datafiles/matcaps/mc03.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 48 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								release/datafiles/matcaps/mc04.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 45 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								release/datafiles/matcaps/mc05.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 20 KiB  |