diff --git a/CMakeLists.txt b/CMakeLists.txt index 7589d4dcfc3..b6630b6ad8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,6 +129,8 @@ option(WITH_IK_ITASC "Enable ITASC IK solver (only disable for development option(WITH_IK_SOLVER "Enable Legacy IK solver (only disable for development)" ON) option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke and audio effects)" ON) option(WITH_BULLET "Enable Bullet (Physics Engine)" ON) +option(WITH_SYSTEM_BULLET "Use the systems bullet library (currently unsupported due to missing features in upstream!)" ) +mark_as_advanced(WITH_SYSTEM_BULLET) option(WITH_GAMEENGINE "Enable Game Engine" ON) option(WITH_PLAYER "Build Player" OFF) option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ON) @@ -149,6 +151,9 @@ mark_as_advanced(WITH_HEADLESS) option(WITH_AUDASPACE "Build with blenders audio library (only disable if you know what you're doing!)" ON) mark_as_advanced(WITH_AUDASPACE) +option(WITH_BOOL_COMPAT "Continue defining \"TRUE\" and \"FALSE\" until these can be replaced with \"true\" and \"false\" from stdbool.h" ON) +mark_as_advanced(WITH_BOOL_COMPAT) + # (unix defaults to OpenMP On) if((UNIX AND NOT APPLE) OR (MINGW)) @@ -267,7 +272,6 @@ mark_as_advanced(WITH_CXX_GUARDEDALLOC) option(WITH_ASSERT_ABORT "Call abort() when raising an assertion through BLI_assert()" OFF) mark_as_advanced(WITH_ASSERT_ABORT) - if(APPLE) cmake_minimum_required(VERSION 2.8.8) cmake_policy(VERSION 2.8.8) @@ -426,6 +430,13 @@ endif() TEST_SSE_SUPPORT(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG) +TEST_STDBOOL_SUPPORT() +if(HAVE_STDBOOL_H) + add_definitions(-DHAVE_STDBOOL_H) +endif() +if(WITH_BOOL_COMPAT) + add_definitions(-DWITH_BOOL_COMPAT) +endif() #----------------------------------------------------------------------------- # Check for valid directories @@ -1090,14 +1101,16 @@ elseif(WIN32) if(WITH_PYTHON) # normally cached but not since we include them with blender if(MSVC10) - set(PYTHON_VERSION 3.2) # CACHE STRING) + set(PYTHON_VERSION 3.3) # CACHE STRING) else() set(PYTHON_VERSION 3.3) # CACHE STRING) endif() set_lib_path(PYTHON "python") STRING(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION}) - set(PYTHON_LIBRARY ${PYTHON}/lib/python${_PYTHON_VERSION_NO_DOTS}.lib) #CACHE FILEPATH + # Use shared libs for vc2008 and vc2010 until we actually have vc2010 libs + set(PYTHON_LIBRARY ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.lib) + # set(PYTHON_LIBRARY ${PYTHON}/lib/python${_PYTHON_VERSION_NO_DOTS}.lib) #CACHE FILEPATH unset(_PYTHON_VERSION_NO_DOTS) #Shared includes for both vc2008 and vc2010 @@ -1836,6 +1849,20 @@ else() set(GLEW_INCLUDE_PATH "${CMAKE_SOURCE_DIR}/extern/glew/include") endif() + +#----------------------------------------------------------------------------- +# Configure Bullet + +if(WITH_BULLET AND WITH_SYSTEM_BULLET) + find_package(Bullet) + if(NOT BULLET_FOUND) + set(WITH_BULLET OFF) + endif() +else() + set(BULLET_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/extern/bullet2/src") + # set(BULLET_LIBRARIES "") +endif() + #----------------------------------------------------------------------------- # Configure Python. @@ -2140,3 +2167,8 @@ if(FIRST_RUN) message("${_config_msg}") endif() + +# debug +message( + STATUS "HAVE_STDBOOL_H = ${HAVE_STDBOOL_H}" +) diff --git a/SConstruct b/SConstruct index 0a91de4e410..a16805bbfaf 100644 --- a/SConstruct +++ b/SConstruct @@ -374,9 +374,10 @@ if btools.ENDIAN == "big": else: env['CPPFLAGS'].append('-D__LITTLE_ENDIAN__') -# TODO, make optional +# TODO, make optional (as with CMake) env['CPPFLAGS'].append('-DWITH_AUDASPACE') env['CPPFLAGS'].append('-DWITH_AVI') +env['CPPFLAGS'].append('-DWITH_BOOL_COMPAT') # lastly we check for root_build_dir ( we should not do before, otherwise we might do wrong builddir B.root_build_dir = env['BF_BUILDDIR'] @@ -443,11 +444,12 @@ if env['WITH_BF_PYTHON']: found_pyconfig_h = True if not (found_python_h and found_pyconfig_h): - print("\nMissing: Python.h and/or pyconfig.h in\"" + env.subst('${BF_PYTHON_INC}') + "\",\n" - " Set 'BF_PYTHON_INC' to point " - "to valid python include path(s).\n Containing " - "Python.h and pyconfig.h for python version \"" + env.subst('${BF_PYTHON_VERSION}') + "\"") + print("""\nMissing: Python.h and/or pyconfig.h in "%s" + Set 'BF_PYTHON_INC' to point to valid include path(s), + containing Python.h and pyconfig.h for Python version "%s". + Example: python scons/scons.py BF_PYTHON_INC=../Python/include + """ % (env.subst('${BF_PYTHON_INC}'), env.subst('${BF_PYTHON_VERSION}'))) Exit() diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 5e33bd050ed..97bd94f55b2 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -1,16 +1,37 @@ -#!/bin/bash +#!/usr/bin/env bash +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# A shell script installing/building all needed dependencies to build Blender, for some Linux distributions. # Parse command line! ARGS=$( \ getopt \ -o s:i:t:h \ ---long source:,install:,threads:,help,with-all,with-osl,all-static,force-all,force-python,\ -force-boost,force-ocio,force-oiio,force-llvm,force-osl,force-ffmpeg,\ -skip-python,skip-boost,skip-ocio,skip-oiio,skip-llvm,skip-osl,skip-ffmpeg \ +--long source:,install:,threads:,help,with-all,with-osl,with-opencollada,all-static,force-all,\ +force-python,force-numpy,force-boost,force-ocio,force-oiio,force-llvm,force-osl,force-opencollada,\ +force-ffmpeg,skip-python,skip-numpy,skip-boost,skip-ocio,skip-oiio,skip-llvm,skip-osl,skip-ffmpeg,\ +skip-opencollada \ -- "$@" \ ) DISTRO="" +RPM="" SRC="$HOME/src/blender-deps" INST="/opt/lib" CWD=$PWD @@ -21,6 +42,9 @@ WITH_ALL=false # Do not yet enable osl, use --with-osl (or --with-all) option to try it. WITH_OSL=false +# Do not yet enable opencollada, use --with-opencollada (or --with-all) option to try it. +WITH_OPENCOLLADA=false + # Try to link everything statically. Use this to produce portable versions of blender. ALL_STATIC=false @@ -37,8 +61,12 @@ or use --source/--install options, if you want to use other paths! Number of threads for building: \$THREADS (automatically detected, use --threads= to override it). Full install: \$WITH_ALL (use --with-all option to enable it). Building OSL: \$WITH_OSL (use --with-osl option to enable it). +Building OpenCOLLADA: \$WITH_OPENCOLLADA (use --with-opencollada option to enable it). All static linking: \$ALL_STATIC (use --all-static option to enable it). +Example: +Full install without OpenCOLLADA: --with-all --skip-opencollada + Use --help to show all available options!\"" ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS: @@ -64,6 +92,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS: Try to install or build the OpenShadingLanguage libraries (and their dependencies). Still experimental! + --with-opencollada + Build and install the OpenCOLLADA libraries. + --all-static Build libraries as statically as possible, to create static builds of Blender. @@ -73,6 +104,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS: --force-python Force the rebuild of Python. + --force-numpy + Force the rebuild of NumPy. + --force-boost Force the rebuild of Boost. @@ -88,6 +122,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS: --force-osl Force the rebuild of OpenShadingLanguage. + --force-opencollada + Force the rebuild of OpenCOLLADA. + --force-ffmpeg Force the rebuild of FFMpeg. @@ -101,6 +138,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS: --skip-python Unconditionally skip Python installation/building. + --skip-numpy + Unconditionally skip NumPy installation/building. + --skip-boost Unconditionally skip Boost installation/building. @@ -116,6 +156,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS: --skip-osl Unconditionally skip OpenShadingLanguage installation/building. + --skip-opencollada + Unconditionally skip OpenCOLLADA installation/building. + --skip-ffmpeg Unconditionally skip FFMpeg installation/building.\"" @@ -125,6 +168,13 @@ PYTHON_SOURCE="http://python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSI PYTHON_FORCE_REBUILD=false PYTHON_SKIP=false +#Could not get numpy-1.6.2 to compile with python-3.3 +NUMPY_VERSION="1.7.0rc1" +NUMPY_VERSION_MIN="1.7" +NUMPY_SOURCE="http://sourceforge.net/projects/numpy/files/NumPy/$NUMPY_VERSION/numpy-$NUMPY_VERSION.tar.gz" +NUMPY_FORCE_REBUILD=false +NUMPY_SKIP=false + BOOST_VERSION="1.51.0" _boost_version_nodots=`echo "$BOOST_VERSION" | sed -r 's/\./_/g'` BOOST_SOURCE="http://sourceforge.net/projects/boost/files/boost/$BOOST_VERSION/boost_$_boost_version_nodots.tar.bz2/download" @@ -158,6 +208,12 @@ OSL_SOURCE="https://github.com/mont29/OpenShadingLanguage/archive/blender-fixes. OSL_FORCE_REBUILD=false OSL_SKIP=false +# Version?? +OPENCOLLADA_VERSION="1.3" +OPENCOLLADA_SOURCE="https://github.com/KhronosGroup/OpenCOLLADA.git" +OPENCOLLADA_FORCE_REBUILD=false +OPENCOLLADA_SKIP=false + FFMPEG_VERSION="1.0" FFMPEG_SOURCE="http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" FFMPEG_VERSION_MIN="0.7.6" @@ -236,22 +292,30 @@ while true; do --with-osl) WITH_OSL=true; shift; continue ;; + --with-opencollada) + WITH_OPENCOLLADA=true; shift; continue + ;; --all-static) ALL_STATIC=true; shift; continue ;; --force-all) PYTHON_FORCE_REBUILD=true + NUMPY_FORCE_REBUILD=true BOOST_FORCE_REBUILD=true OCIO_FORCE_REBUILD=true OIIO_FORCE_REBUILD=true LLVM_FORCE_REBUILD=true OSL_FORCE_REBUILD=true + OPENCOLLADA_FORCE_REBUILD=true FFMPEG_FORCE_REBUILD=true shift; continue ;; --force-python) PYTHON_FORCE_REBUILD=true; shift; continue ;; + --force-numpy) + NUMPY_FORCE_REBUILD=true; shift; continue + ;; --force-boost) BOOST_FORCE_REBUILD=true; shift; continue ;; @@ -267,12 +331,18 @@ while true; do --force-osl) OSL_FORCE_REBUILD=true; shift; continue ;; + --force-opencollada) + OPENCOLLADA_FORCE_REBUILD=true; shift; continue + ;; --force-ffmpeg) FFMPEG_FORCE_REBUILD=true; shift; continue ;; --skip-python) PYTHON_SKIP=true; shift; continue ;; + --skip-numpy) + NUMPY_SKIP=true; shift; continue + ;; --skip-boost) BOOST_SKIP=true; shift; continue ;; @@ -288,6 +358,9 @@ while true; do --skip-osl) OSL_SKIP=true; shift; continue ;; + --skip-opencollada) + OPENCOLLADA_SKIP=true; shift; continue + ;; --skip-ffmpeg) FFMPEG_SKIP=true; shift; continue ;; @@ -308,6 +381,7 @@ done if $WITH_ALL; then WITH_OSL=true + WITH_OPENCOLLADA=true fi # Return 0 if $1 = $2 (i.e. 1.01.0 = 1.1, but 1.1.1 != 1.1), else 1. @@ -397,10 +471,22 @@ version_match() { detect_distro() { if [ -f /etc/debian_version ]; then DISTRO="DEB" - elif [ -f /etc/redhat-release ]; then + elif [ -f /etc/redhat-release -o /etc/SuSE-release ]; then DISTRO="RPM" + elif [ -f /etc/arch-release ]; then + DISTRO="ARCH" + fi +} + +rpm_flavour() { + if [ -f /etc/redhat-release ]; then + if [ "`grep '6\.' /etc/redhat-release`" ]; then + RPM="RHEL" + else + RPM="FEDORA" + fi elif [ -f /etc/SuSE-release ]; then - DISTRO="SUSE" + RPM="SUSE" fi } @@ -483,6 +569,56 @@ compile_Python() { fi } +compile_Numpy() { + # To be changed each time we make edits that would modify the compiled result! + py_magic=0 + + _src=$SRC/numpy-$NUMPY_VERSION + _inst=$INST/numpy-$NUMPY_VERSION + _python=$INST/python-$PYTHON_VERSION + _site=lib/python3.3/site-packages + + # Clean install if needed! + magic_compile_check numpy-$NUMPY_VERSION $py_magic + if [ $? -eq 1 -o $NUMPY_FORCE_REBUILD == true ]; then + rm -rf $_inst + fi + + if [ ! -d $_inst ]; then + INFO "Building Numpy-$NUMPY_VERSION" + + prepare_opt + + if [ ! -d $_src ]; then + mkdir -p $SRC + wget -c $NUMPY_SOURCE -O $_src.tar.gz + + INFO "Unpacking Numpy-$NUMPY_VERSION" + tar -C $SRC -xf $_src.tar.gz + fi + + cd $_src + + $_python/bin/python3 setup.py install --prefix=$_inst + + if [ -d $_inst ]; then + rm -f $_python/$_site/numpy + ln -s $_inst/$_site/numpy $_python/$_site/numpy + else + ERROR "Numpy-$NUMPY_VERSION failed to compile, exiting" + exit 1 + fi + + magic_compile_set numpy-$NUMPY_VERSION $py_magic + + cd $CWD + INFO "Done compiling Numpy-$NUMPY_VERSION!" + else + INFO "Own Numpy-$NUMPY_VERSION is up to date, nothing to do!" + INFO "If you want to force rebuild of this lib, use the --force-numpy option." + fi +} + compile_Boost() { # To be changed each time we make edits that would modify the compiled result! boost_magic=7 @@ -620,7 +756,7 @@ compile_OCIO() { compile_OIIO() { # To be changed each time we make edits that would modify the compiled result! - oiio_magic=6 + oiio_magic=7 _src=$SRC/OpenImageIO-$OIIO_VERSION _inst=$INST/oiio-$OIIO_VERSION @@ -797,6 +933,7 @@ EOF cmake_d="-D CMAKE_BUILD_TYPE=Release" cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst" cmake_d="$cmake_d -D LLVM_ENABLE_FFI=ON" + cmake_d="$cmake_d -D LLVM_TARGETS_TO_BUILD=X86" if [ -d $_FFI_INCLUDE_DIR ]; then cmake_d="$cmake_d -D FFI_INCLUDE_DIR=$_FFI_INCLUDE_DIR" @@ -920,6 +1057,70 @@ compile_OSL() { fi } +compile_OpenCOLLADA() { + # To be changed each time we make edits that would modify the compiled results! + opencollada_magic=5 + + _src=$SRC/OpenCOLLADA-$OPENCOLLADA_VERSION + _inst=$INST/opencollada-$OPENCOLLADA_VERSION + + # Clean install if needed! + magic_compile_check opencollada-$OPENCOLLADA_VERSION $opencollada_magic + if [ $? -eq 1 -o $OPENCOLLADA_FORCE_REBUILD == true ]; then + rm -rf $_inst + fi + + if [ ! -d $_inst ]; then + INFO "Building OpenCOLLADA-$OPENCOLLADA_VERSION" + + prepare_opt + + if [ ! -d $_src ]; then + mkdir -p $SRC + git clone $OPENCOLLADA_SOURCE $_src + fi + + cd $_src + + # XXX For now, always update from latest repo... + git pull origin + + # Always refresh the whole build! + if [ -d build ]; then + rm -rf build + fi + mkdir build + cd build + + cmake_d="-D CMAKE_BUILD_TYPE=Release" + cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst" + cmake_d="$cmake_d -D USE_EXPAT=OFF" + cmake_d="$cmake_d -D USE_LIBXML=ON" + cmake_d="$cmake_d -D USE_STATIC=ON" + + cmake $cmake_d ../ + + make -j$THREADS && make install + make clean + + if [ -d $_inst ]; then + rm -f $INST/opencollada + ln -s opencollada-$OPENCOLLADA_VERSION $INST/opencollada + else + ERROR "OpenCOLLADA-$OPENCOLLADA_VERSION failed to compile, exiting" + exit 1 + fi + + magic_compile_set opencollada-$OPENCOLLADA_VERSION $opencollada_magic + + cd $CWD + INFO "Done compiling OpenCOLLADA-$OPENCOLLADA_VERSION!" + else + INFO "Own OpenCOLLADA-$OPENCOLLADA_VERSION is up to date, nothing to do!" + INFO "If you want to force rebuild of this lib, use the --force-opencollada option." + fi +} + compile_FFmpeg() { # To be changed each time we make edits that would modify the compiled result! ffmpeg_magic=3 @@ -992,9 +1193,9 @@ compile_FFmpeg() { --enable-avfilter --disable-vdpau \ --disable-bzlib --disable-libgsm --disable-libspeex \ --enable-pthreads --enable-zlib --enable-stripping --enable-runtime-cpudetect \ - --disable-vaapi --disable-libfaac --disable-nonfree --enable-gpl \ - --disable-postproc --disable-x11grab --disable-librtmp --disable-libopencore-amrnb \ - --disable-libopencore-amrwb --disable-libdc1394 --disable-version3 --disable-outdev=sdl \ + --disable-vaapi --disable-libfaac --disable-nonfree --enable-gpl \ + --disable-postproc --disable-x11grab --disable-librtmp --disable-libopencore-amrnb \ + --disable-libopencore-amrwb --disable-libdc1394 --disable-version3 --disable-outdev=sdl \ --disable-outdev=alsa --disable-indev=sdl --disable-indev=alsa --disable-indev=jack \ --disable-indev=lavfi $extra @@ -1019,6 +1220,8 @@ compile_FFmpeg() { fi } + + get_package_version_DEB() { dpkg-query -W -f '${Version}' $1 | sed -r 's/.*:\s*([0-9]+:)(([0-9]+\.?)+).*/\2/' } @@ -1056,7 +1259,7 @@ check_package_version_ge_DEB() { } install_packages_DEB() { - sudo apt-get install -y $@ + sudo apt-get install -y --force-yes $@ if [ $? -ge 1 ]; then ERROR "apt-get failed to install requested packages, exiting." exit 1 @@ -1070,6 +1273,9 @@ install_DEB() { INFO "`eval _echo "$COMMON_INFO"`" INFO "" + read -p "Do you want to continue (Y/n)?" + [ "$(echo ${REPLY:=Y} | tr [:upper:] [:lower:])" != "y" ] && exit + if [ ! -z "`cat /etc/debian_version | grep ^6`" ]; then if [ -z "`cat /etc/apt/sources.list | grep backports.debian.org`" ]; then INFO "Looks like you're using Debian Squeeze which does have broken CMake" @@ -1095,27 +1301,37 @@ install_DEB() { fi sudo apt-get update -# XXX Why in hell? Let's let this stuff to the user's responsability!!! -# sudo apt-get -y upgrade # These libs should always be available in debian/ubuntu official repository... OPENJPEG_DEV="libopenjpeg-dev" - SCHRO_DEV="libschroedinger-dev" VORBIS_DEV="libvorbis-dev" THEORA_DEV="libtheora-dev" - _packages="gawk cmake scons build-essential libjpeg-dev libpng-dev libtiff-dev \ + _packages="gawk cmake cmake-curses-gui scons build-essential libjpeg-dev libpng-dev \ libfreetype6-dev libx11-dev libxi-dev wget libsqlite3-dev libbz2-dev \ libncurses5-dev libssl-dev liblzma-dev libreadline-dev $OPENJPEG_DEV \ - libopenexr-dev libopenal-dev libglew-dev yasm $THEORA_DEV \ - $VORBIS_DEV libsdl1.2-dev libfftw3-dev python-dev patch bzip2" + libopenexr-dev libopenal-dev libglew-dev yasm $THEORA_DEV $VORBIS_DEV \ + libsdl1.2-dev libfftw3-dev patch bzip2" + OPENJPEG_USE=true VORBIS_USE=true THEORA_USE=true + # Install newest libtiff-dev in debian/ubuntu. + TIFF="libtiff5" + check_package_DEB $TIFF + if [ $? -eq 0 ]; then + _packages="$_packages $TIFF-dev" + else + TIFF="libtiff" + check_package_DEB $TIFF + if [ $? -eq 0 ]; then + _packages="$_packages $TIFF-dev" + fi + fi + if $WITH_ALL; then - _packages="$_packages $SCHRO_DEV libjack0 libjack-dev" - SCHRO_USE=true + _packages="$_packages libspnav-dev libjack-dev" fi INFO "" @@ -1132,6 +1348,7 @@ install_DEB() { if $WITH_ALL; then INFO "" # Grmpf, debian is libxvidcore-dev and ubuntu libxvidcore4-dev! + # Note: not since ubuntu 10.04 XVID_DEV="libxvidcore-dev" check_package_DEB $XVID_DEV if [ $? -eq 0 ]; then @@ -1163,9 +1380,11 @@ install_DEB() { fi INFO "" - check_package_DEB libspnav-dev + SCHRO_DEV="libschroedinger-dev" + check_package_DEB $SCHRO_DEV if [ $? -eq 0 ]; then - install_packages_DEB libspnav-dev + install_packages_DEB $SCHRO_DEV + SCHRO_USE=true fi fi @@ -1173,11 +1392,28 @@ install_DEB() { if $PYTHON_SKIP; then INFO "WARNING! Skipping Python installation, as requested..." else - check_package_DEB python3.3-dev + check_package_DEB python$PYTHON_VERSION_MIN-dev if [ $? -eq 0 ]; then - install_packages_DEB python3.3-dev + install_packages_DEB python$PYTHON_VERSION_MIN-dev + INFO "" + if $NUMPY_SKIP; then + INFO "WARNING! Skipping NumPy installation, as requested..." + else + check_package_DEB python$PYTHON_VERSION_MIN-numpy + if [ $? -eq 0 ]; then + install_packages_DEB python$PYTHON_VERSION_MIN-numpy + else + INFO "WARNING! Sorry, using python package but no numpy package available!" + fi + fi else compile_Python + INFO "" + if $NUMPY_SKIP; then + INFO "WARNING! Skipping NumPy installation, as requested..." + else + compile_Numpy + fi fi fi @@ -1237,17 +1473,19 @@ install_DEB() { INFO "" check_package_DEB llvm-$LLVM_VERSION-dev if [ $? -eq 0 ]; then - install_packages_DEB llvm-$LLVM_VERSION-dev + install_packages_DEB llvm-$LLVM_VERSION-dev clang have_llvm=true LLVM_VERSION_FOUND=$LLVM_VERSION else check_package_DEB llvm-$LLVM_VERSION_MIN-dev if [ $? -eq 0 ]; then - install_packages_DEB llvm-$LLVM_VERSION_MIN-dev + install_packages_DEB llvm-$LLVM_VERSION_MIN-dev clang have_llvm=true LLVM_VERSION_FOUND=$LLVM_VERSION_MIN else install_packages_DEB libffi-dev + # LLVM can't find the debian ffi header dir + _FFI_INCLUDE_DIR=`dpkg -L libffi-dev | grep -e ".*/ffi.h" | sed -r 's/(.*)\/ffi.h/\1/'` INFO "" compile_LLVM have_llvm=true @@ -1257,12 +1495,11 @@ install_DEB() { fi if $OSL_SKIP; then - INFO "" INFO "WARNING! Skipping OpenShadingLanguage installation, as requested..." else if $have_llvm; then INFO "" - install_packages_DEB clang flex bison libtbb-dev git + install_packages_DEB flex bison libtbb-dev git # No package currently! INFO "" compile_OSL @@ -1270,6 +1507,19 @@ install_DEB() { fi fi + if $WITH_OPENCOLLADA; then + if $OPENCOLLADA_SKIP; then + INFO "WARNING! Skipping OpenCOLLADA installation, as requested..." + else + INFO "" + install_packages_DEB git libpcre3-dev libxml2-dev + # Find path to libxml shared lib... + _XML2_LIB=`dpkg -L libxml2-dev | grep -e ".*/libxml2.so"` + # No package + INFO "" + compile_OpenCOLLADA + fi + fi INFO "" if $FFMPEG_SKIP; then @@ -1294,12 +1544,24 @@ install_DEB() { fi } + + get_package_version_RPM() { - yum info $1 | grep Version | tail -n 1 | sed -r 's/.*:\s+(([0-9]+\.?)+).*/\1/' + rpm_flavour + if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then + yum info $1 | grep Version | tail -n 1 | sed -r 's/.*:\s+(([0-9]+\.?)+).*/\1/' + elif [ $RPM = "SUSE" ]; then + zypper info $1 | grep Version | tail -n 1 | sed -r 's/.*:\s+(([0-9]+\.?)+).*/\1/' + fi } check_package_RPM() { - r=`yum info $1 | grep -c 'Summary'` + rpm_flavour + if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then + r=`yum info $1 | grep -c 'Summary'` + elif [ $RPM = "SUSE" ]; then + r=`zypper info $1 | grep -c 'Summary'` + fi if [ $r -ge 1 ]; then return 0 @@ -1331,10 +1593,20 @@ check_package_version_ge_RPM() { } install_packages_RPM() { - sudo yum install -y $@ - if [ $? -ge 1 ]; then - ERROR "yum failed to install requested packages, exiting." - exit 1 + rpm_flavour + if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then + sudo yum install -y $@ + if [ $? -ge 1 ]; then + ERROR "yum failed to install requested packages, exiting." + exit 1 + fi + + elif [ $RPM = "SUSE" ]; then + sudo zypper --non-interactive install --auto-agree-with-licenses $@ + if [ $? -ge 1 ]; then + ERROR "zypper failed to install requested packages, exiting." + exit 1 + fi fi } @@ -1345,48 +1617,138 @@ install_RPM() { INFO "`eval _echo "$COMMON_INFO"`" INFO "" - sudo yum -y update + read -p "Do you want to continue (Y/n)?" + [ "$(echo ${REPLY:=Y} | tr [:upper:] [:lower:])" != "y" ] && exit - # These libs should always be available in debian/ubuntu official repository... + # Enable non-free repositories for all flavours + rpm_flavour + if [ $RPM = "FEDORA" ]; then + sudo yum -y localinstall --nogpgcheck \ + http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm \ + http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-stable.noarch.rpm + + sudo yum -y update + + # Install cmake now because of difference with RHEL + sudo yum -y install cmake + + elif [ $RPM = "RHEL" ]; then + sudo yum -y localinstall --nogpgcheck \ + http://download.fedoraproject.org/pub/epel/6/$(uname -i)/epel-release-6-8.noarch.rpm \ + http://download1.rpmfusion.org/free/el/updates/6/$(uname -i)/rpmfusion-free-release-6-1.noarch.rpm \ + http://download1.rpmfusion.org/nonfree/el/updates/6/$(uname -i)/rpmfusion-nonfree-release-6-1.noarch.rpm + + sudo yum -y update + + # Install cmake 2.8 from other repo + mkdir -p $SRC + if [ -f $SRC/cmake-2.8.8-4.el6.$(uname -m).rpm ]; then + INFO "" + INFO "Special cmake already installed" + else + curl -O ftp://ftp.pbone.net/mirror/atrpms.net/el6-$(uname -i)/atrpms/testing/cmake-2.8.8-4.el6.$(uname -m).rpm + mv cmake-2.8.8-4.el6.$(uname -m).rpm $SRC/ + sudo rpm -ihv $SRC/cmake-2.8.8-4.el6.$(uname -m).rpm + fi + + elif [ $RPM = "SUSE" ]; then + _suse_rel="`grep VERSION /etc/SuSE-release | gawk '{print $3}'`" + sudo zypper ar -f http://packman.inode.at/suse/openSUSE_$_suse_rel/ packman + + sudo zypper --non-interactive --gpg-auto-import-keys update --auto-agree-with-licenses + fi + + # These libs should always be available in fedora/suse official repository... OPENJPEG_DEV="openjpeg-devel" - SCHRO_DEV="schroedinger-devel" VORBIS_DEV="libvorbis-devel" THEORA_DEV="libtheora-devel" - _packages="gawk gcc gcc-c++ cmake scons libpng-devel libtiff-devel freetype-devel \ - libX11-devel libXi-devel wget libsqlite3x-devel ncurses-devel \ - readline-devel $OPENJPEG_DEV openexr-devel openal-soft-devel \ + _packages="gcc gcc-c++ make scons libpng-devel libtiff-devel \ + freetype-devel libX11-devel libXi-devel wget ncurses-devel \ + readline-devel $OPENJPEG_DEV openal-soft-devel \ glew-devel yasm $THEORA_DEV $VORBIS_DEV SDL-devel fftw-devel \ - lame-libs libjpeg-devel patch python-devel" + libjpeg-devel patch" + OPENJPEG_USE=true VORBIS_USE=true THEORA_USE=true - if $WITH_ALL; then - _packages="$_packages $SCHRO_DEV jack-audio-connection-kit-devel libspnav-devel" - SCHRO_USE=true - fi + if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then - INFO "" - install_packages_RPM $_packages + _packages="$_packages libsqlite3-devel openexr-devel" - INFO "" - X264_DEV="x264-devel" - check_package_version_ge_RPM $X264_DEV $X264_VERSION_MIN - if [ $? -eq 0 ]; then - install_packages_RPM $X264_DEV - X264_USE=true - fi - - if $WITH_ALL; then - INFO "" - XVID_DEV="xvidcore-devel" - check_package_RPM $XVID_DEV - if [ $? -eq 0 ]; then - install_packages_RPM $XVID_DEV - XVID_USE=true + if $WITH_ALL; then + _packages="$_packages jack-audio-connection-kit-devel libspnav-devel" fi + INFO "" + install_packages_RPM $_packages + + INFO "" + X264_DEV="x264-devel" + check_package_version_ge_RPM $X264_DEV $X264_VERSION_MIN + if [ $? -eq 0 ]; then + install_packages_RPM $X264_DEV + X264_USE=true + fi + + if $WITH_ALL; then + INFO "" + XVID_DEV="xvidcore-devel" + check_package_RPM $XVID_DEV + if [ $? -eq 0 ]; then + install_packages_RPM $XVID_DEV + XVID_USE=true + fi + + INFO "" + MP3LAME_DEV="lame-devel" + check_package_RPM $MP3LAME_DEV + if [ $? -eq 0 ]; then + install_packages_RPM $MP3LAME_DEV + MP3LAME_USE=true + fi + fi + + elif [ $RPM = "SUSE" ]; then + + _packages="$_packages cmake sqlite3-devel libopenexr-devel" + + if $WITH_ALL; then + _packages="$_packages libjack-devel libspnav-devel" + fi + + INFO "" + install_packages_RPM $_packages + + INFO "" + X264_DEV="libx264-devel" + check_package_version_ge_RPM $X264_DEV $X264_VERSION_MIN + if [ $? -eq 0 ]; then + install_packages_RPM $X264_DEV + X264_USE=true + fi + + if $WITH_ALL; then + INFO "" + XVID_DEV="libxvidcore-devel" + check_package_RPM $XVID_DEV + if [ $? -eq 0 ]; then + install_packages_RPM $XVID_DEV + XVID_USE=true + fi + + INFO "" + MP3LAME_DEV="libmp3lame-devel" + check_package_RPM $MP3LAME_DEV + if [ $? -eq 0 ]; then + install_packages_RPM $MP3LAME_DEV + MP3LAME_USE=true + fi + fi + fi + + if $WITH_ALL; then INFO "" VPX_DEV="libvpx-devel" check_package_version_ge_RPM $VPX_DEV $VPX_VERSION_MIN @@ -1396,14 +1758,14 @@ install_RPM() { fi INFO "" - MP3LAME_DEV="lame-devel" - check_package_RPM $MP3LAME_DEV + SCHRO_DEV="schroedinger-devel" + check_package_RPM $SCHRO_DEV if [ $? -eq 0 ]; then - install_packages_RPM $MP3LAME_DEV - MP3LAME_USE=true + install_packages_RPM $SCHRO_DEV + SCHRO_USE=true fi fi - + INFO "" if $PYTHON_SKIP; then INFO "WARNING! Skipping Python installation, as requested..." @@ -1411,8 +1773,25 @@ install_RPM() { check_package_version_match_RPM python3-devel $PYTHON_VERSION_MIN if [ $? -eq 0 ]; then install_packages_RPM python3-devel + INFO "" + if $NUMPY_SKIP; then + INFO "WARNING! Skipping NumPy installation, as requested..." + else + check_package_version_match_RPM python3-numpy $NUMPY_VERSION_MIN + if [ $? -eq 0 ]; then + install_packages_RPM python3-numpy + else + INFO "WARNING! Sorry, using python package but no numpy package available!" + fi + fi else compile_Python + INFO "" + if $NUMPY_SKIP; then + INFO "WARNING! Skipping NumPy installation, as requested..." + else + compile_Numpy + fi fi fi @@ -1420,7 +1799,7 @@ install_RPM() { if $BOOST_SKIP; then INFO "WARNING! Skipping Boost installation, as requested..." else - check_package_version_ge_RPM boost-devel $BOOST_VERSION_MIN + check_package_version_ge_RPM boost-devel $BOOST_VERSION if [ $? -eq 0 ]; then install_packages_RPM boost-devel else @@ -1461,25 +1840,15 @@ install_RPM() { else check_package_RPM llvm-$LLVM_VERSION-devel if [ $? -eq 0 ]; then - install_packages_RPM llvm-$LLVM_VERSION-devel + install_packages_RPM llvm-$LLVM_VERSION-devel clang have_llvm=true LLVM_VERSION_FOUND=$LLVM_VERSION else -# check_package_RPM llvm-$LLVM_VERSION_MIN-devel -# if [ $? -eq 0 ]; then -# install_packages_RPM llvm-$LLVM_VERSION_MIN-devel -# have_llvm=true -# LLVM_VERSION_FOUND=$LLVM_VERSION_MIN -# else -# check_package_version_ge_RPM llvm-devel $LLVM_VERSION_MIN -# if [ $? -eq 0 ]; then -# install_packages_RPM llvm-devel -# have_llvm=true -# LLVM_VERSION_FOUND=`get_package_version_RPM llvm-devel` -# fi -# fi + # + # Better to compile it than use minimum version from repo... + # install_packages_RPM libffi-devel - # XXX Stupid fedora puts ffi header into a darn stupid dir! + # LLVM can't find the fedora ffi header dir... _FFI_INCLUDE_DIR=`rpm -ql libffi-devel | grep -e ".*/ffi.h" | sed -r 's/(.*)\/ffi.h/\1/'` INFO "" compile_LLVM @@ -1493,15 +1862,32 @@ install_RPM() { INFO "WARNING! Skipping OpenShadingLanguage installation, as requested..." else if $have_llvm; then - INFO "" - install_packages_RPM flex bison clang tbb-devel git # No package currently! INFO "" + install_packages_RPM flex bison git + if [ $RPM = "FEDORA" -o $RPM = "RHEL" ]; then + install_packages_RPM tbb-devel + fi + INFO "" compile_OSL fi fi fi + if $WITH_OPENCOLLADA; then + if $OPENCOLLADA_SKIP; then + INFO "WARNING! Skipping OpenCOLLADA installation, as requested..." + else + INFO "" + install_packages_RPM pcre-devel libxml2-devel git + # Find path to libxml shared lib... + _XML2_LIB=`rpm -ql libxml2-devel | grep -e ".*/libxml2.so"` + # No package... + INFO "" + compile_OpenCOLLADA + fi + fi + INFO "" if $FFMPEG_SKIP; then INFO "WARNING! Skipping FFMpeg installation, as requested..." @@ -1511,199 +1897,7 @@ install_RPM() { fi } -get_package_version_SUSE() { - zypper info $1 | grep Version | tail -n 1 | sed -r 's/.*:\s+(([0-9]+\.?)+).*/\1/' -} -check_package_SUSE() { - r=`zypper info $1 | grep -c 'Summary'` - - if [ $r -ge 1 ]; then - return 0 - else - return 1 - fi -} - -check_package_version_match_SUSE() { - v=`get_package_version_SUSE $1` - - if [ -z "$v" ]; then - return 1 - fi - - version_match $v $2 - return $? -} - -check_package_version_ge_SUSE() { - v=`get_package_version_SUSE $1` - - if [ -z "$v" ]; then - return 1 - fi - - version_ge $v $2 - return $? -} - -install_packages_SUSE() { - sudo zypper --non-interactive install --auto-agree-with-licenses $@ - if [ $? -ge 1 ]; then - ERROR "zypper failed to install requested packages, exiting." - exit 1 - fi -} - - -install_SUSE() { - INFO "" - INFO "Installing dependencies for SuSE-based distribution" - INFO "" - INFO "`eval _echo "$COMMON_INFO"`" - INFO "" - - sudo zypper --non-interactive update --auto-agree-with-licenses - - # These libs should always be available in debian/ubuntu official repository... - OPENJPEG_DEV="openjpeg-devel" - SCHRO_DEV="schroedinger-devel" - VORBIS_DEV="libvorbis-devel" - THEORA_DEV="libtheora-devel" - - _packages="gawk gcc gcc-c++ cmake scons libpng12-devel libtiff-devel freetype-devel \ - libX11-devel libXi-devel wget sqlite3-devel ncurses-devel \ - readline-devel $OPENJPEG_DEV libopenexr-devel openal-soft-devel \ - glew-devel yasm $THEORA_DEV $VORBIS_DEV libSDL-devel fftw3-devel \ - libjpeg62-devel patch python-devel" - OPENJPEG_USE=true - VORBIS_USE=true - THEORA_USE=true - - if $WITH_ALL; then - _packages="$_packages $SCHRO_DEV libjack-devel libspnav-devel" - SCHRO_USE=true - fi - - INFO "" - install_packages_SUSE $_packages - - INFO "" - X264_DEV="x264-devel" - check_package_version_ge_SUSE $X264_DEV $X264_VERSION_MIN - if [ $? -eq 0 ]; then - install_packages_SUSE $X264_DEV - X264_USE=true - fi - - if $WITH_ALL; then - INFO "" - XVID_DEV="xvidcore-devel" - check_package_SUSE $XVID_DEV - if [ $? -eq 0 ]; then - install_packages_SUSE $XVID_DEV - XVID_USE=true - fi - - INFO "" - VPX_DEV="libvpx-devel" - check_package_version_ge_SUSE $VPX_DEV $VPX_VERSION_MIN - if [ $? -eq 0 ]; then - install_packages_SUSE $VPX_DEV - VPX_USE=true - fi - - INFO "" - # No mp3 in suse, it seems. - MP3LAME_DEV="lame-devel" - check_package_SUSE $MP3LAME_DEV - if [ $? -eq 0 ]; then - install_packages_SUSE $MP3LAME_DEV - MP3LAME_USE=true - fi - fi - - INFO "" - if $PYTHON_SKIP; then - INFO "WARNING! Skipping Python installation, as requested..." - else - check_package_version_match_SUSE python3-devel 3.3. - if [ $? -eq 0 ]; then - install_packages_SUSE python3-devel - else - compile_Python - fi - fi - - INFO "" - if $BOOST_SKIP; then - INFO "WARNING! Skipping Boost installation, as requested..." - else - # No boost_locale currently available, so let's build own boost. - compile_Boost - fi - - INFO "" - if $OCIO_SKIP; then - INFO "WARNING! Skipping OpenColorIO installation, as requested..." - else - # No ocio currently available, so let's build own boost. - compile_OCIO - fi - - INFO "" - if $OIIO_SKIP; then - INFO "WARNING! Skipping OpenImageIO installation, as requested..." - else - # No oiio currently available, so let's build own boost. - compile_OIIO - fi - - if $WITH_OSL; then - have_llvm=false - - INFO "" - if $LLVM_SKIP; then - INFO "WARNING! Skipping LLVM installation, as requested (this also implies skipping OSL!)..." - else - # Suse llvm package *_$SUCKS$_* (tm) !!! -# check_package_version_ge_SUSE llvm-devel $LLVM_VERSION_MIN -# if [ $? -eq 0 ]; then -# install_packages_SUSE llvm-devel -# have_llvm=true -# LLVM_VERSION_FOUND=`get_package_version_SUSE llvm-devel` -# fi - - install_packages_SUSE libffi47-devel - INFO "" - compile_LLVM - have_llvm=true - LLVM_VERSION_FOUND=$LLVM_VERSION - fi - - if $OSL_SKIP; then - INFO "" - INFO "WARNING! Skipping OpenShaderLanguage installation, as requested..." - else - if $have_llvm; then - INFO "" - # XXX No tbb lib! - install_packages_SUSE flex bison git - # No package currently! - INFO "" - compile_OSL - fi - fi - fi - - INFO "" - if $FFMPEG_SKIP; then - INFO "WARNING! Skipping FFMpeg installation, as requested..." - else - # No ffmpeg currently available, so let's build own boost. - compile_FFmpeg - fi -} print_info_ffmpeglink_DEB() { if $ALL_STATIC; then @@ -1714,19 +1908,12 @@ print_info_ffmpeglink_DEB() { } print_info_ffmpeglink_RPM() { - if $ALL_STATIC; then - rpm -ql $_packages | grep -e ".*\/lib[^\/]\+\.a" | gawk '{ printf(nlines ? "'"$_ffmpeg_list_sep"'%s" : "%s", $0); nlines++ }' - else - rpm -ql $_packages | grep -e ".*\/lib[^\/]\+\.so" | gawk '{ printf(nlines ? "'"$_ffmpeg_list_sep"'%s" : "%s", gensub(/.*lib([^\/]+)\.so/, "\\1", "g", $0)); nlines++ }' - fi -} - -print_info_ffmpeglink_SUSE() { - if $ALL_STATIC; then - rpm -ql $_packages | grep -e ".*\/lib[^\/]\+\.a" | gawk '{ printf(nlines ? "'"$_ffmpeg_list_sep"'%s" : "%s", $0); nlines++ }' - else - rpm -ql $_packages | grep -e ".*\/lib[^\/]\+\.so" | gawk '{ printf(nlines ? "'"$_ffmpeg_list_sep"'%s" : "%s", gensub(/.*lib([^\/]+)\.so/, "\\1", "g", $0)); nlines++ }' - fi +# # XXX No static libs... +# if $ALL_STATIC; then +# rpm -ql $_packages | grep -e ".*\/lib[^\/]\+\.a" | gawk '{ printf(nlines ? "'"$_ffmpeg_list_sep"'%s" : "%s", $0); nlines++ }' +# else + rpm -ql $_packages | grep -e ".*\/lib[^\/]\+\.so" | gawk '{ printf(nlines ? "'"$_ffmpeg_list_sep"'%s" : "%s", gensub(/.*lib([^\/]+)\.so/, "\\1", "g", $0)); nlines++ }' +# fi } print_info_ffmpeglink() { @@ -1767,8 +1954,7 @@ print_info_ffmpeglink() { _packages="$_packages $OPENJPEG_DEV" fi - # XXX At least under Debian, static schro gives problem at blender linking time... :/ - if $SCHRO_USE && ! $ALL_STATIC; then + if $SCHRO_USE; then _packages="$_packages $SCHRO_DEV" fi @@ -1776,8 +1962,8 @@ print_info_ffmpeglink() { print_info_ffmpeglink_DEB elif [ "$DISTRO" = "RPM" ]; then print_info_ffmpeglink_RPM - elif [ "$DISTRO" = "SUSE" ]; then - print_info_ffmpeglink_SUSE +# elif [ "$DISTRO" = "ARCH" ]; then +# print_info_ffmpeglink_ARCH # XXX TODO! else INFO "" fi @@ -1791,8 +1977,11 @@ print_info() { if $ALL_STATIC; then _1="-D WITH_STATIC_LIBS=ON" + # XXX Force linking with shared SDL lib! + _2="-D SDL_LIBRARY='libSDL.so;-lpthread'" INFO " $_1" - _buildargs="$_buildargs $_1" + INFO " $_2" + _buildargs="$_buildargs $_1 $_2" fi if [ -d $INST/boost ]; then @@ -1824,6 +2013,17 @@ print_info() { fi fi + if [ -d $INST/opencollada -a $WITH_OPENCOLLADA == true ]; then + _1="-D WITH_OPENCOLLADA=ON" + INFO " $_1" + _buildargs="$_buildargs $_1" + if $ALL_STATIC; then + _1="-D XML2_LIBRARY=$_XML2_LIB" + INFO " $_1" + _buildargs="$_buildargs $_1" + fi + fi + if [ -d $INST/ffmpeg ]; then _1="-D WITH_CODEC_FFMPEG=ON" _2="-D FFMPEG=$INST/ffmpeg" @@ -1835,14 +2035,14 @@ print_info() { fi INFO "" - INFO "Or even simpler, just run (in your build dir):" + INFO "Or even simpler, just run (in your blender-source dir):" INFO " make -j$THREADS BUILD_CMAKE_ARGS=\"$_buildargs\"" INFO "" INFO "If you're using SCons add this to your user-config:" - if [ -d $INST/python-3.3 ]; then - INFO "BF_PYTHON = '$INST/python-3.3'" + if [ -d $INST/python-$PYTHON_VERSION_MIN ]; then + INFO "BF_PYTHON = '$INST/python-$PYTHON_VERSION_MIN'" INFO "BF_PYTHON_ABI_FLAGS = 'm'" fi @@ -1885,11 +2085,14 @@ elif [ "$DISTRO" = "DEB" ]; then install_DEB elif [ "$DISTRO" = "RPM" ]; then install_RPM -elif [ "$DISTRO" = "SUSE" ]; then - install_SUSE +#elif [ "$DISTRO" = "ARCH" ]; then +# install_ARCH fi -print_info +print_info | tee BUILD_NOTES.txt +INFO "" +INFO "This information has been written to BUILD_NOTES.txt" +INFO "" # Switch back to user language. LANG=LANG_BACK diff --git a/build_files/cmake/Modules/FindOpenCOLLADA.cmake b/build_files/cmake/Modules/FindOpenCOLLADA.cmake index 169d3a82fc7..84aead58b60 100644 --- a/build_files/cmake/Modules/FindOpenCOLLADA.cmake +++ b/build_files/cmake/Modules/FindOpenCOLLADA.cmake @@ -66,6 +66,7 @@ SET(_opencollada_SEARCH_DIRS /sw # Fink /opt/local # DarwinPorts /opt/csw # Blastwave + /opt/lib/opencollada ) SET(_opencollada_INCLUDES) diff --git a/build_files/cmake/cmake_consistency_check.py b/build_files/cmake/cmake_consistency_check.py index b13b0ddb424..665bc600efa 100755 --- a/build_files/cmake/cmake_consistency_check.py +++ b/build_files/cmake/cmake_consistency_check.py @@ -75,12 +75,12 @@ def is_cmake(filename): def is_c_header(filename): ext = splitext(filename)[1] - return (ext in (".h", ".hpp", ".hxx")) + return (ext in {".h", ".hpp", ".hxx", ".hh"}) def is_c(filename): ext = splitext(filename)[1] - return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc", ".cc", ".inl")) + return (ext in {".c", ".cpp", ".cxx", ".m", ".mm", ".rc", ".cc", ".inl"}) def is_c_any(filename): diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index efa258aa9dc..bdd82a4f438 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -282,7 +282,9 @@ macro(setup_liblinks if(WITH_SYSTEM_GLEW) target_link_libraries(${target} ${GLEW_LIBRARY}) endif() - + if(WITH_BULLET AND WITH_SYSTEM_BULLET) + target_link_libraries(${target} ${BULLET_LIBRARIES}) + endif() if(WITH_OPENAL) target_link_libraries(${target} ${OPENAL_LIBRARY}) endif() @@ -441,6 +443,15 @@ macro(TEST_SSE_SUPPORT unset(CMAKE_REQUIRED_FLAGS) endmacro() +macro(TEST_STDBOOL_SUPPORT) + # This program will compile correctly if and only if + # this C compiler supports C99 stdbool. + check_c_source_runs(" + #include + int main(void) { return (int)false; }" + HAVE_STDBOOL_H) +endmacro() + # when we have warnings as errors applied globally this # needs to be removed for some external libs which we dont maintain. diff --git a/build_files/cmake/project_info.py b/build_files/cmake/project_info.py index 34f378a58dd..495ca71263e 100755 --- a/build_files/cmake/project_info.py +++ b/build_files/cmake/project_info.py @@ -97,7 +97,7 @@ def is_cmake(filename): def is_c_header(filename): ext = splitext(filename)[1] - return (ext in (".h", ".hpp", ".hxx")) + return (ext in {".h", ".hpp", ".hxx", ".hh"}) def is_py(filename): diff --git a/build_files/cmake/project_source_info.py b/build_files/cmake/project_source_info.py index 10bc36ba1a8..69d09b05ac7 100644 --- a/build_files/cmake/project_source_info.py +++ b/build_files/cmake/project_source_info.py @@ -43,7 +43,7 @@ SOURCE_DIR = abspath(SOURCE_DIR) def is_c_header(filename): ext = os.path.splitext(filename)[1] - return (ext in (".h", ".hpp", ".hxx")) + return (ext in {".h", ".hpp", ".hxx", ".hh"}) def is_c(filename): diff --git a/build_files/package_spec/rpm/blender.spec.in b/build_files/package_spec/rpm/blender.spec.in index a95fce80103..e75cc8ec7a6 100644 --- a/build_files/package_spec/rpm/blender.spec.in +++ b/build_files/package_spec/rpm/blender.spec.in @@ -77,6 +77,7 @@ fi || : %{_bindir}/%{name} %{_datadir}/%{name}/%{blender_api}/datafiles/fonts %{_datadir}/%{name}/%{blender_api}/datafiles/colormanagement +%{_datadir}/%{name}/%{blender_api}/datafiles/locale/languages %{_datadir}/%{name}/%{blender_api}/scripts %{_datadir}/icons/hicolor/*/apps/%{name}.* %{_datadir}/applications/%{name}.desktop diff --git a/doc/python_api/examples/bpy.types.AddonPreferences.1.py b/doc/python_api/examples/bpy.types.AddonPreferences.1.py new file mode 100644 index 00000000000..08de6f4f5a9 --- /dev/null +++ b/doc/python_api/examples/bpy.types.AddonPreferences.1.py @@ -0,0 +1,70 @@ +bl_info = { + "name": "Example Addon Preferences", + "author": "Your Name Here", + "version": (1, 0), + "blender": (2, 65, 0), + "location": "SpaceBar Search -> Addon Preferences Example", + "description": "Example Addon", + "warning": "", + "wiki_url": "", + "tracker_url": "", + "category": "Object"} + + +import bpy +from bpy.types import Operator, AddonPreferences +from bpy.props import StringProperty, IntProperty, BoolProperty + + +class ExampleAddonPreferences(AddonPreferences): + bl_idname = __name__ + + filepath = StringProperty( + name="Example File Path", + subtype='FILE_PATH', + ) + number = IntProperty( + name="Example Number", + default=4, + ) + boolean = BoolProperty( + name="Example Boolean", + default=False, + ) + + def draw(self, context): + layout = self.layout + layout.label(text="This is a preferences view for our addon") + layout.prop(self, "filepath") + layout.prop(self, "number") + layout.prop(self, "boolean") + + +class OBJECT_OT_addon_prefs_example(Operator): + """Display example preferences""" + bl_idname = "object.addon_prefs_example" + bl_label = "Addon Preferences Example" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + user_preferences = context.user_preferences + addon_prefs = user_preferences.addons[__name__].preferences + + info = ("Path: %s, Number: %d, Boolean %r" % + (addon_prefs.filepath, addon_prefs.number, addon_prefs.boolean)) + + self.report({'INFO'}, info) + print(info) + + return {'FINISHED'} + + +# Registration +def register(): + bpy.utils.register_class(OBJECT_OT_addon_prefs_example) + bpy.utils.register_class(ExampleAddonPreferences) + + +def unregister(): + bpy.utils.unregister_class(OBJECT_OT_addon_prefs_example) + bpy.utils.unregister_class(ExampleAddonPreferences) diff --git a/doc/python_api/examples/bpy.types.UIList.py b/doc/python_api/examples/bpy.types.UIList.py new file mode 100644 index 00000000000..f2017e3883d --- /dev/null +++ b/doc/python_api/examples/bpy.types.UIList.py @@ -0,0 +1,89 @@ +""" +Basic UIList Example ++++++++++++++++++++ +This script is the UIList subclass used to show material slots, with a bunch of additional commentaries. + +Notice the name of the class, this naming convention is similar as the one for panels or menus. + +.. note:: + + UIList subclasses must be registered for blender to use them. +""" +import bpy + + +class MATERIAL_UL_matslots_example(bpy.types.UIList): + # The draw_item function is called for each item of the collection that is visible in the list. + # data is the RNA object containing the collection, + # item is the current drawn item of the collection, + # icon is the "computed" icon for the item (as an integer, because some objects like materials or textures + # have custom icons ID, which are not available as enum items). + # active_data is the RNA object containing the active property for the collection (i.e. integer pointing to the + # active item of the collection). + # active_propname is the name of the active property (use 'getattr(active_data, active_propname)'). + # index is index of the current item in the collection. + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + ob = data + slot = item + ma = slot.material + # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code. + if self.layout_type in {'DEFAULT', 'COMPACT'}: + # You should always start your row layout by a label (icon + text), this will also make the row easily + # selectable in the list! + # We use icon_value of label, as our given icon is an integer value, not an enum ID. + layout.label(ma.name if ma else "", icon_value=icon) + # And now we can add other UI stuff... + # Here, we add nodes info if this material uses (old!) shading nodes. + if ma and not context.scene.render.use_shading_nodes: + manode = ma.active_node_material + if manode: + # The static method UILayout.icon returns the integer value of the icon ID "computed" for the given + # RNA object. + layout.label("Node %s" % manode.name, icon_value=layout.icon(manode)) + elif ma.use_nodes: + layout.label("Node ") + else: + layout.label("") + # 'GRID' layout type should be as compact as possible (typically a single icon!). + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) + + +# And now we can use this list everywhere in Blender. Here is a small example panel. +class UIListPanelExample(bpy.types.Panel): + """Creates a Panel in the Object properties window""" + bl_label = "UIList Panel" + bl_idname = "OBJECT_PT_ui_list_example" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "object" + + def draw(self, context): + layout = self.layout + + obj = context.object + + # template_list now takes two new args. + # The first one is the identifier of the registered UIList to use (if you want only the default list, + # with no custom draw code, use "UI_UL_list"). + layout.template_list("MATERIAL_UL_matslots_example", "", obj, "material_slots", obj, "active_material_index") + + # The second one can usually be left as an empty string. It's an additional ID used to distinguish lists in case you + # use the same list several times in a given area. + layout.template_list("MATERIAL_UL_matslots_example", "compact", obj, "material_slots", + obj, "active_material_index", type='COMPACT') + + +def register(): + bpy.utils.register_class(MATERIAL_UL_matslots_example) + bpy.utils.register_class(UIListPanelExample) + + +def unregister(): + bpy.utils.unregister_class(MATERIAL_UL_matslots_example) + bpy.utils.unregister_class(UIListPanelExample) + + +if __name__ == "__main__": + register() \ No newline at end of file diff --git a/doc/python_api/rst/bge.types.rst b/doc/python_api/rst/bge.types.rst index 470e1c56bac..a86272ddf5c 100644 --- a/doc/python_api/rst/bge.types.rst +++ b/doc/python_api/rst/bge.types.rst @@ -3749,6 +3749,18 @@ Types :type: float + .. attribute:: maxJumps + + The maximum number of jumps a character can perform before having to touch the ground. By default this is set to 1. 2 allows for a double jump, etc. + + :type: int + + .. attribute:: jumpCount + + The current jump count. This can be used to have different logic for a single jump versus a double jump. For example, a different animation for the second jump. + + :type: int + .. method:: jump() The character jumps based on it's jump speed. diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index d79c4e8fa9a..89659c10add 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -614,6 +614,10 @@ def pyfunc2sphinx(ident, fw, identifier, py_func, is_class=True): ''' function or class method to sphinx ''' + + if type(py_func) == type(bpy.types.Space.draw_handler_add): + return + arg_str = inspect.formatargspec(*inspect.getargspec(py_func)) if not is_class: diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 2640c528c94..6ad6bdc316f 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -27,9 +27,12 @@ remove_strict_flags() add_subdirectory(colamd) +add_subdirectory(rangetree) if(WITH_BULLET) - add_subdirectory(bullet2) + if(NOT WITH_SYSTEM_BULLET) + add_subdirectory(bullet2) + endif() endif() # now only available in a branch diff --git a/extern/SConscript b/extern/SConscript index 71998ee072c..6a0ffa3f588 100644 --- a/extern/SConscript +++ b/extern/SConscript @@ -4,6 +4,7 @@ Import('env') SConscript(['glew/SConscript']) SConscript(['colamd/SConscript']) +SConscript(['rangetree/SConscript']) if env['WITH_BF_GAMEENGINE']: SConscript(['recastnavigation/SConscript']) diff --git a/extern/rangetree/CMakeLists.txt b/extern/rangetree/CMakeLists.txt new file mode 100644 index 00000000000..ba682233381 --- /dev/null +++ b/extern/rangetree/CMakeLists.txt @@ -0,0 +1,31 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . +) + +set(SRC + range_tree.hh + range_tree_c_api.h + + range_tree_c_api.cc +) + +blender_add_lib(extern_rangetree "${SRC}" "${INC}" "") + diff --git a/extern/rangetree/README.org b/extern/rangetree/README.org new file mode 100644 index 00000000000..46a4cedaf8f --- /dev/null +++ b/extern/rangetree/README.org @@ -0,0 +1,13 @@ +* Overview + Basic class for storing non-overlapping scalar ranges. Underlying + representation is a C++ STL set for fast lookups. + +* License + GPL version 2 or later (see COPYING) + +* Author Note + This implementation is intended for storing free unique IDs in a new + undo system for BMesh in Blender, but could be useful elsewhere. + +* Website + https://github.com/nicholasbishop/RangeTree diff --git a/extern/rangetree/SConscript b/extern/rangetree/SConscript new file mode 100644 index 00000000000..787decd599e --- /dev/null +++ b/extern/rangetree/SConscript @@ -0,0 +1,9 @@ +2#!/usr/bin/python +Import ('env') + +sources = env.Glob('*.cc') + +incs = '.' +defs = '' + +env.BlenderLib ('extern_rangetree', sources, Split(incs), Split(defs), libtype=['extern'], priority=[100] ) diff --git a/extern/rangetree/range_tree.hh b/extern/rangetree/range_tree.hh new file mode 100644 index 00000000000..2a47c5a1d93 --- /dev/null +++ b/extern/rangetree/range_tree.hh @@ -0,0 +1,228 @@ +/* This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include +#include +#include +#include + +#ifndef RANGE_TREE_DEBUG_PRINT_FUNCTION +# define RANGE_TREE_DEBUG_PRINT_FUNCTION 0 +#endif + +template +struct RangeTree { + struct Range { + Range(T min_, T max_) + : min(min_), max(max_), single(min_ == max_) { + assert(min_ <= max_); + } + + Range(T t) + : min(t), max(t), single(true) + {} + + bool operator<(const Range& v) const { + return max < v.min; + } + + const T min; + const T max; + const bool single; + }; + + typedef std::set Tree; + typedef typename Tree::iterator TreeIter; + typedef typename Tree::reverse_iterator TreeIterReverse; + typedef typename Tree::const_iterator TreeIterConst; + + /* Initialize with a single range from 'min' to 'max', inclusive. */ + RangeTree(T min, T max) { + tree.insert(Range(min, max)); + } + + /* Initialize with a single range from 0 to 'max', inclusive. */ + RangeTree(T max) { + tree.insert(Range(0, max)); + } + + RangeTree(const RangeTree& src) { + tree = src.tree; + } + + /* Remove 't' from the associated range in the tree. Precondition: + a range including 't' must exist in the tree. */ + void take(T t) { + #if RANGE_TREE_DEBUG_PRINT_FUNCTION + std::cout << __func__ << "(" << t << ")\n"; + #endif + + /* Find the range that includes 't' and its neighbors */ + TreeIter iter = tree.find(Range(t)); + assert(iter != tree.end()); + Range cur = *iter; + TreeIter prev = iter; + TreeIter next = iter; + --prev; + ++next; + + /* Remove the original range (note that this does not + invalidate the prev/next iterators) */ + tree.erase(iter); + + /* Construct two new ranges that together cover the original + range, except for 't' */ + if (t > cur.min) + tree.insert(Range(cur.min, t - 1)); + if (t + 1 <= cur.max) + tree.insert(Range(t + 1, cur.max)); + } + + /* Take the first element out of the first range in the + tree. Precondition: tree must not be empty. */ + T take_any() { + #if RANGE_TREE_DEBUG_PRINT_FUNCTION + std::cout << __func__ << "()\n"; + #endif + + /* Find the first element */ + TreeIter iter = tree.begin(); + assert(iter != tree.end()); + T first = iter->min; + + /* Take the first element */ + take(first); + return first; + } + + /* Return 't' to the tree, either expanding/merging existing + ranges or adding a range to cover it. Precondition: 't' cannot + be in an existing range. */ + void release(T t) { + #if RANGE_TREE_DEBUG_PRINT_FUNCTION + std::cout << __func__ << "(" << t << ")\n"; + #endif + + /* TODO: these cases should be simplified/unified */ + + TreeIter right = tree.upper_bound(t); + if (right != tree.end()) { + TreeIter left = right; + if (left != tree.begin()) + --left; + + if (left == right) { + /* 't' lies before any existing ranges */ + if (t + 1 == left->min) { + /* 't' lies directly before the first range, + resize and replace that range */ + const Range r(t, left->max); + tree.erase(left); + tree.insert(r); + } + else { + /* There's a gap between 't' and the first range, + add a new range */ + tree.insert(Range(t)); + } + } + else if ((left->max + 1 == t) && + (t + 1 == right->min)) { + /* 't' fills a hole. Remove left and right, and insert a + new range that covers both. */ + const Range r(left->min, right->max); + tree.erase(left); + tree.erase(right); + tree.insert(r); + } + else if (left->max + 1 == t) { + /* 't' lies directly after 'left' range, resize and + replace that range */ + const Range r(left->min, t); + tree.erase(left); + tree.insert(r); + } + else if (t + 1 == right->min) { + /* 't' lies directly before 'right' range, resize and + replace that range */ + const Range r(t, right->max); + tree.erase(right); + tree.insert(r); + } + else { + /* There's a gap between 't' and both adjacent ranges, + add a new range */ + tree.insert(Range(t)); + } + } + else { + /* 't' lies after any existing ranges */ + right = tree.end(); + right--; + if (right->max + 1 == t) { + /* 't' lies directly after last range, resize and + replace that range */ + const Range r(right->min, t); + tree.erase(right); + tree.insert(r); + } + else { + /* There's a gap between the last range and 't', add a + new range */ + tree.insert(Range(t)); + } + } + } + + bool has(T t) const { + TreeIterConst iter = tree.find(Range(t)); + return (iter != tree.end()) && (t <= iter->max); + } + + bool has_range(T min, T max) const { + TreeIterConst iter = tree.find(Range(min, max)); + return (iter != tree.end()) && (min == iter->min && max == iter->max); + } + + bool empty() const { + return tree.empty(); + } + + int size() const { + return tree.size(); + } + + void print() const { + std::cout << "RangeTree:\n"; + for (TreeIterConst iter = tree.begin(); iter != tree.end(); ++iter) { + const Range& r = *iter; + if (r.single) + std::cout << " [" << r.min << "]\n"; + else + std::cout << " [" << r.min << ", " << r.max << "]\n"; + } + if (empty()) + std::cout << " "; + std::cout << "\n"; + } + + unsigned int allocation_lower_bound() const { + return tree.size() * sizeof(Range); + } + +private: + Tree tree; +}; diff --git a/extern/rangetree/range_tree_c_api.cc b/extern/rangetree/range_tree_c_api.cc new file mode 100644 index 00000000000..56f2d90d329 --- /dev/null +++ b/extern/rangetree/range_tree_c_api.cc @@ -0,0 +1,86 @@ +/* This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "range_tree.hh" + +/* Give RangeTreeUInt a real type rather than the opaque struct type + defined for external use. */ +#define RANGE_TREE_C_API_INTERNAL +typedef RangeTree RangeTreeUInt; + +#include "range_tree_c_api.h" + +RangeTreeUInt *range_tree_uint_alloc(unsigned min, unsigned max) +{ + return new RangeTreeUInt(min, max); +} + +RangeTreeUInt *range_tree_uint_copy(RangeTreeUInt *src) +{ + return new RangeTreeUInt(*src); +} + +void range_tree_uint_free(RangeTreeUInt *rt) +{ + delete rt; +} + +void range_tree_uint_take(RangeTreeUInt *rt, unsigned v) +{ + rt->take(v); +} + +unsigned range_tree_uint_take_any(RangeTreeUInt *rt) +{ + return rt->take_any(); +} + +void range_tree_uint_release(RangeTreeUInt *rt, unsigned v) +{ + rt->release(v); +} + +int range_tree_uint_has(const RangeTreeUInt *rt, unsigned v) +{ + return rt->has(v); +} + +int range_tree_uint_has_range(const RangeTreeUInt *rt, + unsigned vmin, + unsigned vmax) +{ + return rt->has_range(vmin, vmax); +} + +int range_tree_uint_empty(const RangeTreeUInt *rt) +{ + return rt->empty(); +} + +unsigned range_tree_uint_size(const RangeTreeUInt *rt) +{ + return rt->size(); +} + +void range_tree_uint_print(const RangeTreeUInt *rt) +{ + rt->print(); +} + +unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt) +{ + return rt->allocation_lower_bound(); +} diff --git a/extern/rangetree/range_tree_c_api.h b/extern/rangetree/range_tree_c_api.h new file mode 100644 index 00000000000..af6a7b161a8 --- /dev/null +++ b/extern/rangetree/range_tree_c_api.h @@ -0,0 +1,60 @@ +/* This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#ifndef RANGE_TREE_C_API_H +#define RANGE_TREE_C_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Simple C-accessible wrapper for RangeTree */ + +#ifndef RANGE_TREE_C_API_INTERNAL +typedef struct RangeTreeUInt RangeTreeUInt; +#endif + +RangeTreeUInt *range_tree_uint_alloc(unsigned min, unsigned max); + +RangeTreeUInt *range_tree_uint_copy(RangeTreeUInt *src); + +void range_tree_uint_free(RangeTreeUInt *rt); + +void range_tree_uint_take(RangeTreeUInt *rt, unsigned v); + +unsigned range_tree_uint_take_any(RangeTreeUInt *rt); + +void range_tree_uint_release(RangeTreeUInt *rt, unsigned v); + +int range_tree_uint_has(const RangeTreeUInt *rt, unsigned v); + +int range_tree_uint_has_range(const RangeTreeUInt *rt, + unsigned vmin, + unsigned vmax); + +int range_tree_uint_empty(const RangeTreeUInt *rt); + +unsigned range_tree_uint_size(const RangeTreeUInt *rt); + +void range_tree_uint_print(const RangeTreeUInt *rt); + +unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt); + +#ifdef __cplusplus +} +#endif + +#endif /* __DUALCON_H__ */ diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index 88363758364..710e8ba6a90 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -24,6 +24,7 @@ set(SRC blender_mesh.cpp blender_object.cpp blender_particles.cpp + blender_curves.cpp blender_python.cpp blender_session.cpp blender_shader.cpp diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index 6d1b6d4f56e..dddf7bafb14 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -21,7 +21,7 @@ bl_info = { "name": "Cycles Render Engine", "author": "", - "blender": (2, 6, 5), + "blender": (2, 60, 5), "location": "Info header, render engine menu", "description": "Cycles Render Engine integration", "warning": "", diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 26fc7a81936..2bc4afe969e 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -64,6 +64,38 @@ enum_panorama_types = ( "Similar to most fisheye modern lens, takes sensor dimensions into consideration"), ) +enum_curve_presets = ( + ('CUSTOM', "Custom", "Set general parameters"), + ('TANGENT_SHADING', "Tangent Normal", "Use planar geometry and tangent normals"), + ('TRUE_NORMAL', "True Normal", "Use true normals (good for thin strands)"), + ('ACCURATE_PRESET', "Accurate", "Use best settings (suitable for glass materials)"), + ) + +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)"), + ) + +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"), + ) + +enum_line_curves = ( + ('ACCURATE', "Accurate", "Always take into consideration strand width for intersections"), + ('QT_CORRECTED', "Corrected", "Ignore width for initial intersection and correct later"), + ('ENDCORRECTED', "Correct found", "Ignore width for all intersections and only correct closest"), + ('QT_UNCORRECTED', "Uncorrected", "Calculate intersections without considering width"), + ) + +enum_curves_interpolation = ( + ('LINEAR', "Linear interpolation", "Use Linear interpolation between segments"), + ('CARDINAL', "Cardinal interpolation", "Use cardinal interpolation between segments"), + ('BSPLINE', "B-spline interpolation", "Use b-spline interpolation between segments"), + ) + class CyclesRenderSettings(bpy.types.PropertyGroup): @classmethod def register(cls): @@ -237,7 +269,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): ) cls.film_transparent = BoolProperty( name="Transparent", - description="World background is transparent", + description="World background is transparent with premultiplied alpha", default=False, ) @@ -573,6 +605,157 @@ class CyclesMeshSettings(bpy.types.PropertyGroup): del bpy.types.Curve.cycles del bpy.types.MetaBall.cycles +class CyclesCurveRenderSettings(bpy.types.PropertyGroup): + @classmethod + def register(cls): + bpy.types.Scene.cycles_curves = PointerProperty( + name="Cycles Hair Rendering Settings", + description="Cycles hair rendering settings", + type=cls, + ) + cls.preset = EnumProperty( + name="Mode", + description="Hair rendering mode", + items=enum_curve_presets, + default='TRUE_NORMAL', + ) + cls.primitive = EnumProperty( + name="Primitive", + description="Type of primitive used for hair rendering", + items=enum_curve_primitives, + default='LINE_SEGMENTS', + ) + cls.triangle_method = EnumProperty( + name="Mesh Geometry", + description="Method for creating triangle geometry", + items=enum_triangle_curves, + default='CAMERA', + ) + cls.line_method = EnumProperty( + name="Intersection Method", + description="Method for line segment intersection", + items=enum_line_curves, + default='ACCURATE', + ) + cls.interpolation = EnumProperty( + name="Interpolation", + description="Interpolation method", + items=enum_curves_interpolation, + default='BSPLINE', + ) + cls.use_backfacing = BoolProperty( + name="Check back-faces", + description="Test back-faces of strands", + default=False, + ) + cls.use_encasing = BoolProperty( + name="Exclude encasing", + description="Ignore strands encasing a ray's initial location", + default=True, + ) + cls.use_tangent_normal_geometry = BoolProperty( + name="Tangent normal geometry", + description="Use the tangent normal for actual normal", + default=False, + ) + cls.use_tangent_normal = BoolProperty( + name="Tangent normal default", + description="Use the tangent normal for all normals", + default=False, + ) + cls.use_tangent_normal_correction = BoolProperty( + name="Strand slope correction", + 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", + default=False, + ) + cls.use_smooth = BoolProperty( + name="Smooth Strands", + description="Use vertex normals", + default=True, + ) + cls.use_joined = BoolProperty( + name="Join", + description="Fill gaps between segments (requires more memory)", + default=False, + ) + cls.use_curves = BoolProperty( + name="Use Cycles Hair Rendering", + description="Activate Cycles hair rendering for particle system", + default=True, + ) + cls.segments = IntProperty( + name="Segments", + description="Number of segments between path keys (note that this combines with the 'draw step' value)", + min=1, max=64, + default=1, + ) + cls.resolution = IntProperty( + name="Resolution", + description="Resolution of generated mesh", + min=3, max=64, + default=3, + ) + cls.normalmix = FloatProperty( + name="Normal mix", + description="Scale factor for tangent normal removal (zero gives ray normal)", + min=0, max=2.0, + default=1, + ) + cls.encasing_ratio = FloatProperty( + name="Encasing ratio", + description="Scale factor for encasing strand width", + min=0, max=100.0, + default=1.01, + ) + + @classmethod + def unregister(cls): + del bpy.types.Scene.cycles_curves + +class CyclesCurveSettings(bpy.types.PropertyGroup): + @classmethod + def register(cls): + bpy.types.ParticleSettings.cycles = PointerProperty( + name="Cycles Hair Settings", + description="Cycles hair settings", + type=cls, + ) + cls.root_width = FloatProperty( + name="Root Size Multiplier", + description="Multiplier of particle size for the strand's width at root", + min=0.0, max=1000.0, + default=1.0, + ) + cls.tip_width = FloatProperty( + name="Tip Size Multiplier", + description="Multiplier of particle size for the strand's width at tip", + min=0.0, max=1000.0, + default=0.0, + ) + cls.shape = FloatProperty( + name="Strand Shape", + description="Strand shape parameter", + min=-1.0, max=1.0, + default=0.0, + ) + cls.use_closetip = BoolProperty( + name="Close tip", + description="Set tip radius to zero", + default=True, + ) + + @classmethod + def unregister(cls): + del bpy.types.ParticleSettings.cycles def register(): bpy.utils.register_class(CyclesRenderSettings) @@ -582,6 +765,8 @@ def register(): bpy.utils.register_class(CyclesWorldSettings) bpy.utils.register_class(CyclesVisibilitySettings) bpy.utils.register_class(CyclesMeshSettings) + bpy.utils.register_class(CyclesCurveRenderSettings) + bpy.utils.register_class(CyclesCurveSettings) def unregister(): @@ -592,3 +777,5 @@ def unregister(): bpy.utils.unregister_class(CyclesWorldSettings) bpy.utils.unregister_class(CyclesMeshSettings) bpy.utils.unregister_class(CyclesVisibilitySettings) + bpy.utils.unregister_class(CyclesCurveRenderSettings) + bpy.utils.unregister_class(CyclesCurveSettings) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 7b19fde8f71..554a9204c7f 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -290,7 +290,7 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel): rd = scene.render row = layout.row() - row.template_list(rd, "layers", rd.layers, "active_index", rows=2) + row.template_list("RENDER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=2) col = row.column(align=True) col.operator("scene.render_layer_add", icon='ZOOMIN', text="") @@ -407,7 +407,7 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel): if ob: row = layout.row() - row.template_list(ob, "material_slots", ob, "active_material_index", rows=2) + row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=2) col = row.column(align=True) col.operator("object.material_slot_add", icon='ZOOMIN', text="") @@ -962,7 +962,7 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel): part = psys.settings row = layout.row() - row.template_list(part, "texture_slots", part, "active_texture_index", rows=2) + row.template_list("TEXTURE_UL_texslots", "", part, "texture_slots", part, "active_texture_index", rows=2) col = row.column(align=True) col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP' @@ -975,6 +975,89 @@ 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): + 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') + 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="") + + def draw(self, context): + layout = self.layout + + scene = context.scene + cscene = scene.cycles_curves + + layout.active = cscene.use_curves + + layout.prop(cscene, "preset", text="Mode") + + if cscene.preset == 'CUSTOM': + layout.prop(cscene, "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") + + row = layout.row() + row.prop(cscene, "use_encasing", text="Exclude encasing") + sub = row.row() + sub.active = cscene.use_encasing + sub.prop(cscene, "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") + + row = layout.row() + row.prop(cscene, "segments", text="Segments") + row.prop(cscene, "normalmix", text="Ray Mix") + + 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") + +class CyclesParticle_PT_CurveSettings(CyclesButtonsPanel, Panel): + bl_label = "Cycles Hair Settings" + bl_context = "particle" + + @classmethod + def poll(cls, context): + use_curves = context.scene.cycles_curves.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') + return CyclesButtonsPanel.poll(context) and experimental and use_curves + + def draw(self, context): + layout = self.layout + + psys = context.particle_settings + cpsys = psys.cycles + + row = layout.row() + row.prop(cpsys, "shape", text="Shape") + row.prop(cpsys, "use_closetip", text="Close tip") + + layout.label(text="Width multiplier:") + row = layout.row() + row.prop(cpsys, "root_width", text="Root") + row.prop(cpsys, "tip_width", text="Tip") + class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel): bl_label = "Simplify" diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp new file mode 100644 index 00000000000..4fad7d45162 --- /dev/null +++ b/intern/cycles/blender/blender_curves.cpp @@ -0,0 +1,1130 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "attribute.h" +#include "mesh.h" +#include "object.h" +#include "scene.h" +#include "curves.h" + +#include "blender_sync.h" +#include "blender_util.h" + +#include "util_foreach.h" + +CCL_NAMESPACE_BEGIN + +/* Utilities */ + +/* Hair curve functions */ + +void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]); +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 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); +void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments); +void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments); +void ExportCurveSegments(Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments); +void ExportCurveTriangleUVs(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, int vert_offset, int resol); + +ParticleCurveData::ParticleCurveData() +{ +} + +ParticleCurveData::~ParticleCurveData() +{ + psys_firstcurve.clear(); + psys_curvenum.clear(); + psys_shader.clear(); + psys_rootradius.clear(); + psys_tipradius.clear(); + psys_shape.clear(); + + curve_firstkey.clear(); + curve_keynum.clear(); + curve_length.clear(); + curve_uv.clear(); + curve_vcol.clear(); + + curvekey_co.clear(); + curvekey_time.clear(); +} + +void interp_weights(float t, float data[4], int type) +{ + float t2, t3, fc; + + if(type == CURVE_LINEAR) { + data[0] = 0.0f; + data[1] = -t + 1.0f; + data[2] = t; + data[3] = 0.0f; + } + else if(type == CURVE_CARDINAL) { + t2 = t * t; + t3 = t2 * t; + fc = 0.71f; + + 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; + } + else if(type == CURVE_BSPLINE) { + t2 = t * t; + t3 = t2 * t; + + data[0] = -0.16666666f * t3 + 0.5f * t2 - 0.5f * t + 0.16666666f; + data[1] = 0.5f * t3 - t2 + 0.66666666f; + data[2] = -0.5f * t3 + 0.5f * t2 + 0.5f * t + 0.16666666f; + data[3] = 0.16666666f * t3; + } +} + +void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]) +{ + p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3]; + p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3]; + p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3]; +} + +float shaperadius(float shape, float root, float tip, float time) +{ + float radius = 1.0f - time; + if(shape != 0.0f) { + if(shape < 0.0f) + radius = (float)pow(1.0f - time, 1.f + shape); + else + radius = (float)pow(1.0f - time, 1.f / (1.f - shape)); + } + return (radius * (root - tip)) + tip; +} + +/* curve functions */ + +void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData, int interpolation) +{ + float3 ckey_loc1 = CData->curvekey_co[key]; + float3 ckey_loc2 = ckey_loc1; + float3 ckey_loc3 = CData->curvekey_co[key+1]; + float3 ckey_loc4 = ckey_loc3; + + if(key > CData->curve_firstkey[curve]) + ckey_loc1 = CData->curvekey_co[key - 1]; + + if(key < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2) + ckey_loc4 = CData->curvekey_co[key + 2]; + + + float time1 = CData->curvekey_time[key]/CData->curve_length[curve]; + float time2 = CData->curvekey_time[key + 1]/CData->curve_length[curve]; + + float dfra = (time2 - time1) / (float)segno; + + if(time) + *time = (dfra * seg) + time1; + + float t[4]; + + interp_weights((float)seg / (float)segno, t, interpolation); + + if(keyloc) + 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) +{ + + int curvenum = 0; + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + Transform tfm = get_transform(b_ob->matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + + 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((const PointerRNA)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 draw_step = b_psys.settings().draw_step(); + int ren_step = (int)pow((float)2.0f,(float)draw_step); + /*b_psys.settings().render_step(draw_step);*/ + + int totparts = b_psys.particles.length(); + int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100; + int totcurves = totchild; + + if(use_parents || b_psys.settings().child_type() == 0) + totcurves += totparts; + + 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")); + + int pa_no = 0; + if(!use_parents && !(b_psys.settings().child_type() == 0)) + pa_no = totparts; + + for(; pa_no < totparts+totchild; pa_no++) { + + CData->curve_firstkey.push_back(keyno); + CData->curve_keynum.push_back(ren_step+1); + + float curve_length = 0.0f; + float3 pcKey; + for(int step_no = 0; step_no <= ren_step; step_no++) { + float nco[3]; + b_psys.co_hair(*b_ob, psmd, pa_no, step_no, nco); + float3 cKey = make_float3(nco[0],nco[1],nco[2]); + cKey = transform_point(&itfm, cKey); + 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++; + } + CData->curve_length.push_back(curve_length); + + curvenum++; + + } + } + + } + } + + return true; + +} + +bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents) +{ + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + Transform tfm = get_transform(b_ob->matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + + 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((const PointerRNA)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 draw_step = b_psys.settings().draw_step(); + int ren_step = (int)pow((float)2.0f,(float)draw_step); + /*b_psys.settings().render_step(draw_step);*/ + + int totparts = b_psys.particles.length(); + int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100; + int totcurves = totchild; + + if (use_parents || b_psys.settings().child_type() == 0) + totcurves += totparts; + + if (totcurves == 0) + continue; + + int pa_no = 0; + if(!use_parents && !(b_psys.settings().child_type() == 0)) + pa_no = totparts; + + BL::ParticleSystem::particles_iterator b_pa; + b_psys.particles.begin(b_pa); + for(; pa_no < totparts+totchild; pa_no++) { + + /*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_psys.uv_on_emitter(psmd, *b_pa, pa_no, &uv.x); + CData->curve_uv.push_back(uv); + + if(pa_no < totparts && b_pa != b_psys.particles.end()) + ++b_pa; + + } + } + + } + } + + return true; + +} + +bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool use_parents, int vcol_num) +{ + int keyno = 0; + + if(!(mesh && b_mesh && b_ob && CData)) + return false; + + Transform tfm = get_transform(b_ob->matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + + 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((const PointerRNA)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 draw_step = b_psys.settings().draw_step(); + int ren_step = (int)pow((float)2.0f,(float)draw_step); + /*b_psys.settings().render_step(draw_step);*/ + + int totparts = b_psys.particles.length(); + int totchild = b_psys.child_particles.length() * b_psys.settings().draw_percentage() / 100; + int totcurves = totchild; + + if (use_parents || b_psys.settings().child_type() == 0) + totcurves += totparts; + + if (totcurves == 0) + continue; + + int pa_no = 0; + if(!use_parents && !(b_psys.settings().child_type() == 0)) + pa_no = totparts; + + BL::ParticleSystem::particles_iterator b_pa; + b_psys.particles.begin(b_pa); + for(; pa_no < totparts+totchild; pa_no++) { + + /*add uvs*/ + BL::Mesh::tessface_vertex_colors_iterator l; + b_mesh->tessface_vertex_colors.begin(l); + + float3 vcol = make_float3(0.0f, 0.0f, 0.0f); + if(b_mesh->tessface_vertex_colors.length()) + b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x); + CData->curve_vcol.push_back(vcol); + + if(pa_no < totparts && b_pa != b_psys.particles.end()) + ++b_pa; + + } + } + + } + } + + return true; + +} + +void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, float3 RotCam) +{ + int vertexno = mesh->verts.size(); + int vertexindex = vertexno; + + for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { + for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + float3 xbasis; + + float3 v1; + + if(curvekey == CData->curve_firstkey[curve]) { + subv = 0; + v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey]; + } + else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 2, CData->curve_firstkey[curve])]; + else + v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1]; + + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + float time = 0.0f; + + if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0)) + ickey_loc = CData->curvekey_co[curvekey]; + else + InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation); + + float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + + if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); + + xbasis = normalize(cross(v1,RotCam - ickey_loc)); + float3 ickey_loc_shfl = ickey_loc - radius * xbasis; + float3 ickey_loc_shfr = ickey_loc + radius * xbasis; + mesh->verts.push_back(ickey_loc_shfl); + mesh->verts.push_back(ickey_loc_shfr); + if(subv!=0) { + mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth); + mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth); + } + vertexindex += 2; + } + } + } + } + + mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + + /* texture coords still needed */ +} + +void ExportCurveTriangleRibbons(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments) +{ + int vertexno = mesh->verts.size(); + int vertexindex = vertexno; + + for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { + for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + + float3 firstxbasis = cross(make_float3(1.0f,0.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]); + if(len_squared(firstxbasis)!= 0.0f) + firstxbasis = normalize(firstxbasis); + else + firstxbasis = normalize(cross(make_float3(0.0f,1.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]])); + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + float3 xbasis = firstxbasis; + float3 v1; + float3 v2; + + if(curvekey == CData->curve_firstkey[curve]) { + v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1]; + v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + } + else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])]; + } + else { + v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + } + + xbasis = cross(v1,v2); + + if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { + firstxbasis = normalize(xbasis); + break; + } + } + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + float3 v1; + float3 v2; + float3 xbasis; + + if(curvekey == CData->curve_firstkey[curve]) { + subv = 0; + v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1]; + v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + } + else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])]; + } + else { + v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + } + + xbasis = cross(v1,v2); + + if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { + xbasis = normalize(xbasis); + firstxbasis = xbasis; + } + else + xbasis = firstxbasis; + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + float time = 0.0f; + + if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0)) + ickey_loc = CData->curvekey_co[curvekey]; + else + InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation); + + float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + + if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); + + float3 ickey_loc_shfl = ickey_loc - radius * xbasis; + float3 ickey_loc_shfr = ickey_loc + radius * xbasis; + mesh->verts.push_back(ickey_loc_shfl); + mesh->verts.push_back(ickey_loc_shfr); + if(subv!=0) { + mesh->add_triangle(vertexindex-2, vertexindex, vertexindex-1, CData->psys_shader[sys], use_smooth); + mesh->add_triangle(vertexindex+1, vertexindex-1, vertexindex, CData->psys_shader[sys], use_smooth); + } + vertexindex += 2; + } + } + } + } + + mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + /* texture coords still needed */ + +} + +void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int resolution, int segments) +{ + int vertexno = mesh->verts.size(); + int vertexindex = vertexno; + + for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { + for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + + float3 firstxbasis = cross(make_float3(1.0f,0.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]]); + if(len_squared(firstxbasis)!= 0.0f) + firstxbasis = normalize(firstxbasis); + else + firstxbasis = normalize(cross(make_float3(0.0f,1.0f,0.0f),CData->curvekey_co[CData->curve_firstkey[curve]+1] - CData->curvekey_co[CData->curve_firstkey[curve]])); + + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + float3 xbasis = firstxbasis; + float3 v1; + float3 v2; + + if(curvekey == CData->curve_firstkey[curve]) { + v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1]; + v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + } + else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])]; + } + else { + v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + } + + xbasis = cross(v1,v2); + + if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { + firstxbasis = normalize(xbasis); + break; + } + } + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + float3 xbasis; + float3 ybasis; + float3 v1; + float3 v2; + + if(curvekey == CData->curve_firstkey[curve]) { + subv = 0; + v1 = CData->curvekey_co[min(curvekey+2,CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)] - CData->curvekey_co[curvekey+1]; + v2 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + } + else if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) { + v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + v2 = CData->curvekey_co[curvekey-1] - CData->curvekey_co[max(curvekey-2,CData->curve_firstkey[curve])]; + } + else { + v1 = CData->curvekey_co[curvekey+1] - CData->curvekey_co[curvekey]; + v2 = CData->curvekey_co[curvekey] - CData->curvekey_co[curvekey-1]; + } + + xbasis = cross(v1,v2); + + if(len_squared(xbasis) >= 0.05f * len_squared(v1) * len_squared(v2)) { + xbasis = normalize(xbasis); + firstxbasis = xbasis; + } + else + xbasis = firstxbasis; + + ybasis = normalize(cross(xbasis,v2)); + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + float time = 0.0f; + + if ((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0)) + ickey_loc = CData->curvekey_co[curvekey]; + else + InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation); + + float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + + if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], 0.0f, 0.95f); + + if((curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) && (subv == segments)) + radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], 0.95f); + + float angle = 2 * M_PI_F / (float)resolution; + for(int section = 0 ; section < resolution; section++) { + float3 ickey_loc_shf = ickey_loc + radius * (cosf(angle * section) * xbasis + sinf(angle * section) * ybasis); + mesh->verts.push_back(ickey_loc_shf); + } + + if(subv!=0) { + for(int section = 0 ; section < resolution - 1; section++) { + mesh->add_triangle(vertexindex - resolution + section, vertexindex + section, vertexindex - resolution + section + 1, CData->psys_shader[sys], use_smooth); + mesh->add_triangle(vertexindex + section + 1, vertexindex - resolution + section + 1, vertexindex + section, CData->psys_shader[sys], use_smooth); + } + mesh->add_triangle(vertexindex-1, vertexindex + resolution - 1, vertexindex - resolution, CData->psys_shader[sys], use_smooth); + mesh->add_triangle(vertexindex, vertexindex - resolution , vertexindex + resolution - 1, CData->psys_shader[sys], use_smooth); + } + vertexindex += resolution; + } + } + } + } + + mesh->reserve(mesh->verts.size(), mesh->triangles.size(), 0, 0); + mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + mesh->add_face_normals(); + mesh->add_vertex_normals(); + mesh->attributes.remove(ATTR_STD_FACE_NORMAL); + + /* texture coords still needed */ +} + +static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData, int interpolation, int segments) +{ + int num_keys = 0; + int num_curves = 0; + + if(!(mesh->curves.empty() && mesh->curve_keys.empty())) + return; + + Attribute *attr_uv = NULL, *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); + + for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { + + if(CData->psys_curvenum[sys] == 0) + continue; + + for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + + if(CData->curve_keynum[curve] <= 1) + continue; + + size_t num_curve_keys = 0; + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + if(curvekey == CData->curve_firstkey[curve]) + subv = 0; + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + float time = 0.0f; + + if((interpolation == CURVE_BSPLINE) && (curvekey == CData->curve_firstkey[curve]) && (subv == 0)) + ickey_loc = CData->curvekey_co[curvekey]; + else + InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation); + + float radius = shaperadius(CData->psys_shape[sys], CData->psys_rootradius[sys], CData->psys_tipradius[sys], time); + + if(CData->psys_closetip[sys] && (subv == segments) && (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 2)) + radius =0.0f; + + mesh->add_curve_key(ickey_loc, radius); + if(attr_intercept) + attr_intercept->add(time); + + num_curve_keys++; + } + } + + 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++; + } + } + + /* check allocation*/ + if((mesh->curve_keys.size() != num_keys) || (mesh->curves.size() != num_curves)) { + /* allocation failed -> clear data */ + mesh->curve_keys.clear(); + mesh->curves.clear(); + mesh->curve_attributes.clear(); + } +} + +void ExportCurveTriangleUVs(Mesh *mesh, ParticleCurveData *CData, int interpolation, bool use_smooth, int segments, int vert_offset, int resol) +{ + float time = 0.0f; + float prevtime = 0.0f; + + Attribute *attr = mesh->attributes.find(ATTR_STD_UV); + if (attr == NULL) + return; + + float3 *uvdata = attr->data_float3(); + + int vertexindex = vert_offset; + + for( int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { + for( int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + + for( int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1; curvekey++) { + + int subv = 1; + + if (curvekey == CData->curve_firstkey[curve]) + subv = 0; + + for (; subv <= segments; subv++) { + + float3 ickey_loc = make_float3(0.0f,0.0f,0.0f); + + InterpolateKeySegments(subv, segments, curvekey, curve, &ickey_loc, &time, CData , interpolation); + + if(subv!=0) { + for(int section = 0 ; section < resol; section++) { + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = prevtime; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = time; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = prevtime; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = time; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = prevtime; + vertexindex++; + uvdata[vertexindex] = CData->curve_uv[curve]; + uvdata[vertexindex].z = time; + vertexindex++; + } + } + + prevtime = time; + } + } + } + } + +} +/* Hair Curve Sync */ + +void BlenderSync::sync_curve_settings() +{ + PointerRNA csscene = RNA_pointer_get(&b_scene.ptr, "cycles_curves"); + + int preset = get_enum(csscene, "preset"); + + CurveSystemManager *curve_system_manager = scene->curve_system_manager; + CurveSystemManager prev_curve_system_manager = *curve_system_manager; + + curve_system_manager->use_curves = get_boolean(csscene, "use_curves"); + + if(preset == CURVE_CUSTOM) { + /*custom properties*/ + curve_system_manager->primitive = get_enum(csscene, "primitive"); + curve_system_manager->line_method = get_enum(csscene, "line_method"); + curve_system_manager->interpolation = get_enum(csscene, "interpolation"); + curve_system_manager->triangle_method = get_enum(csscene, "triangle_method"); + 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->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"); + curve_system_manager->use_joined = get_boolean(csscene, "use_joined"); + curve_system_manager->use_tangent_normal = get_boolean(csscene, "use_tangent_normal"); + curve_system_manager->use_tangent_normal_geometry = get_boolean(csscene, "use_tangent_normal_geometry"); + curve_system_manager->use_tangent_normal_correction = get_boolean(csscene, "use_tangent_normal_correction"); + } + else { + curve_system_manager->primitive = CURVE_LINE_SEGMENTS; + 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; + + switch(preset) { + case CURVE_TANGENT_SHADING: + /*tangent shading*/ + curve_system_manager->line_method = CURVE_UNCORRECTED; + curve_system_manager->use_encasing = true; + curve_system_manager->use_backfacing = false; + curve_system_manager->use_tangent_normal = true; + curve_system_manager->use_tangent_normal_geometry = true; + curve_system_manager->use_tangent_normal_correction = false; + break; + case CURVE_TRUE_NORMAL: + /*True Normal*/ + curve_system_manager->line_method = CURVE_CORRECTED; + curve_system_manager->use_encasing = true; + curve_system_manager->use_backfacing = false; + curve_system_manager->use_tangent_normal = false; + curve_system_manager->use_tangent_normal_geometry = false; + curve_system_manager->use_tangent_normal_correction = false; + break; + case CURVE_ACCURATE_PRESET: + /*Accurate*/ + curve_system_manager->line_method = CURVE_ACCURATE; + curve_system_manager->use_encasing = false; + curve_system_manager->use_backfacing = true; + curve_system_manager->use_tangent_normal = false; + curve_system_manager->use_tangent_normal_geometry = false; + curve_system_manager->use_tangent_normal_correction = false; + break; + } + + } + + if(curve_system_manager->modified_mesh(prev_curve_system_manager)) + { + BL::BlendData::objects_iterator b_ob; + + for(b_data.objects.begin(b_ob); b_ob != b_data.objects.end(); ++b_ob) { + if(object_is_mesh(*b_ob)) { + BL::Object::particle_systems_iterator b_psys; + for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) { + if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) { + BL::ID key = BKE_object_is_modified(*b_ob)? *b_ob: b_ob->data(); + mesh_map.set_recalc(key); + object_map.set_recalc(*b_ob); + } + } + } + } + } + + if(curve_system_manager->modified(prev_curve_system_manager)) + curve_system_manager->tag_update(scene); + +} + +void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool object_updated) +{ + /* Clear stored curve data */ + mesh->curve_keys.clear(); + mesh->curves.clear(); + mesh->curve_attributes.clear(); + + /* obtain general settings */ + bool use_curves = scene->curve_system_manager->use_curves; + + if(!(use_curves && b_ob.mode() == b_ob.mode_OBJECT)) { + mesh->compute_bounds(); + return; + } + + int primitive = scene->curve_system_manager->primitive; + int interpolation = scene->curve_system_manager->interpolation; + int triangle_method = scene->curve_system_manager->triangle_method; + 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; + + /* extract particle hair data - should be combined with connecting to mesh later*/ + + 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); + + /* attach strands to mesh */ + BL::Object b_CamOb = b_scene.camera(); + float3 RotCam = make_float3(0.0f, 0.0f, 0.0f); + if(b_CamOb) { + Transform ctfm = get_transform(b_CamOb.matrix_world()); + Transform tfm = get_transform(b_ob.matrix_world()); + Transform itfm = transform_quick_inverse(tfm); + RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w)); + } + + if(primitive == CURVE_TRIANGLES){ + int vert_num = mesh->triangles.size() * 3; + if(triangle_method == CURVE_CAMERA) { + ExportCurveTrianglePlanes(mesh, &CData, interpolation, use_smooth, segments, RotCam); + ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1); + } + else if(triangle_method == CURVE_RIBBONS) { + ExportCurveTriangleRibbons(mesh, &CData, interpolation, use_smooth, segments); + ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, 1); + } + else { + ExportCurveTriangleGeometry(mesh, &CData, interpolation, use_smooth, resolution, segments); + ExportCurveTriangleUVs(mesh, &CData, interpolation, use_smooth, segments, vert_num, resolution); + } + + } + else { + ExportCurveSegments(scene, mesh, &CData, interpolation, segments); + int ckey_num = mesh->curve_keys.size(); + + /*export tangents or curve data? - not functional yet*/ + if(export_tgs && ckey_num > 1) { + Attribute *attr_tangent = mesh->curve_attributes.add(ATTR_STD_CURVE_TANGENT); + float3 *data_tangent = attr_tangent->data_float3(); + + for(int ck = 0; ck < ckey_num; ck++) { + float3 tg = normalize(normalize(mesh->curve_keys[min(ck + 1, ckey_num - 1)].co - mesh->curve_keys[ck].co) - + normalize(mesh->curve_keys[max(ck - 1, 0)].co - mesh->curve_keys[ck].co)); + + data_tangent[ck] = tg; + } + } + + /* 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); + + 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; + } + } + + /* create vertex color attributes */ + 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; + + /*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); + + ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, use_parents, 0); + + 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]); + } + + } + + } + + mesh->compute_bounds(); +} + + +CCL_NAMESPACE_END + diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index c9748756d43..1dd7800dfa4 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -147,7 +147,7 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la if(active_render) attr = mesh->attributes.add(ATTR_STD_UV_TANGENT, name); else - attr = mesh->attributes.add(name, TypeDesc::TypeVector, Attribute::CORNER); + attr = mesh->attributes.add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); float3 *tangent = attr->data_float3(); @@ -161,7 +161,7 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer b_la if(active_render) attr_sign = mesh->attributes.add(ATTR_STD_UV_TANGENT_SIGN, name_sign); else - attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, Attribute::CORNER); + attr_sign = mesh->attributes.add(name_sign, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER); tangent_sign = attr_sign->data_float(); } @@ -223,10 +223,19 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< int shader = used_shaders[mi]; bool smooth = f->use_smooth(); - mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); - - if(n == 4) - mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth); + if(n == 4) { + if(len_squared(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) == 0.0f || + len_squared(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]])) == 0.0f) { + mesh->add_triangle(vi[0], vi[1], vi[3], shader, smooth); + mesh->add_triangle(vi[2], vi[3], vi[1], shader, smooth); + } + else { + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); + mesh->add_triangle(vi[0], vi[2], vi[3], shader, smooth); + } + } + else + mesh->add_triangle(vi[0], vi[1], vi[2], shader, smooth); nverts.push_back(n); } @@ -240,7 +249,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< continue; Attribute *attr = mesh->attributes.add( - ustring(l->name().c_str()), TypeDesc::TypeColor, Attribute::CORNER); + ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER); BL::MeshColorLayer::data_iterator c; float3 *fdata = attr->data_float3(); @@ -279,7 +288,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< if(active_render) attr = mesh->attributes.add(std, name); else - attr = mesh->attributes.add(name, TypeDesc::TypePoint, Attribute::CORNER); + attr = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); BL::MeshTextureFaceLayer::data_iterator t; float3 *fdata = attr->data_float3(); @@ -319,14 +328,9 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector< * is available in the api. */ if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) { Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); - float3 loc = get_float3(b_mesh.texspace_location()); - float3 size = get_float3(b_mesh.texspace_size()); - if(size.x != 0.0f) size.x = 0.5f/size.x; - if(size.y != 0.0f) size.y = 0.5f/size.y; - if(size.z != 0.0f) size.z = 0.5f/size.z; - - loc = loc*size - make_float3(0.5f, 0.5f, 0.5f); + float3 loc, size; + mesh_texture_space(b_mesh, loc, size); float3 *generated = attr->data_float3(); size_t i = 0; @@ -376,7 +380,7 @@ static void create_subd_mesh(Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, con /* Sync */ -Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated) +Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris) { /* test if we can instance or if the object is modified */ BL::ID b_ob_data = b_ob.data(); @@ -435,16 +439,24 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated) PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles"); vector oldtriangle = mesh->triangles; + + /* compares curve_keys rather than strands in order to handle quick hair adjustsments in dynamic BVH - other methods could probably do this better*/ + vector oldcurve_keys = mesh->curve_keys; mesh->clear(); mesh->used_shaders = used_shaders; mesh->name = ustring(b_ob_data.name().c_str()); if(b_mesh) { - if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision")) - create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders); - else - create_mesh(scene, mesh, b_mesh, used_shaders); + if(!(hide_tris && experimental && is_cpu)) { + if(cmesh.data && experimental && RNA_boolean_get(&cmesh, "use_subdivision")) + create_subd_mesh(mesh, b_mesh, &cmesh, used_shaders); + else + create_mesh(scene, mesh, b_mesh, used_shaders); + } + + if(experimental && is_cpu) + sync_curves(mesh, b_mesh, b_ob, object_updated); /* free derived mesh */ b_data.meshes.remove(b_mesh); @@ -471,6 +483,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated) if(memcmp(&oldtriangle[0], &mesh->triangles[0], sizeof(Mesh::Triangle)*oldtriangle.size()) != 0) rebuild = true; } + + if(oldcurve_keys.size() != mesh->curve_keys.size()) + rebuild = true; + else if(oldcurve_keys.size()) { + if(memcmp(&oldcurve_keys[0], &mesh->curve_keys[0], sizeof(Mesh::CurveKey)*oldcurve_keys.size()) != 0) + rebuild = true; + } mesh->tag_update(scene, rebuild); diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 38f27bcf2af..ad701266c5b 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -196,7 +196,7 @@ void BlenderSync::sync_background_light() /* Object */ -Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion) +Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion, bool hide_tris) { BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent); @@ -247,7 +247,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_P bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0; /* mesh sync */ - object->mesh = sync_mesh(b_ob, object_updated); + object->mesh = sync_mesh(b_ob, object_updated, hide_tris); /* sspecial case not tracked by object update flags */ if(use_holdout != object->use_holdout) { @@ -390,7 +390,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) BL::Array persistent_id = b_dup->persistent_id(); /* sync object and mesh or light data */ - Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion); + Object *object = sync_object(*b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion, false); /* sync possible particle data, note particle_id * starts counting at 1, first is dummy particle */ @@ -412,9 +412,23 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) /* check if we should render or hide particle emitter */ BL::Object::particle_systems_iterator b_psys; - for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) - if(b_psys->settings().use_render_emitter()) + bool hair_present = false; + bool show_emitter = false; + bool hide_tris = false; + + for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) { + + if((b_psys->settings().render_type()==BL::ParticleSettings::render_type_PATH)&&(b_psys->settings().type()==BL::ParticleSettings::type_HAIR)) + hair_present = true; + + if(b_psys->settings().use_render_emitter()) { hide = false; + show_emitter = true; + } + } + + if(hair_present && !show_emitter) + hide_tris = true; /* hide original object for duplis */ BL::Object parent = b_ob->parent(); @@ -424,7 +438,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) if(!hide) { /* object itself */ Transform tfm = get_transform(b_ob->matrix_world()); - sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion); + sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion, hide_tris); } } diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index b8ed942f5b6..770b71afcdc 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -96,7 +96,7 @@ void BlenderSession::create_session() session->set_pause(BlenderSync::get_session_pause(b_scene, background)); /* create sync */ - sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); + sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, session_params.device.type == DEVICE_CPU); sync->sync_data(b_v3d, b_engine.camera_override()); if(b_rv3d) @@ -107,6 +107,8 @@ void BlenderSession::create_session() /* set buffer parameters */ BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_v3d, b_rv3d, scene->camera, width, height); session->reset(buffer_params, session_params.samples); + + b_engine.use_highlight_tiles(session_params.progressive_refine == false); } void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_) @@ -143,12 +145,14 @@ void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_) session->stats.mem_peak = session->stats.mem_used; /* sync object should be re-created */ - sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress); + sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, session_params.device.type == DEVICE_CPU); sync->sync_data(b_v3d, b_engine.camera_override()); sync->sync_camera(b_engine.camera_override(), width, height); BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, PointerRNA_NULL, PointerRNA_NULL, scene->camera, width, height); session->reset(buffer_params, session_params.samples); + + b_engine.use_highlight_tiles(session_params.progressive_refine == false); } void BlenderSession::free_session() @@ -252,7 +256,15 @@ void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_upda if (do_update_only) { /* update only needed */ - update_render_result(b_rr, b_rlay, rtile); + + if (rtile.sample != 0) { + /* sample would be zero at initial tile update, which is only needed + * to tag tile form blender side as IN PROGRESS for proper highlight + * no buffers should be sent to blender yet + */ + update_render_result(b_rr, b_rlay, rtile); + } + end_render_result(b_engine, b_rr, true); } else { diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 848a9a199f9..ddbd7f935e4 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -447,6 +447,10 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen node = new ParticleInfoNode(); break; } + case BL::ShaderNode::type_HAIR_INFO: { + node = new HairInfoNode(); + break; + } case BL::ShaderNode::type_BUMP: { node = new BumpNode(); break; diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index d455bdbe8e2..b9860ca90f2 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -28,6 +28,7 @@ #include "object.h" #include "scene.h" #include "shader.h" +#include "curves.h" #include "device.h" @@ -41,7 +42,7 @@ CCL_NAMESPACE_BEGIN /* Constructor */ -BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_, Progress &progress_) +BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, Scene *scene_, bool preview_, Progress &progress_, bool is_cpu_) : b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), shader_map(&scene_->shaders), @@ -56,6 +57,7 @@ BlenderSync::BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL:: { scene = scene_; preview = preview_; + is_cpu = is_cpu_; } BlenderSync::~BlenderSync() @@ -141,6 +143,7 @@ void BlenderSync::sync_data(BL::SpaceView3D b_v3d, BL::Object b_override, const sync_integrator(); sync_film(); sync_shaders(); + sync_curve_settings(); sync_objects(b_v3d); sync_motion(b_v3d, b_override); } diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index d3d21fbdf72..5050743f1cf 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -50,7 +50,7 @@ class ShaderNode; class BlenderSync { public: - BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_, Progress &progress_); + BlenderSync(BL::RenderEngine b_engine_, BL::BlendData b_data, BL::Scene b_scene, Scene *scene_, bool preview_, Progress &progress_, bool is_cpu_); ~BlenderSync(); /* sync */ @@ -78,10 +78,12 @@ private: void sync_world(bool update_all); void sync_render_layers(BL::SpaceView3D b_v3d, const char *layer); void sync_shaders(); + void sync_curve_settings(); void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree); - Mesh *sync_mesh(BL::Object b_ob, bool object_updated); - Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion); + Mesh *sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris); + void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool object_updated); + Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion, bool hide_tris); void sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm); void sync_background_light(); void sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion); @@ -113,6 +115,7 @@ private: Scene *scene; bool preview; bool experimental; + bool is_cpu; struct RenderLayerInfo { RenderLayerInfo() diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index fbcbe15ec5a..88c98860794 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -242,6 +242,20 @@ static inline string blender_absolute_path(BL::BlendData b_data, BL::ID b_id, co return path; } +/* Texture Space */ + +static inline void mesh_texture_space(BL::Mesh b_mesh, float3& loc, float3& size) +{ + loc = get_float3(b_mesh.texspace_location()); + size = get_float3(b_mesh.texspace_size()); + + if(size.x != 0.0f) size.x = 0.5f/size.x; + if(size.y != 0.0f) size.y = 0.5f/size.y; + if(size.z != 0.0f) size.z = 0.5f/size.z; + + loc = loc*size - make_float3(0.5f, 0.5f, 0.5f); +} + /* ID Map * * Utility class to keep in sync with blender data. diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index b58a34f9942..412b44031e6 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -75,6 +75,8 @@ bool BVH::cache_read(CacheData& key) foreach(Object *ob, objects) { key.add(ob->mesh->verts); key.add(ob->mesh->triangles); + key.add(ob->mesh->curve_keys); + key.add(ob->mesh->curves); key.add(&ob->bounds, sizeof(ob->bounds)); key.add(&ob->visibility, sizeof(ob->visibility)); key.add(&ob->mesh->transform_applied, sizeof(bool)); @@ -91,6 +93,7 @@ bool BVH::cache_read(CacheData& key) value.read(pack.nodes); value.read(pack.object_node); value.read(pack.tri_woop); + value.read(pack.prim_segment); value.read(pack.prim_visibility); value.read(pack.prim_index); value.read(pack.prim_object); @@ -112,6 +115,7 @@ void BVH::cache_write(CacheData& key) value.add(pack.nodes); value.add(pack.object_node); value.add(pack.tri_woop); + value.add(pack.prim_segment); value.add(pack.prim_visibility); value.add(pack.prim_index); value.add(pack.prim_object); @@ -157,10 +161,11 @@ void BVH::build(Progress& progress) } /* build nodes */ + vector prim_segment; vector prim_index; vector prim_object; - BVHBuild bvh_build(objects, prim_index, prim_object, params, progress); + BVHBuild bvh_build(objects, prim_segment, prim_index, prim_object, params, progress); BVHNode *root = bvh_build.run(); if(progress.get_cancel()) { @@ -169,6 +174,7 @@ void BVH::build(Progress& progress) } /* todo: get rid of this copy */ + pack.prim_segment = prim_segment; pack.prim_index = prim_index; pack.prim_object = prim_object; @@ -182,8 +188,8 @@ void BVH::build(Progress& progress) } /* pack triangles */ - progress.set_substatus("Packing BVH triangles"); - pack_triangles(); + progress.set_substatus("Packing BVH triangles and strands"); + pack_primitives(); if(progress.get_cancel()) { root->deleteSubtree(); @@ -215,8 +221,8 @@ void BVH::build(Progress& progress) void BVH::refit(Progress& progress) { - progress.set_substatus("Packing BVH triangles"); - pack_triangles(); + progress.set_substatus("Packing BVH primitives"); + pack_primitives(); if(progress.get_cancel()) return; @@ -263,7 +269,52 @@ void BVH::pack_triangle(int idx, float4 woop[3]) } } -void BVH::pack_triangles() +/* Curves*/ + +void BVH::pack_curve_segment(int idx, float4 woop[3]) +{ + int tob = pack.prim_object[idx]; + const Mesh *mesh = objects[tob]->mesh; + int tidx = pack.prim_index[idx]; + int segment = pack.prim_segment[idx]; + int k0 = mesh->curves[tidx].first_key + segment; + int k1 = mesh->curves[tidx].first_key + segment + 1; + float3 v0 = mesh->curve_keys[k0].co; + float3 v1 = mesh->curve_keys[k1].co; + + float3 d0 = v1 - v0; + float l = len(d0); + + /*Plan + *Transform tfm = make_transform( + * location <3> , l, + * extra curve data <3> , StrID, + * nextkey, flags/tip?, 0, 0); + */ + Attribute *attr_tangent = mesh->curve_attributes.find(ATTR_STD_CURVE_TANGENT); + float3 tg0 = make_float3(1.0f, 0.0f, 0.0f); + float3 tg1 = make_float3(1.0f, 0.0f, 0.0f); + + if(attr_tangent) { + const float3 *data_tangent = attr_tangent->data_float3(); + + tg0 = data_tangent[k0]; + tg1 = data_tangent[k1]; + } + + Transform tfm = make_transform( + tg0.x, tg0.y, tg0.z, l, + tg1.x, tg1.y, tg1.z, 0, + 0, 0, 0, 0, + 0, 0, 0, 1); + + woop[0] = tfm.x; + woop[1] = tfm.y; + woop[2] = tfm.z; + +} + +void BVH::pack_primitives() { int nsize = TRI_NODE_SIZE; size_t tidx_size = pack.prim_index.size(); @@ -277,7 +328,11 @@ void BVH::pack_triangles() if(pack.prim_index[i] != -1) { float4 woop[3]; - pack_triangle(i, woop); + if(pack.prim_segment[i] != ~0) + pack_curve_segment(i, woop); + else + pack_triangle(i, woop); + memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3); int tob = pack.prim_object[i]; @@ -300,11 +355,15 @@ void BVH::pack_instances(size_t nodes_size) /* adjust primitive index to point to the triangle in the global array, for * meshes with transform applied and already in the top level BVH */ for(size_t i = 0; i < pack.prim_index.size(); i++) - if(pack.prim_index[i] != -1) - pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset; + if(pack.prim_index[i] != -1) { + if(pack.prim_segment[i] != ~0) + pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset; + else + pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset; + } /* track offsets of instanced BVH data in global array */ - size_t tri_offset = pack.prim_index.size(); + size_t prim_offset = pack.prim_index.size(); size_t nodes_offset = nodes_size; /* clear array that gives the node indexes for instanced objects */ @@ -339,6 +398,7 @@ void BVH::pack_instances(size_t nodes_size) mesh_map.clear(); pack.prim_index.resize(prim_index_size); + pack.prim_segment.resize(prim_index_size); pack.prim_object.resize(prim_index_size); pack.prim_visibility.resize(prim_index_size); pack.tri_woop.resize(tri_woop_size); @@ -346,6 +406,7 @@ void BVH::pack_instances(size_t nodes_size) pack.object_node.resize(objects.size()); int *pack_prim_index = (pack.prim_index.size())? &pack.prim_index[0]: NULL; + int *pack_prim_segment = (pack.prim_segment.size())? &pack.prim_segment[0]: NULL; int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL; uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL; float4 *pack_tri_woop = (pack.tri_woop.size())? &pack.tri_woop[0]: NULL; @@ -376,6 +437,7 @@ void BVH::pack_instances(size_t nodes_size) int noffset = nodes_offset/nsize; int mesh_tri_offset = mesh->tri_offset; + int mesh_curve_offset = mesh->curve_offset; /* fill in node indexes for instances */ if((bvh->pack.is_leaf.size() != 0) && bvh->pack.is_leaf[0]) @@ -389,10 +451,16 @@ void BVH::pack_instances(size_t nodes_size) if(bvh->pack.prim_index.size()) { size_t bvh_prim_index_size = bvh->pack.prim_index.size(); int *bvh_prim_index = &bvh->pack.prim_index[0]; + int *bvh_prim_segment = &bvh->pack.prim_segment[0]; uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0]; for(size_t i = 0; i < bvh_prim_index_size; i++) { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset; + if(bvh->pack.prim_segment[i] != ~0) + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset; + else + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset; + + pack_prim_segment[pack_prim_index_offset] = bvh_prim_segment[i]; pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i]; pack_prim_object[pack_prim_index_offset] = 0; // unused for instances pack_prim_index_offset++; @@ -401,7 +469,7 @@ void BVH::pack_instances(size_t nodes_size) /* merge triangle intersection data */ if(bvh->pack.tri_woop.size()) { - memcpy(pack_tri_woop+pack_tri_woop_offset, &bvh->pack.tri_woop[0], + memcpy(pack_tri_woop + pack_tri_woop_offset, &bvh->pack.tri_woop[0], bvh->pack.tri_woop.size()*sizeof(float4)); pack_tri_woop_offset += bvh->pack.tri_woop.size(); } @@ -420,8 +488,8 @@ void BVH::pack_instances(size_t nodes_size) int4 data = bvh_nodes[i + nsize_bbox]; if(bvh_is_leaf && bvh_is_leaf[j]) { - data.x += tri_offset; - data.y += tri_offset; + data.x += prim_offset; + data.y += prim_offset; } else { data.x += (data.x < 0)? -noffset: noffset; @@ -443,7 +511,7 @@ void BVH::pack_instances(size_t nodes_size) } nodes_offset += bvh->pack.nodes.size(); - tri_offset += bvh->pack.prim_index.size(); + prim_offset += bvh->pack.prim_index.size(); } } @@ -544,25 +612,38 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility if(leaf) { /* refit leaf node */ - for(int tri = c0; tri < c1; tri++) { - int tidx = pack.prim_index[tri]; - int tob = pack.prim_object[tri]; + for(int prim = c0; prim < c1; prim++) { + int pidx = pack.prim_index[prim]; + int tob = pack.prim_object[prim]; Object *ob = objects[tob]; - if(tidx == -1) { + if(pidx == -1) { /* object instance */ bbox.grow(ob->bounds); } else { - /* triangles */ + /* primitives */ const Mesh *mesh = ob->mesh; - int tri_offset = (params.top_level)? mesh->tri_offset: 0; - const int *vidx = mesh->triangles[tidx - tri_offset].v; - const float3 *vpos = &mesh->verts[0]; - bbox.grow(vpos[vidx[0]]); - bbox.grow(vpos[vidx[1]]); - bbox.grow(vpos[vidx[2]]); + if(pack.prim_segment[prim] != ~0) { + /* curves */ + int str_offset = (params.top_level)? mesh->curve_offset: 0; + 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); + } + else { + /* triangles */ + int tri_offset = (params.top_level)? mesh->tri_offset: 0; + const int *vidx = mesh->triangles[pidx - tri_offset].v; + const float3 *vpos = &mesh->verts[0]; + + bbox.grow(vpos[vidx[0]]); + bbox.grow(vpos[vidx[1]]); + bbox.grow(vpos[vidx[2]]); + } } visibility |= ob->visibility; diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h index 549f1e3ac1d..00c146143b8 100644 --- a/intern/cycles/bvh/bvh.h +++ b/intern/cycles/bvh/bvh.h @@ -51,7 +51,9 @@ struct PackedBVH { /* object index to BVH node index mapping for instances */ array object_node; /* precomputed triangle intersection data, one triangle is 4x float4 */ - array tri_woop; + array tri_woop; + /* primitive type - triangle or strand (should be moved to flag?) */ + array prim_segment; /* visibility visibilitys for primitives */ array prim_visibility; /* mapping from BVH primitive index to true primitive index, as primitives @@ -101,9 +103,10 @@ protected: bool cache_read(CacheData& key); void cache_write(CacheData& key); - /* triangles */ - void pack_triangles(); + /* triangles and strands*/ + void pack_primitives(); void pack_triangle(int idx, float4 woop[3]); + void pack_curve_segment(int idx, float4 woop[3]); /* merge instance BVH's */ void pack_instances(size_t nodes_size); diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 705b805a3a9..38fb1a15a13 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -48,9 +48,10 @@ public: /* Constructor / Destructor */ BVHBuild::BVHBuild(const vector& objects_, - vector& prim_index_, vector& prim_object_, + vector& prim_segment_, vector& prim_index_, vector& prim_object_, const BVHParams& params_, Progress& progress_) : objects(objects_), + prim_segment(prim_segment_), prim_index(prim_index_), prim_object(prim_object_), params(params_), @@ -73,25 +74,55 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, BoundBox bounds = BoundBox::empty; for(int k = 0; k < 3; k++) { - float3 pt = mesh->verts[t.v[k]]; - bounds.grow(pt); + float3 co = mesh->verts[t.v[k]]; + bounds.grow(co); } if(bounds.valid()) { - references.push_back(BVHReference(bounds, j, i)); + references.push_back(BVHReference(bounds, j, i, ~0)); root.grow(bounds); center.grow(bounds.center2()); } } + + for(uint j = 0; j < mesh->curves.size(); j++) { + Mesh::Curve curve = mesh->curves[j]; + + 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; + + bounds.grow(co0, mesh->curve_keys[curve.first_key + k].radius); + bounds.grow(co1, mesh->curve_keys[curve.first_key + k + 1].radius); + + if(bounds.valid()) { + references.push_back(BVHReference(bounds, j, i, k)); + root.grow(bounds); + center.grow(bounds.center2()); + } + } + } } void BVHBuild::add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i) { - references.push_back(BVHReference(ob->bounds, -1, i)); + references.push_back(BVHReference(ob->bounds, -1, i, false)); root.grow(ob->bounds); center.grow(ob->bounds.center2()); } +static size_t count_curve_segments(Mesh *mesh) +{ + size_t num = 0, num_curves = mesh->curves.size(); + + for(size_t i = 0; i < num_curves; i++) + num += mesh->curves[i].num_keys - 1; + + return num; +} + void BVHBuild::add_references(BVHRange& root) { /* reserve space for references */ @@ -99,13 +130,17 @@ void BVHBuild::add_references(BVHRange& root) foreach(Object *ob, objects) { if(params.top_level) { - if(ob->mesh->transform_applied) + if(ob->mesh->transform_applied) { num_alloc_references += ob->mesh->triangles.size(); + num_alloc_references += count_curve_segments(ob->mesh); + } else num_alloc_references++; } - else + else { num_alloc_references += ob->mesh->triangles.size(); + num_alloc_references += count_curve_segments(ob->mesh); + } } references.reserve(num_alloc_references); @@ -162,6 +197,7 @@ BVHNode* BVHBuild::run() progress_total = references.size(); progress_original_total = progress_total; + prim_segment.resize(references.size()); prim_index.resize(references.size()); prim_object.resize(references.size()); @@ -319,10 +355,12 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, if(start == prim_index.size()) { assert(params.use_spatial_split); + prim_segment.push_back(ref->prim_segment()); prim_index.push_back(ref->prim_index()); prim_object.push_back(ref->prim_object()); } else { + prim_segment[start] = ref->prim_segment(); prim_index[start] = ref->prim_index(); prim_object[start] = ref->prim_object(); } @@ -345,6 +383,7 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, BVHNode* BVHBuild::create_leaf_node(const BVHRange& range) { + vector& p_segment = prim_segment; vector& p_index = prim_index; vector& p_object = prim_object; BoundBox bounds = BoundBox::empty; @@ -358,10 +397,12 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range) if(range.start() + num == prim_index.size()) { assert(params.use_spatial_split); + p_segment.push_back(ref.prim_segment()); p_index.push_back(ref.prim_index()); p_object.push_back(ref.prim_object()); } else { + p_segment[range.start() + num] = ref.prim_segment(); p_index[range.start() + num] = ref.prim_index(); p_object[range.start() + num] = ref.prim_object(); } diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h index 44ef918b326..3df4da1739a 100644 --- a/intern/cycles/bvh/bvh_build.h +++ b/intern/cycles/bvh/bvh_build.h @@ -44,6 +44,7 @@ public: /* Constructor/Destructor */ BVHBuild( const vector& objects, + vector& prim_segment, vector& prim_index, vector& prim_object, const BVHParams& params, @@ -87,6 +88,7 @@ protected: int num_original_references; /* output primitive indexes and objects */ + vector& prim_segment; vector& prim_index; vector& prim_object; diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index a78496d841d..f7bc79f71e6 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -98,19 +98,22 @@ class BVHReference public: __forceinline BVHReference() {} - __forceinline BVHReference(const BoundBox& bounds_, int prim_index_, int prim_object_) + __forceinline BVHReference(const BoundBox& bounds_, int prim_index_, int prim_object_, int prim_segment) : rbounds(bounds_) { rbounds.min.w = __int_as_float(prim_index_); rbounds.max.w = __int_as_float(prim_object_); + segment = prim_segment; } __forceinline const BoundBox& bounds() const { return rbounds; } __forceinline int prim_index() const { return __float_as_int(rbounds.min.w); } __forceinline int prim_object() const { return __float_as_int(rbounds.max.w); } + __forceinline int prim_segment() const { return segment; } protected: BoundBox rbounds; + uint segment; }; /* BVH Range diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp index bef384be592..91994be5b96 100644 --- a/intern/cycles/bvh/bvh_sort.cpp +++ b/intern/cycles/bvh/bvh_sort.cpp @@ -43,6 +43,8 @@ public: else if(ra.prim_object() > rb.prim_object()) return false; else if(ra.prim_index() < rb.prim_index()) return true; else if(ra.prim_index() > rb.prim_index()) return false; + else if(ra.prim_segment() < rb.prim_segment()) return true; + else if(ra.prim_segment() > rb.prim_segment()) return false; return false; } diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index 263c5834428..03ff69d7b6d 100644 --- a/intern/cycles/bvh/bvh_split.cpp +++ b/intern/cycles/bvh/bvh_split.cpp @@ -252,14 +252,41 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH /* loop over vertices/edges. */ Object *ob = builder->objects[ref.prim_object()]; const Mesh *mesh = ob->mesh; - const int *inds = mesh->triangles[ref.prim_index()].v; - const float3 *verts = &mesh->verts[0]; - const float3* v1 = &verts[inds[2]]; - for(int i = 0; i < 3; i++) { - const float3* v0 = v1; - int vindex = inds[i]; - v1 = &verts[vindex]; + if (ref.prim_segment() == ~0) { + const int *inds = mesh->triangles[ref.prim_index()].v; + const float3 *verts = &mesh->verts[0]; + const float3* v1 = &verts[inds[2]]; + + for(int i = 0; i < 3; i++) { + const float3* v0 = v1; + int vindex = inds[i]; + v1 = &verts[vindex]; + float v0p = (*v0)[dim]; + float v1p = (*v1)[dim]; + + /* insert vertex to the boxes it belongs to. */ + if(v0p <= pos) + left_bounds.grow(*v0); + + if(v0p >= pos) + right_bounds.grow(*v0); + + /* edge intersects the plane => insert intersection to both boxes. */ + if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) { + float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f)); + left_bounds.grow(t); + right_bounds.grow(t); + } + } + } + else { + /* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/ + const int k0 = mesh->curves[ref.prim_index()].first_key + ref.prim_segment(); + const int k1 = k0 + 1; + const float3* v0 = &mesh->curve_keys[k0].co; + const float3* v1 = &mesh->curve_keys[k1].co; + float v0p = (*v0)[dim]; float v1p = (*v1)[dim]; @@ -270,6 +297,12 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH if(v0p >= pos) right_bounds.grow(*v0); + if(v1p <= pos) + left_bounds.grow(*v1); + + if(v1p >= pos) + right_bounds.grow(*v1); + /* edge intersects the plane => insert intersection to both boxes. */ if((v0p < pos && v1p > pos) || (v0p > pos && v1p < pos)) { float3 t = lerp(*v0, *v1, clamp((pos - v0p) / (v1p - v0p), 0.0f, 1.0f)); @@ -284,9 +317,9 @@ void BVHSpatialSplit::split_reference(BVHBuild *builder, BVHReference& left, BVH left_bounds.intersect(ref.bounds()); right_bounds.intersect(ref.bounds()); - /* set referecnes */ - left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object()); - right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object()); + /* set references */ + left = BVHReference(left_bounds, ref.prim_index(), ref.prim_object(), ref.prim_segment()); + right = BVHReference(right_bounds, ref.prim_index(), ref.prim_object(), ref.prim_segment()); } CCL_NAMESPACE_END diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 9840687b76a..7b31b9ba157 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -84,6 +84,7 @@ public: /* info */ DeviceInfo info; virtual const string& error_message() { return error_msg; } + bool have_error() { return !error_message().empty(); } /* statistics */ Stats &stats; diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 14f8cfa8767..040f3044457 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -124,7 +124,7 @@ public: if(error_msg == "") \ error_msg = message; \ fprintf(stderr, "%s\n", message.c_str()); \ - cuda_abort(); \ + /*cuda_abort();*/ \ } \ } @@ -326,7 +326,8 @@ public: void mem_copy_to(device_memory& mem) { cuda_push_context(); - cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size())) + if(mem.device_pointer) + cuda_assert(cuMemcpyHtoD(cuda_device_ptr(mem.device_pointer), (void*)mem.data_pointer, mem.memory_size())) cuda_pop_context(); } @@ -336,8 +337,13 @@ public: size_t size = elem*w*h; cuda_push_context(); - cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset, - (CUdeviceptr)((uchar*)mem.device_pointer + offset), size)) + if(mem.device_pointer) { + cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset, + (CUdeviceptr)((uchar*)mem.device_pointer + offset), size)) + } + else { + memset((char*)mem.data_pointer + offset, 0, size); + } cuda_pop_context(); } @@ -346,7 +352,8 @@ public: memset((void*)mem.data_pointer, 0, mem.memory_size()); cuda_push_context(); - cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size())) + if(mem.device_pointer) + cuda_assert(cuMemsetD8(cuda_device_ptr(mem.device_pointer), 0, mem.memory_size())) cuda_pop_context(); } @@ -390,13 +397,18 @@ public: default: assert(0); return; } - CUtexref texref; + CUtexref texref = NULL; cuda_push_context(); cuda_assert(cuModuleGetTexRef(&texref, cuModule, name)) + if(!texref) { + cuda_pop_context(); + return; + } + if(interpolation) { - CUarray handle; + CUarray handle = NULL; CUDA_ARRAY_DESCRIPTOR desc; desc.Width = mem.data_width; @@ -406,6 +418,11 @@ public: cuda_assert(cuArrayCreate(&handle, &desc)) + if(!handle) { + cuda_pop_context(); + return; + } + if(mem.data_height > 1) { CUDA_MEMCPY2D param; memset(¶m, 0, sizeof(param)); @@ -481,6 +498,9 @@ public: void path_trace(RenderTile& rtile, int sample) { + if(have_error()) + return; + cuda_push_context(); CUfunction cuPathTrace; @@ -546,6 +566,9 @@ public: void tonemap(DeviceTask& task, device_ptr buffer, device_ptr rgba) { + if(have_error()) + return; + cuda_push_context(); CUfunction cuFilmConvert; @@ -615,6 +638,9 @@ public: void shader(DeviceTask& task) { + if(have_error()) + return; + cuda_push_context(); CUfunction cuDisplace; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index fde881c0a06..6d5b9a063a0 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -20,12 +20,12 @@ set(SRC set(SRC_HEADERS kernel.h kernel_accumulate.h - kernel_attribute.h kernel_bvh.h kernel_camera.h kernel_compat_cpu.h kernel_compat_cuda.h kernel_compat_opencl.h + kernel_curve.h kernel_differential.h kernel_displace.h kernel_emission.h @@ -37,6 +37,7 @@ set(SRC_HEADERS kernel_object.h kernel_passes.h kernel_path.h + kernel_primitive.h kernel_projection.h kernel_random.h kernel_shader.h diff --git a/intern/cycles/kernel/kernel_attribute.h b/intern/cycles/kernel/kernel_attribute.h deleted file mode 100644 index b7ad731c883..00000000000 --- a/intern/cycles/kernel/kernel_attribute.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __KERNEL_ATTRIBUTE_CL__ -#define __KERNEL_ATTRIBUTE_CL__ - -CCL_NAMESPACE_BEGIN - -/* note: declared in kernel.h, have to add it here because kernel.h is not available */ -bool kernel_osl_use(KernelGlobals *kg); - -__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id) -{ -#ifdef __OSL__ - if (kg->osl) { - return OSLShader::find_attribute(kg, sd, id); - } - else -#endif - { - /* for SVM, find attribute by unique id */ - uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; - uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); - - while(attr_map.x != id) - attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset); - - /* return result */ - return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z; - } -} - -CCL_NAMESPACE_END - -#endif /* __KERNEL_ATTRIBUTE_CL__ */ diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h index d70485fd6cf..2cb29207b05 100644 --- a/intern/cycles/kernel/kernel_bvh.h +++ b/intern/cycles/kernel/kernel_bvh.h @@ -205,6 +205,145 @@ __device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *ise } } +#ifdef __HAIR__ +__device_inline void bvh_curve_intersect(KernelGlobals *kg, Intersection *isect, + float3 P, float3 idir, uint visibility, int object, int curveAddr, int segment) +{ + /* curve Intersection check */ + + int flags = kernel_data.curve_kernel_data.curveflags; + + int prim = kernel_tex_fetch(__prim_index, curveAddr); + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + segment; + int k1 = k0 + 1; + + 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); + float3 p1 = float4_to_float3(P1); + float3 p2 = float4_to_float3(P2); + float3 dif = P - p1; + float3 dir = 1.0f/idir; + + float sp_r = mr + 0.5f * l; + float3 sphere_dif = P - ((p1 + p2) * 0.5f); + float sphere_b = dot(dir,sphere_dif); + sphere_dif = sphere_dif - sphere_b * dir; + sphere_b = dot(dir,sphere_dif); + float sdisc = sphere_b * sphere_b - len_squared(sphere_dif) + sp_r * sp_r; + if(sdisc < 0.0f) + return; + + /* obtain parameters and test midpoint distance for suitable modes*/ + float3 tg = (p2 - p1) / l; + float gd = (r2 - r1) / l; + float dirz = dot(dir,tg); + float difz = dot(dif,tg); + + float a = 1.0f - (dirz*dirz*(1 + gd*gd)); + float halfb = (dot(dir,dif) - dirz*(difz + gd*(difz*gd + r1))); + + float tcentre = -halfb/a; + float zcentre = difz + (dirz * tcentre); + + if((tcentre > isect->t) && !(flags & CURVE_KN_ACCURATE)) + return; + if((zcentre < 0 || zcentre > l) && !(flags & CURVE_KN_ACCURATE) && !(flags & CURVE_KN_INTERSECTCORRECTION)) + return; + + /* test minimum separation*/ + float3 cprod = cross(tg, dir); + float3 cprod2 = cross(tg, dif); + float cprodsq = len_squared(cprod); + float cprod2sq = len_squared(cprod2); + float distscaled = dot(cprod,dif); + + if(cprodsq == 0) + distscaled = cprod2sq; + else + distscaled = (distscaled*distscaled)/cprodsq; + + if(distscaled > mr*mr) + return; + + /* calculate true intersection*/ + float3 tdif = P - p1 + tcentre * dir; + float tdifz = dot(tdif,tg); + float tb = 2*(dot(dir,tdif) - dirz*(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*a*tc; + + if (td < 0.0f) + return; + + float rootd = 0.0f; + float correction = 0.0f; + if(flags & CURVE_KN_ACCURATE) { + rootd = sqrtf(td); + correction = ((-tb - rootd)/(2*a)); + } + + float t = tcentre + correction; + + if(t < isect->t) { + + if(flags & CURVE_KN_INTERSECTCORRECTION) { + rootd = sqrtf(td); + correction = ((-tb - rootd)/(2*a)); + t = tcentre + correction; + } + + float z = zcentre + (dirz * correction); + bool backface = false; + + if(flags & CURVE_KN_BACKFACING && (t < 0.0f || z < 0 || z > l)) { + backface = true; + correction = ((-tb + rootd)/(2*a)); + t = tcentre + correction; + z = zcentre + (dirz * correction); + } + + if(t > 0.0f && t < isect->t && z >= 0 && z <= l) { + + if (flags & CURVE_KN_ENCLOSEFILTER) { + + float enc_ratio = kernel_data.curve_kernel_data.encasing_ratio; + if((dot(P - p1, tg) > -r1 * enc_ratio) && (dot(P - p2, tg) < r2 * enc_ratio)) { + float a2 = 1.0f - (dirz*dirz*(1 + gd*gd*enc_ratio*enc_ratio)); + float c2 = dot(dif,dif) - difz * difz * (1 + gd*gd*enc_ratio*enc_ratio) - r1*r1*enc_ratio*enc_ratio - 2*r1*difz*gd*enc_ratio; + if(a2*c2 < 0.0f) + return; + } + } + +#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 = z/l; + isect->v = td/(4*a*a); + isect->t = t; + + if(backface) + isect->u = -isect->u; + } + } + } +} +#endif + __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint visibility, Intersection *isect) { /* traversal stack in CUDA thread-local memory */ @@ -281,10 +420,16 @@ __device_inline bool bvh_intersect(KernelGlobals *kg, const Ray *ray, const uint nodeAddr = traversalStack[stackPtr]; --stackPtr; - /* triangle intersection */ + /* primitive intersection */ while(primAddr < primAddr2) { - /* intersect ray against triangle */ - bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); + /* 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); + else +#endif + bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); /* shadow ray early termination */ if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0) @@ -401,10 +546,16 @@ __device_inline bool bvh_intersect_motion(KernelGlobals *kg, const Ray *ray, con nodeAddr = traversalStack[stackPtr]; --stackPtr; - /* triangle intersection */ + /* primitive intersection */ while(primAddr < primAddr2) { - /* intersect ray against triangle */ - bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); + /* 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); + else +#endif + bvh_triangle_intersect(kg, isect, P, idir, visibility, object, primAddr); /* shadow ray early termination */ if(visibility == PATH_RAY_SHADOW_OPAQUE && isect->prim != ~0) @@ -457,12 +608,15 @@ __device_inline float3 ray_offset(float3 P, float3 Ng) { #ifdef __INTERSECTION_REFINE__ 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 int epsilon_i = 32; float3 res; /* x component */ - if(fabsf(P.x) < epsilon_f) { + if(fabsf(P.x) < epsilon_test) { res.x = P.x + Ng.x*epsilon_f; } else { @@ -472,7 +626,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng) } /* y component */ - if(fabsf(P.y) < epsilon_f) { + if(fabsf(P.y) < epsilon_test) { res.y = P.y + Ng.y*epsilon_f; } else { @@ -482,7 +636,7 @@ __device_inline float3 ray_offset(float3 P, float3 Ng) } /* z component */ - if(fabsf(P.z) < epsilon_f) { + if(fabsf(P.z) < epsilon_test) { res.z = P.z + Ng.z*epsilon_f; } else { @@ -542,5 +696,105 @@ __device_inline float3 bvh_triangle_refine(KernelGlobals *kg, ShaderData *sd, co #endif } +#ifdef __HAIR__ +__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; + float3 P = ray->P; + float3 D = ray->D; + + if(isect->object != ~0) { +#ifdef __OBJECT_MOTION__ + Transform tfm = sd->ob_itfm; +#else + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); +#endif + + P = transform_point(&tfm, P); + D = transform_direction(&tfm, D*t); + D = normalize_len(D, &t); + } + + int prim = kernel_tex_fetch(__prim_index, isect->prim); + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + isect->segment; + int k1 = k0 + 1; + + 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; + 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); + + #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 = normalize(sd->Ng); + 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; + + 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; + 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__ + /* dPdu/dPdv */ + sd->dPdu = tg; + sd->dPdv = cross(tg,sd->Ng); + #endif + + if(isect->object != ~0) { +#ifdef __OBJECT_MOTION__ + Transform tfm = sd->ob_tfm; +#else + Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); +#endif + + P = transform_point(&tfm, P); + } + + return P; +} +#endif + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_curve.h b/intern/cycles/kernel/kernel_curve.h new file mode 100644 index 00000000000..e065717888c --- /dev/null +++ b/intern/cycles/kernel/kernel_curve.h @@ -0,0 +1,141 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +CCL_NAMESPACE_BEGIN + +#ifdef __HAIR__ + +/* curve attributes */ + +__device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) +{ + if(elem == ATTR_ELEMENT_CURVE) { +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; +#endif + + return kernel_tex_fetch(__attributes_float, offset + sd->prim); + } + else if(elem == ATTR_ELEMENT_CURVE_KEY) { + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + int k0 = __float_as_int(curvedata.x) + sd->segment; + int k1 = k0 + 1; + + float f0 = kernel_tex_fetch(__attributes_float, offset + k0); + float f1 = kernel_tex_fetch(__attributes_float, offset + k1); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*(f1 - f0); + if(dy) *dy = 0.0f; +#endif + + return (1.0f - sd->u)*f0 + sd->u*f1; + } + else { +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; +#endif + + return 0.0f; + } +} + +__device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) +{ + if(elem == ATTR_ELEMENT_CURVE) { + /* idea: we can't derive any useful differentials here, but for tiled + * mipmap image caching it would be useful to avoid reading the highest + * detail level always. maybe a derivative based on the hair density + * could be computed somehow? */ +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); +#endif + + return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim)); + } + else if(elem == ATTR_ELEMENT_CURVE_KEY) { + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + int k0 = __float_as_int(curvedata.x) + sd->segment; + int k1 = k0 + 1; + + float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k0)); + float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k1)); + +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = sd->du.dx*(f1 - f0); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); +#endif + + return (1.0f - sd->u)*f0 + sd->u*f1; + } + else { +#ifdef __RAY_DIFFERENTIALS__ + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); +#endif + + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +/* hair info node functions */ + +__device float curve_thickness(KernelGlobals *kg, ShaderData *sd) +{ + float r = 0.0f; + + if(sd->segment != ~0) { + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + int k0 = __float_as_int(curvedata.x) + sd->segment; + int k1 = k0 + 1; + + float4 P1 = kernel_tex_fetch(__curve_keys, k0); + float4 P2 = kernel_tex_fetch(__curve_keys, k1); + r = (P2.w - P1.w) * sd->u + P1.w; + } + + return r*2.0f; +} + +__device float3 curve_tangent_normal(KernelGlobals *kg, ShaderData *sd) +{ + float3 tgN = make_float3(0.0f,0.0f,0.0f); + + if(sd->segment != ~0) { + float normalmix = kernel_data.curve_kernel_data.normalmix; + + tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu,-sd->I) * normalmix / len_squared(sd->dPdu))); + tgN = normalize(tgN); + + /* need to find suitable scaled gd for corrected normal */ +#if 0 + if (kernel_data.curve_kernel_data.use_tangent_normal_correction) + tgN = normalize(tgN - gd * sd->dPdu); +#endif + } + + return tgN; +} + +#endif + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index e56633c9358..d5506ad1dd0 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -47,7 +47,13 @@ __device float3 direct_emissive_eval(KernelGlobals *kg, float rando, else #endif { - shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time); +#ifdef __HAIR__ + if(ls->type == LIGHT_STRAND) + shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time, ls->prim); + else +#endif + shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v, t, time); + ls->Ng = sd.Ng; /* no path flag, we're evaluating this for all closures. that's weak but @@ -150,7 +156,11 @@ __device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, in /* evaluate emissive closure */ float3 L = shader_emissive_eval(kg, sd); +#ifdef __HAIR__ + if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT) && (sd->segment == ~0)) { +#else if(!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_SAMPLE_AS_LIGHT)) { +#endif /* multiple importance sampling, get triangle light pdf, * and compute weight with respect to BSDF pdf */ float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t); diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index 97ae2d3db87..ea0e4d014fe 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -326,6 +326,61 @@ __device float triangle_light_pdf(KernelGlobals *kg, return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi; } +#ifdef __HAIR__ +/* Strand Light */ + +__device void curve_segment_light_sample(KernelGlobals *kg, int prim, int object, + int segment, float randu, float randv, float time, LightSample *ls) +{ + /* this strand code needs completion */ + float4 v00 = kernel_tex_fetch(__curves, prim); + + int k0 = __float_as_int(v00.x) + segment; + int k1 = k0 + 1; + + 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; + float3 tg = float4_to_float3(P2 - P1) / l; + float3 xc = make_float3(tg.x * tg.z, tg.y * tg.z, -(tg.x * tg.x + tg.y * tg.y)); + if (dot(xc, xc) == 0.0f) + xc = make_float3(tg.x * tg.y, -(tg.x * tg.x + tg.z * tg.z), tg.z * tg.y); + xc = normalize(xc); + float3 yc = cross(tg, xc); + float gd = ((r2 - r1)/l); + + /* normal currently ignores gradient */ + ls->Ng = sinf(2 * M_PI_F * randv) * xc + cosf(2 * M_PI_F * randv) * yc; + ls->P = randu * l * tg + (gd * l + r1) * ls->Ng; + ls->object = object; + ls->prim = prim; + ls->t = 0.0f; + ls->type = LIGHT_STRAND; + ls->eval_fac = 1.0f; + ls->shader = __float_as_int(v00.z); + +#ifdef __INSTANCING__ + /* instance transform */ + if(ls->object >= 0) { +#ifdef __OBJECT_MOTION__ + Transform itfm; + Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm); +#else + Transform tfm = object_fetch_transform(kg, ls->object, OBJECT_TRANSFORM); + Transform itfm = object_fetch_transform(kg, ls->object, OBJECT_INVERSE_TRANSFORM); +#endif + + ls->P = transform_point(&tfm, ls->P); + ls->Ng = normalize(transform_direction(&tfm, ls->Ng)); + } +#endif +} +#endif + /* Light Distribution */ __device int light_distribution_sample(KernelGlobals *kg, float randt) @@ -365,10 +420,19 @@ __device void light_sample(KernelGlobals *kg, float randt, float randu, float ra /* fetch light data */ float4 l = kernel_tex_fetch(__light_distribution, index); int prim = __float_as_int(l.y); +#ifdef __HAIR__ + int segment = __float_as_int(l.z); +#endif if(prim >= 0) { int object = __float_as_int(l.w); - triangle_light_sample(kg, prim, object, randu, randv, time, ls); + +#ifdef __HAIR__ + if (segment != ~0) + curve_segment_light_sample(kg, prim, object, segment, randu, randv, time, ls); + else +#endif + triangle_light_sample(kg, prim, object, randu, randv, time, ls); } else { int point = -prim-1; diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h index 7f8b611ba14..727639386ed 100644 --- a/intern/cycles/kernel/kernel_passes.h +++ b/intern/cycles/kernel/kernel_passes.h @@ -70,11 +70,11 @@ __device_inline void kernel_write_data_passes(KernelGlobals *kg, __global float kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, sample, normal); } if(flag & PASS_UV) { - float3 uv = triangle_uv(kg, sd); + float3 uv = primitive_uv(kg, sd); kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, sample, uv); } if(flag & PASS_MOTION) { - float4 speed = triangle_motion_vector(kg, sd); + float4 speed = primitive_motion_vector(kg, sd); kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, sample, speed); kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, sample, 1.0f); } diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 8da21751cbe..20feaf50a2e 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -24,9 +24,10 @@ #include "kernel_montecarlo.h" #include "kernel_projection.h" #include "kernel_object.h" -#include "kernel_attribute.h" -#include "kernel_projection.h" #include "kernel_triangle.h" +#include "kernel_curve.h" +#include "kernel_primitive.h" +#include "kernel_projection.h" #ifdef __QBVH__ #include "kernel_qbvh.h" #else diff --git a/intern/cycles/kernel/kernel_primitive.h b/intern/cycles/kernel/kernel_primitive.h new file mode 100644 index 00000000000..0851af21e87 --- /dev/null +++ b/intern/cycles/kernel/kernel_primitive.h @@ -0,0 +1,185 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __KERNEL_ATTRIBUTE_CL__ +#define __KERNEL_ATTRIBUTE_CL__ + +CCL_NAMESPACE_BEGIN + +/* attribute lookup */ + +__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id, AttributeElement *elem) +{ + if(sd->object == ~0) + return (int)ATTR_STD_NOT_FOUND; + +#ifdef __OSL__ + if (kg->osl) { + return OSLShader::find_attribute(kg, sd, id, elem); + } + else +#endif + { + /* for SVM, find attribute by unique id */ + uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; +#ifdef __HAIR__ + attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE; +#endif + uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + + while(attr_map.x != id) { + attr_offset += ATTR_PRIM_TYPES; + attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + } + + *elem = (AttributeElement)attr_map.y; + + /* return result */ + return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z; + } +} + +__device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) +{ +#ifdef __HAIR__ + if(sd->segment == ~0) +#endif + return triangle_attribute_float(kg, sd, elem, offset, dx, dy); +#ifdef __HAIR__ + else + return curve_attribute_float(kg, sd, elem, offset, dx, dy); +#endif +} + +__device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) +{ +#ifdef __HAIR__ + if(sd->segment == ~0) +#endif + return triangle_attribute_float3(kg, sd, elem, offset, dx, dy); +#ifdef __HAIR__ + else + return curve_attribute_float3(kg, sd, elem, offset, dx, dy); +#endif +} + +__device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd) +{ + AttributeElement elem_uv; + int offset_uv = find_attribute(kg, sd, ATTR_STD_UV, &elem_uv); + + if(offset_uv == ATTR_STD_NOT_FOUND) + return make_float3(0.0f, 0.0f, 0.0f); + + float3 uv = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL); + uv.z = 1.0f; + return uv; +} + +__device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd) +{ +#ifdef __HAIR__ + if(sd->segment != ~0) + return normalize(sd->dPdu); +#endif + + /* try to create spherical tangent from generated coordinates */ + AttributeElement attr_elem; + int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED, &attr_elem); + + if(attr_offset != ATTR_STD_NOT_FOUND) { + 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)));; + } + else { + /* otherwise use surface derivatives */ + return normalize(sd->dPdu); + } +} + +/* motion */ + +__device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd) +{ + float3 motion_pre = sd->P, motion_post = sd->P; + + /* deformation motion */ + AttributeElement elem_pre, elem_post; + int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE, &elem_pre); + int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST, &elem_post); + + if(offset_pre != ATTR_STD_NOT_FOUND) + motion_pre = primitive_attribute_float3(kg, sd, elem_pre, offset_pre, NULL, NULL); + if(offset_post != ATTR_STD_NOT_FOUND) + motion_post = primitive_attribute_float3(kg, sd, elem_post, offset_post, NULL, NULL); + + /* object motion. note that depending on the mesh having motion vectors, this + * transformation was set match the world/object space of motion_pre/post */ + Transform tfm; + + tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE); + motion_pre = transform_point(&tfm, motion_pre); + + tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST); + motion_post = transform_point(&tfm, motion_post); + + float3 P; + + /* camera motion, for perspective/orthographic motion.pre/post will be a + * world-to-raster matrix, for panorama it's world-to-camera */ + if (kernel_data.cam.type != CAMERA_PANORAMA) { + tfm = kernel_data.cam.worldtoraster; + P = transform_perspective(&tfm, sd->P); + + tfm = kernel_data.cam.motion.pre; + motion_pre = transform_perspective(&tfm, motion_pre); + + tfm = kernel_data.cam.motion.post; + motion_post = transform_perspective(&tfm, motion_post); + } + else { + tfm = kernel_data.cam.worldtocamera; + P = normalize(transform_point(&tfm, sd->P)); + P = float2_to_float3(direction_to_panorama(kg, P)); + P.x *= kernel_data.cam.width; + P.y *= kernel_data.cam.height; + + tfm = kernel_data.cam.motion.pre; + motion_pre = normalize(transform_point(&tfm, motion_pre)); + motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre)); + motion_pre.x *= kernel_data.cam.width; + motion_pre.y *= kernel_data.cam.height; + + tfm = kernel_data.cam.motion.post; + motion_post = normalize(transform_point(&tfm, motion_post)); + motion_post = float2_to_float3(direction_to_panorama(kg, motion_post)); + motion_post.x *= kernel_data.cam.width; + motion_post.y *= kernel_data.cam.height; + } + + motion_pre = motion_pre - P; + motion_post = P - motion_post; + + return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y); +} + +CCL_NAMESPACE_END + +#endif /* __KERNEL_ATTRIBUTE_CL__ */ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 47b4d02e5bf..0a5a2ab54b0 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -56,24 +56,11 @@ __device_noinline void shader_setup_object_transforms(KernelGlobals *kg, ShaderD __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray) { - /* fetch triangle data */ - int prim = kernel_tex_fetch(__prim_index, isect->prim); - float4 Ns = kernel_tex_fetch(__tri_normal, prim); - float3 Ng = make_float3(Ns.x, Ns.y, Ns.z); - int shader = __float_as_int(Ns.w); - - /* triangle */ #ifdef __INSTANCING__ sd->object = (isect->object == ~0)? kernel_tex_fetch(__prim_object, isect->prim): isect->object; #endif - sd->prim = prim; -#ifdef __UV__ - sd->u = isect->u; - sd->v = isect->v; -#endif - sd->flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2); - sd->flag |= kernel_tex_fetch(__object_flag, sd->object); + sd->flag = kernel_tex_fetch(__object_flag, sd->object); /* matrices and time */ #ifdef __OBJECT_MOTION__ @@ -81,23 +68,63 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, sd->time = ray->time; #endif - /* vectors */ - sd->P = bvh_triangle_refine(kg, sd, isect, ray); - sd->Ng = Ng; - sd->N = Ng; - sd->I = -ray->D; - sd->shader = shader; + sd->prim = kernel_tex_fetch(__prim_index, isect->prim); sd->ray_length = isect->t; - /* smooth normal */ - if(sd->shader & SHADER_SMOOTH_NORMAL) - sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); +#ifdef __HAIR__ + if(kernel_tex_fetch(__prim_segment, isect->prim) != ~0) { + /* Strand Shader setting*/ + float4 curvedata = kernel_tex_fetch(__curves, sd->prim); + + sd->shader = __float_as_int(curvedata.z); + sd->segment = isect->segment; + + float tcorr = isect->t; + if(kernel_data.curve_kernel_data.curveflags & CURVE_KN_POSTINTERSECTCORRECTION) { + tcorr = (isect->u < 0)? tcorr + sqrtf(isect->v) : tcorr - sqrtf(isect->v); + sd->ray_length = tcorr; + } + + sd->P = bvh_curve_refine(kg, sd, isect, ray, tcorr); + } + else { +#endif + /* fetch triangle data */ + float4 Ns = kernel_tex_fetch(__tri_normal, sd->prim); + float3 Ng = make_float3(Ns.x, Ns.y, Ns.z); + sd->shader = __float_as_int(Ns.w); + +#ifdef __HAIR__ + sd->segment = ~0; +#endif + +#ifdef __UV__ + sd->u = isect->u; + sd->v = isect->v; +#endif + + /* vectors */ + sd->P = bvh_triangle_refine(kg, sd, isect, ray); + sd->Ng = Ng; + sd->N = Ng; + + /* smooth normal */ + if(sd->shader & SHADER_SMOOTH_NORMAL) + sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); #ifdef __DPDU__ - /* dPdu/dPdv */ - triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); + /* dPdu/dPdv */ + triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); #endif +#ifdef __HAIR__ + } +#endif + + sd->I = -ray->D; + + sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2); + #ifdef __INSTANCING__ if(isect->object != ~0) { /* instance transform */ @@ -135,7 +162,7 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd, __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, const float3 P, const float3 Ng, const float3 I, - int shader, int object, int prim, float u, float v, float t, float time) + int shader, int object, int prim, float u, float v, float t, float time, int segment = ~0) { /* vectors */ sd->P = P; @@ -143,11 +170,15 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, sd->Ng = Ng; sd->I = I; sd->shader = shader; +#ifdef __HAIR__ + sd->segment = segment; +#endif /* primitive */ #ifdef __INSTANCING__ sd->object = object; #endif + /* currently no access to bvh prim index for strand sd->prim - this will cause errors with needs fixing*/ sd->prim = prim; #ifdef __UV__ sd->u = u; @@ -183,8 +214,13 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, #endif /* smooth normal */ +#ifdef __HAIR__ + if(sd->shader & SHADER_SMOOTH_NORMAL && sd->segment == ~0) { + sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); +#else if(sd->shader & SHADER_SMOOTH_NORMAL) { sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v); +#endif #ifdef __INSTANCING__ if(instanced) @@ -194,10 +230,17 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd, #ifdef __DPDU__ /* dPdu/dPdv */ +#ifdef __HAIR__ + if(sd->prim == ~0 || sd->segment != ~0) { + sd->dPdu = make_float3(0.0f, 0.0f, 0.0f); + sd->dPdv = make_float3(0.0f, 0.0f, 0.0f); + } +#else if(sd->prim == ~0) { sd->dPdu = make_float3(0.0f, 0.0f, 0.0f); sd->dPdv = make_float3(0.0f, 0.0f, 0.0f); } +#endif else { triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim); @@ -279,6 +322,9 @@ __device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData sd->object = ~0; #endif sd->prim = ~0; +#ifdef __HAIR__ + sd->segment = ~0; +#endif #ifdef __UV__ sd->u = 0.0f; sd->v = 0.0f; @@ -732,8 +778,20 @@ __device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd, Shader __device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect) { int prim = kernel_tex_fetch(__prim_index, isect->prim); - float4 Ns = kernel_tex_fetch(__tri_normal, prim); - int shader = __float_as_int(Ns.w); + int shader = 0; + +#ifdef __HAIR__ + if(kernel_tex_fetch(__prim_segment, isect->prim) == ~0) { +#endif + float4 Ns = kernel_tex_fetch(__tri_normal, prim); + shader = __float_as_int(Ns.w); +#ifdef __HAIR__ + } + else { + float4 str = kernel_tex_fetch(__curves, prim); + shader = __float_as_int(str.z); + } +#endif int flag = kernel_tex_fetch(__shader_flag, (shader & SHADER_MASK)*2); return (flag & SD_HAS_SURFACE_TRANSPARENT) != 0; diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 29f6b3f072c..e27de95e7ab 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -27,6 +27,7 @@ /* bvh */ KERNEL_TEX(float4, texture_float4, __bvh_nodes) KERNEL_TEX(float4, texture_float4, __tri_woop) +KERNEL_TEX(uint, texture_uint, __prim_segment) KERNEL_TEX(uint, texture_uint, __prim_visibility) KERNEL_TEX(uint, texture_uint, __prim_index) KERNEL_TEX(uint, texture_uint, __prim_object) @@ -42,6 +43,10 @@ KERNEL_TEX(float4, texture_float4, __tri_vnormal) KERNEL_TEX(float4, texture_float4, __tri_vindex) KERNEL_TEX(float4, texture_float4, __tri_verts) +/* curves */ +KERNEL_TEX(float4, texture_float4, __curves) +KERNEL_TEX(float4, texture_float4, __curve_keys) + /* attributes */ KERNEL_TEX(uint4, texture_uint4, __attributes_map) KERNEL_TEX(float, texture_float, __attributes_float) diff --git a/intern/cycles/kernel/kernel_triangle.h b/intern/cycles/kernel/kernel_triangle.h index 570ae52d6c2..d346137760f 100644 --- a/intern/cycles/kernel/kernel_triangle.h +++ b/intern/cycles/kernel/kernel_triangle.h @@ -190,82 +190,5 @@ __device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *s } } -/* motion */ - -__device float4 triangle_motion_vector(KernelGlobals *kg, ShaderData *sd) -{ - float3 motion_pre = sd->P, motion_post = sd->P; - - /* deformation motion */ - int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE); - int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST); - - if(offset_pre != ATTR_STD_NOT_FOUND) - motion_pre = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_pre, NULL, NULL); - if(offset_post != ATTR_STD_NOT_FOUND) - motion_post = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_post, NULL, NULL); - - /* object motion. note that depending on the mesh having motion vectors, this - * transformation was set match the world/object space of motion_pre/post */ - Transform tfm; - - tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE); - motion_pre = transform_point(&tfm, motion_pre); - - tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST); - motion_post = transform_point(&tfm, motion_post); - - float3 P; - - /* camera motion, for perspective/orthographic motion.pre/post will be a - * world-to-raster matrix, for panorama it's world-to-camera */ - if (kernel_data.cam.type != CAMERA_PANORAMA) { - tfm = kernel_data.cam.worldtoraster; - P = transform_perspective(&tfm, sd->P); - - tfm = kernel_data.cam.motion.pre; - motion_pre = transform_perspective(&tfm, motion_pre); - - tfm = kernel_data.cam.motion.post; - motion_post = transform_perspective(&tfm, motion_post); - } - else { - tfm = kernel_data.cam.worldtocamera; - P = normalize(transform_point(&tfm, sd->P)); - P = float2_to_float3(direction_to_panorama(kg, P)); - P.x *= kernel_data.cam.width; - P.y *= kernel_data.cam.height; - - tfm = kernel_data.cam.motion.pre; - motion_pre = normalize(transform_point(&tfm, motion_pre)); - motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre)); - motion_pre.x *= kernel_data.cam.width; - motion_pre.y *= kernel_data.cam.height; - - tfm = kernel_data.cam.motion.post; - motion_post = normalize(transform_point(&tfm, motion_post)); - motion_post = float2_to_float3(direction_to_panorama(kg, motion_post)); - motion_post.x *= kernel_data.cam.width; - motion_post.y *= kernel_data.cam.height; - } - - motion_pre = motion_pre - P; - motion_post = P - motion_post; - - return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y); -} - -__device float3 triangle_uv(KernelGlobals *kg, ShaderData *sd) -{ - int offset_uv = find_attribute(kg, sd, ATTR_STD_UV); - - if(offset_uv == ATTR_STD_NOT_FOUND) - return make_float3(0.0f, 0.0f, 0.0f); - - float3 uv = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, offset_uv, NULL, NULL); - uv.z = 1.0f; - return uv; -} - CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index d11b96503d9..2bd6b5859f3 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -47,6 +47,7 @@ CCL_NAMESPACE_BEGIN #define __OSL__ #endif #define __NON_PROGRESSIVE__ +#define __HAIR__ #endif #ifdef __KERNEL_CUDA__ @@ -116,7 +117,6 @@ CCL_NAMESPACE_BEGIN #define __ANISOTROPIC__ #define __OBJECT_MOTION__ #endif - //#define __SOBOL_FULL_SCREEN__ /* Shader Evaluation */ @@ -292,7 +292,8 @@ typedef enum LightType { LIGHT_BACKGROUND, LIGHT_AREA, LIGHT_AO, - LIGHT_SPOT + LIGHT_SPOT, + LIGHT_STRAND } LightType; /* Camera Type */ @@ -343,18 +344,44 @@ typedef struct Intersection { float t, u, v; int prim; int object; + int segment; } Intersection; /* Attributes */ +#define ATTR_PRIM_TYPES 2 +#define ATTR_PRIM_CURVE 1 + typedef enum AttributeElement { + ATTR_ELEMENT_NONE, + ATTR_ELEMENT_VALUE, ATTR_ELEMENT_FACE, ATTR_ELEMENT_VERTEX, ATTR_ELEMENT_CORNER, - ATTR_ELEMENT_VALUE, - ATTR_ELEMENT_NONE + ATTR_ELEMENT_CURVE, + ATTR_ELEMENT_CURVE_KEY } AttributeElement; +typedef enum AttributeStandard { + ATTR_STD_NONE = 0, + ATTR_STD_VERTEX_NORMAL, + ATTR_STD_FACE_NORMAL, + ATTR_STD_UV, + ATTR_STD_UV_TANGENT, + ATTR_STD_UV_TANGENT_SIGN, + ATTR_STD_GENERATED, + ATTR_STD_POSITION_UNDEFORMED, + ATTR_STD_POSITION_UNDISPLACED, + ATTR_STD_MOTION_PRE, + ATTR_STD_MOTION_POST, + ATTR_STD_PARTICLE, + ATTR_STD_CURVE_TANGENT, + ATTR_STD_CURVE_INTERCEPT, + ATTR_STD_NUM, + + ATTR_STD_NOT_FOUND = ~0 +} AttributeStandard; + /* Closure data */ #define MAX_CLOSURE 8 @@ -436,6 +463,11 @@ typedef struct ShaderData { /* primitive id if there is one, ~0 otherwise */ int prim; + +#ifdef __HAIR__ + /* for curves, segment number in curve, ~0 for triangles */ + int segment; +#endif /* parametric coordinates * - barycentric weights for triangles */ float u, v; @@ -650,6 +682,29 @@ typedef struct KernelBVH { int pad2; } KernelBVH; +typedef enum CurveFlag { + /* runtime flags */ + CURVE_KN_BACKFACING = 1, /* backside of cylinder? */ + CURVE_KN_ENCLOSEFILTER = 2, /* don't consider strands surrounding start point? */ + CURVE_KN_CURVEDATA = 4, /* curve data available? */ + CURVE_KN_INTERPOLATE = 8, /* render as a curve? - not supported yet */ + CURVE_KN_ACCURATE = 16, /* use accurate intersections test? */ + CURVE_KN_INTERSECTCORRECTION = 32, /* correct for width after determing closest midpoint? */ + CURVE_KN_POSTINTERSECTCORRECTION = 64, /* correct for width after intersect? */ + 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? */ +} CurveFlag; + +typedef struct KernelCurves { + /* strand intersect and normal parameters - many can be changed to flags*/ + float normalmix; + float encasing_ratio; + int curveflags; + int pad; + +} KernelCurves; + typedef struct KernelData { KernelCamera cam; KernelFilm film; @@ -657,6 +712,7 @@ typedef struct KernelData { KernelSunSky sunsky; KernelIntegrator integrator; KernelBVH bvh; + KernelCurves curve_kernel_data; } KernelData; CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 498d10f385b..28742d56e3b 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -37,9 +37,10 @@ #include "kernel_differential.h" #include "kernel_object.h" #include "kernel_bvh.h" -#include "kernel_attribute.h" -#include "kernel_projection.h" #include "kernel_triangle.h" +#include "kernel_curve.h" +#include "kernel_primitive.h" +#include "kernel_projection.h" #include "kernel_accumulate.h" #include "kernel_shader.h" @@ -74,6 +75,11 @@ ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices"); ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices"); ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices"); ustring OSLRenderServices::u_geom_name("geom:name"); +#ifdef __HAIR__ +ustring OSLRenderServices::u_is_curve("geom:is_curve"); +ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness"); +ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal"); +#endif ustring OSLRenderServices::u_path_ray_length("path:ray_length"); ustring OSLRenderServices::u_trace("trace"); ustring OSLRenderServices::u_hit("hit"); @@ -495,14 +501,14 @@ static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OS attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) { float3 fval[3]; - fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset, - (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); + fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset, + (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); return set_attribute_float3(fval, type, derivatives, val); } else if (attr.type == TypeDesc::TypeFloat) { float fval[3]; - fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset, - (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); + fval[0] = primitive_attribute_float(kg, sd, attr.elem, attr.offset, + (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL); return set_attribute_float(fval, type, derivatives, val); } else { @@ -593,10 +599,13 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD float3 f = particle_angular_velocity(kg, particle_id); return set_attribute_float3(f, type, derivatives, val); } + + /* Geometry Attributes */ else if (name == u_geom_numpolyvertices) { return set_attribute_int(3, type, derivatives, val); } - else if (name == u_geom_trianglevertices || name == u_geom_polyvertices) { + else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices) + && sd->segment == ~0) { float3 P[3]; triangle_vertices(kg, sd->prim, P); @@ -612,6 +621,22 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD ustring object_name = kg->osl->object_names[sd->object]; return set_attribute_string(object_name, type, derivatives, val); } + +#ifdef __HAIR__ + /* Hair Attributes */ + else if (name == u_is_curve) { + float f = (sd->segment != ~0); + return set_attribute_float(f, type, derivatives, val); + } + else if (name == u_curve_thickness) { + float f = curve_thickness(kg, sd); + return set_attribute_float(f, type, derivatives, val); + } + else if (name == u_curve_tangent_normal) { + float3 f = curve_tangent_normal(kg, sd); + return set_attribute_float3(f, type, derivatives, val); + } +#endif else return false; } @@ -634,7 +659,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri { KernelGlobals *kg = kernel_globals; ShaderData *sd = (ShaderData *)renderstate; - int object, tri; + int object, prim, segment; /* lookup of attribute on another object */ if (object_name != u_empty || sd == NULL) { @@ -644,17 +669,20 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri return false; object = it->second; - tri = ~0; + prim = ~0; + segment = ~0; } else { object = sd->object; - tri = sd->prim; + prim = sd->prim; + segment = sd->segment; if (object == ~0) return get_background_attribute(kg, sd, name, type, derivatives, val); } /* find attribute on object */ + object = object*ATTR_PRIM_TYPES + (segment != ~0); OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object]; OSLGlobals::AttributeMap::iterator it = attribute_map.find(name); @@ -663,7 +691,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri if (attr.elem != ATTR_ELEMENT_VALUE) { /* triangle and vertex attributes */ - if (tri != ~0) + if (prim != ~0) return get_mesh_attribute(kg, sd, attr, type, derivatives, val); } else { diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h index cd4a4163209..50c50b9952c 100644 --- a/intern/cycles/kernel/osl/osl_services.h +++ b/intern/cycles/kernel/osl/osl_services.h @@ -130,6 +130,9 @@ public: static ustring u_geom_trianglevertices; static ustring u_geom_polyvertices; static ustring u_geom_name; + static ustring u_is_curve; + static ustring u_curve_thickness; + static ustring u_curve_tangent_normal; static ustring u_path_ray_length; static ustring u_trace; static ustring u_hit; diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index 3ff032374fc..59e307bb408 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -26,9 +26,10 @@ #include "osl_services.h" #include "osl_shader.h" -#include "util_attribute.h" #include "util_foreach.h" +#include "attribute.h" + #include CCL_NAMESPACE_BEGIN @@ -453,15 +454,17 @@ float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_ /* Attributes */ -int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id) +int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem) { /* for OSL, a hash map is used to lookup the attribute by name. */ - OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[sd->object]; - ustring stdname(std::string("std::") + std::string(attribute_standard_name((AttributeStandard)id))); + int object = sd->object*ATTR_PRIM_TYPES + (sd->segment != ~0); + OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[object]; + ustring stdname(std::string("geom:") + std::string(Attribute::standard_name((AttributeStandard)id))); OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname); if (it != attr_map.end()) { const OSLGlobals::Attribute &osl_attr = it->second; + *elem = osl_attr.elem; /* return result */ return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset; } diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h index 2e46a2de42c..2062c651162 100644 --- a/intern/cycles/kernel/osl/osl_shader.h +++ b/intern/cycles/kernel/osl/osl_shader.h @@ -74,7 +74,7 @@ public: const float3 omega_in, const float3 omega_out); /* attributes */ - static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id); + static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem); }; CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 70fc8610c98..acae46f1615 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -27,6 +27,7 @@ set(SRC_OSL node_glass_bsdf.osl node_glossy_bsdf.osl node_gradient_texture.osl + node_hair_info.osl node_holdout.osl node_hsv.osl node_image_texture.osl diff --git a/intern/cycles/kernel/shaders/node_hair_info.osl b/intern/cycles/kernel/shaders/node_hair_info.osl new file mode 100644 index 00000000000..cbb3b98383f --- /dev/null +++ b/intern/cycles/kernel/shaders/node_hair_info.osl @@ -0,0 +1,32 @@ +/* + * Copyright 2012, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "stdosl.h" + +shader node_hair_info( + output float IsStrand = 0.0, + output float Intercept = 0.0, + output float Thickness = 0.0, + output normal TangentNormal = N) +{ + getattribute("geom:is_curve", IsStrand); + getattribute("geom:curve_intercept", Intercept); + getattribute("geom:curve_thickness", Thickness); + getattribute("geom:curve_tangent_normal", TangentNormal); +} + diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index 69ca6b32c36..f340eaff95f 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -161,6 +161,15 @@ vector cross (vector a, vector b) BUILTIN; float dot (vector a, vector b) BUILTIN; float length (vector v) BUILTIN; float distance (point a, point b) BUILTIN; +float distance (point a, point b, point q) +{ + vector d = b - a; + float dd = dot(d, d); + if(dd == 0.0) + return distance(q, a); + float t = dot(q - a, d)/dd; + return distance(q, a + clamp(t, 0.0, 1.0)*d); +} normal normalize (normal v) BUILTIN; vector normalize (vector v) BUILTIN; vector faceforward (vector N, vector I, vector Nref) BUILTIN; @@ -304,7 +313,7 @@ color transformc (string to, color x) r = color (dot (vector(0.299, 0.587, 0.114), (vector)x), dot (vector(0.596, -0.275, -0.321), (vector)x), dot (vector(0.212, -0.523, 0.311), (vector)x)); - else if (to == "xyz") + else if (to == "XYZ") r = color (dot (vector(0.412453, 0.357580, 0.180423), (vector)x), dot (vector(0.212671, 0.715160, 0.072169), (vector)x), dot (vector(0.019334, 0.119193, 0.950227), (vector)x)); @@ -366,7 +375,7 @@ color transformc (string from, string to, color x) r = color (dot (vector(1, 0.9557, 0.6199), (vector)x), dot (vector(1, -0.2716, -0.6469), (vector)x), dot (vector(1, -1.1082, 1.7051), (vector)x)); - else if (from == "xyz") + else if (from == "XYZ") r = color (dot (vector( 3.240479, -1.537150, -0.498535), (vector)x), dot (vector(-0.969256, 1.875991, 0.041556), (vector)x), dot (vector( 0.055648, -0.204043, 1.057311), (vector)x)); @@ -409,6 +418,8 @@ int startswith (string s, string prefix) BUILTIN; int endswith (string s, string suffix) BUILTIN; string substr (string s, int start, int len) BUILTIN; string substr (string s, int start) { return substr (s, start, strlen(s)); } +float strtof (string str) BUILTIN; +int strtoi (string str) BUILTIN; // Define concat in terms of shorter concat string concat (string a, string b, string c) { diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index ec7978066c2..1f4857c0924 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -301,6 +301,12 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT case NODE_PARTICLE_INFO: svm_node_particle_info(kg, sd, stack, node.y, node.z); break; +#ifdef __HAIR__ + case NODE_HAIR_INFO: + svm_node_hair_info(kg, sd, stack, node.y, node.z); + break; +#endif + #endif case NODE_CONVERT: svm_node_convert(sd, stack, node.y, node.z, node.w); diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h index ed70a6dc423..2beec995151 100644 --- a/intern/cycles/kernel/svm/svm_attribute.h +++ b/intern/cycles/kernel/svm/svm_attribute.h @@ -28,10 +28,15 @@ __device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd, /* find attribute by unique id */ uint id = node.y; uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; +#ifdef __HAIR__ + attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE; +#endif uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); - - while(attr_map.x != id) - attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset); + + while(attr_map.x != id) { + attr_offset += ATTR_PRIM_TYPES; + attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + } /* return result */ *elem = (AttributeElement)attr_map.y; @@ -61,21 +66,21 @@ __device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uin /* fetch and store attribute */ if(type == NODE_ATTR_FLOAT) { if(mesh_type == NODE_ATTR_FLOAT) { - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL); stack_store_float(stack, out_offset, f); } else { - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL); stack_store_float(stack, out_offset, average(f)); } } else { if(mesh_type == NODE_ATTR_FLOAT3) { - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL); stack_store_float3(stack, out_offset, f); } else { - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL); stack_store_float3(stack, out_offset, make_float3(f, f, f)); } } @@ -94,24 +99,24 @@ __device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *st if(type == NODE_ATTR_FLOAT) { if(mesh_type == NODE_ATTR_FLOAT) { float dx; - float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL); stack_store_float(stack, out_offset, f+dx); } else { float3 dx; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL); stack_store_float(stack, out_offset, average(f+dx)); } } else { if(mesh_type == NODE_ATTR_FLOAT3) { float3 dx; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL); stack_store_float3(stack, out_offset, f+dx); } else { float dx; - float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL); + float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL); stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx)); } } @@ -130,24 +135,24 @@ __device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *st if(type == NODE_ATTR_FLOAT) { if(mesh_type == NODE_ATTR_FLOAT) { float dy; - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy); stack_store_float(stack, out_offset, f+dy); } else { float3 dy; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy); stack_store_float(stack, out_offset, average(f+dy)); } } else { if(mesh_type == NODE_ATTR_FLOAT3) { float3 dy; - float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy); + float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy); stack_store_float3(stack, out_offset, f+dy); } else { float dy; - float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy); + float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy); stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy)); } } diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h index c4d03c1f948..a04f4ea0fa7 100644 --- a/intern/cycles/kernel/svm/svm_geometry.h +++ b/intern/cycles/kernel/svm/svm_geometry.h @@ -28,23 +28,7 @@ __device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack, case NODE_GEOM_P: data = sd->P; break; case NODE_GEOM_N: data = sd->N; break; #ifdef __DPDU__ - case NODE_GEOM_T: { - /* try to create spherical tangent from generated coordinates */ - int attr_offset = (sd->object != ~0)? find_attribute(kg, sd, ATTR_STD_GENERATED): ATTR_STD_NOT_FOUND; - - if(attr_offset != ATTR_STD_NOT_FOUND) { - data = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL); - data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f); - object_normal_transform(kg, sd, &data); - data = cross(sd->N, normalize(cross(data, sd->N)));; - } - else { - /* otherwise use surface derivatives */ - data = normalize(sd->dPdu); - } - - break; - } + case NODE_GEOM_T: data = primitive_tangent(kg, sd); break; #endif case NODE_GEOM_I: data = sd->I; break; case NODE_GEOM_Ng: data = sd->Ng; break; @@ -160,5 +144,36 @@ __device void svm_node_particle_info(KernelGlobals *kg, ShaderData *sd, float *s } } +#ifdef __HAIR__ + +/* Hair Info */ + +__device void svm_node_hair_info(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset) +{ + float data; + float3 data3; + + switch(type) { + case NODE_INFO_CURVE_IS_STRAND: { + data = (sd->segment != ~0); + stack_store_float(stack, out_offset, data); + break; + } + case NODE_INFO_CURVE_INTERCEPT: + break; /* handled as attribute */ + case NODE_INFO_CURVE_THICKNESS: { + data = curve_thickness(kg, sd); + stack_store_float(stack, out_offset, data); + break; + } + case NODE_INFO_CURVE_TANGENT_NORMAL: { + data3 = curve_tangent_normal(kg, sd); + stack_store_float3(stack, out_offset, data3); + break; + } + } +} +#endif + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index 9f2d3367420..7a1af43b625 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -248,8 +248,9 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac } /* first try to get tangent attribute */ - int attr_offset = find_attribute(kg, sd, node.z); - int attr_sign_offset = find_attribute(kg, sd, node.w); + AttributeElement attr_elem, attr_sign_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); if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND) { stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f)); @@ -257,8 +258,8 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac } /* ensure orthogonal and normalized (interpolation breaks it) */ - float3 tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL); - float sign = triangle_attribute_float(kg, sd, ATTR_ELEMENT_CORNER, attr_sign_offset, NULL, NULL); + 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); object_normal_transform(kg, sd, &tangent); tangent = cross(sd->N, normalize(cross(tangent, sd->N)));; @@ -295,22 +296,24 @@ __device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack, if(direction_type == NODE_TANGENT_UVMAP) { /* UV map */ - int attr_offset = find_attribute(kg, sd, node.z); + AttributeElement attr_elem; + int attr_offset = find_attribute(kg, sd, node.z, &attr_elem); if(attr_offset == ATTR_STD_NOT_FOUND) tangent = make_float3(0.0f, 0.0f, 0.0f); else - tangent = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, attr_offset, NULL, NULL); + tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL); } else { /* radial */ - int attr_offset = find_attribute(kg, sd, node.z); + AttributeElement attr_elem; + int attr_offset = find_attribute(kg, sd, node.z, &attr_elem); float3 generated; if(attr_offset == ATTR_STD_NOT_FOUND) generated = sd->P; else - generated = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, attr_offset, NULL, NULL); + generated = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL); if(axis == NODE_TANGENT_AXIS_X) tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f)); diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index e1a583625fc..57177eec48f 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -97,7 +97,8 @@ typedef enum NodeType { NODE_CLOSURE_SET_NORMAL, NODE_CLOSURE_AMBIENT_OCCLUSION, NODE_TANGENT, - NODE_NORMAL_MAP + NODE_NORMAL_MAP, + NODE_HAIR_INFO } NodeType; typedef enum NodeAttributeType { @@ -132,6 +133,13 @@ typedef enum NodeParticleInfo { NODE_INFO_PAR_ANGULAR_VELOCITY } NodeParticleInfo; +typedef enum NodeHairInfo { + NODE_INFO_CURVE_IS_STRAND, + NODE_INFO_CURVE_INTERCEPT, + NODE_INFO_CURVE_THICKNESS, + NODE_INFO_CURVE_TANGENT_NORMAL +} NodeHairInfo; + typedef enum NodeLightPath { NODE_LP_camera = 0, NODE_LP_shadow, diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index 7907061c19c..d67a686d1e8 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -31,6 +31,7 @@ set(SRC object.cpp osl.cpp particles.cpp + curves.cpp scene.cpp session.cpp shader.cpp @@ -56,6 +57,7 @@ set(SRC_HEADERS object.h osl.h particles.h + curves.h scene.h session.h shader.h diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index 95941c14b6c..b6f6ba47fe8 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -26,7 +26,7 @@ CCL_NAMESPACE_BEGIN /* Attribute */ -void Attribute::set(ustring name_, TypeDesc type_, Element element_) +void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_) { name = name_; type = type_; @@ -39,12 +39,30 @@ void Attribute::set(ustring name_, TypeDesc type_, Element element_) type == TypeDesc::TypeNormal); } -void Attribute::reserve(int numverts, int numtris) +void Attribute::reserve(int numverts, int numtris, int numcurves, int numkeys) { - buffer.resize(buffer_size(numverts, numtris), 0); + buffer.resize(buffer_size(numverts, numtris, numcurves, numkeys), 0); } -size_t Attribute::data_sizeof() +void Attribute::add(const float& f) +{ + char *data = (char*)&f; + size_t size = sizeof(f); + + for(size_t i = 0; i < size; i++) + buffer.push_back(data[i]); +} + +void Attribute::add(const float3& f) +{ + char *data = (char*)&f; + size_t size = sizeof(f); + + for(size_t i = 0; i < size; i++) + buffer.push_back(data[i]); +} + +size_t Attribute::data_sizeof() const { if(type == TypeDesc::TypeFloat) return sizeof(float); @@ -52,19 +70,27 @@ size_t Attribute::data_sizeof() return sizeof(float3); } -size_t Attribute::element_size(int numverts, int numtris) +size_t Attribute::element_size(int numverts, int numtris, int numcurves, int numkeys) const { - if(element == VERTEX) + if(element == ATTR_ELEMENT_VALUE) + return 1; + if(element == ATTR_ELEMENT_VERTEX) return numverts; - else if(element == FACE) + else if(element == ATTR_ELEMENT_FACE) return numtris; - else + else if(element == ATTR_ELEMENT_CORNER) return numtris*3; + else if(element == ATTR_ELEMENT_CURVE) + return numcurves; + else if(element == ATTR_ELEMENT_CURVE_KEY) + return numkeys; + + return 0; } -size_t Attribute::buffer_size(int numverts, int numtris) +size_t Attribute::buffer_size(int numverts, int numtris, int numcurves, int numkeys) const { - return element_size(numverts, numtris)*data_sizeof(); + return element_size(numverts, numtris, numcurves, numkeys)*data_sizeof(); } bool Attribute::same_storage(TypeDesc a, TypeDesc b) @@ -84,18 +110,51 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b) return false; } +const char *Attribute::standard_name(AttributeStandard std) +{ + if(std == ATTR_STD_VERTEX_NORMAL) + return "N"; + else if(std == ATTR_STD_FACE_NORMAL) + return "Ng"; + else if(std == ATTR_STD_UV) + return "uv"; + else if(std == ATTR_STD_GENERATED) + return "generated"; + else if(std == ATTR_STD_UV_TANGENT) + return "tangent"; + else if(std == ATTR_STD_UV_TANGENT_SIGN) + return "tangent_sign"; + else if(std == ATTR_STD_POSITION_UNDEFORMED) + return "undeformed"; + else if(std == ATTR_STD_POSITION_UNDISPLACED) + return "undisplaced"; + else if(std == ATTR_STD_MOTION_PRE) + return "motion_pre"; + else if(std == ATTR_STD_MOTION_POST) + return "motion_post"; + else if(std == ATTR_STD_PARTICLE) + return "particle"; + else if(std == ATTR_STD_CURVE_TANGENT) + return "curve_tangent"; + else if(std == ATTR_STD_CURVE_INTERCEPT) + return "curve_intercept"; + + return ""; +} + /* Attribute Set */ AttributeSet::AttributeSet() { - mesh = NULL; + triangle_mesh = NULL; + curve_mesh = NULL; } AttributeSet::~AttributeSet() { } -Attribute *AttributeSet::add(ustring name, TypeDesc type, Attribute::Element element) +Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement element) { Attribute *attr = find(name); @@ -111,24 +170,22 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, Attribute::Element ele attributes.push_back(Attribute()); attr = &attributes.back(); - if(element == Attribute::VERTEX) - attr->set(name, type, element); - else if(element == Attribute::FACE) - attr->set(name, type, element); - else if(element == Attribute::CORNER) - attr->set(name, type, element); + attr->set(name, type, element); - if(mesh) - attr->reserve(mesh->verts.size(), mesh->triangles.size()); + /* this is weak .. */ + if(triangle_mesh) + attr->reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), 0, 0); + if(curve_mesh) + attr->reserve(0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size()); return attr; } -Attribute *AttributeSet::find(ustring name) +Attribute *AttributeSet::find(ustring name) const { - foreach(Attribute& attr, attributes) + foreach(const Attribute& attr, attributes) if(attr.name == name) - return &attr; + return (Attribute*)&attr; return NULL; } @@ -154,41 +211,59 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) Attribute *attr = NULL; if(name == ustring()) - name = attribute_standard_name(std); + name = Attribute::standard_name(std); - if(std == ATTR_STD_VERTEX_NORMAL) - attr = add(name, TypeDesc::TypeNormal, Attribute::VERTEX); - else if(std == ATTR_STD_FACE_NORMAL) - attr = add(name, TypeDesc::TypeNormal, Attribute::FACE); - else if(std == ATTR_STD_UV) - attr = add(name, TypeDesc::TypePoint, Attribute::CORNER); - else if(std == ATTR_STD_UV_TANGENT) - attr = add(name, TypeDesc::TypeVector, Attribute::CORNER); - else if(std == ATTR_STD_UV_TANGENT_SIGN) - attr = add(name, TypeDesc::TypeFloat, Attribute::CORNER); - else if(std == ATTR_STD_GENERATED) - attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); - else if(std == ATTR_STD_POSITION_UNDEFORMED) - attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); - else if(std == ATTR_STD_POSITION_UNDISPLACED) - attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); - else if(std == ATTR_STD_MOTION_PRE) - attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); - else if(std == ATTR_STD_MOTION_POST) - attr = add(name, TypeDesc::TypePoint, Attribute::VERTEX); - else - assert(0); + if(triangle_mesh) { + if(std == ATTR_STD_VERTEX_NORMAL) + attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_VERTEX); + else if(std == ATTR_STD_FACE_NORMAL) + attr = add(name, TypeDesc::TypeNormal, ATTR_ELEMENT_FACE); + else if(std == ATTR_STD_UV) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER); + else if(std == ATTR_STD_UV_TANGENT) + attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CORNER); + else if(std == ATTR_STD_UV_TANGENT_SIGN) + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CORNER); + else if(std == ATTR_STD_GENERATED) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + else if(std == ATTR_STD_POSITION_UNDEFORMED) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + else if(std == ATTR_STD_POSITION_UNDISPLACED) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + else if(std == ATTR_STD_MOTION_PRE) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + else if(std == ATTR_STD_MOTION_POST) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX); + else + assert(0); + } + else if(curve_mesh) { + if(std == ATTR_STD_UV) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE); + else if(std == ATTR_STD_GENERATED) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE); + else if(std == ATTR_STD_MOTION_PRE) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY); + else if(std == ATTR_STD_MOTION_POST) + attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY); + else if(std == ATTR_STD_CURVE_TANGENT) + attr = add(name, TypeDesc::TypeVector, ATTR_ELEMENT_CURVE_KEY); + else if(std == ATTR_STD_CURVE_INTERCEPT) + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY); + else + assert(0); + } attr->std = std; return attr; } -Attribute *AttributeSet::find(AttributeStandard std) +Attribute *AttributeSet::find(AttributeStandard std) const { - foreach(Attribute& attr, attributes) + foreach(const Attribute& attr, attributes) if(attr.std == std) - return &attr; + return (Attribute*)&attr; return NULL; } @@ -217,10 +292,14 @@ Attribute *AttributeSet::find(AttributeRequest& req) return find(req.std); } -void AttributeSet::reserve(int numverts, int numtris) +void AttributeSet::reserve() { - foreach(Attribute& attr, attributes) - attr.reserve(numverts, numtris); + foreach(Attribute& attr, attributes) { + if(triangle_mesh) + attr.reserve(triangle_mesh->verts.size(), triangle_mesh->triangles.size(), 0, 0); + if(curve_mesh) + attr.reserve(0, 0, curve_mesh->curves.size(), curve_mesh->curve_keys.size()); + } } void AttributeSet::clear() @@ -235,9 +314,13 @@ AttributeRequest::AttributeRequest(ustring name_) name = name_; std = ATTR_STD_NONE; - type = TypeDesc::TypeFloat; - element = ATTR_ELEMENT_NONE; - offset = 0; + triangle_type = TypeDesc::TypeFloat; + triangle_element = ATTR_ELEMENT_NONE; + triangle_offset = 0; + + curve_type = TypeDesc::TypeFloat; + curve_element = ATTR_ELEMENT_NONE; + curve_offset = 0; } AttributeRequest::AttributeRequest(AttributeStandard std_) @@ -245,9 +328,13 @@ AttributeRequest::AttributeRequest(AttributeStandard std_) name = ustring(); std = std_; - type = TypeDesc::TypeFloat; - element = ATTR_ELEMENT_NONE; - offset = 0; + triangle_type = TypeDesc::TypeFloat; + triangle_element = ATTR_ELEMENT_NONE; + triangle_offset = 0; + + curve_type = TypeDesc::TypeFloat; + curve_element = ATTR_ELEMENT_NONE; + curve_offset = 0; } /* AttributeRequestSet */ diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index d05952edfd7..6c0c06d0425 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -21,7 +21,6 @@ #include "kernel_types.h" -#include "util_attribute.h" #include "util_list.h" #include "util_param.h" #include "util_types.h" @@ -42,36 +41,34 @@ class Mesh; class Attribute { public: - enum Element { - VERTEX, - FACE, - CORNER - }; - ustring name; AttributeStandard std; TypeDesc type; vector buffer; - Element element; + AttributeElement element; Attribute() {} - void set(ustring name, TypeDesc type, Element element); - void reserve(int numverts, int numfaces); + void set(ustring name, TypeDesc type, AttributeElement element); + void reserve(int numverts, int numfaces, int numcurves, int numkeys); - size_t data_sizeof(); - size_t element_size(int numverts, int numfaces); - size_t buffer_size(int numverts, int numfaces); + size_t data_sizeof() const; + size_t element_size(int numverts, int numfaces, int numcurves, int numkeys) const; + size_t buffer_size(int numverts, int numfaces, int numcurves, int numkeys) const; char *data() { return (buffer.size())? &buffer[0]: NULL; }; float3 *data_float3() { return (float3*)data(); } float *data_float() { return (float*)data(); } const char *data() const { return (buffer.size())? &buffer[0]: NULL; } - const float3 *data_float3() const { return (float3*)data(); } - const float *data_float() const { return (float*)data(); } + const float3 *data_float3() const { return (const float3*)data(); } + const float *data_float() const { return (const float*)data(); } + + void add(const float& f); + void add(const float3& f); static bool same_storage(TypeDesc a, TypeDesc b); + static const char *standard_name(AttributeStandard std); }; /* Attribute Set @@ -80,23 +77,24 @@ public: class AttributeSet { public: - Mesh *mesh; + Mesh *triangle_mesh; + Mesh *curve_mesh; list attributes; AttributeSet(); ~AttributeSet(); - Attribute *add(ustring name, TypeDesc type, Attribute::Element element); - Attribute *find(ustring name); + Attribute *add(ustring name, TypeDesc type, AttributeElement element); + Attribute *find(ustring name) const; void remove(ustring name); Attribute *add(AttributeStandard std, ustring name = ustring()); - Attribute *find(AttributeStandard std); + Attribute *find(AttributeStandard std) const; void remove(AttributeStandard std); Attribute *find(AttributeRequest& req); - void reserve(int numverts, int numfaces); + void reserve(); void clear(); }; @@ -104,7 +102,7 @@ public: * * Request from a shader to use a certain attribute, so we can figure out * which ones we need to export from the host app end store for the kernel. - * The attribute is found either by name or by standard. */ + * The attribute is found either by name or by standard attribute type. */ class AttributeRequest { public: @@ -112,9 +110,9 @@ public: AttributeStandard std; /* temporary variables used by MeshManager */ - TypeDesc type; - AttributeElement element; - int offset; + TypeDesc triangle_type, curve_type; + AttributeElement triangle_element, curve_element; + int triangle_offset, curve_offset; AttributeRequest(ustring name_); AttributeRequest(AttributeStandard std); diff --git a/intern/cycles/render/curves.cpp b/intern/cycles/render/curves.cpp new file mode 100644 index 00000000000..3299503b4ab --- /dev/null +++ b/intern/cycles/render/curves.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "device.h" +#include "curves.h" +#include "mesh.h" +#include "object.h" +#include "scene.h" + +#include "util_foreach.h" +#include "util_map.h" +#include "util_progress.h" +#include "util_vector.h" + +CCL_NAMESPACE_BEGIN + +/* Hair System Manager */ + +CurveSystemManager::CurveSystemManager() +{ + primitive = CURVE_LINE_SEGMENTS; + line_method = CURVE_CORRECTED; + interpolation = CURVE_CARDINAL; + triangle_method = CURVE_CAMERA; + resolution = 3; + segments = 1; + + 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; + use_joined = false; + use_tangent_normal = false; + use_tangent_normal_geometry = false; + use_tangent_normal_correction = false; + + need_update = true; + need_mesh_update = false; +} + +CurveSystemManager::~CurveSystemManager() +{ +} + +void CurveSystemManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +{ + if(!need_update) + return; + + device_free(device, dscene); + + progress.set_status("Updating Hair settings", "Copying Hair settings to device"); + + KernelCurves *kcurve= &dscene->data.curve_kernel_data; + + kcurve->curveflags = 0; + + if(primitive == CURVE_SEGMENTS) + kcurve->curveflags |= CURVE_KN_INTERPOLATE; + + 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; + + kcurve->normalmix = normalmix; + kcurve->encasing_ratio = encasing_ratio; + + if(progress.get_cancel()) return; + + need_update = false; +} + +void CurveSystemManager::device_free(Device *device, DeviceScene *dscene) +{ + +} + +bool CurveSystemManager::modified(const CurveSystemManager& CurveSystemManager) +{ + return !(line_method == CurveSystemManager.line_method && + interpolation == CurveSystemManager.interpolation && + primitive == CurveSystemManager.primitive && + use_encasing == CurveSystemManager.use_encasing && + use_tangent_normal == CurveSystemManager.use_tangent_normal && + use_tangent_normal_correction == CurveSystemManager.use_tangent_normal_correction && + use_tangent_normal_geometry == CurveSystemManager.use_tangent_normal_geometry && + 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); +} + +bool CurveSystemManager::modified_mesh(const CurveSystemManager& CurveSystemManager) +{ + return !(primitive == CurveSystemManager.primitive && + interpolation == CurveSystemManager.interpolation && + use_parents == CurveSystemManager.use_parents && + 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_cache == CurveSystemManager.use_cache); +} + +void CurveSystemManager::tag_update(Scene *scene) +{ + need_update = true; +} + +void CurveSystemManager::tag_update_mesh() +{ + need_mesh_update = true; +} +CCL_NAMESPACE_END + diff --git a/intern/cycles/render/curves.h b/intern/cycles/render/curves.h new file mode 100644 index 00000000000..bb9ef6d99cf --- /dev/null +++ b/intern/cycles/render/curves.h @@ -0,0 +1,134 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __CURVES_H__ +#define __CURVES_H__ + +#include "util_types.h" +#include "util_vector.h" + +CCL_NAMESPACE_BEGIN + +class Device; +class DeviceScene; +class Progress; +class Scene; + +typedef enum curve_presets { + CURVE_CUSTOM, + CURVE_TANGENT_SHADING, + CURVE_TRUE_NORMAL, + CURVE_ACCURATE_PRESET +} curve_presets; + +typedef enum curve_primitives { + CURVE_TRIANGLES, + CURVE_LINE_SEGMENTS, + CURVE_SEGMENTS +} curve_primitives; + +typedef enum curve_triangles { + CURVE_CAMERA, + CURVE_RIBBONS, + CURVE_TESSELATED +} curve_triangles; + +typedef enum curve_lines { + CURVE_ACCURATE, + CURVE_CORRECTED, + CURVE_POSTCORRECTED, + CURVE_UNCORRECTED +} curve_lines; + +typedef enum curve_interpolation { + CURVE_LINEAR, + CURVE_CARDINAL, + CURVE_BSPLINE +} curve_interpolation; + +class ParticleCurveData { + +public: + + ParticleCurveData(); + ~ParticleCurveData(); + + vector psys_firstcurve; + vector psys_curvenum; + vector psys_shader; + + vector psys_rootradius; + vector psys_tipradius; + vector psys_shape; + vector psys_closetip; + + vector curve_firstkey; + vector curve_keynum; + vector curve_length; + vector curve_uv; + vector curve_vcol; + + vector curvekey_co; + vector curvekey_time; +}; + +/* HairSystem Manager */ + +class CurveSystemManager { +public: + + int primitive; + int line_method; + int interpolation; + int triangle_method; + int resolution; + int segments; + + float normalmix; + float encasing_ratio; + + bool use_curves; + bool use_smooth; + bool use_cache; + bool use_parents; + bool use_encasing; + bool use_backfacing; + bool use_tangent_normal; + bool use_tangent_normal_correction; + bool use_tangent_normal_geometry; + bool use_joined; + + bool need_update; + bool need_mesh_update; + + CurveSystemManager(); + ~CurveSystemManager(); + + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); + void device_free(Device *device, DeviceScene *dscene); + bool modified(const CurveSystemManager& CurveSystemManager); + bool modified_mesh(const CurveSystemManager& CurveSystemManager); + + void tag_update(Scene *scene); + void tag_update_mesh(); +}; + +CCL_NAMESPACE_END + +#endif /* __CURVES_H__ */ + diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 4173da453fd..c8e3e94ec98 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -142,6 +142,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen /* count */ size_t num_lights = scene->lights.size(); size_t num_triangles = 0; + size_t num_curve_segments = 0; foreach(Object *object, scene->objects) { Mesh *mesh = object->mesh; @@ -169,10 +170,19 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen if(shader->sample_as_light && shader->has_surface_emission) num_triangles++; } + + /* disabled for curves */ +#if 0 + foreach(Mesh::Curve& curve, mesh->curves) { + Shader *shader = scene->shaders[curve.shader]; + + if(shader->sample_as_light && shader->has_surface_emission) + num_curve_segments += curve.num_segments(); +#endif } } - size_t num_distribution = num_triangles; + size_t num_distribution = num_triangles + num_curve_segments; num_distribution += num_lights; /* emission area */ @@ -216,7 +226,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen if(shader->sample_as_light && shader->has_surface_emission) { distribution[offset].x = totarea; distribution[offset].y = __int_as_float(i + mesh->tri_offset); - distribution[offset].z = 1.0f; + distribution[offset].z = __int_as_float(~0); distribution[offset].w = __int_as_float(object_id); offset++; @@ -234,6 +244,40 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen totarea += triangle_area(p1, p2, p3); } } + + /*sample as light disabled for strands*/ +#if 0 + size_t i = 0; + + foreach(Mesh::Curve& curve, mesh->curves) { + Shader *shader = scene->shaders[curve.shader]; + int first_key = curve.first_key; + + if(shader->sample_as_light && shader->has_surface_emission) { + for(int j = 0; j < curve.num_segments(); j++) { + distribution[offset].x = totarea; + distribution[offset].y = __int_as_float(i + mesh->curve_offset); // XXX fix kernel code + distribution[offset].z = __int_as_float(j); + distribution[offset].w = __int_as_float(object_id); + offset++; + + float3 p1 = mesh->curve_keys[first_key + j].loc; + float r1 = mesh->curve_keys[first_key + j].radius; + float3 p2 = mesh->curve_keys[first_key + j + 1].loc; + float r2 = mesh->curve_keys[first_key + j + 1].radius; + + if(!transform_applied) { + p1 = transform_point(&tfm, p1); + p2 = transform_point(&tfm, p2); + } + + totarea += M_PI_F * (r1 + r2) * len(p1 - p2); + } + } + + i++; + } +#endif } if(progress.get_cancel()) return; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index bc782a78c60..d4619dcff55 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -51,7 +51,11 @@ Mesh::Mesh() tri_offset = 0; vert_offset = 0; - attributes.mesh = this; + curve_offset = 0; + curvekey_offset = 0; + + attributes.triangle_mesh = this; + curve_attributes.curve_mesh = this; } Mesh::~Mesh() @@ -59,14 +63,18 @@ Mesh::~Mesh() delete bvh; } -void Mesh::reserve(int numverts, int numtris) +void Mesh::reserve(int numverts, int numtris, int numcurves, int numcurvekeys) { /* reserve space to add verts and triangles later */ verts.resize(numverts); triangles.resize(numtris); shader.resize(numtris); smooth.resize(numtris); - attributes.reserve(numverts, numtris); + curve_keys.resize(numcurvekeys); + curves.resize(numcurves); + + attributes.reserve(); + curve_attributes.reserve(); } void Mesh::clear() @@ -77,7 +85,11 @@ void Mesh::clear() shader.clear(); smooth.clear(); + curve_keys.clear(); + curves.clear(); + attributes.clear(); + curve_attributes.clear(); used_shaders.clear(); transform_applied = false; @@ -86,24 +98,47 @@ void Mesh::clear() void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_) { - Triangle t; - t.v[0] = v0; - t.v[1] = v1; - t.v[2] = v2; + Triangle tri; + tri.v[0] = v0; + tri.v[1] = v1; + tri.v[2] = v2; - triangles.push_back(t); + triangles.push_back(tri); shader.push_back(shader_); smooth.push_back(smooth_); } +void Mesh::add_curve_key(float3 co, float radius) +{ + CurveKey key; + key.co = co; + key.radius = radius; + + curve_keys.push_back(key); +} + +void Mesh::add_curve(int first_key, int num_keys, int shader) +{ + Curve curve; + curve.first_key = first_key; + curve.num_keys = num_keys; + curve.shader = shader; + + curves.push_back(curve); +} + void Mesh::compute_bounds() { BoundBox bnds = BoundBox::empty; size_t verts_size = verts.size(); + size_t curve_keys_size = curve_keys.size(); for(size_t i = 0; i < verts_size; i++) bnds.grow(verts[i]); + for(size_t i = 0; i < curve_keys_size; i++) + bnds.grow(curve_keys[i].co, curve_keys[i].radius); + /* happens mostly on empty meshes */ if(!bnds.valid()) bnds.grow(make_float3(0.0f, 0.0f, 0.0f)); @@ -135,7 +170,12 @@ void Mesh::add_face_normals() float3 v1 = verts_ptr[t.v[1]]; float3 v2 = verts_ptr[t.v[2]]; - fN[i] = normalize(cross(v1 - v0, v2 - v0)); + float3 norm = cross(v1 - v0, v2 - v0); + float normlen = len(norm); + if(normlen == 0.0f) + fN[i] = make_float3(0.0f, 0.0f, 0.0f); + else + fN[i] = norm / normlen; if(flip) fN[i] = -fN[i]; @@ -243,6 +283,43 @@ void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset) } } +void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset) +{ + size_t curve_keys_size = curve_keys.size(); + CurveKey *keys_ptr = NULL; + + /* pack curve keys */ + if(curve_keys_size) { + keys_ptr = &curve_keys[0]; + + for(size_t i = 0; i < curve_keys_size; i++) { + float3 p = keys_ptr[i].co; + float radius = keys_ptr[i].radius; + + curve_key_co[i] = make_float4(p.x, p.y, p.z, radius); + } + } + + /* pack curve segments */ + size_t curve_num = curves.size(); + + if(curve_num) { + Curve *curve_ptr = &curves[0]; + int shader_id = 0; + + for(size_t i = 0; i < curve_num; i++) { + Curve curve = curve_ptr[i]; + shader_id = scene->shader_manager->get_shader_id(curve.shader, this, false); + + curve_data[i] = make_float4( + __int_as_float(curve.first_key + curvekey_offset), + __int_as_float(curve.num_keys), + __int_as_float(shader_id), + 0.0f); + } + } +} + void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total) { if(progress->get_cancel()) @@ -327,7 +404,7 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vectorattribute_map.clear(); og->object_names.clear(); - og->attribute_map.resize(scene->objects.size()); + og->attribute_map.resize(scene->objects.size()*ATTR_PRIM_TYPES); for(size_t i = 0; i < scene->objects.size(); i++) { /* set object name to object index map */ @@ -343,7 +420,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vectorattribute_map[i][attr.name()] = osl_attr; + og->attribute_map[i*ATTR_PRIM_TYPES][attr.name()] = osl_attr; + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr; } /* find mesh attributes */ @@ -357,27 +435,46 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vectorattribute_map[i][stdname] = osl_attr; + if(req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i*ATTR_PRIM_TYPES][stdname] = osl_attr; + } + else if(req.name != ustring()) { + /* add lookup by mesh attribute name */ + og->attribute_map[i*ATTR_PRIM_TYPES][req.name] = osl_attr; + } } - else if(req.name != ustring()) { - /* add lookup by mesh attribute name */ - og->attribute_map[i][req.name] = osl_attr; + + if(req.curve_element != ATTR_ELEMENT_NONE) { + osl_attr.elem = req.curve_element; + osl_attr.offset = req.curve_offset; + + if(req.curve_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else + osl_attr.type = TypeDesc::TypeColor; + + if(req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][stdname] = osl_attr; + } + else if(req.name != ustring()) { + /* add lookup by mesh attribute name */ + og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr; + } } } } @@ -393,7 +490,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce int attr_map_stride = 0; for(size_t i = 0; i < scene->meshes.size(); i++) - attr_map_stride = max(attr_map_stride, mesh_attributes[i].size()+1); + attr_map_stride = max(attr_map_stride, (mesh_attributes[i].size() + 1)*ATTR_PRIM_TYPES); if(attr_map_stride == 0) return; @@ -404,12 +501,13 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce for(size_t i = 0; i < scene->objects.size(); i++) { Object *object = scene->objects[i]; + Mesh *mesh = object->mesh; /* find mesh attributes */ size_t j; for(j = 0; j < scene->meshes.size(); j++) - if(scene->meshes[j] == object->mesh) + if(scene->meshes[j] == mesh) break; AttributeRequestSet& attributes = mesh_attributes[j]; @@ -425,14 +523,29 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce else id = scene->shader_manager->get_attribute_id(req.std); - attr_map[index].x = id; - attr_map[index].y = req.element; - attr_map[index].z = as_uint(req.offset); + if(mesh->triangles.size()) { + attr_map[index].x = id; + attr_map[index].y = req.triangle_element; + attr_map[index].z = as_uint(req.triangle_offset); - if(req.type == TypeDesc::TypeFloat) - attr_map[index].w = NODE_ATTR_FLOAT; - else - attr_map[index].w = NODE_ATTR_FLOAT3; + if(req.triangle_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + } + + index++; + + if(mesh->curves.size()) { + attr_map[index].x = id; + attr_map[index].y = req.curve_element; + attr_map[index].z = as_uint(req.curve_offset); + + if(req.curve_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + } index++; } @@ -442,6 +555,15 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce attr_map[index].y = 0; attr_map[index].z = 0; attr_map[index].w = 0; + + index++; + + attr_map[index].x = ATTR_STD_NONE; + attr_map[index].y = 0; + attr_map[index].z = 0; + attr_map[index].w = 0; + + index++; } /* copy to device */ @@ -449,6 +571,60 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce device->tex_alloc("__attributes_map", dscene->attributes_map); } +static void update_attribute_element_offset(Mesh *mesh, vector& attr_float, vector& attr_float3, + Attribute *mattr, TypeDesc& type, int& offset, AttributeElement& element) +{ + if(mattr) { + /* store element and type */ + element = mattr->element; + type = mattr->type; + + /* store attribute data in arrays */ + size_t size = mattr->element_size( + mesh->verts.size(), + mesh->triangles.size(), + mesh->curves.size(), + mesh->curve_keys.size()); + + if(mattr->type == TypeDesc::TypeFloat) { + float *data = mattr->data_float(); + offset = attr_float.size(); + + attr_float.resize(attr_float.size() + size); + + for(size_t k = 0; k < size; k++) + attr_float[offset+k] = data[k]; + } + else { + float3 *data = mattr->data_float3(); + offset = attr_float3.size(); + + attr_float3.resize(attr_float3.size() + size); + + for(size_t k = 0; k < size; k++) + attr_float3[offset+k] = float3_to_float4(data[k]); + } + + /* mesh vertex/curve index is global, not per object, so we sneak + * a correction for that in here */ + if(element == ATTR_ELEMENT_VERTEX) + offset -= mesh->vert_offset; + else if(element == ATTR_ELEMENT_FACE) + offset -= mesh->tri_offset; + else if(element == ATTR_ELEMENT_CORNER) + offset -= 3*mesh->tri_offset; + else if(element == ATTR_ELEMENT_CURVE) + offset -= mesh->curve_offset; + else if(element == ATTR_ELEMENT_CURVE_KEY) + offset -= mesh->curvekey_offset; + } + else { + /* attribute not found */ + element = ATTR_ELEMENT_NONE; + offset = 0; + } +} + void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) { progress.set_status("Updating Mesh", "Computing attributes"); @@ -482,66 +658,24 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, /* todo: we now store std and name attributes from requests even if * they actually refer to the same mesh attributes, optimize */ foreach(AttributeRequest& req, attributes.requests) { - Attribute *mattr = mesh->attributes.find(req); + Attribute *triangle_mattr = mesh->attributes.find(req); + Attribute *curve_mattr = mesh->curve_attributes.find(req); - /* todo: get rid of this exception */ - if(!mattr && req.std == ATTR_STD_GENERATED) { - mattr = mesh->attributes.add(ATTR_STD_GENERATED); + /* todo: get rid of this exception, it's only here for giving some + * working texture coordinate for subdivision as we can't preserve + * any attributes yet */ + if(!triangle_mattr && req.std == ATTR_STD_GENERATED) { + triangle_mattr = mesh->attributes.add(ATTR_STD_GENERATED); if(mesh->verts.size()) - memcpy(mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size()); + memcpy(triangle_mattr->data_float3(), &mesh->verts[0], sizeof(float3)*mesh->verts.size()); } - /* attribute not found */ - if(!mattr) { - req.element = ATTR_ELEMENT_NONE; - req.offset = 0; - continue; - } - - /* we abuse AttributeRequest to pass on info like element and - * offset, it doesn't really make sense but is convenient */ - - /* store element and type */ - if(mattr->element == Attribute::VERTEX) - req.element = ATTR_ELEMENT_VERTEX; - else if(mattr->element == Attribute::FACE) - req.element = ATTR_ELEMENT_FACE; - else if(mattr->element == Attribute::CORNER) - req.element = ATTR_ELEMENT_CORNER; - - req.type = mattr->type; - - /* store attribute data in arrays */ - size_t size = mattr->element_size(mesh->verts.size(), mesh->triangles.size()); - - if(mattr->type == TypeDesc::TypeFloat) { - float *data = mattr->data_float(); - req.offset = attr_float.size(); - - attr_float.resize(attr_float.size() + size); - - for(size_t k = 0; k < size; k++) - attr_float[req.offset+k] = data[k]; - } - else { - float3 *data = mattr->data_float3(); - req.offset = attr_float3.size(); - - attr_float3.resize(attr_float3.size() + size); - - for(size_t k = 0; k < size; k++) - attr_float3[req.offset+k] = float3_to_float4(data[k]); - } - - /* mesh vertex/triangle index is global, not per object, so we sneak - * a correction for that in here */ - if(req.element == ATTR_ELEMENT_VERTEX) - req.offset -= mesh->vert_offset; - else if(mattr->element == Attribute::FACE) - req.offset -= mesh->tri_offset; - else if(mattr->element == Attribute::CORNER) - req.offset -= 3*mesh->tri_offset; + update_attribute_element_offset(mesh, attr_float, attr_float3, triangle_mattr, + req.triangle_type, req.triangle_offset, req.triangle_element); + update_attribute_element_offset(mesh, attr_float, attr_float3, curve_mattr, + req.curve_type, req.curve_offset, req.curve_element); + if(progress.get_cancel()) return; } } @@ -573,39 +707,62 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene size_t vert_size = 0; size_t tri_size = 0; + size_t curve_key_size = 0; + size_t curve_size = 0; + foreach(Mesh *mesh, scene->meshes) { mesh->vert_offset = vert_size; mesh->tri_offset = tri_size; + mesh->curvekey_offset = curve_key_size; + mesh->curve_offset = curve_size; + vert_size += mesh->verts.size(); tri_size += mesh->triangles.size(); + + curve_key_size += mesh->curve_keys.size(); + curve_size += mesh->curves.size(); } - if(tri_size == 0) - return; + if(tri_size != 0) { + /* normals */ + progress.set_status("Updating Mesh", "Computing normals"); - /* normals */ - progress.set_status("Updating Mesh", "Computing normals"); + float4 *normal = dscene->tri_normal.resize(tri_size); + float4 *vnormal = dscene->tri_vnormal.resize(vert_size); + float4 *tri_verts = dscene->tri_verts.resize(vert_size); + float4 *tri_vindex = dscene->tri_vindex.resize(tri_size); - float4 *normal = dscene->tri_normal.resize(tri_size); - float4 *vnormal = dscene->tri_vnormal.resize(vert_size); - float4 *tri_verts = dscene->tri_verts.resize(vert_size); - float4 *tri_vindex = dscene->tri_vindex.resize(tri_size); + foreach(Mesh *mesh, scene->meshes) { + mesh->pack_normals(scene, &normal[mesh->tri_offset], &vnormal[mesh->vert_offset]); + mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset); - foreach(Mesh *mesh, scene->meshes) { - mesh->pack_normals(scene, &normal[mesh->tri_offset], &vnormal[mesh->vert_offset]); - mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset); + if(progress.get_cancel()) return; + } - if(progress.get_cancel()) return; + /* vertex coordinates */ + progress.set_status("Updating Mesh", "Copying Mesh to device"); + + device->tex_alloc("__tri_normal", dscene->tri_normal); + device->tex_alloc("__tri_vnormal", dscene->tri_vnormal); + device->tex_alloc("__tri_verts", dscene->tri_verts); + device->tex_alloc("__tri_vindex", dscene->tri_vindex); } - /* vertex coordinates */ - progress.set_status("Updating Mesh", "Copying Mesh to device"); + if(curve_size != 0) { + progress.set_status("Updating Mesh", "Copying Strands to device"); - device->tex_alloc("__tri_normal", dscene->tri_normal); - device->tex_alloc("__tri_vnormal", dscene->tri_vnormal); - device->tex_alloc("__tri_verts", dscene->tri_verts); - device->tex_alloc("__tri_vindex", dscene->tri_vindex); + float4 *curve_keys = dscene->curve_keys.resize(curve_key_size); + float4 *curves = dscene->curves.resize(curve_size); + + foreach(Mesh *mesh, scene->meshes) { + mesh->pack_curves(scene, &curve_keys[mesh->curvekey_offset], &curves[mesh->curve_offset], mesh->curvekey_offset); + if(progress.get_cancel()) return; + } + + device->tex_alloc("__curve_keys", dscene->curve_keys); + device->tex_alloc("__curves", dscene->curves); + } } void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) @@ -642,6 +799,10 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * dscene->tri_woop.reference(&pack.tri_woop[0], pack.tri_woop.size()); device->tex_alloc("__tri_woop", dscene->tri_woop); } + if(pack.prim_segment.size()) { + dscene->prim_segment.reference((uint*)&pack.prim_segment[0], pack.prim_segment.size()); + device->tex_alloc("__prim_segment", dscene->prim_segment); + } if(pack.prim_visibility.size()) { dscene->prim_visibility.reference((uint*)&pack.prim_visibility[0], pack.prim_visibility.size()); device->tex_alloc("__prim_visibility", dscene->prim_visibility); @@ -751,6 +912,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->bvh_nodes); device->tex_free(dscene->object_node); device->tex_free(dscene->tri_woop); + device->tex_free(dscene->prim_segment); device->tex_free(dscene->prim_visibility); device->tex_free(dscene->prim_index); device->tex_free(dscene->prim_object); @@ -758,6 +920,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->tri_vnormal); device->tex_free(dscene->tri_vindex); device->tex_free(dscene->tri_verts); + device->tex_free(dscene->curves); + device->tex_free(dscene->curve_keys); device->tex_free(dscene->attributes_map); device->tex_free(dscene->attributes_float); device->tex_free(dscene->attributes_float3); @@ -765,6 +929,7 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->bvh_nodes.clear(); dscene->object_node.clear(); dscene->tri_woop.clear(); + dscene->prim_segment.clear(); dscene->prim_visibility.clear(); dscene->prim_index.clear(); dscene->prim_object.clear(); @@ -772,6 +937,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->tri_vnormal.clear(); dscene->tri_vindex.clear(); dscene->tri_verts.clear(); + dscene->curves.clear(); + dscene->curve_keys.clear(); dscene->attributes_map.clear(); dscene->attributes_float.clear(); dscene->attributes_float3.clear(); diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 637143f5adf..b83752ad8df 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -50,6 +50,21 @@ public: int v[3]; }; + /* Mesh Curve */ + struct Curve { + int first_key; + int num_keys; + uint shader; + uint pad; + + int num_segments() { return num_keys - 1; } + }; + + struct CurveKey { + float3 co; + float radius; + }; + /* Displacement */ enum DisplacementMethod { DISPLACE_BUMP, @@ -65,8 +80,12 @@ public: vector shader; vector smooth; + vector curve_keys; + vector curves; + vector used_shaders; AttributeSet attributes; + AttributeSet curve_attributes; BoundBox bounds; bool transform_applied; @@ -82,13 +101,18 @@ public: size_t tri_offset; size_t vert_offset; + size_t curve_offset; + size_t curvekey_offset; + /* Functions */ Mesh(); ~Mesh(); - void reserve(int numverts, int numfaces); + void reserve(int numverts, int numfaces, int numcurves, int numcurvekeys); void clear(); void add_triangle(int v0, int v1, int v2, int shader, bool smooth); + void add_curve_key(float3 loc, float radius); + void add_curve(int first_key, int num_keys, int shader); void compute_bounds(); void add_face_normals(); @@ -96,6 +120,7 @@ public: void pack_normals(Scene *scene, float4 *normal, float4 *vnormal); void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset); + void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset); void compute_bvh(SceneParams *params, Progress *progress, int n, int total); bool need_attribute(Scene *scene, AttributeStandard std); diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp index dea694a811e..04267697b29 100644 --- a/intern/cycles/render/mesh_displace.cpp +++ b/intern/cycles/render/mesh_displace.cpp @@ -19,6 +19,7 @@ #include "device.h" #include "mesh.h" +#include "object.h" #include "scene.h" #include "shader.h" @@ -41,11 +42,24 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p if(!has_displacement) return false; + string msg = string_printf("Computing Displacement %s", mesh->name.c_str()); + progress.set_status("Updating Mesh", msg); + + /* find object index. todo: is arbitrary */ + size_t object_index = ~0; + + for(size_t i = 0; i < scene->objects.size(); i++) { + if(scene->objects[i]->mesh == mesh) { + object_index = i; + break; + } + } + /* setup input for device task */ vector done(mesh->verts.size(), false); device_vector d_input; uint4 *d_input_data = d_input.resize(mesh->verts.size()); - size_t d_input_offset = 0; + size_t d_input_size = 0; for(size_t i = 0; i < mesh->triangles.size(); i++) { Mesh::Triangle t = mesh->triangles[i]; @@ -61,8 +75,8 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p done[t.v[j]] = true; /* set up object, primitive and barycentric coordinates */ - /* when used, non-instanced convention: object = -object-1; */ - int object = ~0; /* todo */ + /* when used, non-instanced convention: object = ~object */ + int object = ~object_index; int prim = mesh->tri_offset + i; float u, v; @@ -81,16 +95,16 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p /* back */ uint4 in = make_uint4(object, prim, __float_as_int(u), __float_as_int(v)); - d_input_data[d_input_offset++] = in; + d_input_data[d_input_size++] = in; } } - if(d_input_offset == 0) + if(d_input_size == 0) return false; /* run device task */ device_vector d_output; - d_output.resize(d_input.size()); + d_output.resize(d_input_size); device->mem_alloc(d_input, MEM_READ_ONLY); device->mem_copy_to(d_input); @@ -101,7 +115,7 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p task.shader_output = d_output.device_pointer; task.shader_eval_type = SHADER_EVAL_DISPLACE; task.shader_x = 0; - task.shader_w = d_input.size(); + task.shader_w = d_output.size(); device->task_add(task); device->task_wait(); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index aef28449e44..14ef3c68ad3 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -2240,6 +2240,63 @@ void ParticleInfoNode::compile(OSLCompiler& compiler) compiler.add(this, "node_particle_info"); } +/* Hair Info */ + +HairInfoNode::HairInfoNode() +: ShaderNode("hair_info") +{ + add_output("Is Strand", SHADER_SOCKET_FLOAT); + add_output("Intercept", SHADER_SOCKET_FLOAT); + add_output("Thickness", SHADER_SOCKET_FLOAT); + add_output("Tangent Normal", SHADER_SOCKET_NORMAL); +} + +void HairInfoNode::attributes(AttributeRequestSet *attributes) +{ + ShaderOutput *intercept_out = output("Intercept"); + + if(!intercept_out->links.empty()) + attributes->add(ATTR_STD_CURVE_INTERCEPT); + + ShaderNode::attributes(attributes); +} + +void HairInfoNode::compile(SVMCompiler& compiler) +{ + ShaderOutput *out; + + out = output("Is Strand"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, out->stack_offset); + } + + out = output("Intercept"); + if(!out->links.empty()) { + int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT); + compiler.stack_assign(out); + compiler.add_node(NODE_ATTR, attr, out->stack_offset, NODE_ATTR_FLOAT); + } + + out = output("Thickness"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, out->stack_offset); + } + + out = output("Tangent Normal"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, out->stack_offset); + } + +} + +void HairInfoNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_hair_info"); +} + /* Value */ ValueNode::ValueNode() diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 8012a99ff05..564ceee5a5b 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -331,6 +331,13 @@ public: void attributes(AttributeRequestSet *attributes); }; +class HairInfoNode : public ShaderNode { +public: + SHADER_NODE_CLASS(HairInfoNode) + + void attributes(AttributeRequestSet *attributes); +}; + class ValueNode : public ShaderNode { public: SHADER_NODE_CLASS(ValueNode) diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 5df8e8c1368..a89f8afd251 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -19,6 +19,7 @@ #include "device.h" #include "light.h" #include "mesh.h" +#include "curves.h" #include "object.h" #include "scene.h" @@ -45,6 +46,7 @@ Object::Object() motion.post = transform_identity(); use_motion = false; use_holdout = false; + curverender = false; } Object::~Object() @@ -86,6 +88,10 @@ void Object::apply_transform() for(size_t i = 0; i < mesh->verts.size(); i++) mesh->verts[i] = transform_point(&tfm, mesh->verts[i]); + 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); @@ -110,6 +116,13 @@ void Object::apply_transform() 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); @@ -133,6 +146,7 @@ void Object::tag_update(Scene *scene) } } + scene->curve_system_manager->need_update = true; scene->mesh_manager->need_update = true; scene->object_manager->need_update = true; } @@ -189,6 +203,20 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene surface_area += triangle_area(p1, p2, p3); } + foreach(Mesh::Curve& curve, mesh->curves) { + int first_key = curve.first_key; + + for(int i = 0; i < curve.num_segments(); i++) { + float3 p1 = mesh->curve_keys[first_key + i].co; + float r1 = mesh->curve_keys[first_key + i].radius; + float3 p2 = mesh->curve_keys[first_key + i + 1].co; + float r2 = mesh->curve_keys[first_key + i + 1].radius; + + /* currently ignores segment overlaps*/ + surface_area += M_PI_F *(r1 + r2) * len(p1 - p2); + } + } + surface_area_map[mesh] = surface_area; } else @@ -204,6 +232,23 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene surface_area += triangle_area(p1, p2, p3); } + + foreach(Mesh::Curve& curve, mesh->curves) { + int first_key = curve.first_key; + + for(int i = 0; i < curve.num_segments(); i++) { + float3 p1 = mesh->curve_keys[first_key + i].co; + float r1 = mesh->curve_keys[first_key + i].radius; + float3 p2 = mesh->curve_keys[first_key + i + 1].co; + float r2 = mesh->curve_keys[first_key + i + 1].radius; + + p1 = transform_point(&tfm, p1); + p2 = transform_point(&tfm, p2); + + /* currently ignores segment overlaps*/ + surface_area += M_PI_F *(r1 + r2) * len(p1 - p2); + } + } } /* pack in texture */ @@ -355,6 +400,7 @@ void ObjectManager::apply_static_transforms(Scene *scene, uint *object_flag, Pro void ObjectManager::tag_update(Scene *scene) { need_update = true; + scene->curve_system_manager->need_update = true; scene->mesh_manager->need_update = true; scene->light_manager->need_update = true; } diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index 9c9b11bc29c..9ba500ca4d6 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -48,6 +48,7 @@ public: MotionTransform motion; bool use_motion; bool use_holdout; + bool curverender; float3 dupli_generated; float2 dupli_uv; diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 8085cfdd3e6..093bfecf88e 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -29,6 +29,7 @@ #include "mesh.h" #include "object.h" #include "particles.h" +#include "curves.h" #include "scene.h" #include "svm.h" #include "osl.h" @@ -54,6 +55,7 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_) integrator = new Integrator(); image_manager = new ImageManager(); particle_system_manager = new ParticleSystemManager(); + curve_system_manager = new CurveSystemManager(); /* OSL only works on the CPU */ if(device_info_.type == DEVICE_CPU) @@ -96,6 +98,7 @@ void Scene::free_memory(bool final) light_manager->device_free(device, &dscene); particle_system_manager->device_free(device, &dscene); + curve_system_manager->device_free(device, &dscene); if(!params.persistent_images || final) image_manager->device_free(device, &dscene); @@ -112,6 +115,7 @@ void Scene::free_memory(bool final) delete shader_manager; delete light_manager; delete particle_system_manager; + delete curve_system_manager; delete image_manager; } else { @@ -165,6 +169,11 @@ void Scene::device_update(Device *device_, Progress& progress) if(progress.get_cancel()) return; + progress.set_status("Updating Hair Systems"); + curve_system_manager->device_update(device, &dscene, this, progress); + + if(progress.get_cancel()) return; + progress.set_status("Updating Meshes"); mesh_manager->device_update(device, &dscene, this, progress); @@ -242,7 +251,8 @@ bool Scene::need_reset() || filter->need_update || integrator->need_update || shader_manager->need_update - || particle_system_manager->need_update); + || particle_system_manager->need_update + || curve_system_manager->need_update); } void Scene::reset() diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index ebe932e40e7..f6e1daea80d 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -25,7 +25,6 @@ #include "kernel_types.h" -#include "util_attribute.h" #include "util_param.h" #include "util_string.h" #include "util_thread.h" @@ -50,6 +49,7 @@ class Object; class ObjectManager; class ParticleSystemManager; class ParticleSystem; +class CurveSystemManager; class Shader; class ShaderManager; class Progress; @@ -62,6 +62,7 @@ public: device_vector bvh_nodes; device_vector object_node; device_vector tri_woop; + device_vector prim_segment; device_vector prim_visibility; device_vector prim_index; device_vector prim_object; @@ -72,6 +73,9 @@ public: device_vector tri_vindex; device_vector tri_verts; + device_vector curves; + device_vector curve_keys; + /* objects */ device_vector objects; device_vector objects_vector; @@ -170,6 +174,7 @@ public: MeshManager *mesh_manager; ObjectManager *object_manager; ParticleSystemManager *particle_system_manager; + CurveSystemManager *curve_system_manager; /* default shaders */ int default_surface; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 1d1a3d54893..36948adce17 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -357,7 +357,7 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile) tile_lock.unlock(); - /* in case of a permant buffer, return it, otherwise we will allocate + /* in case of a permanent buffer, return it, otherwise we will allocate * a new temporary buffer */ if(!params.background) { tile_manager.state.buffer.get_offset_stride(rtile.offset, rtile.stride); @@ -411,6 +411,12 @@ bool Session::acquire_tile(Device *tile_device, RenderTile& rtile) rtile.rgba = 0; rtile.buffers = tilebuffers; + /* this will tag tile as IN PROGRESS in blender-side render pipeline, + * which is needed to highlight currently rendering tile before first + * sample was processed for it + */ + update_tile_sample(rtile); + return true; } diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp index 6920df9954c..48e6808bc38 100644 --- a/intern/cycles/subd/subd_dice.cpp +++ b/intern/cycles/subd/subd_dice.cpp @@ -47,7 +47,7 @@ void EdgeDice::reserve(int num_verts, int num_tris) vert_offset = mesh->verts.size(); tri_offset = mesh->triangles.size(); - mesh->reserve(vert_offset + num_verts, tri_offset + num_tris); + mesh->reserve(vert_offset + num_verts, tri_offset + num_tris, 0, 0); Attribute *attr_vN = mesh->attributes.add(ATTR_STD_VERTEX_NORMAL); diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index dce417704cc..bcaaa9a71b9 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -9,7 +9,6 @@ set(INC_SYS ) set(SRC - util_attribute.cpp util_cache.cpp util_cuda.cpp util_dynlib.cpp @@ -33,7 +32,6 @@ endif() set(SRC_HEADERS util_algorithm.h util_args.h - util_attribute.h util_boundbox.h util_cache.h util_cuda.h diff --git a/intern/cycles/util/util_attribute.cpp b/intern/cycles/util/util_attribute.cpp deleted file mode 100644 index 057fb6213e9..00000000000 --- a/intern/cycles/util/util_attribute.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2011, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "util_attribute.h" - -CCL_NAMESPACE_BEGIN - -const char *attribute_standard_name(AttributeStandard std) -{ - if(std == ATTR_STD_VERTEX_NORMAL) - return "N"; - else if(std == ATTR_STD_FACE_NORMAL) - return "Ng"; - else if(std == ATTR_STD_UV) - return "uv"; - else if(std == ATTR_STD_GENERATED) - return "generated"; - else if(std == ATTR_STD_UV_TANGENT) - return "tangent"; - else if(std == ATTR_STD_UV_TANGENT_SIGN) - return "tangent_sign"; - else if(std == ATTR_STD_POSITION_UNDEFORMED) - return "undeformed"; - else if(std == ATTR_STD_POSITION_UNDISPLACED) - return "undisplaced"; - else if(std == ATTR_STD_MOTION_PRE) - return "motion_pre"; - else if(std == ATTR_STD_MOTION_POST) - return "motion_post"; - else if(std == ATTR_STD_PARTICLE) - return "particle"; - - return ""; -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h index 6dd1c6c71e8..0c857f906ee 100644 --- a/intern/cycles/util/util_boundbox.h +++ b/intern/cycles/util/util_boundbox.h @@ -65,6 +65,13 @@ public: max = ccl::max(max, pt); } + __forceinline void grow(const float3& pt, float border) + { + float3 shift = {border, border, border, 0.0f}; + min = ccl::min(min, pt - shift); + max = ccl::max(max, pt + shift); + } + __forceinline void grow(const BoundBox& bbox) { grow(bbox.min); diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h index 00b6cf5c56e..bb6de1197e7 100644 --- a/intern/cycles/util/util_types.h +++ b/intern/cycles/util/util_types.h @@ -448,24 +448,6 @@ __device_inline int4 make_int4(const float3& f) #endif -typedef enum AttributeStandard { - ATTR_STD_NONE = 0, - ATTR_STD_VERTEX_NORMAL, - ATTR_STD_FACE_NORMAL, - ATTR_STD_UV, - ATTR_STD_UV_TANGENT, - ATTR_STD_UV_TANGENT_SIGN, - ATTR_STD_GENERATED, - ATTR_STD_POSITION_UNDEFORMED, - ATTR_STD_POSITION_UNDISPLACED, - ATTR_STD_MOTION_PRE, - ATTR_STD_MOTION_POST, - ATTR_STD_PARTICLE, - ATTR_STD_NUM, - - ATTR_STD_NOT_FOUND = ~0 -} AttributeStandard; - CCL_NAMESPACE_END #endif /* __UTIL_TYPES_H__ */ diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 39fd038d568..2d9d89d9ad0 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -1579,7 +1579,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) case NSScrollWheel: { - if (!m_hasMultiTouchTrackpad) { + int momentum = 0; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + m_hasMultiTouchTrackpad = 0; + momentum = [event momentumPhase] || [event phase]; +#endif + /* standard scrollwheel case */ + if (!m_hasMultiTouchTrackpad && momentum == 0) { GHOST_TInt32 delta; double deltaF = [event deltaY]; @@ -1593,9 +1599,18 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) else { NSPoint mousePos = [cocoawindow mouseLocationOutsideOfEventStream]; GHOST_TInt32 x, y; - double dx = [event deltaX]; - double dy = -[event deltaY]; + double dx; + double dy; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + /* with 10.7 nice scrolling deltas are supported */ + dx = [event scrollingDeltaX]; + dy = [event scrollingDeltaY]; + +#else + /* trying to pretend you have nice scrolls... */ + dx = [event deltaX]; + dy = -[event deltaY]; const double deltaMax = 50.0; if ((dx == 0) && (dy == 0)) break; @@ -1612,9 +1627,10 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) else dy += 0.5; if (dy < -deltaMax) dy= -deltaMax; else if (dy > deltaMax) dy= deltaMax; - - window->clientToScreenIntern(mousePos.x, mousePos.y, x, y); + dy = -dy; +#endif + window->clientToScreenIntern(mousePos.x, mousePos.y, x, y); pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000, window, GHOST_kTrackpadEventScroll, x, y, dx, dy)); } diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 471505538ba..2d58f0612ce 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -595,6 +595,11 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( [m_window setAcceptsMouseMovedEvents:YES]; +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 + NSView *view = [m_window contentView]; + [view setAcceptsTouchEvents:YES]; +#endif + [m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, NSStringPboardType, NSTIFFPboardType, nil]]; diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp index 939c66bad13..80e75298d70 100644 --- a/intern/locale/boost_locale_wrapper.cpp +++ b/intern/locale/boost_locale_wrapper.cpp @@ -55,44 +55,49 @@ void bl_locale_set(const char *locale) // Specify location of dictionaries. gen.add_messages_path(messages_path); gen.add_messages_domain(default_domain); - //gen.set_default_messages_domain(default_domain); + //gen.set_default_messages_domain(default_domain); - if (locale && locale[0]) { - std::locale::global(gen(locale)); - } - else { -#if defined (__APPLE__) - // workaround to get osx system locale from user defaults - FILE* fp; - std::string locale_osx = ""; - char result[16]; - int result_len = 0; + try { + if (locale && locale[0]) { + std::locale::global(gen(locale)); + } + else { +#ifdef __APPLE__ + // workaround to get osx system locale from user defaults + FILE *fp; + std::string locale_osx = ""; + char result[16]; + int result_len = 0; - fp = popen("defaults read .GlobalPreferences AppleLocale", "r"); + fp = popen("defaults read .GlobalPreferences AppleLocale", "r"); - if(fp) { - result_len = fread(result, 1, sizeof(result) - 1, fp); + if (fp) { + result_len = fread(result, 1, sizeof(result) - 1, fp); - if(result_len > 0) { - result[result_len-1] = '\0'; // \0 terminate and remove \n - locale_osx = std::string(result) + std::string(".UTF-8"); + if (result_len > 0) { + result[result_len - 1] = '\0'; // \0 terminate and remove \n + locale_osx = std::string(result) + std::string(".UTF-8"); + } + + pclose(fp); } - pclose(fp); - } + if (locale_osx == "") + fprintf(stderr, "Locale set: failed to read AppleLocale read from defaults\n"); - if(locale_osx == "") - fprintf(stderr, "Locale set: failed to read AppleLocale read from defaults\n"); - - std::locale::global(gen(locale_osx.c_str())); + std::locale::global(gen(locale_osx.c_str())); #else - std::locale::global(gen("")); + std::locale::global(gen("")); #endif + } + // Note: boost always uses "C" LC_NUMERIC by default! + } + catch(std::exception const &e) { + std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n"; } - // Note: boost always uses "C" LC_NUMERIC by default! } -const char* bl_locale_pgettext(const char *msgctxt, const char *msgid) +const char *bl_locale_pgettext(const char *msgctxt, const char *msgid) { // Note: We cannot use short stuff like boost::locale::gettext, because those return // std::basic_string objects, which c_ptr()-returned char* is no more valid @@ -107,7 +112,7 @@ const char* bl_locale_pgettext(const char *msgctxt, const char *msgid) return msgid; } catch(std::exception const &e) { -// std::cout << "boost_locale_pgettext: " << e.what() << " \n"; +// std::cout << "bl_locale_pgettext(" << msgctxt << ", " << msgid << "): " << e.what() << " \n"; return msgid; } } diff --git a/intern/smoke/CMakeLists.txt b/intern/smoke/CMakeLists.txt index 3b8a4c06e69..b6338f90ebc 100644 --- a/intern/smoke/CMakeLists.txt +++ b/intern/smoke/CMakeLists.txt @@ -29,7 +29,7 @@ set(INC ) set(INC_SYS - ../../extern/bullet2/src + ${BULLET_INCLUDE_DIRS} ${PNG_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS} ) diff --git a/release/darwin/blender.app/Contents/MacOS/blender b/release/darwin/blender.app/Contents/MacOS/blender index 5e05e74a307..48cdce85287 100644 --- a/release/darwin/blender.app/Contents/MacOS/blender +++ b/release/darwin/blender.app/Contents/MacOS/blender @@ -1 +1 @@ -placeholder +placeholder diff --git a/release/darwin/blenderplayer.app/Contents/MacOS/blenderplayer b/release/darwin/blenderplayer.app/Contents/MacOS/blenderplayer index 5e05e74a307..48cdce85287 100644 --- a/release/darwin/blenderplayer.app/Contents/MacOS/blenderplayer +++ b/release/darwin/blenderplayer.app/Contents/MacOS/blenderplayer @@ -1 +1 @@ -placeholder +placeholder diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg index 08a7c92935f..fcade5b38c5 100644 --- a/release/datafiles/blender_icons.svg +++ b/release/datafiles/blender_icons.svg @@ -14,9 +14,9 @@ height="640" id="svg2" sodipodi:version="0.32" - inkscape:version="0.48.2 r9819" + inkscape:version="0.48.3.1 r9886" version="1.0" - sodipodi:docname="Blender ICONS - v.2.5.08.svg" + sodipodi:docname="blender_icons.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" style="display:inline;enable-background:new" inkscape:export-filename="/home/wolter/Documenten/Blender/icons/D:\Documents\Blender\icons\BF icons v.2.5.08a.png" @@ -22237,16 +22237,16 @@ objecttolerance="10000" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1" - inkscape:cx="537.93701" - inkscape:cy="319" + inkscape:zoom="2" + inkscape:cx="199.42005" + inkscape:cy="320.97898" inkscape:document-units="px" inkscape:current-layer="layer3" showgrid="false" - inkscape:window-width="1618" - inkscape:window-height="1028" - inkscape:window-x="54" - inkscape:window-y="-8" + inkscape:window-width="2560" + inkscape:window-height="1571" + inkscape:window-x="0" + inkscape:window-y="1" inkscape:snap-nodes="false" inkscape:snap-bbox="true" showguides="true" @@ -22335,7 +22335,7 @@ inkscape:groupmode="layer" id="layer3" inkscape:label="bckgrnd" - style="display:inline"> + style="display:none"> @@ -30190,7 +30190,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -30208,7 +30208,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -30242,7 +30242,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -30251,7 +30251,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -30265,7 +30265,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -30283,7 +30283,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -30296,7 +30296,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -30339,7 +30339,7 @@ inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png" transform="matrix(1.0911926,0,0,1.176776,253.08415,-79.548088)" - d="M 72,14.5 C 72,15.328427 71.328427,16 70.5,16 69.671573,16 69,15.328427 69,14.5 69,13.671573 69.671573,13 70.5,13 c 0.828427,0 1.5,0.671573 1.5,1.5 z" + d="m 72,14.5 a 1.5,1.5 0 1 1 -3,0 1.5,1.5 0 1 1 3,0 z" sodipodi:ry="1.5" sodipodi:rx="1.5" sodipodi:cy="14.5" @@ -30806,7 +30806,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -30831,7 +30831,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -30840,7 +30840,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -30892,7 +30892,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -30909,7 +30909,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -30982,7 +30982,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -30991,7 +30991,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -31011,7 +31011,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -31028,7 +31028,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -31099,7 +31099,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -31114,7 +31114,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -31131,7 +31131,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -31153,7 +31153,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -31162,7 +31162,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -31233,7 +31233,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 141.08637,118 c 0,5.0181 -4.06811,9.08607 -9.08637,9.08607 -5.01826,0 -9.08637,-4.06797 -9.08637,-9.08607 0,-5.0181 4.06811,-9.08607 9.08637,-9.08607 5.01826,0 9.08637,4.06797 9.08637,9.08607 z" + d="m 141.08637,118 a 9.0863705,9.0860729 0 1 1 -18.17274,0 9.0863705,9.0860729 0 1 1 18.17274,0 z" sodipodi:ry="9.0860729" sodipodi:rx="9.0863705" sodipodi:cy="118" @@ -31259,7 +31259,7 @@ sodipodi:cy="118" sodipodi:rx="9.0863705" sodipodi:ry="9.0860729" - d="m 141.08637,118 c 0,5.0181 -4.06811,9.08607 -9.08637,9.08607 -5.01826,0 -9.08637,-4.06797 -9.08637,-9.08607 0,-5.0181 4.06811,-9.08607 9.08637,-9.08607 5.01826,0 9.08637,4.06797 9.08637,9.08607 z" + d="m 141.08637,118 a 9.0863705,9.0860729 0 1 1 -18.17274,0 9.0863705,9.0860729 0 1 1 18.17274,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -31506,7 +31506,7 @@ sodipodi:cy="-222" sodipodi:rx="3.3084693" sodipodi:ry="1.2798798" - d="m 111.30847,-222 c 0,0.70686 -1.48125,1.27988 -3.30847,1.27988 -1.82722,0 -3.30847,-0.57302 -3.30847,-1.27988 0,-0.70686 1.48125,-1.27988 3.30847,-1.27988 1.82722,0 3.30847,0.57302 3.30847,1.27988 z" + d="m 111.30847,-222 a 3.3084693,1.2798798 0 1 1 -6.61694,0 3.3084693,1.2798798 0 1 1 6.61694,0 z" transform="matrix(1.0307577,0,0,0.9140456,39.651558,-39.251735)" /> @@ -32050,7 +32050,7 @@ inkscape:export-xdpi="90" inkscape:export-ydpi="90"> + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" /> @@ -32451,7 +32451,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -32562,7 +32562,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -32602,7 +32602,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -32641,7 +32641,7 @@ sodipodi:cy="119.5" sodipodi:rx="5.5" sodipodi:ry="5.5" - d="m 196,119.5 c 0,3.03757 -2.46243,5.5 -5.5,5.5 -3.03757,0 -5.5,-2.46243 -5.5,-5.5 0,-3.03757 2.46243,-5.5 5.5,-5.5 3.03757,0 5.5,2.46243 5.5,5.5 z" + d="m 196,119.5 a 5.5,5.5 0 1 1 -11,0 5.5,5.5 0 1 1 11,0 z" transform="matrix(0.61819,0,0,0.618186,73.23488,45.12681)" /> @@ -32660,7 +32660,7 @@ id="g24576"> @@ -32964,7 +32964,7 @@ sodipodi:cy="165" sodipodi:rx="1" sodipodi:ry="1" - d="m 148,165 c 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 0.55228,0 1,0.44772 1,1 z" + d="m 148,165 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" transform="matrix(1.5,0,0,1.5,-73.5,-83.5)" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" @@ -32983,7 +32983,7 @@ inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" transform="matrix(1.5,0,0,1.5,-66.5,-83.5)" - d="m 148,165 c 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 0.55228,0 1,0.44772 1,1 z" + d="m 148,165 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" sodipodi:ry="1" sodipodi:rx="1" sodipodi:cy="165" @@ -33024,7 +33024,7 @@ sodipodi:cy="78.5" sodipodi:rx="3.5" sodipodi:ry="3.5" - d="m 262,78.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" + d="m 262,78.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" transform="matrix(-1.4308622,0,0,1.4308687,469.36987,363.18486)" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" @@ -33052,7 +33052,7 @@ inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" transform="matrix(-1.4308622,0,0,1.4308687,469.36987,363.18486)" - d="m 262,78.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" + d="m 262,78.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" sodipodi:ry="3.5" sodipodi:rx="3.5" sodipodi:cy="78.5" @@ -33078,13 +33078,13 @@ sodipodi:cy="78.5" sodipodi:rx="3.5" sodipodi:ry="3.5" - d="m 262,78.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" + d="m 262,78.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" transform="matrix(-1.14287,0,0,1.142863,463.9317,115.7853)" /> @@ -33853,7 +33853,7 @@ sodipodi:cy="35.5" sodipodi:rx="3.5" sodipodi:ry="3.5" - d="m 334,35.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" + d="m 334,35.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" transform="matrix(1.000048,0,0,0.999998,-0.01591645,12.000064)" /> @@ -33897,7 +33897,7 @@ style="fill:none;stroke:#000000;stroke-width:0.80000001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.5;display:inline" /> @@ -34302,7 +34302,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -34320,7 +34320,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -34973,7 +34973,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -34999,7 +34999,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -35134,7 +35134,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -35142,7 +35142,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -35161,7 +35161,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -35170,7 +35170,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -36541,7 +36541,7 @@ sodipodi:cy="35.5" sodipodi:rx="2.7944512" sodipodi:ry="2.7944512" - d="m 333.29445,35.5 c 0,1.543333 -1.25112,2.794451 -2.79445,2.794451 -1.54333,0 -2.79445,-1.251118 -2.79445,-2.794451 0,-1.543333 1.25112,-2.794451 2.79445,-2.794451 1.54333,0 2.79445,1.251118 2.79445,2.794451 z" + d="m 333.29445,35.5 a 2.7944512,2.7944512 0 1 1 -5.5889,0 2.7944512,2.7944512 0 1 1 5.5889,0 z" transform="matrix(1.4256767,0,0,1.4314068,-320.1963,68.175135)" /> @@ -37248,7 +37248,7 @@ sodipodi:cy="502" sodipodi:rx="2.5312502" sodipodi:ry="2.5" - d="m 80.53125,502 c 0,1.38071 -1.133279,2.5 -2.53125,2.5 -1.397971,0 -2.53125,-1.11929 -2.53125,-2.5 0,-1.38071 1.133279,-2.5 2.53125,-2.5 1.397971,0 2.53125,1.11929 2.53125,2.5 z" + d="m 80.53125,502 a 2.5312502,2.5 0 1 1 -5.0625,0 2.5312502,2.5 0 1 1 5.0625,0 z" transform="matrix(0.7834486,0,0,0.2000006,10.413535,395.5997)" /> + d="m 446.5,108.5 a 3,3 0 1 1 -6,0 3,3 0 1 1 6,0 z" /> + d="m 440.514,108.7895 a 3,3 0 1 1 2.1568,2.59363" /> + d="m 446.5,108.5 a 3,3 0 1 1 -6,0 3,3 0 1 1 6,0 z" /> + d="m 446.5,108.5 a 3,3 0 1 1 -6,0 3,3 0 1 1 6,0 z" /> + d="m 446.5,108.5 a 3,3 0 1 1 -6,0 3,3 0 1 1 6,0 z" /> + d="m 446.5,108.5 a 3,3 0 1 1 -6,0 3,3 0 1 1 6,0 z" /> @@ -37864,7 +37864,7 @@ x="409" y="-41" /> + d="m 446.5,108.5 a 3,3 0 1 1 -6,0 3,3 0 1 1 6,0 z" /> + d="m 446.5,108.5 a 3,3 0 1 1 -6,0 3,3 0 1 1 6,0 z" /> + d="m 446.5,108.5 a 3,3 0 1 1 -6,0 3,3 0 1 1 6,0 z" /> @@ -38043,7 +38043,7 @@ x="409" y="-41" /> + d="m 446.5,108.5 a 3,3 0 1 1 -6,0 3,3 0 1 1 6,0 z" /> @@ -40261,7 +40261,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -40278,7 +40278,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -40287,7 +40287,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -41218,7 +41218,7 @@ inkscape:export-ydpi="90" transform="matrix(1.0004639,0,0,0.9963165,-69.122722,304.28985)"> @@ -42555,7 +42555,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -42583,7 +42583,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -42592,7 +42592,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -43071,11 +43071,11 @@ sodipodi:cy="-23" sodipodi:rx="1" sodipodi:ry="1" - d="m 134,-23 c 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 0.55228,0 1,0.447715 1,1 z" + d="m 134,-23 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" transform="translate(0.5,-0.46875)" /> @@ -43351,7 +43351,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -43364,7 +43364,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -44093,7 +44093,7 @@ @@ -46083,7 +46083,7 @@ sodipodi:cy="502" sodipodi:rx="2.5312502" sodipodi:ry="2.5" - d="m 80.53125,502 c 0,1.38071 -1.133279,2.5 -2.53125,2.5 -1.397971,0 -2.53125,-1.11929 -2.53125,-2.5 0,-1.38071 1.133279,-2.5 2.53125,-2.5 1.397971,0 2.53125,1.11929 2.53125,2.5 z" + d="m 80.53125,502 a 2.5312502,2.5 0 1 1 -5.0625,0 2.5312502,2.5 0 1 1 5.0625,0 z" transform="matrix(0.9552133,0,0,0.9315985,-40.901258,-140.2522)" /> @@ -46739,9 +46739,9 @@ sodipodi:cy="79.5" sodipodi:rx="3.5" sodipodi:ry="3.5" - d="m 211,79.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" /> + d="m 211,79.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" /> @@ -47299,7 +47299,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -48171,13 +48171,13 @@ sodipodi:cy="554" sodipodi:rx="4.5" sodipodi:ry="2.25" - d="m 57.5,554 c 0,1.24264 -2.014719,2.25 -4.5,2.25 -2.485281,0 -4.5,-1.00736 -4.5,-2.25 0,-1.24264 2.014719,-2.25 4.5,-2.25 2.485281,0 4.5,1.00736 4.5,2.25 z" + d="m 57.5,554 a 4.5,2.25 0 1 1 -9,0 4.5,2.25 0 1 1 9,0 z" transform="matrix(0.7630859,-0.2494396,0.2996015,0.9926766,-151.92281,17.77746)" /> + d="m 434.99991,14.5 a 3.9999149,2.91429 0 1 1 -7.99982,0 3.9999149,2.91429 0 1 1 7.99982,0 z" /> + d="m 65,135 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" /> + d="m 65,135 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" /> @@ -49278,7 +49278,7 @@ id="g28085"> @@ -49861,13 +49861,13 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" transform="matrix(0.787566,0,0,0.779223,26.709197,21.3179)" /> + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" /> @@ -51526,7 +51526,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -51543,7 +51543,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -51557,7 +51557,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -51768,13 +51768,13 @@ sodipodi:cy="78.5" sodipodi:rx="3.5" sodipodi:ry="3.5" - d="m 262,78.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" + d="m 262,78.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" transform="matrix(-1.14287,0,0,1.142863,463.9317,115.80133)" /> + d="m 65,135 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" /> @@ -52079,7 +52079,7 @@ sodipodi:cy="78.5" sodipodi:rx="3.5" sodipodi:ry="3.5" - d="m 262,78.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" + d="m 262,78.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" transform="matrix(-1.5000024,0,0,1.4990511,528.75064,424.32781)" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" @@ -52113,7 +52113,7 @@ sodipodi:cy="78.5" sodipodi:rx="3.5" sodipodi:ry="3.5" - d="m 262,78.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" + d="m 262,78.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" transform="matrix(-1.5714299,0,0,1.5714268,505.21462,331.643)" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" @@ -52152,13 +52152,13 @@ sodipodi:cy="78.5" sodipodi:rx="3.5" sodipodi:ry="3.5" - d="m 262,78.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" + d="m 262,78.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" transform="matrix(-1.14287,0,0,1.142863,463.9317,115.7853)" /> @@ -52353,7 +52353,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -52365,7 +52365,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -52409,7 +52409,7 @@ sodipodi:cy="78.5" sodipodi:rx="3.5" sodipodi:ry="3.5" - d="m 262,78.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" + d="m 262,78.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" transform="matrix(-1.5714299,0,0,1.5714268,505.21462,331.643)" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" @@ -52448,13 +52448,13 @@ sodipodi:cy="78.5" sodipodi:rx="3.5" sodipodi:ry="3.5" - d="m 262,78.5 c 0,1.932997 -1.567,3.5 -3.5,3.5 -1.933,0 -3.5,-1.567003 -3.5,-3.5 0,-1.932997 1.567,-3.5 3.5,-3.5 1.933,0 3.5,1.567003 3.5,3.5 z" + d="m 262,78.5 a 3.5,3.5 0 1 1 -7,0 3.5,3.5 0 1 1 7,0 z" transform="matrix(-1.14287,0,0,1.142863,463.9317,115.7853)" /> @@ -52751,7 +52751,7 @@ style="display:inline"> @@ -52999,7 +52999,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -53018,7 +53018,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -53036,7 +53036,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -53705,7 +53705,7 @@ id="g36930"> + d="m 266.5,330.5 a 2,2 0 1 1 -4,0 2,2 0 1 1 4,0 z" /> + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" /> @@ -54769,7 +54769,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -54785,7 +54785,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -54803,7 +54803,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -54819,7 +54819,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -54837,7 +54837,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -54851,7 +54851,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -54866,7 +54866,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -54884,7 +54884,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -55007,7 +55007,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -55016,7 +55016,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -55033,7 +55033,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -55155,7 +55155,7 @@ style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.69999999;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> @@ -55497,7 +55497,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -55592,7 +55592,7 @@ sodipodi:cy="40.5" sodipodi:rx="6.5" sodipodi:ry="2.5" - d="m -213.5,40.5 c 0,1.380712 -2.91015,2.5 -6.5,2.5 -3.58985,0 -6.5,-1.119288 -6.5,-2.5 0,-1.380712 2.91015,-2.5 6.5,-2.5 3.58985,0 6.5,1.119288 6.5,2.5 z" + d="m -213.5,40.5 a 6.5,2.5 0 1 1 -13,0 6.5,2.5 0 1 1 13,0 z" transform="matrix(0.9999986,0,0,1.799999,-2.971883e-4,111.10004)" /> @@ -56010,7 +56010,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -56091,7 +56091,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -56108,7 +56108,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -56122,7 +56122,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -56130,7 +56130,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -56216,7 +56216,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -56224,7 +56224,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -56803,7 +56803,7 @@ inkscape:connector-curvature="0" /> @@ -57050,7 +57050,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57058,7 +57058,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57076,7 +57076,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57089,7 +57089,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57149,7 +57149,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57167,7 +57167,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57175,7 +57175,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57188,7 +57188,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57255,7 +57255,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57263,7 +57263,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57281,7 +57281,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57294,7 +57294,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57346,7 +57346,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57354,7 +57354,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57372,7 +57372,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57385,7 +57385,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57402,7 +57402,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57419,7 +57419,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -57433,7 +57433,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57456,7 +57456,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57464,7 +57464,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57482,7 +57482,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57495,7 +57495,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57705,7 +57705,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57713,7 +57713,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57731,7 +57731,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57779,7 +57779,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57797,7 +57797,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57805,7 +57805,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57827,7 +57827,7 @@ sodipodi:cy="292.5" sodipodi:rx="4" sodipodi:ry="4" - d="m 223.5,292.5 c 0,2.20914 -1.79086,4 -4,4 -2.20914,0 -4,-1.79086 -4,-4 0,-2.20914 1.79086,-4 4,-4 2.20914,0 4,1.79086 4,4 z" + d="m 223.5,292.5 a 4,4 0 1 1 -8,0 4,4 0 1 1 8,0 z" transform="translate(20,0)" /> @@ -57906,7 +57906,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57964,7 +57964,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -57972,7 +57972,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -57990,7 +57990,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -58001,7 +58001,7 @@ style="opacity:0.9;display:inline;enable-background:new"> @@ -58061,11 +58061,11 @@ sodipodi:cy="192.5" sodipodi:rx="1.75" sodipodi:ry="1.75" - d="m 466.25,192.5 c 0,0.9665 -0.7835,1.75 -1.75,1.75 -0.9665,0 -1.75,-0.7835 -1.75,-1.75 0,-0.9665 0.7835,-1.75 1.75,-1.75 0.9665,0 1.75,0.7835 1.75,1.75 z" + d="m 466.25,192.5 a 1.75,1.75 0 1 1 -3.5,0 1.75,1.75 0 1 1 3.5,0 z" transform="matrix(1.7142856,0,0,1.7142871,-330.83199,-136.46043)" /> @@ -58136,7 +58136,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -58144,7 +58144,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -58184,7 +58184,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -58193,7 +58193,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -58205,7 +58205,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -58398,7 +58398,7 @@ sodipodi:cy="14.5" sodipodi:rx="1.5" sodipodi:ry="1.5" - d="M 72,14.5 C 72,15.328427 71.328427,16 70.5,16 69.671573,16 69,15.328427 69,14.5 69,13.671573 69.671573,13 70.5,13 c 0.828427,0 1.5,0.671573 1.5,1.5 z" + d="m 72,14.5 a 1.5,1.5 0 1 1 -3,0 1.5,1.5 0 1 1 3,0 z" transform="matrix(1.3333333,0,0,1.3333343,3,147.66665)" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" @@ -58412,7 +58412,7 @@ sodipodi:cy="14.5" sodipodi:rx="1.5" sodipodi:ry="1.5" - d="M 72,14.5 C 72,15.328427 71.328427,16 70.5,16 69.671573,16 69,15.328427 69,14.5 69,13.671573 69.671573,13 70.5,13 c 0.828427,0 1.5,0.671573 1.5,1.5 z" + d="m 72,14.5 a 1.5,1.5 0 1 1 -3,0 1.5,1.5 0 1 1 3,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -58505,7 +58505,7 @@ sodipodi:end="6.2810509" sodipodi:start="0" transform="matrix(1.2491741,-1.2491602,0.7680871,0.768079,-75.108556,239.34027)" - d="m 182.21113,35 c 0,2.758732 -0.54224,4.995127 -1.21113,4.995127 -0.66889,0 -1.21113,-2.236395 -1.21113,-4.995127 0,-2.758732 0.54224,-4.995127 1.21113,-4.995127 0.66788,0 1.20971,2.229902 1.21113,4.984465" + d="m 182.21113,35 a 1.2111344,4.9951267 0 1 1 0,-0.01066" sodipodi:ry="4.9951267" sodipodi:rx="1.2111344" sodipodi:cy="35" @@ -58521,7 +58521,7 @@ sodipodi:cy="35" sodipodi:rx="1.1763829" sodipodi:ry="5.5293522" - d="m 182.17638,35 c 0,3.053777 -0.52668,5.529352 -1.17638,5.529352 -0.6497,0 -1.17638,-2.475575 -1.17638,-5.529352 0,-3.053777 0.52668,-5.529352 1.17638,-5.529352 0.6497,0 1.17638,2.475575 1.17638,5.529352 z" + d="m 182.17638,35 a 1.1763829,5.5293522 0 1 1 -2.35276,0 1.1763829,5.5293522 0 1 1 2.35276,0 z" transform="matrix(0.9589476,-0.9192618,0.5776079,0.5780619,-15.42366,185.77921)" /> @@ -58932,7 +58932,7 @@ id="g35449"> @@ -59950,7 +59950,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -60109,7 +60109,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -60122,7 +60122,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -60170,7 +60170,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -60190,9 +60190,9 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" /> + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" /> @@ -60242,7 +60242,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" /> + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" /> @@ -60900,7 +60900,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -60950,7 +60950,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -60982,7 +60982,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -61332,7 +61332,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -61352,7 +61352,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -61365,7 +61365,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -61379,7 +61379,7 @@ id="g36537"> @@ -61773,7 +61773,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -61781,7 +61781,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -63691,7 +63691,7 @@ @@ -63729,7 +63729,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -63859,7 +63859,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -63876,14 +63876,14 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" transform="matrix(-0.683022,-0.07745026,0.0778507,-0.683064,209.4726,314.325)" /> + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" /> @@ -65294,7 +65294,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -65362,7 +65362,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -65378,7 +65378,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -66073,13 +66073,13 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" transform="matrix(0.787566,0,0,0.779223,26.709197,21.3179)" /> + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" /> @@ -68115,13 +68115,13 @@ sodipodi:cy="554" sodipodi:rx="4.5" sodipodi:ry="2.25" - d="m 57.5,554 c 0,1.24264 -2.014719,2.25 -4.5,2.25 -2.485281,0 -4.5,-1.00736 -4.5,-2.25 0,-1.24264 2.014719,-2.25 4.5,-2.25 2.485281,0 4.5,1.00736 4.5,2.25 z" + d="m 57.5,554 a 4.5,2.25 0 1 1 -9,0 4.5,2.25 0 1 1 9,0 z" transform="matrix(0.7630859,-0.2494396,0.2996015,0.9926766,-151.92281,17.77746)" /> @@ -68300,7 +68300,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -68334,7 +68334,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -68454,7 +68454,7 @@ transform="matrix(0.5406242,0,0,0.5829534,814.13667,247.65542)"> + d="m 923,342 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z" /> @@ -69643,7 +69643,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -69655,7 +69655,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -70879,7 +70879,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -70888,7 +70888,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -70907,7 +70907,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" transform="matrix(0.5705005,0,0,0.5705012,51.746079,156.18087)" /> @@ -71015,7 +71015,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -71023,7 +71023,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -71036,7 +71036,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -71257,7 +71257,7 @@ sodipodi:end="1.5729572" sodipodi:start="0" transform="matrix(-2.421633,0,0,-2.417581,92.2682,-69.13182)" - d="m 54,-32.5 c 0,2.485281 -2.014719,4.5 -4.5,4.5 -0.0032,0 -0.0065,-4e-6 -0.0097,-1.1e-5" + d="m 54,-32.5 a 4.5,4.5 0 0 1 -4.509724,4.499989" sodipodi:ry="4.5" sodipodi:rx="4.5" sodipodi:cy="-32.5" @@ -71276,7 +71276,7 @@ sodipodi:cy="-32.5" sodipodi:rx="4.5" sodipodi:ry="4.5" - d="m 54,-32.5 c 0,2.485281 -2.014719,4.5 -4.5,4.5 -0.0032,0 -0.0065,-4e-6 -0.0097,-1.1e-5" + d="m 54,-32.5 a 4.5,4.5 0 0 1 -4.509724,4.499989" transform="matrix(-2.421633,0,0,-2.417581,92.2682,-69.13182)" sodipodi:start="0" sodipodi:end="1.5729572" @@ -71293,7 +71293,7 @@ sodipodi:end="1.5729572" sodipodi:start="0" transform="matrix(-2.421633,0,0,-2.417581,92.2682,-69.13182)" - d="m 54,-32.5 c 0,2.485281 -2.014719,4.5 -4.5,4.5 -0.0032,0 -0.0065,-4e-6 -0.0097,-1.1e-5" + d="m 54,-32.5 a 4.5,4.5 0 0 1 -4.509724,4.499989" sodipodi:ry="4.5" sodipodi:rx="4.5" sodipodi:cy="-32.5" @@ -71312,7 +71312,7 @@ sodipodi:cy="-32.5" sodipodi:rx="4.5" sodipodi:ry="4.5" - d="m 54,-32.5 c 0,2.485281 -2.014719,4.5 -4.5,4.5 -0.0032,0 -0.0065,-4e-6 -0.0097,-1.1e-5" + d="m 54,-32.5 a 4.5,4.5 0 0 1 -4.509724,4.499989" transform="matrix(-2.587958,0,0,-2.597682,100.48861,-75.018268)" sodipodi:start="0" sodipodi:end="1.5729572" @@ -71885,7 +71885,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -71899,7 +71899,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -71989,7 +71989,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -72025,7 +72025,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -72051,7 +72051,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -72231,7 +72231,7 @@ @@ -73243,7 +73243,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -73257,7 +73257,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -73415,7 +73415,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -73423,7 +73423,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -73437,7 +73437,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -73571,7 +73571,7 @@ sodipodi:cy="420.25" sodipodi:rx="2.5" sodipodi:ry="1.75" - d="m 751.5,420.25 c 0,0.9665 -1.11929,1.75 -2.5,1.75 -1.38071,0 -2.5,-0.7835 -2.5,-1.75 0,-0.9665 1.11929,-1.75 2.5,-1.75 1.38071,0 2.5,0.7835 2.5,1.75 z" + d="m 751.5,420.25 a 2.5,1.75 0 1 1 -5,0 2.5,1.75 0 1 1 5,0 z" transform="matrix(1,0,0,0.8571429,-212,-302.2143)" /> @@ -74347,7 +74347,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74366,7 +74366,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74384,7 +74384,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -74400,7 +74400,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74418,7 +74418,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -74433,7 +74433,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74452,7 +74452,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -74469,7 +74469,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -74477,7 +74477,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74507,7 +74507,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74526,7 +74526,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74544,7 +74544,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -74560,7 +74560,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74578,7 +74578,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -74593,7 +74593,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74612,7 +74612,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -74629,7 +74629,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -74637,7 +74637,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74667,7 +74667,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74686,7 +74686,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74704,7 +74704,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -74720,7 +74720,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74738,7 +74738,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -74753,7 +74753,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74772,7 +74772,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 132,110 c 2.85812,0 5.49914,1.52479 6.9282,4 L 132,118 z" + d="m 132,110 a 8,8 0 0 1 6.9282,4 L 132,118 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" @@ -74789,7 +74789,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -74797,7 +74797,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74825,7 +74825,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -74833,7 +74833,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -74851,7 +74851,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -74864,7 +74864,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -74872,7 +74872,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\Kopia blender\.blender\icons\blender's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -75991,7 +75991,7 @@ inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png" transform="matrix(1.3333333,0,0,1.3333343,3,147.66665)" - d="M 72,14.5 C 72,15.328427 71.328427,16 70.5,16 69.671573,16 69,15.328427 69,14.5 69,13.671573 69.671573,13 70.5,13 c 0.828427,0 1.5,0.671573 1.5,1.5 z" + d="m 72,14.5 a 1.5,1.5 0 1 1 -3,0 1.5,1.5 0 1 1 3,0 z" sodipodi:ry="1.5" sodipodi:rx="1.5" sodipodi:cy="14.5" @@ -76003,7 +76003,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png" - d="M 72,14.5 C 72,15.328427 71.328427,16 70.5,16 69.671573,16 69,15.328427 69,14.5 69,13.671573 69.671573,13 70.5,13 c 0.828427,0 1.5,0.671573 1.5,1.5 z" + d="m 72,14.5 a 1.5,1.5 0 1 1 -3,0 1.5,1.5 0 1 1 3,0 z" sodipodi:ry="1.5" sodipodi:rx="1.5" sodipodi:cy="14.5" @@ -76190,7 +76190,7 @@ sodipodi:cy="14.5" sodipodi:rx="1.5" sodipodi:ry="1.5" - d="M 72,14.5 C 72,15.328427 71.328427,16 70.5,16 69.671573,16 69,15.328427 69,14.5 69,13.671573 69.671573,13 70.5,13 c 0.828427,0 1.5,0.671573 1.5,1.5 z" + d="m 72,14.5 a 1.5,1.5 0 1 1 -3,0 1.5,1.5 0 1 1 3,0 z" transform="matrix(1.3333333,0,0,1.3333343,170.99998,105.66665)" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" @@ -76204,7 +76204,7 @@ sodipodi:cy="14.5" sodipodi:rx="1.5" sodipodi:ry="1.5" - d="M 72,14.5 C 72,15.328427 71.328427,16 70.5,16 69.671573,16 69,15.328427 69,14.5 69,13.671573 69.671573,13 70.5,13 c 0.828427,0 1.5,0.671573 1.5,1.5 z" + d="m 72,14.5 a 1.5,1.5 0 1 1 -3,0 1.5,1.5 0 1 1 3,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -76381,7 +76381,7 @@ sodipodi:cy="14.5" sodipodi:rx="1.5" sodipodi:ry="1.5" - d="M 72,14.5 C 72,15.328427 71.328427,16 70.5,16 69.671573,16 69,15.328427 69,14.5 69,13.671573 69.671573,13 70.5,13 c 0.828427,0 1.5,0.671573 1.5,1.5 z" + d="m 72,14.5 a 1.5,1.5 0 1 1 -3,0 1.5,1.5 0 1 1 3,0 z" transform="matrix(1.3333333,0,0,1.3333343,209.98999,105.66665)" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" @@ -76395,7 +76395,7 @@ sodipodi:cy="14.5" sodipodi:rx="1.5" sodipodi:ry="1.5" - d="M 72,14.5 C 72,15.328427 71.328427,16 70.5,16 69.671573,16 69,15.328427 69,14.5 69,13.671573 69.671573,13 70.5,13 c 0.828427,0 1.5,0.671573 1.5,1.5 z" + d="m 72,14.5 a 1.5,1.5 0 1 1 -3,0 1.5,1.5 0 1 1 3,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\Kopia blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -78022,7 +78022,7 @@ height="16" width="16" id="rect22783-6-9" - style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;opacity:0" /> + style="opacity:0;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> @@ -78153,7 +78153,7 @@ height="16" width="16" id="rect22783-6" - style="fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;opacity:0" /> + style="opacity:0;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:6;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> + style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:url(#linearGradient30129);fill-opacity:1;stroke:none;stroke-width:2.5999999;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" + d="m 48.25,351.96875 a 1.30013,1.30013 0 0 0 -1.03125,1.0625 c -0.560356,3.27054 0.822741,6.58876 3.4375,8.5625 a 1.3062537,1.3062537 0 0 0 1.5625,-0.0312 A 0.50389111,0.50389111 0 0 1 51.9375,361.5 c -3.258538,-1.90713 -4.860221,-5.92414 -3.625,-9.53125 a 1.30013,1.30013 0 0 0 -0.0625,0 z m 1.03125,0.21875 c -1.14015,3.1617 0.271743,6.74928 3.15625,8.4375 a 0.50389111,0.50389111 0 0 1 0.25,0.3125 1.3062537,1.3062537 0 0 0 -0.46875,-1.4375 c -1.845415,-1.393 -2.825384,-3.76735 -2.4375,-6.03125 a 1.30013,1.30013 0 0 0 -0.5,-1.28125 z" + id="path30105" + inkscape:connector-curvature="0" /> + @@ -78312,7 +78334,7 @@ sodipodi:cy="118" sodipodi:rx="8" sodipodi:ry="8" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> @@ -78320,7 +78342,7 @@ inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="C:\Documents and Settings\Tata\Pulpit\BLENDER ICONSET\blender-cvs-windows\.blender\.blender\icons\jendrzych's iconset.png" - d="m 140,118 c 0,4.41828 -3.58172,8 -8,8 -4.41828,0 -8,-3.58172 -8,-8 0,-4.41828 3.58172,-8 8,-8 4.41828,0 8,3.58172 8,8 z" + d="m 140,118 a 8,8 0 1 1 -16,0 8,8 0 1 1 16,0 z" sodipodi:ry="8" sodipodi:rx="8" sodipodi:cy="118" @@ -78564,7 +78586,7 @@ id="path32864" inkscape:connector-curvature="0" /> +# __all__ = ( "bake_action", @@ -52,7 +52,7 @@ def bake_action(frame_start, :type do_pose: bool :arg do_object: Bake objects. :type do_object: bool - :arg do_constraint_clear: Remove constraints. + :arg do_constraint_clear: Remove constraints (and do 'visual keying'). :type do_constraint_clear: bool :arg do_clean: Remove redundant keyframes after baking. :type do_clean: bool @@ -65,61 +65,20 @@ def bake_action(frame_start, """ # ------------------------------------------------------------------------- - # Helper Functions + # Helper Functions and vars - def pose_frame_info(obj): - from mathutils import Matrix + def pose_frame_info(obj, do_visual_keying): + matrix = {} + for name, pbone in obj.pose.bones.items(): + if do_visual_keying: + # Get the final transform of the bone in its own local space... + matrix[name] = obj.convert_space(pbone, pbone.matrix, 'POSE', 'LOCAL') + else: + matrix[name] = pbone.matrix_basis.copy() + return matrix - info = {} - - pose = obj.pose - - pose_items = pose.bones.items() - - for name, pbone in pose_items: - binfo = {} - bone = pbone.bone - - binfo["parent"] = getattr(bone.parent, "name", None) - binfo["bone"] = bone - binfo["pbone"] = pbone - binfo["matrix_local"] = bone.matrix_local.copy() - try: - binfo["matrix_local_inv"] = binfo["matrix_local"].inverted() - except: - binfo["matrix_local_inv"] = Matrix() - - binfo["matrix"] = bone.matrix.copy() - binfo["matrix_pose"] = pbone.matrix.copy() - try: - binfo["matrix_pose_inv"] = binfo["matrix_pose"].inverted() - except: - binfo["matrix_pose_inv"] = Matrix() - - info[name] = binfo - - for name, pbone in pose_items: - binfo = info[name] - binfo_parent = binfo.get("parent", None) - if binfo_parent: - binfo_parent = info[binfo_parent] - - matrix = binfo["matrix_pose"] - rest_matrix = binfo["matrix_local"] - - if binfo_parent: - matrix = binfo_parent["matrix_pose_inv"] * matrix - rest_matrix = binfo_parent["matrix_local_inv"] * rest_matrix - - binfo["matrix_key"] = rest_matrix.inverted() * matrix - - return info - - def obj_frame_info(obj): - info = {} - # parent = obj.parent - info["matrix_key"] = obj.matrix_local.copy() - return info + def obj_frame_info(obj, do_visual_keying): + return obj.matrix_local.copy() if do_visual_keying else obj.matrix_basis.copy() # ------------------------------------------------------------------------- # Setup the Context @@ -127,33 +86,30 @@ def bake_action(frame_start, # TODO, pass data rather then grabbing from the context! scene = bpy.context.scene obj = bpy.context.object - pose = obj.pose frame_back = scene.frame_current - if pose is None: + if obj.pose is None: do_pose = False - if do_pose is None and do_object is None: + if not (do_pose or do_object): return None pose_info = [] obj_info = [] + options = {'INSERTKEY_NEEDED'} + frame_range = range(frame_start, frame_end + 1, frame_step) # ------------------------------------------------------------------------- # Collect transformations - # could speed this up by applying steps here too... for f in frame_range: scene.frame_set(f) - if do_pose: - pose_info.append(pose_frame_info(obj)) + pose_info.append(pose_frame_info(obj, do_constraint_clear)) if do_object: - obj_info.append(obj_frame_info(obj)) - - f += 1 + obj_info.append(obj_frame_info(obj, do_constraint_clear)) # ------------------------------------------------------------------------- # Create action @@ -164,57 +120,44 @@ def bake_action(frame_start, action = bpy.data.actions.new("Action") atd.action = action - if do_pose: - pose_items = pose.bones.items() - else: - pose_items = [] # skip - # ------------------------------------------------------------------------- # Apply transformations to action # pose - for name, pbone in (pose_items if do_pose else ()): - if only_selected and not pbone.bone.select: - continue + if do_pose: + for name, pbone in obj.pose.bones.items(): + if only_selected and not pbone.bone.select: + continue - if do_constraint_clear: - while pbone.constraints: - pbone.constraints.remove(pbone.constraints[0]) + if do_constraint_clear: + while pbone.constraints: + pbone.constraints.remove(pbone.constraints[0]) - # create compatible eulers - euler_prev = None + # create compatible eulers + euler_prev = None - for f in frame_range: - f_step = (f - frame_start) // frame_step - matrix = pose_info[f_step][name]["matrix_key"] + for (f, matrix) in zip(frame_range, pose_info): + pbone.matrix_basis = matrix[name].copy() - # pbone.location = matrix.to_translation() - # pbone.rotation_quaternion = matrix.to_quaternion() - pbone.matrix_basis = matrix + pbone.keyframe_insert("location", -1, f, name, options) - pbone.keyframe_insert("location", -1, f, name) + rotation_mode = pbone.rotation_mode + if rotation_mode == 'QUATERNION': + pbone.keyframe_insert("rotation_quaternion", -1, f, name, options) + elif rotation_mode == 'AXIS_ANGLE': + pbone.keyframe_insert("rotation_axis_angle", -1, f, name, options) + else: # euler, XYZ, ZXY etc + if euler_prev is not None: + euler = pbone.rotation_euler.copy() + euler.make_compatible(euler_prev) + pbone.rotation_euler = euler + euler_prev = euler + del euler + else: + euler_prev = pbone.rotation_euler.copy() + pbone.keyframe_insert("rotation_euler", -1, f, name, options) - rotation_mode = pbone.rotation_mode - - if rotation_mode == 'QUATERNION': - pbone.keyframe_insert("rotation_quaternion", -1, f, name) - elif rotation_mode == 'AXIS_ANGLE': - pbone.keyframe_insert("rotation_axis_angle", -1, f, name) - else: # euler, XYZ, ZXY etc - - if euler_prev is not None: - euler = pbone.rotation_euler.copy() - euler.make_compatible(euler_prev) - pbone.rotation_euler = euler - euler_prev = euler - del euler - - pbone.keyframe_insert("rotation_euler", -1, f, name) - - if euler_prev is None: - euler_prev = pbone.rotation_euler.copy() - - pbone.keyframe_insert("scale", -1, f, name) + pbone.keyframe_insert("scale", -1, f, name, options) # object. TODO. multiple objects if do_object: @@ -225,18 +168,16 @@ def bake_action(frame_start, # create compatible eulers euler_prev = None - for f in frame_range: - matrix = obj_info[(f - frame_start) // frame_step]["matrix_key"] - obj.matrix_local = matrix + for (f, matrix) in zip(frame_range, obj_info): + obj.matrix_basis = matrix[name] - obj.keyframe_insert("location", -1, f) + obj.keyframe_insert("location", -1, f, options) rotation_mode = obj.rotation_mode - if rotation_mode == 'QUATERNION': - obj.keyframe_insert("rotation_quaternion", -1, f) + obj.keyframe_insert("rotation_quaternion", -1, f, options) elif rotation_mode == 'AXIS_ANGLE': - obj.keyframe_insert("rotation_axis_angle", -1, f) + obj.keyframe_insert("rotation_axis_angle", -1, f, options) else: # euler, XYZ, ZXY etc if euler_prev is not None: euler = obj.rotation_euler.copy() @@ -244,15 +185,11 @@ def bake_action(frame_start, obj.rotation_euler = euler euler_prev = euler del euler - - obj.keyframe_insert("rotation_euler", -1, f) - - if euler_prev is None: + else: euler_prev = obj.rotation_euler.copy() + obj.keyframe_insert("rotation_euler", -1, f, options) - obj.keyframe_insert("scale", -1, f) - - scene.frame_set(frame_back) + obj.keyframe_insert("scale", -1, f, options) # ------------------------------------------------------------------------- # Clean @@ -271,4 +208,6 @@ def bake_action(frame_start, else: i += 1 + scene.frame_set(frame_back) + return action diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 46731b807f7..4e1385cff80 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -26,7 +26,6 @@ __all__ = ( import bpy -import mathutils from bpy.props import BoolProperty, FloatVectorProperty @@ -80,7 +79,7 @@ def add_object_align_init(context, operator): rotation = space_data.region_3d.view_matrix.to_3x3().inverted() rotation.resize_4x4() else: - rotation = mathutils.Matrix() + rotation = Matrix() # set the operator properties if operator: diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 11e1115fa4c..1c861aa3be2 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -673,6 +673,10 @@ class Panel(StructRNA, _GenericUI, metaclass=RNAMeta): __slots__ = () +class UIList(StructRNA, _GenericUI, metaclass=RNAMeta): + __slots__ = () + + class Header(StructRNA, _GenericUI, metaclass=RNAMeta): __slots__ = () diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py index 897dd24e174..c12b0b00f54 100644 --- a/release/scripts/startup/bl_operators/__init__.py +++ b/release/scripts/startup/bl_operators/__init__.py @@ -47,7 +47,7 @@ _modules = [ import bpy -if 'FREESTYLE' in bpy.app.build_options: +if bpy.app.build_options.freestyle: _modules.append("freestyle") __import__(name=__name__, fromlist=_modules) _namespace = globals() diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index 552247f0940..63e796e2b5d 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -19,7 +19,6 @@ # import bpy from bpy.types import Operator -import mathutils from bpy.props import (FloatProperty, IntProperty, @@ -31,9 +30,7 @@ from bpy_extras import object_utils def add_torus(major_rad, minor_rad, major_seg, minor_seg): from math import cos, sin, pi - - Vector = mathutils.Vector - Quaternion = mathutils.Quaternion + from mathutils import Vector, Quaternion PI_2 = pi * 2.0 z_axis = 0.0, 0.0, 1.0 diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py index 902c7007fb9..e34e9a981a6 100644 --- a/release/scripts/startup/bl_operators/anim.py +++ b/release/scripts/startup/bl_operators/anim.py @@ -187,17 +187,20 @@ class BakeAction(Operator): ) only_selected = BoolProperty( name="Only Selected", + description="Only key selected object/bones", default=True, ) clear_constraints = BoolProperty( name="Clear Constraints", + description="Remove all constraints from keyed object/bones, and do 'visual' keying", default=False, ) bake_types = EnumProperty( name="Bake Data", + description="Which data's transformations to bake", options={'ENUM_FLAG'}, - items=(('POSE', "Pose", ""), - ('OBJECT', "Object", ""), + items=(('POSE', "Pose", "Bake bones transformations"), + ('OBJECT', "Object", "Bake object transformations"), ), default={'POSE'}, ) @@ -208,12 +211,12 @@ class BakeAction(Operator): action = anim_utils.bake_action(self.frame_start, self.frame_end, - self.step, - self.only_selected, - 'POSE' in self.bake_types, - 'OBJECT' in self.bake_types, - self.clear_constraints, - True, + frame_step=self.step, + only_selected=self.only_selected, + do_pose='POSE' in self.bake_types, + do_object='OBJECT' in self.bake_types, + do_constraint_clear=self.clear_constraints, + do_clean=True, ) if action is None: diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py index 071eb2e75f9..39e00f94953 100644 --- a/release/scripts/startup/bl_operators/node.py +++ b/release/scripts/startup/bl_operators/node.py @@ -20,7 +20,7 @@ import bpy from bpy.types import Operator -from bpy.props import EnumProperty, StringProperty +from bpy.props import BoolProperty, EnumProperty, StringProperty # Base class for node 'Add' operators class NodeAddOperator(): @@ -75,6 +75,11 @@ class NODE_OT_add_node(NodeAddOperator, Operator): name="Group tree", description="Group node tree name", ) + use_transform = BoolProperty( + name="Use Transform", + description="Start transform operator after inserting the node", + default = False, + ) def execute(self, context): node = self.create_node(context, self.type) @@ -84,27 +89,13 @@ class NODE_OT_add_node(NodeAddOperator, Operator): return {'FINISHED'} - -# Adds a node and immediately starts the transform operator for inserting in a tree -class NODE_OT_add_node_move(NODE_OT_add_node): - '''Add a node to the active tree and start transform''' - bl_idname = "node.add_node_move" - bl_label = "Add Node and Move" - - type = StringProperty( - name="Node Type", - description="Node type", - ) - # optional group tree parameter for group nodes - group_tree = StringProperty( - name="Group tree", - description="Group node tree name", - ) - def invoke(self, context, event): self.store_mouse_cursor(context, event) - self.execute(context) - return bpy.ops.transform.translate('INVOKE_DEFAULT') + result = self.execute(context) + if self.use_transform and ('FINISHED' in result): + return bpy.ops.transform.translate('INVOKE_DEFAULT') + else: + return result # XXX These node item lists should actually be generated by a callback at diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py index 727c4ad739f..d870ef963ea 100644 --- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py +++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py @@ -26,6 +26,7 @@ from bpy.types import Operator def extend(obj, operator, EXTEND_MODE): + import bmesh me = obj.data # script will fail without UVs @@ -46,12 +47,12 @@ def extend(obj, operator, EXTEND_MODE): faces = [f for f in bm.faces if f.select and len(f.verts) == 4] - for f in faces: - f.tag = False - f_act.tag = True - - # our own local walker + def walk_face_init(faces, f_act): + for f in faces: + f.tag = False + f_act.tag = True + def walk_face(f): # all faces in this list must be tagged f.tag = True @@ -73,6 +74,30 @@ def extend(obj, operator, EXTEND_MODE): faces_a, faces_b = faces_b, faces_a faces_b.clear() + def walk_edgeloop(l): + """ + Could make this a generic function + """ + e_first = l.edge + e = None + while True: + e = l.edge + yield e + + # don't step past non-manifold edges + if e.is_manifold: + # welk around the quad and then onto the next face + l = l.link_loop_radial_next + if len(l.face.verts) == 4: + l = l.link_loop_next.link_loop_next + if l.edge is e_first: + break + else: + break + else: + break + + def extrapolate_uv(fac, l_a_outer, l_a_inner, l_b_outer, l_b_inner): @@ -119,7 +144,9 @@ def extend(obj, operator, EXTEND_MODE): l_a_uv = [l[uv_act].uv for l in l_a] l_b_uv = [l[uv_act].uv for l in l_b] - if EXTEND_MODE == 'LENGTH': + if EXTEND_MODE == 'LENGTH_AVERAGE': + fac = edge_lengths[l_b[2].edge.index][0] / edge_lengths[l_a[1].edge.index][0] + elif EXTEND_MODE == 'LENGTH': a0, b0, c0 = l_a[3].vert.co, l_a[0].vert.co, l_b[3].vert.co a1, b1, c1 = l_a[2].vert.co, l_a[1].vert.co, l_b[2].vert.co @@ -140,6 +167,40 @@ def extend(obj, operator, EXTEND_MODE): l_a_uv[2], l_a_uv[1], l_b_uv[2], l_b_uv[1]) + # ------------------------------------------- + # Calculate average length per loop if needed + + if EXTEND_MODE == 'LENGTH_AVERAGE': + bm.edges.index_update() + edge_lengths = [None] * len(bm.edges) + + for f in faces: + # we know its a quad + l_quad = f.loops[:] + l_pair_a = (l_quad[0], l_quad[2]) + l_pair_b = (l_quad[1], l_quad[3]) + + for l_pair in (l_pair_a, l_pair_b): + if edge_lengths[l_pair[0].edge.index] is None: + + edge_length_store = [-1.0] + edge_length_accum = 0.0 + edge_length_total = 0 + + for l in l_pair: + if edge_lengths[l.edge.index] is None: + for e in walk_edgeloop(l): + if edge_lengths[e.index] is None: + edge_lengths[e.index] = edge_length_store + edge_length_accum += e.calc_length() + edge_length_total += 1 + + edge_length_store[0] = edge_length_accum / edge_length_total + + # done with average length + # ------------------------ + + walk_face_init(faces, f_act) for f_triple in walk_face(f_act): apply_uv(*f_triple) @@ -162,8 +223,10 @@ class FollowActiveQuads(Operator): name="Edge Length Mode", description="Method to space UV edge loops", items=(('EVEN', "Even", "Space all UVs evenly"), - ('LENGTH', "Length", "Average space UVs edge length of each loop")), - default='LENGTH', + ('LENGTH', "Length", "Average space UVs edge length of each loop"), + ('LENGTH_AVERAGE', "Length Average", "Average space UVs edge length of each loop"), + ), + default='LENGTH_AVERAGE', ) @classmethod diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py index bfbde2f4b07..e2a820b761a 100644 --- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py +++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py @@ -127,13 +127,14 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean, col[0] = tone * col[0] col[1] = tone * col[1] col[2] = tone * col[2] - + me.update() return {'FINISHED'} import bpy from bpy.types import Operator from bpy.props import FloatProperty, IntProperty, BoolProperty +from math import pi class VertexPaintDirt(Operator): @@ -156,14 +157,16 @@ class VertexPaintDirt(Operator): clean_angle = FloatProperty( name="Highlight Angle", description="Less than 90 limits the angle used in the tonal range", - min=0.0, max=180.0, - default=180.0, + min=0.0, max=pi, + default=pi, + unit="ROTATION", ) dirt_angle = FloatProperty( name="Dirt Angle", description="Less than 90 limits the angle used in the tonal range", - min=0.0, max=180.0, + min=0.0, max=pi, default=0.0, + unit="ROTATION", ) dirt_only = BoolProperty( name="Dirt Only", @@ -171,20 +174,21 @@ class VertexPaintDirt(Operator): default=False, ) + @classmethod + def poll(cls, context): + obj = context.object + return (obj and obj.type == 'MESH') + def execute(self, context): import time from math import radians + obj = context.object - - if not obj or obj.type != 'MESH': - self.report({'ERROR'}, "Error, no active mesh object, aborting") - return {'CANCELLED'} - mesh = obj.data t = time.time() - ret = applyVertexDirt(mesh, self.blur_iterations, self.blur_strength, radians(self.dirt_angle), radians(self.clean_angle), self.dirt_only) + ret = applyVertexDirt(mesh, self.blur_iterations, self.blur_strength, self.dirt_angle, self.clean_angle, self.dirt_only) print('Dirt calculated in %.6f' % (time.time() - t)) diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index ecae4b2d721..3a47b9d2d77 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -133,3 +133,9 @@ def register(): def unregister(): bpy.utils.unregister_module(__name__) + +# Define a default UIList, when a list does not need any custom drawing... +class UI_UL_list(bpy.types.UIList): + pass + +bpy.utils.register_class(UI_UL_list) diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py index 845beb0f862..1643210704e 100644 --- a/release/scripts/startup/bl_ui/properties_data_armature.py +++ b/release/scripts/startup/bl_ui/properties_data_armature.py @@ -124,7 +124,7 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel): rows = 2 if group: rows = 5 - row.template_list(pose, "bone_groups", pose.bone_groups, "active_index", rows=rows) + row.template_list("UI_UL_list", "", pose, "bone_groups", pose.bone_groups, "active_index", rows=rows) col = row.column(align=True) col.active = (ob.proxy is None) @@ -184,7 +184,7 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel): if poselib: # list of poses in pose library row = layout.row() - row.template_list(poselib, "pose_markers", poselib.pose_markers, "active_index", rows=5) + row.template_list("UI_UL_list", "", poselib, "pose_markers", poselib.pose_markers, "active_index", rows=5) # column of operators for active pose # - goes beside list diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py index 25cecc90c70..c74560e14ac 100644 --- a/release/scripts/startup/bl_ui/properties_data_camera.py +++ b/release/scripts/startup/bl_ui/properties_data_camera.py @@ -80,7 +80,7 @@ class DATA_PT_lens(CameraButtonsPanel, Panel): row = col.row() if cam.lens_unit == 'MILLIMETERS': row.prop(cam, "lens") - elif cam.lens_unit == 'DEGREES': + elif cam.lens_unit == 'FOV': row.prop(cam, "angle") row.prop(cam, "lens_unit", text="") diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index e33bed7ec6d..538063cb038 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -18,7 +18,7 @@ # import bpy -from bpy.types import Menu, Panel +from bpy.types import Menu, Panel, UIList from rna_prop_ui import PropertyPanel @@ -54,6 +54,53 @@ class MESH_MT_shape_key_specials(Menu): layout.operator("object.shape_key_add", icon='ZOOMIN', text="New Shape From Mix").from_mix = True +class MESH_UL_vgroups(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.VertexGroup) + vgroup = item + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.label(vgroup.name, icon_value=icon) + icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED' + layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False) + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) + + +class MESH_UL_shape_keys(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.ShapeKey) + obj = active_data + key = data + key_block = item + if self.layout_type in {'DEFAULT', 'COMPACT'}: + split = layout.split(0.66, False) + split.label(item.name, icon_value=icon) + row = split.row(True) + if key_block.mute or (obj.mode == 'EDIT' and not (obj.use_shape_key_edit_mode and obj.type == 'MESH')): + row.active = False + if not item.relative_key or index > 0: + row.prop(key_block, "value", text="", emboss=False) + else: + row.label("") + row.prop(key_block, "mute", text="", emboss=False) + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) + + +class MESH_UL_uvmaps_vcols(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, (bpy.types.MeshTexturePolyLayer, bpy.types.MeshLoopColorLayer)) + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.label(item.name, icon_value=icon) + icon = 'RESTRICT_RENDER_OFF' if item.active_render else 'RESTRICT_RENDER_ON' + layout.prop(item, "active_render", text="", icon=icon, emboss=False) + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) + + class MeshButtonsPanel(): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' @@ -144,7 +191,8 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, Panel): rows = 5 row = layout.row() - row.template_list(ob, "vertex_groups", ob.vertex_groups, "active_index", rows=rows) + row.template_list("MESH_UL_vgroups", "", ob, "vertex_groups", ob.vertex_groups, "active_index", rows=rows) + col = row.column(align=True) col.operator("object.vertex_group_add", icon='ZOOMIN', text="") @@ -202,7 +250,7 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel): rows = 2 if kb: rows = 5 - row.template_list(key, "key_blocks", ob, "active_shape_key_index", rows=rows) + row.template_list("MESH_UL_shape_keys", "", key, "key_blocks", ob, "active_shape_key_index", rows=rows) col = row.column() @@ -282,7 +330,7 @@ class DATA_PT_uv_texture(MeshButtonsPanel, Panel): row = layout.row() col = row.column() - col.template_list(me, "uv_textures", me.uv_textures, "active_index", rows=2) + col.template_list("MESH_UL_uvmaps_vcols", "", me, "uv_textures", me.uv_textures, "active_index", rows=2) col = row.column(align=True) col.operator("mesh.uv_texture_add", icon='ZOOMIN', text="") @@ -305,7 +353,7 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, Panel): row = layout.row() col = row.column() - col.template_list(me, "vertex_colors", me.vertex_colors, "active_index", rows=2) + col.template_list("MESH_UL_uvmaps_vcols", "", me, "vertex_colors", me.vertex_colors, "active_index", rows=2) col = row.column(align=True) col.operator("mesh.vertex_color_add", icon='ZOOMIN', text="") diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index e90d1616929..df29f18853b 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -489,11 +489,13 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col = split.column() col.prop(md, "time") - col.prop(md, "resolution") + col.prop(md, "depth") + col.prop(md, "random_seed") col = split.column() + col.prop(md, "resolution") + col.prop(md, "size") col.prop(md, "spatial_size") - col.prop(md, "depth") layout.label("Waves:") @@ -534,7 +536,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): if md.is_cached: layout.operator("object.ocean_bake", text="Free Bake").free = True else: - layout.operator("object.ocean_bake") + layout.operator("object.ocean_bake").free = False split = layout.split() split.enabled = not md.is_cached @@ -547,7 +549,15 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.label(text="Cache path:") col.prop(md, "filepath", text="") - #col.prop(md, "bake_foam_fade") + split = layout.split() + split.enabled = not md.is_cached + + col = split.column() + col.active = md.use_foam + col.prop(md, "bake_foam_fade") + + col = split.column() + def PARTICLE_INSTANCE(self, layout, ob, md): layout.prop(md, "object") diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index 42f651de6df..58b6aa6916c 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -407,6 +407,7 @@ class RENDER_PT_game_system(RenderButtonsPanel, Panel): col = row.column() col.prop(gs, "use_frame_rate") col.prop(gs, "restrict_animation_updates") + col.prop(gs, "use_material_caching") col = row.column() col.prop(gs, "use_display_lists") col.active = gs.raster_storage != 'VERTEX_BUFFER_OBJECT' diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py index 208b0a63075..9861db39f30 100644 --- a/release/scripts/startup/bl_ui/properties_mask_common.py +++ b/release/scripts/startup/bl_ui/properties_mask_common.py @@ -22,7 +22,24 @@ # menus are referenced `as is` import bpy -from bpy.types import Menu +from bpy.types import Menu, UIList + + +class MASK_UL_layers(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.MaskLayer) + mask = item + if self.layout_type in {'DEFAULT', 'COMPACT'}: + split = layout.split() + split.label(mask.name, icon_value=icon) + row = split.row(align=True) + row.prop(mask, "alpha", text="", emboss=False) + row.prop(mask, "hide", text="", emboss=False) + row.prop(mask, "hide_select", text="", emboss=False) + row.prop(mask, "hide_render", text="", emboss=False) + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) class MASK_PT_mask: @@ -69,8 +86,7 @@ class MASK_PT_layers: rows = 5 if active_layer else 2 row = layout.row() - row.template_list(mask, "layers", - mask, "active_layer_index", rows=rows) + row.template_list("MASK_UL_layers", "", mask, "layers", mask, "active_layer_index", rows=rows) sub = row.column(align=True) diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index 951644db752..7e18cf89080 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -18,7 +18,7 @@ # import bpy -from bpy.types import Menu, Panel +from bpy.types import Menu, Panel, UIList from rna_prop_ui import PropertyPanel @@ -69,6 +69,25 @@ class MATERIAL_MT_specials(Menu): layout.operator("material.paste", icon='PASTEDOWN') +class MATERIAL_UL_matslots(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.MaterialSlot) + ob = data + slot = item + ma = slot.material + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.label(ma.name if ma else "", icon_value=icon) + if ma and not context.scene.render.use_shading_nodes: + manode = ma.active_node_material + if manode: + layout.label("Node %s" % manode.name, icon_value=layout.icon(manode)) + elif ma.use_nodes: + layout.label("Node ") + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) + + class MaterialButtonsPanel(): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' @@ -104,7 +123,7 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel): if ob: row = layout.row() - row.template_list(ob, "material_slots", ob, "active_material_index", rows=2) + row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=2) col = row.column(align=True) col.operator("object.material_slot_add", icon='ZOOMIN', text="") diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index 2c2ced5db0c..90dcf594137 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -96,7 +96,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel): if ob: row = layout.row() - row.template_list(ob, "particle_systems", ob.particle_systems, "active_index", rows=2) + row.template_list("UI_UL_list", "", ob, "particle_systems", ob.particle_systems, "active_index", rows=2) col = row.column(align=True) col.operator("object.particle_system_add", icon='ZOOMIN', text="") @@ -636,7 +636,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel): layout.label(text="Fluid interaction:") row = layout.row() - row.template_list(psys, "targets", psys, "active_particle_target_index") + row.template_list("UI_UL_list", "", psys, "targets", psys, "active_particle_target_index") col = row.column() sub = col.row() @@ -702,7 +702,7 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): # Currently boids can only use the first state so these are commented out for now. #row = layout.row() - #row.template_list(boids, "states", boids, "active_boid_state_index", compact="True") + #row.template_list("UI_UL_list", "", boids, "states", boids, "active_boid_state_index", compact="True") #col = row.row() #sub = col.row(align=True) #sub.operator("boid.state_add", icon='ZOOMIN', text="") @@ -723,7 +723,7 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): row.label(text="") row = layout.row() - row.template_list(state, "rules", state, "active_boid_rule_index") + row.template_list("UI_UL_list", "", state, "rules", state, "active_boid_rule_index") col = row.column() sub = col.row() @@ -886,7 +886,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel): if part.use_group_count and not part.use_whole_group: row = layout.row() - row.template_list(part, "dupli_weights", part, "active_dupliweight_index") + row.template_list("UI_UL_list", "", part, "dupli_weights", part, "active_dupliweight_index") col = row.column() sub = col.row() diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py index 405e877d1e2..b70ff322765 100644 --- a/release/scripts/startup/bl_ui/properties_physics_common.py +++ b/release/scripts/startup/bl_ui/properties_physics_common.py @@ -85,7 +85,7 @@ def point_cache_ui(self, context, cache, enabled, cachetype): layout.context_pointer_set("point_cache", cache) row = layout.row() - row.template_list(cache, "point_caches", cache.point_caches, "active_index", rows=2) + row.template_list("UI_UL_list", "", cache, "point_caches", cache.point_caches, "active_index", rows=2) col = row.column(align=True) col.operator("ptcache.add", icon='ZOOMIN', text="") col.operator("ptcache.remove", icon='ZOOMOUT', text="") diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py index 1df2936b2d4..9393852b8a5 100644 --- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py +++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py @@ -18,13 +18,34 @@ # import bpy -from bpy.types import Panel +from bpy.types import Panel, UIList from bl_ui.properties_physics_common import (point_cache_ui, effector_weights_ui, ) +class PHYSICS_UL_dynapaint_surfaces(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.DynamicPaintSurface) + surf = item + sticon = layout.enum_item_icon(surf, "surface_type", surf.surface_type) + if self.layout_type in {'DEFAULT', 'COMPACT'}: + row = layout.row(align=True) + row.label(text="", icon_value=icon) + row.label(text=surf.name, icon_value=sticon) + row = layout.row(align=True) + if surf.use_color_preview: + row.prop(surf, "show_preview", text="", emboss=False, + icon='RESTRICT_VIEW_OFF' if surf.show_preview else 'RESTRICT_VIEW_ON') + row.prop(surf, "is_active", text="") + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + row = layout.row(align=True) + row.label(text="", icon_value=icon) + row.label(text="", icon_value=sticon) + + class PhysicButtonsPanel(): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' @@ -58,7 +79,8 @@ class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel): surface = canvas.canvas_surfaces.active row = layout.row() - row.template_list(canvas, "canvas_surfaces", canvas.canvas_surfaces, "active_index", rows=2) + row.template_list("PHYSICS_UL_dynapaint_surfaces", "", canvas, "canvas_surfaces", + canvas.canvas_surfaces, "active_index", rows=2) col = row.column(align=True) col.operator("dpaint.surface_slot_add", icon='ZOOMIN', text="") diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 4d14f25c9e8..77bb2d3d50e 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -62,8 +62,7 @@ class RenderFreestyleButtonsPanel(RenderButtonsPanel): def poll(cls, context): if not super().poll(context): return False - rd = context.scene.render - return 'FREESTYLE' in bpy.app.build_options + return bpy.app.build_options.freestyle class RENDER_PT_render(RenderButtonsPanel, Panel): @@ -522,9 +521,12 @@ class RENDER_PT_bake(RenderButtonsPanel, Panel): split = layout.split() col = split.column() - col.prop(rd, "use_bake_clear") - col.prop(rd, "bake_margin") - col.prop(rd, "bake_quad_split", text="Split") + col.prop(rd, "use_bake_to_vertex_color") + sub = col.column() + sub.active = not rd.use_bake_to_vertex_color + sub.prop(rd, "use_bake_clear") + sub.prop(rd, "bake_margin") + sub.prop(rd, "bake_quad_split", text="Split") col = split.column() col.prop(rd, "use_bake_selected_to_active") diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py index 20fc0808759..61750f6e89f 100644 --- a/release/scripts/startup/bl_ui/properties_render_layer.py +++ b/release/scripts/startup/bl_ui/properties_render_layer.py @@ -18,7 +18,7 @@ # import bpy -from bpy.types import Menu, Panel +from bpy.types import Menu, Panel, UIList class RenderLayerButtonsPanel(): @@ -41,7 +41,7 @@ class RenderLayerFreestyleButtonsPanel(RenderLayerButtonsPanel): if not super().poll(context): return False rd = context.scene.render - return 'FREESTYLE' in bpy.app.build_options and rd.use_freestyle and rd.layers.active + return bpy.app.build_options.freestyle and rd.use_freestyle and rd.layers.active class RenderLayerFreestyleEditorButtonsPanel(RenderLayerFreestyleButtonsPanel): @@ -55,6 +55,46 @@ class RenderLayerFreestyleEditorButtonsPanel(RenderLayerFreestyleButtonsPanel): return rl and rl.freestyle_settings.mode == 'EDITOR' +class RENDERLAYER_UL_renderlayers(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.SceneRenderLayer) + layer = item + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.label(layer.name, icon_value=icon) + layout.prop(layer, "use", text="", index=index) + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) + +# else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) { +# uiItemL(sub, name, icon); +# uiBlockSetEmboss(block, UI_EMBOSS); +# uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0, NULL); +# } + + +class RENDERLAYER_UL_linesets(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + lineset = item + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.label(lineset.name, icon_value=icon) + layout.prop(lineset, "use", text="", index=index) + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) + +##ifdef WITH_FREESTYLE +# else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer) || +# RNA_struct_is_a(itemptr->type, &RNA_FreestyleLineSet)) { +##else +# else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) { +##endif +# uiItemL(sub, name, icon); +# uiBlockSetEmboss(block, UI_EMBOSS); +# uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0, NULL); +# } + + class RENDERLAYER_PT_layers(RenderLayerButtonsPanel, Panel): bl_label = "Layers" bl_options = {'HIDE_HEADER'} @@ -67,7 +107,7 @@ class RENDERLAYER_PT_layers(RenderLayerButtonsPanel, Panel): rd = scene.render row = layout.row() - row.template_list(rd, "layers", rd.layers, "active_index", rows=2) + row.template_list("RENDERLAYER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=2) col = row.column(align=True) col.operator("scene.render_layer_add", icon='ZOOMIN', text="") @@ -96,7 +136,7 @@ class RENDERLAYER_PT_layer_options(RenderLayerButtonsPanel, Panel): col = split.column() col.prop(scene, "layers", text="Scene") -# col.label(text="") + col.label(text="") col.prop(rl, "light_override", text="Light") col.prop(rl, "material_override", text="Material") @@ -111,23 +151,22 @@ class RENDERLAYER_PT_layer_options(RenderLayerButtonsPanel, Panel): split = layout.split() col = split.column() - row = col.row(align=True) - row.prop(rl, "use_zmask") - sub = row.row(align=True) - sub.prop(rl, "invert_zmask", text="", icon='ZOOMOUT') - sub.active = rl.use_zmask + col.prop(rl, "use_zmask") + row = col.row() + row.prop(rl, "invert_zmask", text="Negate") + row.active = rl.use_zmask col.prop(rl, "use_all_z") - col.prop(rl, "use_ztransp") col = split.column() col.prop(rl, "use_solid") col.prop(rl, "use_halo") - col.prop(rl, "use_strand") + col.prop(rl, "use_ztransp") col = split.column() col.prop(rl, "use_sky") col.prop(rl, "use_edge_enhance") - if 'FREESTYLE' in bpy.app.build_options: + col.prop(rl, "use_strand") + if bpy.app.build_options.freestyle: row = col.row() row.prop(rl, "use_freestyle") row.active = rd.use_freestyle @@ -267,7 +306,7 @@ class RENDERLAYER_PT_freestyle_lineset(RenderLayerFreestyleEditorButtonsPanel, P col = layout.column() row = col.row() rows = 5 if lineset else 2 - row.template_list(freestyle, "linesets", freestyle.linesets, "active_index", rows=rows) + row.template_list("RENDERLAYER_UL_linesets", "", freestyle, "linesets", freestyle.linesets, "active_index", rows=rows) sub = row.column() subsub = sub.column(align=True) diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index 518b253d0b0..66a16daa22f 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -18,10 +18,22 @@ # import bpy -from bpy.types import Panel +from bpy.types import Panel, UIList from rna_prop_ui import PropertyPanel +class SCENE_UL_keying_set_paths(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.KeyingSetPath) + kspath = item + icon = layout.enum_item_icon(kspath, "id_type", kspath.id_type) + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.label(kspath.data_path, icon_value=icon) + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) + + class SceneButtonsPanel(): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' @@ -107,7 +119,7 @@ class SCENE_PT_keying_sets(SceneButtonsPanel, Panel): row = layout.row() col = row.column() - col.template_list(scene, "keying_sets", scene.keying_sets, "active_index", rows=2) + col.template_list("UI_UL_list", "", scene, "keying_sets", scene.keying_sets, "active_index", rows=2) col = row.column(align=True) col.operator("anim.keying_set_add", icon='ZOOMIN', text="") @@ -151,7 +163,7 @@ class SCENE_PT_keying_set_paths(SceneButtonsPanel, Panel): row = layout.row() col = row.column() - col.template_list(ks, "paths", ks.paths, "active_index", rows=2) + col.template_list("SCENE_UL_keying_set_paths", "", ks, "paths", ks.paths, "active_index", rows=2) col = row.column(align=True) col.operator("anim.keying_set_path_add", icon='ZOOMIN', text="") @@ -251,7 +263,6 @@ class SCENE_PT_color_management(Panel): col.separator() col.label(text="Render:") col.template_colormanaged_view_settings(scene, "view_settings") - col.prop(rd, "use_color_unpremultiply") col = layout.column() col.separator() diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index e623d034b48..eddb542ccc3 100644 --- a/release/scripts/startup/bl_ui/properties_texture.py +++ b/release/scripts/startup/bl_ui/properties_texture.py @@ -18,7 +18,7 @@ # import bpy -from bpy.types import Menu, Panel +from bpy.types import Menu, Panel, UIList from bpy.types import (Brush, Lamp, @@ -55,6 +55,22 @@ class TEXTURE_MT_envmap_specials(Menu): layout.operator("texture.envmap_clear", icon='FILE_REFRESH') layout.operator("texture.envmap_clear_all", icon='FILE_REFRESH') + +class TEXTURE_UL_texslots(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.MaterialTextureSlot) + ma = data + slot = item + tex = slot.texture if slot else None + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.label(tex.name if tex else "", icon_value=icon) + if tex: + layout.prop(ma, "use_textures", text="", index=index) + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) + + from bl_ui.properties_material import active_node_mat @@ -142,7 +158,7 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel, Panel): if tex_collection: row = layout.row() - row.template_list(idblock, "texture_slots", idblock, "active_texture_index", rows=2) + row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots", idblock, "active_texture_index", rows=2) col = row.column(align=True) col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP' @@ -426,7 +442,6 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, Panel): col = split.column() col.label(text="Alpha:") - col.prop(tex, "use_alpha", text="Use") col.prop(tex, "use_calculate_alpha", text="Calculate") col.prop(tex, "invert_alpha", text="Invert") col.separator() diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index cb88226b55a..5fc57133767 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -19,7 +19,18 @@ # import bpy -from bpy.types import Panel, Header, Menu +from bpy.types import Panel, Header, Menu, UIList + + +class CLIP_UL_tracking_objects(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # assert(isinstance(item, bpy.types.MovieTrackingObject) + tobj = item + if self.layout_type in {'DEFAULT', 'COMPACT'}: + layout.label(tobj.name, icon='CAMERA_DATA' if tobj.is_camera else 'OBJECT_DATA') + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon='CAMERA_DATA' if tobj.is_camera else 'OBJECT_DATA') class CLIP_HT_header(Header): @@ -471,8 +482,7 @@ class CLIP_PT_objects(CLIP_PT_clip_view_panel, Panel): tracking = sc.clip.tracking row = layout.row() - row.template_list(tracking, "objects", - tracking, "active_object_index", rows=3) + row.template_list("CLIP_UL_tracking_objects", "", tracking, "objects", tracking, "active_object_index", rows=3) sub = row.column(align=True) @@ -728,7 +738,7 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel): layout.active = stab.use_2d_stabilization row = layout.row() - row.template_list(stab, "tracks", stab, "active_track_index", rows=3) + row.template_list("UI_UL_list", "", stab, "tracks", stab, "active_track_index", rows=3) sub = row.column(align=True) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 5b7a3a82aae..64ad5656bcd 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -433,7 +433,7 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel): elem = False if strip.type == 'IMAGE': - elem = strip.getStripElem(frame_current) + elem = strip.strip_elem_from_frame(frame_current) elif strip.type == 'MOVIE': elem = strip.elements[0] @@ -595,13 +595,14 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): # Current element for the filename - elem = strip.getStripElem(context.scene.frame_current) + elem = strip.strip_elem_from_frame(context.scene.frame_current) if elem: split = layout.split(percentage=0.2) split.label(text="File:") split.prop(elem, "filename", text="") # strip.elements[0] could be a fallback layout.prop(strip.colorspace_settings, "name") + layout.prop(strip, "alpha_mode") layout.operator("sequencer.change_path") @@ -797,7 +798,6 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): col.label(text="Colors:") col.prop(strip, "color_saturation", text="Saturation") col.prop(strip, "color_multiply", text="Multiply") - col.prop(strip, "use_premultiply") col.prop(strip, "use_float") diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index b54fccf45f1..960a945f1c6 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -194,14 +194,33 @@ class TEXT_MT_text(Menu): layout.operator("text.run_script") +class TEXT_MT_templates_py(Menu): + bl_label = "Python" + + def draw(self, context): + self.path_menu(bpy.utils.script_paths("templates_py"), + "text.open", + {"internal": True}, + ) + + +class TEXT_MT_templates_osl(Menu): + bl_label = "Open Shading Language" + + def draw(self, context): + self.path_menu(bpy.utils.script_paths("templates_osl"), + "text.open", + {"internal": True}, + ) + + class TEXT_MT_templates(Menu): bl_label = "Templates" def draw(self, context): - self.path_menu(bpy.utils.script_paths("templates"), - "text.open", - {"internal": True}, - ) + layout = self.layout + layout.menu("TEXT_MT_templates_py") + layout.menu("TEXT_MT_templates_osl") class TEXT_MT_edit_select(Menu): @@ -282,6 +301,7 @@ class TEXT_MT_edit(Menu): layout.operator("text.jump") layout.operator("text.properties", text="Find...") + layout.operator("text.autocomplete") layout.separator() diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 695e09ee025..58c433d3772 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -22,6 +22,27 @@ from bpy.types import Header, Menu, Panel import os +def ui_style_items(col, context): + """ UI Style settings """ + + split = col.split() + + col = split.column() + col.label(text="Kerning Style:") + col.row().prop(context, "font_kerning_style", expand=True) + col.prop(context, "points") + + col = split.column() + col.label(text="Shadow Offset:") + col.prop(context, "shadow_offset_x", text="X") + col.prop(context, "shadow_offset_y", text="Y") + + col = split.column() + col.prop(context, "shadow") + col.prop(context, "shadowalpha") + col.prop(context, "shadowcolor") + + def ui_items_general(col, context): """ General UI Theme Settings (User Interface) """ @@ -492,7 +513,7 @@ class USERPREF_PT_system(Panel): sub.active = system.use_weight_color_range sub.template_color_ramp(system, "weight_color_range", expand=True) - if 'INTERNATIONAL' in bpy.app.build_options: + if bpy.app.build_options.international: column.separator() column.prop(system, "use_international_fonts") if system.use_international_fonts: @@ -774,6 +795,21 @@ class USERPREF_PT_theme(Panel): colsub = padding.column() colsub = padding.column() colsub.row().prop(ui, "show_colored_constraints") + elif theme.theme_area == 'STYLE': + col = split.column() + + style = context.user_preferences.ui_styles[0] + + ui = style.widget + col.label(text="Widget:") + ui_style_items(col, ui) + + col.separator() + col.separator() + + ui = style.widget_label + col.label(text="Widget Label:") + ui_style_items(col, ui) else: self._theme_generic(split, getattr(theme, theme.theme_area.lower())) @@ -1126,7 +1162,8 @@ class USERPREF_PT_addons(Panel): continue # Addon UI Code - box = col.column().box() + col_box = col.column() + box = col_box.box() colsub = box.column() row = colsub.row() @@ -1189,6 +1226,25 @@ class USERPREF_PT_addons(Panel): for i in range(4 - tot_row): split.separator() + # Show addon user preferences + if is_enabled: + addon_preferences = userpref.addons[module_name].preferences + if addon_preferences is not None: + draw = getattr(addon_preferences, "draw", None) + if draw is not None: + addon_preferences_class = type(addon_preferences) + box_prefs = col_box.box() + box_prefs.label("Preferences:") + addon_preferences_class.layout = box_prefs + try: + draw(context) + except: + import traceback + traceback.print_exc() + box_prefs.label(text="Error (see console)", icon='ERROR') + del addon_preferences_class.layout + + # Append missing scripts # First collect scripts that are used but have no script file. module_names = {mod.__name__ for mod, info in addons} diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 7807bb11c8a..a35fb149aae 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -70,7 +70,8 @@ class VIEW3D_HT_header(Header): row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True) # Occlude geometry - if view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'PARTICLE_EDIT' or (mode == 'EDIT' and obj.type == 'MESH')): + if ((view.viewport_shade not in {'BOUNDBOX', 'WIREFRAME'} and (mode == 'PARTICLE_EDIT' or (mode == 'EDIT' and obj.type == 'MESH'))) or + (mode == 'WEIGHT_PAINT')): row.prop(view, "use_occlude_geometry", text="") # Proportional editing @@ -1838,7 +1839,7 @@ class VIEW3D_MT_edit_mesh_edges(Menu): layout.separator() - if context.scene and 'FREESTYLE' in bpy.app.build_options: + if context.scene and bpy.app.build_options.freestyle: layout.operator("mesh.mark_freestyle_edge").clear = False layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True @@ -1884,7 +1885,7 @@ class VIEW3D_MT_edit_mesh_faces(Menu): layout.separator() - if context.scene and 'FREESTYLE' in bpy.app.build_options: + if context.scene and bpy.app.build_options.freestyle: layout.operator("mesh.mark_freestyle_face").clear = False layout.operator("mesh.mark_freestyle_face", text="Clear Freestyle Face").clear = True @@ -2493,7 +2494,7 @@ class VIEW3D_PT_view3d_meshdisplay(Panel): col.prop(mesh, "show_edge_bevel_weight", text="Bevel Weights") col.prop(mesh, "show_edge_seams", text="Seams") col.prop(mesh, "show_edge_sharp", text="Sharp") - if context.scene and 'FREESTYLE' in bpy.app.build_options: + if context.scene and bpy.app.build_options.freestyle: col.prop(mesh, "show_freestyle_edge_marks", text="Freestyle Edge Marks") col.prop(mesh, "show_freestyle_face_marks", text="Freestyle Face Marks") diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 09b32cd0c56..0e1f5d8dff2 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -854,6 +854,36 @@ class VIEW3D_PT_tools_brush_curve(Panel, View3DPaintPanel): row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX' +class VIEW3D_PT_sculpt_topology(Panel, View3DPaintPanel): + bl_label = "Topology" + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return (context.sculpt_object and context.tool_settings.sculpt) + + def draw(self, context): + layout = self.layout + + toolsettings = context.tool_settings + sculpt = toolsettings.sculpt + + if context.sculpt_object.use_dynamic_topology_sculpting: + layout.operator("sculpt.dynamic_topology_toggle", icon='X', text="Disable Dynamic") + else: + layout.operator("sculpt.dynamic_topology_toggle", icon='SCULPT_DYNTOPO', text="Enable Dynamic") + + col = layout.column() + col.active = context.sculpt_object.use_dynamic_topology_sculpting + col.prop(sculpt, "detail_size") + col.prop(sculpt, "use_smooth_shading") + col.prop(sculpt, "use_edge_collapse") + col.operator("sculpt.optimize") + col.separator() + col.prop(sculpt, "symmetrize_direction") + col.operator("sculpt.symmetrize") + + class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel): bl_label = "Options" bl_options = {'DEFAULT_CLOSED'} @@ -1167,7 +1197,8 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel): if pe.type == 'PARTICLES': if ob.particle_systems: if len(ob.particle_systems) > 1: - layout.template_list(ob, "particle_systems", ob.particle_systems, "active_index", rows=2, maxrows=3) + layout.template_list("UI_UL_list", "", ob, "particle_systems", + ob.particle_systems, "active_index", rows=2, maxrows=3) ptcache = ob.particle_systems.active.point_cache else: @@ -1176,7 +1207,8 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel): ptcache = md.point_cache if ptcache and len(ptcache.point_caches) > 1: - layout.template_list(ptcache, "point_caches", ptcache.point_caches, "active_index", rows=2, maxrows=3) + layout.template_list("UI_UL_list", "", ptcache, "point_caches", ptcache.point_caches, "active_index", + rows=2, maxrows=3) if not pe.is_editable: layout.label(text="Point cache must be baked") diff --git a/release/scripts/startup/keyingsets_builtins.py b/release/scripts/startup/keyingsets_builtins.py index 6ad87375738..4f06f8a7be3 100644 --- a/release/scripts/startup/keyingsets_builtins.py +++ b/release/scripts/startup/keyingsets_builtins.py @@ -181,7 +181,7 @@ class BUILTIN_KSI_RotScale(KeyingSetInfo): # ------------ -# Location +# VisualLocation class BUILTIN_KSI_VisualLoc(KeyingSetInfo): """ Insert a keyframe on each of the location channels, taking into account @@ -201,7 +201,7 @@ class BUILTIN_KSI_VisualLoc(KeyingSetInfo): generate = keyingsets_utils.RKS_GEN_location -# Rotation +# VisualRotation class BUILTIN_KSI_VisualRot(KeyingSetInfo): """ Insert a keyframe on each of the rotation channels, taking into account @@ -221,6 +221,26 @@ class BUILTIN_KSI_VisualRot(KeyingSetInfo): generate = keyingsets_utils.RKS_GEN_rotation +# VisualScaling +class BUILTIN_KSI_VisualScaling(KeyingSetInfo): + """ + Insert a keyframe on each of the scale channels, taking into account + effects of constraints and relationships + """ + bl_label = "Visual Scaling" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator - use callback for location + generate = keyingsets_utils.RKS_GEN_scaling + + # VisualLocRot class BUILTIN_KSI_VisualLocRot(KeyingSetInfo): """ @@ -244,6 +264,80 @@ class BUILTIN_KSI_VisualLocRot(KeyingSetInfo): # rotation keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) + +# VisualLocScale +class BUILTIN_KSI_VisualLocScale(KeyingSetInfo): + """ + Insert a keyframe on each of the location and scaling channels, + taking into account effects of constraints and relationships + """ + bl_label = "Visual LocScale" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # location + keyingsets_utils.RKS_GEN_location(self, context, ks, data) + # scaling + keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) + + +# VisualLocRotScale +class BUILTIN_KSI_VisualLocRotScale(KeyingSetInfo): + """ + Insert a keyframe on each of the location, rotation and scaling channels, + taking into account effects of constraints and relationships + """ + bl_label = "Visual LocRotScale" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # location + keyingsets_utils.RKS_GEN_location(self, context, ks, data) + # rotation + keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) + # scaling + keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) + + +# VisualRotScale +class BUILTIN_KSI_VisualRotScale(KeyingSetInfo): + """ + Insert a keyframe on each of the rotation and scaling channels, + taking into account effects of constraints and relationships + """ + bl_label = "Visual RotScale" + + bl_options = {'INSERTKEY_VISUAL'} + + # poll - use predefined callback for selected bones/objects + poll = keyingsets_utils.RKS_POLL_selected_items + + # iterator - use callback for selected bones/objects + iterator = keyingsets_utils.RKS_ITER_selected_item + + # generator + def generate(self, context, ks, data): + # rotation + keyingsets_utils.RKS_GEN_rotation(self, context, ks, data) + # scaling + keyingsets_utils.RKS_GEN_scaling(self, context, ks, data) + # ------------ diff --git a/release/scripts/templates_osl/empty_shader.osl b/release/scripts/templates_osl/empty_shader.osl new file mode 100644 index 00000000000..e2c9a4a257e --- /dev/null +++ b/release/scripts/templates_osl/empty_shader.osl @@ -0,0 +1,6 @@ + +shader name() +{ + +} + diff --git a/release/scripts/templates_osl/noise.osl b/release/scripts/templates_osl/noise.osl new file mode 100644 index 00000000000..05cc31687c0 --- /dev/null +++ b/release/scripts/templates_osl/noise.osl @@ -0,0 +1,18 @@ + +shader noise( + float Time = 1.0, + point Point = P, + output float Cell = 0.0, + output color Perlin = 0.8, + output color UPerlin = 0.8) +{ + /* Cell Noise */ + Cell = noise("cell", Point); + + /* Perlin 4D Noise*/ + Perlin = noise("perlin", Point, Time); + + /* UPerlin 4D Noise*/ + UPerlin = noise("uperlin", Point, Time); +} + diff --git a/release/scripts/templates_osl/wireframe.osl b/release/scripts/templates_osl/wireframe.osl new file mode 100644 index 00000000000..00e4506e73c --- /dev/null +++ b/release/scripts/templates_osl/wireframe.osl @@ -0,0 +1,11 @@ + +#include "oslutil.h" + +shader wireframe( + float Line_Width = 2.0, + int Raster = 1, + output float Wire = 0.0) +{ + Wire = wireframe("triangles", Line_Width, Raster); +} + diff --git a/release/scripts/templates/addon_add_object.py b/release/scripts/templates_py/addon_add_object.py similarity index 100% rename from release/scripts/templates/addon_add_object.py rename to release/scripts/templates_py/addon_add_object.py diff --git a/release/scripts/templates/background_job.py b/release/scripts/templates_py/background_job.py similarity index 100% rename from release/scripts/templates/background_job.py rename to release/scripts/templates_py/background_job.py diff --git a/release/scripts/templates/batch_export.py b/release/scripts/templates_py/batch_export.py similarity index 100% rename from release/scripts/templates/batch_export.py rename to release/scripts/templates_py/batch_export.py diff --git a/release/scripts/templates/bmesh_simple.py b/release/scripts/templates_py/bmesh_simple.py similarity index 100% rename from release/scripts/templates/bmesh_simple.py rename to release/scripts/templates_py/bmesh_simple.py diff --git a/release/scripts/templates/bmesh_simple_editmode.py b/release/scripts/templates_py/bmesh_simple_editmode.py similarity index 100% rename from release/scripts/templates/bmesh_simple_editmode.py rename to release/scripts/templates_py/bmesh_simple_editmode.py diff --git a/release/scripts/templates/builtin_keyingset.py b/release/scripts/templates_py/builtin_keyingset.py similarity index 100% rename from release/scripts/templates/builtin_keyingset.py rename to release/scripts/templates_py/builtin_keyingset.py diff --git a/release/scripts/templates/driver_functions.py b/release/scripts/templates_py/driver_functions.py similarity index 100% rename from release/scripts/templates/driver_functions.py rename to release/scripts/templates_py/driver_functions.py diff --git a/release/scripts/templates/gamelogic.py b/release/scripts/templates_py/gamelogic.py similarity index 100% rename from release/scripts/templates/gamelogic.py rename to release/scripts/templates_py/gamelogic.py diff --git a/release/scripts/templates/gamelogic_module.py b/release/scripts/templates_py/gamelogic_module.py similarity index 100% rename from release/scripts/templates/gamelogic_module.py rename to release/scripts/templates_py/gamelogic_module.py diff --git a/release/scripts/templates/gamelogic_simple.py b/release/scripts/templates_py/gamelogic_simple.py similarity index 100% rename from release/scripts/templates/gamelogic_simple.py rename to release/scripts/templates_py/gamelogic_simple.py diff --git a/release/scripts/templates/operator_file_export.py b/release/scripts/templates_py/operator_file_export.py similarity index 100% rename from release/scripts/templates/operator_file_export.py rename to release/scripts/templates_py/operator_file_export.py diff --git a/release/scripts/templates/operator_file_import.py b/release/scripts/templates_py/operator_file_import.py similarity index 100% rename from release/scripts/templates/operator_file_import.py rename to release/scripts/templates_py/operator_file_import.py diff --git a/release/scripts/templates/operator_mesh_add.py b/release/scripts/templates_py/operator_mesh_add.py similarity index 100% rename from release/scripts/templates/operator_mesh_add.py rename to release/scripts/templates_py/operator_mesh_add.py diff --git a/release/scripts/templates/operator_modal.py b/release/scripts/templates_py/operator_modal.py similarity index 100% rename from release/scripts/templates/operator_modal.py rename to release/scripts/templates_py/operator_modal.py diff --git a/release/scripts/templates/operator_modal_draw.py b/release/scripts/templates_py/operator_modal_draw.py similarity index 100% rename from release/scripts/templates/operator_modal_draw.py rename to release/scripts/templates_py/operator_modal_draw.py diff --git a/release/scripts/templates/operator_modal_timer.py b/release/scripts/templates_py/operator_modal_timer.py similarity index 100% rename from release/scripts/templates/operator_modal_timer.py rename to release/scripts/templates_py/operator_modal_timer.py diff --git a/release/scripts/templates/operator_modal_view3d.py b/release/scripts/templates_py/operator_modal_view3d.py similarity index 100% rename from release/scripts/templates/operator_modal_view3d.py rename to release/scripts/templates_py/operator_modal_view3d.py diff --git a/release/scripts/templates/operator_modal_view3d_raycast.py b/release/scripts/templates_py/operator_modal_view3d_raycast.py similarity index 100% rename from release/scripts/templates/operator_modal_view3d_raycast.py rename to release/scripts/templates_py/operator_modal_view3d_raycast.py diff --git a/release/scripts/templates/operator_node.py b/release/scripts/templates_py/operator_node.py similarity index 100% rename from release/scripts/templates/operator_node.py rename to release/scripts/templates_py/operator_node.py diff --git a/release/scripts/templates/operator_simple.py b/release/scripts/templates_py/operator_simple.py similarity index 100% rename from release/scripts/templates/operator_simple.py rename to release/scripts/templates_py/operator_simple.py diff --git a/release/scripts/templates/operator_uv.py b/release/scripts/templates_py/operator_uv.py similarity index 100% rename from release/scripts/templates/operator_uv.py rename to release/scripts/templates_py/operator_uv.py diff --git a/release/scripts/templates/script_stub.py b/release/scripts/templates_py/script_stub.py similarity index 100% rename from release/scripts/templates/script_stub.py rename to release/scripts/templates_py/script_stub.py diff --git a/release/scripts/templates_py/ui_list.py b/release/scripts/templates_py/ui_list.py new file mode 100644 index 00000000000..18861f7d801 --- /dev/null +++ b/release/scripts/templates_py/ui_list.py @@ -0,0 +1,78 @@ +import bpy + + +class MATERIAL_UL_matslots_example(bpy.types.UIList): + # The draw_item function is called for each item of the collection that is visible in the list. + # data is the RNA object containing the collection, + # item is the current drawn item of the collection, + # icon is the "computed" icon for the item (as an integer, because some objects like materials or textures + # have custom icons ID, which are not available as enum items). + # active_data is the RNA object containing the active property for the collection (i.e. integer pointing to the + # active item of the collection). + # active_propname is the name of the active property (use 'getattr(active_data, active_propname)'). + # index is index of the current item in the collection. + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + ob = data + slot = item + ma = slot.material + # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code. + if self.layout_type in {'DEFAULT', 'COMPACT'}: + # You should always start your row layout by a label (icon + text), this will also make the row easily + # selectable in the list! + # We use icon_value of label, as our given icon is an integer value, not an enum ID. + layout.label(ma.name if ma else "", icon_value=icon) + # And now we can add other UI stuff... + # Here, we add nodes info if this material uses (old!) shading nodes. + if ma and not context.scene.render.use_shading_nodes: + manode = ma.active_node_material + if manode: + # The static method UILayout.icon returns the integer value of the icon ID "computed" for the given + # RNA object. + layout.label("Node %s" % manode.name, icon_value=layout.icon(manode)) + elif ma.use_nodes: + layout.label("Node ") + else: + layout.label("") + # 'GRID' layout type should be as compact as possible (typically a single icon!). + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label("", icon_value=icon) + + +# And now we can use this list everywhere in Blender. Here is a small example panel. +class UIListPanelExample(bpy.types.Panel): + """Creates a Panel in the Object properties window""" + bl_label = "UIList Panel" + bl_idname = "OBJECT_PT_ui_list_example" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "object" + + def draw(self, context): + layout = self.layout + + obj = context.object + + # template_list now takes two new args. + # The first one is the identifier of the registered UIList to use (if you want only the default list, + # with no custom draw code, use "UI_UL_list"). + layout.template_list("MATERIAL_UL_matslots_example", "", obj, "material_slots", obj, "active_material_index") + + # The second one can usually be left as an empty string. It's an additional ID used to distinguish lists in case you + # use the same list several times in a given area. + layout.template_list("MATERIAL_UL_matslots_example", "compact", obj, "material_slots", + obj, "active_material_index", type='COMPACT') + + +def register(): + bpy.utils.register_class(MATERIAL_UL_matslots_example) + bpy.utils.register_class(UIListPanelExample) + + +def unregister(): + bpy.utils.unregister_class(MATERIAL_UL_matslots_example) + bpy.utils.unregister_class(UIListPanelExample) + + +if __name__ == "__main__": + register() \ No newline at end of file diff --git a/release/scripts/templates/ui_menu.py b/release/scripts/templates_py/ui_menu.py similarity index 100% rename from release/scripts/templates/ui_menu.py rename to release/scripts/templates_py/ui_menu.py diff --git a/release/scripts/templates/ui_menu_simple.py b/release/scripts/templates_py/ui_menu_simple.py similarity index 100% rename from release/scripts/templates/ui_menu_simple.py rename to release/scripts/templates_py/ui_menu_simple.py diff --git a/release/scripts/templates/ui_panel.py b/release/scripts/templates_py/ui_panel.py similarity index 100% rename from release/scripts/templates/ui_panel.py rename to release/scripts/templates_py/ui_panel.py diff --git a/release/scripts/templates/ui_panel_simple.py b/release/scripts/templates_py/ui_panel_simple.py similarity index 100% rename from release/scripts/templates/ui_panel_simple.py rename to release/scripts/templates_py/ui_panel_simple.py diff --git a/source/blender/avi/intern/avi_intern.h b/source/blender/avi/intern/avi_intern.h index c8d54fe99e9..5dc48657831 100644 --- a/source/blender/avi/intern/avi_intern.h +++ b/source/blender/avi/intern/avi_intern.h @@ -37,9 +37,27 @@ unsigned int GET_FCC (FILE *fp); unsigned int GET_TCC (FILE *fp); -#define PUT_FCC(ch4, fp) putc(ch4[0],fp); putc(ch4[1],fp); putc(ch4[2],fp); putc(ch4[3],fp) -#define PUT_FCCN(num, fp) putc((num>>0)&0377,fp); putc((num>>8)&0377,fp); putc((num>>16)&0377,fp); putc((num>>24)&0377,fp) -#define PUT_TCC(ch2, fp) putc(ch2[0],fp); putc(ch2[1],fp) +#define PUT_FCC(ch4, fp) \ +{ \ + putc(ch4[0], fp); \ + putc(ch4[1], fp); \ + putc(ch4[2], fp); \ + putc(ch4[3], fp); \ +} (void)0 + +#define PUT_FCCN(num, fp) \ +{ \ + putc((num >> 0) & 0377, fp); \ + putc((num >> 8) & 0377, fp); \ + putc((num >> 16) & 0377, fp); \ + putc((num >> 24) & 0377, fp); \ +} (void)0 + +#define PUT_TCC(ch2, fp) \ +{ \ + putc(ch2[0], fp); \ + putc(ch2[1], fp); \ +} (void)0 void *avi_format_convert (AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, int *size); diff --git a/source/blender/avi/intern/avi_mjpeg.c b/source/blender/avi/intern/avi_mjpeg.c index 396f1199cd9..91b8fa5a060 100644 --- a/source/blender/avi/intern/avi_mjpeg.c +++ b/source/blender/avi/intern/avi_mjpeg.c @@ -206,7 +206,7 @@ static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsign return 1; } -static void Compress_JPEG(int quality, unsigned char *outbuffer, unsigned char *inBuffer, int width, int height, int bufsize) +static void Compress_JPEG(int quality, unsigned char *outbuffer, const unsigned char *inBuffer, int width, int height, int bufsize) { int i, rowstride; unsigned int y; @@ -316,7 +316,8 @@ static int check_and_decode_jpeg(unsigned char *inbuf, unsigned char *outbuf, in } } -static void check_and_compress_jpeg(int quality, unsigned char *outbuf, unsigned char *inbuf, int width, int height, int bufsize) +static void check_and_compress_jpeg(int quality, unsigned char *outbuf, const unsigned char *inbuf, + int width, int height, int bufsize) { /* JPEG's are always multiples of 16, extra is ignored in AVI's */ if ((width & 0xF) || (height & 0xF)) { @@ -379,7 +380,11 @@ void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 1"); if (!movie->interlace) { - check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, buf, buffer, movie->header->Width, movie->header->Height, bufsize); + check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, + buf, buffer, + movie->header->Width, + movie->header->Height, + bufsize); } else { deinterlace(movie->odd_fields, buf, buffer, movie->header->Width, movie->header->Height); @@ -388,10 +393,18 @@ void *avi_converter_to_mjpeg(AviMovie *movie, int stream, unsigned char *buffer, buffer = buf; buf = MEM_mallocN(movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 2"); - check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, buf, buffer, movie->header->Width, movie->header->Height / 2, bufsize / 2); + check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, + buf, buffer, + movie->header->Width, + movie->header->Height / 2, + bufsize / 2); *size += numbytes; numbytes = 0; - check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, buf + *size, buffer + (movie->header->Height / 2) * movie->header->Width * 3, movie->header->Width, movie->header->Height / 2, bufsize / 2); + check_and_compress_jpeg(movie->streams[stream].sh.Quality / 100, + buf + *size, buffer + (movie->header->Height / 2) * movie->header->Width * 3, + movie->header->Width, + movie->header->Height / 2, + bufsize / 2); } *size += numbytes; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 91ecded88be..9c7623f3757 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -383,7 +383,7 @@ int blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) if (gc->cur_tex == -1) { blf_glyph_cache_texture(font, gc); gc->x_offs = gc->pad; - gc->y_offs = gc->pad; + gc->y_offs = 0; } if (gc->x_offs > (gc->p2_width - gc->max_glyph_width)) { @@ -391,7 +391,7 @@ int blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) gc->y_offs += gc->max_glyph_height; if (gc->y_offs > (gc->p2_height - gc->max_glyph_height)) { - gc->y_offs = gc->pad; + gc->y_offs = 0; blf_glyph_cache_texture(font, gc); } } @@ -400,6 +400,19 @@ int blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) g->xoff = gc->x_offs; g->yoff = gc->y_offs; + /* prevent glTexSubImage2D from failing if the character + * asks for pixels out of bounds, this tends only to happen + * with very small sizes (5px high or less) */ + if (UNLIKELY((g->xoff + g->width) > gc->p2_width)) { + g->width -= (g->xoff + g->width) - gc->p2_width; + BLI_assert(g->width > 0); + } + if (UNLIKELY((g->yoff + g->height) > gc->p2_height)) { + g->height -= (g->yoff + g->height) - gc->p2_height; + BLI_assert(g->height > 0); + } + + glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c index 4d066ea8740..9086799f984 100644 --- a/source/blender/blenfont/intern/blf_lang.c +++ b/source/blender/blenfont/intern/blf_lang.c @@ -100,7 +100,7 @@ static void fill_locales(void) /* First loop to find highest locale ID */ while (line) { int t; - str = (char*) line->link; + str = (char *)line->link; if (str[0] == '#' || str[0] == '\0') { line = line->next; continue; /* Comment or void... */ @@ -118,12 +118,12 @@ static void fill_locales(void) line = lines; /* Do not allocate locales with zero-sized mem, as LOCALE macro uses NULL locales as invalid marker! */ if (num_locales > 0) { - locales = MEM_callocN(num_locales * sizeof(char*), __func__); + locales = MEM_callocN(num_locales * sizeof(char *), __func__); while (line) { int id; char *loc, *sep1, *sep2, *sep3; - str = (char*) line->link; + str = (char *)line->link; if (str[0] == '#' || str[0] == '\0') { line = line->next; continue; @@ -230,7 +230,7 @@ void BLF_lang_set(const char *str) bl_locale_set(short_locale_utf8); if (short_locale[0]) { - MEM_freeN((void*)short_locale_utf8); + MEM_freeN((void *)short_locale_utf8); } } diff --git a/source/blender/blenkernel/BKE_addon.h b/source/blender/blenkernel/BKE_addon.h new file mode 100644 index 00000000000..eafaec3e605 --- /dev/null +++ b/source/blender/blenkernel/BKE_addon.h @@ -0,0 +1,42 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_ADDON_H__ +#define __BKE_ADDON_H__ + +#include "RNA_types.h" + +typedef struct bAddonPrefType { + /* type info */ + char idname[64]; // best keep the same size as BKE_ST_MAXNAME + + /* RNA integration */ + ExtensionRNA ext; +} bAddonPrefType; + +bAddonPrefType *BKE_addon_pref_type_find(const char *idname, int quiet); +void BKE_addon_pref_type_add(bAddonPrefType *apt); +void BKE_addon_pref_type_remove(bAddonPrefType *apt); + +void BKE_addon_pref_type_init(void); +void BKE_addon_pref_type_free(void); + +#endif /* __BKE_ADDON_H__ */ diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 11759a82e60..10528f1b270 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -42,7 +42,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 265 -#define BLENDER_SUBVERSION 3 +#define BLENDER_SUBVERSION 5 /* 262 was the last editmesh release but it has compatibility code for bmesh data */ #define BLENDER_MINVERSION 262 diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index cbffb6c0cea..248fe9c8968 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -99,6 +99,7 @@ float BKE_brush_unprojected_radius_get(const struct Scene *scene, struct Brush * void BKE_brush_unprojected_radius_set(struct Scene *scene, struct Brush *brush, float value); float BKE_brush_alpha_get(const struct Scene *scene, struct Brush *brush); +void BKE_brush_alpha_set(Scene *scene, struct Brush *brush, float alpha); float BKE_brush_weight_get(const Scene *scene, struct Brush *brush); void BKE_brush_weight_set(const Scene *scene, struct Brush *brush, float value); diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 79e75127763..c79dc62bb61 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -108,8 +108,8 @@ typedef struct bConstraintTypeInfo { } bConstraintTypeInfo; /* Function Prototypes for bConstraintTypeInfo's */ -bConstraintTypeInfo *constraint_get_typeinfo(struct bConstraint *con); -bConstraintTypeInfo *get_constraint_typeinfo(int type); +bConstraintTypeInfo *BKE_constraint_get_typeinfo(struct bConstraint *con); +bConstraintTypeInfo *BKE_get_constraint_typeinfo(int type); /* ---------------------------------------------------------------------------- */ /* Useful macros for testing various common flag combinations */ @@ -120,38 +120,38 @@ bConstraintTypeInfo *get_constraint_typeinfo(int type); /* ---------------------------------------------------------------------------- */ /* Constraint function prototypes */ -void unique_constraint_name(struct bConstraint *con, struct ListBase *list); +void BKE_unique_constraint_name(struct bConstraint *con, struct ListBase *list); -void free_constraints(struct ListBase *list); -void copy_constraints(struct ListBase *dst, const struct ListBase *src, int do_extern); -void relink_constraints(struct ListBase *list); -void id_loop_constraints(struct ListBase *list, ConstraintIDFunc func, void *userdata); -void free_constraint_data(struct bConstraint *con); +void BKE_free_constraints(struct ListBase *list); +void BKE_copy_constraints(struct ListBase *dst, const struct ListBase *src, int do_extern); +void BKE_relink_constraints(struct ListBase *list); +void BKE_id_loop_constraints(struct ListBase *list, ConstraintIDFunc func, void *userdata); +void BKE_free_constraint_data(struct bConstraint *con); /* Constraint API function prototypes */ -struct bConstraint *constraints_get_active(struct ListBase *list); -void constraints_set_active(ListBase *list, struct bConstraint *con); -struct bConstraint *constraints_findByName(struct ListBase *list, const char *name); - -struct bConstraint *add_ob_constraint(struct Object *ob, const char *name, short type); -struct bConstraint *add_pose_constraint(struct Object *ob, struct bPoseChannel *pchan, const char *name, short type); +struct bConstraint *BKE_constraints_get_active(struct ListBase *list); +void BKE_constraints_set_active(ListBase *list, struct bConstraint *con); +struct bConstraint *BKE_constraints_findByName(struct ListBase *list, const char *name); -int remove_constraint(ListBase *list, struct bConstraint *con); -void remove_constraints_type(ListBase *list, short type, short last_only); +struct bConstraint *BKE_add_ob_constraint(struct Object *ob, const char *name, short type); +struct bConstraint *BKE_add_pose_constraint(struct Object *ob, struct bPoseChannel *pchan, const char *name, short type); + +int BKE_remove_constraint(ListBase *list, struct bConstraint *con); +void BKE_remove_constraints_type(ListBase *list, short type, short last_only); /* Constraints + Proxies function prototypes */ -void extract_proxylocal_constraints(struct ListBase *dst, struct ListBase *src); -short proxylocked_constraints_owner(struct Object *ob, struct bPoseChannel *pchan); +void BKE_extract_proxylocal_constraints(struct ListBase *dst, struct ListBase *src); +short BKE_proxylocked_constraints_owner(struct Object *ob, struct bPoseChannel *pchan); /* Constraint Evaluation function prototypes */ -struct bConstraintOb *constraints_make_evalob(struct Scene *scene, struct Object *ob, void *subdata, short datatype); -void constraints_clear_evalob(struct bConstraintOb *cob); +struct bConstraintOb *BKE_constraints_make_evalob(struct Scene *scene, struct Object *ob, void *subdata, short datatype); +void BKE_constraints_clear_evalob(struct bConstraintOb *cob); -void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to); +void BKE_constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[4][4], short from, short to); -void get_constraint_target_matrix(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime); -void get_constraint_targets_for_solving(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime); -void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime); +void BKE_get_constraint_target_matrix(struct Scene *scene, struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime); +void BKE_get_constraint_targets_for_solving(struct bConstraint *con, struct bConstraintOb *ob, struct ListBase *targets, float ctime); +void BKE_solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index 8306da71432..ab27421b383 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -56,6 +56,9 @@ void defvert_remove_group(struct MDeformVert *dvert, struct void defvert_clear(struct MDeformVert *dvert); int defvert_find_shared(const struct MDeformVert *dvert_a, const struct MDeformVert *dvert_b); +void BKE_defvert_array_free(struct MDeformVert *dvert, int totvert); +void BKE_defvert_array_copy(struct MDeformVert *dst, const struct MDeformVert *src, int totvert); + float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup); float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup); diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 758a2a8a2e8..6b986cdceda 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -83,7 +83,7 @@ void BKE_displist_elem_free(DispList *dl); DispList *BKE_displist_find_or_create(struct ListBase *lb, int type); DispList *BKE_displist_find(struct ListBase *lb, int type); void BKE_displist_normals_add(struct ListBase *lb); -void BKE_displist_count(struct ListBase *lb, int *totvert, int *totface); +void BKE_displist_count(struct ListBase *lb, int *totvert, int *totface, int *tottri); void BKE_displist_free(struct ListBase *lb); int BKE_displist_has_faces(struct ListBase *lb); diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index a9f6a61a655..ad3e4bb2251 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -315,6 +315,8 @@ __attribute__((nonnull)) * the actual struct IDProperty struct either.*/ void IDP_FreeProperty(struct IDProperty *prop); +void IDP_ClearProperty(IDProperty *prop); + /** Unlinks any struct IDProperty<->ID linkage that might be going on.*/ void IDP_UnlinkProperty(struct IDProperty *prop); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 1f9630d9fce..499609932d1 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -60,8 +60,10 @@ int BKE_imbuf_alpha_test(struct ImBuf *ibuf); int BKE_imbuf_write_stamp(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf); int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf); int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf, const short is_copy); -void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame, const char imtype, const short use_ext, const short use_frames); -int BKE_add_image_extension(char *string, const char imtype); +void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame, const struct ImageFormatData *im_format, const short use_ext, const short use_frames); +void BKE_makepicstring_from_type(char *string, const char *base, const char *relbase, int frame, const char imtype, const short use_ext, const short use_frames); +int BKE_add_image_extension(char *string, const struct ImageFormatData *im_format); +int BKE_add_image_extension_from_type(char *string, const char imtype); char BKE_ftype_to_imtype(const int ftype); int BKE_imtype_to_ftype(const char imtype); diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index d7d75b4c4c9..a159cbb13d4 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -59,7 +59,7 @@ void key_curve_position_weights(float t, float data[4], int type); void key_curve_tangent_weights(float t, float data[4], int type); void key_curve_normal_weights(float t, float data[4], int type); -float *do_ob_key(struct Scene *scene, struct Object *ob); +float *BKE_key_evaluate_object(struct Scene *scene, struct Object *ob, int *r_totelem); struct Key *BKE_key_from_object(struct Object *ob); struct KeyBlock *BKE_keyblock_from_object(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 320ced67a2f..db9f1228f76 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -162,8 +162,6 @@ void BKE_mesh_from_nurbs(struct Object *ob); void BKE_mesh_from_nurbs_displist(struct Object *ob, struct ListBase *dispbase, int **orco_index_ptr); void BKE_mesh_from_curve(struct Scene *scene, struct Object *ob); -void free_dverts(struct MDeformVert *dvert, int totvert); -void copy_dverts(struct MDeformVert *dst, const struct MDeformVert *src, int totvert); void BKE_mesh_delete_material_index(struct Mesh *me, short index); void BKE_mesh_smooth_flag_set(struct Object *meshOb, int enableSmooth); void BKE_mesh_convert_mfaces_to_mpolys(struct Mesh *mesh); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index b8f168cbdea..0a2f757b38e 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -557,6 +557,7 @@ struct ShadeResult; #define SH_NODE_BSDF_REFRACTION 173 #define SH_NODE_TANGENT 174 #define SH_NODE_NORMAL_MAP 175 +#define SH_NODE_HAIR_INFO 176 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h index 603cb1f22a6..9dcbb41c7dc 100644 --- a/source/blender/blenkernel/BKE_packedFile.h +++ b/source/blender/blenkernel/BKE_packedFile.h @@ -48,6 +48,7 @@ struct PackedFile *newPackedFile(struct ReportList *reports, const char *filenam struct PackedFile *newPackedFileMemory(void *mem, int memlen); void packAll(struct Main *bmain, struct ReportList *reports); +void packLibraries(struct Main *bmain, struct ReportList *reports); /* unpack */ char *unpackFile(struct ReportList *reports, const char *abs_name, const char *local_name, struct PackedFile *pf, int how); @@ -55,6 +56,7 @@ int unpackVFont(struct ReportList *reports, struct VFont *vfont, int how); int unpackSound(struct Main *bmain, struct ReportList *reports, struct bSound *sound, int how); int unpackImage(struct ReportList *reports, struct Image *ima, int how); void unpackAll(struct Main *bmain, struct ReportList *reports, int how); +int unpackLibraries(struct Main *bmain, struct ReportList *reports); int writePackedFile(struct ReportList *reports, const char *filename, struct PackedFile *pf, int guimode); diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index c452c177143..0a4a7f75e25 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -33,6 +33,7 @@ */ struct bContext; +struct BMesh; struct Brush; struct MDisps; struct MeshElemMap; @@ -92,6 +93,12 @@ typedef struct SculptSession { /* Mesh connectivity */ const struct MeshElemMap *pmap; + /* BMesh for dynamic topology sculpting */ + struct BMesh *bm; + int bm_smooth_shading; + /* Undo/redo log for dynamic topology sculpting */ + struct BMLog *bm_log; + /* PBVH acceleration structure */ struct PBVH *pbvh; int show_diffuse_color; @@ -121,5 +128,6 @@ typedef struct SculptSession { void free_sculptsession(struct Object *ob); void free_sculptsession_deformMats(struct SculptSession *ss); +void sculptsession_bm_to_me(struct Object *ob, int reorder); #endif diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 302de593963..709db7e4570 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -18,8 +18,8 @@ * ***** END GPL LICENSE BLOCK ***** */ -#ifndef __BLI_PBVH_H__ -#define __BLI_PBVH_H__ +#ifndef __BKE_PBVH_H__ +#define __BKE_PBVH_H__ /** \file BKE_pbvh.h * \ingroup bke @@ -27,13 +27,18 @@ */ #include "BLI_bitmap.h" +#include "BLI_ghash.h" +#include "BLI_utildefines.h" + +/* Needed for BMesh functions used in the PBVH iterator macro */ +#include "bmesh.h" struct CCGElem; struct CCGKey; struct CustomData; struct DMFlagMat; struct DMGridAdjacency; -struct ListBase; +struct GHash; struct MFace; struct MVert; struct PBVH; @@ -49,32 +54,35 @@ typedef struct { /* Callbacks */ /* returns 1 if the search should continue from this node, 0 otherwise */ -typedef int (*BLI_pbvh_SearchCallback)(PBVHNode *node, void *data); +typedef int (*BKE_pbvh_SearchCallback)(PBVHNode *node, void *data); -typedef void (*BLI_pbvh_HitCallback)(PBVHNode *node, void *data); -typedef void (*BLI_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *tmin); +typedef void (*BKE_pbvh_HitCallback)(PBVHNode *node, void *data); +typedef void (*BKE_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *tmin); /* Building */ -PBVH *BLI_pbvh_new(void); -void BLI_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts, +PBVH *BKE_pbvh_new(void); +void BKE_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts, int totface, int totvert, struct CustomData *vdata); -void BLI_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems, +void BKE_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems, struct DMGridAdjacency *gridadj, int totgrid, struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden); -void BLI_pbvh_free(PBVH *bvh); +void BKE_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, int smooth_shading, + struct BMLog *log); + +void BKE_pbvh_free(PBVH *bvh); /* Hierarchical Search in the BVH, two methods: * - for each hit calling a callback * - gather nodes in an array (easy to multithread) */ -void BLI_pbvh_search_callback(PBVH *bvh, - BLI_pbvh_SearchCallback scb, void *search_data, - BLI_pbvh_HitCallback hcb, void *hit_data); +void BKE_pbvh_search_callback(PBVH *bvh, + BKE_pbvh_SearchCallback scb, void *search_data, + BKE_pbvh_HitCallback hcb, void *hit_data); -void BLI_pbvh_search_gather(PBVH *bvh, - BLI_pbvh_SearchCallback scb, void *search_data, +void BKE_pbvh_search_gather(PBVH *bvh, + BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot); /* Raycast @@ -82,33 +90,45 @@ void BLI_pbvh_search_gather(PBVH *bvh, * it's up to the callback to find the primitive within the leaves that is * hit first */ -void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data, +void BKE_pbvh_raycast(PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data, const float ray_start[3], const float ray_normal[3], int original); -int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], +int BKE_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco, const float ray_start[3], const float ray_normal[3], float *dist); /* Drawing */ -void BLI_pbvh_node_draw(PBVHNode *node, void *data); -void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], - int (*setMaterial)(int, void *attribs)); +void BKE_pbvh_node_draw(PBVHNode *node, void *data); +void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], + int (*setMaterial)(int, void *attribs), int wireframe); /* PBVH Access */ typedef enum { PBVH_FACES, PBVH_GRIDS, + PBVH_BMESH } PBVHType; -PBVHType BLI_pbvh_type(const PBVH *bvh); +PBVHType BKE_pbvh_type(const PBVH *bvh); /* multires hidden data, only valid for type == PBVH_GRIDS */ -unsigned int **BLI_pbvh_grid_hidden(const PBVH *bvh); +unsigned int **BKE_pbvh_grid_hidden(const PBVH *bvh); /* multires level, only valid for type == PBVH_GRIDS */ -void BLI_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key); +void BKE_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key); + +/* Only valid for type == PBVH_BMESH */ +BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); +void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size); + +typedef enum { + PBVH_Subdivide = 1, + PBVH_Collapse = 2, +} PBVHTopologyUpdateMode; +int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, + const float center[3], float radius); /* Node Access */ @@ -122,45 +142,60 @@ typedef enum { PBVH_UpdateRedraw = 32, PBVH_RebuildDrawBuffers = 64, - PBVH_FullyHidden = 128 + PBVH_FullyHidden = 128, + + PBVH_UpdateTopology = 256, } PBVHNodeFlags; -void BLI_pbvh_node_mark_update(PBVHNode *node); -void BLI_pbvh_node_mark_rebuild_draw(PBVHNode *node); -void BLI_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden); +void BKE_pbvh_node_mark_update(PBVHNode *node); +void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node); +void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden); +void BKE_pbvh_node_mark_topology_update(PBVHNode *node); -void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, +void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, struct CCGElem ***grid_elems, struct DMGridAdjacency **gridadj); -void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, +void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *totvert); -void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, +void BKE_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, int **vert_indices, struct MVert **verts); -void BLI_pbvh_node_get_BB(PBVHNode * node, float bb_min[3], float bb_max[3]); -void BLI_pbvh_node_get_original_BB(PBVHNode * node, float bb_min[3], float bb_max[3]); +void BKE_pbvh_node_get_BB(PBVHNode * node, float bb_min[3], float bb_max[3]); +void BKE_pbvh_node_get_original_BB(PBVHNode * node, float bb_min[3], float bb_max[3]); -float BLI_pbvh_node_get_tmin(PBVHNode *node); +float BKE_pbvh_node_get_tmin(PBVHNode *node); /* test if AABB is at least partially inside the planes' volume */ -int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data); +int BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data); /* test if AABB is at least partially outside the planes' volume */ -int BLI_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data); +int BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data); + +struct GHash *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node); +struct GHash *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node); +void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node); +void BKE_pbvh_bmesh_after_stroke(PBVH *bvh); /* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */ -void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]); -void BLI_pbvh_redraw_BB(PBVH * bvh, float bb_min[3], float bb_max[3]); -void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface); -void BLI_pbvh_grids_update(PBVH *bvh, struct CCGElem **grid_elems, +void BKE_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]); +void BKE_pbvh_redraw_BB(PBVH * bvh, float bb_min[3], float bb_max[3]); +void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface); +void BKE_pbvh_grids_update(PBVH *bvh, struct CCGElem **grid_elems, struct DMGridAdjacency *gridadj, void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden); -/* vertex deformer */ -float (*BLI_pbvh_get_vertCos(struct PBVH *pbvh))[3]; -void BLI_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]); -int BLI_pbvh_isDeformed(struct PBVH *pbvh); +/* Layer displacement */ +/* Get the node's displacement layer, creating it if necessary */ +float *BKE_pbvh_node_layer_disp_get(PBVH *pbvh, PBVHNode *node); + +/* If the node has a displacement layer, free it and set to null */ +void BKE_pbvh_node_layer_disp_free(PBVHNode *node); + +/* vertex deformer */ +float (*BKE_pbvh_get_vertCos(struct PBVH *pbvh))[3]; +void BKE_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]); +int BKE_pbvh_isDeformed(struct PBVH *pbvh); /* Vertex Iterator */ @@ -197,9 +232,15 @@ typedef struct PBVHVertexIter { int *vert_indices; float *vmask; + /* bmesh */ + struct GHashIterator bm_unique_verts; + struct GHashIterator bm_other_verts; + struct CustomData *bm_vdata; + /* result: these are all computed in the macro, but we assume * that compiler optimization's will skip the ones we don't use */ struct MVert *mvert; + struct BMVert *bm_vert; float *co; short *no; float *fno; @@ -213,7 +254,7 @@ typedef struct PBVHVertexIter { void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, PBVHVertexIter *vi, int mode); -#define BLI_pbvh_vertex_iter_begin(bvh, node, vi, mode) \ +#define BKE_pbvh_vertex_iter_begin(bvh, node, vi, mode) \ pbvh_vertex_iter_init(bvh, node, &vi, mode); \ \ for (vi.i = 0, vi.g = 0; vi.g < vi.totgrid; vi.g++) { \ @@ -241,7 +282,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, continue; \ } \ } \ - else { \ + else if (vi.mverts) { \ vi.mvert = &vi.mverts[vi.vert_indices[vi.gx]]; \ if (mode == PBVH_ITER_UNIQUE && vi.mvert->flag & ME_HIDE) \ continue; \ @@ -250,21 +291,39 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, if (vi.vmask) \ vi.mask = &vi.vmask[vi.vert_indices[vi.gx]]; \ } \ + else { \ + if (!BLI_ghashIterator_isDone(&vi.bm_unique_verts)) {\ + vi.bm_vert = BLI_ghashIterator_getKey(&vi.bm_unique_verts); \ + BLI_ghashIterator_step(&vi.bm_unique_verts); \ + } \ + else { \ + vi.bm_vert = BLI_ghashIterator_getKey(&vi.bm_other_verts); \ + BLI_ghashIterator_step(&vi.bm_other_verts); \ + } \ + if (mode == PBVH_ITER_UNIQUE && \ + BM_elem_flag_test(vi.bm_vert, BM_ELEM_HIDDEN)) \ + continue; \ + vi.co = vi.bm_vert->co; \ + vi.fno = vi.bm_vert->no; \ + vi.mask = CustomData_bmesh_get(vi.bm_vdata, \ + vi.bm_vert->head.data, \ + CD_PAINT_MASK); \ + } -#define BLI_pbvh_vertex_iter_end \ +#define BKE_pbvh_vertex_iter_end \ } \ } \ } -void BLI_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count); -void BLI_pbvh_node_free_proxies(PBVHNode *node); -PBVHProxyNode *BLI_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node); -void BLI_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***nodes, int *totnode); +void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count); +void BKE_pbvh_node_free_proxies(PBVHNode *node); +PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node); +void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***nodes, int *totnode); -//void BLI_pbvh_node_BB_reset(PBVHNode *node); -//void BLI_pbvh_node_BB_expand(PBVHNode *node, float co[3]); +//void BKE_pbvh_node_BB_reset(PBVHNode *node); +//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]); void pbvh_show_diffuse_color_set(PBVH *bvh, int show_diffuse_color); -#endif /* __BLI_PBVH_H__ */ +#endif /* __BKE_PBVH_H__ */ diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 8aa08beec57..3c6f886b59a 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -46,6 +46,7 @@ struct bContext; struct bContextDataResult; struct bScreen; struct uiLayout; +struct uiList; struct uiMenuItem; struct wmKeyConfig; struct wmNotifier; @@ -181,6 +182,23 @@ typedef struct PanelType { ExtensionRNA ext; } PanelType; +/* uilist types */ + +/* draw an item in the uiList */ +typedef void (*uiListDrawItemFunc)(struct uiList *, struct bContext *, struct uiLayout *, struct PointerRNA *, + struct PointerRNA *, int, struct PointerRNA *, const char *, int); + +typedef struct uiListType { + struct uiListType *next, *prev; + + char idname[BKE_ST_MAXNAME]; /* unique name */ + + uiListDrawItemFunc draw_item; + + /* RNA integration */ + ExtensionRNA ext; +} uiListType; + /* header types */ typedef struct HeaderType { diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index d1332ba937e..61d82e6c604 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -121,7 +121,8 @@ typedef struct ShrinkwrapCalcData { } ShrinkwrapCalcData; -void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts); +void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, + float (*vertexCos)[3], int numVerts); /* * This function casts a ray in the given BVHTree.. but it takes into consideration the space_transform, that is: @@ -130,9 +131,12 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object * then the input (vert, dir, BVHTreeRayHit) must be defined in ob1 coordinates space * and the BVHTree must be built in ob2 coordinate space. * - * Thus it provides an easy way to cast the same ray across several trees (where each tree was built on its own coords space) + * Thus it provides an easy way to cast the same ray across several trees + * (where each tree was built on its own coords space) */ -int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); +int normal_projection_project_vertex(char options, const float vert[3], const float dir[3], + const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, + BVHTree_RayCastCallback callback, void *userdata); /* * NULL initializers to local data @@ -142,6 +146,4 @@ int normal_projection_project_vertex(char options, const float *vert, const floa #define NULL_BVHTreeRayHit {NULL, } #define NULL_BVHTreeNearest {0, } - -#endif - +#endif /* __BKE_SHRINKWRAP_H__ */ diff --git a/source/blender/blenkernel/BKE_suggestions.h b/source/blender/blenkernel/BKE_suggestions.h index 9b61d9141fb..c36a2d61968 100644 --- a/source/blender/blenkernel/BKE_suggestions.h +++ b/source/blender/blenkernel/BKE_suggestions.h @@ -75,7 +75,7 @@ short texttool_text_is_active(Text *text); /* Suggestions */ void texttool_suggest_add(const char *name, char type); -void texttool_suggest_prefix(const char *prefix); +void texttool_suggest_prefix(const char *prefix, const int prefix_len); void texttool_suggest_clear(void); SuggItem *texttool_suggest_first(void); SuggItem *texttool_suggest_last(void); diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index accac8694a9..1e3dd426efa 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -106,6 +106,7 @@ int text_check_delim(const char ch); int text_check_digit(const char ch); int text_check_identifier(const char ch); int text_check_whitespace(const char ch); +int text_find_identifier_start(const char *str, int i); enum { TXT_MOVE_LINE_UP = -1, diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 7a11bdb1f39..23f23acad6b 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -58,6 +58,7 @@ set(SRC intern/CCGSubSurf.c intern/DerivedMesh.c intern/action.c + intern/addon.c intern/anim.c intern/anim_sys.c intern/armature.c @@ -123,6 +124,7 @@ set(SRC intern/particle.c intern/particle_system.c intern/pbvh.c + intern/pbvh_bmesh.c intern/pointcache.c intern/property.c intern/report.c @@ -152,6 +154,7 @@ set(SRC BKE_DerivedMesh.h BKE_action.h + BKE_addon.h BKE_anim.h BKE_animsys.h BKE_armature.h @@ -242,6 +245,7 @@ set(SRC depsgraph_private.h nla_private.h intern/CCGSubSurf.h + intern/pbvh_intern.h ) add_definitions(-DGLEW_STATIC) @@ -255,7 +259,7 @@ endif() if(WITH_BULLET) list(APPEND INC_SYS - ../../../extern/bullet2/src + ${BULLET_INCLUDE_DIRS} ) add_definitions(-DUSE_BULLET) endif() diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 2dc01513149..ec8d37e1ae3 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1340,6 +1340,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0); int has_multires = mmd != NULL, multires_applied = 0; int sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt; + int sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm); const int draw_flag = ((scene->toolsettings->multipaint ? CALC_WP_MULTIPAINT : 0) | (scene->toolsettings->auto_normalize ? CALC_WP_AUTO_NORMALIZE : 0)); @@ -1407,7 +1408,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos if (!modifier_isEnabled(scene, md, required_mode)) continue; if (useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) continue; - if (mti->type == eModifierTypeType_OnlyDeform) { + if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) { if (!deformedVerts) deformedVerts = mesh_getVertexCos(me, &numVerts); @@ -1465,9 +1466,14 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos modifier_setError(md, "Modifier requires original data, bad stack position"); continue; } - if (sculpt_mode && (!has_multires || multires_applied)) { + if (sculpt_mode && + (!has_multires || multires_applied || ob->sculpt->bm)) + { int unsupported = 0; + if (sculpt_dyntopo) + unsupported = TRUE; + if (scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM) unsupported |= mti->type != eModifierTypeType_OnlyDeform; @@ -2310,20 +2316,19 @@ DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em) static void make_vertexcosnos__mapFunc(void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]) { - float *vec = userData; - - vec += 6 * index; + DMCoNo *co_no = &((DMCoNo *)userData)[index]; /* check if we've been here before (normal should not be 0) */ - if (vec[3] || vec[4] || vec[5]) return; + if (!is_zero_v3(co_no->no)) { + return; + } - copy_v3_v3(vec, co); - vec += 3; + copy_v3_v3(co_no->co, co); if (no_f) { - copy_v3_v3(vec, no_f); + copy_v3_v3(co_no->no, no_f); } else { - normal_short_to_float_v3(vec, no_s); + normal_short_to_float_v3(co_no->no, no_s); } } diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 83d1538ecbe..63e12dfb99d 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -543,7 +543,7 @@ void BKE_pose_copy_data(bPose **dst, bPose *src, int copycon) for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) { /* TODO: rename this argument... */ if (copycon) { - copy_constraints(&listb, &pchan->constraints, TRUE); // copy_constraints NULLs listb + BKE_copy_constraints(&listb, &pchan->constraints, TRUE); // BKE_copy_constraints NULLs listb pchan->constraints = listb; pchan->mpath = NULL; /* motion paths should not get copied yet... */ } @@ -621,7 +621,7 @@ void BKE_pose_channel_free(bPoseChannel *pchan) pchan->mpath = NULL; } - free_constraints(&pchan->constraints); + BKE_free_constraints(&pchan->constraints); if (pchan->prop) { IDP_FreeProperty(pchan->prop); @@ -711,7 +711,7 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f pchan->iklinweight = pchan_from->iklinweight; /* constraints */ - copy_constraints(&pchan->constraints, &pchan_from->constraints, TRUE); + BKE_copy_constraints(&pchan->constraints, &pchan_from->constraints, TRUE); /* id-properties */ if (pchan->prop) { diff --git a/source/blender/blenkernel/intern/addon.c b/source/blender/blenkernel/intern/addon.c new file mode 100644 index 00000000000..7f475cd4732 --- /dev/null +++ b/source/blender/blenkernel/intern/addon.c @@ -0,0 +1,85 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include +#include + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_string.h" + +#include "BKE_addon.h" /* own include */ + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "BLF_translation.h" + +#include "MEM_guardedalloc.h" + +static GHash *global_addonpreftype_hash = NULL; + + +bAddonPrefType *BKE_addon_pref_type_find(const char *idname, int quiet) +{ + if (idname[0]) { + bAddonPrefType *apt; + + apt = BLI_ghash_lookup(global_addonpreftype_hash, idname); + if (apt) { + return apt; + } + + if (!quiet) { + printf("search for unknown addon-pref '%s'\n", idname); + } + } + else { + if (!quiet) { + printf("search for empty addon-pref"); + } + } + + return NULL; +} + +void BKE_addon_pref_type_add(bAddonPrefType *apt) +{ + BLI_ghash_insert(global_addonpreftype_hash, (void *)apt->idname, apt); +} + +void BKE_addon_pref_type_remove(bAddonPrefType *apt) +{ + BLI_ghash_remove(global_addonpreftype_hash, (void *)apt->idname, NULL, (GHashValFreeFP)MEM_freeN); +} + +void BKE_addon_pref_type_init(void) +{ + BLI_assert(global_addonpreftype_hash == NULL); + global_addonpreftype_hash = BLI_ghash_str_new(__func__); +} + +void BKE_addon_pref_type_free(void) +{ + BLI_ghash_free(global_addonpreftype_hash, NULL, (GHashValFreeFP)MEM_freeN); + global_addonpreftype_hash = NULL; +} diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 9155d67dc36..ad14dee168a 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1620,15 +1620,16 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected * 2. copy proxy-pchan's constraints on-to new * 3. add extracted local constraints back on top * - * Note for copy_constraints: when copying constraints, disable 'do_extern' otherwise - * we get the libs direct linked in this blend. */ - extract_proxylocal_constraints(&proxylocal_constraints, &pchan->constraints); - copy_constraints(&pchanw.constraints, &pchanp->constraints, FALSE); + * Note for BKE_copy_constraints: when copying constraints, disable 'do_extern' otherwise + * we get the libs direct linked in this blend. + */ + BKE_extract_proxylocal_constraints(&proxylocal_constraints, &pchan->constraints); + BKE_copy_constraints(&pchanw.constraints, &pchanp->constraints, FALSE); BLI_movelisttolist(&pchanw.constraints, &proxylocal_constraints); /* constraints - set target ob pointer to own object */ for (con = pchanw.constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -2426,15 +2427,15 @@ void BKE_pose_where_is_bone(Scene *scene, Object *ob, bPoseChannel *pchan, float /* prepare PoseChannel for Constraint solving * - makes a copy of matrix, and creates temporary struct to use */ - cob = constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE); + cob = BKE_constraints_make_evalob(scene, ob, pchan, CONSTRAINT_OBTYPE_BONE); /* Solve PoseChannel's Constraints */ - solve_constraints(&pchan->constraints, cob, ctime); /* ctime doesnt alter objects */ + BKE_solve_constraints(&pchan->constraints, cob, ctime); /* ctime doesnt alter objects */ /* cleanup after Constraint Solving * - applies matrix back to pchan, and frees temporary struct used */ - constraints_clear_evalob(cob); + BKE_constraints_clear_evalob(cob); /* prevent constraints breaking a chain */ if (pchan->bone->flag & BONE_CONNECTED) { diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 5c0856bc95b..11ae242023c 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -387,6 +387,7 @@ void BKE_userdef_free(void) wmKeyMap *km; wmKeyMapItem *kmi; wmKeyMapDiffItem *kmdi; + bAddon *addon, *addon_next; for (km = U.user_keymaps.first; km; km = km->next) { for (kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) { @@ -407,11 +408,19 @@ void BKE_userdef_free(void) BLI_freelistN(&km->items); } + for (addon = U.addons.first; addon; addon = addon_next) { + addon_next = addon->next; + if (addon->prop) { + IDP_FreeProperty(addon->prop); + MEM_freeN(addon->prop); + } + MEM_freeN(addon); + } + BLI_freelistN(&U.uistyles); BLI_freelistN(&U.uifonts); BLI_freelistN(&U.themes); BLI_freelistN(&U.user_keymaps); - BLI_freelistN(&U.addons); } /* handle changes in settings that need recalc */ diff --git a/source/blender/blenkernel/intern/bmfont.c b/source/blender/blenkernel/intern/bmfont.c index 0495e729937..fc83b24da5b 100644 --- a/source/blender/blenkernel/intern/bmfont.c +++ b/source/blender/blenkernel/intern/bmfont.c @@ -65,8 +65,8 @@ void printfGlyph(bmGlyph * glyph) printf(" advan: %3d reser: %3d\n", glyph->advance, glyph->reserved); } -#define MAX2(x,y) ((x) > (y) ? (x) : (y)) -#define MAX3(x,y,z) MAX2(MAX2((x), (y)), (z)) +#define MAX2(x, y) ((x) > (y) ? (x) : (y)) +#define MAX3(x, y, z) (MAX2(MAX2((x), (y)), (z))) void calcAlpha(ImBuf * ibuf) { diff --git a/source/blender/blenkernel/intern/booleanops_mesh.c b/source/blender/blenkernel/intern/booleanops_mesh.c index 461b945282f..f53a89fccfd 100644 --- a/source/blender/blenkernel/intern/booleanops_mesh.c +++ b/source/blender/blenkernel/intern/booleanops_mesh.c @@ -56,7 +56,7 @@ CSG_DestroyBlenderMeshInternals( CSG_MeshDescriptor *mesh ) { /* Free face and vertex iterators. */ - FreeMeshDescriptors(&(mesh->m_face_iterator),&(mesh->m_vertex_iterator)); + FreeMeshDescriptors(&(mesh->m_face_iterator), &(mesh->m_vertex_iterator)); } @@ -138,7 +138,7 @@ CSG_AddMeshToBlender( if (mesh == NULL) return 0; if (mesh->base == NULL) return 0; - invert_m4_m4(inv_mat,mesh->base->object->obmat); + invert_m4_m4(inv_mat, mesh->base->object->obmat); /* Create a new blender mesh object - using 'base' as * a template for the new object. */ @@ -191,7 +191,7 @@ CSG_PerformOp( default : op_type = e_csg_intersection; } - output->m_descriptor = CSG_DescibeOperands(bool_op,mesh1->m_descriptor,mesh2->m_descriptor); + output->m_descriptor = CSG_DescibeOperands(bool_op, mesh1->m_descriptor, mesh2->m_descriptor); output->base = mesh1->base; if (output->m_descriptor.user_face_vertex_data_size) { @@ -228,8 +228,8 @@ CSG_PerformOp( /* get the ouput mesh descriptors. */ - CSG_OutputFaceDescriptor(bool_op,&(output->m_face_iterator)); - CSG_OutputVertexDescriptor(bool_op,&(output->m_vertex_iterator)); + CSG_OutputFaceDescriptor(bool_op, &(output->m_face_iterator)); + CSG_OutputVertexDescriptor(bool_op, &(output->m_vertex_iterator)); output->m_destroy_func = CSG_DestroyCSGMeshInternals; return 1; @@ -242,20 +242,20 @@ NewBooleanMeshTest( int op_type ) { - CSG_MeshDescriptor m1,m2,output; - CSG_MeshDescriptor output2,output3; + CSG_MeshDescriptor m1, m2, output; + CSG_MeshDescriptor output2, output3; - if (!MakeCSGMeshFromBlenderBase(base,&m1)) { + if (!MakeCSGMeshFromBlenderBase(base, &m1)) { return 0; } - if (!MakeCSGMeshFromBlenderBase(base_select,&m2)) { + if (!MakeCSGMeshFromBlenderBase(base_select, &m2)) { return 0; } - CSG_PerformOp(&m1,&m2,1,&output); - CSG_PerformOp(&m1,&m2,2,&output2); - CSG_PerformOp(&m1,&m2,3,&output3); + CSG_PerformOp(&m1, &m2, 1, &output); + CSG_PerformOp(&m1, &m2, 2, &output2); + CSG_PerformOp(&m1, &m2, 3, &output3); if (!CSG_AddMeshToBlender(&output)) { return 0; diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 0d44f5cad6f..6db1052d6bd 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -603,8 +603,11 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int case ID_LI: { Library *lib = (Library *)id; - if (rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) { - BKE_library_filepath_set(lib, lib->name); + /* keep packedfile paths always relative to the blend */ + if (lib->packedfile == NULL) { + if (rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) { + BKE_library_filepath_set(lib, lib->name); + } } break; } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 405b1efb25d..aeb0407b37f 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -29,29 +29,16 @@ * \ingroup bke */ - -#include -#include - #include "MEM_guardedalloc.h" #include "DNA_brush_types.h" -#include "DNA_color_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" -#include "DNA_userdef_types.h" -#include "DNA_windowmanager_types.h" - -#include "WM_types.h" - -#include "RNA_access.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_rand.h" -#include "BLI_utildefines.h" -#include "BKE_blender.h" #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_global.h" @@ -66,7 +53,6 @@ #include "IMB_imbuf_types.h" #include "RE_render_ext.h" /* externtex */ -#include "RE_shader_ext.h" static void brush_defaults(Brush *brush) { @@ -696,7 +682,7 @@ float BKE_brush_unprojected_radius_get(const Scene *scene, Brush *brush) brush->unprojected_radius; } -static void brush_alpha_set(Scene *scene, Brush *brush, float alpha) +void BKE_brush_alpha_set(Scene *scene, Brush *brush, float alpha) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; @@ -754,315 +740,6 @@ void BKE_brush_scale_size(int *r_brush_size, (*r_brush_size) = (int)((float)(*r_brush_size) * scale); } -/* Brush Painting */ - -typedef struct BrushPainterCache { - short enabled; - - int size; /* size override, if 0 uses 2*BKE_brush_size_get(brush) */ - short flt; /* need float imbuf? */ - short texonly; /* no alpha, color or fallof, only texture in imbuf */ - - int lastsize; - float lastalpha; - float lastjitter; - - ImBuf *ibuf; - ImBuf *texibuf; - ImBuf *maskibuf; -} BrushPainterCache; - -struct BrushPainter { - Scene *scene; - Brush *brush; - - float lastmousepos[2]; /* mouse position of last paint call */ - - float accumdistance; /* accumulated distance of brush since last paint op */ - float lastpaintpos[2]; /* position of last paint op */ - float startpaintpos[2]; /* position of first paint */ - - double accumtime; /* accumulated time since last paint op (airbrush) */ - double lasttime; /* time of last update */ - - float lastpressure; - - short firsttouch; /* first paint op */ - - float startsize; - float startalpha; - float startjitter; - float startspacing; - - BrushPainterCache cache; -}; - -BrushPainter *BKE_brush_painter_new(Scene *scene, Brush *brush) -{ - BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter"); - - painter->brush = brush; - painter->scene = scene; - painter->firsttouch = 1; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ - - painter->startsize = BKE_brush_size_get(scene, brush); - painter->startalpha = BKE_brush_alpha_get(scene, brush); - painter->startjitter = brush->jitter; - painter->startspacing = brush->spacing; - - return painter; -} - -void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size) -{ - if ((painter->cache.flt != flt) || (painter->cache.size != size) || - ((painter->cache.texonly != texonly) && texonly)) - { - if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); - if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); - painter->cache.ibuf = painter->cache.maskibuf = NULL; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ - } - - if (painter->cache.flt != flt) { - if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); - painter->cache.texibuf = NULL; - painter->cache.lastsize = -1; /* force ibuf create in refresh */ - } - - painter->cache.size = size; - painter->cache.flt = flt; - painter->cache.texonly = texonly; - painter->cache.enabled = 1; -} - -void BKE_brush_painter_free(BrushPainter *painter) -{ - Brush *brush = painter->brush; - - BKE_brush_size_set(painter->scene, brush, painter->startsize); - brush_alpha_set(painter->scene, brush, painter->startalpha); - brush->jitter = painter->startjitter; - brush->spacing = painter->startspacing; - - if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf); - if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf); - if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf); - MEM_freeN(painter); -} - -static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, - int x, int y, int w, int h, int xt, int yt, - const float pos[2]) -{ - Scene *scene = painter->scene; - Brush *brush = painter->brush; - ImBuf *ibuf, *maskibuf, *texibuf; - float *bf, *mf, *tf, *otf = NULL, xoff, yoff, xy[2], rgba[4]; - unsigned char *b, *m, *t, *ot = NULL; - int dotexold, origx = x, origy = y; - const int radius = BKE_brush_size_get(painter->scene, brush); - - xoff = -radius + 0.5f; - yoff = -radius + 0.5f; - xoff += (int)pos[0] - (int)painter->startpaintpos[0]; - yoff += (int)pos[1] - (int)painter->startpaintpos[1]; - - ibuf = painter->cache.ibuf; - texibuf = painter->cache.texibuf; - maskibuf = painter->cache.maskibuf; - - dotexold = (oldtexibuf != NULL); - - /* not sure if it's actually needed or it's a mistake in coords/sizes - * calculation in brush_painter_fixed_tex_partial_update(), but without this - * limitation memory gets corrupted at fast strokes with quite big spacing (sergey) */ - w = min_ii(w, ibuf->x); - h = min_ii(h, ibuf->y); - - if (painter->cache.flt) { - for (; y < h; y++) { - bf = ibuf->rect_float + (y * ibuf->x + origx) * 4; - tf = texibuf->rect_float + (y * texibuf->x + origx) * 4; - mf = maskibuf->rect_float + (y * maskibuf->x + origx) * 4; - - if (dotexold) - otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + xt) * 4; - - for (x = origx; x < w; x++, bf += 4, mf += 4, tf += 4) { - if (dotexold) { - copy_v3_v3(tf, otf); - tf[3] = otf[3]; - otf += 4; - } - else { - xy[0] = x + xoff; - xy[1] = y + yoff; - - BKE_brush_sample_tex(scene, brush, xy, tf, 0); - } - - bf[0] = tf[0] * mf[0]; - bf[1] = tf[1] * mf[1]; - bf[2] = tf[2] * mf[2]; - bf[3] = tf[3] * mf[3]; - } - } - } - else { - for (; y < h; y++) { - b = (unsigned char *)ibuf->rect + (y * ibuf->x + origx) * 4; - t = (unsigned char *)texibuf->rect + (y * texibuf->x + origx) * 4; - m = (unsigned char *)maskibuf->rect + (y * maskibuf->x + origx) * 4; - - if (dotexold) - ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + xt) * 4; - - for (x = origx; x < w; x++, b += 4, m += 4, t += 4) { - if (dotexold) { - t[0] = ot[0]; - t[1] = ot[1]; - t[2] = ot[2]; - t[3] = ot[3]; - ot += 4; - } - else { - xy[0] = x + xoff; - xy[1] = y + yoff; - - BKE_brush_sample_tex(scene, brush, xy, rgba, 0); - rgba_float_to_uchar(t, rgba); - } - - b[0] = t[0] * m[0] / 255; - b[1] = t[1] * m[1] / 255; - b[2] = t[2] * m[2] / 255; - b[3] = t[3] * m[3] / 255; - } - } - } -} - -static void brush_painter_fixed_tex_partial_update(BrushPainter *painter, const float pos[2]) -{ - const Scene *scene = painter->scene; - Brush *brush = painter->brush; - BrushPainterCache *cache = &painter->cache; - ImBuf *oldtexibuf, *ibuf; - int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2; - const int diameter = 2 * BKE_brush_size_get(scene, brush); - - imbflag = (cache->flt) ? IB_rectfloat : IB_rect; - if (!cache->ibuf) - cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag); - ibuf = cache->ibuf; - - oldtexibuf = cache->texibuf; - cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag); - - if (oldtexibuf) { - srcx = srcy = 0; - destx = (int)painter->lastpaintpos[0] - (int)pos[0]; - desty = (int)painter->lastpaintpos[1] - (int)pos[1]; - w = oldtexibuf->x; - h = oldtexibuf->y; - - IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h); - } - else { - srcx = srcy = 0; - destx = desty = 0; - w = h = 0; - } - - x1 = destx; - y1 = desty; - x2 = destx + w; - y2 = desty + h; - - /* blend existing texture in new position */ - if ((x1 < x2) && (y1 < y2)) - brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos); - - if (oldtexibuf) - IMB_freeImBuf(oldtexibuf); - - /* sample texture in new areas */ - if ((0 < x1) && (0 < ibuf->y)) - brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos); - if ((x2 < ibuf->x) && (0 < ibuf->y)) - brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos); - if ((x1 < x2) && (0 < y1)) - brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos); - if ((x1 < x2) && (y2 < ibuf->y)) - brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos); -} - -static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction) -{ - const Scene *scene = painter->scene; - Brush *brush = painter->brush; - BrushPainterCache *cache = &painter->cache; - MTex *mtex = &brush->mtex; - int size; - short flt; - const int diameter = 2 * BKE_brush_size_get(scene, brush); - const float alpha = BKE_brush_alpha_get(scene, brush); - - if (diameter != cache->lastsize || - alpha != cache->lastalpha || - brush->jitter != cache->lastjitter) - { - if (cache->ibuf) { - IMB_freeImBuf(cache->ibuf); - cache->ibuf = NULL; - } - if (cache->maskibuf) { - IMB_freeImBuf(cache->maskibuf); - cache->maskibuf = NULL; - } - - flt = cache->flt; - size = (cache->size) ? cache->size : diameter; - - if (brush->flag & BRUSH_FIXED_TEX) { - BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction); - brush_painter_fixed_tex_partial_update(painter, pos); - } - else - BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction); - - cache->lastsize = diameter; - cache->lastalpha = alpha; - cache->lastjitter = brush->jitter; - } - else if ((brush->flag & BRUSH_FIXED_TEX) && mtex && mtex->tex) { - int dx = (int)painter->lastpaintpos[0] - (int)pos[0]; - int dy = (int)painter->lastpaintpos[1] - (int)pos[1]; - - if ((dx != 0) || (dy != 0)) - brush_painter_fixed_tex_partial_update(painter, pos); - } -} - -void BKE_brush_painter_break_stroke(BrushPainter *painter) -{ - painter->firsttouch = 1; -} - -static void brush_pressure_apply(BrushPainter *painter, Brush *brush, float pressure) -{ - if (BKE_brush_use_alpha_pressure(painter->scene, brush)) - brush_alpha_set(painter->scene, brush, max_ff(0.0f, painter->startalpha * pressure)); - if (BKE_brush_use_size_pressure(painter->scene, brush)) - BKE_brush_size_set(painter->scene, brush, max_ff(1.0f, painter->startsize * pressure)); - if (brush->flag & BRUSH_JITTER_PRESSURE) - brush->jitter = max_ff(0.0f, painter->startjitter * pressure); - if (brush->flag & BRUSH_SPACING_PRESSURE) - brush->spacing = max_ff(1.0f, painter->startspacing * (1.5f - pressure)); -} - void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], float jitterpos[2]) { int use_jitter = brush->jitter != 0; @@ -1090,165 +767,6 @@ void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], } } -int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float pos[2], double time, float pressure, - void *user, int use_color_correction) -{ - Scene *scene = painter->scene; - Brush *brush = painter->brush; - int totpaintops = 0; - - if (pressure == 0.0f) { - if (painter->lastpressure) // XXX - hack, operator misses - pressure = painter->lastpressure; - else - pressure = 1.0f; /* zero pressure == not using tablet */ - } - if (painter->firsttouch) { - /* paint exactly once on first touch */ - painter->startpaintpos[0] = pos[0]; - painter->startpaintpos[1] = pos[1]; - - brush_pressure_apply(painter, brush, pressure); - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, pos, use_color_correction); - totpaintops += func(user, painter->cache.ibuf, pos, pos); - - painter->lasttime = time; - painter->firsttouch = 0; - painter->lastpaintpos[0] = pos[0]; - painter->lastpaintpos[1] = pos[1]; - } -#if 0 - else if (painter->brush->flag & BRUSH_AIRBRUSH) { - float spacing, step, paintpos[2], dmousepos[2], len; - double starttime, curtime = time; - - /* compute brush spacing adapted to brush size */ - spacing = brush->rate; //radius*brush->spacing*0.01f; - - /* setup starting time, direction vector and accumulated time */ - starttime = painter->accumtime; - sub_v2_v2v2(dmousepos, pos, painter->lastmousepos); - len = normalize_v2(dmousepos); - painter->accumtime += curtime - painter->lasttime; - - /* do paint op over unpainted time distance */ - while (painter->accumtime >= spacing) { - step = (spacing - starttime) * len; - paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step; - paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step; - - if (painter->cache.enabled) - brush_painter_refresh_cache(painter); - totpaintops += func(user, painter->cache.ibuf, - painter->lastpaintpos, paintpos); - - painter->lastpaintpos[0] = paintpos[0]; - painter->lastpaintpos[1] = paintpos[1]; - painter->accumtime -= spacing; - starttime -= spacing; - } - - painter->lasttime = curtime; - } -#endif - else { - float startdistance, spacing, step, paintpos[2], dmousepos[2], finalpos[2]; - float t, len, press; - const int radius = BKE_brush_size_get(scene, brush); - - /* compute brush spacing adapted to brush radius, spacing may depend - * on pressure, so update it */ - brush_pressure_apply(painter, brush, painter->lastpressure); - spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f; - - /* setup starting distance, direction vector and accumulated distance */ - startdistance = painter->accumdistance; - sub_v2_v2v2(dmousepos, pos, painter->lastmousepos); - len = normalize_v2(dmousepos); - painter->accumdistance += len; - - if (brush->flag & BRUSH_SPACE) { - /* do paint op over unpainted distance */ - while ((len > 0.0f) && (painter->accumdistance >= spacing)) { - step = spacing - startdistance; - paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step; - paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step; - - t = step / len; - press = (1.0f - t) * painter->lastpressure + t * pressure; - brush_pressure_apply(painter, brush, press); - spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f; - - BKE_brush_jitter_pos(scene, brush, paintpos, finalpos); - - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos, use_color_correction); - - totpaintops += - func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos); - - painter->lastpaintpos[0] = paintpos[0]; - painter->lastpaintpos[1] = paintpos[1]; - painter->accumdistance -= spacing; - startdistance -= spacing; - } - } - else { - BKE_brush_jitter_pos(scene, brush, pos, finalpos); - - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos, use_color_correction); - - totpaintops += func(user, painter->cache.ibuf, pos, finalpos); - - painter->lastpaintpos[0] = pos[0]; - painter->lastpaintpos[1] = pos[1]; - painter->accumdistance = 0; - } - - /* do airbrush paint ops, based on the number of paint ops left over - * from regular painting. this is a temporary solution until we have - * accurate time stamps for mouse move events */ - if (brush->flag & BRUSH_AIRBRUSH) { - double curtime = time; - double painttime = brush->rate * totpaintops; - - painter->accumtime += curtime - painter->lasttime; - if (painter->accumtime <= painttime) - painter->accumtime = 0.0; - else - painter->accumtime -= painttime; - - while (painter->accumtime >= (double)brush->rate) { - brush_pressure_apply(painter, brush, pressure); - - BKE_brush_jitter_pos(scene, brush, pos, finalpos); - - if (painter->cache.enabled) - brush_painter_refresh_cache(painter, finalpos, use_color_correction); - - totpaintops += - func(user, painter->cache.ibuf, painter->lastmousepos, finalpos); - painter->accumtime -= (double)brush->rate; - } - - painter->lasttime = curtime; - } - } - - painter->lastmousepos[0] = pos[0]; - painter->lastmousepos[1] = pos[1]; - painter->lastpressure = pressure; - - brush_alpha_set(scene, brush, painter->startalpha); - BKE_brush_size_set(scene, brush, painter->startsize); - brush->jitter = painter->startjitter; - brush->spacing = painter->startspacing; - - return totpaintops; -} - /* Uses the brush curve control to find a strength value between 0 and 1 */ float BKE_brush_curve_strength_clamp(Brush *br, float p, const float len) { @@ -1275,48 +793,6 @@ float BKE_brush_curve_strength(Brush *br, float p, const float len) return curvemapping_evaluateF(br->curve, 0, p); } -/* TODO: should probably be unified with BrushPainter stuff? */ -unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side) -{ - unsigned int *texcache = NULL; - MTex *mtex = &br->mtex; - TexResult texres = {0}; - int hasrgb, ix, iy; - int side = half_side * 2; - - if (mtex->tex) { - float x, y, step = 2.0 / side, co[3]; - - texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache"); - - /*do normalized cannonical view coords for texture*/ - for (y = -1.0, iy = 0; iy < side; iy++, y += step) { - for (x = -1.0, ix = 0; ix < side; ix++, x += step) { - co[0] = x; - co[1] = y; - co[2] = 0.0f; - - /* This is copied from displace modifier code */ - hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres); - - /* if the texture gave an RGB value, we assume it didn't give a valid - * intensity, so calculate one (formula from do_material_tex). - * if the texture didn't give an RGB value, copy the intensity across - */ - if (hasrgb & TEX_RGB) - texres.tin = rgb_to_grayscale(&texres.tr); - - ((char *)texcache)[(iy * side + ix) * 4] = - ((char *)texcache)[(iy * side + ix) * 4 + 1] = - ((char *)texcache)[(iy * side + ix) * 4 + 2] = - ((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(texres.tin * 255.0f); - } - } - } - - return texcache; -} - /**** Radial Control ****/ struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br) { diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 61d0936d41d..51890851ebc 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -262,6 +262,17 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) cddm->pbvh_draw = can_pbvh_draw(ob, dm); } + /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH */ + if (!cddm->pbvh && ob->sculpt->bm) { + cddm->pbvh = BKE_pbvh_new(); + cddm->pbvh_draw = TRUE; + + BKE_pbvh_build_bmesh(cddm->pbvh, ob->sculpt->bm, + ob->sculpt->bm_smooth_shading, + ob->sculpt->bm_log); + } + + /* always build pbvh from original mesh, and only use it for drawing if * this derivedmesh is just original mesh. it's the multires subsurf dm * that this is actually for, to support a pbvh on a modified mesh */ @@ -270,14 +281,14 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) Mesh *me = ob->data; int deformed = 0; - cddm->pbvh = BLI_pbvh_new(); + cddm->pbvh = BKE_pbvh_new(); cddm->pbvh_draw = can_pbvh_draw(ob, dm); pbvh_show_diffuse_color_set(cddm->pbvh, ob->sculpt->show_diffuse_color); BKE_mesh_tessface_ensure(me); - BLI_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert, + BKE_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert, me->totface, me->totvert, &me->vdata); deformed = ss->modifiers_active || me->key; @@ -290,7 +301,7 @@ static PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm) totvert = deformdm->getNumVerts(deformdm); vertCos = MEM_callocN(3 * totvert * sizeof(float), "cdDM_getPBVH vertCos"); deformdm->getVertCos(deformdm, vertCos); - BLI_pbvh_apply_vertCos(cddm->pbvh, vertCos); + BKE_pbvh_apply_vertCos(cddm->pbvh, vertCos); MEM_freeN(vertCos); } } @@ -310,7 +321,7 @@ static void cdDM_update_normals_from_pbvh(DerivedMesh *dm) face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL); - BLI_pbvh_update(cddm->pbvh, PBVH_UpdateNormals, face_nors); + BKE_pbvh_update(cddm->pbvh, PBVH_UpdateNormals, face_nors); } static void cdDM_drawVerts(DerivedMesh *dm) @@ -414,6 +425,14 @@ static void cdDM_drawEdges(DerivedMesh *dm, int drawLooseEdges, int drawAllEdges MVert *mvert = cddm->mvert; MEdge *medge = cddm->medge; int i; + + if (cddm->pbvh && cddm->pbvh_draw && + BKE_pbvh_type(cddm->pbvh) == PBVH_BMESH) + { + BKE_pbvh_draw(cddm->pbvh, NULL, NULL, NULL, TRUE); + + return; + } if (GPU_buffer_legacy(dm)) { DEBUG_VBO("Using legacy code. cdDM_drawEdges\n"); @@ -530,7 +549,8 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, if (dm->numTessFaceData) { float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL); - BLI_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, setMaterial); + BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, + setMaterial, FALSE); glShadeModel(GL_FLAT); } @@ -664,8 +684,9 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, } else { if (nors) { - nors += 3; continue; + nors += 3; } + continue; } } else if (drawParamsMapped) { @@ -673,8 +694,9 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm, } else { if (nors) { - nors += 3; continue; + nors += 3; } + continue; } } diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index f1d73c7777a..fdd7dc94979 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -1153,7 +1153,7 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm ) if ( !mface[i].v4 ) continue; - spring = ( ClothSpring *) MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" ); + spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring"); if (!spring) { cloth_free_errorsprings(cloth, edgehash, edgelist); diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index f0043d9fa77..60bf67e19e3 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -528,7 +528,7 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned /* extend array */ if (*numobj >= *maxobj) { *maxobj *= 2; - *objs= MEM_reallocN(*objs, sizeof(Object*)*(*maxobj)); + *objs= MEM_reallocN(*objs, sizeof(Object *)*(*maxobj)); } (*objs)[*numobj] = ob; @@ -740,7 +740,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData * clmd, float step, flo /* move object to position (step) in time */ for (i = 0; i < numcollobj; i++) { Object *collob= collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData*)modifiers_findByType(collob, eModifierType_Collision); + CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); if (!collmd->bvhtree) continue; @@ -760,7 +760,7 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData * clmd, float step, flo // check all collision objects for (i = 0; i < numcollobj; i++) { Object *collob= collobjs[i]; - CollisionModifierData *collmd = (CollisionModifierData*)modifiers_findByType(collob, eModifierType_Collision); + CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision); BVHTreeOverlap *overlap = NULL; unsigned int result = 0; diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index c3aab22fe5a..1a25def3829 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -96,7 +96,7 @@ /* -------------- Naming -------------- */ /* Find the first available, non-duplicate name for a given constraint */ -void unique_constraint_name(bConstraint *con, ListBase *list) +void BKE_unique_constraint_name(bConstraint *con, ListBase *list) { BLI_uniquename(list, con, "Const", '.', offsetof(bConstraint, name), sizeof(con->name)); } @@ -105,7 +105,7 @@ void unique_constraint_name(bConstraint *con, ListBase *list) /* package an object/bone for use in constraint evaluation */ /* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */ -bConstraintOb *constraints_make_evalob(Scene *scene, Object *ob, void *subdata, short datatype) +bConstraintOb *BKE_constraints_make_evalob(Scene *scene, Object *ob, void *subdata, short datatype) { bConstraintOb *cob; @@ -169,7 +169,7 @@ bConstraintOb *constraints_make_evalob(Scene *scene, Object *ob, void *subdata, } /* cleanup after constraint evaluation */ -void constraints_clear_evalob(bConstraintOb *cob) +void BKE_constraints_clear_evalob(bConstraintOb *cob) { float delta[4][4], imat[4][4]; @@ -219,7 +219,7 @@ void constraints_clear_evalob(bConstraintOb *cob) * of a matrix from one space to another for constraint evaluation. * For now, this is only implemented for Objects and PoseChannels. */ -void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to) +void BKE_constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to) { float diff_mat[4][4]; float imat[4][4]; @@ -242,7 +242,7 @@ void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4 /* use pose-space as stepping stone for other spaces... */ if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) { /* call self with slightly different values */ - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); } } break; @@ -278,7 +278,7 @@ void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4 /* use pose-space as stepping stone for other spaces */ if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) { /* call self with slightly different values */ - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); } } break; @@ -293,7 +293,7 @@ void constraint_mat_convertspace(Object *ob, bPoseChannel *pchan, float mat[4][4 /* use pose-space as stepping stone for other spaces */ if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) { /* call self with slightly different values */ - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to); } } break; @@ -499,7 +499,7 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m /* Case OBJECT */ if (!strlen(substring)) { copy_m4_m4(mat, ob->obmat); - constraint_mat_convertspace(ob, NULL, mat, from, to); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); } /* Case VERTEXGROUP */ /* Current method just takes the average location of all the points in the @@ -512,11 +512,11 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m */ else if (ob->type == OB_MESH) { contarget_get_mesh_mat(ob, substring, mat); - constraint_mat_convertspace(ob, NULL, mat, from, to); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); } else if (ob->type == OB_LATTICE) { contarget_get_lattice_mat(ob, substring, mat); - constraint_mat_convertspace(ob, NULL, mat, from, to); + BKE_constraint_mat_convertspace(ob, NULL, mat, from, to); } /* Case BONE */ else { @@ -549,7 +549,7 @@ static void constraint_target_to_mat4(Object *ob, const char *substring, float m copy_m4_m4(mat, ob->obmat); /* convert matrix space as required */ - constraint_mat_convertspace(ob, pchan, mat, from, to); + BKE_constraint_mat_convertspace(ob, pchan, mat, from, to); } } @@ -4211,7 +4211,7 @@ static void constraints_init_typeinfo(void) /* This function should be used for getting the appropriate type-info when only * a constraint type is known */ -bConstraintTypeInfo *get_constraint_typeinfo(int type) +bConstraintTypeInfo *BKE_get_constraint_typeinfo(int type) { /* initialize the type-info list? */ if (CTI_INIT) { @@ -4236,11 +4236,11 @@ bConstraintTypeInfo *get_constraint_typeinfo(int type) /* This function should always be used to get the appropriate type-info, as it * has checks which prevent segfaults in some weird cases. */ -bConstraintTypeInfo *constraint_get_typeinfo(bConstraint *con) +bConstraintTypeInfo *BKE_constraint_get_typeinfo(bConstraint *con) { /* only return typeinfo for valid constraints */ if (con) - return get_constraint_typeinfo(con->type); + return BKE_get_constraint_typeinfo(con->type); else return NULL; } @@ -4252,7 +4252,7 @@ bConstraintTypeInfo *constraint_get_typeinfo(bConstraint *con) /* ---------- Data Management ------- */ -/* helper function for free_constraint_data() - unlinks references */ +/* helper function for BKE_free_constraint_data() - unlinks references */ static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, short isReference, void *UNUSED(userData)) { if (*idpoin && isReference) @@ -4263,10 +4263,10 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con), ID **idpoin, short isRe * be sure to run BIK_clear_data() when freeing an IK constraint, * unless DAG_scene_sort is called. */ -void free_constraint_data(bConstraint *con) +void BKE_free_constraint_data(bConstraint *con) { if (con->data) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (cti) { /* perform any special freeing constraint may have */ @@ -4284,13 +4284,13 @@ void free_constraint_data(bConstraint *con) } /* Free all constraints from a constraint-stack */ -void free_constraints(ListBase *list) +void BKE_free_constraints(ListBase *list) { bConstraint *con; /* Free constraint data and also any extra data */ for (con = list->first; con; con = con->next) - free_constraint_data(con); + BKE_free_constraint_data(con); /* Free the whole list */ BLI_freelistN(list); @@ -4298,10 +4298,10 @@ void free_constraints(ListBase *list) /* Remove the specified constraint from the given constraint stack */ -int remove_constraint(ListBase *list, bConstraint *con) +int BKE_remove_constraint(ListBase *list, bConstraint *con) { if (con) { - free_constraint_data(con); + BKE_free_constraint_data(con); BLI_freelinkN(list, con); return 1; } @@ -4310,7 +4310,7 @@ int remove_constraint(ListBase *list, bConstraint *con) } /* Remove all the constraints of the specified type from the given constraint stack */ -void remove_constraints_type(ListBase *list, short type, short last_only) +void BKE_remove_constraints_type(ListBase *list, short type, short last_only) { bConstraint *con, *conp; @@ -4322,7 +4322,7 @@ void remove_constraints_type(ListBase *list, short type, short last_only) conp = con->prev; if (con->type == type) { - remove_constraint(list, con); + BKE_remove_constraint(list, con); if (last_only) return; } @@ -4335,7 +4335,7 @@ void remove_constraints_type(ListBase *list, short type, short last_only) static bConstraint *add_new_constraint_internal(const char *name, short type) { bConstraint *con = MEM_callocN(sizeof(bConstraint), "Constraint"); - bConstraintTypeInfo *cti = get_constraint_typeinfo(type); + bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(type); const char *newName; /* Set up a generic constraint datablock */ @@ -4385,17 +4385,17 @@ static bConstraint *add_new_constraint(Object *ob, bPoseChannel *pchan, const ch * (otherwise unique-naming code will fail, since it assumes element exists in list) */ BLI_addtail(list, con); - unique_constraint_name(con, list); + BKE_unique_constraint_name(con, list); /* if the target list is a list on some PoseChannel belonging to a proxy-protected * Armature layer, we must tag newly added constraints with a flag which allows them * to persist after proxy syncing has been done */ - if (proxylocked_constraints_owner(ob, pchan)) + if (BKE_proxylocked_constraints_owner(ob, pchan)) con->flag |= CONSTRAINT_PROXY_LOCAL; /* make this constraint the active one */ - constraints_set_active(list, con); + BKE_constraints_set_active(list, con); } /* set type+owner specific immutable settings */ @@ -4419,7 +4419,7 @@ static bConstraint *add_new_constraint(Object *ob, bPoseChannel *pchan, const ch /* ......... */ /* Add new constraint for the given bone */ -bConstraint *add_pose_constraint(Object *ob, bPoseChannel *pchan, const char *name, short type) +bConstraint *BKE_add_pose_constraint(Object *ob, bPoseChannel *pchan, const char *name, short type) { if (pchan == NULL) return NULL; @@ -4428,14 +4428,14 @@ bConstraint *add_pose_constraint(Object *ob, bPoseChannel *pchan, const char *na } /* Add new constraint for the given object */ -bConstraint *add_ob_constraint(Object *ob, const char *name, short type) +bConstraint *BKE_add_ob_constraint(Object *ob, const char *name, short type) { return add_new_constraint(ob, NULL, name, type); } /* ......... */ -/* helper for relink_constraints() - call ID_NEW() on every ID reference the constraint has */ +/* helper for BKE_relink_constraints() - call ID_NEW() on every ID reference the constraint has */ static void con_relink_id_cb(bConstraint *UNUSED(con), ID **idpoin, short UNUSED(isReference), void *UNUSED(userdata)) { /* ID_NEW() expects a struct with inline "id" member as first @@ -4449,20 +4449,20 @@ static void con_relink_id_cb(bConstraint *UNUSED(con), ID **idpoin, short UNUSED } /* Reassign links that constraints have to other data (called during file loading?) */ -void relink_constraints(ListBase *conlist) +void BKE_relink_constraints(ListBase *conlist) { /* just a wrapper around ID-loop for just calling ID_NEW() on all ID refs */ - id_loop_constraints(conlist, con_relink_id_cb, NULL); + BKE_id_loop_constraints(conlist, con_relink_id_cb, NULL); } /* Run the given callback on all ID-blocks in list of constraints */ -void id_loop_constraints(ListBase *conlist, ConstraintIDFunc func, void *userdata) +void BKE_id_loop_constraints(ListBase *conlist, ConstraintIDFunc func, void *userdata) { bConstraint *con; for (con = conlist->first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (cti) { if (cti->id_looper) @@ -4473,14 +4473,14 @@ void id_loop_constraints(ListBase *conlist, ConstraintIDFunc func, void *userdat /* ......... */ -/* helper for copy_constraints(), to be used for making sure that ID's are valid */ +/* helper for BKE_copy_constraints(), to be used for making sure that ID's are valid */ static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, short UNUSED(isReference), void *UNUSED(userData)) { if (*idpoin && (*idpoin)->lib) id_lib_extern(*idpoin); } -/* helper for copy_constraints(), to be used for making sure that usercounts of copied ID's are fixed up */ +/* helper for BKE_copy_constraints(), to be used for making sure that usercounts of copied ID's are fixed up */ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, short isReference, void *UNUSED(userData)) { /* increment usercount if this is a reference type */ @@ -4489,7 +4489,7 @@ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, short } /* duplicate all of the constraints in a constraint stack */ -void copy_constraints(ListBase *dst, const ListBase *src, int do_extern) +void BKE_copy_constraints(ListBase *dst, const ListBase *src, int do_extern) { bConstraint *con, *srccon; @@ -4497,7 +4497,7 @@ void copy_constraints(ListBase *dst, const ListBase *src, int do_extern) BLI_duplicatelist(dst, src); for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); /* make a new copy of the constraint's data */ con->data = MEM_dupallocN(con->data); @@ -4524,13 +4524,13 @@ void copy_constraints(ListBase *dst, const ListBase *src, int do_extern) /* ......... */ -bConstraint *constraints_findByName(ListBase *list, const char *name) +bConstraint *BKE_constraints_findByName(ListBase *list, const char *name) { return BLI_findstring(list, name, offsetof(bConstraint, name)); } /* finds the 'active' constraint in a constraint stack */ -bConstraint *constraints_get_active(ListBase *list) +bConstraint *BKE_constraints_get_active(ListBase *list) { bConstraint *con; @@ -4547,7 +4547,7 @@ bConstraint *constraints_get_active(ListBase *list) } /* Set the given constraint as the active one (clearing all the others) */ -void constraints_set_active(ListBase *list, bConstraint *con) +void BKE_constraints_set_active(ListBase *list, bConstraint *con) { bConstraint *c; @@ -4564,7 +4564,7 @@ void constraints_set_active(ListBase *list, bConstraint *con) /* -------- Constraints and Proxies ------- */ /* Rescue all constraints tagged as being CONSTRAINT_PROXY_LOCAL (i.e. added to bone that's proxy-synced in this file) */ -void extract_proxylocal_constraints(ListBase *dst, ListBase *src) +void BKE_extract_proxylocal_constraints(ListBase *dst, ListBase *src) { bConstraint *con, *next; @@ -4581,7 +4581,7 @@ void extract_proxylocal_constraints(ListBase *dst, ListBase *src) } /* Returns if the owner of the constraint is proxy-protected */ -short proxylocked_constraints_owner(Object *ob, bPoseChannel *pchan) +short BKE_proxylocked_constraints_owner(Object *ob, bPoseChannel *pchan) { /* Currently, constraints can only be on object or bone level */ if (ob && ob->proxy) { @@ -4610,9 +4610,9 @@ short proxylocked_constraints_owner(Object *ob, bPoseChannel *pchan) * None of the actual calculations of the matrices should be done here! Also, this function is * not to be used by any new constraints, particularly any that have multiple targets. */ -void get_constraint_target_matrix(struct Scene *scene, bConstraint *con, int n, short ownertype, void *ownerdata, float mat[4][4], float ctime) +void BKE_get_constraint_target_matrix(Scene *scene, bConstraint *con, int index, short ownertype, void *ownerdata, float mat[4][4], float ctime) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintOb *cob; bConstraintTarget *ct; @@ -4657,10 +4657,8 @@ void get_constraint_target_matrix(struct Scene *scene, bConstraint *con, int n, cti->get_constraint_targets(con, &targets); /* only calculate the target matrix on the first target */ - ct = (bConstraintTarget *)targets.first; - while (ct && n-- > 0) - ct = ct->next; - + ct = (bConstraintTarget *)BLI_findlink(&targets, index); + if (ct) { if (cti->get_target_matrix) cti->get_target_matrix(con, cob, ct, ctime); @@ -4679,9 +4677,9 @@ void get_constraint_target_matrix(struct Scene *scene, bConstraint *con, int n, } /* Get the list of targets required for solving a constraint */ -void get_constraint_targets_for_solving(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime) +void BKE_get_constraint_targets_for_solving(bConstraint *con, bConstraintOb *cob, ListBase *targets, float ctime) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (cti && cti->get_constraint_targets) { bConstraintTarget *ct; @@ -4711,10 +4709,10 @@ void get_constraint_targets_for_solving(bConstraint *con, bConstraintOb *cob, Li /* This function is called whenever constraints need to be evaluated. Currently, all * constraints that can be evaluated are everytime this gets run. * - * constraints_make_evalob and constraints_clear_evalob should be called before and + * BKE_constraints_make_evalob and BKE_constraints_clear_evalob should be called before and * after running this function, to sort out cob */ -void solve_constraints(ListBase *conlist, bConstraintOb *cob, float ctime) +void BKE_solve_constraints(ListBase *conlist, bConstraintOb *cob, float ctime) { bConstraint *con; float oldmat[4][4]; @@ -4726,7 +4724,7 @@ void solve_constraints(ListBase *conlist, bConstraintOb *cob, float ctime) /* loop over available constraints, solving and blending them */ for (con = conlist->first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; /* these we can skip completely (invalid constraints...) */ @@ -4746,10 +4744,10 @@ void solve_constraints(ListBase *conlist, bConstraintOb *cob, float ctime) copy_m4_m4(oldmat, cob->matrix); /* move owner matrix into right space */ - constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); + BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace); /* prepare targets for constraint solving */ - get_constraint_targets_for_solving(con, cob, &targets, ctime); + BKE_get_constraint_targets_for_solving(con, cob, &targets, ctime); /* Solve the constraint and put result in cob->matrix */ cti->evaluate_constraint(con, cob, &targets); @@ -4764,7 +4762,7 @@ void solve_constraints(ListBase *conlist, bConstraintOb *cob, float ctime) /* move owner back into worldspace for next constraint/other business */ if ((con->flag & CONSTRAINT_SPACEONCE) == 0) - constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD); + BKE_constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD); /* Interpolate the enforcement, to blend result of constraint into final owner transform * - all this happens in worldspace to prevent any weirdness creeping in ([#26014] and [#25725]), diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 7009f1235c9..a45afa5e69a 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -29,6 +29,7 @@ #include +#include #include #include "MEM_guardedalloc.h" @@ -327,10 +328,13 @@ static void *ctx_data_pointer_get(const bContext *C, const char *member) { bContextDataResult result; - if (C && ctx_data_get((bContext *)C, member, &result) == 1) + if (C && ctx_data_get((bContext *)C, member, &result) == 1) { + BLI_assert(result.type == CTX_DATA_TYPE_POINTER); return result.ptr.data; - - return NULL; + } + else { + return NULL; + } } static int ctx_data_pointer_verify(const bContext *C, const char *member, void **pointer) @@ -343,6 +347,7 @@ static int ctx_data_pointer_verify(const bContext *C, const char *member, void * return 1; } else if (ctx_data_get((bContext *)C, member, &result) == 1) { + BLI_assert(result.type == CTX_DATA_TYPE_POINTER); *pointer = result.ptr.data; return 1; } @@ -357,6 +362,7 @@ static int ctx_data_collection_get(const bContext *C, const char *member, ListBa bContextDataResult result; if (ctx_data_get((bContext *)C, member, &result) == 1) { + BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION); *list = result.list; return 1; } @@ -371,10 +377,13 @@ PointerRNA CTX_data_pointer_get(const bContext *C, const char *member) { bContextDataResult result; - if (ctx_data_get((bContext *)C, member, &result) == 1) + if (ctx_data_get((bContext *)C, member, &result) == 1) { + BLI_assert(result.type == CTX_DATA_TYPE_POINTER); return result.ptr; - else + } + else { return PointerRNA_NULL; + } } PointerRNA CTX_data_pointer_get_type(const bContext *C, const char *member, StructRNA *type) @@ -399,6 +408,7 @@ ListBase CTX_data_collection_get(const bContext *C, const char *member) bContextDataResult result; if (ctx_data_get((bContext *)C, member, &result) == 1) { + BLI_assert(result.type == CTX_DATA_TYPE_COLLECTION); return result.list; } else { diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 7c13ca388e0..cea92d53916 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "MEM_guardedalloc.h" @@ -337,37 +338,12 @@ void defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int flip bDeformGroup *defgroup_find_name(Object *ob, const char *name) { - /* return a pointer to the deform group with this name - * or return NULL otherwise. - */ - bDeformGroup *curdef; - - for (curdef = ob->defbase.first; curdef; curdef = curdef->next) { - if (!strcmp(curdef->name, name)) { - return curdef; - } - } - return NULL; + return BLI_findstring(&ob->defbase, name, offsetof(bDeformGroup, name)); } int defgroup_name_index(Object *ob, const char *name) { - /* Return the location of the named deform group within the list of - * deform groups. This function is a combination of BLI_findlink and - * defgroup_find_name. The other two could be called instead, but that - * require looping over the vertexgroups twice. - */ - bDeformGroup *curdef; - int def_nr; - - if (name && name[0] != '\0') { - for (curdef = ob->defbase.first, def_nr = 0; curdef; curdef = curdef->next, def_nr++) { - if (!strcmp(curdef->name, name)) - return def_nr; - } - } - - return -1; + return (name) ? BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)) : -1; } /* note, must be freed */ @@ -810,3 +786,43 @@ int defvert_find_shared(const MDeformVert *dvert_a, const MDeformVert *dvert_b) return -1; } + +/* -------------------------------------------------------------------- */ +/* Defvert Array functions */ + +void BKE_defvert_array_copy(MDeformVert *dst, const MDeformVert *src, int copycount) +{ + /* Assumes dst is already set up */ + int i; + + if (!src || !dst) + return; + + memcpy(dst, src, copycount * sizeof(MDeformVert)); + + for (i = 0; i < copycount; i++) { + if (src[i].dw) { + dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * src[i].totweight, "copy_deformWeight"); + memcpy(dst[i].dw, src[i].dw, sizeof(MDeformWeight) * src[i].totweight); + } + } + +} + +void BKE_defvert_array_free(MDeformVert *dvert, int totvert) +{ + /* Instead of freeing the verts directly, + * call this function to delete any special + * vert data */ + int i; + + if (!dvert) + return; + + /* Free any special data from the verts */ + for (i = 0; i < totvert; i++) { + if (dvert[i].dw) MEM_freeN(dvert[i].dw); + } + MEM_freeN(dvert); +} + diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 6ba140fcec1..42389564ec0 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -472,7 +472,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -754,7 +754,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O /* object constraints */ for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -2295,7 +2295,7 @@ static void dag_object_time_update_flags(Object *ob) if (ob->constraints.first) { bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -2738,7 +2738,7 @@ static void dag_id_flush_update(Scene *sce, ID *id) for (obt = bmain->object.first; obt; obt = obt->id.next) { bConstraint *con; for (con = obt->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) { @@ -3030,7 +3030,7 @@ void DAG_pose_sort(Object *ob) addtoroot = 0; } for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 083cb02fd3d..71e9daaee6b 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -225,29 +225,48 @@ void BKE_displist_normals_add(ListBase *lb) } } -void BKE_displist_count(ListBase *lb, int *totvert, int *totface) +void BKE_displist_count(ListBase *lb, int *totvert, int *totface, int *tottri) { DispList *dl; - dl = lb->first; - while (dl) { + for (dl = lb->first; dl; dl = dl->next) { + int vert_tot = 0; + int face_tot = 0; + int tri_tot = 0; + switch (dl->type) { case DL_SURF: - *totvert += dl->nr * dl->parts; - *totface += (dl->nr - 1) * (dl->parts - 1); + { + vert_tot = dl->nr * dl->parts; + face_tot = (dl->nr - 1) * (dl->parts - 1); + tri_tot = face_tot * 2; break; + } case DL_INDEX3: - case DL_INDEX4: - *totvert += dl->nr; - *totface += dl->parts; + { + vert_tot = dl->nr; + face_tot = dl->parts; + tri_tot = face_tot; break; + } + case DL_INDEX4: + { + vert_tot = dl->nr; + face_tot = dl->parts; + tri_tot = face_tot * 2; + break; + } case DL_POLY: case DL_SEGM: - *totvert += dl->nr * dl->parts; + { + vert_tot = dl->nr * dl->parts; break; + } } - dl = dl->next; + *totvert += vert_tot; + *totface += face_tot; + *tottri += tri_tot; } } @@ -487,7 +506,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, int flipnormal) } /* XXX (obedit && obedit->actcol)?(obedit->actcol-1):0)) { */ - if (totvert && (tot = BLI_scanfill_calc(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES))) { + if (totvert && (tot = BLI_scanfill_calc(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES | BLI_SCANFILL_CALC_HOLES))) { if (tot) { dlnew = MEM_callocN(sizeof(DispList), "filldisplist"); dlnew->type = DL_INDEX3; @@ -780,7 +799,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, fl required_mode |= eModifierMode_Editmode; if (cu->editnurb == NULL) { - keyVerts = do_ob_key(scene, ob); + keyVerts = BKE_key_evaluate_object(scene, ob, &numVerts); if (keyVerts) { /* split coords from key data, the latter also includes @@ -789,7 +808,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, fl * shape key modifier yet. */ deformedVerts = BKE_curve_keyVertexCos_get(cu, nurb, keyVerts); originalVerts = MEM_dupallocN(deformedVerts); - numVerts = BKE_nurbList_verts_count(nurb); + BLI_assert(BKE_nurbList_verts_count(nurb) == numVerts); } } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index e32f8d53b7d..fff51ab2a59 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -529,7 +529,7 @@ static int subframe_updateObject(Scene *scene, Object *ob, int flags, float fram /* also update constraint targets */ for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; if (cti && cti->get_constraint_targets) { @@ -2689,7 +2689,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam if (format == R_IMF_IMTYPE_OPENEXR) format = R_IMF_IMTYPE_PNG; #endif BLI_strncpy(output_file, filename, sizeof(output_file)); - BKE_add_image_extension(output_file, format); + BKE_add_image_extension_from_type(output_file, format); /* Validate output file path */ BLI_path_abs(output_file, G.main->name); @@ -2839,7 +2839,9 @@ static void dynamicPaint_freeBrushMaterials(BrushMaterials *bMats) /* * Get material diffuse color and alpha (including linked textures) in given coordinates */ -static void dynamicPaint_doMaterialTex(BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb, const float volume_co[3], const float surface_co[3], int faceIndex, short isQuad, DerivedMesh *orcoDm) +static void dynamicPaint_doMaterialTex(BrushMaterials *bMats, float color[3], float *alpha, Object *brushOb, + const float volume_co[3], const float surface_co[3], + int faceIndex, short isQuad, DerivedMesh *orcoDm) { Material *mat = bMats->mat; MFace *mface = orcoDm->getTessFaceArray(orcoDm); diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 480ff23f100..1c43b418a1c 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -113,8 +113,13 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) #define USE_TESSFACE_SPEEDUP BMesh *bm = em->bm; - BMLoop *(*looptris)[3] = NULL; - BLI_array_declare(looptris); + + /* this assumes all faces can be scan-filled, which isn't always true, + * worst case we over alloc a little which is acceptable */ + const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); + const int looptris_tot_prev_alloc = em->looptris ? (MEM_allocN_len(em->looptris) / sizeof(*em->looptris)) : 0; + + BMLoop *(*looptris)[3]; BMIter iter; BMFace *efa; BMLoop *l; @@ -135,17 +140,16 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) #else /* this means no reallocs for quad dominant models, for */ - if ( (em->looptris != NULL) && - (em->tottri != 0) && - /* (totrti <= bm->totface * 2) would be fine for all quads, - * but in case there are some ngons, still re-use the array */ - (em->tottri <= bm->totface * 3)) + if ((em->looptris != NULL) && + /* (em->tottri >= looptris_tot)) */ + /* check against alloc'd size incase we over alloc'd a little */ + ((looptris_tot_prev_alloc >= looptris_tot) && (looptris_tot_prev_alloc <= looptris_tot * 2))) { looptris = em->looptris; } else { if (em->looptris) MEM_freeN(em->looptris); - BLI_array_reserve(looptris, bm->totface); + looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__); } #endif @@ -163,20 +167,16 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) else if (efa->len == 3) { #if 0 int j; - BLI_array_grow_one(looptris); BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, j) { looptris[i][j] = l; } i += 1; #else /* more cryptic but faster */ - BLI_array_grow_one(looptris); - { - BMLoop **l_ptr = looptris[i++]; - l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa); - l_ptr[1] = l = l->next; - l_ptr[2] = l->next; - } + BMLoop **l_ptr = looptris[i++]; + l_ptr[0] = l = BM_FACE_FIRST_LOOP(efa); + l_ptr[1] = l = l->next; + l_ptr[2] = l->next; #endif } else if (efa->len == 4) { @@ -199,15 +199,12 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) i += 1; #else /* more cryptic but faster */ - BLI_array_grow_items(looptris, 2); - { - BMLoop **l_ptr_a = looptris[i++]; - BMLoop **l_ptr_b = looptris[i++]; - (l_ptr_a[0] = l_ptr_b[0] = l = BM_FACE_FIRST_LOOP(efa)); - (l_ptr_a[1] = l = l->next); - (l_ptr_a[2] = l_ptr_b[1] = l = l->next); - ( l_ptr_b[2] = l->next); - } + BMLoop **l_ptr_a = looptris[i++]; + BMLoop **l_ptr_b = looptris[i++]; + (l_ptr_a[0] = l_ptr_b[0] = l = BM_FACE_FIRST_LOOP(efa)); + (l_ptr_a[1] = l = l->next); + (l_ptr_a[2] = l_ptr_b[1] = l = l->next); + ( l_ptr_b[2] = l->next); #endif } @@ -250,9 +247,10 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) BLI_scanfill_edge_add(&sf_ctx, sf_vert_first, sf_vert); totfilltri = BLI_scanfill_calc_ex(&sf_ctx, 0, efa->no); - BLI_array_grow_items(looptris, totfilltri); + BLI_assert(totfilltri <= efa->len - 2); for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) { + BMLoop **l_ptr = looptris[i++]; BMLoop *l1 = sf_tri->v1->tmp.p; BMLoop *l2 = sf_tri->v2->tmp.p; BMLoop *l3 = sf_tri->v3->tmp.p; @@ -261,10 +259,9 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) if (BM_elem_index_get(l2) > BM_elem_index_get(l3)) { SWAP(BMLoop *, l2, l3); } if (BM_elem_index_get(l1) > BM_elem_index_get(l2)) { SWAP(BMLoop *, l1, l2); } - looptris[i][0] = l1; - looptris[i][1] = l2; - looptris[i][2] = l3; - i += 1; + l_ptr[0] = l1; + l_ptr[1] = l2; + l_ptr[2] = l3; } BLI_scanfill_end(&sf_ctx); @@ -274,6 +271,8 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *em) em->tottri = i; em->looptris = looptris; + BLI_assert(em->tottri <= looptris_tot); + #undef USE_TESSFACE_SPEEDUP } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 5e01773cab9..23f3a3ad3fd 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -859,7 +859,7 @@ void testhandles_fcurve(FCurve *fcu, const short use_handle) short flag = 0; /* flag is initialized as selection status - * of beztriple control-points (labelled 0,1,2) + * of beztriple control-points (labelled 0, 1, 2) */ if (bezt->f2 & SELECT) flag |= (1 << 1); // == 2 if (use_handle == FALSE) { @@ -1192,7 +1192,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) /* extract transform just like how the constraints do it! */ copy_m4_m4(mat, pchan->pose_mat); - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); /* ... and from that, we get our transform */ copy_v3_v3(tmp_loc, mat[3]); @@ -1217,7 +1217,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) /* extract transform just like how the constraints do it! */ copy_m4_m4(mat, ob->obmat); - constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); /* ... and from that, we get our transform */ copy_v3_v3(tmp_loc, mat[3]); @@ -1288,7 +1288,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { /* just like how the constraints do it! */ copy_m4_m4(mat, pchan->pose_mat); - constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL); } else { /* specially calculate local matrix, since chan_mat is not valid @@ -1315,7 +1315,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar) if (dtar->flag & DTAR_FLAG_LOCAL_CONSTS) { /* just like how the constraints do it! */ copy_m4_m4(mat, ob->obmat); - constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); + BKE_constraint_mat_convertspace(ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL); } else { /* transforms to matrix */ @@ -2022,12 +2022,12 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime } else { /* bezier interpolation */ - /* v1,v2 are the first keyframe and its 2nd handle */ + /* (v1, v2) are the first keyframe and its 2nd handle */ v1[0] = prevbezt->vec[1][0]; v1[1] = prevbezt->vec[1][1]; v2[0] = prevbezt->vec[2][0]; v2[1] = prevbezt->vec[2][1]; - /* v3,v4 are the last keyframe's 1st handle + the last keyframe */ + /* (v3, v4) are the last keyframe's 1st handle + the last keyframe */ v3[0] = bezt->vec[0][0]; v3[1] = bezt->vec[0][1]; v4[0] = bezt->vec[1][0]; diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 5dd0f08dc71..3be47668fb5 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -815,6 +815,13 @@ void IDP_FreeProperty(IDProperty *prop) } } +void IDP_ClearProperty(IDProperty *prop) +{ + IDP_FreeProperty(prop); + prop->data.pointer = NULL; + prop->len = prop->totallen = 0; +} + /* Unlinks any IDProperty<->ID linkage that might be going on. * note: currently unused.*/ void IDP_UnlinkProperty(IDProperty *prop) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f3cdf11d664..dbc423f98b3 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -312,10 +312,6 @@ static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame) break; ibuf->index = index; - if (ima->flag & IMA_CM_PREDIVIDE) - ibuf->flags |= IB_cm_predivide; - else - ibuf->flags &= ~IB_cm_predivide; /* this function accepts (link == NULL) */ BLI_insertlinkbefore(&ima->ibufs, link, ibuf); @@ -552,6 +548,26 @@ int BKE_image_scale(Image *image, int width, int height) return (ibuf != NULL); } +static void image_init_color_management(Image *ima) +{ + ImBuf *ibuf; + char name[FILE_MAX]; + + BKE_image_user_file_path(NULL, ima, name); + + /* will set input color space to image format default's */ + ibuf = IMB_loadiffname(name, IB_test | IB_alphamode_detect, ima->colorspace_settings.name); + + if (ibuf) { + if (ibuf->flags & IB_alphamode_premul) + ima->alpha_mode = IMA_ALPHA_PREMUL; + else + ima->alpha_mode = IMA_ALPHA_STRAIGHT; + + IMB_freeImBuf(ibuf); + } +} + Image *BKE_image_load(const char *filepath) { Image *ima; @@ -579,6 +595,8 @@ Image *BKE_image_load(const char *filepath) if (BLI_testextensie_array(filepath, imb_ext_movie)) ima->source = IMA_SRC_MOVIE; + image_init_color_management(ima); + return ima; } @@ -666,7 +684,7 @@ static ImBuf *add_ibuf_size(unsigned int width, unsigned int height, const char /* both byte and float buffers are filling in sRGB space, need to linearize float buffer after BKE_image_buf_fill* functions */ IMB_buffer_float_from_float(rect_float, rect_float, ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_SRGB, - ibuf->flags & IB_cm_predivide, ibuf->x, ibuf->y, ibuf->x, ibuf->x); + TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x); } return ibuf; @@ -1119,6 +1137,8 @@ char BKE_imtype_valid_depths(const char imtype) return R_IMF_CHAN_DEPTH_10; case R_IMF_IMTYPE_JP2: return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16; + case R_IMF_IMTYPE_PNG: + return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16; /* most formats are 8bit only */ default: return R_IMF_CHAN_DEPTH_8; @@ -1165,9 +1185,10 @@ char BKE_imtype_from_arg(const char *imtype_arg) else return R_IMF_IMTYPE_INVALID; } -int BKE_add_image_extension(char *string, const char imtype) +static int do_add_image_extension(char *string, const char imtype, const ImageFormatData *im_format) { const char *extension = NULL; + (void)im_format; /* may be unused, depends on build options */ if (imtype == R_IMF_IMTYPE_IRIS) { if (!BLI_testextensie(string, ".rgb")) @@ -1232,8 +1253,22 @@ int BKE_add_image_extension(char *string, const char imtype) } #ifdef WITH_OPENJPEG else if (imtype == R_IMF_IMTYPE_JP2) { - if (!BLI_testextensie(string, ".jp2")) - extension = ".jp2"; + if (im_format) { + if (im_format->jp2_codec == R_IMF_JP2_CODEC_JP2) { + if (!BLI_testextensie(string, ".jp2")) + extension = ".jp2"; + } + else if (im_format->jp2_codec == R_IMF_JP2_CODEC_J2K) { + if (!BLI_testextensie(string, ".j2c")) + extension = ".j2c"; + } + else + BLI_assert(!"Unsupported jp2 codec was specified in im_format->jp2_codec"); + } + else { + if (!BLI_testextensie(string, ".jp2")) + extension = ".jp2"; + } } #endif else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90, R_IMF_IMTYPE_QUICKTIME etc @@ -1259,11 +1294,22 @@ int BKE_add_image_extension(char *string, const char imtype) } } +int BKE_add_image_extension(char *string, const ImageFormatData *im_format) +{ + return do_add_image_extension(string, im_format->imtype, im_format); +} + +int BKE_add_image_extension_from_type(char *string, const char imtype) +{ + return do_add_image_extension(string, imtype, NULL); +} + void BKE_imformat_defaults(ImageFormatData *im_format) { memset(im_format, 0, sizeof(*im_format)); im_format->planes = R_IMF_PLANES_RGB; im_format->imtype = R_IMF_IMTYPE_PNG; + im_format->depth = R_IMF_CHAN_DEPTH_8; im_format->quality = 90; im_format->compress = 90; @@ -1288,9 +1334,13 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i im_format->imtype = R_IMF_IMTYPE_RADHDR; #endif - else if (ftype == PNG) + else if (ftype == PNG) { im_format->imtype = R_IMF_IMTYPE_PNG; + if (custom_flags & PNG_16BIT) + im_format->depth = R_IMF_CHAN_DEPTH_16; + } + #ifdef WITH_DDS else if (ftype == DDS) im_format->imtype = R_IMF_IMTYPE_DDS; @@ -1351,6 +1401,13 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i if (ftype & JP2_CINE_48FPS) im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_48; } + + if (ftype & JP2_JP2) + im_format->jp2_codec = R_IMF_JP2_CODEC_JP2; + else if (ftype & JP2_J2K) + im_format->jp2_codec = R_IMF_JP2_CODEC_J2K; + else + BLI_assert(!"Unsupported jp2 codec was specified in file type"); } #endif @@ -1815,8 +1872,12 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf) else if (ELEM5(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) { ibuf->ftype = PNG; - if (imtype == R_IMF_IMTYPE_PNG) + if (imtype == R_IMF_IMTYPE_PNG) { + if (imf->depth == R_IMF_CHAN_DEPTH_16) + ibuf->ftype |= PNG_16BIT; + ibuf->ftype |= compress; + } } #ifdef WITH_DDS @@ -1906,6 +1967,13 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf) if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_48) ibuf->ftype |= JP2_CINE_48FPS; } + + if (imf->jp2_codec == R_IMF_JP2_CODEC_JP2) + ibuf->ftype |= JP2_JP2; + else if (imf->jp2_codec == R_IMF_JP2_CODEC_J2K) + ibuf->ftype |= JP2_J2K; + else + BLI_assert(!"Unsupported jp2 codec was specified in im_format->jp2_codec"); } #endif else { @@ -1956,7 +2024,8 @@ int BKE_imbuf_write_stamp(Scene *scene, struct Object *camera, ImBuf *ibuf, cons } -void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame, const char imtype, const short use_ext, const short use_frames) +static void do_makepicstring(char *string, const char *base, const char *relbase, int frame, const char imtype, + const ImageFormatData *im_format, const short use_ext, const short use_frames) { if (string == NULL) return; BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */ @@ -1966,8 +2035,17 @@ void BKE_makepicstring(char *string, const char *base, const char *relbase, int BLI_path_frame(string, frame, 4); if (use_ext) - BKE_add_image_extension(string, imtype); + do_add_image_extension(string, imtype, im_format); +} +void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame, const ImageFormatData *im_format, const short use_ext, const short use_frames) +{ + do_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames); +} + +void BKE_makepicstring_from_type(char *string, const char *base, const char *relbase, int frame, const char imtype, const short use_ext, const short use_frames) +{ + do_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames); } /* used by sequencer too */ @@ -2284,7 +2362,7 @@ void BKE_image_backup_render(Scene *scene, Image *ima) static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr) { const char *colorspace = ima->colorspace_settings.name; - int predivide = ima->flag & IMA_CM_PREDIVIDE; + int predivide = ima->alpha_mode == IMA_ALPHA_PREMUL; ima->rr = RE_MultilayerConvert(ibuf->userdata, colorspace, predivide, ibuf->x, ibuf->y); @@ -2316,6 +2394,18 @@ static void image_initialize_after_load(Image *ima, ImBuf *ibuf) } +static int imbuf_alpha_flags_for_image(Image *ima) +{ + int flag = 0; + + if (ima->flag & IMA_IGNORE_ALPHA) + flag |= IB_ignore_alpha; + else if (ima->alpha_mode == IMA_ALPHA_PREMUL) + flag |= IB_alphamode_premul; + + return flag; +} + static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) { struct ImBuf *ibuf; @@ -2330,8 +2420,7 @@ static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame) BKE_image_user_file_path(iuser, ima, name); flag = IB_rect | IB_multilayer; - if (ima->flag & IMA_DO_PREMUL) - flag |= IB_premul; + flag |= imbuf_alpha_flags_for_image(ima); /* read ibuf */ ibuf = IMB_loadiffname(name, flag, ima->colorspace_settings.name); @@ -2490,15 +2579,14 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra) /* is there a PackedFile with this image ? */ if (ima->packedfile) { flag = IB_rect | IB_multilayer; - if (ima->flag & IMA_DO_PREMUL) flag |= IB_premul; + flag |= imbuf_alpha_flags_for_image(ima); ibuf = IMB_ibImageFromMemory((unsigned char *)ima->packedfile->data, ima->packedfile->size, flag, ima->colorspace_settings.name, ""); } else { flag = IB_rect | IB_multilayer | IB_metadata; - if (ima->flag & IMA_DO_PREMUL) - flag |= IB_premul; + flag |= imbuf_alpha_flags_for_image(ima); /* get the right string */ BKE_image_user_frame_calc(iuser, cfra, 0); @@ -2718,15 +2806,6 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_ ibuf->dither = dither; - if (iuser->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE) { - ibuf->flags |= IB_cm_predivide; - ima->flag |= IMA_CM_PREDIVIDE; - } - else { - ibuf->flags &= ~IB_cm_predivide; - ima->flag &= ~IMA_CM_PREDIVIDE; - } - ima->ok = IMA_OK_LOADED; return ibuf; diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index ad95f09826a..ccc57a24540 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -1300,13 +1300,13 @@ static void do_latt_key(Scene *scene, Object *ob, Key *key, char *out, const int } /* returns key coordinates (+ tilt) when key applied, NULL otherwise */ -float *do_ob_key(Scene *scene, Object *ob) +float *BKE_key_evaluate_object(Scene *scene, Object *ob, int *r_totelem) { Key *key = BKE_key_from_object(ob); KeyBlock *actkb = BKE_keyblock_from_object(ob); char *out; int tot = 0, size = 0; - + if (key == NULL || key->block.first == NULL) return NULL; @@ -1344,7 +1344,7 @@ float *do_ob_key(Scene *scene, Object *ob) return NULL; /* allocate array */ - out = MEM_callocN(size, "do_ob_key out"); + out = MEM_callocN(size, "BKE_key_evaluate_object out"); /* prevent python from screwing this up? anyhoo, the from pointer could be dropped */ key->from = (ID *)ob->data; @@ -1383,6 +1383,9 @@ float *do_ob_key(Scene *scene, Object *ob) else if (ob->type == OB_SURF) do_curve_key(scene, ob, key, out, tot); } + if (r_totelem) { + *r_totelem = tot; + } return (float *)out; } @@ -1732,7 +1735,7 @@ void BKE_key_convert_to_mesh(KeyBlock *kb, Mesh *me) } /************************* vert coords ************************/ -float (*BKE_key_convert_to_vertcos(Object * ob, KeyBlock * kb))[3] +float (*BKE_key_convert_to_vertcos(Object *ob, KeyBlock *kb))[3] { float (*vertCos)[3], *co; float *fp = kb->data; diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index d98188d8a6f..fa01e9fd933 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -88,7 +88,7 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) /* vertex weight groups are just freed all for now */ if (lt->dvert) { - free_dverts(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); lt->dvert = NULL; } @@ -209,7 +209,7 @@ Lattice *BKE_lattice_copy(Lattice *lt) if (lt->dvert) { int tot = lt->pntsu * lt->pntsv * lt->pntsw; ltn->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert"); - copy_dverts(ltn->dvert, lt->dvert, tot); + BKE_defvert_array_copy(ltn->dvert, lt->dvert, tot); } ltn->editlatt = NULL; @@ -220,12 +220,12 @@ Lattice *BKE_lattice_copy(Lattice *lt) void BKE_lattice_free(Lattice *lt) { if (lt->def) MEM_freeN(lt->def); - if (lt->dvert) free_dverts(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + if (lt->dvert) BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); if (lt->editlatt) { Lattice *editlt = lt->editlatt->latt; if (editlt->def) MEM_freeN(editlt->def); - if (editlt->dvert) free_dverts(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + if (editlt->dvert) BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); MEM_freeN(editlt); MEM_freeN(lt->editlatt); diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c index 2fa928e7c07..73452b216ff 100644 --- a/source/blender/blenkernel/intern/mask_rasterize.c +++ b/source/blender/blenkernel/intern/mask_rasterize.c @@ -933,7 +933,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas } /* main scan-fill */ - sf_tri_tot = BLI_scanfill_calc_ex(&sf_ctx, 0, zvec); + sf_tri_tot = BLI_scanfill_calc_ex(&sf_ctx, BLI_SCANFILL_CALC_HOLES, zvec); face_array = MEM_mallocN(sizeof(*face_array) * (sf_tri_tot + tot_feather_quads), "maskrast_face_index"); face_index = 0; diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 54bd03ece70..4655dd04261 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -631,11 +631,14 @@ Material *give_current_material(Object *ob, short act) if (totcolp == NULL || ob->totcol == 0) return NULL; if (act < 0) { - printf("no!\n"); + printf("Negative material index!\n"); } - if (act > ob->totcol) act = ob->totcol; - else if (act <= 0) act = 1; + /* return NULL for invalid 'act', can happen for mesh face indices */ + if (act > ob->totcol) + return NULL; + else if (act <= 0) + return NULL; if (ob->matbits && ob->matbits[act - 1]) { /* in object */ ma = ob->mat[act - 1]; @@ -1237,6 +1240,11 @@ int object_remove_material_slot(Object *ob) if (*matarar == NULL) return FALSE; + /* can happen on face selection in editmode */ + if (ob->actcol > ob->totcol) { + ob->actcol = ob->totcol; + } + /* we delete the actcol */ mao = (*matarar)[ob->actcol - 1]; if (mao) mao->id.us--; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 3eb96f218e4..30e7cb3bb36 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -430,42 +430,6 @@ void BKE_mesh_free(Mesh *me, int unlink) if (me->edit_btmesh) MEM_freeN(me->edit_btmesh); } -void copy_dverts(MDeformVert *dst, const MDeformVert *src, int copycount) -{ - /* Assumes dst is already set up */ - int i; - - if (!src || !dst) - return; - - memcpy(dst, src, copycount * sizeof(MDeformVert)); - - for (i = 0; i < copycount; i++) { - if (src[i].dw) { - dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * src[i].totweight, "copy_deformWeight"); - memcpy(dst[i].dw, src[i].dw, sizeof(MDeformWeight) * src[i].totweight); - } - } - -} - -void free_dverts(MDeformVert *dvert, int totvert) -{ - /* Instead of freeing the verts directly, - * call this function to delete any special - * vert data */ - int i; - - if (!dvert) - return; - - /* Free any special data from the verts */ - for (i = 0; i < totvert; i++) { - if (dvert[i].dw) MEM_freeN(dvert[i].dw); - } - MEM_freeN(dvert); -} - static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) { if (free_customdata) { @@ -2488,7 +2452,7 @@ void BKE_mesh_loops_to_mface_corners(CustomData *fdata, CustomData *ldata, */ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomData *pdata, - MVert *mvert, int totface, int UNUSED(totloop), + MVert *mvert, int totface, int totloop, int totpoly, /* when tessellating to recalculate normals after * we can skip copying here */ @@ -2503,15 +2467,15 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, #define TESSFACE_SCANFILL (1 << 0) #define TESSFACE_IS_QUAD (1 << 1) + const int looptris_tot = poly_to_tri_count(totpoly, totloop); + MPoly *mp, *mpoly; MLoop *ml, *mloop; - MFace *mface = NULL, *mf; - BLI_array_declare(mface); + MFace *mface, *mf; ScanFillContext sf_ctx; ScanFillVert *sf_vert, *sf_vert_last, *sf_vert_first; ScanFillFace *sf_tri; - int *mface_to_poly_map = NULL; - BLI_array_declare(mface_to_poly_map); + int *mface_to_poly_map; int lindex[4]; /* only ever use 3 in this case */ int poly_index, j, mface_index; @@ -2525,8 +2489,9 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, /* allocate the length of totfaces, avoid many small reallocs, * if all faces are tri's it will be correct, quads == 2x allocs */ - BLI_array_reserve(mface_to_poly_map, totpoly); - BLI_array_reserve(mface, totpoly); + /* take care. we are _not_ calloc'ing so be sure to initialize each field */ + mface_to_poly_map = MEM_mallocN(sizeof(*mface_to_poly_map) * looptris_tot, __func__); + mface = MEM_mallocN(sizeof(*mface) * looptris_tot, __func__); mface_index = 0; mp = mpoly; @@ -2538,8 +2503,6 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, #ifdef USE_TESSFACE_SPEEDUP #define ML_TO_MF(i1, i2, i3) \ - BLI_array_grow_one(mface_to_poly_map); \ - BLI_array_grow_one(mface); \ mface_to_poly_map[mface_index] = poly_index; \ mf = &mface[mface_index]; \ /* set loop indices, transformed to vert indices later */ \ @@ -2549,12 +2512,11 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, mf->v4 = 0; \ mf->mat_nr = mp->mat_nr; \ mf->flag = mp->flag; \ + mf->edcode = 0; \ (void)0 /* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */ #define ML_TO_MF_QUAD() \ - BLI_array_grow_one(mface_to_poly_map); \ - BLI_array_grow_one(mface); \ mface_to_poly_map[mface_index] = poly_index; \ mf = &mface[mface_index]; \ /* set loop indices, transformed to vert indices later */ \ @@ -2564,7 +2526,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, mf->v4 = mp->loopstart + 3; /* EXCEPTION */ \ mf->mat_nr = mp->mat_nr; \ mf->flag = mp->flag; \ - mf->edcode |= TESSFACE_IS_QUAD; /* EXCEPTION */ \ + mf->edcode = TESSFACE_IS_QUAD; /* EXCEPTION */ \ (void)0 @@ -2607,29 +2569,26 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert_first); totfilltri = BLI_scanfill_calc(&sf_ctx, 0); - if (totfilltri) { - BLI_array_grow_items(mface_to_poly_map, totfilltri); - BLI_array_grow_items(mface, totfilltri); + BLI_assert(totfilltri <= mp->totloop - 2); - for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next, mf++) { - mface_to_poly_map[mface_index] = poly_index; - mf = &mface[mface_index]; + for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next, mf++) { + mface_to_poly_map[mface_index] = poly_index; + mf = &mface[mface_index]; - /* set loop indices, transformed to vert indices later */ - mf->v1 = sf_tri->v1->keyindex; - mf->v2 = sf_tri->v2->keyindex; - mf->v3 = sf_tri->v3->keyindex; - mf->v4 = 0; + /* set loop indices, transformed to vert indices later */ + mf->v1 = sf_tri->v1->keyindex; + mf->v2 = sf_tri->v2->keyindex; + mf->v3 = sf_tri->v3->keyindex; + mf->v4 = 0; - mf->mat_nr = mp->mat_nr; - mf->flag = mp->flag; + mf->mat_nr = mp->mat_nr; + mf->flag = mp->flag; #ifdef USE_TESSFACE_SPEEDUP - mf->edcode |= TESSFACE_SCANFILL; /* tag for sorting loop indices */ + mf->edcode = TESSFACE_SCANFILL; /* tag for sorting loop indices */ #endif - mface_index++; - } + mface_index++; } BLI_scanfill_end(&sf_ctx); @@ -2639,9 +2598,10 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData_free(fdata, totface); totface = mface_index; + BLI_assert(totface <= looptris_tot); /* not essential but without this we store over-alloc'd memory in the CustomData layers */ - if (LIKELY((MEM_allocN_len(mface) / sizeof(*mface)) != totface)) { + if (LIKELY(looptris_tot != totface)) { mface = MEM_reallocN(mface, sizeof(*mface) * totface); mface_to_poly_map = MEM_reallocN(mface_to_poly_map, sizeof(*mface_to_poly_map) * totface); } diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 4156b5b4367..69e368f0d08 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1325,7 +1325,7 @@ void BKE_movieclip_unlink(Main *bmain, MovieClip *clip) bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data; diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 06d7cf55d49..b12463daf72 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -379,7 +379,7 @@ void multires_force_update(Object *ob) ob->derivedFinal = NULL; } if (ob->sculpt && ob->sculpt->pbvh) { - BLI_pbvh_free(ob->sculpt->pbvh); + BKE_pbvh_free(ob->sculpt->pbvh); ob->sculpt->pbvh = NULL; } } @@ -1407,7 +1407,7 @@ void multires_stitch_grids(Object *ob) int totface; if (ccgdm->pbvh) { - BLI_pbvh_get_grid_updates(ccgdm->pbvh, 0, (void ***)&faces, &totface); + BKE_pbvh_get_grid_updates(ccgdm->pbvh, 0, (void ***)&faces, &totface); if (totface) { ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 8babdf2402f..84e280034ed 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1161,11 +1161,11 @@ void ntreeSetOutput(bNodeTree *ntree) bNodeTree *ntreeFromID(ID *id) { switch (GS(id->name)) { - case ID_MA: return ((Material*)id)->nodetree; - case ID_LA: return ((Lamp*)id)->nodetree; - case ID_WO: return ((World*)id)->nodetree; - case ID_TE: return ((Tex*)id)->nodetree; - case ID_SCE: return ((Scene*)id)->nodetree; + case ID_MA: return ((Material *)id)->nodetree; + case ID_LA: return ((Lamp *)id)->nodetree; + case ID_WO: return ((World *)id)->nodetree; + case ID_TE: return ((Tex *)id)->nodetree; + case ID_SCE: return ((Scene *)id)->nodetree; default: return NULL; } } @@ -2323,6 +2323,7 @@ static void registerShaderNodes(bNodeTreeType *ttype) register_node_type_sh_layer_weight(ttype); register_node_type_sh_tex_coord(ttype); register_node_type_sh_particle_info(ttype); + register_node_type_sh_hair_info(ttype); register_node_type_sh_bump(ttype); register_node_type_sh_script(ttype); register_node_type_sh_tangent(ttype); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index d13d456a183..5a22973164e 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -268,14 +268,44 @@ void free_sculptsession_deformMats(SculptSession *ss) ss->deform_imats = NULL; } +/* Write out the sculpt dynamic-topology BMesh to the Mesh */ +void sculptsession_bm_to_me(struct Object *ob, int reorder) +{ + if (ob && ob->sculpt) { + SculptSession *ss = ob->sculpt; + + if (ss->bm) { + if (ob->data) { + BMIter iter; + BMFace *efa; + BM_ITER_MESH (efa, &iter, ss->bm, BM_FACES_OF_MESH) { + BM_elem_flag_set(efa, BM_ELEM_SMOOTH, + ss->bm_smooth_shading); + } + if (reorder) + BM_log_mesh_elems_reorder(ss->bm, ss->bm_log); + BM_mesh_bm_to_me(ss->bm, ob->data, FALSE); + } + } + } +} + void free_sculptsession(Object *ob) { if (ob && ob->sculpt) { SculptSession *ss = ob->sculpt; DerivedMesh *dm = ob->derivedFinal; + if (ss->bm) { + sculptsession_bm_to_me(ob, TRUE); + BM_mesh_free(ss->bm); + } + if (ss->pbvh) - BLI_pbvh_free(ss->pbvh); + BKE_pbvh_free(ss->pbvh); + if (ss->bm_log) + BM_log_free(ss->bm_log); + if (dm && dm->getPBVH) dm->getPBVH(NULL, dm); /* signal to clear */ @@ -353,7 +383,7 @@ void BKE_object_free(Object *ob) free_controllers(&ob->controllers); free_actuators(&ob->actuators); - free_constraints(&ob->constraints); + BKE_free_constraints(&ob->constraints); free_partdeflect(ob->pd); @@ -438,7 +468,7 @@ void BKE_object_unlink(Object *ob) bPoseChannel *pchan; for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -469,7 +499,7 @@ void BKE_object_unlink(Object *ob) sca_remove_ob_poin(obt, ob); for (con = obt->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1143,7 +1173,7 @@ static void copy_object_pose(Object *obn, Object *ob) } for (con = chan->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); ListBase targets = {NULL, NULL}; bConstraintTarget *ct; @@ -1243,7 +1273,7 @@ static Object *object_copy_do(Object *ob, int copy_caches) BKE_pose_rebuild(obn, obn->data); } defgroup_copy_list(&obn->defbase, &ob->defbase); - copy_constraints(&obn->constraints, &ob->constraints, TRUE); + BKE_copy_constraints(&obn->constraints, &ob->constraints, TRUE); obn->mode = 0; obn->sculpt = NULL; @@ -2127,9 +2157,9 @@ void BKE_object_where_is_calc_time(Scene *scene, Object *ob, float ctime) if (ob->constraints.first && !(ob->transflag & OB_NO_CONSTRAINTS)) { bConstraintOb *cob; - cob = constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); - solve_constraints(&ob->constraints, cob, ctime); - constraints_clear_evalob(cob); + cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + BKE_solve_constraints(&ob->constraints, cob, ctime); + BKE_constraints_clear_evalob(cob); } /* set negative scale flag in object */ @@ -2198,9 +2228,9 @@ void BKE_object_where_is_calc_simul(Scene *scene, Object *ob) if (ob->constraints.first) { bConstraintOb *cob; - cob = constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); - solve_constraints(&ob->constraints, cob, (float)scene->r.cfra); - constraints_clear_evalob(cob); + cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + BKE_solve_constraints(&ob->constraints, cob, (float)scene->r.cfra); + BKE_constraints_clear_evalob(cob); } } @@ -2799,7 +2829,7 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) * changing PVBH node organization, we hope topology does not change in * the meantime .. weak */ if (ss->pbvh) { - BLI_pbvh_free(ss->pbvh); + BKE_pbvh_free(ss->pbvh); ss->pbvh = NULL; } @@ -2809,10 +2839,10 @@ void BKE_object_sculpt_modifiers_changed(Object *ob) PBVHNode **nodes; int n, totnode; - BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); for (n = 0; n < totnode; n++) - BLI_pbvh_node_mark_update(nodes[n]); + BKE_pbvh_node_mark_update(nodes[n]); MEM_freeN(nodes); } @@ -2965,12 +2995,13 @@ static KeyBlock *insert_meshkey(Scene *scene, Object *ob, const char *name, int } else { /* copy from current values */ - float *data = do_ob_key(scene, ob); + int totelem; + float *data = BKE_key_evaluate_object(scene, ob, &totelem); /* create new block with prepared data */ kb = BKE_keyblock_add_ctime(key, name, FALSE); kb->data = data; - kb->totelem = me->totvert; + kb->totelem = totelem; } return kb; @@ -3002,11 +3033,12 @@ static KeyBlock *insert_lattkey(Scene *scene, Object *ob, const char *name, int } else { /* copy from current values */ - float *data = do_ob_key(scene, ob); + int totelem; + float *data = BKE_key_evaluate_object(scene, ob, &totelem); /* create new block with prepared data */ kb = BKE_keyblock_add_ctime(key, name, FALSE); - kb->totelem = lt->pntsu * lt->pntsv * lt->pntsw; + kb->totelem = totelem; kb->data = data; } @@ -3041,11 +3073,12 @@ static KeyBlock *insert_curvekey(Scene *scene, Object *ob, const char *name, int } else { /* copy from current values */ - float *data = do_ob_key(scene, ob); + int totelem; + float *data = BKE_key_evaluate_object(scene, ob, &totelem); /* create new block with prepared data */ kb = BKE_keyblock_add_ctime(key, name, FALSE); - kb->totelem = BKE_nurbList_verts_count(lb); + kb->totelem = totelem; kb->data = data; } @@ -3148,11 +3181,11 @@ void BKE_object_relink(Object *ob) if (ob->id.lib) return; - relink_constraints(&ob->constraints); + BKE_relink_constraints(&ob->constraints); if (ob->pose) { bPoseChannel *chan; for (chan = ob->pose->chanbase.first; chan; chan = chan->next) { - relink_constraints(&chan->constraints); + BKE_relink_constraints(&chan->constraints); } } modifiers_foreachIDLink(ob, copy_object__forwardModifierLinks, NULL); diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index e694a7e7eb3..c4274aa1f93 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -35,16 +35,15 @@ #include "DNA_scene_types.h" +#include "BKE_global.h" /* XXX TESTING */ #include "BKE_image.h" #include "BKE_ocean.h" -#include "BKE_global.h" // XXX TESTING -#include "BLI_math_base.h" -#include "BLI_math_inline.h" +#include "BLI_math.h" +#include "BLI_path_util.h" #include "BLI_rand.h" #include "BLI_string.h" #include "BLI_threads.h" -#include "BLI_path_util.h" #include "BLI_utildefines.h" #include "IMB_imbuf.h" @@ -54,7 +53,7 @@ #ifdef WITH_OCEANSIM -// Ocean code +/* Ocean code */ #include "fftw3.h" #define GRAVITY 9.81f @@ -82,7 +81,7 @@ typedef struct Ocean { float _Lx; float _Lz; - float normalize_factor; // init w + float normalize_factor; /* init w */ float time; short _do_disp_y; @@ -96,51 +95,52 @@ typedef struct Ocean { /* ********* sim data arrays ********* */ /* two dimensional arrays of complex */ - fftw_complex *_fft_in; // init w sim w - fftw_complex *_fft_in_x; // init w sim w - fftw_complex *_fft_in_z; // init w sim w - fftw_complex *_fft_in_jxx; // init w sim w - fftw_complex *_fft_in_jzz; // init w sim w - fftw_complex *_fft_in_jxz; // init w sim w - fftw_complex *_fft_in_nx; // init w sim w - fftw_complex *_fft_in_nz; // init w sim w - fftw_complex *_htilda; // init w sim w (only once) + fftw_complex *_fft_in; /* init w sim w */ + fftw_complex *_fft_in_x; /* init w sim w */ + fftw_complex *_fft_in_z; /* init w sim w */ + fftw_complex *_fft_in_jxx; /* init w sim w */ + fftw_complex *_fft_in_jzz; /* init w sim w */ + fftw_complex *_fft_in_jxz; /* init w sim w */ + fftw_complex *_fft_in_nx; /* init w sim w */ + fftw_complex *_fft_in_nz; /* init w sim w */ + fftw_complex *_htilda; /* init w sim w (only once) */ /* fftw "plans" */ - fftw_plan _disp_y_plan; // init w sim r - fftw_plan _disp_x_plan; // init w sim r - fftw_plan _disp_z_plan; // init w sim r - fftw_plan _N_x_plan; // init w sim r - fftw_plan _N_z_plan; // init w sim r - fftw_plan _Jxx_plan; // init w sim r - fftw_plan _Jxz_plan; // init w sim r - fftw_plan _Jzz_plan; // init w sim r + fftw_plan _disp_y_plan; /* init w sim r */ + fftw_plan _disp_x_plan; /* init w sim r */ + fftw_plan _disp_z_plan; /* init w sim r */ + fftw_plan _N_x_plan; /* init w sim r */ + fftw_plan _N_z_plan; /* init w sim r */ + fftw_plan _Jxx_plan; /* init w sim r */ + fftw_plan _Jxz_plan; /* init w sim r */ + fftw_plan _Jzz_plan; /* init w sim r */ /* two dimensional arrays of float */ - double *_disp_y; // init w sim w via plan? - double *_N_x; // init w sim w via plan? - /*float * _N_y; all member of this array has same values, so convert this array to a float to reduce memory usage (MEM01)*/ - double _N_y; // sim w ********* can be rearranged? - double *_N_z; // init w sim w via plan? - double *_disp_x; // init w sim w via plan? - double *_disp_z; // init w sim w via plan? + double *_disp_y; /* init w sim w via plan? */ + double *_N_x; /* init w sim w via plan? */ + /* all member of this array has same values, so convert this array to a float to reduce memory usage (MEM01)*/ + /*float * _N_y; */ + double _N_y; /* sim w ********* can be rearranged? */ + double *_N_z; /* init w sim w via plan? */ + double *_disp_x; /* init w sim w via plan? */ + double *_disp_z; /* init w sim w via plan? */ /* two dimensional arrays of float */ /* Jacobian and minimum eigenvalue */ - double *_Jxx; // init w sim w - double *_Jzz; // init w sim w - double *_Jxz; // init w sim w + double *_Jxx; /* init w sim w */ + double *_Jzz; /* init w sim w */ + double *_Jxz; /* init w sim w */ /* one dimensional float array */ - float *_kx; // init w sim r - float *_kz; // init w sim r + float *_kx; /* init w sim r */ + float *_kz; /* init w sim r */ /* two dimensional complex array */ - fftw_complex *_h0; // init w sim r - fftw_complex *_h0_minus; // init w sim r + fftw_complex *_h0; /* init w sim r */ + fftw_complex *_h0_minus; /* init w sim r */ /* two dimensional float array */ - float *_k; // init w sim r + float *_k; /* init w sim r */ } Ocean; @@ -152,10 +152,13 @@ static float nextfr(float min, float max) static float gaussRand(void) { - float x; // Note: to avoid numerical problems with very small - float y; // numbers, we make these variables singe-precision - float length2; // floats, but later we call the double-precision log() - // and sqrt() functions instead of logf() and sqrtf(). + /* Note: to avoid numerical problems with very small numbers, we make these variables singe-precision floats, + * but later we call the double-precision log() and sqrt() functions instead of logf() and sqrtf(). + */ + float x; + float y; + float length2; + do { x = (float) (nextfr(-1, 1)); y = (float)(nextfr(-1, 1)); @@ -167,12 +170,7 @@ static float gaussRand(void) /** * Some useful functions - * */ -MINLINE float lerp(float a, float b, float f) -{ - return a + (b - a) * f; -} - + */ MINLINE float catrom(float p0, float p1, float p2, float p3, float f) { return 0.5f * ((2.0f * p1) + @@ -186,23 +184,24 @@ MINLINE float omega(float k, float depth) return sqrtf(GRAVITY * k * tanhf(k * depth)); } -// modified Phillips spectrum +/* modified Phillips spectrum */ static float Ph(struct Ocean *o, float kx, float kz) { float tmp; float k2 = kx * kx + kz * kz; if (k2 == 0.0f) { - return 0.0f; // no DC component + return 0.0f; /* no DC component */ } - // damp out the waves going in the direction opposite the wind + /* damp out the waves going in the direction opposite the wind */ tmp = (o->_wx * kx + o->_wz * kz) / sqrtf(k2); if (tmp < 0) { tmp *= o->_damp_reflections; } - return o->_A * expf(-1.0f / (k2 * (o->_L * o->_L))) * expf(-k2 * (o->_l * o->_l)) * powf(fabsf(tmp), o->_wind_alignment) / (k2 * k2); + return o->_A * expf(-1.0f / (k2 * (o->_L * o->_L))) * expf(-k2 * (o->_l * o->_l)) * + powf(fabsf(tmp), o->_wind_alignment) / (k2 * k2); } static void compute_eigenstuff(struct OceanResult *ocr, float jxx, float jzz, float jxz) @@ -240,7 +239,7 @@ static void init_complex(fftw_complex cmpl, float real, float image) cmpl[1] = image; } -#if 0 // unused +#if 0 /* unused */ static void add_complex_f(fftw_complex res, fftw_complex cmpl, float f) { res[0] = cmpl[0] + f; @@ -306,7 +305,7 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float float frac_x, frac_z; float uu, vv; - // first wrap the texture so 0 <= (u, v) < 1 + /* first wrap the texture so 0 <= (u, v) < 1 */ u = fmodf(u, 1.0f); v = fmodf(v, 1.0f); @@ -334,7 +333,9 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float j1 = j1 % oc->_N; -#define BILERP(m) (lerp(lerp(m[i0 * oc->_N + j0], m[i1 * oc->_N + j0], frac_x), lerp(m[i0 * oc->_N + j1], m[i1 * oc->_N + j1], frac_x), frac_z)) +#define BILERP(m) (interpf(interpf(m[i1 * oc->_N + j1], m[i0 * oc->_N + j1], frac_x), \ + interpf(m[i1 * oc->_N + j0], m[i0 * oc->_N + j0], frac_x), \ + frac_z)) { if (oc->_do_disp_y) { ocr->disp[1] = BILERP(oc->_disp_y); @@ -364,14 +365,14 @@ void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float BLI_rw_mutex_unlock(&oc->oceanmutex); } -// use catmullrom interpolation rather than linear +/* use catmullrom interpolation rather than linear */ void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u, float v) { int i0, i1, i2, i3, j0, j1, j2, j3; float frac_x, frac_z; float uu, vv; - // first wrap the texture so 0 <= (u, v) < 1 + /* first wrap the texture so 0 <= (u, v) < 1 */ u = fmod(u, 1.0f); v = fmod(v, 1.0f); @@ -408,11 +409,15 @@ void BKE_ocean_eval_uv_catrom(struct Ocean *oc, struct OceanResult *ocr, float u j0 = j0 < 0 ? j0 + oc->_N : j0; j3 = j3 >= oc->_N ? j3 - oc->_N : j3; -#define INTERP(m) catrom(catrom(m[i0 * oc->_N + j0], m[i1 * oc->_N + j0], m[i2 * oc->_N + j0], m[i3 * oc->_N + j0], frac_x), \ - catrom(m[i0 * oc->_N + j1], m[i1 * oc->_N + j1], m[i2 * oc->_N + j1], m[i3 * oc->_N + j1], frac_x), \ - catrom(m[i0 * oc->_N + j2], m[i1 * oc->_N + j2], m[i2 * oc->_N + j2], m[i3 * oc->_N + j2], frac_x), \ - catrom(m[i0 * oc->_N + j3], m[i1 * oc->_N + j3], m[i2 * oc->_N + j3], m[i3 * oc->_N + j3], frac_x), \ - frac_z) +#define INTERP(m) catrom(catrom(m[i0 * oc->_N + j0], m[i1 * oc->_N + j0], \ + m[i2 * oc->_N + j0], m[i3 * oc->_N + j0], frac_x), \ + catrom(m[i0 * oc->_N + j1], m[i1 * oc->_N + j1], \ + m[i2 * oc->_N + j1], m[i3 * oc->_N + j1], frac_x), \ + catrom(m[i0 * oc->_N + j2], m[i1 * oc->_N + j2], \ + m[i2 * oc->_N + j2], m[i3 * oc->_N + j2], frac_x), \ + catrom(m[i0 * oc->_N + j3], m[i1 * oc->_N + j3], \ + m[i2 * oc->_N + j3], m[i3 * oc->_N + j3], frac_x), \ + frac_z) { if (oc->_do_disp_y) { @@ -452,9 +457,9 @@ void BKE_ocean_eval_xz_catrom(struct Ocean *oc, struct OceanResult *ocr, float x BKE_ocean_eval_uv_catrom(oc, ocr, x / oc->_Lx, z / oc->_Lz); } -// note that this doesn't wrap properly for i, j < 0, but its -// not really meant for that being just a way to get the raw data out -// to save in some image format. +/* note that this doesn't wrap properly for i, j < 0, but its not really meant for that being just a way to get + * the raw data out to save in some image format. + */ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j) { BLI_rw_mutex_lock(&oc->oceanmutex, THREAD_LOCK_READ); @@ -496,11 +501,10 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); - // compute a new htilda + /* compute a new htilda */ #pragma omp parallel for private(i, j) for (i = 0; i < o->_M; ++i) { - // note the <= _N/2 here, see the fftw doco about - // the mechanics of the complex->real fft storage + /* note the <= _N/2 here, see the fftw doco about the mechanics of the complex->real fft storage */ for (j = 0; j <= o->_N / 2; ++j) { fftw_complex exp_param1; fftw_complex exp_param2; @@ -527,15 +531,15 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount #pragma omp section { if (o->_do_disp_y) { - // y displacement + /* y displacement */ fftw_execute(o->_disp_y_plan); } - } // section 1 + } /* section 1 */ #pragma omp section { if (o->_do_chop) { - // x displacement + /* x displacement */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; @@ -546,18 +550,21 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, minus_i); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0f ? 0.0f : o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_x[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_disp_x_plan); } - } //section 2 + } /* section 2 */ #pragma omp section { if (o->_do_chop) { - // z displacement + /* z displacement */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; @@ -568,28 +575,34 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, minus_i); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0f ? 0.0f : o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_z[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_disp_z_plan); } - } // section 3 + } /* section 3 */ #pragma omp section { if (o->_do_jacobian) { - // Jxx + /* Jxx */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; - //init_complex(mul_param, -scale, 0); + /* init_complex(mul_param, -scale, 0); */ init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0f ? 0.0f : o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_jxx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } @@ -601,22 +614,25 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount } } } - } // section 4 + } /* section 4 */ #pragma omp section { if (o->_do_jacobian) { - // Jzz + /* Jzz */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; - //init_complex(mul_param, -scale, 0); + /* init_complex(mul_param, -scale, 0); */ init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0f ? 0.0f : o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_jzz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } @@ -627,32 +643,35 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount } } } - } // section 5 + } /* section 5 */ #pragma omp section { if (o->_do_jacobian) { - // Jxz + /* Jxz */ for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { fftw_complex mul_param; - //init_complex(mul_param, -scale, 0); + /* init_complex(mul_param, -scale, 0); */ init_complex(mul_param, -1, 0); mul_complex_f(mul_param, mul_param, chop_amount); mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0f ? 0.0f : o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); init_complex(o->_fft_in_jxz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } fftw_execute(o->_Jxz_plan); } - } // section 6 + } /* section 6 */ #pragma omp section { - // fft normals + /* fft normals */ if (o->_do_normals) { for (i = 0; i < o->_M; ++i) { for (j = 0; j <= o->_N / 2; ++j) { @@ -667,7 +686,7 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount fftw_execute(o->_N_x_plan); } - } // section 7 + } /* section 7 */ #pragma omp section { @@ -694,9 +713,9 @@ void BKE_simulate_ocean(struct Ocean *o, float t, float scale, float chop_amount #endif o->_N_y = 1.0f / scale; } - } // section 8 + } /* section 8 */ - } // omp sections + } /* omp sections */ BLI_rw_mutex_unlock(&o->oceanmutex); } @@ -726,7 +745,8 @@ static void set_height_normalize_factor(struct Ocean *oc) BLI_rw_mutex_unlock(&oc->oceanmutex); - if (max_h == 0.0f) max_h = 0.00001f; // just in case ... + if (max_h == 0.0f) + max_h = 0.00001f; /* just in case ... */ res = 1.0f / (max_h); @@ -743,7 +763,8 @@ struct Ocean *BKE_add_ocean(void) } void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, float l, float A, float w, float damp, - float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, short do_jacobian, int seed) + float alignment, float depth, float time, short do_height_field, short do_chop, short do_normals, + short do_jacobian, int seed) { int i, j, ii; @@ -761,8 +782,8 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, o->_Lx = Lx; o->_Lz = Lz; o->_wx = cos(w); - o->_wz = -sin(w); // wave direction - o->_L = V * V / GRAVITY; // largest wave for a given velocity V + o->_wz = -sin(w); /* wave direction */ + o->_L = V * V / GRAVITY; /* largest wave for a given velocity V */ o->time = time; o->_do_disp_y = do_height_field; @@ -776,30 +797,30 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, o->_kx = (float *) MEM_mallocN(o->_M * sizeof(float), "ocean_kx"); o->_kz = (float *) MEM_mallocN(o->_N * sizeof(float), "ocean_kz"); - // make this robust in the face of erroneous usage + /* make this robust in the face of erroneous usage */ if (o->_Lx == 0.0f) o->_Lx = 0.001f; if (o->_Lz == 0.0f) o->_Lz = 0.001f; - // the +ve components and DC + /* the +ve components and DC */ for (i = 0; i <= o->_M / 2; ++i) o->_kx[i] = 2.0f * (float)M_PI * i / o->_Lx; - // the -ve components + /* the -ve components */ for (i = o->_M - 1, ii = 0; i > o->_M / 2; --i, ++ii) o->_kx[i] = -2.0f * (float)M_PI * ii / o->_Lx; - // the +ve components and DC + /* the +ve components and DC */ for (i = 0; i <= o->_N / 2; ++i) o->_kz[i] = 2.0f * (float)M_PI * i / o->_Lz; - // the -ve components + /* the -ve components */ for (i = o->_N - 1, ii = 0; i > o->_N / 2; --i, ++ii) o->_kz[i] = -2.0f * (float)M_PI * ii / o->_Lz; - // pre-calculate the k matrix + /* pre-calculate the k matrix */ for (i = 0; i < o->_M; ++i) for (j = 0; j <= o->_N / 2; ++j) o->_k[i * (1 + o->_N / 2) + j] = sqrt(o->_kx[i] * o->_kx[i] + o->_kz[j] * o->_kz[j]); @@ -819,11 +840,11 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, } } - o->_fft_in = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in"); - o->_htilda = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_htilda"); + o->_fft_in = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in"); + o->_htilda = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_htilda"); if (o->_do_disp_y) { - o->_disp_y = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_y"); + o->_disp_y = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_y"); o->_disp_y_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in, o->_disp_y, FFTW_ESTIMATE); } @@ -831,32 +852,35 @@ void BKE_init_ocean(struct Ocean *o, int M, int N, float Lx, float Lz, float V, o->_fft_in_nx = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_nx"); o->_fft_in_nz = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_nz"); - o->_N_x = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x"); + o->_N_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_x"); /* o->_N_y = (float *) fftwf_malloc(o->_M * o->_N * sizeof(float)); (MEM01) */ - o->_N_z = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z"); + o->_N_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_N_z"); o->_N_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nx, o->_N_x, FFTW_ESTIMATE); o->_N_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_nz, o->_N_z, FFTW_ESTIMATE); } if (o->_do_chop) { - o->_fft_in_x = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_x"); - o->_fft_in_z = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_z"); + o->_fft_in_x = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_x"); + o->_fft_in_z = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_z"); - o->_disp_x = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_x"); - o->_disp_z = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_z"); + o->_disp_x = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_x"); + o->_disp_z = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_disp_z"); o->_disp_x_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_x, o->_disp_x, FFTW_ESTIMATE); o->_disp_z_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_z, o->_disp_z, FFTW_ESTIMATE); } if (o->_do_jacobian) { - o->_fft_in_jxx = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_jxx"); - o->_fft_in_jzz = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_jzz"); - o->_fft_in_jxz = (fftw_complex *) MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), "ocean_fft_in_jxz"); + o->_fft_in_jxx = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), + "ocean_fft_in_jxx"); + o->_fft_in_jzz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), + "ocean_fft_in_jzz"); + o->_fft_in_jxz = (fftw_complex *)MEM_mallocN(o->_M * (1 + o->_N / 2) * sizeof(fftw_complex), + "ocean_fft_in_jxz"); - o->_Jxx = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxx"); - o->_Jzz = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jzz"); - o->_Jxz = (double *) MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxz"); + o->_Jxx = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxx"); + o->_Jzz = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jzz"); + o->_Jxz = (double *)MEM_mallocN(o->_M * o->_N * sizeof(double), "ocean_Jxz"); o->_Jxx_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jxx, o->_Jxx, FFTW_ESTIMATE); o->_Jzz_plan = fftw_plan_dft_c2r_2d(o->_M, o->_N, o->_fft_in_jzz, o->_Jzz, FFTW_ESTIMATE); @@ -967,7 +991,7 @@ static void cache_filename(char *string, const char *path, const char *relbase, BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname); - BKE_makepicstring(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, 1, TRUE); + BKE_makepicstring_from_type(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, 1, TRUE); } /* silly functions but useful to inline when the args do a lot of indirections */ @@ -1076,8 +1100,7 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, in } } -struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbase, - int start, int end, float wave_scale, +struct OceanCache *BKE_init_ocean_cache(const char *bakepath, const char *relbase, int start, int end, float wave_scale, float chop_amount, float foam_coverage, float foam_fade, int resolution) { OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data"); @@ -1112,7 +1135,7 @@ void BKE_simulate_ocean_cache(struct OceanCache *och, int frame) /* ibufs array is zero based, but filenames are based on frame numbers */ /* still need to clamp frame numbers to valid range of images on disk though */ CLAMP(frame, och->start, och->end); - f = frame - och->start; // shift to 0 based + f = frame - och->start; /* shift to 0 based */ /* if image is already loaded in mem, return */ if (och->ibufs_disp[f] != NULL) return; @@ -1121,22 +1144,35 @@ void BKE_simulate_ocean_cache(struct OceanCache *och, int frame) cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_DISPLACE); och->ibufs_disp[f] = IMB_loadiffname(string, 0, NULL); - //if (och->ibufs_disp[f] == NULL) printf("error loading %s\n", string); - //else printf("loaded cache %s\n", string); +#if 0 + if (och->ibufs_disp[f] == NULL) + printf("error loading %s\n", string); + else + printf("loaded cache %s\n", string); +#endif cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_FOAM); och->ibufs_foam[f] = IMB_loadiffname(string, 0, NULL); - //if (och->ibufs_foam[f] == NULL) printf("error loading %s\n", string); - //else printf("loaded cache %s\n", string); +#if 0 + if (och->ibufs_foam[f] == NULL) + printf("error loading %s\n", string); + else + printf("loaded cache %s\n", string); +#endif cache_filename(string, och->bakepath, och->relbase, frame, CACHE_TYPE_NORMAL); och->ibufs_norm[f] = IMB_loadiffname(string, 0, NULL); - //if (och->ibufs_norm[f] == NULL) printf("error loading %s\n", string); - //else printf("loaded cache %s\n", string); +#if 0 + if (och->ibufs_norm[f] == NULL) + printf("error loading %s\n", string); + else + printf("loaded cache %s\n", string); +#endif } -void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data) +void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(void *, float progress, int *cancel), + void *update_cb_data) { /* note: some of these values remain uninitialized unless certain options * are enabled, take care that BKE_ocean_eval_ij() initializes a member @@ -1197,13 +1233,13 @@ void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v pr = prev_foam[res_x * y + x]; } - /* r = BLI_frand(); */ /* UNUSED */ // randomly reduce foam + /* r = BLI_frand(); */ /* UNUSED */ /* randomly reduce foam */ - //pr = pr * och->foam_fade; // overall fade + /* pr = pr * och->foam_fade; */ /* overall fade */ - // remember ocean coord sys is Y up! - // break up the foam where height (Y) is low (wave valley), - // and X and Z displacement is greatest + /* remember ocean coord sys is Y up! + * break up the foam where height (Y) is low (wave valley), and X and Z displacement is greatest + */ #if 0 vec[0] = ocr.disp[0]; @@ -1219,22 +1255,27 @@ void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v neg_eplus = ocr.Eplus[2] < 0.0f ? 1.0f + ocr.Eplus[2] : 1.0f; neg_eplus = neg_eplus < 0.0f ? 0.0f : neg_eplus; - //if (ocr.disp[1] < 0.0 || r > och->foam_fade) - // pr *= och->foam_fade; +#if 0 + if (ocr.disp[1] < 0.0 || r > och->foam_fade) + pr *= och->foam_fade; - //pr = pr * (1.0 - hor_stretch) * ocr.disp[1]; - //pr = pr * neg_disp * neg_eplus; + pr = pr * (1.0 - hor_stretch) * ocr.disp[1]; + pr = pr * neg_disp * neg_eplus; +#endif - if (pr < 1.0f) pr *= pr; + if (pr < 1.0f) + pr *= pr; pr *= och->foam_fade * (0.75f + neg_eplus * 0.25f); - - foam_result = pr + ocr.foam; + /* A full clamping should not be needed! */ + foam_result = min_ff(pr + ocr.foam, 1.0f); prev_foam[res_x * y + x] = foam_result; + /*foam_result = min_ff(foam_result, 1.0f); */ + value_to_rgba_unit_alpha(&ibuf_foam->rect_float[4 * (res_x * y + x)], foam_result); } @@ -1279,7 +1320,7 @@ void BKE_bake_ocean(struct Ocean *o, struct OceanCache *och, void (*update_cb)(v och->baked = 1; } -#else // WITH_OCEANSIM +#else /* WITH_OCEANSIM */ /* stub */ typedef struct Ocean { @@ -1297,8 +1338,9 @@ void BKE_ocean_eval_uv(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr) { } -// use catmullrom interpolation rather than linear -void BKE_ocean_eval_uv_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(u), float UNUSED(v)) +/* use catmullrom interpolation rather than linear */ +void BKE_ocean_eval_uv_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(u), + float UNUSED(v)) { } @@ -1306,7 +1348,8 @@ void BKE_ocean_eval_xz(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr) { } -void BKE_ocean_eval_xz_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(x), float UNUSED(z)) +void BKE_ocean_eval_xz_catrom(struct Ocean *UNUSED(oc), struct OceanResult *UNUSED(ocr), float UNUSED(x), + float UNUSED(z)) { } @@ -1325,8 +1368,10 @@ struct Ocean *BKE_add_ocean(void) return oc; } -void BKE_init_ocean(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz), float UNUSED(V), float UNUSED(l), float UNUSED(A), float UNUSED(w), float UNUSED(damp), - float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), short UNUSED(do_height_field), short UNUSED(do_chop), short UNUSED(do_normals), short UNUSED(do_jacobian), int UNUSED(seed)) +void BKE_init_ocean(struct Ocean *UNUSED(o), int UNUSED(M), int UNUSED(N), float UNUSED(Lx), float UNUSED(Lz), + float UNUSED(V), float UNUSED(l), float UNUSED(A), float UNUSED(w), float UNUSED(damp), + float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), short UNUSED(do_height_field), + short UNUSED(do_chop), short UNUSED(do_normals), short UNUSED(do_jacobian), int UNUSED(seed)) { } @@ -1351,17 +1396,19 @@ void BKE_free_ocean_cache(struct OceanCache *och) MEM_freeN(och); } -void BKE_ocean_cache_eval_uv(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), float UNUSED(u), float UNUSED(v)) +void BKE_ocean_cache_eval_uv(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), + float UNUSED(u), float UNUSED(v)) { } -void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), int UNUSED(i), int UNUSED(j)) +void BKE_ocean_cache_eval_ij(struct OceanCache *UNUSED(och), struct OceanResult *UNUSED(ocr), int UNUSED(f), + int UNUSED(i), int UNUSED(j)) { } -OceanCache *BKE_init_ocean_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), - int UNUSED(start), int UNUSED(end), float UNUSED(wave_scale), - float UNUSED(chop_amount), float UNUSED(foam_coverage), float UNUSED(foam_fade), int UNUSED(resolution)) +OceanCache *BKE_init_ocean_cache(const char *UNUSED(bakepath), const char *UNUSED(relbase), int UNUSED(start), + int UNUSED(end), float UNUSED(wave_scale), float UNUSED(chop_amount), + float UNUSED(foam_coverage), float UNUSED(foam_fade), int UNUSED(resolution)) { OceanCache *och = MEM_callocN(sizeof(OceanCache), "ocean cache data"); @@ -1372,9 +1419,10 @@ void BKE_simulate_ocean_cache(struct OceanCache *UNUSED(och), int UNUSED(frame)) { } -void BKE_bake_ocean(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och), void (*update_cb)(void *, float progress, int *cancel), void *UNUSED(update_cb_data)) +void BKE_bake_ocean(struct Ocean *UNUSED(o), struct OceanCache *UNUSED(och), + void (*update_cb)(void *, float progress, int *cancel), void *UNUSED(update_cb_data)) { /* unused */ (void)update_cb; } -#endif // WITH_OCEANSIM +#endif /* WITH_OCEANSIM */ \ No newline at end of file diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index dec49f417ae..9f77094994d 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -43,6 +43,7 @@ #include "MEM_guardedalloc.h" #include "DNA_image_types.h" +#include "DNA_ID.h" #include "DNA_sound_types.h" #include "DNA_vfont_types.h" #include "DNA_packedFile_types.h" @@ -226,6 +227,7 @@ PackedFile *newPackedFile(ReportList *reports, const char *filename, const char return (pf); } +/* no libraries for now */ void packAll(Main *bmain, ReportList *reports) { Image *ima; @@ -538,6 +540,41 @@ int unpackImage(ReportList *reports, Image *ima, int how) return(ret_value); } +int unpackLibraries(Main *bmain, ReportList *reports) +{ + Library *lib; + char *newname; + int ret_value = RET_ERROR; + + for (lib = bmain->library.first; lib; lib = lib->id.next) { + if (lib->packedfile && lib->name[0]) { + + newname = unpackFile(reports, lib->filepath, lib->filepath, lib->packedfile, PF_WRITE_ORIGINAL); + if (newname != NULL) { + ret_value = RET_OK; + + printf("Saved .blend library: %s\n", newname); + + freePackedFile(lib->packedfile); + lib->packedfile = NULL; + + MEM_freeN(newname); + } + } + } + + return(ret_value); +} + +void packLibraries(Main *bmain, ReportList *reports) +{ + Library *lib; + + for (lib = bmain->library.first; lib; lib = lib->id.next) + if (lib->packedfile == NULL) + lib->packedfile = newPackedFile(reports, lib->name, bmain->name); +} + void unpackAll(Main *bmain, ReportList *reports, int how) { Image *ima; diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index fa5268e039e..5847e7508f0 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -212,7 +212,7 @@ int paint_is_face_hidden(const MFace *f, const MVert *mvert) } /* returns non-zero if any of the corners of the grid - * face whose inner corner is at (x,y) are hidden, + * face whose inner corner is at (x, y) are hidden, * zero otherwise */ int paint_is_grid_face_hidden(const unsigned int *grid_hidden, int gridsize, int x, int y) diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 090082b333d..3b897e94241 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -522,9 +522,9 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) vec[0]/=delta[0]; vec[1]/=delta[1]; vec[2]/=delta[2]; - (pa + ((int)(vec[0] * (size[0] - 1)) * res + - (int)(vec[1] * (size[1] - 1))) * res + - (int)(vec[2] * (size[2] - 1)))->flag &= ~PARS_UNEXIST; + pa[((int)(vec[0] * (size[0] - 1)) * res + + (int)(vec[1] * (size[1] - 1))) * res + + (int)(vec[2] * (size[2] - 1))].flag &= ~PARS_UNEXIST; } } else if (ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) { diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 209461bad2f..2df2dd631d5 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -41,124 +41,12 @@ #include "GPU_buffers.h" +#include "pbvh_intern.h" + #define LEAF_LIMIT 10000 //#define PERFCNTRS -/* Axis-aligned bounding box */ -typedef struct { - float bmin[3], bmax[3]; -} BB; - -/* Axis-aligned bounding box with centroid */ -typedef struct { - float bmin[3], bmax[3], bcentroid[3]; -} BBC; - -struct PBVHNode { - /* Opaque handle for drawing code */ - GPU_Buffers *draw_buffers; - - /* Voxel bounds */ - BB vb; - BB orig_vb; - - /* For internal nodes, the offset of the children in the PBVH - * 'nodes' array. */ - int children_offset; - - /* Pointer into the PBVH prim_indices array and the number of - * primitives used by this leaf node. - * - * Used for leaf nodes in both mesh- and multires-based PBVHs. - */ - int *prim_indices; - unsigned int totprim; - - /* Array of indices into the mesh's MVert array. Contains the - * indices of all vertices used by faces that are within this - * node's bounding box. - * - * Note that a vertex might be used by a multiple faces, and - * these faces might be in different leaf nodes. Such a vertex - * will appear in the vert_indices array of each of those leaf - * nodes. - * - * In order to support cases where you want access to multiple - * nodes' vertices without duplication, the vert_indices array - * is ordered such that the first part of the array, up to - * index 'uniq_verts', contains "unique" vertex indices. These - * vertices might not be truly unique to this node, but if - * they appear in another node's vert_indices array, they will - * be above that node's 'uniq_verts' value. - * - * Used for leaf nodes in a mesh-based PBVH (not multires.) - */ - int *vert_indices; - unsigned int uniq_verts, face_verts; - - /* An array mapping face corners into the vert_indices - * array. The array is sized to match 'totprim', and each of - * the face's corners gets an index into the vert_indices - * array, in the same order as the corners in the original - * MFace. The fourth value should not be used if the original - * face is a triangle. - * - * Used for leaf nodes in a mesh-based PBVH (not multires.) - */ - int (*face_vert_indices)[4]; - - /* Indicates whether this node is a leaf or not; also used for - * marking various updates that need to be applied. */ - PBVHNodeFlags flag : 8; - - /* Used for raycasting: how close bb is to the ray point. */ - float tmin; - - int proxy_count; - PBVHProxyNode *proxies; -}; - -struct PBVH { - PBVHType type; - - PBVHNode *nodes; - int node_mem_count, totnode; - - int *prim_indices; - int totprim; - int totvert; - - int leaf_limit; - - /* Mesh data */ - MVert *verts; - MFace *faces; - CustomData *vdata; - - /* Grid Data */ - CCGKey gridkey; - CCGElem **grids; - DMGridAdjacency *gridadj; - void **gridfaces; - const DMFlagMat *grid_flag_mats; - int totgrid; - BLI_bitmap *grid_hidden; - - /* Only used during BVH build and update, - * don't need to remain valid after */ - BLI_bitmap vert_bitmap; - -#ifdef PERFCNTRS - int perf_modified; -#endif - - /* flag are verts/faces deformed */ - int deformed; - - int show_diffuse_color; -}; - #define STACK_FIXED_DEPTH 100 typedef struct PBVHStack { @@ -168,7 +56,7 @@ typedef struct PBVHStack { typedef struct PBVHIter { PBVH *bvh; - BLI_pbvh_SearchCallback scb; + BKE_pbvh_SearchCallback scb; void *search_data; PBVHStack *stack; @@ -178,14 +66,14 @@ typedef struct PBVHIter { int stackspace; } PBVHIter; -static void BB_reset(BB *bb) +void BB_reset(BB *bb) { bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX; bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX; } /* Expand the bounding box to include a new coordinate */ -static void BB_expand(BB *bb, float co[3]) +void BB_expand(BB *bb, const float co[3]) { int i; for (i = 0; i < 3; ++i) { @@ -195,7 +83,7 @@ static void BB_expand(BB *bb, float co[3]) } /* Expand the bounding box to include another bounding box */ -static void BB_expand_with_bb(BB *bb, BB *bb2) +void BB_expand_with_bb(BB *bb, BB *bb2) { int i; for (i = 0; i < 3; ++i) { @@ -205,7 +93,7 @@ static void BB_expand_with_bb(BB *bb, BB *bb2) } /* Return 0, 1, or 2 to indicate the widest axis of the bounding box */ -static int BB_widest_axis(BB *bb) +int BB_widest_axis(const BB *bb) { float dim[3]; int i; @@ -227,7 +115,7 @@ static int BB_widest_axis(BB *bb) } } -static void BBC_update_centroid(BBC *bbc) +void BBC_update_centroid(BBC *bbc) { int i; for (i = 0; i < 3; ++i) @@ -244,11 +132,11 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node) if (node->flag & PBVH_Leaf) { PBVHVertexIter vd; - BLI_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL) + BKE_pbvh_vertex_iter_begin(bvh, node, vd, PBVH_ITER_ALL) { BB_expand(&vb, vd.co); } - BLI_pbvh_vertex_iter_end; + BKE_pbvh_vertex_iter_end; } else { BB_expand_with_bb(&vb, @@ -260,12 +148,12 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node) node->vb = vb; } -//void BLI_pbvh_node_BB_reset(PBVHNode *node) +//void BKE_pbvh_node_BB_reset(PBVHNode *node) //{ // BB_reset(&node->vb); //} // -//void BLI_pbvh_node_BB_expand(PBVHNode *node, float co[3]) +//void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]) //{ // BB_expand(&node->vb, co); //} @@ -332,7 +220,7 @@ static int partition_indices_material(PBVH *bvh, int lo, int hi) } } -static void grow_nodes(PBVH *bvh, int totnode) +void pbvh_grow_nodes(PBVH *bvh, int totnode) { if (totnode > bvh->node_mem_count) { PBVHNode *prev = bvh->nodes; @@ -545,7 +433,7 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, /* Add two child nodes */ bvh->nodes[node_index].children_offset = bvh->totnode; - grow_nodes(bvh, bvh->totnode + 2); + pbvh_grow_nodes(bvh, bvh->totnode + 2); /* Update parent node bounding box */ update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count); @@ -605,7 +493,7 @@ static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim) } /* Do a full rebuild with on Mesh data structure */ -void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert, struct CustomData *vdata) +void BKE_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert, struct CustomData *vdata) { BBC *prim_bbc = NULL; BB cb; @@ -647,7 +535,7 @@ void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int } /* Do a full rebuild with on Grids data structure */ -void BLI_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, +void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap *grid_hidden) { BBC *prim_bbc = NULL; @@ -690,14 +578,14 @@ void BLI_pbvh_build_grids(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, MEM_freeN(prim_bbc); } -PBVH *BLI_pbvh_new(void) +PBVH *BKE_pbvh_new(void) { PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh"); return bvh; } -void BLI_pbvh_free(PBVH *bvh) +void BKE_pbvh_free(PBVH *bvh) { PBVHNode *node; int i; @@ -712,6 +600,14 @@ void BLI_pbvh_free(PBVH *bvh) MEM_freeN(node->vert_indices); if (node->face_vert_indices) MEM_freeN(node->face_vert_indices); + BKE_pbvh_node_layer_disp_free(node); + + if (node->bm_faces) + BLI_ghash_free(node->bm_faces, NULL, NULL); + if (node->bm_unique_verts) + BLI_ghash_free(node->bm_unique_verts, NULL, NULL); + if (node->bm_other_verts) + BLI_ghash_free(node->bm_other_verts, NULL, NULL); } } @@ -731,10 +627,15 @@ void BLI_pbvh_free(PBVH *bvh) if (bvh->prim_indices) MEM_freeN(bvh->prim_indices); + if (bvh->bm_vert_to_node) + BLI_ghash_free(bvh->bm_vert_to_node, NULL, NULL); + if (bvh->bm_face_to_node) + BLI_ghash_free(bvh->bm_face_to_node, NULL, NULL); + MEM_freeN(bvh); } -static void pbvh_iter_begin(PBVHIter *iter, PBVH *bvh, BLI_pbvh_SearchCallback scb, void *search_data) +static void pbvh_iter_begin(PBVHIter *iter, PBVH *bvh, BKE_pbvh_SearchCallback scb, void *search_data) { iter->bvh = bvh; iter->scb = scb; @@ -845,8 +746,8 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter) return NULL; } -void BLI_pbvh_search_gather(PBVH *bvh, - BLI_pbvh_SearchCallback scb, void *search_data, +void BKE_pbvh_search_gather(PBVH *bvh, + BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot) { PBVHIter iter; @@ -886,9 +787,9 @@ void BLI_pbvh_search_gather(PBVH *bvh, *r_tot = tot; } -void BLI_pbvh_search_callback(PBVH *bvh, - BLI_pbvh_SearchCallback scb, void *search_data, - BLI_pbvh_HitCallback hcb, void *hit_data) +void BKE_pbvh_search_callback(PBVH *bvh, + BKE_pbvh_SearchCallback scb, void *search_data, + BKE_pbvh_HitCallback hcb, void *hit_data) { PBVHIter iter; PBVHNode *node; @@ -929,7 +830,7 @@ static void node_tree_insert(node_tree *tree, node_tree *new_node) } } -static void traverse_tree(node_tree *tree, BLI_pbvh_HitOccludedCallback hcb, void *hit_data, float *tmin) +static void traverse_tree(node_tree *tree, BKE_pbvh_HitOccludedCallback hcb, void *hit_data, float *tmin) { if (tree->left) traverse_tree(tree->left, hcb, hit_data, tmin); @@ -953,14 +854,14 @@ static void free_tree(node_tree *tree) free(tree); } -float BLI_pbvh_node_get_tmin(PBVHNode *node) +float BKE_pbvh_node_get_tmin(PBVHNode *node) { return node->tmin; } -static void BLI_pbvh_search_callback_occluded(PBVH *bvh, - BLI_pbvh_SearchCallback scb, void *search_data, - BLI_pbvh_HitOccludedCallback hcb, void *hit_data) +static void BKE_pbvh_search_callback_occluded(PBVH *bvh, + BKE_pbvh_SearchCallback scb, void *search_data, + BKE_pbvh_HitOccludedCallback hcb, void *hit_data) { PBVHIter iter; PBVHNode *node; @@ -1011,6 +912,11 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, float (*vnor)[3]; int n; + if (bvh->type == PBVH_BMESH) { + pbvh_bmesh_normals_update(nodes, totnode); + return; + } + if (bvh->type != PBVH_FACES) return; @@ -1104,8 +1010,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, MEM_freeN(vnor); } -static void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, - int totnode, int flag) +void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) { int n; @@ -1152,6 +1057,11 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) node->prim_indices, node->totprim); break; + case PBVH_BMESH: + node->draw_buffers = + GPU_build_bmesh_buffers(bvh->flags & + PBVH_DYNTOPO_SMOOTH_SHADING); + break; } node->flag &= ~PBVH_RebuildDrawBuffers; @@ -1179,6 +1089,13 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) node->face_vert_indices, bvh->show_diffuse_color); break; + case PBVH_BMESH: + GPU_update_bmesh_buffers(node->draw_buffers, + bvh->bm, + node->bm_faces, + node->bm_unique_verts, + node->bm_other_verts); + break; } node->flag &= ~PBVH_UpdateDrawBuffers; @@ -1217,7 +1134,7 @@ static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) return update; } -void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) +void BKE_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) { PBVHNode **nodes; int totnode; @@ -1225,7 +1142,7 @@ void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) if (!bvh->nodes) return; - BLI_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(flag), + BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(flag), &nodes, &totnode); if (flag & PBVH_UpdateNormals) @@ -1240,7 +1157,7 @@ void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) if (nodes) MEM_freeN(nodes); } -void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]) +void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]) { PBVHIter iter; PBVHNode *node; @@ -1260,7 +1177,7 @@ void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]) copy_v3_v3(bb_max, bb.bmax); } -void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface) +void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface) { PBVHIter iter; PBVHNode *node; @@ -1316,36 +1233,42 @@ void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *tot /***************************** PBVH Access ***********************************/ -PBVHType BLI_pbvh_type(const PBVH *bvh) +PBVHType BKE_pbvh_type(const PBVH *bvh) { return bvh->type; } -BLI_bitmap *BLI_pbvh_grid_hidden(const PBVH *bvh) +BLI_bitmap *BKE_pbvh_grid_hidden(const PBVH *bvh) { BLI_assert(bvh->type == PBVH_GRIDS); return bvh->grid_hidden; } -void BLI_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key) +void BKE_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key) { BLI_assert(bvh->type == PBVH_GRIDS); *key = bvh->gridkey; } +BMesh *BKE_pbvh_get_bmesh(PBVH *bvh) +{ + BLI_assert(bvh->type == PBVH_BMESH); + return bvh->bm; +} + /***************************** Node Access ***********************************/ -void BLI_pbvh_node_mark_update(PBVHNode *node) +void BKE_pbvh_node_mark_update(PBVHNode *node) { node->flag |= PBVH_UpdateNormals | PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; } -void BLI_pbvh_node_mark_rebuild_draw(PBVHNode *node) +void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node) { node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; } -void BLI_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden) +void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden) { BLI_assert(node->flag & PBVH_Leaf); @@ -1355,13 +1278,13 @@ void BLI_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden) node->flag &= ~PBVH_FullyHidden; } -void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, int **vert_indices, MVert **verts) +void BKE_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, int **vert_indices, MVert **verts) { if (vert_indices) *vert_indices = node->vert_indices; if (verts) *verts = bvh->verts; } -void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *totvert) +void BKE_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *totvert) { int tot; @@ -1375,10 +1298,15 @@ void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to if (totvert) *totvert = node->uniq_verts + node->face_verts; if (uniquevert) *uniquevert = node->uniq_verts; break; + case PBVH_BMESH: + tot = BLI_ghash_size(node->bm_unique_verts); + if (totvert) *totvert = tot + BLI_ghash_size(node->bm_other_verts); + if (uniquevert) *uniquevert = tot; + break; } } -void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata, DMGridAdjacency **gridadj) +void BKE_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, CCGElem ***griddata, DMGridAdjacency **gridadj) { switch (bvh->type) { case PBVH_GRIDS: @@ -1390,6 +1318,7 @@ void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int if (gridadj) *gridadj = bvh->gridadj; break; case PBVH_FACES: + case PBVH_BMESH: if (grid_indices) *grid_indices = NULL; if (totgrid) *totgrid = 0; if (maxgrid) *maxgrid = 0; @@ -1400,19 +1329,19 @@ void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int } } -void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) +void BKE_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) { copy_v3_v3(bb_min, node->vb.bmin); copy_v3_v3(bb_max, node->vb.bmax); } -void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) +void BKE_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]) { copy_v3_v3(bb_min, node->orig_vb.bmin); copy_v3_v3(bb_max, node->orig_vb.bmax); } -void BLI_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count) +void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *proxy_count) { if (node->proxy_count > 0) { if (proxies) *proxies = node->proxies; @@ -1437,14 +1366,14 @@ static int ray_aabb_intersect(PBVHNode *node, void *data_v) float bb_min[3], bb_max[3]; if (rcd->original) - BLI_pbvh_node_get_original_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_original_BB(node, bb_min, bb_max); else - BLI_pbvh_node_get_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_BB(node, bb_min, bb_max); return isect_ray_aabb(&rcd->ray, bb_min, bb_max, &node->tmin); } -void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data, +void BKE_pbvh_raycast(PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data, const float ray_start[3], const float ray_normal[3], int original) { @@ -1453,14 +1382,14 @@ void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data, isect_ray_aabb_initialize(&rcd.ray, ray_start, ray_normal); rcd.original = original; - BLI_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data); + BKE_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data); } -static int ray_face_intersection(const float ray_start[3], - const float ray_normal[3], - const float *t0, const float *t1, - const float *t2, const float *t3, - float *fdist) +int ray_face_intersection(const float ray_start[3], + const float ray_normal[3], + const float *t0, const float *t1, + const float *t2, const float *t3, + float *fdist) { float dist; @@ -1566,7 +1495,7 @@ static int pbvh_grids_node_raycast(PBVH *bvh, PBVHNode *node, return hit; } -int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], +int BKE_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco, const float ray_start[3], const float ray_normal[3], float *dist) { @@ -1584,6 +1513,9 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], hit |= pbvh_grids_node_raycast(bvh, node, origco, ray_start, ray_normal, dist); break; + case PBVH_BMESH: + hit = pbvh_bmesh_node_raycast(node, ray_start, ray_normal, dist, use_origco); + break; } return hit; @@ -1591,8 +1523,15 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], //#include -void BLI_pbvh_node_draw(PBVHNode *node, void *setMaterial) +typedef struct { + DMSetMaterial setMaterial; + int wireframe; +} PBVHNodeDrawData; + +void BKE_pbvh_node_draw(PBVHNode *node, void *data_v) { + PBVHNodeDrawData *data = data_v; + #if 0 /* XXX: Just some quick code to show leaf nodes in different colors */ float col[3]; int i; @@ -1611,7 +1550,9 @@ void BLI_pbvh_node_draw(PBVHNode *node, void *setMaterial) #endif if (!(node->flag & PBVH_FullyHidden)) - GPU_draw_buffers(node->draw_buffers, setMaterial); + GPU_draw_buffers(node->draw_buffers, + data->setMaterial, + data->wireframe); } typedef enum { @@ -1654,19 +1595,19 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3], return ret; } -int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data) +int BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data) { float bb_min[3], bb_max[3]; - BLI_pbvh_node_get_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_BB(node, bb_min, bb_max); return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE; } -int BLI_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) +int BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) { float bb_min[3], bb_max[3]; - BLI_pbvh_node_get_BB(node, bb_min, bb_max); + BKE_pbvh_node_get_BB(node, bb_min, bb_max); return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE; } @@ -1679,16 +1620,17 @@ static void pbvh_node_check_diffuse_changed(PBVH *bvh, PBVHNode *node) node->flag |= PBVH_UpdateDrawBuffers; } -void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], - DMSetMaterial setMaterial) +void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], + DMSetMaterial setMaterial, int wireframe) { + PBVHNodeDrawData draw_data = {setMaterial, wireframe}; PBVHNode **nodes; int a, totnode; for (a = 0; a < bvh->totnode; a++) pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]); - BLI_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers), + BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers), &nodes, &totnode); pbvh_update_normals(bvh, nodes, totnode, face_nors); @@ -1697,15 +1639,15 @@ void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], if (nodes) MEM_freeN(nodes); if (planes) { - BLI_pbvh_search_callback(bvh, BLI_pbvh_node_planes_contain_AABB, - planes, BLI_pbvh_node_draw, setMaterial); + BKE_pbvh_search_callback(bvh, BKE_pbvh_node_planes_contain_AABB, + planes, BKE_pbvh_node_draw, &draw_data); } else { - BLI_pbvh_search_callback(bvh, NULL, NULL, BLI_pbvh_node_draw, setMaterial); + BKE_pbvh_search_callback(bvh, NULL, NULL, BKE_pbvh_node_draw, &draw_data); } } -void BLI_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces, +void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap *grid_hidden) { int a; @@ -1719,11 +1661,31 @@ void BLI_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, bvh->grid_hidden = grid_hidden; for (a = 0; a < bvh->totnode; ++a) - BLI_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]); + BKE_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]); } } -float (*BLI_pbvh_get_vertCos(PBVH * pbvh))[3] +/* Get the node's displacement layer, creating it if necessary */ +float *BKE_pbvh_node_layer_disp_get(PBVH *bvh, PBVHNode *node) +{ + if (!node->layer_disp) { + int totvert = 0; + BKE_pbvh_node_num_verts(bvh, node, &totvert, NULL); + node->layer_disp = MEM_callocN(sizeof(float) * totvert, "layer disp"); + } + return node->layer_disp; +} + +/* If the node has a displacement layer, free it and set to null */ +void BKE_pbvh_node_layer_disp_free(PBVHNode *node) +{ + if (node->layer_disp) { + MEM_freeN(node->layer_disp); + node->layer_disp = NULL; + } +} + +float (*BKE_pbvh_get_vertCos(PBVH * pbvh))[3] { int a; float (*vertCos)[3] = NULL; @@ -1732,7 +1694,7 @@ float (*BLI_pbvh_get_vertCos(PBVH * pbvh))[3] float *co; MVert *mvert = pbvh->verts; - vertCos = MEM_callocN(3 * pbvh->totvert * sizeof(float), "BLI_pbvh_get_vertCoords"); + vertCos = MEM_callocN(3 * pbvh->totvert * sizeof(float), "BKE_pbvh_get_vertCoords"); co = (float *)vertCos; for (a = 0; a < pbvh->totvert; a++, mvert++, co += 3) { @@ -1743,7 +1705,7 @@ float (*BLI_pbvh_get_vertCos(PBVH * pbvh))[3] return vertCos; } -void BLI_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) +void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) { int a; @@ -1772,21 +1734,21 @@ void BLI_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) BKE_mesh_calc_normals_tessface(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL); for (a = 0; a < pbvh->totnode; ++a) - BLI_pbvh_node_mark_update(&pbvh->nodes[a]); + BKE_pbvh_node_mark_update(&pbvh->nodes[a]); - BLI_pbvh_update(pbvh, PBVH_UpdateBB, NULL); - BLI_pbvh_update(pbvh, PBVH_UpdateOriginalBB, NULL); + BKE_pbvh_update(pbvh, PBVH_UpdateBB, NULL); + BKE_pbvh_update(pbvh, PBVH_UpdateOriginalBB, NULL); } } -int BLI_pbvh_isDeformed(PBVH *pbvh) +int BKE_pbvh_isDeformed(PBVH *pbvh) { return pbvh->deformed; } /* Proxies */ -PBVHProxyNode *BLI_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node) +PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node) { int index, totverts; @@ -1802,14 +1764,14 @@ PBVHProxyNode *BLI_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node) else node->proxies = MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy"); - BLI_pbvh_node_num_verts(bvh, node, &totverts, NULL); + BKE_pbvh_node_num_verts(bvh, node, &totverts, NULL); node->proxies[index].co = MEM_callocN(sizeof(float[3]) * totverts, "PBVHNodeProxy.co"); } return node->proxies + index; } -void BLI_pbvh_node_free_proxies(PBVHNode *node) +void BKE_pbvh_node_free_proxies(PBVHNode *node) { #pragma omp critical { @@ -1827,7 +1789,7 @@ void BLI_pbvh_node_free_proxies(PBVHNode *node) } } -void BLI_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot) +void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot) { PBVHNode **array = NULL, **newarray, *node; int tot = 0, space = 0; @@ -1840,7 +1802,7 @@ void BLI_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot) if (tot == space) { /* resize array if needed */ space = (tot == 0) ? 32 : space * 2; - newarray = MEM_callocN(sizeof(PBVHNode) * space, "BLI_pbvh_gather_proxies"); + newarray = MEM_callocN(sizeof(PBVHNode) * space, "BKE_pbvh_gather_proxies"); if (array) { memcpy(newarray, array, sizeof(PBVHNode) * tot); @@ -1877,9 +1839,9 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, vi->fno = 0; vi->mvert = 0; - BLI_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); - BLI_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); - BLI_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); + BKE_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); + BKE_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); + BKE_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); vi->key = &bvh->gridkey; vi->grids = grids; @@ -1894,12 +1856,18 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node, vi->vert_indices = vert_indices; vi->mverts = verts; + if (bvh->type == PBVH_BMESH) { + BLI_ghashIterator_init(&vi->bm_unique_verts, node->bm_unique_verts); + BLI_ghashIterator_init(&vi->bm_other_verts, node->bm_other_verts); + vi->bm_vdata = &bvh->bm->vdata; + } + vi->gh = NULL; if (vi->grids && mode == PBVH_ITER_UNIQUE) vi->grid_hidden = bvh->grid_hidden; vi->mask = NULL; - if (!vi->grids) + if (bvh->type == PBVH_FACES) vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK); } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c new file mode 100644 index 00000000000..791288a4dda --- /dev/null +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -0,0 +1,1414 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_buffer.h" +#include "BLI_ghash.h" +#include "BLI_heap.h" +#include "BLI_math.h" + +#include "BKE_ccg.h" +#include "BKE_DerivedMesh.h" +#include "BKE_global.h" +#include "BKE_pbvh.h" + +#include "GPU_buffers.h" + +#include "bmesh.h" +#include "pbvh_intern.h" + +#include + +/****************************** Building ******************************/ + +/* Update node data after splitting */ +static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index) +{ + GHashIterator gh_iter; + PBVHNode *n = &bvh->nodes[node_index]; + + /* Create vert hash sets */ + n->bm_unique_verts = BLI_ghash_ptr_new("bm_unique_verts"); + n->bm_other_verts = BLI_ghash_ptr_new("bm_other_verts"); + + BB_reset(&n->vb); + + GHASH_ITER (gh_iter, n->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BMIter bm_iter; + BMVert *v; + void *node_val = SET_INT_IN_POINTER(node_index); + + /* Update ownership of faces */ + BLI_ghash_insert(bvh->bm_face_to_node, f, node_val); + + /* Update vertices */ + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + if (!BLI_ghash_haskey(n->bm_unique_verts, v)) { + if (BLI_ghash_haskey(bvh->bm_vert_to_node, v)) { + if (!BLI_ghash_haskey(n->bm_other_verts, v)) + BLI_ghash_insert(n->bm_other_verts, v, NULL); + } + else { + BLI_ghash_insert(n->bm_unique_verts, v, NULL); + BLI_ghash_insert(bvh->bm_vert_to_node, v, node_val); + } + } + /* Update node bounding box */ + BB_expand(&n->vb, v->co); + } + } + + BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && + n->vb.bmin[1] <= n->vb.bmax[1] && + n->vb.bmin[2] <= n->vb.bmax[2]); + + n->orig_vb = n->vb; + + /* Build GPU buffers */ + if (!G.background) { + int smooth = bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING; + n->draw_buffers = GPU_build_bmesh_buffers(smooth); + n->flag |= PBVH_UpdateDrawBuffers; + } +} + +/* Recursively split the node if it exceeds the leaf_limit */ +static void pbvh_bmesh_node_split(PBVH *bvh, GHash *prim_bbc, int node_index) +{ + GHash *empty, *other; + GHashIterator gh_iter; + PBVHNode *n, *c1, *c2; + BB cb; + float mid; + int axis, children; + + n = &bvh->nodes[node_index]; + + if (BLI_ghash_size(n->bm_faces) <= bvh->leaf_limit) { + /* Node limit not exceeded */ + pbvh_bmesh_node_finalize(bvh, node_index); + return; + } + + /* Calculate bounding box around primitive centroids */ + BB_reset(&cb); + GHASH_ITER (gh_iter, n->bm_faces) { + const BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + const BBC *bbc = BLI_ghash_lookup(prim_bbc, f); + + BB_expand(&cb, bbc->bcentroid); + } + + /* Find widest axis and its midpoint */ + axis = BB_widest_axis(&cb); + mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f; + + /* Add two new child nodes */ + children = bvh->totnode; + n->children_offset = children; + pbvh_grow_nodes(bvh, bvh->totnode + 2); + + /* Array reallocated, update current node pointer */ + n = &bvh->nodes[node_index]; + + /* Initialize children */ + c1 = &bvh->nodes[children]; + c2 = &bvh->nodes[children + 1]; + c1->flag |= PBVH_Leaf; + c2->flag |= PBVH_Leaf; + c1->bm_faces = BLI_ghash_ptr_new("bm_faces"); + c2->bm_faces = BLI_ghash_ptr_new("bm_faces"); + + /* Partition the parent node's faces between the two children */ + GHASH_ITER (gh_iter, n->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + const BBC *bbc = BLI_ghash_lookup(prim_bbc, f); + + if (bbc->bcentroid[axis] < mid) + BLI_ghash_insert(c1->bm_faces, f, NULL); + else + BLI_ghash_insert(c2->bm_faces, f, NULL); + } + + /* Enforce at least one primitive in each node */ + empty = NULL; + if (BLI_ghash_size(c1->bm_faces) == 0) { + empty = c1->bm_faces; + other = c2->bm_faces; + } + else if (BLI_ghash_size(c2->bm_faces) == 0) { + empty = c2->bm_faces; + other = c1->bm_faces; + } + if (empty) { + GHASH_ITER (gh_iter, other) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + BLI_ghash_insert(empty, key, NULL); + BLI_ghash_remove(other, key, NULL, NULL); + break; + } + } + + /* Clear this node */ + + /* Mark this node's unique verts as unclaimed */ + if (n->bm_unique_verts) { + GHASH_ITER (gh_iter, n->bm_unique_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + BLI_ghash_remove(bvh->bm_vert_to_node, v, NULL, NULL); + } + BLI_ghash_free(n->bm_unique_verts, NULL, NULL); + } + + /* Unclaim faces */ + GHASH_ITER (gh_iter, n->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BLI_ghash_remove(bvh->bm_face_to_node, f, NULL, NULL); + } + BLI_ghash_free(n->bm_faces, NULL, NULL); + + if (n->bm_other_verts) + BLI_ghash_free(n->bm_other_verts, NULL, NULL); + + if (n->layer_disp) + MEM_freeN(n->layer_disp); + + n->bm_faces = NULL; + n->bm_unique_verts = NULL; + n->bm_other_verts = NULL; + n->layer_disp = NULL; + + if (n->draw_buffers) { + GPU_free_buffers(n->draw_buffers); + n->draw_buffers = NULL; + } + n->flag &= ~PBVH_Leaf; + + /* Recurse */ + c1 = c2 = NULL; + pbvh_bmesh_node_split(bvh, prim_bbc, children); + pbvh_bmesh_node_split(bvh, prim_bbc, children + 1); + + /* Array maybe reallocated, update current node pointer */ + n = &bvh->nodes[node_index]; + + /* Update bounding box */ + BB_reset(&n->vb); + BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset].vb); + BB_expand_with_bb(&n->vb, &bvh->nodes[n->children_offset + 1].vb); + n->orig_vb = n->vb; +} + +/* Recursively split the node if it exceeds the leaf_limit */ +static int pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) +{ + GHash *prim_bbc; + GHashIterator gh_iter; + + if (BLI_ghash_size(bvh->nodes[node_index].bm_faces) <= bvh->leaf_limit) { + /* Node limit not exceeded */ + return FALSE; + } + + /* For each BMFace, store the AABB and AABB centroid */ + prim_bbc = BLI_ghash_ptr_new("prim_bbc"); + + GHASH_ITER (gh_iter, bvh->nodes[node_index].bm_faces) { + BMIter bm_iter; + BMVert *v; + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BBC *bbc = MEM_callocN(sizeof(BBC), "BBC"); + + BB_reset((BB *)bbc); + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + BB_expand((BB *)bbc, v->co); + } + BBC_update_centroid(bbc); + + BLI_ghash_insert(prim_bbc, f, bbc); + } + + pbvh_bmesh_node_split(bvh, prim_bbc, node_index); + + BLI_ghash_free(prim_bbc, NULL, (void *)MEM_freeN); + + return TRUE; +} + +/**********************************************************************/ + +static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, GHash *map, void *key) +{ + int node_index; + + BLI_assert(BLI_ghash_haskey(map, key)); + + node_index = GET_INT_FROM_POINTER(BLI_ghash_lookup(map, key)); + BLI_assert(node_index < bvh->totnode); + + return &bvh->nodes[node_index]; +} + +static BMVert *pbvh_bmesh_vert_create(PBVH *bvh, int node_index, + const float co[3], + const BMVert *example) +{ + BMVert *v = BM_vert_create(bvh->bm, co, example, 0); + void *val = SET_INT_IN_POINTER(node_index); + + BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode); + + BLI_ghash_insert(bvh->nodes[node_index].bm_unique_verts, v, NULL); + BLI_ghash_insert(bvh->bm_vert_to_node, v, val); + + /* Log the new vertex */ + BM_log_vert_added(bvh->bm, bvh->bm_log, v); + + return v; +} + +static BMFace *pbvh_bmesh_face_create(PBVH *bvh, int node_index, BMVert *v1, + BMVert *v2, BMVert *v3, + const BMFace *UNUSED(example)) +{ + BMFace *f; + void *val = SET_INT_IN_POINTER(node_index); + + /* Note: passing NULL for the 'example' parameter, profiling shows + * a small performance bump */ + f = BM_face_create_quad_tri(bvh->bm, v1, v2, v3, NULL, NULL, TRUE); + if (!BLI_ghash_haskey(bvh->bm_face_to_node, f)) { + + BLI_ghash_insert(bvh->nodes[node_index].bm_faces, f, NULL); + BLI_ghash_insert(bvh->bm_face_to_node, f, val); + + /* Log the new face */ + BM_log_face_added(bvh->bm_log, f); + } + + return f; +} + +/* Return the number of faces in 'node' that use vertex 'v' */ +static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v) +{ + BMIter bm_iter; + BMFace *f; + int count = 0; + + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + PBVHNode *f_node; + + f_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); + + if (f_node == node) + count++; + } + + return count; +} + +/* Return a node that uses vertex 'v' other than its current owner */ +static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v) +{ + BMIter bm_iter; + BMFace *f; + PBVHNode *current_node; + + current_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v); + + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + PBVHNode *f_node; + + f_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); + + if (f_node != current_node) + return f_node; + } + + return NULL; +} + +static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner, + BMVert *v) +{ + PBVHNode *current_owner; + + current_owner = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v); + BLI_assert(current_owner != new_owner); + + /* Remove current ownership */ + BLI_ghash_remove(bvh->bm_vert_to_node, v, NULL, NULL); + BLI_ghash_remove(current_owner->bm_unique_verts, v, NULL, NULL); + + /* Set new ownership */ + BLI_ghash_insert(bvh->bm_vert_to_node, v, + SET_INT_IN_POINTER(new_owner - bvh->nodes)); + BLI_ghash_insert(new_owner->bm_unique_verts, v, NULL); + BLI_ghash_remove(new_owner->bm_other_verts, v, NULL, NULL); + BLI_assert(!BLI_ghash_haskey(new_owner->bm_other_verts, v)); +} + +static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v) +{ + PBVHNode *v_node; + BMIter bm_iter; + BMFace *f; + + BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v)); + v_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v); + BLI_ghash_remove(v_node->bm_unique_verts, v, NULL, NULL); + BLI_ghash_remove(bvh->bm_vert_to_node, v, NULL, NULL); + + /* Have to check each neighboring face's node */ + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); + + BLI_ghash_remove(f_node->bm_unique_verts, v, NULL, NULL); + BLI_ghash_remove(f_node->bm_other_verts, v, NULL, NULL); + + BLI_assert(!BLI_ghash_haskey(f_node->bm_unique_verts, v)); + BLI_assert(!BLI_ghash_haskey(f_node->bm_other_verts, v)); + } +} + +static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) +{ + PBVHNode *f_node; + BMIter bm_iter; + BMVert *v; + + f_node = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); + + /* Check if any of this face's vertices need to be removed + * from the node */ + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + if (pbvh_bmesh_node_vert_use_count(bvh, f_node, v) == 1) { + if (BLI_ghash_lookup(f_node->bm_unique_verts, v)) { + /* Find a different node that uses 'v' */ + PBVHNode *new_node; + + new_node = pbvh_bmesh_vert_other_node_find(bvh, v); + BLI_assert(new_node || BM_vert_face_count(v) == 1); + + if (new_node) { + pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v); + } + } + else { + /* Remove from other verts */ + BLI_ghash_remove(f_node->bm_other_verts, v, NULL, NULL); + } + } + } + + /* Remove face from node and top level */ + BLI_ghash_remove(f_node->bm_faces, f, NULL, NULL); + BLI_ghash_remove(bvh->bm_face_to_node, f, NULL, NULL); + + /* Log removed face */ + BM_log_face_removed(bvh->bm_log, f); +} + +static BMVert *bm_triangle_other_vert_find(BMFace *triangle, const BMVert *v1, + const BMVert *v2) +{ + BLI_assert(triangle->len == 3); + BLI_assert(v1 != v2); + + if (triangle->len == 3) { + BMIter iter; + BMVert *v, *other = NULL; + int found_v1 = FALSE, found_v2 = FALSE; + + BM_ITER_ELEM (v, &iter, triangle, BM_VERTS_OF_FACE) { + if (v == v1) + found_v1 = TRUE; + else if (v == v2) + found_v2 = TRUE; + else + other = v; + } + + if (found_v1 && found_v2) + return other; + } + + BLI_assert(0); + return NULL; +} + +static void pbvh_bmesh_edge_faces(BLI_Buffer *buf, BMEdge *e) +{ + BLI_buffer_resize(buf, BM_edge_face_count(e)); + BM_iter_as_array(NULL, BM_FACES_OF_EDGE, e, buf->data, buf->count); +} + +/* TODO: maybe a better way to do this, if not then this should go to + * bmesh_queries */ +static int bm_face_edge_backwards(BMFace *f, BMEdge *e) +{ + BMIter bm_iter; + BMLoop *l, *l1 = NULL, *l2 = NULL; + + BM_ITER_ELEM (l, &bm_iter, f, BM_LOOPS_OF_FACE) { + if (l->v == e->v1) + l1 = l; + else if (l->v == e->v2) + l2 = l; + } + + BLI_assert(l1 && l2); + BLI_assert(l1->next == l2 || l2->next == l1); + return l2->next == l1; +} + +static void pbvh_bmesh_node_drop_orig(PBVHNode *node) +{ + if (node->bm_orco) + MEM_freeN(node->bm_orco); + if (node->bm_ortri) + MEM_freeN(node->bm_ortri); + node->bm_orco = NULL; + node->bm_ortri = NULL; + node->bm_tot_ortri = 0; +} + +/****************************** EdgeQueue *****************************/ + +typedef struct { + Heap *heap; + const float *center; + float radius_squared; + float limit_len_squared; +} EdgeQueue; + +static int edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f) +{ + BMVert *v[3]; + float c[3]; + + /* Get closest point in triangle to sphere center */ + BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); + closest_on_tri_to_point_v3(c, q->center, v[0]->co, v[1]->co, v[2]->co); + + /* Check if triangle intersects the sphere */ + return ((len_squared_v3v3(q->center, c) <= q->radius_squared)); +} + +static void edge_queue_insert(EdgeQueue *q, BLI_mempool *pool, BMEdge *e, + float priority) +{ + BMVert **pair; + + pair = BLI_mempool_alloc(pool); + pair[0] = e->v1; + pair[1] = e->v2; + BLI_heap_insert(q->heap, priority, pair); +} + +static void long_edge_queue_edge_add(EdgeQueue *q, BLI_mempool *pool, + BMEdge *e) +{ + const float len_sq = BM_edge_calc_length_squared(e); + if (len_sq > q->limit_len_squared) + edge_queue_insert(q, pool, e, 1.0f / len_sq); +} + +static void short_edge_queue_edge_add(EdgeQueue *q, BLI_mempool *pool, + BMEdge *e) +{ + const float len_sq = BM_edge_calc_length_squared(e); + if (len_sq < q->limit_len_squared) + edge_queue_insert(q, pool, e, len_sq); +} + +static int long_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, + BMFace *f) +{ + BMIter bm_iter; + BMEdge *e; + + if (edge_queue_tri_in_sphere(q, f)) { + /* Check each edge of the face */ + BM_ITER_ELEM (e, &bm_iter, f, BM_EDGES_OF_FACE) { + long_edge_queue_edge_add(q, pool, e); + } + } + + return TRUE; +} + +static int short_edge_queue_face_add(EdgeQueue *q, BLI_mempool *pool, + BMFace *f) +{ + BMIter bm_iter; + BMEdge *e; + + if (edge_queue_tri_in_sphere(q, f)) { + /* Check each edge of the face */ + BM_ITER_ELEM (e, &bm_iter, f, BM_EDGES_OF_FACE) { + short_edge_queue_edge_add(q, pool, e); + } + } + + return TRUE; +} + +/* Create a priority queue containing vertex pairs connected by a long + * edge as defined by PBVH.bm_max_edge_len. + * + * Only nodes marked for topology update are checked, and in those + * nodes only edges used by a face intersecting the (center, radius) + * sphere are checked. + * + * The highest priority (lowest number) is given to the longest edge. + */ +static void long_edge_queue_create(EdgeQueue *q, BLI_mempool *pool, + PBVH *bvh, const float center[3], + float radius) +{ + int n; + + q->heap = BLI_heap_new(); + q->center = center; + q->radius_squared = radius * radius; + q->limit_len_squared = bvh->bm_max_edge_len * bvh->bm_max_edge_len; + + for (n = 0; n < bvh->totnode; n++) { + PBVHNode *node = &bvh->nodes[n]; + + /* Check leaf nodes marked for topology update */ + if ((node->flag & PBVH_Leaf) && + (node->flag & PBVH_UpdateTopology)) + { + GHashIterator gh_iter; + + /* Check each face */ + GHASH_ITER (gh_iter, node->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + long_edge_queue_face_add(q, pool, f); + } + } + } +} + +/* Create a priority queue containing vertex pairs connected by a + * short edge as defined by PBVH.bm_min_edge_len. + * + * Only nodes marked for topology update are checked, and in those + * nodes only edges used by a face intersecting the (center, radius) + * sphere are checked. + * + * The highest priority (lowest number) is given to the shortest edge. + */ +static void short_edge_queue_create(EdgeQueue *q, BLI_mempool *pool, + PBVH *bvh, const float center[3], + float radius) +{ + int n; + + q->heap = BLI_heap_new(); + q->center = center; + q->radius_squared = radius * radius; + q->limit_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; + + for (n = 0; n < bvh->totnode; n++) { + PBVHNode *node = &bvh->nodes[n]; + + /* Check leaf nodes marked for topology update */ + if ((node->flag & PBVH_Leaf) && + (node->flag & PBVH_UpdateTopology)) + { + GHashIterator gh_iter; + + /* Check each face */ + GHASH_ITER (gh_iter, node->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + short_edge_queue_face_add(q, pool, f); + } + } + } +} + +/*************************** Topology update **************************/ + +static void pbvh_bmesh_split_edge(PBVH *bvh, EdgeQueue *q, BLI_mempool *pool, + BMEdge *e, BLI_Buffer *edge_faces) +{ + BMVert *v_new; + float mid[3]; + int i, node_index; + + /* Get all faces adjacent to the edge */ + pbvh_bmesh_edge_faces(edge_faces, e); + + /* Create a new vertex in current node at the edge's midpoint */ + mid_v3_v3v3(mid, e->v1->co, e->v2->co); + + node_index = GET_INT_FROM_POINTER(BLI_ghash_lookup(bvh->bm_vert_to_node, + e->v1)); + v_new = pbvh_bmesh_vert_create(bvh, node_index, mid, e->v1); + + /* For each face, add two new triangles and delete the original */ + for (i = 0; i < edge_faces->count; i++) { + BMFace *f_adj = BLI_buffer_at(edge_faces, BMFace *, i); + BMFace *f_new; + BMVert *opp, *v1, *v2; + void *nip; + int ni; + + BLI_assert(f_adj->len == 3); + nip = BLI_ghash_lookup(bvh->bm_face_to_node, f_adj); + ni = GET_INT_FROM_POINTER(nip); + + /* Ensure node gets redrawn */ + bvh->nodes[ni].flag |= PBVH_UpdateDrawBuffers; + + /* Find the vertex not in the edge */ + opp = bm_triangle_other_vert_find(f_adj, e->v1, e->v2); + + /* Get e->v1 and e->v2 in the order they appear in the + * existing face so that the new faces' winding orders + * match */ + v1 = e->v1; + v2 = e->v2; + if (bm_face_edge_backwards(f_adj, e)) + SWAP(BMVert *, v1, v2); + + if (ni != node_index && i == 0) + pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new); + + /* Create two new faces */ + f_new = pbvh_bmesh_face_create(bvh, ni, v1, v_new, opp, f_adj); + long_edge_queue_face_add(q, pool, f_new); + f_new = pbvh_bmesh_face_create(bvh, ni, v_new, v2, opp, f_adj); + long_edge_queue_face_add(q, pool, f_new); + + /* Delete original */ + pbvh_bmesh_face_remove(bvh, f_adj); + BM_face_kill(bvh->bm, f_adj); + + /* Ensure new vertex is in the node */ + if (!BLI_ghash_haskey(bvh->nodes[ni].bm_unique_verts, v_new) && + !BLI_ghash_haskey(bvh->nodes[ni].bm_other_verts, v_new)) + { + BLI_ghash_insert(bvh->nodes[ni].bm_other_verts, v_new, NULL); + } + + if (BM_vert_edge_count(opp) >= 9) { + BMIter bm_iter; + BMEdge *e2; + + BM_ITER_ELEM (e2, &bm_iter, opp, BM_EDGES_OF_VERT) { + long_edge_queue_edge_add(q, pool, e2); + } + } + } + + BM_edge_kill(bvh->bm, e); +} + +static int pbvh_bmesh_subdivide_long_edges(PBVH *bvh, EdgeQueue *q, + BLI_mempool *pool, + BLI_Buffer *edge_faces) +{ + int any_subdivided = FALSE; + + while (!BLI_heap_is_empty(q->heap)) { + BMVert **pair = BLI_heap_popmin(q->heap); + BMEdge *e; + + /* Check that the edge still exists */ + if (!(e = BM_edge_exists(pair[0], pair[1]))) { + BLI_mempool_free(pool, pair); + continue; + } + + BLI_mempool_free(pool, pair); + pair = NULL; + + /* Check that the edge's vertices are still in the PBVH. It's + * possible that an edge collapse has deleted adjacent faces + * and the node has been split, thus leaving wire edges and + * associated vertices. */ + if (!BLI_ghash_haskey(bvh->bm_vert_to_node, e->v1) || + !BLI_ghash_haskey(bvh->bm_vert_to_node, e->v2)) + { + continue; + } + + if (BM_edge_calc_length_squared(e) <= q->limit_len_squared) + continue; + + any_subdivided = TRUE; + + pbvh_bmesh_split_edge(bvh, q, pool, e, edge_faces); + } + + return any_subdivided; +} + +static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e, BMVert *v1, + BMVert *v2, GHash *deleted_verts, + BLI_Buffer *edge_faces, + BLI_Buffer *deleted_faces) +{ + BMIter bm_iter; + BMFace *f; + int i; + + /* Get all faces adjacent to the edge */ + pbvh_bmesh_edge_faces(edge_faces, e); + + /* Remove the merge vertex from the PBVH */ + pbvh_bmesh_vert_remove(bvh, v2); + + /* Remove all faces adjacent to the edge */ + for (i = 0; i < edge_faces->count; i++) { + BMFace *f_adj = BLI_buffer_at(edge_faces, BMFace *, i); + + pbvh_bmesh_face_remove(bvh, f_adj); + BM_face_kill(bvh->bm, f_adj); + } + + /* Kill the edge */ + BLI_assert(BM_edge_face_count(e) == 0); + BM_edge_kill(bvh->bm, e); + + /* For all remaining faces of v2, create a new face that is the + same except it uses v1 instead of v2 */ + /* Note: this could be done with BM_vert_splice(), but that + * requires handling other issues like duplicate edges, so doesn't + * really buy anything. */ + deleted_faces->count = 0; + BM_ITER_ELEM (f, &bm_iter, v2, BM_FACES_OF_VERT) { + BMVert *v[3]; + BMFace *existing_face; + PBVHNode *n; + int ni; + + /* Get vertices, replace use of v2 with v1 */ + BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); + for (i = 0; i < 3; i++) { + if (v[i] == v2) + v[i] = v1; + } + + /* Check if a face using these vertices already exists. If so, + * skip adding this face and mark the existing one for + * deletion as well. Prevents extraneous "flaps" from being + * created. */ + if (BM_face_exists(v, 3, &existing_face)) { + BLI_assert(existing_face); + BLI_buffer_append(deleted_faces, BMFace *, existing_face); + } + else { + n = pbvh_bmesh_node_lookup(bvh, bvh->bm_face_to_node, f); + ni = n - bvh->nodes; + pbvh_bmesh_face_create(bvh, ni, v[0], v[1], v[2], f); + + /* Ensure that v1 is in the new face's node */ + if (!BLI_ghash_haskey(n->bm_unique_verts, v1) && + !BLI_ghash_haskey(n->bm_other_verts, v1)) { + BLI_ghash_insert(n->bm_other_verts, v1, NULL); + } + } + + BLI_buffer_append(deleted_faces, BMFace *, f); + } + + /* Delete the tagged faces */ + for (i = 0; i < deleted_faces->count; i++) { + BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i); + BMVert *v[3]; + int j; + + BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f_del, (void **)v, 3); + + /* Check if any of the face's vertices are now unused, if so + remove them from the PBVH */ + for (j = 0; j < 3; j++) { + if (v[j] != v2 && BM_vert_face_count(v[j]) == 0) { + BLI_ghash_insert(deleted_verts, v[j], NULL); + pbvh_bmesh_vert_remove(bvh, v[j]); + } + else { + v[j] = NULL; + } + } + + /* Remove the face */ + pbvh_bmesh_face_remove(bvh, f_del); + BM_face_kill(bvh->bm, f_del); + + /* Delete unused vertices */ + for (j = 0; j < 3; j++) { + if (v[j]) { + BM_log_vert_removed(bvh->bm, bvh->bm_log, v[j]); + BM_vert_kill(bvh->bm, v[j]); + } + } + } + + /* Move v1 to the midpoint of v1 and v2 */ + BM_log_vert_before_modified(bvh->bm, bvh->bm_log, v1); + mid_v3_v3v3(v1->co, v1->co, v2->co); + + /* Delete v2 */ + BLI_assert(BM_vert_face_count(v2) == 0); + BLI_ghash_insert(deleted_verts, v2, NULL); + BM_log_vert_removed(bvh->bm, bvh->bm_log, v2); + BM_vert_kill(bvh->bm, v2); +} + +static int pbvh_bmesh_collapse_short_edges(PBVH *bvh, EdgeQueue *q, + BLI_mempool *pool, + BLI_Buffer *edge_faces, + BLI_Buffer *deleted_faces) +{ + float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; + GHash *deleted_verts; + int any_collapsed = FALSE; + + deleted_verts = BLI_ghash_ptr_new("deleted_verts"); + + while (!BLI_heap_is_empty(q->heap)) { + BMVert **pair = BLI_heap_popmin(q->heap); + BMEdge *e; + BMVert *v1, *v2; + + v1 = pair[0]; + v2 = pair[1]; + BLI_mempool_free(pool, pair); + pair = NULL; + + /* Check that the vertices/edge still exist */ + if (BLI_ghash_haskey(deleted_verts, v1) || + BLI_ghash_haskey(deleted_verts, v2) || + !(e = BM_edge_exists(v1, v2))) + { + continue; + } + + /* Check that the edge's vertices are still in the PBVH. It's + * possible that an edge collapse has deleted adjacent faces + * and the node has been split, thus leaving wire edges and + * associated vertices. */ + if (!BLI_ghash_haskey(bvh->bm_vert_to_node, e->v1) || + !BLI_ghash_haskey(bvh->bm_vert_to_node, e->v2)) + { + continue; + } + + if (BM_edge_calc_length_squared(e) >= min_len_squared) + continue; + + any_collapsed = TRUE; + + pbvh_bmesh_collapse_edge(bvh, e, v1, v2, + deleted_verts, edge_faces, + deleted_faces); + } + + BLI_ghash_free(deleted_verts, NULL, NULL); + + return any_collapsed; +} + +/************************* Called from pbvh.c *************************/ + +int pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3], + const float ray_normal[3], float *dist, + int use_original) +{ + GHashIterator gh_iter; + int hit = 0; + + if (use_original && node->bm_tot_ortri) { + int i; + for (i = 0; i < node->bm_tot_ortri; i++) { + const int *t = node->bm_ortri[i]; + hit |= ray_face_intersection(ray_start, ray_normal, + node->bm_orco[t[0]], + node->bm_orco[t[1]], + node->bm_orco[t[2]], + NULL, dist); + } + } + else { + GHASH_ITER (gh_iter, node->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + + BLI_assert(f->len == 3); + if (f->len == 3) { + BMVert *v[3]; + + BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); + hit |= ray_face_intersection(ray_start, ray_normal, + v[0]->co, + v[1]->co, + v[2]->co, + NULL, dist); + } + } + } + + return hit; +} + +void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode) +{ + int n; + + for (n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, node->bm_faces) { + BM_face_normal_update(BLI_ghashIterator_getKey(&gh_iter)); + } + GHASH_ITER (gh_iter, node->bm_unique_verts) { + BM_vert_normal_update(BLI_ghashIterator_getKey(&gh_iter)); + } + } +} + +/***************************** Public API *****************************/ + +/* Build a PBVH from a BMesh */ +void BKE_pbvh_build_bmesh(PBVH *bvh, BMesh *bm, int smooth_shading, + BMLog *log) +{ + BMIter iter; + BMFace *f; + PBVHNode *n; + int node_index = 0; + + bvh->bm = bm; + + BKE_pbvh_bmesh_detail_size_set(bvh, 0.75); + + bvh->type = PBVH_BMESH; + bvh->bm_face_to_node = BLI_ghash_ptr_new("bm_face_to_node"); + bvh->bm_vert_to_node = BLI_ghash_ptr_new("bm_vert_to_node"); + bvh->bm_log = log; + + /* TODO: choose leaf limit better */ + bvh->leaf_limit = 100; + + if (smooth_shading) + bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING; + + /* Start with all faces in the root node */ + n = bvh->nodes = MEM_callocN(sizeof(PBVHNode), "PBVHNode"); + bvh->totnode = 1; + n->flag = PBVH_Leaf; + n->bm_faces = BLI_ghash_ptr_new("bm_faces"); + BM_ITER_MESH (f, &iter, bvh->bm, BM_FACES_OF_MESH) { + BLI_ghash_insert(n->bm_faces, f, NULL); + } + + /* Recursively split the node until it is under the limit; if no + * splitting occurs then finalize the existing leaf node */ + if (!pbvh_bmesh_node_limit_ensure(bvh, node_index)) + pbvh_bmesh_node_finalize(bvh, 0); +} + +/* Collapse short edges, subdivide long edges */ +int BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode, + const float center[3], float radius) +{ + BLI_buffer_declare_static(BMFace *, edge_faces, BLI_BUFFER_NOP, 8); + BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32); + + int modified = FALSE; + int n; + + if (mode & PBVH_Collapse) { + EdgeQueue q; + BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert) * 2, + 128, 128, 0); + short_edge_queue_create(&q, queue_pool, bvh, center, radius); + pbvh_bmesh_collapse_short_edges(bvh, &q, queue_pool, &edge_faces, + &deleted_faces); + BLI_heap_free(q.heap, NULL); + BLI_mempool_destroy(queue_pool); + } + + if (mode & PBVH_Subdivide) { + EdgeQueue q; + BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert) * 2, + 128, 128, 0); + long_edge_queue_create(&q, queue_pool, bvh, center, radius); + pbvh_bmesh_subdivide_long_edges(bvh, &q, queue_pool, &edge_faces); + BLI_heap_free(q.heap, NULL); + BLI_mempool_destroy(queue_pool); + } + + /* Unmark nodes */ + for (n = 0; n < bvh->totnode; n++) { + PBVHNode *node = &bvh->nodes[n]; + + if (node->flag & PBVH_Leaf && + node->flag & PBVH_UpdateTopology) + { + node->flag &= ~PBVH_UpdateTopology; + } + } + BLI_buffer_free(&edge_faces); + BLI_buffer_free(&deleted_faces); + + return modified; +} + +/* In order to perform operations on the original node coordinates + * (such as raycast), store the node's triangles and vertices.*/ +void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node) +{ + GHashIterator gh_iter; + int i, totvert, tottri; + + /* Skip if original coords/triangles are already saved */ + if (node->bm_orco) + return; + + totvert = (BLI_ghash_size(node->bm_unique_verts) + + BLI_ghash_size(node->bm_other_verts)); + + tottri = BLI_ghash_size(node->bm_faces); + + node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, AT); + node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, AT); + + /* Copy out the vertices and assign a temporary index */ + i = 0; + GHASH_ITER (gh_iter, node->bm_unique_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + copy_v3_v3(node->bm_orco[i], v->co); + BM_elem_index_set(v, i); /* set_dirty! */ + i++; + } + GHASH_ITER (gh_iter, node->bm_other_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + copy_v3_v3(node->bm_orco[i], v->co); + BM_elem_index_set(v, i); /* set_dirty! */ + i++; + } + + /* Copy the triangles */ + i = 0; + GHASH_ITER (gh_iter, node->bm_faces) { + BMIter bm_iter; + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + BMVert *v; + int j = 0; + + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + node->bm_ortri[i][j] = BM_elem_index_get(v); + j++; + } + i++; + } + node->bm_tot_ortri = i; +} + +void BKE_pbvh_bmesh_after_stroke(PBVH *bvh) +{ + int i; + for (i = 0; i < bvh->totnode; i++) { + PBVHNode *n = &bvh->nodes[i]; + if (n->flag & PBVH_Leaf) { + /* Free orco/ortri data */ + pbvh_bmesh_node_drop_orig(n); + + /* Recursively split nodes that have gotten too many + * elements */ + pbvh_bmesh_node_limit_ensure(bvh, i); + } + } +} + +void BKE_pbvh_bmesh_detail_size_set(PBVH *bvh, float detail_size) +{ + bvh->bm_max_edge_len = detail_size; + bvh->bm_min_edge_len = bvh->bm_max_edge_len * 0.4f; +} + +void BKE_pbvh_node_mark_topology_update(PBVHNode *node) +{ + node->flag |= PBVH_UpdateTopology; +} + +GHash *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node) +{ + return node->bm_unique_verts; +} + +GHash *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node) +{ + return node->bm_other_verts; +} + +/****************************** Debugging *****************************/ + +#if 0 +void bli_ghash_duplicate_key_check(GHash *gh) +{ + GHashIterator gh_iter1, gh_iter2; + + GHASH_ITER (gh_iter1, gh) { + void *key1 = BLI_ghashIterator_getKey(&gh_iter1); + int dup = -1; + + GHASH_ITER (gh_iter2, gh) { + void *key2 = BLI_ghashIterator_getKey(&gh_iter2); + + if (key1 == key2) { + dup++; + if (dup > 0) { + BLI_assert(!"duplicate in hash"); + } + } + } + } +} + +void bmesh_print(BMesh *bm) +{ + BMIter iter, siter; + BMVert *v; + BMEdge *e; + BMFace *f; + BMLoop *l; + + fprintf(stderr, "\nbm=%p, totvert=%d, totedge=%d, " + "totloop=%d, totface=%d\n", + bm, bm->totvert, bm->totedge, + bm->totloop, bm->totface); + + fprintf(stderr, "vertices:\n"); + BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { + fprintf(stderr, " %d co=(%.3f %.3f %.3f) oflag=%x\n", + BM_elem_index_get(v), v->co[0], v->co[1], v->co[2], + v->oflags[bm->stackdepth - 1].f); + } + + fprintf(stderr, "edges:\n"); + BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) { + fprintf(stderr, " %d v1=%d, v2=%d, oflag=%x\n", + BM_elem_index_get(e), + BM_elem_index_get(e->v1), + BM_elem_index_get(e->v2), + e->oflags[bm->stackdepth - 1].f); + } + + fprintf(stderr, "faces:\n"); + BM_ITER_MESH(f, &iter, bm, BM_FACES_OF_MESH) { + fprintf(stderr, " %d len=%d, oflag=%x\n", + BM_elem_index_get(f), f->len, + f->oflags[bm->stackdepth - 1].f); + + fprintf(stderr, " v: "); + BM_ITER_ELEM(v, &siter, f, BM_VERTS_OF_FACE) { + fprintf(stderr, "%d ", BM_elem_index_get(v)); + } + fprintf(stderr, "\n"); + + fprintf(stderr, " e: "); + BM_ITER_ELEM(e, &siter, f, BM_EDGES_OF_FACE) { + fprintf(stderr, "%d ", BM_elem_index_get(e)); + } + fprintf(stderr, "\n"); + + fprintf(stderr, " l: "); + BM_ITER_ELEM(l, &siter, f, BM_LOOPS_OF_FACE) { + fprintf(stderr, "%d(v=%d, e=%d) ", + BM_elem_index_get(l), + BM_elem_index_get(l->v), + BM_elem_index_get(l->e)); + } + fprintf(stderr, "\n"); + } +} + +void pbvh_bmesh_print(PBVH *bvh) +{ + GHashIterator gh_iter; + int n; + + fprintf(stderr, "\npbvh=%p\n", bvh); + fprintf(stderr, "bm_face_to_node:\n"); + GHASH_ITER (gh_iter, bvh->bm_face_to_node) { + fprintf(stderr, " %d -> %d\n", + BM_elem_index_get((BMFace*)BLI_ghashIterator_getKey(&gh_iter)), + GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter))); + } + + fprintf(stderr, "bm_vert_to_node:\n"); + GHASH_ITER (gh_iter, bvh->bm_vert_to_node) { + fprintf(stderr, " %d -> %d\n", + BM_elem_index_get((BMVert*)BLI_ghashIterator_getKey(&gh_iter)), + GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter))); + } + + for (n = 0; n < bvh->totnode; n++) { + PBVHNode *node = &bvh->nodes[n]; + if (!(node->flag & PBVH_Leaf)) + continue; + + fprintf(stderr, "node %d\n faces:\n", n); + GHASH_ITER (gh_iter, node->bm_faces) + fprintf(stderr, " %d\n", + BM_elem_index_get((BMFace*)BLI_ghashIterator_getKey(&gh_iter))); + fprintf(stderr, " unique verts:\n"); + GHASH_ITER (gh_iter, node->bm_unique_verts) + fprintf(stderr, " %d\n", + BM_elem_index_get((BMVert*)BLI_ghashIterator_getKey(&gh_iter))); + fprintf(stderr, " other verts:\n"); + GHASH_ITER (gh_iter, node->bm_other_verts) + fprintf(stderr, " %d\n", + BM_elem_index_get((BMVert*)BLI_ghashIterator_getKey(&gh_iter))); + } +} + +void print_flag_factors(int flag) +{ + int i; + printf("flag=0x%x:\n", flag); + for (i = 0; i < 32; i++) { + if (flag & (1 << i)) { + printf(" %d (1 << %d)\n", 1 << i, i); + } + } +} + +void pbvh_bmesh_verify(PBVH *bvh) +{ + GHashIterator gh_iter; + int i; + + /* Check faces */ + BLI_assert(bvh->bm->totface == BLI_ghash_size(bvh->bm_face_to_node)); + GHASH_ITER (gh_iter, bvh->bm_face_to_node) { + BMIter bm_iter; + BMVert *v; + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + void *nip = BLI_ghashIterator_getValue(&gh_iter); + int ni = GET_INT_FROM_POINTER(nip); + PBVHNode *n = &bvh->nodes[ni]; + + /* Check that the face's node is a leaf */ + BLI_assert(n->flag & PBVH_Leaf); + + /* Check that the face's node knows it owns the face */ + BLI_assert(BLI_ghash_haskey(n->bm_faces, f)); + + /* Check the face's vertices... */ + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + PBVHNode *nv; + + /* Check that the vertex is in the node */ + BLI_assert(BLI_ghash_haskey(n->bm_unique_verts, v) ^ + BLI_ghash_haskey(n->bm_other_verts, v)); + + /* Check that the vertex has a node owner */ + nv = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v); + + /* Check that the vertex's node knows it owns the vert */ + BLI_assert(BLI_ghash_haskey(nv->bm_unique_verts, v)); + + /* Check that the vertex isn't duplicated as an 'other' vert */ + BLI_assert(!BLI_ghash_haskey(nv->bm_other_verts, v)); + } + } + + /* Check verts */ + BLI_assert(bvh->bm->totvert == BLI_ghash_size(bvh->bm_vert_to_node)); + GHASH_ITER (gh_iter, bvh->bm_vert_to_node) { + BMIter bm_iter; + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + BMFace *f; + void *nip = BLI_ghashIterator_getValue(&gh_iter); + int ni = GET_INT_FROM_POINTER(nip); + PBVHNode *n = &bvh->nodes[ni]; + int found; + + /* Check that the vert's node is a leaf */ + BLI_assert(n->flag & PBVH_Leaf); + + /* Check that the vert's node knows it owns the vert */ + BLI_assert(BLI_ghash_haskey(n->bm_unique_verts, v)); + + /* Check that the vertex isn't duplicated as an 'other' vert */ + BLI_assert(!BLI_ghash_haskey(n->bm_other_verts, v)); + + /* Check that the vert's node also contains one of the vert's + * adjacent faces */ + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + if (BLI_ghash_lookup(bvh->bm_face_to_node, f) == nip) { + found = TRUE; + break; + } + } + BLI_assert(found); + } + + /* Check that node elements are recorded in the top level */ + for (i = 0; i < bvh->totnode; i++) { + PBVHNode *n = &bvh->nodes[i]; + if (n->flag & PBVH_Leaf) { + /* Check for duplicate entries */ + /* Slow */ + #if 0 + bli_ghash_duplicate_key_check(n->bm_faces); + bli_ghash_duplicate_key_check(n->bm_unique_verts); + bli_ghash_duplicate_key_check(n->bm_other_verts); + #endif + + GHASH_ITER (gh_iter, n->bm_faces) { + BMFace *f = BLI_ghashIterator_getKey(&gh_iter); + void *nip = BLI_ghash_lookup(bvh->bm_face_to_node, f); + BLI_assert(BLI_ghash_haskey(bvh->bm_face_to_node, f)); + BLI_assert(GET_INT_FROM_POINTER(nip) == (n - bvh->nodes)); + } + + GHASH_ITER (gh_iter, n->bm_unique_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + void *nip = BLI_ghash_lookup(bvh->bm_vert_to_node, v); + BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v)); + BLI_assert(!BLI_ghash_haskey(n->bm_other_verts, v)); + BLI_assert(GET_INT_FROM_POINTER(nip) == (n - bvh->nodes)); + } + + GHASH_ITER (gh_iter, n->bm_other_verts) { + BMVert *v = BLI_ghashIterator_getKey(&gh_iter); + BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v)); + BLI_assert(BM_vert_face_count(v) > 0); + } + } + } +} + +#endif diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h new file mode 100644 index 00000000000..b3f7bf6e3d1 --- /dev/null +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -0,0 +1,186 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __PBVH_INTERN_H__ +#define __PBVH_INTERN_H__ + +/* Axis-aligned bounding box */ +typedef struct { + float bmin[3], bmax[3]; +} BB; + +/* Axis-aligned bounding box with centroid */ +typedef struct { + float bmin[3], bmax[3], bcentroid[3]; +} BBC; + +/* Note: this structure is getting large, might want to split it into + * union'd structs */ +struct PBVHNode { + /* Opaque handle for drawing code */ + struct GPU_Buffers *draw_buffers; + + /* Voxel bounds */ + BB vb; + BB orig_vb; + + /* For internal nodes, the offset of the children in the PBVH + * 'nodes' array. */ + int children_offset; + + /* Pointer into the PBVH prim_indices array and the number of + * primitives used by this leaf node. + * + * Used for leaf nodes in both mesh- and multires-based PBVHs. + */ + int *prim_indices; + unsigned int totprim; + + /* Array of indices into the mesh's MVert array. Contains the + * indices of all vertices used by faces that are within this + * node's bounding box. + * + * Note that a vertex might be used by a multiple faces, and + * these faces might be in different leaf nodes. Such a vertex + * will appear in the vert_indices array of each of those leaf + * nodes. + * + * In order to support cases where you want access to multiple + * nodes' vertices without duplication, the vert_indices array + * is ordered such that the first part of the array, up to + * index 'uniq_verts', contains "unique" vertex indices. These + * vertices might not be truly unique to this node, but if + * they appear in another node's vert_indices array, they will + * be above that node's 'uniq_verts' value. + * + * Used for leaf nodes in a mesh-based PBVH (not multires.) + */ + int *vert_indices; + unsigned int uniq_verts, face_verts; + + /* An array mapping face corners into the vert_indices + * array. The array is sized to match 'totprim', and each of + * the face's corners gets an index into the vert_indices + * array, in the same order as the corners in the original + * MFace. The fourth value should not be used if the original + * face is a triangle. + * + * Used for leaf nodes in a mesh-based PBVH (not multires.) + */ + int (*face_vert_indices)[4]; + + /* Indicates whether this node is a leaf or not; also used for + * marking various updates that need to be applied. */ + PBVHNodeFlags flag : 16; + + /* Used for raycasting: how close bb is to the ray point. */ + float tmin; + + /* Scalar displacements for sculpt mode's layer brush. */ + float *layer_disp; + + int proxy_count; + PBVHProxyNode *proxies; + + /* Dyntopo */ + GHash *bm_faces; + GHash *bm_unique_verts; + GHash *bm_other_verts; + float (*bm_orco)[3]; + int (*bm_ortri)[3]; + int bm_tot_ortri; +}; + +typedef enum { + PBVH_DYNTOPO_SMOOTH_SHADING = 1 +} PBVHFlags; + +typedef struct PBVHBMeshLog PBVHBMeshLog; + +struct PBVH { + PBVHType type; + PBVHFlags flags; + + PBVHNode *nodes; + int node_mem_count, totnode; + + int *prim_indices; + int totprim; + int totvert; + + int leaf_limit; + + /* Mesh data */ + MVert *verts; + MFace *faces; + CustomData *vdata; + + /* Grid Data */ + CCGKey gridkey; + CCGElem **grids; + DMGridAdjacency *gridadj; + void **gridfaces; + const DMFlagMat *grid_flag_mats; + int totgrid; + BLI_bitmap *grid_hidden; + + /* Only used during BVH build and update, + * don't need to remain valid after */ + BLI_bitmap vert_bitmap; + +#ifdef PERFCNTRS + int perf_modified; +#endif + + /* flag are verts/faces deformed */ + int deformed; + + int show_diffuse_color; + + /* Dynamic topology */ + BMesh *bm; + GHash *bm_face_to_node; + GHash *bm_vert_to_node; + float bm_max_edge_len; + float bm_min_edge_len; + + struct BMLog *bm_log; +}; + +/* pbvh.c */ +void BB_reset(BB *bb); +void BB_expand(BB *bb, const float co[3]); +void BB_expand_with_bb(BB *bb, BB *bb2); +void BBC_update_centroid(BBC *bbc); +int BB_widest_axis(const BB *bb); +void pbvh_grow_nodes(PBVH *bvh, int totnode); +int ray_face_intersection(const float ray_start[3], const float ray_normal[3], + const float *t0, const float *t1, const float *t2, + const float *t3, float *fdist); +void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag); + +/* pbvh_bmesh.c */ +int pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3], + const float ray_normal[3], float *dist, + int use_original); + +void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode); + +#endif diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 2eadfe73858..9c3c1b0e508 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1540,7 +1540,7 @@ void BKE_ptcache_mem_pointers_incr(PTCacheMem *pm) for (i=0; icur[i]) - pm->cur[i] = (char*)pm->cur[i] + ptcache_data_size[i]; + pm->cur[i] = (char *)pm->cur[i] + ptcache_data_size[i]; } } int BKE_ptcache_mem_pointers_seek(int point_index, PTCacheMem *pm) @@ -1558,7 +1558,7 @@ int BKE_ptcache_mem_pointers_seek(int point_index, PTCacheMem *pm) } for (i=0; icur[i] = data_types & (1<data[i] + index * ptcache_data_size[i] : NULL; + pm->cur[i] = data_types & (1<data[i] + index * ptcache_data_size[i] : NULL; return 1; } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 538f21ce20b..04e612d1a33 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -414,6 +414,7 @@ static Scene *scene_add(Main *bmain, const char *name) sce->r.im_format.planes = R_IMF_PLANES_RGB; sce->r.im_format.imtype = R_IMF_IMTYPE_PNG; + sce->r.im_format.depth = R_IMF_CHAN_DEPTH_8; sce->r.im_format.quality = 90; sce->r.im_format.compress = 90; diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 56fddfdaa2b..81bcdc4b06e 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -279,6 +279,7 @@ void BKE_area_region_free(SpaceType *st, ARegion *ar) } BLI_freelistN(&ar->panels); + BLI_freelistN(&ar->ui_lists); } /* not area itself */ diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 3bff209f53c..3ca04f235b8 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -156,42 +156,43 @@ static void init_alpha_over_or_under(Sequence *seq) seq->seq1 = seq2; } -static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, char *rect1, char *rect2, char *out) +static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int fac2, mfac, fac, fac4; - int xo, tempc; - char *rt1, *rt2, *rt; + float fac2, mfac, fac, fac4; + int xo; + unsigned char *cp1, *cp2, *rt; + float tempc[4], rt1[4], rt2[4]; xo = x; - rt1 = (char *) rect1; - rt2 = (char *) rect2; - rt = (char *) out; + cp1 = rect1; + cp2 = rect2; + rt = out; - fac2 = (int) (256.0f * facf0); - fac4 = (int) (256.0f * facf1); + fac2 = facf0; + fac4 = facf1; while (y--) { x = xo; while (x--) { - /* rt = rt1 over rt2 (alpha from rt1) */ - fac = fac2; - mfac = 256 - ( (fac2 * rt1[3]) >> 8); + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - if (fac == 0) *( (unsigned int *) rt) = *( (unsigned int *) rt2); - else if (mfac == 0) *( (unsigned int *) rt) = *( (unsigned int *) rt1); + fac = fac2; + mfac = 1.0f - fac2 * rt1[3]; + + if (fac <= 0.0f) *( (unsigned int *) rt) = *( (unsigned int *) cp2); + else if (mfac <= 0.0f) *( (unsigned int *) rt) = *( (unsigned int *) cp1); else { - tempc = (fac * rt1[0] + mfac * rt2[0]) >> 8; - if (tempc > 255) rt[0] = 255; else rt[0] = tempc; - tempc = (fac * rt1[1] + mfac * rt2[1]) >> 8; - if (tempc > 255) rt[1] = 255; else rt[1] = tempc; - tempc = (fac * rt1[2] + mfac * rt2[2]) >> 8; - if (tempc > 255) rt[2] = 255; else rt[2] = tempc; - tempc = (fac * rt1[3] + mfac * rt2[3]) >> 8; - if (tempc > 255) rt[3] = 255; else rt[3] = tempc; + tempc[0] = fac * rt1[0] + mfac * rt2[0]; + tempc[1] = fac * rt1[1] + mfac * rt2[1]; + tempc[2] = fac * rt1[2] + mfac * rt2[2]; + tempc[3] = fac * rt1[3] + mfac * rt2[3]; + + premul_float_to_straight_uchar(rt, tempc); } - rt1 += 4; rt2 += 4; rt += 4; + cp1 += 4; cp2 += 4; rt += 4; } if (y == 0) break; @@ -199,22 +200,23 @@ static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y, ch x = xo; while (x--) { - fac = fac4; - mfac = 256 - ( (fac4 * rt1[3]) >> 8); + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - if (fac == 0) *( (unsigned int *) rt) = *( (unsigned int *) rt2); - else if (mfac == 0) *( (unsigned int *) rt) = *( (unsigned int *) rt1); + fac = fac4; + mfac = 1.0f - (fac4 * rt1[3]); + + if (fac <= 0.0f) *( (unsigned int *) rt) = *( (unsigned int *) cp2); + else if (mfac <= 0.0f) *( (unsigned int *) rt) = *( (unsigned int *) cp1); else { - tempc = (fac * rt1[0] + mfac * rt2[0]) >> 8; - if (tempc > 255) rt[0] = 255; else rt[0] = tempc; - tempc = (fac * rt1[1] + mfac * rt2[1]) >> 8; - if (tempc > 255) rt[1] = 255; else rt[1] = tempc; - tempc = (fac * rt1[2] + mfac * rt2[2]) >> 8; - if (tempc > 255) rt[2] = 255; else rt[2] = tempc; - tempc = (fac * rt1[3] + mfac * rt2[3]) >> 8; - if (tempc > 255) rt[3] = 255; else rt[3] = tempc; + tempc[0] = fac * rt1[0] + mfac * rt2[0]; + tempc[1] = fac * rt1[1] + mfac * rt2[1]; + tempc[2] = fac * rt1[2] + mfac * rt2[2]; + tempc[3] = fac * rt1[3] + mfac * rt2[3]; + + premul_float_to_straight_uchar(rt, tempc); } - rt1 += 4; rt2 += 4; rt += 4; + cp1 += 4; cp2 += 4; rt += 4; } } } @@ -298,17 +300,17 @@ static void do_alphaover_effect(SeqRenderData context, Sequence *UNUSED(seq), fl slice_get_byte_buffers(&context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaover_effect_byte(facf0, facf1, context.rectx, total_lines, (char *) rect1, (char *) rect2, (char *) rect_out); + do_alphaover_effect_byte(facf0, facf1, context.rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Alpha Under *************************/ -static void do_alphaunder_effect_byte(float facf0, float facf1, int x, int y, char *rect1, char *rect2, char *out) +static void do_alphaunder_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { int fac2, mfac, fac, fac4; int xo; - char *rt1, *rt2, *rt; + unsigned char *rt1, *rt2, *rt; xo = x; rt1 = rect1; @@ -460,17 +462,17 @@ static void do_alphaunder_effect(SeqRenderData context, Sequence *UNUSED(seq), f slice_get_byte_buffers(&context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaunder_effect_byte(facf0, facf1, context.rectx, total_lines, (char *) rect1, (char *) rect2, (char *) rect_out); + do_alphaunder_effect_byte(facf0, facf1, context.rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Cross *************************/ -static void do_cross_effect_byte(float facf0, float facf1, int x, int y, char *rect1, char *rect2, char *out) +static void do_cross_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { int fac1, fac2, fac3, fac4; int xo; - char *rt1, *rt2, *rt; + unsigned char *rt1, *rt2, *rt; xo = x; rt1 = rect1; @@ -570,7 +572,7 @@ static void do_cross_effect(SeqRenderData context, Sequence *UNUSED(seq), float slice_get_byte_buffers(&context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_cross_effect_byte(facf0, facf1, context.rectx, total_lines, (char *) rect1, (char *) rect2, (char *) rect_out); + do_cross_effect_byte(facf0, facf1, context.rectx, total_lines, rect1, rect2, rect_out); } } @@ -713,31 +715,32 @@ static void free_gammacross(Sequence *UNUSED(seq)) static void do_gammacross_effect_byte(float facf0, float UNUSED(facf1), int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int fac1, fac2, col; + float fac1, fac2; int xo; - unsigned char *rt1, *rt2, *rt; - - xo = x; - rt1 = (unsigned char *) rect1; - rt2 = (unsigned char *) rect2; - rt = (unsigned char *) out; + unsigned char *cp1, *cp2, *rt; + float rt1[4], rt2[4], tempc[4]; - fac2 = (int)(256.0f * facf0); - fac1 = 256 - fac2; + xo = x; + cp1 = rect1; + cp2 = rect2; + rt = out; + + fac2 = facf0; + fac1 = 1.0f - fac2; while (y--) { x = xo; while (x--) { - col = (fac1 * igamtab1[rt1[0]] + fac2 * igamtab1[rt2[0]]) >> 8; - if (col > 65535) rt[0] = 255; else rt[0] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[1]] + fac2 * igamtab1[rt2[1]]) >> 8; - if (col > 65535) rt[1] = 255; else rt[1] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[2]] + fac2 * igamtab1[rt2[2]]) >> 8; - if (col > 65535) rt[2] = 255; else rt[2] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[3]] + fac2 * igamtab1[rt2[3]]) >> 8; - if (col > 65535) rt[3] = 255; else rt[3] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0])); + tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1])); + tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2])); + tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3])); + + premul_float_to_straight_uchar(rt, tempc); + cp1 += 4; cp2 += 4; rt += 4; } if (y == 0) @@ -746,16 +749,16 @@ static void do_gammacross_effect_byte(float facf0, float UNUSED(facf1), int x, x = xo; while (x--) { - col = (fac1 * igamtab1[rt1[0]] + fac2 * igamtab1[rt2[0]]) >> 8; - if (col > 65535) rt[0] = 255; else rt[0] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[1]] + fac2 * igamtab1[rt2[1]]) >> 8; - if (col > 65535) rt[1] = 255; else rt[1] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[2]] + fac2 * igamtab1[rt2[2]]) >> 8; - if (col > 65535) rt[2] = 255; else rt[2] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; - col = (fac1 * igamtab1[rt1[3]] + fac2 * igamtab1[rt2[3]]) >> 8; - if (col > 65535) rt[3] = 255; else rt[3] = ( (char *)(gamtab + col))[MOST_SIG_BYTE]; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0])); + tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1])); + tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2])); + tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3])); + + premul_float_to_straight_uchar(rt, tempc); + cp1 += 4; cp2 += 4; rt += 4; } } } @@ -828,31 +831,34 @@ static void do_gammacross_effect(SeqRenderData context, Sequence *UNUSED(seq), f static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int col, xo, fac1, fac3; - char *rt1, *rt2, *rt; + int xo; + unsigned char *cp1, *cp2, *rt; + float fac1, fac3; + float tempc[4], rt1[4], rt2[4]; xo = x; - rt1 = (char *)rect1; - rt2 = (char *)rect2; - rt = (char *)out; + cp1 = rect1; + cp2 = rect2; + rt = out; - fac1 = (int)(256.0f * facf0); - fac3 = (int)(256.0f * facf1); + fac1 = facf0; + fac3 = facf1; while (y--) { x = xo; while (x--) { - col = rt1[0] + ((fac1 * rt2[0]) >> 8); - if (col > 255) rt[0] = 255; else rt[0] = col; - col = rt1[1] + ((fac1 * rt2[1]) >> 8); - if (col > 255) rt[1] = 255; else rt[1] = col; - col = rt1[2] + ((fac1 * rt2[2]) >> 8); - if (col > 255) rt[2] = 255; else rt[2] = col; - col = rt1[3] + ((fac1 * rt2[3]) >> 8); - if (col > 255) rt[3] = 255; else rt[3] = col; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = rt1[0] + fac1 * rt2[0]; + tempc[1] = rt1[1] + fac1 * rt2[1]; + tempc[2] = rt1[2] + fac1 * rt2[2]; + tempc[3] = min_ff(1.0f, rt1[3] + fac1 * rt2[3]); + + premul_float_to_straight_uchar(rt, tempc); + + cp1 += 4; cp2 += 4; rt += 4; } if (y == 0) @@ -861,16 +867,17 @@ static void do_add_effect_byte(float facf0, float facf1, int x, int y, unsigned x = xo; while (x--) { - col = rt1[0] + ((fac3 * rt2[0]) >> 8); - if (col > 255) rt[0] = 255; else rt[0] = col; - col = rt1[1] + ((fac3 * rt2[1]) >> 8); - if (col > 255) rt[1] = 255; else rt[1] = col; - col = rt1[2] + ((fac3 * rt2[2]) >> 8); - if (col > 255) rt[2] = 255; else rt[2] = col; - col = rt1[3] + ((fac3 * rt2[3]) >> 8); - if (col > 255) rt[3] = 255; else rt[3] = col; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = rt1[0] + fac3 * rt2[0]; + tempc[1] = rt1[1] + fac3 * rt2[1]; + tempc[2] = rt1[2] + fac3 * rt2[2]; + tempc[3] = min_ff(1.0f, rt1[3] + fac3 * rt2[3]); + + premul_float_to_straight_uchar(rt, tempc); + + cp1 += 4; cp2 += 4; rt += 4; } } } @@ -890,22 +897,28 @@ static void do_add_effect_float(float facf0, float facf1, int x, int y, float *r fac3 = facf1; while (y--) { - x = xo * 4; + x = xo; while (x--) { - *rt = *rt1 + fac1 * (*rt2); + rt[0] = rt1[0] + fac1 * rt2[0]; + rt[1] = rt1[1] + fac1 * rt2[1]; + rt[2] = rt1[2] + fac1 * rt2[2]; + rt[3] = min_ff(1.0f, rt1[3] + fac1 * rt2[3]); - rt1++; rt2++; rt++; + rt1 += 4; rt2 += 4; rt += 4; } if (y == 0) break; y--; - x = xo * 4; + x = xo; while (x--) { - *rt = *rt1 + fac3 * (*rt2); + rt[0] = rt1[0] + fac1 * rt2[0]; + rt[1] = rt1[1] + fac1 * rt2[1]; + rt[2] = rt1[2] + fac1 * rt2[2]; + rt[3] = min_ff(1.0f, rt1[3] + fac3 * rt2[3]); - rt1++; rt2++; rt++; + rt1 += 4; rt2 += 4; rt += 4; } } } @@ -931,32 +944,35 @@ static void do_add_effect(SeqRenderData context, Sequence *UNUSED(seq), float UN /*********************** Sub *************************/ -static void do_sub_effect_byte(float facf0, float facf1, int x, int y, char *rect1, char *rect2, char *out) +static void do_sub_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int col, xo, fac1, fac3; - char *rt1, *rt2, *rt; + int xo; + unsigned char *cp1, *cp2, *rt; + float fac1, fac3; + float tempc[4], rt1[4], rt2[4]; xo = x; - rt1 = (char *) rect1; - rt2 = (char *) rect2; - rt = (char *) out; + cp1 = rect1; + cp2 = rect2; + rt = out; - fac1 = (int) (256.0f * facf0); - fac3 = (int) (256.0f * facf1); + fac1 = facf0; + fac3 = facf1; while (y--) { x = xo; while (x--) { - col = rt1[0] - ((fac1 * rt2[0]) >> 8); - if (col < 0) rt[0] = 0; else rt[0] = col; - col = rt1[1] - ((fac1 * rt2[1]) >> 8); - if (col < 0) rt[1] = 0; else rt[1] = col; - col = rt1[2] - ((fac1 * rt2[2]) >> 8); - if (col < 0) rt[2] = 0; else rt[2] = col; - col = rt1[3] - ((fac1 * rt2[3]) >> 8); - if (col < 0) rt[3] = 0; else rt[3] = col; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = rt1[0] - fac1 * rt2[0]; + tempc[1] = rt1[1] - fac1 * rt2[1]; + tempc[2] = rt1[2] - fac1 * rt2[2]; + tempc[3] = rt1[3] - fac1 * rt2[3]; + + premul_float_to_straight_uchar(rt, tempc); + + cp1 += 4; cp2 += 4; rt += 4; } if (y == 0) @@ -965,16 +981,17 @@ static void do_sub_effect_byte(float facf0, float facf1, int x, int y, char *rec x = xo; while (x--) { - col = rt1[0] - ((fac3 * rt2[0]) >> 8); - if (col < 0) rt[0] = 0; else rt[0] = col; - col = rt1[1] - ((fac3 * rt2[1]) >> 8); - if (col < 0) rt[1] = 0; else rt[1] = col; - col = rt1[2] - ((fac3 * rt2[2]) >> 8); - if (col < 0) rt[2] = 0; else rt[2] = col; - col = rt1[3] - ((fac3 * rt2[3]) >> 8); - if (col < 0) rt[3] = 0; else rt[3] = col; + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); - rt1 += 4; rt2 += 4; rt += 4; + tempc[0] = rt1[0] - fac3 * rt2[0]; + tempc[1] = rt1[1] - fac3 * rt2[1]; + tempc[2] = rt1[2] - fac3 * rt2[2]; + tempc[3] = rt1[3] - fac3 * rt2[3]; + + premul_float_to_straight_uchar(rt, tempc); + + cp1 += 4; cp2 += 4; rt += 4; } } } @@ -1029,7 +1046,7 @@ static void do_sub_effect(SeqRenderData context, Sequence *UNUSED(seq), float UN slice_get_byte_buffers(&context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_sub_effect_byte(facf0, facf1, context.rectx, total_lines, (char *) rect1, (char *) rect2, (char *) rect_out); + do_sub_effect_byte(facf0, facf1, context.rectx, total_lines, rect1, rect2, rect_out); } } @@ -1039,10 +1056,10 @@ static void do_sub_effect(SeqRenderData context, Sequence *UNUSED(seq), float UN #define XOFF 8 #define YOFF 8 -static void do_drop_effect_byte(float facf0, float facf1, int x, int y, char *rect2i, char *rect1i, char *outi) +static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi) { int height, width, temp, fac, fac1, fac2; - char *rt1, *rt2, *out; + unsigned char *rt1, *rt2, *out; int field = 1; width = x; @@ -1051,9 +1068,9 @@ static void do_drop_effect_byte(float facf0, float facf1, int x, int y, char *re fac1 = (int) (70.0f * facf0); fac2 = (int) (70.0f * facf1); - rt2 = (char *) (rect2i + YOFF * width); - rt1 = (char *) rect1i; - out = (char *) outi; + rt2 = (unsigned char *) (rect2i + YOFF * width); + rt1 = (unsigned char *) rect1i; + out = (unsigned char *) outi; for (y = 0; y < height - YOFF; y++) { if (field) fac = fac1; else fac = fac2; @@ -1122,12 +1139,12 @@ static void do_mul_effect_byte(float facf0, float facf1, int x, int y, unsigned unsigned char *out) { int xo, fac1, fac3; - char *rt1, *rt2, *rt; + unsigned char *rt1, *rt2, *rt; xo = x; - rt1 = (char *)rect1; - rt2 = (char *)rect2; - rt = (char *)out; + rt1 = rect1; + rt2 = rect2; + rt = out; fac1 = (int)(256.0f * facf0); fac3 = (int)(256.0f * facf1); @@ -1539,13 +1556,13 @@ static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), WipeZone wipezone; WipeVars *wipe = (WipeVars *)seq->effectdata; int xo, yo; - char *rt1, *rt2, *rt; + unsigned char *cp1, *cp2, *rt; precalc_wipe_zone(&wipezone, wipe, x, y); - rt1 = (char *)rect1; - rt2 = (char *)rect2; - rt = (char *)out; + cp1 = rect1; + cp2 = rect2; + rt = out; xo = x; yo = y; @@ -1553,11 +1570,18 @@ static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), for (x = 0; x < xo; x++) { float check = check_zone(&wipezone, x, y, seq, facf0); if (check) { - if (rt1) { - rt[0] = (int)(rt1[0] * check) + (int)(rt2[0] * (1 - check)); - rt[1] = (int)(rt1[1] * check) + (int)(rt2[1] * (1 - check)); - rt[2] = (int)(rt1[2] * check) + (int)(rt2[2] * (1 - check)); - rt[3] = (int)(rt1[3] * check) + (int)(rt2[3] * (1 - check)); + if (cp1) { + float rt1[4], rt2[4], tempc[4]; + + straight_uchar_to_premul_float(rt1, cp1); + straight_uchar_to_premul_float(rt2, cp2); + + tempc[0] = rt1[0] * check + rt2[0] * (1 - check); + tempc[1] = rt1[1] * check + rt2[1] * (1 - check); + tempc[2] = rt1[2] * check + rt2[2] * (1 - check); + tempc[3] = rt1[3] * check + rt2[3] * (1 - check); + + premul_float_to_straight_uchar(rt, tempc); } else { rt[0] = 0; @@ -1567,11 +1591,11 @@ static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), } } else { - if (rt2) { - rt[0] = rt2[0]; - rt[1] = rt2[1]; - rt[2] = rt2[2]; - rt[3] = rt2[3]; + if (cp2) { + rt[0] = cp2[0]; + rt[1] = cp2[1]; + rt[2] = cp2[2]; + rt[3] = cp2[3]; } else { rt[0] = 0; @@ -1582,11 +1606,11 @@ static void do_wipe_effect_byte(Sequence *seq, float facf0, float UNUSED(facf1), } rt += 4; - if (rt1 != NULL) { - rt1 += 4; + if (cp1 != NULL) { + cp1 += 4; } - if (rt2 != NULL) { - rt2 += 4; + if (cp2 != NULL) { + cp2 += 4; } } } @@ -1803,166 +1827,6 @@ static ImBuf *do_transform_effect(SeqRenderData context, Sequence *seq, float UN /*********************** Glow *************************/ -static void RVBlurBitmap2_byte(unsigned char *map, int width, int height, float blur, int quality) -/* MUUUCCH better than the previous blur. */ -/* We do the blurring in two passes which is a whole lot faster. */ -/* I changed the math arount to implement an actual Gaussian */ -/* distribution. */ -/* */ -/* Watch out though, it tends to misbehaven with large blur values on */ -/* a small bitmap. Avoid avoid avoid. */ -/*=============================== */ -{ - unsigned char *temp = NULL, *swap; - float *filter = NULL; - int x, y, i, fx, fy; - int index, ix, halfWidth; - float fval, k, curColor[3], curColor2[3], weight = 0; - - /* If we're not really blurring, bail out */ - if (blur <= 0) - return; - - /*Allocate memory for the tempmap and the blur filter matrix */ - temp = MEM_mallocN((width * height * 4), "blurbitmaptemp"); - if (!temp) - return; - - /*Allocate memory for the filter elements */ - halfWidth = ((quality + 1) * blur); - filter = (float *)MEM_mallocN(sizeof(float) * halfWidth * 2, "blurbitmapfilter"); - if (!filter) { - MEM_freeN(temp); - return; - } - - /* Apparently we're calculating a bell curve based on the standard deviation (or radius) - * This code is based on an example posted to comp.graphics.algorithms by - * Blancmange (bmange@airdmhor.gen.nz) - */ - - k = -1.0f / (2.0f * (float)M_PI * blur * blur); - for (ix = 0; ix < halfWidth; ix++) { - weight = (float)exp(k * (ix * ix)); - filter[halfWidth - ix] = weight; - filter[halfWidth + ix] = weight; - } - filter[0] = weight; - - /* Normalize the array */ - fval = 0; - for (ix = 0; ix < halfWidth * 2; ix++) - fval += filter[ix]; - - for (ix = 0; ix < halfWidth * 2; ix++) - filter[ix] /= fval; - - /* Blur the rows */ - for (y = 0; y < height; y++) { - /* Do the left & right strips */ - for (x = 0; x < halfWidth; x++) { - index = (x + y * width) * 4; - fx = 0; - zero_v3(curColor); - zero_v3(curColor2); - - for (i = x - halfWidth; i < x + halfWidth; i++) { - if ((i >= 0) && (i < width)) { - curColor[0] += map[(i + y * width) * 4 + GlowR] * filter[fx]; - curColor[1] += map[(i + y * width) * 4 + GlowG] * filter[fx]; - curColor[2] += map[(i + y * width) * 4 + GlowB] * filter[fx]; - - curColor2[0] += map[(width - 1 - i + y * width) * 4 + GlowR] * filter[fx]; - curColor2[1] += map[(width - 1 - i + y * width) * 4 + GlowG] * filter[fx]; - curColor2[2] += map[(width - 1 - i + y * width) * 4 + GlowB] * filter[fx]; - } - fx++; - } - temp[index + GlowR] = curColor[0]; - temp[index + GlowG] = curColor[1]; - temp[index + GlowB] = curColor[2]; - - temp[((width - 1 - x + y * width) * 4) + GlowR] = curColor2[0]; - temp[((width - 1 - x + y * width) * 4) + GlowG] = curColor2[1]; - temp[((width - 1 - x + y * width) * 4) + GlowB] = curColor2[2]; - - } - - /* Do the main body */ - for (x = halfWidth; x < width - halfWidth; x++) { - index = (x + y * width) * 4; - fx = 0; - zero_v3(curColor); - for (i = x - halfWidth; i < x + halfWidth; i++) { - curColor[0] += map[(i + y * width) * 4 + GlowR] * filter[fx]; - curColor[1] += map[(i + y * width) * 4 + GlowG] * filter[fx]; - curColor[2] += map[(i + y * width) * 4 + GlowB] * filter[fx]; - fx++; - } - temp[index + GlowR] = curColor[0]; - temp[index + GlowG] = curColor[1]; - temp[index + GlowB] = curColor[2]; - } - } - - /* Swap buffers */ - swap = temp; temp = map; map = swap; - - /* Blur the columns */ - for (x = 0; x < width; x++) { - /* Do the top & bottom strips */ - for (y = 0; y < halfWidth; y++) { - index = (x + y * width) * 4; - fy = 0; - zero_v3(curColor); - zero_v3(curColor2); - for (i = y - halfWidth; i < y + halfWidth; i++) { - if ((i >= 0) && (i < height)) { - /* Bottom */ - curColor[0] += map[(x + i * width) * 4 + GlowR] * filter[fy]; - curColor[1] += map[(x + i * width) * 4 + GlowG] * filter[fy]; - curColor[2] += map[(x + i * width) * 4 + GlowB] * filter[fy]; - - /* Top */ - curColor2[0] += map[(x + (height - 1 - i) * width) * 4 + GlowR] * filter[fy]; - curColor2[1] += map[(x + (height - 1 - i) * width) * 4 + GlowG] * filter[fy]; - curColor2[2] += map[(x + (height - 1 - i) * width) * 4 + GlowB] * filter[fy]; - } - fy++; - } - temp[index + GlowR] = curColor[0]; - temp[index + GlowG] = curColor[1]; - temp[index + GlowB] = curColor[2]; - temp[((x + (height - 1 - y) * width) * 4) + GlowR] = curColor2[0]; - temp[((x + (height - 1 - y) * width) * 4) + GlowG] = curColor2[1]; - temp[((x + (height - 1 - y) * width) * 4) + GlowB] = curColor2[2]; - } - - /* Do the main body */ - for (y = halfWidth; y < height - halfWidth; y++) { - index = (x + y * width) * 4; - fy = 0; - zero_v3(curColor); - for (i = y - halfWidth; i < y + halfWidth; i++) { - curColor[0] += map[(x + i * width) * 4 + GlowR] * filter[fy]; - curColor[1] += map[(x + i * width) * 4 + GlowG] * filter[fy]; - curColor[2] += map[(x + i * width) * 4 + GlowB] * filter[fy]; - fy++; - } - temp[index + GlowR] = curColor[0]; - temp[index + GlowG] = curColor[1]; - temp[index + GlowB] = curColor[2]; - } - } - - /* Swap buffers */ - swap = temp; temp = map; /* map = swap; */ /* UNUSED */ - - /* Tidy up */ - MEM_freeN(filter); - MEM_freeN(temp); -} - static void RVBlurBitmap2_float(float *map, int width, int height, float blur, int quality) /* MUUUCCH better than the previous blur. */ /* We do the blurring in two passes which is a whole lot faster. */ @@ -2124,26 +1988,6 @@ static void RVBlurBitmap2_float(float *map, int width, int height, float blur, i MEM_freeN(temp); } - -/* Adds two bitmaps and puts the results into a third map. */ -/* C must have been previously allocated but it may be A or B. */ -/* We clamp values to 255 to prevent weirdness */ -/*=============================== */ -static void RVAddBitmaps_byte(unsigned char *a, unsigned char *b, unsigned char *c, int width, int height) -{ - int x, y, index; - - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - index = (x + y * width) * 4; - c[index + GlowR] = MIN2(255, a[index + GlowR] + b[index + GlowR]); - c[index + GlowG] = MIN2(255, a[index + GlowG] + b[index + GlowG]); - c[index + GlowB] = MIN2(255, a[index + GlowB] + b[index + GlowB]); - c[index + GlowA] = MIN2(255, a[index + GlowA] + b[index + GlowA]); - } - } -} - static void RVAddBitmaps_float(float *a, float *b, float *c, int width, int height) { int x, y, index; @@ -2159,37 +2003,6 @@ static void RVAddBitmaps_float(float *a, float *b, float *c, int width, int heig } } -/* For each pixel whose total luminance exceeds the threshold, - * Multiply it's value by BOOST and add it to the output map - */ -static void RVIsolateHighlights_byte(unsigned char *in, unsigned char *out, int width, int height, int threshold, - float boost, float clamp) -{ - int x, y, index; - int intensity; - - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - index = (x + y * width) * 4; - - /* Isolate the intensity */ - intensity = (in[index + GlowR] + in[index + GlowG] + in[index + GlowB] - threshold); - if (intensity > 0) { - out[index + GlowR] = MIN2(255 * clamp, (in[index + GlowR] * boost * intensity) / 255); - out[index + GlowG] = MIN2(255 * clamp, (in[index + GlowG] * boost * intensity) / 255); - out[index + GlowB] = MIN2(255 * clamp, (in[index + GlowB] * boost * intensity) / 255); - out[index + GlowA] = MIN2(255 * clamp, (in[index + GlowA] * boost * intensity) / 255); - } - else { - out[index + GlowR] = 0; - out[index + GlowG] = 0; - out[index + GlowB] = 0; - out[index + GlowA] = 0; - } - } - } -} - static void RVIsolateHighlights_float(float *in, float *out, int width, int height, float threshold, float boost, float clamp) { int x, y, index; @@ -2254,16 +2067,27 @@ static void copy_glow_effect(Sequence *dst, Sequence *src) } static void do_glow_effect_byte(Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y, - char *rect1, char *UNUSED(rect2), char *out) + unsigned char *rect1, unsigned char *UNUSED(rect2), unsigned char *out) { - unsigned char *outbuf = (unsigned char *)out; - unsigned char *inbuf = (unsigned char *)rect1; + float *outbuf, *inbuf; GlowVars *glow = (GlowVars *)seq->effectdata; - - RVIsolateHighlights_byte(inbuf, outbuf, x, y, glow->fMini * 765, glow->fBoost * facf0, glow->fClamp); - RVBlurBitmap2_byte(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality); + + inbuf = MEM_mallocN(4 * sizeof(float) * x * y, "glow effect input"); + outbuf = MEM_mallocN(4 * sizeof(float) * x * y, "glow effect output"); + + IMB_buffer_float_from_byte(inbuf, rect1, IB_PROFILE_SRGB, IB_PROFILE_SRGB, FALSE, x, y, x, x); + IMB_buffer_float_premultiply(inbuf, x, y); + + RVIsolateHighlights_float(inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp); + RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality); if (!glow->bNoComp) - RVAddBitmaps_byte(inbuf, outbuf, outbuf, x, y); + RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y); + + IMB_buffer_float_unpremultiply(outbuf, x, y); + IMB_buffer_byte_from_float(out, outbuf, 4, 0.0f, IB_PROFILE_SRGB, IB_PROFILE_SRGB, FALSE, x, y, x, x); + + MEM_freeN(inbuf); + MEM_freeN(outbuf); } static void do_glow_effect_float(Sequence *seq, int render_size, float facf0, float UNUSED(facf1), int x, int y, @@ -2292,7 +2116,7 @@ static ImBuf *do_glow_effect(SeqRenderData context, Sequence *seq, float UNUSED( } else { do_glow_effect_byte(seq, render_size, facf0, facf1, context.rectx, context.recty, - (char *) ibuf1->rect, (char *) ibuf2->rect, (char *) out->rect); + (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect); } return out; @@ -2735,7 +2559,7 @@ static ImBuf *do_speed_effect(SeqRenderData context, Sequence *UNUSED(seq), floa } else { do_cross_effect_byte(facf0, facf1, context.rectx, context.recty, - (char *) ibuf1->rect, (char *) ibuf2->rect, (char *) out->rect); + (unsigned char *) ibuf1->rect, (unsigned char *) ibuf2->rect, (unsigned char *) out->rect); } return out; } @@ -2761,8 +2585,8 @@ static void do_overdrop_effect(SeqRenderData context, Sequence *UNUSED(seq), flo slice_get_byte_buffers(&context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_drop_effect_byte(facf0, facf1, x, y, (char *) rect1, (char *) rect2, (char *) rect_out); - do_alphaover_effect_byte(facf0, facf1, x, y, (char *) rect1, (char *) rect2, (char *) rect_out); + do_drop_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out); + do_alphaover_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out); } } diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c index 5b2e9f2bf23..3d8a2f7cddf 100644 --- a/source/blender/blenkernel/intern/seqmodifier.c +++ b/source/blender/blenkernel/intern/seqmodifier.c @@ -226,24 +226,28 @@ static void curves_apply_threaded(int width, int height, unsigned char *rect, fl } if (rect) { unsigned char *pixel = rect + pixel_index; - unsigned char result[3]; + float result[3], tempc[4]; - curvemapping_evaluate_premulRGB(curve_mapping, result, pixel); + straight_uchar_to_premul_float(tempc, pixel); + + curvemapping_evaluate_premulRGBF(curve_mapping, result, tempc); if (mask_rect) { float t[3]; rgb_uchar_to_float(t, mask_rect + pixel_index); - pixel[0] = pixel[0] * (1.0f - t[0]) + result[0] * t[0]; - pixel[1] = pixel[1] * (1.0f - t[1]) + result[1] * t[1]; - pixel[2] = pixel[2] * (1.0f - t[2]) + result[2] * t[2]; + tempc[0] = pixel[0] * (1.0f - t[0]) + result[0] * t[0]; + tempc[1] = pixel[1] * (1.0f - t[1]) + result[1] * t[1]; + tempc[2] = pixel[2] * (1.0f - t[2]) + result[2] * t[2]; } else { - pixel[0] = result[0]; - pixel[1] = result[1]; - pixel[2] = result[2]; + tempc[0] = result[0]; + tempc[1] = result[1]; + tempc[2] = result[2]; } + + premul_float_to_straight_uchar(pixel, tempc); } } } diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 5e44f2d6d9e..8d010de408a 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -324,7 +324,6 @@ void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, int make_ { const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); const char *to_colorspace = scene->sequencer_colorspace_settings.name; - int predivide = ibuf->flags & IB_cm_predivide; if (!ibuf->rect_float) { if (make_float && ibuf->rect) { @@ -354,7 +353,7 @@ void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, int make_ imb_freerectImBuf(ibuf); IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, predivide); + from_colorspace, to_colorspace, TRUE); } } @@ -367,10 +366,8 @@ void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf) return; if (to_colorspace && to_colorspace[0] != '\0') { - int predivide = ibuf->flags & IB_cm_predivide; - IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, predivide); + from_colorspace, to_colorspace, TRUE); } } @@ -636,7 +633,7 @@ void BKE_sequence_calc(Scene *scene, Sequence *seq) } } -/* note: caller should run calc_sequence(scene, seq) after */ +/* note: caller should run BKE_sequence_calc(scene, seq) after */ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, int lock_range) { char str[FILE_MAX]; @@ -1517,18 +1514,6 @@ MINLINE float color_balance_fl(float in, const float lift, const float gain, con return powf(x, gamma) * mul; } -static void make_cb_table_byte(float lift, float gain, float gamma, - unsigned char *table, float mul) -{ - int y; - - for (y = 0; y < 256; y++) { - float v = color_balance_fl((float)y * (1.0f / 255.0f), lift, gain, gamma, mul); - - table[y] = FTOCHAR(v); - } -} - static void make_cb_table_float(float lift, float gain, float gamma, float *table, float mul) { @@ -1543,35 +1528,33 @@ static void make_cb_table_float(float lift, float gain, float gamma, static void color_balance_byte_byte(StripColorBalance *cb_, unsigned char *rect, unsigned char *mask_rect, int width, int height, float mul) { - unsigned char cb_tab[3][256]; - int c; - unsigned char *p = rect; - unsigned char *e = p + width * 4 * height; + //unsigned char cb_tab[3][256]; + unsigned char *cp = rect; + unsigned char *e = cp + width * 4 * height; unsigned char *m = mask_rect; StripColorBalance cb = calc_cb(cb_); - for (c = 0; c < 3; c++) { - make_cb_table_byte(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul); - } + while (cp < e) { + float p[4]; + int c; - while (p < e) { - if (m) { - float t[3] = {m[0] / 255.0f, m[1] / 255.0f, m[2] / 255.0f}; + straight_uchar_to_premul_float(p, cp); - p[0] = p[0] * (1.0f - t[0]) + t[0] * cb_tab[0][p[0]]; - p[1] = p[1] * (1.0f - t[1]) + t[1] * cb_tab[1][p[1]]; - p[2] = p[2] * (1.0f - t[2]) + t[2] * cb_tab[2][p[2]]; + for (c = 0; c < 3; c++) { + float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul); - m += 4; - } - else { - p[0] = cb_tab[0][p[0]]; - p[1] = cb_tab[1][p[1]]; - p[2] = cb_tab[2][p[2]]; + if (m) + p[c] = p[c] * (1.0f - (float)m[c] / 255.0f) + t * m[c]; + else + p[c] = t; } - p += 4; + premul_float_to_straight_uchar(cp, p); + + cp += 4; + if (m) + m += 4; } } @@ -1795,7 +1778,7 @@ int BKE_sequencer_input_have_to_preprocess(SeqRenderData UNUSED(context), Sequen { float mul; - if (seq->flag & (SEQ_FILTERY | SEQ_USE_CROP | SEQ_USE_TRANSFORM | SEQ_FLIPX | SEQ_FLIPY | SEQ_MAKE_PREMUL | SEQ_MAKE_FLOAT)) { + if (seq->flag & (SEQ_FILTERY | SEQ_USE_CROP | SEQ_USE_TRANSFORM | SEQ_FLIPX | SEQ_FLIPY | SEQ_MAKE_FLOAT)) { return TRUE; } @@ -1892,7 +1875,8 @@ static ImBuf *input_preprocess(SeqRenderData context, Sequence *seq, float cfra, ImBuf *i = IMB_allocImBuf(dx, dy, 32, ibuf->rect_float ? IB_rectfloat : IB_rect); IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy); - + sequencer_imbuf_assign_spaces(context.scene, i); + IMB_freeImBuf(ibuf); ibuf = i; @@ -1931,12 +1915,6 @@ static ImBuf *input_preprocess(SeqRenderData context, Sequence *seq, float cfra, multibuf(ibuf, mul); } - if (seq->flag & SEQ_MAKE_PREMUL) { - if (ibuf->planes == 32 && ibuf->zbuf == NULL) { - IMB_premultiply_alpha(ibuf); - } - } - if (ibuf->x != context.rectx || ibuf->y != context.recty) { if (context.scene->r.mode & R_OSA) { IMB_scaleImBuf(ibuf, (short)context.rectx, (short)context.recty); @@ -2546,13 +2524,18 @@ static ImBuf *do_render_strip_uncached(SeqRenderData context, Sequence *seq, flo case SEQ_TYPE_IMAGE: { StripElem *s_elem = BKE_sequencer_give_stripelem(seq, cfra); + int flag; if (s_elem) { BLI_join_dirfile(name, sizeof(name), seq->strip->dir, s_elem->name); BLI_path_abs(name, G.main->name); } - if (s_elem && (ibuf = IMB_loadiffname(name, IB_rect, seq->strip->colorspace_settings.name))) { + flag = IB_rect; + if (seq->alpha_mode == SEQ_ALPHA_PREMUL) + flag |= IB_alphamode_premul; + + if (s_elem && (ibuf = IMB_loadiffname(name, flag, seq->strip->colorspace_settings.name))) { /* we don't need both (speed reasons)! */ if (ibuf->rect_float && ibuf->rect) imb_freerectImBuf(ibuf); @@ -2641,7 +2624,7 @@ static ImBuf *do_render_strip_uncached(SeqRenderData context, Sequence *seq, flo static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) { ImBuf *ibuf = NULL; - int use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra); + int use_preprocess = FALSE; int is_proxy_image = FALSE; float nr = give_stripelem_index(seq, cfra); /* all effects are handled similarly with the exception of speed effect */ @@ -2650,30 +2633,36 @@ static ImBuf *seq_render_strip(SeqRenderData context, Sequence *seq, float cfra) ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF); - /* currently, we cache preprocessed images in SEQ_STRIPELEM_IBUF, - * but not(!) on SEQ_STRIPELEM_IBUF_ENDSTILL and ..._STARTSTILL */ - if (ibuf) - use_preprocess = FALSE; - - if (ibuf == NULL) - ibuf = copy_from_ibuf_still(context, seq, nr); - if (ibuf == NULL) { - ibuf = BKE_sequencer_preprocessed_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF); + if (ibuf == NULL) + ibuf = copy_from_ibuf_still(context, seq, nr); if (ibuf == NULL) { - /* MOVIECLIPs have their own proxy management */ - if (ibuf == NULL && seq->type != SEQ_TYPE_MOVIECLIP) { - ibuf = seq_proxy_fetch(context, seq, cfra); - is_proxy_image = (ibuf != NULL); + ibuf = BKE_sequencer_preprocessed_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF); + + if (ibuf == NULL) { + /* MOVIECLIPs have their own proxy management */ + if (ibuf == NULL && seq->type != SEQ_TYPE_MOVIECLIP) { + ibuf = seq_proxy_fetch(context, seq, cfra); + is_proxy_image = (ibuf != NULL); + } + + if (ibuf == NULL) + ibuf = do_render_strip_uncached(context, seq, cfra); + + if (ibuf) + BKE_sequencer_preprocessed_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf); } - - if (ibuf == NULL) - ibuf = do_render_strip_uncached(context, seq, cfra); - - if (ibuf) - BKE_sequencer_preprocessed_cache_put(context, seq, cfra, SEQ_STRIPELEM_IBUF, ibuf); } + + if (ibuf) + use_preprocess = BKE_sequencer_input_have_to_preprocess(context, seq, cfra); + } + else { + /* currently, we cache preprocessed images in SEQ_STRIPELEM_IBUF, + * but not(!) on SEQ_STRIPELEM_IBUF_ENDSTILL and ..._STARTSTILL + * so, no need in check for preprocess here + */ } if (ibuf == NULL) { @@ -3973,10 +3962,18 @@ void BKE_sequence_init_colorspace(Sequence *seq) /* initialize input color space */ if (seq->type == SEQ_TYPE_IMAGE) { - ibuf = IMB_loadiffname(name, IB_rect, seq->strip->colorspace_settings.name); + ibuf = IMB_loadiffname(name, IB_test | IB_alphamode_detect, seq->strip->colorspace_settings.name); + + /* byte images are default to straight alpha, however sequencer + * works in premul space, so mark strip to be premultiplied first + */ + seq->alpha_mode = SEQ_ALPHA_STRAIGHT; + if (ibuf) { + if (ibuf->flags & IB_alphamode_premul) + seq->alpha_mode = IMA_ALPHA_PREMUL; - if (ibuf) IMB_freeImBuf(ibuf); + } } } } @@ -4176,7 +4173,7 @@ static Sequence *seq_dupli(Scene *scene, Scene *scene_to, Sequence *seq, int dup seqn->seqbase.first = seqn->seqbase.last = NULL; /* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */ - /* - seq_dupli_recursive(&seq->seqbase,&seqn->seqbase);*/ + /* - seq_dupli_recursive(&seq->seqbase, &seqn->seqbase);*/ } else if (seq->type == SEQ_TYPE_SCENE) { seqn->strip->stripdata = NULL; diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 629b2c989d3..2563fc268b1 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -2407,7 +2407,7 @@ static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene) bv[3] = (float)sds->res[1]; // y bv[5] = (float)sds->res[2]; // z -// #pragma omp parallel for schedule(static,1) +// #pragma omp parallel for schedule(static, 1) for (z = 0; z < sds->res[2]; z++) { size_t index = z * slabsize; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 37c9c1dd84e..b1917c6091d 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -1577,7 +1577,7 @@ static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm) CCGFace **faces; int totface; - BLI_pbvh_get_grid_updates(ccgdm->pbvh, 1, (void ***)&faces, &totface); + BKE_pbvh_get_grid_updates(ccgdm->pbvh, 1, (void ***)&faces, &totface); if (totface) { ccgSubSurf_updateFromFaces(ccgdm->ss, 0, faces, totface); ccgSubSurf_updateNormals(ccgdm->ss, faces, totface); @@ -1715,7 +1715,8 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes) if (ccgdm->pbvh && ccgdm->multires.mmd && !fast) { if (dm->numTessFaceData) { - BLI_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL, setMaterial); + BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL, + setMaterial, FALSE); glShadeModel(GL_FLAT); } @@ -3033,7 +3034,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) * when the ccgdm gets remade, the assumption is that the topology * does not change. */ ccgdm_create_grids(dm); - BLI_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void **)ccgdm->gridFaces, + BKE_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void **)ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } @@ -3051,15 +3052,15 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm) numGrids = ccgDM_getNumGrids(dm); - ob->sculpt->pbvh = ccgdm->pbvh = BLI_pbvh_new(); - BLI_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, + ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new(); + BKE_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden); } else if (ob->type == OB_MESH) { Mesh *me = ob->data; - ob->sculpt->pbvh = ccgdm->pbvh = BLI_pbvh_new(); + ob->sculpt->pbvh = ccgdm->pbvh = BKE_pbvh_new(); BLI_assert(!(me->mface == NULL && me->mpoly != NULL)); /* BMESH ONLY complain if mpoly is valid but not mface */ - BLI_pbvh_build_mesh(ccgdm->pbvh, me->mface, me->mvert, + BKE_pbvh_build_mesh(ccgdm->pbvh, me->mface, me->mvert, me->totface, me->totvert, &me->vdata); } diff --git a/source/blender/blenkernel/intern/suggestions.c b/source/blender/blenkernel/intern/suggestions.c index ff9774f85af..6f9736df683 100644 --- a/source/blender/blenkernel/intern/suggestions.c +++ b/source/blender/blenkernel/intern/suggestions.c @@ -163,13 +163,13 @@ void texttool_suggest_add(const char *name, char type) suggestions.top = 0; } -void texttool_suggest_prefix(const char *prefix) +void texttool_suggest_prefix(const char *prefix, const int prefix_len) { SuggItem *match, *first, *last; - int cmp, len = strlen(prefix), top = 0; + int cmp, top = 0; if (!suggestions.first) return; - if (len == 0) { + if (prefix_len == 0) { suggestions.selected = suggestions.firstmatch = suggestions.first; suggestions.lastmatch = suggestions.last; return; @@ -177,7 +177,7 @@ void texttool_suggest_prefix(const char *prefix) first = last = NULL; for (match = suggestions.first; match; match = match->next) { - cmp = txttl_cmp(prefix, match->name, len); + cmp = txttl_cmp(prefix, match->name, prefix_len); if (cmp == 0) { if (!first) { first = match; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 322b77e0462..c337e339ebf 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -2936,3 +2936,18 @@ int text_check_whitespace(const char ch) return 1; return 0; } + +int text_find_identifier_start(const char *str, int i) +{ + if (UNLIKELY(i <= 0)) { + return 0; + } + + while (i--) { + if (!text_check_identifier(str[i])) { + break; + } + } + i++; + return i; +} diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 149842bc038..fbaf6f70fbc 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -440,7 +440,7 @@ void default_tex(Tex *tex) tex->type = TEX_CLOUDS; tex->stype = 0; tex->flag = TEX_CHECKER_ODD; - tex->imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA; + tex->imaflag = TEX_INTERPOL | TEX_MIPMAP; tex->extend = TEX_REPEAT; tex->cropxmin = tex->cropymin = 0.0; tex->cropxmax = tex->cropymax = 1.0; diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h new file mode 100644 index 00000000000..880a97acb80 --- /dev/null +++ b/source/blender/blenlib/BLI_buffer.h @@ -0,0 +1,90 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_BUFFER_H__ +#define __BLI_BUFFER_H__ + +/* Note: this more or less fills same purpose as BLI_array, but makes + * it much easier to resize the array outside of the function it was + * declared in since */ + +/* Usage examples: + * + * { + * BLI_buffer_declare_static(int, my_int_array, BLI_BUFFER_NOP, 32); + * + * BLI_buffer_append(my_int_array, int, 42); + * assert(my_int_array.count == 1); + * assert(BLI_buffer_at(my_int_array, int, 0) == 42); + * + * BLI_buffer_free(&my_int_array); + * } + */ + +typedef struct { + void *data; + const int elem_size; + int count, alloc_count; + int flag; +} BLI_Buffer; + +enum { + BLI_BUFFER_NOP = 0, + BLI_BUFFER_USE_STATIC = (1 << 0), + BLI_BUFFER_USE_CALLOC = (1 << 1), /* ensure the array is always calloc'd */ +}; + +#define BLI_buffer_declare_static(type_, name_, flag_, static_count_) \ + type_ *name_ ## _static_[static_count_]; \ + BLI_Buffer name_ = { \ + /* clear the static memory if this is a calloc'd array */ \ + ((void)((flag_ & BLI_BUFFER_USE_CALLOC) ? \ + memset(name_ ## _static_, 0, sizeof(name_ ## _static_)) : 0\ + ), /* memset-end */ \ + name_ ## _static_), \ + sizeof(type_), \ + 0, \ + static_count_, \ + BLI_BUFFER_USE_STATIC | flag_} + +/* never use static*/ +#define BLI_buffer_declare(type_, name_, flag_) \ + BLI_Buffer name_ = {NULL, \ + sizeof(type_), \ + 0, \ + 0, \ + flag_} + + +#define BLI_buffer_at(buffer_, type_, index_) ( \ + (((type_ *)(buffer_)->data)[(BLI_assert(sizeof(type_) == (buffer_)->elem_size)), index_])) + +#define BLI_buffer_append(buffer_, type_, val_) ( \ + BLI_buffer_resize(buffer_, (buffer_)->count + 1), \ + (BLI_buffer_at(buffer_, type_, (buffer_)->count - 1) = val_) \ +) + +/* Never decreases the amount of memory allocated */ +void BLI_buffer_resize(BLI_Buffer *buffer, int new_count); + +/* Does not free the buffer structure itself */ +void BLI_buffer_free(BLI_Buffer *buffer); + +#endif /* __BLI_BUFFER_H__ */ diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h index c71463da61d..3831ec3cbb4 100644 --- a/source/blender/blenlib/BLI_math_color.h +++ b/source/blender/blenlib/BLI_math_color.h @@ -100,6 +100,13 @@ MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[ void BLI_init_srgb_conversion(void); +/**************** Alpha Transformations *****************/ + +MINLINE void premul_to_straight_v4(float straight[4], const float premul[4]); +MINLINE void straight_to_premul_v4(float straight[4], const float premul[4]); +MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]); +MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4]); + /************************** Other *************************/ int constrain_rgb(float *r, float *g, float *b); diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 423765bad3d..b322d9d7aef 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -72,6 +72,9 @@ float closest_to_line_v2(float r[2], const float p[2], const float l1[2], const void closest_to_line_segment_v3(float r[3], const float p[3], const float l1[3], const float l2[3]); void closest_to_plane_v3(float r[3], const float plane_co[3], const float plane_no_unit[3], const float pt[3]); +/* Set 'r' to the point in triangle (t1, t2, t3) closest to point 'p' */ +void closest_on_tri_to_point_v3(float r[3], const float p[3], const float t1[3], const float t2[3], const float t3[3]); + float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3]); float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2]); @@ -262,6 +265,8 @@ void axis_dominant_v3(int *axis_a, int *axis_b, const float axis[3]); MINLINE int max_axis_v3(const float vec[3]); MINLINE int min_axis_v3(const float vec[3]); +MINLINE int poly_to_tri_count(const int poly_count, const int corner_count); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 557ecb3dd0c..8c51c925d97 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -120,7 +120,11 @@ int BLI_split_name_num(char *left, int *nr, const char *name, const char delim); void BLI_splitdirstring(char *di, char *fi); /* make sure path separators conform to system one */ -void BLI_clean(char *path); +void BLI_clean(char *path) +#ifdef __GNUC__ +__attribute__((nonnull(1))) +#endif +; /** * dir can be any input, like from buttons, and this function @@ -173,7 +177,11 @@ int BLI_path_is_rel(const char *path); * \a from The character to replace * \a to The character to replace with */ -void BLI_char_switch(char *string, char from, char to); +void BLI_char_switch(char *string, char from, char to) +#ifdef __GNUC__ +__attribute__((nonnull(1))) +#endif +; /* Initialize path to program executable */ void BLI_init_program_path(const char *argv0); diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h index c8fd72bbbd2..5204e0dd718 100644 --- a/source/blender/blenlib/BLI_scanfill.h +++ b/source/blender/blenlib/BLI_scanfill.h @@ -101,6 +101,10 @@ enum { * Assumes ordered edges, otherwise we risk an eternal loop * removing double verts. - campbell */ BLI_SCANFILL_CALC_REMOVE_DOUBLES = (1 << 1), + + /* note: This flag removes checks for overlapping polygons. + * when this flag is set, we'll never get back more faces then (totvert - 2)*/ + BLI_SCANFILL_CALC_HOLES = (1 << 2) }; int BLI_scanfill_begin(ScanFillContext *sf_ctx); diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index 7c3b70545d6..cb30138c4f9 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -32,12 +32,37 @@ * \ingroup bli */ -#ifndef FALSE -# define FALSE 0 +/* note: use of (int, TRUE / FALSE) is deprecated, + * use (bool, true / false) instead */ +#ifdef HAVE_STDBOOL_H +# include +#else +# ifndef HAVE__BOOL +# ifdef __cplusplus +typedef bool _BLI_Bool; +# else +# define _BLI_Bool signed char +# endif +# else +# define _BLI_Bool _Bool +# endif +# define bool _BLI_Bool +# define false 0 +# define true 1 +# define __bool_true_false_are_defined 1 #endif -#ifndef TRUE -# define TRUE 1 +/* remove this when we're ready to remove TRUE/FALSE completely */ +#ifdef WITH_BOOL_COMPAT +/* interim until all occurrences of these can be updated to stdbool */ +/* XXX Why not use the true/false velues here? */ +# ifndef FALSE +# define FALSE 0 +# endif + +# ifndef TRUE +# define TRUE 1 +# endif #endif /* useful for finding bad use of min/max */ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index fe954fb10ac..f438e6bdec3 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -48,6 +48,7 @@ set(SRC intern/BLI_mempool.c intern/DLRB_tree.c intern/boxpack2d.c + intern/buffer.c intern/callbacks.c intern/cpu.c intern/dynlib.c @@ -96,6 +97,7 @@ set(SRC BLI_array.h BLI_bitmap.h BLI_blenlib.h + BLI_buffer.h BLI_boxpack2d.h BLI_callbacks.h BLI_cpu.h diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 55f67cedfc6..b2d07b9ee4d 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -1554,7 +1554,7 @@ int BLI_bvhtree_ray_cast(BVHTree *tree, const float co[3], const float dir[3], f float BLI_bvhtree_bb_raycast(const float bv[6], const float light_start[3], const float light_end[3], float pos[3]) { BVHRayCastData data; - float dist = 0.0; + float dist; data.hit.dist = FLT_MAX; diff --git a/source/blender/blenlib/intern/buffer.c b/source/blender/blenlib/intern/buffer.c new file mode 100644 index 00000000000..b2280b9a0d1 --- /dev/null +++ b/source/blender/blenlib/intern/buffer.c @@ -0,0 +1,81 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_buffer.h" +#include "BLI_utildefines.h" + +#include + +static void *buffer_alloc(BLI_Buffer *buffer, int len) +{ + return ((buffer->flag & BLI_BUFFER_USE_CALLOC) ? + MEM_callocN : MEM_mallocN) + (buffer->elem_size * len, "BLI_Buffer.data"); +} + +static void *buffer_realloc(BLI_Buffer *buffer, int len) +{ + return ((buffer->flag & BLI_BUFFER_USE_CALLOC) ? + MEM_recallocN : MEM_reallocN) + (buffer->data, (buffer->elem_size * len)); +} + +void BLI_buffer_resize(BLI_Buffer *buffer, int new_count) +{ + if (new_count > buffer->alloc_count) { + if (buffer->flag & BLI_BUFFER_USE_STATIC) { + void *orig = buffer->data; + + buffer->data = buffer_alloc(buffer, new_count); + memcpy(buffer->data, orig, buffer->elem_size * buffer->count); + buffer->alloc_count = new_count; + buffer->flag &= ~BLI_BUFFER_USE_STATIC; + } + else { + if (buffer->alloc_count && (new_count < buffer->alloc_count * 2)) { + buffer->alloc_count *= 2; + } + else { + buffer->alloc_count = new_count; + } + + if (buffer->data) { + buffer->data = buffer_realloc(buffer, buffer->alloc_count); + } + else { + buffer->data = buffer_alloc(buffer, buffer->alloc_count); + } + } + } + + buffer->count = new_count; +} + +void BLI_buffer_free(BLI_Buffer *buffer) +{ + if ((buffer->flag & BLI_BUFFER_USE_STATIC) == 0) { + if (buffer->data) { + MEM_freeN(buffer->data); + } + } + memset(buffer, 0, sizeof(*buffer)); +} diff --git a/source/blender/blenlib/intern/jitter.c b/source/blender/blenlib/intern/jitter.c index 6203a98828b..3fe0ef158df 100644 --- a/source/blender/blenlib/intern/jitter.c +++ b/source/blender/blenlib/intern/jitter.c @@ -165,7 +165,7 @@ void BLI_jitter_init(float *jitarr, int num) MEM_freeN(jit2); - /* finally, move jittertab to be centered around (0,0) */ + /* finally, move jittertab to be centered around (0, 0) */ for (i = 0; i < 2 * num; i += 2) { jitarr[i] -= 0.5f; jitarr[i + 1] -= 0.5f; diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index 4c8bd43ef73..b8eeca50db6 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -149,31 +149,6 @@ MINLINE void linearrgb_to_srgb_ushort4(unsigned short srgb[4], const float linea srgb[3] = FTOUSHORT(linear[3]); } -MINLINE void linearrgb_to_srgb_ushort4_predivide(unsigned short srgb[4], const float linear[4]) -{ - float alpha, inv_alpha, t; - int i; - - if (linear[3] == 1.0f || linear[3] == 0.0f) { - linearrgb_to_srgb_ushort4(srgb, linear); - return; - } - - alpha = linear[3]; - inv_alpha = 1.0f / alpha; - - for (i = 0; i < 3; ++i) { - t = linear[i] * inv_alpha; - srgb[i] = (t <= 1.0f) ? - /* warning - converts: float -> short -> float -> short */ - (unsigned short) (to_srgb_table_lookup(t) * alpha) : - /* if FTOUSHORT was an inline function this could be done less confusingly */ - ((t = linearrgb_to_srgb(t) * alpha), FTOUSHORT(t)); - } - - srgb[3] = FTOUSHORT(linear[3]); -} - MINLINE void srgb_to_linearrgb_uchar4(float linear[4], const unsigned char srgb[4]) { linear[0] = BLI_color_from_srgb_table[srgb[0]]; @@ -293,4 +268,62 @@ MINLINE int compare_rgb_uchar(const unsigned char col_a[3], const unsigned char return 0; } +/**************** Alpha Transformations *****************/ + +MINLINE void premul_to_straight_v4(float straight[4], const float premul[4]) +{ + if (premul[3] == 0.0f || premul[3] == 1.0f) { + straight[0] = premul[0]; + straight[1] = premul[1]; + straight[2] = premul[2]; + straight[3] = premul[3]; + } + else { + float alpha_inv = 1.0f / premul[3]; + straight[0] = premul[0] * alpha_inv; + straight[1] = premul[1] * alpha_inv; + straight[2] = premul[2] * alpha_inv; + straight[3] = premul[3]; + } +} + +MINLINE void straight_to_premul_v4(float premul[4], const float straight[4]) +{ + float alpha = straight[3]; + premul[0] = straight[0] * alpha; + premul[1] = straight[1] * alpha; + premul[2] = straight[2] * alpha; + premul[3] = straight[3]; +} + +MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]) +{ + float alpha = color[3] / 255.0f; + float fac = alpha / 255.0f; + + result[0] = color[0] * fac; + result[1] = color[1] * fac; + result[2] = color[2] * fac; + result[3] = alpha; +} + +MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4]) +{ + if (color[3] == 0.0f || color[3] == 1.0f) { + result[0] = FTOCHAR(color[0]); + result[1] = FTOCHAR(color[1]); + result[2] = FTOCHAR(color[2]); + result[3] = FTOCHAR(color[3]); + } + else { + float alpha_inv = 1.0f / color[3]; + + /* hopefully this would be optimized */ + result[0] = FTOCHAR(color[0] * alpha_inv); + result[1] = FTOCHAR(color[1] * alpha_inv); + result[2] = FTOCHAR(color[2] * alpha_inv); + result[3] = FTOCHAR(color[3]); + } +} + #endif /* __MATH_COLOR_INLINE_C__ */ diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 10a9a2df9f5..3527af365ec 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -296,6 +296,88 @@ float dist_to_line_segment_v3(const float v1[3], const float v2[3], const float return len_v3v3(closest, v1); } +/* Adapted from "Real-Time Collision Detection" by Christer Ericson, + * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. + * + * Set 'r' to the point in triangle (a, b, c) closest to point 'p' */ +void closest_on_tri_to_point_v3(float r[3], const float p[3], + const float a[3], const float b[3], const float c[3]) +{ + float ab[3], ac[3], ap[3], d1, d2; + float bp[3], d3, d4, vc, cp[3], d5, d6, vb, va; + float denom, v, w; + + /* Check if P in vertex region outside A */ + sub_v3_v3v3(ab, b, a); + sub_v3_v3v3(ac, c, a); + sub_v3_v3v3(ap, p, a); + d1 = dot_v3v3(ab, ap); + d2 = dot_v3v3(ac, ap); + if (d1 <= 0.0f && d2 <= 0.0f) { + /* barycentric coordinates (1,0,0) */ + copy_v3_v3(r, a); + return; + } + + /* Check if P in vertex region outside B */ + sub_v3_v3v3(bp, p, b); + d3 = dot_v3v3(ab, bp); + d4 = dot_v3v3(ac, bp); + if (d3 >= 0.0f && d4 <= d3) { + /* barycentric coordinates (0,1,0) */ + copy_v3_v3(r, b); + return; + } + /* Check if P in edge region of AB, if so return projection of P onto AB */ + vc = d1*d4 - d3*d2; + if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) { + float v = d1 / (d1 - d3); + /* barycentric coordinates (1-v,v,0) */ + madd_v3_v3v3fl(r, a, ab, v); + return; + } + /* Check if P in vertex region outside C */ + sub_v3_v3v3(cp, p, c); + d5 = dot_v3v3(ab, cp); + d6 = dot_v3v3(ac, cp); + if (d6 >= 0.0f && d5 <= d6) { + /* barycentric coordinates (0,0,1) */ + copy_v3_v3(r, c); + return; + } + /* Check if P in edge region of AC, if so return projection of P onto AC */ + vb = d5*d2 - d1*d6; + if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) { + float w = d2 / (d2 - d6); + /* barycentric coordinates (1-w,0,w) */ + madd_v3_v3v3fl(r, a, ac, w); + return; + } + /* Check if P in edge region of BC, if so return projection of P onto BC */ + va = d3*d6 - d5*d4; + if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) { + float w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); + /* barycentric coordinates (0,1-w,w) */ + sub_v3_v3v3(r, c, b); + mul_v3_fl(r, w); + add_v3_v3(r, b); + return; + } + + /* P inside face region. Compute Q through its barycentric coordinates (u,v,w) */ + denom = 1.0f / (va + vb + vc); + v = vb * denom; + w = vc * denom; + + /* = u*a + v*b + w*c, u = va * denom = 1.0f - v - w */ + /* ac * w */ + mul_v3_fl(ac, w); + /* a + ab * v */ + madd_v3_v3v3fl(r, a, ab, v); + /* a + ab * v + ac * w */ + add_v3_v3(r, ac); +} + /******************************* Intersection ********************************/ /* intersect Line-Line, shorts */ @@ -1037,7 +1119,7 @@ int isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const flo if (t0 > 1.0f || t1 < 0.0f) return 0; - /* clamp to [0,1] */ + /* clamp to [0, 1] */ CLAMP(t0, 0.0f, 1.0f); CLAMP(t1, 0.0f, 1.0f); @@ -1157,10 +1239,10 @@ int isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const flo } /*e3*/ - /* sub_v3_v3v3(bv,v0,p1); */ /* UNUSED */ - /* elen2 = dot_v3v3(e1,e1); */ /* UNUSED */ - /* edotv = dot_v3v3(e1,vel); */ /* UNUSED */ - /* edotbv = dot_v3v3(e1,bv); */ /* UNUSED */ + /* sub_v3_v3v3(bv, v0, p1); */ /* UNUSED */ + /* elen2 = dot_v3v3(e1, e1); */ /* UNUSED */ + /* edotv = dot_v3v3(e1, vel); */ /* UNUSED */ + /* edotbv = dot_v3v3(e1, bv); */ /* UNUSED */ sub_v3_v3v3(bv, v1, p1); elen2 = dot_v3v3(e3, e3); @@ -1195,7 +1277,7 @@ int isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3] int a0 = axis, a1 = (axis + 1) % 3, a2 = (axis + 2) % 3; #if 0 - return isect_line_tri_v3(p1,p2,v0,v1,v2,lambda); + return isect_line_tri_v3(p1, p2, v0, v1, v2, lambda); /* first a simple bounding box test */ if (min_fff(v0[a1], v1[a1], v2[a1]) > p1[a1]) return 0; @@ -1415,8 +1497,8 @@ int isect_ray_aabb(const IsectRayAABBData *data, const float bb_min[3], return TRUE; } -/* find closest point to p on line through l1,l2 and return lambda, - * where (0 <= lambda <= 1) when cp is in the line segment l1,l2 +/* find closest point to p on line through (l1, l2) and return lambda, + * where (0 <= lambda <= 1) when cp is in the line segment (l1, l2) */ float closest_to_line_v3(float cp[3], const float p[3], const float l1[3], const float l2[3]) { @@ -1702,9 +1784,9 @@ static int point_in_slice(const float p[3], const float v1[3], const float l1[3] /* * what is a slice ? * some maths: - * a line including l1,l2 and a point not on the line + * a line including (l1, l2) and a point not on the line * define a subset of R3 delimited by planes parallel to the line and orthogonal - * to the (point --> line) distance vector,one plane on the line one on the point, + * to the (point --> line) distance vector, one plane on the line one on the point, * the room inside usually is rather small compared to R3 though still infinite * useful for restricting (speeding up) searches * e.g. all points of triangular prism are within the intersection of 3 'slices' @@ -2304,7 +2386,7 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[ } } -/* (x1,v1)(t1=0)------(x2,v2)(t2=1), 0 (x,v)(t) */ +/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0 (x, v)(t) */ void interp_cubic_v3(float x[3], float v[3], const float x1[3], const float v1[3], const float x2[3], const float v2[3], const float t) { float a[3], b[3]; @@ -2791,8 +2873,8 @@ void tangent_from_uv(float uv1[2], float uv2[2], float uv3[3], float co1[3], flo /****************************** Vector Clouds ********************************/ /* vector clouds */ -/* void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight,float (*rpos)[3], float *rweight, - * float lloc[3],float rloc[3],float lrot[3][3],float lscale[3][3]) +/* void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, float (*rpos)[3], float *rweight, + * float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3]) * * input * ( @@ -2881,9 +2963,9 @@ void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, fl /* build 'projection' matrix */ for (a = 0; a < list_size; a++) { sub_v3_v3v3(va, rpos[a], accu_rcom); - /* mul_v3_fl(va,bp->mass); mass needs renormalzation here ?? */ + /* mul_v3_fl(va, bp->mass); mass needs renormalzation here ?? */ sub_v3_v3v3(vb, pos[a], accu_com); - /* mul_v3_fl(va,rp->mass); */ + /* mul_v3_fl(va, rp->mass); */ m[0][0] += va[0] * vb[0]; m[0][1] += va[0] * vb[1]; m[0][2] += va[0] * vb[2]; diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c index ba9770e1bd1..f32b477787b 100644 --- a/source/blender/blenlib/intern/math_geom_inline.c +++ b/source/blender/blenlib/intern/math_geom_inline.c @@ -158,4 +158,31 @@ MINLINE int min_axis_v3(const float vec[3]) ((y < z) ? 1 : 2)); } +/** + * Simple method to find how many tri's we need when we already know the corner+poly count. + * + * Formula is: + * + * tri = ((corner_count / poly_count) - 2) * poly_count; + * + * Use doubles since this is used for allocating and we + * don't want float precision to give incorrect results. + * + * \param poly_count The number of ngon's/tris (1-2 sided faces will give incorrect results) + * \param corner_count - also known as loops in BMesh/DNA + */ +MINLINE int poly_to_tri_count(const int poly_count, const int corner_count) +{ + if (poly_count != 0) { + const double poly_count_d = (double)poly_count; + const double corner_count_d = (double)corner_count; + BLI_assert(poly_count > 0); + BLI_assert(corner_count > 0); + return (int)((((corner_count_d / poly_count_d) - 2.0) * poly_count_d) + 0.5); + } + else { + return 0; + } +} + #endif /* __MATH_GEOM_INLINE_C__ */ diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 3a294769eb3..02fc5b07d6d 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -990,7 +990,7 @@ void normalize_m4_m4(float rmat[4][4], float mat[4][4]) if (len != 0.0f) rmat[2][3] = mat[2][3] / len; } -void adjoint_m2_m2(float m1[][2], float m[][2]) +void adjoint_m2_m2(float m1[2][2], float m[2][2]) { BLI_assert(m1 != m); m1[0][0] = m[1][1]; diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 04b9d574347..8c62fdf81a7 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -461,7 +461,7 @@ MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3]) r[2] = v1[2] * v2[2]; } -MINLINE void negate_v2(float r[3]) +MINLINE void negate_v2(float r[2]) { r[0] = -r[0]; r[1] = -r[1]; diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 7c1842b10f2..06b1f1f09b1 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1212,8 +1212,6 @@ void BLI_setenv_if_new(const char *env, const char *val) void BLI_clean(char *path) { - if (path == NULL) return; - #ifdef WIN32 if (path && BLI_strnlen(path, 3) > 2) { BLI_char_switch(path + 2, '/', '\\'); @@ -1225,7 +1223,6 @@ void BLI_clean(char *path) void BLI_char_switch(char *string, char from, char to) { - if (string == NULL) return; while (*string != 0) { if (*string == from) *string = to; string++; @@ -1622,7 +1619,7 @@ int BLI_rebase_path(char *abs, size_t abs_len, char *rel, size_t rel_len, const rel_dir[0] = 0; /* if image is "below" current .blend file directory */ - if (!strncmp(path, blend_dir, len)) { + if (!BLI_path_ncmp(path, blend_dir, len)) { /* if image is _in_ current .blend file directory */ if (BLI_path_cmp(dir, blend_dir) == 0) { diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c index defe500cb21..771295b4b78 100644 --- a/source/blender/blenlib/intern/scanfill.c +++ b/source/blender/blenlib/intern/scanfill.c @@ -459,7 +459,7 @@ static void testvertexnearedge(ScanFillContext *sf_ctx) /* new edge */ ed1 = BLI_scanfill_edge_add(sf_ctx, eed->v1, eve); - /* printf("fill: vertex near edge %x\n",eve); */ + /* printf("fill: vertex near edge %x\n", eve); */ ed1->f = 0; ed1->poly_nr = eed->poly_nr; eed->v1 = eve; @@ -630,11 +630,16 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) /* (temporal) security: never much more faces than vertices */ totface = 0; - maxface = 2 * verts; /* 2*verts: based at a filled circle within a triangle */ + if (flag & BLI_SCANFILL_CALC_HOLES) { + maxface = 2 * verts; /* 2*verts: based at a filled circle within a triangle */ + } + else { + maxface = verts - 2; /* when we don't calc any holes, we assume face is a non overlapping loop */ + } sc = sf_ctx->_scdata; for (a = 0; a < verts; a++) { - /* printf("VERTEX %d %x\n",a,sc->v1); */ + /* printf("VERTEX %d %x\n", a, sc->v1); */ ed1 = sc->edge_first; while (ed1) { /* set connectflags */ nexted = ed1->next; @@ -654,7 +659,7 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) /* commented out... the ESC here delivers corrupted memory (and doesnt work during grab) */ /* if (callLocalInterruptCallBack()) break; */ - if (totface > maxface) { + if (totface >= maxface) { /* printf("Fill error: endless loop. Escaped at vert %d, tot: %d.\n", a, verts); */ a = verts; break; @@ -675,30 +680,31 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) v3 = ed2->v2; /* this happens with a serial of overlapping edges */ if (v1 == v2 || v2 == v3) break; - /* printf("test verts %x %x %x\n",v1,v2,v3); */ + /* printf("test verts %x %x %x\n", v1, v2, v3); */ miny = min_ff(v1->xy[1], v3->xy[1]); - /* miny = min_ff(v1->xy[1],v3->xy[1]); */ + /* miny = min_ff(v1->xy[1], v3->xy[1]); */ sc1 = sc + 1; test = 0; for (b = a + 1; b < verts; b++) { if (sc1->vert->f == 0) { if (sc1->vert->xy[1] <= miny) break; - - if (testedgeside(v1->xy, v2->xy, sc1->vert->xy)) - if (testedgeside(v2->xy, v3->xy, sc1->vert->xy)) + if (testedgeside(v1->xy, v2->xy, sc1->vert->xy)) { + if (testedgeside(v2->xy, v3->xy, sc1->vert->xy)) { if (testedgeside(v3->xy, v1->xy, sc1->vert->xy)) { /* point in triangle */ - + test = 1; break; } + } + } } sc1++; } if (test) { /* make new edge, and start over */ - /* printf("add new edge %x %x and start again\n",v2,sc1->vert); */ + /* printf("add new edge %x %x and start again\n", v2, sc1->vert); */ ed3 = BLI_scanfill_edge_add(sf_ctx, v2, sc1->vert); BLI_remlink(&sf_ctx->filledgebase, ed3); @@ -710,7 +716,7 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) } else { /* new triangle */ - /* printf("add face %x %x %x\n",v1,v2,v3); */ + /* printf("add face %x %x %x\n", v1, v2, v3); */ addfillface(sf_ctx, v1, v2, v3); totface++; BLI_remlink((ListBase *)&(sc->edge_first), ed1); @@ -734,7 +740,7 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) ed3->v1->h++; ed3->v2->h++; - /* printf("add new edge %x %x\n",v1,v3); */ + /* printf("add new edge %x %x\n", v1, v3); */ sc1 = addedgetoscanlist(sf_ctx, ed3, verts); if (sc1) { /* ed3 already exists: remove if a boundary */ @@ -773,12 +779,15 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag) ed1 = nexted; } } + sc++; } MEM_freeN(sf_ctx->_scdata); sf_ctx->_scdata = NULL; + BLI_assert(totface <= maxface); + return totface; } @@ -910,50 +919,68 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float no /* STEP 1: COUNT POLYS */ - eve = sf_ctx->fillvertbase.first; - while (eve) { - eve->xy[0] = eve->co[co_x]; - eve->xy[1] = eve->co[co_y]; + if (flag & BLI_SCANFILL_CALC_HOLES) { + eve = sf_ctx->fillvertbase.first; + while (eve) { + eve->xy[0] = eve->co[co_x]; + eve->xy[1] = eve->co[co_y]; - /* get first vertex with no poly number */ - if (eve->poly_nr == 0) { - poly++; - /* now a sort of select connected */ - ok = 1; - eve->poly_nr = poly; - - while (ok) { - - ok = 0; - toggle++; - if (toggle & 1) eed = sf_ctx->filledgebase.first; - else eed = sf_ctx->filledgebase.last; + /* get first vertex with no poly number */ + if (eve->poly_nr == 0) { + poly++; + /* now a sort of select connected */ + ok = 1; + eve->poly_nr = poly; - while (eed) { - if (eed->v1->poly_nr == 0 && eed->v2->poly_nr == poly) { - eed->v1->poly_nr = poly; - eed->poly_nr = poly; - ok = 1; - } - else if (eed->v2->poly_nr == 0 && eed->v1->poly_nr == poly) { - eed->v2->poly_nr = poly; - eed->poly_nr = poly; - ok = 1; - } - else if (eed->poly_nr == 0) { - if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) { + while (ok) { + + ok = 0; + toggle++; + if (toggle & 1) eed = sf_ctx->filledgebase.first; + else eed = sf_ctx->filledgebase.last; + + while (eed) { + if (eed->v1->poly_nr == 0 && eed->v2->poly_nr == poly) { + eed->v1->poly_nr = poly; eed->poly_nr = poly; ok = 1; } + else if (eed->v2->poly_nr == 0 && eed->v1->poly_nr == poly) { + eed->v2->poly_nr = poly; + eed->poly_nr = poly; + ok = 1; + } + else if (eed->poly_nr == 0) { + if (eed->v1->poly_nr == poly && eed->v2->poly_nr == poly) { + eed->poly_nr = poly; + ok = 1; + } + } + if (toggle & 1) eed = eed->next; + else eed = eed->prev; } - if (toggle & 1) eed = eed->next; - else eed = eed->prev; } } + eve = eve->next; + } + /* printf("amount of poly's: %d\n", poly); */ + } + else { + poly = 1; + + eve = sf_ctx->fillvertbase.first; + while (eve) { + eve->xy[0] = eve->co[co_x]; + eve->xy[1] = eve->co[co_y]; + eve->poly_nr = poly; + eve = eve->next; + } + eed = sf_ctx->filledgebase.first; + while (eed) { + eed->poly_nr = poly; + eed = eed->next; } - eve = eve->next; } - /* printf("amount of poly's: %d\n",poly); */ /* STEP 2: remove loose edges and strings of edges */ eed = sf_ctx->filledgebase.first; diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index e9caa337129..b2d37e36004 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -311,6 +311,9 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil /* makes lookup of existing video clips in old main */ blo_make_movieclip_pointer_map(fd, oldmain); + /* makes lookup of existing video clips in old main */ + blo_make_packed_pointer_map(fd, oldmain); + bfd = blo_read_file_internal(fd, filename); /* ensures relinked images are not freed */ @@ -319,6 +322,9 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil /* ensures relinked movie clips are not freed */ blo_end_movieclip_pointer_map(fd, oldmain); + /* ensures relinked packed data is not freed */ + blo_end_packed_pointer_map(fd, oldmain); + /* move libraries from old main to new main */ if (bfd && mainlist.first != mainlist.last) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 4c3ba747906..151a929a445 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -546,7 +546,9 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab BLI_strncpy(name1, filepath, sizeof(name1)); cleanup_path(relabase, name1); -// printf("blo_find_main: original in %s\n", name); + +// printf("blo_find_main: relabase %s\n", relabase); +// printf("blo_find_main: original in %s\n", filepath); // printf("blo_find_main: converted to %s\n", name1); for (m = mainlist->first; m; m = m->next) { @@ -1023,6 +1025,46 @@ FileData *blo_openblenderfile(const char *filepath, ReportList *reports) } } +static int fd_read_gzip_from_memory(FileData *filedata, void *buffer, unsigned int size) +{ + int err; + + filedata->strm.next_out = (Bytef *) buffer; + filedata->strm.avail_out = size; + + // Inflate another chunk. + err = inflate (&filedata->strm, Z_SYNC_FLUSH); + + if (err == Z_STREAM_END) { + return 0; + } + else if (err != Z_OK) { + printf("fd_read_gzip_from_memory: zlib error\n"); + return 0; + } + + filedata->seek += size; + + return (size); +} + +static int fd_read_gzip_from_memory_init(FileData *fd) +{ + + fd->strm.next_in = (Bytef *) fd->buffer; + fd->strm.avail_in = fd->buffersize; + fd->strm.total_out = 0; + fd->strm.zalloc = Z_NULL; + fd->strm.zfree = Z_NULL; + + if (inflateInit2(&fd->strm, (16+MAX_WBITS)) != Z_OK) + return 0; + + fd->read = fd_read_gzip_from_memory; + + return 1; +} + FileData *blo_openblendermemory(void *mem, int memsize, ReportList *reports) { if (!mem || memsizebuffer = mem; fd->buffersize = memsize; + + /* test if gzip */ + if (cp[0] == 0x1f && cp[1] == 0x8b) { + if (0 == fd_read_gzip_from_memory_init(fd)) { + blo_freefiledata(fd); + return NULL; + } + } + else fd->read = fd_read_from_memory; + fd->flags |= FD_FLAGS_NOT_MY_BUFFER; return blo_decode_and_check(fd, reports); @@ -1069,6 +1123,12 @@ void blo_freefiledata(FileData *fd) gzclose(fd->gzfiledes); } + if (fd->strm.next_in) { + if (inflateEnd (&fd->strm) != Z_OK) { + printf("close gzip stream error\n"); + } + } + if (fd->buffer && !(fd->flags & FD_FLAGS_NOT_MY_BUFFER)) { MEM_freeN(fd->buffer); fd->buffer = NULL; @@ -1092,6 +1152,8 @@ void blo_freefiledata(FileData *fd) oldnewmap_free(fd->imamap); if (fd->movieclipmap) oldnewmap_free(fd->movieclipmap); + if (fd->packedmap) + oldnewmap_free(fd->packedmap); if (fd->libmap && !(fd->flags & FD_FLAGS_NOT_MY_LIBMAP)) oldnewmap_free(fd->libmap); if (fd->bheadmap) @@ -1176,6 +1238,14 @@ static void *newmclipadr(FileData *fd, void *adr) /* used to restor return NULL; } +static void *newpackedadr(FileData *fd, void *adr) /* used to restore packed data after undo */ +{ + if (fd->packedmap && adr) + return oldnewmap_lookup_and_inc(fd->packedmap, adr); + + return oldnewmap_lookup_and_inc(fd->datamap, adr); +} + static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */ { @@ -1372,6 +1442,69 @@ void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain) } } +static void insert_packedmap(FileData *fd, PackedFile *pf) +{ + oldnewmap_insert(fd->packedmap, pf, pf, 0); + oldnewmap_insert(fd->packedmap, pf->data, pf->data, 0); +} + +void blo_make_packed_pointer_map(FileData *fd, Main *oldmain) +{ + Image *ima; + VFont *vfont; + bSound *sound; + Library *lib; + + fd->packedmap = oldnewmap_new(); + + for (ima = oldmain->image.first; ima; ima = ima->id.next) + if (ima->packedfile) + insert_packedmap(fd, ima->packedfile); + + for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next) + if (vfont->packedfile) + insert_packedmap(fd, vfont->packedfile); + + for (sound = oldmain->sound.first; sound; sound = sound->id.next) + if (sound->packedfile) + insert_packedmap(fd, sound->packedfile); + + for (lib = oldmain->library.first; lib; lib = lib->id.next) + if (lib->packedfile) + insert_packedmap(fd, lib->packedfile); + +} + +/* set old main packed data to zero if it has been restored */ +/* this works because freeing old main only happens after this call */ +void blo_end_packed_pointer_map(FileData *fd, Main *oldmain) +{ + Image *ima; + VFont *vfont; + bSound *sound; + Library *lib; + OldNew *entry = fd->packedmap->entries; + int i; + + /* used entries were restored, so we put them to zero */ + for (i=0; i < fd->packedmap->nentries; i++, entry++) { + if (entry->nr > 0) + entry->newp = NULL; + } + + for (ima = oldmain->image.first; ima; ima = ima->id.next) + ima->packedfile = newpackedadr(fd, ima->packedfile); + + for (vfont = oldmain->vfont.first; vfont; vfont = vfont->id.next) + vfont->packedfile = newpackedadr(fd, vfont->packedfile); + + for (sound = oldmain->sound.first; sound; sound = sound->id.next) + sound->packedfile = newpackedadr(fd, sound->packedfile); + + for (lib = oldmain->library.first; lib; lib = lib->id.next) + lib->packedfile = newpackedadr(fd, lib->packedfile); +} + /* undo file support: add all library pointers in lookup */ void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd) @@ -1711,10 +1844,10 @@ static void direct_link_script(FileData *UNUSED(fd), Script *script) static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf) { - PackedFile *pf = newdataadr(fd, oldpf); + PackedFile *pf = newpackedadr(fd, oldpf); if (pf) { - pf->data = newdataadr(fd, pf->data); + pf->data = newpackedadr(fd, pf->data); } return pf; @@ -2538,7 +2671,7 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist) cld.fd = fd; cld.id = id; - id_loop_constraints(conlist, lib_link_constraint_cb, &cld); + BKE_id_loop_constraints(conlist, lib_link_constraint_cb, &cld); } static void direct_link_constraints(FileData *fd, ListBase *lb) @@ -5725,6 +5858,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) { Panel *pa; + uiList *ui_list; link_list(fd, &ar->panels); @@ -5735,6 +5869,12 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype) pa->type = NULL; } + link_list(fd, &ar->ui_lists); + + for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) { + ui_list->type = NULL; + } + ar->regiondata = newdataadr(fd, ar->regiondata); if (ar->regiondata) { if (spacetype == SPACE_VIEW3D) { @@ -6057,6 +6197,7 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) { Main *newmain; + /* check if the library was already read */ for (newmain = fd->mainlist->first; newmain; newmain = newmain->next) { if (newmain->curlib) { if (BLI_path_cmp(newmain->curlib->filepath, lib->filepath) == 0) { @@ -6075,14 +6216,14 @@ static void direct_link_library(FileData *fd, Library *lib, Main *main) } } } - /* make sure we have full path in lib->filename */ + /* make sure we have full path in lib->filepath */ BLI_strncpy(lib->filepath, lib->name, sizeof(lib->name)); cleanup_path(fd->relabase, lib->filepath); -#if 0 - printf("direct_link_library: name %s\n", lib->name); - printf("direct_link_library: filename %s\n", lib->filename); -#endif +// printf("direct_link_library: name %s\n", lib->name); +// printf("direct_link_library: filepath %s\n", lib->filepath); + + lib->packedfile = direct_link_packedfile(fd, lib->packedfile); /* new main */ newmain= MEM_callocN(sizeof(Main), "directlink"); @@ -7713,7 +7854,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) for (ob = main->object.first; ob; ob = ob->id.next) { bConstraint *con; for (con = ob->constraints.first; con; con = con->next) { - bConstraintTypeInfo *cti = constraint_get_typeinfo(con); + bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con); if (!cti) continue; @@ -8636,15 +8777,41 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } - { + if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 5)) { Scene *scene; + Image *image; + Tex *tex; for (scene = main->scene.first; scene; scene = scene->id.next) { + Sequence *seq; + + SEQ_BEGIN (scene->ed, seq) + { + if (seq->flag & SEQ_MAKE_PREMUL) + seq->alpha_mode = SEQ_ALPHA_STRAIGHT; + } + SEQ_END + if (scene->r.bake_samples == 0) scene->r.bake_samples = 256; } + + for (image = main->image.first; image; image = image->id.next) { + if (image->flag & IMA_DO_PREMUL) + image->alpha_mode = IMA_ALPHA_STRAIGHT; } + for (tex = main->tex.first; tex; tex = tex->id.next) { + if (tex->type == TEX_IMAGE && (tex->imaflag & TEX_USEALPHA) == 0) { + image = blo_do_versions_newlibadr(fd, tex->id.lib, tex->ima); + + if (image) + image->flag |= IMA_IGNORE_ALPHA; + } + } + } + + #ifdef WITH_FREESTYLE /* default values in Freestyle settings */ { @@ -8759,6 +8926,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) wmKeyMap *keymap; wmKeyMapItem *kmi; wmKeyMapDiffItem *kmdi; + bAddon *addon; bfd->user = user= read_struct(fd, bhead, "user def"); @@ -8797,6 +8965,13 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) direct_link_keymapitem(fd, kmi); } + for (addon = user->addons.first; addon; addon = addon->next) { + addon->prop = newdataadr(fd, addon->prop); + if (addon->prop) { + IDP_DirectLinkProperty(addon->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + } + } + // XXX user->uifonts.first = user->uifonts.last= NULL; @@ -9001,6 +9176,14 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) Library *lib = read_struct(fd, bheadlib, "Library"); Main *ptr = blo_find_main(fd, lib->name, fd->relabase); + if (ptr->curlib == NULL) { + const char *idname= bhead_id_name(fd, bhead); + + BKE_reportf_wrap(fd->reports, RPT_WARNING, TIP_("LIB ERROR: Data refers to main .blend file: '%s' from %s"), + idname, mainvar->curlib->filepath); + return; + } + else id = is_yet_read(fd, ptr, bhead); if (id == NULL) { @@ -9440,7 +9623,7 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb) ced.fd = fd; ced.mainvar = mainvar; - id_loop_constraints(lb, expand_constraint_cb, &ced); + BKE_id_loop_constraints(lb, expand_constraint_cb, &ced); /* deprecated manual expansion stuff */ for (curcon = lb->first; curcon; curcon = curcon->next) { @@ -10299,12 +10482,26 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) FileData *fd = mainptr->curlib->filedata; if (fd == NULL) { + /* printf and reports for now... its important users know this */ + + /* if packed file... */ + if (mainptr->curlib->packedfile) { + PackedFile *pf = mainptr->curlib->packedfile; + + BKE_reportf_wrap(basefd->reports, RPT_INFO, TIP_("Read packed library: '%s'"), + mainptr->curlib->name); + fd = blo_openblendermemory(pf->data, pf->size, basefd->reports); + + + /* needed for library_append and read_libraries */ + BLI_strncpy(fd->relabase, mainptr->curlib->filepath, sizeof(fd->relabase)); + } + else { BKE_reportf_wrap(basefd->reports, RPT_INFO, TIP_("Read library: '%s', '%s'"), mainptr->curlib->filepath, mainptr->curlib->name); - fd = blo_openblenderfile(mainptr->curlib->filepath, basefd->reports); - + } /* allow typing in a new lib path */ if (G.debug_value == -666) { while (fd == NULL) { diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index a979a16220d..a0895c92b24 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -69,6 +69,9 @@ typedef struct FileData { char headerdone; int inbuffer; + // gzip stream for memory decompression + z_stream strm; + // general reading variables struct SDNA *filesdna; struct SDNA *memsdna; @@ -83,6 +86,7 @@ typedef struct FileData { struct OldNewMap *libmap; struct OldNewMap *imamap; struct OldNewMap *movieclipmap; + struct OldNewMap *packedmap; struct BHeadSort *bheadmap; int tot_bheadmap; @@ -127,6 +131,8 @@ void blo_make_image_pointer_map(FileData *fd, Main *oldmain); void blo_end_image_pointer_map(FileData *fd, Main *oldmain); void blo_make_movieclip_pointer_map(FileData *fd, Main *oldmain); void blo_end_movieclip_pointer_map(FileData *fd, Main *oldmain); +void blo_make_packed_pointer_map(FileData *fd, Main *oldmain); +void blo_end_packed_pointer_map(FileData *fd, Main *oldmain); void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd); void blo_freefiledata(FileData *fd); diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 1521739258e..f4d841fd22a 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -292,7 +292,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb) memcpy(&ar->v2d, &soops->v2d, sizeof(View2D)); ar->v2d.scroll &= ~V2D_SCROLL_LEFT; - ar->v2d.scroll |= (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM_O); + ar->v2d.scroll |= (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM); ar->v2d.align = (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_POS_Y); ar->v2d.keepzoom |= (V2D_LOCKZOOM_X|V2D_LOCKZOOM_Y|V2D_KEEPASPECT); ar->v2d.keeptot = V2D_KEEPTOT_STRICT; @@ -415,7 +415,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb) ar->v2d.tot.ymax = ar->winy; ar->v2d.cur = ar->v2d.tot; ar->regiontype = RGN_TYPE_WINDOW; - ar->v2d.scroll = (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM_O); + ar->v2d.scroll = (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM); ar->v2d.align = (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_POS_Y); ar->v2d.keepzoom = (V2D_LOCKZOOM_X|V2D_LOCKZOOM_Y|V2D_LIMITZOOM|V2D_KEEPASPECT); break; diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 8a56e3c2ab8..65a60e11ab3 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -289,11 +289,10 @@ static void ntree_version_245(FileData *fd, Library *lib, bNodeTree *ntree) iuser = node->storage; if (iuser->flag & IMA_OLD_PREMUL) { iuser->flag &= ~IMA_OLD_PREMUL; - iuser->flag |= IMA_DO_PREMUL; } if (iuser->flag & IMA_DO_PREMUL) { image->flag &= ~IMA_OLD_PREMUL; - image->flag |= IMA_DO_PREMUL; + image->alpha_mode = IMA_ALPHA_STRAIGHT; } } } @@ -545,7 +544,7 @@ void blo_do_version_old_trackto_to_constraints(Object *ob) { /* create new trackto constraint from the relationship */ if (ob->track) { - bConstraint *con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO); + bConstraint *con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO); bTrackToConstraint *data = con->data; /* copy tracking settings from the object */ @@ -1840,7 +1839,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) SEQ_BEGIN (sce->ed, seq) { if (seq->type == SEQ_TYPE_IMAGE || seq->type == SEQ_TYPE_MOVIE) - seq->flag |= SEQ_MAKE_PREMUL; + seq->alpha_mode = SEQ_ALPHA_STRAIGHT; } SEQ_END } @@ -2901,20 +2900,19 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main) for (ima = main->image.first; ima; ima = ima->id.next) { if (ima->flag & IMA_OLD_PREMUL) { ima->flag &= ~IMA_OLD_PREMUL; - ima->flag |= IMA_DO_PREMUL; + ima->alpha_mode = IMA_ALPHA_STRAIGHT; } } for (tex = main->tex.first; tex; tex = tex->id.next) { if (tex->iuser.flag & IMA_OLD_PREMUL) { tex->iuser.flag &= ~IMA_OLD_PREMUL; - tex->iuser.flag |= IMA_DO_PREMUL; } ima = blo_do_versions_newlibadr(fd, lib, tex->ima); if (ima && (tex->iuser.flag & IMA_DO_PREMUL)) { ima->flag &= ~IMA_OLD_PREMUL; - ima->flag |= IMA_DO_PREMUL; + ima->alpha_mode = IMA_ALPHA_STRAIGHT; } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 3f80674bf60..b1aee9f498a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -853,8 +853,12 @@ static void write_userdef(WriteData *wd) write_keymapitem(wd, kmi); } - for (bext= U.addons.first; bext; bext=bext->next) + for (bext= U.addons.first; bext; bext=bext->next) { writestruct(wd, DATA, "bAddon", 1, bext); + if (bext->prop) { + IDP_WriteProperty(bext->prop, wd); + } + } for (style= U.uistyles.first; style; style= style->next) { writestruct(wd, DATA, "uiStyle", 1, style); @@ -1231,7 +1235,7 @@ static void write_constraints(WriteData *wd, ListBase *conlist) bConstraint *con; for (con=conlist->first; con; con=con->next) { - bConstraintTypeInfo *cti= constraint_get_typeinfo(con); + bConstraintTypeInfo *cti= BKE_constraint_get_typeinfo(con); /* Write the specific data */ if (cti && con->data) { @@ -1511,7 +1515,7 @@ static void write_vfonts(WriteData *wd, ListBase *idbase) /* direct data */ - if (vf->packedfile) { + if (vf->packedfile && !wd->current) { pf = vf->packedfile; writestruct(wd, DATA, "PackedFile", 1, pf); writedata(wd, DATA, pf->size, pf->data); @@ -1961,7 +1965,7 @@ static void write_images(WriteData *wd, ListBase *idbase) writestruct(wd, ID_IM, "Image", 1, ima); if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd); - if (ima->packedfile) { + if (ima->packedfile && !wd->current) { pf = ima->packedfile; writestruct(wd, DATA, "PackedFile", 1, pf); writedata(wd, DATA, pf->size, pf->data); @@ -2415,6 +2419,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase) for (sa= sc->areabase.first; sa; sa= sa->next) { SpaceLink *sl; Panel *pa; + uiList *ui_list; ARegion *ar; writestruct(wd, DATA, "ScrArea", 1, sa); @@ -2424,6 +2429,9 @@ static void write_screens(WriteData *wd, ListBase *scrbase) for (pa= ar->panels.first; pa; pa= pa->next) writestruct(wd, DATA, "Panel", 1, pa); + + for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) + writestruct(wd, DATA, "uiList", 1, ui_list); } sl= sa->spacedata.first; @@ -2551,20 +2559,31 @@ static void write_libraries(WriteData *wd, Main *main) a=tot= set_listbasepointers(main, lbarray); /* test: is lib being used */ - foundone = FALSE; - while (tot--) { - for (id= lbarray[tot]->first; id; id= id->next) { - if (id->us>0 && (id->flag & LIB_EXTERN)) { - foundone = TRUE; - break; + if (main->curlib && main->curlib->packedfile) + foundone = TRUE; + else { + foundone = FALSE; + while (tot--) { + for (id= lbarray[tot]->first; id; id= id->next) { + if (id->us>0 && (id->flag & LIB_EXTERN)) { + foundone = TRUE; + break; + } } + if (foundone) break; } - if (foundone) break; } - + if (foundone) { writestruct(wd, ID_LI, "Library", 1, main->curlib); + if (main->curlib->packedfile && !wd->current) { + PackedFile *pf = main->curlib->packedfile; + writestruct(wd, DATA, "PackedFile", 1, pf); + writedata(wd, DATA, pf->size, pf->data); + printf("write packed .blend: %s\n", main->curlib->name); + } + while (a--) { for (id= lbarray[a]->first; id; id= id->next) { if (id->us>0 && (id->flag & LIB_EXTERN)) { @@ -2693,7 +2712,7 @@ static void write_sounds(WriteData *wd, ListBase *idbase) writestruct(wd, ID_SO, "bSound", 1, sound); if (sound->id.properties) IDP_WriteProperty(sound->id.properties, wd); - if (sound->packedfile) { + if (sound->packedfile && !wd->current) { pf = sound->packedfile; writestruct(wd, DATA, "PackedFile", 1, pf); writedata(wd, DATA, pf->size, pf->data); diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index f80dbc45926..0606222bb17 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -30,7 +30,7 @@ set(INC ../blenlib ../makesdna ../../../intern/guardedalloc - ../../../extern/bullet2/src + ../../../extern/rangetree ../../../intern/opennl/extern ) @@ -74,6 +74,8 @@ set(SRC intern/bmesh_iterators.c intern/bmesh_iterators.h intern/bmesh_iterators_inline.h + intern/bmesh_log.c + intern/bmesh_log.h intern/bmesh_marking.c intern/bmesh_marking.h intern/bmesh_mesh.c @@ -124,6 +126,9 @@ endif() if(WITH_BULLET) add_definitions(-DWITH_BULLET) + list(APPEND INC_SYS + ${BULLET_INCLUDE_DIRS} + ) endif() if(WITH_INTERNATIONAL) diff --git a/source/blender/bmesh/SConscript b/source/blender/bmesh/SConscript index ee2380084ca..fa6bdbcf26f 100644 --- a/source/blender/bmesh/SConscript +++ b/source/blender/bmesh/SConscript @@ -41,7 +41,9 @@ incs = [ '../blenkernel', '#/intern/guardedalloc', '#/extern/bullet2/src', - '#/intern/opennl/extern', ] + '#/extern/rangetree', + '#/intern/opennl/extern' + ] defs = [] diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index 6257aa4bf3e..60d38719ddb 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -254,6 +254,7 @@ extern "C" { #include "intern/bmesh_core.h" #include "intern/bmesh_interp.h" #include "intern/bmesh_iterators.h" +#include "intern/bmesh_log.h" #include "intern/bmesh_marking.h" #include "intern/bmesh_mesh.h" #include "intern/bmesh_mesh_conv.h" diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 2362ae7237a..5eeee45e7a9 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -173,15 +173,16 @@ void BM_face_copy_shared(BMesh *bm, BMFace *f) */ BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, const int create_flag) { - BMEdge **edges2 = BLI_array_alloca(edges2, len); - BMVert **verts = BLI_array_alloca(verts, len + 1); - int e2_index = 0; - int v_index = 0; + BMEdge **edges_sort = BLI_array_alloca(edges_sort, len); + BMVert **verts_sort = BLI_array_alloca(verts_sort, len + 1); + int esort_index = 0; + int vsort_index = 0; BMFace *f = NULL; BMEdge *e; BMVert *v, *ev1, *ev2; - int i, /* j, */ v1found, reverse; + int i; + bool is_v1_found, is_reverse; /* this code is hideous, yeek. I'll have to think about ways of @@ -189,10 +190,7 @@ BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, i * _and_ the old bmesh_mf functions, so its kindof smashed together * - joeedh */ - if (!len || !v1 || !v2 || !edges || !bm) { - BLI_assert(0); - return NULL; - } + BLI_assert(len && v1 && v2 && edges && bm); /* put edges in correct order */ for (i = 0; i < len; i++) { @@ -209,14 +207,19 @@ BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, i SWAP(BMVert *, ev1, ev2); } - verts[v_index++] = ev1; + verts_sort[vsort_index++] = ev1; v = ev2; e = edges[0]; do { BMEdge *e2 = e; - verts[v_index++] = v; - edges2[e2_index++] = e; + /* vertex array is (len + 1) */ + if (UNLIKELY(vsort_index > len)) { + goto err; /* vertex in loop twice */ + } + + verts_sort[vsort_index++] = v; + edges_sort[esort_index++] = e; /* we only flag the verts to check if they are in the face more then once */ BM_ELEM_API_FLAG_ENABLE(v, _FLAG_MV); @@ -229,66 +232,67 @@ BMFace *BM_face_create_ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, i } } while (e2 != e); - if (e2 == e) + if (UNLIKELY(e2 == e)) { goto err; /* the edges do not form a closed loop */ + } e = e2; } while (e != edges[0]); - if (e2_index != len) { + if (UNLIKELY(esort_index != len)) { goto err; /* we didn't use all edges in forming the boundary loop */ } /* ok, edges are in correct order, now ensure they are going * in the correct direction */ - v1found = reverse = FALSE; + is_v1_found = is_reverse = false; for (i = 0; i < len; i++) { - if (BM_vert_in_edge(edges2[i], v1)) { + if (BM_vert_in_edge(edges_sort[i], v1)) { /* see if v1 and v2 are in the same edge */ - if (BM_vert_in_edge(edges2[i], v2)) { + if (BM_vert_in_edge(edges_sort[i], v2)) { /* if v1 is shared by the *next* edge, then the winding * is incorrect */ - if (BM_vert_in_edge(edges2[(i + 1) % len], v1)) { - reverse = TRUE; + if (BM_vert_in_edge(edges_sort[(i + 1) % len], v1)) { + is_reverse = true; break; } } - v1found = TRUE; + is_v1_found = true; } - if ((v1found == FALSE) && BM_vert_in_edge(edges2[i], v2)) { - reverse = TRUE; + if ((is_v1_found == false) && BM_vert_in_edge(edges_sort[i], v2)) { + is_reverse = true; break; } } - if (reverse) { + if (is_reverse) { for (i = 0; i < len / 2; i++) { - v = verts[i]; - verts[i] = verts[len - i - 1]; - verts[len - i - 1] = v; + v = verts_sort[i]; + verts_sort[i] = verts_sort[len - i - 1]; + verts_sort[len - i - 1] = v; } } for (i = 0; i < len; i++) { - edges2[i] = BM_edge_exists(verts[i], verts[(i + 1) % len]); - if (!edges2[i]) { + edges_sort[i] = BM_edge_exists(verts_sort[i], verts_sort[(i + 1) % len]); + if (UNLIKELY(edges_sort[i] == NULL)) { goto err; } /* check if vert is in face more then once. if the flag is disabled. we've already visited */ - if (!BM_ELEM_API_FLAG_TEST(verts[i], _FLAG_MV)) { + if (UNLIKELY(!BM_ELEM_API_FLAG_TEST(verts_sort[i], _FLAG_MV))) { goto err; } - BM_ELEM_API_FLAG_DISABLE(verts[i], _FLAG_MV); + BM_ELEM_API_FLAG_DISABLE(verts_sort[i], _FLAG_MV); } - f = BM_face_create(bm, verts, edges2, len, create_flag); + f = BM_face_create(bm, verts_sort, edges_sort, len, create_flag); /* clean up flags */ for (i = 0; i < len; i++) { - BM_ELEM_API_FLAG_DISABLE(edges2[i], _FLAG_MF); + BM_ELEM_API_FLAG_DISABLE(edges_sort[i], _FLAG_MF); } return f; @@ -297,8 +301,8 @@ err: for (i = 0; i < len; i++) { BM_ELEM_API_FLAG_DISABLE(edges[i], _FLAG_MF); } - for (i = 0; i < v_index; i++) { - BM_ELEM_API_FLAG_DISABLE(verts[i], _FLAG_MV); + for (i = 0; i < vsort_index; i++) { + BM_ELEM_API_FLAG_DISABLE(verts_sort[i], _FLAG_MV); } return NULL; diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index df58b90bc03..4ec91b8d8d7 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -603,7 +603,7 @@ void BM_loop_interp_from_face(BMesh *bm, BMLoop *target, BMFace *source, { BMLoop *l_iter; BMLoop *l_first; - void **vblocks = BLI_array_alloca(vblocks, do_vertex ? source->len : 0); + void **vblocks = do_vertex ? BLI_array_alloca(vblocks, source->len) : NULL; void **blocks = BLI_array_alloca(blocks, source->len); float (*cos)[3] = BLI_array_alloca(cos, source->len); float *w = BLI_array_alloca(w, source->len); diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c new file mode 100644 index 00000000000..b821c9875db --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_log.c @@ -0,0 +1,962 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_ghash.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_mempool.h" +#include "BLI_utildefines.h" + +#include "BKE_customdata.h" + +#include "bmesh.h" +#include "bmesh_log.h" +#include "range_tree_c_api.h" + +struct BMLogEntry { + struct BMLogEntry *next, *prev; + + /* The following GHashes map from an element ID to one of the log + * types above */ + + /* Elements that were in the previous entry, but have been + * deleted */ + GHash *deleted_verts; + GHash *deleted_faces; + /* Elements that were not in the previous entry, but are in the + * result of this entry */ + GHash *added_verts; + GHash *added_faces; + + /* Vertices whose coordinates, mask value, or hflag have changed */ + GHash *modified_verts; + + BLI_mempool *pool_verts; + BLI_mempool *pool_faces; + + /* This is only needed for dropping BMLogEntries while still in + * dynamic-topology mode, as that should release vert/face IDs + * back to the BMLog but no BMLog pointer is available at that + * time. + * + * This field is not guaranteed to be valid, any use of it should + * check for NULL. */ + BMLog *log; +}; + +struct BMLog { + /* Tree of free IDs */ + struct RangeTreeUInt *unused_ids; + + /* Mapping from unique IDs to vertices and faces + * + * Each vertex and face in the log gets a unique unsigned integer + * assigned. That ID is taken from the set managed by the + * unused_ids range tree. + * + * The ID is needed because element pointers will change as they + * are created and deleted. + */ + GHash *id_to_elem; + GHash *elem_to_id; + + /* All BMLogEntrys, ordered from earliest to most recent */ + ListBase entries; + + /* The current log entry from entries list + * + * If null, then the original mesh from before any of the log + * entries is current (i.e. there is nothing left to undo.) + * + * If equal to the last entry in the entries list, then all log + * entries have been applied (i.e. there is nothing left to redo.) + */ + BMLogEntry *current_entry; +}; + +typedef struct { + float co[3]; + float mask; + char hflag; +} BMLogVert; + +typedef struct { + unsigned int v_ids[3]; +} BMLogFace; + +/************************* Get/set element IDs ************************/ + +/* Get the vertex's unique ID from the log */ +static unsigned int bm_log_vert_id_get(BMLog *log, BMVert *v) +{ + BLI_assert(BLI_ghash_haskey(log->elem_to_id, v)); + return GET_INT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, v)); +} + +/* Set the vertex's unique ID in the log */ +static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id) +{ + void *vid = SET_INT_IN_POINTER(id); + + BLI_ghash_remove(log->id_to_elem, vid, NULL, NULL); + BLI_ghash_insert(log->id_to_elem, vid, v); + BLI_ghash_remove(log->elem_to_id, v, NULL, NULL); + BLI_ghash_insert(log->elem_to_id, v, vid); +} + +/* Get a vertex from its unique ID */ +static BMVert *bm_log_vert_from_id(BMLog *log, unsigned int id) +{ + void *key = SET_INT_IN_POINTER(id); + BLI_assert(BLI_ghash_haskey(log->id_to_elem, key)); + return BLI_ghash_lookup(log->id_to_elem, key); +} + +/* Get the face's unique ID from the log */ +static unsigned int bm_log_face_id_get(BMLog *log, BMFace *f) +{ + BLI_assert(BLI_ghash_haskey(log->elem_to_id, f)); + return GET_INT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, f)); +} + +/* Set the face's unique ID in the log */ +static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id) +{ + void *fid = SET_INT_IN_POINTER(id); + + BLI_ghash_remove(log->id_to_elem, fid, NULL, NULL); + BLI_ghash_insert(log->id_to_elem, fid, f); + BLI_ghash_remove(log->elem_to_id, f, NULL, NULL); + BLI_ghash_insert(log->elem_to_id, f, fid); +} + +/* Get a face from its unique ID */ +static BMFace *bm_log_face_from_id(BMLog *log, unsigned int id) +{ + void *key = SET_INT_IN_POINTER(id); + BLI_assert(BLI_ghash_haskey(log->id_to_elem, key)); + return BLI_ghash_lookup(log->id_to_elem, key); +} + + +/************************ BMLogVert / BMLogFace ***********************/ + +/* Get a vertex's paint-mask value + * + * Returns zero if no paint-mask layer is present */ +static float vert_mask_get(BMesh *bm, BMVert *v) +{ + CustomData *cd = &bm->vdata; + if (CustomData_has_layer(&bm->vdata, CD_PAINT_MASK)) { + float *mask = CustomData_bmesh_get(cd, v->head.data, CD_PAINT_MASK); + return *mask; + } + else { + return 0; + } +} + +/* Set a vertex's paint-mask value + * + * Has no effect is no paint-mask layer is present */ +static void vert_mask_set(BMesh *bm, BMVert *v, float new_mask) +{ + CustomData *cd = &bm->vdata; + if (CustomData_has_layer(cd, CD_PAINT_MASK)) { + float *mask = CustomData_bmesh_get(cd, v->head.data, CD_PAINT_MASK); + (*mask) = new_mask; + } +} + +/* Update a BMLogVert with data from a BMVert */ +static void bm_log_vert_bmvert_copy(BMesh *bm, BMLogVert *lv, BMVert *v) +{ + copy_v3_v3(lv->co, v->co); + lv->mask = vert_mask_get(bm, v); + lv->hflag = v->head.hflag; +} + +/* Allocate and initialize a BMLogVert */ +static BMLogVert *bm_log_vert_alloc(BMesh *bm, BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + BMLogVert *lv = BLI_mempool_alloc(entry->pool_verts); + + bm_log_vert_bmvert_copy(bm, lv, v); + + return lv; +} + +/* Allocate and initialize a BMLogFace */ +static BMLogFace *bm_log_face_alloc(BMLog *log, BMFace *f) +{ + BMLogEntry *entry = log->current_entry; + BMLogFace *lf = BLI_mempool_alloc(entry->pool_faces); + BMVert *v[3]; + + BLI_assert(f->len == 3); + + BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3); + + lf->v_ids[0] = bm_log_vert_id_get(log, v[0]); + lf->v_ids[1] = bm_log_vert_id_get(log, v[1]); + lf->v_ids[2] = bm_log_vert_id_get(log, v[2]); + + return lf; +} + + +/************************ Helpers for undo/redo ***********************/ + +static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts) +{ + GHashIterator gh_iter; + GHASH_ITER (gh_iter, verts) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter); + unsigned int id = GET_INT_FROM_POINTER(key); + BMVert *v = bm_log_vert_from_id(log, id); + + /* Ensure the log has the final values of the vertex before + * deleting it */ + bm_log_vert_bmvert_copy(bm, lv, v); + + BM_vert_kill(bm, v); + } +} + +static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces) +{ + GHashIterator gh_iter; + GHASH_ITER (gh_iter, faces) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + unsigned int id = GET_INT_FROM_POINTER(key); + BMFace *f = bm_log_face_from_id(log, id); + + BM_face_kill(bm, f); + } +} + +static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts) +{ + GHashIterator gh_iter; + GHASH_ITER (gh_iter, verts) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter); + BMVert *v = BM_vert_create(bm, lv->co, NULL, 0); + v->head.hflag = lv->hflag; + vert_mask_set(bm, v, lv->mask); + bm_log_vert_id_set(log, v, GET_INT_FROM_POINTER(key)); + } +} + +static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces) +{ + GHashIterator gh_iter; + GHASH_ITER (gh_iter, faces) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter); + BMVert *v[3] = {bm_log_vert_from_id(log, lf->v_ids[0]), + bm_log_vert_from_id(log, lf->v_ids[1]), + bm_log_vert_from_id(log, lf->v_ids[2])}; + BMFace *f; + + f = BM_face_create_quad_tri_v(bm, v, 3, NULL, FALSE); + bm_log_face_id_set(log, f, GET_INT_FROM_POINTER(key)); + } +} + +static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts) +{ + GHashIterator gh_iter; + GHASH_ITER (gh_iter, verts) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter); + unsigned int id = GET_INT_FROM_POINTER(key); + BMVert *v = bm_log_vert_from_id(log, id); + float mask; + + swap_v3_v3(v->co, lv->co); + SWAP(char, v->head.hflag, lv->hflag); + mask = lv->mask; + lv->mask = vert_mask_get(bm, v); + vert_mask_set(bm, v, mask); + } +} + + +/**********************************************************************/ + +/* Assign unique IDs to all vertices and faces already in the BMesh */ +static void bm_log_assign_ids(BMesh *bm, BMLog *log) +{ + BMIter iter; + BMVert *v; + BMFace *f; + + /* Generate vertex IDs */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + unsigned int id = range_tree_uint_take_any(log->unused_ids); + bm_log_vert_id_set(log, v, id); + } + + /* Generate face IDs */ + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + unsigned int id = range_tree_uint_take_any(log->unused_ids); + bm_log_face_id_set(log, f, id); + } +} + +/* Allocate an empty log entry */ +static BMLogEntry *bm_log_entry_create(void) +{ + BMLogEntry *entry = MEM_callocN(sizeof(BMLogEntry), AT); + + entry->deleted_verts = BLI_ghash_ptr_new(AT); + entry->deleted_faces = BLI_ghash_ptr_new(AT); + entry->added_verts = BLI_ghash_ptr_new(AT); + entry->added_faces = BLI_ghash_ptr_new(AT); + entry->modified_verts = BLI_ghash_ptr_new(AT); + + entry->pool_verts = BLI_mempool_create(sizeof(BMLogVert), 1, 64, 0); + entry->pool_faces = BLI_mempool_create(sizeof(BMLogFace), 1, 64, 0); + + return entry; +} + +/* Free the data in a log entry + * + * Note: does not free the log entry itself */ +static void bm_log_entry_free(BMLogEntry *entry) +{ + BLI_ghash_free(entry->deleted_verts, NULL, NULL); + BLI_ghash_free(entry->deleted_faces, NULL, NULL); + BLI_ghash_free(entry->added_verts, NULL, NULL); + BLI_ghash_free(entry->added_faces, NULL, NULL); + BLI_ghash_free(entry->modified_verts, NULL, NULL); + + BLI_mempool_destroy(entry->pool_verts); + BLI_mempool_destroy(entry->pool_faces); +} + +static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash) +{ + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, id_ghash) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + unsigned int id = GET_INT_FROM_POINTER(key); + + if (range_tree_uint_has(unused_ids, id)) { + range_tree_uint_take(unused_ids, id); + } + } +} + +static int uint_compare(const void *a_v, const void *b_v) +{ + const unsigned int *a = a_v; + const unsigned int *b = b_v; + return (*a) < (*b); +} + +/* Remap IDs to contiguous indices + * + * E.g. if the vertex IDs are (4, 1, 10, 3), the mapping will be: + * 4 -> 2 + * 1 -> 0 + * 10 -> 3 + * 3 -> 1 + */ +static GHash *bm_log_compress_ids_to_indices(unsigned int *ids, int totid) +{ + GHash *map = BLI_ghash_int_new(AT); + int i; + + qsort(ids, totid, sizeof(*ids), uint_compare); + + for (i = 0; i < totid; i++) { + void *key = SET_INT_IN_POINTER(ids[i]); + void *val = SET_INT_IN_POINTER(i); + BLI_ghash_insert(map, key, val); + } + + return map; +} + +/* Release all ID keys in id_ghash */ +static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash) +{ + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, id_ghash) { + void *key = BLI_ghashIterator_getKey(&gh_iter); + unsigned int id = GET_INT_FROM_POINTER(key); + range_tree_uint_release(log->unused_ids, id); + } +} + +/***************************** Public API *****************************/ + +/* Allocate, initialize, and assign a new BMLog */ +BMLog *BM_log_create(BMesh *bm) +{ + BMLog *log = MEM_callocN(sizeof(*log), AT); + + log->unused_ids = range_tree_uint_alloc(0, (unsigned)-1); + log->id_to_elem = BLI_ghash_ptr_new(AT); + log->elem_to_id = BLI_ghash_ptr_new(AT); + + /* Assign IDs to all existing vertices and faces */ + bm_log_assign_ids(bm, log); + + return log; +} + +/* Allocate and initialize a new BMLog using existing BMLogEntries + * + * The 'entry' should be the last entry in the BMLog. Its prev pointer + * will be followed back to find the first entry. + * + * The unused IDs field of the log will be initialized by taking all + * keys from all GHashes in the log entry. + */ +BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry) +{ + BMLog *log = BM_log_create(bm); + + if (entry->prev) + log->current_entry = entry; + else + log->current_entry = NULL; + + /* Let BMLog manage the entry list again */ + log->entries.first = log->entries.last = entry; + if (entry) { + while (entry->prev) { + entry = entry->prev; + log->entries.first = entry; + } + entry = log->entries.last; + while (entry->next) { + entry = entry->next; + log->entries.last = entry; + } + } + + for (entry = log->entries.first; entry; entry = entry->next) { + entry->log = log; + + /* Take all used IDs */ + bm_log_id_ghash_retake(log->unused_ids, entry->deleted_verts); + bm_log_id_ghash_retake(log->unused_ids, entry->deleted_faces); + bm_log_id_ghash_retake(log->unused_ids, entry->added_verts); + bm_log_id_ghash_retake(log->unused_ids, entry->added_faces); + bm_log_id_ghash_retake(log->unused_ids, entry->modified_verts); + } + + return log; +} + +/* Free all the data in a BMLog including the log itself */ +void BM_log_free(BMLog *log) +{ + BMLogEntry *entry; + + if (log->unused_ids) + range_tree_uint_free(log->unused_ids); + + if (log->id_to_elem) + BLI_ghash_free(log->id_to_elem, NULL, NULL); + + if (log->elem_to_id) + BLI_ghash_free(log->elem_to_id, NULL, NULL); + + /* Clear the BMLog references within each entry, but do not free + * the entries themselves */ + for (entry = log->entries.first; entry; entry = entry->next) + entry->log = NULL; + + MEM_freeN(log); +} + +/* Get the number of log entries */ +int BM_log_length(const BMLog *log) +{ + return BLI_countlist(&log->entries); +} + +/* Apply a consistent ordering to BMesh vertices */ +void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log) +{ + void *varr; + void *farr; + + GHash *id_to_idx; + + BMIter bm_iter; + BMVert *v; + BMFace *f; + + int i; + + /* Put all vertex IDs into an array */ + i = 0; + varr = MEM_mallocN(sizeof(int) * bm->totvert, AT); + BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) { + ((unsigned int*)varr)[i++] = bm_log_vert_id_get(log, v); + } + + /* Put all face IDs into an array */ + i = 0; + farr = MEM_mallocN(sizeof(int) * bm->totface, AT); + BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) { + ((unsigned int*)farr)[i++] = bm_log_face_id_get(log, f); + } + + /* Create BMVert index remap array */ + id_to_idx = bm_log_compress_ids_to_indices(varr, bm->totvert); + i = 0; + BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) { + const unsigned id = bm_log_vert_id_get(log, v); + const void *key = SET_INT_IN_POINTER(id); + const void *val = BLI_ghash_lookup(id_to_idx, key); + ((int *)varr)[i++] = GET_INT_FROM_POINTER(val); + } + BLI_ghash_free(id_to_idx, NULL, NULL); + + /* Create BMFace index remap array */ + id_to_idx = bm_log_compress_ids_to_indices(farr, bm->totface); + i = 0; + BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) { + const unsigned id = bm_log_face_id_get(log, f); + const void *key = SET_INT_IN_POINTER(id); + const void *val = BLI_ghash_lookup(id_to_idx, key); + ((int *)farr)[i++] = GET_INT_FROM_POINTER(val); + } + BLI_ghash_free(id_to_idx, NULL, NULL); + + BM_mesh_remap(bm, varr, NULL, farr); + + MEM_freeN(varr); + MEM_freeN(farr); +} + +/* Start a new log entry and update the log entry list + * + * If the log entry list is empty, or if the current log entry is the + * last entry, the new entry is simply appended to the end. + * + * Otherwise, the new entry is added after the current entry and all + * following entries are deleted. + * + * In either case, the new entry is set as the current log entry. + */ +BMLogEntry *BM_log_entry_add(BMLog *log) +{ + BMLogEntry *entry, *next; + + /* Delete any entries after the current one */ + entry = log->current_entry; + if (entry) { + for (entry = entry->next; entry; entry = next) { + next = entry->next; + bm_log_entry_free(entry); + BLI_freelinkN(&log->entries, entry); + } + } + + /* Create and append the new entry */ + entry = bm_log_entry_create(); + BLI_addtail(&log->entries, entry); + entry->log = log; + log->current_entry = entry; + + return entry; +} + +/* Remove an entry from the log + * + * Uses entry->log as the log. If the log is NULL, the entry will be + * free'd but not removed from any list, nor shall its IDs be + * released. + * + * This operation is only valid on the first and last entries in the + * log. Deleting from the middle will assert. + */ +void BM_log_entry_drop(BMLogEntry *entry) +{ + BMLog *log = entry->log; + + if (!log) { + /* Unlink */ + BLI_assert(!(entry->prev && entry->next)); + if (entry->prev) + entry->prev->next = NULL; + else if (entry->next) + entry->next->prev = NULL; + + bm_log_entry_free(entry); + MEM_freeN(entry); + return; + } + + if (!entry->prev) { + /* Release IDs of elements that are deleted by this + * entry. Since the entry is at the beginning of the undo + * stack, and it's being deleted, those elements can never be + * restored. Their IDs can go back into the pool. */ + bm_log_id_ghash_release(log, entry->deleted_faces); + bm_log_id_ghash_release(log, entry->deleted_verts); + } + else if (!entry->next) { + /* Release IDs of elements that are added by this entry. Since + * the entry is at the end of the undo stack, and it's being + * deleted, those elements can never be restored. Their IDs + * can go back into the pool. */ + bm_log_id_ghash_release(log, entry->added_faces); + bm_log_id_ghash_release(log, entry->added_verts); + } + else { + BLI_assert(!"Cannot drop BMLogEntry from middle"); + } + + if (log->current_entry == entry) + log->current_entry = entry->prev; + + bm_log_entry_free(entry); + BLI_freelinkN(&log->entries, entry); +} + +/* Undo one BMLogEntry + * + * Has no effect if there's nothing left to undo */ +void BM_log_undo(BMesh *bm, BMLog *log) +{ + BMLogEntry *entry = log->current_entry; + + if (entry) { + log->current_entry = entry->prev; + + /* Delete added faces and verts */ + bm_log_faces_unmake(bm, log, entry->added_faces); + bm_log_verts_unmake(bm, log, entry->added_verts); + + /* Restore deleted verts and faces */ + bm_log_verts_restore(bm, log, entry->deleted_verts); + bm_log_faces_restore(bm, log, entry->deleted_faces); + + /* Restore vertex coordinates, mask, and hflag */ + bm_log_vert_values_swap(bm, log, entry->modified_verts); + } +} + +/* Redo one BMLogEntry + * + * Has no effect if there's nothing left to redo */ +void BM_log_redo(BMesh *bm, BMLog *log) +{ + BMLogEntry *entry = log->current_entry; + + if (!entry) { + /* Currently at the beginning of the undo stack, move to first entry */ + entry = log->entries.first; + } + else if (entry && entry->next) { + /* Move to next undo entry */ + entry = entry->next; + } + else { + /* Currently at the end of the undo stack, nothing left to redo */ + return; + } + + log->current_entry = entry; + + if (entry) { + /* Re-delete previously deleted faces and verts */ + bm_log_faces_unmake(bm, log, entry->deleted_faces); + bm_log_verts_unmake(bm, log, entry->deleted_verts); + + /* Restore previously added verts and faces */ + bm_log_verts_restore(bm, log, entry->added_verts); + bm_log_faces_restore(bm, log, entry->added_faces); + + /* Restore vertex coordinates, mask, and hflag */ + bm_log_vert_values_swap(bm, log, entry->modified_verts); + } +} + +/* Log a vertex before it is modified + * + * Before modifying vertex coordinates, masks, or hflags, call this + * function to log it's current values. This is better than logging + * after the coordinates have been modified, because only those + * vertices that are modified need to have their original values + * stored. + * + * Handles two separate cases: + * + * If the vertex was added in the current log entry, update the + * vertex in the map of added vertices. + * + * If the vertex already existed prior to the current log entry, a + * seperate key/value map of modified vertices is used (using the + * vertex's ID as the key). The values stored in that case are + * the vertex's original state so that an undo can restore the + * previous state. + * + * On undo, the current vertex state will be swapped with the stored + * state so that a subsequent redo operation will restore the newer + * vertex state. + */ +void BM_log_vert_before_modified(BMesh *bm, BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + BMLogVert *lv; + unsigned int v_id = bm_log_vert_id_get(log, v); + void *key = SET_INT_IN_POINTER(v_id); + + /* Find or create the BMLogVert entry */ + if ((lv = BLI_ghash_lookup(entry->added_verts, key))) { + bm_log_vert_bmvert_copy(bm, lv, v); + } + else if (!BLI_ghash_haskey(entry->modified_verts, key)) { + lv = bm_log_vert_alloc(bm, log, v); + BLI_ghash_insert(entry->modified_verts, key, lv); + } +} + +/* Log a new vertex as added to the BMesh + * + * The new vertex gets a unique ID assigned. It is then added to a map + * of added vertices, with the key being its ID and the value + * containing everything needed to reconstruct that vertex. + */ +void BM_log_vert_added(BMesh *bm, BMLog *log, BMVert *v) +{ + BMLogVert *lv; + unsigned int v_id = range_tree_uint_take_any(log->unused_ids); + void *key = SET_INT_IN_POINTER(v_id); + + bm_log_vert_id_set(log, v, v_id); + lv = bm_log_vert_alloc(bm, log, v); + BLI_ghash_insert(log->current_entry->added_verts, key, lv); +} + +/* Log a new face as added to the BMesh + * + * The new face gets a unique ID assigned. It is then added to a map + * of added faces, with the key being its ID and the value containing + * everything needed to reconstruct that face. + */ +void BM_log_face_added(BMLog *log, BMFace *f) +{ + BMLogFace *lf; + unsigned int f_id = range_tree_uint_take_any(log->unused_ids); + void *key = SET_INT_IN_POINTER(f_id); + + /* Only triangles are supported for now */ + BLI_assert(f->len == 3); + + bm_log_face_id_set(log, f, f_id); + lf = bm_log_face_alloc(log, f); + BLI_ghash_insert(log->current_entry->added_faces, key, lf); +} + +/* Log a vertex as removed from the BMesh + * + * A couple things can happen here: + * + * If the vertex was added as part of the current log entry, then it's + * deleted and forgotten about entirely. Its unique ID is returned to + * the unused pool. + * + * If the vertex was already part of the BMesh before the current log + * entry, it is added to a map of deleted vertices, with the key being + * its ID and the value containing everything needed to reconstruct + * that vertex. + * + * If there's a move record for the vertex, that's used as the + * vertices original location, then the move record is deleted. + */ +void BM_log_vert_removed(BMesh *bm, BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + unsigned int v_id = bm_log_vert_id_get(log, v); + void *key = SET_INT_IN_POINTER(v_id); + + if (BLI_ghash_lookup(entry->added_verts, key)) { + BLI_ghash_remove(entry->added_verts, key, NULL, NULL); + range_tree_uint_release(log->unused_ids, v_id); + } + else { + BMLogVert *lv, *lv_mod; + + lv = bm_log_vert_alloc(bm, log, v); + BLI_ghash_insert(entry->deleted_verts, key, lv); + + /* If the vertex was modified before deletion, ensure that the + * original vertex values are stored */ + if ((lv_mod = BLI_ghash_lookup(entry->modified_verts, key))) { + (*lv) = (*lv_mod); + BLI_ghash_remove(entry->modified_verts, key, NULL, NULL); + } + } +} + +/* Log a face as removed from the BMesh + * + * A couple things can happen here: + * + * If the face was added as part of the current log entry, then it's + * deleted and forgotten about entirely. Its unique ID is returned to + * the unused pool. + * + * If the face was already part of the BMesh before the current log + * entry, it is added to a map of deleted faces, with the key being + * its ID and the value containing everything needed to reconstruct + * that face. + */ +void BM_log_face_removed(BMLog *log, BMFace *f) +{ + BMLogEntry *entry = log->current_entry; + unsigned int f_id = bm_log_face_id_get(log, f); + void *key = SET_INT_IN_POINTER(f_id); + + if (BLI_ghash_lookup(entry->added_faces, key)) { + BLI_ghash_remove(entry->added_faces, key, NULL, NULL); + range_tree_uint_release(log->unused_ids, f_id); + } + else { + BMLogFace *lf; + + lf = bm_log_face_alloc(log, f); + BLI_ghash_insert(entry->deleted_faces, key, lf); + } +} + +/* Log all vertices/faces in the BMesh as added */ +void BM_log_all_added(BMesh *bm, BMLog *log) +{ + BMIter bm_iter; + BMVert *v; + BMFace *f; + + /* Log all vertices as newly created */ + BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) { + BM_log_vert_added(bm, log, v); + } + + /* Log all faces as newly created */ + BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) { + BM_log_face_added(log, f); + } +} + +/* Log all vertices/faces in the BMesh as removed */ +void BM_log_before_all_removed(BMesh *bm, BMLog *log) +{ + BMIter bm_iter; + BMVert *v; + BMFace *f; + + /* Log deletion of all faces */ + BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) { + BM_log_face_removed(log, f); + } + + /* Log deletion of all vertices */ + BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) { + BM_log_vert_removed(bm, log, v); + } +} + +/* Get the logged coordinates of a vertex + * + * Does not modify the log or the vertex */ +const float *BM_log_original_vert_co(BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + const BMLogVert *lv; + unsigned v_id = bm_log_vert_id_get(log, v); + void *key = SET_INT_IN_POINTER(v_id); + + BLI_assert(entry); + + BLI_assert(BLI_ghash_haskey(entry->modified_verts, key)); + + lv = BLI_ghash_lookup(entry->modified_verts, key); + return lv->co; +} + +/* Get the logged mask of a vertex + * + * Does not modify the log or the vertex */ +float BM_log_original_mask(BMLog *log, BMVert *v) +{ + BMLogEntry *entry = log->current_entry; + const BMLogVert *lv; + unsigned v_id = bm_log_vert_id_get(log, v); + void *key = SET_INT_IN_POINTER(v_id); + + BLI_assert(entry); + + BLI_assert(BLI_ghash_haskey(entry->modified_verts, key)); + + lv = BLI_ghash_lookup(entry->modified_verts, key); + return lv->mask; +} + +/************************ Debugging and Testing ***********************/ + +/* For internal use only (unit testing) */ +BMLogEntry *BM_log_current_entry(BMLog *log) +{ + return log->current_entry; +} + +/* For internal use only (unit testing) */ +RangeTreeUInt *BM_log_unused_ids(BMLog *log) +{ + return log->unused_ids; +} + +#if 0 +/* Print the list of entries, marking the current one + * + * Keep around for debugging */ +void bm_log_print(const BMLog *log, const char *description) +{ + const BMLogEntry *entry; + const char *current = " <-- current"; + int i; + + printf("%s:\n", description); + printf(" % 2d: [ initial ]%s\n", 0, + (!log->current_entry) ? current : ""); + for (entry = log->entries.first, i = 1; entry; entry = entry->next, i++) { + printf(" % 2d: [%p]%s\n", i, entry, + (entry == log->current_entry) ? current : ""); + } +} +#endif diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h new file mode 100644 index 00000000000..958ff340b43 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_log.h @@ -0,0 +1,102 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BMESH_LOG_H__ +#define __BMESH_LOG_H__ + +/* The BMLog is an interface for storing undo/redo steps as a BMesh is + * modified. It only stores changes to the BMesh, not full copies. + * + * Currently it supports the following types of changes: + * + * - Adding and removing vertices + * - Adding and removing faces + * - Moving vertices + * - Setting vertex paint-mask values + * - Setting vertex hflags + */ + +struct BMFace; +struct BMVert; +struct BMesh; +struct RangeTreeUInt; + +typedef struct BMLog BMLog; +typedef struct BMLogEntry BMLogEntry; + +/* Allocate and initialize a new BMLog */ +BMLog *BM_log_create(BMesh *bm); + +/* Allocate and initialize a new BMLog using existing BMLogEntries */ +BMLog *BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry); + +/* Free all the data in a BMLog including the log itself */ +void BM_log_free(BMLog *log); + +/* Get the number of log entries */ +int BM_log_length(const BMLog *log); + +/* Apply a consistent ordering to BMesh vertices and faces */ +void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log); + +/* Start a new log entry and update the log entry list */ +BMLogEntry *BM_log_entry_add(BMLog *log); + +/* Remove an entry from the log */ +void BM_log_entry_drop(BMLogEntry *entry); + +/* Undo one BMLogEntry */ +void BM_log_undo(BMesh *bm, BMLog *log); + +/* Redo one BMLogEntry */ +void BM_log_redo(BMesh *bm, BMLog *log); + +/* Log a vertex before it is modified */ +void BM_log_vert_before_modified(BMesh *bm, BMLog *log, struct BMVert *v); + +/* Log a new vertex as added to the BMesh */ +void BM_log_vert_added(BMesh *bm, BMLog *log, struct BMVert *v); + +/* Log a new face as added to the BMesh */ +void BM_log_face_added(BMLog *log, struct BMFace *f); + +/* Log a vertex as removed from the BMesh */ +void BM_log_vert_removed(BMesh *bm, BMLog *log, struct BMVert *v); + +/* Log a face as removed from the BMesh */ +void BM_log_face_removed(BMLog *log, struct BMFace *f); + +/* Log all vertices/faces in the BMesh as added */ +void BM_log_all_added(BMesh *bm, BMLog *log); + +/* Log all vertices/faces in the BMesh as removed */ +void BM_log_before_all_removed(BMesh *bm, BMLog *log); + +/* Get the logged coordinates of a vertex */ +const float *BM_log_original_vert_co(BMLog *log, BMVert *v); + +/* Get the logged mask of a vertex */ +float BM_log_original_mask(BMLog *log, BMVert *v); + +/* For internal use only (unit testing) */ +BMLogEntry *BM_log_current_entry(BMLog *log); +struct RangeTreeUInt *BM_log_unused_ids(BMLog *log); + +#endif diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 3a7a1c4eaaa..8461ec6fe08 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -128,7 +128,7 @@ static BMOpDefine bmo_smooth_laplacian_vert_def = { "smooth_laplacian_vert", /* slots_in */ {{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */ - {"lambda", BMO_OP_SLOT_FLT}, /* lambda param */ + {"lambda_factor", BMO_OP_SLOT_FLT}, /* lambda param */ {"lambda_border", BMO_OP_SLOT_FLT}, /* lambda param in border */ {"use_x", BMO_OP_SLOT_BOOL}, /* Smooth object along X axis */ {"use_y", BMO_OP_SLOT_BOOL}, /* Smooth object along Y axis */ @@ -1403,6 +1403,7 @@ static BMOpDefine bmo_bevel_def = { {{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input edges and vertices */ {"offset", BMO_OP_SLOT_FLT}, /* amount to offset beveled edge */ {"segments", BMO_OP_SLOT_INT}, /* number of segments in bevel */ + {"vertex_only", BMO_OP_SLOT_BOOL}, /* only bevel vertices, not edges */ {{'\0'}}, }, /* slots_out */ diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h index 7df9c94a2f1..b8fbfbee37f 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api.h +++ b/source/blender/bmesh/intern/bmesh_operator_api.h @@ -435,7 +435,7 @@ void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_ * //whether it's a float, pointer, whatever. * // * // so to get a pointer, for example, use: - * // *((void**)BMO_iter_map_value(&oiter)); + * // *((void **)BMO_iter_map_value(&oiter)); * //or something like that. * } * \endcode diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 5f5c60dde3f..b5b6c69bd7e 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -468,13 +468,21 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first) } /** - * Returms edge length + * Returns edge length */ float BM_edge_calc_length(BMEdge *e) { return len_v3v3(e->v1->co, e->v2->co); } +/** + * Returns edge length squared (for comparisons) + */ +float BM_edge_calc_length_squared(BMEdge *e) +{ + return len_squared_v3v3(e->v1->co, e->v2->co); +} + /** * Utility function, since enough times we have an edge * and want to access 2 connected faces. diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 9af792417bf..a9d6719c491 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -37,6 +37,7 @@ int BM_vert_in_edge(BMEdge *e, BMVert *v); int BM_verts_in_edge(BMVert *v1, BMVert *v2, BMEdge *e); float BM_edge_calc_length(BMEdge *e); +float BM_edge_calc_length_squared(BMEdge *e); int BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb); int BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb); BMVert *BM_edge_other_vert(BMEdge *e, BMVert *v); diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index 126d0f46119..eb8e84da63f 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.c @@ -34,6 +34,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) { const float offset = BMO_slot_float_get(op->slots_in, "offset"); const int seg = BMO_slot_int_get(op->slots_in, "segments"); + const int vonly = BMO_slot_bool_get(op->slots_in, "vertex_only"); if (offset > 0) { BMOIter siter; @@ -54,7 +55,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) } } - BM_mesh_bevel(bm, offset, seg); + BM_mesh_bevel(bm, offset, seg, vonly); BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG); } diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index 9a58d7acfb9..f288901c272 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -483,7 +483,7 @@ void bmo_spin_exec(BMesh *bm, BMOperator *op) { BMOperator dupop, extop; float cent[3], dvec[3]; - float axis[3] = {0.0f, 0.0f, 1.0f}; + float axis[3]; float rmat[3][3]; float phi; int steps, do_dupli, a, usedvec; diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index 956d9e5767e..2cca3fcb24a 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -315,27 +315,29 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) /* calculate verts to delete */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - found = FALSE; + if (v->e) { /* only deal with verts attached to geometry [#33651] */ + found = FALSE; - BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, EXT_INPUT) || !BMO_elem_flag_test(bm, e, EXT_DEL)) { - found = TRUE; - break; - } - } - - /* avoid an extra loop */ - if (found == TRUE) { - BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) { + BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) { + if (!BMO_elem_flag_test(bm, e, EXT_INPUT) || !BMO_elem_flag_test(bm, e, EXT_DEL)) { found = TRUE; break; } } - } - if (found == FALSE) { - BMO_elem_flag_enable(bm, v, EXT_DEL); + /* avoid an extra loop */ + if (found == TRUE) { + BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) { + if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) { + found = TRUE; + break; + } + } + } + + if (found == FALSE) { + BMO_elem_flag_enable(bm, v, EXT_DEL); + } } } diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c index 4a367a8fd6f..ce584686757 100644 --- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c +++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c @@ -538,7 +538,7 @@ void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) int i; int m_vertex_id; int usex, usey, usez, preserve_volume; - float lambda, lambda_border; + float lambda_factor, lambda_border; float w; BMOIter siter; BMVert *v; @@ -553,7 +553,7 @@ void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) memset_laplacian_system(sys, 0); BM_mesh_elem_index_ensure(bm, BM_VERT); - lambda = BMO_slot_float_get(op->slots_in, "lambda"); + lambda_factor = BMO_slot_float_get(op->slots_in, "lambda_factor"); lambda_border = BMO_slot_float_get(op->slots_in, "lambda_border"); sys->min_area = 0.00001f; usex = BMO_slot_bool_get(op->slots_in, "use_x"); @@ -592,12 +592,12 @@ void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) i = m_vertex_id; if (sys->zerola[i] == 0) { w = sys->vweights[i] * sys->ring_areas[i]; - sys->vweights[i] = (w == 0.0f) ? 0.0f : -lambda / (4.0f * w); + sys->vweights[i] = (w == 0.0f) ? 0.0f : -lambda_factor / (4.0f * w); w = sys->vlengths[i]; sys->vlengths[i] = (w == 0.0f) ? 0.0f : -lambda_border * 2.0f / w; if (!vert_is_boundary(v)) { - nlMatrixAdd(i, i, 1.0f + lambda / (4.0f * sys->ring_areas[i])); + nlMatrixAdd(i, i, 1.0f + lambda_factor / (4.0f * sys->ring_areas[i])); } else { nlMatrixAdd(i, i, 1.0f + lambda_border * 2.0f); diff --git a/source/blender/bmesh/operators/bmo_symmetrize.c b/source/blender/bmesh/operators/bmo_symmetrize.c index 248c7268ac6..172f0d40b27 100644 --- a/source/blender/bmesh/operators/bmo_symmetrize.c +++ b/source/blender/bmesh/operators/bmo_symmetrize.c @@ -361,6 +361,12 @@ static BMFace *symm_face_create_v(BMesh *bm, BMFace *example, BMFace *f_new; int i; + /* TODO: calling symmetrize in dynamic-topology sculpt mode + * frequently tries to create faces of length less than two, + * should investigate further */ + if (len < 3) + return NULL; + for (i = 0; i < len; i++) { int j = (i + 1) % len; fe[i] = BM_edge_exists(fv[i], fv[j]); @@ -374,6 +380,7 @@ static BMFace *symm_face_create_v(BMesh *bm, BMFace *example, BM_elem_attrs_copy(bm, bm, example, f_new); BM_face_select_set(bm, f_new, TRUE); BMO_elem_flag_enable(bm, f_new, SYMM_OUTPUT_GEOM); + return f_new; } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index fbac538eb7f..759246c38e0 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -119,6 +119,7 @@ typedef struct BevelParams { float offset; /* blender units to offset each side of a beveled edge */ int seg; /* number of segments in beveled edge profile */ + int vertex_only; /* bevel vertices only */ } BevelParams; // #pragma GCC diagnostic ignored "-Wpadded" @@ -166,6 +167,7 @@ static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert { NewVert *nv = mesh_vert(vm, i, j, k); nv->v = BM_vert_create(bm, nv->co, eg, 0); + BM_elem_flag_disable(nv->v, BM_ELEM_TAG); } static void copy_mesh_vert(VMesh *vm, int ito, int jto, int kto, @@ -698,8 +700,9 @@ static void snap_to_edge_profile(EdgeHalf *e, const float va[3], const float vb[ * of a vertex on the the boundary of the beveled vertex bv->v. * Also decide on the mesh pattern that will be used inside the boundary. * Doesn't make the actual BMVerts */ -static void build_boundary(MemArena *mem_arena, BevVert *bv) +static void build_boundary(BevelParams *bp, BevVert *bv) { + MemArena *mem_arena = bp->mem_arena; EdgeHalf *efirst, *e; BoundVert *v; VMesh *vm; @@ -707,9 +710,13 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv) const float *no; float lastd; - e = efirst = next_bev(bv, NULL); vm = bv->vmesh; + if (bp->vertex_only) + e = efirst = &bv->edges[0]; + else + e = efirst = next_bev(bv, NULL); + BLI_assert(bv->edgecount >= 2); /* since bevel edges incident to 2 faces */ if (bv->edgecount == 2 && bv->selcount == 1) { @@ -734,7 +741,7 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv) return; } - lastd = e->offset; + lastd = bp->vertex_only ? bp->offset : e->offset; vm->boundstart = NULL; do { if (e->is_bev) { @@ -1276,7 +1283,7 @@ static void bevel_build_trifan(BMesh *bm, BevVert *bv) else { BLI_assert(0); } } else { - if (l_fan->v == v_fan) { l_fan = l_fan; } + if (l_fan->v == v_fan) { /* l_fan = l_fan; */ } else if (l_fan->next->v == v_fan) { l_fan = l_fan->next; } else if (l_fan->prev->v == v_fan) { l_fan = l_fan->prev; } else { BLI_assert(0); } @@ -1325,8 +1332,9 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv) /* Given that the boundary is built, now make the actual BMVerts * for the boundary and the interior of the vertex mesh. */ -static void build_vmesh(MemArena *mem_arena, BMesh *bm, BevVert *bv) +static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) { + MemArena *mem_arena = bp->mem_arena; VMesh *vm = bv->vmesh; BoundVert *v, *weld1, *weld2; int n, ns, ns2, i, k, weld; @@ -1504,7 +1512,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) */ BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) { - if (BM_elem_flag_test(bme, BM_ELEM_TAG)) { + if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) { BLI_assert(BM_edge_is_manifold(bme)); nsel++; } @@ -1513,7 +1521,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) BM_BEVEL_EDGE_TAG_DISABLE(bme); } - if (nsel == 0) { + if ((nsel == 0 && !bp->vertex_only) || (ntot < 3 && bp->vertex_only)) { /* signal this vert isn't being beveled */ BM_elem_flag_disable(v, BM_ELEM_TAG); return; @@ -1570,7 +1578,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) } bme = e->e; BM_BEVEL_EDGE_TAG_ENABLE(bme); - if (BM_elem_flag_test(bme, BM_ELEM_TAG)) { + if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) { e->is_bev = TRUE; e->seg = bp->seg; } @@ -1626,8 +1634,8 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v) BM_BEVEL_EDGE_TAG_DISABLE(e->e); } - build_boundary(bp->mem_arena, bv); - build_vmesh(bp->mem_arena, bm, bv); + build_boundary(bp, bv); + build_vmesh(bp, bm, bv); } /* Face f has at least one beveled vertex. Rebuild f */ @@ -1790,7 +1798,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) * * \warning all tagged edges _must_ be manifold. */ -void BM_mesh_bevel(BMesh *bm, const float offset, const float segments) +void BM_mesh_bevel(BMesh *bm, const float offset, const float segments, const int vertex_only) { BMIter iter; BMVert *v; @@ -1799,6 +1807,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const float segments) bp.offset = offset; bp.seg = segments; + bp.vertex_only = vertex_only; if (bp.offset > 0) { /* primary alloc */ @@ -1814,9 +1823,11 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const float segments) } /* Build polygons for edges */ - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - bevel_build_edge_polygons(bm, &bp, e); + if (!bp.vertex_only) { + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + bevel_build_edge_polygons(bm, &bp, e); + } } } diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h index a80e4f3a4a2..d56aa13c984 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.h +++ b/source/blender/bmesh/tools/bmesh_bevel.h @@ -27,6 +27,6 @@ * \ingroup bmesh */ -void BM_mesh_bevel(BMesh *bm, const float offset, const float segments); +void BM_mesh_bevel(BMesh *bm, const float offset, const float segments, const int vertex_only); #endif /* __BMESH_BEVEL_H__ */ diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c index acdab2510a4..71c1cedbd5e 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c +++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c @@ -268,7 +268,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const int BMW_end(&walker); #else - BM_elem_index_set(v_first, (offset + depth) % nth ? VERT_INDEX_IGNORE : VERT_INDEX_DO_COLLAPSE); /* set_dirty! */ + BM_elem_index_set(v_first, ((offset + depth) % nth) ? VERT_INDEX_IGNORE : VERT_INDEX_DO_COLLAPSE); /* set_dirty! */ vert_seek_b_tot = 0; vert_seek_b[vert_seek_b_tot++] = v_first; diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 44e74e320cc..3d0ceb560ed 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -1194,7 +1194,7 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vectormtex[i]->texco = TEXCO_UV; ma->mtex[i]->tex = add_texture("Texture"); ma->mtex[i]->tex->type = TEX_IMAGE; - ma->mtex[i]->tex->imaflag &= ~TEX_USEALPHA; ma->mtex[i]->tex->ima = uid_image_map[ima_uid]; texindex_texarray_map[ctex.getTextureMapId()].push_back(ma->mtex[i]); @@ -745,7 +744,6 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); if (mtex != NULL) { mtex->mapto = MAP_ALPHA; - mtex->tex->imaflag |= TEX_USEALPHA; i++; ma->spectra = ma->alpha = 0; ma->mode |= MA_ZTRANSP | MA_TRANSP; diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp index aba290f5ce4..55fe2034869 100644 --- a/source/blender/collada/ImageExporter.cpp +++ b/source/blender/collada/ImageExporter.cpp @@ -89,7 +89,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies) // make absolute destination path BLI_strncpy(export_file, name.c_str(), sizeof(export_file)); - BKE_add_image_extension(export_file, imageFormat.imtype); + BKE_add_image_extension(export_file, &imageFormat); BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file); diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index de8d1e85eb9..8256618bfa3 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -1083,8 +1083,8 @@ void MeshImporter::optimize_material_assignments() Object *ob = (*it); Mesh *me = (Mesh *) ob->data; if (me->id.us==1) { - bc_copy_materials_to_data(ob,me); - bc_remove_materials_from_object(ob,me); + bc_copy_materials_to_data(ob, me); + bc_remove_materials_from_object(ob, me); bc_remove_mark(ob); } else if (me->id.us > 1) @@ -1101,10 +1101,10 @@ void MeshImporter::optimize_material_assignments() } } if (can_move) { - bc_copy_materials_to_data(ref_ob,me); + bc_copy_materials_to_data(ref_ob, me); for (int index = 0; index < mesh_users.size(); index++) { Object *object = mesh_users[index]; - bc_remove_materials_from_object(object,me); + bc_remove_materials_from_object(object, me); bc_remove_mark(object); } } diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index 8259cb6f297..0e8ddf4068c 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -491,10 +491,10 @@ set(SRC operations/COM_ColorMatteOperation.h operations/COM_ChannelMatteOperation.cpp operations/COM_ChannelMatteOperation.h - operations/COM_ConvertPremulToKeyOperation.cpp - operations/COM_ConvertPremulToKeyOperation.h - operations/COM_ConvertKeyToPremulOperation.cpp - operations/COM_ConvertKeyToPremulOperation.h + operations/COM_ConvertPremulToStraightOperation.cpp + operations/COM_ConvertPremulToStraightOperation.h + operations/COM_ConvertStraightToPremulOperation.cpp + operations/COM_ConvertStraightToPremulOperation.h operations/COM_ReadBufferOperation.cpp operations/COM_ReadBufferOperation.h diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index 25f06108d96..9beccba0c73 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -41,7 +41,8 @@ using namespace std; * In order to get to an efficient model for execution, several steps are being done. these steps are explained below. * * @section EM_Step1 Step 1: translating blender node system to the new compsitor system - * Blenders node structure is based on C structs (DNA). These structs are not efficient in the new architecture. We want to use classes in order to simplify the system. + * Blenders node structure is based on C structs (DNA). These structs are not efficient in the new architecture. + * We want to use classes in order to simplify the system. * during this step the blender node_tree is evaluated and converted to a CPP node system. * * @see ExecutionSystem @@ -49,13 +50,17 @@ using namespace std; * @see Node * * @section EM_Step2 Step2: translating nodes to operations - * Ungrouping the GroupNodes. Group nodes are node_tree's in node_tree's. The new system only supports a single level of node_tree. We will 'flatten' the system in a single level. + * Ungrouping the GroupNodes. Group nodes are node_tree's in node_tree's. + * The new system only supports a single level of node_tree. We will 'flatten' the system in a single level. * @see GroupNode * @see ExecutionSystemHelper.ungroup * - * Every node has the ability to convert itself to operations. The node itself is responsible to create a correct NodeOperation setup based on its internal settings. - * Most Node only need to convert it to its NodeOperation. Like a ColorToBWNode doesn't check anything, but replaces itself with a ConvertColorToBWOperation. - * More complex nodes can use different NodeOperation based on settings; like MixNode. based on the selected Mixtype a different operation will be used. + * Every node has the ability to convert itself to operations. The node itself is responsible to create a correct + * NodeOperation setup based on its internal settings. + * Most Node only need to convert it to its NodeOperation. Like a ColorToBWNode doesn't check anything, + * but replaces itself with a ConvertColorToBWOperation. + * More complex nodes can use different NodeOperation based on settings; like MixNode. + * based on the selected Mixtype a different operation will be used. * for more information see the page about creating new Nodes. [@subpage newnode] * * @see ExecutionSystem.convertToOperations @@ -63,9 +68,12 @@ using namespace std; * @see NodeOperation base class for all operations in the system * * @section EM_Step3 Step3: add additional conversions to the operation system - * - Data type conversions: the system has 3 data types COM_DT_VALUE, COM_DT_VECTOR, COM_DT_COLOR. The user can connect a Value socket to a color socket. As values are ordered differently than colors a conversion happens. + * - Data type conversions: the system has 3 data types COM_DT_VALUE, COM_DT_VECTOR, COM_DT_COLOR. + * The user can connect a Value socket to a color socket. + * As values are ordered differently than colors a conversion happens. * - * - Image size conversions: the system can automatically convert when resolutions do not match. An InputSocket has a resize mode. This can be any of the following settings. + * - Image size conversions: the system can automatically convert when resolutions do not match. + * An InputSocket has a resize mode. This can be any of the following settings. * - [@ref InputSocketResizeMode.COM_SC_CENTER]: The center of both images are aligned * - [@ref InputSocketResizeMode.COM_SC_FIT_WIDTH]: The width of both images are aligned * - [@ref InputSocketResizeMode.COM_SC_FIT_HEIGHT]: the height of both images are aligned @@ -77,8 +85,10 @@ using namespace std; * @see Converter.convertResolution Image size conversions * * @section EM_Step4 Step4: group operations in executions groups - * ExecutionGroup are groups of operations that are calculated as being one bigger operation. All operations will be part of an ExecutionGroup. - * Complex nodes will be added to separate groups. Between ExecutionGroup's the data will be stored in MemoryBuffers. ReadBufferOperations and WriteBufferOperations are added where needed. + * ExecutionGroup are groups of operations that are calculated as being one bigger operation. + * All operations will be part of an ExecutionGroup. + * Complex nodes will be added to separate groups. Between ExecutionGroup's the data will be stored in MemoryBuffers. + * ReadBufferOperations and WriteBufferOperations are added where needed. * *
  *
diff --git a/source/blender/compositor/intern/COM_NodeOperation.cpp b/source/blender/compositor/intern/COM_NodeOperation.cpp
index a05c37e1b09..d33b8085022 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperation.cpp
@@ -34,6 +34,7 @@ NodeOperation::NodeOperation() : NodeBase()
 	this->m_complex = false;
 	this->m_width = 0;
 	this->m_height = 0;
+	this->m_isResolutionSet = false;
 	this->m_openCL = false;
 	this->m_btree = NULL;
 }
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index f856d8e6a11..60ffadf60f7 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -81,6 +81,7 @@ private:
 	 */
 	const bNodeTree *m_btree;
 
+	bool m_isResolutionSet;
 public:
 	/**
 	 * @brief is this node an operation?
@@ -170,7 +171,7 @@ public:
 	virtual void deinitExecution();
 
 	bool isResolutionSet() {
-		return this->m_width != 0 && this->m_height != 0;
+		return this->m_isResolutionSet;
 	}
 
 	/**
@@ -181,6 +182,7 @@ public:
 		if (!isResolutionSet()) {
 			this->m_width = resolution[0];
 			this->m_height = resolution[1];
+			this->m_isResolutionSet = true;
 		}
 	}
 	
@@ -254,8 +256,8 @@ public:
 protected:
 	NodeOperation();
 
-	void setWidth(unsigned int width) { this->m_width = width; }
-	void setHeight(unsigned int height) { this->m_height = height; }
+	void setWidth(unsigned int width) { this->m_width = width; this->m_isResolutionSet = true; }
+	void setHeight(unsigned int height) { this->m_height = height; this->m_isResolutionSet = true; }
 	SocketReader *getInputSocketReader(unsigned int inputSocketindex);
 	NodeOperation *getInputOperation(unsigned int inputSocketindex);
 
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp
index d5da079c9fd..bb60a629812 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp
@@ -65,12 +65,16 @@ void OpenCLDevice::execute(WorkPackage *work)
 	
 	executionGroup->finalizeChunkExecution(chunkNumber, inputBuffers);
 }
-cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, list *cleanup, MemoryBuffer **inputMemoryBuffers, SocketReader *reader)
+cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex,
+                                                               list *cleanup, MemoryBuffer **inputMemoryBuffers,
+                                                               SocketReader *reader)
 {
 	return COM_clAttachMemoryBufferToKernelParameter(kernel, parameterIndex, offsetIndex, cleanup, inputMemoryBuffers, (ReadBufferOperation *)reader);
 }
 
-cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, list *cleanup, MemoryBuffer **inputMemoryBuffers, ReadBufferOperation *reader)
+cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex,
+                                                               list *cleanup, MemoryBuffer **inputMemoryBuffers,
+                                                               ReadBufferOperation *reader)
 {
 	cl_int error;
 	
diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
index 254dfb7b9c7..a7149cc63b2 100644
--- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
+++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp
@@ -20,8 +20,8 @@
  */
 
 #include "COM_ConvertAlphaNode.h"
-#include "COM_ConvertPremulToKeyOperation.h"
-#include "COM_ConvertKeyToPremulOperation.h"
+#include "COM_ConvertPremulToStraightOperation.h"
+#include "COM_ConvertStraightToPremulOperation.h"
 #include "COM_ExecutionSystem.h"
 
 void ConvertAlphaNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
@@ -31,10 +31,10 @@ void ConvertAlphaNode::convertToOperations(ExecutionSystem *graph, CompositorCon
 
 	/* value hardcoded in rna_nodetree.c */
 	if (node->custom1 == 1) {
-		operation = new ConvertPremulToKeyOperation();
+		operation = new ConvertPremulToStraightOperation();
 	}
 	else {
-		operation = new ConvertKeyToPremulOperation();
+		operation = new ConvertStraightToPremulOperation();
 	}
 
 	this->getInputSocket(0)->relinkConnections(operation->getInputSocket(0), 0, graph);
diff --git a/source/blender/compositor/operations/COM_ConvertPremulToKeyOperation.cpp b/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.cpp
similarity index 78%
rename from source/blender/compositor/operations/COM_ConvertPremulToKeyOperation.cpp
rename to source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.cpp
index b92da4c324f..2af4b55de1a 100644
--- a/source/blender/compositor/operations/COM_ConvertPremulToKeyOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.cpp
@@ -19,10 +19,10 @@
  *		Dalai Felinto
  */
 
-#include "COM_ConvertPremulToKeyOperation.h"
+#include "COM_ConvertPremulToStraightOperation.h"
 #include "BLI_math.h"
 
-ConvertPremulToKeyOperation::ConvertPremulToKeyOperation() : NodeOperation()
+ConvertPremulToStraightOperation::ConvertPremulToStraightOperation() : NodeOperation()
 {
 	this->addInputSocket(COM_DT_COLOR);
 	this->addOutputSocket(COM_DT_COLOR);
@@ -30,12 +30,12 @@ ConvertPremulToKeyOperation::ConvertPremulToKeyOperation() : NodeOperation()
 	this->m_inputColor = NULL;
 }
 
-void ConvertPremulToKeyOperation::initExecution()
+void ConvertPremulToStraightOperation::initExecution()
 {
 	this->m_inputColor = getInputSocketReader(0);
 }
 
-void ConvertPremulToKeyOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
+void ConvertPremulToStraightOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
 {
 	float inputValue[4];
 	float alpha;
@@ -54,7 +54,7 @@ void ConvertPremulToKeyOperation::executePixel(float output[4], float x, float y
 	output[3] = alpha;
 }
 
-void ConvertPremulToKeyOperation::deinitExecution()
+void ConvertPremulToStraightOperation::deinitExecution()
 {
 	this->m_inputColor = NULL;
 }
diff --git a/source/blender/compositor/operations/COM_ConvertPremulToKeyOperation.h b/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.h
similarity index 85%
rename from source/blender/compositor/operations/COM_ConvertPremulToKeyOperation.h
rename to source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.h
index 04a9965858d..9d3ab156555 100644
--- a/source/blender/compositor/operations/COM_ConvertPremulToKeyOperation.h
+++ b/source/blender/compositor/operations/COM_ConvertPremulToStraightOperation.h
@@ -19,8 +19,8 @@
  *		Dalai Felinto
  */
 
-#ifndef _COM_ConvertPremulToKeyOperation_h
-#define _COM_ConvertPremulToKeyOperation_h
+#ifndef _COM_ConvertPremulToStraightOperation_h
+#define _COM_ConvertPremulToStraightOperation_h
 #include "COM_NodeOperation.h"
 
 
@@ -28,14 +28,14 @@
  * this program converts an input color to an output value.
  * it assumes we are in sRGB color space.
  */
-class ConvertPremulToKeyOperation : public NodeOperation {
+class ConvertPremulToStraightOperation : public NodeOperation {
 private:
 	SocketReader *m_inputColor;
 public:
 	/**
 	 * Default constructor
 	 */
-	ConvertPremulToKeyOperation();
+	ConvertPremulToStraightOperation();
 
 	/**
 	 * the inner loop of this program
diff --git a/source/blender/compositor/operations/COM_ConvertKeyToPremulOperation.cpp b/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.cpp
similarity index 77%
rename from source/blender/compositor/operations/COM_ConvertKeyToPremulOperation.cpp
rename to source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.cpp
index 4497db52a0f..ae55d949ff2 100644
--- a/source/blender/compositor/operations/COM_ConvertKeyToPremulOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.cpp
@@ -19,10 +19,10 @@
  *		Dalai Felinto
  */
 
-#include "COM_ConvertKeyToPremulOperation.h"
+#include "COM_ConvertStraightToPremulOperation.h"
 #include "BLI_math.h"
 
-ConvertKeyToPremulOperation::ConvertKeyToPremulOperation() : NodeOperation()
+ConvertStraightToPremulOperation::ConvertStraightToPremulOperation() : NodeOperation()
 {
 	this->addInputSocket(COM_DT_COLOR);
 	this->addOutputSocket(COM_DT_COLOR);
@@ -30,12 +30,12 @@ ConvertKeyToPremulOperation::ConvertKeyToPremulOperation() : NodeOperation()
 	this->m_inputColor = NULL;
 }
 
-void ConvertKeyToPremulOperation::initExecution()
+void ConvertStraightToPremulOperation::initExecution()
 {
 	this->m_inputColor = getInputSocketReader(0);
 }
 
-void ConvertKeyToPremulOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
+void ConvertStraightToPremulOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
 {
 	float inputValue[4];
 	float alpha;
@@ -49,7 +49,7 @@ void ConvertKeyToPremulOperation::executePixel(float output[4], float x, float y
 	output[3] = alpha;
 }
 
-void ConvertKeyToPremulOperation::deinitExecution()
+void ConvertStraightToPremulOperation::deinitExecution()
 {
 	this->m_inputColor = NULL;
 }
diff --git a/source/blender/compositor/operations/COM_ConvertKeyToPremulOperation.h b/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.h
similarity index 86%
rename from source/blender/compositor/operations/COM_ConvertKeyToPremulOperation.h
rename to source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.h
index 502674e26db..d0191f292d2 100644
--- a/source/blender/compositor/operations/COM_ConvertKeyToPremulOperation.h
+++ b/source/blender/compositor/operations/COM_ConvertStraightToPremulOperation.h
@@ -19,8 +19,8 @@
  *		Dalai Felinto
  */
 
-#ifndef _COM_ConvertKeyToPremulOperation_h
-#define _COM_ConvertKeyToPremulOperation_h
+#ifndef _COM_ConvertStraightToPremulOperation_h
+#define _COM_ConvertStraightToPremulOperation_h
 #include "COM_NodeOperation.h"
 
 
@@ -28,14 +28,14 @@
  * this program converts an input color to an output value.
  * it assumes we are in sRGB color space.
  */
-class ConvertKeyToPremulOperation : public NodeOperation {
+class ConvertStraightToPremulOperation : public NodeOperation {
 private:
 	SocketReader *m_inputColor;
 public:
 	/**
 	 * Default constructor
 	 */
-	ConvertKeyToPremulOperation();
+	ConvertStraightToPremulOperation();
 
 	/**
 	 * the inner loop of this program
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
index 7d05202df96..47b69ec87f9 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
@@ -141,7 +141,7 @@ void OutputSingleLayerOperation::deinitExecution()
 		IMB_colormanagement_imbuf_for_write(ibuf, TRUE, FALSE, m_viewSettings, m_displaySettings,
 		                                    this->m_format);
 
-		BKE_makepicstring(filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format->imtype,
+		BKE_makepicstring(filename, this->m_path, bmain->name, this->m_rd->cfra, this->m_format,
 		                  (this->m_rd->scemode & R_EXTENSION), true);
 		
 		if (0 == BKE_imbuf_write(ibuf, filename, this->m_format))
@@ -205,7 +205,7 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
 		char filename[FILE_MAX];
 		void *exrhandle = IMB_exr_get_handle();
 		
-		BKE_makepicstring(filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
+		BKE_makepicstring_from_type(filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
 		                  (this->m_rd->scemode & R_EXTENSION), true);
 		BLI_make_existing_file(filename);
 		
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index ca036a8540e..6687cce88cd 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -62,16 +62,28 @@
 /* Check if the operator can be run from the current context */
 static int change_frame_poll(bContext *C)
 {
-	ScrArea *curarea = CTX_wm_area(C);
+	ScrArea *sa = CTX_wm_area(C);
 	
 	/* XXX temp? prevent changes during render */
-	if (G.is_rendering) return 0;
+	if (G.is_rendering) return FALSE;
 	
-	/* as long as there is an active area, and it isn't a Graph Editor 
-	 * (since the Graph Editor has its own version which does extra stuff),
-	 * we're fine
+	/* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION,
+	 * this shouldn't show up in 3D editor (or others without 2D timeline view) via search
 	 */
-	return ((curarea) && (curarea->spacetype != SPACE_IPO));
+	if (sa) {
+		if (ELEM5(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+			return TRUE;
+		}
+		else if (sa->spacetype == SPACE_IPO) {
+			/* NOTE: Graph Editor has special version which does some extra stuff.
+			 * No need to show the generic error message for that case though!
+			 */
+			return FALSE;
+		}
+	}
+	
+	CTX_wm_operator_poll_msg_set(C, "Expected an timeline/animation area to be active");
+	return FALSE;
 }
 
 /* Set the new frame number */
@@ -83,7 +95,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
 	/* set the new frame number */
 	CFRA = RNA_int_get(op->ptr, "frame");
 	FRAMENUMBER_MIN_CLAMP(CFRA);
-	SUBFRA = 0.f;
+	SUBFRA = 0.0f;
 	
 	/* do updates */
 	sound_seek_scene(bmain, scene);
@@ -161,7 +173,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event)
 static void ANIM_OT_change_frame(wmOperatorType *ot)
 {
 	/* identifiers */
-	ot->name = "Change frame";
+	ot->name = "Change Frame";
 	ot->idname = "ANIM_OT_change_frame";
 	ot->description = "Interactively change the current frame number";
 	
@@ -175,7 +187,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
 	ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_POINTER;
 
 	/* rna */
-	RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
+	ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
 }
 
 /* ****************** set preview range operator ****************************/
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 8ba330e7c3c..9add193a514 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -540,8 +540,8 @@ static float setting_get_rna_value(PointerRNA *ptr, PropertyRNA *prop, int index
 enum {
 	VISUALKEY_NONE = 0,
 	VISUALKEY_LOC,
-	VISUALKEY_ROT
-	/* VISUALKEY_SCA */ /* TODO - looks like support can be added now */
+	VISUALKEY_ROT,
+	VISUALKEY_SCA,
 };
 
 /* This helper function determines if visual-keyframing should be used when  
@@ -560,7 +560,7 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
 	/* validate data */
 	if (ELEM3(NULL, ptr, ptr->data, prop))
 		return 0;
-		
+	
 	/* get first constraint and determine type of keyframe constraints to check for 
 	 *  - constraints can be on either Objects or PoseChannels, so we only check if the
 	 *    ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for
@@ -586,7 +586,7 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
 	/* check if any data to search using */
 	if (ELEM(NULL, con, identifier) && (has_parent == FALSE))
 		return 0;
-		
+	
 	/* location or rotation identifiers only... */
 	if (identifier == NULL) {
 		printf("%s failed: NULL identifier\n", __func__);
@@ -598,6 +598,9 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
 	else if (strstr(identifier, "rotation")) {
 		searchtype = VISUALKEY_ROT;
 	}
+	else if (strstr(identifier, "scale")) {
+		searchtype = VISUALKEY_SCA;
+	}
 	else {
 		printf("%s failed: identifier - '%s'\n", __func__, identifier);
 		return 0;
@@ -628,7 +631,7 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
 					return 1;
 				case CONSTRAINT_TYPE_KINEMATIC:
 					return 1;
-					
+				
 				/* single-transform constraits  */
 				case CONSTRAINT_TYPE_TRACKTO:
 					if (searchtype == VISUALKEY_ROT) return 1;
@@ -642,15 +645,21 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
 				case CONSTRAINT_TYPE_LOCLIMIT:
 					if (searchtype == VISUALKEY_LOC) return 1;
 					break;
-				case CONSTRAINT_TYPE_ROTLIKE:
-					if (searchtype == VISUALKEY_ROT) return 1;
+				case CONSTRAINT_TYPE_SIZELIMIT:
+					if (searchtype == VISUALKEY_SCA) return 1;
 					break;
 				case CONSTRAINT_TYPE_DISTLIMIT:
 					if (searchtype == VISUALKEY_LOC) return 1;
 					break;
+				case CONSTRAINT_TYPE_ROTLIKE:
+					if (searchtype == VISUALKEY_ROT) return 1;
+					break;
 				case CONSTRAINT_TYPE_LOCLIKE:
 					if (searchtype == VISUALKEY_LOC) return 1;
 					break;
+				case CONSTRAINT_TYPE_SIZELIKE:
+					if (searchtype == VISUALKEY_SCA) return 1;
+					break;
 				case CONSTRAINT_TYPE_LOCKTRACK:
 					if (searchtype == VISUALKEY_ROT) return 1;
 					break;
@@ -675,45 +684,26 @@ static short visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
 static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_index)
 {
 	const char *identifier = RNA_property_identifier(prop);
+	float tmat[4][4];
+	int rotmode;
 	
 	/* handle for Objects or PoseChannels only 
+	 *  - only Location, Rotation or Scale keyframes are supported curently
 	 *  - constraints can be on either Objects or PoseChannels, so we only check if the
-	 *	  ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for
+	 *    ptr->type is RNA_Object or RNA_PoseBone, which are the RNA wrapping-info for
 	 *        those structs, allowing us to identify the owner of the data
-	 *	- assume that array_index will be sane
+	 *  - assume that array_index will be sane
 	 */
 	if (ptr->type == &RNA_Object) {
 		Object *ob = (Object *)ptr->data;
-		
-		/* only Location or Rotation keyframes are supported now */
+
+		/* Loc code is specific... */
 		if (strstr(identifier, "location")) {
 			return ob->obmat[3][array_index];
 		}
-		else if (strstr(identifier, "rotation_euler")) {
-			float eul[3];
-			
-			mat4_to_eulO(eul, ob->rotmode, ob->obmat);
-			return eul[array_index];
-		}
-		else if (strstr(identifier, "rotation_quaternion")) {
-			float trimat[3][3], quat[4];
-			
-			copy_m3_m4(trimat, ob->obmat);
-			mat3_to_quat_is_ok(quat, trimat);
-			
-			return quat[array_index];
-		}
-		else if (strstr(identifier, "rotation_axis_angle")) {
-			float axis[3], angle;
-			
-			mat4_to_axis_angle(axis, &angle, ob->obmat);
-			
-			/* w = 0, x,y,z = 1,2,3 */
-			if (array_index == 0)
-				return angle;
-			else
-				return axis[array_index - 1];
-		}
+
+		copy_m4_m4(tmat, ob->obmat);
+		rotmode = ob->rotmode;
 	}
 	else if (ptr->type == &RNA_PoseBone) {
 		Object *ob = (Object *)ptr->id.data; /* we assume that this is always set, and is an object */
@@ -726,41 +716,52 @@ static float visualkey_get_value(PointerRNA *ptr, PropertyRNA *prop, int array_i
 		 * will be what owns the pose-channel that is getting this anyway.
 		 */
 		copy_m4_m4(tmat, pchan->pose_mat);
-		constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
+		BKE_constraint_mat_convertspace(ob, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
+		rotmode = pchan->rotmode;
 		
-		/* Loc, Rot/Quat keyframes are supported... */
+		/* Loc code is specific... */
 		if (strstr(identifier, "location")) {
 			/* only use for non-connected bones */
-			if ((pchan->bone->parent) && !(pchan->bone->flag & BONE_CONNECTED))
-				return tmat[3][array_index];
-			else if (pchan->bone->parent == NULL)
+			if ((pchan->bone->parent == NULL) || !(pchan->bone->flag & BONE_CONNECTED))
 				return tmat[3][array_index];
 		}
-		else if (strstr(identifier, "rotation_euler")) {
-			float eul[3];
-			
-			mat4_to_eulO(eul, pchan->rotmode, tmat);
-			return eul[array_index];
-		}
-		else if (strstr(identifier, "rotation_quaternion")) {
-			float trimat[3][3], quat[4];
-			
-			copy_m3_m4(trimat, tmat);
-			mat3_to_quat_is_ok(quat, trimat);
-			
-			return quat[array_index];
-		}
-		else if (strstr(identifier, "rotation_axis_angle")) {
-			float axis[3], angle;
-			
-			mat4_to_axis_angle(axis, &angle, tmat);
-			
-			/* w = 0, x,y,z = 1,2,3 */
-			if (array_index == 0)
-				return angle;
-			else
-				return axis[array_index - 1];
-		}
+	}
+	else {
+		return setting_get_rna_value(ptr, prop, array_index);
+	}
+	
+	/* Rot/Scale code are common! */
+	if (strstr(identifier, "rotation_euler")) {
+		float eul[3];
+		
+		mat4_to_eulO(eul, rotmode, tmat);
+		return eul[array_index];
+	}
+	else if (strstr(identifier, "rotation_quaternion")) {
+		float mat3[3][3], quat[4];
+		
+		copy_m3_m4(mat3, tmat);
+		mat3_to_quat_is_ok(quat, mat3);
+		
+		return quat[array_index];
+	}
+	else if (strstr(identifier, "rotation_axis_angle")) {
+		float axis[3], angle;
+		
+		mat4_to_axis_angle(axis, &angle, tmat);
+		
+		/* w = 0, x,y,z = 1,2,3 */
+		if (array_index == 0)
+			return angle;
+		else
+			return axis[array_index - 1];
+	}
+	else if (strstr(identifier, "scale")) {
+		float scale[3];
+		
+		mat4_to_size(scale, tmat);
+		
+		return scale[array_index];
 	}
 	
 	/* as the function hasn't returned yet, read value from system in the default way */
diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c
index ae405c0e113..37314373e98 100644
--- a/source/blender/editors/armature/editarmature.c
+++ b/source/blender/editors/armature/editarmature.c
@@ -812,7 +812,7 @@ static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChann
 			pose = ob->pose;
 			for (pchant = pose->chanbase.first; pchant; pchant = pchant->next) {
 				for (con = pchant->constraints.first; con; con = con->next) {
-					bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+					bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 					ListBase targets = {NULL, NULL};
 					bConstraintTarget *ct;
 					
@@ -859,7 +859,7 @@ static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChann
 		/* fix object-level constraints */
 		if (ob != srcArm) {
 			for (con = ob->constraints.first; con; con = con->next) {
-				bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+				bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 				ListBase targets = {NULL, NULL};
 				bConstraintTarget *ct;
 				
@@ -1032,7 +1032,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm)
 		if (ob->type == OB_ARMATURE) {
 			for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
 				for (con = pchan->constraints.first; con; con = con->next) {
-					bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+					bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 					ListBase targets = {NULL, NULL};
 					bConstraintTarget *ct;
 					
@@ -1070,7 +1070,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm)
 		/* fix object-level constraints */
 		if (ob != origArm) {
 			for (con = ob->constraints.first; con; con = con->next) {
-				bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+				bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 				ListBase targets = {NULL, NULL};
 				bConstraintTarget *ct;
 				
@@ -1712,7 +1712,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
 			}
 			else {
 				for (con = pchan->constraints.first; con; con = con->next) {
-					bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+					bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 					ListBase targets = {NULL, NULL};
 					bConstraintTarget *ct;
 					
@@ -2523,7 +2523,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Obj
 				/* does this constraint have a subtarget in
 				 * this armature?
 				 */
-				bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon);
+				bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
 				ListBase targets = {NULL, NULL};
 				bConstraintTarget *ct;
 				
@@ -5533,7 +5533,7 @@ static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldnam
 	bConstraintTarget *ct;
 	
 	for (curcon = conlist->first; curcon; curcon = curcon->next) {
-		bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon);
+		bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
 		ListBase targets = {NULL, NULL};
 		
 		if (cti && cti->get_constraint_targets) {
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index 68cfc7fb8c0..3e34a4c6808 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -725,7 +725,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
 		/* DO SOME MAGIC HERE */
 		for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
 			for (con = pchan->constraints.first; con; con = con->next) {
-				bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+				bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 				ListBase targets = {NULL, NULL};
 				bConstraintTarget *ct;
 				
@@ -850,7 +850,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
 				/* DO SOME MAGIC HERE */
 				for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) {
 					for (con = pchan->constraints.first; con; con = con->next) {
-						bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+						bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 						ListBase targets = {NULL, NULL};
 						bConstraintTarget *ct;
 						
@@ -1830,7 +1830,9 @@ static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEd
 }
 #endif
 
-static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge, float *vec0, float *vec1, float *vec2, int i1, int i2, float angle_weight, float length_weight, float distance_weight)
+static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge,
+                                         float *vec0, float *vec1, float *vec2, int i1, int i2,
+                                         float angle_weight, float length_weight, float distance_weight)
 {
 	float vec_second[3], vec_first[3];
 	float length2;
@@ -1878,7 +1880,9 @@ static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions,
 	}
 }
 
-static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, int joints_left, float angle_weight, float length_weight, float distance_weight)
+static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache,
+                             int nb_joints, int nb_positions, int previous, int current, RigEdge *edge,
+                             int joints_left, float angle_weight, float length_weight, float distance_weight)
 {
 	MemoNode *node;
 	int index = indexMemoNode(nb_positions, previous, current, joints_left);
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 2848db18d59..19a97fa0810 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -649,7 +649,9 @@ static float heat_limit_weight(float weight)
 		return weight;
 }
 
-void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
+void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
+                         bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
+                         float (*root)[3], float (*tip)[3], int *selected, const char **err_str)
 {
 	LaplacianSystem *sys;
 	MPoly *mp;
diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c
index 576e5983d16..49d4b670cde 100644
--- a/source/blender/editors/armature/poseobject.c
+++ b/source/blender/editors/armature/poseobject.c
@@ -417,7 +417,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
 	{
 		if (pchan->bone->flag & BONE_SELECTED) {
 			for (con = pchan->constraints.first; con; con = con->next) {
-				bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+				bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 				ListBase targets = {NULL, NULL};
 				bConstraintTarget *ct;
 				
@@ -925,7 +925,7 @@ static void pose_copy_menu(Scene *scene)
 						/* copy constraints to tmpbase and apply 'local' tags before 
 						 * appending to list of constraints for this channel
 						 */
-						copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE);
+						BKE_copy_constraints(&tmp_constraints, &pchanact->constraints, TRUE);
 						if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
 							bConstraint *con;
 							
@@ -1034,7 +1034,7 @@ static void pose_copy_menu(Scene *scene)
 				/* copy constraints to tmpbase and apply 'local' tags before 
 				 * appending to list of constraints for this channel
 				 */
-				copy_constraints(&tmp_constraints, &const_copy, TRUE);
+				BKE_copy_constraints(&tmp_constraints, &const_copy, TRUE);
 				if ((ob->proxy) && (pchan->bone->layer & arm->layer_protected)) {
 					/* add proxy-local tags */
 					for (con = tmp_constraints.first; con; con = con->next)
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 1b4a67d38c0..f5ab002e0ef 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -291,9 +291,9 @@ int            mesh_get_x_mirror_vert(struct Object *ob, int index);
 struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, struct BMVert *eve, const float co[3], int index);
 int           *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em);
 
-int ED_mesh_pick_vert(struct bContext *C, struct Mesh *me, const int mval[2], unsigned int *index, int size);
-int ED_mesh_pick_face(struct bContext *C, struct Mesh *me, const int mval[2], unsigned int *index, int size);
-int ED_mesh_pick_face_vert(struct bContext *C, struct Mesh *me, struct Object *ob, const int mval[2], unsigned int *index, int size);
+int ED_mesh_pick_vert(struct bContext *C,      struct Object *ob, const int mval[2], unsigned int *index, int size, int use_zbuf);
+int ED_mesh_pick_face(struct bContext *C,      struct Object *ob, const int mval[2], unsigned int *index, int size);
+int ED_mesh_pick_face_vert(struct bContext *C, struct Object *ob, const int mval[2], unsigned int *index, int size);
 
 #define ED_MESH_PICK_DEFAULT_VERT_SIZE 50
 #define ED_MESH_PICK_DEFAULT_FACE_SIZE 3
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index f7f58a4ee7a..3d13938c204 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -85,6 +85,7 @@ typedef struct ViewDepths {
 } ViewDepths;
 
 float *give_cursor(struct Scene *scene, struct View3D *v3d);
+void ED_view3d_cursor3d_position(struct bContext *C, float *fp, int mx, int my);
 
 void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist);
 void ED_view3d_from_m4(float mat[4][4], float ofs[3], float quat[4], float *dist);
@@ -124,6 +125,10 @@ typedef enum {
 /* view3d_iterators.c */
 
 /* foreach iterators */
+void meshobject_foreachScreenVert(
+        struct ViewContext *vc,
+        void (*func)(void *userData, struct MVert *eve, const float screen_co[2], int index),
+        void *userData, const eV3DProjTest clip_flag);
 void mesh_foreachScreenVert(
         struct ViewContext *vc,
         void (*func)(void *userData, struct BMVert *eve, const float screen_co[2], int index),
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 99f7f0856b3..0a794040692 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -699,9 +699,7 @@ DEF_ICON(RNDCURVE)
 DEF_ICON(PROP_OFF)
 DEF_ICON(PROP_ON)
 DEF_ICON(PROP_CON)
-#ifndef DEF_ICON_BLANK_SKIP
-	DEF_ICON(BLANK212)
-#endif
+DEF_ICON(SCULPT_DYNTOPO)
 DEF_ICON(PARTICLE_POINT)
 DEF_ICON(PARTICLE_TIP)
 DEF_ICON(PARTICLE_PATH)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 90f8779b2c7..080367c4325 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -56,6 +56,7 @@ struct PropertyRNA;
 struct ReportList;
 struct rcti;
 struct rctf;
+struct uiList;
 struct uiStyle;
 struct uiFontStyle;
 struct uiWidgetColors;
@@ -658,6 +659,7 @@ void uiDrawPanels(const struct bContext *C, struct ARegion *ar);
 
 struct Panel *uiBeginPanel(struct ScrArea *sa, struct ARegion *ar, uiBlock *block, struct PanelType *pt, int *open);
 void uiEndPanel(uiBlock *block, int width, int height);
+void uiScalePanels(struct ARegion *ar, float new_width);
 
 /* Handlers
  *
@@ -778,7 +780,7 @@ uiLayout *uiLayoutRow(uiLayout *layout, int align);
 uiLayout *uiLayoutColumn(uiLayout *layout, int align);
 uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align);
 uiLayout *uiLayoutBox(uiLayout *layout);
-uiLayout *uiLayoutListBox(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop,
+uiLayout *uiLayoutListBox(uiLayout *layout, struct uiList *ui_list, struct PointerRNA *ptr, struct PropertyRNA *prop,
                           struct PointerRNA *actptr, struct PropertyRNA *actprop);
 uiLayout *uiLayoutAbsolute(uiLayout *layout, int align);
 uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align);
@@ -824,7 +826,9 @@ void uiTemplateTextureImage(uiLayout *layout, struct bContext *C, struct Tex *te
 void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
 void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
 
-void uiTemplateList(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *activeptr, const char *activeprop, const char *prop_list, int rows, int maxrows, int type);
+void uiTemplateList(uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id,
+                    struct PointerRNA *dataptr, const char *propname, struct PointerRNA *active_dataptr,
+                    const char *active_propname, int rows, int maxrows, int layout_type);
 void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
 void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
 void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index aa94bdec724..f578d68b852 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -32,12 +32,14 @@
 #ifndef __UI_INTERFACE_ICONS_H__
 #define __UI_INTERFACE_ICONS_H__
 
+struct bContext;
 struct Image;
 struct ImBuf;
 struct World;
 struct Tex;
 struct Lamp;
 struct Material;
+struct PointerRNA;
 
 typedef struct IconFile {
 	struct IconFile *next, *prev;
@@ -74,5 +76,6 @@ void UI_icons_free_drawinfo(void *drawinfo);
 struct ListBase *UI_iconfile_list(void);
 int UI_iconfile_get_index(const char *filename);
 
+int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, int big);
 
 #endif /*  __UI_INTERFACE_ICONS_H__ */
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 236cc371d8b..1035f5815f2 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -122,9 +122,12 @@ enum {
 
 	TH_SYNTAX_B,
 	TH_SYNTAX_V,
+	TH_SYNTAX_R,
 	TH_SYNTAX_C,
 	TH_SYNTAX_L,
+	TH_SYNTAX_D,
 	TH_SYNTAX_N,
+	TH_SYNTAX_S,
 	
 	TH_BONE_SOLID,
 	TH_BONE_POSE,
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index 3ae1e93dc3d..81a0f526049 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -148,7 +148,6 @@ typedef struct View2DScrollers View2DScrollers;
 void UI_view2d_region_reinit(struct View2D *v2d, short type, int winx, int winy);
 
 void UI_view2d_curRect_validate(struct View2D *v2d);
-void UI_view2d_curRect_validate_resize(struct View2D *v2d, int resize);
 void UI_view2d_curRect_reset(struct View2D *v2d);
 void UI_view2d_sync(struct bScreen *screen, struct ScrArea *sa, struct View2D *v2dcur, int flag);
 
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 25f85883d9c..1d26cbd344b 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -2666,6 +2666,8 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
 	
 	/* we could do some more error checks here */
 	if ((type & BUTTYPE) == LABEL) {
+		if ((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f)))
+			printf("blah\n");
 		BLI_assert((poin != NULL || min != 0.0f || max != 0.0f || (a1 == 0.0f && a2 != 0.0f) || (a1 != 0.0f && a1 != 1.0f)) == FALSE);
 	}
 
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index fed84092133..1c9cd92271c 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -44,6 +44,7 @@
 
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
@@ -219,6 +220,29 @@ static void button_timers_tooltip_remove(bContext *C, uiBut *but);
 
 /* ******************** menu navigation helpers ************** */
 
+/* assumes event type is MOUSEPAN */
+void ui_pan_to_scroll(wmEvent *event, int *type, int *val)
+{
+	static int lastdy = 0;
+	int dy = event->prevy - event->y;
+	
+	/* sign differs, reset */
+	if ((dy > 0 && lastdy < 0) || (dy < 0 && lastdy > 0))
+		lastdy = dy;
+	else {
+		lastdy += dy;
+		
+		if (ABS(lastdy) > (int)UI_UNIT_Y) {
+			*val = KM_PRESS;
+			if (event->prevy - event->y > 0)
+				*type = WHEELUPMOUSE;
+			else
+				*type = WHEELDOWNMOUSE;
+			lastdy = 0;
+		}
+	}
+}
+
 static int ui_but_editable(uiBut *but)
 {
 	return ELEM5(but->type, LABEL, SEPR, ROUNDBOX, LISTBOX, PROGRESSBAR);
@@ -1893,6 +1917,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
 		case WHEELUPMOUSE:
 		case WHEELDOWNMOUSE:
 		case MOUSEMOVE:
+		case MOUSEPAN:
 			if (data->searchbox)
 				ui_searchbox_event(C, data->searchbox, but, event);
 			
@@ -2687,12 +2712,16 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
 	ui_window_to_block(data->region, block, &mx, &my);
 
 	if (data->state == BUTTON_STATE_HIGHLIGHT) {
+		int type = event->type, val = event->val;
+		
+		ui_pan_to_scroll(event, &type, &val);
+		
 		/* XXX hardcoded keymap check.... */
-		if (event->type == WHEELDOWNMOUSE && event->alt) {
+		if (type == WHEELDOWNMOUSE && event->alt) {
 			mx = but->rect.xmin;
 			click = 1;
 		}
-		else if (event->type == WHEELUPMOUSE && event->alt) {
+		else if (type == WHEELUPMOUSE && event->alt) {
 			mx = but->rect.xmax;
 			click = 1;
 		}
@@ -2911,12 +2940,16 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
 	ui_window_to_block(data->region, block, &mx, &my);
 
 	if (data->state == BUTTON_STATE_HIGHLIGHT) {
+		int type = event->type, val = event->val;
+		
+		ui_pan_to_scroll(event, &type, &val);
+
 		/* XXX hardcoded keymap check.... */
-		if (event->type == WHEELDOWNMOUSE && event->alt) {
+		if (type == WHEELDOWNMOUSE && event->alt) {
 			mx = but->rect.xmin;
 			click = 2;
 		}
-		else if (event->type == WHEELUPMOUSE && event->alt) {
+		else if (type == WHEELUPMOUSE && event->alt) {
 			mx = but->rect.xmax;
 			click = 2;
 		}
@@ -3142,7 +3175,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, wm
 			}
 		}
 		else if (but->type == COLOR) {
-			if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+			if (ELEM3(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
 				float *hsv = ui_block_hsv_get(but->block);
 				float col[3];
 				
@@ -3151,8 +3184,12 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, wm
 
 				if (event->type == WHEELDOWNMOUSE)
 					hsv[2] = CLAMPIS(hsv[2] - 0.05f, 0.0f, 1.0f);
-				else
+				else if (event->type == WHEELUPMOUSE)
 					hsv[2] = CLAMPIS(hsv[2] + 0.05f, 0.0f, 1.0f);
+				else {
+					float fac = 0.005 * (event->y - event->prevy);
+					hsv[2] = CLAMPIS(hsv[2] + fac, 0.0f, 1.0f);
+				}
 				
 				hsv_to_rgb_v(hsv, data->vec);
 				ui_set_but_vectorf(but, data->vec);
@@ -5248,32 +5285,15 @@ static int ui_mouse_inside_region(ARegion *ar, int x, int y)
 	 */
 	if (ar->v2d.mask.xmin != ar->v2d.mask.xmax) {
 		View2D *v2d = &ar->v2d;
-		rcti mask_rct;
 		int mx, my;
 		
 		/* convert window coordinates to region coordinates */
 		mx = x;
 		my = y;
 		ui_window_to_region(ar, &mx, &my);
-		
-		/* make a copy of the mask rect, and tweak accordingly for hidden scrollbars */
-		mask_rct = v2d->mask;
-		
-		if (v2d->scroll & (V2D_SCROLL_VERTICAL_HIDE | V2D_SCROLL_VERTICAL_FULLR)) {
-			if (v2d->scroll & V2D_SCROLL_LEFT)
-				mask_rct.xmin = v2d->vert.xmin;
-			else if (v2d->scroll & V2D_SCROLL_RIGHT)
-				mask_rct.xmax = v2d->vert.xmax;
-		}
-		if (v2d->scroll & (V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_HORIZONTAL_FULLR)) {
-			if (v2d->scroll & (V2D_SCROLL_BOTTOM | V2D_SCROLL_BOTTOM_O))
-				mask_rct.ymin = v2d->hor.ymin;
-			else if (v2d->scroll & V2D_SCROLL_TOP)
-				mask_rct.ymax = v2d->hor.ymax;
-		}
-		
+
 		/* check if in the rect */
-		if (!BLI_rcti_isect_pt(&mask_rct, mx, my)) 
+		if (!BLI_rcti_isect_pt(&v2d->mask, mx, my))
 			return 0;
 	}
 	
@@ -6109,64 +6129,81 @@ static int ui_handle_list_event(bContext *C, wmEvent *event, ARegion *ar)
 	uiBut *but = ui_list_find_mouse_over(ar, event->x, event->y);
 	int retval = WM_UI_HANDLER_CONTINUE;
 	int value, min, max;
+	int type = event->type, val = event->val;
 
-	if (but && (event->val == KM_PRESS)) {
-		Panel *pa = but->block->panel;
+	if (but) {
+		uiList *ui_list = but->custom_data;
 
-		if (ELEM(event->type, UPARROWKEY, DOWNARROWKEY) ||
-		    ((ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt)))
-		{
-			/* activate up/down the list */
-			value = RNA_property_int_get(&but->rnapoin, but->rnaprop);
+		if (ui_list) {
+			
+			/* convert pan to scrollwheel */
+			if (type == MOUSEPAN) {
+				ui_pan_to_scroll(event, &type, &val);
+				
+				/* if type still is mousepan, we call it handled, since delta-y accumulate */
+				/* also see wm_event_system.c do_wheel_ui hack */
+				if (type == MOUSEPAN)
+					retval = WM_UI_HANDLER_BREAK;
+			}
+			
+			if (val == KM_PRESS) {
+				
+				if (ELEM(type, UPARROWKEY, DOWNARROWKEY) ||
+					((ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt)))
+				{
+					/* activate up/down the list */
+					value = RNA_property_int_get(&but->rnapoin, but->rnaprop);
 
-			if (ELEM(event->type, UPARROWKEY, WHEELUPMOUSE))
-				value--;
-			else
-				value++;
+					if (ELEM(type, UPARROWKEY, WHEELUPMOUSE))
+						value--;
+					else
+						value++;
 
-			CLAMP(value, 0, pa->list_last_len - 1);
+					CLAMP(value, 0, ui_list->list_last_len - 1);
 
-			if (value < pa->list_scroll)
-				pa->list_scroll = value;
-			else if (value >= pa->list_scroll + pa->list_size)
-				pa->list_scroll = value - pa->list_size + 1;
+					if (value < ui_list->list_scroll)
+						ui_list->list_scroll = value;
+					else if (value >= ui_list->list_scroll + ui_list->list_size)
+						ui_list->list_scroll = value - ui_list->list_size + 1;
 
-			RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max);
-			value = CLAMPIS(value, min, max);
+					RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max);
+					value = CLAMPIS(value, min, max);
 
-			RNA_property_int_set(&but->rnapoin, but->rnaprop, value);
-			RNA_property_update(C, &but->rnapoin, but->rnaprop);
-			ED_region_tag_redraw(ar);
+					RNA_property_int_set(&but->rnapoin, but->rnaprop, value);
+					RNA_property_update(C, &but->rnapoin, but->rnaprop);
+					ED_region_tag_redraw(ar);
 
-			retval = WM_UI_HANDLER_BREAK;
-		}
-		else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) {
-			/* silly replacement for proper grip */
-			if (pa->list_grip_size == 0)
-				pa->list_grip_size = pa->list_size;
+					retval = WM_UI_HANDLER_BREAK;
+				}
+				else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) {
+					/* silly replacement for proper grip */
+					if (ui_list->list_grip_size == 0)
+						ui_list->list_grip_size = ui_list->list_size;
 
-			if (event->type == WHEELUPMOUSE)
-				pa->list_grip_size--;
-			else
-				pa->list_grip_size++;
+					if (type == WHEELUPMOUSE)
+						ui_list->list_grip_size--;
+					else
+						ui_list->list_grip_size++;
 
-			pa->list_grip_size = MAX2(pa->list_grip_size, 1);
+					ui_list->list_grip_size = MAX2(ui_list->list_grip_size, 1);
 
-			ED_region_tag_redraw(ar);
+					ED_region_tag_redraw(ar);
 
-			retval = WM_UI_HANDLER_BREAK;
-		}
-		else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
-			if (pa->list_last_len > pa->list_size) {
-				/* list template will clamp */
-				if (event->type == WHEELUPMOUSE)
-					pa->list_scroll--;
-				else
-					pa->list_scroll++;
+					retval = WM_UI_HANDLER_BREAK;
+				}
+				else if (ELEM(type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
+					if (ui_list->list_last_len > ui_list->list_size) {
+						/* list template will clamp */
+						if (type == WHEELUPMOUSE)
+							ui_list->list_scroll--;
+						else
+							ui_list->list_scroll++;
 
-				ED_region_tag_redraw(ar);
+						ED_region_tag_redraw(ar);
 
-				retval = WM_UI_HANDLER_BREAK;
+						retval = WM_UI_HANDLER_BREAK;
+					}
+				}
 			}
 		}
 	}
@@ -6472,21 +6509,29 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
 				case DOWNARROWKEY:
 				case WHEELUPMOUSE:
 				case WHEELDOWNMOUSE:
+				case MOUSEPAN:
 					/* arrowkeys: only handle for block_loop blocks */
 					if (event->alt || event->shift || event->ctrl || event->oskey) {
 						/* pass */
 					}
 					else if (inside || (block->flag & UI_BLOCK_LOOP)) {
-						if (event->val == KM_PRESS) {
+						int type = event->type;
+						int val = event->val;
+						
+						/* convert pan to scrollwheel */
+						if (type == MOUSEPAN)
+							ui_pan_to_scroll(event, &type, &val);
+						
+						if (val == KM_PRESS) {
 
 							PASS_EVENT_TO_PARENT_IF_NONACTIVE;
 
 							but = ui_but_find_activated(ar);
 							if (but) {
 								/* is there a situation where UI_LEFT or UI_RIGHT would also change navigation direction? */
-								if (((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_DOWN)) ||
-								    ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_RIGHT)) ||
-								    ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_TOP)))
+								if (((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_DOWN)) ||
+								    ((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_RIGHT)) ||
+								    ((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_TOP)))
 								{
 									/* the following is just a hack - uiBut->type set to BUT and BUTM have there menus built 
 									 * opposite ways - this should be changed so that all popup-menus use the same uiBlock->direction */
@@ -6509,9 +6554,9 @@ static int ui_handle_menu_event(bContext *C, wmEvent *event, uiPopupBlockHandle
 							}
 
 							if (!but) {
-								if (((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_DOWN)) ||
-								    ((ELEM(event->type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_RIGHT)) ||
-								    ((ELEM(event->type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_TOP)))
+								if (((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_DOWN)) ||
+								    ((ELEM(type, UPARROWKEY, WHEELUPMOUSE)) && (block->direction & UI_RIGHT)) ||
+								    ((ELEM(type, DOWNARROWKEY, WHEELDOWNMOUSE)) && (block->direction & UI_TOP)))
 								{
 									if ((bt = ui_but_first(block)) && (bt->type & BUT)) {
 										bt = ui_but_last(block);
@@ -6928,8 +6973,6 @@ static int ui_handler_region_menu(bContext *C, wmEvent *event, void *UNUSED(user
 {
 	ARegion *ar;
 	uiBut *but;
-	uiHandleButtonData *data;
-	int retval;
 
 	/* here we handle buttons at the window level, modal, for example
 	 * while number sliding, text editing, or when a menu block is open */
@@ -6940,17 +6983,23 @@ static int ui_handler_region_menu(bContext *C, wmEvent *event, void *UNUSED(user
 	but = ui_but_find_activated(ar);
 
 	if (but) {
+		uiHandleButtonData *data;
+
 		/* handle activated button events */
 		data = but->active;
 
 		if (data->state == BUTTON_STATE_MENU_OPEN) {
+			int retval;
+
 			/* handle events for menus and their buttons recursively,
 			 * this will handle events from the top to the bottom menu */
 			if (data->menu)
 				retval = ui_handle_menus_recursive(C, event, data->menu, 0);
 
 			/* handle events for the activated button */
-			if (retval == WM_UI_HANDLER_CONTINUE || event->type == TIMER) {
+			if ((data->menu && (retval == WM_UI_HANDLER_CONTINUE)) ||
+			    (event->type == TIMER))
+			{
 				if (data->menu && data->menu->menuretval)
 					ui_handle_button_return_submenu(C, event, but);
 				else
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 2928a5607c0..ebc80d61af3 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -49,6 +49,7 @@
 #include "BLI_utildefines.h"
 
 #include "DNA_brush_types.h"
+#include "DNA_dynamicpaint_types.h"
 #include "DNA_object_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
@@ -75,8 +76,8 @@
 #include "interface_intern.h"
 
 
-#define ICON_IMAGE_W        600
-#define ICON_IMAGE_H        640
+// #define ICON_IMAGE_W        600
+// #define ICON_IMAGE_H        640
 
 #define ICON_GRID_COLS      26
 #define ICON_GRID_ROWS      30
@@ -574,13 +575,15 @@ static void init_internal_icons(void)
 				glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect);
 				
 				while (b16buf->x > 1) {
-					b16buf = IMB_onehalf(b16buf);
-					glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect);
+					ImBuf *nbuf = IMB_onehalf(b16buf);
+					glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, nbuf->x, nbuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nbuf->rect);
 					level++;
+					IMB_freeImBuf(b16buf);
+					b16buf = nbuf;
 				}
 				
 				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 				
 				glBindTexture(GL_TEXTURE_2D, 0);
 				
@@ -597,7 +600,7 @@ static void init_internal_icons(void)
 	else
 		icontype = ICON_TYPE_BUFFER;
 	
-	if (b16buf) {
+	if (b32buf) {
 		for (y = 0; y < ICON_GRID_ROWS; y++) {
 			for (x = 0; x < ICON_GRID_COLS; x++) {
 				def_internal_icon(b32buf, BIFICONID_FIRST + y * ICON_GRID_COLS + x,
@@ -1179,6 +1182,44 @@ int ui_id_icon_get(bContext *C, ID *id, int big)
 	return iconid;
 }
 
+int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, int big)
+{
+	ID *id = NULL;
+
+	if (!ptr->data)
+		return rnaicon;
+
+	/* try ID, material, texture or dynapaint slot */
+	if (RNA_struct_is_ID(ptr->type)) {
+		id = ptr->id.data;
+	}
+	else if (RNA_struct_is_a(ptr->type, &RNA_MaterialSlot)) {
+		id = RNA_pointer_get(ptr, "material").data;
+	}
+	else if (RNA_struct_is_a(ptr->type, &RNA_TextureSlot)) {
+		id = RNA_pointer_get(ptr, "texture").data;
+	}
+	else if (RNA_struct_is_a(ptr->type, &RNA_DynamicPaintSurface)) {
+		DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data;
+
+		if (surface->format == MOD_DPAINT_SURFACE_F_PTEX)
+			return ICON_TEXTURE_SHADED;
+		else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX)
+			return ICON_OUTLINER_DATA_MESH;
+		else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+			return ICON_FILE_IMAGE;
+	}
+
+	/* get icon from ID */
+	if (id) {
+		int icon = ui_id_icon_get(C, id, big);
+
+		return icon ? icon : rnaicon;
+	}
+
+	return rnaicon;
+}
+
 static void icon_draw_at_size(float x, float y, int icon_id, float aspect, float alpha, enum eIconSizes size, int nocreate)
 {
 	int draw_size = get_draw_size(size);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index f088b3a54f4..706301dc060 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -271,6 +271,9 @@ struct uiBut {
 	/* active button data */
 	struct uiHandleButtonData *active;
 
+	/* Custom button data. */
+	void *custom_data;
+
 	char *editstr;
 	double *editval;
 	float *editvec;
@@ -504,6 +507,7 @@ void ui_draw_but_IMAGE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, rct
 void ui_draw_but_TRACKPREVIEW(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, rcti *rect);
 
 /* interface_handlers.c */
+extern void ui_pan_to_scroll(struct wmEvent *event, int *type, int *val);
 extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, uiBut *but);
 extern void ui_button_active_free(const struct bContext *C, uiBut *but);
 extern int ui_button_is_active(struct ARegion *ar);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index a15256bc86f..f4af1f036a3 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -186,13 +186,13 @@ static const char *ui_item_name_add_colon(const char *name, char namestr[UI_MAX_
 
 static int ui_item_fit(int item, int pos, int all, int available, int last, int alignment, int *offset)
 {
+	if (offset)
+		*offset = 0;
+
 	/* available == 0 is unlimited */
 	if (available == 0)
 		return item;
-	
-	if (offset)
-		*offset = 0;
-	
+
 	if (all > available) {
 		/* contents is bigger than available space */
 		if (last)
@@ -346,7 +346,9 @@ static void ui_layer_but_cb(bContext *C, void *arg_but, void *arg_index)
 }
 
 /* create buttons for an item with an RNA array */
-static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h), int expand, int slider, int toggle, int icon_only)
+static void ui_item_array(uiLayout *layout, uiBlock *block, const char *name, int icon,
+                          PointerRNA *ptr, PropertyRNA *prop, int len, int x, int y, int w, int UNUSED(h),
+                          int expand, int slider, int toggle, int icon_only)
 {
 	uiStyle *style = layout->root->style;
 	uiBut *but;
@@ -2306,11 +2308,14 @@ uiLayout *uiLayoutBox(uiLayout *layout)
 	return (uiLayout *)ui_layout_box(layout, ROUNDBOX);
 }
 
-uiLayout *uiLayoutListBox(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr, PropertyRNA *actprop)
+uiLayout *uiLayoutListBox(uiLayout *layout, uiList *ui_list, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr,
+                          PropertyRNA *actprop)
 {
 	uiLayoutItemBx *box = ui_layout_box(layout, LISTBOX);
 	uiBut *but = box->roundbox;
 
+	but->custom_data = ui_list;
+
 	but->rnasearchpoin = *ptr;
 	but->rnasearchprop = prop;
 	but->rnapoin = *actptr;
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 5b6a609e4d2..9fbf2fe8898 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -112,7 +112,7 @@ static int panel_aligned(ScrArea *sa, ARegion *ar)
 	else if (sa->spacetype == SPACE_FILE && ar->regiontype == RGN_TYPE_CHANNELS)
 		return BUT_VERTICAL;
 	else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW)
-		return BUT_VERTICAL; 
+		return BUT_VERTICAL;
 	else if (ELEM3(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS))
 		return BUT_VERTICAL;
 	
@@ -812,8 +812,8 @@ static void ui_panels_size(ScrArea *sa, ARegion *ar, int *x, int *y)
 {
 	Panel *pa;
 	int align = panel_aligned(sa, ar);
-	int sizex = UI_PANEL_WIDTH;
-	int sizey = UI_PANEL_WIDTH;
+	int sizex = 0;
+	int sizey = 0;
 
 	/* compute size taken up by panels, for setting in view2d */
 	for (pa = ar->panels.first; pa; pa = pa->next) {
@@ -834,6 +834,11 @@ static void ui_panels_size(ScrArea *sa, ARegion *ar, int *x, int *y)
 		}
 	}
 
+	if (sizex == 0)
+		sizex = UI_PANEL_WIDTH;
+	if (sizey == 0)
+		sizey = -UI_PANEL_WIDTH;
+	
 	*x = sizex;
 	*y = sizey;
 }
@@ -956,6 +961,25 @@ void uiDrawPanels(const bContext *C, ARegion *ar)
 	}
 }
 
+void uiScalePanels(ARegion *ar, float new_width)
+{
+	uiBlock *block;
+	uiBut *but;
+	
+	for (block = ar->uiblocks.first; block; block = block->next) {
+		if (block->panel) {
+			float fac = new_width / (float)block->panel->sizex;
+			printf("scaled %f\n", fac);
+			block->panel->sizex = new_width;
+			
+			for (but = block->buttons.first; but; but = but->next) {
+				but->rect.xmin *= fac;
+				but->rect.xmax *= fac;
+			}
+		}
+	}
+}
+
 /* ------------ panel merging ---------------- */
 
 static void check_panel_overlap(ARegion *ar, Panel *panel)
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 57c126c31c5..4a8ad5d24a6 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -651,10 +651,10 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
 	ofsx = 0; //(but->block->panel) ? but->block->panel->ofsx : 0;
 	ofsy = 0; //(but->block->panel) ? but->block->panel->ofsy : 0;
 
-	rect_fl.xmin = (but->rect.xmin + but->rect.xmax) * 0.5f + ofsx - (TIP_BORDER_X );
-	rect_fl.xmax = rect_fl.xmin + fontw + (TIP_BORDER_X );
-	rect_fl.ymax = but->rect.ymin + ofsy - (TIP_BORDER_Y );
-	rect_fl.ymin = rect_fl.ymax - fonth  - (TIP_BORDER_Y );
+	rect_fl.xmin = (but->rect.xmin + but->rect.xmax) * 0.5f + ofsx - TIP_BORDER_X;
+	rect_fl.xmax = rect_fl.xmin + fontw + TIP_BORDER_X;
+	rect_fl.ymax = but->rect.ymin + ofsy - TIP_BORDER_Y;
+	rect_fl.ymin = rect_fl.ymax - fonth  - TIP_BORDER_Y;
 
 #undef TIP_MARGIN_Y
 #undef TIP_BORDER_X
@@ -896,8 +896,12 @@ void ui_searchbox_apply(uiBut *but, ARegion *ar)
 void ui_searchbox_event(bContext *C, ARegion *ar, uiBut *but, wmEvent *event)
 {
 	uiSearchboxData *data = ar->regiondata;
+	int type = event->type, val = event->val;
 	
-	switch (event->type) {
+	if (type == MOUSEPAN)
+		ui_pan_to_scroll(event, &type, &val);
+	
+	switch (type) {
 		case WHEELUPMOUSE:
 		case UPARROWKEY:
 			ui_searchbox_select(C, ar, but, -1);
@@ -1527,6 +1531,7 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar)
 
 static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
 {
+	uiBut *bt;
 	int width = UI_ThemeMenuShadowWidth();
 	int winx, winy;
 
@@ -1536,7 +1541,6 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
 
 	winx = WM_window_pixels_x(window);
 	winy = WM_window_pixels_y(window);
-	// wm_window_get_size(window, &winx, &winy);
 	
 	if (block->rect.xmin < width)
 		block->rect.xmin = width;
@@ -1547,6 +1551,15 @@ static void ui_popup_block_clip(wmWindow *window, uiBlock *block)
 		block->rect.ymin = width;
 	if (block->rect.ymax > winy - MENU_TOP)
 		block->rect.ymax = winy - MENU_TOP;
+	
+	/* ensure menu items draw inside left/right boundary */
+	for (bt = block->buttons.first; bt; bt = bt->next) {
+		if (bt->rect.xmin < block->rect.xmin)
+			bt->rect.xmin = block->rect.xmin;
+		if (bt->rect.xmax > block->rect.xmax)
+			bt->rect.xmax = block->rect.xmax;
+	}
+
 }
 
 void ui_popup_block_scrolltest(uiBlock *block)
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 33f647d1db6..f704ac0e203 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -31,18 +31,16 @@
 
 #include "MEM_guardedalloc.h"
 
-#include "DNA_anim_types.h"
 #include "DNA_dynamicpaint_types.h"
-#include "DNA_key_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_object_types.h"
-#include "DNA_userdef_types.h"
 
 #include "BLI_utildefines.h"
 #include "BLI_string.h"
 #include "BLI_ghash.h"
 #include "BLI_rect.h"
 
+#include "BLF_api.h"
 #include "BLF_translation.h"
 
 #include "BKE_animsys.h"
@@ -59,6 +57,7 @@
 #include "BKE_displist.h"
 #include "BKE_sca.h"
 #include "BKE_scene.h"
+#include "BKE_screen.h"
 
 #include "ED_screen.h"
 #include "ED_object.h"
@@ -71,11 +70,9 @@
 #include "WM_types.h"
 
 #include "UI_interface.h"
+#include "UI_interface_icons.h"
 #include "interface_intern.h"
 
-#include "BLF_api.h"
-#include "BLF_translation.h"
-
 void UI_template_fix_linking(void)
 {
 }
@@ -1090,7 +1087,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
 	// int rb_col; // UNUSED
 
 	/* get constraint typeinfo */
-	cti = constraint_get_typeinfo(con);
+	cti = BKE_constraint_get_typeinfo(con);
 	if (cti == NULL) {
 		/* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
 		BLI_strncpy(typestr, (con->type == CONSTRAINT_TYPE_NULL) ? "Null" : "Unknown", sizeof(typestr));
@@ -1099,7 +1096,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
 		BLI_strncpy(typestr, cti->name, sizeof(typestr));
 		
 	/* determine whether constraint is proxy protected or not */
-	if (proxylocked_constraints_owner(ob, pchan))
+	if (BKE_proxylocked_constraints_owner(ob, pchan))
 		proxy_protected = (con->flag & CONSTRAINT_PROXY_LOCAL) == 0;
 	else
 		proxy_protected = 0;
@@ -1161,7 +1158,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con)
 		 *
 		 *  Up/Down buttons should only be shown (or not grayed - todo) if they serve some purpose.
 		 */
-		if (proxylocked_constraints_owner(ob, pchan)) {
+		if (BKE_proxylocked_constraints_owner(ob, pchan)) {
 			if (con->prev) {
 				prev_proxylock = (con->prev->flag & CONSTRAINT_PROXY_LOCAL) ? 0 : 1;
 			}
@@ -2341,437 +2338,195 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam
 
 
 /************************* List Template **************************/
-
-static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big)
+static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UNUSED(C), struct uiLayout *layout,
+                                     struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon,
+                                     struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname),
+                                     int UNUSED(index))
 {
-	ID *id = NULL;
-	int icon;
-
-	if (!itemptr->data)
-		return rnaicon;
-
-	/* try ID, material or texture slot */
-	if (RNA_struct_is_ID(itemptr->type)) {
-		id = itemptr->id.data;
-	}
-	else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
-		id = RNA_pointer_get(itemptr, "material").data;
-	}
-	else if (RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
-		id = RNA_pointer_get(itemptr, "texture").data;
-	}
-	else if (RNA_struct_is_a(itemptr->type, &RNA_DynamicPaintSurface)) {
-		DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data;
-
-		if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) return ICON_TEXTURE_SHADED;
-		else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) return ICON_OUTLINER_DATA_MESH;
-		else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return ICON_FILE_IMAGE;
-	}
-
-	/* get icon from ID */
-	if (id) {
-		icon = ui_id_icon_get(C, id, big);
-
-		if (icon)
-			return icon;
-	}
-
-	return rnaicon;
-}
-
-static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i,
-                          int rnaicon, PointerRNA *activeptr, PropertyRNA *activeprop, const char *prop_list_id)
-{
-	uiBlock *block = uiLayoutGetBlock(layout);
-	uiBut *but;
-	uiLayout *split, *overlap, *sub, *row;
 	char *namebuf;
 	const char *name;
-	int icon;
-
-	overlap = uiLayoutOverlap(layout);
-
-	/* list item behind label & other buttons */
-	sub = uiLayoutRow(overlap, FALSE);
-
-	but = uiDefButR_prop(block, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr, activeprop,
-	                     0, 0, i, 0, 0, "");
-	uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
-
-	sub = uiLayoutRow(overlap, FALSE);
-
-	/* retrieve icon and name */
-	icon = list_item_icon_get(C, itemptr, rnaicon, 0);
-	if (icon == ICON_NONE || icon == ICON_DOT)
-		icon = 0;
 
 	namebuf = RNA_struct_name_get_alloc(itemptr, NULL, 0, NULL);
 	name = (namebuf) ? namebuf : "";
 
-	/* hardcoded types */
-	if (itemptr->type == &RNA_MeshTexturePolyLayer || itemptr->type == &RNA_MeshLoopColorLayer) {
-		uiItemL(sub, name, icon);
-		uiBlockSetEmboss(block, UI_EMBOSSN);
-		uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render",
-		              0, 0, 0, 0, 0, NULL);
-		uiBlockSetEmboss(block, UI_EMBOSS);
+	/* Simplest one! */
+	switch (ui_list->layout_type) {
+	case UILST_LAYOUT_GRID:
+		uiItemL(layout, "", icon);
+		break;
+	case UILST_LAYOUT_DEFAULT:
+	case UILST_LAYOUT_COMPACT:
+	default:
+		uiItemL(layout, name, icon);
+		break;
 	}
-	else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
-		uiItemL(sub, name, icon);
-		uiBlockSetEmboss(block, UI_EMBOSS);
-		uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
-	}
-#ifdef WITH_FREESTYLE
-	else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer) || 
-	         RNA_struct_is_a(itemptr->type, &RNA_FreestyleLineSet)) {
-#else
-	else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
-#endif
-		uiItemL(sub, name, icon);
-		uiBlockSetEmboss(block, UI_EMBOSS);
-		uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0,  NULL);
-	}
-	else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
-		/* provision to draw active node name */
-		Material *ma, *manode;
-		Scene *scene = CTX_data_scene(C);
-		Object *ob = (Object *)ptr->id.data;
-		int index = (Material **)itemptr->data - ob->mat;
 		
-		/* default item with material base name */
-		uiItemL(sub, name, icon);
-		
-		ma = give_current_material(ob, index + 1);
-		if (ma && !BKE_scene_use_new_shading_nodes(scene)) {
-			manode = give_node_material(ma);
-			if (manode) {
-				char str[MAX_ID_NAME + 12];
-				BLI_snprintf(str, sizeof(str), IFACE_("Node %s"), manode->id.name + 2);
-				uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1));
-			}
-			else if (ma->use_nodes) {
-				uiItemL(sub, IFACE_("Node "), ICON_NONE);
-			}
-		}
-	}
-	else if (itemptr->type == &RNA_ShapeKey) {
-		Object *ob = (Object *)activeptr->data;
-		Key *key = (Key *)itemptr->id.data;
-		KeyBlock *kb = (KeyBlock *)itemptr->data;
-
-		split = uiLayoutSplit(sub, 0.66f, FALSE);
-
-		uiItemL(split, name, icon);
-
-		uiBlockSetEmboss(block, UI_EMBOSSN);
-		row = uiLayoutRow(split, TRUE);
-		if (i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE);
-		else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
-		uiItemR(row, itemptr, "mute", 0, "", ICON_NONE);
-
-		if ((kb->flag & KEYBLOCK_MUTE) ||
-		    (ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH)))
-		{
-			uiLayoutSetActive(row, FALSE);
-		}
-		uiBlockSetEmboss(block, UI_EMBOSS);
-	}
-	else if (itemptr->type == &RNA_VertexGroup) {
-		bDeformGroup *dg = (bDeformGroup *)itemptr->data;
-		uiItemL(sub, name, icon);
-		/* RNA does not allow nice lock icons, use lower level buttons */
-#if 0
-		uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "lock_weight", 0, 0, 0, 0, 0,  NULL);
-#else
-		uiBlockSetEmboss(block, UI_EMBOSSN);
-		uiDefIconButBitC(block, TOG, DG_LOCK_WEIGHT, 0, (dg->flag & DG_LOCK_WEIGHT) ? ICON_LOCKED : ICON_UNLOCKED,
-		                 0, 0, UI_UNIT_X, UI_UNIT_Y, &dg->flag, 0, 0, 0, 0,
-		                 TIP_("Maintain relative weights while painting"));
-		uiBlockSetEmboss(block, UI_EMBOSS);
-#endif
-	}
-	else if (itemptr->type == &RNA_KeyingSetPath) {
-		KS_Path *ksp = (KS_Path *)itemptr->data;
-		
-		/* icon needs to be the type of ID which is currently active */
-		RNA_enum_icon_from_value(id_type_items, ksp->idtype, &icon);
-		
-		/* nothing else special to do... */
-		uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
-	}
-	else if (itemptr->type == &RNA_DynamicPaintSurface) {
-		char name_final[96];
-		const char *enum_name;
-		PropertyRNA *prop = RNA_struct_find_property(itemptr, "surface_type");
-		DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data;
-
-		RNA_property_enum_name(C, itemptr, prop, RNA_property_enum_get(itemptr, prop), &enum_name);
-
-		BLI_snprintf(name_final, sizeof(name_final), "%s (%s)", name, enum_name);
-		uiItemL(sub, name_final, icon);
-		if (dynamicPaint_surfaceHasColorPreview(surface)) {
-			uiBlockSetEmboss(block, UI_EMBOSSN);
-			uiDefIconButR(block, OPTION, 0,
-			              (surface->flags & MOD_DPAINT_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON,
-			              0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "show_preview", 0, 0, 0, 0, 0, NULL);
-			uiBlockSetEmboss(block, UI_EMBOSS);
-		}
-		uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "is_active", i, 0, 0, 0, 0,  NULL);
-	}
-	else if (itemptr->type == &RNA_MovieTrackingObject) {
-		MovieTrackingObject *tracking_object = (MovieTrackingObject *)itemptr->data;
-
-		split = uiLayoutSplit(sub, 0.75f, FALSE);
-		if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
-			uiItemL(split, name, ICON_CAMERA_DATA);
-		}
-		else {
-			uiItemL(split, name, ICON_OBJECT_DATA);
-		}
-	}
-	else if (itemptr->type == &RNA_MaskLayer) {
-		split = uiLayoutRow(sub, FALSE);
-
-		uiItemL(split, name, icon);
-
-		uiBlockSetEmboss(block, UI_EMBOSSN);
-		row = uiLayoutRow(split, TRUE);
-		uiItemR(row, itemptr, "alpha", 0, "", ICON_NONE);
-		uiItemR(row, itemptr, "hide", 0, "", ICON_NONE);
-		uiItemR(row, itemptr, "hide_select", 0, "", ICON_NONE);
-		uiItemR(row, itemptr, "hide_render", 0, "", ICON_NONE);
-
-		uiBlockSetEmboss(block, UI_EMBOSS);
-	}
-
-	/* There is a last chance to display custom controls (in addition to the name/label):
-	 * If the given item property group features a string property named as prop_list,
-	 * this tries to add controls for all properties of the item listed in that string property.
-	 * (colon-separated names).
-	 *
-	 * This is especially useful for python. E.g., if you list a collection of this property
-	 * group:
-	 *
-	 * class TestPropertyGroup(bpy.types.PropertyGroup):
-	 *     bool    = BoolProperty(default=False)
-	 *     integer = IntProperty()
-	 *     string  = StringProperty()
-	 * 
-	 *     # A string of all identifiers (colon-separated) which property's controls should be
-	 *     # displayed in a template_list.
-	 *     template_list_controls = StringProperty(default="integer:bool:string", options={"HIDDEN"})
-	 *
-	 * ... you'll get a numfield for the integer prop, a check box for the bool prop, and a textfield
-	 * for the string prop, after the name of each item of the collection.
-	 */
-	else if (prop_list_id) {
-		row = uiLayoutRow(sub, TRUE);
-		uiItemL(row, name, icon);
-
-		/* XXX: Check, as sometimes we get an itemptr looking like
-		 *      {id = {data = 0x0}, type = 0x0, data = 0x0}
-		 *      which would obviously produce a sigsev... */
-		if (itemptr->type) {
-			/* If the special property is set for the item, and it is a collection... */
-			PropertyRNA *prop_list = RNA_struct_find_property(itemptr, prop_list_id);
-
-			if (prop_list && RNA_property_type(prop_list) == PROP_STRING) {
-				int prop_names_len;
-				char *prop_names = RNA_property_string_get_alloc(itemptr, prop_list, NULL, 0, &prop_names_len);
-				char *prop_names_end = prop_names + prop_names_len;
-				char *id = prop_names;
-				char *id_next;
-				while (id < prop_names_end) {
-					if ((id_next = strchr(id, ':'))) *id_next++ = '\0';
-					else id_next = prop_names_end;
-					uiItemR(row, itemptr, id, 0, NULL, ICON_NONE);
-					id = id_next;
-				}
-				MEM_freeN(prop_names);
-			}
-		}
-	}
-
-	else
-		uiItemL(sub, name, icon);  /* fails, backdrop LISTROW... */
-
 	/* free name */
 	if (namebuf) {
 		MEM_freeN(namebuf);
 	}
 }
 
-void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *activeptr,
-                    const char *activepropname, const char *prop_list, int rows, int maxrows, int listtype)
+void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
+                    PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr,
+                    const char *active_propname, int rows, int maxrows, int layout_type)
 {
+	uiListType *ui_list_type;
+	uiList *ui_list = NULL;
+	ARegion *ar;
+	uiListDrawItemFunc draw_item;
+
 	PropertyRNA *prop = NULL, *activeprop;
 	PropertyType type, activetype;
 	StructRNA *ptype;
-	uiLayout *box, *row, *col;
-	uiBlock *block;
+	uiLayout *box, *row, *col, *sub, *overlap;
+	uiBlock *block, *subblock;
 	uiBut *but;
-	Panel *pa;
-	const char *name;
+
+	char ui_list_id[UI_MAX_NAME_STR];
 	char numstr[32];
-	int rnaicon = 0, icon = 0, i = 0, activei = 0, len = 0, items, found, min, max;
+	int rnaicon = ICON_NONE, icon = ICON_NONE;
+	int i = 0, activei = 0;
+	int len = 0;
+	int items;
+	int found;
+	int min, max;
 
 	/* validate arguments */
 	block = uiLayoutGetBlock(layout);
-	pa = block->panel;
 
-	if (!pa) {
-		RNA_warning("Only works inside a panel");
+	if (!active_dataptr->data) {
+		RNA_warning("No active data");
 		return;
 	}
 
-	if (!activeptr->data)
-		return;
-	
-	if (ptr->data) {
-		prop = RNA_struct_find_property(ptr, propname);
+	if (dataptr->data) {
+		prop = RNA_struct_find_property(dataptr, propname);
 		if (!prop) {
-			RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+			RNA_warning("Property not found: %s.%s", RNA_struct_identifier(dataptr->type), propname);
 			return;
 		}
 	}
 
-	activeprop = RNA_struct_find_property(activeptr, activepropname);
+	activeprop = RNA_struct_find_property(active_dataptr, active_propname);
 	if (!activeprop) {
-		RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), activepropname);
+		RNA_warning("Property not found: %s.%s", RNA_struct_identifier(active_dataptr->type), active_propname);
 		return;
 	}
 
 	if (prop) {
 		type = RNA_property_type(prop);
 		if (type != PROP_COLLECTION) {
-			RNA_warning("uiExpected collection property");
+			RNA_warning("Expected a collection data property");
 			return;
 		}
 	}
 
 	activetype = RNA_property_type(activeprop);
 	if (activetype != PROP_INT) {
-		RNA_warning("Expected integer property");
+		RNA_warning("Expected an integer active data property");
 		return;
 	}
 
 	/* get icon */
-	if (ptr->data && prop) {
-		ptype = RNA_property_pointer_type(ptr, prop);
+	if (dataptr->data && prop) {
+		ptype = RNA_property_pointer_type(dataptr, prop);
 		rnaicon = RNA_struct_ui_icon(ptype);
 	}
 
 	/* get active data */
-	activei = RNA_property_int_get(activeptr, activeprop);
+	activei = RNA_property_int_get(active_dataptr, activeprop);
 
-	if (listtype == 'i') {
-		box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
-		col = uiLayoutColumn(box, TRUE);
-		row = uiLayoutRow(col, FALSE);
+	/* Find the uiList type. */
+	ui_list_type = WM_uilisttype_find(listtype_name, FALSE);
 
-		if (ptr->data && prop) {
-			/* create list items */
-			RNA_PROP_BEGIN (ptr, itemptr, prop)
-			{
-				/* create button */
-				if (!(i % 9))
-					row = uiLayoutRow(col, FALSE);
-
-				icon = list_item_icon_get(C, &itemptr, rnaicon, 1);
-				but = uiDefIconButR_prop(block, LISTROW, 0, icon, 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr,
-				                         activeprop, 0, 0, i, 0, 0, "");
-				uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
-				
-
-				i++;
+	if (ui_list_type == NULL) {
+		RNA_warning("List type %s not found", listtype_name);
+		return;
 			}
-			RNA_PROP_END;
-		}
-	}
-	else if (listtype == 'c') {
-		/* compact layout */
 
-		row = uiLayoutRow(layout, TRUE);
+	draw_item = ui_list_type->draw_item ? ui_list_type->draw_item : uilist_draw_item_default;
 
-		if (ptr->data && prop) {
-			/* create list items */
-			RNA_PROP_BEGIN (ptr, itemptr, prop)
-			{
-				found = (activei == i);
+	/* Find or add the uiList to the current Region. */
+	/* We tag the list id with the list type... */
+	BLI_snprintf(ui_list_id, sizeof(ui_list_id), "%s_%s", ui_list_type->idname, list_id ? list_id : "");
 
-				if (found) {
-					/* create button */
-					name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL);
-					icon = list_item_icon_get(C, &itemptr, rnaicon, 0);
-					uiItemL(row, (name) ? name : "", icon);
+	ar = CTX_wm_region(C);
+	ui_list = BLI_findstring(&ar->ui_lists, ui_list_id, offsetof(uiList, list_id));
 
-					if (name) {
-						MEM_freeN((void *)name);
+	if (!ui_list) {
+		ui_list = MEM_callocN(sizeof(uiList), __func__);
+		BLI_strncpy(ui_list->list_id, ui_list_id, sizeof(ui_list->list_id));
+		BLI_addtail(&ar->ui_lists, ui_list);
 					}
-				}
 
-				i++;
-			}
-			RNA_PROP_END;
-		}
+	/* Because we can't actually pass type across save&load... */
+	ui_list->type = ui_list_type;
+	ui_list->layout_type = layout_type;
 
-		/* if not found, add in dummy button */
-		if (i == 0)
-			uiItemL(row, "", ICON_NONE);
-
-		/* next/prev button */
-		BLI_snprintf(numstr, sizeof(numstr), "%d :", i);
-		but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, activeptr,
-		                             activeprop, 0, 0, 0, 0, 0, "");
-		if (i == 0)
-			uiButSetFlag(but, UI_BUT_DISABLED);
-	}
-	else {
+	switch (layout_type) {
+	case UILST_LAYOUT_DEFAULT:
 		/* default rows */
 		if (rows == 0)
 			rows = 5;
 		if (maxrows == 0)
 			maxrows = 5;
-		if (pa->list_grip_size != 0)
-			rows = pa->list_grip_size;
+		if (ui_list->list_grip_size != 0)
+			rows = ui_list->list_grip_size;
 
 		/* layout */
-		box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
+		box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop);
 		row = uiLayoutRow(box, FALSE);
 		col = uiLayoutColumn(row, TRUE);
 
 		/* init numbers */
-		RNA_property_int_range(activeptr, activeprop, &min, &max);
+		RNA_property_int_range(active_dataptr, activeprop, &min, &max);
 
 		if (prop)
-			len = RNA_property_collection_length(ptr, prop);
+			len = RNA_property_collection_length(dataptr, prop);
 		items = CLAMPIS(len, rows, MAX2(rows, maxrows));
 
 		/* if list length changes and active is out of view, scroll to it */
-		if (pa->list_last_len != len)
-			if ((activei < pa->list_scroll || activei >= pa->list_scroll + items))
-				pa->list_scroll = activei;
+		if ((ui_list->list_last_len != len) &&
+		    (activei < ui_list->list_scroll || activei >= ui_list->list_scroll + items)) {
+			ui_list->list_scroll = activei;
+		}
 
-		pa->list_scroll = MIN2(pa->list_scroll, len - items);
-		pa->list_scroll = MAX2(pa->list_scroll, 0);
-		pa->list_size = items;
-		pa->list_last_len = len;
+		ui_list->list_scroll = min_ii(ui_list->list_scroll, len - items);
+		ui_list->list_scroll = max_ii(ui_list->list_scroll, 0);
+		ui_list->list_size = items;
+		ui_list->list_last_len = len;
 
-		if (ptr->data && prop) {
+		if (dataptr->data && prop) {
 			/* create list items */
-			RNA_PROP_BEGIN (ptr, itemptr, prop)
+			RNA_PROP_BEGIN (dataptr, itemptr, prop)
 			{
-				if (i >= pa->list_scroll && i < pa->list_scroll + items)
-					list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activeprop, prop_list);
+				if (i >= ui_list->list_scroll && i < ui_list->list_scroll + items) {
+					subblock = uiLayoutGetBlock(col);
+					overlap = uiLayoutOverlap(col);
 
+					/* list item behind label & other buttons */
+					sub = uiLayoutRow(overlap, FALSE);
+
+					but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+					                     active_dataptr, activeprop, 0, 0, i, 0, 0, "");
+					uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
+
+					sub = uiLayoutRow(overlap, FALSE);
+
+					icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE);
+					if (icon == ICON_DOT)
+						icon = ICON_NONE;
+					draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i);
+				}
 				i++;
 			}
 			RNA_PROP_END;
 		}
 
 		/* add dummy buttons to fill space */
-		while (i < pa->list_scroll + items) {
-			if (i >= pa->list_scroll)
+		while (i < ui_list->list_scroll + items) {
+			if (i >= ui_list->list_scroll)
 				uiItemL(col, "", ICON_NONE);
 			i++;
 		}
@@ -2779,9 +2534,75 @@ void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *
 		/* add scrollbar */
 		if (len > items) {
 			col = uiLayoutColumn(row, FALSE);
-			uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &pa->list_scroll,
+			uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &ui_list->list_scroll,
 			          0, len - items, items, 0, "");
 		}
+		break;
+	case UILST_LAYOUT_COMPACT:
+		row = uiLayoutRow(layout, TRUE);
+
+		if (dataptr->data && prop) {
+			/* create list items */
+			RNA_PROP_BEGIN (dataptr, itemptr, prop)
+			{
+				found = (activei == i);
+
+				if (found) {
+					icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE);
+					if (icon == ICON_DOT)
+						icon = ICON_NONE;
+					draw_item(ui_list, C, row, dataptr, &itemptr, icon, active_dataptr, active_propname, i);
+	}
+
+				i++;
+}
+			RNA_PROP_END;
+		}
+
+		/* if list is empty, add in dummy button */
+		if (i == 0)
+			uiItemL(row, "", ICON_NONE);
+
+		/* next/prev button */
+		BLI_snprintf(numstr, sizeof(numstr), "%d :", i);
+		but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y,
+		                             active_dataptr, activeprop, 0, 0, 0, 0, 0, "");
+		if (i == 0)
+			uiButSetFlag(but, UI_BUT_DISABLED);
+		break;
+	case UILST_LAYOUT_GRID:
+		box = uiLayoutListBox(layout, ui_list, dataptr, prop, active_dataptr, activeprop);
+		col = uiLayoutColumn(box, TRUE);
+		row = uiLayoutRow(col, FALSE);
+
+		if (dataptr->data && prop) {
+			/* create list items */
+			RNA_PROP_BEGIN (dataptr, itemptr, prop)
+			{
+				/* create button */
+				if (!(i % 9))
+					row = uiLayoutRow(col, FALSE);
+
+				subblock = uiLayoutGetBlock(row);
+				overlap = uiLayoutOverlap(row);
+
+				/* list item behind label & other buttons */
+				sub = uiLayoutRow(overlap, FALSE);
+
+				but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+				                     active_dataptr, activeprop, 0, 0, i, 0, 0, "");
+				uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
+
+				sub = uiLayoutRow(overlap, FALSE);
+
+				icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE);
+				draw_item(ui_list, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i);
+
+				i++;
+			}
+			RNA_PROP_END;
+		}
+		break;
 	}
 }
 
@@ -3095,7 +2916,7 @@ void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char
 
 	colorspace_settings_ptr = RNA_property_pointer_get(ptr, prop);
 
-	uiItemL(layout, "Color Space:", ICON_NONE);
+	uiItemL(layout, "Input Color Space:", ICON_NONE);
 	uiItemR(layout, &colorspace_settings_ptr, "name", 0, "", ICON_NONE);
 }
 
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 4687647223a..e4ad3a4f73b 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -1324,11 +1324,13 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
 			/* icons default draw 0.8f x height */
 			rect->xmin += (int)(0.8f * BLI_rcti_size_y(rect));
 
-			if (but->editstr || (but->flag & UI_TEXT_LEFT))
-				rect->xmin += 0.4f * U.widget_unit;
+			if (but->editstr || (but->flag & UI_TEXT_LEFT)) {
+				rect->xmin += (0.4f * U.widget_unit) / but->block->aspect;
+			}
+		}
+		else if ((but->flag & UI_TEXT_LEFT)) {
+			rect->xmin += (0.4f * U.widget_unit) / but->block->aspect;
 		}
-		else if ((but->flag & UI_TEXT_LEFT))
-			rect->xmin += 0.4f * U.widget_unit;
 
 		/* always draw text for textbutton cursor */
 		widget_draw_text(fstyle, wcol, but, rect);
@@ -2319,7 +2321,7 @@ void ui_draw_link_bezier(const rcti *rect)
 
 		glEnableClientState(GL_VERTEX_ARRAY);
 		glVertexPointer(2, GL_FLOAT, 0, coord_array);
-		glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL);
+		glDrawArrays(GL_LINE_STRIP, 0, LINK_RESOL + 1);
 		glDisableClientState(GL_VERTEX_ARRAY);
 
 		glDisable(GL_BLEND);
@@ -3467,14 +3469,14 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, const char *name, int ic
 	if (iconid) {
 		float height, aspect;
 		int xs = rect->xmin + 0.2f * UI_UNIT_X;
-		int ys = 1 + (rect->ymin + rect->ymax - UI_DPI_ICON_SIZE) / 2;
+		int ys = rect->ymin + 0.1f * BLI_rcti_size_y(rect);
 		
 		/* icons are 80% of height of button (16 pixels inside 20 height) */
 		height = 0.8f * BLI_rcti_size_y(rect);
 		aspect = ICON_DEFAULT_HEIGHT / height;
-
+		
 		glEnable(GL_BLEND);
-		UI_icon_draw_aspect(xs, ys, iconid, aspect, 0.5f); /* XXX scale weak get from fstyle? */
+		UI_icon_draw_aspect(xs, ys, iconid, aspect, 1.0f); /* XXX scale weak get from fstyle? */
 		glDisable(GL_BLEND);
 	}
 }
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index fd84c1fd4c4..361bdfacbb2 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -364,8 +364,14 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
 					cp = ts->syntaxc; break;
 				case TH_SYNTAX_L:
 					cp = ts->syntaxl; break;
+				case TH_SYNTAX_D:
+					cp = ts->syntaxd; break;
+				case TH_SYNTAX_R:
+					cp = ts->syntaxr; break;
 				case TH_SYNTAX_N:
 					cp = ts->syntaxn; break;
+				case TH_SYNTAX_S:
+					cp = ts->syntaxs; break;
 
 				case TH_NODE:
 					cp = ts->syntaxl; break;
@@ -879,8 +885,8 @@ void ui_theme_init_default(void)
 	rgba_char_args_set_fl(btheme->tima.preview_stitch_vert, 0.0, 0.0, 1.0, 0.2);
 	rgba_char_args_set_fl(btheme->tima.preview_stitch_stitchable, 0.0, 1.0, 0.0, 1.0);
 	rgba_char_args_set_fl(btheme->tima.preview_stitch_unstitchable, 1.0, 0.0, 0.0, 1.0);
-    rgba_char_args_set_fl(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140);
-    
+	rgba_char_args_set_fl(btheme->tima.preview_stitch_active, 0.886, 0.824, 0.765, 0.140);
+
 	/* space text */
 	btheme->text = btheme->tv3d;
 	rgba_char_args_set(btheme->text.back,   153, 153, 153, 255);
@@ -890,10 +896,13 @@ void ui_theme_init_default(void)
 	
 	/* syntax highlighting */
 	rgba_char_args_set(btheme->text.syntaxn,    0, 0, 200, 255);    /* Numbers  Blue*/
-	rgba_char_args_set(btheme->text.syntaxl,    100, 0, 0, 255);    /* Strings  red */
-	rgba_char_args_set(btheme->text.syntaxc,    0, 100, 50, 255);   /* Comments greenish */
-	rgba_char_args_set(btheme->text.syntaxv,    95, 95, 0, 255);    /* Special */
-	rgba_char_args_set(btheme->text.syntaxb,    128, 0, 80, 255);   /* Builtin, red-purple */
+	rgba_char_args_set(btheme->text.syntaxl,    100, 0, 0, 255);    /* Strings  Red */
+	rgba_char_args_set(btheme->text.syntaxc,    0, 100, 50, 255);   /* Comments  Greenish */
+	rgba_char_args_set(btheme->text.syntaxv,    95, 95, 0, 255);    /* Special  Yellow*/
+	rgba_char_args_set(btheme->text.syntaxd,    50, 0, 140, 255);   /* Decorator/Preprocessor Dir.  Blue-purple */
+	rgba_char_args_set(btheme->text.syntaxr,    140, 60, 0, 255);   /* Reserved  Orange*/
+	rgba_char_args_set(btheme->text.syntaxb,    128, 0, 80, 255);   /* Builtin  Red-purple */
+	rgba_char_args_set(btheme->text.syntaxs,    76, 76, 76, 255);   /* Grey (mix between fg/bg) */
 	
 	/* space oops */
 	btheme->toops = btheme->tv3d;
@@ -2106,6 +2115,15 @@ void init_userdef_do_versions(void)
 			}
 		}
 	}
+
+	if (!MAIN_VERSION_ATLEAST(bmain, 266, 4)) {
+		bTheme *btheme;
+		for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+			rgba_char_args_set(btheme->text.syntaxd,    50, 0, 140, 255);   /* Decorator/Preprocessor Dir.  Blue-purple */
+			rgba_char_args_set(btheme->text.syntaxr,    140, 60, 0, 255);   /* Reserved  Orange */
+			rgba_char_args_set(btheme->text.syntaxs,    76, 76, 76, 255);   /* Grey (mix between fg/bg) */
+		}
+	}
 	
 	if (U.pixelsize == 0.0f)
 		U.pixelsize = 1.0f;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 190d90b3c36..d0d631e14a5 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -60,6 +60,8 @@
 
 #include "interface_intern.h"
 
+static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers);
+
 /* *********************************************************************** */
 
 /* XXX still unresolved: scrolls hide/unhide vs region mask handling */
@@ -73,15 +75,15 @@
  */
 static int view2d_scroll_mapped(int scroll)
 {
-	if (scroll & V2D_SCROLL_HORIZONTAL_HIDE)
+	if (scroll & V2D_SCROLL_HORIZONTAL_FULLR)
 		scroll &= ~(V2D_SCROLL_HORIZONTAL);
-	if (scroll & V2D_SCROLL_VERTICAL_HIDE)
+	if (scroll & V2D_SCROLL_VERTICAL_FULLR)
 		scroll &= ~(V2D_SCROLL_VERTICAL);
 	return scroll;
 }
 
 /* called each time cur changes, to dynamically update masks */
-static void view2d_masks(View2D *v2d)
+static void view2d_masks(View2D *v2d, int check_scrollers)
 {
 	int scroll;
 	
@@ -90,19 +92,26 @@ static void view2d_masks(View2D *v2d)
 	v2d->mask.xmax = v2d->winx - 1; /* -1 yes! masks are pixels */
 	v2d->mask.ymax = v2d->winy - 1;
 
-#if 0
-	/* XXX see above */
-	v2d->scroll &= ~(V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_VERTICAL_HIDE);
-	/* check size if: */
-	if (v2d->scroll & V2D_SCROLL_HORIZONTAL)
-		if (!(v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL))
-			if (BLI_rctf_size_x(&v2d->tot) <= BLI_rcti_size_x(&v2d->cur))
-				v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
-	if (v2d->scroll & V2D_SCROLL_VERTICAL)
-		if (!(v2d->scroll & V2D_SCROLL_SCALE_VERTICAL))
-			if (BLI_rctf_size_y(&v2d->tot) <= BLI_rctf_size_y(&v2d->cur))
-				v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE;
-#endif
+	if (check_scrollers) {
+		/* check size if hiding flag is set: */
+		if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) {
+			if (!(v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL)) {
+				if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur))
+					v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR;
+				else
+					v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR;
+			}
+		}
+		if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) {
+			if (!(v2d->scroll & V2D_SCROLL_SCALE_VERTICAL)) {
+				if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur))
+					v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR;
+				else
+					v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR;
+			}
+		}
+	}
+	
 	scroll = view2d_scroll_mapped(v2d->scroll);
 	
 	/* scrollers shrink mask area, but should be based off regionsize 
@@ -126,8 +135,8 @@ static void view2d_masks(View2D *v2d)
 		}
 		
 		/* horizontal scroller */
-		if (scroll & (V2D_SCROLL_BOTTOM | V2D_SCROLL_BOTTOM_O)) {
-			/* on bottom edge of region (V2D_SCROLL_BOTTOM_O is outliner, the other is for standard) */
+		if (scroll & (V2D_SCROLL_BOTTOM)) {
+			/* on bottom edge of region */
 			v2d->hor = v2d->mask;
 			v2d->hor.ymax = V2D_SCROLL_HEIGHT;
 			v2d->mask.ymin = v2d->hor.ymax + 1;
@@ -142,8 +151,8 @@ static void view2d_masks(View2D *v2d)
 		/* adjust vertical scroller if there's a horizontal scroller, to leave corner free */
 		if (scroll & V2D_SCROLL_VERTICAL) {
 			/* just set y min/max for vertical scroller to y min/max of mask as appropriate */
-			if (scroll & (V2D_SCROLL_BOTTOM | V2D_SCROLL_BOTTOM_O)) {
-				/* on bottom edge of region (V2D_SCROLL_BOTTOM_O is outliner, the other is for standard) */
+			if (scroll & (V2D_SCROLL_BOTTOM)) {
+				/* on bottom edge of region */
 				v2d->vert.ymin = v2d->mask.ymin;
 			}
 			else if (scroll & V2D_SCROLL_TOP) {
@@ -152,7 +161,6 @@ static void view2d_masks(View2D *v2d)
 			}
 		}
 	}
-	
 }
 
 /* Refresh and Validation */
@@ -165,163 +173,173 @@ static void view2d_masks(View2D *v2d)
  */
 void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
 {
-	short tot_changed = 0, init = 0;
+	short tot_changed = 0, do_init;
 	uiStyle *style = UI_GetStyle();
 
-	/* initialize data if there is a need for such */
-	if ((v2d->flag & V2D_IS_INITIALISED) == 0) {
-		/* set initialized flag so that View2D doesn't get reinitialised next time again */
-		v2d->flag |= V2D_IS_INITIALISED;
-
-		init = 1;
+	do_init = (v2d->flag & V2D_IS_INITIALISED) == 0;
 		
-		/* see eView2D_CommonViewTypes in UI_view2d.h for available view presets */
-		switch (type) {
-			/* 'standard view' - optimum setup for 'standard' view behavior,
-			 *  that should be used new views as basis for their
-			 *  own unique View2D settings, which should be used instead of this in most cases...
+	/* see eView2D_CommonViewTypes in UI_view2d.h for available view presets */
+	switch (type) {
+		/* 'standard view' - optimum setup for 'standard' view behavior,
+		 *  that should be used new views as basis for their
+		 *  own unique View2D settings, which should be used instead of this in most cases...
+		 */
+		case V2D_COMMONVIEW_STANDARD:
+		{
+			/* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
+			v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM);
+			v2d->minzoom = 0.01f;
+			v2d->maxzoom = 1000.0f;
+			
+			/* tot rect and cur should be same size, and aligned using 'standard' OpenGL coordinates for now 
+			 *	- region can resize 'tot' later to fit other data
+			 *	- keeptot is only within bounds, as strict locking is not that critical
+			 *	- view is aligned for (0,0) -> (winx-1, winy-1) setup
 			 */
-			case V2D_COMMONVIEW_STANDARD:
-			{
-				/* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
-				v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM);
-				v2d->minzoom = 0.01f;
-				v2d->maxzoom = 1000.0f;
-				
-				/* tot rect and cur should be same size, and aligned using 'standard' OpenGL coordinates for now 
-				 *	- region can resize 'tot' later to fit other data
-				 *	- keeptot is only within bounds, as strict locking is not that critical
-				 *	- view is aligned for (0,0) -> (winx-1, winy-1) setup
-				 */
-				v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y);
-				v2d->keeptot = V2D_KEEPTOT_BOUNDS;
-				
+			v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y);
+			v2d->keeptot = V2D_KEEPTOT_BOUNDS;
+			
+			if (do_init) {
 				v2d->tot.xmin = v2d->tot.ymin = 0.0f;
 				v2d->tot.xmax = (float)(winx - 1);
 				v2d->tot.ymax = (float)(winy - 1);
 				
 				v2d->cur = v2d->tot;
-				
-				/* scrollers - should we have these by default? */
-				/* XXX for now, we don't override this, or set it either! */
 			}
-			break;
+			/* scrollers - should we have these by default? */
+			/* XXX for now, we don't override this, or set it either! */
+		}
+		break;
+		
+		/* 'list/channel view' - zoom, aspect ratio, and alignment restrictions are set here */
+		case V2D_COMMONVIEW_LIST:
+		{
+			/* zoom + aspect ratio are locked */
+			v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
+			v2d->minzoom = v2d->maxzoom = 1.0f;
 			
-			/* 'list/channel view' - zoom, aspect ratio, and alignment restrictions are set here */
-			case V2D_COMMONVIEW_LIST:
-			{
-				/* zoom + aspect ratio are locked */
-				v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
-				v2d->minzoom = v2d->maxzoom = 1.0f;
-				
-				/* tot rect has strictly regulated placement, and must only occur in +/- quadrant */
-				v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
-				v2d->keeptot = V2D_KEEPTOT_STRICT;
-				tot_changed = 1;
-				
-				/* scroller settings are currently not set here... that is left for regions... */
-			}
-			break;
-				
-			/* 'stack view' - practically the same as list/channel view, except is located in the pos y half instead. 
-			 *  zoom, aspect ratio, and alignment restrictions are set here */
-			case V2D_COMMONVIEW_STACK:
-			{
-				/* zoom + aspect ratio are locked */
-				v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
-				v2d->minzoom = v2d->maxzoom = 1.0f;
-				
-				/* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */
-				v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y);
-				v2d->keeptot = V2D_KEEPTOT_STRICT;
-				tot_changed = 1;
-				
-				/* scroller settings are currently not set here... that is left for regions... */
-			}
-			break;
-				
-			/* 'header' regions - zoom, aspect ratio, alignment, and panning restrictions are set here */
-			case V2D_COMMONVIEW_HEADER:
-			{
-				/* zoom + aspect ratio are locked */
-				v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
-				v2d->minzoom = v2d->maxzoom = 1.0f;
-				v2d->min[0] = v2d->max[0] = (float)(winx - 1);
-				v2d->min[1] = v2d->max[1] = (float)(winy - 1);
-				
-				/* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */
-				v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y);
-				v2d->keeptot = V2D_KEEPTOT_STRICT;
-				tot_changed = 1;
-				
-				/* panning in y-axis is prohibited */
-				v2d->keepofs = V2D_LOCKOFS_Y;
-				
-				/* absolutely no scrollers allowed */
-				v2d->scroll = 0;
-				
-			}
-			break;
+			/* tot rect has strictly regulated placement, and must only occur in +/- quadrant */
+			v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
+			v2d->keeptot = V2D_KEEPTOT_STRICT;
+			tot_changed = do_init;
 			
-			/* panels view, with horizontal/vertical align */
-			case V2D_COMMONVIEW_PANELS_UI:
-			{
-				float panelzoom = (style) ? style->panelzoom : 1.0f;
-				
-				/* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
-				v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM | V2D_KEEPZOOM);
-				v2d->minzoom = 0.5f;
-				v2d->maxzoom = 2.0f;
-				//tot_changed = 1;
-				
-				v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
-				v2d->keeptot = V2D_KEEPTOT_BOUNDS;
-				
-				v2d->scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
-				v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
-				v2d->scroll &= ~V2D_SCROLL_VERTICAL_HIDE;
-
+			/* scroller settings are currently not set here... that is left for regions... */
+		}
+		break;
+			
+		/* 'stack view' - practically the same as list/channel view, except is located in the pos y half instead. 
+		 *  zoom, aspect ratio, and alignment restrictions are set here */
+		case V2D_COMMONVIEW_STACK:
+		{
+			/* zoom + aspect ratio are locked */
+			v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
+			v2d->minzoom = v2d->maxzoom = 1.0f;
+			
+			/* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */
+			v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y);
+			v2d->keeptot = V2D_KEEPTOT_STRICT;
+			tot_changed = do_init;
+			
+			/* scroller settings are currently not set here... that is left for regions... */
+		}
+		break;
+			
+		/* 'header' regions - zoom, aspect ratio, alignment, and panning restrictions are set here */
+		case V2D_COMMONVIEW_HEADER:
+		{
+			/* zoom + aspect ratio are locked */
+			v2d->keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
+			v2d->minzoom = v2d->maxzoom = 1.0f;
+			
+			if (do_init) {
 				v2d->tot.xmin = 0.0f;
 				v2d->tot.xmax = winx;
+				v2d->tot.ymin = 0.0f;
+				v2d->tot.ymax = winy;
+				v2d->cur = v2d->tot;
+				
+				v2d->min[0] = v2d->max[0] = (float)(winx - 1);
+				v2d->min[1] = v2d->max[1] = (float)(winy - 1);
+			}
+			/* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */
+			v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y);
+			v2d->keeptot = V2D_KEEPTOT_STRICT;
+			tot_changed = do_init;
+			
+			/* panning in y-axis is prohibited */
+			v2d->keepofs = V2D_LOCKOFS_Y;
+			
+			/* absolutely no scrollers allowed */
+			v2d->scroll = 0;
+			
+		}
+		break;
+		
+		/* panels view, with horizontal/vertical align */
+		case V2D_COMMONVIEW_PANELS_UI:
+		{
+			
+			/* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
+			v2d->keepzoom = (V2D_KEEPASPECT | V2D_LIMITZOOM | V2D_KEEPZOOM);
+			v2d->minzoom = 0.5f;
+			v2d->maxzoom = 2.0f;
+			
+			v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
+			v2d->keeptot = V2D_KEEPTOT_BOUNDS;
+			
+			/* note, scroll is being flipped in ED_region_panels() drawing */
+			v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
+			v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE;
+
+			if (do_init) {
+				float panelzoom = (style) ? style->panelzoom : 1.0f;
+				float scrolw = v2d->scroll & V2D_SCROLL_RIGHT ? V2D_SCROLL_WIDTH : 0.0f;
+				
+				v2d->tot.xmin = 0.0f;
+				v2d->tot.xmax = winx - scrolw;
 				
 				v2d->tot.ymax = 0.0f;
 				v2d->tot.ymin = -winy;
 				
 				v2d->cur.xmin = 0.0f;
-				/* bad workaround for keeping zoom level with scrollers */
-				v2d->cur.xmax = (winx - V2D_SCROLL_WIDTH) * panelzoom;
+				v2d->cur.xmax = (winx) * panelzoom - scrolw;
 				
 				v2d->cur.ymax = 0.0f;
 				v2d->cur.ymin = (-winy) * panelzoom;
 			}
-			break;
-				
-			/* other view types are completely defined using their own settings already */
-			default:
-				/* we don't do anything here, as settings should be fine, but just make sure that rect */
-				break;
 		}
+		break;
+			
+		/* other view types are completely defined using their own settings already */
+		default:
+			/* we don't do anything here, as settings should be fine, but just make sure that rect */
+			break;
 	}
 	
+	/* set initialized flag so that View2D doesn't get reinitialised next time again */
+	v2d->flag |= V2D_IS_INITIALISED;
+
 	/* store view size */
 	v2d->winx = winx;
 	v2d->winy = winy;
 	
-	/* set masks */
-	view2d_masks(v2d);
+	/* set masks (always do), but leave scroller scheck to totrect_set */
+	view2d_masks(v2d, 0);
 	
 	/* set 'tot' rect before setting cur? */
-	if (tot_changed) 
-		UI_view2d_totRect_set_resize(v2d, winx, winy, !init);
+	/* XXX confusing stuff here still - I made this function not check scroller hide - that happens in totrect_set */
+	if (tot_changed)
+		UI_view2d_totRect_set_resize(v2d, winx, winy, !do_init);
 	else
-		UI_view2d_curRect_validate_resize(v2d, !init);
+		ui_view2d_curRect_validate_resize(v2d, !do_init, 0);
+	
 }
 
 /* Ensure View2D rects remain in a viable configuration 
  *	- cur is not allowed to be: larger than max, smaller than min, or outside of tot
  */
 // XXX pre2.5 -> this used to be called  test_view2d()
-void UI_view2d_curRect_validate_resize(View2D *v2d, int resize)
+static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_scrollers)
 {
 	float totwidth, totheight, curwidth, curheight, width, height;
 	float winx, winy;
@@ -715,12 +733,12 @@ void UI_view2d_curRect_validate_resize(View2D *v2d, int resize)
 	}
 	
 	/* set masks */
-	view2d_masks(v2d);
+	view2d_masks(v2d, mask_scrollers);
 }
 
 void UI_view2d_curRect_validate(View2D *v2d)
 {
-	UI_view2d_curRect_validate_resize(v2d, 0);
+	ui_view2d_curRect_validate_resize(v2d, 0, 1);
 }
 
 /* ------------------ */
@@ -844,7 +862,7 @@ void UI_view2d_curRect_reset(View2D *v2d)
 /* Change the size of the maximum viewable area (i.e. 'tot' rect) */
 void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize)
 {
-	int scroll = view2d_scroll_mapped(v2d->scroll);
+//	int scroll = view2d_scroll_mapped(v2d->scroll);
 	
 	/* don't do anything if either value is 0 */
 	width = abs(width);
@@ -853,10 +871,10 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize
 	/* hrumf! */
 	/* XXX: there are work arounds for this in the panel and file browse code. */
 	/* round to int, because this is called with width + V2D_SCROLL_WIDTH */
-	if (scroll & V2D_SCROLL_HORIZONTAL) 
-		width -= (int)V2D_SCROLL_WIDTH;
-	if (scroll & V2D_SCROLL_VERTICAL) 
-		height -= (int)V2D_SCROLL_HEIGHT;
+//	if (scroll & V2D_SCROLL_HORIZONTAL)
+//		width -= (int)V2D_SCROLL_WIDTH;
+//	if (scroll & V2D_SCROLL_VERTICAL)
+//		height -= (int)V2D_SCROLL_HEIGHT;
 	
 	if (ELEM(0, width, height)) {
 		if (G.debug & G_DEBUG)
@@ -903,12 +921,21 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, int resize
 	}
 	
 	/* make sure that 'cur' rect is in a valid state as a result of these changes */
-	UI_view2d_curRect_validate_resize(v2d, resize);
+	ui_view2d_curRect_validate_resize(v2d, resize, 1);
+	
 }
 
 void UI_view2d_totRect_set(View2D *v2d, int width, int height)
 {
+	int scroll = view2d_scroll_mapped(v2d->scroll);
+
 	UI_view2d_totRect_set_resize(v2d, width, height, 0);
+	
+	/* solve bad recursion... if scroller state changed, mask is different, so you get different rects */
+	if (scroll != view2d_scroll_mapped(v2d->scroll)) {
+		UI_view2d_totRect_set_resize(v2d, width, height, 0);
+	}
+	
 }
 
 int UI_view2d_tab_set(View2D *v2d, int tab)
@@ -1494,15 +1521,6 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d,
 			CLAMP(scrollers->hor_min, hor.xmin, hor.xmax - V2D_SCROLLER_HANDLE_SIZE);
 		}
 		
-		/* check whether sliders can disappear due to the full-range being used */
-		if (v2d->keeptot) {
-			if ((fac1 <= 0.0f) && (fac2 >= 1.0f)) {
-				v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR;
-				scrollers->horfull = 1;
-			}
-			else
-				v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR;
-		}
 	}
 	
 	/* vertical scrollers */
@@ -1536,15 +1554,6 @@ View2DScrollers *UI_view2d_scrollers_calc(const bContext *C, View2D *v2d,
 			CLAMP(scrollers->vert_min, vert.ymin, vert.ymax - V2D_SCROLLER_HANDLE_SIZE);
 		}
 
-		/* check whether sliders can disappear due to the full-range being used */
-		if (v2d->keeptot) {
-			if ((fac1 <= 0.0f) && (fac2 >= 1.0f)) {
-				v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR;
-				scrollers->vertfull = 1;
-			}
-			else
-				v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR;
-		}
 	}
 	
 	/* grid markings on scrollbars */
@@ -1618,45 +1627,42 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
 	
 	/* horizontal scrollbar */
 	if (scroll & V2D_SCROLL_HORIZONTAL) {
-		/* only draw scrollbar when it doesn't fill the entire space */
-		if (vs->horfull == 0) {
-			bTheme *btheme = UI_GetTheme();
-			uiWidgetColors wcol = btheme->tui.wcol_scroll;
-			rcti slider;
-			int state;
-			unsigned char col[4];
-			
-			slider.xmin = vs->hor_min;
-			slider.xmax = vs->hor_max;
-			slider.ymin = hor.ymin;
-			slider.ymax = hor.ymax;
-			
-			state = (v2d->scroll_ui & V2D_SCROLL_H_ACTIVE) ? UI_SCROLL_PRESSED : 0;
-			
-			/* show zoom handles if:
-			 *	- zooming on x-axis is allowed (no scroll otherwise)
-			 *	- slider bubble is large enough (no overdraw confusion)
-			 *	- scale is shown on the scroller 
-			 *	  (workaround to make sure that button windows don't show these, 
-			 *		and only the time-grids with their zoomability can do so)
-			 */
-			if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 &&
-			    (v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) &&
-			    (BLI_rcti_size_x(&slider) > V2D_SCROLLER_HANDLE_SIZE))
-			{
-				state |= UI_SCROLL_ARROWS;
-			}
-			
-			/* clean rect behind slider, but not with transparent background */
-			UI_GetThemeColor4ubv(TH_BACK, col);
-			if (col[3] == 255) {
-				glColor3ub(col[0], col[1], col[2]);
-				glRecti(v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax);
-			}
-			
-			uiWidgetScrollDraw(&wcol, &hor, &slider, state);
+		bTheme *btheme = UI_GetTheme();
+		uiWidgetColors wcol = btheme->tui.wcol_scroll;
+		rcti slider;
+		int state;
+		unsigned char col[4];
+		
+		slider.xmin = vs->hor_min;
+		slider.xmax = vs->hor_max;
+		slider.ymin = hor.ymin;
+		slider.ymax = hor.ymax;
+		
+		state = (v2d->scroll_ui & V2D_SCROLL_H_ACTIVE) ? UI_SCROLL_PRESSED : 0;
+		
+		/* show zoom handles if:
+		 *	- zooming on x-axis is allowed (no scroll otherwise)
+		 *	- slider bubble is large enough (no overdraw confusion)
+		 *	- scale is shown on the scroller 
+		 *	  (workaround to make sure that button windows don't show these, 
+		 *		and only the time-grids with their zoomability can do so)
+		 */
+		if ((v2d->keepzoom & V2D_LOCKZOOM_X) == 0 &&
+			(v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) &&
+			(BLI_rcti_size_x(&slider) > V2D_SCROLLER_HANDLE_SIZE))
+		{
+			state |= UI_SCROLL_ARROWS;
 		}
 		
+		/* clean rect behind slider, but not with transparent background */
+		UI_GetThemeColor4ubv(TH_BACK, col);
+		if (col[3] == 255) {
+			glColor3ub(col[0], col[1], col[2]);
+			glRecti(v2d->hor.xmin, v2d->hor.ymin, v2d->hor.xmax, v2d->hor.ymax);
+		}
+		
+		uiWidgetScrollDraw(&wcol, &hor, &slider, state);
+		
 		/* scale indicators */
 		if ((scroll & V2D_SCROLL_SCALE_HORIZONTAL) && (vs->grid)) {
 			View2DGrid *grid = vs->grid;
@@ -1734,45 +1740,42 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
 	
 	/* vertical scrollbar */
 	if (scroll & V2D_SCROLL_VERTICAL) {
-		/* only draw scrollbar when it doesn't fill the entire space */
-		if (vs->vertfull == 0) {
-			bTheme *btheme = UI_GetTheme();
-			uiWidgetColors wcol = btheme->tui.wcol_scroll;
-			rcti slider;
-			int state;
-			unsigned char col[4];
-			
-			slider.xmin = vert.xmin;
-			slider.xmax = vert.xmax;
-			slider.ymin = vs->vert_min;
-			slider.ymax = vs->vert_max;
-			
-			state = (v2d->scroll_ui & V2D_SCROLL_V_ACTIVE) ? UI_SCROLL_PRESSED : 0;
-			
-			/* show zoom handles if:
-			 *	- zooming on y-axis is allowed (no scroll otherwise)
-			 *	- slider bubble is large enough (no overdraw confusion)
-			 *	- scale is shown on the scroller 
-			 *	  (workaround to make sure that button windows don't show these, 
-			 *		and only the time-grids with their zoomability can do so)
-			 */
-			if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 &&
-			    (v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) &&
-			    (BLI_rcti_size_y(&slider) > V2D_SCROLLER_HANDLE_SIZE))
-			{
-				state |= UI_SCROLL_ARROWS;
-			}
-			
-			/* clean rect behind slider, but not with transparent background */
-			UI_GetThemeColor4ubv(TH_BACK, col);
-			if (col[3] == 255) {
-				glColor3ub(col[0], col[1], col[2]);
-				glRecti(v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax);
-			}
-			
-			uiWidgetScrollDraw(&wcol, &vert, &slider, state);
+		bTheme *btheme = UI_GetTheme();
+		uiWidgetColors wcol = btheme->tui.wcol_scroll;
+		rcti slider;
+		int state;
+		unsigned char col[4];
+		
+		slider.xmin = vert.xmin;
+		slider.xmax = vert.xmax;
+		slider.ymin = vs->vert_min;
+		slider.ymax = vs->vert_max;
+		
+		state = (v2d->scroll_ui & V2D_SCROLL_V_ACTIVE) ? UI_SCROLL_PRESSED : 0;
+		
+		/* show zoom handles if:
+		 *	- zooming on y-axis is allowed (no scroll otherwise)
+		 *	- slider bubble is large enough (no overdraw confusion)
+		 *	- scale is shown on the scroller 
+		 *	  (workaround to make sure that button windows don't show these, 
+		 *		and only the time-grids with their zoomability can do so)
+		 */
+		if ((v2d->keepzoom & V2D_LOCKZOOM_Y) == 0 &&
+			(v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) &&
+			(BLI_rcti_size_y(&slider) > V2D_SCROLLER_HANDLE_SIZE))
+		{
+			state |= UI_SCROLL_ARROWS;
 		}
 		
+		/* clean rect behind slider, but not with transparent background */
+		UI_GetThemeColor4ubv(TH_BACK, col);
+		if (col[3] == 255) {
+			glColor3ub(col[0], col[1], col[2]);
+			glRecti(v2d->vert.xmin, v2d->vert.ymin, v2d->vert.xmax, v2d->vert.ymax);
+		}
+		
+		uiWidgetScrollDraw(&wcol, &vert, &slider, state);
+		
 		
 		/* scale indiators */
 		if ((scroll & V2D_SCROLL_SCALE_VERTICAL) && (vs->grid)) {
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 006644bf366..cc473998340 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -937,7 +937,7 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event)
 	vzd = op->customdata;
 	v2d = vzd->v2d;
 	
-	if (event->type == MOUSEZOOM) {
+	if (event->type == MOUSEZOOM || event->type == MOUSEPAN) {
 		float dx, dy, fac;
 		
 		vzd->lastx = event->prevx;
@@ -948,6 +948,8 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, wmEvent *event)
 		 */
 		fac = 0.01f * (event->x - event->prevx);
 		dx = fac * BLI_rctf_size_x(&v2d->cur) / 10.0f;
+		if (event->type == MOUSEPAN)
+			fac = 0.01f * (event->y - event->prevy);
 		dy = fac * BLI_rctf_size_y(&v2d->cur) / 10.0f;
 
 		RNA_float_set(op->ptr, "deltax", dx);
@@ -1744,8 +1746,8 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, wmEvent *event)
 		}
 		
 		/* zone is also inappropriate if scroller is not visible... */
-		if (((vsm->scroller == 'h') && (v2d->scroll & (V2D_SCROLL_HORIZONTAL_HIDE | V2D_SCROLL_HORIZONTAL_FULLR))) ||
-		    ((vsm->scroller == 'v') && (v2d->scroll & (V2D_SCROLL_VERTICAL_HIDE | V2D_SCROLL_VERTICAL_FULLR))) )
+		if (((vsm->scroller == 'h') && (v2d->scroll & (V2D_SCROLL_HORIZONTAL_FULLR))) ||
+		    ((vsm->scroller == 'v') && (v2d->scroll & (V2D_SCROLL_VERTICAL_FULLR))) )
 		{
 			/* free customdata initialized */
 			scroller_activate_exit(C, op);
@@ -1903,6 +1905,7 @@ void UI_view2d_keymap(wmKeyConfig *keyconf)
 	WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0);
 	WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0);
 	WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0);
+	WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0);
 	
 	WM_keymap_verify_item(keymap, "VIEW2D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0);
 
@@ -1951,6 +1954,7 @@ void UI_view2d_keymap(wmKeyConfig *keyconf)
 	
 	WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
 	WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEZOOM, 0, 0, 0);
+	WM_keymap_add_item(keymap, "VIEW2D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0);
 	WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_out", PADMINUS, KM_PRESS, 0, 0);
 	WM_keymap_add_item(keymap, "VIEW2D_OT_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0);
 	WM_keymap_add_item(keymap, "VIEW2D_OT_reset", HOMEKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 29139c5154f..3fbfaabbc0d 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -69,7 +69,14 @@ void paintface_flush_flags(Object *ob)
 	int totface, totpoly;
 	int i;
 	
-	if (me == NULL || dm == NULL)
+	if (me == NULL)
+		return;
+
+	/* we could call this directly in all areas that change selection,
+	 * since this could become slow for realtime updates (circle-select for eg) */
+	BKE_mesh_flush_select_from_polys(me);
+
+	if (dm == NULL)
 		return;
 
 	/*
@@ -477,7 +484,7 @@ int paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], in
 	/* Get the face under the cursor */
 	me = BKE_mesh_from_object(ob);
 
-	if (!ED_mesh_pick_face(C, me, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE))
+	if (!ED_mesh_pick_face(C, ob, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE))
 		return 0;
 	
 	if (index >= me->totpoly)
@@ -603,7 +610,14 @@ void paintvert_flush_flags(Object *ob)
 	int totvert;
 	int i;
 
-	if (me == NULL || dm == NULL)
+	if (me == NULL)
+		return;
+
+	/* we could call this directly in all areas that change selection,
+	 * since this could become slow for realtime updates (circle-select for eg) */
+	BKE_mesh_flush_select_from_verts(me);
+
+	if (dm == NULL)
 		return;
 
 	index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index c8a1264fd10..590bcd5939e 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1315,7 +1315,7 @@ static void knife_bgl_get_mats(KnifeTool_OpData *UNUSED(kcd), bglMats *mats)
 	//copy_m4_m4(mats->projection, kcd->vc.rv3d->winmat);
 }
 
-/* Calculate maximum excursion (doubled) from (0,0,0) of mesh */
+/* Calculate maximum excursion from (0,0,0) of mesh */
 static void calc_ortho_extent(KnifeTool_OpData *kcd)
 {
 	BMIter iter;
@@ -1328,7 +1328,19 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
 		for (i = 0; i < 3; i++)
 			max_xyz = max_ff(max_xyz, fabs(v->co[i]));
 	}
-	kcd->ortho_extent = 2 * max_xyz;
+	kcd->ortho_extent = max_xyz;
+}
+
+/* Clip the line (v1, v2) to planes perpendicular to it and distances d from
+ * the closest point on the line to the origin */
+static void clip_to_ortho_planes(float v1[3], float v2[3], float d)
+{
+	float closest[3];
+	const float origin[3] = {0.0f, 0.0f, 0.0f};
+
+	closest_to_line_v3(closest, origin, v1, v2);
+	dist_ensure_v3_v3fl(v1, closest, d);
+	dist_ensure_v3_v3fl(v2, closest, d);
 }
 
 /* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */
@@ -1375,8 +1387,8 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
 	if (kcd->is_ortho) {
 		if (kcd->ortho_extent == 0.0f)
 			calc_ortho_extent(kcd);
-		limit_dist_v3(v1, v3, kcd->ortho_extent + 10.0f);
-		limit_dist_v3(v2, v4, kcd->ortho_extent + 10.0f);
+		clip_to_ortho_planes(v1, v3, kcd->ortho_extent + 10.0f);
+		clip_to_ortho_planes(v2, v4, kcd->ortho_extent + 10.0f);
 	}
 
 	BLI_smallhash_init(ehash);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 41b263e8929..27c68ce21bc 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -1674,7 +1674,7 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
 	BMEditMesh *em = BMEdit_FromObject(obedit);
 	int usex = TRUE, usey = TRUE, usez = TRUE, preserve_volume = TRUE;
 	int i, repeat;
-	float lambda;
+	float lambda_factor;
 	float lambda_border;
 	BMIter fiter;
 	BMFace *f;
@@ -1695,7 +1695,7 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
 	}
 
 	repeat = RNA_int_get(op->ptr, "repeat");
-	lambda = RNA_float_get(op->ptr, "lambda");
+	lambda_factor = RNA_float_get(op->ptr, "lambda_factor");
 	lambda_border = RNA_float_get(op->ptr, "lambda_border");
 	usex = RNA_boolean_get(op->ptr, "use_x");
 	usey = RNA_boolean_get(op->ptr, "use_y");
@@ -1706,8 +1706,8 @@ static int edbm_do_smooth_laplacian_vertex_exec(bContext *C, wmOperator *op)
 	
 	for (i = 0; i < repeat; i++) {
 		if (!EDBM_op_callf(em, op,
-		                   "smooth_laplacian_vert verts=%hv lambda=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b",
-		                   BM_ELEM_SELECT, lambda, lambda_border, usex, usey, usez, preserve_volume))
+		                   "smooth_laplacian_vert verts=%hv lambda_factor=%f lambda_border=%f use_x=%b use_y=%b use_z=%b preserve_volume=%b",
+		                   BM_ELEM_SELECT, lambda_factor, lambda_border, usex, usey, usez, preserve_volume))
 		{
 			return OPERATOR_CANCELLED;
 		}
@@ -1740,7 +1740,7 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot)
 
 	RNA_def_int(ot->srna, "repeat", 1, 1, 200,
 	            "Number of iterations to smooth the mesh", "", 1, 200);
-	RNA_def_float(ot->srna, "lambda", 0.00005f, 0.0000001f, 1000.0f,
+	RNA_def_float(ot->srna, "lambda_factor", 0.00005f, 0.0000001f, 1000.0f,
 	              "Lambda factor", "", 0.0000001f, 1000.0f);
 	RNA_def_float(ot->srna, "lambda_border", 0.00005f, 0.0000001f, 1000.0f,
 	              "Lambda factor in border", "", 0.0000001f, 1000.0f);
@@ -3582,7 +3582,7 @@ void MESH_OT_dissolve_limited(wmOperatorType *ot)
 
 	prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
 	                              "Max Angle", "Angle limit", 0.0f, DEG2RADF(180.0f));
-	RNA_def_property_float_default(prop, DEG2RADF(15.0f));
+	RNA_def_property_float_default(prop, DEG2RADF(5.0f));
 	RNA_def_boolean(ot->srna, "use_dissolve_boundaries", 0, "All Boundaries",
 	                "Dissolve all vertices inbetween face boundaries");
 }
@@ -4768,6 +4768,7 @@ static int edbm_bevel_calc(wmOperator *op)
 #ifdef NEW_BEVEL
 	float offset = RNA_float_get(op->ptr, "offset");
 	int segments = RNA_int_get(op->ptr, "segments");
+	int vertex_only = RNA_boolean_get(op->ptr, "vertex_only");
 
 	/* revert to original mesh */
 	if (opdata->is_modal) {
@@ -4775,8 +4776,8 @@ static int edbm_bevel_calc(wmOperator *op)
 	}
 
 	if (!EDBM_op_init(em, &bmop, op,
-		              "bevel geom=%hev offset=%f segments=%i",
-		              BM_ELEM_SELECT, offset, segments))
+		              "bevel geom=%hev offset=%f segments=%i vertex_only=%b",
+		              BM_ELEM_SELECT, offset, segments, vertex_only))
 	{
 		return 0;
 	}
@@ -5101,6 +5102,7 @@ void MESH_OT_bevel(wmOperatorType *ot)
 #ifdef NEW_BEVEL
 	RNA_def_float(ot->srna, "offset", 0.0f, -FLT_MAX, FLT_MAX, "Offset", "", 0.0f, 1.0f);
 	RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
+	RNA_def_boolean(ot->srna, "vertex_only", FALSE, "Vertex only", "Bevel only vertices");
 #else
 	/* take note, used as a factor _and_ a distance depending on 'use_dist' */
 	RNA_def_float(ot->srna, "percent", 0.0f, -FLT_MAX, FLT_MAX, "Percentage", "", 0.0f, 1.0f);
@@ -5732,18 +5734,6 @@ static int mesh_symmetrize_exec(bContext *C, wmOperator *op)
 
 void MESH_OT_symmetrize(struct wmOperatorType *ot)
 {
-	static EnumPropertyItem axis_direction_items[] = {
-		{BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""},
-		{BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""},
-
-		{BMO_SYMMETRIZE_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y to +Y", ""},
-		{BMO_SYMMETRIZE_POSITIVE_Y, "POSITIVE_Y", 0, "+Y to -Y", ""},
-
-		{BMO_SYMMETRIZE_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z to +Z", ""},
-		{BMO_SYMMETRIZE_POSITIVE_Z, "POSITIVE_Z", 0, "+Z to -Z", ""},
-		{0, NULL, 0, NULL, NULL},
-	};
-
 	/* identifiers */
 	ot->name = "Symmetrize";
 	ot->description = "Enforce symmetry (both form and topological) across an axis";
@@ -5756,7 +5746,7 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot)
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
-	ot->prop = RNA_def_enum(ot->srna, "direction", axis_direction_items,
+	ot->prop = RNA_def_enum(ot->srna, "direction", symmetrize_direction_items,
 	                        BMO_SYMMETRIZE_NEGATIVE_X,
 	                        "Direction", "Which sides to copy from and to");
 }
diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
index 1a81cab8de7..99fa85b3ee7 100644
--- a/source/blender/editors/mesh/mesh_navmesh.c
+++ b/source/blender/editors/mesh/mesh_navmesh.c
@@ -157,8 +157,9 @@ static void createVertsTrisData(bContext *C, LinkNode *obs, int *nverts_r, float
 	*tris_r = tris;
 }
 
-static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris,
-                        struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh)
+static bool buildNavMesh(const RecastData *recastParams, int nverts, float *verts, int ntris, int *tris,
+                         struct recast_polyMesh **pmesh, struct recast_polyMeshDetail **dmesh,
+                         ReportList *reports)
 {
 	float bmin[3], bmax[3];
 	struct recast_heightfield *solid;
@@ -185,14 +186,20 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts
 	/* Set the area where the navigation will be build. */
 	recast_calcGridSize(bmin, bmax, recastParams->cellsize, &width, &height);
 
+	/* zero dimensions cause zero alloc later on [#33758] */
+	if (width <= 0 || height <= 0) {
+		BKE_report(reports, RPT_ERROR, "Object has a width or height of zero");
+		return false;
+	}
+
 	/* ** Step 2: Rasterize input polygon soup ** */
 	/* Allocate voxel heightfield where we rasterize our input data to */
 	solid = recast_newHeightfield();
 
 	if (!recast_createHeightfield(solid, width, height, bmin, bmax, recastParams->cellsize, recastParams->cellheight)) {
 		recast_destroyHeightfield(solid);
-
-		return 0;
+		BKE_report(reports, RPT_ERROR, "Failed to create height field");
+		return false;
 	}
 
 	/* Allocate array that can hold triangle flags */
@@ -215,7 +222,8 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts
 		recast_destroyHeightfield(solid);
 		recast_destroyCompactHeightfield(chf);
 
-		return 0;
+		BKE_report(reports, RPT_ERROR, "Failed to create compact height field");
+		return false;
 	}
 
 	recast_destroyHeightfield(solid);
@@ -224,21 +232,24 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts
 	if (!recast_erodeWalkableArea(walkableRadius, chf)) {
 		recast_destroyCompactHeightfield(chf);
 
-		return 0;
+		BKE_report(reports, RPT_ERROR, "Failed to erode walkable area");
+		return false;
 	}
 
 	/* Prepare for region partitioning, by calculating distance field along the walkable surface */
 	if (!recast_buildDistanceField(chf)) {
 		recast_destroyCompactHeightfield(chf);
 
-		return 0;
+		BKE_report(reports, RPT_ERROR, "Failed to build distance field");
+		return false;
 	}
 
 	/* Partition the walkable surface into simple regions without holes */
 	if (!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) {
 		recast_destroyCompactHeightfield(chf);
 
-		return 0;
+		BKE_report(reports, RPT_ERROR, "Failed to build regions");
+		return false;
 	}
 
 	/* ** Step 5: Trace and simplify region contours ** */
@@ -249,7 +260,8 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts
 		recast_destroyCompactHeightfield(chf);
 		recast_destroyContourSet(cset);
 
-		return 0;
+		BKE_report(reports, RPT_ERROR, "Failed to build contours");
+		return false;
 	}
 
 	/* ** Step 6: Build polygons mesh from contours ** */
@@ -259,7 +271,8 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts
 		recast_destroyContourSet(cset);
 		recast_destroyPolyMesh(*pmesh);
 
-		return 0;
+		BKE_report(reports, RPT_ERROR, "Failed to build poly mesh");
+		return false;
 	}
 
 
@@ -272,13 +285,14 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts
 		recast_destroyPolyMesh(*pmesh);
 		recast_destroyPolyMeshDetail(*dmesh);
 
-		return 0;
+		BKE_report(reports, RPT_ERROR, "Failed to build poly mesh detail");
+		return false;
 	}
 
 	recast_destroyCompactHeightfield(chf);
 	recast_destroyContourSet(cset);
 
-	return 1;
+	return true;
 }
 
 static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, Base *base)
@@ -437,6 +451,7 @@ static int navmesh_create_exec(bContext *C, wmOperator *op)
 	if (obs) {
 		struct recast_polyMesh *pmesh = NULL;
 		struct recast_polyMeshDetail *dmesh = NULL;
+		bool ok;
 
 		int nverts = 0, ntris = 0;
 		int *tris = 0;
@@ -444,13 +459,14 @@ static int navmesh_create_exec(bContext *C, wmOperator *op)
 
 		createVertsTrisData(C, obs, &nverts, &verts, &ntris, &tris);
 		BLI_linklist_free(obs, NULL);
-		buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh);
-		createRepresentation(C, pmesh, dmesh, navmeshBase);
+		if ((ok = buildNavMesh(&scene->gm.recastData, nverts, verts, ntris, tris, &pmesh, &dmesh, op->reports))) {
+			createRepresentation(C, pmesh, dmesh, navmeshBase);
+		}
 
 		MEM_freeN(verts);
 		MEM_freeN(tris);
 
-		return OPERATOR_FINISHED;
+		return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 	}
 	else {
 		BKE_report(op->reports, RPT_ERROR, "No mesh objects found");
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 773331d20f8..96b8f1080b9 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -40,6 +40,8 @@
 #include "DNA_modifier_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
@@ -1165,9 +1167,12 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em)
  *
  * \return boolean TRUE == Found
  */
-int ED_mesh_pick_face(bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size)
+int ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size)
 {
 	ViewContext vc;
+	Mesh *me = ob->data;
+
+	BLI_assert(me && GS(me->id.name) == ID_ME);
 
 	if (!me || me->totpoly == 0)
 		return 0;
@@ -1197,11 +1202,14 @@ int ED_mesh_pick_face(bContext *C, Mesh *me, const int mval[2], unsigned int *in
  * Use when the back buffer stores face index values. but we want a vert.
  * This gets the face then finds the closest vertex to mval.
  */
-int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2], unsigned int *index, int size)
+int ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size)
 {
 	unsigned int poly_index;
+	Mesh *me = ob->data;
 
-	if (ED_mesh_pick_face(C, me, mval, &poly_index, size)) {
+	BLI_assert(me && GS(me->id.name) == ID_ME);
+
+	if (ED_mesh_pick_face(C, ob, mval, &poly_index, size)) {
 		Scene *scene = CTX_data_scene(C);
 		struct ARegion *ar = CTX_wm_region(C);
 
@@ -1210,6 +1218,8 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2],
 		int v_idx_best = -1;
 
 		if (dm->getVertCo) {
+			RegionView3D *rv3d = ar->regiondata;
+
 			/* find the vert closest to 'mval' */
 			const float mval_f[2] = {(float)mval[0],
 			                         (float)mval[1]};
@@ -1217,14 +1227,15 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2],
 			int fidx;
 			float len_best = FLT_MAX;
 
+			ED_view3d_init_mats_rv3d(ob, rv3d);
+
 			fidx = mp->totloop - 1;
 			do {
 				float co[3], sco[2], len;
 				const int v_idx = me->mloop[mp->loopstart + fidx].v;
 				dm->getVertCo(dm, v_idx, co);
-				mul_m4_v3(ob->obmat, co);
-				if (ED_view3d_project_float_global(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
-					len = len_squared_v2v2(mval_f, sco);
+				if (ED_view3d_project_float_object(ar, co, sco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+					len = len_manhattan_v2v2(mval_f, sco);
 					if (len < len_best) {
 						len_best = len;
 						v_idx_best = v_idx;
@@ -1250,31 +1261,97 @@ int ED_mesh_pick_face_vert(bContext *C, Mesh *me, Object *ob, const int mval[2],
  *
  * \return boolean TRUE == Found
  */
-int ED_mesh_pick_vert(bContext *C, Mesh *me, const int mval[2], unsigned int *index, int size)
+typedef struct VertPickData {
+	const MVert *mvert;
+	const float *mval_f;  /* [2] */
+	ARegion *ar;
+
+	/* runtime */
+	float len_best;
+	int v_idx_best;
+} VertPickData;
+
+static void ed_mesh_pick_vert__mapFunc(void *userData, int index, const float co[3],
+                                       const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+	VertPickData *data = userData;
+	if ((data->mvert[index].flag & ME_HIDE) == 0) {
+		float sco[2];
+
+		if (ED_view3d_project_float_object(data->ar, co, sco, V3D_PROJ_TEST_CLIP_DEFAULT) == V3D_PROJ_RET_OK) {
+			const float len = len_manhattan_v2v2(data->mval_f, sco);
+			if (len < data->len_best) {
+				data->len_best = len;
+				data->v_idx_best = index;
+			}
+		}
+	}
+}
+int ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], unsigned int *index, int size, int use_zbuf)
 {
 	ViewContext vc;
+	Mesh *me = ob->data;
+
+	BLI_assert(me && GS(me->id.name) == ID_ME);
 
 	if (!me || me->totvert == 0)
 		return 0;
 
 	view3d_set_viewcontext(C, &vc);
 
-	if (size > 0) {
-		/* sample rect to increase chances of selecting, so that when clicking
-		 * on an face in the backbuf, we can still select a vert */
+	if (use_zbuf) {
+		if (size > 0) {
+			/* sample rect to increase chances of selecting, so that when clicking
+			 * on an face in the backbuf, we can still select a vert */
 
-		float dummy_dist;
-		*index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL);
+			float dummy_dist;
+			*index = view3d_sample_backbuf_rect(&vc, mval, size, 1, me->totvert + 1, &dummy_dist, 0, NULL, NULL);
+		}
+		else {
+			/* sample only on the exact position */
+			*index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+		}
+
+		if ((*index) <= 0 || (*index) > (unsigned int)me->totvert)
+			return 0;
+
+		(*index)--;
 	}
 	else {
-		/* sample only on the exact position */
-		*index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+		/* derived mesh to find deformed locations */
+		DerivedMesh *dm = mesh_get_derived_final(vc.scene, ob, CD_MASK_BAREMESH);
+		ARegion *ar = vc.ar;
+		RegionView3D *rv3d = ar->regiondata;
+
+		/* find the vert closest to 'mval' */
+		const float mval_f[2] = {(float)mval[0],
+		                         (float)mval[1]};
+
+		VertPickData data = {0};
+
+		ED_view3d_init_mats_rv3d(ob, rv3d);
+
+		if (dm == NULL) {
+			return 0;
+		}
+
+		/* setup data */
+		data.mvert = me->mvert;
+		data.ar = ar;
+		data.mval_f = mval_f;
+		data.len_best = FLT_MAX;
+		data.v_idx_best = -1;
+
+		dm->foreachMappedVert(dm, ed_mesh_pick_vert__mapFunc, &data);
+
+		dm->release(dm);
+
+		if (data.v_idx_best == -1) {
+			return 0;
+		}
+
+		*index = data.v_idx_best;
 	}
 
-	if ((*index) <= 0 || (*index) > (unsigned int)me->totvert)
-		return 0;
-
-	(*index)--;
-
 	return 1;
 }
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 473119c90f3..4db416b6f72 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -808,9 +808,16 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
 	
 	if (RNA_struct_property_is_set(op->ptr, "name")) {
 		char name[MAX_ID_NAME - 2];
-
+		
 		RNA_string_get(op->ptr, "name", name);
 		group = (Group *)BKE_libblock_find_name(ID_GR, name);
+		
+		if (0 == RNA_struct_property_is_set(op->ptr, "location")) {
+			wmEvent *event = CTX_wm_window(C)->eventstate;
+			ED_object_location_from_view(C, loc);
+			ED_view3d_cursor3d_position(C, loc, event->x, event->y);
+			RNA_float_set_array(op->ptr, "location", loc);
+		}
 	}
 	else
 		group = BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "group"));
@@ -1994,6 +2001,7 @@ void OBJECT_OT_duplicate(wmOperatorType *ot)
 
 static int add_named_exec(bContext *C, wmOperator *op)
 {
+	wmEvent *event = CTX_wm_window(C)->eventstate;
 	Main *bmain = CTX_data_main(C);
 	Scene *scene = CTX_data_scene(C);
 	Base *basen, *base;
@@ -2026,6 +2034,8 @@ static int add_named_exec(bContext *C, wmOperator *op)
 	basen->lay = basen->object->lay = scene->lay;
 
 	ED_object_location_from_view(C, basen->object->loc);
+	ED_view3d_cursor3d_position(C, basen->object->loc, event->x, event->y);
+	
 	ED_base_object_activate(C, basen);
 
 	copy_object_set_idnew(C, dupflag);
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index d3ebd1dae0a..f36c6d79783 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -89,6 +89,7 @@ typedef struct MultiresBakerJobData {
 	struct MultiresBakerJobData *next, *prev;
 	DerivedMesh *lores_dm, *hires_dm;
 	int simple, lvl, tot_lvl;
+	ListBase images;
 } MultiresBakerJobData;
 
 /* data passing to multires-baker job */
@@ -429,7 +430,7 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa
 
 		RE_multires_bake_images(&bkr);
 
-		BLI_freelistN(&bkr.image);
+		data->images = bkr.image;
 
 		baked_objects++;
 	}
@@ -439,12 +440,22 @@ static void multiresbake_freejob(void *bkv)
 {
 	MultiresBakeJob *bkj = bkv;
 	MultiresBakerJobData *data, *next;
+	LinkData *link;
 
 	data = bkj->data.first;
 	while (data) {
 		next = data->next;
 		data->lores_dm->release(data->lores_dm);
 		data->hires_dm->release(data->hires_dm);
+
+		/* delete here, since this delete will be called from main thread */
+		for (link = data->images.first; link; link = link->next) {
+			Image *ima = (Image *)link->data;
+			GPU_free_image(ima);
+		}
+
+		BLI_freelistN(&data->images);
+
 		MEM_freeN(data);
 		data = next;
 	}
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index f78e1203bc4..6cb7cd5e326 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -141,7 +141,7 @@ ListBase *get_constraint_lb(Object *ob, bConstraint *con, bPoseChannel **pchan_r
 /* single constraint */
 bConstraint *get_active_constraint(Object *ob)
 {
-	return constraints_get_active(get_active_constraints(ob));
+	return BKE_constraints_get_active(get_active_constraints(ob));
 }
 
 /* -------------- Constraint Management (Add New, Remove, Rename) -------------------- */
@@ -225,7 +225,7 @@ static void update_pyconstraint_cb(void *arg1, void *arg2)
 /* helper function for add_constriant - sets the last target for the active constraint */
 static void set_constraint_nth_target(bConstraint *con, Object *target, const char subtarget[], int index)
 {
-	bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+	bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 	ListBase targets = {NULL, NULL};
 	bConstraintTarget *ct;
 	int num_targets, i;
@@ -297,7 +297,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
 	/* Check all constraints - is constraint valid? */
 	if (conlist) {
 		for (curcon = conlist->first; curcon; curcon = curcon->next) {
-			bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon);
+			bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
 			ListBase targets = {NULL, NULL};
 			bConstraintTarget *ct;
 			
@@ -610,7 +610,7 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int
 		list = get_active_constraints(ob);
 	}
 	
-	con = constraints_findByName(list, constraint_name);
+	con = BKE_constraints_findByName(list, constraint_name);
 	//if (G.debug & G_DEBUG)
 	//printf("constraint found = %p, %s\n", (void *)con, (con)?con->name:"");
 
@@ -1123,7 +1123,7 @@ void ED_object_constraint_set_active(Object *ob, bConstraint *con)
 	if ((lb && con) && (con->flag & CONSTRAINT_ACTIVE))
 		return;
 	
-	constraints_set_active(lb, con);
+	BKE_constraints_set_active(lb, con);
 }
 
 void ED_object_constraint_update(Object *ob)
@@ -1162,9 +1162,9 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op))
 	const short is_ik = ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK);
 
 	/* free the constraint */
-	if (remove_constraint(lb, con)) {
+	if (BKE_remove_constraint(lb, con)) {
 		/* there's no active constraint now, so make sure this is the case */
-		constraints_set_active(lb, NULL);
+		BKE_constraints_set_active(lb, NULL);
 		
 		ED_object_constraint_update(ob); /* needed to set the flags on posebones correctly */
 		
@@ -1308,7 +1308,7 @@ static int pose_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op))
 	/* free constraints for all selected bones */
 	CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
 	{
-		free_constraints(&pchan->constraints);
+		BKE_free_constraints(&pchan->constraints);
 		pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_SPLINEIK | PCHAN_HAS_CONST);
 	}
 	CTX_DATA_END;
@@ -1346,7 +1346,7 @@ static int object_constraints_clear_exec(bContext *C, wmOperator *UNUSED(op))
 	/* do freeing */
 	CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
 	{
-		free_constraints(&ob->constraints);
+		BKE_free_constraints(&ob->constraints);
 		DAG_id_tag_update(&ob->id, OB_RECALC_OB);
 	}
 	CTX_DATA_END;
@@ -1391,7 +1391,7 @@ static int pose_constraint_copy_exec(bContext *C, wmOperator *op)
 	{
 		/* if we're not handling the object we're copying from, copy all constraints over */
 		if (pchan != chan) {
-			copy_constraints(&chan->constraints, &pchan->constraints, TRUE);
+			BKE_copy_constraints(&chan->constraints, &pchan->constraints, TRUE);
 			/* update flags (need to add here, not just copy) */
 			chan->constflag |= pchan->constflag;
 		}
@@ -1432,7 +1432,7 @@ static int object_constraint_copy_exec(bContext *C, wmOperator *UNUSED(op))
 	{
 		/* if we're not handling the object we're copying from, copy all constraints over */
 		if (obact != ob) {
-			copy_constraints(&ob->constraints, &obact->constraints, TRUE);
+			BKE_copy_constraints(&ob->constraints, &obact->constraints, TRUE);
 			DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 		}
 	}
@@ -1642,9 +1642,9 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase
 	
 	/* create a new constraint of the type requried, and add it to the active/given constraints list */
 	if (pchan)
-		con = add_pose_constraint(ob, pchan, NULL, type);
+		con = BKE_add_pose_constraint(ob, pchan, NULL, type);
 	else
-		con = add_ob_constraint(ob, NULL, type);
+		con = BKE_add_ob_constraint(ob, NULL, type);
 	
 	/* get the first selected object/bone, and make that the target
 	 *	- apart from the buttons-window add buttons, we shouldn't add in this way
@@ -1940,7 +1940,7 @@ static int pose_ik_clear_exec(bContext *C, wmOperator *UNUSED(op))
 		for (con = pchan->constraints.first; con; con = next) {
 			next = con->next;
 			if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
-				remove_constraint(&pchan->constraints, con);
+				BKE_remove_constraint(&pchan->constraints, con);
 			}
 		}
 		pchan->constflag &= ~(PCHAN_HAS_IK | PCHAN_HAS_TARGET);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index c9492d8f683..fcc3b5d012e 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -954,7 +954,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
 				}
 				else if (event == 22) {
 					/* Copy the constraint channels over */
-					copy_constraints(&base->object->constraints, &ob->constraints, TRUE);
+					BKE_copy_constraints(&base->object->constraints, &ob->constraints, TRUE);
 					
 					do_scene_sort = TRUE;
 				}
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index a3bf27a19d6..7bf1a5db3b1 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -313,7 +313,7 @@ static int group_create_exec(bContext *C, wmOperator *op)
 	
 	group = add_group(name);
 		
-	CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
+	CTX_DATA_BEGIN (C, Base *, base, selected_bases)
 	{
 		add_to_group(group, base->object, scene, base);
 	}
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c
index 4aa2e825954..c9eae776ac7 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/object/object_lattice.c
@@ -52,7 +52,7 @@
 #include "BKE_depsgraph.h"
 #include "BKE_key.h"
 #include "BKE_lattice.h"
-#include "BKE_mesh.h"
+#include "BKE_deform.h"
 
 #include "ED_lattice.h"
 #include "ED_object.h"
@@ -77,7 +77,7 @@ void free_editLatt(Object *ob)
 		if (editlt->def)
 			MEM_freeN(editlt->def);
 		if (editlt->dvert)
-			free_dverts(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw);
+			BKE_defvert_array_free(editlt->dvert, editlt->pntsu * editlt->pntsv * editlt->pntsw);
 
 		MEM_freeN(editlt);
 		MEM_freeN(lt->editlatt);
@@ -104,7 +104,7 @@ void make_editLatt(Object *obedit)
 	if (lt->dvert) {
 		int tot = lt->pntsu * lt->pntsv * lt->pntsw;
 		lt->editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
-		copy_dverts(lt->editlatt->latt->dvert, lt->dvert, tot);
+		BKE_defvert_array_copy(lt->editlatt->latt->dvert, lt->dvert, tot);
 	}
 
 	if (lt->key) lt->editlatt->shapenr = obedit->shapenr;
@@ -156,7 +156,7 @@ void load_editLatt(Object *obedit)
 	}
 
 	if (lt->dvert) {
-		free_dverts(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
+		BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw);
 		lt->dvert = NULL;
 	}
 
@@ -164,7 +164,7 @@ void load_editLatt(Object *obedit)
 		tot = lt->pntsu * lt->pntsv * lt->pntsw;
 
 		lt->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Lattice MDeformVert");
-		copy_dverts(lt->dvert, editlt->dvert, tot);
+		BKE_defvert_array_copy(lt->dvert, editlt->dvert, tot);
 	}
 }
 
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index d19277d20a2..03b50c05071 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -252,15 +252,6 @@ void ED_operatormacros_object(void)
 		RNA_enum_set(otmacro->ptr, "proportional", PROP_EDIT_OFF);
 	}
 	
-	/* XXX */
-	ot = WM_operatortype_append_macro("OBJECT_OT_add_named_cursor", "Add Named At Cursor",
-	                                  "Add named object at cursor", OPTYPE_UNDO | OPTYPE_REGISTER);
-	if (ot) {
-		RNA_def_string(ot->srna, "name", "Cube", MAX_ID_NAME - 2, "Name", "Object name to add");
-
-		WM_operatortype_macro_define(ot, "VIEW3D_OT_cursor3d");
-		WM_operatortype_macro_define(ot, "OBJECT_OT_add_named");
-	}
 }
 
 static int object_mode_poll(bContext *C)
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 0988a196fb1..fa44d3d7fb4 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -716,12 +716,12 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
 				bFollowPathConstraint *data;
 				float cmat[4][4], vec[3];
 				
-				con = add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH);
+				con = BKE_add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH);
 				
 				data = con->data;
 				data->tar = par;
 				
-				get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
+				BKE_get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
 				sub_v3_v3v3(vec, ob->obmat[3], cmat[3]);
 				
 				ob->loc[0] = vec[0];
@@ -1051,7 +1051,7 @@ static int object_track_clear_exec(bContext *C, wmOperator *op)
 		for (con = ob->constraints.last; con; con = pcon) {
 			pcon = con->prev;
 			if (ELEM3(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK))
-				remove_constraint(&ob->constraints, con);
+				BKE_remove_constraint(&ob->constraints, con);
 		}
 		
 		if (type == 1)
@@ -1109,7 +1109,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
 		CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
 		{
 			if (ob != obact) {
-				con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK);
+				con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK);
 
 				data = con->data;
 				data->tar = obact;
@@ -1129,7 +1129,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
 		CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
 		{
 			if (ob != obact) {
-				con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO);
+				con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO);
 
 				data = con->data;
 				data->tar = obact;
@@ -1151,7 +1151,7 @@ static int track_set_exec(bContext *C, wmOperator *op)
 		CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
 		{
 			if (ob != obact) {
-				con = add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK);
+				con = BKE_add_ob_constraint(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK);
 
 				data = con->data;
 				data->tar = obact;
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 2aa737d204d..07eca749a74 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -42,6 +42,7 @@
 #include "DNA_property_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_armature_types.h"
+#include "DNA_lamp_types.h"
 
 #include "BLI_math.h"
 #include "BLI_listbase.h"
@@ -525,6 +526,7 @@ static EnumPropertyItem prop_select_grouped_types[] = {
 	{10, "COLOR", 0, "Color", "Object Color"},
 	{11, "PROPERTIES", 0, "Properties", "Game Properties"},
 	{12, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"},
+	{13, "LAMP_TYPE", 0, "Lamp Type", "Matching lamp types"},
 	{0, NULL, 0, NULL, NULL}
 };
 
@@ -656,7 +658,25 @@ static short select_grouped_siblings(bContext *C, Object *ob)
 	CTX_DATA_END;
 	return changed;
 }
+static short select_similar_lamps(bContext *C, Object *ob)
+{
+	Lamp *la = ob->data;
 
+	short changed = 0;
+
+	CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
+	{
+		if (base->object->type == OB_LAMP) {
+			Lamp *la_test = base->object->data;
+			if ((la->type == la_test->type) && !(base->flag & SELECT)) {
+				ED_base_object_select(base, BA_SELECT);
+				changed = 1;
+			}
+		}
+	}
+	CTX_DATA_END;
+	return changed;
+}
 static short select_grouped_type(bContext *C, Object *ob)
 {
 	short changed = 0;
@@ -803,7 +823,12 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
 		BKE_report(op->reports, RPT_ERROR, "No active object");
 		return OPERATOR_CANCELLED;
 	}
-	
+
+	if (nr == 13 && ob->type != OB_LAMP) {
+		BKE_report(op->reports, RPT_ERROR, "Active object must be a lamp");
+		return OPERATOR_CANCELLED;
+	}
+
 	if      (nr == 1) changed |= select_grouped_children(C, ob, 1);
 	else if (nr == 2) changed |= select_grouped_children(C, ob, 0);
 	else if (nr == 3) changed |= select_grouped_parent(C);
@@ -816,6 +841,7 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
 	else if (nr == 10) changed |= select_grouped_color(C, ob);
 	else if (nr == 11) changed |= select_grouped_gameprops(C, ob);
 	else if (nr == 12) changed |= select_grouped_keyingset(C, ob);
+	else if (nr == 13) changed |= select_similar_lamps(C, ob);
 	
 	if (changed) {
 		WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, CTX_data_scene(C));
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 16fe94ff2e5..cbc076b3342 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -281,7 +281,7 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
 				IMB_color_to_bw(ibuf);
 			}
 
-			BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, FALSE);
+			BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, FALSE);
 			ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, TRUE); /* no need to stamp here */
 			if (ok) printf("OpenGL Render written to '%s'\n", name);
 			else printf("OpenGL Render failed to write '%s'\n", name);
@@ -505,7 +505,7 @@ static int screen_opengl_render_anim_step(bContext *C, wmOperator *op)
 	is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
 
 	if (!is_movie) {
-		BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, TRUE);
+		BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, TRUE);
 
 		if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
 			printf("skipping existing frame \"%s\"\n", name);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index a864fe306b3..8d748d3ea20 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -280,11 +280,6 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
 			sce->r.tiley = sce->r.ysch / 4;
 		}
 		
-		/* exception: don't apply render part of display transform for texture previews or icons */
-		if ((id && sp->pr_method == PR_ICON_RENDER) || id_type == ID_TE) {
-			BKE_scene_disable_color_management(sce);
-		}
-		
 		if ((id && sp->pr_method == PR_ICON_RENDER) && id_type != ID_WO)
 			sce->r.alphamode = R_ALPHAPREMUL;
 		else
@@ -488,24 +483,15 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
 
 /* new UI convention: draw is in pixel space already. */
 /* uses ROUNDBOX button in block to get the rect */
-static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int first, rcti *rect, rcti *newrect)
+static int ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, rcti *newrect)
 {
 	Render *re;
 	RenderResult rres;
 	char name[32];
-	int do_gamma_correct = FALSE, do_predivide = FALSE;
 	int offx = 0;
 	int newx = BLI_rcti_size_x(rect);
 	int newy = BLI_rcti_size_y(rect);
 
-	if (id && GS(id->name) != ID_TE) {
-		/* exception: don't color manage texture previews - show the raw values */
-		if (sce) {
-			do_gamma_correct = TRUE;
-			do_predivide = sce->r.color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE;
-		}
-	}
-
 	if (!split || first) sprintf(name, "Preview %p", (void *)sa);
 	else sprintf(name, "SecondPreview %p", (void *)sa);
 
@@ -520,8 +506,10 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int
 		}
 	}
 
+	/* test if something rendered ok */
 	re = RE_GetRender(name);
 	RE_AcquireResultImage(re, &rres);
+	RE_ReleaseResultImage(re);
 
 	if (rres.rectf) {
 		
@@ -531,40 +519,20 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int
 			newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
 
 			if (rres.rectx && rres.recty) {
-				/* temporary conversion to byte for drawing */
+				unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect");
 				float fx = rect->xmin + offx;
 				float fy = rect->ymin;
-				int dither = 0;
-				unsigned char *rect_byte;
-
-				rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect");
-
-				if (do_gamma_correct) {
-					IMB_display_buffer_transform_apply(rect_byte, rres.rectf, rres.rectx, rres.recty, 4,
-					                                   &sce->view_settings, &sce->display_settings, do_predivide);
-
-				}
-				else {
-					/* OCIO_TODO: currently seems an exception for textures (came fro mlegacish time),
-					 *            but is it indeed expected behavior, or textures should be
-					 *            color managed as well?
-					 */
-					IMB_buffer_byte_from_float(rect_byte, rres.rectf,
-					                           4, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, do_predivide,
-					                           rres.rectx, rres.recty, rres.rectx, rres.rectx);
-				}
-
+				
+				RE_ResultGet32(re, (unsigned int *)rect_byte);
 				glaDrawPixelsSafe(fx, fy, rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect_byte);
-
+				
 				MEM_freeN(rect_byte);
+				
+				return 1;
 			}
-
-			RE_ReleaseResultImage(re);
-			return 1;
 		}
 	}
 
-	RE_ReleaseResultImage(re);
 	return 0;
 }
 
@@ -572,7 +540,6 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
 {
 	if (idp) {
 		ScrArea *sa = CTX_wm_area(C);
-		Scene *sce = CTX_data_scene(C);
 		ID *id = (ID *)idp;
 		ID *parent = (ID *)parentp;
 		MTex *slot = (MTex *)slotp;
@@ -588,11 +555,11 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
 		newrect.ymax = rect->ymin;
 
 		if (parent) {
-			ok = ed_preview_draw_rect(sa, sce, id, 1, 1, rect, &newrect);
-			ok &= ed_preview_draw_rect(sa, sce, parent, 1, 0, rect, &newrect);
+			ok = ed_preview_draw_rect(sa, 1, 1, rect, &newrect);
+			ok &= ed_preview_draw_rect(sa, 1, 0, rect, &newrect);
 		}
 		else
-			ok = ed_preview_draw_rect(sa, sce, id, 0, 0, rect, &newrect);
+			ok = ed_preview_draw_rect(sa, 0, 0, rect, &newrect);
 
 		if (ok)
 			*rect = newrect;
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index bc33936b2e3..dfc53d0b195 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -1310,7 +1310,7 @@ static int envmap_save_exec(bContext *C, wmOperator *op)
 	RNA_string_get(op->ptr, "filepath", path);
 	
 	if (scene->r.scemode & R_EXTENSION) {
-		BKE_add_image_extension(path, imtype);
+		BKE_add_image_extension(path, &scene->r.im_format);
 	}
 	
 	WM_cursor_wait(1);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index fbdec3dd8ad..5af60726f14 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -574,8 +574,8 @@ static void area_azone_initialize(bScreen *screen, ScrArea *sa)
 	az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
 	BLI_addtail(&(sa->actionzones), az);
 	az->type = AZONE_AREA;
-	az->x1 = sa->totrct.xmin - 1;
-	az->y1 = sa->totrct.ymin - 1;
+	az->x1 = sa->totrct.xmin;
+	az->y1 = sa->totrct.ymin;
 	az->x2 = sa->totrct.xmin + (AZONESPOT - 1);
 	az->y2 = sa->totrct.ymin + (AZONESPOT - 1);
 	BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
@@ -917,7 +917,7 @@ static int region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar)
 {
 	if (U.uiflag2 & USER_REGION_OVERLAP)
 		if (WM_is_draw_triple(win))
-			if (ELEM5(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ, SPACE_CLIP, SPACE_NODE))
+			if (ELEM4(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ, SPACE_CLIP))
 				if (ELEM3(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS))
 					return 1;
 	return 0;
@@ -1300,6 +1300,9 @@ void ED_region_init(bContext *C, ARegion *ar)
 	ar->winx = BLI_rcti_size_x(&ar->winrct) + 1;
 	ar->winy = BLI_rcti_size_y(&ar->winrct) + 1;
 	
+	/* v2d mask is used to subtract scrollbars from a 2d view. Needs initialize here. */
+	BLI_rcti_init(&ar->v2d.mask, 0, ar->winx - 1, 0, ar->winy -1);
+
 	/* UI convention */
 	wmOrtho2(-0.01f, ar->winx - 0.01f, -0.01f, ar->winy - 0.01f);
 	glLoadIdentity();
@@ -1612,86 +1615,141 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
 	View2D *v2d = &ar->v2d;
 	View2DScrollers *scrollers;
 	int x, y, xco, yco, w, em, triangle, open, newcontext = 0;
-	
+	int redo;
+	int scroll;
+
 	if (contextnr >= 0)
 		newcontext = UI_view2d_tab_set(v2d, contextnr);
-
+	
+	/* before setting the view */
 	if (vertical) {
-		w = BLI_rctf_size_x(&v2d->cur);
-		em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y;
+		/* only allow scrolling in vertical direction */
+		v2d->keepofs |= V2D_LOCKOFS_X | V2D_KEEPOFS_Y;
+		v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X);
+		v2d->scroll &= ~(V2D_SCROLL_BOTTOM);
+		v2d->scroll |= (V2D_SCROLL_RIGHT);
 	}
 	else {
-		w = UI_PANEL_WIDTH;
-		em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y;
+		/* for now, allow scrolling in both directions (since layouts are optimized for vertical,
+		 * they often don't fit in horizontal layout)
+		 */
+		v2d->keepofs &= ~(V2D_LOCKOFS_X | V2D_LOCKOFS_Y | V2D_KEEPOFS_X | V2D_KEEPOFS_Y);
+		v2d->scroll |= (V2D_SCROLL_BOTTOM);
+		v2d->scroll &= ~(V2D_SCROLL_RIGHT);
 	}
 
-	/* create panels */
-	uiBeginPanels(C, ar);
-
-	/* set view2d view matrix for scrolling (without scrollers) */
-	UI_view2d_view_ortho(v2d);
-
-	for (pt = ar->type->paneltypes.first; pt; pt = pt->next) {
-		/* verify context */
-		if (context)
-			if (pt->context[0] && strcmp(context, pt->context) != 0)
-				continue;
-
-		/* draw panel */
-		if (pt->draw && (!pt->poll || pt->poll(C, pt))) {
-			block = uiBeginBlock(C, ar, pt->idname, UI_EMBOSS);
-			panel = uiBeginPanel(sa, ar, block, pt, &open);
-
-			/* bad fixed values */
-			triangle = (int)(UI_UNIT_Y * 1.1f);
-
-			if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
-				/* for enabled buttons */
-				panel->layout = uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
-				                              triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, style);
-
-				pt->draw_header(C, panel);
-
-				uiBlockLayoutResolve(block, &xco, &yco);
-				panel->labelofs = xco - triangle;
-				panel->layout = NULL;
-			}
-			else {
-				panel->labelofs = 0;
-			}
-
-			if (open) {
-				short panelContext;
-				
-				/* panel context can either be toolbar region or normal panels region */
-				if (ar->regiontype == RGN_TYPE_TOOLS)
-					panelContext = UI_LAYOUT_TOOLBAR;
-				else
-					panelContext = UI_LAYOUT_PANEL;
-				
-				panel->layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, panelContext,
-				                              style->panelspace, 0, w - 2 * style->panelspace, em, style);
-
-				pt->draw(C, panel);
-
-				uiBlockLayoutResolve(block, &xco, &yco);
-				panel->layout = NULL;
-
-				yco -= 2 * style->panelspace;
-				uiEndPanel(block, w, -yco);
-			}
-			else {
-				yco = 0;
-				uiEndPanel(block, w, 0);
-			}
-
-			uiEndBlock(C, block);
+	scroll = v2d->scroll;
+	
+	/* sortof hack - but we cannot predict the height of panels, until it's being generated */
+	/* the layout engine works with fixed width (from v2d->cur), which is being set at end of the loop */
+	/* in case scroller settings (hide flags) differ from previous, the whole loop gets done again */
+	for (redo = 2; redo > 0; redo--) {
+		
+		if (vertical) {
+			w = BLI_rctf_size_x(&v2d->cur);
+			em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y;
 		}
+		else {
+			w = UI_PANEL_WIDTH;
+			em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y;
+		}
+		
+		/* create panels */
+		uiBeginPanels(C, ar);
+
+		/* set view2d view matrix  - uiBeginBlock() stores it */
+		UI_view2d_view_ortho(v2d);
+
+		for (pt = ar->type->paneltypes.first; pt; pt = pt->next) {
+			/* verify context */
+			if (context)
+				if (pt->context[0] && strcmp(context, pt->context) != 0)
+					continue;
+
+			/* draw panel */
+			if (pt->draw && (!pt->poll || pt->poll(C, pt))) {
+				block = uiBeginBlock(C, ar, pt->idname, UI_EMBOSS);
+				panel = uiBeginPanel(sa, ar, block, pt, &open);
+
+				/* bad fixed values */
+				triangle = (int)(UI_UNIT_Y * 1.1f);
+
+				if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
+					/* for enabled buttons */
+					panel->layout = uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
+					                              triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, style);
+
+					pt->draw_header(C, panel);
+
+					uiBlockLayoutResolve(block, &xco, &yco);
+					panel->labelofs = xco - triangle;
+					panel->layout = NULL;
+				}
+				else {
+					panel->labelofs = 0;
+				}
+
+				if (open) {
+					short panelContext;
+					
+					/* panel context can either be toolbar region or normal panels region */
+					if (ar->regiontype == RGN_TYPE_TOOLS)
+						panelContext = UI_LAYOUT_TOOLBAR;
+					else
+						panelContext = UI_LAYOUT_PANEL;
+					
+					panel->layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, panelContext,
+					                              style->panelspace, 0, w - 2 * style->panelspace, em, style);
+
+					pt->draw(C, panel);
+
+					uiBlockLayoutResolve(block, &xco, &yco);
+					panel->layout = NULL;
+
+					yco -= 2 * style->panelspace;
+					uiEndPanel(block, w, -yco);
+				}
+				else {
+					yco = 0;
+					uiEndPanel(block, w, 0);
+				}
+
+				uiEndBlock(C, block);
+			}
+		}
+
+		/* align panels and return size */
+		uiEndPanels(C, ar, &x, &y);
+		
+		/* before setting the view */
+		if (vertical) {
+			/* we always keep the scroll offset - so the total view gets increased with the scrolled away part */
+			if (v2d->cur.ymax < - 0.001f)
+				y = min_ii(y, v2d->cur.ymin);
+			
+			y = -y;
+		}
+		else {
+			/* don't jump back when panels close or hide */
+			if (!newcontext)
+				x = max_ii(x, v2d->cur.xmax);
+			y = -y;
+		}
+		
+		/* this also changes the 'cur' */
+		UI_view2d_totRect_set(v2d, x, y);
+		
+		if (scroll != v2d->scroll) {
+			/* Note: this code scales fine, but because of rounding differences, positions of elements
+			 * flip +1 or -1 pixel compared to redoing the entire layout again.
+			 * Leaving in commented code for future tests */
+			/* uiScalePanels(ar, BLI_rctf_size_x(&v2d->cur));
+			   break; */
+		}
+		else break;
 	}
-
-	/* align panels and return size */
-	uiEndPanels(C, ar, &x, &y);
-
+	
+	
 	/* clear */
 	if (ar->overlap) {
 		/* view should be in pixelspace */
@@ -1706,36 +1764,6 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
 		glClear(GL_COLOR_BUFFER_BIT);
 	}
 	
-	/* before setting the view */
-	if (vertical) {
-		/* only allow scrolling in vertical direction */
-		v2d->keepofs |= V2D_LOCKOFS_X | V2D_KEEPOFS_Y;
-		v2d->keepofs &= ~(V2D_LOCKOFS_Y | V2D_KEEPOFS_X);
-		v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
-		v2d->scroll &= ~V2D_SCROLL_VERTICAL_HIDE;
-
-		/* ensure tot is set correctly, to keep views on bottons, with sliders */
-		y = min_ii(y, v2d->cur.ymin);
-		y = -y;
-	}
-	else {
-		/* for now, allow scrolling in both directions (since layouts are optimized for vertical,
-		 * they often don't fit in horizontal layout)
-		 */
-		v2d->keepofs &= ~(V2D_LOCKOFS_X | V2D_LOCKOFS_Y | V2D_KEEPOFS_X | V2D_KEEPOFS_Y);
-		//v2d->keepofs |= V2D_LOCKOFS_Y|V2D_KEEPOFS_X;
-		//v2d->keepofs &= ~(V2D_LOCKOFS_X|V2D_KEEPOFS_Y);
-		v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE;
-		v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_HIDE;
-
-		/* don't jump back when panels close or hide */
-		if (!newcontext)
-			x = max_ii(x, v2d->cur.xmax);
-		y = -y;
-	}
-
-	/* +V2D_SCROLL_HEIGHT is workaround to set the actual height (needs to be int) */
-	UI_view2d_totRect_set(v2d, x + (int)V2D_SCROLL_WIDTH, y + (int)V2D_SCROLL_HEIGHT);
 
 	/* set the view */
 	UI_view2d_view_ortho(v2d);
@@ -1755,17 +1783,6 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
 void ED_region_panels_init(wmWindowManager *wm, ARegion *ar)
 {
 	wmKeyMap *keymap;
-	
-	/* XXX quick hacks for files saved with 2.5 already (i.e. the builtin defaults file)
-	 * scrollbars for button regions */
-	ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
-	ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
-	ar->v2d.scroll &= ~V2D_SCROLL_VERTICAL_HIDE;
-	ar->v2d.keepzoom |= V2D_KEEPZOOM;
-
-	/* correctly initialized User-Prefs? */
-	if (!(ar->v2d.align & V2D_ALIGN_NO_POS_Y))
-		ar->v2d.flag &= ~V2D_IS_INITIALISED;
 
 	UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy);
 
@@ -1828,6 +1845,7 @@ void ED_region_header(const bContext *C, ARegion *ar)
 
 void ED_region_header_init(ARegion *ar)
 {
+	ar->v2d.flag &= ~V2D_IS_INITIALISED;
 	UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
 }
 
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index ca85daadf3b..2982e1f21af 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -223,7 +223,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)
 static int screenshot_check(bContext *UNUSED(C), wmOperator *op)
 {
 	ScreenshotData *scd = op->customdata;
-	return WM_operator_filesel_ensure_ext_imtype(op, scd->im_format.imtype);
+	return WM_operator_filesel_ensure_ext_imtype(op, &scd->im_format);
 }
 
 static int screenshot_cancel(bContext *UNUSED(C), wmOperator *op)
@@ -361,7 +361,7 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
 				char name[FILE_MAX];
 				int ok;
 				
-				BKE_makepicstring(name, rd.pic, sj->bmain->name, rd.cfra, rd.im_format.imtype, rd.scemode & R_EXTENSION, TRUE);
+				BKE_makepicstring(name, rd.pic, sj->bmain->name, rd.cfra, &rd.im_format, rd.scemode & R_EXTENSION, TRUE);
 				
 				ibuf->rect = sj->dumprect;
 				ok = BKE_imbuf_write(ibuf, name, &rd.im_format);
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index ae72dce1415..5bed31e2e52 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -42,6 +42,7 @@ set(SRC
 	paint_cursor.c
 	paint_hide.c
 	paint_image.c
+	paint_image_2d.c
 	paint_mask.c
 	paint_ops.c
 	paint_stroke.c
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 36fe4715fc0..d50261a3b98 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -112,8 +112,8 @@ static void partialvis_update_mesh(Object *ob,
 	int *vert_indices;
 	int any_changed = 0, any_visible = 0, totvert, i;
 			
-	BLI_pbvh_node_num_verts(pbvh, node, NULL, &totvert);
-	BLI_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
+	BKE_pbvh_node_num_verts(pbvh, node, NULL, &totvert);
+	BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
 	paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
 
 	sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
@@ -136,8 +136,8 @@ static void partialvis_update_mesh(Object *ob,
 	}
 
 	if (any_changed) {
-		BLI_pbvh_node_mark_rebuild_draw(node);
-		BLI_pbvh_node_fully_hidden_set(node, !any_visible);
+		BKE_pbvh_node_mark_rebuild_draw(node);
+		BKE_pbvh_node_fully_hidden_set(node, !any_visible);
 	}
 }
 
@@ -157,11 +157,11 @@ static void partialvis_update_grids(Object *ob,
 	int *grid_indices, totgrid, any_changed, i;
 
 	/* get PBVH data */
-	BLI_pbvh_node_get_grids(pbvh, node,
+	BKE_pbvh_node_get_grids(pbvh, node,
 	                        &grid_indices, &totgrid, NULL, NULL,
 	                        &grids, NULL);
-	grid_hidden = BLI_pbvh_grid_hidden(pbvh);
-	BLI_pbvh_get_grid_key(pbvh, &key);
+	grid_hidden = BKE_pbvh_grid_hidden(pbvh);
+	BKE_pbvh_get_grid_key(pbvh, &key);
 	
 	sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
 	
@@ -226,12 +226,81 @@ static void partialvis_update_grids(Object *ob,
 
 	/* mark updates if anything was hidden/shown */
 	if (any_changed) {
-		BLI_pbvh_node_mark_rebuild_draw(node);
-		BLI_pbvh_node_fully_hidden_set(node, !any_visible);
+		BKE_pbvh_node_mark_rebuild_draw(node);
+		BKE_pbvh_node_fully_hidden_set(node, !any_visible);
 		multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED);
 	}
 }
 
+static void partialvis_update_bmesh_verts(BMesh *bm,
+										  GHash *verts,
+										  PartialVisAction action,
+										  PartialVisArea area,
+										  float planes[4][4],
+										  int *any_changed,
+										  int *any_visible)
+{
+	GHashIterator gh_iter;
+
+	GHASH_ITER (gh_iter, verts) {
+		BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
+		float *vmask = CustomData_bmesh_get(&bm->vdata,
+											v->head.data,
+											CD_PAINT_MASK);
+
+		/* hide vertex if in the hide volume */
+		if (is_effected(area, planes, v->co, *vmask)) {
+			if (action == PARTIALVIS_HIDE)
+				BM_elem_flag_enable(v, BM_ELEM_HIDDEN);
+			else
+				BM_elem_flag_disable(v, BM_ELEM_HIDDEN);
+			(*any_changed) = TRUE;
+		}
+
+		if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+			(*any_visible) = TRUE;
+	}
+}
+
+static void partialvis_update_bmesh(Object *ob,
+									PBVH *pbvh,
+									PBVHNode *node,
+									PartialVisAction action,
+									PartialVisArea area,
+									float planes[4][4])
+{
+	BMesh *bm;
+	GHash *unique, *other;
+	int any_changed = 0, any_visible = 0;
+
+	bm = BKE_pbvh_get_bmesh(pbvh);
+	unique = BKE_pbvh_bmesh_node_unique_verts(node);
+	other = BKE_pbvh_bmesh_node_other_verts(node);
+
+	sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
+
+	partialvis_update_bmesh_verts(bm,
+								  unique,
+								  action,
+								  area,
+								  planes,
+								  &any_changed,
+								  &any_visible);
+
+	partialvis_update_bmesh_verts(bm,
+								  other,
+								  action,
+								  area,
+								  planes,
+								  &any_changed,
+								  &any_visible);
+
+	if (any_changed) {
+		BKE_pbvh_node_mark_rebuild_draw(node);
+		BKE_pbvh_node_fully_hidden_set(node, !any_visible);
+	}
+}
+
 static void rect_from_props(rcti *rect, PointerRNA *ptr)
 {
 	rect->xmin = RNA_int_get(ptr, "xmin");
@@ -265,22 +334,22 @@ static void get_pbvh_nodes(PBVH *pbvh,
                            float clip_planes[4][4],
                            PartialVisArea mode)
 {
-	BLI_pbvh_SearchCallback cb = NULL;
+	BKE_pbvh_SearchCallback cb = NULL;
 
 	/* select search callback */
 	switch (mode) {
 		case PARTIALVIS_INSIDE:
-			cb = BLI_pbvh_node_planes_contain_AABB;
+			cb = BKE_pbvh_node_planes_contain_AABB;
 			break;
 		case PARTIALVIS_OUTSIDE:
-			cb = BLI_pbvh_node_planes_exclude_AABB;
+			cb = BKE_pbvh_node_planes_exclude_AABB;
 			break;
 		case PARTIALVIS_ALL:
 		case PARTIALVIS_MASKED:
 			break;
 	}
 	
-	BLI_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode);
+	BKE_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode);
 }
 
 static int hide_show_exec(bContext *C, wmOperator *op)
@@ -310,7 +379,7 @@ static int hide_show_exec(bContext *C, wmOperator *op)
 	ob->sculpt->pbvh = pbvh;
 
 	get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
-	pbvh_type = BLI_pbvh_type(pbvh);
+	pbvh_type = BKE_pbvh_type(pbvh);
 
 	/* start undo */
 	switch (action) {
@@ -330,6 +399,9 @@ static int hide_show_exec(bContext *C, wmOperator *op)
 			case PBVH_GRIDS:
 				partialvis_update_grids(ob, pbvh, nodes[i], action, area, clip_planes);
 				break;
+			case PBVH_BMESH:
+				partialvis_update_bmesh(ob, pbvh, nodes[i], action, area, clip_planes);
+				break;
 		}
 	}
 
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 8c9531e5554..fa8252c824d 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -42,7 +42,6 @@
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
 #include "BLI_linklist.h"
 #include "BLI_memarena.h"
 #include "BLI_threads.h"
@@ -54,13 +53,9 @@
 #include "IMB_imbuf_types.h"
 
 #include "DNA_brush_types.h"
-#include "DNA_camera_types.h"
 #include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
 #include "DNA_node_types.h"
 #include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
 
 #include "BKE_camera.h"
 #include "BKE_context.h"
@@ -77,8 +72,7 @@
 #include "BKE_paint.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
-#include "BKE_global.h"
-#include "BKE_deform.h"
+#include "BKE_colortools.h"
 
 #include "BKE_tessmesh.h"
 
@@ -102,7 +96,6 @@
 #include "RNA_enum_types.h"
 
 #include "GPU_draw.h"
-#include "GPU_extensions.h"
 
 #include "IMB_colormanagement.h"
 
@@ -5142,15 +5135,16 @@ static int texture_paint_init(bContext *C, wmOperator *op)
 			return 0;
 		}
 	}
-	
-	paint_brush_init_tex(pop->s.brush);
-	
+
 	/* note, if we have no UVs on the derived mesh, then we must return here */
 	if (pop->mode == PAINT_MODE_3D_PROJECT) {
 
 		/* initialize all data from the context */
 		project_state_init(C, OBACT, &pop->ps);
-		
+
+		/* needed so multiple threads don't try to initialize the brush at once (can leak memory) */
+		curvemapping_initialize(pop->ps.brush->curve);
+
 		paint_brush_init_tex(pop->ps.brush);
 
 		pop->ps.source = PROJ_SRC_VIEW;
@@ -5168,6 +5162,9 @@ static int texture_paint_init(bContext *C, wmOperator *op)
 		if (pop->ps.dm == NULL)
 			return 0;
 	}
+	else {
+		paint_brush_init_tex(pop->s.brush);
+	}
 	
 	settings->imapaint.flag |= IMAGEPAINT_DRAWING;
 	undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
@@ -5237,8 +5234,6 @@ static void paint_exit(bContext *C, wmOperator *op)
 	if (pop->restore_projection)
 		settings->imapaint.flag &= ~IMAGEPAINT_PROJECT_DISABLE;
 
-	paint_brush_exit_tex(pop->s.brush);
-	
 	settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
 	imapaint_canvas_free(&pop->s);
 	BKE_brush_painter_free(pop->painter);
@@ -5250,6 +5245,8 @@ static void paint_exit(bContext *C, wmOperator *op)
 		project_paint_end(&pop->ps);
 	}
 	else {
+		paint_brush_exit_tex(pop->s.brush);
+
 		/* non projection 3d paint, could move into own function of more needs adding */
 		if (pop->s.dm_release)
 			pop->s.dm->release(pop->s.dm);
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
new file mode 100644
index 00000000000..c30996f03de
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -0,0 +1,561 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/sculpt_paint/paint_image_2d.c
+ *  \ingroup bke
+ */
+//#include 
+#include 
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_brush.h"
+
+#include "BLI_math.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "RE_shader_ext.h"
+
+ /* Brush Painting for 2D image editor */
+
+typedef struct BrushPainterCache {
+	short enabled;
+
+	int size;           /* size override, if 0 uses 2*BKE_brush_size_get(brush) */
+	short flt;          /* need float imbuf? */
+	short texonly;      /* no alpha, color or fallof, only texture in imbuf */
+
+	int lastsize;
+	float lastalpha;
+	float lastjitter;
+
+	ImBuf *ibuf;
+	ImBuf *texibuf;
+	ImBuf *maskibuf;
+} BrushPainterCache;
+
+struct BrushPainter {
+	Scene *scene;
+	Brush *brush;
+
+	float lastmousepos[2];  /* mouse position of last paint call */
+
+	float accumdistance;    /* accumulated distance of brush since last paint op */
+	float lastpaintpos[2];  /* position of last paint op */
+	float startpaintpos[2]; /* position of first paint */
+
+	double accumtime;       /* accumulated time since last paint op (airbrush) */
+	double lasttime;        /* time of last update */
+
+	float lastpressure;
+
+	short firsttouch;       /* first paint op */
+
+	float startsize;
+	float startalpha;
+	float startjitter;
+	float startspacing;
+
+	BrushPainterCache cache;
+};
+
+BrushPainter *BKE_brush_painter_new(Scene *scene, Brush *brush)
+{
+	BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
+
+	painter->brush = brush;
+	painter->scene = scene;
+	painter->firsttouch = 1;
+	painter->cache.lastsize = -1; /* force ibuf create in refresh */
+
+	painter->startsize = BKE_brush_size_get(scene, brush);
+	painter->startalpha = BKE_brush_alpha_get(scene, brush);
+	painter->startjitter = brush->jitter;
+	painter->startspacing = brush->spacing;
+
+	return painter;
+}
+
+
+static void brush_pressure_apply(BrushPainter *painter, Brush *brush, float pressure)
+{
+	if (BKE_brush_use_alpha_pressure(painter->scene, brush))
+		BKE_brush_alpha_set(painter->scene, brush, max_ff(0.0f, painter->startalpha * pressure));
+	if (BKE_brush_use_size_pressure(painter->scene, brush))
+		BKE_brush_size_set(painter->scene, brush, max_ff(1.0f, painter->startsize * pressure));
+	if (brush->flag & BRUSH_JITTER_PRESSURE)
+		brush->jitter = max_ff(0.0f, painter->startjitter * pressure);
+	if (brush->flag & BRUSH_SPACING_PRESSURE)
+		brush->spacing = max_ff(1.0f, painter->startspacing * (1.5f - pressure));
+}
+
+
+void BKE_brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size)
+{
+	if ((painter->cache.flt != flt) || (painter->cache.size != size) ||
+	    ((painter->cache.texonly != texonly) && texonly))
+	{
+		if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
+		if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf);
+		painter->cache.ibuf = painter->cache.maskibuf = NULL;
+		painter->cache.lastsize = -1; /* force ibuf create in refresh */
+	}
+
+	if (painter->cache.flt != flt) {
+		if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
+		painter->cache.texibuf = NULL;
+		painter->cache.lastsize = -1; /* force ibuf create in refresh */
+	}
+
+	painter->cache.size = size;
+	painter->cache.flt = flt;
+	painter->cache.texonly = texonly;
+	painter->cache.enabled = 1;
+}
+
+void BKE_brush_painter_free(BrushPainter *painter)
+{
+	Brush *brush = painter->brush;
+
+	BKE_brush_size_set(painter->scene, brush, painter->startsize);
+	BKE_brush_alpha_set(painter->scene, brush, painter->startalpha);
+	brush->jitter = painter->startjitter;
+	brush->spacing = painter->startspacing;
+
+	if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
+	if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
+	if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf);
+	MEM_freeN(painter);
+}
+
+static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf,
+                                     int x, int y, int w, int h, int xt, int yt,
+                                     const float pos[2])
+{
+	Scene *scene = painter->scene;
+	Brush *brush = painter->brush;
+	ImBuf *ibuf, *maskibuf, *texibuf;
+	float *bf, *mf, *tf, *otf = NULL, xoff, yoff, xy[2], rgba[4];
+	unsigned char *b, *m, *t, *ot = NULL;
+	int dotexold, origx = x, origy = y;
+	const int radius = BKE_brush_size_get(painter->scene, brush);
+
+	xoff = -radius + 0.5f;
+	yoff = -radius + 0.5f;
+	xoff += (int)pos[0] - (int)painter->startpaintpos[0];
+	yoff += (int)pos[1] - (int)painter->startpaintpos[1];
+
+	ibuf = painter->cache.ibuf;
+	texibuf = painter->cache.texibuf;
+	maskibuf = painter->cache.maskibuf;
+
+	dotexold = (oldtexibuf != NULL);
+
+	/* not sure if it's actually needed or it's a mistake in coords/sizes
+	 * calculation in brush_painter_fixed_tex_partial_update(), but without this
+	 * limitation memory gets corrupted at fast strokes with quite big spacing (sergey) */
+	w = min_ii(w, ibuf->x);
+	h = min_ii(h, ibuf->y);
+
+	if (painter->cache.flt) {
+		for (; y < h; y++) {
+			bf = ibuf->rect_float + (y * ibuf->x + origx) * 4;
+			tf = texibuf->rect_float + (y * texibuf->x + origx) * 4;
+			mf = maskibuf->rect_float + (y * maskibuf->x + origx) * 4;
+
+			if (dotexold)
+				otf = oldtexibuf->rect_float + ((y - origy + yt) * oldtexibuf->x + xt) * 4;
+
+			for (x = origx; x < w; x++, bf += 4, mf += 4, tf += 4) {
+				if (dotexold) {
+					copy_v3_v3(tf, otf);
+					tf[3] = otf[3];
+					otf += 4;
+				}
+				else {
+					xy[0] = x + xoff;
+					xy[1] = y + yoff;
+
+					BKE_brush_sample_tex(scene, brush, xy, tf, 0);
+				}
+
+				bf[0] = tf[0] * mf[0];
+				bf[1] = tf[1] * mf[1];
+				bf[2] = tf[2] * mf[2];
+				bf[3] = tf[3] * mf[3];
+			}
+		}
+	}
+	else {
+		for (; y < h; y++) {
+			b = (unsigned char *)ibuf->rect + (y * ibuf->x + origx) * 4;
+			t = (unsigned char *)texibuf->rect + (y * texibuf->x + origx) * 4;
+			m = (unsigned char *)maskibuf->rect + (y * maskibuf->x + origx) * 4;
+
+			if (dotexold)
+				ot = (unsigned char *)oldtexibuf->rect + ((y - origy + yt) * oldtexibuf->x + xt) * 4;
+
+			for (x = origx; x < w; x++, b += 4, m += 4, t += 4) {
+				if (dotexold) {
+					t[0] = ot[0];
+					t[1] = ot[1];
+					t[2] = ot[2];
+					t[3] = ot[3];
+					ot += 4;
+				}
+				else {
+					xy[0] = x + xoff;
+					xy[1] = y + yoff;
+
+					BKE_brush_sample_tex(scene, brush, xy, rgba, 0);
+					rgba_float_to_uchar(t, rgba);
+				}
+
+				b[0] = t[0] * m[0] / 255;
+				b[1] = t[1] * m[1] / 255;
+				b[2] = t[2] * m[2] / 255;
+				b[3] = t[3] * m[3] / 255;
+			}
+		}
+	}
+}
+
+static void brush_painter_fixed_tex_partial_update(BrushPainter *painter, const float pos[2])
+{
+	const Scene *scene = painter->scene;
+	Brush *brush = painter->brush;
+	BrushPainterCache *cache = &painter->cache;
+	ImBuf *oldtexibuf, *ibuf;
+	int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
+	const int diameter = 2 * BKE_brush_size_get(scene, brush);
+
+	imbflag = (cache->flt) ? IB_rectfloat : IB_rect;
+	if (!cache->ibuf)
+		cache->ibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
+	ibuf = cache->ibuf;
+
+	oldtexibuf = cache->texibuf;
+	cache->texibuf = IMB_allocImBuf(diameter, diameter, 32, imbflag);
+
+	if (oldtexibuf) {
+		srcx = srcy = 0;
+		destx = (int)painter->lastpaintpos[0] - (int)pos[0];
+		desty = (int)painter->lastpaintpos[1] - (int)pos[1];
+		w = oldtexibuf->x;
+		h = oldtexibuf->y;
+
+		IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
+	}
+	else {
+		srcx = srcy = 0;
+		destx = desty = 0;
+		w = h = 0;
+	}
+	
+	x1 = destx;
+	y1 = desty;
+	x2 = destx + w;
+	y2 = desty + h;
+
+	/* blend existing texture in new position */
+	if ((x1 < x2) && (y1 < y2))
+		brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos);
+
+	if (oldtexibuf)
+		IMB_freeImBuf(oldtexibuf);
+
+	/* sample texture in new areas */
+	if ((0 < x1) && (0 < ibuf->y))
+		brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos);
+	if ((x2 < ibuf->x) && (0 < ibuf->y))
+		brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos);
+	if ((x1 < x2) && (0 < y1))
+		brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos);
+	if ((x1 < x2) && (y2 < ibuf->y))
+		brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
+}
+
+static void brush_painter_refresh_cache(BrushPainter *painter, const float pos[2], int use_color_correction)
+{
+	const Scene *scene = painter->scene;
+	Brush *brush = painter->brush;
+	BrushPainterCache *cache = &painter->cache;
+	MTex *mtex = &brush->mtex;
+	int size;
+	short flt;
+	const int diameter = 2 * BKE_brush_size_get(scene, brush);
+	const float alpha = BKE_brush_alpha_get(scene, brush);
+
+	if (diameter != cache->lastsize ||
+	    alpha != cache->lastalpha ||
+	    brush->jitter != cache->lastjitter)
+	{
+		if (cache->ibuf) {
+			IMB_freeImBuf(cache->ibuf);
+			cache->ibuf = NULL;
+		}
+		if (cache->maskibuf) {
+			IMB_freeImBuf(cache->maskibuf);
+			cache->maskibuf = NULL;
+		}
+
+		flt = cache->flt;
+		size = (cache->size) ? cache->size : diameter;
+
+		if (brush->flag & BRUSH_FIXED_TEX) {
+			BKE_brush_imbuf_new(scene, brush, flt, 3, size, &cache->maskibuf, use_color_correction);
+			brush_painter_fixed_tex_partial_update(painter, pos);
+		}
+		else
+			BKE_brush_imbuf_new(scene, brush, flt, 2, size, &cache->ibuf, use_color_correction);
+
+		cache->lastsize = diameter;
+		cache->lastalpha = alpha;
+		cache->lastjitter = brush->jitter;
+	}
+	else if ((brush->flag & BRUSH_FIXED_TEX) && mtex && mtex->tex) {
+		int dx = (int)painter->lastpaintpos[0] - (int)pos[0];
+		int dy = (int)painter->lastpaintpos[1] - (int)pos[1];
+
+		if ((dx != 0) || (dy != 0))
+			brush_painter_fixed_tex_partial_update(painter, pos);
+	}
+}
+
+void BKE_brush_painter_break_stroke(BrushPainter *painter)
+{
+	painter->firsttouch = 1;
+}
+
+
+int BKE_brush_painter_paint(BrushPainter *painter, BrushFunc func, const float pos[2], double time, float pressure,
+                            void *user, int use_color_correction)
+{
+	Scene *scene = painter->scene;
+	Brush *brush = painter->brush;
+	int totpaintops = 0;
+
+	if (pressure == 0.0f) {
+		if (painter->lastpressure) // XXX - hack, operator misses
+			pressure = painter->lastpressure;
+		else
+			pressure = 1.0f;    /* zero pressure == not using tablet */
+	}
+	if (painter->firsttouch) {
+		/* paint exactly once on first touch */
+		painter->startpaintpos[0] = pos[0];
+		painter->startpaintpos[1] = pos[1];
+
+		brush_pressure_apply(painter, brush, pressure);
+		if (painter->cache.enabled)
+			brush_painter_refresh_cache(painter, pos, use_color_correction);
+		totpaintops += func(user, painter->cache.ibuf, pos, pos);
+		
+		painter->lasttime = time;
+		painter->firsttouch = 0;
+		painter->lastpaintpos[0] = pos[0];
+		painter->lastpaintpos[1] = pos[1];
+	}
+#if 0
+	else if (painter->brush->flag & BRUSH_AIRBRUSH) {
+		float spacing, step, paintpos[2], dmousepos[2], len;
+		double starttime, curtime = time;
+
+		/* compute brush spacing adapted to brush size */
+		spacing = brush->rate; //radius*brush->spacing*0.01f;
+
+		/* setup starting time, direction vector and accumulated time */
+		starttime = painter->accumtime;
+		sub_v2_v2v2(dmousepos, pos, painter->lastmousepos);
+		len = normalize_v2(dmousepos);
+		painter->accumtime += curtime - painter->lasttime;
+
+		/* do paint op over unpainted time distance */
+		while (painter->accumtime >= spacing) {
+			step = (spacing - starttime) * len;
+			paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step;
+			paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step;
+
+			if (painter->cache.enabled)
+				brush_painter_refresh_cache(painter);
+			totpaintops += func(user, painter->cache.ibuf,
+			                    painter->lastpaintpos, paintpos);
+
+			painter->lastpaintpos[0] = paintpos[0];
+			painter->lastpaintpos[1] = paintpos[1];
+			painter->accumtime -= spacing;
+			starttime -= spacing;
+		}
+		
+		painter->lasttime = curtime;
+	}
+#endif
+	else {
+		float startdistance, spacing, step, paintpos[2], dmousepos[2], finalpos[2];
+		float t, len, press;
+		const int radius = BKE_brush_size_get(scene, brush);
+
+		/* compute brush spacing adapted to brush radius, spacing may depend
+		 * on pressure, so update it */
+		brush_pressure_apply(painter, brush, painter->lastpressure);
+		spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f;
+
+		/* setup starting distance, direction vector and accumulated distance */
+		startdistance = painter->accumdistance;
+		sub_v2_v2v2(dmousepos, pos, painter->lastmousepos);
+		len = normalize_v2(dmousepos);
+		painter->accumdistance += len;
+
+		if (brush->flag & BRUSH_SPACE) {
+			/* do paint op over unpainted distance */
+			while ((len > 0.0f) && (painter->accumdistance >= spacing)) {
+				step = spacing - startdistance;
+				paintpos[0] = painter->lastmousepos[0] + dmousepos[0] * step;
+				paintpos[1] = painter->lastmousepos[1] + dmousepos[1] * step;
+
+				t = step / len;
+				press = (1.0f - t) * painter->lastpressure + t * pressure;
+				brush_pressure_apply(painter, brush, press);
+				spacing = max_ff(1.0f, radius) * brush->spacing * 0.01f;
+
+				BKE_brush_jitter_pos(scene, brush, paintpos, finalpos);
+
+				if (painter->cache.enabled)
+					brush_painter_refresh_cache(painter, finalpos, use_color_correction);
+
+				totpaintops +=
+				    func(user, painter->cache.ibuf, painter->lastpaintpos, finalpos);
+
+				painter->lastpaintpos[0] = paintpos[0];
+				painter->lastpaintpos[1] = paintpos[1];
+				painter->accumdistance -= spacing;
+				startdistance -= spacing;
+			}
+		}
+		else {
+			BKE_brush_jitter_pos(scene, brush, pos, finalpos);
+
+			if (painter->cache.enabled)
+				brush_painter_refresh_cache(painter, finalpos, use_color_correction);
+
+			totpaintops += func(user, painter->cache.ibuf, pos, finalpos);
+
+			painter->lastpaintpos[0] = pos[0];
+			painter->lastpaintpos[1] = pos[1];
+			painter->accumdistance = 0;
+		}
+
+		/* do airbrush paint ops, based on the number of paint ops left over
+		 * from regular painting. this is a temporary solution until we have
+		 * accurate time stamps for mouse move events */
+		if (brush->flag & BRUSH_AIRBRUSH) {
+			double curtime = time;
+			double painttime = brush->rate * totpaintops;
+
+			painter->accumtime += curtime - painter->lasttime;
+			if (painter->accumtime <= painttime)
+				painter->accumtime = 0.0;
+			else
+				painter->accumtime -= painttime;
+
+			while (painter->accumtime >= (double)brush->rate) {
+				brush_pressure_apply(painter, brush, pressure);
+
+				BKE_brush_jitter_pos(scene, brush, pos, finalpos);
+
+				if (painter->cache.enabled)
+					brush_painter_refresh_cache(painter, finalpos, use_color_correction);
+
+				totpaintops +=
+				    func(user, painter->cache.ibuf, painter->lastmousepos, finalpos);
+				painter->accumtime -= (double)brush->rate;
+			}
+
+			painter->lasttime = curtime;
+		}
+	}
+
+	painter->lastmousepos[0] = pos[0];
+	painter->lastmousepos[1] = pos[1];
+	painter->lastpressure = pressure;
+
+	BKE_brush_alpha_set(scene, brush, painter->startalpha);
+	BKE_brush_size_set(scene, brush, painter->startsize);
+	brush->jitter = painter->startjitter;
+	brush->spacing = painter->startspacing;
+
+	return totpaintops;
+}
+
+
+/* TODO: should probably be unified with BrushPainter stuff? */
+unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side)
+{
+	unsigned int *texcache = NULL;
+	MTex *mtex = &br->mtex;
+	TexResult texres = {0};
+	int hasrgb, ix, iy;
+	int side = half_side * 2;
+	
+	if (mtex->tex) {
+		float x, y, step = 2.0 / side, co[3];
+
+		texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache");
+
+		/*do normalized cannonical view coords for texture*/
+		for (y = -1.0, iy = 0; iy < side; iy++, y += step) {
+			for (x = -1.0, ix = 0; ix < side; ix++, x += step) {
+				co[0] = x;
+				co[1] = y;
+				co[2] = 0.0f;
+				
+				/* This is copied from displace modifier code */
+				hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres);
+			
+				/* if the texture gave an RGB value, we assume it didn't give a valid
+				 * intensity, so calculate one (formula from do_material_tex).
+				 * if the texture didn't give an RGB value, copy the intensity across
+				 */
+				if (hasrgb & TEX_RGB)
+					texres.tin = rgb_to_grayscale(&texres.tr);
+
+				((char *)texcache)[(iy * side + ix) * 4] =
+				((char *)texcache)[(iy * side + ix) * 4 + 1] =
+				((char *)texcache)[(iy * side + ix) * 4 + 2] =
+				((char *)texcache)[(iy * side + ix) * 4 + 3] = (char)(texres.tin * 255.0f);
+			}
+		}
+	}
+
+	return texcache;
+}
+
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 9fe7fc1d3ac..3cf67667f39 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -96,7 +96,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
 	pbvh = dm->getPBVH(ob, dm);
 	ob->sculpt->pbvh = pbvh;
 
-	BLI_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+	BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
 
 	sculpt_undo_push_begin("Mask flood fill");
 
@@ -105,12 +105,12 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
 
 		sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
 
-		BLI_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) {
+		BKE_pbvh_vertex_iter_begin(pbvh, nodes[i], vi, PBVH_ITER_UNIQUE) {
 			mask_flood_fill_set_elem(vi.mask, mode, value);
-		} BLI_pbvh_vertex_iter_end;
+		} BKE_pbvh_vertex_iter_end;
 		
-		BLI_pbvh_node_mark_update(nodes[i]);
-		if (BLI_pbvh_type(pbvh) == PBVH_GRIDS)
+		BKE_pbvh_node_mark_update(nodes[i]);
+		if (BKE_pbvh_type(pbvh) == PBVH_GRIDS)
 			multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
 	}
 	
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 10b9f26dbcd..9e702c16e2f 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -648,6 +648,18 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
 	kmi = WM_keymap_add_item(keymap, "PAINT_OT_mask_flood_fill", IKEY, KM_PRESS, KM_CTRL, 0);
 	RNA_enum_set(kmi->ptr, "mode", PAINT_MASK_INVERT);
 
+	/* Toggle dynamic topology */
+	WM_keymap_add_item(keymap, "SCULPT_OT_dynamic_topology_toggle", DKEY, KM_PRESS, KM_CTRL, 0);
+
+	/* Dynamic-topology detail size
+	 * 
+	 * This should be improved further, perhaps by showing a triangle
+	 * grid rather than brush alpha */
+	kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", DKEY, KM_PRESS, KM_SHIFT, 0);
+	set_brush_rc_props(kmi->ptr, "sculpt", "detail_size", NULL, 0);
+	RNA_string_set(kmi->ptr, "data_path_primary",
+				   "tool_settings.sculpt.detail_size");
+
 	/* multires switch */
 	kmi = WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", PAGEUPKEY, KM_PRESS, 0, 0);
 	RNA_int_set(kmi->ptr, "level", 1);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 9ebeb61a7bb..2f4115dcd94 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -416,6 +416,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
 	if (!stroke->stroke_started) {
 		copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
 		stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
+		BLI_assert((stroke->stroke_started & ~1) == 0);  /* 0/1 */
 
 		if (stroke->stroke_started) {
 			stroke->smooth_stroke_cursor =
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 359486a4a8d..08c26aaa755 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -372,31 +372,22 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active)
 	bDeformGroup *defgroup = BLI_findlink(&ob->defbase, vgroup_active);
 
 	if (defgroup) {
-		bDeformGroup *curdef;
 		int mirrdef;
 		char name[MAXBONENAME];
 
 		flip_side_name(name, defgroup->name, FALSE);
-
-		if (strcmp(name, defgroup->name) != 0) {
-			for (curdef = ob->defbase.first, mirrdef = 0; curdef; curdef = curdef->next, mirrdef++) {
-				if (!strcmp(curdef->name, name)) {
-					break;
-				}
-			}
-
-			if (curdef == NULL) {
-				int olddef = ob->actdef;  /* tsk, ED_vgroup_add sets the active defgroup */
-				curdef = ED_vgroup_add_name(ob, name);
-				ob->actdef = olddef;
-			}
-
-			/* curdef should never be NULL unless this is
-			 * a  lamp and ED_vgroup_add_name fails */
-			if (curdef) {
-				return mirrdef;
+		mirrdef = defgroup_name_index(ob, name);
+		if (mirrdef == -1) {
+			int olddef = ob->actdef;  /* tsk, ED_vgroup_add sets the active defgroup */
+			if (ED_vgroup_add_name(ob, name)) {
+				mirrdef = BLI_countlist(&ob->defbase) - 1;
 			}
+			ob->actdef = olddef;
 		}
+
+		/* curdef should never be NULL unless this is
+		 * a  lamp and ED_vgroup_add_name fails */
+		return mirrdef;
 	}
 
 	return -1;
@@ -414,7 +405,7 @@ static void free_vpaint_prev(VPaint *vp)
 static void free_wpaint_prev(VPaint *vp)
 {
 	if (vp->wpaint_prev) {
-		MEM_freeN(vp->wpaint_prev);
+		BKE_defvert_array_free(vp->wpaint_prev, vp->tot);
 		vp->wpaint_prev = NULL;
 		vp->tot = 0;
 	}
@@ -441,7 +432,7 @@ static void copy_wpaint_prev(VPaint *wp, MDeformVert *dverts, int dcount)
 		
 		wp->wpaint_prev = MEM_mallocN(sizeof(MDeformVert) * dcount, "wpaint prev");
 		wp->tot = dcount;
-		copy_dverts(wp->wpaint_prev, dverts, dcount);
+		BKE_defvert_array_copy(wp->wpaint_prev, dverts, dcount);
 	}
 }
 
@@ -868,7 +859,10 @@ static float calc_vp_strength_dl(VPaint *vp, ViewContext *vc, const float co[3],
 {
 	float vertco[2];
 
-	if (ED_view3d_project_float_global(vc->ar, co, vertco, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+	if (ED_view3d_project_float_object(vc->ar,
+	                                   co, vertco,
+	                                   V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+	{
 		float delta[2];
 		float dist_squared;
 
@@ -1037,15 +1031,15 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
 		view3d_operator_needs_opengl(C);
 
 		if (use_vert_sel) {
-			if (ED_mesh_pick_vert(C, me, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) {
+			if (ED_mesh_pick_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) {
 				v_idx_best = index;
 			}
 		}
 		else {
-			if (ED_mesh_pick_face_vert(C, me, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
+			if (ED_mesh_pick_face_vert(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
 				v_idx_best = index;
 			}
-			else if (ED_mesh_pick_face(C, me, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
+			else if (ED_mesh_pick_face(C, vc.obact, event->mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
 				/* this relies on knowning the internal worksings of ED_mesh_pick_face_vert() */
 				BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
 			}
@@ -1126,13 +1120,13 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA
 				view3d_operator_needs_opengl(C);
 
 				if (use_vert_sel) {
-					if (ED_mesh_pick_vert(C, me, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) {
+					if (ED_mesh_pick_vert(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, TRUE)) {
 						MDeformVert *dvert = &me->dvert[index];
 						found |= weight_paint_sample_enum_itemf__helper(dvert, defbase_tot, groups);
 					}
 				}
 				else {
-					if (ED_mesh_pick_face(C, me, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
+					if (ED_mesh_pick_face(C, vc.obact, mval, &index, ED_MESH_PICK_DEFAULT_FACE_SIZE)) {
 						MPoly *mp = &me->mpoly[index];
 						unsigned int fidx = mp->totloop - 1;
 
@@ -2058,32 +2052,28 @@ struct WPaintData {
 	int vgroup_mirror;
 	DMCoNo *vertexcosnos;
 	float wpimat[3][3];
-	
+
 	/* variables for auto normalize */
 	const char *vgroup_validmap; /* stores if vgroups tie to deforming bones or not */
 	const char *lock_flags;
 	int defbase_tot;
 };
 
-static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2]))
+/* ensure we have data on wpaint start, add if needed */
+static int wpaint_ensure_data(bContext *C, wmOperator *op)
 {
 	Scene *scene = CTX_data_scene(C);
-	struct PaintStroke *stroke = op->customdata;
-	ToolSettings *ts = scene->toolsettings;
-	VPaint *wp = ts->wpaint;
 	Object *ob = CTX_data_active_object(C);
-	struct WPaintData *wpd;
-	Mesh *me;
+	Mesh *me = BKE_mesh_from_object(ob);
 
-	float mat[4][4], imat[4][4];
-	
 	if (scene->obedit) {
 		return FALSE;
 	}
-	
-	me = BKE_mesh_from_object(ob);
-	if (me == NULL || me->totpoly == 0) return OPERATOR_PASS_THROUGH;
-	
+
+	if (me == NULL || me->totpoly == 0) {
+		return FALSE;
+	}
+
 	/* if nothing was added yet, we make dverts and a vertex deform group */
 	if (!me->dvert) {
 		ED_vgroup_data_create(&me->id);
@@ -2122,6 +2112,25 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNU
 		return FALSE;
 	}
 
+	return TRUE;
+}
+
+static int wpaint_stroke_test_start(bContext *C, wmOperator *op, const float UNUSED(mouse[2]))
+{
+	Scene *scene = CTX_data_scene(C);
+	struct PaintStroke *stroke = op->customdata;
+	ToolSettings *ts = scene->toolsettings;
+	VPaint *wp = ts->wpaint;
+	Object *ob = CTX_data_active_object(C);
+	Mesh *me = BKE_mesh_from_object(ob);
+	struct WPaintData *wpd;
+
+	float mat[4][4], imat[4][4];
+
+	if (wpaint_ensure_data(C, op) == FALSE) {
+		return FALSE;
+	}
+
 	{
 		/* check if we are attempting to paint onto a locked vertex group,
 		 * and other options disallow it from doing anything useful */
@@ -2184,7 +2193,15 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
 	unsigned int index, totindex;
 	float alpha;
 	float mval[2];
-	int use_vert_sel;
+	bool use_vert_sel;
+	bool use_face_sel;
+	bool use_depth;
+
+	MDeformWeight *(*dw_func)(MDeformVert *, const int) =
+	        (brush->vertexpaint_tool == PAINT_BLEND_BLUR) ?
+	        ((wp->flag & VP_ONLYVGROUP) ?
+	             (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index :
+	              defvert_verify_index) : NULL;
 
 	const float pressure = RNA_float_get(itemptr, "pressure");
 	const float brush_size_pressure = BKE_brush_size_get(scene, brush) * (BKE_brush_use_size_pressure(scene, brush) ? pressure : 1.0f);
@@ -2201,7 +2218,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
 		ED_region_tag_redraw(CTX_wm_region(C));
 		return;
 	}
-		
+
 	vc = &wpd->vc;
 	ob = vc->obact;
 	me = ob->data;
@@ -2242,31 +2259,38 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
 	swap_m4m4(wpd->vc.rv3d->persmat, mat);
 
 	use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+	use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
+	use_depth = (vc->v3d->flag & V3D_ZBUF_SELECT);
 
 	/* which faces are involved */
-	if (wp->flag & VP_AREA) {
-		/* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */
-		me->editflag &= ~ME_EDIT_PAINT_VERT_SEL;
-		totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
-		me->editflag |= use_vert_sel ? ME_EDIT_PAINT_VERT_SEL : 0;
-	}
-	else {
-		indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]);
-		if (indexar[0]) totindex = 1;
-		else totindex = 0;
-	}
+	if (use_depth) {
+		if (wp->flag & VP_AREA) {
+			/* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */
+			me->editflag &= ~ME_EDIT_PAINT_VERT_SEL;
+			totindex = sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure);
+			me->editflag |= use_vert_sel ? ME_EDIT_PAINT_VERT_SEL : 0;
+		}
+		else {
+			indexar[0] = view3d_sample_backbuf(vc, mval[0], mval[1]);
+			if (indexar[0]) totindex = 1;
+			else totindex = 0;
+		}
 
-	if ((me->editflag & ME_EDIT_PAINT_FACE_SEL) && me->mpoly) {
-		for (index = 0; index < totindex; index++) {
-			if (indexar[index] && indexar[index] <= me->totpoly) {
-				MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1);
-						
-				if ((mpoly->flag & ME_FACE_SEL) == 0) {
-					indexar[index] = 0;
+		if (use_face_sel && me->mpoly) {
+			for (index = 0; index < totindex; index++) {
+				if (indexar[index] && indexar[index] <= me->totpoly) {
+					MPoly *mpoly = ((MPoly *)me->mpoly) + (indexar[index] - 1);
+
+					if ((mpoly->flag & ME_FACE_SEL) == 0) {
+						indexar[index] = 0;
+					}
 				}
 			}
 		}
 	}
+	else {
+		indexar = NULL;
+	}
 
 	/* make sure each vertex gets treated only once */
 	/* and calculate filter weight */
@@ -2275,80 +2299,121 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
 		paintweight = 0.0f;
 	else
 		paintweight = BKE_brush_weight_get(scene, brush);
-			
-	for (index = 0; index < totindex; index++) {
-		if (indexar[index] && indexar[index] <= me->totpoly) {
-			MPoly *mpoly = me->mpoly + (indexar[index] - 1);
-			MLoop *ml = me->mloop + mpoly->loopstart;
-			int i;
 
-			if (use_vert_sel) {
-				for (i = 0; i < mpoly->totloop; i++, ml++) {
-					me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT);
+#define WP_BLUR_ACCUM(v_idx_var)  \
+	{ \
+		const unsigned int vidx = v_idx_var; \
+		const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure); \
+		if (fac > 0.0f) { \
+			MDeformWeight *dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); \
+			paintweight += dw ? (dw->weight * fac) : 0.0f; \
+			totw += fac; \
+		} \
+	} (void)0
+
+
+	if (use_depth) {
+		for (index = 0; index < totindex; index++) {
+			if (indexar[index] && indexar[index] <= me->totpoly) {
+				MPoly *mpoly = me->mpoly + (indexar[index] - 1);
+				MLoop *ml = me->mloop + mpoly->loopstart;
+				int i;
+
+				if (use_vert_sel) {
+					for (i = 0; i < mpoly->totloop; i++, ml++) {
+						me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT);
+					}
 				}
-			}
-			else {
-				for (i = 0; i < mpoly->totloop; i++, ml++) {
-					me->dvert[ml->v].flag = 1;
+				else {
+					for (i = 0; i < mpoly->totloop; i++, ml++) {
+						me->dvert[ml->v].flag = 1;
+					}
 				}
-			}
-					
-			if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
-				MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int);
-						
-				if (wp->flag & VP_ONLYVGROUP)
-					dw_func = (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index;
-				else
-					dw_func = defvert_verify_index;
-						
-				ml = me->mloop + mpoly->loopstart;
-				for (i = 0; i < mpoly->totloop; i++, ml++) {
-					unsigned int vidx = ml->v;
-					const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos[vidx].co, mval, brush_size_pressure);
-					if (fac > 0.0f) {
-						dw = dw_func(&me->dvert[vidx], wpi.vgroup_active);
-						paintweight += dw ? (dw->weight * fac) : 0.0f;
-						totw += fac;
+
+				if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
+					ml = me->mloop + mpoly->loopstart;
+					for (i = 0; i < mpoly->totloop; i++, ml++) {
+						WP_BLUR_ACCUM(ml->v);
 					}
 				}
 			}
 		}
 	}
-			
+	else {
+		const unsigned int totvert = me->totvert;
+		unsigned int       i;
+
+		/* in the case of face selection we need to flush */
+		if (use_vert_sel || use_face_sel) {
+			for (i = 0; i < totvert; i++) {
+				me->dvert[i].flag = me->mvert[i].flag & SELECT;
+			}
+		}
+		else {
+			for (i = 0; i < totvert; i++) {
+				me->dvert[i].flag = SELECT;
+			}
+		}
+
+		if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
+			for (i = 0; i < totvert; i++) {
+				WP_BLUR_ACCUM(i);
+			}
+		}
+	}
+
+#undef WP_BLUR_ACCUM
+
+
 	if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) {
 		paintweight /= totw;
 	}
 
-	for (index = 0; index < totindex; index++) {
+#define WP_PAINT(v_idx_var)  \
+	{ \
+		unsigned int vidx = v_idx_var; \
+		if (me->dvert[vidx].flag) { \
+			alpha = calc_vp_alpha_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx], \
+			                         mval, brush_size_pressure, brush_alpha_pressure); \
+			if (alpha) { \
+				do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight); \
+			} \
+			me->dvert[vidx].flag = 0; \
+		} \
+	} (void)0
 
-		if (indexar[index] && indexar[index] <= me->totpoly) {
-			MPoly *mpoly = me->mpoly + (indexar[index] - 1);
-			MLoop *ml = me->mloop + mpoly->loopstart;
-			int i;
+	if (use_depth) {
+		for (index = 0; index < totindex; index++) {
 
-			for (i = 0; i < mpoly->totloop; i++, ml++) {
-				unsigned int vidx = ml->v;
+			if (indexar[index] && indexar[index] <= me->totpoly) {
+				MPoly *mpoly = me->mpoly + (indexar[index] - 1);
+				MLoop *ml = me->mloop + mpoly->loopstart;
+				int i;
 
-				if (me->dvert[vidx].flag) {
-					alpha = calc_vp_alpha_dl(wp, vc, wpd->wpimat, &wpd->vertexcosnos[vidx],
-					                         mval, brush_size_pressure, brush_alpha_pressure);
-					if (alpha) {
-						do_weight_paint_vertex(wp, ob, &wpi, vidx, alpha, paintweight);
-					}
-					me->dvert[vidx].flag = 0;
+				for (i = 0; i < mpoly->totloop; i++, ml++) {
+					WP_PAINT(ml->v);
 				}
 			}
 		}
 	}
+	else {
+		const unsigned int totvert = me->totvert;
+		unsigned int       i;
+
+		for (i = 0; i < totvert; i++) {
+			WP_PAINT(i);
+		}
+	}
+#undef WP_PAINT
 
 
 	/* *** free wpi members */
 	MEM_freeN((void *)wpi.defbase_sel);
-	/* *** don't freeing wpi members */
+	/* *** done freeing wpi members */
 
 
 	swap_m4m4(vc->rv3d->persmat, mat);
-			
+
 	DAG_id_tag_update(ob->data, 0);
 	ED_region_tag_redraw(vc->ar);
 }
@@ -2442,7 +2507,7 @@ void PAINT_OT_weight_paint(wmOperatorType *ot)
 	RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
 }
 
-static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op))
+static int weight_paint_set_exec(bContext *C, wmOperator *op)
 {
 	struct Scene *scene = CTX_data_scene(C);
 	Object *obact = CTX_data_active_object(C);
@@ -2450,6 +2515,10 @@ static int weight_paint_set_exec(bContext *C, wmOperator *UNUSED(op))
 	Brush *brush = paint_brush(&ts->wpaint->paint);
 	float vgroup_weight = BKE_brush_weight_get(scene, brush);
 
+	if (wpaint_ensure_data(C, op) == FALSE) {
+		return OPERATOR_CANCELLED;
+	}
+
 	wpaint_fill(scene->toolsettings->wpaint, obact, vgroup_weight);
 	ED_region_tag_redraw(CTX_wm_region(C)); /* XXX - should redraw all 3D views */
 	return OPERATOR_FINISHED;
@@ -2992,9 +3061,9 @@ static void gradientVert__mapFunc(void *userData, int index, const float co[3],
 		 * the screen coords of the verts need to be cached because
 		 * updating the mesh may move them about (entering feedback loop) */
 		if (grad_data->is_init) {
-			if (ED_view3d_project_float_global(grad_data->ar,
+			if (ED_view3d_project_float_object(grad_data->ar,
 			                                   co, vs->sco,
-			                                   V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
+			                                   V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
 			{
 				/* ok */
 				MDeformVert *dv = &me->dvert[index];
@@ -3022,11 +3091,9 @@ static void gradientVert__mapFunc(void *userData, int index, const float co[3],
 			if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
 				alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
 			}
-			else if (grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL) {
-				alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
-			}
 			else {
-				BLI_assert(0);
+				BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL);
+				alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
 			}
 			/* no need to clamp 'alpha' yet */
 
@@ -3082,7 +3149,7 @@ static int paint_weight_gradient_modal(bContext *C, wmOperator *op, wmEvent *eve
 		VPaint *wp = ts->wpaint;
 		Object *ob = CTX_data_active_object(C);
 		Mesh *me = ob->data;
-		copy_dverts(me->dvert, wp->wpaint_prev, me->totvert);
+		BKE_defvert_array_copy(me->dvert, wp->wpaint_prev, me->totvert);
 		free_wpaint_prev(wp);
 
 		DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -3159,7 +3226,13 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
 
 static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
-	int ret = WM_gesture_straightline_invoke(C, op, event);
+	int ret;
+
+	if (wpaint_ensure_data(C, op) == FALSE) {
+		return OPERATOR_CANCELLED;
+	}
+
+	ret = WM_gesture_straightline_invoke(C, op, event);
 	if (ret & OPERATOR_RUNNING_MODAL) {
 		struct ARegion *ar = CTX_wm_region(C);
 		if (ar->regiontype == RGN_TYPE_WINDOW) {
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 8325b47beab..54ae2ebf588 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -65,6 +65,7 @@
 #include "BKE_report.h"
 #include "BKE_lattice.h" /* for armature_deform_verts */
 #include "BKE_node.h"
+#include "BKE_object.h"
 #include "BKE_subsurf.h"
 
 #include "BIF_glutil.h"
@@ -86,6 +87,8 @@
 
 #include "GPU_buffers.h"
 
+#include "bmesh.h"
+
 #include 
 #include 
 #include 
@@ -98,8 +101,13 @@ void ED_sculpt_force_update(bContext *C)
 {
 	Object *ob = CTX_data_active_object(C);
 
-	if (ob && (ob->mode & OB_MODE_SCULPT))
+	if (ob && (ob->mode & OB_MODE_SCULPT)) {
 		multires_force_update(ob);
+
+		/* Set reorder=false so that saving the file doesn't reorder
+		 * the BMesh's elements */
+		sculptsession_bm_to_me(ob, FALSE);
+	}
 }
 
 float *ED_sculpt_get_last_stroke(struct Object *ob)
@@ -172,7 +180,8 @@ static int sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
 	Mesh *me = (Mesh *)ob->data;
 	MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
 
-	if (mmd) return 0;
+	if (mmd || ob->sculpt->bm)
+		return 0;
 
 	/* non-locked shape keys could be handled in the same way as deformed mesh */
 	if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr)
@@ -281,12 +290,130 @@ typedef struct StrokeCache {
 	rcti previous_r; /* previous redraw rectangle */
 } StrokeCache;
 
+/************** Access to original unmodified vertex data *************/
+
+typedef struct {
+	BMLog *bm_log;
+
+	SculptUndoNode *unode;
+	float (*coords)[3];
+	short (*normals)[3];
+	float *vmasks;
+
+	/* Original coordinate, normal, and mask */
+	const float *co;
+	float mask;
+	short no[3];
+} SculptOrigVertData;
+
+
+/* Initialize a SculptOrigVertData for accessing original vertex data;
+ * handles BMesh, mesh, and multires */
+static void sculpt_orig_vert_data_unode_init(SculptOrigVertData *data,
+											 Object *ob,
+											 SculptUndoNode *unode)
+{
+	SculptSession *ss = ob->sculpt;
+	BMesh *bm = ss->bm;
+
+	memset(data, 0, sizeof(*data));
+	data->unode = unode;
+
+	if (bm) {
+		data->bm_log = ss->bm_log;
+	}
+	else {
+		data->coords = data->unode->co;
+		data->normals = data->unode->no;
+		data->vmasks = data->unode->mask;
+	}
+}
+
+/* Initialize a SculptOrigVertData for accessing original vertex data;
+ * handles BMesh, mesh, and multires */
+static void sculpt_orig_vert_data_init(SculptOrigVertData *data,
+									   Object *ob,
+									   PBVHNode *node)
+{
+	SculptUndoNode *unode;
+	unode = sculpt_undo_push_node(ob, node, SCULPT_UNDO_COORDS);
+	sculpt_orig_vert_data_unode_init(data, ob, unode);
+									 
+}
+
+/* Update a SculptOrigVertData for a particular vertex from the PBVH
+ * iterator */
+static void sculpt_orig_vert_data_update(SculptOrigVertData *orig_data,
+										 PBVHVertexIter *iter)
+{
+	if (orig_data->unode->type == SCULPT_UNDO_COORDS) {
+		if (orig_data->coords) {
+			orig_data->co = orig_data->coords[iter->i];
+		}
+		else {
+			orig_data->co = BM_log_original_vert_co(orig_data->bm_log, iter->bm_vert);
+		}
+
+		if (orig_data->normals) {
+			copy_v3_v3_short(orig_data->no, orig_data->normals[iter->i]);
+		}
+		else {
+			/* TODO: log doesn't store normals yet */
+			normal_float_to_short_v3(orig_data->no, iter->bm_vert->no);
+		}
+	}
+	else if (orig_data->unode->type == SCULPT_UNDO_MASK) {
+		if (orig_data->vmasks) {
+			orig_data->mask = orig_data->vmasks[iter->i];
+		}
+		else {
+			orig_data->mask = BM_log_original_mask(orig_data->bm_log, iter->bm_vert);
+		}
+	}
+}
+
+/**********************************************************************/
+
+/* Returns true if the stroke will use dynamic topology, false
+   otherwise.
+
+   Factors: some brushes like grab cannot do dynamic topology.
+   Others, like smooth, are better without. Same goes for alt-
+   key smoothing. */
+static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
+										  const Brush *brush)
+{
+	return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
+
+			(!ss->cache || (!ss->cache->alt_smooth)) &&
+
+			/* Requires mesh restore, which doesn't work with
+			 * dynamic-topology */
+			!(brush->flag & BRUSH_ANCHORED) &&
+			!(brush->flag & BRUSH_RESTORE_MESH) &&
+
+			(!ELEM6(brush->sculpt_tool,
+					/* These brushes, as currently coded, cannot
+					 * support dynamic topology */
+					SCULPT_TOOL_GRAB,
+					SCULPT_TOOL_ROTATE,
+					SCULPT_TOOL_THUMB,
+					SCULPT_TOOL_LAYER,
+
+					/* These brushes could handle dynamic topology,
+					 * but user feedback indicates it's better not
+					 * to */
+					SCULPT_TOOL_SMOOTH,
+					SCULPT_TOOL_MASK)));
+}
 
 /*** paint mesh ***/
 
-static void paint_mesh_restore_co(Sculpt *sd, SculptSession *ss)
+static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
 {
+	SculptSession *ss = ob->sculpt;
 	StrokeCache *cache = ss->cache;
+	const Brush *brush = paint_brush(&sd->paint);
 	int i;
 
 	PBVHNode **nodes;
@@ -296,31 +423,38 @@ static void paint_mesh_restore_co(Sculpt *sd, SculptSession *ss)
 	(void)sd; /* quied unused warning */
 #endif
 
-	BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+	BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
 
 	#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
 	for (n = 0; n < totnode; n++) {
 		SculptUndoNode *unode;
-		
-		unode = sculpt_undo_get_node(nodes[n]);
+		SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ?
+							   SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+
+		unode = sculpt_undo_push_node(ob, nodes[n], type);
 		if (unode) {
 			PBVHVertexIter vd;
+			SculptOrigVertData orig_data;
 
-			BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+			sculpt_orig_vert_data_unode_init(&orig_data, ob, unode);
+		
+			BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 			{
-				if (unode->type == SCULPT_UNDO_COORDS) {
-					copy_v3_v3(vd.co, unode->co[vd.i]);
-					if (vd.no) copy_v3_v3_short(vd.no, unode->no[vd.i]);
-					else normal_short_to_float_v3(vd.fno, unode->no[vd.i]);
+				sculpt_orig_vert_data_update(&orig_data, &vd);
+
+				if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
+					copy_v3_v3(vd.co, orig_data.co);
+					if (vd.no) copy_v3_v3_short(vd.no, orig_data.no);
+					else normal_short_to_float_v3(vd.fno, orig_data.no);
 				}
-				else if (unode->type == SCULPT_UNDO_MASK) {
-					*vd.mask = unode->mask[vd.i];
+				else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
+					*vd.mask = orig_data.mask;
 				}
 				if (vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
-			BLI_pbvh_vertex_iter_end;
+			BKE_pbvh_vertex_iter_end;
 
-			BLI_pbvh_node_mark_update(nodes[n]);
+			BKE_pbvh_node_mark_update(nodes[n]);
 		}
 	}
 
@@ -347,7 +481,7 @@ static int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
 	if (!pbvh)
 		return 0;
 
-	BLI_pbvh_redraw_BB(pbvh, bb_min, bb_max);
+	BKE_pbvh_redraw_BB(pbvh, bb_min, bb_max);
 
 	/* convert 3D bounding box to screen space */
 	if (!paint_convert_bb_to_rect(rect,
@@ -387,7 +521,7 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
 
 	/* clear redraw flag from nodes */
 	if (pbvh)
-		BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
+		BKE_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
 }
 
 /************************ Brush Testing *******************/
@@ -405,7 +539,7 @@ static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
 	test->dist = 0.0f;   /* just for initialize */
 }
 
-static int sculpt_brush_test(SculptBrushTest *test, float co[3])
+static int sculpt_brush_test(SculptBrushTest *test, const float co[3])
 {
 	float distsq = len_squared_v3v3(co, test->location);
 
@@ -418,7 +552,7 @@ static int sculpt_brush_test(SculptBrushTest *test, float co[3])
 	}
 }
 
-static int sculpt_brush_test_sq(SculptBrushTest *test, float co[3])
+static int sculpt_brush_test_sq(SculptBrushTest *test, const float co[3])
 {
 	float distsq = len_squared_v3v3(co, test->location);
 
@@ -734,7 +868,8 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
 }
 
 /* Return a multiplier for brush strength on a particular vertex. */
-static float tex_strength(SculptSession *ss, Brush *br, float point[3],
+static float tex_strength(SculptSession *ss, Brush *br,
+						  const float point[3],
                           const float len,
                           const float sculpt_normal[3],
                           const short vno[3],
@@ -871,9 +1006,9 @@ static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
 	int i;
 
 	if (data->original)
-		BLI_pbvh_node_get_original_BB(node, bb_min, bb_max);
+		BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
 	else
-		BLI_pbvh_node_get_BB(node, bb_min, bb_max);
+		BKE_pbvh_node_get_BB(node, bb_min, bb_max);
 	
 	for (i = 0; i < 3; ++i) {
 		if (bb_min[i] > center[i])
@@ -926,6 +1061,11 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
 	original = (paint_brush(&sd->paint)->sculpt_tool == SCULPT_TOOL_GRAB ?
 	            TRUE : ss->cache->original);
 
+	/* In general the original coords are not available with dynamic
+	 * topology */
+	if (ss->bm)
+		original = FALSE;
+
 	(void)sd; /* unused w/o openmp */
 	
 	zero_v3(an);
@@ -942,7 +1082,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
 		sculpt_brush_test_init(ss, &test);
 
 		if (original) {
-			BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+			BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 			{
 				if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
 					float fno[3];
@@ -951,10 +1091,10 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
 					add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
 				}
 			}
-			BLI_pbvh_vertex_iter_end;
+			BKE_pbvh_vertex_iter_end;
 		}
 		else {
-			BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+			BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 			{
 				if (sculpt_brush_test_fast(&test, vd.co)) {
 					if (vd.no) {
@@ -968,7 +1108,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
 					}
 				}
 			}
-			BLI_pbvh_vertex_iter_end;
+			BKE_pbvh_vertex_iter_end;
 		}
 
 		#pragma omp critical
@@ -1210,6 +1350,71 @@ static float neighbor_average_mask(SculptSession *ss, unsigned vert)
 		return vmask[vert];
 }
 
+/* Same logic as neighbor_average(), but for bmesh rather than mesh */
+static void bmesh_neighbor_average(float avg[3], BMVert *v)
+{
+	const int vfcount = BM_vert_face_count(v);
+
+	zero_v3(avg);
+		
+	/* Don't modify corner vertices */
+	if (vfcount > 1) {
+		BMIter liter;
+		BMLoop *l;
+		int i, total = 0;
+
+		BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+			BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+
+			for (i = 0; i < 3; i++) {
+				if (vfcount != 2 || BM_vert_face_count(adj_v[i]) <= 2) {
+					add_v3_v3(avg, adj_v[i]->co);
+					total++;
+				}
+			}
+		}
+
+		if (total > 0) {
+			mul_v3_fl(avg, 1.0f / total);
+			return;
+		}
+	}
+
+	copy_v3_v3(avg, v->co);
+}
+
+/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh */
+static float bmesh_neighbor_average_mask(BMesh *bm, BMVert *v)
+{
+	BMIter liter;
+	BMLoop *l;
+	float avg = 0;
+	int i, total = 0;
+
+	BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+		BMVert *adj_v[3] = {l->prev->v, v, l->next->v};
+
+		for (i = 0; i < 3; i++) {
+			BMVert *v2 = adj_v[i];
+			float *vmask = CustomData_bmesh_get(&bm->vdata,
+												v2->head.data,
+												CD_PAINT_MASK);
+			avg += (*vmask);
+			total++;
+		}
+	}
+
+	if (total > 0) {
+		return avg / (float)total;
+	}
+	else {
+		float *vmask = CustomData_bmesh_get(&bm->vdata,
+											v->head.data,
+											CD_PAINT_MASK);
+		return (*vmask);
+	}
+}
+
 static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask)
 {
 	Brush *brush = paint_brush(&sd->paint);
@@ -1220,7 +1425,7 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
 
 	sculpt_brush_test_init(ss, &test);
 
-	BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+	BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
 	{
 		if (sculpt_brush_test(&test, vd.co)) {
 			const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1248,7 +1453,48 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
 				vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 		}
 	}
-	BLI_pbvh_vertex_iter_end;
+	BKE_pbvh_vertex_iter_end;
+}
+
+static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength, int smooth_mask)
+{
+	Brush *brush = paint_brush(&sd->paint);
+	PBVHVertexIter vd;
+	SculptBrushTest test;
+	
+	CLAMP(bstrength, 0.0f, 1.0f);
+
+	sculpt_brush_test_init(ss, &test);
+
+	BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+	{
+		if (sculpt_brush_test(&test, vd.co)) {
+			const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
+			                                            ss->cache->view_normal, vd.no, vd.fno,
+			                                            smooth_mask ? 0 : *vd.mask);
+			if (smooth_mask) {
+				float val = bmesh_neighbor_average_mask(ss->bm, vd.bm_vert) - *vd.mask;
+				val *= fade * bstrength;
+				*vd.mask += val;
+				CLAMP(*vd.mask, 0, 1);
+			}
+			else {
+				float avg[3], val[3];
+
+				bmesh_neighbor_average(avg, vd.bm_vert);
+				sub_v3_v3v3(val, avg, vd.co);
+				mul_v3_fl(val, fade);
+
+				add_v3_v3(val, vd.co);
+
+				sculpt_clip(sd, ss, vd.co, val);
+			}
+
+			if (vd.mvert)
+				vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+		}
+	}
+	BKE_pbvh_vertex_iter_end;
 }
 
 static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
@@ -1269,9 +1515,9 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
 
 	CLAMP(bstrength, 0.0f, 1.0f);
 
-	BLI_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
+	BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
 	                        NULL, &gridsize, &griddata, &gridadj);
-	BLI_pbvh_get_grid_key(ss->pbvh, &key);
+	BKE_pbvh_get_grid_key(ss->pbvh, &key);
 
 	thread_num = 0;
 #ifdef _OPENMP
@@ -1405,7 +1651,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
 	SculptSession *ss = ob->sculpt;
 	const int max_iterations = 4;
 	const float fract = 1.0f / max_iterations;
-	PBVHType type = BLI_pbvh_type(ss->pbvh);
+	PBVHType type = BKE_pbvh_type(ss->pbvh);
 	int iteration, n, count;
 	float last;
 
@@ -1433,6 +1679,9 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
 					do_mesh_smooth_brush(sd, ss, nodes[n], strength,
 					                     smooth_mask);
 					break;
+				case PBVH_BMESH:
+					do_bmesh_smooth_brush(sd, ss, nodes[n], strength, smooth_mask);
+					break;
 			}
 		}
 
@@ -1462,7 +1711,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test(&test, vd.co)) {
 				float fade = tex_strength(ss, brush, vd.co, test.dist,
@@ -1474,7 +1723,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
 				if (vd.mvert)
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
-			BLI_pbvh_vertex_iter_end;
+			BKE_pbvh_vertex_iter_end;
 		}
 	}
 }
@@ -1514,11 +1763,11 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test(&test, vd.co)) {
 				/* offset vertex */
@@ -1532,7 +1781,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -1570,11 +1819,11 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test(&test, vd.co)) {
 				/* offset vertex */
@@ -1597,7 +1846,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -1614,11 +1863,11 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test(&test, vd.co)) {
 				float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1633,7 +1882,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -1659,26 +1908,27 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
 	#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
 	for (n = 0; n < totnode; n++) {
 		PBVHVertexIter vd;
-		SculptUndoNode *unode;
 		SculptBrushTest test;
-		float (*origco)[3];
-		short (*origno)[3];
+		SculptOrigVertData orig_data;
 		float (*proxy)[3];
 
-		unode =  sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
-		origco = unode->co;
-		origno = unode->no;
+		sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
-			if (sculpt_brush_test(&test, origco[vd.i])) {
-				const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist,
-				                                            ss->cache->sculpt_normal_symm, origno[vd.i],
-				                                            NULL, vd.mask ? *vd.mask : 0.0f);
+			sculpt_orig_vert_data_update(&orig_data, &vd);
+
+			if (sculpt_brush_test(&test, orig_data.co)) {
+				const float fade = bstrength * tex_strength(ss, brush,
+															orig_data.co,
+															test.dist,
+				                                            ss->cache->sculpt_normal_symm,
+															orig_data.no,
+															NULL, vd.mask ? *vd.mask : 0.0f);
 
 				mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
 
@@ -1686,7 +1936,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -1710,11 +1960,11 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test(&test, vd.co)) {
 				const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1727,7 +1977,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -1759,11 +2009,11 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test(&test, vd.co)) {
 				const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1776,7 +2026,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -1797,26 +2047,27 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 	#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
 	for (n = 0; n < totnode; n++) {
 		PBVHVertexIter vd;
-		SculptUndoNode *unode;
 		SculptBrushTest test;
-		float (*origco)[3];
-		short (*origno)[3];
+		SculptOrigVertData orig_data;
 		float (*proxy)[3];
 
-		unode =  sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
-		origco = unode->co;
-		origno = unode->no;
+		sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
-			if (sculpt_brush_test(&test, origco[vd.i])) {
-				const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist,
+			sculpt_orig_vert_data_update(&orig_data, &vd);
+
+			if (sculpt_brush_test(&test, orig_data.co)) {
+				const float fade = bstrength * tex_strength(ss, brush,
+															orig_data.co,
+															test.dist,
 				                                            ss->cache->sculpt_normal_symm,
-				                                            origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f);
+				                                            orig_data.no,
+															NULL, vd.mask ? *vd.mask : 0.0f);
 
 				mul_v3_v3fl(proxy[vd.i], cono, fade);
 
@@ -1824,7 +2075,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -1850,36 +2101,37 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
 	#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
 	for (n = 0; n < totnode; n++) {
 		PBVHVertexIter vd;
-		SculptUndoNode *unode;
 		SculptBrushTest test;
-		float (*origco)[3];
-		short (*origno)[3];
+		SculptOrigVertData orig_data;
 		float (*proxy)[3];
 
-		unode =  sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
-		origco = unode->co;
-		origno = unode->no;
+		sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
-			if (sculpt_brush_test(&test, origco[vd.i])) {
-				const float fade = bstrength * tex_strength(ss, brush, origco[vd.i], test.dist,
-				                                            ss->cache->sculpt_normal_symm,
-				                                            origno[vd.i], NULL, vd.mask ? *vd.mask : 0.0f);
+			sculpt_orig_vert_data_update(&orig_data, &vd);
 
-				mul_v3_m4v3(proxy[vd.i], m, origco[vd.i]);
-				sub_v3_v3(proxy[vd.i], origco[vd.i]);
+			if (sculpt_brush_test(&test, orig_data.co)) {
+				const float fade = bstrength * tex_strength(ss, brush,
+				                                            orig_data.co,
+				                                            test.dist,
+				                                            ss->cache->sculpt_normal_symm,
+				                                            orig_data.no,
+		                                                    NULL, vd.mask ? *vd.mask : 0.0f);
+
+				mul_v3_m4v3(proxy[vd.i], m, orig_data.co);
+				sub_v3_v3(proxy[vd.i], orig_data.co);
 				mul_v3_fl(proxy[vd.i], fade);
 
 				if (vd.mvert)
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -1901,25 +2153,25 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 	for (n = 0; n < totnode; n++) {
 		PBVHVertexIter vd;
 		SculptBrushTest test;
-		SculptUndoNode *unode;
-		float (*origco)[3], *layer_disp;
+		SculptOrigVertData orig_data;
+		float *layer_disp;
 		/* XXX: layer brush needs conversion to proxy but its more complicated */
-		/* proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
+		/* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
 		
-		unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
-		origco = unode->co;
-		if (!unode->layer_disp) {
-			#pragma omp critical 
-			unode->layer_disp = MEM_callocN(sizeof(float) * unode->totvert, "layer disp");
+		sculpt_orig_vert_data_init(&orig_data, ob, nodes[n]);
+
+		#pragma omp critical
+		{
+			layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, nodes[n]);
 		}
-
-		layer_disp = unode->layer_disp;
-
+		
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
-			if (sculpt_brush_test(&test, origco[vd.i])) {
+			sculpt_orig_vert_data_update(&orig_data, &vd);
+
+			if (sculpt_brush_test(&test, orig_data.co)) {
 				const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
 				                                            ss->cache->sculpt_normal_symm,
 				                                            vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
@@ -1941,7 +2193,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 					add_v3_v3(val, ss->layer_co[index]);
 				}
 				else {
-					add_v3_v3(val, origco[vd.i]);
+					add_v3_v3(val, orig_data.co);
 				}
 
 				sculpt_clip(sd, ss, vd.co, val);
@@ -1950,7 +2202,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -1967,11 +2219,11 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test(&test, vd.co)) {
 				const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
@@ -1989,7 +2241,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
 					vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -2016,24 +2268,24 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
 		sculpt_brush_test_init(ss, &test);
 
 		if (ss->cache->original) {
-			BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+			BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 			{
 				if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
 					add_v3_v3(private_fc, unode->co[vd.i]);
 					private_count++;
 				}
 			}
-			BLI_pbvh_vertex_iter_end;
+			BKE_pbvh_vertex_iter_end;
 		}
 		else {
-			BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+			BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 			{
 				if (sculpt_brush_test_fast(&test, vd.co)) {
 					add_v3_v3(private_fc, vd.co);
 					private_count++;
 				}
 			}
-			BLI_pbvh_vertex_iter_end;
+			BKE_pbvh_vertex_iter_end;
 		}
 
 		#pragma omp critical
@@ -2082,8 +2334,8 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
 		unode = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS);
 		sculpt_brush_test_init(ss, &test);
 
-		if (ss->cache->original) {
-			BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		if (ss->cache->original && unode->co) {
+			BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 			{
 				if (sculpt_brush_test_fast(&test, unode->co[vd.i])) {
 					/* for area normal */
@@ -2097,10 +2349,10 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
 					private_count++;
 				}
 			}
-			BLI_pbvh_vertex_iter_end;
+			BKE_pbvh_vertex_iter_end;
 		}
 		else {
-			BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+			BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 			{
 				if (sculpt_brush_test_fast(&test, vd.co)) {
 					/* for area normal */
@@ -2119,7 +2371,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
 					private_count++;
 				}
 			}
-			BLI_pbvh_vertex_iter_end;
+			BKE_pbvh_vertex_iter_end;
 		}
 
 		#pragma omp critical
@@ -2301,11 +2553,11 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test_sq(&test, vd.co)) {
 				float intr[3];
@@ -2326,7 +2578,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
 				}
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -2373,11 +2625,11 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test_sq(&test, vd.co)) {
 				if (plane_point_side_flip(vd.co, an, fc, flip)) {
@@ -2401,7 +2653,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
 				}
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -2475,11 +2727,11 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test_cube(&test, vd.co, mat)) {
 				if (plane_point_side_flip(vd.co, sn, fc, flip)) {
@@ -2503,7 +2755,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
 				}
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -2539,11 +2791,11 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test_sq(&test, vd.co)) {
 				if (plane_point_side(vd.co, an, fc)) {
@@ -2567,7 +2819,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
 				}
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -2603,11 +2855,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
 		SculptBrushTest test;
 		float (*proxy)[3];
 
-		proxy = BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+		proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
 
 		sculpt_brush_test_init(ss, &test);
 
-		BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+		BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 		{
 			if (sculpt_brush_test_sq(&test, vd.co)) {
 				if (!plane_point_side(vd.co, an, fc)) {
@@ -2631,7 +2883,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
 				}
 			}
 		}
-		BLI_pbvh_vertex_iter_end;
+		BKE_pbvh_vertex_iter_end;
 	}
 }
 
@@ -2688,6 +2940,65 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
 	BKE_key_convert_from_vertcos(ob, kb, vertCos);
 }
 
+/* Note: we do the topology update before any brush actions to avoid
+ * issues with the proxies. The size of the proxy can't change, so
+ * topology must be updated first. */
+static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush)
+{
+	SculptSession *ss = ob->sculpt;
+	SculptSearchSphereData data;
+	PBVHNode **nodes = NULL;
+	float radius;
+	int n, totnode;
+
+	/* Build a list of all nodes that are potentially within the
+	 * brush's area of influence */
+	data.ss = ss;
+	data.sd = sd;
+
+	radius = ss->cache->radius * 1.25f;
+
+	data.radius_squared = radius * radius;
+	data.original = ELEM4(brush->sculpt_tool,
+	                      SCULPT_TOOL_GRAB,
+	                      SCULPT_TOOL_ROTATE,
+	                      SCULPT_TOOL_THUMB,
+	                      SCULPT_TOOL_LAYER);
+
+	BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+
+	/* Only act if some verts are inside the brush area */
+	if (totnode) {
+		PBVHTopologyUpdateMode mode = PBVH_Subdivide;
+
+		if ((sd->flags & SCULPT_DYNTOPO_COLLAPSE) ||
+			(brush->sculpt_tool == SCULPT_TOOL_SIMPLIFY))
+		{
+			mode |= PBVH_Collapse;
+		}
+
+		for (n = 0; n < totnode; n++) {
+			sculpt_undo_push_node(ob, nodes[n],
+			                      brush->sculpt_tool == SCULPT_TOOL_MASK ?
+			                      SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
+			BKE_pbvh_node_mark_update(nodes[n]);
+
+			if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+				BKE_pbvh_node_mark_topology_update(nodes[n]);
+				BKE_pbvh_bmesh_node_save_orig(nodes[n]);
+			}
+		}
+
+		if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+			BKE_pbvh_bmesh_update_topology(ss->pbvh, mode,
+										   ss->cache->location,
+			                               ss->cache->radius);
+		}
+
+		MEM_freeN(nodes);
+	}
+}
+
 static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
 {
 	SculptSession *ss = ob->sculpt;
@@ -2704,7 +3015,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
 	                      SCULPT_TOOL_ROTATE,
 	                      SCULPT_TOOL_THUMB,
 	                      SCULPT_TOOL_LAYER);
-	BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
+	BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
 
 	/* Only act if some verts are inside the brush area */
 	if (totnode) {
@@ -2713,7 +3024,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
 			sculpt_undo_push_node(ob, nodes[n],
 			                      brush->sculpt_tool == SCULPT_TOOL_MASK ?
 			                      SCULPT_UNDO_MASK : SCULPT_UNDO_COORDS);
-			BLI_pbvh_node_mark_update(nodes[n]);
+			BKE_pbvh_node_mark_update(nodes[n]);
 		}
 
 		if (brush_needs_sculpt_normal(brush))
@@ -2821,7 +3132,7 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
 	PBVHNode **nodes;
 	int totnode, n;
 
-	BLI_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+	BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
 
 	if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER)) {
 		/* these brushes start from original coordinates */
@@ -2835,18 +3146,25 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
 			int proxy_count;
 			float (*orco)[3];
 
-			if (use_orco)
+			if (use_orco && !ss->bm)
 				orco = sculpt_undo_push_node(ob, nodes[n], SCULPT_UNDO_COORDS)->co;
 
-			BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
+			BKE_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
 
-			BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+			BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 			{
 				float val[3];
 				int p;
 
-				if (use_orco)
-					copy_v3_v3(val, orco[vd.i]);
+				if (use_orco) {
+					if (ss->bm) {
+						copy_v3_v3(val,
+								   BM_log_original_vert_co(ss->bm_log,
+								   vd.bm_vert));
+					}
+					else
+						copy_v3_v3(val, orco[vd.i]);
+				}
 				else
 					copy_v3_v3(val, vd.co);
 
@@ -2858,9 +3176,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
 				if (ss->modifiers_active)
 					sculpt_flush_pbvhvert_deform(ob, &vd);
 			}
-			BLI_pbvh_vertex_iter_end;
+			BKE_pbvh_vertex_iter_end;
 
-			BLI_pbvh_node_free_proxies(nodes[n]);
+			BKE_pbvh_node_free_proxies(nodes[n]);
 		}
 	}
 
@@ -2877,7 +3195,7 @@ static void sculpt_update_keyblock(Object *ob)
 	/* Keyblock update happens after handling deformation caused by modifiers,
 	 * so ss->orig_cos would be updated with new stroke */
 	if (ss->orig_cos) vertCos = ss->orig_cos;
-	else vertCos = BLI_pbvh_get_vertCos(ss->pbvh);
+	else vertCos = BKE_pbvh_get_vertCos(ss->pbvh);
 
 	if (vertCos) {
 		sculpt_vertcos_to_key(ob, ss->kb, vertCos);
@@ -2905,13 +3223,13 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
 		if (ss->kb)
 			vertCos = MEM_callocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts");
 
-		BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+		BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
 
 		#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
 		for (n = 0; n < totnode; n++) {
 			PBVHVertexIter vd;
 
-			BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+			BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
 			{
 				sculpt_flush_pbvhvert_deform(ob, &vd);
 
@@ -2920,7 +3238,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
 					copy_v3_v3(vertCos[index], ss->orig_cos[index]);
 				}
 			}
-			BLI_pbvh_vertex_iter_end;
+			BKE_pbvh_vertex_iter_end;
 		}
 
 		if (vertCos) {
@@ -2978,7 +3296,10 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
 	mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry);
 }
 
+typedef void (*BrushActionFunc)(Sculpt *sd, Object *ob, Brush *brush);
+
 static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush,
+							   BrushActionFunc action,
                                const char symm, const int axis,
                                const float feather)
 {
@@ -2989,7 +3310,7 @@ static void do_radial_symmetry(Sculpt *sd, Object *ob, Brush *brush,
 		const float angle = 2 * M_PI * i / sd->radial_symm[axis - 'X'];
 		ss->cache->radial_symmetry_pass = i;
 		calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather);
-		do_brush_action(sd, ob, brush);
+		action(sd, ob, brush);
 	}
 }
 
@@ -3006,7 +3327,8 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
 		multires_stitch_grids(ob);
 }
 
-static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob)
+static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
+										 BrushActionFunc action)
 {
 	Brush *brush = paint_brush(&sd->paint);
 	SculptSession *ss = ob->sculpt;
@@ -3017,7 +3339,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob)
 	float feather = calc_symmetry_feather(sd, ss->cache);
 
 	cache->bstrength = brush_strength(sd, cache, feather);
-
 	cache->symmetry = symm;
 
 	/* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */ 
@@ -3027,23 +3348,13 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob)
 			cache->radial_symmetry_pass = 0;
 
 			calc_brushdata_symm(sd, cache, i, 0, 0, feather);
-			do_brush_action(sd, ob, brush);
+			action(sd, ob, brush);
 
-			do_radial_symmetry(sd, ob, brush, i, 'X', feather);
-			do_radial_symmetry(sd, ob, brush, i, 'Y', feather);
-			do_radial_symmetry(sd, ob, brush, i, 'Z', feather);
+			do_radial_symmetry(sd, ob, brush, action, i, 'X', feather);
+			do_radial_symmetry(sd, ob, brush, action, i, 'Y', feather);
+			do_radial_symmetry(sd, ob, brush, action, i, 'Z', feather);
 		}
 	}
-
-	sculpt_combine_proxies(sd, ob);
-
-	/* hack to fix noise texture tearing mesh */
-	sculpt_fix_noise_tear(sd, ob);
-
-	if (ss->modifiers_active)
-		sculpt_flush_stroke_deform(sd, ob);
-
-	cache->first_time = 0;
 }
 
 static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
@@ -3142,7 +3453,7 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
 			ss->orig_cos = (ss->kb) ? BKE_key_convert_to_vertcos(ob, ss->kb) : mesh_getVertexCos(me, NULL);
 
 			crazyspace_build_sculpt(scene, ob, &ss->deform_imats, &ss->deform_cos);
-			BLI_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
+			BKE_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
 
 			for (a = 0; a < me->totvert; ++a) {
 				invert_m3(ss->deform_imats[a]);
@@ -3152,12 +3463,12 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
 	else free_sculptsession_deformMats(ss);
 
 	/* if pbvh is deformed, key block is already applied to it */
-	if (ss->kb && !BLI_pbvh_isDeformed(ss->pbvh)) {
+	if (ss->kb && !BKE_pbvh_isDeformed(ss->pbvh)) {
 		float (*vertCos)[3] = BKE_key_convert_to_vertcos(ob, ss->kb);
 
 		if (vertCos) {
 			/* apply shape keys coordinates to PBVH */
-			BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
+			BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
 			MEM_freeN(vertCos);
 		}
 	}
@@ -3220,6 +3531,8 @@ static const char *sculpt_tool_name(Sculpt *sd)
 			return "Rotate Brush";
 		case SCULPT_TOOL_MASK:
 			return "Mask Brush";
+		case SCULPT_TOOL_SIMPLIFY:
+			return "Simplify Brush";
 	}
 
 	return "Sculpting";
@@ -3291,7 +3604,7 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
 
 	if (ss->multires) {
 		int i, gridsize, array_mem_size;
-		BLI_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
+		BKE_pbvh_node_get_grids(ss->pbvh, NULL, NULL, NULL, NULL,
 		                        &gridsize, NULL, NULL);
 
 		array_mem_size = cache->num_threads * sizeof(void *);
@@ -3406,8 +3719,9 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
 	ED_view3d_global_to_vector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal);
 	/* Initialize layer brush displacements and persistent coords */
 	if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
-		/* not supported yet for multires */
-		if (!ss->multires && !ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
+		/* not supported yet for multires or dynamic topology */
+		if (!ss->multires && !ss->bm && !ss->layer_co &&
+			(brush->flag & BRUSH_PERSISTENT)) {
 			if (!ss->layer_co)
 				ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert,
 				                           "sculpt mesh vertices copy");
@@ -3721,17 +4035,26 @@ typedef struct {
 
 static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
 {
-	if (BLI_pbvh_node_get_tmin(node) < *tmin) {
+	if (BKE_pbvh_node_get_tmin(node) < *tmin) {
 		SculptRaycastData *srd = data_v;
 		float (*origco)[3] = NULL;
+		int use_origco = FALSE;
 
 		if (srd->original && srd->ss->cache) {
-			/* intersect with coordinates from before we started stroke */
-			SculptUndoNode *unode = sculpt_undo_get_node(node);
-			origco = (unode) ? unode->co : NULL;
+			if (BKE_pbvh_type(srd->ss->pbvh) == PBVH_BMESH) {
+				use_origco = TRUE;
+			}
+			else {
+				/* intersect with coordinates from before we started stroke */
+				SculptUndoNode *unode = sculpt_undo_get_node(node);
+				origco = (unode) ? unode->co : NULL;
+				use_origco = origco ? TRUE : FALSE;
+			}
 		}
 
-		if (BLI_pbvh_node_raycast(srd->ss->pbvh, node, origco, srd->ray_start, srd->ray_normal, &srd->dist)) {
+		if (BKE_pbvh_node_raycast(srd->ss->pbvh, node, origco, use_origco,
+								  srd->ray_start, srd->ray_normal, &srd->dist))
+		{
 			srd->hit = 1;
 			*tmin = srd->dist;
 		}
@@ -3780,7 +4103,7 @@ int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
 	srd.dist = dist;
 	srd.hit = 0;
 	srd.original = (cache) ? cache->original : 0;
-	BLI_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd,
+	BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd,
 	                 ray_start, ray_normal, srd.original);
 	
 	copy_v3_v3(out, ray_normal);
@@ -3829,8 +4152,9 @@ static int sculpt_brush_stroke_init(bContext *C, wmOperator *op)
 	return 1;
 }
 
-static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
+static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
 {
+	SculptSession *ss = ob->sculpt;
 	Brush *brush = paint_brush(&sd->paint);
 
 	/* Restore the mesh before continuing with anchored stroke */
@@ -3839,7 +4163,7 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
 	     BKE_brush_use_size_pressure(ss->cache->vc->scene, brush)) ||
 	    (brush->flag & BRUSH_RESTORE_MESH))
 	{
-		paint_mesh_restore_co(sd, ss);
+		paint_mesh_restore_co(sd, ob);
 	}
 }
 
@@ -3862,7 +4186,7 @@ static void sculpt_flush_update(bContext *C)
 	else {
 		rcti r;
 
-		BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
+		BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
 		if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
 			if (ss->cache)
 				ss->cache->previous_r = r;
@@ -3917,11 +4241,33 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
 	Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
 	Object *ob = CTX_data_active_object(C);
 	SculptSession *ss = ob->sculpt;
+	const Brush *brush = paint_brush(&sd->paint);
 	
 	sculpt_stroke_modifiers_check(C, ob);
 	sculpt_update_cache_variants(C, sd, ob, stroke, itemptr);
-	sculpt_restore_mesh(sd, ss);
-	do_symmetrical_brush_actions(sd, ob);
+	sculpt_restore_mesh(sd, ob);
+
+	BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
+								   (ss->cache->radius /
+									(float)ss->cache->pixel_radius) *
+								   (float)sd->detail_size);
+
+	if (sculpt_stroke_dynamic_topology(ss, brush)) {
+		do_symmetrical_brush_actions(sd, ob, sculpt_topology_update);
+	}
+
+	if (paint_brush(&sd->paint)->sculpt_tool != SCULPT_TOOL_SIMPLIFY)
+		do_symmetrical_brush_actions(sd, ob, do_brush_action);
+
+	sculpt_combine_proxies(sd, ob);
+
+	/* hack to fix noise texture tearing mesh */
+	sculpt_fix_noise_tear(sd, ob);
+
+	if (ss->modifiers_active)
+		sculpt_flush_stroke_deform(sd, ob);
+
+	ss->cache->first_time = FALSE;
 
 	/* Cleanup */
 	sculpt_flush_update(C);
@@ -3980,7 +4326,10 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
 
 		sculpt_undo_push_end();
 
-		BLI_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
+		BKE_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
+		
+		if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH)
+			BKE_pbvh_bmesh_after_stroke(ss->pbvh);
 
 		/* optimization: if there is locked key and active modifiers present in */
 		/* the stack, keyblock is updating at each step. otherwise we could update */
@@ -4055,7 +4404,7 @@ static int sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
 	Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
 
 	if (ss->cache) {
-		paint_mesh_restore_co(sd, ss);
+		paint_mesh_restore_co(sd, ob);
 	}
 
 	paint_stroke_cancel(C, op);
@@ -4137,6 +4486,266 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/************************** Dynamic Topology **************************/
+
+static void sculpt_dynamic_topology_triangulate(BMesh *bm)
+{
+	BMO_op_callf(bm, BMO_FLAG_DEFAULTS, "triangulate faces=%af");
+}
+
+void sculpt_pbvh_clear(Object *ob)
+{
+	SculptSession *ss = ob->sculpt;
+	DerivedMesh *dm = ob->derivedFinal;
+
+	/* Clear out any existing DM and PBVH */
+	if (ss->pbvh)
+		BKE_pbvh_free(ss->pbvh);
+	ss->pbvh = NULL;
+	if (dm)
+		dm->getPBVH(NULL, dm);
+	BKE_object_free_display(ob);
+}
+
+void sculpt_update_after_dynamic_topology_toggle(bContext *C)
+{
+	Scene *scene = CTX_data_scene(C);
+	Object *ob = CTX_data_active_object(C);
+	Sculpt *sd = scene->toolsettings->sculpt;
+
+	/* Create the PBVH */
+	sculpt_update_mesh_elements(scene, sd, ob, FALSE, FALSE);
+	WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+}
+
+void sculpt_dynamic_topology_enable(bContext *C)
+{
+	Scene *scene = CTX_data_scene(C);
+	Object *ob = CTX_data_active_object(C);
+	SculptSession *ss = ob->sculpt;
+	Mesh *me = ob->data;
+
+	sculpt_pbvh_clear(ob);
+
+	ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags &
+							 SCULPT_DYNTOPO_SMOOTH_SHADING);
+
+	/* Create triangles-only BMesh */
+	ss->bm = BM_mesh_create(&bm_mesh_allocsize_default);
+
+	BM_mesh_bm_from_me(ss->bm, me, TRUE, ob->shapenr);
+	sculpt_dynamic_topology_triangulate(ss->bm);
+	BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
+	BM_mesh_normals_update(ss->bm, TRUE);
+
+	/* Enable dynamic topology */
+	me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+	
+	/* Enable logging for undo/redo */
+	ss->bm_log = BM_log_create(ss->bm);
+
+	/* Refresh */
+	sculpt_update_after_dynamic_topology_toggle(C);
+}
+
+/* Free the sculpt BMesh and BMLog
+ *
+ * If 'unode' is given, the BMesh's data is copied out to the unode
+ * before the BMesh is deleted so that it can be restored from */
+void sculpt_dynamic_topology_disable(bContext *C,
+									 SculptUndoNode *unode)
+{
+	Object *ob = CTX_data_active_object(C);
+	SculptSession *ss = ob->sculpt;
+	Mesh *me = ob->data;
+
+	sculpt_pbvh_clear(ob);
+
+	if (unode) {
+		/* Free all existing custom data */
+		CustomData_free(&me->vdata, me->totvert);
+		CustomData_free(&me->edata, me->totedge);
+		CustomData_free(&me->fdata, me->totface);
+		CustomData_free(&me->ldata, me->totloop);
+		CustomData_free(&me->pdata, me->totpoly);
+
+		/* Copy over stored custom data */
+		me->totvert = unode->bm_enter_totvert;
+		me->totloop = unode->bm_enter_totloop;
+		me->totpoly = unode->bm_enter_totpoly;
+		me->totedge = unode->bm_enter_totedge;
+		me->totface = 0;
+		CustomData_copy(&unode->bm_enter_vdata, &me->vdata, CD_MASK_MESH,
+						CD_DUPLICATE, unode->bm_enter_totvert);
+		CustomData_copy(&unode->bm_enter_edata, &me->edata, CD_MASK_MESH,
+						CD_DUPLICATE, unode->bm_enter_totedge);
+		CustomData_copy(&unode->bm_enter_ldata, &me->ldata, CD_MASK_MESH,
+						CD_DUPLICATE, unode->bm_enter_totloop);
+		CustomData_copy(&unode->bm_enter_pdata, &me->pdata, CD_MASK_MESH,
+						CD_DUPLICATE, unode->bm_enter_totpoly);
+
+		mesh_update_customdata_pointers(me, FALSE);
+	} else {
+		sculptsession_bm_to_me(ob, TRUE);
+	}
+
+	BM_mesh_free(ss->bm);
+
+	/* Clear data */
+	me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+	ss->bm = NULL;
+	BM_log_free(ss->bm_log);
+	ss->bm_log = NULL;
+
+	/* Refresh */
+	sculpt_update_after_dynamic_topology_toggle(C);
+}
+
+static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+	Object *ob = CTX_data_active_object(C);
+	SculptSession *ss = ob->sculpt;
+
+	if (ss->bm) {
+		sculpt_undo_push_begin("Dynamic topology disable");
+		sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
+		sculpt_dynamic_topology_disable(C, NULL);
+	}
+	else {
+		sculpt_undo_push_begin("Dynamic topology enable");
+		sculpt_dynamic_topology_enable(C);
+		sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+	}
+	sculpt_undo_push_end();
+
+	return OPERATOR_FINISHED;
+}
+
+static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op,
+												 wmEvent *UNUSED(event))
+{
+	Object *ob = CTX_data_active_object(C);
+	Mesh *me = ob->data;
+	SculptSession *ss = ob->sculpt;
+	const char *msg = "Dynamic-topology sculpting will not preserve"
+		              "vertex colors, UVs, or other customdata";
+
+	if (!ss->bm) {
+		int i;
+
+		for (i = 0; i < CD_NUMTYPES; i++) {
+			if (!ELEM7(i, CD_MVERT, CD_MEDGE, CD_MFACE,
+					   CD_MLOOP, CD_MPOLY, CD_PAINT_MASK,
+					   CD_ORIGINDEX) &&
+				(CustomData_has_layer(&me->vdata, i) ||
+				 CustomData_has_layer(&me->edata, i) ||
+				 CustomData_has_layer(&me->fdata, i))) {
+				/* The mesh has customdata that will be lost, let the
+				 * user confirm this is OK */
+				return WM_operator_confirm_message(C, op, msg);
+			}
+		}
+	}
+
+	return sculpt_dynamic_topology_toggle_exec(C, op);
+}
+
+static void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Dynamic Topology Toggle";
+	ot->idname = "SCULPT_OT_dynamic_topology_toggle";
+	ot->description = "Dynamic topology alters the mesh topology while sculpting";
+	
+	/* api callbacks */
+	ot->invoke = sculpt_dynamic_topology_toggle_invoke;
+	ot->exec = sculpt_dynamic_topology_toggle_exec;
+	ot->poll = sculpt_mode_poll;
+	
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/************************* SCULPT_OT_optimize *************************/
+
+static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+	Object *ob = CTX_data_active_object(C);
+
+	sculpt_pbvh_clear(ob);
+	WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+	return OPERATOR_FINISHED;
+}
+
+static int sculpt_and_dynamic_topology_poll(bContext *C)
+{
+	Object *ob = CTX_data_active_object(C);
+
+	return sculpt_mode_poll(C) && ob->sculpt->bm;
+}
+
+/* The BVH gets less optimal more quickly with dynamic topology than
+ * regular sculpting. There is no doubt more clever stuff we can do to
+ * optimize it on the fly, but for now this gives the user a nicer way
+ * to recalculate it than toggling modes. */
+static void SCULPT_OT_optimize(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Optimize";
+	ot->idname = "SCULPT_OT_optimize";
+	ot->description = "Recalculate the sculpt BVH to improve performance";
+	
+	/* api callbacks */
+	ot->exec = sculpt_optimize_exec;
+	ot->poll = sculpt_and_dynamic_topology_poll;
+	
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************* Dynamic topology symmetrize ********************/
+
+static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+	Object *ob = CTX_data_active_object(C);
+	const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+	SculptSession *ss = ob->sculpt;
+
+	/* To simplify undo for symmetrize, all BMesh elements are logged
+	 * as deleted, then after symmetrize operation all BMesh elements
+	 * are logged as added (as opposed to attempting to store just the
+	 * parts that symmetrize modifies) */
+	sculpt_undo_push_begin("Dynamic topology symmetrize");
+	sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
+	BM_log_before_all_removed(ss->bm, ss->bm_log);
+
+	/* Symmetrize and re-triangulate */
+	BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS,
+				 "symmetrize input=%avef direction=%i",
+				 sd->symmetrize_direction);
+	sculpt_dynamic_topology_triangulate(ss->bm);
+
+	/* Finish undo */
+	BM_log_all_added(ss->bm, ss->bm_log);
+	sculpt_undo_push_end();
+
+	/* Redraw */
+	sculpt_pbvh_clear(ob);
+	WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+	return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_symmetrize(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Symmetrize";
+	ot->idname = "SCULPT_OT_symmetrize";
+	
+	/* api callbacks */
+	ot->exec = sculpt_symmetrize_exec;
+	ot->poll = sculpt_and_dynamic_topology_poll;
+}
+
 /**** Toggle operator for turning sculpt mode on or off ****/
 
 static void sculpt_init_session(Scene *scene, Object *ob)
@@ -4222,6 +4831,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
 	Scene *scene = CTX_data_scene(C);
 	ToolSettings *ts = CTX_data_tool_settings(C);
 	Object *ob = CTX_data_active_object(C);
+	Mesh *me = ob->data;
 	MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
 	int flush_recalc = 0;
 
@@ -4234,9 +4844,16 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
 		if (mmd)
 			multires_force_update(ob);
 
-		if (flush_recalc)
+		if (flush_recalc || (ob->sculpt && ob->sculpt->bm))
 			DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 
+		if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+			/* Dynamic topology must be disabled before exiting sculpt
+			 * mode to ensure the undo stack stays in a consistent
+			 * state */
+			sculpt_dynamic_topology_toggle_exec(C, NULL);
+		}
+
 		/* Leave sculptmode */
 		ob->mode &= ~OB_MODE_SCULPT;
 
@@ -4257,6 +4874,9 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
 			ts->sculpt->flags |= SCULPT_SYMM_X;
 		}
 
+		if (!ts->sculpt->detail_size)
+			ts->sculpt->detail_size = 30;
+
 		/* Create sculpt mode session data */
 		if (ob->sculpt)
 			free_sculptsession(ob);
@@ -4271,7 +4891,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *UNUSED(op))
 		}
 
 		BKE_paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
-		
+
 		paint_cursor_start(C, sculpt_poll);
 	}
 
@@ -4299,4 +4919,7 @@ void ED_operatortypes_sculpt(void)
 	WM_operatortype_append(SCULPT_OT_brush_stroke);
 	WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
 	WM_operatortype_append(SCULPT_OT_set_persistent_base);
+	WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
+	WM_operatortype_append(SCULPT_OT_optimize);
+	WM_operatortype_append(SCULPT_OT_symmetrize);
 }
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 44068122b89..e56962a3964 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -49,6 +49,7 @@ struct Object;
 struct Scene;
 struct Sculpt;
 struct SculptStroke;
+struct SculptUndoNode;
 
 /* Interface */
 struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob);
@@ -67,12 +68,22 @@ void free_sculptsession_deformMats(struct SculptSession *ss);
 /* Stroke */
 int sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2]);
 
+/* Dynamic topology */
+void sculpt_pbvh_clear(Object *ob);
+void sculpt_update_after_dynamic_topology_toggle(bContext *C);
+void sculpt_dynamic_topology_enable(struct bContext *C);
+void sculpt_dynamic_topology_disable(struct bContext *C,
+									 struct SculptUndoNode *unode);
+
 /* Undo */
 
 typedef enum {
 	SCULPT_UNDO_COORDS,
 	SCULPT_UNDO_HIDDEN,
-	SCULPT_UNDO_MASK
+	SCULPT_UNDO_MASK,
+	SCULPT_UNDO_DYNTOPO_BEGIN,
+	SCULPT_UNDO_DYNTOPO_END,
+	SCULPT_UNDO_DYNTOPO_SYMMETRIZE,
 } SculptUndoType;
 
 typedef struct SculptUndoNode {
@@ -101,8 +112,17 @@ typedef struct SculptUndoNode {
 	int *grids;                 /* to restore into right location */
 	BLI_bitmap *grid_hidden;
 
-	/* layer brush */
-	float *layer_disp;
+	/* bmesh */
+	struct BMLogEntry *bm_entry;
+	int applied;
+	CustomData bm_enter_vdata;
+	CustomData bm_enter_edata;
+	CustomData bm_enter_ldata;
+	CustomData bm_enter_pdata;
+	int bm_enter_totvert;
+	int bm_enter_totedge;
+	int bm_enter_totloop;
+	int bm_enter_totpoly;
 
 	/* shape keys */
 	char shapeName[sizeof(((KeyBlock *)0))->name];
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 1b3fd24ae22..c828e8c8651 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -65,6 +65,7 @@
 #include "GPU_buffers.h"
 
 #include "ED_sculpt.h"
+#include "bmesh.h"
 #include "paint_intern.h"
 #include "sculpt_intern.h"
 
@@ -72,10 +73,10 @@
 
 static void update_cb(PBVHNode *node, void *rebuild)
 {
-	BLI_pbvh_node_mark_update(node);
+	BKE_pbvh_node_mark_update(node);
 	if (*((int *)rebuild))
-		BLI_pbvh_node_mark_rebuild_draw(node);
-	BLI_pbvh_node_fully_hidden_set(node, 0);
+		BKE_pbvh_node_mark_rebuild_draw(node);
+	BKE_pbvh_node_fully_hidden_set(node, 0);
 }
 
 static void sculpt_undo_restore_deformed(const SculptSession *ss,
@@ -142,7 +143,7 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo
 
 			/* pbvh uses it's own mvert array, so coords should be */
 			/* propagated to pbvh here */
-			BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
+			BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
 
 			MEM_freeN(vertCos);
 		}
@@ -261,6 +262,111 @@ static int sculpt_undo_restore_mask(bContext *C, DerivedMesh *dm, SculptUndoNode
 	return 1;
 }
 
+static void sculpt_undo_bmesh_restore_generic(SculptUndoNode *unode,
+											  Object *ob,
+											  SculptSession *ss)
+{
+	if (unode->applied) {
+		BM_log_undo(ss->bm, ss->bm_log);
+		unode->applied = FALSE;
+	}
+	else {
+		BM_log_redo(ss->bm, ss->bm_log);
+		unode->applied = TRUE;
+	}
+
+	/* A bit lame, but for now just recreate the PBVH. The alternative
+	 * is to store changes to the PBVH in the undo stack. */
+	sculpt_pbvh_clear(ob);
+}
+
+/* Create empty sculpt BMesh and enable logging */
+static void sculpt_undo_bmesh_enable(Object *ob,
+									 SculptUndoNode *unode)
+{
+	SculptSession *ss = ob->sculpt;
+	Mesh *me = ob->data;
+
+	sculpt_pbvh_clear(ob);
+
+	/* Create empty BMesh and enable logging */
+	ss->bm = BM_mesh_create(&bm_mesh_allocsize_default);
+	BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
+	me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+	/* Restore the BMLog using saved entries */
+	ss->bm_log = BM_log_from_existing_entries_create(ss->bm,
+													 unode->bm_entry);
+}
+
+static void sculpt_undo_bmesh_restore_begin(bContext *C,
+											SculptUndoNode *unode,
+											Object *ob,
+											SculptSession *ss)
+{
+	if (unode->applied) {
+		sculpt_dynamic_topology_disable(C, unode);
+		unode->applied = FALSE;
+	}
+	else {
+		sculpt_undo_bmesh_enable(ob, unode);
+
+		/* Restore the mesh from the first log entry */
+		BM_log_redo(ss->bm, ss->bm_log);
+
+		unode->applied = TRUE;
+	}
+}
+
+static void sculpt_undo_bmesh_restore_end(bContext *C,
+										  SculptUndoNode *unode,
+										  Object *ob,
+										  SculptSession *ss)
+{
+	if (unode->applied) {
+		sculpt_undo_bmesh_enable(ob, unode);
+
+		/* Restore the mesh from the last log entry */
+		BM_log_undo(ss->bm, ss->bm_log);
+
+		unode->applied = FALSE;
+	}
+	else {
+		/* Disable dynamic topology sculpting */
+		sculpt_dynamic_topology_disable(C, NULL);
+		unode->applied = TRUE;
+	}
+}
+
+/* Handle all dynamic-topology updates
+ *
+ * Returns TRUE if this was a dynamic-topology undo step, otherwise
+ * returns FALSE to indicate the non-dyntopo code should run. */
+static int sculpt_undo_bmesh_restore(bContext *C,
+									 SculptUndoNode *unode,
+									 Object *ob,
+									 SculptSession *ss)
+{
+	switch (unode->type) {
+		case SCULPT_UNDO_DYNTOPO_BEGIN:
+			sculpt_undo_bmesh_restore_begin(C, unode, ob, ss);
+			return TRUE;
+
+		case SCULPT_UNDO_DYNTOPO_END:
+			sculpt_undo_bmesh_restore_end(C, unode, ob, ss);
+			return TRUE;
+
+		default:
+			if (ss->bm_log) {
+				sculpt_undo_bmesh_restore_generic(unode, ob, ss);
+				return TRUE;
+			}
+			break;
+	}
+
+	return FALSE;
+}
+
 static void sculpt_undo_restore(bContext *C, ListBase *lb)
 {
 	Scene *scene = CTX_data_scene(C);
@@ -289,6 +395,9 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
 	/* call _after_ sculpt_update_mesh_elements() which may update 'ob->derivedFinal' */
 	dm = mesh_get_derived_final(scene, ob, 0);
 
+	if (lb->first && sculpt_undo_bmesh_restore(C, lb->first, ob, ss))
+		return;
+
 	for (unode = lb->first; unode; unode = unode->next) {
 		if (!(strcmp(unode->idname, ob->id.name) == 0))
 			continue;
@@ -306,9 +415,6 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
 				continue;
 			}
 		}
-		else {
-			continue;
-		}
 
 		switch (unode->type) {
 			case SCULPT_UNDO_COORDS:
@@ -323,6 +429,12 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
 				if (sculpt_undo_restore_mask(C, dm, unode))
 					update = TRUE;
 				break;
+
+			case SCULPT_UNDO_DYNTOPO_BEGIN:
+			case SCULPT_UNDO_DYNTOPO_END:
+			case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+				BLI_assert(!"Dynamic topology should've already been handled");
+				break;
 		}
 	}
 
@@ -331,8 +443,8 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
 		/* we update all nodes still, should be more clever, but also
 		 * needs to work correct when exiting/entering sculpt mode and
 		 * the nodes get recreated, though in that case it could do all */
-		BLI_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
-		BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw, NULL);
+		BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
+		BKE_pbvh_update(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw, NULL);
 
 		if ((mmd = sculpt_multires_active(scene, ob))) {
 			if (rebuild)
@@ -374,8 +486,6 @@ static void sculpt_undo_free(ListBase *lb)
 			MEM_freeN(unode->index);
 		if (unode->grids)
 			MEM_freeN(unode->grids);
-		if (unode->layer_disp)
-			MEM_freeN(unode->layer_disp);
 		if (unode->orig_co)
 			MEM_freeN(unode->orig_co);
 		if (unode->vert_hidden)
@@ -389,6 +499,17 @@ static void sculpt_undo_free(ListBase *lb)
 		}
 		if (unode->mask)
 			MEM_freeN(unode->mask);
+		if (unode->bm_entry) {
+			BM_log_entry_drop(unode->bm_entry);
+		}
+		if (unode->bm_enter_totvert)
+			CustomData_free(&unode->bm_enter_vdata, unode->bm_enter_totvert);
+		if (unode->bm_enter_totedge)
+			CustomData_free(&unode->bm_enter_edata, unode->bm_enter_totedge);
+		if (unode->bm_enter_totloop)
+			CustomData_free(&unode->bm_enter_ldata, unode->bm_enter_totloop);
+		if (unode->bm_enter_totpoly)
+			CustomData_free(&unode->bm_enter_pdata, unode->bm_enter_totpoly);
 	}
 }
 
@@ -410,9 +531,9 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh,
 	BLI_bitmap *grid_hidden;
 	int i, *grid_indices, totgrid;
 
-	grid_hidden = BLI_pbvh_grid_hidden(pbvh);
+	grid_hidden = BKE_pbvh_grid_hidden(pbvh);
 
-	BLI_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid,
+	BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid,
 	                        NULL, NULL, NULL, NULL);
 			
 	unode->grid_hidden = MEM_mapallocN(sizeof(BLI_bitmap) * totgrid,
@@ -439,11 +560,13 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
 	unode->type = type;
 	unode->node = node;
 
-	BLI_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
-	BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
-	                        &maxgrid, &gridsize, NULL, NULL);
+	if (node) {
+		BKE_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
+		BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
+								&maxgrid, &gridsize, NULL, NULL);
 
-	unode->totvert = totvert;
+		unode->totvert = totvert;
+	}
 	
 	/* we will use this while sculpting, is mapalloc slow to access then? */
 
@@ -468,6 +591,11 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node,
 			unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask");
 			undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float) * sizeof(int)) * allvert);
 			break;
+		case SCULPT_UNDO_DYNTOPO_BEGIN:
+		case SCULPT_UNDO_DYNTOPO_END:
+		case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+			BLI_assert(!"Dynamic topology should've already been handled");
+			break;
 	}
 	
 	BLI_addtail(lb, unode);
@@ -496,7 +624,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
 	SculptSession *ss = ob->sculpt;
 	PBVHVertexIter vd;
 
-	BLI_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
+	BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
 	{
 		copy_v3_v3(unode->co[vd.i], vd.co);
 		if (vd.no) copy_v3_v3_short(unode->no[vd.i], vd.no);
@@ -505,7 +633,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
 		if (ss->modifiers_active)
 			copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]);
 	}
-	BLI_pbvh_vertex_iter_end;
+	BKE_pbvh_vertex_iter_end;
 }
 
 static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode)
@@ -521,8 +649,8 @@ static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode)
 		int *vert_indices, allvert;
 		int i;
 		
-		BLI_pbvh_node_num_verts(pbvh, node, NULL, &allvert);
-		BLI_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
+		BKE_pbvh_node_num_verts(pbvh, node, NULL, &allvert);
+		BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
 		for (i = 0; i < allvert; i++) {
 			BLI_BITMAP_MODIFY(unode->vert_hidden, i,
 			                  mvert[vert_indices[i]].flag & ME_HIDE);
@@ -535,11 +663,85 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode)
 	SculptSession *ss = ob->sculpt;
 	PBVHVertexIter vd;
 
-	BLI_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
+	BKE_pbvh_vertex_iter_begin(ss->pbvh, unode->node, vd, PBVH_ITER_ALL)
 	{
 		unode->mask[vd.i] = *vd.mask;
 	}
-	BLI_pbvh_vertex_iter_end;
+	BKE_pbvh_vertex_iter_end;
+}
+
+static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob,
+											  PBVHNode *node,
+											  SculptUndoType type)
+{
+	ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
+	SculptUndoNode *unode = lb->first;
+	SculptSession *ss = ob->sculpt;
+	PBVHVertexIter vd;
+
+	if (!lb->first) {
+		unode = MEM_callocN(sizeof(*unode), AT);
+
+		BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
+		unode->type = type;
+		unode->applied = TRUE;
+
+		if (type == SCULPT_UNDO_DYNTOPO_END) {
+			unode->bm_entry = BM_log_entry_add(ss->bm_log);
+			BM_log_before_all_removed(ss->bm, ss->bm_log);
+		}
+		else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) {
+			Mesh *me = ob->data;
+
+			/* Store a copy of the mesh's current vertices, loops, and
+			 * polys. A full copy like this is needed because entering
+			 * dynamic-topology immediately does topological edits
+			 * (converting polys to triangles) that the BMLog can't
+			 * fully restore from */
+			CustomData_copy(&me->vdata, &unode->bm_enter_vdata, CD_MASK_MESH,
+							CD_DUPLICATE, me->totvert);
+			CustomData_copy(&me->edata, &unode->bm_enter_edata, CD_MASK_MESH,
+							CD_DUPLICATE, me->totedge);
+			CustomData_copy(&me->ldata, &unode->bm_enter_ldata, CD_MASK_MESH,
+							CD_DUPLICATE, me->totloop);
+			CustomData_copy(&me->pdata, &unode->bm_enter_pdata, CD_MASK_MESH,
+							CD_DUPLICATE, me->totpoly);
+			unode->bm_enter_totvert = me->totvert;
+			unode->bm_enter_totedge = me->totedge;
+			unode->bm_enter_totloop = me->totloop;
+			unode->bm_enter_totpoly = me->totpoly;
+
+			unode->bm_entry = BM_log_entry_add(ss->bm_log);
+			BM_log_all_added(ss->bm, ss->bm_log);
+		}
+		else {
+			unode->bm_entry = BM_log_entry_add(ss->bm_log);
+		}
+
+		BLI_addtail(lb, unode);
+	}
+
+	if (node) {
+		switch (type) {
+			case SCULPT_UNDO_COORDS:
+			case SCULPT_UNDO_HIDDEN:
+			case SCULPT_UNDO_MASK:
+				/* Before any vertex values get modified, ensure their
+				 * original positions are logged */
+				BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) {
+					BM_log_vert_before_modified(ss->bm, ss->bm_log, vd.bm_vert);
+				}
+				BKE_pbvh_vertex_iter_end;
+				break;
+
+			case SCULPT_UNDO_DYNTOPO_BEGIN:
+			case SCULPT_UNDO_DYNTOPO_END:
+			case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+				break;
+		}
+	}
+
+	return unode;
 }
 
 SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
@@ -551,7 +753,18 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
 	/* list is manipulated by multiple threads, so we lock */
 	BLI_lock_thread(LOCK_CUSTOM1);
 
-	if ((unode = sculpt_undo_get_node(node))) {
+	if (ss->bm ||
+		ELEM(type,
+			 SCULPT_UNDO_DYNTOPO_BEGIN,
+			 SCULPT_UNDO_DYNTOPO_END))
+	{
+		/* Dynamic topology stores only one undo node per stroke,
+		 * regardless of the number of PBVH nodes modified */
+		unode = sculpt_undo_bmesh_push(ob, node, type);
+		BLI_unlock_thread(LOCK_CUSTOM1);
+		return unode;
+	}
+	else if ((unode = sculpt_undo_get_node(node))) {
 		BLI_unlock_thread(LOCK_CUSTOM1);
 		return unode;
 	}
@@ -564,14 +777,14 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
 
 	if (unode->grids) {
 		int totgrid, *grids;
-		BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
+		BKE_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
 		                        NULL, NULL, NULL, NULL);
 		memcpy(unode->grids, grids, sizeof(int) * totgrid);
 	}
 	else {
 		int *vert_indices, allvert;
-		BLI_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert);
-		BLI_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL);
+		BKE_pbvh_node_num_verts(ss->pbvh, node, NULL, &allvert);
+		BKE_pbvh_node_get_verts(ss->pbvh, node, &vert_indices, NULL);
 		memcpy(unode->index, vert_indices, sizeof(int) * unode->totvert);
 	}
 
@@ -585,6 +798,11 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
 		case SCULPT_UNDO_MASK:
 			sculpt_undo_store_mask(ob, unode);
 			break;
+		case SCULPT_UNDO_DYNTOPO_BEGIN:
+		case SCULPT_UNDO_DYNTOPO_END:
+		case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
+			BLI_assert(!"Dynamic topology should've already been handled");
+			break;
 	}
 
 	/* store active shape key */
@@ -612,10 +830,8 @@ void sculpt_undo_push_end(void)
 			unode->no = NULL;
 		}
 
-		if (unode->layer_disp) {
-			MEM_freeN(unode->layer_disp);
-			unode->layer_disp = NULL;
-		}
+		if (unode->node)
+			BKE_pbvh_node_layer_disp_free(unode->node);
 	}
 
 	undo_paint_push_end(UNDO_PAINT_MESH);
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 9bd7d2a44ca..4b1954c8889 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -82,13 +82,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
 	filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
 	items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
 	
-	/* Update max-extent of channels here (taking into account scrollers):
-	 *  - this is done to allow the channel list to be scrollable, but must be done here
-	 *    to avoid regenerating the list again and/or also because channels list is drawn first
-	 *	- offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
-	 *	  start of list offset, and the second is as a correction for the scrollers.
-	 */
-	height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2));
+	height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT));
 	if (height > BLI_rcti_size_y(&v2d->mask)) {
 		/* don't use totrect set, as the width stays the same 
 		 * (NOTE: this is ok here, the configuration is pretty straightforward) 
@@ -199,13 +193,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
 	filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
 	items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
 	
-	/* Update max-extent of channels here (taking into account scrollers):
-	 *  - this is done to allow the channel list to be scrollable, but must be done here
-	 *    to avoid regenerating the list again and/or also because channels list is drawn first
-	 *	- offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for 
-	 *	  start of list offset, and the second is as a correction for the scrollers.
-	 */
-	height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2));
+	height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT));
 	/* don't use totrect set, as the width stays the same 
 	 * (NOTE: this is ok here, the configuration is pretty straightforward) 
 	 */
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index c5f3ccee101..e0ca589c1fb 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -219,6 +219,9 @@ static void action_channel_area_init(wmWindowManager *wm, ARegion *ar)
 {
 	wmKeyMap *keymap;
 	
+	/* ensure the 2d view sync works - main region has bottom scroller */
+	ar->v2d.scroll = V2D_SCROLL_BOTTOM;
+	
 	UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
 	
 	/* own keymap */
@@ -231,7 +234,6 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar)
 	/* draw entirely, view changes should be handled here */
 	bAnimContext ac;
 	View2D *v2d = &ar->v2d;
-	View2DScrollers *scrollers;
 	
 	/* clear and setup matrix */
 	UI_ThemeClearColor(TH_BACK);
@@ -247,10 +249,7 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar)
 	/* reset view matrix */
 	UI_view2d_view_restore(C);
 	
-	/* scrollers */
-	scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
-	UI_view2d_scrollers_draw(C, v2d, scrollers);
-	UI_view2d_scrollers_free(scrollers);
+	/* no scrollers here */
 }
 
 
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 77662d8ac13..56a890c714a 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -1801,7 +1801,7 @@ static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat
 	int found = FALSE;
 
 	for (con = ob->constraints.first; con; con = con->next) {
-		bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+		bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 
 		if (!cti)
 			continue;
@@ -1832,7 +1832,7 @@ static Object *object_solver_camera(Scene *scene, Object *ob)
 	bConstraint *con;
 
 	for (con = ob->constraints.first; con; con = con->next) {
-		bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+		bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 
 		if (!cti)
 			continue;
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index fb438ae45fb..08f01b47b52 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -321,8 +321,7 @@ void file_calc_previews(const bContext *C, ARegion *ar)
 	View2D *v2d = &ar->v2d;
 	
 	ED_fileselect_init_layout(sfile, ar);
-	/* +SCROLL_HEIGHT is bad hack to work around issue in UI_view2d_totRect_set */
-	UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height + V2D_SCROLL_HEIGHT);
+	UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height);
 }
 
 static void file_draw_preview(uiBlock *block, struct direntry *file, int sx, int sy, ImBuf *imb, FileLayout *layout, short dropshadow)
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index fa7c6bd472a..734c0e6c479 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -309,6 +309,12 @@ static void graph_channel_area_init(wmWindowManager *wm, ARegion *ar)
 {
 	wmKeyMap *keymap;
 	
+	/* make sure we keep the hide flags */
+	ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
+	ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP);	/* prevent any noise of past */
+	ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
+	ar->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE;
+	
 	UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
 	
 	/* own keymap */
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index d02186e59dd..060a181612b 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -219,7 +219,7 @@ static void preview_cb(ScrArea *sa, struct uiBlock *block)
 	BLI_rcti_translate(disprect, -curarea->winrct.xmin, -curarea->winrct.ymin);
 	
 	calc_image_view(sima, 'p');
-//	printf("winrct %d %d %d %d\n", disprect->xmin, disprect->ymin,disprect->xmax, disprect->ymax);
+//	printf("winrct %d %d %d %d\n", disprect->xmin, disprect->ymin, disprect->xmax, disprect->ymax);
 	/* map to image space coordinates */
 	mval[0] = disprect->xmin; mval[1] = disprect->ymin;
 	areamouseco_to_ipoco(v2d, mval, &dispf.xmin, &dispf.ymin);
@@ -236,7 +236,7 @@ static void preview_cb(ScrArea *sa, struct uiBlock *block)
 	CLAMP(disprect->xmax, 0, winx);
 	CLAMP(disprect->ymin, 0, winy);
 	CLAMP(disprect->ymax, 0, winy);
-//	printf("drawrct %d %d %d %d\n", disprect->xmin, disprect->ymin,disprect->xmax, disprect->ymax);
+//	printf("drawrct %d %d %d %d\n", disprect->xmin, disprect->ymin, disprect->xmax, disprect->ymax);
 
 }
 
@@ -674,6 +674,24 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
 
 			if (ima->source != IMA_SRC_GENERATED) {
 				if (compact == 0) { /* background image view doesnt need these */
+					ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+					int has_alpha = TRUE;
+
+					if (ibuf) {
+						int imtype = BKE_ftype_to_imtype(ibuf->ftype);
+						char valid_channels = BKE_imtype_valid_channels(imtype);
+
+						has_alpha = valid_channels & IMA_CHAN_FLAG_ALPHA;
+
+						BKE_image_release_ibuf(ima, ibuf, NULL);
+					}
+
+					if (has_alpha) {
+						col = uiLayoutColumn(layout, FALSE);
+						uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE);
+						uiItemR(col, &imaptr, "alpha_mode", 0, "Alpha", ICON_NONE);
+					}
+
 					uiItemS(layout);
 
 					split = uiLayoutSplit(layout, 0.0f, FALSE);
@@ -694,10 +712,6 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
 					row = uiLayoutRow(col, FALSE);
 					uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_fields"));
 					uiItemR(row, &imaptr, "field_order", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
-					
-					row = uiLayoutRow(layout, FALSE);
-					uiItemR(row, &imaptr, "use_premultiply", 0, NULL, ICON_NONE);
-					uiItemR(row, &imaptr, "use_color_unpremultiply", 0, NULL, ICON_NONE);
 				}
 			}
 
@@ -796,6 +810,8 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man
 	}
 
 	if (imf->imtype == R_IMF_IMTYPE_JP2) {
+		uiItemR(col, imfptr, "jpeg2k_codec", 0, NULL, ICON_NONE);
+
 		row = uiLayoutRow(col, FALSE);
 		uiItemR(row, imfptr, "use_jpeg2k_cinema_preset", 0, NULL, ICON_NONE);
 		uiItemR(row, imfptr, "use_jpeg2k_cinema_48", 0, NULL, ICON_NONE);
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index d565e6f9e9a..0534b9f4ffd 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -75,13 +75,15 @@
 #include "WM_types.h"
 
 #include "RE_pipeline.h"
+#include "RE_engine.h"
 
 #include "image_intern.h"
 
-static void draw_render_info(Scene *scene, Image *ima, ARegion *ar)
+static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx, float zoomy)
 {
 	RenderResult *rr;
-	
+	Render *re = RE_GetRender(scene->id.name);
+
 	rr = BKE_image_acquire_renderresult(scene, ima);
 
 	if (rr && rr->text) {
@@ -89,6 +91,73 @@ static void draw_render_info(Scene *scene, Image *ima, ARegion *ar)
 	}
 
 	BKE_image_release_renderresult(scene, ima);
+
+	if (re) {
+		int total_tiles;
+		rcti *tiles;
+
+		RE_engine_get_current_tiles(re, &total_tiles, &tiles);
+
+		if (total_tiles) {
+			int i, x, y;
+			rcti *tile;
+
+			/* find window pixel coordinates of origin */
+			UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y);
+
+			glPushMatrix();
+			glTranslatef(x, y, 0.0f);
+			glScalef(zoomx, zoomy, 1.0f);
+
+			if (scene->r.mode & R_BORDER) {
+				glTranslatef(-scene->r.border.xmin * scene->r.xsch * scene->r.size / 100.0f,
+				             -scene->r.border.ymin * scene->r.ysch * scene->r.size / 100.0f,
+				             0.0f);
+			}
+
+			UI_ThemeColor(TH_FACE_SELECT);
+
+			for (i = 0, tile = tiles; i < total_tiles; i++, tile++) {
+				float delta_x = 4.0f * UI_DPI_FAC / zoomx;
+				float delta_y = 4.0f * UI_DPI_FAC / zoomy;
+
+				delta_x = min_ff(delta_x, tile->xmax - tile->xmin);
+				delta_y = min_ff(delta_y, tile->ymax - tile->ymin);
+
+				/* left bottom corner */
+				glBegin(GL_LINE_STRIP);
+				glVertex2f(tile->xmin, tile->ymin + delta_y);
+				glVertex2f(tile->xmin, tile->ymin);
+				glVertex2f(tile->xmin + delta_x, tile->ymin);
+				glEnd();
+
+				/* left top corner */
+				glBegin(GL_LINE_STRIP);
+				glVertex2f(tile->xmin, tile->ymax - delta_y);
+				glVertex2f(tile->xmin, tile->ymax);
+				glVertex2f(tile->xmin + delta_x, tile->ymax);
+				glEnd();
+
+				/* right bottom corner */
+				glBegin(GL_LINE_STRIP);
+				glVertex2f(tile->xmax - delta_x, tile->ymin);
+				glVertex2f(tile->xmax, tile->ymin);
+				glVertex2f(tile->xmax, tile->ymin + delta_y);
+				glEnd();
+
+				/* right top corner */
+				glBegin(GL_LINE_STRIP);
+				glVertex2f(tile->xmax - delta_x, tile->ymax);
+				glVertex2f(tile->xmax, tile->ymax);
+				glVertex2f(tile->xmax, tile->ymax - delta_y);
+				glEnd();
+			}
+
+			MEM_freeN(tiles);
+
+			glPopMatrix();
+		}
+	}
 }
 
 /* used by node view too */
@@ -146,7 +215,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def
 	if (channels >= 3) {
 		glColor3ubv(red);
 		if (fp)
-			BLI_snprintf(str, sizeof(str), "  R:%-.4f", fp[0]);
+			BLI_snprintf(str, sizeof(str), "  R:%-.5f", fp[0]);
 		else if (cp)
 			BLI_snprintf(str, sizeof(str), "  R:%-3d", cp[0]);
 		else
@@ -157,7 +226,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def
 		
 		glColor3ubv(green);
 		if (fp)
-			BLI_snprintf(str, sizeof(str), "  G:%-.4f", fp[1]);
+			BLI_snprintf(str, sizeof(str), "  G:%-.5f", fp[1]);
 		else if (cp)
 			BLI_snprintf(str, sizeof(str), "  G:%-3d", cp[1]);
 		else
@@ -168,7 +237,7 @@ void ED_image_draw_info(Scene *scene, ARegion *ar, int color_manage, int use_def
 		
 		glColor3ubv(blue);
 		if (fp)
-			BLI_snprintf(str, sizeof(str), "  B:%-.4f", fp[2]);
+			BLI_snprintf(str, sizeof(str), "  B:%-.5f", fp[2]);
 		else if (cp)
 			BLI_snprintf(str, sizeof(str), "  B:%-3d", cp[2]);
 		else
@@ -518,8 +587,8 @@ static void draw_image_buffer_tiled(SpaceImage *sima, ARegion *ar, Scene *scene,
 		sima->curtile = ima->xrep * ima->yrep - 1;
 	
 	/* retrieve part of image buffer */
-	dx = ibuf->x / ima->xrep;
-	dy = ibuf->y / ima->yrep;
+	dx = max_ii(ibuf->x / ima->xrep, 1);
+	dy = max_ii(ibuf->y / ima->yrep, 1);
 	sx = (sima->curtile % ima->xrep) * dx;
 	sy = (sima->curtile / ima->xrep) * dy;
 	rect = get_part_from_buffer((unsigned int *)display_buffer, ibuf->x, sx, sy, sx + dx, sy + dy);
@@ -786,7 +855,6 @@ void draw_image_main(const bContext *C, ARegion *ar)
 	if (sima->mode == SI_MODE_PAINT)
 		draw_image_paint_helpers(C, ar, scene, zoomx, zoomy);
 
-
 	/* XXX integrate this code */
 #if 0
 	if (ibuf) {
@@ -812,5 +880,5 @@ void draw_image_main(const bContext *C, ARegion *ar)
 
 	/* render info */
 	if (ima && show_render)
-		draw_render_info(scene, ima, ar);
+		draw_render_info(scene, ima, ar, zoomx, zoomy);
 }
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 0d0fdc6be1c..f1662bc254d 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -457,7 +457,7 @@ enum {
 
 static int image_view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
-	if (event->type == MOUSEZOOM) {
+	if (event->type == MOUSEZOOM || event->type == MOUSEPAN) {
 		SpaceImage *sima = CTX_wm_space_image(C);
 		ARegion *ar = CTX_wm_region(C);
 		float delta, factor, location[2];
@@ -1217,7 +1217,7 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
 			simopts->im_format.imtype = R_IMF_IMTYPE_PNG;
 		}
 		else {
-			simopts->im_format.imtype = BKE_ftype_to_imtype(ibuf->ftype);
+			BKE_imbuf_to_image_format(&simopts->im_format, ibuf);
 		}
 		//simopts->subimtype = scene->r.subimtype; /* XXX - this is lame, we need to make these available too! */
 		simopts->im_format.quality = ibuf->ftype & 0xff;
@@ -1434,7 +1434,7 @@ static int image_save_as_exec(bContext *C, wmOperator *op)
 static int image_save_as_check(bContext *UNUSED(C), wmOperator *op)
 {
 	ImageFormatData *imf = op->customdata;
-	return WM_operator_filesel_ensure_ext_imtype(op, imf->imtype);
+	return WM_operator_filesel_ensure_ext_imtype(op, imf);
 }
 
 static int image_save_as_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
@@ -1559,6 +1559,7 @@ static int image_save_exec(bContext *C, wmOperator *op)
 	Scene *scene = CTX_data_scene(C);
 	SaveImageOptions simopts;
 
+	save_image_options_defaults(&simopts);
 	if (save_image_options_init(&simopts, sima, scene, FALSE) == 0)
 		return OPERATOR_CANCELLED;
 	save_image_options_from_op(&simopts, op);
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index b0e9f8bcf99..9492e29734d 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -292,6 +292,7 @@ static void image_keymap(struct wmKeyConfig *keyconf)
 	WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_out", PADMINUS, KM_PRESS, 0, 0);
 	WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MIDDLEMOUSE, KM_PRESS, KM_CTRL, 0);
 	WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEZOOM, 0, 0, 0);
+	WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom", MOUSEPAN, 0, KM_CTRL, 0);
 
 	/* ctrl now works as well, shift + numpad works as arrow keys on Windows */
 	RNA_float_set(WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_ratio", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "ratio", 8.0f);
diff --git a/source/blender/editors/space_info/info_intern.h b/source/blender/editors/space_info/info_intern.h
index 80018e849d3..62e9a3a7f73 100644
--- a/source/blender/editors/space_info/info_intern.h
+++ b/source/blender/editors/space_info/info_intern.h
@@ -39,11 +39,15 @@ struct ReportList;
 
 void FILE_OT_pack_all(struct wmOperatorType *ot);
 void FILE_OT_unpack_all(struct wmOperatorType *ot);
+void FILE_OT_pack_libraries(struct wmOperatorType *ot);
+void FILE_OT_unpack_libraries(struct wmOperatorType *ot);
+
 void FILE_OT_make_paths_relative(struct wmOperatorType *ot);
 void FILE_OT_make_paths_absolute(struct wmOperatorType *ot);
 void FILE_OT_report_missing_files(struct wmOperatorType *ot);
 void FILE_OT_find_missing_files(struct wmOperatorType *ot);
 
+
 void INFO_OT_reports_display_update(struct wmOperatorType *ot);
 
 /* info_draw.c */
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index e902a4ea6f4..104349e172a 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -66,15 +66,70 @@
 
 #include "info_intern.h"
 
+/********************* pack blend file libararies operator *********************/
+
+static int pack_libraries_exec(bContext *C, wmOperator *op)
+{
+	Main *bmain = CTX_data_main(C);
+
+	packLibraries(bmain, op->reports);
+
+	return OPERATOR_FINISHED;
+}
+
+void FILE_OT_pack_libraries(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Pack Blender Libraries";
+	ot->idname = "FILE_OT_pack_libraries";
+	ot->description = "Pack all used Blender library files into the current .blend";
+	
+	/* api callbacks */
+	ot->exec = pack_libraries_exec;
+
+	/* flags */
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int unpack_libraries_exec(bContext *C, wmOperator *op)
+{
+	Main *bmain = CTX_data_main(C);
+	
+	unpackLibraries(bmain, op->reports);
+	
+	return OPERATOR_FINISHED;
+}
+
+static int unpack_libraries_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+	return WM_operator_confirm_message(C, op, "Unpack Blender Libraries - creates directories, all new paths should work");
+}
+
+void FILE_OT_unpack_libraries(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Unpack Blender Libraries";
+	ot->idname = "FILE_OT_unpack_libraries";
+	ot->description = "Unpack all used Blender library files from this .blend file";
+	
+	/* api callbacks */
+	ot->invoke = unpack_libraries_invoke;
+	ot->exec = unpack_libraries_exec;
+	
+	/* flags */
+	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
 /********************* pack all operator *********************/
 
 static int pack_all_exec(bContext *C, wmOperator *op)
 {
 	Main *bmain = CTX_data_main(C);
-
+	
 	packAll(bmain, op->reports);
 	G.fileflags |= G_AUTOPACK;
-
+	
 	return OPERATOR_FINISHED;
 }
 
@@ -83,7 +138,7 @@ static int pack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 	Main *bmain = CTX_data_main(C);
 	Image *ima;
 	ImBuf *ibuf;
-
+	
 	// first check for dirty images
 	for (ima = bmain->image.first; ima; ima = ima->id.next) {
 		if (ima->ibufs.first) { /* XXX FIX */
@@ -93,16 +148,16 @@ static int pack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 				BKE_image_release_ibuf(ima, ibuf, NULL);
 				break;
 			}
-
+			
 			BKE_image_release_ibuf(ima, ibuf, NULL);
 		}
 	}
-
+	
 	if (ima) {
 		uiPupMenuOkee(C, "FILE_OT_pack_all", "Some images are painted on. These changes will be lost. Continue?");
 		return OPERATOR_CANCELLED;
 	}
-
+	
 	return pack_all_exec(C, op);
 }
 
@@ -116,11 +171,12 @@ void FILE_OT_pack_all(wmOperatorType *ot)
 	/* api callbacks */
 	ot->exec = pack_all_exec;
 	ot->invoke = pack_all_invoke;
-
+	
 	/* flags */
 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+
 /********************* unpack all operator *********************/
 
 static const EnumPropertyItem unpack_all_method_items[] = {
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 5e5e0c87feb..3f73fc2605a 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -39,6 +39,7 @@
 #include "DNA_scene_types.h"
 
 #include "BLI_utildefines.h"
+#include "BLI_math.h"
 
 #include "BKE_anim.h"
 #include "BKE_blender.h"
@@ -47,6 +48,7 @@
 #include "BKE_DerivedMesh.h"
 #include "BKE_key.h"
 #include "BKE_mesh.h"
+#include "BKE_paint.h"
 #include "BKE_particle.h"
 #include "BKE_tessmesh.h"
 
@@ -62,7 +64,7 @@ typedef struct SceneStats {
 	int totbone, totbonesel;
 	int totobj,  totobjsel;
 	int totlamp, totlampsel; 
-	int tottri, totmesh, totcurve;
+	int tottri, totmesh;
 
 	char infostr[512];
 } SceneStats;
@@ -74,7 +76,7 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
 		{
 			/* we assume derivedmesh is already built, this strictly does stats now. */
 			DerivedMesh *dm = ob->derivedFinal;
-			int totvert, totedge, totface;
+			int totvert, totedge, totface, totloop;
 
 			stats->totmesh += totob;
 
@@ -82,10 +84,12 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
 				totvert = dm->getNumVerts(dm);
 				totedge = dm->getNumEdges(dm);
 				totface = dm->getNumPolys(dm);
+				totloop = dm->getNumLoops(dm);
 
 				stats->totvert += totvert * totob;
 				stats->totedge += totedge * totob;
 				stats->totface += totface * totob;
+				stats->tottri  += poly_to_tri_count(totface, totloop) * totob;
 
 				if (sel) {
 					stats->totvertsel += totvert;
@@ -103,40 +107,23 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
 		case OB_SURF:
 		case OB_CURVE:
 		case OB_FONT:
-		{
-			int tot = 0, totf = 0;
-
-			stats->totcurve += totob;
-
-			if (ob->disp.first)
-				BKE_displist_count(&ob->disp, &tot, &totf);
-
-			tot *= totob;
-			totf *= totob;
-
-			stats->totvert += tot;
-			stats->totface += totf;
-
-			if (sel) {
-				stats->totvertsel += tot;
-				stats->totfacesel += totf;
-			}
-			break;
-		}
 		case OB_MBALL:
 		{
-			int tot = 0, totf = 0;
+			int totv = 0, totf = 0, tottri = 0;
 
-			BKE_displist_count(&ob->disp, &tot, &totf);
+			if (ob->disp.first)
+				BKE_displist_count(&ob->disp, &totv, &totf, &tottri);
 
-			tot *= totob;
-			totf *= totob;
+			totv   *= totob;
+			totf   *= totob;
+			tottri *= totob;
 
-			stats->totvert += tot;
+			stats->totvert += totv;
 			stats->totface += totf;
+			stats->tottri  += tottri;
 
 			if (sel) {
-				stats->totvertsel += tot;
+				stats->totvertsel += totv;
 				stats->totfacesel += totf;
 			}
 			break;
@@ -260,6 +247,12 @@ static void stats_object_pose(Object *ob, SceneStats *stats)
 	}
 }
 
+static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats)
+{
+	stats->totvert = ob->sculpt->bm->totvert;
+	stats->tottri = ob->sculpt->bm->totface;
+}
+
 static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
 {
 	if (base->flag & SELECT) stats->totobjsel++;
@@ -319,6 +312,12 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats)
 	}
 }
 
+static int stats_is_object_dynamic_topology_sculpt(Object *ob)
+{
+	return (ob && (ob->mode & OB_MODE_SCULPT) &&
+	        ob->sculpt && ob->sculpt->bm);
+}
+
 /* Statistics displayed in info header. Called regularly on scene changes. */
 static void stats_update(Scene *scene)
 {
@@ -334,6 +333,10 @@ static void stats_update(Scene *scene)
 		/* Pose Mode */
 		stats_object_pose(ob, &stats);
 	}
+	else if (stats_is_object_dynamic_topology_sculpt(ob)) {
+		/* Dynamic-topology sculpt mode */
+		stats_object_sculpt_dynamic_topology(ob, &stats);
+	}
 	else {
 		/* Objects */
 		for (base = scene->base.first; base; base = base->next)
@@ -388,9 +391,12 @@ static void stats_string(Scene *scene)
 		s += sprintf(s, "Bones:%d/%d %s",
 		             stats->totbonesel, stats->totbone, memstr);
 	}
+	else if (stats_is_object_dynamic_topology_sculpt(ob)) {
+		s += sprintf(s, "Verts:%d | Tris:%d", stats->totvert, stats->tottri);
+	}
 	else {
-		s += sprintf(s, "Verts:%d | Faces:%d | Objects:%d/%d | Lamps:%d/%d%s",
-		             stats->totvert, stats->totface, stats->totobjsel, stats->totobj, stats->totlampsel, stats->totlamp, memstr);
+		s += sprintf(s, "Verts:%d | Faces:%d| Tris:%d | Objects:%d/%d | Lamps:%d/%d%s",
+		             stats->totvert, stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel, stats->totlamp, memstr);
 	}
 
 	if (ob)
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index db9be22eedb..60b04f7b029 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -178,7 +178,10 @@ static void info_main_area_draw(const bContext *C, ARegion *ar)
 static void info_operatortypes(void)
 {
 	WM_operatortype_append(FILE_OT_pack_all);
+	WM_operatortype_append(FILE_OT_pack_libraries);
 	WM_operatortype_append(FILE_OT_unpack_all);
+	WM_operatortype_append(FILE_OT_unpack_libraries);
+	
 	WM_operatortype_append(FILE_OT_make_paths_relative);
 	WM_operatortype_append(FILE_OT_make_paths_absolute);
 	WM_operatortype_append(FILE_OT_report_missing_files);
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 00745062582..a7599f21ad5 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -1006,7 +1006,7 @@ static void draw_sensor_actuator(uiLayout *layout, PointerRNA *ptr)
 
 static void draw_sensor_armature(uiLayout *layout, PointerRNA *ptr)
 {
-	bSensor *sens = (bSensor*)ptr->data;
+	bSensor *sens = (bSensor *)ptr->data;
 	bArmatureSensor *as = (bArmatureSensor *) sens->data;
 	Object *ob = (Object *)ptr->id.data;
 	PointerRNA pose_ptr, pchan_ptr;
@@ -1476,7 +1476,7 @@ static void draw_actuator_action(uiLayout *layout, PointerRNA *ptr)
 
 static void draw_actuator_armature(uiLayout *layout, PointerRNA *ptr)
 {
-	bActuator *act = (bActuator*)ptr->data;
+	bActuator *act = (bActuator *)ptr->data;
 	bArmatureActuator *aa = (bArmatureActuator *) act->data;
 	Object *ob = (Object *)ptr->id.data;
 	bConstraint *constraint = NULL;
diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c
index 4cd53215697..8795d655e77 100644
--- a/source/blender/editors/space_logic/space_logic.c
+++ b/source/blender/editors/space_logic/space_logic.c
@@ -148,7 +148,7 @@ static SpaceLink *logic_new(const bContext *C)
 /* not spacelink itself */
 static void logic_free(SpaceLink *UNUSED(sl))
 {	
-//	Spacelogic *slogic= (SpaceLogic*) sl;
+//	Spacelogic *slogic= (SpaceLogic *) sl;
 	
 //	if (slogic->gpd)
 // XXX		BKE_gpencil_free(slogic->gpd);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 59dd66a0207..8797cb4a459 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -399,8 +399,8 @@ static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA
 
 static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
-	bNodeTree *ntree = (bNodeTree*)ptr->id.data;
-	bNode *node = (bNode*)ptr->data;
+	bNodeTree *ntree = (bNodeTree *)ptr->id.data;
+	bNode *node = (bNode *)ptr->data;
 	bNodeSocket *sock = node->outputs.first;     /* first socket stores normal */
 	PointerRNA sockptr;
 
@@ -2152,12 +2152,12 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C
 	active_index = RNA_int_get(ptr, "active_input_index");
 	/* using different collection properties if multilayer format is enabled */
 	if (multilayer) {
-		uiTemplateList(col, C, ptr, "layer_slots", ptr, "active_input_index", NULL, 0, 0, 0);
+		uiTemplateList(col, C, "UI_UL_list", "", ptr, "layer_slots", ptr, "active_input_index", 0, 0, 0);
 		RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"),
 		                                   active_index, &active_input_ptr);
 	}
 	else {
-		uiTemplateList(col, C, ptr, "file_slots", ptr, "active_input_index", NULL, 0, 0, 0);
+		uiTemplateList(col, C, "UI_UL_list", "", ptr, "file_slots", ptr, "active_input_index", 0, 0, 0);
 		RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"),
 		                                   active_index, &active_input_ptr);
 	}
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index f386657c460..492ff0dcbd4 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -69,12 +69,15 @@ static int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, cons
 	bNode *node;
 	rctf cur_new;
 	float oldwidth, oldheight, width, height;
+	float oldasp, asp;
 	int tot = 0;
 	int has_frame = FALSE;
 	
 	oldwidth  = BLI_rctf_size_x(&ar->v2d.cur);
 	oldheight = BLI_rctf_size_y(&ar->v2d.cur);
 
+	oldasp = oldwidth / oldheight;
+
 	BLI_rctf_init_minmax(&cur_new);
 
 	if (snode->edittree) {
@@ -93,6 +96,7 @@ static int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, cons
 	if (tot) {
 		width  = BLI_rctf_size_x(&cur_new);
 		height = BLI_rctf_size_y(&cur_new);
+		asp = width / height;
 
 		/* for single non-frame nodes, don't zoom in, just pan view,
 		 * but do allow zooming out, this allows for big nodes to be zoomed out */
@@ -104,17 +108,15 @@ static int space_node_view_flag(bContext *C, SpaceNode *snode, ARegion *ar, cons
 			BLI_rctf_resize(&cur_new, oldwidth, oldheight);
 		}
 		else {
-			if (width > height) {
-				float newheight;
-				newheight = oldheight * width / oldwidth;
-				cur_new.ymin = cur_new.ymin - newheight / 4;
-				cur_new.ymax = cur_new.ymax + newheight / 4;
+			if (oldasp < asp) {
+				const float height_new = width / oldasp;
+				cur_new.ymin = cur_new.ymin - height_new / 2.0f;
+				cur_new.ymax = cur_new.ymax + height_new / 2.0f;
 			}
 			else {
-				float newwidth;
-				newwidth = oldwidth * height / oldheight;
-				cur_new.xmin = cur_new.xmin - newwidth / 4;
-				cur_new.xmax = cur_new.xmax + newwidth / 4;
+				const float width_new = height * oldasp;
+				cur_new.xmin = cur_new.xmin - width_new / 2.0f;
+				cur_new.xmax = cur_new.xmax + width_new / 2.0f;
 			}
 		}
 
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 6913ebc8a11..1a058104c78 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -421,17 +421,17 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
 				
 				uiBlockSetEmboss(block, UI_EMBOSSN);
 				bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_VIEW_OFF,
-				                   (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                   (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
 				                   &ptr, "hide", -1, 0, 0, -1, -1, NULL);
 				uiButSetFunc(bt, restrictbutton_view_cb, scene, ob);
 				
 				bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_SELECT_OFF,
-				                   (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                   (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
 				                   &ptr, "hide_select", -1, 0, 0, -1, -1, NULL);
 				uiButSetFunc(bt, restrictbutton_sel_cb, scene, ob);
 				
 				bt = uiDefIconButR(block, ICONTOG, 0, ICON_RESTRICT_RENDER_OFF,
-				                   (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                   (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
 				                   &ptr, "hide_render", -1, 0, 0, -1, -1, NULL);
 				uiButSetFunc(bt, restrictbutton_rend_cb, scene, ob);
 				
@@ -445,15 +445,21 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
 				uiBlockSetEmboss(block, UI_EMBOSSN);
 
 				restrict_bool = group_restrict_flag(gr, OB_RESTRICT_VIEW);
-				bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF, (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
+				bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_VIEW_ON : ICON_RESTRICT_VIEW_OFF,
+				                  (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                  NULL, 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
 				uiButSetFunc(bt, restrictbutton_gr_restrict_view, scene, gr);
 
 				restrict_bool = group_restrict_flag(gr, OB_RESTRICT_SELECT);
-				bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF, (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
+				bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_SELECT_ON : ICON_RESTRICT_SELECT_OFF,
+				                  (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                  NULL, 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
 				uiButSetFunc(bt, restrictbutton_gr_restrict_select, scene, gr);
 
 				restrict_bool = group_restrict_flag(gr, OB_RESTRICT_RENDER);
-				bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF, (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, "Restrict/Allow renderability");
+				bt = uiDefIconBut(block, ICONTOG, 0, restrict_bool ? ICON_RESTRICT_RENDER_ON : ICON_RESTRICT_RENDER_OFF,
+				                  (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                  NULL, 0, 0, 0, 0, "Restrict/Allow renderability");
 				uiButSetFunc(bt, restrictbutton_gr_restrict_render, scene, gr);
 
 				uiBlockSetEmboss(block, UI_EMBOSS);
@@ -463,7 +469,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
 				uiBlockSetEmboss(block, UI_EMBOSSN);
 				
 				bt = uiDefIconButBitI(block, ICONTOGN, SCE_LAY_DISABLE, 0, ICON_CHECKBOX_HLT - 1,
-				                      (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, te->directdata, 0, 0, 0, 0, "Render this RenderLayer");
+				                      (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                      te->directdata, 0, 0, 0, 0, "Render this RenderLayer");
 				uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
 				
 				uiBlockSetEmboss(block, UI_EMBOSS);
@@ -476,13 +483,18 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
 				
 				
 				bt = uiDefIconButBitI(block, ICONTOG, passflag, 0, ICON_CHECKBOX_HLT - 1,
-				                      (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, layflag, 0, 0, 0, 0, "Render this Pass");
+				                      (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                      layflag, 0, 0, 0, 0, "Render this Pass");
 				uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
 				
 				layflag++;  /* is lay_xor */
-				if (ELEM8(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT, SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT))
+				if (ELEM8(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT,
+				          SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT))
+				{
 					bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
-					                      (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, layflag, 0, 0, 0, 0, "Exclude this Pass from Combined");
+					                      (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+					                      layflag, 0, 0, 0, 0, "Exclude this Pass from Combined");
+				}
 				uiButSetFunc(bt, restrictbutton_r_lay_cb, tselem->id, NULL);
 				
 				uiBlockSetEmboss(block, UI_EMBOSS);
@@ -493,11 +505,13 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
 				
 				uiBlockSetEmboss(block, UI_EMBOSSN);
 				bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Realtime, 0, ICON_RESTRICT_VIEW_OFF,
-				                      (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
+				                      (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                      &(md->mode), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
 				uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob);
 				
 				bt = uiDefIconButBitI(block, ICONTOGN, eModifierMode_Render, 0, ICON_RESTRICT_RENDER_OFF,
-				                      (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability");
+				                      (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                      &(md->mode), 0, 0, 0, 0, "Restrict/Allow renderability");
 				uiButSetFunc(bt, restrictbutton_modifier_cb, scene, ob);
 			}
 			else if (tselem->type == TSE_POSE_CHANNEL) {
@@ -506,11 +520,13 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
 				
 				uiBlockSetEmboss(block, UI_EMBOSSN);
 				bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_P, 0, ICON_RESTRICT_VIEW_OFF,
-				                      (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
+				                      (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                      &(bone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
 				uiButSetFunc(bt, restrictbutton_bone_cb, NULL, bone);
 				
 				bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
-				                      (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
+				                      (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                      &(bone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
 				uiButSetFunc(bt, restrictbutton_bone_cb, NULL, NULL);
 			}
 			else if (tselem->type == TSE_EBONE) {
@@ -518,11 +534,13 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
 				
 				uiBlockSetEmboss(block, UI_EMBOSSN);
 				bt = uiDefIconButBitI(block, ICONTOG, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF,
-				                      (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
+				                      (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                      &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
 				uiButSetFunc(bt, restrictbutton_ebone_cb, NULL, ebone);
 				
 				bt = uiDefIconButBitI(block, ICONTOG, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF,
-				                      (int)ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX, (int)te->ys, UI_UNIT_X, UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
+				                      (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)te->ys, UI_UNIT_X, UI_UNIT_Y,
+				                      &(ebone->flag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
 				uiButSetFunc(bt, restrictbutton_ebone_cb, NULL, NULL);
 			}
 		}
@@ -535,7 +553,7 @@ static void outliner_draw_rnacols(ARegion *ar, int sizex)
 {
 	View2D *v2d = &ar->v2d;
 
-	float miny = v2d->cur.ymin - V2D_SCROLL_HEIGHT;
+	float miny = v2d->cur.ymin;
 	if (miny < v2d->tot.ymin) miny = v2d->tot.ymin;
 
 	UI_ThemeColorShadeAlpha(TH_BACK, -15, -200);
@@ -832,7 +850,7 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo
 				
 				/* rna property */
 				if (kmi->ptr && kmi->ptr->data) {
-					uiDefBut(block, LABEL, 0, "(RNA property)", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, &kmi->oskey, 0, 0, 0, 0, ""); xstart += butw2;
+					uiDefBut(block, LABEL, 0, "(RNA property)", xstart, (int)te->ys + 1, butw2, UI_UNIT_Y - 1, NULL, 0, 0, 0, 0, ""); xstart += butw2;
 				}
 
 				(void)xstart;
@@ -1515,13 +1533,13 @@ static void outliner_draw_struct_marks(ARegion *ar, SpaceOops *soops, ListBase *
 		/* selection status */
 		if (TSELEM_OPEN(tselem, soops))
 			if (tselem->type == TSE_RNA_STRUCT)
-				glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, *starty + UI_UNIT_Y - 1);
+				glRecti(0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1);
 
 		*starty -= UI_UNIT_Y;
 		if (TSELEM_OPEN(tselem, soops)) {
 			outliner_draw_struct_marks(ar, soops, &te->subtree, starty);
 			if (tselem->type == TSE_RNA_STRUCT)
-				fdrawline(0, (float)*starty + UI_UNIT_Y, ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, (float)*starty + UI_UNIT_Y);
+				fdrawline(0, (float)*starty + UI_UNIT_Y, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y);
 		}
 	}
 }
@@ -1590,7 +1608,7 @@ static void outliner_back(ARegion *ar)
 	ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET;
 	
 	while (ystart + 2 * UI_UNIT_Y > ar->v2d.cur.ymin) {
-		glRecti(0, ystart, (int)ar->v2d.cur.xmax + V2D_SCROLL_WIDTH, ystart + UI_UNIT_Y);
+		glRecti(0, ystart, (int)ar->v2d.cur.xmax, ystart + UI_UNIT_Y);
 		ystart -= 2 * UI_UNIT_Y;
 	}
 }
@@ -1601,10 +1619,8 @@ static void outliner_draw_restrictcols(ARegion *ar)
 	
 	/* background underneath */
 	UI_ThemeColor(TH_BACK);
-	glRecti((int)ar->v2d.cur.xmax - OL_TOGW,
-	        (int)ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT - 1,
-	        (int)ar->v2d.cur.xmax + V2D_SCROLL_WIDTH,
-	        (int)ar->v2d.cur.ymax);
+	glRecti((int)(ar->v2d.cur.xmax - OL_TOGW),
+	        (int)(ar->v2d.cur.ymin - 1), (int)ar->v2d.cur.xmax, (int)ar->v2d.cur.ymax);
 	
 	UI_ThemeColorShade(TH_BACK, 6);
 	ystart = (int)ar->v2d.tot.ymax;
@@ -1618,22 +1634,22 @@ static void outliner_draw_restrictcols(ARegion *ar)
 	UI_ThemeColorShadeAlpha(TH_BACK, -15, -200);
 
 	/* view */
-	fdrawline(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX,
-	          ar->v2d.cur.ymax,
-	          ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX,
-	          ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT);
+	sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX),
+	          (int)ar->v2d.cur.ymax,
+	          (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX),
+	          (int)ar->v2d.cur.ymin);
 
 	/* render */
-	fdrawline(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX,
-	          ar->v2d.cur.ymax,
-	          ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX,
-	          ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT);
+	sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX),
+	          (int)ar->v2d.cur.ymax,
+	          (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX),
+	          (int)ar->v2d.cur.ymin);
 
 	/* render */
-	fdrawline(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX,
-	          ar->v2d.cur.ymax,
-	          ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX,
-	          ar->v2d.cur.ymin - V2D_SCROLL_HEIGHT);
+	sdrawline((int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX),
+	          (int)ar->v2d.cur.ymax,
+	          (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX),
+	          (int)ar->v2d.cur.ymin);
 }
 
 /* ****************************************************** */
@@ -1682,11 +1698,9 @@ void draw_outliner(const bContext *C)
 		// XXX this isn't that great yet...
 		if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0)
 			sizex += OL_TOGW * 3;
+		
 	}
 	
-	/* tweak to display last line (when list bigger than window) */
-	sizey += V2D_SCROLL_HEIGHT;
-	
 	/* adds vertical offset */
 	sizey += OL_Y_OFFSET;
 
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index f9fca378568..63452de18d0 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -116,8 +116,8 @@ typedef struct TreeElement {
 /* size constants */
 #define OL_Y_OFFSET 2
 
-#define OL_TOG_RESTRICT_VIEWX   (UI_UNIT_X * 3)
-#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2)
+#define OL_TOG_RESTRICT_VIEWX   (UI_UNIT_X * 3.0f)
+#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2.0f)
 #define OL_TOG_RESTRICT_RENDERX UI_UNIT_X
 
 #define OL_TOGW OL_TOG_RESTRICT_VIEWX
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index ddbc49bf995..f723fbedc7b 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -803,8 +803,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
 	}
 
 	/* One exception */
-	if (type == TSE_ID_BASE);
-	else if (id == NULL) return NULL;
+	if (type == TSE_ID_BASE) {
+		/* pass */
+	}
+	else if (id == NULL) {
+		return NULL;
+	}
 
 	te = MEM_callocN(sizeof(TreeElement), "tree elem");
 	/* add to the visual tree */
@@ -832,7 +836,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
 		/* pass */
 	}
 	else {
-		te->name = id->name + 2; // default, can be overridden by Library or non-ID data
+		/* do here too, for blend file viewer, own ID_LI then shows file name */
+		if (GS(id->name) == ID_LI)
+			te->name = ((Library *)id)->name;
+		else
+			te->name = id->name + 2; // default, can be overridden by Library or non-ID data
 		te->idcode = GS(id->name);
 	}
 	
@@ -840,7 +848,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
 		TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL;
 		
 		/* ID datablock */
-		if (tsepar==NULL || tsepar->type != TSE_ID_BASE)
+		if (tsepar == NULL || tsepar->type != TSE_ID_BASE)
 			outliner_add_id_contents(soops, te, tselem, id);
 	}
 	else if (type == TSE_ANIM_DATA) {
@@ -1511,7 +1519,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops)
 		}
 		/* make hierarchy */
 		ten = soops->tree.first;
-		ten= ten->next; /* first one is main */
+		ten = ten->next;  /* first one is main */
 		while (ten) {
 			TreeElement *nten = ten->next, *par;
 			tselem = TREESTORE(ten);
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index ecc09a35670..4bf88376b74 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -67,6 +67,17 @@ static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar)
 	ListBase *lb;
 	wmKeyMap *keymap;
 	
+	/* make sure we keep the hide flags */
+	ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
+	ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP);	/* prevent any noise of past */
+	ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
+	ar->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE;
+
+	ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
+	ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
+	ar->v2d.keeptot = V2D_KEEPTOT_STRICT;
+	ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f;
+
 	UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
 	
 	/* own keymap */
@@ -410,12 +421,6 @@ static SpaceLink *outliner_new(const bContext *UNUSED(C))
 	BLI_addtail(&soutliner->regionbase, ar);
 	ar->regiontype = RGN_TYPE_WINDOW;
 	
-	ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM_O);
-	ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
-	ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT);
-	ar->v2d.keeptot = V2D_KEEPTOT_STRICT;
-	ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f;
-	
 	return (SpaceLink *)soutliner;
 }
 
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 6219a9061f4..29a6a1f6d50 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -49,6 +49,8 @@
 #include "DNA_mask_types.h"
 #include "DNA_userdef_types.h"
 
+#include "BLF_translation.h"
+
 #include "BKE_context.h"
 #include "BKE_global.h"
 #include "BKE_library.h"
@@ -400,6 +402,7 @@ void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot)
 	sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
 	prop = RNA_def_enum(ot->srna, "clip", DummyRNA_NULL_items, 0, "Clip", "");
 	RNA_def_enum_funcs(prop, RNA_movieclip_itemf);
+	RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_MOVIECLIP);
 	ot->prop = prop;
 }
 
@@ -871,7 +874,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
 		if (BKE_sequence_test_overlap(ed->seqbasep, seq)) BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
 	}
 
-	BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* runs calc_sequence */
+	BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* runs BKE_sequence_calc */
 
 
 	/* not sure if this is needed with update_changed_seq_and_deps.
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 409f655bb79..c6c70ccb424 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -925,7 +925,7 @@ static void set_filter_seq(Scene *scene)
 			if (seq->type == SEQ_TYPE_MOVIE) {
 				seq->flag |= SEQ_FILTERY;
 				reload_sequence_new_file(scene, seq, FALSE);
-				calc_sequence(scene, seq);
+				BKE_sequence_calc(scene, seq);
 			}
 
 		}
@@ -1906,6 +1906,9 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
 		for (seq = ed->seqbasep->first; seq; seq = seq->next)
 			BKE_sequence_calc(scene, seq);
 
+		if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq))
+			BKE_sequence_base_shuffle(ed->seqbasep, ms->parseq, scene);
+
 		BKE_sequencer_active_set(scene, ms->parseq);
 
 		ms->parseq->flag |= SELECT;
diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt
index 6aaf4212779..a33a9abada1 100644
--- a/source/blender/editors/space_text/CMakeLists.txt
+++ b/source/blender/editors/space_text/CMakeLists.txt
@@ -36,12 +36,13 @@ set(INC_SYS
 
 set(SRC
 	space_text.c
+	text_autocomplete.c
 	text_draw.c
 	text_format.c
+	text_format_osl.c
 	text_format_py.c
 	text_header.c
 	text_ops.c
-	text_python.c
 
 	text_format.h
 	text_intern.h
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 9ac66ca1698..fa3eefcc0f7 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -223,6 +223,8 @@ static void text_operatortypes(void)
 	WM_operatortype_append(TEXT_OT_to_3d_object);
 
 	WM_operatortype_append(TEXT_OT_resolve_conflict);
+
+	WM_operatortype_append(TEXT_OT_autocomplete);
 }
 
 static void text_keymap(struct wmKeyConfig *keyconf)
@@ -276,7 +278,7 @@ static void text_keymap(struct wmKeyConfig *keyconf)
 	kmi = WM_keymap_add_item(keymap, "WM_OT_context_cycle_int", PADMINUS, KM_PRESS, KM_CTRL, 0);
 	RNA_string_set(kmi->ptr, "data_path", "space_data.font_size");
 	RNA_boolean_set(kmi->ptr, "reverse", TRUE);
-	
+
 	WM_keymap_add_item(keymap, "TEXT_OT_new", NKEY, KM_PRESS, KM_CTRL, 0);
 	WM_keymap_add_item(keymap, "TEXT_OT_open", OKEY, KM_PRESS, KM_ALT, 0);
 	WM_keymap_add_item(keymap, "TEXT_OT_reload", RKEY, KM_PRESS, KM_ALT, 0);
@@ -375,6 +377,8 @@ static void text_keymap(struct wmKeyConfig *keyconf)
 	WM_keymap_add_item(keymap, "TEXT_OT_line_break", PADENTER, KM_PRESS, 0, 0);
 
 	WM_keymap_add_menu(keymap, "TEXT_MT_toolbox", RIGHTMOUSE, KM_PRESS, KM_ANY, 0);
+
+	WM_keymap_add_item(keymap, "TEXT_OT_autocomplete", SPACEKEY, KM_PRESS, KM_CTRL, 0);
 	
 	WM_keymap_add_item(keymap, "TEXT_OT_line_number", KM_TEXTINPUT, KM_ANY, KM_ANY, 0);
 	WM_keymap_add_item(keymap, "TEXT_OT_insert", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); // last!
@@ -555,5 +559,6 @@ void ED_spacetype_text(void)
 
 	/* register formatters */
 	ED_text_format_register_py();
+	ED_text_format_register_osl();
 }
 
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
new file mode 100644
index 00000000000..e406a1b7166
--- /dev/null
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -0,0 +1,541 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_text/text_autocomplete.c
+ *  \ingroup sptext
+ */
+
+#include 
+#include 
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_text_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+
+#include "BKE_context.h"
+#include "BKE_text.h"
+#include "BKE_screen.h"
+#include "BKE_suggestions.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "UI_interface.h"
+
+#include "text_format.h"
+#include "text_intern.h"  /* own include */
+
+
+/* -------------------------------------------------------------------- */
+/* Public API */
+
+int text_do_suggest_select(SpaceText *st, ARegion *ar)
+{
+	SuggItem *item, *first, *last /* , *sel */ /* UNUSED */;
+	TextLine *tmp;
+	int l, x, y, w, h, i;
+	int tgti, *top;
+	int mval[2] = {0, 0};
+
+	if (!st || !st->text) return 0;
+	if (!texttool_text_is_active(st->text)) return 0;
+
+	first = texttool_suggest_first();
+	last = texttool_suggest_last();
+	/* sel = texttool_suggest_selected(); */ /* UNUSED */
+	top = texttool_suggest_top();
+
+	if (!last || !first)
+		return 0;
+
+	/* Count the visible lines to the cursor */
+	for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ;
+	if (l < 0) return 0;
+
+	text_update_character_width(st);
+
+	if (st->showlinenrs) {
+		x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET + TEXTXLOC - 4;
+	}
+	else {
+		x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4;
+	}
+	y = ar->winy - st->lheight_dpi * l - 2;
+
+	w = SUGG_LIST_WIDTH * st->cwidth + U.widget_unit;
+	h = SUGG_LIST_SIZE * st->lheight_dpi + 0.4f * U.widget_unit;
+
+	// XXX getmouseco_areawin(mval);
+
+	if (mval[0] < x || x + w < mval[0] || mval[1] < y - h || y < mval[1])
+		return 0;
+
+	/* Work out which of the items is at the top of the visible list */
+	for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ;
+
+	/* Work out the target item index in the visible list */
+	tgti = (y - mval[1] - 4) / st->lheight_dpi;
+	if (tgti < 0 || tgti > SUGG_LIST_SIZE)
+		return 1;
+
+	for (i = tgti; i > 0 && item->next; i--, item = item->next) ;
+	if (item)
+		texttool_suggest_select(item);
+	return 1;
+}
+
+void text_pop_suggest_list(void)
+{
+	SuggItem *item, *sel;
+	int *top, i;
+
+	item = texttool_suggest_first();
+	sel = texttool_suggest_selected();
+	top = texttool_suggest_top();
+
+	i = 0;
+	while (item && item != sel) {
+		item = item->next;
+		i++;
+	}
+	if (i > *top + SUGG_LIST_SIZE - 1)
+		*top = i - SUGG_LIST_SIZE + 1;
+	else if (i < *top)
+		*top = i;
+}
+
+/* -------------------------------------------------------------------- */
+/* Private API */
+
+static void text_autocomplete_free(bContext *C, wmOperator *op);
+
+static GHash *text_autocomplete_build(Text *text)
+{
+	GHash *gh;
+	int seek_len = 0;
+	const char *seek;
+	texttool_text_clear();
+
+	texttool_text_set_active(text);
+
+	/* first get the word we're at */
+	{
+		const int i = text_find_identifier_start(text->curl->line, text->curc);
+		seek_len = text->curc - i;
+		seek = text->curl->line + i;
+
+		// BLI_strncpy(seek, seek_ptr, seek_len);
+	}
+
+	/* now walk over entire doc and suggest words */
+	{
+		TextLine *linep;
+
+		gh = BLI_ghash_str_new(__func__);
+
+		for (linep = text->lines.first; linep; linep = linep->next) {
+			int i_start = 0;
+			int i_end = 0;
+
+			while (i_start < linep->len) {
+				/* seek identifier beginning */
+				while (i_start < linep->len && !text_check_identifier(linep->line[i_start])) {
+					i_start++;
+				}
+				i_end = i_start;
+				while (i_end < linep->len && text_check_identifier(linep->line[i_end])) {
+					i_end++;
+				}
+
+				if (i_start != i_end) {
+					char *str_sub = &linep->line[i_start];
+					const int choice_len = i_end - i_start;
+
+					if ((choice_len > seek_len) &&
+					    (seek_len == 0 || strncmp(seek, str_sub, seek_len) == 0) &&
+					    (seek != str_sub))
+					{
+						// printf("Adding: %s\n", s);
+						char str_sub_last = str_sub[choice_len];
+						str_sub[choice_len] = '\0';
+						if (!BLI_ghash_lookup(gh, str_sub)) {
+							char *str_dup = BLI_strdupn(str_sub, choice_len);
+							BLI_ghash_insert(gh, str_dup, str_dup);  /* A 'set' would make more sense here */
+						}
+						str_sub[choice_len] = str_sub_last;
+					}
+				}
+				i_start = i_end;
+			}
+		}
+
+		{
+			GHashIterator *iter = BLI_ghashIterator_new(gh);
+
+			/* get the formatter for highlighting */
+			TextFormatType *tft;
+			tft = ED_text_format_get(text);
+
+			for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
+				const char *s = BLI_ghashIterator_getValue(iter);
+				texttool_suggest_add(s, tft->format_identifier(s));
+			}
+			BLI_ghashIterator_free(iter);
+
+		}
+	}
+
+	texttool_suggest_prefix(seek, seek_len);
+
+	return gh;
+}
+
+/* -- */
+
+static void get_suggest_prefix(Text *text, int offset)
+{
+	int i, len;
+	char *line;
+
+	if (!text) return;
+	if (!texttool_text_is_active(text)) return;
+
+	line = text->curl->line;
+	i = text_find_identifier_start(line, text->curc + offset);
+	len = text->curc - i + offset;
+	texttool_suggest_prefix(line + i, len);
+}
+
+static void confirm_suggestion(Text *text)
+{
+	SuggItem *sel;
+	int i, over = 0;
+	const char *line;
+
+	if (!text) return;
+	if (!texttool_text_is_active(text)) return;
+
+	sel = texttool_suggest_selected();
+	if (!sel) return;
+
+	line = text->curl->line;
+	i = text_find_identifier_start(line, text->curc /* - skipleft */);
+	over = text->curc - i;
+
+//	for (i = 0; i < skipleft; i++)
+//		txt_move_left(text, 0);
+	for (i = 0; i < over; i++)
+		txt_move_left(text, 1);
+
+	txt_insert_buf(text, sel->name);
+
+//	for (i = 0; i < skipleft; i++)
+//		txt_move_right(text, 0);
+
+	texttool_text_clear();
+}
+
+/* -- */
+
+
+static int text_autocomplete_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+	SpaceText *st = CTX_wm_space_text(C);
+	Text *text = CTX_data_edit_text(C);
+
+	st->doplugins = TRUE;
+	op->customdata = text_autocomplete_build(text);
+
+	if (texttool_suggest_first()) {
+
+		ED_area_tag_redraw(CTX_wm_area(C));
+
+		if (texttool_suggest_first() == texttool_suggest_last()) {
+			confirm_suggestion(st->text);
+			text_update_line_edited(st->text->curl);
+			text_autocomplete_free(C, op);
+			return OPERATOR_FINISHED;
+		}
+		else {
+			WM_event_add_modal_handler(C, op);
+			return OPERATOR_RUNNING_MODAL;
+		}
+	}
+	else {
+		text_autocomplete_free(C, op);
+		return OPERATOR_CANCELLED;
+	}
+}
+
+static int doc_scroll = 0;
+
+static int text_autocomplete_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+	SpaceText *st = CTX_wm_space_text(C);
+	ScrArea *sa = CTX_wm_area(C);
+	ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+
+	int draw = 0, tools = 0, swallow = 0, scroll = 1;
+	Text *text = CTX_data_edit_text(C);
+	int retval = OPERATOR_RUNNING_MODAL;
+
+	(void)text;
+
+	if (st->doplugins && texttool_text_is_active(st->text)) {
+		if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST;
+		if (texttool_docs_get()) tools |= TOOL_DOCUMENT;
+	}
+
+	switch (event->type) {
+		case LEFTMOUSE:
+			if (event->val == KM_PRESS) {
+				if (text_do_suggest_select(st, ar))
+					swallow = 1;
+				else {
+					if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
+					if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
+					retval = OPERATOR_FINISHED;
+				}
+				draw = 1;
+			}
+			break;
+		case MIDDLEMOUSE:
+			if (event->val == KM_PRESS) {
+				if (text_do_suggest_select(st, ar)) {
+					confirm_suggestion(st->text);
+					text_update_line_edited(st->text->curl);
+					swallow = 1;
+				}
+				else {
+					if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
+					if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
+					retval = OPERATOR_FINISHED;
+				}
+				draw = 1;
+			}
+			break;
+		case ESCKEY:
+			if (event->val == KM_PRESS) {
+				draw = swallow = 1;
+				if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
+				else if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
+				else draw = swallow = 0;
+				retval = OPERATOR_CANCELLED;
+			}
+			break;
+		case RETKEY:
+			if (event->val == KM_PRESS) {
+				if (tools & TOOL_SUGG_LIST) {
+					confirm_suggestion(st->text);
+					text_update_line_edited(st->text->curl);
+					swallow = 1;
+					draw = 1;
+				}
+				if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1;
+				retval = OPERATOR_FINISHED;
+			}
+			break;
+		case LEFTARROWKEY:
+		case BACKSPACEKEY:
+			if (event->val == KM_PRESS) {
+				if (tools & TOOL_SUGG_LIST) {
+					if (event->ctrl) {
+						texttool_suggest_clear();
+						retval = OPERATOR_CANCELLED;
+					}
+					else {
+						/* Work out which char we are about to delete/pass */
+						if (st->text->curl && st->text->curc > 0) {
+							char ch = st->text->curl->line[st->text->curc - 1];
+							if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
+								get_suggest_prefix(st->text, -1);
+								text_pop_suggest_list();
+							}
+							else {
+								texttool_suggest_clear();
+								retval = OPERATOR_CANCELLED;
+							}
+						}
+						else {
+							texttool_suggest_clear();
+							retval = OPERATOR_CANCELLED;
+						}
+					}
+				}
+				if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
+			}
+			break;
+		case RIGHTARROWKEY:
+			if (event->val == KM_PRESS) {
+				if (tools & TOOL_SUGG_LIST) {
+					if (event->ctrl) {
+						texttool_suggest_clear();
+						retval = OPERATOR_CANCELLED;
+					}
+					else {
+						/* Work out which char we are about to pass */
+						if (st->text->curl && st->text->curc < st->text->curl->len) {
+							char ch = st->text->curl->line[st->text->curc + 1];
+							if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
+								get_suggest_prefix(st->text, 1);
+								text_pop_suggest_list();
+							}
+							else {
+								texttool_suggest_clear();
+								retval = OPERATOR_CANCELLED;
+							}
+						}
+						else {
+							texttool_suggest_clear();
+							retval = OPERATOR_CANCELLED;
+						}
+					}
+				}
+				if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
+			}
+			break;
+		case PAGEDOWNKEY:
+			scroll = SUGG_LIST_SIZE - 1;
+		case WHEELDOWNMOUSE:
+		case DOWNARROWKEY:
+			if (event->val == KM_PRESS) {
+				if (tools & TOOL_DOCUMENT) {
+					doc_scroll++;
+					swallow = 1;
+					draw = 1;
+				}
+				else if (tools & TOOL_SUGG_LIST) {
+					SuggItem *sel = texttool_suggest_selected();
+					if (!sel) {
+						texttool_suggest_select(texttool_suggest_first());
+					}
+					else {
+						while (sel && sel != texttool_suggest_last() && sel->next && scroll--) {
+							texttool_suggest_select(sel->next);
+							sel = sel->next;
+						}
+					}
+					text_pop_suggest_list();
+					swallow = 1;
+					draw = 1;
+				}
+			}
+			break;
+		case PAGEUPKEY:
+			scroll = SUGG_LIST_SIZE - 1;
+		case WHEELUPMOUSE:
+		case UPARROWKEY:
+			if (event->val == KM_PRESS) {
+				if (tools & TOOL_DOCUMENT) {
+					if (doc_scroll > 0) doc_scroll--;
+					swallow = 1;
+					draw = 1;
+				}
+				else if (tools & TOOL_SUGG_LIST) {
+					SuggItem *sel = texttool_suggest_selected();
+					while (sel && sel != texttool_suggest_first() && sel->prev && scroll--) {
+						texttool_suggest_select(sel->prev);
+						sel = sel->prev;
+					}
+					text_pop_suggest_list();
+					swallow = 1;
+					draw = 1;
+				}
+			}
+			break;
+		case RIGHTSHIFTKEY:
+		case LEFTSHIFTKEY:
+			break;
+#if 0
+		default:
+			if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw = 1;
+			if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1;
+#endif
+	}
+
+	if (draw) {
+		ED_area_tag_redraw(CTX_wm_area(C));
+	}
+
+//	if (swallow) {
+//		retval = OPERATOR_RUNNING_MODAL;
+//	}
+
+	if (texttool_suggest_first()) {
+		if (retval != OPERATOR_RUNNING_MODAL) {
+			text_autocomplete_free(C, op);
+		}
+		return retval;
+	}
+	else {
+		text_autocomplete_free(C, op);
+		return OPERATOR_FINISHED;
+	}
+}
+
+static void text_autocomplete_free(bContext *C, wmOperator *op)
+{
+	GHash *gh = op->customdata;
+	if (gh) {
+		BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
+		op->customdata = NULL;
+	}
+
+	/* other stuff */
+	{
+		SpaceText *st = CTX_wm_space_text(C);
+		st->doplugins = FALSE;
+		texttool_text_clear();
+	}
+}
+
+static int text_autocomplete_cancel(bContext *C, wmOperator *op)
+{
+	text_autocomplete_free(C, op);
+	return OPERATOR_CANCELLED;
+}
+
+void TEXT_OT_autocomplete(wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "Text Auto Complete";
+	ot->description = "Show a list of used text in the open document";
+	ot->idname = "TEXT_OT_autocomplete";
+
+	/* api callbacks */
+	ot->invoke = text_autocomplete_invoke;
+	ot->cancel = text_autocomplete_cancel;
+	ot->modal = text_autocomplete_modal;
+	ot->poll = text_space_edit_poll;
+
+	/* flags */
+	ot->flag = OPTYPE_BLOCKING;
+}
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 7d4c9e5af98..c264368e714 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -77,26 +77,17 @@ static int text_font_draw(SpaceText *UNUSED(st), int x, int y, const char *str)
 
 static int text_font_draw_character(SpaceText *st, int x, int y, char c)
 {
-	char str[2];
-	str[0] = c;
-	str[1] = '\0';
-
 	BLF_position(mono, x, y, 0);
-	BLF_draw(mono, str, 1);
+	BLF_draw(mono, &c, 1);
 
 	return st->cwidth;
 }
 
 static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char *c)
 {
-	char str[BLI_UTF8_MAX + 1];
-	size_t len = BLI_str_utf8_size_safe(c);
-	memcpy(str, c, len);
-	str[len] = '\0';
-
+	const size_t len = BLI_str_utf8_size_safe(c);
 	BLF_position(mono, x, y, 0);
-	BLF_draw(mono, str, len);
-
+	BLF_draw(mono, c, len);
 	return st->cwidth;
 }
 
@@ -117,27 +108,33 @@ static void txt_format_text(SpaceText *st)
 static void format_draw_color(char formatchar)
 {
 	switch (formatchar) {
-		case '_': /* Whitespace */
+		case FMT_TYPE_WHITESPACE:
 			break;
-		case '!': /* Symbols */
-			UI_ThemeColorBlend(TH_TEXT, TH_BACK, 0.5f);
+		case FMT_TYPE_SYMBOL:
+			UI_ThemeColor(TH_SYNTAX_S);
 			break;
-		case '#': /* Comments */
+		case FMT_TYPE_COMMENT:
 			UI_ThemeColor(TH_SYNTAX_C);
 			break;
-		case 'n': /* Numerals */
+		case FMT_TYPE_NUMERAL:
 			UI_ThemeColor(TH_SYNTAX_N);
 			break;
-		case 'l': /* Strings */
+		case FMT_TYPE_STRING:
 			UI_ThemeColor(TH_SYNTAX_L);
 			break;
-		case 'v': /* Specials: class, def */
+		case FMT_TYPE_DIRECTIVE:
+			UI_ThemeColor(TH_SYNTAX_D);
+			break;
+		case FMT_TYPE_SPECIAL:
 			UI_ThemeColor(TH_SYNTAX_V);
 			break;
-		case 'b': /* Keywords: for, print, etc. */
+		case FMT_TYPE_RESERVED:
+			UI_ThemeColor(TH_SYNTAX_R);
+			break;
+		case FMT_TYPE_KEYWORD:
 			UI_ThemeColor(TH_SYNTAX_B);
 			break;
-		case 'q': /* Other text (identifiers) */
+		case FMT_TYPE_DEFAULT:
 		default:
 			UI_ThemeColor(TH_TEXT);
 			break;
@@ -359,6 +356,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
 	FlattenString fs;
 	int basex, i, a, start, end, max, lines; /* view */
 	int mi, ma, mstart, mend;                /* mem */
+	char fmt_prev = 0xff;
 	
 	flatten_string(st, &fs, str);
 	str = fs.buf;
@@ -382,7 +380,9 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
 
 			/* Draw the visible portion of text on the overshot line */
 			for (a = start, ma = mstart; a < end; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
-				if (st->showsyntax && format) format_draw_color(format[a]);
+				if (st->showsyntax && format) {
+					if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
+				}
 				x += text_font_draw_character_utf8(st, x, y, str + ma);
 			}
 			y -= st->lheight_dpi + TXT_LINE_SPACING;
@@ -400,8 +400,9 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
 
 	/* Draw the remaining text */
 	for (a = start, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
-		if (st->showsyntax && format)
-			format_draw_color(format[a]);
+		if (st->showsyntax && format) {
+			if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
+		}
 
 		x += text_font_draw_character_utf8(st, x, y, str + ma);
 	}
@@ -432,15 +433,18 @@ static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int dra
 		
 		if (st->showsyntax && format) {
 			int a, str_shift = 0;
+			char fmt_prev = 0xff;
 			format = format + cshift;
 
 			for (a = 0; a < amount; a++) {
-				format_draw_color(format[a]);
+				if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]);
 				x += text_font_draw_character_utf8(st, x, y, in + str_shift);
 				str_shift += BLI_str_utf8_size_safe(in + str_shift);
 			}
 		}
-		else text_font_draw(st, x, y, in);
+		else {
+			text_font_draw(st, x, y, in);
+		}
 	}
 	else {
 		while (w-- && *acc++ < maxwidth)
@@ -890,7 +894,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar)
 
 	/* top = */ /* UNUSED */ y = ar->winy - st->lheight_dpi * l - 2;
 	boxw = DOC_WIDTH * st->cwidth + 20;
-	boxh = (DOC_HEIGHT + 1) * st->lheight_dpi;
+	boxh = (DOC_HEIGHT + 1) * (st->lheight_dpi + TXT_LINE_SPACING);
 
 	/* Draw panel */
 	UI_ThemeColor(TH_BACK);
@@ -953,9 +957,11 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
 	SuggItem *item, *first, *last, *sel;
 	TextLine *tmp;
 	char str[SUGG_LIST_WIDTH + 1];
-	int w, boxw = 0, boxh, i, l, x, y, b, *top;
+	int w, boxw = 0, boxh, i, l, x, y, *top;
+	const int lheight = st->lheight_dpi + TXT_LINE_SPACING;
+	const int margin_x = 2;
 	
-	if (!st || !st->text) return;
+	if (!st->text) return;
 	if (!texttool_text_is_active(st->text)) return;
 
 	first = texttool_suggest_first();
@@ -977,14 +983,20 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
 	else {
 		x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4;
 	}
-	y = ar->winy - st->lheight_dpi * l - 2;
+	/* offset back so the start of the text lines up with the suggestions,
+	 * not essential but makes suggestions easier to follow */
+	x -= st->cwidth * (st->text->curc - text_find_identifier_start(st->text->curl->line, st->text->curc));
+	y = ar->winy - lheight * l - 2;
 
 	boxw = SUGG_LIST_WIDTH * st->cwidth + 20;
-	boxh = SUGG_LIST_SIZE * st->lheight_dpi + 8;
+	boxh = SUGG_LIST_SIZE * lheight + 8;
 	
+	/* not needed but stands out nicer */
+	uiDrawBoxShadow(220, x, y - boxh, x + boxw, y);
+
 	UI_ThemeColor(TH_SHADE1);
 	glRecti(x - 1, y + 1, x + boxw + 1, y - boxh - 1);
-	UI_ThemeColor(TH_BACK);
+	UI_ThemeColorShade(TH_BACK, 16);
 	glRecti(x, y, x + boxw, y - boxh);
 
 	/* Set the top 'item' of the visible list */
@@ -992,7 +1004,7 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
 
 	for (i = 0; i < SUGG_LIST_SIZE && item; i++, item = item->next) {
 
-		y -= st->lheight_dpi;
+		y -= lheight;
 
 		BLI_strncpy(str, item->name, SUGG_LIST_WIDTH);
 
@@ -1000,21 +1012,11 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar)
 		
 		if (item == sel) {
 			UI_ThemeColor(TH_SHADE2);
-			glRecti(x + 16, y - 3, x + 16 + w, y + st->lheight_dpi - 3);
+			glRecti(x + margin_x, y - 3, x + margin_x + w, y + lheight - 3);
 		}
-		b = 1; /* b=1 color block, text is default. b=0 no block, color text */
-		switch (item->type) {
-			case 'k': UI_ThemeColor(TH_SYNTAX_B); b = 0; break;
-			case 'm': UI_ThemeColor(TH_TEXT); break;
-			case 'f': UI_ThemeColor(TH_SYNTAX_L); break;
-			case 'v': UI_ThemeColor(TH_SYNTAX_N); break;
-			case '?': UI_ThemeColor(TH_TEXT); b = 0; break;
-		}
-		if (b) {
-			glRecti(x + 8, y + 2, x + 11, y + 5);
-			UI_ThemeColor(TH_TEXT);
-		}
-		text_draw(st, str, 0, 0, 1, x + 16, y - 1, NULL);
+
+		format_draw_color(item->type);
+		text_draw(st, str, 0, 0, 1, x + margin_x, y - 1, NULL);
 
 		if (item == last) break;
 	}
@@ -1027,7 +1029,7 @@ static void draw_cursor(SpaceText *st, ARegion *ar)
 	Text *text = st->text;
 	int vcurl, vcurc, vsell, vselc, hidden = 0;
 	int x, y, w, i;
-	int lheight = st->lheight_dpi + TXT_LINE_SPACING;
+	const int lheight = st->lheight_dpi + TXT_LINE_SPACING;
 
 	/* Draw the selection */
 	if (text->curl != text->sell || text->curc != text->selc) {
@@ -1168,7 +1170,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar)
 	stack = 0;
 	
 	/* Don't highlight backets if syntax HL is off or bracket in string or comment. */
-	if (!linep->format || linep->format[fc] == 'l' || linep->format[fc] == '#')
+	if (!linep->format || linep->format[fc] == FMT_TYPE_STRING || linep->format[fc] == FMT_TYPE_COMMENT)
 		return;
 
 	if (b > 0) {
@@ -1177,7 +1179,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar)
 		c += BLI_str_utf8_size_safe(linep->line + c);
 		while (linep) {
 			while (c < linep->len) {
-				if (linep->format && linep->format[fc] != 'l' && linep->format[fc] != '#') {
+				if (linep->format && linep->format[fc] != FMT_TYPE_STRING && linep->format[fc] != FMT_TYPE_COMMENT) {
 					b = text_check_bracket(linep->line[c]);
 					if (b == find) {
 						if (stack == 0) {
@@ -1206,7 +1208,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar)
 		if (c > 0) c -= linep->line + c - BLI_str_prev_char_utf8(linep->line + c);
 		while (linep) {
 			while (fc >= 0) {
-				if (linep->format && linep->format[fc] != 'l' && linep->format[fc] != '#') {
+				if (linep->format && linep->format[fc] != FMT_TYPE_STRING && linep->format[fc] != FMT_TYPE_COMMENT) {
 					b = text_check_bracket(linep->line[c]);
 					if (b == find) {
 						if (stack == 0) {
@@ -1271,7 +1273,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar)
 void draw_text_main(SpaceText *st, ARegion *ar)
 {
 	Text *text = st->text;
-	TextFormatType *tft = ED_text_format_get(text);
+	TextFormatType *tft;
 	TextLine *tmp;
 	rcti scroll, back;
 	char linenr[12];
@@ -1299,6 +1301,7 @@ void draw_text_main(SpaceText *st, ARegion *ar)
 	calc_text_rcts(st, ar, &scroll, &back); /* scroll will hold the entire bar size */
 
 	/* update syntax formatting if needed */
+	tft = ED_text_format_get(text);
 	tmp = text->lines.first;
 	lineno = 0;
 	for (i = 0; i < st->top && tmp; i++) {
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index 0b3856f4414..294f94dd4b7 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -113,6 +113,14 @@ void flatten_string_free(FlattenString *fs)
 		MEM_freeN(fs->accum);
 }
 
+/* takes a string within fs->buf and returns its length */
+int flatten_string_strlen(FlattenString *fs, const char *str)
+{
+	const int len = (fs->pos - (int)(str - fs->buf)) - 1;
+	BLI_assert(strlen(str) == len);
+	return len;
+}
+
 /* Ensures the format string for the given line is long enough, reallocating
  * as needed. Allocation is done here, alone, to ensure consistency. */
 int text_check_format_len(TextLine *line, unsigned int len)
@@ -139,10 +147,16 @@ void ED_text_format_register(TextFormatType *tft)
 	BLI_addtail(&tft_lb, tft);
 }
 
-TextFormatType *ED_text_format_get(Text *UNUSED(text))
+TextFormatType *ED_text_format_get(Text *text)
 {
 	/* NOTE: once more types are added we'll need to return some type based on 'text'
 	 * for now this function is more of a placeholder */
 
-	return tft_lb.first;
+	/* XXX, wrong, but OK for testing */
+	if (text && BLI_testextensie(text->id.name + 2, ".osl")) {
+		return tft_lb.last;
+	}
+	else {
+		return tft_lb.first;
+	}
 }
diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h
index 7b5b326db6a..e593e41d42c 100644
--- a/source/blender/editors/space_text/text_format.h
+++ b/source/blender/editors/space_text/text_format.h
@@ -41,8 +41,24 @@ typedef struct FlattenString {
 	int pos, len;
 } FlattenString;
 
+/* format continuation flags (stored just after the NULL terminator) */
+enum {
+	FMT_CONT_NOP                = 0,  /* no continuation */
+	FMT_CONT_QUOTESINGLE        = (1 << 0),  /* single quotes */
+	FMT_CONT_QUOTEDOUBLE        = (1 << 1),  /* double quotes */
+	FMT_CONT_TRIPLE             = (1 << 2),  /* triplets of quotes: """ or ''' */
+	FMT_CONT_QUOTESINGLE_TRIPLE = (FMT_CONT_TRIPLE | FMT_CONT_QUOTESINGLE),
+	FMT_CONT_QUOTEDOUBLE_TRIPLE = (FMT_CONT_TRIPLE | FMT_CONT_QUOTEDOUBLE),
+	FMT_CONT_COMMENT_C          = (1 << 3),  /* multi-line comments, OSL only (C style) */
+	FMT_CONT_COMMENT_CXX        = (1 << 4),  /* single-line comments, OSL only (C++ style) */
+};
+#define FMT_CONT_ALL \
+	(FMT_CONT_QUOTESINGLE | FMT_CONT_QUOTEDOUBLE | FMT_CONT_TRIPLE | FMT_CONT_COMMENT_C | FMT_CONT_COMMENT_CXX)
+
 int  flatten_string(struct SpaceText *st, FlattenString *fs, const char *in);
 void flatten_string_free(FlattenString *fs);
+int  flatten_string_strlen(FlattenString *fs, const char *str);
+
 int  text_check_format_len(TextLine *line, unsigned int len);
 
 
@@ -50,28 +66,43 @@ int  text_check_format_len(TextLine *line, unsigned int len);
 typedef struct TextFormatType {
 	struct TextFormatType *next, *prev;
 
+	char (*format_identifier)(const char *string);
+
 	/* Formats the specified line. If do_next is set, the process will move on to
 	 * the succeeding line if it is affected (eg. multiline strings). Format strings
 	 * may contain any of the following characters:
-	 *  '_'  Whitespace
-	 *  '#'  Comment text
-	 *  '!'  Punctuation and other symbols
-	 *  'n'  Numerals
-	 *  'l'  String letters
-	 *  'v'  Special variables (class, def)
-	 *  'b'  Built-in names (print, for, etc.)
-	 *  'q'  Other text (identifiers, etc.)
+	 *
 	 * It is terminated with a null-terminator '\0' followed by a continuation
-	 * flag indicating whether the line is part of a multi-line string. */
+	 * flag indicating whether the line is part of a multi-line string.
+	 *
+	 * See: FMT_TYPE_ enums below
+	 */
 	void (*format_line)(SpaceText *st, TextLine *line, int do_next);
 
 	const char **ext;  /* NULL terminated extensions */
 } TextFormatType;
 
+enum {
+	FMT_TYPE_WHITESPACE = '_',  /* Whitespace */
+	FMT_TYPE_COMMENT    = '#',  /* Comment text */
+	FMT_TYPE_SYMBOL     = '!',  /* Punctuation and other symbols */
+	FMT_TYPE_NUMERAL    = 'n',  /* Numerals */
+	FMT_TYPE_STRING     = 'l',  /* String letters */
+	FMT_TYPE_DIRECTIVE  = 'd',  /* Decorator / Preprocessor directive */
+	FMT_TYPE_SPECIAL    = 'v',  /* Special variables (class, def) */
+	FMT_TYPE_RESERVED   = 'r',  /* Reserved keywords currently not in use, but still prohibited (OSL -> switch e.g.) */
+	FMT_TYPE_KEYWORD    = 'b',  /* Built-in names (return, for, etc.) */
+	FMT_TYPE_DEFAULT    = 'q',  /* Regular text (identifiers, etc.) */
+};
+
 TextFormatType *ED_text_format_get(Text *text);
 void            ED_text_format_register(TextFormatType *tft);
 
 /* formatters */
 void ED_text_format_register_py(void);
+void ED_text_format_register_osl(void);
+
+#define STR_LITERAL_STARTSWITH(str, str_literal, len_var) \
+	(strncmp(str, str_literal, len_var = (sizeof(str_literal) - 1)) == 0)
 
 #endif  /* __TEXT_FORMAT_H__ */
diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c
new file mode 100644
index 00000000000..3120e88163e
--- /dev/null
+++ b/source/blender/editors/space_text/text_format_osl.c
@@ -0,0 +1,335 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_text/text_format_osl.c
+ *  \ingroup sptext
+ */
+
+#include 
+
+#include "BLI_blenlib.h"
+
+#include "DNA_text_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_text.h"
+
+#include "text_format.h"
+
+/* *** Local Functions (for format_line) *** */
+
+static int txtfmt_osl_find_builtinfunc(const char *string)
+{
+	int i, len;
+	/* list is from
+	 * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf
+	 */
+	if      (STR_LITERAL_STARTSWITH(string, "break",        len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "closure",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "color",        len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "continue",     len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "do",           len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "else",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "emit",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "float",        len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "for",          len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "if",           len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "illuminance",  len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "illuminate",   len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "int",          len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "matrix",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "normal",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "output",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "point",        len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "public",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "return",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "string",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "struct",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "vector",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "void",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "while",        len)) i = len;
+	else                                                          i = 0;
+
+	/* If next source char is an identifier (eg. 'i' in "definate") no match */
+	if (i == 0 || text_check_identifier(string[i]))
+		return -1;
+	return i;
+}
+
+static int txtfmt_osl_find_reserved(const char *string)
+{
+	int i, len;
+	/* list is from...
+	 * https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf
+	 */
+	if      (STR_LITERAL_STARTSWITH(string, "bool",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "case",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "catch",        len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "char",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "const",        len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "delete",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "default",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "double",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "enum",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "extern",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "false",        len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "friend",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "goto",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "inline",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "long",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "new",          len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "operator",     len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "private",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "protected",    len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "short",        len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "signed",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "sizeof",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "static",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "switch",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "template",     len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "this",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "throw",        len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "true",         len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "try",          len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "typedef",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "uniform",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "union",        len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "unsigned",     len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "varying",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "virtual",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "volatile",     len)) i = len;
+	else                                                          i = 0;
+
+	/* If next source char is an identifier (eg. 'i' in "definate") no match */
+	if (i == 0 || text_check_identifier(string[i]))
+		return -1;
+	return i;
+}
+
+/* Checks the specified source string for a OSL special name. This name must
+ * start at the beginning of the source string and must be followed by a non-
+ * identifier (see text_check_identifier(char)) or null character.
+ *
+ * If a special name is found, the length of the matching name is returned.
+ * Otherwise, -1 is returned. */
+
+static int txtfmt_osl_find_specialvar(const char *string)
+{
+	int i, len;
+	
+	/* OSL shader types */
+	if      (STR_LITERAL_STARTSWITH(string, "shader", 		len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "surface", 		len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "volume", 		len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "displacement",	len)) i = len;
+	else                                                    i = 0;
+
+	/* If next source char is an identifier (eg. 'i' in "definate") no match */
+	if (i == 0 || text_check_identifier(string[i]))
+		return -1;
+	return i;
+}
+
+/* matches py 'txtfmt_osl_find_decorator' */
+static int txtfmt_osl_find_preprocessor(const char *string)
+{
+	if (string[0] == '#') {
+		int i = 1;
+		/* Whitespace is ok '#  foo' */
+		while (text_check_whitespace(string[i])) {
+			i++;
+		}
+		while (text_check_identifier(string[i])) {
+			i++;
+		}
+		return i;
+	}
+	return -1;
+}
+
+static char txtfmt_osl_format_identifier(const char *str)
+{
+	char fmt;
+	if      ((txtfmt_osl_find_specialvar(str))   != -1) fmt = FMT_TYPE_SPECIAL;
+	else if ((txtfmt_osl_find_builtinfunc(str))  != -1) fmt = FMT_TYPE_KEYWORD;
+	else if ((txtfmt_osl_find_reserved(str))     != -1) fmt = FMT_TYPE_RESERVED;
+	else if ((txtfmt_osl_find_preprocessor(str)) != -1) fmt = FMT_TYPE_DIRECTIVE;
+	else                                                fmt = FMT_TYPE_DEFAULT;
+	return fmt;
+}
+
+static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const int do_next)
+{
+	FlattenString fs;
+	const char *str;
+	char *fmt;
+	char cont_orig, cont, find, prev = ' ';
+	int len, i;
+
+	/* Get continuation from previous line */
+	if (line->prev && line->prev->format != NULL) {
+		fmt = line->prev->format;
+		cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+		BLI_assert((FMT_CONT_ALL & cont) == cont);
+	}
+	else {
+		cont = FMT_CONT_NOP;
+	}
+
+	/* Get original continuation from this line */
+	if (line->format != NULL) {
+		fmt = line->format;
+		cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+		BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig);
+	}
+	else {
+		cont_orig = 0xFF;
+	}
+
+	len = flatten_string(st, &fs, line->line);
+	str = fs.buf;
+	if (!text_check_format_len(line, len)) {
+		flatten_string_free(&fs);
+		return;
+	}
+	fmt = line->format;
+
+	while (*str) {
+		/* Handle escape sequences by skipping both \ and next char */
+		if (*str == '\\') {
+			*fmt = prev; fmt++; str++;
+			if (*str == '\0') break;
+			*fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str);
+			continue;
+		}
+		/* Handle continuations */
+		else if (cont) {
+			/* C-Style comments */
+			if (cont & FMT_CONT_COMMENT_CXX) {
+				*fmt = FMT_TYPE_COMMENT;
+			}
+			else if (cont & FMT_CONT_COMMENT_C) {
+				if (*str == '*' && *(str + 1) == '/') {
+					*fmt = FMT_TYPE_COMMENT; fmt++; str++;
+					*fmt = FMT_TYPE_COMMENT;
+					cont = FMT_CONT_NOP;
+				}
+				else {
+					*fmt = FMT_TYPE_COMMENT;
+				}
+				/* Handle other comments */
+			}
+			else {
+				find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
+				if (*str == find) cont = 0;
+				*fmt = FMT_TYPE_STRING;
+			}
+
+			str += BLI_str_utf8_size_safe(str) - 1;
+		}
+		/* Not in a string... */
+		else {
+			/* Deal with comments first */
+			if (*str == '/' && *(str + 1) == '/') {
+				cont = FMT_CONT_COMMENT_CXX;
+				*fmt = FMT_TYPE_COMMENT;
+			}
+			/* C-Style (multi-line) comments */
+			else if (*str == '/' && *(str + 1) == '*') {
+				cont = FMT_CONT_COMMENT_C;
+				*fmt = FMT_TYPE_COMMENT; fmt++; str++;
+				*fmt = FMT_TYPE_COMMENT;
+			}
+			else if (*str == '"' || *str == '\'') {
+				/* Strings */
+				find = *str;
+				cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
+				*fmt = FMT_TYPE_STRING;
+			}
+			/* Whitespace (all ws. has been converted to spaces) */
+			else if (*str == ' ') {
+				*fmt = FMT_TYPE_WHITESPACE;
+			}
+			/* Numbers (digits not part of an identifier and periods followed by digits) */
+			else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
+			         (*str == '.' && text_check_digit(*(str + 1))))
+			{
+				*fmt = FMT_TYPE_NUMERAL;
+			}
+			/* Punctuation */
+			else if ((*str != '#') && text_check_delim(*str)) {
+				*fmt = FMT_TYPE_SYMBOL;
+			}
+			/* Identifiers and other text (no previous ws. or delims. so text continues) */
+			else if (prev == FMT_TYPE_DEFAULT) {
+				str += BLI_str_utf8_size_safe(str) - 1;
+				*fmt = FMT_TYPE_DEFAULT;
+			}
+			/* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+			else {
+				/* Special vars(v) or built-in keywords(b) */
+				/* keep in sync with 'txtfmt_osl_format_identifier()' */
+				if      ((i = txtfmt_osl_find_specialvar(str))   != -1) prev = FMT_TYPE_SPECIAL;
+				else if ((i = txtfmt_osl_find_builtinfunc(str))  != -1) prev = FMT_TYPE_KEYWORD;
+				else if ((i = txtfmt_osl_find_reserved(str))     != -1) prev = FMT_TYPE_RESERVED;
+				else if ((i = txtfmt_osl_find_preprocessor(str)) != -1) prev = FMT_TYPE_DIRECTIVE;
+
+				if (i > 0) {
+					memset(fmt, prev, i);
+					i--; fmt += i; str += i;
+				}
+				else {
+					str += BLI_str_utf8_size_safe(str) - 1;
+					*fmt = FMT_TYPE_DEFAULT;
+				}
+			}
+		}
+		prev = *fmt; fmt++; str++;
+	}
+
+	/* Terminate and add continuation char */
+	*fmt = '\0'; fmt++;
+	*fmt = cont;
+
+	/* If continuation has changed and we're allowed, process the next line */
+	if (cont != cont_orig && do_next && line->next) {
+		txtfmt_osl_format_line(st, line->next, do_next);
+	}
+
+	flatten_string_free(&fs);
+}
+
+void ED_text_format_register_osl(void)
+{
+	static TextFormatType tft = {0};
+	static const char *ext[] = {"osl", NULL};
+
+	tft.format_identifier = txtfmt_osl_format_identifier;
+	tft.format_line       = txtfmt_osl_format_line;
+	tft.ext = ext;
+
+	ED_text_format_register(&tft);
+}
diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c
index 2a0f483d80c..cbccc6a770f 100644
--- a/source/blender/editors/space_text/text_format_py.c
+++ b/source/blender/editors/space_text/text_format_py.c
@@ -41,7 +41,6 @@
 
 /* *** Local Functions (for format_line) *** */
 
-
 /* Checks the specified source string for a Python built-in function name. This
  * name must start at the beginning of the source string and must be followed by
  * a non-identifier (see text_check_identifier(char)) or null character.
@@ -53,38 +52,53 @@
  * http://docs.python.org/py3k/reference/lexical_analysis.html#keywords
  */
 
-static int txtfmt_py_find_builtinfunc(char *string)
+static int txtfmt_py_find_builtinfunc(const char *string)
 {
-	int a, i;
-	const char *builtinfuncs[] = {
-		/* "False", "None", "True", */ /* see find_bool() */
-		"and", "as", "assert", "break",
-		"class", "continue", "def", "del", "elif", "else", "except",
-		"finally", "for", "from", "global", "if", "import", "in",
-		"is", "lambda", "nonlocal", "not", "or", "pass", "raise",
-		"return", "try", "while", "with", "yield",
-	};
+	int i, len;
+	/* list is from...
+	 * ", ".join(['"%s"' % kw
+	 *            for kw in  __import__("keyword").kwlist
+	 *            if kw not in {"False", "None", "True", "def", "class"}])
+	 *
+	 * ... and for this code:
+	 * print("\n".join(['else if (STR_LITERAL_STARTSWITH(string, "%s", len)) i = len;' % kw
+	 *                  for kw in  __import__("keyword").kwlist
+	 *                  if kw not in {"False", "None", "True", "def", "class"}]))
+	 */
 
-	for (a = 0; a < sizeof(builtinfuncs) / sizeof(builtinfuncs[0]); a++) {
-		i = 0;
-		while (1) {
-			/* If we hit the end of a keyword... (eg. "def") */
-			if (builtinfuncs[a][i] == '\0') {
-				/* If we still have identifier chars in the source (eg. "definate") */
-				if (text_check_identifier(string[i]))
-					i = -1;  /* No match */
-				break; /* Next keyword if no match, otherwise we're done */
+	if      (STR_LITERAL_STARTSWITH(string, "and",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "as",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "assert",   len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "break",    len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "continue", len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "del",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "elif",     len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "else",     len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "except",   len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "finally",  len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "for",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "from",     len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "global",   len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "if",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "import",   len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "in",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "is",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "lambda",   len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "nonlocal", len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "not",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "or",       len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "pass",     len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "raise",    len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "return",   len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "try",      len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "while",    len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "with",     len)) i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "yield",    len)) i = len;
+	else                                                      i = 0;
 
-				/* If chars mismatch, move on to next keyword */
-			}
-			else if (string[i] != builtinfuncs[a][i]) {
-				i = -1;
-				break; /* Break inner loop, start next keyword */
-			}
-			i++;
-		}
-		if (i > 0) break;  /* If we have a match, we're done */
-	}
+	/* If next source char is an identifier (eg. 'i' in "definate") no match */
+	if (i == 0 || text_check_identifier(string[i]))
+		return -1;
 	return i;
 }
 
@@ -95,25 +109,28 @@ static int txtfmt_py_find_builtinfunc(char *string)
  * If a special name is found, the length of the matching name is returned.
  * Otherwise, -1 is returned. */
 
-static int txtfmt_py_find_specialvar(char *string)
+static int txtfmt_py_find_specialvar(const char *string)
 {
-	int i = 0;
-	/* Check for "def" */
-	if (string[0] == 'd' && string[1] == 'e' && string[2] == 'f')
-		i = 3;
-	/* Check for "class" */
-	else if (string[0] == 'c' && string[1] == 'l' && string[2] == 'a' && string[3] == 's' && string[4] == 's')
-		i = 5;
+	int i, len;
+
+	if      (STR_LITERAL_STARTSWITH(string, "def", len))   i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "class", len)) i = len;
+	else                                                   i = 0;
+
 	/* If next source char is an identifier (eg. 'i' in "definate") no match */
 	if (i == 0 || text_check_identifier(string[i]))
 		return -1;
 	return i;
 }
 
-static int txtfmt_py_find_decorator(char *string)
+static int txtfmt_py_find_decorator(const char *string)
 {
 	if (string[0] == '@') {
 		int i = 1;
+		/* Whitespace is ok '@  foo' */
+		while (text_check_whitespace(string[i])) {
+			i++;
+		}
 		while (text_check_identifier(string[i])) {
 			i++;
 		}
@@ -122,46 +139,57 @@ static int txtfmt_py_find_decorator(char *string)
 	return -1;
 }
 
-static int txtfmt_py_find_bool(char *string)
+static int txtfmt_py_find_bool(const char *string)
 {
-	int i = 0;
-	/* Check for "False" */
-	if (string[0] == 'F' && string[1] == 'a' && string[2] == 'l' && string[3] == 's' && string[4] == 'e')
-		i = 5;
-	/* Check for "True" */
-	else if (string[0] == 'T' && string[1] == 'r' && string[2] == 'u' && string[3] == 'e')
-		i = 4;
-	/* Check for "None" */
-	else if (string[0] == 'N' && string[1] == 'o' && string[2] == 'n' && string[3] == 'e')
-		i = 4;
-	/* If next source char is an identifier (eg. 'i' in "definate") no match */
+	int i, len;
+
+	if      (STR_LITERAL_STARTSWITH(string, "None",  len))  i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "True",  len))  i = len;
+	else if (STR_LITERAL_STARTSWITH(string, "False", len))  i = len;
+	else                                                    i = 0;
+
+	/* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */
 	if (i == 0 || text_check_identifier(string[i]))
 		return -1;
 	return i;
 }
 
-static void txtfmt_py_format_line(SpaceText *st, TextLine *line, int do_next)
+static char txtfmt_py_format_identifier(const char *str)
+{
+	char fmt;
+	if      ((txtfmt_py_find_specialvar(str))   != -1) fmt = FMT_TYPE_SPECIAL;
+	else if ((txtfmt_py_find_builtinfunc(str))  != -1) fmt = FMT_TYPE_KEYWORD;
+	else if ((txtfmt_py_find_decorator(str))    != -1) fmt = FMT_TYPE_RESERVED;
+	else                                               fmt = FMT_TYPE_DEFAULT;
+	return fmt;
+}
+
+static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const int do_next)
 {
 	FlattenString fs;
-	char *str, *fmt, orig, cont, find, prev = ' ';
+	const char *str;
+	char *fmt;
+	char cont_orig, cont, find, prev = ' ';
 	int len, i;
 
 	/* Get continuation from previous line */
 	if (line->prev && line->prev->format != NULL) {
 		fmt = line->prev->format;
 		cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+		BLI_assert((FMT_CONT_ALL & cont) == cont);
 	}
 	else {
-		cont = 0;
+		cont = FMT_CONT_NOP;
 	}
 
 	/* Get original continuation from this line */
 	if (line->format != NULL) {
 		fmt = line->format;
-		orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+		cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */
+		BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig);
 	}
 	else {
-		orig = 0xFF;
+		cont_orig = 0xFF;
 	}
 
 	len = flatten_string(st, &fs, line->line);
@@ -183,93 +211,90 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, int do_next)
 		/* Handle continuations */
 		else if (cont) {
 			/* Triple strings ("""...""" or '''...''') */
-			if (cont & TXT_TRISTR) {
-				find = (cont & TXT_DBLQUOTSTR) ? '"' : '\'';
+			if (cont & FMT_CONT_TRIPLE) {
+				find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
 				if (*str == find && *(str + 1) == find && *(str + 2) == find) {
-					*fmt = 'l'; fmt++; str++;
-					*fmt = 'l'; fmt++; str++;
-					cont = 0;
+					*fmt = FMT_TYPE_STRING; fmt++; str++;
+					*fmt = FMT_TYPE_STRING; fmt++; str++;
+					cont = FMT_CONT_NOP;
 				}
 				/* Handle other strings */
 			}
 			else {
-				find = (cont & TXT_DBLQUOTSTR) ? '"' : '\'';
-				if (*str == find) cont = 0;
+				find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\'';
+				if (*str == find) cont = FMT_CONT_NOP;
 			}
 
-			*fmt = 'l';
+			*fmt = FMT_TYPE_STRING;
 			str += BLI_str_utf8_size_safe(str) - 1;
 		}
 		/* Not in a string... */
 		else {
 			/* Deal with comments first */
-			if (prev == '#' || *str == '#') {
-				*fmt = '#';
+			if (prev == FMT_TYPE_COMMENT || *str == '#') {
+				*fmt = FMT_TYPE_COMMENT;
 				str += BLI_str_utf8_size_safe(str) - 1;
 			}
 			else if (*str == '"' || *str == '\'') {
 				/* Strings */
 				find = *str;
-				cont = (*str == '"') ? TXT_DBLQUOTSTR : TXT_SNGQUOTSTR;
+				cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE;
 				if (*(str + 1) == find && *(str + 2) == find) {
-					*fmt = 'l'; fmt++; str++;
-					*fmt = 'l'; fmt++; str++;
-					cont |= TXT_TRISTR;
+					*fmt = FMT_TYPE_STRING; fmt++; str++;
+					*fmt = FMT_TYPE_STRING; fmt++; str++;
+					cont |= FMT_CONT_TRIPLE;
 				}
-				*fmt = 'l';
+				*fmt = FMT_TYPE_STRING;
 			}
 			/* Whitespace (all ws. has been converted to spaces) */
-			else if (*str == ' ')
-				*fmt = '_';
+			else if (*str == ' ') {
+				*fmt = FMT_TYPE_WHITESPACE;
+			}
 			/* Numbers (digits not part of an identifier and periods followed by digits) */
-			else if ((prev != 'q' && text_check_digit(*str)) || (*str == '.' && text_check_digit(*(str + 1))))
-				*fmt = 'n';
+			else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) ||
+			         (*str == '.' && text_check_digit(*(str + 1))))
+			{
+				*fmt = FMT_TYPE_NUMERAL;
+			}
 			/* Booleans */
-			else if (prev != 'q' && (i = txtfmt_py_find_bool(str)) != -1)
+			else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_py_find_bool(str)) != -1) {
 				if (i > 0) {
-					while (i > 1) {
-						*fmt = 'n'; fmt++; str++;
-						i--;
-					}
-					*fmt = 'n';
+					memset(fmt, FMT_TYPE_NUMERAL, i);
+					i--; fmt += i; str += i;
 				}
 				else {
 					str += BLI_str_utf8_size_safe(str) - 1;
-					*fmt = 'q';
+					*fmt = FMT_TYPE_DEFAULT;
 				}
+			}
 			/* Punctuation */
-			else if (text_check_delim(*str))
-				*fmt = '!';
+			else if ((*str != '@') && text_check_delim(*str)) {
+				*fmt = FMT_TYPE_SYMBOL;
+			}
 			/* Identifiers and other text (no previous ws. or delims. so text continues) */
-			else if (prev == 'q') {
+			else if (prev == FMT_TYPE_DEFAULT) {
 				str += BLI_str_utf8_size_safe(str) - 1;
-				*fmt = 'q';
+				*fmt = FMT_TYPE_DEFAULT;
 			}
 			/* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
 			else {
 				/* Special vars(v) or built-in keywords(b) */
-				if ((i = txtfmt_py_find_specialvar(str)) != -1)
-					prev = 'v';
-				else if ((i = txtfmt_py_find_builtinfunc(str)) != -1)
-					prev = 'b';
-				else if ((i = txtfmt_py_find_decorator(str)) != -1)
-					prev = 'v';  /* could have a new color for this */
+				/* keep in sync with 'txtfmt_py_format_identifier()' */
+				if      ((i = txtfmt_py_find_specialvar(str))   != -1) prev = FMT_TYPE_SPECIAL;
+				else if ((i = txtfmt_py_find_builtinfunc(str))  != -1) prev = FMT_TYPE_KEYWORD;
+				else if ((i = txtfmt_py_find_decorator(str))    != -1) prev = FMT_TYPE_DIRECTIVE;
+
 				if (i > 0) {
-					while (i > 1) {
-						*fmt = prev; fmt++; str++;
-						i--;
-					}
-					*fmt = prev;
+					memset(fmt, prev, i);
+					i--; fmt += i; str += i;
 				}
 				else {
 					str += BLI_str_utf8_size_safe(str) - 1;
-					*fmt = 'q';
+					*fmt = FMT_TYPE_DEFAULT;
 				}
 			}
 		}
-		prev = *fmt;
-		fmt++;
-		str++;
+		prev = *fmt; fmt++; str++;
 	}
 
 	/* Terminate and add continuation char */
@@ -277,7 +302,7 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, int do_next)
 	*fmt = cont;
 
 	/* If continuation has changed and we're allowed, process the next line */
-	if (cont != orig && do_next && line->next) {
+	if (cont != cont_orig && do_next && line->next) {
 		txtfmt_py_format_line(st, line->next, do_next);
 	}
 
@@ -289,7 +314,8 @@ void ED_text_format_register_py(void)
 	static TextFormatType tft = {0};
 	static const char *ext[] = {"py", NULL};
 
-	tft.format_line = txtfmt_py_format_line;
+	tft.format_identifier = txtfmt_py_format_identifier;
+	tft.format_line       = txtfmt_py_format_line;
 	tft.ext = ext;
 
 	ED_text_format_register(&tft);
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index c7f9512737f..799bc49b624 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -143,6 +143,11 @@ void TEXT_OT_to_3d_object(struct wmOperatorType *ot);
 
 void TEXT_OT_resolve_conflict(struct wmOperatorType *ot);
 
+int text_space_edit_poll(struct bContext *C);
+
+/* text_autocomplete.c */
+void TEXT_OT_autocomplete(struct wmOperatorType *ot);
+
 /* space_text.c */
 extern const char *text_context_dir[]; /* doc access */
 
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 01041c0e385..21966ef614c 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -98,7 +98,7 @@ static int text_edit_poll(bContext *C)
 	return 1;
 }
 
-static int text_space_edit_poll(bContext *C)
+int text_space_edit_poll(bContext *C)
 {
 	SpaceText *st = CTX_wm_space_text(C);
 	Text *text = CTX_data_edit_text(C);
@@ -1931,6 +1931,8 @@ static int text_jump_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 
 void TEXT_OT_jump(wmOperatorType *ot)
 {
+	PropertyRNA *prop;
+
 	/* identifiers */
 	ot->name = "Jump";
 	ot->idname = "TEXT_OT_jump";
@@ -1942,7 +1944,8 @@ void TEXT_OT_jump(wmOperatorType *ot)
 	ot->poll = text_edit_poll;
 
 	/* properties */
-	RNA_def_int(ot->srna, "line", 1, 1, INT_MAX, "Line", "Line number to jump to", 1, 10000);
+	prop = RNA_def_int(ot->srna, "line", 1, 1, INT_MAX, "Line", "Line number to jump to", 1, 10000);
+	RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_TEXT);
 }
 
 /******************* delete operator **********************/
diff --git a/source/blender/editors/space_text/text_python.c b/source/blender/editors/space_text/text_python.c
deleted file mode 100644
index 1201302dad0..00000000000
--- a/source/blender/editors/space_text/text_python.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version. 
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008 Blender Foundation.
- * All rights reserved.
- *
- * 
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/space_text/text_python.c
- *  \ingroup sptext
- */
-
-#include 
-
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_text_types.h"
-#include "DNA_userdef_types.h"
-
-#include "BKE_suggestions.h"
-#include "BKE_text.h"
-
-#include "BLI_blenlib.h"
-
-#include "WM_types.h"
-
-#include "text_intern.h"
-
-int text_do_suggest_select(SpaceText *st, ARegion *ar)
-{
-	SuggItem *item, *first, *last /* , *sel */ /* UNUSED */;
-	TextLine *tmp;
-	int l, x, y, w, h, i;
-	int tgti, *top;
-	int mval[2] = {0, 0};
-	
-	if (!st || !st->text) return 0;
-	if (!texttool_text_is_active(st->text)) return 0;
-
-	first = texttool_suggest_first();
-	last = texttool_suggest_last();
-	/* sel = texttool_suggest_selected(); */ /* UNUSED */
-	top = texttool_suggest_top();
-
-	if (!last || !first)
-		return 0;
-
-	/* Count the visible lines to the cursor */
-	for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ;
-	if (l < 0) return 0;
-
-	text_update_character_width(st);
-	
-	if (st->showlinenrs) {
-		x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET + TEXTXLOC - 4;
-	}
-	else {
-		x = st->cwidth * (st->text->curc - st->left) + TXT_OFFSET - 4;
-	}
-	y = ar->winy - st->lheight_dpi * l - 2;
-
-	w = SUGG_LIST_WIDTH * st->cwidth + U.widget_unit;
-	h = SUGG_LIST_SIZE * st->lheight_dpi + 0.4f * U.widget_unit;
-
-	// XXX getmouseco_areawin(mval);
-
-	if (mval[0] < x || x + w < mval[0] || mval[1] < y - h || y < mval[1])
-		return 0;
-
-	/* Work out which of the items is at the top of the visible list */
-	for (i = 0, item = first; i < *top && item->next; i++, item = item->next) ;
-
-	/* Work out the target item index in the visible list */
-	tgti = (y - mval[1] - 4) / st->lheight_dpi;
-	if (tgti < 0 || tgti > SUGG_LIST_SIZE)
-		return 1;
-
-	for (i = tgti; i > 0 && item->next; i--, item = item->next) ;
-	if (item)
-		texttool_suggest_select(item);
-	return 1;
-}
-
-void text_pop_suggest_list(void)
-{
-	SuggItem *item, *sel;
-	int *top, i;
-
-	item = texttool_suggest_first();
-	sel = texttool_suggest_selected();
-	top = texttool_suggest_top();
-
-	i = 0;
-	while (item && item != sel) {
-		item = item->next;
-		i++;
-	}
-	if (i > *top + SUGG_LIST_SIZE - 1)
-		*top = i - SUGG_LIST_SIZE + 1;
-	else if (i < *top)
-		*top = i;
-}
-
-static void get_suggest_prefix(Text *text, int offset)
-{
-	int i, len;
-	char *line, tmp[256];
-
-	if (!text) return;
-	if (!texttool_text_is_active(text)) return;
-
-	line = text->curl->line;
-	for (i = text->curc - 1 + offset; i >= 0; i--)
-		if (!text_check_identifier(line[i]))
-			break;
-	i++;
-	len = text->curc - i + offset;
-	if (len > 255) {
-		printf("Suggestion prefix too long\n");
-		len = 255;
-	}
-	BLI_strncpy(tmp, line + i, len);
-	tmp[len] = '\0';
-	texttool_suggest_prefix(tmp);
-}
-
-static void confirm_suggestion(Text *text, int skipleft)
-{
-	SuggItem *sel;
-	int i, over = 0;
-	char *line;
-
-	if (!text) return;
-	if (!texttool_text_is_active(text)) return;
-
-	sel = texttool_suggest_selected();
-	if (!sel) return;
-
-	line = text->curl->line;
-	i = text->curc - skipleft - 1;
-	while (i >= 0) {
-		if (!text_check_identifier(line[i]))
-			break;
-		over++;
-		i--;
-	}
-
-	for (i = 0; i < skipleft; i++)
-		txt_move_left(text, 0);
-	for (i = 0; i < over; i++)
-		txt_move_left(text, 1);
-
-	txt_insert_buf(text, sel->name);
-	
-	for (i = 0; i < skipleft; i++)
-		txt_move_right(text, 0);
-
-	texttool_text_clear();
-}
-
-// XXX
-#define LR_SHIFTKEY 0
-#define LR_ALTKEY 0
-#define LR_CTRLKEY 0
-
-// XXX
-static int doc_scroll = 0;
-
-static short UNUSED_FUNCTION(do_texttools) (SpaceText * st, char ascii, unsigned short evnt, short val)
-{
-	ARegion *ar = NULL; // XXX
-	int qual = 0; // XXX
-	int draw = 0, tools = 0, swallow = 0, scroll = 1;
-	if (!texttool_text_is_active(st->text)) return 0;
-	if (!st->text || st->text->id.lib) return 0;
-
-	if (st->doplugins && texttool_text_is_active(st->text)) {
-		if (texttool_suggest_first()) tools |= TOOL_SUGG_LIST;
-		if (texttool_docs_get()) tools |= TOOL_DOCUMENT;
-	}
-
-	if (ascii) {
-		if (tools & TOOL_SUGG_LIST) {
-			if ((ascii != '_' && ascii != '*' && ispunct(ascii)) || text_check_whitespace(ascii)) {
-				confirm_suggestion(st->text, 0);
-				text_update_line_edited(st->text->curl);
-			}
-			else if ((st->overwrite && txt_replace_char(st->text, ascii)) || txt_add_char(st->text, ascii)) {
-				get_suggest_prefix(st->text, 0);
-				text_pop_suggest_list();
-				swallow = 1;
-				draw = 1;
-			}
-		}
-		if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1;
-
-	}
-	else if (val == 1 && evnt) {
-		switch (evnt) {
-			case LEFTMOUSE:
-				if (text_do_suggest_select(st, ar))
-					swallow = 1;
-				else {
-					if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
-					if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
-				}
-				draw = 1;
-				break;
-			case MIDDLEMOUSE:
-				if (text_do_suggest_select(st, ar)) {
-					confirm_suggestion(st->text, 0);
-					text_update_line_edited(st->text->curl);
-					swallow = 1;
-				}
-				else {
-					if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
-					if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
-				}
-				draw = 1;
-				break;
-			case ESCKEY:
-				draw = swallow = 1;
-				if (tools & TOOL_SUGG_LIST) texttool_suggest_clear();
-				else if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
-				else draw = swallow = 0;
-				break;
-			case RETKEY:
-				if (tools & TOOL_SUGG_LIST) {
-					confirm_suggestion(st->text, 0);
-					text_update_line_edited(st->text->curl);
-					swallow = 1;
-					draw = 1;
-				}
-				if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1;
-				break;
-			case LEFTARROWKEY:
-			case BACKSPACEKEY:
-				if (tools & TOOL_SUGG_LIST) {
-					if (qual)
-						texttool_suggest_clear();
-					else {
-						/* Work out which char we are about to delete/pass */
-						if (st->text->curl && st->text->curc > 0) {
-							char ch = st->text->curl->line[st->text->curc - 1];
-							if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
-								get_suggest_prefix(st->text, -1);
-								text_pop_suggest_list();
-							}
-							else
-								texttool_suggest_clear();
-						}
-						else
-							texttool_suggest_clear();
-					}
-				}
-				if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
-				break;
-			case RIGHTARROWKEY:
-				if (tools & TOOL_SUGG_LIST) {
-					if (qual)
-						texttool_suggest_clear();
-					else {
-						/* Work out which char we are about to pass */
-						if (st->text->curl && st->text->curc < st->text->curl->len) {
-							char ch = st->text->curl->line[st->text->curc + 1];
-							if ((ch == '_' || !ispunct(ch)) && !text_check_whitespace(ch)) {
-								get_suggest_prefix(st->text, 1);
-								text_pop_suggest_list();
-							}
-							else
-								texttool_suggest_clear();
-						}
-						else
-							texttool_suggest_clear();
-					}
-				}
-				if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0;
-				break;
-			case PAGEDOWNKEY:
-				scroll = SUGG_LIST_SIZE - 1;
-			case WHEELDOWNMOUSE:
-			case DOWNARROWKEY:
-				if (tools & TOOL_DOCUMENT) {
-					doc_scroll++;
-					swallow = 1;
-					draw = 1;
-					break;
-				}
-				else if (tools & TOOL_SUGG_LIST) {
-					SuggItem *sel = texttool_suggest_selected();
-					if (!sel) {
-						texttool_suggest_select(texttool_suggest_first());
-					}
-					else {
-						while (sel && sel != texttool_suggest_last() && sel->next && scroll--) {
-							texttool_suggest_select(sel->next);
-							sel = sel->next;
-						}
-					}
-					text_pop_suggest_list();
-					swallow = 1;
-					draw = 1;
-					break;
-				}
-			case PAGEUPKEY:
-				scroll = SUGG_LIST_SIZE - 1;
-			case WHEELUPMOUSE:
-			case UPARROWKEY:
-				if (tools & TOOL_DOCUMENT) {
-					if (doc_scroll > 0) doc_scroll--;
-					swallow = 1;
-					draw = 1;
-					break;
-				}
-				else if (tools & TOOL_SUGG_LIST) {
-					SuggItem *sel = texttool_suggest_selected();
-					while (sel && sel != texttool_suggest_first() && sel->prev && scroll--) {
-						texttool_suggest_select(sel->prev);
-						sel = sel->prev;
-					}
-					text_pop_suggest_list();
-					swallow = 1;
-					draw = 1;
-					break;
-				}
-			case RIGHTSHIFTKEY:
-			case LEFTSHIFTKEY:
-				break;
-			default:
-				if (tools & TOOL_SUGG_LIST) texttool_suggest_clear(), draw = 1;
-				if (tools & TOOL_DOCUMENT) texttool_docs_clear(), doc_scroll = 0, draw = 1;
-		}
-	}
-
-	if (draw) {
-		// XXX redraw_alltext();
-	}
-
-	return swallow;
-}
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index 1ea3876f5cc..5ebbebec35b 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -105,14 +105,16 @@ static SpaceLink *userpref_duplicate(SpaceLink *sl)
 /* add handlers, stuff you only do once or on area/region changes */
 static void userpref_main_area_init(wmWindowManager *wm, ARegion *ar)
 {
+	/* do not use here, the properties changed in userprefs do a system-wide refresh, then scroller jumps back */
+	/*	ar->v2d.flag &= ~V2D_IS_INITIALISED; */
+	
+	ar->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE;
+
 	ED_region_panels_init(wm, ar);
 }
 
 static void userpref_main_area_draw(const bContext *C, ARegion *ar)
 {
-	/* this solves "vibrating UI" bug #25422 */
-	UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy);
-	
 	ED_region_panels(C, ar, 1, NULL, -1);
 }
 
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index e36654323fd..fa72f28cc44 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -396,6 +396,7 @@ static void draw_textured_end(void)
 
 	glShadeModel(GL_FLAT);
 	glDisable(GL_CULL_FACE);
+	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
 
 	/* XXX, bad patch - GPU_default_lights() calls
 	 * glLightfv(GL_POSITION, ...) which
@@ -1018,7 +1019,7 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
 	const short do_light = (v3d->drawtype >= OB_SOLID);
 
 	/* hide faces in face select mode */
-	if (draw_flags & DRAW_FACE_SELECT)
+	if (me->editflag & (ME_EDIT_PAINT_VERT_SEL | ME_EDIT_PAINT_FACE_SEL))
 		facemask = wpaint__setSolidDrawOptions_facemask;
 
 	if (ob->mode & OB_MODE_WEIGHT_PAINT) {
@@ -1066,12 +1067,18 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
 		draw_mesh_face_select(rv3d, me, dm);
 	}
 	else if ((do_light == FALSE) || (ob->dtx & OB_DRAWWIRE)) {
+		const int use_depth = (v3d->flag & V3D_ZBUF_SELECT);
 
 		/* weight paint in solid mode, special case. focus on making the weights clear
 		 * rather than the shading, this is also forced in wire view */
 
-		bglPolygonOffset(rv3d->dist, 1.0);
-		glDepthMask(0);  /* disable write in zbuffer, selected edge wires show better */
+		if (use_depth) {
+			bglPolygonOffset(rv3d->dist, 1.0);
+			glDepthMask(0);  /* disable write in zbuffer, selected edge wires show better */
+		}
+		else {
+			glDisable(GL_DEPTH_TEST);
+		}
 
 		glEnable(GL_BLEND);
 		glColor4ub(255, 255, 255, 96);
@@ -1080,8 +1087,14 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
 
 		dm->drawEdges(dm, 1, 1);
 
-		bglPolygonOffset(rv3d->dist, 0.0);
-		glDepthMask(1);
+		if (use_depth) {
+			bglPolygonOffset(rv3d->dist, 0.0);
+			glDepthMask(1);
+		}
+		else {
+			glEnable(GL_DEPTH_TEST);
+		}
+
 		glDisable(GL_LINE_STIPPLE);
 		glDisable(GL_BLEND);
 	}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 3722e6797f8..ebb5fd30666 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -101,7 +101,7 @@ typedef enum eWireDrawMode {
 } eWireDrawMode;
 
 typedef struct drawDMVerts_userData {
-	BMEditMesh *em; /* BMESH BRANCH ONLY */
+	BMEditMesh *em;
 
 	int sel;
 	BMVert *eve_act;
@@ -119,7 +119,7 @@ typedef struct drawDMVerts_userData {
 } drawDMVerts_userData;
 
 typedef struct drawDMEdgesSel_userData {
-	BMEditMesh *em; /* BMESH BRANCH ONLY */
+	BMEditMesh *em;
 
 	unsigned char *baseCol, *selCol, *actCol;
 	BMEdge *eed_act;
@@ -132,8 +132,8 @@ typedef struct drawDMFacesSel_userData {
 	unsigned char *cols[3];
 #endif
 
-	DerivedMesh *dm; /* BMESH BRANCH ONLY */
-	BMEditMesh *em;  /* BMESH BRANCH ONLY */
+	DerivedMesh *dm;
+	BMEditMesh *em;
 
 	BMFace *efa_act;
 	int *orig_index_mf_to_mpoly;
@@ -2629,10 +2629,10 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, BMEditMesh *em, UnitS
 
 	/* make the precision of the display value proportionate to the gridsize */
 
-	if (grid < 0.01f) conv_float = "%.6g";
-	else if (grid < 0.1f) conv_float = "%.5g";
-	else if (grid < 1.0f) conv_float = "%.4g";
-	else if (grid < 10.0f) conv_float = "%.3g";
+	if (grid <= 0.01f) conv_float = "%.6g";
+	else if (grid <= 0.1f) conv_float = "%.5g";
+	else if (grid <= 1.0f) conv_float = "%.4g";
+	else if (grid <= 10.0f) conv_float = "%.3g";
 	else conv_float = "%.2g";
 	
 	if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
@@ -3312,11 +3312,15 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
 	}
 	
 	if (is_obact && paint_vertsel_test(ob)) {
-		
+		const int use_depth = (v3d->flag & V3D_ZBUF_SELECT);
 		glColor3f(0.0f, 0.0f, 0.0f);
 		glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
-		
+
+		if (!use_depth) glDisable(GL_DEPTH_TEST);
+		else            bglPolygonOffset(rv3d->dist, 1.0);
 		drawSelectedVertices(dm, ob->data);
+		if (!use_depth) glEnable(GL_DEPTH_TEST);
+		else            bglPolygonOffset(rv3d->dist, 0.0);
 		
 		glPointSize(1.0f);
 	}
@@ -6949,10 +6953,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
 			UI_make_axis_color(col1, col2, 'Z');
 			glColor3ubv(col2);
 			
-			cob = constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+			cob = BKE_constraints_make_evalob(scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
 			
 			for (curcon = list->first; curcon; curcon = curcon->next) {
-				bConstraintTypeInfo *cti = constraint_get_typeinfo(curcon);
+				bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(curcon);
 				ListBase targets = {NULL, NULL};
 				bConstraintTarget *ct;
 				
@@ -7006,7 +7010,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
 				}
 			}
 			
-			constraints_clear_evalob(cob);
+			BKE_constraints_clear_evalob(cob);
 		}
 	}
 
@@ -7167,7 +7171,21 @@ static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index)
 		return DM_DRAW_OPTION_SKIP;
 	}
 }
-static void bbs_mesh_solid(Scene *scene, Object *ob)
+
+static void bbs_mesh_solid_verts(Scene *scene, Object *ob)
+{
+	Mesh *me = ob->data;
+	DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
+	glColor3ub(0, 0, 0);
+
+	dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_enable_material, NULL, me, 0);
+
+	bbs_obmode_mesh_verts(ob, dm, 1);
+	bm_vertoffs = me->totvert + 1;
+	dm->release(dm);
+}
+
+static void bbs_mesh_solid_faces(Scene *scene, Object *ob)
 {
 	DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
 	Mesh *me = (Mesh *)ob->data;
@@ -7232,18 +7250,10 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
 				    /* currently vertex select only supports weight paint */
 				    (ob->mode & OB_MODE_WEIGHT_PAINT))
 				{
-					DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
-					glColor3ub(0, 0, 0);
-
-					dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_enable_material, NULL, me, 0);
-
-
-					bbs_obmode_mesh_verts(ob, dm, 1);
-					bm_vertoffs = me->totvert + 1;
-					dm->release(dm);
+					bbs_mesh_solid_verts(scene, ob);
 				}
 				else {
-					bbs_mesh_solid(scene, ob);
+					bbs_mesh_solid_faces(scene, ob);
 				}
 			}
 			break;
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 4ade47fbdc7..1d87895d64a 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -520,14 +520,8 @@ static int view3d_ima_ob_drop_poll(bContext *C, wmDrag *drag, wmEvent *event)
 static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
 {
 	ID *id = (ID *)drag->poin;
-	PointerRNA ptr;
 
-	/* need to put name in sub-operator in macro */
-	ptr = RNA_pointer_get(drop->ptr, "OBJECT_OT_add_named");
-	if (ptr.data)
-		RNA_string_set(&ptr, "name", id->name + 2);
-	else
-		RNA_string_set(drop->ptr, "name", id->name + 2);
+	RNA_string_set(drop->ptr, "name", id->name + 2);
 }
 
 static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop)
@@ -561,7 +555,7 @@ static void view3d_dropboxes(void)
 {
 	ListBase *lb = WM_dropboxmap_find("View3D", SPACE_VIEW3D, RGN_TYPE_WINDOW);
 	
-	WM_dropbox_add(lb, "OBJECT_OT_add_named_cursor", view3d_ob_drop_poll, view3d_ob_drop_copy);
+	WM_dropbox_add(lb, "OBJECT_OT_add_named", view3d_ob_drop_poll, view3d_ob_drop_copy);
 	WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", view3d_mat_drop_poll, view3d_id_drop_copy);
 	WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_ob_drop_poll, view3d_id_path_drop_copy);
 	WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 7475f65317a..4ccf26e12b1 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -2596,10 +2596,10 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar,
 			linearrgb_to_srgb_v3_v3(backcol, &scene->world->horr);
 		}
 
-		glClearColor(backcol[0], backcol[1], backcol[2], 0.0);
+		glClearColor(backcol[0], backcol[1], backcol[2], 0.0f);
 	}
 	else {
-		UI_ThemeClearColor(TH_BACK);
+		 UI_ThemeClearColor(TH_BACK);
 	}
 
 
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 78c3f4e4f4a..e984a3f5cfd 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -921,7 +921,8 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
 	}
 	
 	if (event->type == MOUSEPAN) {
-		viewrotate_apply(vod, event->prevx, event->prevy);
+		/* invert it, trackpad scroll then follows how you mapped it globally */
+		viewrotate_apply(vod, 2 * event->x - event->prevx, 2 * event->y - event->prevy);
 		ED_view3d_depth_tag_update(rv3d);
 		
 		viewops_data_free(C, op);
@@ -1008,17 +1009,20 @@ void ndof_to_quat(struct wmNDOFMotionData *ndof, float q[4])
  */
 static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
-	ViewOpsData *vod = op->customdata;
 	
 	if (event->type != NDOF_MOTION)
 		return OPERATOR_CANCELLED;
 	else {
 		View3D *v3d = CTX_wm_view3d(C);
+		ViewOpsData *vod;
 		RegionView3D *rv3d = CTX_wm_region_view3d(C);
 		wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata;
 
 		ED_view3d_camera_lock_init(v3d, rv3d);
 
+		viewops_data_create(C, op, event);
+		vod = op->customdata;
+
 		rv3d->rot_angle = 0.f; /* off by default, until changed later this function */
 
 		if (ndof->progress != P_FINISHING) {
@@ -1138,8 +1142,10 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
 			}
 		}
 
+		viewops_data_free(C, op);
+		
 		ED_view3d_camera_lock_sync(v3d, rv3d);
-
+		
 		ED_region_tag_redraw(CTX_wm_region(C));
 
 		return OPERATOR_FINISHED;
@@ -1161,6 +1167,181 @@ void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot)
 	ot->flag = 0;
 }
 
+
+static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+	
+	if (event->type != NDOF_MOTION)
+		return OPERATOR_CANCELLED;
+	else {
+		ViewOpsData *vod;
+		View3D *v3d = CTX_wm_view3d(C);
+		RegionView3D *rv3d = CTX_wm_region_view3d(C);
+		wmNDOFMotionData *ndof = (wmNDOFMotionData *) event->customdata;
+
+		ED_view3d_camera_lock_init(v3d, rv3d);
+
+		rv3d->rot_angle = 0.f; /* off by default, until changed later this function */
+
+		viewops_data_create(C, op, event);
+		vod = op->customdata;
+
+		if (ndof->progress != P_FINISHING) {
+			const float dt = ndof->dt;
+
+			/* tune these until everything feels right */
+			const float rot_sensitivity = 1.f;
+
+			const float zoom_sensitivity = 1.f;
+
+			const float pan_sensitivity = 1.f;
+			const int has_rotation = rv3d->viewlock != RV3D_LOCKED && !is_zero_v3(ndof->rvec);
+
+			float view_inv[4];
+			invert_qt_qt(view_inv, rv3d->viewquat);
+
+			/* #define DEBUG_NDOF_MOTION */
+			#ifdef DEBUG_NDOF_MOTION
+			printf("ndof: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f delivered to 3D view\n",
+			       ndof->tx, ndof->ty, ndof->tz, ndof->rx, ndof->ry, ndof->rz, ndof->dt);
+			#endif
+
+			if (ndof->tz) {
+				/* Zoom!
+				 * velocity should be proportional to the linear velocity attained by rotational motion of same strength
+				 * [got that?]
+				 * proportional to arclength = radius * angle
+				 */
+				float zoom_distance = zoom_sensitivity * rv3d->dist * dt * ndof->tz;
+
+				if (U.ndof_flag & NDOF_ZOOM_INVERT)
+					zoom_distance = -zoom_distance;
+
+				rv3d->dist += zoom_distance;
+			}
+			
+			if (rv3d->viewlock == RV3D_LOCKED) {
+				/* rotation not allowed -- explore panning options instead */
+				float pan_vec[3] = {ndof->tx, ndof->ty, 0.0f};
+				mul_v3_fl(pan_vec, pan_sensitivity * rv3d->dist * dt);
+
+				/* transform motion from view to world coordinates */
+				invert_qt_qt(view_inv, rv3d->viewquat);
+				mul_qt_v3(view_inv, pan_vec);
+
+				/* move center of view opposite of hand motion (this is camera mode, not object mode) */
+				sub_v3_v3(rv3d->ofs, pan_vec);
+			}
+
+			if (has_rotation) {
+
+				rv3d->view = RV3D_VIEW_USER;
+
+				if (U.ndof_flag & NDOF_TURNTABLE) {
+
+					/* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
+					float angle, rot[4];
+					float xvec[3] = {1, 0, 0};
+
+					/* Determine the direction of the x vector (for rotating up and down) */
+					mul_qt_v3(view_inv, xvec);
+
+					/* Perform the up/down rotation */
+					angle = rot_sensitivity * dt * ndof->rx;
+					if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
+						angle = -angle;
+					rot[0] = cos(angle);
+					mul_v3_v3fl(rot + 1, xvec, sin(angle));
+					mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+
+					/* Perform the orbital rotation */
+					angle = rot_sensitivity * dt * ndof->ry;
+					if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
+						angle = -angle;
+
+					/* update the onscreen doo-dad */
+					rv3d->rot_angle = angle;
+					rv3d->rot_axis[0] = 0;
+					rv3d->rot_axis[1] = 0;
+					rv3d->rot_axis[2] = 1;
+
+					rot[0] = cos(angle);
+					rot[1] = rot[2] = 0.0;
+					rot[3] = sin(angle);
+					mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+					
+				}
+				else {
+					float rot[4];
+					float axis[3];
+					float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
+
+					if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS)
+						axis[2] = -axis[2];
+
+					if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
+						axis[0] = -axis[0];
+
+					if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
+						axis[1] = -axis[1];
+					
+
+					/* transform rotation axis from view to world coordinates */
+					mul_qt_v3(view_inv, axis);
+
+					/* update the onscreen doo-dad */
+					rv3d->rot_angle = angle;
+					copy_v3_v3(rv3d->rot_axis, axis);
+
+					axis_angle_to_quat(rot, axis, angle);
+
+					/* apply rotation */
+					mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+					
+				}
+				
+				/* rotate around custom center */
+				if (vod && vod->use_dyn_ofs) {
+					float q1[4];
+					
+					/* compute the post multiplication quat, to rotate the offset correctly */
+					conjugate_qt_qt(q1, vod->oldquat);
+					mul_qt_qtqt(q1, q1, rv3d->viewquat);
+					
+					conjugate_qt(q1); /* conj == inv for unit quat */
+					copy_v3_v3(rv3d->ofs, vod->ofs);
+					sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
+					mul_qt_v3(q1, rv3d->ofs);
+					add_v3_v3(rv3d->ofs, vod->dyn_ofs);
+				}
+			}
+		}
+
+		viewops_data_free(C, op);
+		
+		ED_view3d_camera_lock_sync(v3d, rv3d);
+
+		ED_region_tag_redraw(CTX_wm_region(C));
+
+		return OPERATOR_FINISHED;
+	}
+}
+
+void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot)
+{
+	/* identifiers */
+	ot->name = "NDOF Orbit View with zoom";
+	ot->description = "Explore every angle of an object using the 3D mouse";
+	ot->idname = "VIEW3D_OT_ndof_orbit_zoom";
+
+	/* api callbacks */
+	ot->invoke = ndof_orbit_zoom_invoke;
+	ot->poll = ED_operator_view3d_active;
+
+	/* flags */
+	ot->flag = 0;
+}
+
 /* -- "pan" navigation
  * -- zoom or dolly?
  */
@@ -1197,8 +1378,7 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
 
 			mul_v3_fl(pan_vec, pan_sensitivity * rv3d->dist * dt);
 #else /* ------------------------------------------------------- dolly with Z */
-			float speed = 10.f; /* blender units per second */
-			/* ^^ this is ok for default cube scene, but should scale with.. something */
+			float speed = rv3d->dist; /* uses distance from pivot to define dolly */
 
 			/* tune these until everything feels right */
 			const float forward_sensitivity = 1.f;
@@ -1261,8 +1441,9 @@ void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot)
  */
 static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
-	if (event->type != NDOF_MOTION)
+	if (event->type != NDOF_MOTION) {
 		return OPERATOR_CANCELLED;
+	}
 	else {
 	
 		ViewOpsData *vod;
@@ -1282,23 +1463,14 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
 			const float dt = ndof->dt;
 			float view_inv[4];
 
-			float speed = 10.f; /* blender units per second */
-			/* ^^ this is ok for default cube scene, but should scale with.. something */
+			float speed = rv3d->dist; /* uses distance from pivot to define dolly */
 
 			/* tune these until everything feels right */
 			const float forward_sensitivity = 1.f;
 			const float vertical_sensitivity = 0.4f;
 			const float lateral_sensitivity = 0.6f;
-
 			float pan_vec[3];
 			const float rot_sensitivity = 1.f;
-#if 0
-			const float zoom_sensitivity = 1.f;
-			const float pan_sensitivity = 1.f;
-			float rot[4];
-			float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
-			float axis[3];
-#endif
 
 			/* inverse view */
 			invert_qt_qt(view_inv, rv3d->viewquat);
@@ -1389,7 +1561,7 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
 			}
 			
 			/* rotate around custom center */
-			if (vod && vod->use_dyn_ofs) {
+			if (vod->use_dyn_ofs) {
 				float q1[4];
 				
 				/* compute the post multiplication quat, to rotate the offset correctly */
@@ -1404,10 +1576,13 @@ static int ndof_all_invoke(bContext *C, wmOperator *op, wmEvent *event)
 			}
 
 		}
+		
+		viewops_data_free(C, op);
+		
 		ED_view3d_camera_lock_sync(v3d, rv3d);
 
 		ED_region_tag_redraw(CTX_wm_region(C));
-		viewops_data_free(C, op);
+		
 		return OPERATOR_FINISHED;
 	}
 }
@@ -3677,17 +3852,21 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
 
 /* ***************** 3d cursor cursor op ******************* */
 
-/* mx my in region coords */
-static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+/* cursor position in vec, result in vec, mval in region coords */
+/* note: cannot use event->mval here (called by object_add() */
+void ED_view3d_cursor3d_position(bContext *C, float *fp, int mx, int my)
 {
 	Scene *scene = CTX_data_scene(C);
 	ARegion *ar = CTX_wm_region(C);
 	View3D *v3d = CTX_wm_view3d(C);
 	RegionView3D *rv3d = CTX_wm_region_view3d(C);
-	float *fp = give_cursor(scene, v3d);
 	float mval_fl[2];
+	int mval[2];
 	int flip;
 
+	mval[0] = mx - ar->winrct.xmin;
+	mval[1] = my - ar->winrct.ymin;
+	
 	flip = initgrabz(rv3d, fp[0], fp[1], fp[2]);
 	
 	/* reset the depth based on the view offset (we _know_ the offset is infront of us) */
@@ -3702,20 +3881,20 @@ static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *
 
 		if (U.uiflag & USER_ZBUF_CURSOR) {  /* maybe this should be accessed some other way */
 			view3d_operator_needs_opengl(C);
-			if (ED_view3d_autodist(scene, ar, v3d, event->mval, fp))
+			if (ED_view3d_autodist(scene, ar, v3d, mval, fp))
 				depth_used = TRUE;
 		}
 
 		if (depth_used == FALSE) {
 			float dvec[3];
-			VECSUB2D(mval_fl, mval_fl, event->mval);
+			VECSUB2D(mval_fl, mval_fl, mval);
 			ED_view3d_win_to_delta(ar, mval_fl, dvec);
 			sub_v3_v3(fp, dvec);
 		}
 	}
 	else {
-		const float dx = ((float)(event->mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2);
-		const float dy = ((float)(event->mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2);
+		const float dx = ((float)(mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2);
+		const float dy = ((float)(mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2);
 		const float fz = (rv3d->persmat[0][3] * fp[0] +
 		                  rv3d->persmat[1][3] * fp[1] +
 		                  rv3d->persmat[2][3] * fp[2] +
@@ -3726,11 +3905,21 @@ static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *
 		fp[2] = (rv3d->persinv[0][2] * dx + rv3d->persinv[1][2] * dy + rv3d->persinv[2][2] * fz) - rv3d->ofs[2];
 	}
 
+}
+
+static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+{
+	Scene *scene = CTX_data_scene(C);
+	View3D *v3d = CTX_wm_view3d(C);
+	float *fp = give_cursor(scene, v3d);
+
+	ED_view3d_cursor3d_position(C, fp, event->x, event->y);
+	
 	if (v3d && v3d->localvd)
 		WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
 	else
 		WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
-
+	
 	return OPERATOR_FINISHED;
 }
 
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 79bf003a563..2b30e4e6b81 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -487,11 +487,17 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
 		block = uiLayoutGetBlock(row);
 		
 		if (v3d->twflag & V3D_USE_MANIPULATOR) {
-			but = uiDefIconButBitC(block, TOG, V3D_MANIP_TRANSLATE, B_MAN_TRANS, ICON_MAN_TRANS, 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, TIP_("Translate manipulator - Shift-Click for multiple modes"));
+			but = uiDefIconButBitC(block, TOG, V3D_MANIP_TRANSLATE, B_MAN_TRANS, ICON_MAN_TRANS,
+			                       0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0,
+			                       TIP_("Translate manipulator - Shift-Click for multiple modes"));
 			uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
-			but = uiDefIconButBitC(block, TOG, V3D_MANIP_ROTATE, B_MAN_ROT, ICON_MAN_ROT, 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, TIP_("Rotate manipulator - Shift-Click for multiple modes"));
+			but = uiDefIconButBitC(block, TOG, V3D_MANIP_ROTATE, B_MAN_ROT, ICON_MAN_ROT,
+			                       0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0,
+			                       TIP_("Rotate manipulator - Shift-Click for multiple modes"));
 			uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
-			but = uiDefIconButBitC(block, TOG, V3D_MANIP_SCALE, B_MAN_SCALE, ICON_MAN_SCALE, 0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0, TIP_("Scale manipulator - Shift-Click for multiple modes"));
+			but = uiDefIconButBitC(block, TOG, V3D_MANIP_SCALE, B_MAN_SCALE, ICON_MAN_SCALE,
+			                       0, 0, UI_UNIT_X, UI_UNIT_Y, &v3d->twtype, 1.0, 0.0, 0, 0,
+			                       TIP_("Scale manipulator - Shift-Click for multiple modes"));
 			uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
 		}
 			
@@ -500,7 +506,8 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
 		}
 			
 		str_menu = BIF_menustringTransformOrientation(C, "Orientation");
-		but = uiDefButC(block, MENU, B_MAN_MODE, str_menu, 0, 0, 70 * dpi_fac, UI_UNIT_Y, &v3d->twmode, 0, 0, 0, 0, TIP_("Transform Orientation"));
+		but = uiDefButC(block, MENU, B_MAN_MODE, str_menu, 0, 0, 70 * dpi_fac, UI_UNIT_Y, &v3d->twmode, 0, 0, 0, 0,
+		                TIP_("Transform Orientation"));
 		uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
 		MEM_freeN((void *)str_menu);
 	}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index f8a7cdde8a5..a6daf610052 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -77,6 +77,7 @@ void VIEW3D_OT_zoom_camera_1_to_1(struct wmOperatorType *ot);
 void VIEW3D_OT_move(struct wmOperatorType *ot);
 void VIEW3D_OT_rotate(struct wmOperatorType *ot);
 void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot);
+void VIEW3D_OT_ndof_orbit_zoom(struct wmOperatorType *ot);
 void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot);
 void VIEW3D_OT_ndof_all(struct wmOperatorType *ot);
 void VIEW3D_OT_view_all(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index a0b36e57d69..81e890c37ee 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -27,6 +27,7 @@
 #include "DNA_curve_types.h"
 #include "DNA_lattice_types.h"
 #include "DNA_meta_types.h"
+#include "DNA_mesh_types.h"
 #include "DNA_armature_types.h"
 #include "DNA_object_types.h"
 
@@ -47,6 +48,12 @@
 #include "ED_object.h"
 #include "ED_view3d.h"
 
+typedef struct foreachScreenObjectVert_userData {
+	void (*func)(void *userData, MVert *mv, const float screen_co_b[2], int index);
+	void *userData;
+	ViewContext vc;
+	eV3DProjTest clip_flag;
+} foreachScreenObjectVert_userData;
 
 typedef struct foreachScreenVert_userData {
 	void (*func)(void *userData, BMVert *eve, const float screen_co_b[2], int index);
@@ -79,6 +86,46 @@ typedef struct foreachScreenFace_userData {
 
 /* ------------------------------------------------------------------------ */
 
+
+static void meshobject_foreachScreenVert__mapFunc(void *userData, int index, const float co[3],
+                                            const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+	foreachScreenObjectVert_userData *data = userData;
+	struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index];
+
+	if (!(mv->flag & ME_HIDE)) {
+		float screen_co[2];
+
+		if (ED_view3d_project_float_object(data->vc.ar, co, screen_co, data->clip_flag) != V3D_PROJ_RET_OK) {
+			return;
+		}
+
+		data->func(data->userData, mv, screen_co, index);
+	}
+}
+
+void meshobject_foreachScreenVert(
+        ViewContext *vc,
+        void (*func)(void *userData, MVert *eve, const float screen_co[2], int index),
+        void *userData, eV3DProjTest clip_flag)
+{
+	foreachScreenObjectVert_userData data;
+	DerivedMesh *dm = mesh_get_derived_deform(vc->scene, vc->obact, CD_MASK_BAREMESH);
+
+	data.vc = *vc;
+	data.func = func;
+	data.userData = userData;
+	data.clip_flag = clip_flag;
+
+	if (clip_flag & V3D_PROJ_TEST_CLIP_BB) {
+		ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat);  /* for local clipping lookups */
+	}
+
+	dm->foreachMappedVert(dm, meshobject_foreachScreenVert__mapFunc, &data);
+
+	dm->release(dm);
+}
+
 static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3],
                                             const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
 {
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 4101ced616a..615ae71cf9b 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -131,6 +131,7 @@ void view3d_operatortypes(void)
 	WM_operatortype_append(VIEW3D_OT_zoom);
 	WM_operatortype_append(VIEW3D_OT_zoom_camera_1_to_1);
 	WM_operatortype_append(VIEW3D_OT_dolly);
+	WM_operatortype_append(VIEW3D_OT_ndof_orbit_zoom);
 	WM_operatortype_append(VIEW3D_OT_ndof_orbit);
 	WM_operatortype_append(VIEW3D_OT_ndof_pan);
 	WM_operatortype_append(VIEW3D_OT_ndof_all);
@@ -195,34 +196,6 @@ void view3d_keymap(wmKeyConfig *keyconf)
 	/* only for region 3D window */
 	keymap = WM_keymap_find(keyconf, "3D View", SPACE_VIEW3D, 0);
 
-
-	/* NDOF: begin */
-	/* note: positioned here so keymaps show keyboard keys if assigned */
-	/* 3D mouse */
-	WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit", NDOF_MOTION, 0, KM_CTRL, 0);
-	WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_pan", NDOF_MOTION, 0, KM_SHIFT, 0);
-	WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, 0, 0);
-	WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
-	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
-	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK);
-	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_LEFT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_LEFT);
-	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT);
-	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP);
-	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BOTTOM, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BOTTOM);
-
-	/* 3D mouse align */
-	kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, KM_SHIFT, 0);
-	RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT);
-	RNA_boolean_set(kmi->ptr, "align_active", TRUE);
-	kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, KM_SHIFT, 0);
-	RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT);
-	RNA_boolean_set(kmi->ptr, "align_active", TRUE);
-	kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0);
-	RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP);
-	RNA_boolean_set(kmi->ptr, "align_active", TRUE);
-	/* NDOF: end */
-
-
 	kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0);
 	RNA_boolean_set(kmi->ptr, "release_confirm", TRUE);
 	/*
@@ -248,9 +221,9 @@ void view3d_keymap(wmKeyConfig *keyconf)
 
 	WM_keymap_verify_item(keymap, "VIEW3D_OT_smoothview", TIMER1, KM_ANY, KM_ANY, 0);
 	
-	WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, KM_ALT, 0);
+	WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEPAN, 0, 0, 0);
 	WM_keymap_add_item(keymap, "VIEW3D_OT_rotate", MOUSEROTATE, 0, 0, 0);
-	WM_keymap_add_item(keymap, "VIEW3D_OT_move", MOUSEPAN, 0, 0, 0);
+	WM_keymap_add_item(keymap, "VIEW3D_OT_move", MOUSEPAN, 0, KM_SHIFT, 0);
 	WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEZOOM, 0, 0, 0);
 	WM_keymap_add_item(keymap, "VIEW3D_OT_zoom", MOUSEPAN, 0, KM_CTRL, 0);
 	
@@ -331,6 +304,34 @@ void view3d_keymap(wmKeyConfig *keyconf)
 
 	WM_keymap_add_item(keymap, "VIEW3D_OT_localview", PADSLASHKEY, KM_PRESS, 0, 0);
 	
+	/* NDOF: begin */
+	/* note: positioned here so keymaps show keyboard keys if assigned */
+	/* 3D mouse */
+	WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit_zoom", NDOF_MOTION, 0, 0, 0);
+	WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_orbit", NDOF_MOTION, 0, KM_CTRL, 0);
+	WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_pan", NDOF_MOTION, 0, KM_SHIFT, 0);
+	WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, KM_CTRL | KM_SHIFT, 0);
+	WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
+	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
+	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK);
+	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_LEFT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_LEFT);
+	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT);
+	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP);
+	RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BOTTOM, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BOTTOM);
+	
+	/* 3D mouse align */
+	kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, KM_SHIFT, 0);
+	RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT);
+	RNA_boolean_set(kmi->ptr, "align_active", TRUE);
+	kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, KM_SHIFT, 0);
+	RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT);
+	RNA_boolean_set(kmi->ptr, "align_active", TRUE);
+	kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0);
+	RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP);
+	RNA_boolean_set(kmi->ptr, "align_active", TRUE);
+	/* NDOF: end */
+	
+
 	/* layers, shift + alt are properties set in invoke() */
 	RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ACCENTGRAVEKEY, KM_PRESS, 0, 0)->ptr, "nr", 0);
 	RNA_int_set(WM_keymap_add_item(keymap, "VIEW3D_OT_layers", ONEKEY, KM_PRESS, KM_ANY, 0)->ptr, "nr", 1);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index d4bdf6c3177..c428cb02236 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -110,7 +110,7 @@ eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base)
 
 /* perspmat is typically...
  * - 'rv3d->perspmat',   is_local == FALSE
- * - 'rv3d->perspmatob', is_local == TRUE
+ * - 'rv3d->persmatob', is_local == TRUE
  */
 static eV3DProjStatus ed_view3d_project__internal(ARegion *ar,
                                                   float perspmat[4][4], const int is_local,  /* normally hidden */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index d37042fa2ec..dac887f7f13 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -70,6 +70,7 @@
 #include "BKE_paint.h"
 #include "BKE_tessmesh.h"
 #include "BKE_tracking.h"
+#include "BKE_utildefines.h"
 
 
 #include "BIF_gl.h"
@@ -741,67 +742,19 @@ static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short m
 	mball_foreachScreenElem(vc, do_lasso_select_mball__doSelectElem, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
 }
 
-static int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int extend)
+static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
 {
-	Mesh *me;
-	MVert *mvert;
-	struct ImBuf *ibuf;
-	unsigned int *rt;
-	int a, index;
-	char *selar;
-	int sx = BLI_rcti_size_x(rect) + 1;
-	int sy = BLI_rcti_size_y(rect) + 1;
+	LassoSelectUserData *data = userData;
 
-	me = vc->obact->data;
-
-	if (me == NULL || me->totvert == 0 || sx * sy <= 0)
-		return OPERATOR_CANCELLED;
-
-	selar = MEM_callocN(me->totvert + 1, "selar");
-
-	if (extend == 0 && select)
-		paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE);
-
-	view3d_validate_backbuf(vc);
-
-	ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect);
-	rt = ibuf->rect;
-	glReadPixels(rect->xmin + vc->ar->winrct.xmin,  rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
-	if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
-
-	a = sx * sy;
-	while (a--) {
-		if (*rt) {
-			index = WM_framebuffer_to_index(*rt);
-			if (index <= me->totvert) selar[index] = 1;
-		}
-		rt++;
+	if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+	    BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED))
+	{
+		BKE_BIT_TEST_SET(mv->flag, data->select, SELECT);
 	}
-
-	mvert = me->mvert;
-	for (a = 1; a <= me->totvert; a++, mvert++) {
-		if (selar[a]) {
-			if ((mvert->flag & ME_HIDE) == 0) {
-				if (select) mvert->flag |=  SELECT;
-				else        mvert->flag &= ~SELECT;
-			}
-		}
-	}
-
-	IMB_freeImBuf(ibuf);
-	MEM_freeN(selar);
-
-#ifdef __APPLE__	
-	glReadBuffer(GL_BACK);
-#endif
-
-	paintvert_flush_flags(vc->obact);
-
-	return OPERATOR_FINISHED;
 }
-
 static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, short extend, short select)
 {
+	const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
 	Object *ob = vc->obact;
 	Mesh *me = ob ? ob->data : NULL;
 	rcti rect;
@@ -811,14 +764,31 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh
 
 	if (extend == 0 && select)
 		paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE);  /* flush selection at the end */
-	bm_vertoffs = me->totvert + 1; /* max index array */
 
 	BLI_lasso_boundbox(&rect, mcords, moves);
-	EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
 
-	edbm_backbuf_check_and_select_verts_obmode(me, select);
+	if (use_zbuf) {
+		bm_vertoffs = me->totvert + 1; /* max index array */
 
-	EDBM_backbuf_free();
+		EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+		edbm_backbuf_check_and_select_verts_obmode(me, select);
+
+		EDBM_backbuf_free();
+	}
+	else {
+		LassoSelectUserData data;
+		rcti rect;
+
+		BLI_lasso_boundbox(&rect, mcords, moves);
+
+		view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select);
+
+		ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
+
+		meshobject_foreachScreenVert(vc, do_lasso_select_meshobject__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+	}
 
 	paintvert_flush_flags(ob);
 }
@@ -1217,31 +1187,42 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int
 	}
 }
 
+static int selectbuffer_has_bones(const unsigned int *buffer, const unsigned int hits)
+{
+	unsigned int i;
+	for (i = 0; i < hits; i++) {
+		if (buffer[(4 * i) + 3] & 0xFFFF0000) {
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
+
 /* we want a select buffer with bones, if there are... */
 /* so check three selection levels and compare */
 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2])
 {
 	rcti rect;
 	int offs;
-	short a, hits15, hits9 = 0, hits5 = 0;
-	short has_bones15 = 0, has_bones9 = 0, has_bones5 = 0;
+	short hits15, hits9 = 0, hits5 = 0;
+	short has_bones15 = FALSE, has_bones9 = FALSE, has_bones5 = FALSE;
 	
 	BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14);
 	hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
 	if (hits15 > 0) {
-		for (a = 0; a < hits15; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones15 = 1;
+		has_bones15 = selectbuffer_has_bones(buffer, hits15);
 
 		offs = 4 * hits15;
 		BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9);
 		hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect);
 		if (hits9 > 0) {
-			for (a = 0; a < hits9; a++) if (buffer[offs + 4 * a + 3] & 0xFFFF0000) has_bones9 = 1;
+			has_bones9 = selectbuffer_has_bones(buffer + offs, hits9);
 
 			offs += 4 * hits9;
 			BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5);
 			hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect);
 			if (hits5 > 0) {
-				for (a = 0; a < hits5; a++) if (buffer[offs + 4 * a + 3] & 0xFFFF0000) has_bones5 = 1;
+				has_bones5 = selectbuffer_has_bones(buffer + offs, hits5);
 			}
 		}
 		
@@ -1383,10 +1364,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
 	hits = mixed_bones_object_selectbuffer(&vc, buffer, mval);
 	
 	if (hits > 0) {
-		int a, has_bones = 0;
-		
-		for (a = 0; a < hits; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones = 1;
-		
+		const int has_bones = selectbuffer_has_bones(buffer, hits);
 		basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones);
 	}
 	
@@ -1420,7 +1398,6 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese
 	View3D *v3d = CTX_wm_view3d(C);
 	Scene *scene = CTX_data_scene(C);
 	Base *base, *startbase = NULL, *basact = NULL, *oldbasact = NULL;
-	int  a;
 	float dist = 100.0f;
 	int retval = 0;
 	short hits;
@@ -1473,10 +1450,8 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese
 		hits = mixed_bones_object_selectbuffer(&vc, buffer, mval);
 		
 		if (hits > 0) {
-			int has_bones = 0;
-			
 			/* note: bundles are handling in the same way as bones */
-			for (a = 0; a < hits; a++) if (buffer[4 * a + 3] & 0xFFFF0000) has_bones = 1;
+			const int has_bones = selectbuffer_has_bones(buffer, hits);
 
 			/* note; shift+alt goes to group-flush-selecting */
 			if (has_bones == 0 && enumerate) {
@@ -1502,7 +1477,7 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese
 							}
 
 							/* index of bundle is 1<<16-based. if there's no "bone" index
-							 * in height word, this buffer value belongs to camera,. not to bundle */
+							 * in height word, this buffer value belongs to camera. not to bundle */
 							if (buffer[4 * i + 3] & 0xFFFF0000) {
 								MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, 0);
 								MovieTracking *tracking = &clip->tracking;
@@ -1670,6 +1645,85 @@ int edge_inside_circle(const float cent[2], float radius, const float screen_co_
 	return FALSE;
 }
 
+static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
+{
+	BoxSelectUserData *data = userData;
+
+	if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) {
+		BKE_BIT_TEST_SET(mv->flag, data->select, SELECT);
+	}
+}
+static int do_paintvert_box_select(ViewContext *vc, rcti *rect, int select, int extend)
+{
+	const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
+	Mesh *me;
+	MVert *mvert;
+	struct ImBuf *ibuf;
+	unsigned int *rt;
+	int a, index;
+	char *selar;
+	int sx = BLI_rcti_size_x(rect) + 1;
+	int sy = BLI_rcti_size_y(rect) + 1;
+
+	me = vc->obact->data;
+
+	if (me == NULL || me->totvert == 0 || sx * sy <= 0)
+		return OPERATOR_CANCELLED;
+
+
+	if (extend == 0 && select)
+		paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE);
+
+	if (use_zbuf) {
+		selar = MEM_callocN(me->totvert + 1, "selar");
+		view3d_validate_backbuf(vc);
+
+		ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect);
+		rt = ibuf->rect;
+		glReadPixels(rect->xmin + vc->ar->winrct.xmin,  rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
+		if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+
+		a = sx * sy;
+		while (a--) {
+			if (*rt) {
+				index = WM_framebuffer_to_index(*rt);
+				if (index <= me->totvert) selar[index] = 1;
+			}
+			rt++;
+		}
+
+		mvert = me->mvert;
+		for (a = 1; a <= me->totvert; a++, mvert++) {
+			if (selar[a]) {
+				if ((mvert->flag & ME_HIDE) == 0) {
+					if (select) mvert->flag |=  SELECT;
+					else        mvert->flag &= ~SELECT;
+				}
+			}
+		}
+
+		IMB_freeImBuf(ibuf);
+		MEM_freeN(selar);
+
+#ifdef __APPLE__
+		glReadBuffer(GL_BACK);
+#endif
+	}
+	else {
+		BoxSelectUserData data;
+
+		view3d_userdata_boxselect_init(&data, vc, rect, select);
+
+		ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
+
+		meshobject_foreachScreenVert(vc, do_paintvert_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+	}
+
+	paintvert_flush_flags(vc->obact);
+
+	return OPERATOR_FINISHED;
+}
+
 static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
 {
 	BoxSelectUserData *data = userData;
@@ -2142,11 +2196,14 @@ void VIEW3D_OT_select_border(wmOperatorType *ot)
 /* gets called via generic mouse select operator */
 static int mouse_weight_paint_vertex_select(bContext *C, const int mval[2], short extend, short deselect, short toggle, Object *obact)
 {
+	View3D *v3d = CTX_wm_view3d(C);
+	const int use_zbuf = (v3d->flag & V3D_ZBUF_SELECT);
+
 	Mesh *me = obact->data; /* already checked for NULL */
 	unsigned int index = 0;
 	MVert *mv;
 
-	if (ED_mesh_pick_vert(C, me, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE)) {
+	if (ED_mesh_pick_vert(C, obact, mval, &index, ED_MESH_PICK_DEFAULT_VERT_SIZE, use_zbuf)) {
 		mv = &me->mvert[index];
 		if (extend) {
 			mv->flag |= SELECT;
@@ -2366,22 +2423,39 @@ static void paint_facesel_circle_select(ViewContext *vc, int select, const int m
 	}
 }
 
+static void paint_vertsel_circle_select_doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
+{
+	CircleSelectUserData *data = userData;
 
+	if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
+		BKE_BIT_TEST_SET(mv->flag, data->select, SELECT);
+	}
+}
 static void paint_vertsel_circle_select(ViewContext *vc, int select, const int mval[2], float rad)
 {
+	const int use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT);
 	Object *ob = vc->obact;
-	Mesh *me = ob ? ob->data : NULL;
+	Mesh *me = ob->data;
 	/* int bbsel; */ /* UNUSED */
 	/* CircleSelectUserData data = {NULL}; */ /* UNUSED */
-	if (me) {
+
+	if (use_zbuf) {
 		bm_vertoffs = me->totvert + 1; /* max index array */
 
 		/* bbsel = */ /* UNUSED */ EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f));
 		edbm_backbuf_check_and_select_verts_obmode(me, select == LEFTMOUSE);
 		EDBM_backbuf_free();
-
-		paintvert_flush_flags(ob);
 	}
+	else {
+		CircleSelectUserData data;
+
+		ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */
+
+		view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+		meshobject_foreachScreenVert(vc, paint_vertsel_circle_select_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+	}
+
+	paintvert_flush_flags(ob);
 }
 
 
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index b2ee17b8a8b..3b443e8bbac 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -686,6 +686,9 @@ static void view_editmove(unsigned short UNUSED(event))
 #define TFM_MODAL_EDGESLIDE_UP 24
 #define TFM_MODAL_EDGESLIDE_DOWN 25
 
+/* for analog input, like trackpad */
+#define TFM_MODAL_PROPSIZE		26
+
 /* called in transform_ops.c, on each regeneration of keymaps */
 wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
 {
@@ -715,6 +718,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
 		{TFM_MODAL_AUTOIK_LEN_DEC, "AUTOIK_CHAIN_LEN_DOWN", 0, "Decrease Max AutoIK Chain Length", ""},
 		{TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""},
 		{TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""},
+		{TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""},
 		{0, NULL, 0, NULL, NULL}
 	};
 	
@@ -750,6 +754,7 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
 	WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
 	WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
 	WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
+	WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE);
 
 	WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
 	WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_DOWN);
@@ -1024,6 +1029,19 @@ int transformEvent(TransInfo *t, wmEvent *event)
 				removeSnapPoint(t);
 				t->redraw |= TREDRAW_HARD;
 				break;
+				
+			case TFM_MODAL_PROPSIZE:
+				/* MOUSEPAN usage... */
+				if (t->flag & T_PROP_EDIT) {
+					float fac = 1.0f + 0.005f *(event->y - event->prevy);
+					t->prop_size *= fac;
+					if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
+						t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
+					calculatePropRatio(t);
+				}
+				t->redraw |= TREDRAW_HARD;
+				break;
+				
 			case TFM_MODAL_PROPSIZE_UP:
 				if (t->flag & T_PROP_EDIT) {
 					t->prop_size *= 1.1f;
@@ -1500,7 +1518,6 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
 				glTranslatef(mval[0], mval[1], 0);
 
 				glLineWidth(3.0);
-				glBegin(GL_LINES);
 				drawArrow(UP, 5, 10, 5);
 				drawArrow(DOWN, 5, 10, 5);
 				glLineWidth(1.0);
@@ -2258,8 +2275,8 @@ static void protectedQuaternionBits(short protectflag, float *quat, float *oldqu
 static void constraintTransLim(TransInfo *t, TransData *td)
 {
 	if (td->con) {
-		bConstraintTypeInfo *ctiLoc = get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
-		bConstraintTypeInfo *ctiDist = get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT);
+		bConstraintTypeInfo *ctiLoc = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
+		bConstraintTypeInfo *ctiDist = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT);
 		
 		bConstraintOb cob = {NULL};
 		bConstraint *con;
@@ -2309,7 +2326,7 @@ static void constraintTransLim(TransInfo *t, TransData *td)
 				}
 				
 				/* get constraint targets if needed */
-				get_constraint_targets_for_solving(con, &cob, &targets, ctime);
+				BKE_get_constraint_targets_for_solving(con, &cob, &targets, ctime);
 				
 				/* do constraint */
 				cti->evaluate_constraint(con, &cob, &targets);
@@ -2361,7 +2378,7 @@ static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
 static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
 {
 	if (td->con) {
-		bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
+		bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
 		bConstraintOb cob;
 		bConstraint *con;
 		int do_limit = FALSE;
@@ -2428,7 +2445,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
 static void constraintSizeLim(TransInfo *t, TransData *td)
 {
 	if (td->con && td->ext) {
-		bConstraintTypeInfo *cti = get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
+		bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
 		bConstraintOb cob = {NULL};
 		bConstraint *con;
 		float size_sign[3], size_abs[3];
@@ -2721,6 +2738,18 @@ int handleEventShear(TransInfo *t, wmEvent *event)
 
 		status = 1;
 	}
+	else if (event->type == XKEY && event->val == KM_PRESS) {
+		initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
+		t->customData = NULL;
+		
+		status = 1;
+	}
+	else if (event->type == YKEY && event->val == KM_PRESS) {
+		initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
+		t->customData = (void *)1;
+		
+		status = 1;
+	}
 	
 	return status;
 }
@@ -2754,7 +2783,7 @@ int Shear(TransInfo *t, const int UNUSED(mval[2]))
 	}
 	else {
 		/* default header print */
-		sprintf(str, "Shear: %.3f %s", value, t->proptext);
+		sprintf(str, "Shear: %.3f %s (Press X or Y to set shear axis)", value, t->proptext);
 	}
 	
 	t->values[0] = value;
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 7da47425370..12b0341d395 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -835,7 +835,7 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
 		}
 	}
 
-	con = add_pose_constraint(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
+	con = BKE_add_pose_constraint(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
 	pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);    /* for draw, but also for detecting while pose solving */
 	data = con->data;
 	if (targetless) {
@@ -4090,7 +4090,7 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count
 				/* Meta's can only directly be moved between channels since they
 				 * don't have their start and length set directly (children affect that)
 				 * since this Meta is nested we don't need any of its data in fact.
-				 * calc_sequence() will update its settings when run on the toplevel meta */
+				 * BKE_sequence_calc() will update its settings when run on the toplevel meta */
 				*flag = 0;
 				*count = 0;
 				*recursive = TRUE;
@@ -4268,8 +4268,8 @@ static void freeSeqData(TransInfo *t)
 			{
 				int overlap = 0;
 
+				seq_prev = NULL;
 				for (a = 0; a < t->total; a++, td++) {
-					seq_prev = NULL;
 					seq = ((TransDataSeq *)td->extra)->seq;
 					if ((seq != seq_prev) && (seq->depth == 0) && (seq->flag & SEQ_OVERLAP)) {
 						overlap = 1;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 8f1d6a7b46e..2591c61c5ab 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -61,6 +61,8 @@
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 
+#include "BIK_api.h"
+
 #include "BKE_animsys.h"
 #include "BKE_action.h"
 #include "BKE_armature.h"
@@ -847,6 +849,8 @@ static void recalcData_view3d(TransInfo *t)
 		/* old optimize trick... this enforces to bypass the depgraph */
 		if (!(arm->flag & ARM_DELAYDEFORM)) {
 			DAG_id_tag_update(&ob->id, OB_RECALC_DATA);  /* sets recalc flags */
+			/* transformation of pose may affect IK tree, make sure it is rebuilt */
+			BIK_clear_data(ob->pose);
 		}
 		else
 			BKE_pose_where_is(t->scene, ob);
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index c9c4f7e2c7b..4bd6496e083 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -764,7 +764,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
 			EditBone *ebone;
 			int ok = FALSE;
 			
-			/* grr,.but better then duplicate code */
+			/* grr. but better then duplicate code */
 #define EBONE_CALC_NORMAL_PLANE  { \
 			float tmat[3][3]; \
 			float vec[3]; \
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index 1753a564a3c..1dc7e0c90e8 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -162,15 +162,18 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
 		}
 	}
 	else {
-		int do_glob_undo = FALSE;
-		
+		/* Note: we used to do a fall-through here where if the
+		 * mode-specific undo system had no more steps to undo (or
+		 * redo), the global undo would run.
+		 *
+		 * That was inconsistent with editmode, and also makes for
+		 * unecessarily tricky interaction with the other undo
+		 * systems. */
 		if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) {
-			if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname))
-				do_glob_undo = TRUE;
+			ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname);
 		}
 		else if (obact && obact->mode & OB_MODE_SCULPT) {
-			if (!ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname))
-				do_glob_undo = TRUE;
+			ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname);
 		}
 		else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
 			if (step == 1)
@@ -178,24 +181,17 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
 			else
 				PE_redo(CTX_data_scene(C));
 		}
-		else {
-			do_glob_undo = TRUE;
-		}
-		
-		if (do_glob_undo) {
-			if (U.uiflag & USER_GLOBALUNDO) {
-				// note python defines not valid here anymore.
-				//#ifdef WITH_PYTHON
-				// XXX		BPY_scripts_clear_pyobjects();
-				//#endif
-				if (undoname)
-					BKE_undo_name(C, undoname);
-				else
-					BKE_undo_step(C, step);
+		else if (U.uiflag & USER_GLOBALUNDO) {
+			// note python defines not valid here anymore.
+			//#ifdef WITH_PYTHON
+			// XXX		BPY_scripts_clear_pyobjects();
+			//#endif
+			if (undoname)
+				BKE_undo_name(C, undoname);
+			else
+				BKE_undo_step(C, step);
 				
-				WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
-			}
-			
+			WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
 		}
 	}
 	
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 27bbba11e75..4d52282d540 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -73,6 +73,7 @@ void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditM
 /* utility tool functions */
 
 void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit);
+void uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, float *aspx, float *aspy);
 
 /* operators */
 
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index bd50857c8b8..8c3eaa1192f 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -136,6 +136,7 @@ typedef struct UvEdge {
 
 /* stitch state object */
 typedef struct StitchState {
+	float aspect;
 	/* use limit flag */
 	char use_limit;
 	/* limit to operator, same as original operator */
@@ -285,10 +286,12 @@ static int getNumOfIslandUvs(UvElementMap *elementMap, int island)
 	}
 }
 
-static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2])
+static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2], float aspect)
 {
 	float uv_rotation_result[2];
 
+	uv[1] /= aspect;
+
 	uv[0] -= medianPoint[0];
 	uv[1] -= medianPoint[1];
 
@@ -297,6 +300,8 @@ static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2])
 
 	uv[0] = uv_rotation_result[0] + medianPoint[0];
 	uv[1] = uv_rotation_result[1] + medianPoint[1];
+
+	uv[1] *= aspect;
 }
 
 /* check if two uvelements are stitchable. This should only operate on -different- separate UvElements */
@@ -413,9 +418,11 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition
 				island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements;
 				island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements;
 				island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements;
+				island_stitch_data[i].medianPoint[1] /= state->aspect;
 			}
 			island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements;
 			island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements;
+
 			numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
 			element = &state->element_map->buf[state->element_map->islandIndices[i]];
 			for (j = 0; j < numOfIslandUVs; j++, element++) {
@@ -429,7 +436,7 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition
 
 					if (final) {
 
-						stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, luv->uv);
+						stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, luv->uv, state->aspect);
 
 						add_v2_v2(luv->uv, island_stitch_data[i].translation);
 					}
@@ -438,7 +445,7 @@ static void stitch_calculate_island_snapping(StitchState *state, PreviewPosition
 						int face_preview_pos = preview_position[BM_elem_index_get(element->l->f)].data_position;
 
 						stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint,
-						                 preview->preview_polys + face_preview_pos + 2 * element->tfindex);
+						                 preview->preview_polys + face_preview_pos + 2 * element->tfindex, state->aspect);
 
 						add_v2_v2(preview->preview_polys + face_preview_pos + 2 * element->tfindex,
 						          island_stitch_data[i].translation);
@@ -461,15 +468,12 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *sta
 	int index1, index2;
 	float rotation;
 	MLoopUV *luv1, *luv2;
-	BMLoop *l1, *l2;
 
 	element1 = state->uvs[edge->uv1];
 	element2 = state->uvs[edge->uv2];
 
-	l1 = element1->l;
-	luv1 = CustomData_bmesh_get(&state->em->bm->ldata, l1->head.data, CD_MLOOPUV);
-	l2 = element2->l;
-	luv2 = CustomData_bmesh_get(&state->em->bm->ldata, l2->head.data, CD_MLOOPUV);
+	luv1 = CustomData_bmesh_get(&state->em->bm->ldata, element1->l->head.data, CD_MLOOPUV);
+	luv2 = CustomData_bmesh_get(&state->em->bm->ldata, element2->l->head.data, CD_MLOOPUV);
 
 	if (state->mode == STITCH_VERT) {
 		index1 = uvfinal_map[element1 - state->element_map->buf];
@@ -484,14 +488,18 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *sta
 	uv1[0] = luv2->uv[0] - luv1->uv[0];
 	uv1[1] = luv2->uv[1] - luv1->uv[1];
 
+	uv1[1] /= state->aspect;
+
 	uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0];
 	uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1];
 
+	uv2[1] /= state->aspect;
+
 	normalize_v2(uv1);
 	normalize_v2(uv2);
 
-	edgecos = uv1[0] * uv2[0] + uv1[1] * uv2[1];
-	edgesin = uv1[0] * uv2[1] - uv2[0] * uv1[1];
+	edgecos = dot_v2v2(uv1, uv2);
+	edgesin = cross_v2v2(uv1, uv2);
 
 	rotation = (edgesin > 0.0f) ?
 	            +acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))) :
@@ -536,7 +544,9 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat
 			negate_v2_v2(normal, state->normals + index_tmp2 * 2);
 			edgecos = dot_v2v2(normal, state->normals + index_tmp1 * 2);
 			edgesin = cross_v2v2(normal, state->normals + index_tmp1 * 2);
-			rotation += (edgesin > 0.0f) ? acosf(edgecos) : -acosf(edgecos);
+			rotation += (edgesin > 0.0f) ?
+			    +acosf(max_ff(-1.0f, min_ff(1.0f, edgecos))) :
+			    -acosf(max_ff(-1.0f, min_ff(1.0f, edgecos)));
 		}
 	}
 
@@ -837,13 +847,13 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
 	int previous_island = state->static_island;
 	BMFace *efa;
 	BMIter iter;
-	UVVertAverage *final_position;
+	UVVertAverage *final_position = NULL;
 
 	char stitch_midpoints = state->midpoints;
 	/* used to map uv indices to uvaverage indices for selection */
-	unsigned int *uvfinal_map;
+	unsigned int *uvfinal_map = NULL;
 	/* per face preview position in preview buffer */
-	PreviewPosition *preview_position;
+	PreviewPosition *preview_position = NULL;
 
 	/* cleanup previous preview */
 	stitch_preview_delete(state->stitch_preview);
@@ -1157,6 +1167,14 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
 		}
 	}
 
+	/* take mean position here. For edge case, this can't be done inside the loop for shared uvverts */
+	if (state->mode == STITCH_EDGE && stitch_midpoints) {
+		for (i = 0; i < state->total_separate_uvs; i++) {
+			final_position[i].uv[0] /= final_position[i].count;
+			final_position[i].uv[1] /= final_position[i].count;
+		}
+	}
+
 	/* second pass, calculate island rotation and translation before modifying any uvs */
 	if (state->snap_islands) {
 		if (state->mode == STITCH_VERT) {
@@ -1211,11 +1229,6 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final)
 			for (i = 0; i < state->total_separate_uvs; i++) {
 				UvElement *element = state->uvs[i];
 
-				if (stitch_midpoints) {
-					final_position[i].uv[0] /= final_position[i].count;
-					final_position[i].uv[1] /= final_position[i].count;
-				}
-
 				if (element->flag & STITCH_STITCHABLE) {
 					BMLoop *l;
 					MLoopUV *luv;
@@ -1419,18 +1432,19 @@ static void stitch_switch_selection_mode(StitchState *state)
 	MEM_freeN(old_selection_stack);
 }
 
-static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal)
+static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal, float aspect)
 {
 	BMLoop *l1 = edge->element->l;
-	BMLoop *l2 = l1->next;
 	MLoopUV *luv1, *luv2;
 	float tangent[2];
 
 	luv1 = CustomData_bmesh_get(&em->bm->ldata, l1->head.data, CD_MLOOPUV);
-	luv2 = CustomData_bmesh_get(&em->bm->ldata, l2->head.data, CD_MLOOPUV);
+	luv2 = CustomData_bmesh_get(&em->bm->ldata, l1->next->head.data, CD_MLOOPUV);
 
 	sub_v2_v2v2(tangent, luv2->uv,  luv1->uv);
 
+	tangent[1] /= aspect;
+
 	normal[0] = tangent[1];
 	normal[1] = -tangent[0];
 
@@ -1447,6 +1461,8 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *ar
 	glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
 	glEnableClientState(GL_VERTEX_ARRAY);
 
+	glPointSize(pointsize * 2.0f);
+
 	glEnable(GL_BLEND);
 
 	UI_ThemeColor4(TH_STITCH_PREVIEW_ACTIVE);
@@ -1462,19 +1478,18 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *ar
 		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 		UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE);
 		glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]);
+		#if 0
+		glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
+		UI_ThemeColor4(TH_STITCH_PREVIEW_VERT);
+		glDrawArrays(GL_POLYGON, index, stitch_preview->uvs_per_polygon[i]);
+		#endif
 
 		index += stitch_preview->uvs_per_polygon[i];
 	}
-	glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
-#if 0
-	UI_ThemeColor4(TH_STITCH_PREVIEW_VERT);
-	glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris * 3);
-#endif
 	glDisable(GL_BLEND);
 
 	/* draw vert preview */
 	if (state->mode == STITCH_VERT) {
-		glPointSize(pointsize * 2.0f);
 		UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
 		glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
 		glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable);
@@ -1541,7 +1556,7 @@ static int stitch_init(bContext *C, wmOperator *op)
 	Scene *scene = CTX_data_scene(C);
 	ToolSettings *ts = scene->toolsettings;
 	ARegion *ar = CTX_wm_region(C);
-
+	float aspx, aspy;
 	Object *obedit = CTX_data_edit_object(C);
 
 	if (!ar)
@@ -1595,6 +1610,9 @@ static int stitch_init(bContext *C, wmOperator *op)
 		return 0;
 	}
 
+	uvedit_get_aspect(scene, obedit, em, &aspx, &aspy);
+	state->aspect = aspx / aspy;
+
 	/* Entirely possible if redoing last operator that static island is bigger than total number of islands.
 	 * This ensures we get no hang in the island checking code in stitch_stitch_process_data. */
 	state->static_island %= state->element_map->totalIslands;
@@ -1720,15 +1738,16 @@ static int stitch_init(bContext *C, wmOperator *op)
 	 * the winding of the polygon (assuming counter-clockwise flow). */
 
 	for (i = 0; i < total_edges; i++) {
+		UvEdge *edge = edges + i;
 		float normal[2];
-		if (edges[i].flag & STITCH_BOUNDARY) {
-			stitch_calculate_edge_normal(em, edges + i, normal);
+		if (edge->flag & STITCH_BOUNDARY) {
+			stitch_calculate_edge_normal(em, edge, normal, state->aspect);
 
-			add_v2_v2(state->normals + edges[i].uv1 * 2, normal);
-			add_v2_v2(state->normals + edges[i].uv2 * 2, normal);
+			add_v2_v2(state->normals + edge->uv1 * 2, normal);
+			add_v2_v2(state->normals + edge->uv2 * 2, normal);
 
-			normalize_v2(state->normals + edges[i].uv1 * 2);
-			normalize_v2(state->normals + edges[i].uv2 * 2);
+			normalize_v2(state->normals + edge->uv1 * 2);
+			normalize_v2(state->normals + edge->uv2 * 2);
 		}
 	}
 
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 2ca711a4a6a..81f548b2b5d 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -196,7 +196,7 @@ static int uvedit_have_selection(Scene *scene, BMEditMesh *em, short implicit)
 	return 0;
 }
 
-static void ED_uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, float *aspy)
+void uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, float *aspy)
 {
 	int sloppy = TRUE;
 	int selected = FALSE;
@@ -238,7 +238,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMEditMesh
 	if (correct_aspect) {
 		float aspx, aspy;
 
-		ED_uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
+		uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
 
 		if (aspx != aspy)
 			param_aspect_ratio(handle, aspx, aspy);
@@ -423,7 +423,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, B
 	if (correct_aspect) {
 		float aspx, aspy;
 
-		ED_uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
+		uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
 
 		if (aspx != aspy)
 			param_aspect_ratio(handle, aspx, aspy);
@@ -1047,7 +1047,7 @@ static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em)
 	BMFace *efa;
 	float scale, aspx, aspy;
 	
-	ED_uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
+	uvedit_get_aspect(scene, ob, em, &aspx, &aspy);
 	
 	if (aspx == aspy)
 		return;
@@ -1563,7 +1563,6 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
 	uv_map_transform(C, op, center, rotmat);
 
 	BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
-		tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 		if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
 			continue;
 		
@@ -1573,6 +1572,7 @@ static int cylinder_project_exec(bContext *C, wmOperator *op)
 			uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
 		}
 
+		tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 		uv_map_mirror(em, efa, tf);
 	}
 
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 356b752466e..f80761c3cc7 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -117,6 +117,10 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render* re, int render_count) : Str
 	freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG;
 	BKE_scene_disable_color_management(freestyle_scene);
 
+	// Render layer
+	SceneRenderLayer *srl = (SceneRenderLayer *)freestyle_scene->r.layers.first;
+	srl->layflag = SCE_LAY_SOLID | SCE_LAY_ZTRA;
+
 	BKE_scene_set_background(G.main, freestyle_scene);
 
 	// Camera
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 9ce42d9e0bb..6abc41759e7 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
 	../blenkernel
 	../blenlib
 	../blenloader
+	../bmesh
 	../imbuf
 	../makesdna
 	../makesrna
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 36fbd818f11..9f6f80585ab 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -39,12 +39,15 @@
 #define DEBUG_VBO(X)
 #endif
 
+struct BMesh;
 struct CCGElem;
 struct CCGKey;
 struct CustomData;
 struct DMFlagMat;
 struct DerivedMesh;
+struct GHash;
 struct GPUVertPointLink;
+struct PBVH;
 
 typedef struct GPUBuffer {
 	int size;	/* in bytes */
@@ -168,12 +171,21 @@ void GPU_update_mesh_buffers(GPU_Buffers *buffers, MVert *mvert,
 GPU_Buffers *GPU_build_grid_buffers(int *grid_indices, int totgrid,
                                     unsigned int **grid_hidden, int gridsize);
 
+GPU_Buffers *GPU_build_bmesh_buffers(int smooth_shading);
+
+void GPU_update_bmesh_buffers(GPU_Buffers *buffers,
+							  struct BMesh *bm,
+							  struct GHash *bm_faces,
+							  struct GHash *bm_unique_verts,
+							  struct GHash *bm_other_verts);
+
 void GPU_update_grid_buffers(GPU_Buffers *buffers, struct CCGElem **grids,
                              const struct DMFlagMat *grid_flag_mats,
                              int *grid_indices, int totgrid, const struct CCGKey *key,
                              int show_diffuse_color);
 
-void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial);
+void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial,
+					  int wireframe);
 
 int GPU_buffers_diffuse_changed(GPU_Buffers *buffers, int show_diffuse_color);
 
diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript
index aeb7edc2c56..f7db3dfeaa0 100644
--- a/source/blender/gpu/SConscript
+++ b/source/blender/gpu/SConscript
@@ -33,7 +33,7 @@ sources += env.Glob('shaders/*.c')
 defs = [ 'GLEW_STATIC' ]
 
 incs = '../blenlib ../blenkernel ../makesdna ../makesrna ../include ../blenloader ../nodes ../nodes/intern'
-incs += ' #/extern/glew/include #intern/guardedalloc #intern/smoke/extern ../imbuf .'
+incs += ' #/extern/glew/include #intern/guardedalloc #intern/smoke/extern ../imbuf ../bmesh .'
 
 if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
     incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index daf97c4841f..5f9f68e9c99 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -57,6 +57,8 @@
 #include "GPU_buffers.h"
 #include "GPU_draw.h"
 
+#include "bmesh.h"
+
 typedef enum {
 	GPU_BUFFER_VERTEX_STATE = 1,
 	GPU_BUFFER_NORMAL_STATE = 2,
@@ -1269,6 +1271,8 @@ struct GPU_Buffers {
 	int totgrid;
 	int has_hidden;
 
+	int use_bmesh;
+
 	unsigned int tot_tri, tot_quad;
 
 	/* The PBVH ensures that either all faces in the node are
@@ -1862,6 +1866,254 @@ GPU_Buffers *GPU_build_grid_buffers(int *grid_indices, int totgrid,
 
 #undef FILL_QUAD_BUFFER
 
+/* Output a BMVert into a VertexBufferFormat array
+ *
+ * The vertex is skipped if hidden, otherwise the output goes into
+ * index '*v_index' in the 'vert_data' array and '*v_index' is
+ * incremented.
+ */
+static void gpu_bmesh_vert_to_buffer_copy(BMVert *v, BMesh *bm,
+										  VertexBufferFormat *vert_data,
+										  int *v_index,
+										  const float fno[3],
+										  const float *fmask)
+{
+	VertexBufferFormat *vd = &vert_data[*v_index];
+	float *mask;
+
+	if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+		/* TODO: should use material color */
+		float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f};
+
+		/* Set coord, normal, and mask */
+		copy_v3_v3(vd->co, v->co);
+		normal_float_to_short_v3(vd->no, fno ? fno : v->no);
+		mask = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_PAINT_MASK);
+		gpu_color_from_mask_copy(fmask ? *fmask : *mask,
+								 diffuse_color,
+								 vd->color);
+		
+
+		/* Assign index for use in the triangle index buffer */
+		BM_elem_index_set(v, (*v_index)); /* set_dirty! */
+
+		(*v_index)++;
+	}
+}
+
+/* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */
+static int gpu_bmesh_vert_visible_count(GHash *bm_unique_verts,
+										GHash *bm_other_verts)
+{
+	GHashIterator gh_iter;
+	int totvert = 0;
+
+	GHASH_ITER (gh_iter, bm_unique_verts) {
+		BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
+		if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+			totvert++;
+	}
+	GHASH_ITER (gh_iter, bm_other_verts) {
+		BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
+		if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+			totvert++;
+	}
+
+	return totvert;
+}
+
+/* Return TRUE if all vertices in the face are visible, FALSE otherwise */
+static int gpu_bmesh_face_visible(BMFace *f)
+{
+	BMIter bm_iter;
+	BMVert *v;
+
+	BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
+		if (BM_elem_flag_test(v, BM_ELEM_HIDDEN))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+/* Return the total number of visible faces */
+static int gpu_bmesh_face_visible_count(GHash *bm_faces)
+{
+	GHashIterator gh_iter;
+	int totface = 0;
+
+	GHASH_ITER (gh_iter, bm_faces) {
+		BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+
+		if (gpu_bmesh_face_visible(f))
+			totface++;
+	}
+
+	return totface;
+}
+
+/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
+   shading, an element index buffer. */
+void GPU_update_bmesh_buffers(GPU_Buffers *buffers,
+							  BMesh *bm,
+							  GHash *bm_faces,
+							  GHash *bm_unique_verts,
+							  GHash *bm_other_verts)
+{
+	VertexBufferFormat *vert_data;
+	void *tri_data;
+	int tottri, totvert, maxvert = 0;
+
+	if (!buffers->vert_buf || (buffers->smooth && !buffers->index_buf))
+		return;
+
+	/* Count visible triangles */
+	tottri = gpu_bmesh_face_visible_count(bm_faces);
+
+	if (buffers->smooth) {
+		/* Count visible vertices */
+		totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts);
+	}
+	else
+		totvert = tottri * 3;
+
+	/* Initialize vertex buffer */
+	glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
+	glBufferDataARB(GL_ARRAY_BUFFER_ARB,
+					sizeof(VertexBufferFormat) * totvert,
+					NULL, GL_STATIC_DRAW_ARB);
+
+	/* Fill vertex buffer */
+	vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+	if (vert_data) {
+		GHashIterator gh_iter;
+		int v_index = 0;
+
+		if (buffers->smooth) {
+			/* Vertices get an index assigned for use in the triangle
+			   index buffer */
+			bm->elem_index_dirty |= BM_VERT;
+
+			GHASH_ITER (gh_iter, bm_unique_verts) {
+				gpu_bmesh_vert_to_buffer_copy(BLI_ghashIterator_getKey(&gh_iter),
+											  bm, vert_data, &v_index, NULL, NULL);
+			}
+
+			GHASH_ITER (gh_iter, bm_other_verts) {
+				gpu_bmesh_vert_to_buffer_copy(BLI_ghashIterator_getKey(&gh_iter),
+											  bm, vert_data, &v_index, NULL, NULL);
+			}
+
+			maxvert = v_index;
+		}
+		else {
+			GHASH_ITER (gh_iter, bm_faces) {
+				BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+
+				BLI_assert(f->len == 3);
+
+				if (gpu_bmesh_face_visible(f)) {
+					BMVert *v[3];
+					float fmask = 0;
+					int i;
+
+					BM_iter_as_array(bm, BM_VERTS_OF_FACE, f, (void**)v, 3);
+
+					/* Average mask value */
+					for (i = 0; i < 3; i++) {
+						fmask += *((float*)CustomData_bmesh_get(&bm->vdata,
+																v[i]->head.data,
+																CD_PAINT_MASK));
+					}
+					fmask /= 3.0f;
+					
+					for (i = 0; i < 3; i++) {
+						gpu_bmesh_vert_to_buffer_copy(v[i], bm, vert_data,
+													  &v_index, f->no, &fmask);
+					}
+				}
+			}
+
+			buffers->tot_tri = tottri;
+		}
+
+		glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+	}
+	else {
+		/* Memory map failed */
+		glDeleteBuffersARB(1, &buffers->vert_buf);
+		buffers->vert_buf = 0;
+		return;
+	}
+
+	if (buffers->smooth) {
+		const int use_short = (maxvert < USHRT_MAX);
+
+		/* Initialize triangle index buffer */
+		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
+		glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
+						(use_short ?
+						 sizeof(unsigned short) :
+						 sizeof(unsigned int)) * 3 * tottri,
+						NULL, GL_STATIC_DRAW_ARB);
+
+		/* Fill triangle index buffer */
+		tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+		if (tri_data) {
+			GHashIterator gh_iter;
+
+			GHASH_ITER (gh_iter, bm_faces) {
+				BMIter bm_iter;
+				BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+				BMVert *v;
+
+				if (gpu_bmesh_face_visible(f)) {
+					BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
+						if (use_short) {
+							unsigned short *elem = tri_data;
+							(*elem) = BM_elem_index_get(v);
+							elem++;
+							tri_data = elem;
+						}
+						else {
+							unsigned int *elem = tri_data;
+							(*elem) = BM_elem_index_get(v);
+							elem++;
+							tri_data = elem;
+						}
+					}
+				}
+			}
+
+			glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+
+			buffers->tot_tri = tottri;
+			buffers->index_type = (use_short ?
+								   GL_UNSIGNED_SHORT :
+								   GL_UNSIGNED_INT);
+		}
+		else {
+			/* Memory map failed */
+			glDeleteBuffersARB(1, &buffers->index_buf);
+			buffers->index_buf = 0;
+		}
+	}
+}
+
+GPU_Buffers *GPU_build_bmesh_buffers(int smooth_shading)
+{
+	GPU_Buffers *buffers;
+
+	buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
+	if (smooth_shading)
+		glGenBuffersARB(1, &buffers->index_buf);
+	glGenBuffersARB(1, &buffers->vert_buf);
+	buffers->use_bmesh = TRUE;
+	buffers->smooth = smooth_shading;
+
+	return buffers;
+}
+
 static void gpu_draw_buffers_legacy_mesh(GPU_Buffers *buffers)
 {
 	const MVert *mvert = buffers->mvert;
@@ -2060,7 +2312,8 @@ static void gpu_draw_buffers_legacy_grids(GPU_Buffers *buffers)
 	}
 }
 
-void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial)
+void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial,
+					  int wireframe)
 {
 	if (buffers->totface) {
 		const MFace *f = &buffers->mface[buffers->face_indices[0]];
@@ -2077,14 +2330,19 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial)
 
 	if (buffers->vert_buf) {
 		glEnableClientState(GL_VERTEX_ARRAY);
-		glEnableClientState(GL_NORMAL_ARRAY);
-		gpu_colors_enable(VBO_ENABLED);
+		if (!wireframe) {
+			glEnableClientState(GL_NORMAL_ARRAY);
+			gpu_colors_enable(VBO_ENABLED);
+		}
 
 		glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
 
 		if (buffers->index_buf)
 			glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
 
+		if (wireframe)
+			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
 		if (buffers->tot_quad) {
 			char *offset = 0;
 			int i, last = buffers->has_hidden ? 1 : buffers->totgrid;
@@ -2117,13 +2375,18 @@ void GPU_draw_buffers(GPU_Buffers *buffers, DMSetMaterial setMaterial)
 				glDrawArrays(GL_TRIANGLES, 0, totelem);
 		}
 
+		if (wireframe)
+			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
 		glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
 		if (buffers->index_buf)
 			glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
 
 		glDisableClientState(GL_VERTEX_ARRAY);
-		glDisableClientState(GL_NORMAL_ARRAY);
-		gpu_colors_disable(VBO_ENABLED);
+		if (!wireframe) {
+			glDisableClientState(GL_NORMAL_ARRAY);
+			gpu_colors_disable(VBO_ENABLED);
+		}
 	}
 	/* fallbacks if we are out of memory or VBO is disabled */
 	else if (buffers->totface) {
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 07462302700..254899e6e07 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -92,7 +92,7 @@ void GPU_render_text(MTFace *tface, int mode,
 	float *v1, float *v2, float *v3, float *v4, int glattrib)
 {
 	if ((mode & GEMAT_TEXT) && (textlen>0) && tface->tpage) {
-		Image* ima = (Image*)tface->tpage;
+		Image* ima = (Image *)tface->tpage;
 		int index, character;
 		float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
 		float advance_tab;
@@ -556,8 +556,9 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
 				if (do_color_management) {
 					srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(float)*4, "floar_buf_col_cor");
 					IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float,
-						ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, 0,
+						ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE,
 						ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+					IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y);
 					/* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */
 					IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y);
 					frect= srgb_frect + texwinsy*ibuf->x + texwinsx;
@@ -581,8 +582,9 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, int compare, int
 				if (do_color_management) {
 					frect = srgb_frect = MEM_mallocN(ibuf->x*ibuf->y*sizeof(*srgb_frect)*4, "floar_buf_col_cor");
 					IMB_buffer_float_from_float(srgb_frect, ibuf->rect_float,
-							ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, 0,
+							ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE,
 							ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+					IMB_buffer_float_unpremultiply(srgb_frect, ibuf->x, ibuf->y);
 					/* clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images */
 					IMB_buffer_float_clamp(srgb_frect, ibuf->x, ibuf->y);
 				}
@@ -813,7 +815,7 @@ void GPU_create_gl_tex_compressed(unsigned int *bind, unsigned int *pix, int x,
 	glBindTexture(GL_TEXTURE_2D, *bind);
 
 	if (GPU_upload_dxt_texture(ibuf) == 0) {
-		glDeleteTextures(1, (GLuint*)bind);
+		glDeleteTextures(1, (GLuint *)bind);
 		GPU_create_gl_tex(bind, pix, NULL, x, y, mipmap, 0, ima);
 	}
 #endif
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index 7a0ac29c9ab..bc859d0ec07 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -134,8 +134,8 @@ void GPU_extensions_init(void)
 	glGetIntegerv(GL_BLUE_BITS, &b);
 	GG.colordepth = r+g+b; /* assumes same depth for RGB */
 
-	vendor = (const char*)glGetString(GL_VENDOR);
-	renderer = (const char*)glGetString(GL_RENDERER);
+	vendor = (const char *)glGetString(GL_VENDOR);
+	renderer = (const char *)glGetString(GL_RENDERER);
 
 	if (strstr(vendor, "ATI")) {
 		GG.device = GPU_DEVICE_ATI;
@@ -916,7 +916,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b
 	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object);
 
 	GPU_shader_bind(blur_shader);
-	GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float*)scaleh);
+	GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scaleh);
 	GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex);
 	glViewport(0, 0, GPU_texture_opengl_width(blurtex), GPU_texture_opengl_height(blurtex));
 
@@ -942,7 +942,7 @@ void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *b
 
 	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
 	glViewport(0, 0, GPU_texture_opengl_width(tex), GPU_texture_opengl_height(tex));
-	GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float*)scalev);
+	GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, (float *)scalev);
 	GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex);
 	GPU_texture_bind(blurtex, 0);
 
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 2039f01a740..a2fc1eb05ec 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -1035,8 +1035,7 @@ static void do_material_tex(GPUShadeInput *shi)
 				GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, FALSE), &tin, &trgb);
 				rgbnor= TEX_RGB;
 
-				if (tex->imaflag & TEX_USEALPHA)
-					talpha= 1;
+				talpha= 1;
 			}
 			else {
 				continue;
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c
index 75aaa23369b..67f0694797b 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.c
+++ b/source/blender/ikplugin/intern/iksolver_plugin.c
@@ -372,7 +372,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
 		/* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
 		 * strictly speaking, it is a posechannel)
 		 */
-		get_constraint_target_matrix(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+		BKE_get_constraint_target_matrix(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
 
 		/* and set and transform goal */
 		mult_m4_m4m4(goal, goalinv, rootmat);
@@ -383,7 +383,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
 
 		/* same for pole vector target */
 		if (data->poletar) {
-			get_constraint_target_matrix(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+			BKE_get_constraint_target_matrix(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
 
 			if (data->flag & CONSTRAINT_IK_SETANGLE) {
 				/* don't solve IK when we are setting the pole angle */
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 903080d5b79..e1ef7d92bd0 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -370,7 +370,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co
 
 static bool is_cartesian_constraint(bConstraint *con)
 {
-	//bKinematicConstraint* data=(bKinematicConstraint*)con->data;
+	//bKinematicConstraint* data=(bKinematicConstraint *)con->data;
 
 	return true;
 }
@@ -551,7 +551,7 @@ static bool target_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Fram
 	bConstraint *constraint = (bConstraint *)target->blenderConstraint;
 	float tarmat[4][4];
 
-	get_constraint_target_matrix(target->blscene, constraint, 0, CONSTRAINT_OBTYPE_OBJECT, target->owner, tarmat, 1.0);
+	BKE_get_constraint_target_matrix(target->blscene, constraint, 0, CONSTRAINT_OBTYPE_OBJECT, target->owner, tarmat, 1.0);
 
 	// rootmat contains the target pose in world coordinate
 	// if enforce is != 1.0, blend the target position with the end effector position
@@ -620,7 +620,7 @@ static bool base_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Frame&
 		IK_Channel &rootchan = ikscene->channels[0];
 
 		// get polar target matrix in world space
-		get_constraint_target_matrix(ikscene->blscene, ikscene->polarConstraint, 1, CONSTRAINT_OBTYPE_OBJECT, ikscene->blArmature, mat, 1.0);
+		BKE_get_constraint_target_matrix(ikscene->blscene, ikscene->polarConstraint, 1, CONSTRAINT_OBTYPE_OBJECT, ikscene->blArmature, mat, 1.0);
 		// convert to armature space
 		mult_m4_m4m4(polemat, imat, mat);
 		// get the target in world space (was computed before as target object are defined before base object)
@@ -864,7 +864,7 @@ static bool joint_callback(const iTaSC::Timestamp& timestamp, iTaSC::ConstraintV
 }
 
 // build array of joint corresponding to IK chain
-static int convert_channels(IK_Scene *ikscene, PoseTree *tree)
+static int convert_channels(IK_Scene *ikscene, PoseTree *tree, float ctime)
 {
 	IK_Channel *ikchan;
 	bPoseChannel *pchan;
@@ -877,6 +877,14 @@ static int convert_channels(IK_Scene *ikscene, PoseTree *tree)
 		ikchan->parent = (a > 0) ? tree->parent[a] : -1;
 		ikchan->owner = ikscene->blArmature;
 
+		// the constraint and channels must be applied before we build the iTaSC scene,
+		// this is because some of the pose data (e.g. pose head) don't have corresponding 
+		// joint angles and can't be applied to the iTaSC armature dynamically
+		if (!(pchan->flag & POSE_DONE))
+			BKE_pose_where_is_bone(ikscene->blscene, ikscene->blArmature, pchan, ctime, 1);
+		// tell blender that this channel was controlled by IK, it's cleared on each BKE_pose_where_is()
+		pchan->flag |= (POSE_DONE | POSE_CHAIN);
+
 		/* set DoF flag */
 		flag = 0;
 		if (!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP) &&
@@ -1049,7 +1057,7 @@ static void BKE_pose_rest(IK_Scene *ikscene)
 	}
 }
 
-static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan)
+static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan, float ctime)
 {
 	PoseTree *tree = (PoseTree *)pchan->iktree.first;
 	PoseTarget *target;
@@ -1068,6 +1076,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan)
 	float length;
 	bool ret = true, ingame;
 	double *rot;
+	float start[3];
 
 	if (tree->totchannel == 0)
 		return NULL;
@@ -1126,7 +1135,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan)
 	std::vector weights;
 	double weight[3];
 	// build the array of joints corresponding to the IK chain
-	convert_channels(ikscene, tree);
+	convert_channels(ikscene, tree, ctime);
 	if (ingame) {
 		// in the GE, set the initial joint angle to match the current pose
 		// this will update the jointArray in ikscene
@@ -1137,17 +1146,37 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan)
 		BKE_pose_rest(ikscene);
 	}
 	rot = ikscene->jointArray(0);
+
 	for (a = 0, ikchan = ikscene->channels; a < tree->totchannel; ++a, ++ikchan) {
 		pchan = ikchan->pchan;
 		bone = pchan->bone;
 
 		KDL::Frame tip(iTaSC::F_identity);
+		// compute the position and rotation of the head from previous segment
 		Vector3 *fl = bone->bone_mat;
 		KDL::Rotation brot(
 		    fl[0][0], fl[1][0], fl[2][0],
 		    fl[0][1], fl[1][1], fl[2][1],
 		    fl[0][2], fl[1][2], fl[2][2]);
-		KDL::Vector bpos(bone->head[0], bone->head[1], bone->head[2]);
+		// if the bone is disconnected, the head is movable in pose mode
+		// take that into account by using pose matrix instead of bone
+		// Note that pose is expressed in armature space, convert to previous bone space
+		{
+			float R_parmat[3][3];
+			float iR_parmat[3][3];
+			if (pchan->parent)
+				copy_m3_m4(R_parmat, pchan->parent->pose_mat);
+			else
+				unit_m3(R_parmat);
+			if (pchan->parent)
+				sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail);
+			else
+				start[0] = start[1] = start[2] = 0.0f;
+			invert_m3_m3(iR_parmat, R_parmat);
+			normalize_m3(iR_parmat);
+			mul_m3_v3(iR_parmat, start);
+		}
+		KDL::Vector bpos(start[0], start[1], start[2]);
 		bpos *= ikscene->blScale;
 		KDL::Frame head(brot, bpos);
 
@@ -1155,7 +1184,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan)
 		length = bone->length * ikscene->blScale;
 		parent = (a > 0) ? ikscene->channels[tree->parent[a]].tail : root;
 		// first the fixed segment to the bone head
-		if (head.p.Norm() > KDL::epsilon || head.M.GetRot().Norm() > KDL::epsilon) {
+		if (!(ikchan->pchan->bone->flag & BONE_CONNECTED) || head.M.GetRot().Norm() > KDL::epsilon) {
 			joint = bone->name;
 			joint += ":H";
 			ret = arm->addSegment(joint, parent, KDL::Joint::None, 0.0, head);
@@ -1497,7 +1526,7 @@ static IK_Scene *convert_tree(Scene *blscene, Object *ob, bPoseChannel *pchan)
 	return ikscene;
 }
 
-static void create_scene(Scene *scene, Object *ob)
+static void create_scene(Scene *scene, Object *ob, float ctime)
 {
 	bPoseChannel *pchan;
 
@@ -1508,7 +1537,7 @@ static void create_scene(Scene *scene, Object *ob)
 		if (tree) {
 			IK_Data *ikdata = get_ikdata(ob->pose);
 			// convert tree in iTaSC::Scene
-			IK_Scene *ikscene = convert_tree(scene, ob, pchan);
+			IK_Scene *ikscene = convert_tree(scene, ob, pchan, ctime);
 			if (ikscene) {
 				ikscene->next = ikdata->first;
 				ikdata->first = ikscene;
@@ -1732,15 +1761,21 @@ void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime)
 			count += initialize_scene(ob, pchan);
 	}
 	// if at least one tree, create the scenes from the PoseTree stored in the channels
-	if (count)
-		create_scene(scene, ob);
-	itasc_update_param(ob->pose);
+	// postpone until execute_tree: this way the pose constraint are included
+	//if (count)
+	//	create_scene(scene, ob, ctime);
+	//itasc_update_param(ob->pose);
 	// make sure we don't rebuilt until the user changes something important
 	ob->pose->flag &= ~POSE_WAS_REBUILT;
 }
 
 void itasc_execute_tree(struct Scene *scene, struct Object *ob,  struct bPoseChannel *pchan, float ctime)
 {
+	if (!ob->pose->ikdata) {
+		// IK tree not yet created, no it now
+		create_scene(scene, ob, ctime);
+		itasc_update_param(ob->pose);
+	}
 	if (ob->pose->ikdata) {
 		IK_Data *ikdata = (IK_Data *)ob->pose->ikdata;
 		bItasc *ikparam = (bItasc *) ob->pose->ikparam;
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 0653956e113..1e33f8da363 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -138,6 +138,7 @@ struct ColormanageProcessor *IMB_colormanagement_display_processor_new(const str
                                                                        const struct ColorManagedDisplaySettings *display_settings);
 struct ColormanageProcessor *IMB_colormanagement_colorspace_processor_new(const char *from_colorspace, const char *to_colorspace);
 void IMB_colormanagement_processor_apply_v4(struct ColormanageProcessor *cm_processor, float pixel[4]);
+void IMB_colormanagement_processor_apply_v4_predivide(struct ColormanageProcessor *cm_processor, float pixel[4]);
 void IMB_colormanagement_processor_apply_v3(struct ColormanageProcessor *cm_processor, float pixel[3]);
 void IMB_colormanagement_processor_apply(struct ColormanageProcessor *cm_processor, float *buffer, int width, int height,
                                          int channels, int predivide);
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index db1404813b1..850060ef4d5 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -373,7 +373,6 @@ void IMB_rect_from_float(struct ImBuf *ibuf);
  * Changed part will be stored in buffer. This is expected to be used for texture painting updates */
 void IMB_partial_rect_from_float(struct ImBuf *ibuf, float *buffer, int x, int y, int w, int h, int is_data);
 void IMB_float_from_rect(struct ImBuf *ibuf);
-void IMB_float_from_rect_simple(struct ImBuf *ibuf); /* no profile conversion */
 /* note, check that the conversion exists, only some are supported */
 float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc);
 void IMB_color_to_bw(struct ImBuf *ibuf);
@@ -393,6 +392,8 @@ void IMB_buffer_byte_from_byte(unsigned char *rect_to, const unsigned char *rect
 	int profile_to, int profile_from, int predivide,
 	int width, int height, int stride_to, int stride_from);
 void IMB_buffer_float_clamp(float *buf, int width, int height);
+void IMB_buffer_float_unpremultiply(float *buf, int width, int height);
+void IMB_buffer_float_premultiply(float *buf, int width, int height);
 
 /**
  * Change the ordering of the color bytes pointed to by rect from
@@ -467,6 +468,7 @@ void IMB_flipy(struct ImBuf *ibuf);
 /* Premultiply alpha */
 
 void IMB_premultiply_alpha(struct ImBuf *ibuf);
+void IMB_unpremultiply_alpha(struct ImBuf *ibuf);
 
 /**
  *
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 28e62d496b2..49e2e7fc80d 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -167,14 +167,15 @@ typedef struct ImBuf {
 #define IB_animdeinterlace	(1 << 9)
 #define IB_tiles			(1 << 10)
 #define IB_tilecache		(1 << 11)
-#define IB_premul			(1 << 12)
-#define IB_cm_predivide		(1 << 13)
+#define IB_alphamode_premul	(1 << 12)  /* indicates whether image on disk have premul alpha */
+#define IB_alphamode_detect	(1 << 13)  /* if this flag is set, alpha mode would be guessed from file */
+#define IB_ignore_alpha		(1 << 14)  /* ignore alpha on load and substitude it with 1.0f */
 
 /*
  * The bit flag is stored in the ImBuf.ftype variable.
- * Note that the lower 10 bits is used for storing custom flags
+ * Note that the lower 11 bits is used for storing custom flags
  */
-#define IB_CUSTOM_FLAGS_MASK 0x3ff
+#define IB_CUSTOM_FLAGS_MASK 0x400
 
 #define PNG				(1 << 30)
 #define TGA				(1 << 28)
@@ -217,8 +218,12 @@ typedef struct ImBuf {
 #define JP2_YCC			(1 << 15)
 #define JP2_CINE		(1 << 14)
 #define JP2_CINE_48FPS	(1 << 13) 
+#define JP2_JP2	(1 << 12)
+#define JP2_J2K	(1 << 11)
 #endif
 
+#define PNG_16BIT			(1 << 10)
+
 #define RAWTGA	        (TGA | 1)
 
 #define JPG_STD	        (JPG | (0 << 8))
diff --git a/source/blender/imbuf/intern/IMB_filter.h b/source/blender/imbuf/intern/IMB_filter.h
index eaedb160c94..6bd5f44307f 100644
--- a/source/blender/imbuf/intern/IMB_filter.h
+++ b/source/blender/imbuf/intern/IMB_filter.h
@@ -41,6 +41,9 @@ void imb_filterx(struct ImBuf *ibuf);
 void IMB_premultiply_rect(unsigned int *rect, char planes, int w, int h);
 void IMB_premultiply_rect_float(float *rect_float, char planes, int w, int h);
 
+void IMB_unpremultiply_rect(unsigned int *rect, char planes, int w, int h);
+void IMB_unpremultiply_rect_float(float *rect_float, char planes, int w, int h);
+
 void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1);
 
 #endif
diff --git a/source/blender/imbuf/intern/IMB_metadata.h b/source/blender/imbuf/intern/IMB_metadata.h
index a68d7a7813e..f731fd69620 100644
--- a/source/blender/imbuf/intern/IMB_metadata.h
+++ b/source/blender/imbuf/intern/IMB_metadata.h
@@ -42,7 +42,7 @@ typedef struct ImMetaData {
 	int len;
 } ImMetaData;
 
-/** The metadata is a list of key/value pairs (both char*) that can me
+/** The metadata is a list of key/value pairs (both char *) that can me
  * saved in the header of several image formats.
  * Apart from some common keys like
  * 'Software' and 'Description' (png standard) we'll use keys within the
diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c
index c8bc3f8ebb8..ba84063f317 100644
--- a/source/blender/imbuf/intern/cineon/cineon_dpx.c
+++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c
@@ -95,6 +95,9 @@ static struct ImBuf *imb_load_dpx_cineon(unsigned char *mem, size_t size, int us
 	if (flags & IB_rect)
 		IMB_rect_from_float(ibuf);
 
+	if (flags & IB_alphamode_detect)
+		ibuf->flags |= IB_alphamode_premul;
+
 	return ibuf;
 }
 
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 1c68a466ade..bcfddfe425a 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -189,7 +189,6 @@ typedef struct ColormnaageCacheData {
 	int flag;        /* view flags of cached buffer */
 	float exposure;  /* exposure value cached buffer is calculated with */
 	float gamma;     /* gamma value cached buffer is calculated with */
-	int predivide;   /* predivide flag of cached buffer */
 	CurveMapping *curve_mapping;  /* curve mapping used for cached buffer */
 	int curve_mapping_timestamp;  /* time stamp of curve mapping used for cached buffer */
 } ColormnaageCacheData;
@@ -323,7 +322,6 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV
 	ColormanageCacheKey key;
 	ImBuf *cache_ibuf;
 	int view_flag = 1 << (view_settings->view - 1);
-	int predivide = ibuf->flags & IB_cm_predivide;
 	CurveMapping *curve_mapping = view_settings->curve_mapping;
 	int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
 
@@ -353,7 +351,6 @@ static unsigned char *colormanage_cache_get(ImBuf *ibuf, const ColormanageCacheV
 
 		if (cache_data->exposure != view_settings->exposure ||
 		    cache_data->gamma != view_settings->gamma ||
-			cache_data->predivide != predivide ||
 			cache_data->flag != view_settings->flag ||
 			cache_data->curve_mapping != curve_mapping ||
 			cache_data->curve_mapping_timestamp != curve_mapping_timestamp)
@@ -379,7 +376,6 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting
 	ImBuf *cache_ibuf;
 	ColormnaageCacheData *cache_data;
 	int view_flag = 1 << (view_settings->view - 1);
-	int predivide = ibuf->flags & IB_cm_predivide;
 	struct MovieCache *moviecache = colormanage_moviecache_ensure(ibuf);
 	CurveMapping *curve_mapping = view_settings->curve_mapping;
 	int curve_mapping_timestamp = curve_mapping ? curve_mapping->changed_timestamp : 0;
@@ -400,7 +396,6 @@ static void colormanage_cache_put(ImBuf *ibuf, const ColormanageCacheViewSetting
 	cache_data = MEM_callocN(sizeof(ColormnaageCacheData), "color manage cache imbuf data");
 	cache_data->exposure = view_settings->exposure;
 	cache_data->gamma = view_settings->gamma;
-	cache_data->predivide = predivide;
 	cache_data->flag = view_settings->flag;
 	cache_data->curve_mapping = curve_mapping;
 	cache_data->curve_mapping_timestamp = curve_mapping_timestamp;
@@ -897,13 +892,12 @@ void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace)
 
 	if (ibuf->rect_float) {
 		const char *to_colorspace = global_role_scene_linear;
-		int predivide = ibuf->flags & IB_cm_predivide;
 
 		if (ibuf->rect)
 			imb_freerectImBuf(ibuf);
 
 		IMB_colormanagement_transform(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
-		                              from_colorspace, to_colorspace, predivide);
+		                              from_colorspace, to_colorspace, TRUE);
 	}
 }
 
@@ -1130,7 +1124,6 @@ typedef struct DisplayBufferThread {
 
 	int channels;
 	float dither;
-	int predivide;
 	int is_data;
 
 	const char *byte_colorspace;
@@ -1158,7 +1151,6 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l
 	DisplayBufferInitData *init_data = (DisplayBufferInitData *) init_data_v;
 	ImBuf *ibuf = init_data->ibuf;
 
-	int predivide = ibuf->flags & IB_cm_predivide;
 	int channels = ibuf->channels;
 	float dither = ibuf->dither;
 	int is_data = ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA;
@@ -1189,7 +1181,6 @@ static void display_buffer_init_handle(void *handle_v, int start_line, int tot_l
 
 	handle->channels = channels;
 	handle->dither = dither;
-	handle->predivide = predivide;
 	handle->is_data = is_data;
 
 	handle->byte_colorspace = init_data->byte_colorspace;
@@ -1206,7 +1197,6 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle)
 
 	int buffer_size = channels * width * height;
 
-	int predivide = handle->predivide;
 	int is_data = handle->is_data;
 	int is_data_display = handle->cm_processor->is_data_result;
 
@@ -1224,16 +1214,25 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle)
 
 		/* first convert byte buffer to float, keep in image space */
 		for (i = 0, fp = linear_buffer, cp = byte_buffer;
-		     i < channels * width * height;
-		     i++, fp++, cp++)
+		     i < width * height;
+		     i++, fp += channels, cp += channels)
 		{
-			*fp = (float)(*cp) / 255.0f;
+			if (channels == 3) {
+				rgb_uchar_to_float(fp, cp);
+			}
+			else if (channels == 4) {
+				rgba_uchar_to_float(fp, cp);
+				straight_to_premul_v4(fp, fp);
+			}
+			else {
+				BLI_assert(!"Buffers of 3 or 4 channels are only supported here");
+			}
 		}
 
 		if (!is_data && !is_data_display) {
 			/* convert float buffer to scene linear space */
 			IMB_colormanagement_transform(linear_buffer, width, height, channels,
-			                              from_colorspace, to_colorspace, predivide);
+			                              from_colorspace, to_colorspace, TRUE);
 		}
 	}
 	else if (handle->float_colorspace) {
@@ -1249,7 +1248,7 @@ static void *display_buffer_apply_get_linear_buffer(DisplayBufferThread *handle)
 		memcpy(linear_buffer, handle->buffer, buffer_size * sizeof(float));
 
 		IMB_colormanagement_transform(linear_buffer, width, height, channels,
-		                              from_colorspace, to_colorspace, predivide);
+		                              from_colorspace, to_colorspace, TRUE);
 	}
 	else {
 		/* some processors would want to modify float original buffer
@@ -1277,13 +1276,12 @@ static void *do_display_buffer_apply_thread(void *handle_v)
 	int width = handle->width;
 	int height = handle->tot_line;
 	float dither = handle->dither;
-	int predivide = handle->predivide;
 	int is_data = handle->is_data;
 
 	if (cm_processor == NULL) {
 		if (display_buffer_byte) {
 			IMB_buffer_byte_from_byte(display_buffer_byte, handle->byte_buffer, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
-			                         FALSE, width, height, width, width);
+			                          FALSE, width, height, width, width);
 		}
 
 		if (display_buffer) {
@@ -1301,7 +1299,7 @@ static void *do_display_buffer_apply_thread(void *handle_v)
 		}
 		else {
 			/* apply processor */
-			IMB_colormanagement_processor_apply(cm_processor, linear_buffer, width, height, channels, predivide);
+			IMB_colormanagement_processor_apply(cm_processor, linear_buffer, width, height, channels, TRUE);
 		}
 
 		/* copy result to output buffers */
@@ -1309,7 +1307,7 @@ static void *do_display_buffer_apply_thread(void *handle_v)
 			/* do conversion */
 			IMB_buffer_byte_from_float(display_buffer_byte, linear_buffer,
 			                           channels, dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
-			                           predivide, width, height, width, width);
+			                           TRUE, width, height, width, width);
 		}
 
 		if (display_buffer)
@@ -1663,7 +1661,7 @@ static void colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorMan
 
 	if (global_tot_display == 0 || global_tot_view == 0) {
 		IMB_buffer_float_from_float(ibuf->rect_float, ibuf->rect_float, ibuf->channels, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB,
-		                            ibuf->flags & IB_cm_predivide, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+		                            TRUE, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
 	}
 	else {
 		colormanage_display_buffer_process_ex(ibuf, ibuf->rect_float, (unsigned char *)ibuf->rect,
@@ -2326,7 +2324,6 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
 {
 	int x, y;
 	int channels = ibuf->channels;
-	int predivide = ibuf->flags & IB_cm_predivide;
 	float dither = ibuf->dither;
 	ColorSpace *rect_colorspace = ibuf->rect_colorspace;
 	float *display_buffer_float = NULL;
@@ -2350,13 +2347,11 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
 			else if (byte_buffer) {
 				rgba_uchar_to_float(pixel, byte_buffer + linear_index);
 				IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, rect_colorspace);
+				straight_to_premul_v4(pixel, pixel);
 			}
 
 			if (!is_data) {
-				if (predivide)
-					IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
-				else
-					IMB_colormanagement_processor_apply_v4(cm_processor, pixel);
+				IMB_colormanagement_processor_apply_v4_predivide(cm_processor, pixel);
 			}
 
 			if (display_buffer_float) {
@@ -2365,7 +2360,9 @@ static void partial_buffer_update_rect(ImBuf *ibuf, unsigned char *display_buffe
 				copy_v4_v4(display_buffer_float + index, pixel);
 			}
 			else {
-				rgba_float_to_uchar(display_buffer + display_index, pixel);
+				float pixel_straight[4];
+				premul_to_straight_v4(pixel_straight, pixel);
+				rgba_float_to_uchar(display_buffer + display_index, pixel_straight);
 			}
 		}
 	}
@@ -2389,7 +2386,6 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
 		/* update byte buffer created by legacy color management */
 
 		unsigned char *rect = (unsigned char *) ibuf->rect;
-		int predivide = ibuf->flags & IB_cm_predivide;
 		int channels = ibuf->channels;
 		int width = xmax - xmin;
 		int height = ymax - ymin;
@@ -2397,7 +2393,7 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
 		int linear_index = ((ymin - offset_y) * stride + (xmin - offset_x)) * channels;
 
 		IMB_buffer_byte_from_float(rect + rect_index, linear_buffer + linear_index, channels, ibuf->dither,
-		                           IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, predivide, width, height, ibuf->x, stride);
+		                           IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE, width, height, ibuf->x, stride);
 	}
 
 	if (ibuf->display_buffer_flags) {
@@ -2503,6 +2499,15 @@ void IMB_colormanagement_processor_apply_v4(ColormanageProcessor *cm_processor,
 		OCIO_processorApplyRGBA(cm_processor->processor, pixel);
 }
 
+void IMB_colormanagement_processor_apply_v4_predivide(ColormanageProcessor *cm_processor, float pixel[4])
+{
+	if (cm_processor->curve_mapping)
+		curvemapping_evaluate_premulRGBF(cm_processor->curve_mapping, pixel, pixel);
+
+	if (cm_processor->processor)
+		OCIO_processorApplyRGBA_predivide(cm_processor->processor, pixel);
+}
+
 void IMB_colormanagement_processor_apply_v3(ColormanageProcessor *cm_processor, float pixel[3])
 {
 	if (cm_processor->curve_mapping)
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
index 5459cffe590..c41bbd594b3 100644
--- a/source/blender/imbuf/intern/dds/dds_api.cpp
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -164,7 +164,7 @@ struct ImBuf *imb_load_dds(unsigned char *mem, size_t size, int flags, char colo
 		}
 
 		if (ibuf->dds_data.fourcc != FOURCC_DDS) {
-			ibuf->dds_data.data = (unsigned char*)dds.readData(ibuf->dds_data.size);
+			ibuf->dds_data.data = (unsigned char *)dds.readData(ibuf->dds_data.size);
 
 			/* flip compressed texture */
 			FlipDXTCImage(dds.width(), dds.height(), dds.mipmapCount(), dds.fourCC(), ibuf->dds_data.data);
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index f049c404e2d..f0d8b7cac72 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -39,6 +39,7 @@
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 #include "IMB_allocimbuf.h"
+#include "IMB_filter.h"
 
 #include "IMB_colormanagement.h"
 #include "IMB_colormanagement_intern.h"
@@ -249,11 +250,25 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
 			uchar *to = rect_to + stride_to * y * 4;
 
 			if (profile_to == profile_from) {
+				float straight[4];
+
 				/* no color space conversion */
-				if (dither) {
+				if (dither && predivide) {
+					for (x = 0; x < width; x++, from += 4, to += 4) {
+						premul_to_straight_v4(straight, from);
+						float_to_byte_dither_v4(to, straight, di);
+					}
+				}
+				else if (dither) {
 					for (x = 0; x < width; x++, from += 4, to += 4)
 						float_to_byte_dither_v4(to, from, di);
 				}
+				else if (predivide) {
+					for (x = 0; x < width; x++, from += 4, to += 4) {
+						premul_to_straight_v4(straight, from);
+						rgba_float_to_uchar(to, straight);
+					}
+				}
 				else {
 					for (x = 0; x < width; x++, from += 4, to += 4)
 						rgba_float_to_uchar(to, from);
@@ -262,10 +277,12 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
 			else if (profile_to == IB_PROFILE_SRGB) {
 				/* convert from linear to sRGB */
 				unsigned short us[4];
+				float straight[4];
 
 				if (dither && predivide) {
 					for (x = 0; x < width; x++, from += 4, to += 4) {
-						linearrgb_to_srgb_ushort4_predivide(us, from);
+						premul_to_straight_v4(straight, from);
+						linearrgb_to_srgb_ushort4(us, from);
 						ushort_to_byte_dither_v4(to, us, di);
 					}
 				}
@@ -277,7 +294,8 @@ void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
 				}
 				else if (predivide) {
 					for (x = 0; x < width; x++, from += 4, to += 4) {
-						linearrgb_to_srgb_ushort4_predivide(us, from);
+						premul_to_straight_v4(straight, from);
+						linearrgb_to_srgb_ushort4(us, from);
 						ushort_to_byte_v4(to, us);
 					}
 				}
@@ -526,7 +544,6 @@ void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from,
 
 void IMB_rect_from_float(ImBuf *ibuf)
 {
-	int predivide = (ibuf->flags & IB_cm_predivide);
 	float *buffer;
 	const char *from_colorspace;
 
@@ -548,7 +565,10 @@ void IMB_rect_from_float(ImBuf *ibuf)
 	buffer = MEM_dupallocN(ibuf->rect_float);
 
 	/* first make float buffer in byte space */
-	IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, predivide);
+	IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, TRUE);
+
+	/* convert from float's premul alpha to byte's straight alpha */
+	IMB_unpremultiply_rect_float(buffer, ibuf->planes, ibuf->x, ibuf->y);
 
 	/* convert float to byte */
 	IMB_buffer_byte_from_float((unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
@@ -565,7 +585,6 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w
 {
 	float *rect_float;
 	uchar *rect_byte;
-	int predivide = (ibuf->flags & IB_cm_predivide);
 	int profile_from = IB_PROFILE_LINEAR_RGB;
 
 	/* verify we have a float buffer */
@@ -588,12 +607,12 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w
 
 		/* and do color space conversion to byte */
 		IMB_buffer_byte_from_float(rect_byte, rect_float,
-		                           4, ibuf->dither, IB_PROFILE_SRGB, profile_from, predivide,
+		                           4, ibuf->dither, IB_PROFILE_SRGB, profile_from, TRUE,
 		                           w, h, ibuf->x, w);
 	}
 	else {
 		IMB_buffer_float_from_float(buffer, rect_float,
-		                            ibuf->channels, IB_PROFILE_SRGB, profile_from, predivide,
+		                            ibuf->channels, IB_PROFILE_SRGB, profile_from, TRUE,
 		                            w, h, w, ibuf->x);
 
 		/* XXX: need to convert to image buffer's rect space */
@@ -608,8 +627,6 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w
 
 void IMB_float_from_rect(ImBuf *ibuf)
 {
-	int predivide = (ibuf->flags & IB_cm_predivide);
-
 	/* verify if we byte and float buffers */
 	if (ibuf->rect == NULL)
 		return;
@@ -634,24 +651,14 @@ void IMB_float_from_rect(ImBuf *ibuf)
 
 	/* then make float be in linear space */
 	IMB_colormanagement_colorspace_to_scene_linear(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels,
-	                                               ibuf->rect_colorspace, predivide);
+	                                               ibuf->rect_colorspace, FALSE);
+
+	/* byte buffer is straight alpha, float should always be premul */
+	IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y);
 
 	BLI_unlock_thread(LOCK_COLORMANAGE);
 }
 
-/* no profile conversion */
-void IMB_float_from_rect_simple(ImBuf *ibuf)
-{
-	int predivide = (ibuf->flags & IB_cm_predivide);
-
-	if (ibuf->rect_float == NULL)
-		imb_addrectfloatImBuf(ibuf);
-
-	IMB_buffer_float_from_byte(ibuf->rect_float, (uchar *)ibuf->rect,
-	                           IB_PROFILE_SRGB, IB_PROFILE_SRGB, predivide,
-	                           ibuf->x, ibuf->y, ibuf->x, ibuf->x);
-}
-
 /* use when you need to get a buffer with a certain profile
  * if the return  */
 
@@ -660,7 +667,6 @@ void IMB_float_from_rect_simple(ImBuf *ibuf)
  */
 float *IMB_float_profile_ensure(ImBuf *ibuf, int profile, int *alloc)
 {
-	int predivide = (ibuf->flags & IB_cm_predivide);
 	int profile_from = IB_PROFILE_LINEAR_RGB;
 	int profile_to;
 
@@ -686,12 +692,13 @@ float *IMB_float_profile_ensure(ImBuf *ibuf, int profile, int *alloc)
 
 		if (ibuf->rect_float == NULL) {
 			IMB_buffer_float_from_byte(fbuf, (uchar *)ibuf->rect,
-			                           profile_to, profile_from, predivide,
+			                           profile_to, profile_from, FALSE,
 			                           ibuf->x, ibuf->y, ibuf->x, ibuf->x);
+			IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y);
 		}
 		else {
 			IMB_buffer_float_from_float(fbuf, ibuf->rect_float,
-			                            4, profile_to, profile_from, predivide,
+			                            4, profile_to, profile_from, TRUE,
 			                            ibuf->x, ibuf->y, ibuf->x, ibuf->x);
 		}
 
@@ -727,6 +734,26 @@ void IMB_buffer_float_clamp(float *buf, int width, int height)
 	}
 }
 
+void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
+{
+	int total = width * height;
+	float *cp = buf;
+	while (total--) {
+		premul_to_straight_v4(cp, cp);
+		cp += 4;
+	}
+}
+
+void IMB_buffer_float_premultiply(float *buf, int width, int height)
+{
+	int total = width * height;
+	float *cp = buf;
+	while (total--) {
+		straight_to_premul_v4(cp, cp);
+		cp += 4;
+	}
+}
+
 /**************************** alter saturation *****************************/
 
 void IMB_saturation(ImBuf *ibuf, float sat)
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
index 678b2908b96..51fee232034 100644
--- a/source/blender/imbuf/intern/filter.c
+++ b/source/blender/imbuf/intern/filter.c
@@ -599,3 +599,67 @@ void IMB_premultiply_alpha(ImBuf *ibuf)
 		IMB_premultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y);
 }
 
+void IMB_unpremultiply_rect(unsigned int *rect, char planes, int w, int h)
+{
+	char *cp;
+	int x, y;
+	float val;
+
+	if (planes == 24) { /* put alpha at 255 */
+		cp = (char *)(rect);
+
+		for (y = 0; y < h; y++)
+			for (x = 0; x < w; x++, cp += 4)
+				cp[3] = 255;
+	}
+	else {
+		cp = (char *)(rect);
+
+		for (y = 0; y < h; y++) {
+			for (x = 0; x < w; x++, cp += 4) {
+				val = cp[3] != 0 ? 1.0f / (float)cp[3] : 1.0f;
+				cp[0] = FTOCHAR(cp[0] * val);
+				cp[1] = FTOCHAR(cp[1] * val);
+				cp[2] = FTOCHAR(cp[2] * val);
+			}
+		}
+	}
+}
+
+void IMB_unpremultiply_rect_float(float *rect_float, char planes, int w, int h)
+{
+	float val, *fp;
+	int x, y;
+
+	if (planes == 24) {   /* put alpha at 1.0 */
+		fp = rect_float;
+
+		for (y = 0; y < h; y++)
+			for (x = 0; x < w; x++, fp += 4)
+				fp[3] = 1.0;
+	}
+	else {
+		fp = rect_float;
+		for (y = 0; y < h; y++) {
+			for (x = 0; x < w; x++, fp += 4) {
+				val = fp[3] != 0.0f ? 1.0f / fp[3] : 1.0f;
+				fp[0] = fp[0] * val;
+				fp[1] = fp[1] * val;
+				fp[2] = fp[2] * val;
+			}
+		}
+	}
+
+}
+
+void IMB_unpremultiply_alpha(ImBuf *ibuf)
+{
+	if (ibuf == NULL)
+		return;
+
+	if (ibuf->rect)
+		IMB_unpremultiply_rect(ibuf->rect, ibuf->planes, ibuf->x, ibuf->y);
+
+	if (ibuf->rect_float)
+		IMB_unpremultiply_rect_float(ibuf->rect_float, ibuf->planes, ibuf->x, ibuf->y);
+}
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index 92b8dd8c724..1eac6236829 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -104,7 +104,7 @@ void bicubic_interpolation_color(struct ImBuf *in, unsigned char outI[4], float
 		BLI_bicubic_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
 	}
 	else {
-		BLI_bicubic_interpolation_char((unsigned char*) in->rect, outI, in->x, in->y, 4, u, v);
+		BLI_bicubic_interpolation_char((unsigned char *) in->rect, outI, in->x, in->y, 4, u, v);
 	}
 }
 
@@ -130,7 +130,7 @@ void bilinear_interpolation_color(struct ImBuf *in, unsigned char outI[4], float
 		BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v);
 	}
 	else {
-		BLI_bilinear_interpolation_char((unsigned char*) in->rect, outI, in->x, in->y, 4, u, v);
+		BLI_bilinear_interpolation_char((unsigned char *) in->rect, outI, in->x, in->y, 4, u, v);
 	}
 }
 
diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c
index 3a2bf99c75c..8d6218a389e 100644
--- a/source/blender/imbuf/intern/jp2.c
+++ b/source/blender/imbuf/intern/jp2.c
@@ -228,6 +228,10 @@ struct ImBuf *imb_jp2_decode(unsigned char *mem, size_t size, int flags, char co
 	}
 	
 	ibuf->ftype = JP2;
+	if (is_jp2)
+		ibuf->ftype |= JP2_JP2;
+	else
+		ibuf->ftype |= JP2_J2K;
 	
 	if (use_float) {
 		float *rect_float = ibuf->rect_float;
@@ -852,9 +856,15 @@ int imb_savejp2(struct ImBuf *ibuf, const char *name, int flags)
 		int codestream_length;
 		opj_cio_t *cio = NULL;
 		FILE *f = NULL;
+		opj_cinfo_t *cinfo = NULL;
 
 		/* get a JP2 compressor handle */
-		opj_cinfo_t *cinfo = opj_create_compress(CODEC_JP2);
+		if (ibuf->ftype & JP2_JP2)
+			cinfo = opj_create_compress(CODEC_JP2);
+		else if (ibuf->ftype & JP2_J2K)
+			cinfo = opj_create_compress(CODEC_J2K);
+		else
+			BLI_assert(!"Unsupported codec was specified in save settings");
 
 		/* catch events using our callbacks and give a local context */
 		opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, stderr);
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index 758617bdd48..6a5b534c688 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -234,7 +234,7 @@ static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, size_t
  * If must suspend, take the specified action (typically "return FALSE").
  */
 #define INPUT_BYTE(cinfo, V, action)  \
-	MAKESTMT(MAKE_BYTE_AVAIL(cinfo,action); \
+	MAKESTMT(MAKE_BYTE_AVAIL(cinfo, action); \
 	         bytes_in_buffer--; \
 	         V = GETJOCTET(*next_input_byte++); )
 
@@ -242,7 +242,7 @@ static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, size_t
  * V should be declared unsigned int or perhaps INT32.
  */
 #define INPUT_2BYTES(cinfo, V, action)  \
-	MAKESTMT(MAKE_BYTE_AVAIL(cinfo,action); \
+	MAKESTMT(MAKE_BYTE_AVAIL(cinfo, action); \
 	      bytes_in_buffer--; \
 	      V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \
 	      MAKE_BYTE_AVAIL(cinfo, action); \
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index da7b31cc2ba..18b08c9b59b 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -1197,6 +1197,9 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
 					delete file;
 				}
 			}
+
+			if (flags & IB_alphamode_detect)
+				ibuf->flags |= IB_alphamode_premul;
 		}
 		return(ibuf);
 	}
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index dcfebb95b87..bbe43132051 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -109,10 +109,14 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
 
 	unsigned char *pixels = NULL;
 	unsigned char *from, *to;
+	unsigned short *pixels16 = NULL, *to16;
+	float *from_float, from_straight[4];
 	png_bytepp row_pointers = NULL;
 	int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY;
 	FILE *fp = NULL;
 
+	int is_16bit = (ibuf->ftype & PNG_16BIT) && ibuf->rect_float;
+
 	/* use the jpeg quality setting for compression */
 	int compression;
 	compression = (int)(((float)(ibuf->ftype & 0xff) / 11.1111f));
@@ -150,8 +154,12 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
 
 	/* copy image data */
 
-	pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
-	if (pixels == NULL) {
+	if (is_16bit)
+		pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned short), "png 16bit pixels");
+	else
+		pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "png 8bit pixels");
+
+	if (pixels == NULL && pixels16 == NULL) {
 		png_destroy_write_struct(&png_ptr, &info_ptr);
 		printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name);
 		return 0;
@@ -159,32 +167,66 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
 
 	from = (unsigned char *) ibuf->rect;
 	to = pixels;
+	from_float = ibuf->rect_float;
+	to16 = pixels16;
 
 	switch (bytesperpixel) {
 		case 4:
 			color_type = PNG_COLOR_TYPE_RGBA;
-			for (i = ibuf->x * ibuf->y; i > 0; i--) {
-				to[0] = from[0];
-				to[1] = from[1];
-				to[2] = from[2];
-				to[3] = from[3];
-				to += 4; from += 4;
+			if (is_16bit) {
+				for (i = ibuf->x * ibuf->y; i > 0; i--) {
+					premul_to_straight_v4(from_straight, from_float);
+					to16[0] = FTOUSHORT(from_straight[0]);
+					to16[1] = FTOUSHORT(from_straight[1]);
+					to16[2] = FTOUSHORT(from_straight[2]);
+					to16[3] = FTOUSHORT(from_straight[3]);
+					to16 += 4; from_float += 4;
+				}
+			}
+			else {
+				for (i = ibuf->x * ibuf->y; i > 0; i--) {
+					to[0] = from[0];
+					to[1] = from[1];
+					to[2] = from[2];
+					to[3] = from[3];
+					to += 4; from += 4;
+				}
 			}
 			break;
 		case 3:
 			color_type = PNG_COLOR_TYPE_RGB;
-			for (i = ibuf->x * ibuf->y; i > 0; i--) {
-				to[0] = from[0];
-				to[1] = from[1];
-				to[2] = from[2];
-				to += 3; from += 4;
+			if (is_16bit) {
+				for (i = ibuf->x * ibuf->y; i > 0; i--) {
+					premul_to_straight_v4(from_straight, from_float);
+					to16[0] = FTOUSHORT(from_straight[0]);
+					to16[1] = FTOUSHORT(from_straight[1]);
+					to16[2] = FTOUSHORT(from_straight[2]);
+					to16 += 3; from_float += 4;
+				}
+			}
+			else {
+				for (i = ibuf->x * ibuf->y; i > 0; i--) {
+					to[0] = from[0];
+					to[1] = from[1];
+					to[2] = from[2];
+					to += 3; from += 4;
+				}
 			}
 			break;
 		case 1:
 			color_type = PNG_COLOR_TYPE_GRAY;
-			for (i = ibuf->x * ibuf->y; i > 0; i--) {
-				to[0] = from[0];
-				to++; from += 4;
+			if (is_16bit) {
+				for (i = ibuf->x * ibuf->y; i > 0; i--) {
+					premul_to_straight_v4(from_straight, from_float);
+					to16[0] = FTOUSHORT(from_straight[0]);
+					to16++; from_float += 4;
+				}
+			}
+			else {
+				for (i = ibuf->x * ibuf->y; i > 0; i--) {
+					to[0] = from[0];
+					to++; from += 4;
+				}
 			}
 			break;
 	}
@@ -203,7 +245,10 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
 		fp = BLI_fopen(name, "wb");
 		if (!fp) {
 			png_destroy_write_struct(&png_ptr, &info_ptr);
-			MEM_freeN(pixels);
+			if (pixels)
+				MEM_freeN(pixels);
+			if (pixels16)
+				MEM_freeN(pixels16);
 			printf("imb_savepng: Cannot open file for writing: '%s'\n", name);
 			return 0;
 		}
@@ -227,7 +272,7 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
 	             info_ptr,
 	             ibuf->x,
 	             ibuf->y,
-	             8,
+	             is_16bit ? 16 : 8,
 	             color_type,
 	             PNG_INTERLACE_NONE,
 	             PNG_COMPRESSION_TYPE_DEFAULT,
@@ -268,12 +313,19 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
 	/* write the file header information */
 	png_write_info(png_ptr, info_ptr);
 
+#ifdef __LITTLE_ENDIAN__
+	png_set_swap(png_ptr);
+#endif
+
 	/* allocate memory for an array of row-pointers */
 	row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
 	if (row_pointers == NULL) {
 		printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name);
 		png_destroy_write_struct(&png_ptr, &info_ptr);
-		MEM_freeN(pixels);
+		if (pixels)
+			MEM_freeN(pixels);
+		if (pixels16)
+			MEM_freeN(pixels16);
 		if (fp) {
 			fclose(fp);
 		}
@@ -281,9 +333,17 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
 	}
 
 	/* set the individual row-pointers to point at the correct offsets */
-	for (i = 0; i < ibuf->y; i++) {
-		row_pointers[ibuf->y - 1 - i] = (png_bytep)
-		                                ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+	if (is_16bit) {
+		for (i = 0; i < ibuf->y; i++) {
+			row_pointers[ibuf->y - 1 - i] = (png_bytep)
+			                                ((unsigned short *)pixels16 + (i * ibuf->x) * bytesperpixel);
+		}
+	}
+	else {
+		for (i = 0; i < ibuf->y; i++) {
+			row_pointers[ibuf->y - 1 - i] = (png_bytep)
+			                                ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+		}
 	}
 
 	/* write out the entire image data in one call */
@@ -293,7 +353,10 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
 	png_write_end(png_ptr, info_ptr);
 
 	/* clean up */
-	MEM_freeN(pixels);
+	if (pixels)
+		MEM_freeN(pixels);
+	if (pixels16)
+		MEM_freeN(pixels16);
 	MEM_freeN(row_pointers);
 	png_destroy_write_struct(&png_ptr, &info_ptr);
 
@@ -394,6 +457,8 @@ ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[I
 
 	if (ibuf) {
 		ibuf->ftype = PNG;
+		if (bit_depth == 16)
+			ibuf->ftype |= PNG_16BIT;
 
 		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
 			int unit_type;
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
index 03ed1bb8008..d09adeb09b5 100644
--- a/source/blender/imbuf/intern/radiance_hdr.c
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -212,6 +212,9 @@ struct ImBuf *imb_loadhdr(unsigned char *mem, size_t size, int flags, char color
 			if (ibuf == NULL) return NULL;
 			ibuf->ftype = RADHDR;
 
+			if (flags & IB_alphamode_detect)
+				ibuf->flags |= IB_alphamode_premul;
+
 			if (flags & IB_test) return ibuf;
 
 			/* read in and decode the actual data */
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index be20c80bdec..00bc78ee488 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -86,15 +86,32 @@ ImBuf *IMB_ibImageFromMemory(unsigned char *mem, size_t size, int flags, char co
 					BLI_strncpy(colorspace, effective_colorspace, IM_MAX_SPACE);
 				}
 
+				if (flags & IB_ignore_alpha) {
+					IMB_rectfill_alpha(ibuf, 1.0f);
+				}
+				else {
+					if (flags & IB_alphamode_premul) {
+						if (ibuf->rect) {
+							IMB_unpremultiply_alpha(ibuf);
+						}
+						else {
+							/* pass, floats are expected to be premul */
+						}
+					}
+					else {
+						if (ibuf->rect_float) {
+							IMB_premultiply_alpha(ibuf);
+						}
+						else {
+							/* pass, bytes are expected to be straight */
+						}
+					}
+				}
+
 				/* OCIO_TODO: in some cases it's faster to do threaded conversion,
 				 *            but how to distinguish such cases */
 				colormanage_imbuf_make_linear(ibuf, effective_colorspace);
 
-				if (flags & IB_premul) {
-					IMB_premultiply_alpha(ibuf);
-					ibuf->flags |= IB_premul;
-				}
-
 				return ibuf;
 			}
 		}
@@ -230,4 +247,3 @@ void imb_loadtile(ImBuf *ibuf, int tx, int ty, unsigned int *rect)
 
 	close(file);
 }
-
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index 1e701b8d615..1050d3f8715 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -33,6 +33,7 @@
 
 
 #include "BLI_utildefines.h"
+#include "BLI_math_color.h"
 #include "MEM_guardedalloc.h"
 
 #include "imbuf.h"
@@ -291,6 +292,37 @@ struct ImBuf *IMB_double_y(struct ImBuf *ibuf1)
 	return (ibuf2);
 }
 
+/* pretty much specific functions which converts uchar <-> ushort but assumes
+ * ushort range of 255*255 which is more convenient here
+ */
+MINLINE void straight_uchar_to_premul_ushort(unsigned short result[4], const unsigned char color[4])
+{
+	unsigned short alpha = color[3];
+
+	result[0] = color[0] * alpha;
+	result[1] = color[1] * alpha;
+	result[2] = color[2] * alpha;
+	result[3] = alpha * 255;
+}
+
+MINLINE void premul_ushort_to_straight_uchar(unsigned char *result, const unsigned short color[4])
+{
+	if (color[3] <= 255) {
+		result[0] = color[0] / 255;
+		result[1] = color[1] / 255;
+		result[2] = color[2] / 255;
+		result[3] = color[3] / 255;
+	}
+	else {
+		unsigned short alpha = color[3] / 255;
+
+		result[0] = color[0] / alpha;
+		result[1] = color[1] / alpha;
+		result[2] = color[2] / alpha;
+		result[3] = alpha;
+	}
+}
+
 /* result in ibuf2, scaling should be done correctly */
 void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1)
 {
@@ -303,23 +335,33 @@ void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1)
 	}
 
 	if (do_rect) {
-		char *p1, *p2, *dest;
+		unsigned char *cp1, *cp2, *dest;
 		
-		p1 = (char *) ibuf1->rect;
-		dest = (char *) ibuf2->rect;
+		cp1 = (unsigned char *) ibuf1->rect;
+		dest = (unsigned char *) ibuf2->rect;
 		for (y = ibuf2->y; y > 0; y--) {
-			p2 = p1 + (ibuf1->x << 2);
+			cp2 = cp1 + (ibuf1->x << 2);
 			for (x = ibuf2->x; x > 0; x--) {
-				dest[0] = (p1[0] + p2[0] + p1[4] + p2[4]) >> 2;
-				dest[1] = (p1[1] + p2[1] + p1[5] + p2[5]) >> 2;
-				dest[2] = (p1[2] + p2[2] + p1[6] + p2[6]) >> 2;
-				dest[3] = (p1[3] + p2[3] + p1[7] + p2[7]) >> 2;
-				p1 += 8; 
-				p2 += 8; 
+				unsigned short p1i[8], p2i[8], desti[4];
+
+				straight_uchar_to_premul_ushort(p1i, cp1);
+				straight_uchar_to_premul_ushort(p2i, cp2);
+				straight_uchar_to_premul_ushort(p1i + 4, cp1 + 4);
+				straight_uchar_to_premul_ushort(p2i + 4, cp2 + 4);
+
+				desti[0] = ((unsigned int) p1i[0] + p2i[0] + p1i[4] + p2i[4]) >> 2;
+				desti[1] = ((unsigned int) p1i[1] + p2i[1] + p1i[5] + p2i[5]) >> 2;
+				desti[2] = ((unsigned int) p1i[2] + p2i[2] + p1i[6] + p2i[6]) >> 2;
+				desti[3] = ((unsigned int) p1i[3] + p2i[3] + p1i[7] + p2i[7]) >> 2;
+
+				premul_ushort_to_straight_uchar(dest, desti);
+
+				cp1 += 8;
+				cp2 += 8;
 				dest += 4;
 			}
-			p1 = p2;
-			if (ibuf1->x & 1) p1 += 4;
+			cp1 = cp2;
+			if (ibuf1->x & 1) cp1 += 4;
 		}
 	}
 	
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 83830f260e1..2630aebef3b 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -376,7 +376,7 @@ static void imb_read_tiff_resolution(ImBuf *ibuf, TIFF *image)
  * This method is most flexible and can handle multiple different bit depths 
  * and RGB channel orderings.
  */
-static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul)
+static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image)
 {
 	ImBuf *tmpibuf;
 	int success = 0;
@@ -390,6 +390,23 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul)
 	TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp);     /* number of 'channels' */
 	TIFFGetField(image, TIFFTAG_PLANARCONFIG, &config);
 
+	if (spp == 4) {
+		/* HACK: this is really tricky hack, which is only needed to force libtiff
+		 *       do not touch RGB channels when there's alpha channel present
+		 *       The thing is: libtiff will premul RGB if alpha mode is set to
+		 *       unassociated, which really conflicts with blender's assumptions
+		 *
+		 *       Alternative would be to unpremul after load, but it'll be really
+		 *       lossy and unwanted behavior
+		 *
+		 *       So let's keep this thing here for until proper solution is found (sergey)
+		 */
+
+		unsigned short extraSampleTypes[1];
+		extraSampleTypes[0] = EXTRASAMPLE_ASSOCALPHA;
+		TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1, extraSampleTypes);
+	}
+
 	imb_read_tiff_resolution(ibuf, image);
 
 	scanline = TIFFScanlineSize(image);
@@ -471,10 +488,6 @@ static int imb_read_tiff_pixels(ImBuf *ibuf, TIFF *image, int premul)
 		if (bitspersample < 16)
 			if (ENDIAN_ORDER == B_ENDIAN)
 				IMB_convert_rgba_to_abgr(tmpibuf);
-		if (premul) {
-			IMB_premultiply_alpha(tmpibuf);
-			ibuf->flags |= IB_premul;
-		}
 		
 		/* assign rect last */
 		if (tmpibuf->rect_float)
@@ -557,6 +570,18 @@ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[
 		return NULL;
 	}
 
+	/* get alpha mode from file header */
+	if (flags & IB_alphamode_detect) {
+		if (spp == 4) {
+			unsigned short extra, *extraSampleTypes;
+
+			TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extra, &extraSampleTypes);
+
+			if (extraSampleTypes[0] == EXTRASAMPLE_ASSOCALPHA)
+				ibuf->flags |= IB_alphamode_premul;
+		}
+	}
+
 	/* if testing, we're done */
 	if (flags & IB_test) {
 		TIFFClose(image);
@@ -585,9 +610,6 @@ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[
 					hbuf->miplevel = level;
 					hbuf->ftype = ibuf->ftype;
 					ibuf->mipmap[level - 1] = hbuf;
-
-					if (flags & IB_premul)
-						hbuf->flags |= IB_premul;
 				}
 				else
 					hbuf = ibuf;
@@ -608,7 +630,7 @@ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[
 	}
 
 	/* read pixels */
-	if (!(ibuf->flags & IB_tilecache) && !imb_read_tiff_pixels(ibuf, image, 0)) {
+	if (!(ibuf->flags & IB_tilecache) && !imb_read_tiff_pixels(ibuf, image)) {
 		fprintf(stderr, "imb_loadtiff: Failed to read tiff image.\n");
 		TIFFClose(image);
 		return NULL;
@@ -644,9 +666,6 @@ void imb_loadtiletiff(ImBuf *ibuf, unsigned char *mem, size_t size, int tx, int
 				if (TIFFReadRGBATile(image, tx * ibuf->tilex, (ibuf->ytiles - 1 - ty) * ibuf->tiley, rect) == 1) {
 					if (ibuf->tiley > ibuf->y)
 						memmove(rect, rect + ibuf->tilex * (ibuf->tiley - ibuf->y), sizeof(int) * ibuf->tilex * ibuf->y);
-
-					if (ibuf->flags & IB_premul)
-						IMB_premultiply_rect(rect, 32, ibuf->tilex, ibuf->tiley);
 				}
 				else
 					printf("imb_loadtiff: failed to read tiff tile at mipmap level %d\n", ibuf->miplevel);
@@ -689,8 +708,6 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
 	float *fromf = NULL;
 	float xres, yres;
 	int x, y, from_i, to_i, i;
-	int extraSampleTypes[1] = { EXTRASAMPLE_ASSOCALPHA };
-	
 
 	/* check for a valid number of bytes per pixel.  Like the PNG writer,
 	 * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
@@ -763,6 +780,13 @@ int imb_savetiff(ImBuf *ibuf, const char *name, int flags)
 	TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
 
 	if (samplesperpixel == 4) {
+		unsigned short extraSampleTypes[1];
+
+		if (bitspersample == 16)
+			extraSampleTypes[0] = EXTRASAMPLE_ASSOCALPHA;
+		else
+			extraSampleTypes[0] = EXTRASAMPLE_UNASSALPHA;
+
 		/* RGBA images */
 		TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1,
 		             extraSampleTypes);
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 7b2773a8205..68896992287 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -42,6 +42,7 @@ extern "C" {
 struct Library;
 struct FileData;
 struct ID;
+struct PackedFile;
 
 typedef struct IDPropertyData {
 	void *pointer;
@@ -136,6 +137,8 @@ typedef struct Library {
 							 * setting 'name' directly and it will be kept in
 							 * sync - campbell */
 	struct Library *parent;	/* set for indirectly linked libs, used in the outliner and while reading */
+	
+	struct PackedFile *packedfile;
 } Library;
 
 enum eIconSizes {
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index cc26ee479d7..e3571c767bd 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -156,10 +156,7 @@ typedef enum BrushSculptTool {
 	SCULPT_TOOL_THUMB = 12,
 	SCULPT_TOOL_SNAKE_HOOK = 13,
 	SCULPT_TOOL_ROTATE = 14,
-	
-	/* slot 15 is free for use */
-	/* SCULPT_TOOL_ = 15, */
-	
+	SCULPT_TOOL_SIMPLIFY = 15,
 	SCULPT_TOOL_CREASE = 16,
 	SCULPT_TOOL_BLOB = 17,
 	SCULPT_TOOL_CLAY_STRIPS = 18,
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index fe3550327f7..0f47ee224ae 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -111,6 +111,9 @@ typedef struct Image {
 
 	/* color management */
 	ColorManagedColorspaceSettings colorspace_settings;
+	char alpha_mode;
+
+	char pad[7];
 } Image;
 
 
@@ -119,15 +122,16 @@ typedef struct Image {
 /* Image.flag */
 #define IMA_FIELDS			1
 #define IMA_STD_FIELD		2
-#define IMA_DO_PREMUL		4
+#define IMA_DO_PREMUL		4    /* deprecated, should not be used */
 #define IMA_REFLECT			16
 #define IMA_NOCOLLECT   	32
 #define IMA_DEPRECATED		64
 #define IMA_OLD_PREMUL		128
-#define IMA_CM_PREDIVIDE	256
+/*#define IMA_CM_PREDIVIDE	256*/  /* deprecated, should not be used */
 #define IMA_USED_FOR_RENDER	512
 #define IMA_USER_FRAME_IN_RANGE	1024 /* for image user, but these flags are mixed */
 #define IMA_VIEW_AS_RENDER	2048
+#define IMA_IGNORE_ALPHA	4096
 
 /* Image.tpageflag */
 #define IMA_TILES			1
@@ -148,4 +152,10 @@ typedef struct Image {
 /* gen_flag */
 #define IMA_GEN_FLOAT		1
 
+/* alpha_mode */
+enum {
+	IMA_ALPHA_STRAIGHT = 0,
+	IMA_ALPHA_PREMUL = 1,
+};
+
 #endif
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index da7ea94aeff..03b23c5137a 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -170,6 +170,7 @@ typedef struct TFace {
 #define ME_SUBSURF		128
 #define ME_OPT_EDGES	256
 #define ME_DS_EXPAND	512
+#define ME_SCULPT_DYNAMIC_TOPOLOGY 1024
 
 /* me->drawflag, short */
 #define ME_DRAWEDGES	(1 << 0)
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index ef9dca58862..4194395ec43 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -281,8 +281,9 @@ typedef struct ImageFormatData {
 
 	/* Jpeg2000 */
 	char  jp2_flag;
+	char jp2_codec;
 
-	char pad[7];
+	char pad[6];
 
 	/* color management */
 	ColorManagedViewSettings view_settings;
@@ -351,6 +352,10 @@ typedef struct ImageFormatData {
 #define R_IMF_JP2_FLAG_CINE_PRESET  (1<<1)  /* was R_JPEG2K_CINE_PRESET */
 #define R_IMF_JP2_FLAG_CINE_48      (1<<2)  /* was R_JPEG2K_CINE_48FPS */
 
+/* ImageFormatData.jp2_codec */
+#define R_IMF_JP2_CODEC_JP2  0
+#define R_IMF_JP2_CODEC_J2K  1
+
 /* ImageFormatData.cineon_flag */
 #define R_IMF_CINEON_FLAG_LOG (1<<0)  /* was R_CINEON_LOG */
 
@@ -704,6 +709,7 @@ typedef struct GameData {
 #define GAME_SHOW_MOUSE						(1 << 14)
 #define GAME_GLSL_NO_COLOR_MANAGEMENT		(1 << 15)
 #define GAME_SHOW_OBSTACLE_SIMULATION		(1 << 16)
+#define GAME_NO_MATERIAL_CACHING			(1 << 17)
 /* Note: GameData.flag is now an int (max 32 flags). A short could only take 16 flags */
 
 /* GameData.playerflag */
@@ -840,6 +846,12 @@ typedef struct Sculpt {
 
 	float special_rotation;
 
+	/* Maximum edge length for dynamic topology sculpting (in pixels) */
+	int detail_size;
+
+	/* Direction used for SCULPT_OT_symmetrize operator */
+	int symmetrize_direction;
+
 	int pad;
 } Sculpt;
 
@@ -1296,11 +1308,11 @@ typedef struct Scene {
 /* alphamode */
 #define R_ADDSKY		0
 #define R_ALPHAPREMUL	1
-#define R_ALPHAKEY		2
+/*#define R_ALPHAKEY		2*/ /* deprecated, shouldn't be used */
 
 /* color_mgt_flag */
 #define R_COLOR_MANAGEMENT              (1 << 0)  /* deprecated, should only be used in versioning code only */
-#define R_COLOR_MANAGEMENT_PREDIVIDE    (1 << 1)
+/*#define R_COLOR_MANAGEMENT_PREDIVIDE    (1 << 1)*/  /* deprecated, shouldn't be used */
 
 /* subimtype, flag options for imtype */
 #define R_OPENEXR_HALF    1                                      /*deprecated*/
@@ -1323,6 +1335,7 @@ typedef struct Scene {
 #define R_BAKE_NORMALIZE	8
 #define R_BAKE_MULTIRES		16
 #define R_BAKE_LORES_MESH	32
+#define R_BAKE_VCOL			64
 
 /* bake_normal_space */
 #define R_BAKE_SPACE_CAMERA	 0
@@ -1495,6 +1508,14 @@ typedef enum SculptFlags {
 	SCULPT_USE_OPENMP = (1<<7),
 	SCULPT_ONLY_DEFORM = (1<<8),
 	SCULPT_SHOW_DIFFUSE = (1<<9),
+
+	/* If set, the mesh will be drawn with smooth-shading in
+	 * dynamic-topology mode */
+	SCULPT_DYNTOPO_SMOOTH_SHADING = (1<<10),
+
+	/* If set, dynamic-topology brushes will collapse short edges in
+	 * addition to subdividing long ones */
+	SCULPT_DYNTOPO_COLLAPSE = (1<<11)
 } SculptFlags;
 
 /* ImagePaintSettings.flag */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index de6ddb4b896..d6100dcdbce 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -110,12 +110,26 @@ typedef struct Panel {		/* the part from uiBlock that needs saved in file */
 	int sortorder;			/* panels are aligned according to increasing sortorder */
 	struct Panel *paneltab;		/* this panel is tabbed in *paneltab */
 	void *activedata;			/* runtime for panel manipulation */
-
-	int list_scroll, list_size;
-	int list_last_len, list_grip_size;
-	char list_search[64];
 } Panel;
 
+typedef struct uiList {				/* some list UI data need to be saved in file */
+	struct uiList *next, *prev;
+
+	struct uiListType *type;		/* runtime */
+	void *padp;
+
+	char list_id[64];				/* defined as UI_MAX_NAME_STR */
+
+	int layout_type;				/* How items are layedout in the list */
+	int padi;
+
+	int list_scroll;
+	int list_size;
+	int list_last_len;
+	int list_grip_size;
+/*	char list_search[64]; */
+} uiList;
+
 typedef struct ScrArea {
 	struct ScrArea *next, *prev;
 	
@@ -167,6 +181,7 @@ typedef struct ARegion {
 	
 	ListBase uiblocks;			/* uiBlock */
 	ListBase panels;			/* Panel */
+	ListBase ui_lists;			/* uiList */
 	ListBase handlers;			/* wmEventHandler */
 	
 	struct wmTimer *regiontimer; /* blend in/out */
@@ -216,6 +231,13 @@ typedef struct ARegion {
 #define PNL_DEFAULT_CLOSED		1
 #define PNL_NO_HEADER			2
 
+/* uilist layout_type */
+enum {
+	UILST_LAYOUT_DEFAULT          = 0,
+	UILST_LAYOUT_COMPACT          = 1,
+	UILST_LAYOUT_GRID             = 2,
+};
+
 /* regiontype, first two are the default set */
 /* Do NOT change order, append on end. Types are hardcoded needed */
 enum {
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index f106c8f918a..0aa466f7245 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -172,7 +172,10 @@ typedef struct Sequence {
 	float blend_opacity;
 
 	/* is sfra needed anymore? - it looks like its only used in one place */
-	int sfra, pad;  /* starting frame according to the timeline of the scene. */
+	int sfra;  /* starting frame according to the timeline of the scene. */
+
+	char alpha_mode;
+	char pad[3];
 
 	/* modifiers */
 	ListBase modifiers;
@@ -315,7 +318,7 @@ typedef struct SequencerScopes {
 #define SEQ_OVERLAP                 (1 << 3)
 #define SEQ_FILTERY                 (1 << 4)
 #define SEQ_MUTE                    (1 << 5)
-#define SEQ_MAKE_PREMUL             (1 << 6)
+#define SEQ_MAKE_PREMUL             (1 << 6) /* deprecated, used for compatibility code only */
 #define SEQ_REVERSE_FRAMES          (1 << 7)
 #define SEQ_IPO_FRAME_LOCKED        (1 << 8)
 #define SEQ_EFFECT_NOT_LOADED       (1 << 9)
@@ -366,6 +369,12 @@ typedef struct SequencerScopes {
 #define SEQ_PROXY_TC_RECORD_RUN_NO_GAPS         8
 #define SEQ_PROXY_TC_ALL                        15
 
+/* seq->alpha_mode */
+enum {
+	SEQ_ALPHA_STRAIGHT = 0,
+	SEQ_ALPHA_PREMUL   = 1
+};
+
 /* seq->type WATCH IT: SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!!! */
 enum {
 	SEQ_TYPE_IMAGE       = 0,
diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h
index 6ce883905d4..3194adba3a0 100644
--- a/source/blender/makesdna/DNA_text_types.h
+++ b/source/blender/makesdna/DNA_text_types.h
@@ -75,12 +75,4 @@ typedef struct Text {
 #define TXT_FOLLOW              0x0200 /* always follow cursor (console) */
 #define TXT_TABSTOSPACES        0x0400 /* use space instead of tabs */
 
-/* format continuation flags */
-#define TXT_NOCONT				0x00 /* no continuation */
-#define TXT_SNGQUOTSTR			0x01 /* single quotes */
-#define TXT_DBLQUOTSTR			0x02 /* double quotes */
-#define TXT_TRISTR				0x04 /* triplets of quotes: """ or ''' */
-#define TXT_SNGTRISTR			0x05 /*(TXT_TRISTR | TXT_SNGQUOTSTR)*/
-#define TXT_DBLTRISTR			0x06 /*(TXT_TRISTR | TXT_DBLQUOTSTR)*/
-
 #endif
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index dd63e6aad59..ea4f281efd6 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -340,7 +340,7 @@ typedef struct ColorMapping {
 
 /* imaflag */
 #define TEX_INTERPOL	1
-#define TEX_USEALPHA	2
+#define TEX_USEALPHA	2 /* deprecated, used for versioning only */
 #define TEX_MIPMAP		4
 #define TEX_IMAROT		16
 #define TEX_CALCALPHA	32
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index ce4e0c1591d..e7f27834c85 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -249,11 +249,14 @@ typedef struct ThemeSpace {
 	char vertex_size, outline_width, facedot_size;
 	char noodle_curving;
 
-	char syntaxl[4], syntaxn[4], syntaxb[4]; /* syntax for textwindow and nodes */
+	/* syntax for textwindow and nodes */
+	char syntaxl[4], syntaxs[4];
+	char syntaxb[4], syntaxn[4];
 	char syntaxv[4], syntaxc[4];
+	char syntaxd[4], syntaxr[4];
 	
 	char movie[4], movieclip[4], mask[4], image[4], scene[4], audio[4];		/* for sequence editor */
-	char effect[4], hpad0[4], transition[4], meta[4];
+	char effect[4], transition[4], meta[4];
 	char editmesh_active[4]; 
 
 	char handle_vertex[4];
@@ -346,6 +349,7 @@ typedef struct bTheme {
 typedef struct bAddon {
 	struct bAddon *next, *prev;
 	char module[64];
+	IDProperty *prop;  /* User-Defined Properties on this  Addon (for storing preferences) */
 } bAddon;
 
 typedef struct SolidLight {
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
index 084496871bf..a7921be44d5 100644
--- a/source/blender/makesdna/DNA_view2d_types.h
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -123,9 +123,9 @@ typedef struct View2D {
 	/* horizontal scrollbar */
 #define V2D_SCROLL_TOP 				(1<<2)
 #define V2D_SCROLL_BOTTOM 			(1<<3)
-	/* special hack for outliner hscroll - prevent hanging older versions of Blender */
-#define V2D_SCROLL_BOTTOM_O   		(1<<4)
-#define V2D_SCROLL_HORIZONTAL  		(V2D_SCROLL_TOP|V2D_SCROLL_BOTTOM|V2D_SCROLL_BOTTOM_O)
+
+/* UNUSED							(1<<4) */
+#define V2D_SCROLL_HORIZONTAL  		(V2D_SCROLL_TOP|V2D_SCROLL_BOTTOM)
 	/* scale markings - vertical */
 #define V2D_SCROLL_SCALE_VERTICAL	(1<<5)
 	/* scale markings - horizontal */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index ce7cb32c6e6..8956e9d9005 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -54,6 +54,7 @@ extern StructRNA RNA_ActionPoseMarkers;
 extern StructRNA RNA_Actuator;
 extern StructRNA RNA_ActuatorSensor;
 extern StructRNA RNA_Addon;
+extern StructRNA RNA_AddonPreferences;
 extern StructRNA RNA_AdjustmentSequence;
 extern StructRNA RNA_AlwaysSensor;
 extern StructRNA RNA_AndController;
@@ -104,7 +105,8 @@ extern StructRNA RNA_CollectionProperty;
 extern StructRNA RNA_CollisionModifier;
 extern StructRNA RNA_CollisionSensor;
 extern StructRNA RNA_CollisionSettings;
-extern StructRNA RNA_ColorManagedColorspaceSettings;
+extern StructRNA RNA_ColorManagedInputColorspaceSettings;
+extern StructRNA RNA_ColorManagedSequencerColorspaceSettings;
 extern StructRNA RNA_ColorManagedDisplaySettings;
 extern StructRNA RNA_ColorManagedViewSettings;
 extern StructRNA RNA_ColorRamp;
@@ -625,7 +627,7 @@ extern StructRNA RNA_TrackToConstraint;
 extern StructRNA RNA_TransformConstraint;
 extern StructRNA RNA_TransformSequence;
 extern StructRNA RNA_UILayout;
-extern StructRNA RNA_UIListItem;
+extern StructRNA RNA_UIList;
 extern StructRNA RNA_UVWarpModifier;
 extern StructRNA RNA_UVProjectModifier;
 extern StructRNA RNA_UVProjector;
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 75bb3475fed..a8df3b9dfdd 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -70,6 +70,7 @@ extern EnumPropertyItem keyframe_handle_type_items[];
 extern EnumPropertyItem keyblock_type_items[];
 
 extern EnumPropertyItem keyingset_path_grouping_items[];
+extern EnumPropertyItem keying_flag_items[];
 
 extern EnumPropertyItem keyframe_paste_offset_items[];
 extern EnumPropertyItem keyframe_paste_merge_items[];
@@ -89,6 +90,8 @@ extern EnumPropertyItem brush_sculpt_tool_items[];
 extern EnumPropertyItem brush_vertex_tool_items[];
 extern EnumPropertyItem brush_image_tool_items[];
 
+extern EnumPropertyItem symmetrize_direction_items[];
+
 extern EnumPropertyItem texture_type_items[];
 
 extern EnumPropertyItem lamp_type_items[];
@@ -132,6 +135,9 @@ extern EnumPropertyItem prop_dynamicpaint_type_items[];
 
 extern EnumPropertyItem clip_editor_mode_items[];
 
+extern EnumPropertyItem icon_items[];
+extern EnumPropertyItem uilist_layout_type_items[];
+
 #ifdef WITH_FREESTYLE
 extern EnumPropertyItem linestyle_color_modifier_type_items[];
 extern EnumPropertyItem linestyle_alpha_modifier_type_items[];
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 1b1e4f19cbb..a9cb6cdf77e 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -415,10 +415,10 @@ static const char *rna_type_type_name(PropertyRNA *prop)
 			return "float";
 		case PROP_STRING:
 			if (prop->flag & PROP_THICK_WRAP) {
-				return "char*";
+				return "char *";
 			}
 			else {
-				return "const char*";
+				return "const char *";
 			}
 		default:
 			return NULL;
@@ -870,16 +870,16 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr
 
 				if (prop->flag & PROP_ID_REFCOUNT) {
 					fprintf(f, "\n	if (data->%s)\n", dp->dnaname);
-					fprintf(f, "		id_us_min((ID*)data->%s);\n", dp->dnaname);
+					fprintf(f, "		id_us_min((ID *)data->%s);\n", dp->dnaname);
 					fprintf(f, "	if (value.data)\n");
-					fprintf(f, "		id_us_plus((ID*)value.data);\n\n");
+					fprintf(f, "		id_us_plus((ID *)value.data);\n\n");
 				}
 				else {
 					PointerPropertyRNA *pprop = (PointerPropertyRNA *)dp->prop;
 					StructRNA *type = rna_find_struct((const char *)pprop->type);
 					if (type && (type->flag & STRUCT_ID)) {
 						fprintf(f, "	if (value.data)\n");
-						fprintf(f, "		id_lib_extern((ID*)value.data);\n\n");
+						fprintf(f, "		id_lib_extern((ID *)value.data);\n\n");
 					}
 				}
 
@@ -1084,7 +1084,7 @@ static char *rna_def_property_begin_func(FILE *f, StructRNA *srna, PropertyRNA *
 
 	fprintf(f, "\n	memset(iter, 0, sizeof(*iter));\n");
 	fprintf(f, "	iter->parent= *ptr;\n");
-	fprintf(f, "	iter->prop= (PropertyRNA*)&rna_%s_%s;\n", srna->identifier, prop->identifier);
+	fprintf(f, "	iter->prop= (PropertyRNA *)&rna_%s_%s;\n", srna->identifier, prop->identifier);
 
 	if (dp->dnalengthname || dp->dnalengthfixed) {
 		if (manualfunc) {
@@ -1768,7 +1768,7 @@ static void rna_def_property_funcs_header_cpp(FILE *f, StructRNA *srna, Property
 			const char *collection_funcs = "DefaultCollectionFunctions";
 
 			if (!(dp->prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)) && cprop->property.srna)
-				collection_funcs  = (char*)cprop->property.srna;
+				collection_funcs  = (char *)cprop->property.srna;
 
 			if (cprop->item_type)
 				fprintf(f, "\tCOLLECTION_PROPERTY(%s, %s, %s, %s, %s, %s, %s)", collection_funcs, (const char *)cprop->item_type, srna->identifier,
@@ -2906,9 +2906,9 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr
 	        rna_property_structname(prop->type),
 	        srna->identifier, strnest, prop->identifier);
 
-	if (prop->next) fprintf(f, "\t{(PropertyRNA*)&rna_%s%s_%s, ", srna->identifier, strnest, prop->next->identifier);
+	if (prop->next) fprintf(f, "\t{(PropertyRNA *)&rna_%s%s_%s, ", srna->identifier, strnest, prop->next->identifier);
 	else fprintf(f, "\t{NULL, ");
-	if (prop->prev) fprintf(f, "(PropertyRNA*)&rna_%s%s_%s,\n", srna->identifier, strnest, prop->prev->identifier);
+	if (prop->prev) fprintf(f, "(PropertyRNA *)&rna_%s%s_%s,\n", srna->identifier, strnest, prop->prev->identifier);
 	else fprintf(f, "NULL,\n");
 	fprintf(f, "\t%d, ", prop->magic);
 	rna_print_c_string(f, prop->identifier);
@@ -3080,12 +3080,12 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
 		fprintf(f, "%s%s rna_%s_%s_func = {\n", "", "FunctionRNA", srna->identifier, func->identifier);
 
 		if (func->cont.next)
-			fprintf(f, "\t{(FunctionRNA*)&rna_%s_%s_func, ", srna->identifier,
+			fprintf(f, "\t{(FunctionRNA *)&rna_%s_%s_func, ", srna->identifier,
 			        ((FunctionRNA *)func->cont.next)->identifier);
 		else
 			fprintf(f, "\t{NULL, ");
 		if (func->cont.prev)
-			fprintf(f, "(FunctionRNA*)&rna_%s_%s_func,\n", srna->identifier,
+			fprintf(f, "(FunctionRNA *)&rna_%s_%s_func,\n", srna->identifier,
 			        ((FunctionRNA *)func->cont.prev)->identifier);
 		else
 			fprintf(f, "NULL,\n");
@@ -3093,11 +3093,11 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
 		fprintf(f, "\tNULL,\n");
 
 		parm = func->cont.properties.first;
-		if (parm) fprintf(f, "\t{(PropertyRNA*)&rna_%s_%s_%s, ", srna->identifier, func->identifier, parm->identifier);
+		if (parm) fprintf(f, "\t{(PropertyRNA *)&rna_%s_%s_%s, ", srna->identifier, func->identifier, parm->identifier);
 		else fprintf(f, "\t{NULL, ");
 
 		parm = func->cont.properties.last;
-		if (parm) fprintf(f, "(PropertyRNA*)&rna_%s_%s_%s}},\n", srna->identifier, func->identifier, parm->identifier);
+		if (parm) fprintf(f, "(PropertyRNA *)&rna_%s_%s_%s}},\n", srna->identifier, func->identifier, parm->identifier);
 		else fprintf(f, "NULL}},\n");
 
 		fprintf(f, "\t");
@@ -3110,7 +3110,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
 		else fprintf(f, "\tNULL,\n");
 
 		if (func->c_ret)
-			fprintf(f, "\t(PropertyRNA*)&rna_%s_%s_%s\n", srna->identifier, func->identifier, func->c_ret->identifier);
+			fprintf(f, "\t(PropertyRNA *)&rna_%s_%s_%s\n", srna->identifier, func->identifier, func->c_ret->identifier);
 		else
 			fprintf(f, "\tNULL\n");
 
@@ -3128,11 +3128,11 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
 	fprintf(f, "\tNULL,\n");
 
 	prop = srna->cont.properties.first;
-	if (prop) fprintf(f, "\t{(PropertyRNA*)&rna_%s_%s, ", srna->identifier, prop->identifier);
+	if (prop) fprintf(f, "\t{(PropertyRNA *)&rna_%s_%s, ", srna->identifier, prop->identifier);
 	else fprintf(f, "\t{NULL, ");
 
 	prop = srna->cont.properties.last;
-	if (prop) fprintf(f, "(PropertyRNA*)&rna_%s_%s}},\n", srna->identifier, prop->identifier);
+	if (prop) fprintf(f, "(PropertyRNA *)&rna_%s_%s}},\n", srna->identifier, prop->identifier);
 	else fprintf(f, "NULL}},\n");
 	fprintf(f, "\t");
 	rna_print_c_string(f, srna->identifier);
@@ -3151,7 +3151,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
 		while (base->base && base->base->nameproperty == prop)
 			base = base->base;
 
-		fprintf(f, "\t(PropertyRNA*)&rna_%s_%s, ", base->identifier, prop->identifier);
+		fprintf(f, "\t(PropertyRNA *)&rna_%s_%s, ", base->identifier, prop->identifier);
 	}
 	else fprintf(f, "\tNULL, ");
 
@@ -3159,7 +3159,7 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
 	base = srna;
 	while (base->base && base->base->iteratorproperty == prop)
 		base = base->base;
-	fprintf(f, "(PropertyRNA*)&rna_%s_rna_properties,\n", base->identifier);
+	fprintf(f, "(PropertyRNA *)&rna_%s_rna_properties,\n", base->identifier);
 
 	if (srna->base) fprintf(f, "\t&RNA_%s,\n", srna->base->identifier);
 	else fprintf(f, "\tNULL,\n");
@@ -3181,11 +3181,11 @@ static void rna_generate_struct(BlenderRNA *UNUSED(brna), StructRNA *srna, FILE
 	}
 
 	func = srna->functions.first;
-	if (func) fprintf(f, "\t{(FunctionRNA*)&rna_%s_%s_func, ", srna->identifier, func->identifier);
+	if (func) fprintf(f, "\t{(FunctionRNA *)&rna_%s_%s_func, ", srna->identifier, func->identifier);
 	else fprintf(f, "\t{NULL, ");
 
 	func = srna->functions.last;
-	if (func) fprintf(f, "(FunctionRNA*)&rna_%s_%s_func}\n", srna->identifier, func->identifier);
+	if (func) fprintf(f, "(FunctionRNA *)&rna_%s_%s_func}\n", srna->identifier, func->identifier);
 	else fprintf(f, "NULL}\n");
 
 	fprintf(f, "};\n");
@@ -3578,7 +3578,7 @@ static const char *cpp_classes = ""
 "	int length;\n"
 "\n"
 "	DynamicArray() : data(NULL), length(0) {}\n"
-"	DynamicArray(int new_length) : data(NULL), length(new_length) { data = (float*)malloc(sizeof(T) * new_length); }\n"
+"	DynamicArray(int new_length) : data(NULL), length(new_length) { data = (float *)malloc(sizeof(T) * new_length); }\n"
 "	DynamicArray(const DynamicArray& other) { copy_from(other); }\n"
 "	const DynamicArray& operator=(const DynamicArray& other) { copy_from(other); return *this; }\n"
 "\n"
@@ -3589,7 +3589,7 @@ static const char *cpp_classes = ""
 "protected:\n"
 "	void copy_from(const DynamicArray& other) {\n"
 "		if (data) free(data);\n"
-"		data = (float*)malloc(sizeof(T) * other.length);\n"
+"		data = (float *)malloc(sizeof(T) * other.length);\n"
 "		memcpy(data, other.data, sizeof(T) * other.length);\n"
 "		length = other.length;\n"
 "	}\n"
@@ -3620,7 +3620,7 @@ static const char *cpp_classes = ""
 "{ return iter.valid != other.iter.valid; }\n"
 "\n"
 "	void begin(const Pointer &ptr)\n"
-"	{ if (init) Tend(&iter); Tbegin(&iter, (PointerRNA*)&ptr.ptr); t = T(iter.ptr); init = true; }\n"
+"	{ if (init) Tend(&iter); Tbegin(&iter, (PointerRNA *)&ptr.ptr); t = T(iter.ptr); init = true; }\n"
 "\n"
 "private:\n"
 "	const CollectionIterator& operator="
@@ -3754,13 +3754,13 @@ static void rna_generate_header_cpp(BlenderRNA *UNUSED(brna), FILE *f)
 					if (first_collection_func_struct == NULL)
 						first_collection_func_struct = ds->srna->identifier;
 
-					if (!rna_is_collection_functions_struct(collection_func_structs, (char*)prop->srna)) {
+					if (!rna_is_collection_functions_struct(collection_func_structs, (char *)prop->srna)) {
 						if (all_collection_func_structs >= max_collection_func_structs) {
 							printf("Array size to store all collection structures names is too small\n");
 							exit(1);
 						}
 
-						collection_func_structs[all_collection_func_structs++] = (char*)prop->srna;
+						collection_func_structs[all_collection_func_structs++] = (char *)prop->srna;
 					}
 				}
 			}
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index caa53a23d77..0048e1c60c2 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -4204,6 +4204,8 @@ char *RNA_path_full_struct_py(struct PointerRNA *ptr)
 	ret = BLI_sprintfN("%s.%s",
 	                   id_path, data_path);
 
+	MEM_freeN(data_path);
+
 	return ret;
 }
 
@@ -4235,6 +4237,10 @@ char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
 		ret = BLI_sprintfN("%s.%s[%d]",
 		                   id_path, data_path, index);
 	}
+	MEM_freeN(id_path);
+	if (data_path) {
+		MEM_freeN(data_path);
+	}
 
 	return ret;
 }
@@ -4264,6 +4270,10 @@ char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
 		                   data_path, index);
 	}
 
+	if (data_path) {
+		MEM_freeN(data_path);
+	}
+
 	return ret;
 }
 
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 7229dddf6d6..402d05a20b6 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -52,6 +52,20 @@ EnumPropertyItem keyingset_path_grouping_items[] = {
 	{0, NULL, 0, NULL, NULL}
 };
 
+/* It would be cool to get rid of this 'INSERTKEY_' prefix in 'py strings' values, but it would break existing
+ * exported keyingset... :/
+ */
+EnumPropertyItem keying_flag_items[] = {
+	{INSERTKEY_NEEDED, "INSERTKEY_NEEDED", 0, "Only Needed",
+	                   "Only insert keyframes where they're needed in the relevant F-Curves"},
+	{INSERTKEY_MATRIX, "INSERTKEY_VISUAL", 0, "Visual Keying",
+	                   "Insert keyframes based on 'visual transforms'"},
+	{INSERTKEY_XYZ2RGB, "INSERTKEY_XYZ_TO_RGB", 0, "XYZ=RGB Colors",
+	                    "Color for newly added transformation F-Curves (Location, Rotation, Scale) "
+	                    "and also Color is based on the transform axis"},
+	{0, NULL, 0, NULL, NULL}
+};
+
 #ifdef RNA_RUNTIME
 
 #include "BLI_math_base.h"
@@ -518,17 +532,6 @@ static void rna_def_common_keying_flags(StructRNA *srna, short UNUSED(reg))
 {
 	PropertyRNA *prop;
 
-	static EnumPropertyItem keying_flag_items[] = {
-		{INSERTKEY_NEEDED, "INSERTKEY_NEEDED", 0, "Only Needed",
-		                   "Only insert keyframes where they're needed in the relevant F-Curves"},
-		{INSERTKEY_MATRIX, "INSERTKEY_VISUAL", 0, "Visual Keying",
-		                   "Insert keyframes based on 'visual transforms'"},
-		{INSERTKEY_XYZ2RGB, "INSERTKEY_XYZ_TO_RGB", 0, "XYZ=RGB Colors",
-		                    "Color for newly added transformation F-Curves (Location, Rotation, Scale) "
-		                    "and also Color is based on the transform axis"},
-		{0, NULL, 0, NULL, NULL}
-	};
-
 	prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
 	RNA_def_property_enum_sdna(prop, NULL, "keyingflag");
 	RNA_def_property_enum_items(prop, keying_flag_items);
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 7bdebd620ee..3d5106b0cef 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -65,6 +65,7 @@ EnumPropertyItem brush_sculpt_tool_items[] = {
 	{SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""},
 	{SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""},
 	{SCULPT_TOOL_SCRAPE, "SCRAPE", ICON_BRUSH_SCRAPE, "Scrape", ""},
+	{SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_SUBTRACT /* icon TODO */, "Simplify", ""},
 	{SCULPT_TOOL_SMOOTH, "SMOOTH", ICON_BRUSH_SMOOTH, "Smooth", ""},
 	{SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""},
 	{SCULPT_TOOL_THUMB, "THUMB", ICON_BRUSH_THUMB, "Thumb", ""},
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index b72bba0422a..0b1e1c215c4 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -112,8 +112,8 @@ void RNA_def_camera(BlenderRNA *brna)
 		{0, NULL, 0, NULL, NULL}
 	};
 	static EnumPropertyItem prop_lens_unit_items[] = {
-		{0, "MILLIMETERS", 0, "Millimeters", ""},
-		{CAM_ANGLETOGGLE, "DEGREES", 0, "Degrees", ""},
+		{0, "MILLIMETERS", 0, "Millimeters", "Specify the lens in millimeters"},
+		{CAM_ANGLETOGGLE, "FOV", 0, "Field of View", "Specify the lens as the field of view's angle"},
 		{0, NULL, 0, NULL, NULL}
 	};
 	static EnumPropertyItem sensor_fit_items[] = {
@@ -154,23 +154,23 @@ void RNA_def_camera(BlenderRNA *brna)
 	RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
 
 	prop = RNA_def_property(srna, "angle_x", PROP_FLOAT, PROP_ANGLE);
-	RNA_def_property_range(prop, M_PI * (0.367 / 180.0), M_PI * (172.847 / 180.0));
+	RNA_def_property_range(prop, DEG2RAD(0.367), DEG2RAD(172.847));
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-	RNA_def_property_ui_text(prop, "Horizontal FOV", "Camera lens horizontal field of view in degrees");
+	RNA_def_property_ui_text(prop, "Horizontal FOV", "Camera lens horizontal field of view");
 	RNA_def_property_float_funcs(prop, "rna_Camera_angle_x_get", "rna_Camera_angle_x_set", NULL);
 	RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update");
 
 	prop = RNA_def_property(srna, "angle_y", PROP_FLOAT, PROP_ANGLE);
-	RNA_def_property_range(prop, M_PI * (0.367 / 180.0), M_PI * (172.847 / 180.0));
+	RNA_def_property_range(prop, DEG2RAD(0.367), DEG2RAD(172.847));
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-	RNA_def_property_ui_text(prop, "Vertical FOV", "Camera lens vertical field of view in degrees");
+	RNA_def_property_ui_text(prop, "Vertical FOV", "Camera lens vertical field of view");
 	RNA_def_property_float_funcs(prop, "rna_Camera_angle_y_get", "rna_Camera_angle_y_set", NULL);
 	RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update");
 
 	prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
-	RNA_def_property_range(prop, M_PI * (0.367 / 180.0), M_PI * (172.847 / 180.0));
+	RNA_def_property_range(prop, DEG2RAD(0.367), DEG2RAD(172.847));
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-	RNA_def_property_ui_text(prop, "Field of View", "Camera lens field of view in degrees");
+	RNA_def_property_ui_text(prop, "Field of View", "Camera lens field of view");
 	RNA_def_property_float_funcs(prop, "rna_Camera_angle_get", "rna_Camera_angle_set", NULL);
 	RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_update");
 
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 851ae69ed3f..36d5a575ab4 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -1011,15 +1011,26 @@ static void rna_def_colormanage(BlenderRNA *brna)
 	RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagement_update");
 
 	/* ** Colorspace **  */
-	srna = RNA_def_struct(brna, "ColorManagedColorspaceSettings", NULL);
-	RNA_def_struct_ui_text(srna, "ColorManagedColorspaceSettings", "Input color space settings");
+	srna = RNA_def_struct(brna, "ColorManagedInputColorspaceSettings", NULL);
+	RNA_def_struct_ui_text(srna, "ColorManagedInputColorspaceSettings", "Input color space settings");
 
 	prop = RNA_def_property(srna, "name", PROP_ENUM, PROP_NONE);
 	RNA_def_property_enum_items(prop, color_space_items);
 	RNA_def_property_enum_funcs(prop, "rna_ColorManagedColorspaceSettings_colorspace_get",
 	                                  "rna_ColorManagedColorspaceSettings_colorspace_set",
 	                                  "rna_ColorManagedColorspaceSettings_colorspace_itemf");
-	RNA_def_property_ui_text(prop, "Color Space", "Input color space name");
+	RNA_def_property_ui_text(prop, "Input Color Space", "Color space of the image or movie on disk");
+	RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagedColorspaceSettings_reload_update");
+
+	srna = RNA_def_struct(brna, "ColorManagedSequencerColorspaceSettings", NULL);
+	RNA_def_struct_ui_text(srna, "ColorManagedSequencerColorspaceSettings", "Input color space settings");
+
+	prop = RNA_def_property(srna, "name", PROP_ENUM, PROP_NONE);
+	RNA_def_property_enum_items(prop, color_space_items);
+	RNA_def_property_enum_funcs(prop, "rna_ColorManagedColorspaceSettings_colorspace_get",
+	                                  "rna_ColorManagedColorspaceSettings_colorspace_set",
+	                                  "rna_ColorManagedColorspaceSettings_colorspace_itemf");
+	RNA_def_property_ui_text(prop, "Color Space", "Color space that the sequencer operates in");
 	RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagedColorspaceSettings_reload_update");
 }
 
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 30a9bfd81f6..0c8fb3d6a36 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -214,7 +214,7 @@ static void rna_Constraint_name_set(PointerRNA *ptr, const char *value)
 		
 		/* if we have the list, check for unique name, otherwise give up */
 		if (list)
-			unique_constraint_name(con, list);
+			BKE_unique_constraint_name(con, list);
 	}
 	
 	/* fix all the animation data which may link to this */
@@ -293,7 +293,7 @@ static EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSED(C),
                                                            PropertyRNA *UNUSED(prop), int *UNUSED(free))
 {
 	bConstraint *con = (bConstraint *)ptr->data;
-	bConstraintTypeInfo *cti = constraint_get_typeinfo(con);
+	bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
 	ListBase targets = {NULL, NULL};
 	bConstraintTarget *ct;
 	
@@ -1392,19 +1392,19 @@ static void rna_def_constraint_rigid_body_joint(BlenderRNA *brna)
 	prop = RNA_def_property(srna, "axis_x", PROP_FLOAT, PROP_ANGLE);
 	RNA_def_property_float_sdna(prop, NULL, "axX");
 	RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
-	RNA_def_property_ui_text(prop, "Axis X", "Rotate pivot on X axis in degrees");
+	RNA_def_property_ui_text(prop, "Axis X", "Rotate pivot on X axis");
 	RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 
 	prop = RNA_def_property(srna, "axis_y", PROP_FLOAT, PROP_ANGLE);
 	RNA_def_property_float_sdna(prop, NULL, "axY");
 	RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
-	RNA_def_property_ui_text(prop, "Axis Y", "Rotate pivot on Y axis in degrees");
+	RNA_def_property_ui_text(prop, "Axis Y", "Rotate pivot on Y axis");
 	RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 
 	prop = RNA_def_property(srna, "axis_z", PROP_FLOAT, PROP_ANGLE);
 	RNA_def_property_float_sdna(prop, NULL, "axZ");
 	RNA_def_property_range(prop, -M_PI * 2, M_PI * 2);
-	RNA_def_property_ui_text(prop, "Axis Z", "Rotate pivot on Z axis in degrees");
+	RNA_def_property_ui_text(prop, "Axis Z", "Rotate pivot on Z axis");
 	RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
 
 	prop = RNA_def_property(srna, "use_linked_collision", PROP_BOOLEAN, PROP_NONE);
@@ -1528,7 +1528,7 @@ static void rna_def_constraint_clamp_to(BlenderRNA *brna)
 	prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
 	RNA_def_property_pointer_sdna(prop, NULL, "tar");
 	RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Curve_object_poll");
-	RNA_def_property_ui_text(prop, "Target", "Target Object");
+	RNA_def_property_ui_text(prop, "Target", "Target Object (Curves only)");
 	RNA_def_property_flag(prop, PROP_EDITABLE);
 	RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
 
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index bb1ecea6a24..727b1e44931 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -391,7 +391,9 @@ static int rna_validate_identifier(const char *identifier, char *error, int prop
 {
 	int a = 0;
 	
-	/*  list from http://docs.python.org/py3k/reference/lexical_analysis.html#keywords */
+	/* list is from...
+	 * ", ".join(['"%s"' % kw for kw in  __import__("keyword").kwlist if kw not in {"False", "None", "True"}])
+	 */
 	static const char *kwlist[] = {
 		/* "False", "None", "True", */
 		"and", "as", "assert", "break",
@@ -631,7 +633,7 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char *
 	if (DefRNA.preprocess) {
 		char error[512];
 
-		if (rna_validate_identifier(identifier, error, 0) == 0) {
+		if (rna_validate_identifier(identifier, error, FALSE) == 0) {
 			fprintf(stderr, "%s: struct identifier \"%s\" error - %s\n", __func__, identifier, error);
 			DefRNA.error = 1;
 		}
@@ -909,7 +911,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
 	if (DefRNA.preprocess) {
 		char error[512];
 		
-		if (rna_validate_identifier(identifier, error, 1) == 0) {
+		if (rna_validate_identifier(identifier, error, TRUE) == 0) {
 			fprintf(stderr, "%s: property identifier \"%s.%s\" - %s\n", __func__,
 			        CONTAINER_RNA_ID(cont), identifier, error);
 			DefRNA.error = 1;
@@ -926,6 +928,16 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier
 		dprop = MEM_callocN(sizeof(PropertyDefRNA), "PropertyDefRNA");
 		rna_addtail(&dcont->properties, dprop);
 	}
+	else {
+#ifdef DEBUG
+		char error[512];
+		if (rna_validate_identifier(identifier, error, TRUE) == 0) {
+			fprintf(stderr, "%s: runtime property identifier \"%s.%s\" - %s\n", __func__,
+			        CONTAINER_RNA_ID(cont), identifier, error);
+			DefRNA.error = 1;
+		}
+#endif
+	}
 
 	prop = MEM_callocN(rna_property_type_sizeof(type), "PropertyRNA");
 
@@ -2674,7 +2686,7 @@ static FunctionRNA *rna_def_function(StructRNA *srna, const char *identifier)
 	if (DefRNA.preprocess) {
 		char error[512];
 
-		if (rna_validate_identifier(identifier, error, 0) == 0) {
+		if (rna_validate_identifier(identifier, error, FALSE) == 0) {
 			fprintf(stderr, "%s: function identifier \"%s\" - %s\n", __func__, identifier, error);
 			DefRNA.error = 1;
 		}
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index 4f9f2009a14..99d2f6dbbda 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -32,6 +32,8 @@
 
 #include "rna_internal.h"
 
+#include "BLI_math_base.h"
+
 #include "BKE_modifier.h"
 #include "BKE_dynamicpaint.h"
 
@@ -219,6 +221,14 @@ static int rna_DynamicPaint_is_cache_user_get(PointerRNA *ptr)
 	return (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ) ?  1 : 0;
 }
 
+/* is some 3D view preview available */
+static int rna_DynamicPaint_use_color_preview_get(PointerRNA *ptr)
+{
+	DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data;
+
+	return dynamicPaint_surfaceHasColorPreview(surface);
+}
+
 /* does output layer exist*/
 static int rna_DynamicPaint_is_output_exists(DynamicPaintSurface *surface, Object *ob, int index)
 {
@@ -239,6 +249,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe
 	tmp.value = MOD_DPAINT_SURFACE_T_PAINT;
 	tmp.identifier = "PAINT";
 	tmp.name = "Paint";
+	tmp.icon = ICON_TPAINT_HLT;
 	RNA_enum_item_add(&item, &totitem, &tmp);
 
 	/* Displace */
@@ -248,6 +259,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe
 		tmp.value = MOD_DPAINT_SURFACE_T_DISPLACE;
 		tmp.identifier = "DISPLACE";
 		tmp.name = "Displace";
+		tmp.icon = ICON_MOD_DISPLACE;
 		RNA_enum_item_add(&item, &totitem, &tmp);
 	}
 
@@ -256,6 +268,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe
 		tmp.value = MOD_DPAINT_SURFACE_T_WEIGHT;
 		tmp.identifier = "WEIGHT";
 		tmp.name = "Weight";
+		tmp.icon = ICON_MOD_VERTEX_WEIGHT;
 		RNA_enum_item_add(&item, &totitem, &tmp);
 	}
 
@@ -264,6 +277,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe
 		tmp.value = MOD_DPAINT_SURFACE_T_WAVE;
 		tmp.identifier = "WAVE";
 		tmp.name = "Waves";
+		tmp.icon = ICON_MOD_WAVE;
 		RNA_enum_item_add(&item, &totitem, &tmp);
 	}
 
@@ -705,6 +719,14 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
 	RNA_def_property_boolean_funcs(prop, "rna_DynamicPaint_is_cache_user_get", NULL);
 	RNA_def_property_ui_text(prop, "Use Cache", "");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+
+	/* whether this surface has preview data for 3D view */
+	RNA_define_verify_sdna(FALSE);
+	prop = RNA_def_property(srna, "use_color_preview", PROP_BOOLEAN, PROP_NONE);
+	RNA_def_property_boolean_funcs(prop, "rna_DynamicPaint_use_color_preview_get", NULL);
+	RNA_def_property_ui_text(prop, "Use Color Preview", "Whether this surface has some color preview for 3D view");
+	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+	RNA_define_verify_sdna(TRUE);
 }
 
 static void rna_def_dynamic_paint_canvas_settings(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 9fedbee41ff..5d37f67fa93 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -116,15 +116,6 @@ static void rna_Image_fields_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P
 	BKE_image_release_ibuf(ima, ibuf, lock);
 }
 
-static void rna_Image_free_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
-{
-	Image *ima = ptr->id.data;
-	BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
-	WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id);
-	DAG_id_tag_update(&ima->id, 0);
-}
-
-
 static void rna_Image_reload_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
 {
 	Image *ima = ptr->id.data;
@@ -139,6 +130,15 @@ static void rna_Image_generated_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
 	BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
 }
 
+static void rna_Image_colormanage_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+	Image *ima = ptr->id.data;
+	BKE_image_signal(ima, NULL, IMA_SIGNAL_COLORMANAGE);
+	DAG_id_tag_update(&ima->id, 0);
+	WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id);
+	WM_main_add_notifier(NC_IMAGE | NA_EDITED, &ima->id);
+}
+
 static void rna_ImageUser_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
 {
 	ImageUser *iuser = ptr->data;
@@ -463,6 +463,11 @@ static void rna_def_image(BlenderRNA *brna)
 		{IMA_STD_FIELD, "ODD", 0, "Lower First", "Lower field first"},
 		{0, NULL, 0, NULL, NULL}
 	};
+	static const EnumPropertyItem alpha_mode_items[] = {
+		{IMA_ALPHA_STRAIGHT, "STRAIGHT", 0, "Straight", "Transparent RGB and alpha pixels are unmodified"},
+		{IMA_ALPHA_PREMUL, "PREMUL", 0, "Premultiplied", "Transparent RGB pixels are multiplied by the alpha channel"},
+		{0, NULL, 0, NULL, NULL}
+	};
 
 	srna = RNA_def_struct(brna, "Image", "ID");
 	RNA_def_struct_ui_text(srna, "Image", "Image datablock referencing an external or packed image");
@@ -512,23 +517,17 @@ static void rna_def_image(BlenderRNA *brna)
 	RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_fields_update");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 	
-	prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE);
-	RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DO_PREMUL);
-	RNA_def_property_ui_text(prop, "Premultiply", "Convert RGB from key alpha to premultiplied alpha");
-	RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_free_update");
-	
-	prop = RNA_def_property(srna, "use_color_unpremultiply", PROP_BOOLEAN, PROP_NONE);
-	RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_CM_PREDIVIDE);
-	RNA_def_property_ui_text(prop, "Color Unpremultiply",
-	                         "For premultiplied alpha images, do color space conversion on colors without alpha, "
-	                         "to avoid fringing for images with light backgrounds");
-	RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_free_update");
 
 	prop = RNA_def_property(srna, "view_as_render", PROP_BOOLEAN, PROP_NONE);
 	RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_VIEW_AS_RENDER);
 	RNA_def_property_ui_text(prop, "View as Render", "Apply render part of display transformation when displaying this image on the screen");
 	RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
 
+	prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE);
+	RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", IMA_IGNORE_ALPHA);
+	RNA_def_property_ui_text(prop, "Use Alpha", "Use the alpha channel information from the image or make image fully opaque");
+	RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
+
 	prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
 	RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL);
 	RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@@ -674,9 +673,14 @@ static void rna_def_image(BlenderRNA *brna)
 
 	prop = RNA_def_property(srna, "colorspace_settings", PROP_POINTER, PROP_NONE);
 	RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings");
-	RNA_def_property_struct_type(prop, "ColorManagedColorspaceSettings");
+	RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings");
 	RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
 
+	prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE);
+	RNA_def_property_enum_items(prop, alpha_mode_items);
+	RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels");
+	RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
+
 	RNA_api_image(srna);
 }
 
diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c
index af39500442d..660f6fc6ab7 100644
--- a/source/blender/makesrna/intern/rna_lamp.c
+++ b/source/blender/makesrna/intern/rna_lamp.c
@@ -54,7 +54,7 @@ static void rna_Lamp_buffer_size_set(PointerRNA *ptr, int value)
 {
 	Lamp *la = (Lamp *)ptr->data;
 
-	CLAMP(value, 512, 10240);
+	CLAMP(value, 128, 10240);
 	la->bufsize = value;
 	la->bufsize &= (~15); /* round to multiple of 16 */
 }
@@ -540,7 +540,7 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area)
 
 	prop = RNA_def_property(srna, "shadow_buffer_size", PROP_INT, PROP_NONE);
 	RNA_def_property_int_sdna(prop, NULL, "bufsize");
-	RNA_def_property_range(prop, 512, 10240);
+	RNA_def_property_range(prop, 128, 10240);
 	RNA_def_property_ui_text(prop, "Shadow Buffer Size",
 	                         "Resolution of the shadow buffer, higher values give crisper shadows "
 	                         "but use more memory");
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index eb1fd61d9a7..31e27ebc982 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -154,7 +154,6 @@ static void rna_Mesh_update_vertmask(Main *bmain, Scene *scene, PointerRNA *ptr)
 	Mesh *me = ptr->data;
 	if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && (me->editflag & ME_EDIT_PAINT_FACE_SEL)) {
 		me->editflag &= ~ME_EDIT_PAINT_FACE_SEL;
-		BKE_mesh_flush_select_from_polys(me);
 	}
 	rna_Mesh_update_draw(bmain, scene, ptr);
 }
@@ -164,7 +163,6 @@ static void rna_Mesh_update_facemask(Main *bmain, Scene *scene, PointerRNA *ptr)
 	Mesh *me = ptr->data;
 	if ((me->editflag & ME_EDIT_PAINT_VERT_SEL) && (me->editflag & ME_EDIT_PAINT_FACE_SEL)) {
 		me->editflag &= ~ME_EDIT_PAINT_VERT_SEL;
-		BKE_mesh_flush_select_from_verts(me);
 	}
 	rna_Mesh_update_draw(bmain, scene, ptr);
 }
@@ -2963,7 +2961,7 @@ static void rna_def_mesh(BlenderRNA *brna)
 	prop = RNA_def_property(srna, "show_extra_face_angle", PROP_BOOLEAN, PROP_NONE);
 	RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_FACEANG);
 	RNA_def_property_ui_text(prop, "Face Angles",
-	                         "Display the angles in the selected edges in degrees, "
+	                         "Display the angles in the selected edges, "
 	                         "using global values when set in the transform panel");
 	RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
 
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index e1489d821a0..7a576c88677 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -748,13 +748,13 @@ static void rna_BevelModifier_angle_limit_set(PointerRNA *ptr, float value)
 
 static void rna_UVWarpModifier_vgroup_set(PointerRNA *ptr, const char *value)
 {
-	UVWarpModifierData *umd = (UVWarpModifierData*)ptr->data;
+	UVWarpModifierData *umd = (UVWarpModifierData *)ptr->data;
 	rna_object_vgroup_name_set(ptr, value, umd->vgroup_name, sizeof(umd->vgroup_name));
 }
 
 static void rna_UVWarpModifier_uvlayer_set(PointerRNA *ptr, const char *value)
 {
-	UVWarpModifierData *umd = (UVWarpModifierData*)ptr->data;
+	UVWarpModifierData *umd = (UVWarpModifierData *)ptr->data;
 	rna_object_uvlayer_name_set(ptr, value, umd->uvlayer_name, sizeof(umd->uvlayer_name));
 }
 
@@ -3269,7 +3269,7 @@ static void rna_def_modifier_ocean(BlenderRNA *brna)
 	
 	prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_UNSIGNED);
 	RNA_def_property_float_sdna(prop, NULL, "size");
-	RNA_def_property_ui_text(prop, "Size", "");
+	RNA_def_property_ui_text(prop, "Size", "Surface scale factor (does not affect the height of the waves)");
 	RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 0);
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_topology_update");
 	
@@ -3310,16 +3310,17 @@ static void rna_def_modifier_ocean(BlenderRNA *brna)
 	RNA_def_property_ui_text(prop, "Resolution", "Resolution of the generated surface");
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
 	
-	prop = RNA_def_property(srna, "spatial_size", PROP_INT, PROP_DISTANCE);
+	prop = RNA_def_property(srna, "spatial_size", PROP_INT, PROP_NONE);
 	RNA_def_property_int_sdna(prop, NULL, "spatial_size");
 	RNA_def_property_ui_range(prop, 1, 512, 2, 0);
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-	RNA_def_property_ui_text(prop, "Spatial Size", "Physical size of the simulation domain (m)");
+	RNA_def_property_ui_text(prop, "Spatial Size",
+	                         "Size of the simulation domain (in meters), and of the generated geometry (in BU)");
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
 	
 	prop = RNA_def_property(srna, "wind_velocity", PROP_FLOAT, PROP_VELOCITY);
 	RNA_def_property_float_sdna(prop, NULL, "wind_velocity");
-	RNA_def_property_ui_text(prop, "Wind Velocity", "Wind speed (m/s)");
+	RNA_def_property_ui_text(prop, "Wind Velocity", "Wind speed");
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
 	
 	prop = RNA_def_property(srna, "damping", PROP_FLOAT, PROP_FACTOR);
@@ -3332,42 +3333,43 @@ static void rna_def_modifier_ocean(BlenderRNA *brna)
 	RNA_def_property_float_sdna(prop, NULL, "smallest_wave");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 	RNA_def_property_range(prop, 0.0, FLT_MAX);
-	RNA_def_property_ui_text(prop, "Smallest Wave", "Shortest allowed wavelength (m)");
+	RNA_def_property_ui_text(prop, "Smallest Wave", "Shortest allowed wavelength");
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
 	
 	prop = RNA_def_property(srna, "wave_alignment", PROP_FLOAT, PROP_UNSIGNED);
 	RNA_def_property_float_sdna(prop, NULL, "wave_alignment");
 	RNA_def_property_range(prop, 0.0, 10.0);
-	RNA_def_property_ui_text(prop, "Wave Alignment", "");
+	RNA_def_property_ui_text(prop, "Wave Alignment", "How much the waves are aligned to each other");
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
 	
 	prop = RNA_def_property(srna, "wave_direction", PROP_FLOAT, PROP_ANGLE);
 	RNA_def_property_float_sdna(prop, NULL, "wave_direction");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-	RNA_def_property_ui_text(prop, "Wave Direction", "");
+	RNA_def_property_ui_text(prop, "Wave Direction", "Main direction of the waves when they are (partially) aligned");
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
 	
 	prop = RNA_def_property(srna, "wave_scale", PROP_FLOAT, PROP_UNSIGNED);
 	RNA_def_property_float_sdna(prop, NULL, "wave_scale");
-	RNA_def_property_ui_text(prop, "Wave Scale", "");
+	RNA_def_property_ui_text(prop, "Wave Scale", "Scale of the displacement effect");
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_sim_update");
 	
-	prop = RNA_def_property(srna, "depth", PROP_FLOAT, PROP_UNSIGNED);
+	prop = RNA_def_property(srna, "depth", PROP_FLOAT, PROP_DISTANCE);
 	RNA_def_property_float_sdna(prop, NULL, "depth");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-	RNA_def_property_ui_text(prop, "Depth", "");
+	RNA_def_property_ui_text(prop, "Depth", "Depth of the solid ground below the water surface");
 	RNA_def_property_ui_range(prop, 0, 250, 1, 0);
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
 	
 	prop = RNA_def_property(srna, "foam_coverage", PROP_FLOAT, PROP_NONE);
 	RNA_def_property_float_sdna(prop, NULL, "foam_coverage");
-	RNA_def_property_ui_text(prop, "Foam Coverage", "");
+	RNA_def_property_ui_text(prop, "Foam Coverage", "Amount of generated foam");
 	RNA_def_property_update(prop, 0, "rna_Modifier_update");
 	
 	prop = RNA_def_property(srna, "bake_foam_fade", PROP_FLOAT, PROP_UNSIGNED);
 	RNA_def_property_float_sdna(prop, NULL, "foam_fade");
-	RNA_def_property_ui_text(prop, "Foam Fade", "");
-	RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 0);
+	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+	RNA_def_property_ui_text(prop, "Foam Fade", "How much foam accumulates over time (baked ocean only)");
+	RNA_def_property_ui_range(prop, 0.0, 10.0, 1, 0);
 	RNA_def_property_update(prop, 0, NULL);
 	
 	prop = RNA_def_property(srna, "foam_layer_name", PROP_STRING, PROP_NONE);
@@ -3377,33 +3379,34 @@ static void rna_def_modifier_ocean(BlenderRNA *brna)
 	
 	prop = RNA_def_property(srna, "choppiness", PROP_FLOAT, PROP_UNSIGNED);
 	RNA_def_property_float_sdna(prop, NULL, "chop_amount");
-	RNA_def_property_ui_text(prop, "Choppiness", "");
+	RNA_def_property_ui_text(prop, "Choppiness",
+	                         "Choppiness of the wave's crest (adds some horizontal component to the displacement)");
 	RNA_def_property_ui_range(prop, 0.0, 4.0, 3, 0);
 	RNA_def_property_float_funcs(prop, NULL, "rna_OceanModifier_ocean_chop_set", NULL);
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_sim_update");
 	
 	prop = RNA_def_property(srna, "time", PROP_FLOAT, PROP_UNSIGNED);
 	RNA_def_property_float_sdna(prop, NULL, "time");
-	RNA_def_property_ui_text(prop, "Time", "");
+	RNA_def_property_ui_text(prop, "Time", "Current time of the simulation");
 	RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 0);
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_sim_update");
 	
 	prop = RNA_def_property(srna, "random_seed", PROP_INT, PROP_UNSIGNED);
 	RNA_def_property_int_sdna(prop, NULL, "seed");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-	RNA_def_property_ui_text(prop, "Random Seed", "");
+	RNA_def_property_ui_text(prop, "Random Seed", "Seed of the random generator");
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
 	
 	prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_UNSIGNED);
 	RNA_def_property_int_sdna(prop, NULL, "bakestart");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-	RNA_def_property_ui_text(prop, "Bake Start", "");
+	RNA_def_property_ui_text(prop, "Bake Start", "Start frame of the ocean baking");
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
 	
 	prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_UNSIGNED);
 	RNA_def_property_int_sdna(prop, NULL, "bakeend");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
-	RNA_def_property_ui_text(prop, "Bake End", "");
+	RNA_def_property_ui_text(prop, "Bake End", "End frame of the ocean baking");
 	RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update");
 	
 	prop = RNA_def_property(srna, "is_cached", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index 99effc990a8..3b018591455 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -308,7 +308,7 @@ static void rna_def_movieclip(BlenderRNA *brna)
 	/* color management */
 	prop = RNA_def_property(srna, "colorspace_settings", PROP_POINTER, PROP_NONE);
 	RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings");
-	RNA_def_property_struct_type(prop, "ColorManagedColorspaceSettings");
+	RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings");
 	RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
 }
 
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 3e9f5f1b88f..18dfd8aa6f9 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -1101,7 +1101,7 @@ static void rna_ShaderNodeScript_mode_set(PointerRNA *ptr, int value)
 
 		/* replace text datablock by filepath */
 		if (node->id) {
-			Text *text = (Text*)node->id;
+			Text *text = (Text *)node->id;
 
 			if (value == NODE_SCRIPT_EXTERNAL && text->name) {
 				BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath));
@@ -3217,8 +3217,8 @@ static void def_cmp_premul_key(StructRNA *srna)
 	PropertyRNA *prop;
 	
 	static EnumPropertyItem type_items[] = {
-		{0, "KEY_TO_PREMUL", 0, "Key to Premul", ""},
-		{1, "PREMUL_TO_KEY", 0, "Premul to Key", ""},
+		{0, "STRAIGHT_TO_PREMUL", 0, "Straight to Premul", ""},
+		{1, "PREMUL_TO_STRAIGHT", 0, "Premul to Straight", ""},
 		{0, NULL, 0, NULL, NULL}
 	};
 	
diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h
index de535156199..46f2306f284 100644
--- a/source/blender/makesrna/intern/rna_nodetree_types.h
+++ b/source/blender/makesrna/intern/rna_nodetree_types.h
@@ -84,6 +84,7 @@ DefNode( ShaderNode,     SH_NODE_LIGHT_PATH,         0,                      "LI
 DefNode( ShaderNode,     SH_NODE_LIGHT_FALLOFF,      0,                      "LIGHT_FALLOFF",      LightFalloff,     "Light Falloff",     ""       )
 DefNode( ShaderNode,     SH_NODE_OBJECT_INFO,        0,                      "OBJECT_INFO",        ObjectInfo,       "Object Info",       ""       )
 DefNode( ShaderNode,     SH_NODE_PARTICLE_INFO,      0,                      "PARTICLE_INFO",      ParticleInfo,     "Particle Info",     ""       )
+DefNode( ShaderNode,     SH_NODE_HAIR_INFO,          0,                      "HAIR_INFO",          HairInfo,         "Hair Info",         ""       )
 DefNode( ShaderNode,     SH_NODE_BUMP,               0,                      "BUMP",               Bump,             "Bump",              ""       )
 DefNode( ShaderNode,     SH_NODE_NORMAL_MAP,         def_sh_normal_map,      "NORMAL_MAP",         NormalMap,        "Normal Map",        ""       )
 DefNode( ShaderNode,     SH_NODE_TANGENT,            def_sh_tangent,         "TANGENT",            Tangent,          "Tangent",           ""       )
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index b218cc6a944..80d74c3a9fe 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -48,6 +48,7 @@
 
 #include "BLI_utildefines.h"
 
+#include "BKE_paint.h"
 #include "BKE_tessmesh.h"
 #include "BKE_group.h" /* needed for object_in_group() */
 
@@ -1123,7 +1124,7 @@ static void rna_GameObjectSettings_used_state_get(PointerRNA *ptr, int *values)
 
 static void rna_GameObjectSettings_col_group_get(PointerRNA *ptr, int *values)
 {
-	Object *ob = (Object*)ptr->data;
+	Object *ob = (Object *)ptr->data;
 	int i;
 
 	for (i = 0; i < OB_MAX_COL_MASKS; i++) {
@@ -1133,7 +1134,7 @@ static void rna_GameObjectSettings_col_group_get(PointerRNA *ptr, int *values)
 
 static void rna_GameObjectSettings_col_group_set(PointerRNA *ptr, const int *values)
 {
-	Object *ob = (Object*)ptr->data;
+	Object *ob = (Object *)ptr->data;
 	int i, tot = 0;
 
 	/* ensure we always have some group selected */
@@ -1152,7 +1153,7 @@ static void rna_GameObjectSettings_col_group_set(PointerRNA *ptr, const int *val
 
 static void rna_GameObjectSettings_col_mask_get(PointerRNA *ptr, int *values)
 {
-	Object *ob = (Object*)ptr->data;
+	Object *ob = (Object *)ptr->data;
 	int i;
 
 	for (i = 0; i < OB_MAX_COL_MASKS; i++) {
@@ -1162,7 +1163,7 @@ static void rna_GameObjectSettings_col_mask_get(PointerRNA *ptr, int *values)
 
 static void rna_GameObjectSettings_col_mask_set(PointerRNA *ptr, const int *values)
 {
-	Object *ob = (Object*)ptr->data;
+	Object *ob = (Object *)ptr->data;
 	int i, tot = 0;
 
 	/* ensure we always have some mask selected */
@@ -1252,20 +1253,20 @@ static PointerRNA rna_Object_collision_get(PointerRNA *ptr)
 static PointerRNA rna_Object_active_constraint_get(PointerRNA *ptr)
 {
 	Object *ob = (Object *)ptr->id.data;
-	bConstraint *con = constraints_get_active(&ob->constraints);
+	bConstraint *con = BKE_constraints_get_active(&ob->constraints);
 	return rna_pointer_inherit_refine(ptr, &RNA_Constraint, con);
 }
 
 static void rna_Object_active_constraint_set(PointerRNA *ptr, PointerRNA value)
 {
 	Object *ob = (Object *)ptr->id.data;
-	constraints_set_active(&ob->constraints, (bConstraint *)value.data);
+	BKE_constraints_set_active(&ob->constraints, (bConstraint *)value.data);
 }
 
 static bConstraint *rna_Object_constraints_new(Object *object, int type)
 {
 	WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_ADDED, object);
-	return add_ob_constraint(object, NULL, type);
+	return BKE_add_ob_constraint(object, NULL, type);
 }
 
 static void rna_Object_constraints_remove(Object *object, ReportList *reports, PointerRNA *con_ptr)
@@ -1276,7 +1277,7 @@ static void rna_Object_constraints_remove(Object *object, ReportList *reports, P
 		return;
 	}
 
-	remove_constraint(&object->constraints, con);
+	BKE_remove_constraint(&object->constraints, con);
 	RNA_POINTER_INVALIDATE(con_ptr);
 
 	ED_object_constraint_update(object);
@@ -1286,7 +1287,7 @@ static void rna_Object_constraints_remove(Object *object, ReportList *reports, P
 
 static void rna_Object_constraints_clear(Object *object)
 {
-	free_constraints(&object->constraints);
+	BKE_free_constraints(&object->constraints);
 
 	ED_object_constraint_update(object);
 	ED_object_constraint_set_active(object, NULL);
@@ -1436,6 +1437,12 @@ int rna_DupliObject_index_get(PointerRNA *ptr)
 	return dob->persistent_id[0];
 }
 
+int rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr)
+{
+	SculptSession *ss = ((Object *)ptr->id.data)->sculpt;
+	return (ss && ss->bm);
+}
+
 #else
 
 static int rna_matrix_dimsize_4x4[] = {4, 4};
@@ -2629,6 +2636,12 @@ static void rna_def_object(BlenderRNA *brna)
 	RNA_def_property_ui_text(prop, "Active Shape Key Index", "Current shape key index");
 	RNA_def_property_update(prop, 0, "rna_Object_active_shape_update");
 
+	/* sculpt */
+	prop = RNA_def_property(srna, "use_dynamic_topology_sculpting", PROP_BOOLEAN, PROP_NONE);
+	RNA_def_property_boolean_funcs(prop, "rna_Object_use_dynamic_topology_sculpting_get", NULL);
+	RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+	RNA_def_property_ui_text(prop, "Dynamic Topology Sculpting", NULL);
+
 	RNA_api_object(srna);
 }
 
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 87fc3be28a2..d7115256fe5 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -36,42 +36,79 @@
 
 #include "RNA_define.h"
 
-#include "DNA_object_types.h"
+#include "DNA_constraint_types.h"
 #include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
 
 #include "rna_internal.h"  /* own include */
 
+static EnumPropertyItem space_items[] = {
+	{CONSTRAINT_SPACE_WORLD,    "WORLD", 0, "World Space",
+	                            "The most gobal space in Blender"},
+	{CONSTRAINT_SPACE_POSE,     "POSE", 0, "Pose Space",
+	                            "The pose space of a bone (its armature's object space)"},
+	{CONSTRAINT_SPACE_PARLOCAL, "LOCAL_WITH_PARENT", 0, "Local With Parent",
+	                            "The local space of a bone's parent bone"},
+	{CONSTRAINT_SPACE_LOCAL,    "LOCAL", 0, "Local Space",
+	                            "The local space of an object/bone"},
+	{0, NULL, 0, NULL, NULL}
+};
+
 #ifdef RNA_RUNTIME
+
 #include "BLI_math.h"
 
-#include "BKE_main.h"
-#include "BKE_global.h"
-#include "BKE_context.h"
-#include "BKE_report.h"
-#include "BKE_object.h"
-#include "BKE_mesh.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_bvhutils.h"
-
-#include "BKE_customdata.h"
 #include "BKE_anim.h"
+#include "BKE_bvhutils.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_customdata.h"
 #include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
 #include "BKE_displist.h"
 #include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
 #include "BKE_mball.h"
 #include "BKE_modifier.h"
-#include "BKE_cdderivedmesh.h"
+#include "BKE_object.h"
+#include "BKE_report.h"
 
-#include "DNA_mesh_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_meshdata_types.h"
 #include "DNA_curve_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_constraint_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
 #include "DNA_view3d_types.h"
 
 #include "MEM_guardedalloc.h"
 
+/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
+static void rna_Scene_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan,
+                                        float *mat, float *mat_ret, int from, int to)
+{
+	copy_m4_m4((float (*)[4])mat_ret, (float (*)[4])mat);
+
+	/* Error in case of invalid from/to values when pchan is NULL */
+	if (pchan == NULL) {
+		if (ELEM(from, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL)) {
+			const char *identifier = NULL;
+			RNA_enum_identifier(space_items, from, &identifier);
+			BKE_reportf(reports, RPT_ERROR, "'from_space' '%s' is invalid when no pose bone is given!", identifier);
+			return;
+		}
+		if (ELEM(to, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL)) {
+			const char *identifier = NULL;
+			RNA_enum_identifier(space_items, to, &identifier);
+			BKE_reportf(reports, RPT_ERROR, "'to_space' '%s' is invalid when no pose bone is given!", identifier);
+			return;
+		}
+	}
+
+	BKE_constraint_mat_convertspace(ob, pchan, (float (*)[4])mat_ret, from, to);
+}
+
 /* copied from Mesh_getFromObject and adapted to RNA interface */
 /* settings: 0 - preview, 1 - render */
 static Mesh *rna_Object_to_mesh(Object *ob, ReportList *reports, Scene *sce, int apply_modifiers, int settings)
@@ -570,7 +607,7 @@ void rna_Object_dm_info(struct Object *ob, int type, char *result)
 }
 #endif /* NDEBUG */
 
-#else
+#else /* RNA_RUNTIME */
 
 void RNA_api_object(StructRNA *srna)
 {
@@ -583,6 +620,8 @@ void RNA_api_object(StructRNA *srna)
 		{0, NULL, 0, NULL, NULL}
 	};
 
+	static int rna_matrix_dimsize_4x4[] = {4, 4};
+
 #ifndef NDEBUG
 	static EnumPropertyItem mesh_dm_info_items[] = {
 		{0, "SOURCE", 0, "Source", "Source mesh"},
@@ -592,6 +631,25 @@ void RNA_api_object(StructRNA *srna)
 	};
 #endif
 
+	/* Matrix space conversion */
+	func = RNA_def_function(srna, "convert_space", "rna_Scene_mat_convert_space");
+	RNA_def_function_ui_description(func, "Convert (transform) the given matrix from one space to another");
+	RNA_def_function_flag(func, FUNC_USE_REPORTS);
+	parm = RNA_def_pointer(func, "pose_bone", "PoseBone", "",
+	                       "Bone to use to define spaces (may be None, in which case only the two 'WORLD' and "
+	                       "'LOCAL' spaces are usable)");
+	parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
+	RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
+	RNA_def_property_ui_text(parm, "", "The matrix to transform");
+	parm = RNA_def_property(func, "matrix_return", PROP_FLOAT, PROP_MATRIX);
+	RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
+	RNA_def_property_ui_text(parm, "", "The transformed matrix");
+	RNA_def_function_output(func, parm);
+	parm = RNA_def_enum(func, "from_space", space_items, CONSTRAINT_SPACE_WORLD, "",
+	                    "The space in which 'matrix' is currently");
+	parm = RNA_def_enum(func, "to_space", space_items, CONSTRAINT_SPACE_WORLD, "",
+	                    "The space to which you want to transform 'matrix'");
+
 	/* mesh */
 	func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh");
 	RNA_def_function_ui_description(func, "Create a Mesh datablock with modifiers applied");
@@ -737,5 +795,4 @@ void RNA_api_object_base(StructRNA *srna)
 	RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
 }
 
-#endif
-
+#endif /* RNA_RUNTIME */
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 6d7187da7d9..0c2944b3966 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -763,7 +763,8 @@ static void rna_def_pointcache(BlenderRNA *brna)
 	
 	prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME);
 	RNA_def_property_int_sdna(prop, NULL, "startframe");
-	RNA_def_property_range(prop, 1, MAXFRAME);
+	RNA_def_property_range(prop, -MAXFRAME, MAXFRAME);
+	RNA_def_property_ui_range(prop, -1000, MAXFRAME, 1, 1);
 	RNA_def_property_ui_text(prop, "Start", "Frame on which the simulation starts");
 	
 	prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_TIME);
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 93f940b1aa3..be3cbfaece3 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -238,7 +238,329 @@ static void rna_ParticleHairKey_location_object_set(PointerRNA *ptr, const float
 	}
 }
 
-/* property update functions */
+static void rna_ParticleHairKey_co_object(HairKey *hairkey, Object *object, ParticleSystemModifierData *modifier, ParticleData *particle,
+                                             float n_co[3])
+{
+
+	DerivedMesh *hairdm = (modifier->psys->flag & PSYS_HAIR_DYNAMICS) ? modifier->psys->hair_out_dm : NULL;
+	if (particle) {
+		if (hairdm) {
+			MVert *mvert = CDDM_get_vert(hairdm, particle->hair_index + (hairkey - particle->hair));
+			copy_v3_v3(n_co, mvert->co);
+		}
+		else {
+			float hairmat[4][4];
+			psys_mat_hair_to_object(object, modifier->dm, modifier->psys->part->from, particle, hairmat);
+			copy_v3_v3(n_co, hairkey->co);
+			mul_m4_v3(hairmat, n_co);
+		}
+	}
+	else {
+		zero_v3(n_co);
+	}
+}
+
+static void rna_Particle_uv_on_emitter(ParticleData *particle, ParticleSystemModifierData *modifier, float n_uv[2])
+{
+	/*psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, nor, 0, 0, sd.orco, 0);*/
+
+	/* get uvco & mcol */
+	int num = particle->num_dmcache;
+	int from = modifier->psys->part->from;
+
+	if (num == DMCACHE_NOTFOUND)
+		if (particle->num < modifier->dm->getNumTessFaces(modifier->dm))
+			num = particle->num;
+
+	/* get uvco */
+	if (n_uv && ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+		
+		if (num != DMCACHE_NOTFOUND) {
+			MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
+			MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0);
+			mtface += num;
+			
+			psys_interpolate_uvs(mtface, mface->v4, particle->fuv, n_uv);
+		}
+		else {
+			n_uv[0] = 0.0f;
+			n_uv[1] = 0.0f;
+		}
+	}
+}
+
+static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *object, ParticleSystemModifierData *modifier, int particle_no, int step,
+                                       float n_co[3])
+{
+	ParticleSettings *part = 0;
+	ParticleData *pars = 0;
+	ParticleCacheKey *cache = 0;
+	int totchild = 0;
+	int path_nbr = 0;
+	int totpart;
+	int max_k = 0;
+
+	if (particlesystem == NULL)
+		return;
+
+	part = particlesystem->part;
+	pars = particlesystem->particles;
+
+	if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem))
+		return;
+	
+	if (part->ren_as == PART_DRAW_OB || part->ren_as == PART_DRAW_GR || part->ren_as == PART_DRAW_NOT)
+		return;
+
+	totchild = particlesystem->totchild * part->disp / 100;
+
+	/* can happen for disconnected/global hair */
+	if (part->type == PART_HAIR && !particlesystem->childcache)
+		totchild = 0;
+
+	totpart = particlesystem->totpart;
+
+	if (particle_no >= totpart + totchild)
+		return;
+
+	if (part->ren_as == PART_DRAW_PATH && particlesystem->pathcache)
+		path_nbr = (int)pow(2.0, part->draw_step);
+
+	if (particle_no < totpart) {
+
+		if (path_nbr) {
+			cache = particlesystem->pathcache[particle_no];
+			max_k = (int)cache->steps;
+		}
+
+	}
+	else {
+
+		if (path_nbr) {
+			cache = particlesystem->childcache[particle_no - totpart];
+
+			if (cache->steps < 0)
+				max_k = 0;
+			else
+				max_k = (int)cache->steps;
+		}
+	}
+
+	/*strands key loop data stored in cache + step->co*/
+	if (path_nbr) {
+		if (step >= 0 && step <= path_nbr) {
+			if (step <= max_k)
+				copy_v3_v3(n_co, (cache + step)->co);
+		}
+	}
+
+}
+
+static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, ParticleSystemModifierData *modifier, ParticleData *particle, int particle_no,
+                                             float n_uv[2])
+{
+	ParticleSettings *part = 0;
+	int totpart;
+	int totchild = 0;
+	int num;
+
+	/* 1. check that everything is ok & updated */
+	if (particlesystem == NULL)
+		return;
+
+	part = particlesystem->part;
+
+		totchild = particlesystem->totchild;
+
+	/* can happen for disconnected/global hair */
+	if (part->type == PART_HAIR && !particlesystem->childcache)
+		totchild = 0;
+
+	totpart = particlesystem->totpart;
+
+	if (particle_no >= totpart + totchild)
+		return;
+
+/* 3. start creating renderable things */
+	/* setup per particle individual stuff */
+	if (particle_no < totpart) {
+
+		/* get uvco & mcol */
+		num = particle->num_dmcache;
+
+		if (num == DMCACHE_NOTFOUND)
+			if (particle->num < modifier->dm->getNumTessFaces(modifier->dm))
+				num = particle->num;
+
+		if (n_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+			if (num != DMCACHE_NOTFOUND) {
+				MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
+				MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0);
+				mtface += num;
+				
+				psys_interpolate_uvs(mtface, mface->v4, particle->fuv, n_uv);
+			}
+			else {
+				n_uv[0] = 0.0f;
+				n_uv[1] = 0.0f;
+			}
+		}
+	}
+	else {
+		ChildParticle *cpa = particlesystem->child + particle_no - totpart;
+
+		num = cpa->num;
+
+		/* get uvco & mcol */
+		if (part->childtype == PART_CHILD_FACES) {
+			if (n_uv && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) {
+				if (cpa->num != DMCACHE_NOTFOUND) {
+					MFace *mface = modifier->dm->getTessFaceData(modifier->dm, cpa->num, CD_MFACE);
+					MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0);
+					mtface += cpa->num;
+					
+					psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, n_uv);
+				}
+				else {
+					n_uv[0] = 0.0f;
+					n_uv[1] = 0.0f;
+				}
+			}
+		}
+		else {
+			ParticleData *parent = particlesystem->particles + cpa->parent;
+			num = parent->num_dmcache;
+
+			if (num == DMCACHE_NOTFOUND)
+				if (parent->num < modifier->dm->getNumTessFaces(modifier->dm))
+					num = parent->num;
+
+			if (n_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+				if (num != DMCACHE_NOTFOUND) {
+					MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
+					MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, 0);
+					mtface += num;
+					
+					psys_interpolate_uvs(mtface, mface->v4, parent->fuv, n_uv);
+				}
+				else {
+					n_uv[0] = 0.0f;
+					n_uv[1] = 0.0f;
+				}
+			}
+		}
+	}
+}
+
+static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, ParticleSystemModifierData *modifier, ParticleData *particle, int particle_no, int vcol_no,
+                                             float n_mcol[3])
+{
+	ParticleSettings *part = 0;
+	int totpart;
+	int totchild = 0;
+	int num;
+	MCol mcol = {255, 255, 255, 255};
+
+	/* 1. check that everything is ok & updated */
+	if (particlesystem == NULL)
+		return;
+
+	part = particlesystem->part;
+
+		totchild = particlesystem->totchild;
+
+	/* can happen for disconnected/global hair */
+	if (part->type == PART_HAIR && !particlesystem->childcache)
+		totchild = 0;
+
+	totpart = particlesystem->totpart;
+
+	if (particle_no >= totpart + totchild)
+		return;
+
+/* 3. start creating renderable things */
+	/* setup per particle individual stuff */
+	if (particle_no < totpart) {
+
+		/* get uvco & mcol */
+		num = particle->num_dmcache;
+
+		if (num == DMCACHE_NOTFOUND)
+			if (particle->num < modifier->dm->getNumTessFaces(modifier->dm))
+				num = particle->num;
+
+		if (n_mcol && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+			if (num != DMCACHE_NOTFOUND) {
+				MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
+				MCol *mc = (MCol*)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no);
+				mc += num * 4;
+
+				psys_interpolate_mcol(mc, mface->v4, particle->fuv, &mcol);
+				n_mcol[0] = (float)mcol.b / 255.0f;
+				n_mcol[1] = (float)mcol.g / 255.0f;
+				n_mcol[2] = (float)mcol.r / 255.0f;
+			}
+			else {
+				n_mcol[0] = 0.0f;
+				n_mcol[1] = 0.0f;
+				n_mcol[2] = 0.0f;
+			}
+		}
+	}
+	else {
+		ChildParticle *cpa = particlesystem->child + particle_no - totpart;
+
+		num = cpa->num;
+
+		/* get uvco & mcol */
+		if (part->childtype == PART_CHILD_FACES) {
+			if (n_mcol && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) {
+				if (cpa->num != DMCACHE_NOTFOUND) {
+					MFace *mface = modifier->dm->getTessFaceData(modifier->dm, cpa->num, CD_MFACE);
+					MCol *mc = (MCol*)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, 0);
+					mc += cpa->num * 4;
+
+					psys_interpolate_mcol(mc, mface->v4, cpa->fuv, &mcol);
+					n_mcol[0] = (float)mcol.b / 255.0f;
+					n_mcol[1] = (float)mcol.g / 255.0f;
+					n_mcol[2] = (float)mcol.r / 255.0f;
+				}
+				else {
+					n_mcol[0] = 0.0f;
+					n_mcol[1] = 0.0f;
+					n_mcol[2] = 0.0f;
+				}
+			}
+		}
+		else {
+			ParticleData *parent = particlesystem->particles + cpa->parent;
+			num = parent->num_dmcache;
+
+			if (num == DMCACHE_NOTFOUND)
+				if (parent->num < modifier->dm->getNumTessFaces(modifier->dm))
+					num = parent->num;
+
+			if (n_mcol && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+				if (num != DMCACHE_NOTFOUND) {
+					MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
+					MCol *mc = (MCol*)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, 0);
+					mc += num * 4;
+
+					psys_interpolate_mcol(mc, mface->v4, parent->fuv, &mcol);
+					n_mcol[0] = (float)mcol.b / 255.0f;
+					n_mcol[1] = (float)mcol.g / 255.0f;
+					n_mcol[2] = (float)mcol.r / 255.0f;
+				}
+				else {
+					n_mcol[0] = 0.0f;
+					n_mcol[1] = 0.0f;
+					n_mcol[2] = 0.0f;
+				}
+			}
+		}
+	}
+}
+
 static void particle_recalc(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr, short flag)
 {
 	if (ptr->type == &RNA_ParticleSystem) {
@@ -905,6 +1227,7 @@ static void rna_def_particle_hair_key(BlenderRNA *brna)
 {
 	StructRNA *srna;
 	PropertyRNA *prop;
+	FunctionRNA *func;
 
 	srna = RNA_def_struct(brna, "ParticleHairKey", NULL);
 	RNA_def_struct_sdna(srna, "HairKey");
@@ -928,6 +1251,19 @@ static void rna_def_particle_hair_key(BlenderRNA *brna)
 	RNA_def_property_ui_text(prop, "Location",
 	                         "Location of the hair key in its internal coordinate system, "
 	                         "relative to the emitting face");
+
+	/* Aided co func */
+	func = RNA_def_function(srna, "co_object", "rna_ParticleHairKey_co_object");
+	RNA_def_function_ui_description(func, "Obtain hairkey location with particle and modifier data");
+
+	prop = RNA_def_pointer(func, "object", "Object", "", "Object");
+	prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+	prop = RNA_def_pointer(func, "particle", "Particle", "", "hair particle");
+	
+	prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
+	                            "Exported hairkey location", -1e4, 1e4);
+	RNA_def_property_flag(prop, PROP_THICK_WRAP);
+	RNA_def_function_output(func, prop);
 }
 
 static void rna_def_particle_key(BlenderRNA *brna)
@@ -979,6 +1315,7 @@ static void rna_def_particle(BlenderRNA *brna)
 {
 	StructRNA *srna;
 	PropertyRNA *prop;
+	FunctionRNA *func;
 
 	static EnumPropertyItem alive_items[] = {
 		/*{PARS_KILLED, "KILLED", 0, "Killed", ""}, */
@@ -1083,6 +1420,15 @@ static void rna_def_particle(BlenderRNA *brna)
 	RNA_def_property_ui_text(prop, "Alive State", "");
 
 /*	short rt2; */
+
+/* UVs */
+	func = RNA_def_function(srna, "uv_on_emitter", "rna_Particle_uv_on_emitter");
+	RNA_def_function_ui_description(func, "Obtain uv for particle on derived mesh");
+	prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+	prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
+	RNA_def_property_array(prop, 2);
+	RNA_def_property_flag(prop, PROP_THICK_WRAP);
+	RNA_def_function_output(func, prop);
 }
 
 static void rna_def_particle_dupliweight(BlenderRNA *brna)
@@ -2696,6 +3042,7 @@ static void rna_def_particle_system(BlenderRNA *brna)
 {
 	StructRNA *srna;
 	PropertyRNA *prop;
+	FunctionRNA *func;
 
 	srna = RNA_def_struct(brna, "ParticleSystem", NULL);
 	RNA_def_struct_ui_text(srna, "Particle System", "Particle system in an object");
@@ -2793,7 +3140,6 @@ static void rna_def_particle_system(BlenderRNA *brna)
 	                           "rna_ParticleSystem_active_particle_target_index_range");
 	RNA_def_property_ui_text(prop, "Active Particle Target Index", "");
 
-
 	/* billboard */
 	prop = RNA_def_property(srna, "billboard_normal_uv", PROP_STRING, PROP_NONE);
 	RNA_def_property_string_sdna(prop, NULL, "bb_uvname[0]");
@@ -2995,6 +3341,44 @@ static void rna_def_particle_system(BlenderRNA *brna)
 	RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 
 	RNA_def_struct_path_func(srna, "rna_ParticleSystem_path");
+
+	/* extract cached hair location data */
+	func = RNA_def_function(srna, "co_hair", "rna_ParticleSystem_co_hair");
+	RNA_def_function_ui_description(func, "Obtain cache hair data");
+
+	prop = RNA_def_pointer(func, "object", "Object", "", "Object");
+	prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+	prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
+	prop = RNA_def_int(func, "step", 0, INT_MIN, INT_MAX, "step no", "", INT_MIN, INT_MAX);
+
+	prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co",
+	                            "Exported hairkey location", -1e4, 1e4);
+	RNA_def_property_flag(prop, PROP_THICK_WRAP);
+	RNA_def_function_output(func, prop);
+
+	/* extract hair UVs */
+	func = RNA_def_function(srna, "uv_on_emitter", "rna_ParticleSystem_uv_on_emitter");
+	RNA_def_function_ui_description(func, "Obtain uv for all particles");
+	prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+	prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle");
+	prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
+	prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS);
+	RNA_def_property_array(prop, 2);
+	RNA_def_property_flag(prop, PROP_THICK_WRAP);
+	RNA_def_function_output(func, prop);
+
+	/* extract hair mcols */
+	func = RNA_def_function(srna, "mcol_on_emitter", "rna_ParticleSystem_mcol_on_emitter");
+	RNA_def_function_ui_description(func, "Obtain mcol for all particles");
+	prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
+	prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle");
+	prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX);
+	prop = RNA_def_int(func, "vcol_no", 0, INT_MIN, INT_MAX, "vcol no", "", INT_MIN, INT_MAX);
+	prop = RNA_def_property(func, "mcol", PROP_FLOAT, PROP_COLOR);
+	RNA_def_property_array(prop, 3);
+	RNA_def_property_flag(prop, PROP_THICK_WRAP);
+	RNA_def_function_output(func, prop);
+
 }
 
 void RNA_def_particle(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 28d1de2c601..23f61282b78 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -472,14 +472,14 @@ static void rna_pose_pgroup_name_set(PointerRNA *ptr, const char *value, char *r
 static PointerRNA rna_PoseChannel_active_constraint_get(PointerRNA *ptr)
 {
 	bPoseChannel *pchan = (bPoseChannel *)ptr->data;
-	bConstraint *con = constraints_get_active(&pchan->constraints);
+	bConstraint *con = BKE_constraints_get_active(&pchan->constraints);
 	return rna_pointer_inherit_refine(ptr, &RNA_Constraint, con);
 }
 
 static void rna_PoseChannel_active_constraint_set(PointerRNA *ptr, PointerRNA value)
 {
 	bPoseChannel *pchan = (bPoseChannel *)ptr->data;
-	constraints_set_active(&pchan->constraints, (bConstraint *)value.data);
+	BKE_constraints_set_active(&pchan->constraints, (bConstraint *)value.data);
 }
 
 static bConstraint *rna_PoseChannel_constraints_new(bPoseChannel *pchan, int type)
@@ -487,7 +487,7 @@ static bConstraint *rna_PoseChannel_constraints_new(bPoseChannel *pchan, int typ
 	/*WM_main_add_notifier(NC_OBJECT|ND_CONSTRAINT|NA_ADDED, object); */
 	/* TODO, pass object also */
 	/* TODO, new pose bones don't have updated draw flags */
-	return add_pose_constraint(NULL, pchan, NULL, type);
+	return BKE_add_pose_constraint(NULL, pchan, NULL, type);
 }
 
 static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, ReportList *reports, PointerRNA *con_ptr)
@@ -501,12 +501,12 @@ static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, Repo
 		return;
 	}
 
-	remove_constraint(&pchan->constraints, con);
+	BKE_remove_constraint(&pchan->constraints, con);
 	RNA_POINTER_INVALIDATE(con_ptr);
 
 	ED_object_constraint_update(ob);
 
-	constraints_set_active(&pchan->constraints, NULL);  /* XXX, is this really needed? - Campbell */
+	BKE_constraints_set_active(&pchan->constraints, NULL);  /* XXX, is this really needed? - Campbell */
 
 	WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, id);
 
@@ -786,14 +786,14 @@ static void rna_def_pose_channel(BlenderRNA *brna)
 	RNA_def_property_editable_array_func(prop, "rna_PoseChannel_location_editable");
 	RNA_def_property_ui_text(prop, "Location", "");
 	RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT);
-	RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+	RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_IK_update");
 
 	prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
 	RNA_def_property_float_sdna(prop, NULL, "size");
 	RNA_def_property_editable_array_func(prop, "rna_PoseChannel_scale_editable");
 	RNA_def_property_float_array_default(prop, default_scale);
 	RNA_def_property_ui_text(prop, "Scale", "");
-	RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_update");
+	RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_IK_update");
 
 	prop = RNA_def_property(srna, "rotation_quaternion", PROP_FLOAT, PROP_QUATERNION);
 	RNA_def_property_float_sdna(prop, NULL, "quat");
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 46b22cd0963..93c5b45e642 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -137,7 +137,7 @@ static void engine_update_script_node(RenderEngine *engine, struct bNodeTree *nt
 	FunctionRNA *func;
 
 	RNA_pointer_create(NULL, engine->type->ext.srna, engine, &ptr);
-	RNA_pointer_create((ID*)ntree, &RNA_Node, node, &nodeptr);
+	RNA_pointer_create((ID *)ntree, &RNA_Node, node, &nodeptr);
 	func = &rna_RenderEngine_update_script_node_func;
 
 	RNA_parameter_list_create(&list, &ptr, func);
@@ -406,6 +406,9 @@ static void rna_def_render_engine(BlenderRNA *brna)
 	RNA_def_property_int_sdna(prop, NULL, "resolution_y");
 	RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 
+	prop = RNA_def_property(srna, "use_highlight_tiles", PROP_BOOLEAN, PROP_NONE);
+	RNA_def_property_boolean_sdna(prop, NULL, "flag", RE_ENGINE_HIGHLIGHT_TILES);
+
 	/* registration */
 
 	prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 29d7391ccb4..8d99cecd9fa 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -119,7 +119,8 @@ EnumPropertyItem proportional_falloff_curve_only_items[] = {
 EnumPropertyItem proportional_editing_items[] = {
 	{PROP_EDIT_OFF, "DISABLED", ICON_PROP_OFF, "Disable", "Proportional Editing disabled"},
 	{PROP_EDIT_ON, "ENABLED", ICON_PROP_ON, "Enable", "Proportional Editing enabled"},
-	{PROP_EDIT_CONNECTED, "CONNECTED", ICON_PROP_CON, "Connected", "Proportional Editing using connected geometry only"},
+	{PROP_EDIT_CONNECTED, "CONNECTED", ICON_PROP_CON, "Connected",
+	                      "Proportional Editing using connected geometry only"},
 	{0, NULL, 0, NULL, NULL}
 };
 
@@ -880,7 +881,7 @@ static int rna_SceneRender_file_ext_length(PointerRNA *ptr)
 	RenderData *rd = (RenderData *)ptr->data;
 	char ext[8];
 	ext[0] = '\0';
-	BKE_add_image_extension(ext, rd->im_format.imtype);
+	BKE_add_image_extension(ext, &rd->im_format);
 	return strlen(ext);
 }
 
@@ -888,7 +889,7 @@ static void rna_SceneRender_file_ext_get(PointerRNA *ptr, char *str)
 {
 	RenderData *rd = (RenderData *)ptr->data;
 	str[0] = '\0';
-	BKE_add_image_extension(str, rd->im_format.imtype);
+	BKE_add_image_extension(str, &rd->im_format);
 }
 
 #ifdef WITH_QUICKTIME
@@ -1137,7 +1138,7 @@ static void rna_SceneRenderLayer_name_set(PointerRNA *ptr, const char *value)
 
 static char *rna_SceneRenderLayer_path(PointerRNA *ptr)
 {
-	SceneRenderLayer *srl = (SceneRenderLayer*)ptr->data;
+	SceneRenderLayer *srl = (SceneRenderLayer *)ptr->data;
 	return BLI_sprintfN("render.layers[\"%s\"]", srl->name);
 }
 
@@ -1368,7 +1369,8 @@ static void rna_TimeLine_remove(Scene *scene, ReportList *reports, PointerRNA *m
 {
 	TimeMarker *marker = marker_ptr->data;
 	if (BLI_remlink_safe(&scene->markers, marker) == FALSE) {
-		BKE_reportf(reports, RPT_ERROR, "Timeline marker '%s' not found in scene '%s'", marker->name, scene->id.name + 2);
+		BKE_reportf(reports, RPT_ERROR, "Timeline marker '%s' not found in scene '%s'",
+		            marker->name, scene->id.name + 2);
 		return;
 	}
 
@@ -2050,7 +2052,8 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
 
 	if (scene) {
 		prop = RNA_def_property(srna, "samples", PROP_INT, PROP_UNSIGNED);
-		RNA_def_property_ui_text(prop, "Samples", "Override number of render samples for this render layer, 0 will use the scene setting");
+		RNA_def_property_ui_text(prop, "Samples", "Override number of render samples for this render layer, "
+		                                          "0 will use the scene setting");
 		RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
 	}
 
@@ -2799,7 +2802,7 @@ static void rna_def_scene_game_recast_data(BlenderRNA *brna)
 	prop = RNA_def_property(srna, "slope_max", PROP_FLOAT, PROP_ANGLE);
 	RNA_def_property_float_sdna(prop, NULL, "agentmaxslope");
 	RNA_def_property_range(prop, 0, M_PI / 2);
-	RNA_def_property_ui_text(prop, "Max Slope", "Maximum walkable slope angle in degrees");
+	RNA_def_property_ui_text(prop, "Max Slope", "Maximum walkable slope angle");
 	RNA_def_property_update(prop, NC_SCENE, NULL);
 
 
@@ -2924,8 +2927,10 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
 		{RAS_STORE_AUTO, "AUTO", 0, "Auto Select", "Chooses the best supported mode"},
 		{RAS_STORE_IMMEDIATE, "IMMEDIATE", 0, "Immediate Mode", "Slowest performance, requires OpenGL (any version)"},
 		{RAS_STORE_VA, "VERTEX_ARRAY", 0, "Vertex Arrays", "Better performance, requires at least OpenGL 1.1"},
-		/* VBOS are currently disabled since they cannot beat vertex array with display lists in performance. */
-		/* {RAS_STORE_VBO, "VERTEX_BUFFER_OBJECT", 0, "Vertex Buffer Objects", "Best performance, requires at least OpenGL 1.4"}, */
+#if 0  /* XXX VBOS are currently disabled since they cannot beat vertex array with display lists in performance. */
+		{RAS_STORE_VBO, "VERTEX_BUFFER_OBJECT", 0, "Vertex Buffer Objects",
+		                "Best performance, requires at least OpenGL 1.4"}, 
+#endif
 		{0, NULL, 0, NULL, NULL}};
 
 	srna = RNA_def_struct(brna, "SceneGameData", NULL);
@@ -2960,13 +2965,13 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
 	RNA_def_property_enum_sdna(prop, NULL, "exitkey");
 	RNA_def_property_enum_items(prop, event_type_items);
 	RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_exit_key_set", NULL);
-	RNA_def_property_ui_text(prop, "Exit Key",  "The key that exits the Game Engine");
+	RNA_def_property_ui_text(prop, "Exit Key", "The key that exits the Game Engine");
 	RNA_def_property_update(prop, NC_SCENE, NULL);
 	
 	prop = RNA_def_property(srna, "raster_storage", PROP_ENUM, PROP_NONE);
 	RNA_def_property_enum_sdna(prop, NULL, "raster_storage");
 	RNA_def_property_enum_items(prop, storage_items);
-	RNA_def_property_ui_text(prop, "Storage",  "Sets the storage mode used by the rasterizer");
+	RNA_def_property_ui_text(prop, "Storage", "Set the storage mode used by the rasterizer");
 	RNA_def_property_update(prop, NC_SCENE, NULL);
 	
 	/* Do we need it here ? (since we already have it in World */
@@ -3252,6 +3257,12 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
 	                         "Use extra textures like normal or specular maps for GLSL rendering");
 	RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update");
 
+	prop = RNA_def_property(srna, "use_material_caching", PROP_BOOLEAN, PROP_NONE);
+	RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_NO_MATERIAL_CACHING);
+	RNA_def_property_ui_text(prop, "Use Material Caching",
+	                         "Cache materials in the converter (this is faster, but can cause problems with older "
+	                         "Singletexture and Multitexture games");
+
 	/* obstacle simulation */
 	prop = RNA_def_property(srna, "obstacle_simulation", PROP_ENUM, PROP_NONE);
 	RNA_def_property_enum_sdna(prop, NULL, "obstacleSimulation");
@@ -3370,6 +3381,14 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
 	};
 #endif
 
+#ifdef WITH_OPENJPEG
+	static EnumPropertyItem jp2_codec_items[] = {
+		{R_IMF_JP2_CODEC_JP2, "JP2", 0, "JP2", ""},
+		{R_IMF_JP2_CODEC_J2K, "J2K", 0, "J2K", ""},
+		{0, NULL, 0, NULL, NULL}
+	};
+#endif
+
 	StructRNA *srna;
 	PropertyRNA *prop;
 
@@ -3457,6 +3476,12 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
 	RNA_def_property_boolean_sdna(prop, NULL, "jp2_flag", R_IMF_JP2_FLAG_CINE_48);
 	RNA_def_property_ui_text(prop, "Cinema (48)", "Use Openjpeg Cinema Preset (48fps)");
 	RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+	prop = RNA_def_property(srna, "jpeg2k_codec", PROP_ENUM, PROP_NONE);
+	RNA_def_property_enum_sdna(prop, NULL, "jp2_codec");
+	RNA_def_property_enum_items(prop, jp2_codec_items);
+	RNA_def_property_ui_text(prop, "Codec", "Codec settings for Jpek2000");
+	RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
 #endif
 
 	/* Cineon and DPX */
@@ -3796,8 +3821,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
 		
 	static EnumPropertyItem alpha_mode_items[] = {
 		{R_ADDSKY, "SKY", 0, "Sky", "Transparent pixels are filled with sky color"},
-		{R_ALPHAPREMUL, "PREMUL", 0, "Premultiplied", "Transparent RGB pixels are multiplied by the alpha channel"},
-		{R_ALPHAKEY, "STRAIGHT", 0, "Straight Alpha", "Transparent RGB and alpha pixels are unmodified"},
+		{R_ALPHAPREMUL, "TRANSPARENT", 0, "Transparent", "World background is transparent with premultiplied alpha"},
 		{0, NULL, 0, NULL, NULL}
 	};
 
@@ -4174,10 +4198,9 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 	RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
 	
-	prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_NONE);
+	prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_UNSIGNED);
 	RNA_def_property_float_sdna(prop, NULL, "blurfac");
-	RNA_def_property_range(prop, 0.01f, 10.0f);
-	RNA_def_property_ui_range(prop, 0.01, 2.0f, 1, 0);
+	RNA_def_property_ui_range(prop, 0.01f, 2.0f, 1, 0);
 	RNA_def_property_ui_text(prop, "Shutter", "Time taken in frames between shutter open and close");
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 	RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
@@ -4248,13 +4271,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
 	                         "editor pipeline, if sequencer strips exist");
 	RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
 	
-	prop = RNA_def_property(srna, "use_color_unpremultiply", PROP_BOOLEAN, PROP_NONE);
-	RNA_def_property_boolean_sdna(prop, NULL, "color_mgt_flag", R_COLOR_MANAGEMENT_PREDIVIDE);
-	RNA_def_property_ui_text(prop, "Color Unpremultiply",
-	                         "For premultiplied alpha render output, do color space conversion on "
-	                         "colors without alpha, to avoid fringing on light backgrounds");
-	RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-	
 	prop = RNA_def_property(srna, "use_file_extension", PROP_BOOLEAN, PROP_NONE);
 	RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_EXTENSION);
 	RNA_def_property_ui_text(prop, "File Extensions",
@@ -4407,6 +4423,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
 	RNA_def_property_ui_text(prop, "Samples", "Number of samples used for ambient occlusion baking from multires");
 	RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
 
+	prop = RNA_def_property(srna, "use_bake_to_vertex_color", PROP_BOOLEAN, PROP_NONE);
+	RNA_def_property_boolean_sdna(prop, NULL, "bake_flag", R_BAKE_VCOL);
+	RNA_def_property_ui_text(prop, "Bake to Vertex Color",
+	                         "Bake to vertex colors instead of to a UV-mapped image");
+	RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
 	/* stamp */
 	
 	prop = RNA_def_property(srna, "use_stamp_time", PROP_BOOLEAN, PROP_NONE);
@@ -5169,7 +5191,7 @@ void RNA_def_scene(BlenderRNA *brna)
 
 	prop = RNA_def_property(srna, "sequencer_colorspace_settings", PROP_POINTER, PROP_NONE);
 	RNA_def_property_pointer_sdna(prop, NULL, "sequencer_colorspace_settings");
-	RNA_def_property_struct_type(prop, "ColorManagedColorspaceSettings");
+	RNA_def_property_struct_type(prop, "ColorManagedSequencerColorspaceSettings");
 	RNA_def_property_ui_text(prop, "Sequencer Color Space Settings", "Settings of color space sequencer is working in");
 
 	/* Nestled Data  */
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 012767b5845..9b5a858a581 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -84,7 +84,7 @@ static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, char *name
 	if (BKE_imtype_is_movie(rd->im_format.imtype))
 		BKE_movie_filepath_get(name, rd);
 	else
-		BKE_makepicstring(name, rd->pic, G.main->name, (frame == INT_MIN) ? rd->cfra : frame, rd->im_format.imtype,
+		BKE_makepicstring(name, rd->pic, G.main->name, (frame == INT_MIN) ? rd->cfra : frame, &rd->im_format,
 		                  rd->scemode & R_EXTENSION, TRUE);
 }
 
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index f717c83075a..17edf2944aa 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -40,6 +40,9 @@
 #include "WM_api.h"
 #include "WM_types.h"
 
+#include "BLI_utildefines.h"
+#include "bmesh.h"
+
 static EnumPropertyItem particle_edit_hair_brush_items[] = {
 	{PE_BRUSH_NONE, "NONE", 0, "None", "Don't use any brush"},
 	{PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs"},
@@ -52,6 +55,18 @@ static EnumPropertyItem particle_edit_hair_brush_items[] = {
 	{0, NULL, 0, NULL, NULL}
 };
 
+EnumPropertyItem symmetrize_direction_items[] = {
+	{BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""},
+	{BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""},
+
+	{BMO_SYMMETRIZE_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y to +Y", ""},
+	{BMO_SYMMETRIZE_POSITIVE_Y, "POSITIVE_Y", 0, "+Y to -Y", ""},
+
+	{BMO_SYMMETRIZE_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z to +Z", ""},
+	{BMO_SYMMETRIZE_POSITIVE_Z, "POSITIVE_Z", 0, "+Z to -Z", ""},
+	{0, NULL, 0, NULL, NULL},
+};
+
 #ifdef RNA_RUNTIME
 #include "MEM_guardedalloc.h"
 
@@ -204,6 +219,11 @@ static void rna_Sculpt_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNU
 	if (ob) {
 		DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 		WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
+
+		if (ob->sculpt) {
+			ob->sculpt->bm_smooth_shading = (scene->toolsettings->sculpt->flags &
+											 SCULPT_DYNTOPO_SMOOTH_SHADING);
+		}
 	}
 }
 
@@ -319,6 +339,27 @@ static void rna_def_sculpt(BlenderRNA  *brna)
 	RNA_def_property_ui_text(prop, "Show Diffuse Color",
 	                         "Show diffuse color of object and overlay sculpt mask on top of it");
 	RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_ShowDiffuseColor_update");
+
+	prop = RNA_def_property(srna, "detail_size", PROP_INT, PROP_DISTANCE);
+	RNA_def_property_ui_range(prop, 2, 100, 0, 0);
+	RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (in pixels)");
+
+	prop = RNA_def_property(srna, "use_smooth_shading", PROP_BOOLEAN, PROP_NONE);
+	RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_DYNTOPO_SMOOTH_SHADING);
+	RNA_def_property_ui_text(prop, "Smooth Shading",
+	                         "Show faces in dynamic-topology mode with smooth "
+	                         "shading rather than flat shaded");
+	RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update");
+
+	prop = RNA_def_property(srna, "use_edge_collapse", PROP_BOOLEAN, PROP_NONE);
+	RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_DYNTOPO_COLLAPSE);
+	RNA_def_property_ui_text(prop, "Collapse Short Edges",
+	                         "In dynamic-topology mode, collapse short edges "
+	                         "in addition to subdividing long ones");
+
+	prop = RNA_def_property(srna, "symmetrize_direction", PROP_ENUM, PROP_NONE);
+	RNA_def_property_enum_items(prop, symmetrize_direction_items);
+	RNA_def_property_ui_text(prop, "Direction", "Source and destination for symmetrize operator");
 }
 
 
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 18a9b9683f8..a41551fc8da 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -1401,26 +1401,26 @@ static void rna_def_sequence(BlenderRNA *brna)
 
 	prop = RNA_def_property(srna, "frame_offset_start", PROP_INT, PROP_TIME);
 	RNA_def_property_int_sdna(prop, NULL, "startofs");
-	RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
+//	RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
 	RNA_def_property_ui_text(prop, "Start Offset", "");
 	RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
 	
 	prop = RNA_def_property(srna, "frame_offset_end", PROP_INT, PROP_TIME);
 	RNA_def_property_int_sdna(prop, NULL, "endofs");
-	RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
+//	RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
 	RNA_def_property_ui_text(prop, "End Offset", "");
 	RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
 	
 	prop = RNA_def_property(srna, "frame_still_start", PROP_INT, PROP_TIME);
 	RNA_def_property_int_sdna(prop, NULL, "startstill");
-	RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
+//	RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
 	RNA_def_property_range(prop, 0, MAXFRAME);
 	RNA_def_property_ui_text(prop, "Start Still", "");
 	RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
 	
 	prop = RNA_def_property(srna, "frame_still_end", PROP_INT, PROP_TIME);
 	RNA_def_property_int_sdna(prop, NULL, "endstill");
-	RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
+//	RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
 	RNA_def_property_range(prop, 0, MAXFRAME);
 	RNA_def_property_ui_text(prop, "End Still", "");
 	RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
@@ -1541,14 +1541,20 @@ static void rna_def_filter_video(StructRNA *srna)
 {
 	PropertyRNA *prop;
 
+	static const EnumPropertyItem alpha_mode_items[] = {
+		{SEQ_ALPHA_STRAIGHT, "STRAIGHT", 0, "Straight", "RGB channels in transparent pixels are unaffected by the alpha channel"},
+		{SEQ_ALPHA_PREMUL, "PREMUL", 0, "Premultiplied", "RGB channels in transparent pixels are multiplied by the alpha channel"},
+		{0, NULL, 0, NULL, NULL}
+	};
+
 	prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE);
 	RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_FILTERY);
 	RNA_def_property_ui_text(prop, "De-Interlace", "For video movies to remove fields");
 	RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update_reopen_files");
 
-	prop = RNA_def_property(srna, "use_premultiply", PROP_BOOLEAN, PROP_NONE);
-	RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_MAKE_PREMUL);
-	RNA_def_property_ui_text(prop, "Premultiply", "Convert RGB from key alpha to premultiplied alpha");
+	prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE);
+	RNA_def_property_enum_items(prop, alpha_mode_items);
+	RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels");
 	RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
 
 	prop = RNA_def_property(srna, "use_flip_x", PROP_BOOLEAN, PROP_NONE);
@@ -1694,7 +1700,7 @@ static void rna_def_color_management(StructRNA *srna)
 
 	prop = RNA_def_property(srna, "colorspace_settings", PROP_POINTER, PROP_NONE);
 	RNA_def_property_pointer_sdna(prop, NULL, "strip->colorspace_settings");
-	RNA_def_property_struct_type(prop, "ColorManagedColorspaceSettings");
+	RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings");
 	RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
 }
 
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 7602ec99c2b..69d35a3c2f0 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -37,6 +37,8 @@
 #include "DNA_scene_types.h"
 #include "DNA_sequence_types.h"
 
+#include "BLI_utildefines.h"
+
 #ifdef RNA_RUNTIME
 
 //#include "DNA_anim_types.h"
@@ -62,6 +64,16 @@
 
 #include "WM_api.h"
 
+static void rna_Sequence_update_rnafunc(ID *id, Sequence *self, int do_data)
+{
+	if (do_data) {
+		BKE_sequencer_update_changed_seq_and_deps((Scene *)id, self, true, true);
+		// new_tstripdata(self); // need 2.6x version of this.
+	}
+	BKE_sequence_calc((Scene *)id, self);
+	BKE_sequence_calc_disp((Scene *)id, self);
+}
+
 static void rna_Sequence_swap_internal(Sequence *seq_self, ReportList *reports, Sequence *seq_other)
 {
 	const char *error_msg;
@@ -389,7 +401,13 @@ void RNA_api_sequence_strip(StructRNA *srna)
 	FunctionRNA *func;
 	PropertyRNA *parm;
 
-	func = RNA_def_function(srna, "getStripElem", "BKE_sequencer_give_stripelem");
+	func = RNA_def_function(srna, "update", "rna_Sequence_update_rnafunc");
+	RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+	RNA_def_function_ui_description(func, "Update the strip dimensions");
+	parm = RNA_def_boolean(func, "data", false, "Frame",
+	                       "Update strip data");
+
+	func = RNA_def_function(srna, "strip_elem_from_frame", "BKE_sequencer_give_stripelem");
 	RNA_def_function_ui_description(func, "Return the strip element from a given frame or None");
 	parm = RNA_def_int(func, "frame", 0, -MAXFRAME, MAXFRAME, "Frame",
 	                   "The frame to get the strip element from", -MAXFRAME, MAXFRAME);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 09209ddea4d..7fa3aae8ede 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -2375,11 +2375,11 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
 	
 	/* XXX: action-editor is currently for object-level only actions, so show that using object-icon hint */
 	static EnumPropertyItem mode_items[] = {
-		{SACTCONT_DOPESHEET, "DOPESHEET", ICON_OOPS, "DopeSheet", "DopeSheet Editor"},
-		{SACTCONT_ACTION, "ACTION", ICON_OBJECT_DATA, "Action Editor", "Action Editor"},
-		{SACTCONT_SHAPEKEY, "SHAPEKEY", ICON_SHAPEKEY_DATA, "ShapeKey Editor", "ShapeKey Editor"},
-		{SACTCONT_GPENCIL, "GPENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Grease Pencil"},
-		{SACTCONT_MASK, "MASK", ICON_MOD_MASK, "Mask", "Mask Editor"},
+		{SACTCONT_DOPESHEET, "DOPESHEET", ICON_OOPS, "DopeSheet", "Edit all keyframes in scene"},
+		{SACTCONT_ACTION, "ACTION", ICON_OBJECT_DATA, "Action Editor", "Edit keyframes in active object's Object-level action"},
+		{SACTCONT_SHAPEKEY, "SHAPEKEY", ICON_SHAPEKEY_DATA, "ShapeKey Editor", "Edit keyframes in active object's Shape Keys action"},
+		{SACTCONT_GPENCIL, "GPENCIL", ICON_GREASEPENCIL, "Grease Pencil", "Edit timings for all Grease Pencil sketches in file"},
+		{SACTCONT_MASK, "MASK", ICON_MOD_MASK, "Mask", "Edit timings for Mask Editor splines"},
 		{0, NULL, 0, NULL, NULL}
 	};
 		
@@ -2723,6 +2723,7 @@ static void rna_def_console_line(BlenderRNA *brna)
 	                              "rna_ConsoleLine_body_set");
 	RNA_def_property_ui_text(prop, "Line", "Text in the line");
 	RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CONSOLE, NULL);
+	RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_TEXT);
 	
 	prop = RNA_def_property(srna, "current_character", PROP_INT, PROP_NONE); /* copied from text editor */
 	RNA_def_property_int_sdna(prop, NULL, "cursor");
diff --git a/source/blender/makesrna/intern/rna_speaker.c b/source/blender/makesrna/intern/rna_speaker.c
index 139582104ee..8a75aa2d227 100644
--- a/source/blender/makesrna/intern/rna_speaker.c
+++ b/source/blender/makesrna/intern/rna_speaker.c
@@ -62,6 +62,7 @@ static void rna_def_speaker(BlenderRNA *brna)
 	RNA_def_property_boolean_sdna(prop, NULL, "flag", SPK_MUTED);
 	RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 	RNA_def_property_ui_text(prop, "Mute", "Mute the speaker");
+	RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_SOUND);
 	/* RNA_def_property_update(prop, 0, "rna_Speaker_update"); */
 
 #if 0 /* This shouldn't be changed actually, hiding it! */
diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c
index b1637ef4c8a..df6181af4b2 100644
--- a/source/blender/makesrna/intern/rna_text.c
+++ b/source/blender/makesrna/intern/rna_text.c
@@ -30,6 +30,8 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "BLF_translation.h"
+
 #include "BKE_text.h"
 
 #include "RNA_define.h"
@@ -127,6 +129,7 @@ static void rna_def_text_line(BlenderRNA *brna)
 	RNA_def_property_string_funcs(prop, "rna_TextLine_body_get", "rna_TextLine_body_length", "rna_TextLine_body_set");
 	RNA_def_property_ui_text(prop, "Line", "Text in the line");
 	RNA_def_property_update(prop, NC_TEXT | NA_EDITED, NULL);
+	RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_TEXT);
 }
 
 static void rna_def_text(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index e116e5df0de..2ab448c9188 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -1194,11 +1194,6 @@ static void rna_def_texture_image(BlenderRNA *brna)
 	RNA_def_property_ui_text(prop, "Flip Axis", "Flip the texture's X and Y axis");
 	RNA_def_property_update(prop, 0, "rna_Texture_update");
 
-	prop = RNA_def_property(srna, "use_alpha", PROP_BOOLEAN, PROP_NONE);
-	RNA_def_property_boolean_sdna(prop, NULL, "imaflag", TEX_USEALPHA);
-	RNA_def_property_ui_text(prop, "Use Alpha", "Use the alpha channel information in the image");
-	RNA_def_property_update(prop, 0, "rna_Texture_update");
-
 	prop = RNA_def_property(srna, "use_calculate_alpha", PROP_BOOLEAN, PROP_NONE);
 	RNA_def_property_boolean_sdna(prop, NULL, "imaflag", TEX_CALCALPHA);
 	RNA_def_property_ui_text(prop, "Calculate Alpha", "Calculate an alpha channel based on RGB values in the image");
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index f5bcab3e530..7cc57947671 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -280,7 +280,7 @@ static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerR
 
 static void rna_trackingObject_tracks_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
 {
-	MovieTrackingObject *object = (MovieTrackingObject * )ptr->data;
+	MovieTrackingObject *object = (MovieTrackingObject *)ptr->data;
 
 	if (object->flag & TRACKING_OBJECT_CAMERA) {
 		MovieClip *clip = (MovieClip *)ptr->id.data;
@@ -294,7 +294,7 @@ static void rna_trackingObject_tracks_begin(CollectionPropertyIterator *iter, Po
 
 static PointerRNA rna_trackingObject_reconstruction_get(PointerRNA *ptr)
 {
-	MovieTrackingObject *object = (MovieTrackingObject * )ptr->data;
+	MovieTrackingObject *object = (MovieTrackingObject *)ptr->data;
 
 	if (object->flag & TRACKING_OBJECT_CAMERA) {
 		MovieClip *clip = (MovieClip *)ptr->id.data;
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index de359fd6413..14789a437b7 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -55,6 +55,16 @@ EnumPropertyItem operator_context_items[] = {
 	{0, NULL, 0, NULL, NULL}
 };
 
+EnumPropertyItem uilist_layout_type_items[] = {
+	{UILST_LAYOUT_DEFAULT, "DEFAULT", 0, "Default Layout",
+	                       "Use the default, multi-rows layout"},
+	{UILST_LAYOUT_COMPACT, "COMPACT", 0, "Compact Layout",
+	                       "Use the compact, single-row layout"},
+	{UILST_LAYOUT_GRID, "GRID", 0, "Grid Layout",
+	                    "Use the grid-based layout"},
+	{0, NULL, 0, NULL, NULL}
+};
+
 #ifdef RNA_RUNTIME
 
 #include 
@@ -252,6 +262,105 @@ static StructRNA *rna_Panel_refine(PointerRNA *ptr)
 	return (hdr->type && hdr->type->ext.srna) ? hdr->type->ext.srna : &RNA_Panel;
 }
 
+/* UIList */
+static void uilist_draw_item(uiList *ui_list, bContext *C, uiLayout *layout, PointerRNA *dataptr, PointerRNA *itemptr,
+                             int icon, PointerRNA *active_dataptr, const char *active_propname, int index)
+{
+	extern FunctionRNA rna_UIList_draw_item_func;
+
+	PointerRNA ul_ptr;
+	ParameterList list;
+	FunctionRNA *func;
+
+	RNA_pointer_create(&CTX_wm_screen(C)->id, ui_list->type->ext.srna, ui_list, &ul_ptr);
+	func = &rna_UIList_draw_item_func; /* RNA_struct_find_function(&ul_ptr, "draw_item"); */
+
+	RNA_parameter_list_create(&list, &ul_ptr, func);
+	RNA_parameter_set_lookup(&list, "context", &C);
+	RNA_parameter_set_lookup(&list, "layout", &layout);
+	RNA_parameter_set_lookup(&list, "data", dataptr);
+	RNA_parameter_set_lookup(&list, "item", itemptr);
+	RNA_parameter_set_lookup(&list, "icon", &icon);
+	RNA_parameter_set_lookup(&list, "active_data", active_dataptr);
+	RNA_parameter_set_lookup(&list, "active_property", &active_propname);
+	RNA_parameter_set_lookup(&list, "index", &index);
+	ui_list->type->ext.call((bContext *)C, &ul_ptr, func, &list);
+
+	RNA_parameter_list_free(&list);
+}
+
+static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type)
+{
+	uiListType *ult = RNA_struct_blender_type_get(type);
+
+	if (!ult)
+		return;
+
+	RNA_struct_free_extension(type, &ult->ext);
+
+	WM_uilisttype_freelink(ult);
+
+	RNA_struct_free(&BLENDER_RNA, type);
+
+	/* update while blender is running */
+	WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+}
+
+static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
+                                      StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+{
+	uiListType *ult, dummyult = {NULL};
+	uiList dummyuilist = {NULL};
+	PointerRNA dummyul_ptr;
+	int have_function[1];
+	size_t over_alloc = 0; /* warning, if this becomes a bess, we better do another alloc */
+
+	/* setup dummy menu & menu type to store static properties in */
+	dummyuilist.type = &dummyult;
+	RNA_pointer_create(NULL, &RNA_UIList, &dummyuilist, &dummyul_ptr);
+
+	/* validate the python class */
+	if (validate(&dummyul_ptr, data, have_function) != 0)
+		return NULL;
+
+	if (strlen(identifier) >= sizeof(dummyult.idname)) {
+		BKE_reportf(reports, RPT_ERROR, "Registering uilist class: '%s' is too long, maximum length is %d",
+		            identifier, (int)sizeof(dummyult.idname));
+		return NULL;
+	}
+
+	/* check if we have registered this uilist type before, and remove it */
+	ult = WM_uilisttype_find(dummyult.idname, TRUE);
+	if (ult && ult->ext.srna)
+		rna_UIList_unregister(bmain, ult->ext.srna);
+
+	/* create a new menu type */
+	ult = MEM_callocN(sizeof(uiListType) + over_alloc, "python uilist");
+	memcpy(ult, &dummyult, sizeof(dummyult));
+
+	ult->ext.srna = RNA_def_struct(&BLENDER_RNA, ult->idname, "UIList");
+	ult->ext.data = data;
+	ult->ext.call = call;
+	ult->ext.free = free;
+	RNA_struct_blender_type_set(ult->ext.srna, ult);
+	RNA_def_struct_flag(ult->ext.srna, STRUCT_NO_IDPROPERTIES);
+
+	ult->draw_item = (have_function[0]) ? uilist_draw_item : NULL;
+
+	WM_uilisttype_add(ult);
+
+	/* update while blender is running */
+	WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+	return ult->ext.srna;
+}
+
+static StructRNA *rna_UIList_refine(PointerRNA *ptr)
+{
+	uiList *ui_list = (uiList *)ptr->data;
+	return (ui_list->type && ui_list->type->ext.srna) ? ui_list->type->ext.srna : &RNA_UIList;
+}
+
 /* Header */
 
 static void header_draw(const bContext *C, Header *hdr)
@@ -495,6 +604,8 @@ static void rna_Menu_bl_description_set(PointerRNA *ptr, const char *value)
 	else assert(!"setting the bl_description on a non-builtin menu");
 }
 
+/* UILayout */
+
 static int rna_UILayout_active_get(PointerRNA *ptr)
 {
 	return uiLayoutGetActive(ptr->data);
@@ -738,6 +849,58 @@ static void rna_def_panel(BlenderRNA *brna)
 	RNA_def_property_ui_text(prop, "Options",  "Options for this panel type");
 }
 
+static void rna_def_uilist(BlenderRNA *brna)
+{
+	StructRNA *srna;
+	PropertyRNA *prop;
+	PropertyRNA *parm;
+	FunctionRNA *func;
+
+	srna = RNA_def_struct(brna, "UIList", NULL);
+	RNA_def_struct_ui_text(srna, "UIList", "UI list containing the elements of a collection");
+	RNA_def_struct_sdna(srna, "uiList");
+	RNA_def_struct_refine_func(srna, "rna_UIList_refine");
+	RNA_def_struct_register_funcs(srna, "rna_UIList_register", "rna_UIList_unregister", NULL);
+
+	/* draw */
+	func = RNA_def_function(srna, "draw_item", NULL);
+	RNA_def_function_ui_description(func, "Draw an item in the list (NOTE: when you define your own draw_item "
+	                                      "function, you may want to check given 'item' is of the right type...)");
+	RNA_def_function_flag(func, FUNC_REGISTER);
+	parm = RNA_def_pointer(func, "context", "Context", "", "");
+	RNA_def_property_flag(parm, PROP_REQUIRED);
+	parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item");
+	RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+	parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take Collection property");
+	RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+	parm = RNA_def_pointer(func, "item", "AnyType", "", "Item of the collection property");
+	RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+	parm = RNA_def_int(func, "icon", 0, 0, INT_MAX, "", "Icon of the item in the collection", 0, INT_MAX);
+	RNA_def_property_flag(parm, PROP_REQUIRED);
+	parm = RNA_def_pointer(func, "active_data", "AnyType", "",
+	                       "Data from which to take property for the active element");
+	RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+	parm = RNA_def_string(func, "active_property", "", 0, "",
+	                      "Identifier of property in active_data, for the active element");
+	RNA_def_property_flag(parm, PROP_REQUIRED);
+	RNA_def_int(func, "index", 0, 0, INT_MAX, "", "Index of the item in the collection", 0, INT_MAX);
+	RNA_def_property_flag(parm, PROP_REQUIRED);
+
+	prop = RNA_def_property(srna, "layout_type", PROP_ENUM, PROP_NONE);
+	RNA_def_property_enum_items(prop, uilist_layout_type_items);
+	RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+	/* registration */
+	prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
+	RNA_def_property_string_sdna(prop, NULL, "type->idname");
+	RNA_def_property_flag(prop, PROP_REGISTER | PROP_NEVER_CLAMP);
+	RNA_def_property_ui_text(prop, "ID Name",
+	                         "If this is set, the uilist gets a custom ID, otherwise it takes the "
+	                         "name of the class used to define the uilist (for example, if the "
+	                         "class name is \"OBJECT_UL_vgroups\", and bl_idname is not set by the "
+	                         "script, then bl_idname = \"OBJECT_UL_vgroups\")");
+}
+
 static void rna_def_header(BlenderRNA *brna)
 {
 	StructRNA *srna;
@@ -852,6 +1015,7 @@ void RNA_def_ui(BlenderRNA *brna)
 {
 	rna_def_ui_layout(brna);
 	rna_def_panel(brna);
+	rna_def_uilist(brna);
 	rna_def_header(brna);
 	rna_def_menu(brna);
 }
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 548539e3395..366d0dc1fd9 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -33,8 +33,12 @@
 #include 
 
 #include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "DNA_screen_types.h"
 
 #include "UI_resources.h"
+#include "UI_interface_icons.h"
 
 #include "rna_internal.h"
 
@@ -70,12 +74,117 @@ static PointerRNA rna_uiItemO(uiLayout *layout, const char *opname, const char *
 	return uiItemFullO(layout, opname, name, icon, NULL, uiLayoutGetOperatorContext(layout), flag);
 }
 
+static void rna_uiItemL(uiLayout *layout, const char *name, int icon, int icon_value)
+{
+	if (icon_value && !icon) {
+		icon = icon_value;
+	}
+
+	uiItemL(layout, name, icon);
+}
+
+static int rna_ui_get_rnaptr_icon(bContext *C, PointerRNA *ptr_icon)
+{
+	return UI_rnaptr_icon_get(C, ptr_icon, RNA_struct_ui_icon(ptr_icon->type), FALSE);
+}
+
+static const char *rna_ui_get_enum_name(bContext *C, PointerRNA *ptr, const char *propname, const char *identifier)
+{
+	PropertyRNA *prop = NULL;
+	EnumPropertyItem *items = NULL, *item;
+	int free;
+	const char *name = "";
+
+	prop = RNA_struct_find_property(ptr, propname);
+	if (!prop || (RNA_property_type(prop) != PROP_ENUM)) {
+		RNA_warning("Property not found or not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
+		return name;
+	}
+
+	RNA_property_enum_items_gettexted(C, ptr, prop, &items, NULL, &free);
+
+	if (items) {
+		for (item = items; item->identifier; item++) {
+			if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) {
+				name = item->name;
+				break;
+			}
+		}
+		if (free) {
+			MEM_freeN(items);
+		}
+	}
+
+	return name;
+}
+
+static const char *rna_ui_get_enum_description(bContext *C, PointerRNA *ptr, const char *propname,
+                                               const char *identifier)
+{
+	PropertyRNA *prop = NULL;
+	EnumPropertyItem *items = NULL, *item;
+	int free;
+	const char *desc = "";
+
+	prop = RNA_struct_find_property(ptr, propname);
+	if (!prop || (RNA_property_type(prop) != PROP_ENUM)) {
+		RNA_warning("Property not found or not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
+		return desc;
+	}
+
+	RNA_property_enum_items_gettexted(C, ptr, prop, &items, NULL, &free);
+
+	if (items) {
+		for (item = items; item->identifier; item++) {
+			if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) {
+				desc = item->description;
+				break;
+			}
+		}
+		if (free) {
+			MEM_freeN(items);
+		}
+	}
+
+	return desc;
+}
+
+static int rna_ui_get_enum_icon(bContext *C, PointerRNA *ptr, const char *propname, const char *identifier)
+{
+	PropertyRNA *prop = NULL;
+	EnumPropertyItem *items = NULL, *item;
+	int free;
+	int icon = ICON_NONE;
+
+	prop = RNA_struct_find_property(ptr, propname);
+	if (!prop || (RNA_property_type(prop) != PROP_ENUM)) {
+		RNA_warning("Property not found or not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
+		return icon;
+	}
+
+	RNA_property_enum_items(C, ptr, prop, &items, NULL, &free);
+
+	if (items) {
+		for (item = items; item->identifier; item++) {
+			if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) {
+				icon = item->icon;
+				break;
+			}
+		}
+		if (free) {
+			MEM_freeN(items);
+		}
+	}
+
+	return icon;
+}
+
 #else
 
 #define DEF_ICON_BLANK_SKIP
 #define DEF_ICON(name) {ICON_##name, (#name), 0, (#name), ""},
 #define DEF_VICO(name) {VICO_##name, (#name), 0, (#name), ""},
-static EnumPropertyItem icon_items[] = {
+EnumPropertyItem icon_items[] = {
 #include "UI_icons.h"
 	{0, NULL, 0, NULL, NULL}
 };
@@ -92,7 +201,6 @@ static void api_ui_item_common(FunctionRNA *func)
 	prop = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
 	RNA_def_property_enum_items(prop, icon_items);
 	RNA_def_property_ui_text(prop, "Icon", "Override automatic icon of the item");
-
 }
 
 static void api_ui_item_op(FunctionRNA *func)
@@ -130,13 +238,6 @@ void RNA_api_ui_layout(StructRNA *srna)
 		{'h', "HUE", 0, "Hue", ""},
 		{0, NULL, 0, NULL, NULL}
 	};
-	
-	static EnumPropertyItem list_type_items[] = {
-		{0, "DEFAULT", 0, "None", ""},
-		{'c', "COMPACT", 0, "Compact", ""},
-		{'i', "ICONS", 0, "Icons", ""},
-		{0, NULL, 0, NULL, NULL}
-	};
 
 	/* simple layout specifiers */
 	func = RNA_def_function(srna, "row", "uiLayoutRow");
@@ -175,6 +276,44 @@ void RNA_api_ui_layout(StructRNA *srna)
 	RNA_def_float(func, "percentage", 0.0f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at", 0.0f, 1.0f);
 	RNA_def_boolean(func, "align", 0, "", "Align buttons to each other");
 
+	/* Icon of a rna pointer */
+	func = RNA_def_function(srna, "icon", "rna_ui_get_rnaptr_icon");
+	parm = RNA_def_int(func, "icon_value", ICON_NONE, 0, INT_MAX, "", "Icon identifier", 0, INT_MAX);
+	RNA_def_function_return(func, parm);
+	RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+	parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take the icon");
+	RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+	RNA_def_function_ui_description(func, "Return the custom icon for this data, "
+	                                      "use it e.g. to get materials or texture icons");
+
+	/* UI name, description and icon of an enum item */
+	func = RNA_def_function(srna, "enum_item_name", "rna_ui_get_enum_name");
+	parm = RNA_def_string(func, "name", "", 0, "", "UI name of the enum item");
+	RNA_def_function_return(func, parm);
+	RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+	api_ui_item_rna_common(func);
+	parm = RNA_def_string(func, "identifier", "", 0, "", "Identifier of the enum item");
+	RNA_def_property_flag(parm, PROP_REQUIRED);
+	RNA_def_function_ui_description(func, "Return the UI name for this enum item");
+
+	func = RNA_def_function(srna, "enum_item_description", "rna_ui_get_enum_description");
+	parm = RNA_def_string(func, "description", "", 0, "", "UI description of the enum item");
+	RNA_def_function_return(func, parm);
+	RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+	api_ui_item_rna_common(func);
+	parm = RNA_def_string(func, "identifier", "", 0, "", "Identifier of the enum item");
+	RNA_def_property_flag(parm, PROP_REQUIRED);
+	RNA_def_function_ui_description(func, "Return the UI description for this enum item");
+
+	func = RNA_def_function(srna, "enum_item_icon", "rna_ui_get_enum_icon");
+	parm = RNA_def_int(func, "icon_value", ICON_NONE, 0, INT_MAX, "", "Icon identifier", 0, INT_MAX);
+	RNA_def_function_return(func, parm);
+	RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+	api_ui_item_rna_common(func);
+	parm = RNA_def_string(func, "identifier", "", 0, "", "Identifier of the enum item");
+	RNA_def_property_flag(parm, PROP_REQUIRED);
+	RNA_def_function_ui_description(func, "Return the icon for this enum item");
+
 	/* items */
 	func = RNA_def_function(srna, "prop", "rna_uiItemR");
 	RNA_def_function_ui_description(func, "Item. Exposes an RNA item and places it into the layout");
@@ -274,9 +413,13 @@ void RNA_api_ui_layout(StructRNA *srna)
 	RNA_def_property_flag(parm, PROP_REQUIRED);
 #endif
 
-	func = RNA_def_function(srna, "label", "uiItemL");
-	RNA_def_function_ui_description(func, "Item. Display text in the layout");
+	func = RNA_def_function(srna, "label", "rna_uiItemL");
+	RNA_def_function_ui_description(func, "Item. Display text and/or icon in the layout");
 	api_ui_item_common(func);
+	parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
+	RNA_def_property_ui_text(parm, "Icon Value",
+	                         "Override automatic icon of the item "
+	                         "(use it e.g. with custom material icons returned by icon()...)");
 
 	func = RNA_def_function(srna, "menu", "uiItemM");
 	RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -439,26 +582,29 @@ void RNA_api_ui_layout(StructRNA *srna)
 	RNA_def_boolean(func, "compact", 0, "", "Use more compact layout");
 
 	func = RNA_def_function(srna, "template_list", "uiTemplateList");
-	RNA_def_function_ui_description(func, "Item. A list widget to display data, e.g. vertexgroups "
-	                                      "(WARNING: only one per panel allowed!).");
+	RNA_def_function_ui_description(func, "Item. A list widget to display data, e.g. vertexgroups.");
 	RNA_def_function_flag(func, FUNC_USE_CONTEXT);
-	parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
+	parm = RNA_def_string(func, "listtype_name", "", 0, "", "Identifier of the list type to use");
+	RNA_def_property_flag(parm, PROP_REQUIRED);
+	parm = RNA_def_string(func, "list_id", "", 0, "",
+	                      "Identifier of this list widget. "
+	                      "If this is set, the uilist gets a custom ID, otherwise it takes the "
+	                      "name of the class used to define the uilist (for example, if the "
+	                      "class name is \"OBJECT_UL_vgroups\", and list_id is not set by the "
+	                      "script, then bl_idname = \"OBJECT_UL_vgroups\")");
+	parm = RNA_def_pointer(func, "dataptr", "AnyType", "", "Data from which to take the Collection property");
 	RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
-	parm = RNA_def_string(func, "property", "", 0, "", "Identifier of property in data");
+	parm = RNA_def_string(func, "propname", "", 0, "", "Identifier of the Collection property in data");
 	RNA_def_property_flag(parm, PROP_REQUIRED);
-	parm = RNA_def_pointer(func, "active_data", "AnyType", "",
-	                       "Data from which to take property for the active element");
+	parm = RNA_def_pointer(func, "active_dataptr", "AnyType", "",
+	                       "Data from which to take the integer property, index of the active item");
 	RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
-	parm = RNA_def_string(func, "active_property", "", 0, "",
-	                      "Identifier of property in data, for the active element");
+	parm = RNA_def_string(func, "active_propname", "", 0, "",
+	                      "Identifier of the integer property in active_data, index of the active item");
 	RNA_def_property_flag(parm, PROP_REQUIRED);
-	RNA_def_string(func, "prop_list", "", 0, "",
-	               "Identifier of a string property in each data member, specifying which "
-	               "of its properties should have a widget displayed in its row "
-	               "(format: \"propname1:propname2:propname3:...\")");
 	RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Number of rows to display", 0, INT_MAX);
 	RNA_def_int(func, "maxrows", 5, 0, INT_MAX, "", "Maximum number of rows to display", 0, INT_MAX);
-	RNA_def_enum(func, "type", list_type_items, 0, "Type", "Type of list to use");
+	RNA_def_enum(func, "type", uilist_layout_type_items, UILST_LAYOUT_DEFAULT, "Type", "Type of layout to use");
 
 	func = RNA_def_function(srna, "template_running_jobs", "uiTemplateRunningJobs");
 	RNA_def_function_flag(func, FUNC_USE_CONTEXT);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 06154a235aa..7474ff40e32 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -47,6 +47,7 @@
 #include "BLF_translation.h"
 
 #include "BKE_sound.h"
+#include "BKE_addon.h"
 
 #ifdef WITH_CYCLES
 static EnumPropertyItem compute_device_type_items[] = {
@@ -67,6 +68,7 @@ static EnumPropertyItem compute_device_type_items[] = {
 #include "BKE_depsgraph.h"
 #include "BKE_global.h"
 #include "BKE_main.h"
+#include "BKE_idprop.h"
 
 #include "GPU_draw.h"
 
@@ -79,6 +81,8 @@ static EnumPropertyItem compute_device_type_items[] = {
 
 #include "CCL_api.h"
 
+#include "BKE_addon.h"
+
 static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
 {
 	WM_main_add_notifier(NC_WINDOW, NULL);
@@ -428,6 +432,103 @@ static EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C), Poi
 }
 #endif
 
+static IDProperty *rna_AddonPref_idprops(PointerRNA *ptr, int create)
+{
+	if (create && !ptr->data) {
+		IDPropertyTemplate val = {0};
+		ptr->data = IDP_New(IDP_GROUP, &val, "RNA_AddonPreferences group");
+	}
+
+	return ptr->data;
+}
+
+static PointerRNA rna_Addon_preferences_get(PointerRNA *ptr)
+{
+	bAddon *addon = (bAddon *)ptr->data;
+	bAddonPrefType *apt = BKE_addon_pref_type_find(addon->module, TRUE);
+	if (apt) {
+		if (addon->prop == NULL) {
+			IDPropertyTemplate val = {0};
+			addon->prop = IDP_New(IDP_GROUP, &val, addon->module); /* name is unimportant  */
+		}
+		return rna_pointer_inherit_refine(ptr, apt->ext.srna, addon->prop);
+	}
+	else {
+		return PointerRNA_NULL;
+	}
+}
+
+static void rna_AddonPref_unregister(Main *UNUSED(bmain), StructRNA *type)
+{
+	bAddonPrefType *apt = RNA_struct_blender_type_get(type);
+
+	if (!apt)
+		return;
+
+	RNA_struct_free_extension(type, &apt->ext);
+
+	BKE_addon_pref_type_remove(apt);
+	RNA_struct_free(&BLENDER_RNA, type);
+
+	/* update while blender is running */
+	WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+}
+
+static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
+                                         StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+{
+	bAddonPrefType *apt, dummyapt = {{'\0'}};
+	bAddon dummyaddon = {NULL};
+	PointerRNA dummyhtr;
+	// int have_function[1];
+
+	/* setup dummy header & header type to store static properties in */
+	RNA_pointer_create(NULL, &RNA_AddonPreferences, &dummyaddon, &dummyhtr);
+
+	/* validate the python class */
+	if (validate(&dummyhtr, data, NULL /* have_function */ ) != 0)
+		return NULL;
+
+	BLI_strncpy(dummyapt.idname, dummyaddon.module, sizeof(dummyapt.idname));
+	if (strlen(identifier) >= sizeof(dummyapt.idname)) {
+		BKE_reportf(reports, RPT_ERROR, "Registering addon-prefs class: '%s' is too long, maximum length is %d",
+		            identifier, (int)sizeof(dummyapt.idname));
+		return NULL;
+	}
+
+	/* check if we have registered this header type before, and remove it */
+	apt = BKE_addon_pref_type_find(dummyaddon.module, TRUE);
+	if (apt) {
+		if (apt->ext.srna) {
+			rna_AddonPref_unregister(bmain, apt->ext.srna);
+		}
+	}
+
+	/* create a new header type */
+	apt = MEM_mallocN(sizeof(bAddonPrefType), "addonpreftype");
+	memcpy(apt, &dummyapt, sizeof(dummyapt));
+	BKE_addon_pref_type_add(apt);
+
+	apt->ext.srna = RNA_def_struct(&BLENDER_RNA, identifier, "AddonPreferences");
+	apt->ext.data = data;
+	apt->ext.call = call;
+	apt->ext.free = free;
+	RNA_struct_blender_type_set(apt->ext.srna, apt);
+
+//	apt->draw = (have_function[0]) ? header_draw : NULL;
+
+	/* update while blender is running */
+	WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+	return apt->ext.srna;
+}
+
+/* placeholder, doesn't do anything useful yet */
+static StructRNA *rna_AddonPref_refine(PointerRNA *ptr)
+{
+	return (ptr->type) ? ptr->type : &RNA_AddonPreferences;
+}
+
 #else
 
 static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna)
@@ -437,7 +538,7 @@ static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna)
 	
 	static EnumPropertyItem font_kerning_style[] = {
 		{0, "UNFITTED", 0, "Unfitted", "Use scaled but un-grid-fitted kerning distances"},
-		{1, "DEFAULT", 0, "Default", "Use scaled and grid-fitted kerning distances"},
+		{1, "FITTED", 0, "Fitted", "Use scaled and grid-fitted kerning distances"},
 		{0, NULL, 0, NULL, NULL}
 	};
 
@@ -1549,10 +1650,28 @@ static void rna_def_userdef_theme_space_text(BlenderRNA *brna)
 	RNA_def_property_ui_text(prop, "Syntax Built-in", "");
 	RNA_def_property_update(prop, 0, "rna_userdef_update");
 	
+	prop = RNA_def_property(srna, "syntax_symbols", PROP_FLOAT, PROP_COLOR_GAMMA);
+	RNA_def_property_float_sdna(prop, NULL, "syntaxs");
+	RNA_def_property_array(prop, 3);
+	RNA_def_property_ui_text(prop, "Syntax Symbols", "");
+	RNA_def_property_update(prop, 0, "rna_userdef_update");
+
 	prop = RNA_def_property(srna, "syntax_special", PROP_FLOAT, PROP_COLOR_GAMMA);
 	RNA_def_property_float_sdna(prop, NULL, "syntaxv");
 	RNA_def_property_array(prop, 3);
-	RNA_def_property_ui_text(prop, "Decorator", "");
+	RNA_def_property_ui_text(prop, "Syntax Special", "");
+	RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+	prop = RNA_def_property(srna, "syntax_preprocessor", PROP_FLOAT, PROP_COLOR_GAMMA);
+	RNA_def_property_float_sdna(prop, NULL, "syntaxd");
+	RNA_def_property_array(prop, 3);
+	RNA_def_property_ui_text(prop, "Syntax PreProcessor", "");
+	RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+	prop = RNA_def_property(srna, "syntax_reserved", PROP_FLOAT, PROP_COLOR_GAMMA);
+	RNA_def_property_float_sdna(prop, NULL, "syntaxr");
+	RNA_def_property_array(prop, 3);
+	RNA_def_property_ui_text(prop, "Syntax Reserved", "");
 	RNA_def_property_update(prop, 0, "rna_userdef_update");
 
 	prop = RNA_def_property(srna, "syntax_comment", PROP_FLOAT, PROP_COLOR_GAMMA);
@@ -2228,6 +2347,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
 	
 	static EnumPropertyItem active_theme_area[] = {
 		{0, "USER_INTERFACE", ICON_UI, "User Interface", ""},
+		{19, "STYLE", ICON_FONTPREVIEW, "Text Style", ""},
 		{18, "BONE_COLOR_SETS", ICON_COLOR, "Bone Color Sets", ""},
 		{1, "VIEW_3D", ICON_VIEW3D, "3D View", ""},
 		{2, "TIMELINE", ICON_TIME, "Timeline", ""},
@@ -2394,6 +2514,32 @@ static void rna_def_userdef_addon(BlenderRNA *brna)
 	prop = RNA_def_property(srna, "module", PROP_STRING, PROP_NONE);
 	RNA_def_property_ui_text(prop, "Module", "Module name");
 	RNA_def_struct_name_property(srna, prop);
+
+	/* Collection active property */
+	prop = RNA_def_property(srna, "preferences", PROP_POINTER, PROP_NONE);
+	RNA_def_property_struct_type(prop, "AddonPreferences");
+	RNA_def_property_pointer_funcs(prop, "rna_Addon_preferences_get", NULL, NULL, NULL);
+}
+
+static void rna_def_userdef_addon_pref(BlenderRNA *brna)
+{
+	StructRNA *srna;
+	PropertyRNA *prop;
+
+	srna = RNA_def_struct(brna, "AddonPreferences", NULL);
+	RNA_def_struct_ui_text(srna, "Addon Preferences", "");
+	RNA_def_struct_sdna(srna, "bAddon");  /* WARNING: only a bAddon during registration */
+
+	RNA_def_struct_refine_func(srna, "rna_AddonPref_refine");
+	RNA_def_struct_register_funcs(srna, "rna_AddonPref_register", "rna_AddonPref_unregister", NULL);
+	RNA_def_struct_idprops_func(srna, "rna_AddonPref_idprops");
+
+	/* registration */
+	RNA_define_verify_sdna(0);
+	prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
+	RNA_def_property_string_sdna(prop, NULL, "module");
+	RNA_def_property_flag(prop, PROP_REGISTER | PROP_NEVER_CLAMP);
+	RNA_define_verify_sdna(1);
 }
 
 
@@ -3031,62 +3177,10 @@ static void rna_def_userdef_system(BlenderRNA *brna)
 		{0, NULL, 0, NULL, NULL}
 	};
 	
-#if 0
-	/* hardcoded here, could become dynamic somehow */
-	/* locale according to http://www.roseindia.net/tutorials/I18N/locales-list.shtml */
-	/* if you edit here, please also edit the source/blender/blenfont/intern/blf_lang.c 's locales */
-	/* Note: As this list is in alphabetical order, and not defined order,
-	 *       here is the highest define currently in use: 35 (Esperanto). */
 	static EnumPropertyItem language_items[] = {
-		{ 0, "", 0, N_("Nearly Done"), ""},
-		{ 0, "DEFAULT", 0, "Default (Default)", ""},
-		/* using the utf8 flipped form of Arabic (العربية) */
-		{21, "ARABIC", 0, "Arabic (ﺔﻴﺑﺮﻌﻟﺍ)", "ar_EG"},
-		{32, "BRAZILIANPORTUGUESE", 0, "Brazilian Portuguese (Português do Brasil)", "pt_BR"},
-		{ 1, "ENGLISH", 0, "English (English)", "en_US"},
-		{ 8, "FRENCH", 0, "French (Français)", "fr_FR"},
-		{ 4, "ITALIAN", 0, "Italian (Italiano)", "it_IT"},
-		{ 2, "JAPANESE", 0, "Japanese (日本語)", "ja_JP"},
-		{12, "PORTUGUESE", 0, "Portuguese (Português)", "pt"},
-		{15, "RUSSIAN", 0, "Russian (Русский)", "ru_RU"},
-		{13, "SIMPLIFIED_CHINESE", 0, "Simplified Chinese (简体中文)", "zh_CN"},
-		{ 9, "SPANISH", 0, "Spanish (Español)", "es"},
-		{14, "TRADITIONAL_CHINESE", 0, "Traditional Chinese (繁體中文)", "zh_TW"},
-		{18, "UKRAINIAN", 0, "Ukrainian (Український)", "uk_UA"},
-		{ 0, "", 0, N_("In Progress"), ""},
-/*		{22, "BULGARIAN", 0, "Bulgarian (Български)", "bg_BG"},*/ /* XXX Not active nor enough translated. */
-/*		{10, "CATALAN", 0, "Catalan (Català)", "ca_AD"},*/ /* XXX Not active nor enough translated. */
-		{16, "CROATIAN", 0, "Croatian (Hrvatski)", "hr_HR"},
-		{11, "CZECH", 0, "Czech (Český)", "cs_CZ"},
-		{ 3, "DUTCH", 0, "Dutch (Nederlandse taal)", "nl_NL"},
-		{35, "ESPERANTO", 0, "Esperanto (Esperanto)", "eo"},
-		{34, "ESTONIAN", 0, "Estonian (Eestlane)", "et_EE"},
-/*		{ 6, "FINNISH", 0, "Finnish (Suomi)", "fi_FI"},*/ /* XXX Not active nor enough translated. */
-		{ 5, "GERMAN", 0, "German (Deutsch)", "de_DE"},
-/*		{23, "GREEK", 0, "Greek (Ελληνικά)", "el_GR"},*/ /* XXX Not active nor enough translated. */
-		/* using the utf8 flipped form of Hebrew (עִבְרִית)) */
-		{33, "HEBREW", 0, "Hebrew (תירִבְעִ)", "he_IL"},
-		{31, "HUNGARIAN", 0, "Hungarian (Magyar)", "hu_HU"},
-		{27, "INDONESIAN", 0, "Indonesian (Bahasa indonesia)", "id_ID"},
-		{29, "KYRGYZ", 0, "Kyrgyz (Кыргыз тили)", "ky_KG"},
-/*		{24, "KOREAN", 0, "Korean (한국 언어)", "ko_KR"}, */ /* XXX Not active nor enough translated. */
-/*		{25, "NEPALI", 0, "Nepali (नेपाली)", "ne_NP"},*/ /* XXX Not active nor enough translated. */
-		/* using the utf8 flipped form of Persian (فارسی) */
-		{26, "PERSIAN", 0, "Persian (ﯽﺳﺭﺎﻓ)", "fa_IR"},
-/*		{19, "POLISH", 0, "Polish (Polski)", "pl_PL"},*/ /* XXX Not active nor enough translated. */
-/*		{20, "ROMANIAN", 0, "Romanian (Român)", "ro_RO"}, */ /* XXX Not active nor enough translated. */
-		{17, "SERBIAN", 0, "Serbian (Српски)", "sr_RS"},
-		{28, "SERBIAN_LATIN", 0, "Serbian Latin (Srpski latinica)", "sr_RS@latin"},
-		{ 7, "SWEDISH", 0, "Swedish (Svenska)", "sv_SE"},
-		{30, "TURKISH", 0, "Turkish (Türkçe)", "tr_TR"},
-		{ 0, NULL, 0, NULL, NULL}
+		{0, "DEFAULT", 0, "Default (Default)", ""},
+		{0, NULL, 0, NULL, NULL}
 	};
-#else
-	static EnumPropertyItem language_items[] = {
-		{ 0, "DEFAULT", 0, "Default (Default)", ""},
-		{ 0, NULL, 0, NULL, NULL}
-	};
-#endif
 
 #ifdef WITH_CYCLES
 	static EnumPropertyItem compute_device_items[] = {
@@ -3801,6 +3895,7 @@ void RNA_def_userdef(BlenderRNA *brna)
 	rna_def_userdef_filepaths(brna);
 	rna_def_userdef_system(brna);
 	rna_def_userdef_addon(brna);
+	rna_def_userdef_addon_pref(brna);
 	
 }
 
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 59befe4db05..776adb57c13 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -140,7 +140,7 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *UNUSED(ob),
 		}
 	}
 
-	BM_mesh_bevel(bm, bmd->value, segments);
+	BM_mesh_bevel(bm, bmd->value, segments, bmd->flags & BME_BEVEL_VERT);
 
 	result = CDDM_from_bmesh(bm, TRUE);
 
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index a23b677f8e6..2d3d5c97af7 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -63,7 +63,7 @@ static void initData(ModifierData *md)
 	DecimateModifierData *dmd = (DecimateModifierData *) md;
 
 	dmd->percent = 1.0;
-	dmd->angle   = DEG2RADF(15.0f);
+	dmd->angle   = DEG2RADF(5.0f);
 }
 
 static void copyData(ModifierData *md, ModifierData *target)
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 5c786626c94..33601c197b9 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -48,7 +48,6 @@
 
 #include "DNA_object_types.h"
 
-#define EDGE_MARK  1
 
 static DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd, Object *UNUSED(ob))
 {
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 564fa696c2a..c0e529f1eae 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -139,10 +139,10 @@ static void initData(ModifierData *md)
 	omd->ocean = BKE_add_ocean();
 	init_ocean_modifier(omd);
 	simulate_ocean_modifier(omd);
-#else  // WITH_OCEANSIM
+#else  /* WITH_OCEANSIM */
 	   /* unused */
 	(void)md;
-#endif // WITH_OCEANSIM
+#endif /* WITH_OCEANSIM */
 }
 
 static void freeData(ModifierData *md)
@@ -153,10 +153,10 @@ static void freeData(ModifierData *md)
 	BKE_free_ocean(omd->ocean);
 	if (omd->oceancache)
 		BKE_free_ocean_cache(omd->oceancache);
-#else // WITH_OCEANSIM
+#else /* WITH_OCEANSIM */
 	/* unused */
 	(void)md;
-#endif // WITH_OCEANSIM
+#endif /* WITH_OCEANSIM */
 }
 
 static void copyData(ModifierData *md, ModifierData *target)
@@ -201,11 +201,11 @@ static void copyData(ModifierData *md, ModifierData *target)
 	tomd->ocean = BKE_add_ocean();
 	init_ocean_modifier(tomd);
 	simulate_ocean_modifier(tomd);
-#else // WITH_OCEANSIM
+#else /* WITH_OCEANSIM */
 	/* unused */
 	(void)md;
 	(void)target;
-#endif // WITH_OCEANSIM
+#endif /* WITH_OCEANSIM */
 }
 
 #ifdef WITH_OCEANSIM
@@ -219,14 +219,14 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
 
 	return dataMask;
 }
-#else // WITH_OCEANSIM
+#else /* WITH_OCEANSIM */
 static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
 {
 	/* unused */
 	(void)md;
 	return 0;
 }
-#endif // WITH_OCEANSIM
+#endif /* WITH_OCEANSIM */
 
 #if 0
 static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, float *oy)
@@ -302,11 +302,7 @@ static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd)
 	mpolys = CDDM_get_polys(result);
 	mloops = CDDM_get_loops(result);
 
-#if 0 // trunk
-	origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
-#else // bmesh
 	origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX);
-#endif
 
 	/* create vertices */
 	#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES)
@@ -443,7 +439,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
 
 	cfra = md->scene->r.cfra;
 	CLAMP(cfra, omd->bakestart, omd->bakeend);
-	cfra -= omd->bakestart; // shift to 0 based
+	cfra -= omd->bakestart; /* shift to 0 based */
 
 	num_verts = dm->getNumVerts(dm);
 	num_faces = dm->getNumPolys(dm);
@@ -500,7 +496,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
 
 	/* displace the geometry */
 
-	//#pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES)
+	/* #pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES) */
 	for (i = 0, mv = mverts; i < num_verts; i++, mv++) {
 		const float u = OCEAN_CO(size_co_inv, mv->co[0]);
 		const float v = OCEAN_CO(size_co_inv, mv->co[1]);
@@ -522,7 +518,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob,
 
 	return dm;
 }
-#else  // WITH_OCEANSIM
+#else  /* WITH_OCEANSIM */
 static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob),
                             DerivedMesh *derivedData,
                             int UNUSED(useRenderParams))
@@ -531,7 +527,7 @@ static DerivedMesh *doOcean(ModifierData *md, Object *UNUSED(ob),
 	(void)md;
 	return derivedData;
 }
-#endif // WITH_OCEANSIM
+#endif /* WITH_OCEANSIM */
 
 static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
                                   DerivedMesh *derivedData,
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 93b5e36e5a4..ff88cd97197 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -225,7 +225,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
 
 		/* angle */
 
-#if 0   // cant incluide this, not predictable enough, though quite fun,.
+#if 0   /* cant incluide this, not predictable enough, though quite fun. */
 		if (ltmd->flag & MOD_SCREW_OBJECT_ANGLE) {
 			float mtx3_tx[3][3];
 			copy_m3_m4(mtx3_tx, mtx_tx);
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index 7fe8dc69790..697ccdc49a4 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -54,13 +54,16 @@ static void deformVerts(ModifierData *md, Object *ob,
                         int numVerts,
                         ModifierApplyFlag UNUSED(flag))
 {
-	KeyBlock *kb = BKE_keyblock_from_object(ob);
+	Key *key = BKE_key_from_object(ob);
 	float (*deformedVerts)[3];
 
-	if (kb && kb->totelem == numVerts) {
-		deformedVerts = (float(*)[3])do_ob_key(md->scene, ob);
+	if (key && key->block.first) {
+		int deformedVerts_tot;
+		deformedVerts = (float(*)[3])BKE_key_evaluate_object(md->scene, ob, &deformedVerts_tot);
 		if (deformedVerts) {
-			memcpy(vertexCos, deformedVerts, sizeof(float) * 3 * numVerts);
+			if (numVerts == deformedVerts_tot) {
+				memcpy(vertexCos, deformedVerts, sizeof(float) * 3 * numVerts);
+			}
 			MEM_freeN(deformedVerts);
 		}
 	}
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 75e54d77b15..038fb4913ec 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -185,6 +185,8 @@ static void copyData(ModifierData *md, ModifierData *target)
 	tsmd->crease_outer = smd->crease_outer;
 	tsmd->crease_rim = smd->crease_rim;
 	tsmd->flag = smd->flag;
+	tsmd->mat_ofs = smd->mat_ofs;
+	tsmd->mat_ofs_rim = smd->mat_ofs_rim;
 	BLI_strncpy(tsmd->defgrp_name, smd->defgrp_name, sizeof(tsmd->defgrp_name));
 }
 
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 5883b176317..f025352795b 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -361,7 +361,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
 
 	/* Mix weights. */
 	for (i = 0; i < numIdx; i++) {
-		float weight2 = 0.0;
+		float weight2;
 		org_w[i] = dw1[i] ? dw1[i]->weight : wmd->default_weight_a;
 		weight2  = dw2[i] ? dw2[i]->weight : wmd->default_weight_b;
 
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index e936e571a5b..71d6d4880ad 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -107,9 +107,9 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
 	/*nearest_v.dist  = nearest_e.dist  = nearest_f.dist  = FLT_MAX;*/
 	/* Find the nearest vert/edge/face. */
 #ifndef __APPLE__
-#pragma omp parallel for default(none) private(i) firstprivate(nearest_v,nearest_e,nearest_f) \
-                         shared(treeData_v,treeData_e,treeData_f,numVerts,v_cos,dist_v,dist_e, \
-                                dist_f,loc2trgt) \
+#pragma omp parallel for default(none) private(i) firstprivate(nearest_v, nearest_e, nearest_f) \
+                         shared(treeData_v, treeData_e, treeData_f, numVerts, v_cos, dist_v, dist_e, \
+                                dist_f, loc2trgt) \
                          schedule(static)
 #endif
 	for (i = 0; i < numVerts; i++) {
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 141a3680df2..a7b491cf42b 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -168,6 +168,7 @@ set(SRC
 	shader/nodes/node_shader_mix_shader.c
 	shader/nodes/node_shader_normal_map.c
 	shader/nodes/node_shader_object_info.c
+	shader/nodes/node_shader_hair_info.c
 	shader/nodes/node_shader_output_lamp.c
 	shader/nodes/node_shader_output_material.c
 	shader/nodes/node_shader_output_world.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 74135776c9c..0a7a11e4506 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -78,6 +78,7 @@ void register_node_type_sh_fresnel(struct bNodeTreeType *ttype);
 void register_node_type_sh_layer_weight(struct bNodeTreeType *ttype);
 void register_node_type_sh_tex_coord(struct bNodeTreeType *ttype);
 void register_node_type_sh_particle_info(struct bNodeTreeType *ttype);
+void register_node_type_sh_hair_info(struct bNodeTreeType *ttype);
 void register_node_type_sh_script(struct bNodeTreeType *ttype);
 void register_node_type_sh_normal_map(struct bNodeTreeType *ttype);
 void register_node_type_sh_tangent(struct bNodeTreeType *ttype);
diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c
index 57eb99021f6..c4b48b83b16 100644
--- a/source/blender/nodes/composite/node_composite_util.c
+++ b/source/blender/nodes/composite/node_composite_util.c
@@ -615,7 +615,7 @@ void generate_preview(void *data, bNode *node, CompBuf *stackbuf)
 	bNodePreview *preview= node->preview;
 	int xsize, ysize;
 	int profile_from= (rd->color_mgt_flag & R_COLOR_MANAGEMENT)? IB_PROFILE_LINEAR_RGB: IB_PROFILE_SRGB;
-	int predivide= (rd->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE);
+	int predivide= TRUE;
 	int dither= 0;
 	unsigned char *rect;
 	
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index 88d78df190f..7e44210928c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -291,7 +291,6 @@ static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
 float *node_composit_get_float_buffer(RenderData *rd, ImBuf *ibuf, int *alloc)
 {
 	float *rect;
-	int predivide= (ibuf->flags & IB_cm_predivide);
 
 	*alloc= FALSE;
 
@@ -305,7 +304,7 @@ float *node_composit_get_float_buffer(RenderData *rd, ImBuf *ibuf, int *alloc)
 		rect= MEM_mapallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, "node_composit_get_image");
 
 		IMB_buffer_float_from_float(rect, ibuf->rect_float,
-			4, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, predivide,
+			4, IB_PROFILE_SRGB, IB_PROFILE_LINEAR_RGB, TRUE,
 			ibuf->x, ibuf->y, ibuf->x, ibuf->x);
 
 			*alloc= TRUE;
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
index 214617c91e5..fe23f7373fb 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c
@@ -269,7 +269,7 @@ static void exec_output_file_singlelayer(RenderData *rd, bNode *node, bNodeStack
 			
 			/* get full path */
 			BLI_join_dirfile(path, FILE_MAX, nimf->base_path, sockdata->path);
-			BKE_makepicstring(filename, path, bmain->name, rd->cfra, format->imtype, (rd->scemode & R_EXTENSION), TRUE);
+			BKE_makepicstring(filename, path, bmain->name, rd->cfra, format, (rd->scemode & R_EXTENSION), TRUE);
 			
 			if (0 == BKE_imbuf_write(ibuf, filename, format))
 				printf("Cannot save Node File Output to %s\n", filename);
@@ -304,7 +304,7 @@ static void exec_output_file_multilayer(RenderData *rd, bNode *node, bNodeStack
 	int recty = -1;
 	int has_preview = 0;
 	
-	BKE_makepicstring(filename, nimf->base_path, bmain->name, rd->cfra, R_IMF_IMTYPE_MULTILAYER, (rd->scemode & R_EXTENSION), TRUE);
+	BKE_makepicstring_from_type(filename, nimf->base_path, bmain->name, rd->cfra, R_IMF_IMTYPE_MULTILAYER, (rd->scemode & R_EXTENSION), TRUE);
 	BLI_make_existing_file(filename);
 	
 	for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) {
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c
index 86ef8a14c12..dc8d427c0ae 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.c
@@ -305,7 +305,7 @@ void node_group_verify(struct bNodeTree *ntree, struct bNode *node, struct ID *i
 {
 	/* check inputs and outputs, and remove or insert them */
 	if (node->id==id) {
-		bNodeTree *ngroup= (bNodeTree*)node->id;
+		bNodeTree *ngroup= (bNodeTree *)node->id;
 		group_verify_socket_list(ntree, node, &node->inputs, SOCK_IN, &ngroup->inputs);
 		group_verify_socket_list(ntree, node, &node->outputs, SOCK_OUT, &ngroup->outputs);
 	}
@@ -314,7 +314,7 @@ void node_group_verify(struct bNodeTree *ntree, struct bNode *node, struct ID *i
 struct bNodeTree *node_group_edit_get(bNode *node)
 {
 	if (node->flag & NODE_GROUP_EDIT)
-		return (bNodeTree*)node->id;
+		return (bNodeTree *)node->id;
 	else
 		return NULL;
 }
@@ -322,7 +322,7 @@ struct bNodeTree *node_group_edit_get(bNode *node)
 struct bNodeTree *node_group_edit_set(bNode *node, int edit)
 {
 	if (edit) {
-		bNodeTree *ngroup= (bNodeTree*)node->id;
+		bNodeTree *ngroup= (bNodeTree *)node->id;
 		if (ngroup) {
 			if (ngroup->id.lib)
 				ntreeMakeLocal(ngroup);
@@ -339,7 +339,7 @@ struct bNodeTree *node_group_edit_set(bNode *node, int edit)
 
 void node_group_edit_clear(bNode *node)
 {
-	bNodeTree *ngroup= (bNodeTree*)node->id;
+	bNodeTree *ngroup= (bNodeTree *)node->id;
 	bNode *inode;
 	
 	node->flag &= ~NODE_GROUP_EDIT;
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 3cc7ebf9337..86f8f4dfbbf 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -114,13 +114,13 @@ static struct bNodeStack *setup_stack(bNodeStack *stack, bNodeSocket *sock)
 	if (sock->default_value) {
 		switch (sock->type) {
 		case SOCK_FLOAT:
-			ns->vec[0] = ((bNodeSocketValueFloat*)sock->default_value)->value;
+			ns->vec[0] = ((bNodeSocketValueFloat *)sock->default_value)->value;
 			break;
 		case SOCK_VECTOR:
-			copy_v3_v3(ns->vec, ((bNodeSocketValueVector*)sock->default_value)->value);
+			copy_v3_v3(ns->vec, ((bNodeSocketValueVector *)sock->default_value)->value);
 			break;
 		case SOCK_RGBA:
-			copy_v4_v4(ns->vec, ((bNodeSocketValueRGBA*)sock->default_value)->value);
+			copy_v4_v4(ns->vec, ((bNodeSocketValueRGBA *)sock->default_value)->value);
 			break;
 		}
 	}
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 6130fe72af3..544ccb8fda6 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -139,49 +139,49 @@ void nodeShaderSynchronizeID(bNode *node, int copyto)
 				if (copyto) {
 					switch (a) {
 						case MAT_IN_COLOR:
-							copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA*)sock->default_value)->value); break;
+							copy_v3_v3(&ma->r, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
 						case MAT_IN_SPEC:
-							copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA*)sock->default_value)->value); break;
+							copy_v3_v3(&ma->specr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
 						case MAT_IN_REFL:
-							ma->ref= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
+							ma->ref= ((bNodeSocketValueFloat *)sock->default_value)->value; break;
 						case MAT_IN_MIR:
-							copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA*)sock->default_value)->value); break;
+							copy_v3_v3(&ma->mirr, ((bNodeSocketValueRGBA *)sock->default_value)->value); break;
 						case MAT_IN_AMB:
-							ma->amb= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
+							ma->amb = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
 						case MAT_IN_EMIT:
-							ma->emit= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
+							ma->emit = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
 						case MAT_IN_SPECTRA:
-							ma->spectra= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
+							ma->spectra = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
 						case MAT_IN_RAY_MIRROR:
-							ma->ray_mirror= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
+							ma->ray_mirror = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
 						case MAT_IN_ALPHA:
-							ma->alpha= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
+							ma->alpha = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
 						case MAT_IN_TRANSLUCENCY:
-							ma->translucency= ((bNodeSocketValueFloat*)sock->default_value)->value; break;
+							ma->translucency = ((bNodeSocketValueFloat *)sock->default_value)->value; break;
 					}
 				}
 				else {
 					switch (a) {
 						case MAT_IN_COLOR:
-							copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->r); break;
+							copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->r); break;
 						case MAT_IN_SPEC:
-							copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->specr); break;
+							copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->specr); break;
 						case MAT_IN_REFL:
-							((bNodeSocketValueFloat*)sock->default_value)->value= ma->ref; break;
+							((bNodeSocketValueFloat *)sock->default_value)->value= ma->ref; break;
 						case MAT_IN_MIR:
-							copy_v3_v3(((bNodeSocketValueRGBA*)sock->default_value)->value, &ma->mirr); break;
+							copy_v3_v3(((bNodeSocketValueRGBA *)sock->default_value)->value, &ma->mirr); break;
 						case MAT_IN_AMB:
-							((bNodeSocketValueFloat*)sock->default_value)->value= ma->amb; break;
+							((bNodeSocketValueFloat *)sock->default_value)->value = ma->amb; break;
 						case MAT_IN_EMIT:
-							((bNodeSocketValueFloat*)sock->default_value)->value= ma->emit; break;
+							((bNodeSocketValueFloat *)sock->default_value)->value = ma->emit; break;
 						case MAT_IN_SPECTRA:
-							((bNodeSocketValueFloat*)sock->default_value)->value= ma->spectra; break;
+							((bNodeSocketValueFloat *)sock->default_value)->value = ma->spectra; break;
 						case MAT_IN_RAY_MIRROR:
-							((bNodeSocketValueFloat*)sock->default_value)->value= ma->ray_mirror; break;
+							((bNodeSocketValueFloat *)sock->default_value)->value = ma->ray_mirror; break;
 						case MAT_IN_ALPHA:
-							((bNodeSocketValueFloat*)sock->default_value)->value= ma->alpha; break;
+							((bNodeSocketValueFloat *)sock->default_value)->value = ma->alpha; break;
 						case MAT_IN_TRANSLUCENCY:
-							((bNodeSocketValueFloat*)sock->default_value)->value= ma->translucency; break;
+							((bNodeSocketValueFloat *)sock->default_value)->value = ma->translucency; break;
 					}
 				}
 			}
@@ -259,7 +259,7 @@ bNode *nodeGetActiveTexture(bNodeTree *ntree)
 			break;
 
 	if (node)
-		ntree= (bNodeTree*)node->id;
+		ntree = (bNodeTree *)node->id;
 
 	for (node= ntree->nodes.first; node; node= node->next)
 		if (node->flag & NODE_ACTIVE_TEXTURE)
@@ -320,7 +320,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in
 	float domax= (texmap->flag & TEXMAP_CLIP_MAX) != 0;
 
 	if (domin || domax || !(texmap->flag & TEXMAP_UNIT_MATRIX)) {
-		GPUNodeLink *tmat = GPU_uniform((float*)texmap->mat);
+		GPUNodeLink *tmat = GPU_uniform((float *)texmap->mat);
 		GPUNodeLink *tmin = GPU_uniform(texmap->min);
 		GPUNodeLink *tmax = GPU_uniform(texmap->max);
 		GPUNodeLink *tdomin = GPU_uniform(&domin);
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c
index 688d77d8350..cf6f778bbf5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.c
@@ -70,7 +70,7 @@ static void move_stack(bNodeStack *to, bNodeStack *from)
 
 static void *group_initexec(bNode *node)
 {
-	bNodeTree *ngroup= (bNodeTree*)node->id;
+	bNodeTree *ngroup = (bNodeTree *)node->id;
 	bNodeTreeExec *exec;
 	
 	if (!ngroup)
@@ -84,7 +84,7 @@ static void *group_initexec(bNode *node)
 
 static void group_freeexec(bNode *UNUSED(node), void *nodedata)
 {
-	bNodeTreeExec*gexec= (bNodeTreeExec*)nodedata;
+	bNodeTreeExec*gexec = (bNodeTreeExec *)nodedata;
 	
 	ntreeShaderEndExecTree(gexec, 0);
 }
@@ -121,7 +121,7 @@ static void group_move_outputs(bNode *node, bNodeStack **out, bNodeStack *gstack
 
 static void group_execute(void *data, int thread, struct bNode *node, void *nodedata, struct bNodeStack **in, struct bNodeStack **out)
 {
-	bNodeTreeExec *exec= (bNodeTreeExec*)nodedata;
+	bNodeTreeExec *exec = (bNodeTreeExec *)nodedata;
 	bNodeThreadStack *nts;
 	
 	if (!exec)
@@ -177,7 +177,7 @@ static void group_gpu_move_outputs(bNode *node, GPUNodeStack *out, bNodeStack *g
 
 static int gpu_group_execute(GPUMaterial *mat, bNode *node, void *nodedata, GPUNodeStack *in, GPUNodeStack *out)
 {
-	bNodeTreeExec *exec= (bNodeTreeExec*)nodedata;
+	bNodeTreeExec *exec = (bNodeTreeExec *)nodedata;
 	
 	group_gpu_copy_inputs(node, in, exec->stack);
 	ntreeExecGPUNodes(exec, mat, (node->flag & NODE_GROUP_EDIT));
diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.c b/source/blender/nodes/shader/nodes/node_shader_hair_info.c
new file mode 100644
index 00000000000..5cd4c8bd1d3
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.c
@@ -0,0 +1,53 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+static bNodeSocketTemplate outputs[] = {
+	{	SOCK_FLOAT,  0, N_("Is Strand"),			0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+	{	SOCK_FLOAT,  0, N_("Intercept"),		0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+	{	SOCK_FLOAT,  0, N_("Thickness"),			0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+	{	SOCK_VECTOR, 0, N_("Tangent Normal"),	0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+	{	-1, 0, ""	}
+};
+
+/* node type definition */
+void register_node_type_sh_hair_info(bNodeTreeType *ttype)
+{
+	static bNodeType ntype;
+
+	node_type_base(ttype, &ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT, 0);
+	node_type_compatibility(&ntype, NODE_NEW_SHADING);
+	node_type_socket_templates(&ntype, NULL, outputs);
+	node_type_size(&ntype, 150, 60, 200);
+	node_type_init(&ntype, NULL);
+	node_type_storage(&ntype, "", NULL, NULL);
+	node_type_exec(&ntype, NULL);
+	node_type_gpu(&ntype, NULL);
+
+	nodeRegisterType(ttype, &ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index cedd3a4910c..396c1ac60bf 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c
@@ -77,7 +77,7 @@ static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in, G
 	TexMapping *texmap= node->storage;
 	float domin= (texmap->flag & TEXMAP_CLIP_MIN) != 0;
 	float domax= (texmap->flag & TEXMAP_CLIP_MAX) != 0;
-	GPUNodeLink *tmat = GPU_uniform((float*)texmap->mat);
+	GPUNodeLink *tmat = GPU_uniform((float *)texmap->mat);
 	GPUNodeLink *tmin = GPU_uniform(texmap->min);
 	GPUNodeLink *tmax = GPU_uniform(texmap->max);
 	GPUNodeLink *tdomin = GPU_uniform(&domin);
diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript
index 15403d7acf4..4fb6d771c5b 100644
--- a/source/blender/python/SConscript
+++ b/source/blender/python/SConscript
@@ -134,6 +134,12 @@ if env['WITH_BF_TIFF']:
 if env['WITH_BF_INTERNATIONAL']:
     defs.append('WITH_INTERNATIONAL')
 
+if env['WITH_BF_OPENAL']:
+    defs.append('WITH_OPENAL')
+
+if env['WITH_BF_SDL']:
+    defs.append('WITH_SDL')
+
 if env['WITH_BF_JACK']:
     defs.append('WITH_JACK')
 
@@ -155,12 +161,12 @@ if env['WITH_BF_REMESH']:
 if env['WITH_BF_SMOKE']:
     defs.append('WITH_SMOKE')
 
-if env['WITH_BF_OPENAL']:
-    defs.append('WITH_OPENAL')
-
 if env['WITH_BF_COLLADA']:
     defs.append('WITH_COLLADA')
 
+if env['WITH_BF_OIIO']:
+    defs.append('WITH_OCIO')
+
 if env['WITH_BF_PLAYER']:
     defs.append('WITH_PLAYER')
 
diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c
index 9abb13731af..ce8153fb994 100644
--- a/source/blender/python/bmesh/bmesh_py_api.c
+++ b/source/blender/python/bmesh/bmesh_py_api.c
@@ -110,14 +110,17 @@ PyDoc_STRVAR(bpy_bm_update_edit_mesh_doc,
 "   :arg destructive: Use when grometry has been added or removed.\n"
 "   :type destructive: boolean\n"
 );
-static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args)
+static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
 {
+	static const char *kwlist[] = {"mesh", "tessface", "destructive", NULL};
 	PyObject *py_me;
 	Mesh *me;
 	int do_tessface = TRUE;
 	int is_destructive = TRUE;
 
-	if (!PyArg_ParseTuple(args, "O|ii:update_edit_mesh", &py_me, &do_tessface, &is_destructive)) {
+	if (!PyArg_ParseTupleAndKeywords(args, kw, "O|ii:update_edit_mesh", (char **)kwlist,
+	                                 &py_me, &do_tessface, &is_destructive))
+	{
 		return NULL;
 	}
 
@@ -144,7 +147,7 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args)
 static struct PyMethodDef BPy_BM_methods[] = {
 	{"new",            (PyCFunction)bpy_bm_new,            METH_NOARGS,  bpy_bm_new_doc},
 	{"from_edit_mesh", (PyCFunction)bpy_bm_from_edit_mesh, METH_O,       bpy_bm_from_edit_mesh_doc},
-	{"update_edit_mesh", (PyCFunction)bpy_bm_update_edit_mesh, METH_VARARGS, bpy_bm_update_edit_mesh_doc},
+	{"update_edit_mesh", (PyCFunction)bpy_bm_update_edit_mesh, METH_VARARGS | METH_KEYWORDS, bpy_bm_update_edit_mesh_doc},
 	{NULL, NULL, 0, NULL}
 };
 
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index 53112d46098..10ca7a943cb 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -836,6 +836,11 @@ static PyObject *BPy_IDGroup_to_dict(BPy_IDProperty *self)
 	return BPy_IDGroup_MapDataToPy(self->prop);
 }
 
+static PyObject *BPy_IDGroup_clear(BPy_IDProperty *self)
+{
+	IDP_ClearProperty(self->prop);
+	Py_RETURN_NONE;
+}
 
 /* Matches python dict.get(key, [default]) */
 static PyObject *BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
@@ -875,6 +880,8 @@ static struct PyMethodDef BPy_IDGroup_methods[] = {
 	 "idprop.get(k[,d]) -> idprop[k] if k in idprop, else d.  d defaults to None"},
 	{"to_dict", (PyCFunction)BPy_IDGroup_to_dict, METH_NOARGS,
 	 "return a purely python version of the group"},
+	{"clear", (PyCFunction)BPy_IDGroup_clear, METH_NOARGS,
+	 "clear all members from this group"},
 	{NULL, NULL, 0, NULL}
 };
 
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index f62fdaf09db..9a064923736 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -241,6 +241,23 @@ PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...)
 	return item;
 }
 
+PyObject *PyC_FrozenSetFromStrings(const char **strings)
+{
+	const char **str;
+	PyObject *ret;
+
+	ret = PyFrozenSet_New(NULL);
+
+	for (str = strings; *str; str++) {
+		PyObject *py_str = PyUnicode_FromString(*str);
+		PySet_Add(ret, py_str);
+		Py_DECREF(py_str);
+	}
+
+	return ret;
+}
+
+
 /* similar to PyErr_Format(),
  *
  * implementation - we cant actually preprend the existing exception,
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 935a5f9030b..db582bd7086 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -33,6 +33,7 @@ void			PyC_LineSpit(void);
 void			PyC_StackSpit(void);
 PyObject *		PyC_ExceptionBuffer(void);
 PyObject *		PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
+PyObject *		PyC_FrozenSetFromStrings(const char **strings);
 PyObject *		PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...);
 void			PyC_FileAndNum(const char **filename, int *lineno);
 void			PyC_FileAndNum_Safe(const char **filename, int *lineno); /* checks python is running */
@@ -53,7 +54,7 @@ void PyC_MainModule_Restore(PyObject *main_mod);
 
 void PyC_SetHomePath(const char *py_path_bundle);
 
-#define PYC_INTERPRETER_ACTIVE (((PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)) != NULL)
+#define PYC_INTERPRETER_ACTIVE (((PyThreadState *)_Py_atomic_load_relaxed(&_PyThreadState_Current)) != NULL)
 
 void *PyC_RNA_AsPointer(PyObject *value, const char *type_name);
 
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 8f90a823668..823c7c709d7 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -56,6 +56,7 @@ set(SRC
 	bpy_library.c
 	bpy_operator.c
 	bpy_operator_wrap.c
+	bpy_path.c
 	bpy_props.c
 	bpy_rna.c
 	bpy_rna_anim.c
@@ -76,6 +77,7 @@ set(SRC
 	bpy_library.h
 	bpy_operator.h
 	bpy_operator_wrap.h
+	bpy_path.h
 	bpy_props.h
 	bpy_rna.h
 	bpy_rna_anim.h
@@ -190,12 +192,16 @@ if(WITH_INTERNATIONAL)
 	add_definitions(-DWITH_INTERNATIONAL)
 endif()
 
-if(WITH_JACK)
-	add_definitions(-DWITH_JACK)
+if(WITH_OPENAL)
+	add_definitions(-DWITH_OPENAL)
 endif()
 
-if(WITH_LIBMV)
-	add_definitions(-DWITH_LIBMV)
+if(WITH_SDL)
+	add_definitions(-DWITH_SDL)
+endif()
+
+if(WITH_JACK)
+	add_definitions(-DWITH_JACK)
 endif()
 
 if(WITH_LIBMV)
@@ -222,14 +228,14 @@ if(WITH_MOD_SMOKE)
 	add_definitions(-DWITH_SMOKE)
 endif()
 
-if(WITH_OPENAL)
-	add_definitions(-DWITH_OPENAL)
-endif()
-
 if(WITH_OPENCOLLADA)
 	add_definitions(-DWITH_COLLADA)
 endif()
 
+if(WITH_OPENCOLORIO)
+	add_definitions(-DWITH_OCIO)
+endif()
+
 if(WITH_PLAYER)
 	add_definitions(-DWITH_PLAYER)
 endif()
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index 74df3ef7307..8815348c22d 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -15,7 +15,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
- * Contributor(s): Bastien Montagne
+ * Contributor(s): Sergey Sharybin
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -29,152 +29,282 @@
 
 #include "bpy_app_build_options.h"
 
-static PyObject *make_build_options(void)
+static PyTypeObject BlenderAppBuildOptionsType;
+
+static PyStructSequence_Field app_builtopts_info_fields[] = {
+	/* names mostly follow CMake options, lowecases, after WITH_ */
+	{(char *)"bullet", NULL},
+	{(char *)"codec_avi", NULL},
+	{(char *)"codec_ffmpeg", NULL},
+	{(char *)"codec_quicktime", NULL},
+	{(char *)"codec_sndfile", NULL},
+	{(char *)"compositor", NULL},
+	{(char *)"cycles", NULL},
+	{(char *)"cycles_osl", NULL},
+	{(char *)"freestyle", NULL},
+	{(char *)"gameengine", NULL},
+	{(char *)"image_cineon", NULL},
+	{(char *)"image_dds", NULL},
+	{(char *)"image_frameserver", NULL},
+	{(char *)"image_hdr", NULL},
+	{(char *)"image_openexr", NULL},
+	{(char *)"image_openjpeg", NULL},
+	{(char *)"image_redcode", NULL},
+	{(char *)"image_tiff", NULL},
+	{(char *)"input_ndof", NULL},
+	{(char *)"audaspace", NULL},
+	{(char *)"international", NULL},
+	{(char *)"openal", NULL},
+	{(char *)"sdl", NULL},
+	{(char *)"jack", NULL},
+	{(char *)"libmv", NULL},
+	{(char *)"mod_boolean", NULL},
+	{(char *)"mod_fluid", NULL},
+	{(char *)"mod_oceansim", NULL},
+	{(char *)"mod_remesh", NULL},
+	{(char *)"mod_smoke", NULL},
+	{(char *)"collada", NULL},
+	{(char *)"opencolorio", NULL},
+	{(char *)"player", NULL},
+	{NULL}
+};
+
+
+static PyStructSequence_Desc app_builtopts_info_desc = {
+	(char *)"bpy.app.build_options",     /* name */
+	(char *)"This module contains information about FFmpeg blender is linked against",    /* doc */
+	app_builtopts_info_fields,    /* fields */
+	(sizeof(app_builtopts_info_fields) / sizeof(PyStructSequence_Field)) - 1
+};
+
+static PyObject *make_builtopts_info(void)
 {
-	PyObject *build_options = PyFrozenSet_New(NULL);
+	PyObject *builtopts_info;
+	int pos = 0;
 
-#define SetStrItem(str) \
-	PySet_Add(build_options, PyUnicode_FromString(str));
-
-#ifdef WITH_AUDASPACE
-	SetStrItem("AUDASPACE");
-#endif
-
-#ifdef WITH_BULLET
-	SetStrItem("BULLET");
-#endif
-
-#ifdef WITH_AVI
-	SetStrItem("CODEC_AVI");
-#endif
-
-#ifdef WITH_FFMPEG
-	SetStrItem("CODEC_FFMPEG");
-#endif
-
-#ifdef WITH_QUICKTIME
-	SetStrItem("CODEC_QUICKTIME");
-#endif
-
-#ifdef WITH_SNDFILE
-	SetStrItem("CODEC_SNDFILE");
-#endif
-
-#ifdef WITH_COMPOSITOR
-	SetStrItem("COMPOSITOR");
-#endif
-
-#ifdef WITH_CYCLES
-	SetStrItem("CYCLES");
-#endif
-
-#ifdef WITH_CYCLES_OSL
-	SetStrItem("CYCLES_OSL");
-#endif
-
-#ifdef WITH_FREESTYLE
-	SetStrItem("FREESTYLE");
-#endif
-
-#ifdef WITH_GAMEENGINE
-	SetStrItem("GAMEENGINE");
-#endif
-
-#ifdef WITH_CINEON
-	SetStrItem("IMAGE_CINEON");
-#endif
-
-#ifdef WITH_DDS
-	SetStrItem("IMAGE_DDS");
-#endif
-
-#ifdef WITH_FRAMESERVER
-	SetStrItem("IMAGE_FRAMESERVER");
-#endif
-
-#ifdef WITH_HDR
-	SetStrItem("IMAGE_HDR");
-#endif
-
-#ifdef WITH_OPENEXR
-	SetStrItem("IMAGE_OPENEXR");
-#endif
-
-#ifdef WITH_OPENJPEG
-	SetStrItem("IMAGE_OPENJPEG");
-#endif
-
-#ifdef WITH_REDCODE
-	SetStrItem("IMAGE_REDCODE");
-#endif
-
-#ifdef WITH_TIFF
-	SetStrItem("IMAGE_TIFF");
-#endif
-
-#ifdef WITH_INPUT_NDOF
-	SetStrItem("INPUT_NDOF");
-#endif
-
-#ifdef WITH_INTERNATIONAL
-	SetStrItem("INTERNATIONAL");
-#endif
-
-#ifdef WITH_JACK
-	SetStrItem("JACK");
-#endif
-
-#ifdef WITH_LIBMV
-	SetStrItem("LIBMV");
-#endif
-
-#ifdef WITH_MOD_BOOLEAN
-	SetStrItem("MOD_BOOLEAN");
-#endif
-
-#ifdef WITH_MOD_FLUID
-	SetStrItem("MOD_FLUID");
-#endif
-
-#ifdef WITH_OCEANSIM
-	SetStrItem("MOD_OCEANSIM");
-#endif
-
-#ifdef WITH_MOD_REMESH
-	SetStrItem("MOD_REMESH");
-#endif
-
-#ifdef WITH_SMOKE
-	SetStrItem("MOD_SMOKE");
-#endif
-
-#ifdef WITH_OPENAL
-	SetStrItem("OPENAL");
-#endif
-
-#ifdef WITH_COLLADA
-	SetStrItem("COLLADA");
-#endif
-
-#ifdef WITH_PLAYER
-	SetStrItem("PLAYER");
-#endif
-
-#undef SetStrItem
-
-	if (PyErr_Occurred()) {
-		Py_CLEAR(build_options);
+	builtopts_info = PyStructSequence_New(&BlenderAppBuildOptionsType);
+	if (builtopts_info == NULL) {
 		return NULL;
 	}
 
-	return build_options;
+#define SetObjIncref(item) \
+	PyStructSequence_SET_ITEM(builtopts_info, pos++, (Py_IncRef(item), item))
+
+#ifdef WITH_BULLET
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_AVI
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_FFMPEG
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_QUICKTIME
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_SNDFILE
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_COMPOSITOR
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_CYCLES
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_CYCLES_OSL
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_FREESTYLE
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_GAMEENGINE
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_CINEON
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_DDS
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_FRAMESERVER
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_HDR
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_OPENEXR
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_OPENJPEG
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_REDCODE
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_TIFF
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_INPUT_NDOF
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_AUDASPACE
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_INTERNATIONAL
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_OPENAL
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_SDL
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_JACK
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_LIBMV
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_MOD_BOOLEAN
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_MOD_FLUID
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_OCEANSIM
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_MOD_REMESH
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_SMOKE
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_COLLADA
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_OCIO
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_PLAYER
+	SetObjIncref(Py_True);
+#else
+	SetObjIncref(Py_False);
+#endif
+
+#undef SetObjIncref
+
+	return builtopts_info;
 }
 
 PyObject *BPY_app_build_options_struct(void)
 {
 	PyObject *ret;
 
-	ret = make_build_options();
+	PyStructSequence_InitType(&BlenderAppBuildOptionsType, &app_builtopts_info_desc);
+
+	ret = make_builtopts_info();
+
+	/* prevent user from creating new instances */
+	BlenderAppBuildOptionsType.tp_init = NULL;
+	BlenderAppBuildOptionsType.tp_new = NULL;
+	BlenderAppBuildOptionsType.tp_hash = (hashfunc)_Py_HashPointer; /* without this we can't do set(sys.modules) [#29635] */
 
 	return ret;
 }
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index cdecf64c93c..7bce8673943 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -44,6 +44,7 @@
 #include "bpy.h"
 #include "gpu.h"
 #include "bpy_rna.h"
+#include "bpy_path.h"
 #include "bpy_util.h"
 #include "bpy_traceback.h"
 #include "bpy_intern_string.h"
@@ -212,6 +213,7 @@ static struct _inittab bpy_internal_modules[] = {
 	{(char *)"mathutils", PyInit_mathutils},
 //	{(char *)"mathutils.geometry", PyInit_mathutils_geometry},
 //	{(char *)"mathutils.noise", PyInit_mathutils_noise},
+	{(char *)"_bpy_path", BPyInit__bpy_path},
 	{(char *)"bgl", BPyInit_bgl},
 	{(char *)"blf", BPyInit_blf},
 	{(char *)"bmesh", BPyInit_bmesh},
@@ -269,7 +271,8 @@ void BPY_python_start(int argc, const char **argv)
 	Py_Initialize();
 
 	/* THIS IS BAD: see http://bugs.python.org/issue16129 */
-#if 1
+	/* this clobbers the stdout on exit (no 'MEM_printmemlist_stats') */
+#if 0
 	/* until python provides a reliable way to set the env var */
 	PyRun_SimpleString("import sys, io\n"
 	                   "sys.__backup_stdio__ = sys.__stdout__, sys.__stderr__\n"  /* else we loose the FD's [#32720] */
@@ -817,7 +820,7 @@ typedef struct {
 } dealloc_obj;
 
 /* call once __file__ is set */
-void bpy_module_delay_init(PyObject *bpy_proxy)
+static void bpy_module_delay_init(PyObject *bpy_proxy)
 {
 	const int argc = 1;
 	const char *argv[2];
@@ -855,6 +858,9 @@ static void dealloc_obj_dealloc(PyObject *self)
 	dealloc_obj_Type.tp_free(self);
 }
 
+PyMODINIT_FUNC
+PyInit_bpy(void);
+
 PyMODINIT_FUNC
 PyInit_bpy(void)
 {
diff --git a/source/blender/python/intern/bpy_path.c b/source/blender/python/intern/bpy_path.c
new file mode 100644
index 00000000000..8df7ed2364f
--- /dev/null
+++ b/source/blender/python/intern/bpy_path.c
@@ -0,0 +1,65 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/intern/bpy_path.c
+ *  \ingroup pythonintern
+ *
+ * This file defines '_bpy_path' module, Some 'C' funtionality used by 'bpy.path'
+ */
+
+#include 
+
+#include "bpy_path.h"
+
+#include "../generic/py_capi_utils.h"
+
+/* #include "IMB_imbuf_types.h" */
+extern const char *imb_ext_image[];
+extern const char *imb_ext_movie[];
+extern const char *imb_ext_audio[];
+
+/*----------------------------MODULE INIT-------------------------*/
+static struct PyModuleDef _bpy_path_module_def = {
+	PyModuleDef_HEAD_INIT,
+	"_bpy_path",  /* m_name */
+	NULL,  /* m_doc */
+	0,  /* m_size */
+	NULL,  /* m_methods */
+	NULL,  /* m_reload */
+	NULL,  /* m_traverse */
+	NULL,  /* m_clear */
+	NULL,  /* m_free */
+};
+
+PyObject *BPyInit__bpy_path(void)
+{
+	PyObject *submodule;
+
+	submodule = PyModule_Create(&_bpy_path_module_def);
+
+	PyModule_AddObject(submodule, "extensions_image", PyC_FrozenSetFromStrings(imb_ext_image));
+	PyModule_AddObject(submodule, "extensions_movie", PyC_FrozenSetFromStrings(imb_ext_movie));
+	PyModule_AddObject(submodule, "extensions_audio", PyC_FrozenSetFromStrings(imb_ext_audio));
+
+	return submodule;
+}
+
diff --git a/intern/cycles/util/util_attribute.h b/source/blender/python/intern/bpy_path.h
similarity index 72%
rename from intern/cycles/util/util_attribute.h
rename to source/blender/python/intern/bpy_path.h
index 334864c7f44..a0f31202264 100644
--- a/intern/cycles/util/util_attribute.h
+++ b/source/blender/python/intern/bpy_path.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011, Blender Foundation.
+ * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -14,18 +14,20 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
  */
 
-#ifndef __UTIL_ATTRIBUTE_H__
-#define __UTIL_ATTRIBUTE_H__
+/** \file blender/python/intern/bpy_path.h
+ *  \ingroup pythonintern
+ */
 
-#include "util_types.h"
 
-CCL_NAMESPACE_BEGIN
+#ifndef __BPY_PATH_H__
+#define __BPY_PATH_H__
 
-const char *attribute_standard_name(AttributeStandard std);
-
-CCL_NAMESPACE_END
-
-#endif /* __UTIL_ATTRIBUTE_H__ */
+PyObject *BPyInit__bpy_path(void);
 
+#endif
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index bd033736865..57ddee0c8c0 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -1233,6 +1233,8 @@ BPY_PROPDEF_DESC_DOC
 "      For dynamic values a callback can be passed which returns a list in\n"
 "      the same format as the static list.\n"
 "      This function must take 2 arguments (self, context)\n"
+"      WARNING: Do not use generators here (they will work the first time, but will lead to empty values\n"
+"               in some unload/reload scenarii)!\n"
 "   :type items: sequence of string triplets or a function\n"
 BPY_PROPDEF_UPDATE_DOC
 );
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 2de477c46c3..bc245ecda5c 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -7373,8 +7373,9 @@ PyDoc_STRVAR(pyrna_register_class_doc,
 ".. method:: register_class(cls)\n"
 "\n"
 "   Register a subclass of a blender type in (:class:`bpy.types.Panel`,\n"
-"   :class:`bpy.types.Menu`, :class:`bpy.types.Header`, :class:`bpy.types.Operator`,\n"
-"   :class:`bpy.types.KeyingSetInfo`, :class:`bpy.types.RenderEngine`).\n"
+"   :class:`bpy.types.UIList`, :class:`bpy.types.Menu`, :class:`bpy.types.Header`,\n"
+"   :class:`bpy.types.Operator`, :class:`bpy.types.KeyingSetInfo`,\n"
+"   :class:`bpy.types.RenderEngine`).\n"
 "\n"
 "   If the class has a *register* class method it will be called\n"
 "   before registration.\n"
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index 69839514a12..0acfc36bb4e 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -44,6 +44,7 @@
 #include "BKE_fcurve.h"
 
 #include "RNA_access.h"
+#include "RNA_enum_types.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
@@ -147,14 +148,17 @@ static int pyrna_struct_anim_args_parse(
 /* internal use for insert and delete */
 static int pyrna_struct_keyframe_parse(
         PointerRNA *ptr, PyObject *args, PyObject *kw, const char *parse_str, const char *error_prefix,
-        const char **path_full, int *index, float *cfra, const char **group_name)     /* return values */
+        const char **path_full, int *index, float *cfra, const char **group_name, int *options)     /* return values */
 {
-	static const char *kwlist[] = {"data_path", "index", "frame", "group", NULL};
+	static const char *kwlist[] = {"data_path", "index", "frame", "group", "options", NULL};
+	PyObject *pyoptions = NULL;
 	const char *path;
 
-	/* note, parse_str MUST start with 's|ifs' */
-	if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name))
+	/* note, parse_str MUST start with 's|ifsO!' */
+	if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name,
+	                                 &PySet_Type, &pyoptions)) {
 		return -1;
+	}
 
 	if (pyrna_struct_anim_args_parse(ptr, error_prefix, path, path_full, index) < 0)
 		return -1;
@@ -162,6 +166,10 @@ static int pyrna_struct_keyframe_parse(
 	if (*cfra == FLT_MAX)
 		*cfra = CTX_data_scene(BPy_GetContext())->r.cfra;
 
+	/* flag may be null (no option currently for remove keyframes e.g.). */
+	if (pyoptions && options && (pyrna_set_to_enum_bitfield(keying_flag_items, pyoptions, options, error_prefix) < 0))
+		return -1;
+
 	return 0; /* success */
 }
 
@@ -172,12 +180,19 @@ char pyrna_struct_keyframe_insert_doc[] =
 "\n"
 "   :arg data_path: path to the property to key, analogous to the fcurve's data path.\n"
 "   :type data_path: string\n"
-"   :arg index: array index of the property to key. Defaults to -1 which will key all indices or a single channel if the property is not an array.\n"
+"   :arg index: array index of the property to key. Defaults to -1 which will key all indices or a single channel "
+               "if the property is not an array.\n"
 "   :type index: int\n"
 "   :arg frame: The frame on which the keyframe is inserted, defaulting to the current frame.\n"
 "   :type frame: float\n"
 "   :arg group: The name of the group the F-Curve should be added to if it doesn't exist yet.\n"
 "   :type group: str\n"
+"   :arg options: Some optional flags:\n"
+"                     'NEEDED': Only insert keyframes where they're needed in the relevant F-Curves.\n"
+"                     'VISUAL': Insert keyframes based on 'visual transforms'.\n"
+"                     'XYZ_TO_RGB': Color for newly added transformation F-Curves (Location, Rotation, Scale) "
+                                   "and also Color is based on the transform axis.\n"
+"   :type flag: set\n"
 "   :return: Success of keyframe insertion.\n"
 "   :rtype: boolean\n"
 ;
@@ -188,12 +203,13 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
 	int index = -1;
 	float cfra = FLT_MAX;
 	const char *group_name = NULL;
+	int options = 0;
 
 	PYRNA_STRUCT_CHECK_OBJ(self);
 
 	if (pyrna_struct_keyframe_parse(&self->ptr, args, kw,
-	                                "s|ifs:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()",
-	                                &path_full, &index, &cfra, &group_name) == -1)
+	                                "s|ifsO!:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()",
+	                                &path_full, &index, &cfra, &group_name, &options) == -1)
 	{
 		return NULL;
 	}
@@ -203,7 +219,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb
 
 		BKE_reports_init(&reports, RPT_STORE);
 
-		result = insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0);
+		result = insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, options);
 		MEM_freeN((void *)path_full);
 
 		if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1)
@@ -240,9 +256,9 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb
 	PYRNA_STRUCT_CHECK_OBJ(self);
 
 	if (pyrna_struct_keyframe_parse(&self->ptr, args, kw,
-	                                "s|ifs:bpy_struct.keyframe_delete()",
+	                                "s|ifsO!:bpy_struct.keyframe_delete()",
 	                                "bpy_struct.keyframe_insert()",
-	                                &path_full, &index, &cfra, &group_name) == -1)
+	                                &path_full, &index, &cfra, &group_name, NULL) == -1)
 	{
 		return NULL;
 	}
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index d2ffc3a0e26..64135a16f5d 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -61,6 +61,7 @@ struct Scene;
 #define RE_ENGINE_DO_DRAW		4
 #define RE_ENGINE_DO_UPDATE		8
 #define RE_ENGINE_RENDERING		16
+#define RE_ENGINE_HIGHLIGHT_TILES	32
 
 extern ListBase R_engines;
 
@@ -130,5 +131,7 @@ void RE_engines_exit(void);
 
 RenderEngineType *RE_engines_find(const char *idname);
 
+void RE_engine_get_current_tiles(struct Render *re, int *total_tiles_r, rcti **tiles_r);
+
 #endif /* __RE_ENGINE_H__ */
 
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 5d61417cbaf..61b39a59b0b 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -91,7 +91,7 @@ void render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd
 	struct ImBuf *ibuf);
 
 void render_result_rect_fill_zero(struct RenderResult *rr);
-void render_result_rect_get_pixels(struct RenderResult *rr, struct RenderData *rd,
+void render_result_rect_get_pixels(struct RenderResult *rr,
 	unsigned int *rect, int rectx, int recty,
 	const struct ColorManagedViewSettings *view_settings,
 	const struct ColorManagedDisplaySettings *display_settings);
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index c45c6dfc1bc..3b8cd3c6aa5 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -104,13 +104,19 @@ typedef struct RenderPart {
 
 	rcti disprect;					/* part coordinates within total picture */
 	int rectx, recty;				/* the size */
-	short crop, ready;				/* crop is amount of pixels we crop, for filter */
+	short crop, status;				/* crop is amount of pixels we crop, for filter */
 	short sample, nr;				/* sample can be used by zbuffers, nr is partnr */
 	short thread;					/* thread id */
 	
 	char *clipflag;					/* clipflags for part zbuffering */
 } RenderPart;
 
+enum {
+	PART_STATUS_NONE        = 0,
+	PART_STATUS_IN_PROGRESS = 1,
+	PART_STATUS_READY       = 2
+};
+
 /* controls state of render, everything that's read-only during render stage */
 struct Render
 {
diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h
index 24989b13c48..1e81ca20d03 100644
--- a/source/blender/render/intern/include/renderdatabase.h
+++ b/source/blender/render/intern/include/renderdatabase.h
@@ -59,12 +59,16 @@ typedef struct VertTableNode {
 	float *tangent;
 	float *stress;
 	float *winspeed;
+	/* Index of vertex in source mesh (before modifiers). */
+	int *origindex;
 } VertTableNode;
 
 typedef struct VlakTableNode {
 	struct VlakRen *vlak;
 	struct MTFace *mtface;
 	struct MCol *mcol;
+	/* Index of mpoly in source mesh (before tessellation). */
+	int *origindex;
 	int totmtface, totmcol;
 	float *surfnor;
 	float *tangent;
@@ -114,9 +118,11 @@ float *RE_vertren_get_rad(struct ObjectRen *obr, struct VertRen *ver, int verify
 float *RE_vertren_get_strand(struct ObjectRen *obr, struct VertRen *ver, int verify);
 float *RE_vertren_get_tangent(struct ObjectRen *obr, struct VertRen *ver, int verify);
 float *RE_vertren_get_winspeed(struct ObjectInstanceRen *obi, struct VertRen *ver, int verify);
+int *RE_vertren_get_origindex(struct ObjectRen *obr, VertRen *ver, int verify);
 
 struct MTFace *RE_vlakren_get_tface(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify);
 struct MCol *RE_vlakren_get_mcol(struct ObjectRen *obr, VlakRen *ren, int n, char **name, int verify);
+int *RE_vlakren_get_origindex(struct ObjectRen *obr, VlakRen *vlak, int verify);
 float *RE_vlakren_get_surfnor(struct ObjectRen *obr, VlakRen *ren, int verify);
 float *RE_vlakren_get_nmap_tangent(struct ObjectRen *obr, VlakRen *ren, int verify);
 RadFace **RE_vlakren_get_radface(struct ObjectRen *obr, VlakRen *ren, int verify);
diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp
index f9ed012b117..01e592cba0c 100644
--- a/source/blender/render/intern/raytrace/rayobject_instance.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp
@@ -173,13 +173,13 @@ static int  RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
 
 static void RE_rayobject_instance_free(RayObject *o)
 {
-	InstanceRayObject *obj = (InstanceRayObject*)o;
+	InstanceRayObject *obj = (InstanceRayObject *)o;
 	MEM_freeN(obj);
 }
 
 static float RE_rayobject_instance_cost(RayObject *o)
 {
-	InstanceRayObject *obj = (InstanceRayObject*)o;
+	InstanceRayObject *obj = (InstanceRayObject *)o;
 	return RE_rayobject_cost(obj->target) + RE_COST_INSTANCE;
 }
 
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index cfa6bb0b11d..74aab678ea8 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -164,7 +164,7 @@ static HaloRen *initstar(Render *re, ObjectRen *obr, const float vec[3], float h
  */
 
 void RE_make_stars(Render *re, Scene *scenev3d, void (*initfunc)(void),
-                   void (*vertexfunc)(float*),  void (*termfunc)(void))
+                   void (*vertexfunc)(float *),  void (*termfunc)(void))
 {
 	extern unsigned char hash[512];
 	ObjectRen *obr= NULL;
@@ -3258,7 +3258,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
 	CustomDataMask mask;
 	float xn, yn, zn,  imat[3][3], mat[4][4];  //nor[3],
 	float *orco=0;
-	int need_orco=0, need_stress=0, need_nmap_tangent=0, need_tangent=0;
+	int need_orco=0, need_stress=0, need_nmap_tangent=0, need_tangent=0, need_origindex=0;
 	int a, a1, ok, vertofs;
 	int end, do_autosmooth = FALSE, totvert = 0;
 	int use_original_normals = FALSE;
@@ -3308,6 +3308,10 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
 		need_nmap_tangent= 1;
 	}
 	
+	/* origindex currently only used when baking to vertex colors */
+	if(re->flag & R_BAKING && re->r.bake_flag & R_BAKE_VCOL)
+		need_origindex= 1;
+
 	/* check autosmooth and displacement, we then have to skip only-verts optimize */
 	do_autosmooth |= (me->flag & ME_AUTOSMOOTH);
 	if (do_autosmooth)
@@ -3345,6 +3349,15 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
 		make_render_halos(re, obr, me, totvert, mvert, ma, orco);
 	}
 	else {
+		const int *index_vert_orig = NULL;
+		const int *index_mf_to_mpoly = NULL;
+		const int *index_mp_to_orig = NULL;
+		if (need_origindex) {
+			index_vert_orig = dm->getVertDataArray(dm, CD_ORIGINDEX);
+			/* double lookup for faces -> polys */
+			index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+			index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+		}
 
 		for (a=0; atotvert++);
@@ -3361,6 +3374,18 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
 				ver->orco= orco;
 				orco+=3;
 			}
+
+			if (need_origindex) {
+				int *origindex;
+				origindex = RE_vertren_get_origindex(obr, ver, 1);
+
+				/* Use orig index array if it's available (e.g. in the presence
+				 * of modifiers). */
+				if (index_vert_orig)
+					*origindex = index_vert_orig[a];
+				else
+					*origindex = a;
+			}
 		}
 		
 		if (!timeoffset) {
@@ -3514,6 +3539,21 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
 										}
 									}
 								}
+
+								if (need_origindex) {
+									/* Find original index of mpoly for this tessface. Options:
+									   - Modified mesh; two-step look up from tessface -> modified mpoly -> original mpoly
+									   - OR Tesselated mesh; look up from tessface -> mpoly
+									   - OR Failsafe; tessface == mpoly. Could probably assert(false) in this case? */
+									int *origindex;
+									origindex = RE_vlakren_get_origindex(obr, vlr, 1);
+									if (index_mf_to_mpoly && index_mp_to_orig)
+										*origindex = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a);
+									else if (index_mf_to_mpoly)
+										*origindex = index_mf_to_mpoly[a];
+									else
+										*origindex = a;
+								}
 							}
 						}
 					}
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index 6fdf11ba48c..296c8b6eba8 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -150,6 +150,23 @@ void RE_engine_free(RenderEngine *engine)
 
 /* Render Results */
 
+static RenderPart *get_part_from_result(Render *re, RenderResult *result)
+{
+	RenderPart *pa;
+
+	for (pa = re->parts.first; pa; pa = pa->next) {
+		if (result->tilerect.xmin == pa->disprect.xmin - re->disprect.xmin &&
+		    result->tilerect.ymin == pa->disprect.ymin - re->disprect.ymin &&
+		    result->tilerect.xmax == pa->disprect.xmax - re->disprect.xmin &&
+		    result->tilerect.ymax == pa->disprect.ymax - re->disprect.ymin)
+		{
+			return pa;
+		}
+	}
+
+	return NULL;
+}
+
 RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername)
 {
 	Render *re = engine->re;
@@ -179,12 +196,19 @@ RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w,
 
 	/* can be NULL if we CLAMP the width or height to 0 */
 	if (result) {
+		RenderPart *pa;
+
 		BLI_addtail(&engine->fullresult, result);
 
 		result->tilerect.xmin += re->disprect.xmin;
 		result->tilerect.xmax += re->disprect.xmin;
 		result->tilerect.ymin += re->disprect.ymin;
 		result->tilerect.ymax += re->disprect.ymin;
+
+		pa = get_part_from_result(re, result);
+
+		if (pa)
+			pa->status = PART_STATUS_IN_PROGRESS;
 	}
 
 	return result;
@@ -203,7 +227,6 @@ void RE_engine_update_result(RenderEngine *engine, RenderResult *result)
 void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel)
 {
 	Render *re = engine->re;
-	RenderPart *pa;
 
 	if (!result) {
 		return;
@@ -212,15 +235,10 @@ void RE_engine_end_result(RenderEngine *engine, RenderResult *result, int cancel
 	/* merge. on break, don't merge in result for preview renders, looks nicer */
 	if (!cancel) {
 		/* for exr tile render, detect tiles that are done */
-		for (pa = re->parts.first; pa; pa = pa->next) {
-			if (result->tilerect.xmin == pa->disprect.xmin &&
-			    result->tilerect.ymin == pa->disprect.ymin &&
-			    result->tilerect.xmax == pa->disprect.xmax &&
-			    result->tilerect.ymax == pa->disprect.ymax)
-			{
-				pa->ready = 1;
-			}
-		}
+		RenderPart *pa = get_part_from_result(re, result);
+
+		if (pa)
+			pa->status = PART_STATUS_READY;
 
 		if (re->result->do_exr_tile)
 			render_result_exr_file_merge(re->result, result);
@@ -310,6 +328,47 @@ void RE_engine_report(RenderEngine *engine, int type, const char *msg)
 		BKE_report(engine->reports, type, msg);
 }
 
+void RE_engine_get_current_tiles(Render *re, int *total_tiles_r, rcti **tiles_r)
+{
+	RenderPart *pa;
+	int total_tiles = 0;
+	rcti *tiles = NULL;
+	int allocation_size = 0, allocation_step = BLENDER_MAX_THREADS;
+
+	if (re->engine && (re->engine->flag & RE_ENGINE_HIGHLIGHT_TILES) == 0) {
+		*total_tiles_r = 0;
+		*tiles_r = NULL;
+		return;
+	}
+
+	for (pa = re->parts.first; pa; pa = pa->next) {
+		if (pa->status == PART_STATUS_IN_PROGRESS) {
+			if (total_tiles >= allocation_size) {
+				if (tiles == NULL)
+					tiles = MEM_mallocN(allocation_step * sizeof(rcti), "current engine tiles");
+				else
+					tiles = MEM_reallocN(tiles, (total_tiles + allocation_step) * sizeof(rcti));
+
+				allocation_size += allocation_step;
+			}
+
+			tiles[total_tiles] = pa->disprect;
+
+			if (pa->crop) {
+				tiles[total_tiles].xmin += pa->crop;
+				tiles[total_tiles].ymin += pa->crop;
+				tiles[total_tiles].xmax -= pa->crop;
+				tiles[total_tiles].ymax -= pa->crop;
+			}
+
+			total_tiles++;
+		}
+	}
+
+	*total_tiles_r = total_tiles;
+	*tiles_r = tiles;
+}
+
 /* Render */
 
 int RE_engine_render(Render *re, int do_all)
@@ -354,9 +413,7 @@ int RE_engine_render(Render *re, int do_all)
 
 	if (!engine) {
 		engine = RE_engine_create(type);
-
-		if (persistent_data)
-			re->engine = engine;
+		re->engine = engine;
 	}
 
 	engine->flag |= RE_ENGINE_RENDERING;
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index 7c14e0e5465..4aaa6247478 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -102,6 +102,11 @@ static void ibuf_get_color(float col[4], struct ImBuf *ibuf, int x, int y)
 		col[1] = ((float)rect[1])*(1.0f/255.0f);
 		col[2] = ((float)rect[2])*(1.0f/255.0f);
 		col[3] = ((float)rect[3])*(1.0f/255.0f);
+
+		/* bytes are internally straight, however render pipeline seems to expect premul */
+		col[0] *= col[3];
+		col[1] *= col[3];
+		col[2] *= col[3];
 	}
 }
 
@@ -219,10 +224,8 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
 	}
 
 	/* keep this before interpolation [#29761] */
-	if (tex->imaflag & TEX_USEALPHA) {
-		if ((tex->imaflag & TEX_CALCALPHA) == 0) {
-			texres->talpha = TRUE;
-		}
+	if ((tex->imaflag & TEX_CALCALPHA) == 0) {
+		texres->talpha = TRUE;
 	}
 
 	/* interpolate */
@@ -710,9 +713,10 @@ static int ibuf_get_color_clip(float col[4], ImBuf *ibuf, int x, int y, int extf
 	}
 	else {
 		char *rect = (char *)(ibuf->rect + x + y*ibuf->x);
-		col[0] = rect[0]*(1.f/255.f);
-		col[1] = rect[1]*(1.f/255.f);
-		col[2] = rect[2]*(1.f/255.f);
+		float inv_alpha_fac = (1.0f / 255.0f) * rect[3] * (1.0f / 255.0f);
+		col[0] = rect[0] * inv_alpha_fac;
+		col[1] = rect[1] * inv_alpha_fac;
+		col[2] = rect[2] * inv_alpha_fac;
 		col[3] = clip ? 0.f : rect[3]*(1.f/255.f);
 	}
 	return clip;
@@ -1088,7 +1092,8 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
 	/* mipmap test */
 	image_mipmap_test(tex, ibuf);
 	
-	if ((tex->imaflag & TEX_USEALPHA) && ((tex->imaflag & TEX_CALCALPHA) == 0)) texres->talpha = 1;
+	if ((tex->imaflag & TEX_CALCALPHA) == 0)
+		texres->talpha = 1;
 	texr.talpha = texres->talpha;
 
 	if (tex->imaflag & TEX_IMAROT) {
@@ -1501,13 +1506,8 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
 	/* mipmap test */
 	image_mipmap_test(tex, ibuf);
 
-	if (tex->imaflag & TEX_USEALPHA) {
-		if (tex->imaflag & TEX_CALCALPHA) {
-			/* pass */
-		}
-		else {
-			texres->talpha = TRUE;
-		}
+	if ((tex->imaflag & TEX_CALCALPHA) == 0) {
+		texres->talpha = TRUE;
 	}
 	
 	texr.talpha= texres->talpha;
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index 9785edd3288..b8784685836 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -233,8 +233,8 @@ static void set_rast_triangle(const MBakeRast *bake_rast, const int x, const int
 
 	if (x >= 0 && x < w && y >= 0 && y < h) {
 		if ((bake_rast->texels[y * w + x]) == 0) {
-			flush_pixel(bake_rast->data, x, y);
 			bake_rast->texels[y * w + x] = FILTER_MASK_USED;
+			flush_pixel(bake_rast->data, x, y);
 		}
 	}
 }
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index c7c5fcf354f..43bada3b383 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -341,7 +341,7 @@ void RE_ResultGet32(Render *re, unsigned int *rect)
 	RenderResult rres;
 	
 	RE_AcquireResultImage(re, &rres);
-	render_result_rect_get_pixels(&rres, &re->r, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings);
+	render_result_rect_get_pixels(&rres, rect, re->rectx, re->recty, &re->scene->view_settings, &re->scene->display_settings);
 	RE_ReleaseResultImage(re);
 }
 
@@ -660,7 +660,9 @@ static int render_display_draw_enabled(Render *re)
 static void *do_part_thread(void *pa_v)
 {
 	RenderPart *pa = pa_v;
-	
+
+	pa->status = PART_STATUS_IN_PROGRESS;
+
 	/* need to return nicely all parts on esc */
 	if (R.test_break(R.tbh) == 0) {
 		
@@ -691,7 +693,7 @@ static void *do_part_thread(void *pa_v)
 		}
 	}
 	
-	pa->ready = 1;
+	pa->status = PART_STATUS_READY;
 	
 	return NULL;
 }
@@ -732,7 +734,7 @@ static RenderPart *find_next_pano_slice(Render *re, int *minx, rctf *viewplane)
 	
 	/* most left part of the non-rendering parts */
 	for (pa = re->parts.first; pa; pa = pa->next) {
-		if (pa->ready == 0 && pa->nr == 0) {
+		if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
 			if (pa->disprect.xmin < *minx) {
 				best = pa;
 				*minx = pa->disprect.xmin;
@@ -770,7 +772,7 @@ static RenderPart *find_next_part(Render *re, int minx)
 	
 	/* find center of rendered parts, image center counts for 1 too */
 	for (pa = re->parts.first; pa; pa = pa->next) {
-		if (pa->ready) {
+		if (pa->status == PART_STATUS_READY) {
 			centx += BLI_rcti_cent_x(&pa->disprect);
 			centy += BLI_rcti_cent_y(&pa->disprect);
 			tot++;
@@ -781,7 +783,7 @@ static RenderPart *find_next_part(Render *re, int minx)
 	
 	/* closest of the non-rendering parts */
 	for (pa = re->parts.first; pa; pa = pa->next) {
-		if (pa->ready == 0 && pa->nr == 0) {
+		if (pa->status == PART_STATUS_NONE && pa->nr == 0) {
 			long long int distx = centx - BLI_rcti_cent_x(&pa->disprect);
 			long long int disty = centy - BLI_rcti_cent_y(&pa->disprect);
 			distx = (long long int)sqrt(distx * distx + disty * disty);
@@ -838,7 +840,7 @@ static void threaded_tile_processor(Render *re)
 	
 	if (re->result == NULL)
 		return;
-	
+
 	/* warning; no return here without closing exr file */
 	
 	RE_parts_init(re, TRUE);
@@ -889,7 +891,7 @@ static void threaded_tile_processor(Render *re)
 		rendering = 0;
 		hasdrawn = 0;
 		for (pa = re->parts.first; pa; pa = pa->next) {
-			if (pa->ready) {
+			if (pa->status == PART_STATUS_READY) {
 				
 				BLI_remove_thread(&threads, pa);
 				
@@ -1108,7 +1110,7 @@ static void do_render_blur_3d(Render *re)
 		
 		blurfac = 1.0f / (float)(re->r.mblur_samples - blur);
 		
-		merge_renderresult_blur(rres, re->result, blurfac, re->r.alphamode & R_ALPHAKEY);
+		merge_renderresult_blur(rres, re->result, blurfac, FALSE);
 		if (re->test_break(re->tbh)) break;
 	}
 	
@@ -1253,7 +1255,7 @@ static void do_render_fields_blur_3d(Render *re)
 	Object *camera = RE_GetCamera(re);
 	/* also check for camera here */
 	if (camera == NULL) {
-		printf("ERROR: Cannot render, no camera\n");
+		BKE_report(re->reports, RPT_ERROR, "Cannot render, no camera");
 		G.is_break = TRUE;
 		return;
 	}
@@ -2209,7 +2211,7 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
 			}
 			else {
 				char name[FILE_MAX];
-				BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, FALSE);
+				BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, FALSE);
 
 				/* reports only used for Movie */
 				do_write_image_or_movie(re, bmain, scene, NULL, name);
@@ -2279,7 +2281,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
 		if (name_override)
 			BLI_strncpy(name, name_override, sizeof(name));
 		else
-			BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, TRUE);
+			BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, TRUE);
 		
 		if (re->r.im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
 			if (re->result) {
@@ -2307,7 +2309,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
 
 				if (BLI_testextensie(name, ".exr"))
 					name[strlen(name) - 4] = 0;
-				BKE_add_image_extension(name, R_IMF_IMTYPE_JPEG90);
+				BKE_add_image_extension(name, &imf);
 				ibuf->planes = 24;
 
 				IMB_colormanagement_imbuf_for_write(ibuf, TRUE, FALSE, &scene->view_settings,
@@ -2412,7 +2414,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
 			/* Touch/NoOverwrite options are only valid for image's */
 			if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) {
 				if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH))
-					BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, scene->r.im_format.imtype, scene->r.scemode & R_EXTENSION, TRUE);
+					BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra, &scene->r.im_format, scene->r.scemode & R_EXTENSION, TRUE);
 
 				if (scene->r.mode & R_NO_OVERWRITE && BLI_exists(name)) {
 					printf("skipping existing frame \"%s\"\n", name);
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index fb9eb59cbbf..bef5902588c 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -81,7 +81,7 @@ extern struct Render R;
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 static int test_break(void *data)
 {
-	Render *re = (Render*)data;
+	Render *re = (Render *)data;
 	return re->test_break(re->tbh);
 }
 
@@ -250,9 +250,9 @@ RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi)
 		//Create Ray cast accelaration structure
 		raytree = rayobject_create( re,  re->r.raytrace_structure, faces );
 		if (  (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) )
-			vlakprimitive = obr->rayprimitives = (VlakPrimitive*)MEM_callocN(faces*sizeof(VlakPrimitive), "ObjectRen primitives");
+			vlakprimitive = obr->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "ObjectRen primitives");
 		else
-			face = obr->rayfaces = (RayFace*)MEM_callocN(faces*sizeof(RayFace), "ObjectRen faces");
+			face = obr->rayfaces = (RayFace *)MEM_callocN(faces * sizeof(RayFace), "ObjectRen faces");
 
 		obr->rayobi = obi;
 		
@@ -345,10 +345,10 @@ static void makeraytree_single(Render *re)
 	raytree = re->raytree = rayobject_create( re, re->r.raytrace_structure, faces+special );
 
 	if ( (re->r.raytrace_options & R_RAYTRACE_USE_LOCAL_COORDS) ) {
-		vlakprimitive = re->rayprimitives = (VlakPrimitive*)MEM_callocN(faces*sizeof(VlakPrimitive), "Raytrace vlak-primitives");
+		vlakprimitive = re->rayprimitives = (VlakPrimitive *)MEM_callocN(faces * sizeof(VlakPrimitive), "Raytrace vlak-primitives");
 	}
 	else {
-		face = re->rayfaces	= (RayFace*)MEM_callocN(faces*sizeof(RayFace), "Render ray faces");
+		face = re->rayfaces	= (RayFace *)MEM_callocN(faces * sizeof(RayFace), "Render ray faces");
 	}
 	
 	for (obi=re->instancetable.first; obi; obi=obi->next)
@@ -496,8 +496,8 @@ static void shade_ray_set_derivative(ShadeInput *shi)
 
 void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
 {
-	ObjectInstanceRen *obi= (ObjectInstanceRen*)is->hit.ob;
-	VlakRen *vlr= (VlakRen*)is->hit.face;
+	ObjectInstanceRen *obi = (ObjectInstanceRen *)is->hit.ob;
+	VlakRen *vlr = (VlakRen *)is->hit.face;
 	
 	/* set up view vector */
 	copy_v3_v3(shi->view, is->dir);
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 1d84f0e5a94..0587b097f36 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -438,7 +438,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
 	rr->renrect.xmin = 0; rr->renrect.xmax = rectx - 2 * crop;
 	/* crop is one or two extra pixels rendered for filtering, is used for merging and display too */
 	rr->crop = crop;
-	
+
 	/* tilerect is relative coordinates within render disprect. do not subtract crop yet */
 	rr->tilerect.xmin = partrct->xmin - re->disprect.xmin;
 	rr->tilerect.xmax = partrct->xmax - re->disprect.xmin;
@@ -931,7 +931,7 @@ static void save_empty_result_tiles(Render *re)
 			IMB_exrtile_clear_channels(rl->exrhandle);
 		
 			for (pa = re->parts.first; pa; pa = pa->next) {
-				if (pa->ready == 0) {
+				if (pa->status != PART_STATUS_READY) {
 					int party = pa->disprect.ymin - re->disprect.ymin + pa->crop;
 					int partx = pa->disprect.xmin - re->disprect.xmin + pa->crop;
 					IMB_exrtile_write_channels(rl->exrhandle, partx, party, 0);
@@ -1084,8 +1084,7 @@ int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, c
 
 ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd)
 {
-	int flags = (rd->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE) ? IB_cm_predivide : 0;
-	ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, flags);
+	ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0);
 	
 	/* if not exists, BKE_imbuf_write makes one */
 	ibuf->rect = (unsigned int *)rr->rect32;
@@ -1155,17 +1154,15 @@ void render_result_rect_fill_zero(RenderResult *rr)
 		rr->rect32 = MEM_callocN(sizeof(int) * rr->rectx * rr->recty, "render_seq rect");
 }
 
-void render_result_rect_get_pixels(RenderResult *rr, RenderData *rd, unsigned int *rect, int rectx, int recty,
+void render_result_rect_get_pixels(RenderResult *rr, unsigned int *rect, int rectx, int recty,
                                    const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings)
 {
 	if (rr->rect32) {
 		memcpy(rect, rr->rect32, sizeof(int) * rr->rectx * rr->recty);
 	}
 	else if (rr->rectf) {
-		int predivide = (rd->color_mgt_flag & R_COLOR_MANAGEMENT_PREDIVIDE);
-
 		IMB_display_buffer_transform_apply((unsigned char *) rect, rr->rectf, rr->rectx, rr->recty, 4,
-		                                   view_settings, display_settings, predivide);
+		                                   view_settings, display_settings, TRUE);
 	}
 	else
 		/* else fill with black */
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index bd0061c0e68..14586f16478 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -20,6 +20,7 @@
  *
  * Contributors: Hos, Robert Wenzlaff.
  * Contributors: 2004/2005/2006 Blender Foundation, full recode
+ * Contributors: Vertex color baking, Copyright 2011 AutoCRC
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -51,9 +52,12 @@
 #include "DNA_image_types.h"
 #include "DNA_lamp_types.h"
 #include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 #include "DNA_group_types.h"
 
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
 #include "BKE_global.h"
 #include "BKE_image.h"
 #include "BKE_main.h"
@@ -710,9 +714,11 @@ static void sky_tile(RenderPart *pa, RenderLayer *rl)
 					
 					if (pass[3]==0.0f) {
 						copy_v4_v4(pass, col);
+						pass[3] = 1.0f;
 					}
 					else {
 						addAlphaUnderFloat(pass, col);
+						pass[3] = 1.0f;
 					}
 				}
 			}
@@ -981,29 +987,6 @@ static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect)
 	}
 }
 
-static void convert_to_key_alpha(RenderPart *pa, RenderLayer *rl)
-{
-	RenderLayer *rlpp[RE_MAX_OSA];
-	int y, sample, totsample;
-	
-	totsample= get_sample_layers(pa, rl, rlpp);
-	
-	for (sample= 0; samplerectf;
-		
-		for (y= pa->rectx*pa->recty; y>0; y--, rectf+=4) {
-			if (rectf[3] >= 1.0f) {
-				/* pass */
-			}
-			else if (rectf[3] > 0.0f) {
-				rectf[0] /= rectf[3];
-				rectf[1] /= rectf[3];
-				rectf[2] /= rectf[3];
-			}
-		}
-	}
-}
-
 /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */
 static void clamp_alpha_rgb_range(RenderPart *pa, RenderLayer *rl)
 {
@@ -1172,7 +1155,7 @@ typedef struct ZbufSolidData {
 
 static void make_pixelstructs(RenderPart *pa, ZSpan *zspan, int sample, void *data)
 {
-	ZbufSolidData *sdata= (ZbufSolidData*)data;
+	ZbufSolidData *sdata = (ZbufSolidData *)data;
 	ListBase *lb= sdata->psmlist;
 	intptr_t *rd= pa->rectdaps;
 	int *ro= zspan->recto;
@@ -1312,10 +1295,6 @@ void zbufshadeDA_tile(RenderPart *pa)
 		/* clamp alpha to 0..1 range, can go outside due to filter */
 		clamp_alpha_rgb_range(pa, rl);
 		
-		/* de-premul alpha */
-		if (R.r.alphamode & R_ALPHAKEY)
-			convert_to_key_alpha(pa, rl);
-		
 		/* free stuff within loop! */
 		MEM_freeN(pa->rectdaps); pa->rectdaps= NULL;
 		freeps(&psmlist);
@@ -1476,10 +1455,6 @@ void zbufshade_tile(RenderPart *pa)
 		if (rl->passflag & SCE_PASS_VECTOR)
 			reset_sky_speed(pa, rl);
 		
-		/* de-premul alpha */
-		if (R.r.alphamode & R_ALPHAKEY)
-			convert_to_key_alpha(pa, rl);
-		
 		if (edgerect) MEM_freeN(edgerect);
 		edgerect= NULL;
 
@@ -1740,7 +1715,7 @@ void zbufshade_sss_tile(RenderPart *pa)
 #if 0
 			if (rs) {
 				/* for each sample in this pixel, shade it */
-				for (ps=(PixStr*)*rs; ps; ps=ps->next) {
+				for (ps = (PixStr *)(*rs); ps; ps=ps->next) {
 					ObjectInstanceRen *obi= &re->objectinstance[ps->obi];
 					ObjectRen *obr= obi->obr;
 					vlr= RE_findOrAddVlak(obr, (ps->facenr-1) & RE_QUAD_MASK);
@@ -2032,6 +2007,12 @@ typedef struct BakeShade {
 
 	float dir[3];
 	Object *actob;
+
+	/* Output: vertex color or image data. If vcol is not NULL, rect and
+	 * rect_float should be NULL. */
+	MPoly *mpoly;
+	MLoop *mloop;
+	MLoopCol *vcol;
 	
 	unsigned int *rect;
 	float *rect_float;
@@ -2208,7 +2189,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua
 		}
 	}
 	
-	if (bs->rect_float) {
+	if (bs->rect_float && !bs->vcol) {
 		float *col= bs->rect_float + 4*(bs->rectx*y + x);
 		copy_v3_v3(col, shr.combined);
 		if (bs->type==RE_BAKE_ALL || bs->type==RE_BAKE_TEXTURE) {
@@ -2219,7 +2200,8 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua
 		}
 	}
 	else {
-		unsigned char *col= (unsigned char *)(bs->rect + bs->rectx*y + x);
+		/* Target is char (LDR). */
+		unsigned char col[4];
 
 		if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE)) {
 			float rgb[3];
@@ -2239,6 +2221,19 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua
 		else {
 			col[3]= 255;
 		}
+
+		if (bs->vcol) {
+			/* Vertex colour baking. Vcol has no useful alpha channel (it exists
+			 * but is used only for vertex painting). */
+			bs->vcol->r = col[0];
+			bs->vcol->g = col[1];
+			bs->vcol->b = col[2];
+		}
+		else {
+			unsigned char *imcol= (unsigned char *)(bs->rect + bs->rectx*y + x);
+			copy_v4_v4_char((char *)imcol, (char *)col);
+		}
+
 	}
 	
 	if (bs->rect_mask) {
@@ -2258,15 +2253,28 @@ static void bake_displacement(void *handle, ShadeInput *UNUSED(shi), float dist,
 		disp = 0.5f + dist; /* alter the range from [-0.5,0.5] to [0,1]*/
 	}
 	
-	if (bs->rect_float) {
+	if (bs->rect_float && !bs->vcol) {
 		float *col= bs->rect_float + 4*(bs->rectx*y + x);
 		col[0] = col[1] = col[2] = disp;
 		col[3]= 1.0f;
 	}
 	else {
-		char *col= (char *)(bs->rect + bs->rectx*y + x);
+		/* Target is char (LDR). */
+		unsigned char col[4];
 		col[0] = col[1] = col[2] = FTOCHAR(disp);
-		col[3]= 255;
+		col[3] = 255;
+
+		if(bs->vcol) {
+			/* Vertex colour baking. Vcol has no useful alpha channel (it exists
+			 * but is used only for vertex painting). */
+			bs->vcol->r = col[0];
+			bs->vcol->g = col[1];
+			bs->vcol->b = col[2];
+		}
+		else {
+			char *imcol= (char *)(bs->rect + bs->rectx*y + x);
+			copy_v4_v4_char((char *)imcol, (char *)col);
+		}
 	}
 	if (bs->rect_mask) {
 		bs->rect_mask[bs->rectx*y + x] = FILTER_MASK_USED;
@@ -2461,8 +2469,8 @@ static void do_bake_shade(void *handle, int x, int y, float u, float v)
 
 		/* if hit, we shade from the new point, otherwise from point one starting face */
 		if (hit) {
-			obi= (ObjectInstanceRen*)minisec.hit.ob;
-			vlr= (VlakRen*)minisec.hit.face;
+			obi = (ObjectInstanceRen *)minisec.hit.ob;
+			vlr = (VlakRen *)minisec.hit.face;
 			quad= (minisec.isect == 2);
 			copy_v3_v3(shi->co, minco);
 			
@@ -2502,13 +2510,55 @@ static int get_next_bake_face(BakeShade *bs)
 			vlr= RE_findOrAddVlak(obr, v);
 
 			if ((bs->actob && bs->actob == obr->ob) || (!bs->actob && (obr->ob->flag & SELECT))) {
-				tface= RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
+				if(R.r.bake_flag & R_BAKE_VCOL) {
+					/* Gather face data for vertex colour bake */
+					Mesh *me;
+					int *origindex, vcollayer;
+					CustomDataLayer *cdl;
 
-				if (tface && tface->tpage) {
-					Image *ima= tface->tpage;
-					ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL);
+					if(obr->ob->type != OB_MESH)
+						continue;
+					me = obr->ob->data;
+
+					origindex = RE_vlakren_get_origindex(obr, vlr, 0);
+					if(origindex == NULL)
+						continue;
+					if (*origindex >= me->totpoly) {
+						/* Small hack for Array modifier, which gives false
+						   original indices - z0r */
+						continue;
+					}
+#if 0
+					/* Only shade selected faces. */
+					if((me->mface[*origindex].flag & ME_FACE_SEL) == 0)
+						continue;
+#endif
+
+					vcollayer = CustomData_get_render_layer_index(&me->ldata, CD_MLOOPCOL);
+					if(vcollayer == -1)
+						continue;
+
+					cdl = &me->ldata.layers[vcollayer];
+					bs->mpoly = me->mpoly + *origindex;
+					bs->vcol = ((MLoopCol*)cdl->data) + bs->mpoly->loopstart;
+					bs->mloop = me->mloop + bs->mpoly->loopstart;
+
+					/* Tag mesh for reevaluation. */
+					DAG_id_tag_update(&me->id, 0);
+				}
+				else {
+					Image *ima = NULL;
+					ImBuf *ibuf = NULL;
 					const float vec_alpha[4]= {0.0f, 0.0f, 0.0f, 0.0f};
 					const float vec_solid[4]= {0.0f, 0.0f, 0.0f, 1.0f};
+
+					tface= RE_vlakren_get_tface(obr, vlr, obr->bakemtface, NULL, 0);
+
+					if (!tface || !tface->tpage)
+						continue;
+
+					ima = tface->tpage;
+					ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
 					
 					if (ibuf==NULL)
 						continue;
@@ -2544,20 +2594,17 @@ static int get_next_bake_face(BakeShade *bs)
 						R.bakebuf= ima;
 					}
 
+					/* Tag image for redraw. */
 					ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
-					bs->obi= obi;
-					bs->vlr= vlr;
-					
-					bs->vdone++;	/* only for error message if nothing was rendered */
-					v++;
-					
-					BLI_unlock_thread(LOCK_CUSTOM1);
-
 					BKE_image_release_ibuf(ima, ibuf, NULL);
-
-					return 1;
 				}
+
+				bs->obi = obi;
+				bs->vlr = vlr;
+				bs->vdone++;	/* only for error message if nothing was rendered */
+				v++;
+				BLI_unlock_thread(LOCK_CUSTOM1);
+				return 1;
 			}
 		}
 	}
@@ -2566,6 +2613,73 @@ static int get_next_bake_face(BakeShade *bs)
 	return 0;
 }
 
+static void bake_single_vertex(BakeShade *bs, VertRen *vert, float u, float v)
+{
+	int *origindex, i;
+	MLoopCol *basevcol;
+	MLoop *mloop;
+
+	origindex = RE_vertren_get_origindex(bs->obi->obr, vert, 0);
+	if (!origindex || *origindex == ORIGINDEX_NONE)
+		return;
+
+	/* Search for matching vertex index and apply shading. */
+	for (i = 0; i < bs->mpoly->totloop; i++) {
+		mloop = bs->mloop + i;
+		if (mloop->v != *origindex)
+			continue;
+		basevcol = bs->vcol;
+		bs->vcol = basevcol + i;
+		do_bake_shade(bs, 0, 0, u, v);
+		bs->vcol = basevcol;
+		break;
+	}
+}
+
+/* Bake all vertices of a face. Actually, this still works on a face-by-face
+   basis, and each vertex on each face is shaded. Vertex colors are a property
+   of loops, not vertices. */
+static void shade_verts(BakeShade *bs)
+{
+	VlakRen *vlr = bs->vlr;
+
+	/* Disable baking to image; write to vcol instead. vcol pointer is set in
+	 * bake_single_vertex. */
+	bs->ima = NULL;
+	bs->rect = NULL;
+	bs->rect_float = NULL;
+
+	bs->quad = 0;
+
+	/* No anti-aliasing for vertices. */
+	zero_v3(bs->dxco);
+	zero_v3(bs->dyco);
+
+	/* Shade each vertex of the face. u and v are barycentric coordinates; since
+	   we're only interested in vertices, these will be 0 or 1. */
+	if ((vlr->flag & R_FACE_SPLIT) == 0) {
+		/* Processing triangle face, whole quad, or first half of split quad. */
+
+		bake_single_vertex(bs, bs->vlr->v1, 1.0f, 0.0f);
+		bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f);
+		bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f);
+
+		if (vlr->v4) {
+			bs->quad = 1;
+			bake_single_vertex(bs, bs->vlr->v4, 0.0f, 0.0f);
+		}
+	}
+	else {
+		/* Processing second half of split quad. Only one vertex to go. */
+		if (vlr->flag & R_DIVIDE_24) {
+			bake_single_vertex(bs, bs->vlr->v2, 0.0f, 1.0f);
+		}
+		else {
+			bake_single_vertex(bs, bs->vlr->v3, 0.0f, 0.0f);
+		}
+	}
+}
+
 /* already have tested for tface and ima and zspan */
 static void shade_tface(BakeShade *bs)
 {
@@ -2593,6 +2707,7 @@ static void shade_tface(BakeShade *bs)
 	bs->rect= bs->ibuf->rect;
 	bs->rect_colorspace= bs->ibuf->rect_colorspace;
 	bs->rect_float= bs->ibuf->rect_float;
+	bs->vcol = NULL;
 	bs->quad= 0;
 	
 	if (bs->use_mask) {
@@ -2636,7 +2751,10 @@ static void *do_bake_thread(void *bs_v)
 	BakeShade *bs= bs_v;
 	
 	while (get_next_bake_face(bs)) {
-		shade_tface(bs);
+		if (R.r.bake_flag & R_BAKE_VCOL)
+			shade_verts(bs);
+		else
+			shade_tface(bs);
 		
 		/* fast threadsafe break test */
 		if (R.test_break(R.tbh))
@@ -2700,14 +2818,16 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
 		use_mask = TRUE;
 	
 	/* baker uses this flag to detect if image was initialized */
-	for (ima= G.main->image.first; ima; ima= ima->id.next) {
-		ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL);
-		ima->id.flag |= LIB_DOIT;
-		ima->flag&= ~IMA_USED_FOR_RENDER;
-		if (ibuf) {
-			ibuf->userdata = NULL; /* use for masking if needed */
+	if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
+		for (ima = G.main->image.first; ima; ima = ima->id.next) {
+			ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+			ima->id.flag |= LIB_DOIT;
+			ima->flag &= ~IMA_USED_FOR_RENDER;
+			if (ibuf) {
+				ibuf->userdata = NULL; /* use for masking if needed */
+			}
+			BKE_image_release_ibuf(ima, ibuf, NULL);
 		}
-		BKE_image_release_ibuf(ima, ibuf, NULL);
 	}
 	
 	BLI_init_threads(&threads, do_bake_thread, re->r.threads);
@@ -2731,7 +2851,10 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
 		
 		handles[a].type= type;
 		handles[a].actob= actob;
-		handles[a].zspan= MEM_callocN(sizeof(ZSpan), "zspan for bake");
+		if (R.r.bake_flag & R_BAKE_VCOL)
+			handles[a].zspan = NULL;
+		else
+			handles[a].zspan = MEM_callocN(sizeof(ZSpan), "zspan for bake");
 		
 		handles[a].use_mask = use_mask;
 
@@ -2758,27 +2881,29 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up
 	}
 	
 	/* filter and refresh images */
-	for (ima= G.main->image.first; ima; ima= ima->id.next) {
-		if ((ima->id.flag & LIB_DOIT)==0) {
-			ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL);
+	if ((R.r.bake_flag & R_BAKE_VCOL) == 0) {
+		for (ima = G.main->image.first; ima; ima = ima->id.next) {
+			if ((ima->id.flag & LIB_DOIT)==0) {
+				ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
 
-			if (ima->flag & IMA_USED_FOR_RENDER)
-				result= BAKE_RESULT_FEEDBACK_LOOP;
+				if (ima->flag & IMA_USED_FOR_RENDER)
+					result = BAKE_RESULT_FEEDBACK_LOOP;
 
-			if (!ibuf)
-				continue;
+				if (!ibuf)
+					continue;
 
-			RE_bake_ibuf_filter(ibuf, (char *)ibuf->userdata, re->r.bake_filter);
+				RE_bake_ibuf_filter(ibuf, (char *)ibuf->userdata, re->r.bake_filter);
 
-			ibuf->userflags |= IB_BITMAPDIRTY;
-			BKE_image_release_ibuf(ima, ibuf, NULL);
+				ibuf->userflags |= IB_BITMAPDIRTY;
+				BKE_image_release_ibuf(ima, ibuf, NULL);
+			}
+		}
+
+		/* calculate return value */
+		for (a = 0; a < re->r.threads; a++) {
+			zbuf_free_span(handles[a].zspan);
+			MEM_freeN(handles[a].zspan);
 		}
-	}
-	
-	/* calculate return value */
-	for (a=0; ar.threads; a++) {
-		zbuf_free_span(handles[a].zspan);
-		MEM_freeN(handles[a].zspan);
 	}
 
 	MEM_freeN(handles);
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index e189d8bdaea..7ca4f01ae47 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -105,6 +105,8 @@
 #define RE_MTFACE_ELEMS		1
 #define RE_MCOL_ELEMS		4
 #define RE_UV_ELEMS			2
+#define RE_VLAK_ORIGINDEX_ELEMS	1
+#define RE_VERT_ORIGINDEX_ELEMS	1
 #define RE_SURFNOR_ELEMS	3
 #define RE_RADFACE_ELEMS	1
 #define RE_SIMPLIFY_ELEMS	2
@@ -192,10 +194,26 @@ float *RE_vertren_get_winspeed(ObjectInstanceRen *obi, VertRen *ver, int verify)
 	return winspeed + ver->index*RE_WINSPEED_ELEMS;
 }
 
+int *RE_vertren_get_origindex(ObjectRen *obr, VertRen *ver, int verify)
+{
+	int *origindex;
+	int nr= ver->index>>8;
+
+	origindex= obr->vertnodes[nr].origindex;
+	if (origindex==NULL) {
+		if (verify)
+			origindex= obr->vertnodes[nr].origindex= MEM_mallocN(256*RE_VERT_ORIGINDEX_ELEMS*sizeof(int), "origindex table");
+		else
+			return NULL;
+	}
+	return origindex + (ver->index & 255)*RE_VERT_ORIGINDEX_ELEMS;
+}
+
 VertRen *RE_vertren_copy(ObjectRen *obr, VertRen *ver)
 {
 	VertRen *v1= RE_findOrAddVert(obr, obr->totvert++);
 	float *fp1, *fp2;
+	int *int1, *int2;
 	int index= v1->index;
 	
 	*v1= *ver;
@@ -221,6 +239,11 @@ VertRen *RE_vertren_copy(ObjectRen *obr, VertRen *ver)
 		fp2= RE_vertren_get_tangent(obr, v1, 1);
 		memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float));
 	}
+	int1= RE_vertren_get_origindex(obr, ver, 0);
+	if (int1) {
+		int2= RE_vertren_get_origindex(obr, v1, 1);
+		memcpy(int2, int1, RE_VERT_ORIGINDEX_ELEMS*sizeof(int));
+	}
 	return v1;
 }
 
@@ -332,6 +355,21 @@ MCol *RE_vlakren_get_mcol(ObjectRen *obr, VlakRen *vlr, int n, char **name, int
 	return node->mcol + index*RE_MCOL_ELEMS;
 }
 
+int *RE_vlakren_get_origindex(ObjectRen *obr, VlakRen *vlak, int verify)
+{
+	int *origindex;
+	int nr= vlak->index>>8;
+
+	origindex= obr->vlaknodes[nr].origindex;
+	if(origindex==NULL) {
+		if(verify)
+			origindex= obr->vlaknodes[nr].origindex= MEM_callocN(256*RE_VLAK_ORIGINDEX_ELEMS*sizeof(int), "origindex table");
+		else
+			return NULL;
+	}
+	return origindex + (vlak->index & 255)*RE_VLAK_ORIGINDEX_ELEMS;
+}
+
 float *RE_vlakren_get_surfnor(ObjectRen *obr, VlakRen *vlak, int verify)
 {
 	float *surfnor;
@@ -370,7 +408,7 @@ RadFace **RE_vlakren_get_radface(ObjectRen *obr, VlakRen *vlak, int verify)
 	radface= obr->vlaknodes[nr].radface;
 	if (radface==NULL) {
 		if (verify) 
-			radface= obr->vlaknodes[nr].radface= MEM_callocN(256*RE_RADFACE_ELEMS*sizeof(void*), "radface table");
+			radface = obr->vlaknodes[nr].radface= MEM_callocN(256 * RE_RADFACE_ELEMS * sizeof(void *), "radface table");
 		else
 			return NULL;
 	}
@@ -383,6 +421,7 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
 	MTFace *mtface, *mtface1;
 	MCol *mcol, *mcol1;
 	float *surfnor, *surfnor1, *tangent, *tangent1;
+	int *origindex, *origindex1;
 	RadFace **radface, **radface1;
 	int i, index = vlr1->index;
 	char *name;
@@ -400,6 +439,13 @@ VlakRen *RE_vlakren_copy(ObjectRen *obr, VlakRen *vlr)
 		memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS);
 	}
 
+	origindex= RE_vlakren_get_origindex(obr, vlr, 0);
+	if(origindex) {
+		origindex1= RE_vlakren_get_origindex(obr, vlr1, 1);
+		/* Just an int, but memcpy for consistency. */
+		memcpy(origindex1, origindex, sizeof(int)*RE_VLAK_ORIGINDEX_ELEMS);
+	}
+
 	surfnor= RE_vlakren_get_surfnor(obr, vlr, 0);
 	if (surfnor) {
 		surfnor1= RE_vlakren_get_surfnor(obr, vlr1, 1);
@@ -725,6 +771,8 @@ void free_renderdata_vertnodes(VertTableNode *vertnodes)
 			MEM_freeN(vertnodes[a].stress);
 		if (vertnodes[a].winspeed)
 			MEM_freeN(vertnodes[a].winspeed);
+		if (vertnodes[a].origindex)
+			MEM_freeN(vertnodes[a].origindex);
 	}
 	
 	MEM_freeN(vertnodes);
@@ -743,6 +791,8 @@ void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
 			MEM_freeN(vlaknodes[a].mtface);
 		if (vlaknodes[a].mcol)
 			MEM_freeN(vlaknodes[a].mcol);
+		if(vlaknodes[a].origindex)
+			MEM_freeN(vlaknodes[a].origindex);
 		if (vlaknodes[a].surfnor)
 			MEM_freeN(vlaknodes[a].surfnor);
 		if (vlaknodes[a].tangent)
@@ -888,9 +938,9 @@ HaloRen *RE_findOrAddHalo(ObjectRen *obr, int nr)
 		//	TABLEINITSIZE, obr->blohalen+TABLEINITSIZE );
 		temp=obr->bloha;
 		
-		obr->bloha=(HaloRen**)MEM_callocN(sizeof(void*)*(obr->blohalen+TABLEINITSIZE), "Bloha");
-		if (temp) memcpy(obr->bloha, temp, obr->blohalen*sizeof(void*));
-		memset(&(obr->bloha[obr->blohalen]), 0, TABLEINITSIZE*sizeof(void*));
+		obr->bloha = (HaloRen**)MEM_callocN(sizeof(void *) * (obr->blohalen + TABLEINITSIZE), "Bloha");
+		if (temp) memcpy(obr->bloha, temp, obr->blohalen*sizeof(void *));
+		memset(&(obr->bloha[obr->blohalen]), 0, TABLEINITSIZE * sizeof(void *));
 		obr->blohalen+=TABLEINITSIZE;  /*Does this really need to be power of 2?*/
 		if (temp) MEM_freeN(temp);
 	}
diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c
index 078c11a2061..87912f546e8 100644
--- a/source/blender/render/intern/source/shadbuf.c
+++ b/source/blender/render/intern/source/shadbuf.c
@@ -812,7 +812,7 @@ void makeshadowbuf(Render *re, LampRen *lar)
 
 static void *do_shadow_thread(void *re_v)
 {
-	Render *re= (Render*)re_v;
+	Render *re = (Render *)re_v;
 	LampRen *lar;
 
 	do {
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c
index 569bac29205..a37ffb1eb28 100644
--- a/source/blender/render/intern/source/strand.c
+++ b/source/blender/render/intern/source/strand.c
@@ -522,7 +522,7 @@ static APixstrand *addpsAstrand(ZSpan *zspan)
 
 static void do_strand_fillac(void *handle, int x, int y, float u, float v, float z)
 {
-	StrandPart *spart= (StrandPart*)handle;
+	StrandPart *spart= (StrandPart *)handle;
 	StrandShadeCache *cache= spart->cache;
 	StrandSegment *sseg= spart->segment;
 	APixstrand *apn, *apnew;
diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c
index 549148f4e29..a9db197ed48 100644
--- a/source/blender/render/intern/source/volume_precache.c
+++ b/source/blender/render/intern/source/volume_precache.c
@@ -493,7 +493,7 @@ typedef struct VolPrecacheQueue {
  */
 static void *vol_precache_part(void *data)
 {
-	VolPrecacheQueue *queue = (VolPrecacheQueue*)data;
+	VolPrecacheQueue *queue = (VolPrecacheQueue *)data;
 	VolPrecachePart *pa;
 
 	while ((pa = BLI_thread_queue_pop(queue->work))) {
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 75ab0f5bcd7..eee4b5a3a57 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -62,6 +62,7 @@ struct MenuType;
 struct wmDropBox;
 struct wmDrag;
 struct ImBuf;
+struct ImageFormatData;
 
 typedef struct wmJob wmJob;
 
@@ -185,7 +186,7 @@ int			WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, struct wm
 int			WM_operator_confirm		(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
 		/* invoke callback, file selector "filepath" unset + exec */
 int			WM_operator_filesel		(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
-int         WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const char imtype);
+int         WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFormatData *im_format);
 			/* poll callback, context checks */
 int			WM_operator_winactive	(struct bContext *C);
 			/* invoke callback, exec + redo popup */
@@ -264,6 +265,13 @@ char		*WM_prop_pystring_assign(struct bContext *C, struct PointerRNA *ptr, struc
 void		WM_operator_bl_idname(char *to, const char *from);
 void		WM_operator_py_idname(char *to, const char *from);
 
+/* *************** uilist types ******************** */
+void                WM_uilisttype_init(void);
+struct uiListType  *WM_uilisttype_find(const char *idname, int quiet);
+int                 WM_uilisttype_add(struct uiListType *ult);
+void                WM_uilisttype_freelink(struct uiListType *ult);
+void                WM_uilisttype_free(void);
+
 /* *************** menu types ******************** */
 void                WM_menutype_init(void);
 struct MenuType    *WM_menutype_find(const char *idname, int quiet);
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 8fe387765ce..53e67e91bd2 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -149,7 +149,63 @@ void WM_operator_stack_clear(wmWindowManager *wm)
 	WM_main_add_notifier(NC_WM | ND_HISTORY, NULL);
 }
 
-/* ****************************************** */
+
+/* ************ uiListType handling ************** */
+
+static GHash *uilisttypes_hash = NULL;
+
+uiListType *WM_uilisttype_find(const char *idname, int quiet)
+{
+	uiListType *ult;
+
+	if (idname[0]) {
+		ult = BLI_ghash_lookup(uilisttypes_hash, idname);
+		if (ult) {
+			return ult;
+		}
+	}
+
+	if (!quiet) {
+		printf("search for unknown uilisttype %s\n", idname);
+	}
+
+	return NULL;
+}
+
+int WM_uilisttype_add(uiListType *ult)
+{
+	BLI_ghash_insert(uilisttypes_hash, (void *)ult->idname, ult);
+	return 1;
+}
+
+void WM_uilisttype_freelink(uiListType *ult)
+{
+	BLI_ghash_remove(uilisttypes_hash, ult->idname, NULL, (GHashValFreeFP)MEM_freeN);
+}
+
+/* called on initialize WM_init() */
+void WM_uilisttype_init(void)
+{
+	uilisttypes_hash = BLI_ghash_str_new("uilisttypes_hash gh");
+}
+
+void WM_uilisttype_free(void)
+{
+	GHashIterator *iter = BLI_ghashIterator_new(uilisttypes_hash);
+
+	for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
+		uiListType *ult = BLI_ghashIterator_getValue(iter);
+		if (ult->ext.free) {
+			ult->ext.free(ult->ext.data);
+		}
+	}
+	BLI_ghashIterator_free(iter);
+
+	BLI_ghash_free(uilisttypes_hash, NULL, (GHashValFreeFP)MEM_freeN);
+	uilisttypes_hash = NULL;
+}
+
+/* ************ MenuType handling ************** */
 
 static GHash *menutypes_hash = NULL;
 
diff --git a/source/blender/windowmanager/intern/wm_apple.c b/source/blender/windowmanager/intern/wm_apple.c
index a7bd43986dd..842fc353699 100644
--- a/source/blender/windowmanager/intern/wm_apple.c
+++ b/source/blender/windowmanager/intern/wm_apple.c
@@ -77,7 +77,7 @@ static int checkAppleVideoCard(void)
 					if ((theErr == 0) && (value != 0)) {
 						theErr = CGLDescribeRenderer(rend, j, kCGLRPCompliant, &value);
 						if ((theErr == 0) && (value != 0)) {
-							/*fprintf(stderr,"make it big\n");*/
+							/*fprintf(stderr, "make it big\n");*/
 							CGLDestroyRendererInfo(rend);
 							macPrefState = 8;
 							return 1;
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index e462e21d9f4..a6b3efd30bf 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -66,6 +66,8 @@
 
 #include "RNA_access.h"
 
+#include "BIF_gl.h"
+
 #include "UI_interface.h"
 
 #include "PIL_time.h"
@@ -338,7 +340,7 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve
 	ARegion *region = CTX_wm_region(C);
 	ARegion *menu = CTX_wm_menu(C);
 	static int do_wheel_ui = TRUE;
-	int is_wheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE);
+	int is_wheel = ELEM3(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN);
 	int retval;
 	
 	/* UI code doesn't handle return values - it just always returns break. 
@@ -2180,6 +2182,13 @@ void wm_event_do_handlers(bContext *C)
 
 	/* update key configuration after handling events */
 	WM_keyconfig_update(wm);
+
+	if (G.debug) {
+		GLenum error = glGetError();
+		if (error != GL_NO_ERROR) {
+			printf("GL error: %s\n", gluErrorString(error));
+		}
+	}
 }
 
 /* ********** filesector handling ************ */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 918068cc7d1..61699c94567 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -538,7 +538,7 @@ int wm_homefile_read(bContext *C, ReportList *UNUSED(reports), short from_memory
 	}
 	
 	if (U.themes.first == NULL) {
-		printf("\nError: No valid "STRINGIFY (BLENDER_STARTUP_FILE)", fall back to built-in default.\n\n");
+		printf("\nNote: No (valid) "STRINGIFY (BLENDER_STARTUP_FILE)" found, fall back to built-in default.\n\n");
 		success = 0;
 	}
 
@@ -556,7 +556,7 @@ int wm_homefile_read(bContext *C, ReportList *UNUSED(reports), short from_memory
 	/* check new prefs only after startup.blend was finished */
 	if (!from_memory && BLI_exists(prefstr)) {
 		int done = BKE_read_file_userdef(prefstr, NULL);
-		if (done) printf("read new prefs: %s\n", prefstr);
+		if (done) printf("Read new prefs: %s\n", prefstr);
 	}
 	
 	/* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 1cf44a69c17..168c2312d9f 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -258,7 +258,7 @@ static void draw_filled_lasso(wmGesture *gt)
 	if (sf_vert_first) {
 		const float zvec[3] = {0.0f, 0.0f, 1.0f};
 		BLI_scanfill_edge_add(&sf_ctx, sf_vert_first, sf_vert);
-		BLI_scanfill_calc_ex(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES, zvec);
+		BLI_scanfill_calc_ex(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES | BLI_SCANFILL_CALC_HOLES, zvec);
 	
 		glEnable(GL_BLEND);
 		glColor4f(1.0, 1.0, 1.0, 0.05);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 3cffa143ebc..de0da3df868 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -66,6 +66,7 @@
 #include "BKE_node.h"
 #include "BKE_report.h"
 
+#include "BKE_addon.h"
 #include "BKE_packedFile.h"
 #include "BKE_sequencer.h" /* free seq clipboard */
 #include "BKE_material.h" /* clear_matcopybuf */
@@ -135,8 +136,12 @@ void WM_init(bContext *C, int argc, const char **argv)
 		wm_init_cursor_data();
 	}
 	GHOST_CreateSystemPaths();
+
+	BKE_addon_pref_type_init();
+
 	wm_operatortype_init();
 	WM_menutype_init();
+	WM_uilisttype_init();
 
 	set_free_windowmanager_cb(wm_close_and_free);   /* library.c */
 	set_blender_test_break_cb(wm_window_testbreak); /* blender.c */
@@ -400,9 +405,12 @@ void WM_exit_ext(bContext *C, const short do_python)
 			ED_screen_exit(C, win, win->screen);
 		}
 	}
+
+	BKE_addon_pref_type_free();
 	wm_operatortype_free();
 	wm_dropbox_free();
 	WM_menutype_free();
+	WM_uilisttype_free();
 	
 	/* all non-screen and non-space stuff editors did, like editmode */
 	if (C)
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index b5f1d590f37..bfcd4b1e955 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -583,7 +583,7 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
 
 	for (link = lb.first; link; link = link->next) {
 		const char *identifier = link->data;
-		PointerRNA ctx_item_ptr = CTX_data_pointer_get(C, identifier);
+		PointerRNA ctx_item_ptr = {{0}}; // CTX_data_pointer_get(C, identifier);
 
 		if (ctx_item_ptr.type == NULL) {
 			continue;
@@ -976,14 +976,14 @@ int WM_operator_filesel(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 	}
 }
 
-int WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const char imtype)
+int WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFormatData *im_format)
 {
 	PropertyRNA *prop;
 	char filepath[FILE_MAX];
 	/* dont NULL check prop, this can only run on ops with a 'filepath' */
 	prop = RNA_struct_find_property(op->ptr, "filepath");
 	RNA_property_string_get(op->ptr, prop, filepath);
-	if (BKE_add_image_extension(filepath, imtype)) {
+	if (BKE_add_image_extension(filepath, im_format)) {
 		RNA_property_string_set(op->ptr, prop, filepath);
 		/* note, we could check for and update 'filename' here,
 		 * but so far nothing needs this. */
@@ -2129,8 +2129,11 @@ void wm_recover_last_session(bContext *C, ReportList *reports)
 		/* XXX bad global... fixme */
 		if (G.main->name[0])
 			G.file_loaded = 1;	/* prevents splash to show */
-		else
+		else {
 			G.relbase_valid = 0;
+			G.save_over = 0;    /* start with save preference untitled.blend */
+		}
+
 	}
 }
 
@@ -2168,7 +2171,7 @@ static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
 	WM_file_read(C, path, op->reports);
 
 	G.fileflags &= ~G_FILE_RECOVER;
-
+	
 	return OPERATOR_FINISHED;
 }
 
@@ -2426,9 +2429,8 @@ static int wm_console_toggle_op(bContext *UNUSED(C), wmOperator *UNUSED(op))
 
 static void WM_OT_console_toggle(wmOperatorType *ot)
 {
-	/* XXX Have to mark these for xgettext, as under linux they do not exists...
-	 *     And even worth, have to give the context as text, as xgettext doesn't expand macros. :( */
-	ot->name = CTX_N_("Operator" /* BLF_I18NCONTEXT_OPERATOR_DEFAULT */, "Toggle System Console");
+	/* XXX Have to mark these for xgettext, as under linux they do not exists... */
+	ot->name = CTX_N_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Toggle System Console");
 	ot->idname = "WM_OT_console_toggle";
 	ot->description = N_("Toggle System Console");
 	
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index be202a23d33..ec94501c8be 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -544,6 +544,7 @@ void WM_window_open_temp(bContext *C, rcti *position, int type)
 	}
 	
 	ED_screen_set(C, win->screen);
+	ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
 	
 	if (sa->spacetype == SPACE_IMAGE)
 		GHOST_SetTitle(win->ghostwin, IFACE_("Blender Render"));
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index c90bbaf8d6c..78a67a31e0f 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -53,6 +53,9 @@
 #define MOUSEX		4
 #define MOUSEY		5
 
+
+/* *** wmEvent.type *** */
+
 /* non-event, for example disabled timer */
 #define EVENT_NONE		0
 /* MOUSE : 0x00x */
@@ -154,8 +157,7 @@ enum {
 #define TIMERF			0x011F	/* last timer */
 
 /* test whether the event is timer event */
-#define ISTIMER(event)	(event >= TIMER && event <= TIMERF)
-
+#define ISTIMER(event_type)	(event_type >= TIMER && event_type <= TIMERF)
 
 /* standard keyboard */
 #define AKEY		'a'
@@ -289,29 +291,30 @@ enum {
 /* for event checks */
 	/* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */
 	/* UNUSED - see wm_eventmatch - BUG [#30479] */
-// #define ISTEXTINPUT(event)  (event >= ' ' && event <= 255)
+// #define ISTEXTINPUT(event_type)  (event_type >= ' ' && event_type <= 255)
+/* note, an alternative could be to check 'event->utf8_buf' */
 
 	/* test whether the event is a key on the keyboard */
-#define ISKEYBOARD(event)  (event >= ' ' && event <= 320)
+#define ISKEYBOARD(event_type)  (event_type >= ' ' && event_type <= 320)
 
 	/* test whether the event is a modifier key */
-#define ISKEYMODIFIER(event)  ((event >= LEFTCTRLKEY && event <= LEFTSHIFTKEY) || event == OSKEY)
+#define ISKEYMODIFIER(event_type)  ((event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) || event_type == OSKEY)
 
 	/* test whether the event is a mouse button */
-#define ISMOUSE(event)  (event >= LEFTMOUSE && event <= MOUSEROTATE)
+#define ISMOUSE(event_type)  (event_type >= LEFTMOUSE && event_type <= MOUSEROTATE)
 
 	/* test whether the event is tweak event */
-#define ISTWEAK(event)  (event >= EVT_TWEAK_L && event <= EVT_GESTURE)
+#define ISTWEAK(event_type)  (event_type >= EVT_TWEAK_L && event_type <= EVT_GESTURE)
 
 	/* test whether the event is a NDOF event */
-#define ISNDOF(event)  (event >= NDOF_MOTION && event < NDOF_LAST)
+#define ISNDOF(event_type)  (event_type >= NDOF_MOTION && event_type < NDOF_LAST)
 
 /* test whether event type is acceptable as hotkey, excluding modifiers */
-#define ISHOTKEY(event)                                           \
-	((ISKEYBOARD(event) || ISMOUSE(event) || ISNDOF(event)) &&    \
-	 (event != ESCKEY) &&                                         \
-	 (event >= LEFTCTRLKEY && event <= LEFTSHIFTKEY) == FALSE &&  \
-	 (event >= UNKNOWNKEY  && event <= GRLESSKEY) == FALSE)
+#define ISHOTKEY(event_type)                                                  \
+	((ISKEYBOARD(event_type) || ISMOUSE(event_type) || ISNDOF(event_type)) && \
+	 (event_type != ESCKEY) &&                                                \
+	 (event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) == FALSE &&    \
+	 (event_type >= UNKNOWNKEY  && event_type <= GRLESSKEY) == FALSE)
 
 /* **************** BLENDER GESTURE EVENTS (0x5000) **************** */
 
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 85bb07d6e83..d606605e8d5 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -149,6 +149,7 @@ endif()
 		bf_intern_raskter
 		bf_intern_opencolorio
 		bf_intern_opennl
+		extern_rangetree
 	)
 
 	if(WITH_MOD_CLOTH_ELTOPO)
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index f394290d952..71881a99419 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -207,9 +207,15 @@ void WM_operator_stack_clear(struct bContext *C) {}
 void WM_autosave_init(struct bContext *C) {}
 void WM_jobs_kill_all_except(struct wmWindowManager *wm) {}
 
-char *WM_clipboard_text_get(int selection) {return (char*)0;}
+char *WM_clipboard_text_get(int selection) {return (char *)0;}
 void WM_clipboard_text_set(char *buf, int selection) {}
 
+void                WM_uilisttype_init(void) {}
+struct uiListType  *WM_uilisttype_find(const char *idname, int quiet) {return (struct uiListType *)NULL;}
+int                 WM_uilisttype_add(struct uiListType *ult) {return 0;}
+void                WM_uilisttype_freelink(struct uiListType *ult) {}
+void                WM_uilisttype_free(void) {}
+
 struct wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id) {return (struct wmKeyMapItem *) NULL;}
 int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, struct wmEvent *event) {return 0;}
 void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) {}
@@ -407,6 +413,7 @@ void uiItemFullR(struct uiLayout *layout, struct PointerRNA *ptr, struct Propert
 void uiLayoutSetContextPointer(struct uiLayout *layout, char *name, struct PointerRNA *ptr) {}
 char *uiLayoutIntrospect(struct uiLayout *layout) {return (char *)NULL;}
 void UI_reinit_font(void) {}
+int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, int big) {return 0;}
 
 /* rna template */
 void uiTemplateAnyID(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, char *text) {}
@@ -421,7 +428,9 @@ void uiTemplateCurveMapping(struct uiLayout *layout, struct CurveMapping *cumap,
 void uiTemplateColorRamp(struct uiLayout *layout, struct ColorBand *coba, int expand) {}
 void uiTemplateLayers(struct uiLayout *layout, struct PointerRNA *ptr, char *propname) {}
 void uiTemplateImageLayers(struct uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser) {}
-ListBase uiTemplateList(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, struct PointerRNA *activeptr, char *activepropname, int rows, int listtype) {struct ListBase b = {0,0}; return b;}
+void uiTemplateList(struct uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id,
+                    PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr,
+                    const char *active_propname, int rows, int maxrows, int layout_type) {}
 void uiTemplateRunningJobs(struct uiLayout *layout, struct bContext *C) {}
 void uiTemplateOperatorSearch(struct uiLayout *layout) {}
 void uiTemplateHeader3D(struct uiLayout *layout, struct bContext *C) {}
@@ -509,6 +518,7 @@ float sculpt_get_brush_alpha(struct Brush *brush) {return 0.0f;}
 void sculpt_set_brush_alpha(struct Brush *brush, float alpha) {}
 void ED_sculpt_modifiers_changed(struct Object *ob) {}
 void ED_mesh_calc_tessface(struct Mesh *mesh) {}
+void BKE_brush_gen_texture_cache(struct Brush *br, int half_side) {}
 
 /* bpy/python internal api */
 void operator_wrapper(struct wmOperatorType *ot, void *userdata) {}
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index e0a38096904..7db4b5bfc89 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -793,8 +793,7 @@ add_dependencies(blender makesdna)
 
 get_property(BLENDER_LINK_LIBS GLOBAL PROPERTY BLENDER_LINK_LIBS)
 
-set(BLENDER_LINK_LIBS
-	${BLENDER_LINK_LIBS}
+list(APPEND BLENDER_LINK_LIBS
 	bf_windowmanager
 	bf_render
 )
@@ -908,7 +907,6 @@ endif()
 		ge_scenegraph
 		ge_logic_network
 		ge_logic_ngnetwork
-		extern_bullet
 		ge_logic_loopbacknetwork
 		bf_intern_moto
 		extern_openjpeg
@@ -929,6 +927,7 @@ endif()
 		cycles_subd
 		bf_intern_raskter
 		bf_intern_opencolorio
+		extern_rangetree
 	)
 
 	if(WITH_COMPOSITOR)
@@ -986,6 +985,10 @@ endif()
 		list(APPEND BLENDER_SORTED_LIBS bf_intern_locale)
 	endif()
 
+	if(WITH_BULLET AND NOT WITH_BULLET_SYSTEM)
+		list_insert_after(BLENDER_SORTED_LIBS "ge_logic_ngnetwork" "extern_bullet")
+	endif()
+
 	foreach(SORTLIB ${BLENDER_SORTED_LIBS})
 		set(REMLIB ${SORTLIB})
 		foreach(SEARCHLIB ${BLENDER_LINK_LIBS})
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 706ced245bb..d678df33ad0 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -1420,7 +1420,7 @@ int main(int argc, const char **argv)
 	WM_main(C);
 
 	return 0;
-} /* end of int main(argc,argv)	*/
+} /* end of int main(argc, argv)	*/
 
 #ifdef WITH_PYTHON_MODULE
 void main_python_exit(void)
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
index 482700d5958..176dc33d057 100644
--- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -468,6 +468,8 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
 				sceneconverter->SetMaterials(true);
 			if (useglslmat && (gs.matmode == GAME_MAT_GLSL))
 				sceneconverter->SetGLSLMaterials(true);
+			if (scene->gm.flag & GAME_NO_MATERIAL_CACHING)
+				sceneconverter->SetCacheMaterials(false);
 					
 			KX_Scene* startscene = new KX_Scene(keyboarddevice,
 				mousedevice,
diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt
index 9a47d223f76..d833534605b 100644
--- a/source/gameengine/BlenderRoutines/CMakeLists.txt
+++ b/source/gameengine/BlenderRoutines/CMakeLists.txt
@@ -30,7 +30,6 @@ set(INC
 )
 
 set(INC_SYS
-	../../../extern/bullet2/src
 	${PTHREADS_INCLUDE_DIRS}
 	${GLEW_INCLUDE_PATH}
 	${BOOST_INCLUDE_DIR}
@@ -70,4 +69,12 @@ if(WITH_CODEC_FFMPEG)
 	add_definitions(-DWITH_FFMPEG)
 endif()
 
+if(WITH_BULLET)
+	list(APPEND INC_SYS
+		${BULLET_INCLUDE_DIRS}
+	)
+	add_definitions(-DUSE_BULLET)
+endif()
+
+
 blender_add_lib(ge_blen_routines "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
index 346d2017ef0..719041e8d41 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
@@ -178,6 +178,18 @@ SetViewPort(
 	glScissor(minx + x1, miny + y1, vp_width, vp_height);
 }
 
+	void
+KX_BlenderCanvas::
+UpdateViewPort(
+	int x1, int y1,
+	int x2, int y2
+) {
+	m_viewport[0] = x1;
+	m_viewport[1] = y1;
+	m_viewport[2] = x2;
+	m_viewport[3] = y2;
+}
+
 	const int*
 KX_BlenderCanvas::
 GetViewPort() {
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
index 244394a115d..4117c13aede 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
@@ -151,6 +151,13 @@ public:
 		int x1, int y1,
 		int x2, int y2
 	);
+
+		void
+	UpdateViewPort(
+		int x1, int y1,
+		int x2, int y2
+	);
+
 		const int*
 	GetViewPort();
 
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp
index 00836fa8ecb..f8ad8870e83 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp
+++ b/source/gameengine/BlenderRoutines/KX_BlenderGL.cpp
@@ -259,7 +259,7 @@ void BL_MakeScreenShot(ScrArea *curarea, const char* filename)
 		ImBuf *ibuf;
 		BLI_path_abs(path, G.main->name);
 		/* BKE_add_image_extension() checks for if extension was already set */
-		BKE_add_image_extension(path, R_IMF_IMTYPE_PNG); /* scene->r.im_format.imtype */
+		BKE_add_image_extension_from_type(path, R_IMF_IMTYPE_PNG); /* scene->r.im_format.imtype */
 		ibuf= IMB_allocImBuf(dumpsx, dumpsy, 24, 0);
 		ibuf->rect= dumprect;
 		ibuf->ftype= PNG;
diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp
index 1f1c404efcb..395a57d753c 100644
--- a/source/gameengine/Converter/BL_ArmatureObject.cpp
+++ b/source/gameengine/Converter/BL_ArmatureObject.cpp
@@ -112,7 +112,8 @@ void game_copy_pose(bPose **dst, bPose *src, int copy_constraint)
 		if (copy_constraint) {
 			ListBase listb;
 			// copy all constraint for backward compatibility
-			copy_constraints(&listb, &pchan->constraints, FALSE);  // copy_constraints NULLs listb, no need to make extern for this operation.
+			// BKE_copy_constraints NULLs listb, no need to make extern for this operation.
+			BKE_copy_constraints(&listb, &pchan->constraints, FALSE);
 			pchan->constraints= listb;
 		} else {
 			pchan->constraints.first = NULL;
@@ -304,7 +305,7 @@ void BL_ArmatureObject::LoadConstraints(KX_BlenderSceneConverter* converter)
 			case CONSTRAINT_TYPE_TRANSFORM:
 			case CONSTRAINT_TYPE_DISTLIMIT:
 			case CONSTRAINT_TYPE_TRANSLIKE:
-				cti = constraint_get_typeinfo(pcon);
+				cti = BKE_constraint_get_typeinfo(pcon);
 				gametarget = gamesubtarget = NULL;
 				if (cti && cti->get_constraint_targets) {
 					ListBase listb = { NULL, NULL };
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index 874bf614413..a4c4253754e 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -922,6 +922,9 @@ static RAS_MaterialBucket *material_from_mesh(Material *ma, MFace *mface, MTFace
 		/* do Texture Face materials */
 		Image* bima = (tface)? (Image*)tface->tpage: NULL;
 		STR_String imastr =  (tface)? (bima? (bima)->id.name : "" ) : "";
+
+		if (!converter->GetCacheMaterials())
+			polymat = NULL;
 		
 		char alpha_blend=0;
 		short tile=0;
@@ -1044,7 +1047,8 @@ static RAS_MaterialBucket *material_from_mesh(Material *ma, MFace *mface, MTFace
 				polymat->m_shininess = 35.0;
 			}
 			
-			converter->CachePolyMaterial(ma, polymat);
+			if (converter->GetCacheMaterials())
+				converter->CachePolyMaterial(ma, polymat);
 		}
 	}
 	
@@ -1260,7 +1264,7 @@ static PHY_MaterialProps *CreateMaterialFromBlenderObject(struct Object* blender
 	
 	MT_assert(materialProps && "Create physics material properties failed");
 		
-	Material* blendermat = give_current_material(blenderobject, 0);
+	Material* blendermat = give_current_material(blenderobject, 1);
 		
 	if (blendermat)
 	{
@@ -1345,11 +1349,7 @@ static float my_boundbox_mesh(Mesh *me, float *loc, float *size)
 	int a;
 	
 	if (me->bb==0) {
-		// This can be called in a seperate (not main) thread when doing async libload,
-		// so lets try to be safe...
-		BLI_begin_threaded_malloc();
-		me->bb= (struct BoundBox *)MEM_callocN(sizeof(BoundBox), "boundbox");
-		BLI_end_threaded_malloc();
+		me->bb = BKE_boundbox_alloc_unit();
 	}
 	bb= me->bb;
 	
@@ -2360,6 +2360,10 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
 	set allblobj;	// all objects converted
 	set groupobj;	// objects from groups (never in active layer)
 
+	// This is bad, but we use this to make sure the first time this is called
+	// is not in a separate thread.
+	BL_Texture::GetMaxUnits();
+
 	if (alwaysUseExpandFraming) {
 		frame_type = RAS_FrameSettings::e_frame_extend;
 		aspect_width = canvas->GetWidth();
diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt
index e01729e156f..8ac9e523d5d 100644
--- a/source/gameengine/Converter/CMakeLists.txt
+++ b/source/gameengine/Converter/CMakeLists.txt
@@ -112,7 +112,7 @@ set(SRC
 
 if(WITH_BULLET)
 	list(APPEND INC_SYS
-		../../../extern/bullet2/src
+		${BULLET_INCLUDE_DIRS}
 	)
 	add_definitions(-DUSE_BULLET)
 endif()
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
index ceaa0a5f5a8..5524612f707 100644
--- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
+++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
@@ -131,7 +131,8 @@ KX_BlenderSceneConverter::KX_BlenderSceneConverter(
 							m_ketsjiEngine(engine),
 							m_alwaysUseExpandFraming(false),
 							m_usemat(false),
-							m_useglslmat(false)
+							m_useglslmat(false),
+							m_use_mat_cache(true)
 {
 	tag_main(maggie, 0); /* avoid re-tagging later on */
 	m_newfilename = "";
@@ -488,6 +489,11 @@ void KX_BlenderSceneConverter::SetGLSLMaterials(bool val)
 	m_useglslmat = val;
 }
 
+void KX_BlenderSceneConverter::SetCacheMaterials(bool val)
+{
+	m_use_mat_cache = val;
+}
+
 bool KX_BlenderSceneConverter::GetMaterials()
 {
 	return m_usemat;
@@ -498,6 +504,11 @@ bool KX_BlenderSceneConverter::GetGLSLMaterials()
 	return m_useglslmat;
 }
 
+bool KX_BlenderSceneConverter::GetCacheMaterials()
+{
+	return m_use_mat_cache;
+}
+
 void KX_BlenderSceneConverter::RegisterBlenderMaterial(BL_Material *mat)
 {
 	// First make sure we don't register the material twice
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h
index f7723350eee..06dac1707c5 100644
--- a/source/gameengine/Converter/KX_BlenderSceneConverter.h
+++ b/source/gameengine/Converter/KX_BlenderSceneConverter.h
@@ -91,6 +91,7 @@ class KX_BlenderSceneConverter : public KX_ISceneConverter
 	bool					m_alwaysUseExpandFraming;
 	bool					m_usemat;
 	bool					m_useglslmat;
+	bool					m_use_mat_cache;
 
 public:
 	KX_BlenderSceneConverter(
@@ -160,6 +161,10 @@ public:
 	virtual void SetGLSLMaterials(bool val);
 	virtual bool GetGLSLMaterials();
 
+	// cache materials during conversion
+	virtual void SetCacheMaterials(bool val);
+	virtual bool GetCacheMaterials();
+
 	struct Scene* GetBlenderSceneForName(const STR_String& name);
 
 //	struct Main* GetMain() { return m_maggie; }
diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/KX_ConvertControllers.cpp
index 769abd01ce0..5d3d0f33bec 100644
--- a/source/gameengine/Converter/KX_ConvertControllers.cpp
+++ b/source/gameengine/Converter/KX_ConvertControllers.cpp
@@ -157,7 +157,7 @@ void BL_ConvertControllers(
 				SCA_PythonController* pyctrl = new SCA_PythonController(gameobj, pycont->mode);
 				gamecontroller = pyctrl;
 #ifdef WITH_PYTHON
-
+				PyGILState_STATE gstate = PyGILState_Ensure();
 				pyctrl->SetNamespace(converter->GetPyNamespace());
 				
 				if (pycont->mode==SCA_PythonController::SCA_PYEXEC_SCRIPT) {
@@ -186,6 +186,7 @@ void BL_ConvertControllers(
 					}
 				}
 				
+				PyGILState_Release(gstate);
 #endif // WITH_PYTHON
 
 				break;
@@ -218,6 +219,7 @@ void BL_ConvertControllers(
 			converter->RegisterGameController(gamecontroller, bcontr);
 
 #ifdef WITH_PYTHON
+			PyGILState_STATE gstate = PyGILState_Ensure();
 			if (bcontr->type==CONT_PYTHON) {
 				SCA_PythonController *pyctrl= static_cast(gamecontroller);
 				/* not strictly needed but gives syntax errors early on and
@@ -232,6 +234,8 @@ void BL_ConvertControllers(
 					// pyctrl->Import();
 				}
 			}
+
+			PyGILState_Release(gstate);
 #endif // WITH_PYTHON
 
 			//done with gamecontroller
diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp
index 11b00b7bbf5..4e910a885eb 100644
--- a/source/gameengine/Expressions/PyObjectPlus.cpp
+++ b/source/gameengine/Expressions/PyObjectPlus.cpp
@@ -118,16 +118,16 @@ PyTypeObject PyObjectPlus::Type = {
 	0,								/* setattrfunc tp_setattr; */
 	0,								/* tp_compare */ /* DEPRECATED in python 3.0! */
 	py_base_repr,					/* tp_repr */
-	0,0,0,0,0,0,0,0,0,				/* Method suites for standard classes */
-	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* long tp_flags; */
-	0,0,0,0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0,		/* Method suites for standard classes */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* long tp_flags; */
+	0, 0, 0, 0,
 	/* weak reference enabler */
 #ifdef USE_WEAKREFS
 	offsetof(PyObjectPlus_Proxy, in_weakreflist),	/* long tp_weaklistoffset; */
 #else
 	0,
 #endif
-	0,0,
+	0, 0,
 	Methods,
 	0,
 	0,
@@ -311,14 +311,14 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *
 				{
 					bool *val = reinterpret_cast(ptr);
 					ptr += sizeof(bool);
-					PyList_SET_ITEM(resultlist,i,PyBool_FromLong(*val));
+					PyList_SET_ITEM(resultlist, i, PyBool_FromLong(*val));
 					break;
 				}
 			case KX_PYATTRIBUTE_TYPE_SHORT:
 				{
 					short int *val = reinterpret_cast(ptr);
 					ptr += sizeof(short int);
-					PyList_SET_ITEM(resultlist,i,PyLong_FromLong(*val));
+					PyList_SET_ITEM(resultlist, i, PyLong_FromLong(*val));
 					break;
 				}
 			case KX_PYATTRIBUTE_TYPE_ENUM:
@@ -333,14 +333,14 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *
 				{
 					int *val = reinterpret_cast(ptr);
 					ptr += sizeof(int);
-					PyList_SET_ITEM(resultlist,i,PyLong_FromLong(*val));
+					PyList_SET_ITEM(resultlist, i, PyLong_FromLong(*val));
 					break;
 				}
 			case KX_PYATTRIBUTE_TYPE_FLOAT:
 				{
 					float *val = reinterpret_cast(ptr);
 					ptr += sizeof(float);
-					PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(*val));
+					PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble(*val));
 					break;
 				}
 			default:
@@ -423,7 +423,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *
 						PyObject *resultlist = PyList_New(attrdef->m_imax);
 						for (unsigned int i=0; im_imax; i++)
 						{
-							PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble(val[i]));
+							PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble(val[i]));
 						}
 						return resultlist;
 #endif
@@ -443,9 +443,9 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *
 						PyObject *col = PyList_New(attrdef->m_imax);
 						for (unsigned int j=0; jm_imax; j++)
 						{
-							PyList_SET_ITEM(col,j,PyFloat_FromDouble(val[j]));
+							PyList_SET_ITEM(col, j, PyFloat_FromDouble(val[j]));
 						}
-						PyList_SET_ITEM(collist,i,col);
+						PyList_SET_ITEM(collist, i, col);
 						val += attrdef->m_imax;
 					}
 					return collist;
@@ -463,7 +463,7 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *
 				PyObject *resultlist = PyList_New(3);
 				for (unsigned int i=0; i<3; i++)
 				{
-					PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble((*val)[i]));
+					PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble((*val)[i]));
 				}
 				return resultlist;
 #endif
@@ -1110,7 +1110,7 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt
 ------------------------------*/
 PyObject *PyObjectPlus::py_repr(void)
 {
-	PyErr_SetString(PyExc_SystemError, "Representation not overridden by object.");  
+	PyErr_SetString(PyExc_SystemError, "Representation not overridden by object.");
 	return NULL;
 }
 
@@ -1187,7 +1187,7 @@ void PyObjectPlus::SetDeprecationWarnings(bool ignoreDeprecationWarnings)
 	m_ignore_deprecation_warnings = ignoreDeprecationWarnings;
 }
 
-void PyObjectPlus::ShowDeprecationWarning_func(const char* old_way,const char* new_way)
+void PyObjectPlus::ShowDeprecationWarning_func(const char *old_way, const char *new_way)
 {
 	printf("Method %s is deprecated, please use %s instead.\n", old_way, new_way);
 	PyC_LineSpit();
diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h
index 37e26e88750..e2e7c248795 100644
--- a/source/gameengine/Expressions/PyObjectPlus.h
+++ b/source/gameengine/Expressions/PyObjectPlus.h
@@ -389,139 +389,139 @@ typedef struct KX_PYATTRIBUTE_DEF {
 	} m_typeCheck;
 } PyAttributeDef;
 
-#define KX_PYATTRIBUTE_BOOL_RW(name,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_BOOL_RW_CHECK(name,object,field,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_BOOL_RO(name,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_BOOL_RW(name, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_BOOL_RW_CHECK(name, object, field, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_BOOL_RO(name, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} }
 
 /* attribute points to a single bit of an integer field, attribute=true if bit is set */
-#define KX_PYATTRIBUTE_FLAG_RW(name,object,field,bit) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLAG_RW_CHECK(name,object,field,bit,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLAG_RO(name,object,field,bit) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLAG_RW(name, object, field, bit) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLAG_RW_CHECK(name, object, field, bit, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLAG_RO(name, object, field, bit) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
 
 /* attribute points to a single bit of an integer field, attribute=true if bit is set*/
-#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW(name,object,field,bit) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW_CHECK(name,object,field,bit,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RO(name,object,field,bit) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 1, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW(name, object, field, bit) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW_CHECK(name, object, field, bit, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RO(name, object, field, bit) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
 
 // enum field cannot be mapped to pointer (because we would need a pointer for each enum)
 // use field size to verify mapping at runtime only, assuming enum size is equal to int size.
-#define KX_PYATTRIBUTE_ENUM_RW(name,min,max,clamp,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_ENUM_RW_CHECK(name,min,max,clamp,object,field,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_ENUM_RO(name,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_ENUM_RW(name, min, max, clamp, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_ENUM_RW_CHECK(name, min, max, clamp, object, field, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_ENUM_RO(name, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
 
-#define KX_PYATTRIBUTE_SHORT_RW(name,min,max,clamp,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_SHORT_RW_CHECK(name,min,max,clamp,object,field,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_SHORT_RO(name,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name,min,max,clamp,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_RW(name, min, max, clamp, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_RW_CHECK(name, min, max, clamp, object, field, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_RO(name, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name, min, max, clamp, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name, min, max, clamp, object, field, length, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
 // SHORT_LIST
-#define KX_PYATTRIBUTE_SHORT_LIST_RW(name,min,max,clamp,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_SHORT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_SHORT_LIST_RO(name,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_LIST_RW(name, min, max, clamp, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_LIST_RW_CHECK(name, min, max, clamp, object, field, length, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_LIST_RO(name, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} }
 
-#define KX_PYATTRIBUTE_INT_RW(name,min,max,clamp,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_INT_RW_CHECK(name,min,max,clamp,object,field,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_INT_RO(name,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_INT_ARRAY_RW(name,min,max,clamp,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name,min,max,clamp,object,field,length,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_INT_ARRAY_RO(name,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_RW(name, min, max, clamp, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_RW_CHECK(name, min, max, clamp, object, field, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_RO(name, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_ARRAY_RW(name, min, max, clamp, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name, min, max, clamp, object, field, length, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_ARRAY_RO(name, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} }
 // INT_LIST
-#define KX_PYATTRIBUTE_INT_LIST_RW(name,min,max,clamp,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_INT_LIST_RW_CHECK(name,min,max,clamp,object,field,length,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_INT_LIST_RO(name,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_LIST_RW(name, min, max, clamp, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_LIST_RW_CHECK(name, min, max, clamp, object, field, length, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_LIST_RO(name, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} }
 
 // always clamp for float
-#define KX_PYATTRIBUTE_FLOAT_RW(name,min,max,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name,min,max,object,field,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLOAT_RO(name,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_RW(name, min, max, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name, min, max, object, field, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_RO(name, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} }
 // field must be float[n], returns a sequence
-#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name,min,max,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name, min, max, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name, min, max, object, field, length, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
 // field must be float[n], returns a vector
-#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW(name,min,max,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW_CHECK(name,min,max,object,field,length,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLOAT_VECTOR_RO(name,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, length, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW(name, min, max, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW_CHECK(name, min, max, object, field, length, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_VECTOR_RO(name, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, length, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} }
 // field must be float[n][n], returns a matrix
-#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW(name,min,max,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW_CHECK(name,min,max,object,field,length,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_FLOAT_MATRIX_RO(name,object,field,length) \
-	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, length, length, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW(name, min, max, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW_CHECK(name, min, max, object, field, length, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_MATRIX_RO(name, object, field, length) \
+	{ name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, length, length, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} }
 
 // only for STR_String member
-#define KX_PYATTRIBUTE_STRING_RW(name,min,max,clamp,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} }
-#define KX_PYATTRIBUTE_STRING_RW_CHECK(name,min,max,clamp,object,field,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} }
-#define KX_PYATTRIBUTE_STRING_RO(name,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} }
+#define KX_PYATTRIBUTE_STRING_RW(name, min, max, clamp, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} }
+#define KX_PYATTRIBUTE_STRING_RW_CHECK(name, min, max, clamp, object, field, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} }
+#define KX_PYATTRIBUTE_STRING_RO(name, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} }
 
 // only for char [] array 
-#define KX_PYATTRIBUTE_CHAR_RW(name,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} }
-#define KX_PYATTRIBUTE_CHAR_RW_CHECK(name,object,field,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object,field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} }
-#define KX_PYATTRIBUTE_CHAR_RO(name,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), sizeof(((object *)0)->field), 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} }
+#define KX_PYATTRIBUTE_CHAR_RW(name, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} }
+#define KX_PYATTRIBUTE_CHAR_RW_CHECK(name, object, field, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} }
+#define KX_PYATTRIBUTE_CHAR_RO(name, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} }
 
 // for MT_Vector3 member
-#define KX_PYATTRIBUTE_VECTOR_RW(name,min,max,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} }
-#define KX_PYATTRIBUTE_VECTOR_RW_CHECK(name,min,max,clamp,object,field,function) \
-	{ name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object,field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} }
-#define KX_PYATTRIBUTE_VECTOR_RO(name,object,field) \
-	{ name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object,field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} }
+#define KX_PYATTRIBUTE_VECTOR_RW(name, min, max, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} }
+#define KX_PYATTRIBUTE_VECTOR_RW_CHECK(name, min, max, clamp, object, field, function) \
+	{ name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} }
+#define KX_PYATTRIBUTE_VECTOR_RO(name, object, field) \
+	{ name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} }
 
-#define KX_PYATTRIBUTE_RW_FUNCTION(name,object,getfunction,setfunction) \
+#define KX_PYATTRIBUTE_RW_FUNCTION(name, object, getfunction, setfunction) \
 	{ name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_RO_FUNCTION(name,object,getfunction) \
+#define KX_PYATTRIBUTE_RO_FUNCTION(name, object, getfunction) \
 	{ name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_ARRAY_RW_FUNCTION(name,object,length,getfunction,setfunction) \
-	{ name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0,f, false, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
-#define KX_PYATTRIBUTE_ARRAY_RO_FUNCTION(name,object,length,getfunction) \
-	{ name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0,f, false, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_ARRAY_RW_FUNCTION(name, object, length, getfunction, setfunction) \
+	{ name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0, f, false, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_ARRAY_RO_FUNCTION(name, object, length, getfunction) \
+	{ name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0, f, false, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} }
 
 
 /*------------------------------
@@ -614,7 +614,7 @@ public:
 	/** enable/disable display of deprecation warnings */
 	static void			SetDeprecationWarnings(bool ignoreDeprecationWarnings);
 	/** Shows a deprecation warning */
-	static void			ShowDeprecationWarning_func(const char* method,const char* prop);
+	static void			ShowDeprecationWarning_func(const char *method, const char *prop);
 	static void			ClearDeprecationWarning();
 	
 #endif
diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp
index 5ad5aedbd39..6a87d3ccb98 100644
--- a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp
+++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp
@@ -97,6 +97,11 @@ bool SCA_2DFilterActuator::Update()
 }
 
 
+void SCA_2DFilterActuator::SetScene(SCA_IScene *scene)
+{
+	m_scene = scene;
+}
+
 void SCA_2DFilterActuator::SetShaderText(const char *text)
 {
 	m_shaderText = text;
diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.h b/source/gameengine/GameLogic/SCA_2DFilterActuator.h
index a754d950859..4635a8ad9f8 100644
--- a/source/gameengine/GameLogic/SCA_2DFilterActuator.h
+++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.h
@@ -64,6 +64,8 @@ public:
 	virtual ~SCA_2DFilterActuator();
 	virtual bool Update();
 
+	void	SetScene(SCA_IScene *scene);
+
 	virtual CValue* GetReplica();
 };
 #endif
diff --git a/source/gameengine/GameLogic/SCA_PythonJoystick.cpp b/source/gameengine/GameLogic/SCA_PythonJoystick.cpp
index ee792111705..8c0a0c5ae33 100644
--- a/source/gameengine/GameLogic/SCA_PythonJoystick.cpp
+++ b/source/gameengine/GameLogic/SCA_PythonJoystick.cpp
@@ -122,14 +122,14 @@ PyObject* SCA_PythonJoystick::pyattr_get_active_buttons(void *self_v, const KX_P
 {
 	SCA_PythonJoystick* self = static_cast(self_v);
 	
-	int button_index = self->m_joystick->GetNumberOfButtons();
+	const int button_number = self->m_joystick->GetNumberOfButtons();
 
 	PyObject *list = PyList_New(0);
 	PyObject *value;
 
-	for (int i=0; i < self->m_joystick->GetNumberOfButtons(); i++) {
+	for (int i=0; i < button_number; i++) {
 		if (self->m_joystick->aButtonPressIsPositive(i)) {
-			value = PyLong_FromSsize_t(i);
+			value = PyLong_FromLong(i);
 			PyList_Append(list, value);
 			Py_DECREF(value);
 		}
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
index b5c1c29238a..058454ca352 100644
--- a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
@@ -131,7 +131,15 @@ void GPC_Canvas::SetViewPort(int x1, int y1, int x2, int y2)
 
 	glViewport(x1,y1,x2-x1 + 1,y2-y1 + 1);
 	glScissor(x1,y1,x2-x1 + 1,y2-y1 + 1);
-};
+}
+
+void GPC_Canvas::UpdateViewPort(int x1, int y1, int x2, int y2)
+{
+	m_viewport[0] = x1;
+	m_viewport[1] = y1;
+	m_viewport[2] = x2;
+	m_viewport[3] = y2;
+}
 
 const int *GPC_Canvas::GetViewPort()
 {
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.h b/source/gameengine/GamePlayer/common/GPC_Canvas.h
index ec5375c0e13..00c5911a8b4 100644
--- a/source/gameengine/GamePlayer/common/GPC_Canvas.h
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.h
@@ -155,6 +155,7 @@ public:
 	);
 	
 	void SetViewPort(int x1, int y1, int x2, int y2);
+	void UpdateViewPort(int x1, int y1, int x2, int y2);
 	const int *GetViewPort();
 
 	void ClearColor(float r, float g, float b, float a);
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
index 1dcc68c8e75..89d11515bb3 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -703,6 +703,8 @@ bool GPG_Application::startEngine(void)
 			m_sceneconverter->SetMaterials(true);
 		if (m_blenderglslmat && (m_globalSettings->matmode == GAME_MAT_GLSL))
 			m_sceneconverter->SetGLSLMaterials(true);
+		if (m_startScene->gm.flag & GAME_NO_MATERIAL_CACHING)
+			m_sceneconverter->SetCacheMaterials(false);
 
 		KX_Scene* startscene = new KX_Scene(m_keyboard,
 			m_mouse,
diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt
index 524a38a4c26..e42c2a74a8e 100644
--- a/source/gameengine/Ketsji/CMakeLists.txt
+++ b/source/gameengine/Ketsji/CMakeLists.txt
@@ -252,7 +252,7 @@ if(WITH_BULLET)
 		../Physics/Bullet
 	)
 	list(APPEND INC
-		../../../extern/bullet2/src
+		${BULLET_INCLUDE_DIRS}
 	)
 	add_definitions(-DUSE_BULLET)
 endif()
diff --git a/source/gameengine/Ketsji/KX_CharacterWrapper.cpp b/source/gameengine/Ketsji/KX_CharacterWrapper.cpp
index ce208f3a75f..64bbbb7d344 100644
--- a/source/gameengine/Ketsji/KX_CharacterWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_CharacterWrapper.cpp
@@ -45,6 +45,8 @@ PyTypeObject KX_CharacterWrapper::Type = {
 PyAttributeDef KX_CharacterWrapper::Attributes[] = {
 	KX_PYATTRIBUTE_RO_FUNCTION("onGround", KX_CharacterWrapper, pyattr_get_onground),
 	KX_PYATTRIBUTE_RW_FUNCTION("gravity", KX_CharacterWrapper, pyattr_get_gravity, pyattr_set_gravity),
+	KX_PYATTRIBUTE_RW_FUNCTION("maxJumps", KX_CharacterWrapper, pyattr_get_max_jumps, pyattr_set_max_jumps),
+	KX_PYATTRIBUTE_RO_FUNCTION("jumpCount", KX_CharacterWrapper, pyattr_get_jump_count),
 	{ NULL }	//Sentinel
 };
 
@@ -77,6 +79,35 @@ int KX_CharacterWrapper::pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_D
 	return PY_SET_ATTR_SUCCESS;
 }
 
+PyObject *KX_CharacterWrapper::pyattr_get_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+	KX_CharacterWrapper* self = static_cast(self_v);
+
+	return PyLong_FromLong(self->m_character->GetMaxJumps());
+}
+
+int KX_CharacterWrapper::pyattr_set_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+	KX_CharacterWrapper* self = static_cast(self_v);
+	long param = PyLong_AsLong(value);
+
+	if (param == -1)
+	{
+		PyErr_SetString(PyExc_ValueError, "KX_CharacterWrapper.maxJumps: expected an integer");
+		return PY_SET_ATTR_FAIL;
+	}
+
+	self->m_character->SetMaxJumps((int)param);
+	return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject *KX_CharacterWrapper::pyattr_get_jump_count(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+	KX_CharacterWrapper* self = static_cast(self_v);
+
+	return PyLong_FromLong(self->m_character->GetJumpCount());
+}
+
 PyMethodDef KX_CharacterWrapper::Methods[] = {
 	KX_PYMETHODTABLE_NOARGS(KX_CharacterWrapper, jump),
 	{NULL,NULL} //Sentinel
diff --git a/source/gameengine/Ketsji/KX_CharacterWrapper.h b/source/gameengine/Ketsji/KX_CharacterWrapper.h
index 3b0058aca6f..f1c977f4e5d 100644
--- a/source/gameengine/Ketsji/KX_CharacterWrapper.h
+++ b/source/gameengine/Ketsji/KX_CharacterWrapper.h
@@ -26,6 +26,9 @@ public:
 	
 	static PyObject*	pyattr_get_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
 	static int			pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+	static PyObject*	pyattr_get_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+	static int			pyattr_set_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+	static PyObject*	pyattr_get_jump_count(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
 #endif // WITH_PYTHON
 
 private:
diff --git a/source/gameengine/Ketsji/KX_ISceneConverter.h b/source/gameengine/Ketsji/KX_ISceneConverter.h
index 7c1d593a81e..616895a8269 100644
--- a/source/gameengine/Ketsji/KX_ISceneConverter.h
+++ b/source/gameengine/Ketsji/KX_ISceneConverter.h
@@ -89,6 +89,10 @@ public:
 	virtual void SetGLSLMaterials(bool val) =0;
 	virtual bool GetGLSLMaterials()=0;
 
+	// cache materials during conversion
+	virtual void SetCacheMaterials(bool val) =0;
+	virtual bool GetCacheMaterials()=0;
+
 	virtual struct Scene* GetBlenderSceneForName(const STR_String& name)=0;
 	
 	
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index 6638b711a1b..f0d5d5c6685 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -1167,7 +1167,7 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
 			m_rasterizer->SetDrawingMode(RAS_IRasterizer::KX_SHADOW);
 
 			/* binds framebuffer object, sets up camera .. */
-			light->BindShadowBuffer(m_rasterizer, cam, camtrans);
+			light->BindShadowBuffer(m_rasterizer, m_canvas, cam, camtrans);
 
 			/* update scene */
 			scene->CalculateVisibleMeshes(m_rasterizer, cam, light->GetShadowLayer());
diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp
index cf58d18838a..5414a4df0f8 100644
--- a/source/gameengine/Ketsji/KX_Light.cpp
+++ b/source/gameengine/Ketsji/KX_Light.cpp
@@ -236,7 +236,7 @@ int KX_LightObject::GetShadowLayer()
 		return 0;
 }
 
-void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_Transform& camtrans)
+void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, RAS_ICanvas *canvas, KX_Camera *cam, MT_Transform& camtrans)
 {
 	GPULamp *lamp;
 	float viewmat[4][4], winmat[4][4];
@@ -246,6 +246,9 @@ void KX_LightObject::BindShadowBuffer(RAS_IRasterizer *ras, KX_Camera *cam, MT_T
 	lamp = GetGPULamp();
 	GPU_lamp_shadow_buffer_bind(lamp, viewmat, &winsize, winmat);
 
+	/* GPU_lamp_shadow_buffer_bind() changes the viewport, so update the canvas */
+	canvas->UpdateViewPort(0, 0, winsize, winsize);
+
 	/* setup camera transformation */
 	MT_Matrix4x4 modelviewmat((float*)viewmat);
 	MT_Matrix4x4 projectionmat((float*)winmat);
diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h
index 52f076c772a..f88fc7f6a1b 100644
--- a/source/gameengine/Ketsji/KX_Light.h
+++ b/source/gameengine/Ketsji/KX_Light.h
@@ -64,7 +64,7 @@ public:
 	struct GPULamp *GetGPULamp();
 	bool HasShadowBuffer();
 	int GetShadowLayer();
-	void BindShadowBuffer(class RAS_IRasterizer *ras, class KX_Camera *cam, class MT_Transform& camtrans);
+	void BindShadowBuffer(class RAS_IRasterizer *ras, class RAS_ICanvas *canvas, class KX_Camera *cam, class MT_Transform& camtrans);
 	void UnbindShadowBuffer(class RAS_IRasterizer *ras);
 	struct Image *GetTextureImage(short texslot);
 	void Update();
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index 0d39eb844b5..02995a53954 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -1921,6 +1921,9 @@ PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur
 		PySys_SetObject("argv", py_argv);
 		Py_DECREF(py_argv);
 	}
+	
+	/* Initialize thread support (also acquires lock) */
+	PyEval_InitThreads();
 
 	bpy_import_init(PyEval_GetBuiltins());
 
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index 72be5f57b95..55c9ff5307f 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -47,6 +47,7 @@
 //#include "SCA_AlwaysEventManager.h"
 //#include "SCA_RandomEventManager.h"
 //#include "KX_RayEventManager.h"
+#include "SCA_2DFilterActuator.h"
 #include "KX_TouchEventManager.h"
 #include "SCA_KeyboardManager.h"
 #include "SCA_MouseManager.h"
@@ -227,7 +228,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
 	}
 	
 #ifdef WITH_PYTHON
-	m_attr_dict = PyDict_New(); /* new ref */
+	m_attr_dict = NULL;
 	m_draw_call_pre = NULL;
 	m_draw_call_post = NULL;
 #endif
@@ -287,9 +288,11 @@ KX_Scene::~KX_Scene()
 	}
 
 #ifdef WITH_PYTHON
-	PyDict_Clear(m_attr_dict);
-	/* Py_CLEAR: Py_DECREF's and NULL's */
-	Py_CLEAR(m_attr_dict);
+	if (m_attr_dict) {
+		PyDict_Clear(m_attr_dict);
+		/* Py_CLEAR: Py_DECREF's and NULL's */
+		Py_CLEAR(m_attr_dict);
+	}
 
 	/* these may be NULL but the macro checks */
 	Py_CLEAR(m_draw_call_pre);
@@ -1779,6 +1782,11 @@ static void MergeScene_LogicBrick(SCA_ILogicBrick* brick, KX_Scene *to)
 	if (sensor) {
 		sensor->Replace_EventManager(logicmgr);
 	}
+
+	SCA_2DFilterActuator *filter_actuator = dynamic_cast(brick);
+	if (filter_actuator) {
+		filter_actuator->SetScene(to);
+	}
 }
 
 #ifdef USE_BULLET
@@ -2062,6 +2070,9 @@ static PyObject *Map_GetItem(PyObject *self_v, PyObject *item)
 		PyErr_SetString(PyExc_SystemError, "val = scene[key]: KX_Scene, "BGE_PROXY_ERROR_MSG);
 		return NULL;
 	}
+
+	if (!self->m_attr_dict)
+		self->m_attr_dict = PyDict_New();
 	
 	if (self->m_attr_dict && (pyconvert=PyDict_GetItem(self->m_attr_dict, item))) {
 		
@@ -2089,7 +2100,10 @@ static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val)
 		PyErr_SetString(PyExc_SystemError, "scene[key] = value: KX_Scene, "BGE_PROXY_ERROR_MSG);
 		return -1;
 	}
-	
+
+	if (!self->m_attr_dict)
+		self->m_attr_dict = PyDict_New();
+
 	if (val==NULL) { /* del ob["key"] */
 		int del= 0;
 		
@@ -2133,7 +2147,10 @@ static int Seq_Contains(PyObject *self_v, PyObject *value)
 		PyErr_SetString(PyExc_SystemError, "val in scene: KX_Scene, "BGE_PROXY_ERROR_MSG);
 		return -1;
 	}
-	
+
+	if (!self->m_attr_dict)
+		self->m_attr_dict = PyDict_New();
+
 	if (self->m_attr_dict && PyDict_GetItem(self->m_attr_dict, value))
 		return 1;
 	
diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt
index 43b1bfe7468..afb166eee57 100644
--- a/source/gameengine/Physics/Bullet/CMakeLists.txt
+++ b/source/gameengine/Physics/Bullet/CMakeLists.txt
@@ -44,7 +44,6 @@ set(INC
 )
 
 set(INC_SYS
-	../../../../extern/bullet2/src
 	${GLEW_INCLUDE_PATH}
 	${PYTHON_INCLUDE_DIRS}
 )
@@ -60,6 +59,9 @@ set(SRC
 )
 
 if(WITH_BULLET)
+	list(APPEND INC
+		${BULLET_INCLUDE_DIRS}
+	)
 	add_definitions(-DUSE_BULLET)
 endif()
 
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
index a1b30ccb001..cf96f22a345 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
@@ -68,6 +68,53 @@ float gAngularSleepingTreshold;
 
 btVector3 startVel(0,0,0);//-10000);
 
+BlenderBulletCharacterController::BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight)
+	: btKinematicCharacterController(ghost,shape,stepHeight,2),
+		m_motionState(motionState),
+		m_jumps(0),
+		m_maxJumps(1)
+{
+}
+
+void BlenderBulletCharacterController::updateAction(btCollisionWorld *collisionWorld, btScalar dt)
+{
+	btKinematicCharacterController::updateAction(collisionWorld,dt);
+	m_motionState->setWorldTransform(getGhostObject()->getWorldTransform());
+}
+
+int BlenderBulletCharacterController::getMaxJumps() const
+{
+	return m_maxJumps;
+}
+
+void BlenderBulletCharacterController::setMaxJumps(int maxJumps)
+{
+	m_maxJumps = maxJumps;
+}
+
+int BlenderBulletCharacterController::getJumpCount() const
+{
+	return m_jumps;
+}
+
+bool BlenderBulletCharacterController::canJump() const
+{
+	return onGround() || m_jumps < m_maxJumps;
+}
+
+void BlenderBulletCharacterController::jump()
+{
+	if (onGround())
+		m_jumps = 0;
+
+	if (!canJump())
+		return;
+		
+	m_verticalVelocity = m_jumpSpeed;
+	m_wasJumping = true;
+	m_jumps++;
+}
+
 CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci)
 :m_cci(ci)
 {
@@ -154,25 +201,6 @@ public:
 
 };
 
-class BlenderBulletCharacterController : public btKinematicCharacterController
-{
-private:
-	btMotionState* m_motionState;
-
-public:
-	BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight)
-		: btKinematicCharacterController(ghost,shape,stepHeight,2),
-		  m_motionState(motionState)
-	{
-	}
-
-	virtual void updateAction(btCollisionWorld *collisionWorld, btScalar dt)
-	{
-		btKinematicCharacterController::updateAction(collisionWorld,dt);
-		m_motionState->setWorldTransform(getGhostObject()->getWorldTransform());
-	}
-};
-
 btRigidBody* CcdPhysicsController::GetRigidBody()
 {
 	return btRigidBody::upcast(m_object);
@@ -463,9 +491,6 @@ bool CcdPhysicsController::CreateCharacterController()
 
 	m_characterController = new BlenderBulletCharacterController(m_bulletMotionState,(btPairCachingGhostObject*)m_object,(btConvexShape*)m_collisionShape,m_cci.m_stepHeight);
 
-	PHY__Vector3 gravity;
-	m_cci.m_physicsEnv->getGravity(gravity);
-	m_characterController->setGravity(-gravity.m_vec[2]); // need positive gravity
 	m_characterController->setJumpSpeed(m_cci.m_jumpSpeed);
 	m_characterController->setFallSpeed(m_cci.m_fallSpeed);
 
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
index 6df5c85f5c0..b151c2f6b59 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
@@ -391,10 +391,33 @@ struct CcdConstructionInfo
 
 };
 
-
 class btRigidBody;
 class btCollisionObject;
 class btSoftBody;
+class btPairCachingGhostObject;
+
+class BlenderBulletCharacterController : public btKinematicCharacterController
+{
+private:
+	btMotionState* m_motionState;
+	int m_jumps;
+	int m_maxJumps;
+
+public:
+	BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight);
+
+	virtual void updateAction(btCollisionWorld *collisionWorld, btScalar dt);
+
+	int getMaxJumps() const;
+
+	void setMaxJumps(int maxJumps);
+
+	int getJumpCount() const;
+
+	virtual bool canJump() const;
+
+	virtual void jump();
+};
 
 ///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution.
 class CcdPhysicsController : public PHY_IPhysicsController
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
index 486411d7e35..cadba97023e 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
@@ -270,10 +270,10 @@ public:
 class CharacterWrapper : public PHY_ICharacter
 {
 private:
-	btKinematicCharacterController* m_controller;
+	BlenderBulletCharacterController* m_controller;
 
 public:
-	CharacterWrapper(btKinematicCharacterController* cont)
+	CharacterWrapper(BlenderBulletCharacterController* cont)
 		: m_controller(cont)
 	{}
 
@@ -295,6 +295,21 @@ public:
 	{
 		m_controller->setGravity(gravity);
 	}
+
+	virtual int GetMaxJumps()
+	{
+		return m_controller->getMaxJumps();
+	}
+
+	virtual void SetMaxJumps(int maxJumps)
+	{
+		m_controller->setMaxJumps(maxJumps);
+	}
+
+	virtual int GetJumpCount()
+	{
+		return m_controller->getJumpCount();
+	}
 };
 
 class CcdOverlapFilterCallBack : public btOverlapFilterCallback
@@ -2320,7 +2335,7 @@ PHY_ICharacter* CcdPhysicsEnvironment::getCharacterController(KX_GameObject *ob)
 {
 	CcdPhysicsController* controller = (CcdPhysicsController*)ob->GetPhysicsController()->GetUserData();
 	if (controller->GetCharacterController())
-		return new CharacterWrapper(controller->GetCharacterController());
+		return new CharacterWrapper((BlenderBulletCharacterController*)controller->GetCharacterController());
 
 	return NULL;
 }
diff --git a/source/gameengine/Physics/common/PHY_ICharacter.h b/source/gameengine/Physics/common/PHY_ICharacter.h
index e2fc5e45125..63f6c0bd18a 100644
--- a/source/gameengine/Physics/common/PHY_ICharacter.h
+++ b/source/gameengine/Physics/common/PHY_ICharacter.h
@@ -21,6 +21,11 @@ public:
 
 	virtual float GetGravity()= 0;
 	virtual void SetGravity(float gravity)= 0;
+	
+	virtual int GetMaxJumps()= 0;
+	virtual void SetMaxJumps(int maxJumps)= 0;
+
+	virtual int GetJumpCount()= 0;
 
 #ifdef WITH_CXX_GUARDEDALLOC
 	MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_ICharacter")
diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
index cf869e71945..ab0f62c84c7 100644
--- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
+++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
@@ -428,8 +428,7 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
 
 	// reverting to texunit 0, without this we get bug [#28462]
 	glActiveTextureARB(GL_TEXTURE0);
-
-	glViewport(rect.GetLeft(), rect.GetBottom(), rect_width, rect_height);
+	canvas->SetViewPort(0, 0, rect_width-1, rect_height-1);
 
 	glDisable(GL_DEPTH_TEST);
 	// in case the previous material was wire
@@ -466,7 +465,7 @@ void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas)
 	}
 
 	glEnable(GL_DEPTH_TEST);
-	glViewport(viewport[0],viewport[1],viewport[2],viewport[3]);
+	canvas->SetViewPort(viewport[0],viewport[1],viewport[2],viewport[3]);
 	EndShaderProgram();
 	glPopMatrix();
 	glMatrixMode(GL_MODELVIEW);
diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.h b/source/gameengine/Rasterizer/RAS_ICanvas.h
index 60b9f052075..63ad7892aa5 100644
--- a/source/gameengine/Rasterizer/RAS_ICanvas.h
+++ b/source/gameengine/Rasterizer/RAS_ICanvas.h
@@ -178,7 +178,19 @@ public:
 	SetViewPort(
 		int x1, int y1,
 		int x2, int y2
-	) = 0; 
+	) = 0;
+
+	/**
+	 * Update the Canvas' viewport (used when the viewport changes without using SetViewPort()
+	 * eg: Shadow buffers and FBOs
+	 */
+
+	virtual
+		void
+	UpdateViewPort(
+		int x1, int y1,
+		int x2, int y2
+	) = 0;
 
 	/**
 	 * Get the visible viewport
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
index 0eddde7c203..558850a9173 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h
@@ -51,7 +51,6 @@ typedef std::map		  RAS_DerivedMeshLists;
 
 class RAS_ListRasterizer : public RAS_OpenGLRasterizer
 {
-	bool mUseVertexArrays;
 	bool mATI;
 	RAS_ArrayLists mArrayLists;
 	RAS_DerivedMeshLists mDerivedMeshLists;
diff --git a/source/tests/check_deprecated.py b/source/tests/check_deprecated.py
index c5c7bdcdcb0..bb9fcd818d2 100644
--- a/source/tests/check_deprecated.py
+++ b/source/tests/check_deprecated.py
@@ -31,12 +31,12 @@ SKIP_DIRS = ("extern",
 
 def is_c_header(filename):
     ext = splitext(filename)[1]
-    return (ext in (".h", ".hpp", ".hxx"))
+    return (ext in {".h", ".hpp", ".hxx", ".hh"})
 
 
 def is_c(filename):
     ext = splitext(filename)[1]
-    return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc", ".cc", ".inl"))
+    return (ext in {".c", ".cpp", ".cxx", ".m", ".mm", ".rc", ".cc", ".inl"})
 
 
 def is_c_any(filename):