diff options
285 files changed, 6516 insertions, 2582 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c33f4384a76..d5c1b5c287f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,18 +289,14 @@ if(APPLE) set(OSX_SYSTEM unsupported) endif() message(STATUS "Detected system-version: " ${OSX_SYSTEM}) - - if(NOT CMAKE_OSX_DEPLOYMENT_TARGET) - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.6" CACHE STRING "" FORCE) # 10.6 is our min. target, if you use higher sdk, weak linking happens - with 10.5 we have still not solved problems, build those with 10.5.sdk for now !!! - endif() if(${CMAKE_GENERATOR} MATCHES "Xcode") - ##### workaround for actual official cmake incompatibility with xcode 4.3 ##### + ##### cmake incompatibility with xcode 4.3 and higher ##### if(${XCODE_VERSION} MATCHES '') # cmake fails due looking for xcode in the wrong path, thus will be empty var - message("Official cmake does not yet support Xcode 4.3, get a patched version here: http://www.jensverwiebe.de/Blender/CMake%202.8-7patched.zip") + message(FATAL_ERROR "Xcode 4.3 and higher must be used with cmake 2.8-8 or higher") endif() - ### end workaround for actual official cmake incompatibility with xcode 4.3 ### + ### end cmake incompatibility with xcode 4.3 and higher ### if(${XCODE_VERSION} VERSION_EQUAL 4 OR ${XCODE_VERSION} VERSION_GREATER 4 AND ${XCODE_VERSION} VERSION_LESS 4.3) # Xcode 4 defaults to the Apple LLVM Compiler. @@ -315,7 +311,28 @@ if(APPLE) endif() message(STATUS "Detected Xcode-version: " ${XCODE_VERSION}) + + if(${XCODE_VERSION} VERSION_LESS 4.3) + set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX${OSX_SYSTEM}.sdk CACHE PATH "" FORCE) # use guaranteed existing sdk + else() + # note: i don't use xcode-select path on purpose, cause also /Applications/Xcode.app would be allowed + # absolute pathes are more foolproof here ! + set(OSX_SYSROOT_PREFIX /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform) + set(OSX_DEVELOPER_PREFIX /Developer/SDKs/MacOSX${OSX_SYSTEM}.sdk) # use guaranteed existing sdk + set(CMAKE_OSX_SYSROOT ${OSX_SYSROOT_PREFIX}/${OSX_DEVELOPER_PREFIX} CACHE PATH "" FORCE) + endif() + if(NOT CMAKE_OSX_DEPLOYMENT_TARGET) + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.5" CACHE STRING "" FORCE) # 10.5 is our min. target, if you use higher sdk, weak linking happens + endif() + + if(NOT ${CMAKE_GENERATOR} MATCHES "Xcode") + # force CMAKE_OSX_DEPLOYMENT_TARGET for makefiles, will not work else ( cmake bug ? ) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") + add_definitions ("-DMACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") + endif() + option(WITH_COCOA "Use Cocoa framework instead of deprecated Carbon" ON) option(USE_QTKIT "Use QtKit instead of Carbon quicktime (needed for having partial quicktime for 64bit)" OFF) option(WITH_LIBS10.5 "Use 10.5 libs (needed for 64bit builds)" OFF) @@ -336,8 +353,8 @@ if(NOT WITH_GAMEENGINE AND WITH_PLAYER) message(FATAL_ERROR "WITH_PLAYER requires WITH_GAMEENGINE") endif() -if(NOT WITH_AUDASPACE AND (WITH_OPENAL OR WITH_SDL OR WITH_JACK OR WITH_GAMEENGINE)) - message(FATAL_ERROR "WITH_OPENAL/WITH_SDL/WITH_JACK/WITH_CODEC_FFMPEG/WITH_GAMEENGINE require WITH_AUDASPACE") +if(NOT WITH_AUDASPACE AND (WITH_OPENAL OR WITH_JACK OR WITH_GAMEENGINE)) + message(FATAL_ERROR "WITH_OPENAL/WITH_JACK/WITH_CODEC_FFMPEG/WITH_GAMEENGINE require WITH_AUDASPACE") endif() if(NOT WITH_SDL AND WITH_GHOST_SDL) @@ -372,8 +389,8 @@ if(WITH_CYCLES) set(WITH_OPENIMAGEIO ON) endif() -# auto enable boost for cycles and booleans -if(WITH_CYCLES OR WITH_MOD_BOOLEAN) +# auto enable boost for cycles, booleans, audaspace or i18n +if(WITH_CYCLES OR WITH_MOD_BOOLEAN OR WITH_AUDASPACE OR WITH_INTERNATIONAL) set(WITH_BOOST ON) endif() @@ -589,28 +606,6 @@ if(UNIX AND NOT APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__STDC_CONSTANT_MACROS") endif() - if(WITH_INTERNATIONAL) - find_library(INTL_LIBRARY - NAMES intl - PATHS - /sw/lib - ) - - find_library(ICONV_LIBRARY - NAMES iconv - PATHS - /sw/lib - ) - mark_as_advanced( - ICONV_LIBRARY - INTL_LIBRARY - ) - - if(INTL_LIBRARY AND ICONV_LIBRARY) - set(GETTEXT_LIBRARIES ${INTL_LIBRARY} ${ICONV_LIBRARY}) - endif() - endif() - if(WITH_FFTW3) find_package(Fftw3) if(NOT FFTW3_FOUND) @@ -658,7 +653,11 @@ if(UNIX AND NOT APPLE) else() set(Boost_USE_MULTITHREADED ON) endif() - find_package(Boost 1.34 COMPONENTS filesystem regex system thread) + set(__boost_packages filesystem regex system thread) + if (WITH_INTERNATIONAL) + list(APPEND __boost_packages locale) + endif() + find_package(Boost 1.34 COMPONENTS ${__boost_packages}) mark_as_advanced(Boost_DIR) # why doesnt boost do this? endif() @@ -715,7 +714,7 @@ if(UNIX AND NOT APPLE) set(LLVM_DIRECTORY ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation") set(LLVM_VERSION "3.0" CACHE STRING "Version of LLVM to use") set(LLVM_STATIC YES) - if(LLVM_DIRECTORY) + if(EXISTS "${LLVM_DIRECTORY}/bin/llvm-config") set(LLVM_CONFIG "${LLVM_DIRECTORY}/bin/llvm-config") else() set(LLVM_CONFIG llvm-config) @@ -730,7 +729,7 @@ if(UNIX AND NOT APPLE) OUTPUT_VARIABLE LLVM_LIB_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) find_library(LLVM_LIBRARY - NAMES libLLVMAnalysis.a # first of a whole bunch of libs to get + NAMES LLVMAnalysis # first of a whole bunch of libs to get PATHS ${LLVM_LIB_DIR}) message(STATUS "LLVM version = ${LLVM_VERSION}") message(STATUS "LLVM dir = ${LLVM_DIRECTORY}") @@ -875,13 +874,6 @@ elseif(WIN32) add_definitions(-DWIN32) - if(WITH_INTERNATIONAL) - set(ICONV ${LIBDIR}/iconv) - set(ICONV_INCLUDE_DIRS ${ICONV}/include) - set(ICONV_LIBRARIES iconv) - set(ICONV_LIBPATH ${ICONV}/lib) - endif() - set(JPEG "${LIBDIR}/jpeg") set(JPEG_INCLUDE_DIR "${JPEG}/include") set(JPEG_LIBPATH ${JPEG}/lib) # not cmake defined @@ -974,13 +966,6 @@ elseif(WIN32) set(CXX_WARNINGS "${_WARNINGS}") unset(_WARNINGS) - if(WITH_INTERNATIONAL) - set(GETTEXT ${LIBDIR}/gettext) - set(GETTEXT_INCLUDE_DIRS ${GETTEXT}/include) - set(GETTEXT_LIBPATH ${GETTEXT}/lib) - set(GETTEXT_LIBRARIES gnu_gettext) - endif() - if(WITH_MOD_CLOTH_ELTOPO) set(LAPACK ${LIBDIR}/lapack) # set(LAPACK_INCLUDE_DIR ${LAPACK}/include) @@ -1133,6 +1118,11 @@ elseif(WIN32) debug libboost_date_time-${BOOST_DEBUG_POSTFIX} debug libboost_filesystem-${BOOST_DEBUG_POSTFIX} debug libboost_regex-${BOOST_DEBUG_POSTFIX} debug libboost_system-${BOOST_DEBUG_POSTFIX} debug libboost_thread-${BOOST_DEBUG_POSTFIX}) + if(WITH_INTERNATIONAL) + set(BOOST_LIBRARIES ${BOOST_LIBRARIES} + optimized libboost_locale-${BOOST_POSTFIX} + debug libboost_locale-${BOOST_DEBUG_POSTFIX}) + endif(WITH_INTERNATIONAL) set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB") endif() @@ -1186,16 +1176,8 @@ elseif(WIN32) add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE) - add_definitions(-DFREE_WINDOWS) - if(WITH_INTERNATIONAL) - set(GETTEXT ${LIBDIR}/gettext) - set(GETTEXT_INCLUDE_DIRS ${GETTEXT}/include) - set(GETTEXT_LIBPATH ${GETTEXT}/lib) - set(GETTEXT_LIBRARIES intl) - endif() - set(PNG "${LIBDIR}/png") set(PNG_INCLUDE_DIR "${PNG}/include") set(PNG_LIBPATH ${PNG}/lib) # not cmake defined @@ -1313,6 +1295,11 @@ elseif(WIN32) debug boost_date_time-${BOOST_DEBUG_POSTFIX} boost_filesystem-${BOOST_DEBUG_POSTFIX} boost_regex-${BOOST_DEBUG_POSTFIX} boost_system-${BOOST_DEBUG_POSTFIX} boost_thread-${BOOST_DEBUG_POSTFIX}) + if(WITH_INTERNATIONAL) + set(BOOST_LIBRARIES ${BOOST_LIBRARIES} + optimized libboost_locale-${BOOST_POSTFIX} + debug libboost_locale-${BOOST_DEBUG_POSTFIX}) + endif(WITH_CYCLES_OSL) set(BOOST_LIBPATH ${BOOST}/lib) set(BOOST_DEFINITIONS "-DBOOST_ALL_NO_LIB -DBOOST_THREAD_USE_LIB ") endif() @@ -1347,16 +1334,6 @@ elseif(APPLE) set(WITH_LIBS10.5 ON CACHE BOOL "Use 10.5 libs" FORCE) # valid also for 10.6/10.7 endif() - if(${XCODE_VERSION} VERSION_LESS 4.3) - set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX${OSX_SYSTEM}.sdk CACHE PATH "" FORCE) # use guaranteed existing sdk - else() - # note: i don't use xcode-select path on purpose, cause also /Applications/Xcode.app would be allowed - # absolute pathes are more foolproof here ! - set(OSX_SYSROOT_PREFIX /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform) - set(OSX_DEVELOPER_PREFIX /Developer/SDKs/MacOSX${OSX_SYSTEM}.sdk) # use guaranteed existing sdk - set(CMAKE_OSX_SYSROOT ${OSX_SYSROOT_PREFIX}/${OSX_DEVELOPER_PREFIX} CACHE PATH "" FORCE) - endif() - if(WITH_LIBS10.5) set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/darwin-9.x.universal) else() @@ -1379,10 +1356,13 @@ elseif(APPLE) endif() if(WITH_JACK) - set(JACK /usr) - set(JACK_INCLUDE_DIRS ${JACK}/include/jack) - set(JACK_LIBRARIES jack) - set(JACK_LIBPATH ${JACK}/lib) + find_library(JACK_FRAMEWORK + NAMES jackmp + ) + set(JACK_INCLUDE_DIRS ${JACK_FRAMEWORK}/headers) + if(NOT JACK_FRAMEWORK) + set(WITH_JACK OFF) + endif() endif() if(WITH_CODEC_SNDFILE) @@ -1420,13 +1400,6 @@ elseif(APPLE) set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") endif() - if(WITH_INTERNATIONAL) - set(GETTEXT ${LIBDIR}/gettext) - set(GETTEXT_INCLUDE_DIRS "${GETTEXT}/include") - set(GETTEXT_LIBRARIES intl iconv) - set(GETTEXT_LIBPATH ${GETTEXT}/lib) - endif() - if(WITH_FFTW3) set(FFTW3 ${LIBDIR}/fftw3) set(FFTW3_INCLUDE_DIRS ${FFTW3}/include) @@ -1493,18 +1466,22 @@ elseif(APPLE) if(WITH_INPUT_NDOF) # This thread it *should* work and check the framework - campbell # http://www.cmake.org/pipermail/cmake/2005-December/007740.html - find_library(3D_CONNEXION_CLIENT_LIBRARY + find_library(3DCONNEXION_CLIENT_FRAMEWORK NAMES 3DconnexionClient ) - if(NOT 3D_CONNEXION_CLIENT_LIBRARY) + if(NOT 3DCONNEXION_CLIENT_FRAMEWORK) set(WITH_INPUT_NDOF OFF) endif() if(WITH_INPUT_NDOF) - set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -weak_framework 3DconnexionClient") + set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -weak_framework /Library/Frameworks/3DconnexionClient.framework/3DconnexionClient") endif() endif() + if(WITH_JACK) + set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -weak_framework jackmp") + endif() + else() set(PLATFORM_CFLAGS "-pipe -funsigned-char") set(PLATFORM_LINKFLAGS "-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Carbon -framework AGL -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework QuickTime") @@ -1568,6 +1545,10 @@ elseif(APPLE) set(BOOST ${LIBDIR}/boost) set(BOOST_INCLUDE_DIR ${BOOST}/include) set(BOOST_LIBRARIES boost_date_time-mt boost_filesystem-mt boost_regex-mt boost_system-mt boost_thread-mt) + if (WITH_INTERNATIONAL) + list(APPEND BOOST_LIBRARIES boost_locale-mt) + set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -liconv") # boost_locale needs it ! + endif() set(BOOST_LIBPATH ${BOOST}/lib) set(BOOST_DEFINITIONS) endif() @@ -1592,7 +1573,7 @@ elseif(APPLE) set(LLVM_DIRECTORY ${LIBDIR}/llvm CACHE PATH "Path to the LLVM installation") set(LLVM_VERSION "3.1" CACHE STRING "Version of LLVM to use") set(LLVM_STATIC YES) - if(LLVM_DIRECTORY) + if(EXISTS "${LLVM_DIRECTORY}/bin/llvm-config") set(LLVM_CONFIG "${LLVM_DIRECTORY}/bin/llvm-config") else() set(LLVM_CONFIG llvm-config) @@ -1607,7 +1588,7 @@ elseif(APPLE) OUTPUT_VARIABLE LLVM_LIB_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) find_library(LLVM_LIBRARY - NAMES libLLVMAnalysis.a # first of a whole bunch of libs to get + NAMES LLVMAnalysis # first of a whole bunch of libs to get PATHS ${LLVM_LIB_DIR}) message(STATUS "LLVM version = ${LLVM_VERSION}") message(STATUS "LLVM dir = ${LLVM_DIRECTORY}") @@ -1693,6 +1674,11 @@ if(WITH_CYCLES) endif() endif() +if(WITH_INTERNATIONAL) + if(NOT WITH_BOOST) + message(FATAL_ERROR "Internationalization reqires WITH_BOOST, the library may not have been found. Configure BOOST or disable WITH_INTERNATIONAL") + endif() +endif() # See TEST_SSE_SUPPORT() for how this is defined. diff --git a/SConstruct b/SConstruct index 064ae0bc0b5..b7b27baae5a 100644 --- a/SConstruct +++ b/SConstruct @@ -819,10 +819,6 @@ else: if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'): dllsources = [] - if not env['OURPLATFORM'] in ('win32-mingw', 'linuxcross'): - # For MinGW and linuxcross static linking will be used - dllsources += ['${LCGDIR}/gettext/lib/gnu_gettext.dll'] - dllsources += ['${BF_ZLIB_LIBPATH}/zlib.dll'] # Used when linking to libtiff was dynamic # keep it here until compilation on all platform would be ok diff --git a/build_files/cmake/Modules/FindPythonLibsUnix.cmake b/build_files/cmake/Modules/FindPythonLibsUnix.cmake index fdf2c29704d..7f272ee5b14 100644 --- a/build_files/cmake/Modules/FindPythonLibsUnix.cmake +++ b/build_files/cmake/Modules/FindPythonLibsUnix.cmake @@ -108,9 +108,10 @@ IF((NOT _IS_INC_DEF) OR (NOT _IS_INC_CONF_DEF) OR (NOT _IS_LIB_DEF) OR (NOT _IS_ include/python${PYTHON_VERSION}${_CURRENT_ABI_FLAGS} include/${CMAKE_LIBRARY_ARCHITECTURE}/python${PYTHON_VERSION}${_CURRENT_ABI_FLAGS} ) - IF(NOT PYTHON_INCLUDE_CONFIG_DIR AND PYTHON_INCLUDE_DIR) + IF((NOT PYTHON_INCLUDE_CONFIG_DIR) AND PYTHON_INCLUDE_DIR) # Fallback... - SET(PYTHON_INCLUDE_CONFIG_DIR ${PYTHON_INCLUDE_DIR}) + UNSET(PYTHON_INCLUDE_CONFIG_DIR CACHE) + SET(PYTHON_INCLUDE_CONFIG_DIR ${PYTHON_INCLUDE_DIR} CACHE PATH "") ENDIF() ENDIF() @@ -134,8 +135,9 @@ IF((NOT _IS_INC_DEF) OR (NOT _IS_INC_CONF_DEF) OR (NOT _IS_LIB_DEF) OR (NOT _IS_ PATH_SUFFIXES lib64 lib ) - IF(NOT PYTHON_LIBPATH AND PYTHON_LIBRARY) + IF((NOT PYTHON_LIBPATH) AND PYTHON_LIBRARY) # Fallback... + UNSET(PYTHON_LIBPATH CACHE) GET_FILENAME_COMPONENT(PYTHON_LIBPATH ${PYTHON_LIBRARY} PATH) ENDIF() ENDIF() @@ -177,7 +179,6 @@ INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonLibsUnix DEFAULT_MSG PYTHON_LIBRARY PYTHON_LIBPATH PYTHON_INCLUDE_DIR PYTHON_INCLUDE_CONFIG_DIR) - IF(PYTHONLIBSUNIX_FOUND) # Assign cache items SET(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIR} ${PYTHON_INCLUDE_CONFIG_DIR}) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 3c321cc60be..2d9de5a5792 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -196,10 +196,6 @@ macro(SETUP_LIBDIRS) if(WITH_PYTHON) # AND NOT WITH_PYTHON_MODULE # WIN32 needs link_directories(${PYTHON_LIBPATH}) endif() - if(WITH_INTERNATIONAL) - link_directories(${ICONV_LIBPATH}) - link_directories(${GETTEXT_LIBPATH}) - endif() if(WITH_SDL) link_directories(${SDL_LIBPATH}) endif() @@ -287,14 +283,6 @@ macro(setup_liblinks target_link_libraries(${target} ${GLEW_LIBRARY}) endif() - if(WITH_INTERNATIONAL) - target_link_libraries(${target} ${GETTEXT_LIBRARIES}) - - if(WIN32 AND NOT UNIX) - target_link_libraries(${target} ${ICONV_LIBRARIES}) - endif() - endif() - if(WITH_OPENAL) target_link_libraries(${target} ${OPENAL_LIBRARY}) endif() diff --git a/build_files/scons/config/darwin-config.py b/build_files/scons/config/darwin-config.py index afab4131de8..ea7d60a62eb 100644 --- a/build_files/scons/config/darwin-config.py +++ b/build_files/scons/config/darwin-config.py @@ -223,11 +223,6 @@ BF_ZLIB_LIB = 'z' WITH_BF_INTERNATIONAL = True -BF_GETTEXT = LIBDIR + '/gettext' -BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'intl' -BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' - WITH_BF_GAMEENGINE = True WITH_BF_PLAYER = True WITH_BF_OCEANSIM = True @@ -297,6 +292,8 @@ WITH_BF_BOOST = True BF_BOOST = LIBDIR + '/boost' BF_BOOST_INC = BF_BOOST + '/include' BF_BOOST_LIB = 'boost_date_time-mt boost_filesystem-mt boost_regex-mt boost_system-mt boost_thread-mt' +if WITH_BF_INTERNATIONAL: + BF_BOOST_LIB += ' boost_locale-mt' BF_BOOST_LIBPATH = BF_BOOST + '/lib' WITH_BF_CYCLES_CUDA_BINARIES = False diff --git a/build_files/scons/config/freebsd7-config.py b/build_files/scons/config/freebsd7-config.py index 412b08d895b..61358de12b4 100644 --- a/build_files/scons/config/freebsd7-config.py +++ b/build_files/scons/config/freebsd7-config.py @@ -77,11 +77,6 @@ BF_ZLIB_LIB = 'z' WITH_BF_INTERNATIONAL = True -BF_GETTEXT = '/usr/local' -BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'gettextlib' -BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' - WITH_BF_GAMEENGINE = False WITH_BF_PLAYER = True WITH_BF_OCEANSIM = True diff --git a/build_files/scons/config/freebsd8-config.py b/build_files/scons/config/freebsd8-config.py index ece86f799c3..0f6c7f64786 100644 --- a/build_files/scons/config/freebsd8-config.py +++ b/build_files/scons/config/freebsd8-config.py @@ -77,11 +77,6 @@ BF_ZLIB_LIB = 'z' WITH_BF_INTERNATIONAL = True -BF_GETTEXT = '/usr/local' -BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'gettextlib' -BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' - WITH_BF_GAMEENGINE = False WITH_BF_PLAYER = True WITH_BF_OCEANSIM = True diff --git a/build_files/scons/config/freebsd9-config.py b/build_files/scons/config/freebsd9-config.py index a31c6da90f0..c0df68f99ad 100644 --- a/build_files/scons/config/freebsd9-config.py +++ b/build_files/scons/config/freebsd9-config.py @@ -77,11 +77,6 @@ BF_ZLIB_LIB = 'z' WITH_BF_INTERNATIONAL = True -BF_GETTEXT = '/usr/local' -BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'gettextlib' -BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' - WITH_BF_GAMEENGINE = False WITH_BF_PLAYER = True WITH_BF_OCEANSIM = True diff --git a/build_files/scons/config/linux-config.py b/build_files/scons/config/linux-config.py index 45f6602e4dd..9bab4bc1dad 100644 --- a/build_files/scons/config/linux-config.py +++ b/build_files/scons/config/linux-config.py @@ -89,13 +89,6 @@ BF_ZLIB_LIB = 'z' WITH_BF_INTERNATIONAL = True -BF_GETTEXT = '/usr' -BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'gettextlib' -BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' -#WITH_BF_GETTEXT_STATIC = True -#BF_GETTEXT_LIB_STATIC = '${BF_GETTEXT}/lib/libgettextlib.a' - WITH_BF_GAMEENGINE = True WITH_BF_PLAYER = True WITH_BF_OCEANSIM = True @@ -233,6 +226,8 @@ if not os.path.exists(LCGDIR + '/boost'): BF_BOOST = '/usr' BF_BOOST_INC = BF_BOOST + '/include' BF_BOOST_LIB = 'boost_date_time boost_filesystem boost_regex boost_system boost_thread' +if WITH_BF_INTERNATIONAL: + BF_BOOST_LIB += ' boost_locale' BF_BOOST_LIBPATH = BF_BOOST + '/lib' WITH_BF_CYCLES = WITH_BF_OIIO and WITH_BF_BOOST diff --git a/build_files/scons/config/linuxcross-config.py b/build_files/scons/config/linuxcross-config.py index 6866241793b..63264807720 100644 --- a/build_files/scons/config/linuxcross-config.py +++ b/build_files/scons/config/linuxcross-config.py @@ -83,11 +83,6 @@ BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib' WITH_BF_INTERNATIONAL = True -BF_GETTEXT = LIBDIR + '/gcc/gettext' -BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'intl' -BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' - WITH_BF_GAMEENGINE = True WITH_BF_PLAYER = False WITH_BF_OCEANSIM = True diff --git a/build_files/scons/config/win32-mingw-config.py b/build_files/scons/config/win32-mingw-config.py index 0a72d87bb2a..768722fac32 100644 --- a/build_files/scons/config/win32-mingw-config.py +++ b/build_files/scons/config/win32-mingw-config.py @@ -83,11 +83,6 @@ BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib' WITH_BF_INTERNATIONAL = True -BF_GETTEXT = LIBDIR + '/gettext' -BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'intl' -BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' - WITH_BF_OPENJPEG = True BF_OPENJPEG = '#extern/libopenjpeg' BF_OPENJPEG_LIB = '' @@ -169,6 +164,8 @@ WITH_BF_BOOST = True BF_BOOST = LIBDIR + '/boost' BF_BOOST_INC = BF_BOOST + '/include' BF_BOOST_LIB = 'boost_date_time-mgw46-mt-s-1_49 boost_filesystem-mgw46-mt-s-1_49 boost_regex-mgw46-mt-s-1_49 boost_system-mgw46-mt-s-1_49 boost_thread-mgw46-mt-s-1_49' +if WITH_BF_INTERNATIONAL: + BF_BOOST_LIB += ' boost_locale-mgw46-mt-s-1_49' BF_BOOST_LIBPATH = BF_BOOST + '/lib' #Ray trace optimization diff --git a/build_files/scons/config/win32-vc-config.py b/build_files/scons/config/win32-vc-config.py index b77ff8e70e0..c093fdb4a99 100644 --- a/build_files/scons/config/win32-vc-config.py +++ b/build_files/scons/config/win32-vc-config.py @@ -87,11 +87,6 @@ BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib' WITH_BF_INTERNATIONAL = True -BF_GETTEXT = LIBDIR + '/gettext' -BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'gnu_gettext' -BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' - WITH_BF_GAMEENGINE = True WITH_BF_PLAYER = True WITH_BF_OCEANSIM = True @@ -171,6 +166,8 @@ WITH_BF_BOOST = True BF_BOOST = '${LIBDIR}/boost' BF_BOOST_INC = '${BF_BOOST}/include' BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_49 libboost_filesystem-vc90-mt-s-1_49 libboost_regex-vc90-mt-s-1_49 libboost_system-vc90-mt-s-1_49 libboost_thread-vc90-mt-s-1_49' +if WITH_BF_INTERNATIONAL: + BF_BOOST_LIB += ' libboost_locale-vc90-mt-s-1_49' BF_BOOST_LIBPATH = '${BF_BOOST}/lib' #CUDA diff --git a/build_files/scons/config/win64-mingw-config.py b/build_files/scons/config/win64-mingw-config.py index 838822bbbcb..bca3df16289 100644 --- a/build_files/scons/config/win64-mingw-config.py +++ b/build_files/scons/config/win64-mingw-config.py @@ -80,11 +80,6 @@ BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib' WITH_BF_INTERNATIONAL = True -BF_GETTEXT = LIBDIR + '/gettext' -BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'intl' -BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' - WITH_BF_OPENJPEG = True BF_OPENJPEG = '#extern/libopenjpeg' BF_OPENJPEG_LIB = '' @@ -169,6 +164,8 @@ WITH_BF_BOOST = True BF_BOOST = LIBDIR + '/boost' BF_BOOST_INC = BF_BOOST + '/include' BF_BOOST_LIB = 'boost_date_time-mgw47-mt-s-1_49 boost_date_time-mgw47-mt-sd-1_49 boost_filesystem-mgw47-mt-s-1_49 boost_filesystem-mgw47-mt-sd-1_49 boost_regex-mgw47-mt-s-1_49 boost_regex-mgw47-mt-sd-1_49 boost_system-mgw47-mt-s-1_49 boost_system-mgw47-mt-sd-1_49 boost_thread-mgw47-mt-s-1_49 boost_thread-mgw47-mt-sd-1_49' +if WITH_BF_INTERNATIONAL: + BF_BOOST_LIB += ' boost_locale-mgw47-mt-s-1_49 boost_locale-mgw47-mt-sd-1_49' BF_BOOST_LIBPATH = BF_BOOST + '/lib' #Ray trace optimization diff --git a/build_files/scons/config/win64-vc-config.py b/build_files/scons/config/win64-vc-config.py index 4b719469c39..9d3f42f7c7b 100644 --- a/build_files/scons/config/win64-vc-config.py +++ b/build_files/scons/config/win64-vc-config.py @@ -83,11 +83,6 @@ BF_ZLIB_LIBPATH = '${BF_ZLIB}/lib' WITH_BF_INTERNATIONAL = True -BF_GETTEXT = LIBDIR + '/gettext' -BF_GETTEXT_INC = '${BF_GETTEXT}/include' -BF_GETTEXT_LIB = 'gnu_gettext' -BF_GETTEXT_LIBPATH = '${BF_GETTEXT}/lib' - WITH_BF_GAMEENGINE = True WITH_BF_PLAYER = True WITH_BF_OCEANSIM = True @@ -169,6 +164,8 @@ WITH_BF_BOOST = True BF_BOOST = '${LIBDIR}/boost' BF_BOOST_INC = '${BF_BOOST}/include' BF_BOOST_LIB = 'libboost_date_time-vc90-mt-s-1_49 libboost_filesystem-vc90-mt-s-1_49 libboost_regex-vc90-mt-s-1_49 libboost_system-vc90-mt-s-1_49 libboost_thread-vc90-mt-s-1_49' +if WITH_BF_INTERNATIONAL: + BF_BOOST_LIB += ' libboost_locale-vc90-mt-s-1_49' BF_BOOST_LIBPATH = '${BF_BOOST}/lib' #CUDA diff --git a/build_files/scons/tools/Blender.py b/build_files/scons/tools/Blender.py index 8443e7afb19..6baa96aae60 100644 --- a/build_files/scons/tools/Blender.py +++ b/build_files/scons/tools/Blender.py @@ -173,9 +173,6 @@ def setup_staticlibs(lenv): if lenv['WITH_BF_FFMPEG'] and lenv['WITH_BF_STATICFFMPEG']: statlibs += Split(lenv['BF_FFMPEG_LIB_STATIC']) if lenv['WITH_BF_INTERNATIONAL']: - libincs += Split(lenv['BF_GETTEXT_LIBPATH']) - if lenv['WITH_BF_GETTEXT_STATIC']: - statlibs += Split(lenv['BF_GETTEXT_LIB_STATIC']) if lenv['WITH_BF_FREETYPE_STATIC']: statlibs += Split(lenv['BF_FREETYPE_LIB_STATIC']) if lenv['WITH_BF_OPENAL']: @@ -252,8 +249,6 @@ def setup_syslibs(lenv): syslibs.append(lenv['BF_PYTHON_LIB']+'_d') else: syslibs.append(lenv['BF_PYTHON_LIB']) - if lenv['WITH_BF_INTERNATIONAL'] and not lenv['WITH_BF_GETTEXT_STATIC']: - syslibs += Split(lenv['BF_GETTEXT_LIB']) if lenv['WITH_BF_OPENAL']: if not lenv['WITH_BF_STATICOPENAL']: syslibs += Split(lenv['BF_OPENAL_LIB']) diff --git a/build_files/scons/tools/btools.py b/build_files/scons/tools/btools.py index 19652bb7851..90d3f578d98 100644 --- a/build_files/scons/tools/btools.py +++ b/build_files/scons/tools/btools.py @@ -116,7 +116,6 @@ def validate_arguments(args, bc): 'WITH_BF_TIFF', 'BF_TIFF', 'BF_TIFF_INC', 'BF_TIFF_LIB', 'BF_TIFF_LIBPATH', 'WITH_BF_STATICTIFF', 'BF_TIFF_LIB_STATIC', 'WITH_BF_ZLIB', 'BF_ZLIB', 'BF_ZLIB_INC', 'BF_ZLIB_LIB', 'BF_ZLIB_LIBPATH', 'WITH_BF_STATICZLIB', 'BF_ZLIB_LIB_STATIC', 'WITH_BF_INTERNATIONAL', - 'BF_GETTEXT', 'BF_GETTEXT_INC', 'BF_GETTEXT_LIB', 'WITH_BF_GETTEXT_STATIC', 'BF_GETTEXT_LIB_STATIC', 'BF_GETTEXT_LIBPATH', 'WITH_BF_ICONV', 'BF_ICONV', 'BF_ICONV_INC', 'BF_ICONV_LIB', 'BF_ICONV_LIBPATH', 'WITH_BF_GAMEENGINE', 'WITH_BF_BULLET', 'BF_BULLET', 'BF_BULLET_INC', 'BF_BULLET_LIB', @@ -381,15 +380,8 @@ def read_opts(env, cfg, args): ('BF_ZLIB_LIBPATH', 'ZLib library path', ''), ('BF_ZLIB_LIB_STATIC', 'ZLib static library', ''), - (BoolVariable('WITH_BF_INTERNATIONAL', 'Use Gettext if true', True)), + (BoolVariable('WITH_BF_INTERNATIONAL', 'Use Boost::locale if true', True)), - ('BF_GETTEXT', 'gettext base path', ''), - ('BF_GETTEXT_INC', 'gettext include path', ''), - ('BF_GETTEXT_LIB', 'gettext library', ''), - (BoolVariable('WITH_BF_GETTEXT_STATIC', 'Use static gettext library if true', False)), - ('BF_GETTEXT_LIB_STATIC', 'static gettext library', ''), - ('BF_GETTEXT_LIBPATH', 'gettext library path', ''), - (BoolVariable('WITH_BF_ICONV', 'Use iconv if true', True)), ('BF_ICONV', 'iconv base path', ''), ('BF_ICONV_INC', 'iconv include path', ''), diff --git a/doc/python_api/rst/bge.types.rst b/doc/python_api/rst/bge.types.rst index fdaeb61173f..7ce913a54f3 100644 --- a/doc/python_api/rst/bge.types.rst +++ b/doc/python_api/rst/bge.types.rst @@ -1957,6 +1957,28 @@ Types :return: a polygon object. :rtype: :class:`PolyProxy` + .. method:: transform(matid, matrix) + + Transforms the vertices of a mesh. + + :arg matid: material index, -1 transforms all. + :type matid: integer + :arg matrix: transformation matrix. + :type matrix: 4x4 matrix [[float]] + + .. method:: transform_uv(matid, matrix, uv_index=-1, uv_index_from=-1) + + Transforms the vertices UV's of a mesh. + + :arg matid: material index, -1 transforms all. + :type matid: integer + :arg matrix: transformation matrix. + :type matrix: 4x4 matrix [[float]] + :arg uv_index: optional uv index, -1 for all, otherwise 0 or 1. + :type uv_index: integer + :arg uv_index_from: optional uv index to copy from, -1 to transform the current uv. + :type uv_index_from: integer + .. class:: SCA_MouseSensor(SCA_ISensor) Mouse Sensor logic brick. @@ -3113,6 +3135,12 @@ Types :type: list + .. attribute:: gravity + + The scene gravity using the world x, y and z axis. + + :type: list [fx, fy, fz] + .. method:: addObject(object, other, time=0) Adds an object to the scene like the Add Object Actuator would. diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index cb2fc239859..be797c45ba1 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -65,6 +65,10 @@ if(WITH_CYCLES) add_subdirectory(cycles) endif() +if(WITH_INTERNATIONAL) + add_subdirectory(locale) +endif() + # only windows needs utf16 converter if(WIN32) add_subdirectory(utfconv) diff --git a/intern/SConscript b/intern/SConscript index 59e412333b0..5360ce4ea88 100644 --- a/intern/SConscript +++ b/intern/SConscript @@ -30,6 +30,9 @@ if env['WITH_BF_CYCLES']: if env['WITH_BF_BOOLEAN']: SConscript(['bsp/SConscript']) +if env['WITH_BF_INTERNATIONAL']: + SConscript(['locale/SConscript']) + if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-mingw', 'linuxcross', 'win64-vc'): SConscript(['utfconv/SConscript']) diff --git a/intern/container/CTR_HashedPtr.h b/intern/container/CTR_HashedPtr.h index b7ac460f270..ee832eee153 100644 --- a/intern/container/CTR_HashedPtr.h +++ b/intern/container/CTR_HashedPtr.h @@ -46,13 +46,13 @@ class CTR_HashedPtr void *m_valptr; public: CTR_HashedPtr(void *val) : m_valptr(val) { - }; + } unsigned int hash() const { return CTR_Hash(m_valptr); - }; + } inline friend bool operator ==(const CTR_HashedPtr & rhs, const CTR_HashedPtr & lhs) { return rhs.m_valptr == lhs.m_valptr; - }; + } void *getValue() const { return m_valptr; } diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 7562ee0a0a5..7495a98aed1 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -44,10 +44,6 @@ if(WITH_CYCLES_OSL) include_directories(${OSL_INCLUDES}) endif() -if(WITH_CYCLES_PARTIO) - add_definitions(-DWITH_PARTIO) -endif() - if(WITH_CYCLES_CUDA_BINARIES) add_definitions(-DWITH_CUDA_BINARIES) endif() @@ -69,7 +65,10 @@ if(WITH_CYCLES_BLENDER) add_subdirectory(blender) endif() -add_subdirectory(app) +if(WITH_CYCLES_TEST) + add_subdirectory(app) +endif() + add_subdirectory(bvh) add_subdirectory(device) add_subdirectory(doc) diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt index 83b3f731ffe..3fb8aaf934f 100644 --- a/intern/cycles/app/CMakeLists.txt +++ b/intern/cycles/app/CMakeLists.txt @@ -35,10 +35,6 @@ if(WITH_CYCLES_OSL) list(APPEND LIBRARIES cycles_kernel_osl ${OSL_LIBRARIES}) endif() -if(WITH_CYCLES_PARTIO) - list(APPEND LIBRARIES ${PARTIO_LIBRARIES}) -endif() - include_directories(${INC}) include_directories(SYSTEM ${INC_SYS}) diff --git a/intern/cycles/app/cycles_test.cpp b/intern/cycles/app/cycles_test.cpp index e921cc46fe4..625e8cc1706 100644 --- a/intern/cycles/app/cycles_test.cpp +++ b/intern/cycles/app/cycles_test.cpp @@ -326,7 +326,7 @@ using namespace ccl; int main(int argc, const char **argv) { - path_init("../build/bin/2.59/scripts/addons/cycles/"); + path_init(); options_parse(argc, argv); diff --git a/intern/cycles/blender/CCL_api.h b/intern/cycles/blender/CCL_api.h index 469d63d1530..b8a30b71717 100644 --- a/intern/cycles/blender/CCL_api.h +++ b/intern/cycles/blender/CCL_api.h @@ -23,12 +23,12 @@ extern "C" { #endif -/* returns a list of devices for selection, array is name NULL pointer +/* returns a list of devices for selection, array is empty identifier * terminated and must not be freed */ typedef struct CCLDeviceInfo { - const char *identifier; - const char *name; + char identifier[128]; + char name[512]; int value; } CCLDeviceInfo; diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index 16697c08b2b..0fad2ac5618 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -48,7 +48,11 @@ class CyclesRender(bpy.types.RenderEngine): # final render def update(self, data, scene): - engine.create(self, data, scene) + if not self.session: + engine.create(self, data, scene) + else: + engine.reset(self, data, scene) + engine.update(self, data, scene) def render(self, scene): diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index e4f80cb4d5d..ca5cbee9325 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -61,6 +61,13 @@ def render(engine): _cycles.render(engine.session) +def reset(engine, data, scene): + import _cycles + data = data.as_pointer() + scene = scene.as_pointer() + _cycles.reset(engine.session, data, scene) + + def update(engine, data, scene): import _cycles _cycles.sync(engine.session) diff --git a/intern/cycles/blender/addon/enums.py b/intern/cycles/blender/addon/enums.py index a98a6aab4c4..82b48973ca1 100644 --- a/intern/cycles/blender/addon/enums.py +++ b/intern/cycles/blender/addon/enums.py @@ -57,8 +57,7 @@ aperture_types = ( panorama_types = ( ('EQUIRECTANGULAR', "Equirectangular", "Render the scene with a spherical camera, also known as Lat Long panorama"), - ('FISHEYE_EQUIDISTANT', "Fisheye Equidistant", "Ignore the sensor dimensions"), + ('FISHEYE_EQUIDISTANT', "Fisheye Equidistant", "Ideal for fulldomes, ignore the sensor dimensions"), ('FISHEYE_EQUISOLID', "Fisheye Equisolid", - "Similar to most fisheye modern lens, takes sensor dimensions into consideration " - "(for fulldomes use it with a square sensor ratio)"), + "Similar to most fisheye modern lens, takes sensor dimensions into consideration"), ) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 9cc58e65bef..4a651eb5aab 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -216,6 +216,10 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): sub.label(text="Viewport:") sub.prop(cscene, "preview_start_resolution") + sub = col.column(align=True) + sub.label(text="Final Render:") + sub.prop(rd, "use_persistent_data", text="Persistent Images") + class CyclesRender_PT_layers(CyclesButtonsPanel, Panel): bl_label = "Layers" @@ -953,7 +957,7 @@ def draw_device(self, context): elif device_type == 'OPENCL' and cscene.feature_set == 'EXPERIMENTAL': layout.prop(cscene, "device") - if engine.with_osl() and (cscene.device == 'CPU' or device_type == 'None'): + if engine.with_osl() and (cscene.device == 'CPU' or device_type == 'NONE'): layout.prop(cscene, "shading_system") diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp index af16e210301..61fe7cf254d 100644 --- a/intern/cycles/blender/blender_camera.cpp +++ b/intern/cycles/blender/blender_camera.cpp @@ -56,10 +56,8 @@ struct BlenderCamera { float sensor_width; float sensor_height; - float border_left; - float border_right; - float border_bottom; - float border_top; + BoundBox2D border; + BoundBox2D pano_viewplane; Transform matrix; }; @@ -75,8 +73,10 @@ static void blender_camera_init(BlenderCamera *bcam) bcam->sensor_height = 18.0f; bcam->sensor_fit = BlenderCamera::AUTO; bcam->shuttertime = 1.0f; - bcam->border_right = 1.0f; - bcam->border_top = 1.0f; + bcam->border.right = 1.0f; + bcam->border.top = 1.0f; + bcam->pano_viewplane.right = 1.0f; + bcam->pano_viewplane.top = 1.0f; } static float blender_camera_focal_distance(BL::Object b_ob, BL::Camera b_camera) @@ -199,7 +199,7 @@ static Transform blender_camera_matrix(const Transform& tfm, CameraType type) } static void blender_camera_viewplane(BlenderCamera *bcam, int width, int height, - float *left, float *right, float *bottom, float *top, float *aspectratio, float *sensor_size) + BoundBox2D *viewplane, float *aspectratio, float *sensor_size) { /* dimensions */ float xratio = width*bcam->pixelaspect.x; @@ -244,32 +244,26 @@ static void blender_camera_viewplane(BlenderCamera *bcam, int width, int height, if(bcam->type == CAMERA_PANORAMA) { /* set viewplane */ - *left = 0.0f; - *right = 1.0f; - *bottom = 0.0f; - *top = 1.0f; + *viewplane = bcam->pano_viewplane; } else { /* set viewplane */ - *left = -xaspect; - *right = xaspect; - *bottom = -yaspect; - *top = yaspect; + viewplane->left = -xaspect; + viewplane->right = xaspect; + viewplane->bottom = -yaspect; + viewplane->top = yaspect; /* zoom for 3d camera view */ - *left *= bcam->zoom; - *right *= bcam->zoom; - *bottom *= bcam->zoom; - *top *= bcam->zoom; + *viewplane = (*viewplane) * bcam->zoom; /* modify viewplane with camera shift and 3d camera view offset */ float dx = 2.0f*(*aspectratio*bcam->shift.x + bcam->offset.x*xaspect*2.0f); float dy = 2.0f*(*aspectratio*bcam->shift.y + bcam->offset.y*yaspect*2.0f); - *left += dx; - *right += dx; - *bottom += dy; - *top += dy; + viewplane->left += dx; + viewplane->right += dx; + viewplane->bottom += dy; + viewplane->top += dy; } } @@ -281,7 +275,7 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int /* viewplane */ blender_camera_viewplane(bcam, width, height, - &cam->left, &cam->right, &cam->bottom, &cam->top, &aspectratio, &sensor_size); + &cam->viewplane, &aspectratio, &sensor_size); /* sensor */ cam->sensorwidth = bcam->sensor_width; @@ -314,10 +308,7 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int cam->shuttertime = bcam->shuttertime; /* border */ - cam->border_left = bcam->border_left; - cam->border_right = bcam->border_right; - cam->border_bottom = bcam->border_bottom; - cam->border_top = bcam->border_top; + cam->border = bcam->border; /* set update flag */ if(cam->modified(prevcam)) @@ -340,10 +331,10 @@ void BlenderSync::sync_camera(BL::Object b_override, int width, int height) /* border */ if(r.use_border()) { - bcam.border_left = r.border_min_x(); - bcam.border_right = r.border_max_x(); - bcam.border_bottom = r.border_min_y(); - bcam.border_top = r.border_max_y(); + bcam.border.left = r.border_min_x(); + bcam.border.right = r.border_max_x(); + bcam.border.bottom = r.border_min_y(); + bcam.border.top = r.border_max_y(); } /* camera object */ @@ -381,6 +372,9 @@ void BlenderSync::sync_camera_motion(BL::Object b_ob, int motion) /* Sync 3D View Camera */ +static void blender_camera_view_subset(BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d, + BL::RegionView3D b_rv3d, int width, int height, BoundBox2D *view_box, BoundBox2D *cam_box); + static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height, bool skip_panorama = false) { /* 3d view parameters */ @@ -396,14 +390,25 @@ static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL: if(b_ob) { blender_camera_from_object(bcam, b_ob, skip_panorama); - /* magic zoom formula */ - bcam->zoom = (float)b_rv3d.view_camera_zoom(); - bcam->zoom = (1.41421f + bcam->zoom/50.0f); - bcam->zoom *= bcam->zoom; - bcam->zoom = 2.0f/bcam->zoom; - - /* offset */ - bcam->offset = get_float2(b_rv3d.view_camera_offset()); + if(!skip_panorama && bcam->type == CAMERA_PANORAMA) { + /* in panorama camera view, we map viewplane to camera border */ + BoundBox2D view_box, cam_box; + + blender_camera_view_subset(b_scene, b_ob, b_v3d, b_rv3d, width, height, + &view_box, &cam_box); + + bcam->pano_viewplane = view_box.make_relative_to(cam_box); + } + else { + /* magic zoom formula */ + bcam->zoom = (float)b_rv3d.view_camera_zoom(); + bcam->zoom = (1.41421f + bcam->zoom/50.0f); + bcam->zoom *= bcam->zoom; + bcam->zoom = 2.0f/bcam->zoom; + + /* offset */ + bcam->offset = get_float2(b_rv3d.view_camera_offset()); + } } } else if(b_rv3d.view_perspective() == BL::RegionView3D::view_perspective_ORTHO) { @@ -427,6 +432,37 @@ static void blender_camera_from_view(BlenderCamera *bcam, BL::Scene b_scene, BL: bcam->matrix = transform_inverse(get_transform(b_rv3d.view_matrix())); } +static void blender_camera_view_subset(BL::Scene b_scene, BL::Object b_ob, BL::SpaceView3D b_v3d, + BL::RegionView3D b_rv3d, int width, int height, BoundBox2D *view_box, BoundBox2D *cam_box) +{ + BL::RenderSettings r = b_scene.render(); + BoundBox2D cam, view; + float view_aspect, cam_aspect, sensor_size; + + /* get viewport viewplane */ + BlenderCamera view_bcam; + blender_camera_init(&view_bcam); + blender_camera_from_view(&view_bcam, b_scene, b_v3d, b_rv3d, width, height, true); + + blender_camera_viewplane(&view_bcam, width, height, + &view, &view_aspect, &sensor_size); + + /* get camera viewplane */ + BlenderCamera cam_bcam; + blender_camera_init(&cam_bcam); + blender_camera_from_object(&cam_bcam, b_ob, true); + + width = (int)(r.resolution_x()*r.resolution_percentage()/100); + height = (int)(r.resolution_y()*r.resolution_percentage()/100); + + blender_camera_viewplane(&cam_bcam, width, height, + &cam, &cam_aspect, &sensor_size); + + /* return */ + *view_box = view * (1.0f/view_aspect); + *cam_box = cam * (1.0f/cam_aspect); +} + static void blender_camera_border(BlenderCamera *bcam, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height) { @@ -442,10 +478,10 @@ static void blender_camera_border(BlenderCamera *bcam, BL::Scene b_scene, BL::Sp * assume viewport has got correctly clamped border already */ if(b_v3d.use_render_border()) { - bcam->border_left = b_v3d.render_border_min_x(); - bcam->border_right = b_v3d.render_border_max_x(); - bcam->border_bottom = b_v3d.render_border_min_y(); - bcam->border_top = b_v3d.render_border_max_y(); + bcam->border.left = b_v3d.render_border_min_x(); + bcam->border.right = b_v3d.render_border_max_x(); + bcam->border.bottom = b_v3d.render_border_min_y(); + bcam->border.top = b_v3d.render_border_max_y(); return; } @@ -458,60 +494,20 @@ static void blender_camera_border(BlenderCamera *bcam, BL::Scene b_scene, BL::Sp if(!b_ob) return; - bcam->border_left = r.border_min_x(); - bcam->border_right = r.border_max_x(); - bcam->border_bottom = r.border_min_y(); - bcam->border_top = r.border_max_y(); - - float cam_left, cam_right, cam_bottom, cam_top; - float view_left, view_right, view_bottom, view_top; - float view_aspect, cam_aspect, sensor_size; - - /* get viewport viewplane */ - BlenderCamera view_bcam; - blender_camera_init(&view_bcam); - blender_camera_from_view(&view_bcam, b_scene, b_v3d, b_rv3d, width, height, true); - - blender_camera_viewplane(&view_bcam, width, height, - &view_left, &view_right, &view_bottom, &view_top, &view_aspect, &sensor_size); - - view_left /= view_aspect; - view_right /= view_aspect; - view_bottom /= view_aspect; - view_top /= view_aspect; + bcam->border.left = r.border_min_x(); + bcam->border.right = r.border_max_x(); + bcam->border.bottom = r.border_min_y(); + bcam->border.top = r.border_max_y(); - /* get camera viewplane */ - BlenderCamera cam_bcam; - blender_camera_init(&cam_bcam); - blender_camera_from_object(&cam_bcam, b_ob, true); - - width = (int)(r.resolution_x()*r.resolution_percentage()/100); - height = (int)(r.resolution_y()*r.resolution_percentage()/100); - - blender_camera_viewplane(&cam_bcam, width, height, - &cam_left, &cam_right, &cam_bottom, &cam_top, &cam_aspect, &sensor_size); + /* determine camera viewport subset */ + BoundBox2D view_box, cam_box; - cam_left /= cam_aspect; - cam_right /= cam_aspect; - cam_bottom /= cam_aspect; - cam_top /= cam_aspect; + blender_camera_view_subset(b_scene, b_ob, b_v3d, b_rv3d, width, height, + &view_box, &cam_box); /* determine viewport subset matching camera border */ - float tmp_left = ((cam_left - view_left) / (view_right - view_left)); - float tmp_right = ((cam_right - view_left) / (view_right - view_left)); - float tmp_bottom = ((cam_bottom - view_bottom) / (view_top - view_bottom)); - float tmp_top = ((cam_top - view_bottom) / (view_top - view_bottom)); - - bcam->border_left = tmp_left + bcam->border_left*(tmp_right - tmp_left); - bcam->border_right = tmp_left + bcam->border_right*(tmp_right - tmp_left); - bcam->border_bottom = tmp_bottom + bcam->border_bottom*(tmp_top - tmp_bottom); - bcam->border_top = tmp_bottom + bcam->border_top*(tmp_top - tmp_bottom); - - /* clamp */ - bcam->border_left = clamp(bcam->border_left, 0.0f, 1.0f); - bcam->border_right = clamp(bcam->border_right, 0.0f, 1.0f); - bcam->border_bottom = clamp(bcam->border_bottom, 0.0f, 1.0f); - bcam->border_top = clamp(bcam->border_top, 0.0f, 1.0f); + cam_box = cam_box.make_relative_to(view_box); + bcam->border = cam_box.subset(bcam->border).clamp(); } void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height) @@ -539,10 +535,10 @@ BufferParams BlenderSync::get_buffer_params(BL::Scene b_scene, BL::SpaceView3D b if(use_border) { /* border render */ - params.full_x = cam->border_left*width; - params.full_y = cam->border_bottom*height; - params.width = (int)(cam->border_right*width) - params.full_x; - params.height = (int)(cam->border_top*height) - params.full_y; + params.full_x = cam->border.left*width; + params.full_y = cam->border.bottom*height; + params.width = (int)(cam->border.right*width) - params.full_x; + params.height = (int)(cam->border.top*height) - params.full_y; /* survive in case border goes out of view or becomes too small */ params.width = max(params.width, 1); diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 1b920249733..e8fa5c0ff3d 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -86,11 +86,11 @@ static uint object_ray_visibility(BL::Object b_ob) /* Light */ -void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm) +void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm) { /* test if we need to sync */ Light *light; - ObjectKey key(b_parent, b_index, b_ob); + ObjectKey key(b_parent, persistent_id, b_ob); if(!light_map.sync(&light, b_ob, b_parent, key)) return; @@ -196,23 +196,24 @@ void BlenderSync::sync_background_light() /* Object */ -void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::DupliObject b_dupli_ob, Transform& tfm, uint layer_flag, int motion, int particle_id) +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) { BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent); /* light is handled separately */ if(object_is_light(b_ob)) { if(!motion) - sync_light(b_parent, b_index, b_ob, tfm); - return; + sync_light(b_parent, persistent_id, b_ob, tfm); + + return NULL; } /* only interested in object that we can create meshes from */ if(!object_is_mesh(b_ob)) - return; + return NULL; /* key to lookup object */ - ObjectKey key(b_parent, b_index, b_ob); + ObjectKey key(b_parent, persistent_id, b_ob); Object *object; /* motion vector case */ @@ -234,7 +235,7 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::DupliObject sync_mesh_motion(b_ob, object->mesh, motion); } - return; + return object; } /* test if we need to sync */ @@ -248,13 +249,15 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::DupliObject /* mesh sync */ object->mesh = sync_mesh(b_ob, object_updated); + /* sspecial case not tracked by object update flags */ if(use_holdout != object->use_holdout) { object->use_holdout = use_holdout; scene->object_manager->tag_update(scene); + object_updated = true; } - /* object sync */ - /* transform comparison should not be needed, but duplis don't work perfect + /* object sync + * transform comparison should not be needed, but duplis don't work perfect * in the depsgraph and may not signal changes, so this is a workaround */ if(object_updated || (object->mesh && object->mesh->need_update) || tfm != object->tfm) { object->name = b_ob.name().c_str(); @@ -264,7 +267,15 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::DupliObject object->motion.post = tfm; object->use_motion = false; - object->random_id = hash_int_2d(hash_string(object->name.c_str()), b_index); + /* random number */ + object->random_id = hash_string(object->name.c_str()); + + if(persistent_id) { + for(int i = 0; i < OBJECT_PERSISTENT_ID_SIZE; i++) + object->random_id = hash_int_2d(object->random_id, persistent_id[i]); + } + else + object->random_id = hash_int_2d(object->random_id, 0); /* visibility flags for both parent */ object->visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL; @@ -273,6 +284,10 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::DupliObject object->random_id ^= hash_int(hash_string(b_parent.name().c_str())); } + /* make holdout objects on excluded layer invisible for non-camera rays */ + if(use_holdout && (layer_flag & render_layer.exclude_layer)) + object->visibility &= ~(PATH_RAY_ALL - PATH_RAY_CAMERA); + /* camera flag is not actually used, instead is tested * against render layer flags */ if(object->visibility & PATH_RAY_CAMERA) { @@ -289,10 +304,10 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::DupliObject object->dupli_uv = make_float2(0.0f, 0.0f); } - object->particle_id = particle_id; - object->tag_update(scene); } + + return object; } /* Object Loop */ @@ -314,7 +329,9 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) /* object loop */ BL::Scene::objects_iterator b_ob; BL::Scene b_sce = b_scene; - int particle_offset = 1; /* first particle is dummy for regular, non-instanced objects */ + + /* global particle index counter */ + int particle_id = 1; bool cancel = false; @@ -327,16 +344,14 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) if(!hide) { progress.set_sync_status("Synchronizing object", (*b_ob).name()); - int num_particles = object_count_particles(*b_ob); - if(b_ob->is_duplicator()) { - hide = true; /* duplicators hidden by default */ + /* duplicators hidden by default */ + hide = true; /* dupli objects */ b_ob->dupli_list_create(b_scene, 2); BL::Object::dupli_list_iterator b_dup; - int b_index = 0; for(b_ob->dupli_list.begin(b_dup); b_dup != b_ob->dupli_list.end(); ++b_dup) { Transform tfm = get_transform(b_dup->matrix()); @@ -345,7 +360,8 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) bool emitter_hide = false; if(b_dup_ob.is_duplicator()) { - emitter_hide = true; /* duplicators hidden by default */ + /* duplicators hidden by default */ + emitter_hide = true; /* check if we should render or hide particle emitter */ BL::Object::particle_systems_iterator b_psys; @@ -355,21 +371,34 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) } if(!(b_dup->hide() || dup_hide || emitter_hide)) { - sync_object(*b_ob, b_index, *b_dup, tfm, ob_layer, motion, b_dup->particle_index() + particle_offset); + /* the persistent_id allows us to match dupli objects + * between frames and updates */ + BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> 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); + + /* sync possible particle data, note particle_id + * starts counting at 1, first is dummy particle */ + if(!motion && object && sync_dupli_particle(*b_ob, *b_dup, object)) { + if(particle_id != object->particle_id) { + object->particle_id = particle_id; + scene->object_manager->tag_update(scene); + } + + particle_id++; + } + } - - ++b_index; } b_ob->dupli_list_clear(); } - /* sync particles and check if we should render or hide particle emitter */ + /* 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(!motion) - sync_particles(*b_ob, *b_psys); + for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) { if(b_psys->settings().use_render_emitter()) hide = false; } @@ -377,10 +406,8 @@ 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, 0, PointerRNA_NULL, tfm, ob_layer, motion, 0); + sync_object(*b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion); } - - particle_offset += num_particles; } cancel = progress.get_cancel(); diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp index c4c6d2f79a3..769cd9f532d 100644 --- a/intern/cycles/blender/blender_particles.cpp +++ b/intern/cycles/blender/blender_particles.cpp @@ -17,6 +17,7 @@ */ #include "mesh.h" +#include "object.h" #include "particles.h" #include "blender_sync.h" @@ -28,170 +29,57 @@ CCL_NAMESPACE_BEGIN /* Utilities */ - -/* Particles Sync */ - -bool BlenderSync::psys_need_update(BL::ParticleSystem b_psys) -{ - /* Particle data is only needed for - * a) Billboard render mode if object's own material uses particle info - * b) object/group render mode if any dupli object's material uses particle info - * - * Note: Meshes have to be synced at this point! - */ - bool need_update = false; - - switch (b_psys.settings().render_type()) { - /* XXX not implemented yet! - * billboards/strands would become part of the mesh data (?), - * so the mesh attributes would store whether particle info is required. - */ - #if 0 - case BL::ParticleSettings::render_type_BILLBOARD: - case BL::ParticleSettings::render_type_PATH: { /* for strand rendering */ - BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob.data(); - Mesh *mesh = mesh_map.find(key); - if(mesh) { - need_update |= mesh->need_attribute(scene, ATTR_STD_PARTICLE) && mesh->need_update; - } - break; - } - #endif - - case BL::ParticleSettings::render_type_OBJECT: { - BL::Object b_dupli_ob = b_psys.settings().dupli_object(); - if(b_dupli_ob) { - BL::ID key = (BKE_object_is_modified(b_dupli_ob))? b_dupli_ob: b_dupli_ob.data(); - Mesh *mesh = mesh_map.find(key); - if(mesh) { - need_update |= mesh->need_attribute(scene, ATTR_STD_PARTICLE) && mesh->need_update; - } - } - break; - } - - case BL::ParticleSettings::render_type_GROUP: { - BL::Group b_dupli_group = b_psys.settings().dupli_group(); - if(b_dupli_group) { - BL::Group::objects_iterator b_gob; - for (b_dupli_group.objects.begin(b_gob); b_gob != b_dupli_group.objects.end(); ++b_gob) { - BL::ID key = (BKE_object_is_modified(*b_gob))? *b_gob: b_gob->data(); - Mesh *mesh = mesh_map.find(key); - if(mesh) { - need_update |= mesh->need_attribute(scene, ATTR_STD_PARTICLE) && mesh->need_update; - } - } - } - break; - } - - default: - /* avoid compiler warning */ - break; - } - - return need_update; -} - -static bool use_particle_system(BL::ParticleSystem b_psys) -{ - /* only use duplicator particles? disabled particle info for - * halo and billboard to reduce particle count. - * Probably not necessary since particles don't contain a huge amount - * of data compared to other textures. - */ - #if 0 - int render_type = b_psys->settings().render_type(); - return (render_type == BL::ParticleSettings::render_type_OBJECT - || render_type == BL::ParticleSettings::render_type_GROUP); - #endif - - return true; -} - -static bool use_particle(BL::Particle b_pa, bool preview, bool show_unborn, bool use_dead) -{ - return b_pa.is_exist() && (!preview || b_pa.is_visible()) && - (b_pa.alive_state() != BL::Particle::alive_state_UNBORN || show_unborn) && - (b_pa.alive_state() != BL::Particle::alive_state_DEAD || use_dead); -} - -static int psys_count_particles(BL::ParticleSystem b_psys, bool preview) +bool BlenderSync::sync_dupli_particle(BL::Object b_ob, BL::DupliObject b_dup, Object *object) { - BL::ParticleSystem::particles_iterator b_pa; - bool show_unborn = b_psys.settings().show_unborn(); - bool use_dead = b_psys.settings().use_dead(); - int num = 0; + /* test if this dupli was generated from a particle sytem */ + BL::ParticleSystem b_psys = b_dup.particle_system(); + if(!b_psys) + return false; - for(b_psys.particles.begin(b_pa); b_pa != b_psys.particles.end(); ++b_pa) - if(use_particle(*b_pa, preview, show_unborn, use_dead)) - ++num; + /* test if we need particle data */ + if(!object->mesh->need_attribute(scene, ATTR_STD_PARTICLE)) + return false; - return num; -} + /* don't handle child particles yet */ + BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup.persistent_id(); -int BlenderSync::object_count_particles(BL::Object b_ob) -{ - BL::Object::particle_systems_iterator b_psys; - int num = 0; + if(persistent_id[0] >= b_psys.particles.length()) + return false; - for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) - if(use_particle_system(*b_psys)) - num += psys_count_particles(*b_psys, preview); + /* find particle system */ + ParticleSystemKey key(b_ob, persistent_id); + ParticleSystem *psys; - return num; -} + bool first_use = !particle_system_map.is_used(key); + bool need_update = particle_system_map.sync(&psys, b_ob, b_dup.object(), key); -void BlenderSync::sync_particles(BL::Object b_ob, BL::ParticleSystem b_psys) -{ - /* depending on settings the psys may not even be rendered */ - if(!use_particle_system(b_psys)) - return; - - /* key to lookup particle system */ - ParticleSystemKey key(b_ob, b_psys); - ParticleSystem *psys; - - /* test if we need to sync */ - bool object_updated = false; - - if(particle_system_map.sync(&psys, b_ob, b_ob, key)) - object_updated = true; - - bool need_update = psys_need_update(b_psys); - - if(object_updated || need_update) { - bool show_unborn = b_psys.settings().show_unborn(); - bool use_dead = b_psys.settings().use_dead(); + /* no update needed? */ + if(!need_update && !object->mesh->need_update && !scene->object_manager->need_update) + return true; - int num = psys_count_particles(b_psys, preview); + /* first time used in this sync loop? clear and tag update */ + if(first_use) { psys->particles.clear(); - psys->particles.reserve(num); - - BL::ParticleSystem::particles_iterator b_pa; - int index = 0; - - for(b_psys.particles.begin(b_pa); b_pa != b_psys.particles.end(); ++b_pa) { - if(use_particle(*b_pa, preview, show_unborn, use_dead)) { - Particle pa; - - pa.index = index; - pa.age = b_scene.frame_current() - b_pa->birth_time(); - pa.lifetime = b_pa->lifetime(); - pa.location = get_float3(b_pa->location()); - pa.rotation = get_float4(b_pa->rotation()); - pa.size = b_pa->size(); - pa.velocity = get_float3(b_pa->velocity()); - pa.angular_velocity = get_float3(b_pa->angular_velocity()); - - psys->particles.push_back(pa); - } - - ++index; - } - psys->tag_update(scene); } + + /* add particle */ + BL::Particle b_pa = b_psys.particles[persistent_id[0]]; + Particle pa; + + pa.index = persistent_id[0]; + pa.age = b_scene.frame_current() - b_pa.birth_time(); + pa.lifetime = b_pa.lifetime(); + pa.location = get_float3(b_pa.location()); + pa.rotation = get_float4(b_pa.rotation()); + pa.size = b_pa.size(); + pa.velocity = get_float3(b_pa.velocity()); + pa.angular_velocity = get_float3(b_pa.angular_velocity()); + + psys->particles.push_back(pa); + + /* return that this object has particle data */ + return true; } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 3b78651a6a1..d164920ceff 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -146,6 +146,32 @@ static PyObject *draw_func(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject *reset_func(PyObject *self, PyObject *args) +{ + PyObject *pysession, *pydata, *pyscene; + + if(!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pyscene)) + return NULL; + + BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); + + PointerRNA dataptr; + RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydata), &dataptr); + BL::BlendData b_data(dataptr); + + PointerRNA sceneptr; + RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr); + BL::Scene b_scene(sceneptr); + + Py_BEGIN_ALLOW_THREADS + + session->reset_session(b_data, b_scene); + + Py_END_ALLOW_THREADS + + Py_RETURN_NONE; +} + static PyObject *sync_func(PyObject *self, PyObject *value) { Py_BEGIN_ALLOW_THREADS @@ -258,6 +284,8 @@ static PyObject *osl_update_node_func(PyObject *self, PyObject *args) if(param->validdefault) default_string = param->sdefault[0]; } + else + continue; } else continue; @@ -352,6 +380,7 @@ static PyMethodDef methods[] = { {"render", render_func, METH_O, ""}, {"draw", draw_func, METH_VARARGS, ""}, {"sync", sync_func, METH_O, ""}, + {"reset", reset_func, METH_VARARGS, ""}, #ifdef WITH_OSL {"osl_update_node", osl_update_node_func, METH_VARARGS, ""}, {"osl_compile", osl_compile_func, METH_VARARGS, ""}, @@ -389,14 +418,23 @@ static CCLDeviceInfo *compute_device_list(DeviceType type) if(info.type == type || (info.type == DEVICE_MULTI && info.multi_devices[0].type == type)) { - CCLDeviceInfo cinfo = {info.id.c_str(), info.description.c_str(), i++}; + CCLDeviceInfo cinfo; + + strncpy(cinfo.identifier, info.id.c_str(), sizeof(cinfo.identifier)); + cinfo.identifier[info.id.length()] = '\0'; + + strncpy(cinfo.name, info.description.c_str(), sizeof(cinfo.name)); + cinfo.name[info.description.length()] = '\0'; + + cinfo.value = i++; + device_list.push_back(cinfo); } } /* null terminate */ if(!device_list.empty()) { - CCLDeviceInfo cinfo = {NULL, NULL, 0}; + CCLDeviceInfo cinfo = {"", "", 0}; device_list.push_back(cinfo); } } diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 01bd5f013e3..ad43c39469c 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -109,9 +109,53 @@ void BlenderSession::create_session() session->reset(buffer_params, session_params.samples); } +void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_) +{ + b_data = b_data_; + b_scene = b_scene_; + + SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); + SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background); + + width = b_engine.resolution_x(); + height = b_engine.resolution_y(); + + if(scene->params.modified(scene_params) || + session->params.modified(session_params)) + { + /* if scene or session parameters changed, it's easier to simply re-create + * them rather than trying to distinguish which settings need to be updated + */ + + delete session; + + create_session(); + + return; + } + + session->progress.reset(); + scene->reset(); + + /* peak memory usage should show current render peak, not peak for all renders + * made by this render session + */ + 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->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); +} + void BlenderSession::free_session() { - delete sync; + if(sync) + delete sync; + delete session; } @@ -304,6 +348,15 @@ void BlenderSession::render() /* clear callback */ session->write_render_tile_cb = NULL; session->update_render_tile_cb = NULL; + + /* free all memory used (host and device), so we wouldn't leave render + * engine with extra memory allocated + */ + + session->device_free(); + + delete sync; + sync = NULL; } void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only) diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index d52e0103bbf..7f3973ae873 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -46,6 +46,8 @@ public: void create_session(); void free_session(); + void reset_session(BL::BlendData b_data, BL::Scene b_scene); + /* offline render */ void render(); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index c63f72c68c6..9ebdcfd04bd 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -241,6 +241,7 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D b_v3d, const char *layer) render_layer.use_localview = (b_v3d.local_view() ? true : false); render_layer.scene_layer = get_layer(b_v3d.layers(), b_v3d.layers_local_view(), render_layer.use_localview); render_layer.layer = render_layer.scene_layer; + render_layer.exclude_layer = 0; render_layer.holdout_layer = 0; render_layer.material_override = PointerRNA_NULL; render_layer.use_background = true; @@ -258,10 +259,16 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D b_v3d, const char *layer) for(r.layers.begin(b_rlay); b_rlay != r.layers.end(); ++b_rlay) { if((!layer && first_layer) || (layer && b_rlay->name() == layer)) { render_layer.name = b_rlay->name(); - render_layer.scene_layer = get_layer(b_scene.layers()) & ~get_layer(b_rlay->layers_exclude()); - render_layer.layer = get_layer(b_rlay->layers()); + render_layer.holdout_layer = get_layer(b_rlay->layers_zmask()); + render_layer.exclude_layer = get_layer(b_rlay->layers_exclude()); + + render_layer.scene_layer = get_layer(b_scene.layers()) & ~render_layer.exclude_layer; + render_layer.scene_layer |= render_layer.exclude_layer & render_layer.holdout_layer; + + render_layer.layer = get_layer(b_rlay->layers()); render_layer.layer |= render_layer.holdout_layer; + render_layer.material_override = b_rlay->material_override(); render_layer.use_background = b_rlay->use_sky(); render_layer.use_viewport_visibility = false; @@ -277,6 +284,7 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D b_v3d, const char *layer) SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background) { + BL::RenderSettings r = b_scene.render(); SceneParams params; PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); int shadingsystem = RNA_enum_get(&cscene, "shading_system"); @@ -294,6 +302,8 @@ SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background) params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits"); params.use_bvh_cache = (background)? RNA_boolean_get(&cscene, "use_cache"): false; + params.persistent_images = (background)? r.use_persistent_data(): false; + return params; } @@ -379,7 +389,10 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine b_engine, BL::Use params.start_resolution = get_int(cscene, "preview_start_resolution"); /* other parameters */ - params.threads = b_scene.render().threads(); + if(b_scene.render().threads_mode() == BL::RenderSettings::threads_mode_FIXED) + params.threads = b_scene.render().threads(); + else + params.threads = 0; params.cancel_timeout = get_float(cscene, "debug_cancel_timeout"); params.reset_timeout = get_float(cscene, "debug_reset_timeout"); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 36cd5e684a7..71781bc5459 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -42,6 +42,7 @@ class Film; class Light; class Mesh; class Object; +class ParticleSystem; class Scene; class Shader; class ShaderGraph; @@ -80,20 +81,20 @@ private: void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree); Mesh *sync_mesh(BL::Object b_ob, bool object_updated); - void sync_object(BL::Object b_parent, int b_index, BL::DupliObject b_dupli_object, Transform& tfm, uint layer_flag, int motion, int particle_id); - void sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm); + 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); + 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); void sync_camera_motion(BL::Object b_ob, int motion); - void sync_particles(BL::Object b_ob, BL::ParticleSystem b_psys); + + /* particles */ + bool sync_dupli_particle(BL::Object b_ob, BL::DupliObject b_dup, Object *object); /* util */ void find_shader(BL::ID id, vector<uint>& used_shaders, int default_shader); bool BKE_object_is_modified(BL::Object b_ob); bool object_is_mesh(BL::Object b_ob); bool object_is_light(BL::Object b_ob); - bool psys_need_update(BL::ParticleSystem b_psys); - int object_count_particles(BL::Object b_ob); /* variables */ BL::RenderEngine b_engine; @@ -115,7 +116,8 @@ private: struct RenderLayerInfo { RenderLayerInfo() - : scene_layer(0), layer(0), holdout_layer(0), + : scene_layer(0), layer(0), + holdout_layer(0), exclude_layer(0), material_override(PointerRNA_NULL), use_background(true), use_viewport_visibility(false), @@ -126,6 +128,7 @@ private: uint scene_layer; uint layer; uint holdout_layer; + uint exclude_layer; BL::Material material_override; bool use_background; bool use_viewport_visibility; diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index df1e99882b8..4feb8b556d5 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -284,6 +284,12 @@ public: return recalc; } + bool is_used(const K& key) + { + T *data = find(key); + return (data) ? used_set.find(data) != used_set.end() : false; + } + void used(T *data) { /* tag data as still in use */ @@ -343,27 +349,49 @@ protected: /* Object Key */ +enum { OBJECT_PERSISTENT_ID_SIZE = 8 }; + struct ObjectKey { void *parent; - int index; + int id[OBJECT_PERSISTENT_ID_SIZE]; void *ob; - ObjectKey(void *parent_, int index_, void *ob_) - : parent(parent_), index(index_), ob(ob_) {} + ObjectKey(void *parent_, int id_[OBJECT_PERSISTENT_ID_SIZE], void *ob_) + : parent(parent_), ob(ob_) + { + if(id_) + memcpy(id, id_, sizeof(id)); + else + memset(id, 0, sizeof(id)); + } bool operator<(const ObjectKey& k) const - { return (parent < k.parent || (parent == k.parent && (index < k.index || (index == k.index && ob < k.ob)))); } + { + return (parent < k.parent) || + (parent == k.parent && (memcmp(id, k.id, sizeof(id)) < 0)) || + (memcmp(id, k.id, sizeof(id)) == 0 && ob < k.ob); + } }; struct ParticleSystemKey { void *ob; - void *psys; + int id[OBJECT_PERSISTENT_ID_SIZE]; - ParticleSystemKey(void *ob_, void *psys_) - : ob(ob_), psys(psys_) {} + ParticleSystemKey(void *ob_, int id_[OBJECT_PERSISTENT_ID_SIZE]) + : ob(ob_) + { + if(id_) + memcpy(id, id_, sizeof(id)); + else + memset(id, 0, sizeof(id)); + } bool operator<(const ParticleSystemKey& k) const - { return (ob < k.ob && psys < k.psys); } + { + /* first id is particle index, we don't compare that */ + return (ob < k.ob) || + (ob == k.ob && (memcmp(id+1, k.id+1, sizeof(int)*(OBJECT_PERSISTENT_ID_SIZE-1)) < 0)); + } }; CCL_NAMESPACE_END diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake index 332d3d74715..790049898ff 100644 --- a/intern/cycles/cmake/external_libs.cmake +++ b/intern/cycles/cmake/external_libs.cmake @@ -18,33 +18,6 @@ else() endif() ########################################################################### -# Partio - -if(WITH_CYCLES_PARTIO) - - set(CYCLES_PARTIO "" CACHE PATH "Path to Partio installation") - - message(STATUS "CYCLES_PARTIO = ${CYCLES_PARTIO}") - - find_library(PARTIO_LIBRARIES NAMES partio PATHS ${CYCLES_PARTIO}/lib) - find_path(PARTIO_INCLUDES Partio.h ${CYCLES_PARTIO}/include) - - find_package(ZLIB) - - if(PARTIO_INCLUDES AND PARTIO_LIBRARIES AND ZLIB_LIBRARIES) - list(APPEND PARTIO_LIBRARIES ${ZLIB_LIBRARIES}) - set(PARTIO_FOUND TRUE) - message(STATUS "PARTIO includes = ${PARTIO_INCLUDES}") - message(STATUS "PARTIO library = ${PARTIO_LIBRARIES}") - else() - message(STATUS "PARTIO not found") - endif() - - include_directories(${PARTIO_INCLUDES}) - -endif() - -########################################################################### # CUDA if(WITH_CYCLES_CUDA_BINARIES) diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 550da2982a3..c6a2c678bac 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -78,13 +78,13 @@ void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int w glDisable(GL_BLEND); } -Device *Device::create(DeviceInfo& info, Stats &stats, bool background, int threads) +Device *Device::create(DeviceInfo& info, Stats &stats, bool background) { Device *device; switch(info.type) { case DEVICE_CPU: - device = device_cpu_create(info, stats, threads); + device = device_cpu_create(info, stats); break; #ifdef WITH_CUDA case DEVICE_CUDA: diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 95da0a89833..9840687b76a 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -134,7 +134,7 @@ public: virtual int device_number(Device *sub_device) { return 0; } /* static */ - static Device *create(DeviceInfo& info, Stats &stats, bool background = true, int threads = 0); + static Device *create(DeviceInfo& info, Stats &stats, bool background = true); static DeviceType type_from_string(const char *name); static string string_from_type(DeviceType type); diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 519c458ffdf..bc280616615 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -45,7 +45,7 @@ public: TaskPool task_pool; KernelGlobals *kg; - CPUDevice(Stats &stats, int threads_num) : Device(stats) + CPUDevice(Stats &stats) : Device(stats) { kg = kernel_globals_create(); @@ -274,7 +274,7 @@ public: /* split task into smaller ones, more than number of threads for uneven * workloads where some parts of the image render slower than others */ list<DeviceTask> tasks; - task.split(tasks, TaskScheduler::num_threads()+1); + task.split(tasks, TaskScheduler::num_threads()); foreach(DeviceTask& task, tasks) task_pool.push(new CPUDeviceTask(this, task)); @@ -291,9 +291,9 @@ public: } }; -Device *device_cpu_create(DeviceInfo& info, Stats &stats, int threads) +Device *device_cpu_create(DeviceInfo& info, Stats &stats) { - return new CPUDevice(stats, threads); + return new CPUDevice(stats); } void device_cpu_info(vector<DeviceInfo>& devices) diff --git a/intern/cycles/device/device_intern.h b/intern/cycles/device/device_intern.h index 02fbac6860e..b49ebba3e8b 100644 --- a/intern/cycles/device/device_intern.h +++ b/intern/cycles/device/device_intern.h @@ -23,7 +23,7 @@ CCL_NAMESPACE_BEGIN class Device; -Device *device_cpu_create(DeviceInfo& info, Stats &stats, int threads); +Device *device_cpu_create(DeviceInfo& info, Stats &stats); Device *device_opencl_create(DeviceInfo& info, Stats &stats, bool background); Device *device_cuda_create(DeviceInfo& info, Stats &stats, bool background); Device *device_network_create(DeviceInfo& info, Stats &stats, const char *address); diff --git a/intern/cycles/device/device_task.cpp b/intern/cycles/device/device_task.cpp index c85e182d629..b3f02deaf6f 100644 --- a/intern/cycles/device/device_task.cpp +++ b/intern/cycles/device/device_task.cpp @@ -101,7 +101,7 @@ void DeviceTask::update_progress(RenderTile &rtile) if(update_tile_sample) { double current_time = time_dt(); - if (current_time - last_update_time >= 1.0f) { + if (current_time - last_update_time >= 1.0) { update_tile_sample(rtile); last_update_time = current_time; diff --git a/intern/cycles/kernel/kernel_projection.h b/intern/cycles/kernel/kernel_projection.h index 64747bcb42e..6516b9e4d82 100644 --- a/intern/cycles/kernel/kernel_projection.h +++ b/intern/cycles/kernel/kernel_projection.h @@ -98,7 +98,7 @@ __device float3 fisheye_to_direction(float u, float v, float fov) return make_float3(0.0f, 0.0f, 0.0f); float phi = acosf((r != 0.0f)? u/r: 0.0f); - float theta = asinf(r) * (fov / M_PI_F); + float theta = r * fov * 0.5f; if(v < 0.0f) phi = -phi; diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h index 5d557ffcb07..80ced9dfd62 100644 --- a/intern/cycles/kernel/osl/osl_globals.h +++ b/intern/cycles/kernel/osl/osl_globals.h @@ -68,6 +68,11 @@ struct OSLGlobals { }; static tls_ptr(ThreadData, thread_data); + static thread_mutex thread_data_mutex; + static volatile int thread_data_users; + + void thread_data_init(); + void thread_data_free(); }; CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index 0c8de058b5b..abf7c041cb3 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -32,9 +32,32 @@ CCL_NAMESPACE_BEGIN tls_ptr(OSLGlobals::ThreadData, OSLGlobals::thread_data); +volatile int OSLGlobals::thread_data_users = 0; +thread_mutex OSLGlobals::thread_data_mutex; /* Threads */ +void OSLGlobals::thread_data_init() +{ + thread_scoped_lock thread_data_lock(thread_data_mutex); + + if(thread_data_users == 0) + tls_create(OSLGlobals::ThreadData, thread_data); + + thread_data_users++; +} + +void OSLGlobals::thread_data_free() +{ + /* thread local storage delete */ + thread_scoped_lock thread_data_lock(thread_data_mutex); + + thread_data_users--; + + if(thread_data_users == 0) + tls_delete(OSLGlobals::ThreadData, thread_data); +} + void OSLShader::thread_init(KernelGlobals *kg) { OSL::ShadingSystem *ss = kg->osl.ss; diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl index e238313509e..d101ee870b7 100644 --- a/intern/cycles/kernel/shaders/node_normal_map.osl +++ b/intern/cycles/kernel/shaders/node_normal_map.osl @@ -20,6 +20,7 @@ shader node_normal_map( normal NormalIn = N, + float Strength = 1.0, color Color = color(0.5, 0.5, 1.0), string space = "Tangent", string attr_name = "geom:tangent", @@ -44,5 +45,8 @@ shader node_normal_map( Normal = normalize(transform("object", "world", vector(mcolor))); else if (space == "World") Normal = normalize(vector(mcolor)); + + if (Strength != 1.0) + Normal = normalize(NormalIn + (Normal - NormalIn)*max(Strength, 0.0)); } diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h index 68177493f4e..c4d03c1f948 100644 --- a/intern/cycles/kernel/svm/svm_geometry.h +++ b/intern/cycles/kernel/svm/svm_geometry.h @@ -34,7 +34,7 @@ __device void svm_node_geometry(KernelGlobals *kg, ShaderData *sd, float *stack, 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.5), (data.x - 0.5), 0.0f); + 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)));; } diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index a9449c0ded9..8ca7dff3970 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -227,12 +227,14 @@ __device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, floa __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) { - uint color_offset, normal_offset, space; - decode_node_uchar4(node.y, &color_offset, &normal_offset, &space, NULL); + uint color_offset, strength_offset, normal_offset, space; + decode_node_uchar4(node.y, &color_offset, &strength_offset, &normal_offset, &space); float3 color = stack_load_float3(stack, color_offset); color = 2.0f*make_float3(color.x - 0.5f, color.y - 0.5f, color.z - 0.5f); + float3 N; + if(space == NODE_NORMAL_MAP_TANGENT) { /* tangent space */ if(sd->object == ~0) { @@ -257,19 +259,26 @@ __device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *stac tangent = cross(sd->N, normalize(cross(tangent, sd->N)));; float3 B = sign * cross(sd->N, tangent); - float3 N = color.x * tangent + color.y * B + color.z * sd->N; - - stack_store_float3(stack, normal_offset, normalize(N)); + N = normalize(color.x * tangent + color.y * B + color.z * sd->N); } else { /* object, world space */ - float3 N = color; + N = color; if(space == NODE_NORMAL_MAP_OBJECT) object_normal_transform(kg, sd, &N); - stack_store_float3(stack, normal_offset, normalize(N)); + N = normalize(N); + } + + float strength = stack_load_float(stack, strength_offset); + + if(strength != 1.0f) { + strength = max(strength, 0.0f); + N = normalize(sd->N + (N - sd->N)*strength); } + + stack_store_float3(stack, normal_offset, normalize(N)); } __device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 649936bec04..308ebd0794a 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -55,15 +55,10 @@ Camera::Camera() width = 1024; height = 512; - left = -((float)width/(float)height); - right = (float)width/(float)height; - bottom = -1.0f; - top = 1.0f; - - border_left = 0.0f; - border_right = 1.0f; - border_bottom = 0.0f; - border_top = 1.0f; + viewplane.left = -((float)width/(float)height); + viewplane.right = (float)width/(float)height; + viewplane.bottom = -1.0f; + viewplane.top = 1.0f; screentoworld = transform_identity(); rastertoworld = transform_identity(); @@ -95,10 +90,11 @@ void Camera::update() /* raster to screen */ Transform screentoraster = ndctoraster; - + screentoraster = ndctoraster * - transform_scale(1.0f/(right - left), 1.0f/(top - bottom), 1.0f) * - transform_translate(-left, -bottom, 0.0f); + transform_scale(1.0f/(viewplane.right - viewplane.left), + 1.0f/(viewplane.top - viewplane.bottom), 1.0f) * + transform_translate(-viewplane.left, -viewplane.bottom, 0.0f); Transform rastertoscreen = transform_inverse(screentoraster); @@ -265,14 +261,8 @@ bool Camera::modified(const Camera& cam) // modified for progressive render // (width == cam.width) && // (height == cam.height) && - (left == cam.left) && - (right == cam.right) && - (bottom == cam.bottom) && - (top == cam.top) && - (border_left == cam.border_left) && - (border_right == cam.border_right) && - (border_bottom == cam.border_bottom) && - (border_top == cam.border_top) && + (viewplane == cam.viewplane) && + (border == cam.border) && (matrix == cam.matrix) && (panorama_type == cam.panorama_type) && (fisheye_fov == cam.fisheye_fov) && diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h index 1407c86e7c2..4c2de7b50b8 100644 --- a/intern/cycles/render/camera.h +++ b/intern/cycles/render/camera.h @@ -21,6 +21,7 @@ #include "kernel_types.h" +#include "util_boundbox.h" #include "util_transform.h" #include "util_types.h" @@ -65,10 +66,10 @@ public: /* screen */ int width, height; - float left, right, bottom, top; + BoundBox2D viewplane; /* border */ - float border_left, border_right, border_bottom, border_top; + BoundBox2D border; /* transformation */ Transform matrix; diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index d77516a1b18..4173da453fd 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -147,6 +147,10 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen Mesh *mesh = object->mesh; bool have_emission = false; + /* skip if we are not visible for BSDFs */ + if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) + continue; + /* skip if we have no emission shaders */ foreach(uint sindex, mesh->used_shaders) { Shader *shader = scene->shaders[sindex]; @@ -183,6 +187,10 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen Mesh *mesh = object->mesh; bool have_emission = false; + /* skip if we are not visible for BSDFs */ + if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) + continue; + /* skip if we have no emission shaders */ foreach(uint sindex, mesh->used_shaders) { Shader *shader = scene->shaders[sindex]; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 4f50de11edf..82afab4dc1a 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -3032,7 +3032,9 @@ NormalMapNode::NormalMapNode() attribute = ustring(""); add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f); add_input("Color", SHADER_SOCKET_COLOR); + add_output("Normal", SHADER_SOCKET_NORMAL); } @@ -3055,6 +3057,7 @@ void NormalMapNode::attributes(AttributeRequestSet *attributes) void NormalMapNode::compile(SVMCompiler& compiler) { ShaderInput *color_in = input("Color"); + ShaderInput *strength_in = input("Strength"); ShaderOutput *normal_out = output("Normal"); int attr = 0, attr_sign = 0; @@ -3070,11 +3073,13 @@ void NormalMapNode::compile(SVMCompiler& compiler) } compiler.stack_assign(color_in); + compiler.stack_assign(strength_in); compiler.stack_assign(normal_out); compiler.add_node(NODE_NORMAL_MAP, compiler.encode_uchar4( color_in->stack_offset, + strength_in->stack_offset, normal_out->stack_offset, space_enum[space]), attr, attr_sign); diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 8bdb09eaf70..5fbc7932849 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -45,6 +45,8 @@ CCL_NAMESPACE_BEGIN OSLShaderManager::OSLShaderManager() { + thread_data_initialized = false; + services = new OSLRenderServices(); shading_system_init(); @@ -91,8 +93,6 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene og->background_state = og->surface_state[background_id & SHADER_MASK]; og->use = true; - tls_create(OSLGlobals::ThreadData, og->thread_data); - foreach(Shader *shader, scene->shaders) shader->need_update = false; @@ -102,6 +102,11 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene scene->image_manager->set_osl_texture_system((void*)ts); device_update_common(device, dscene, scene, progress); + + if(!thread_data_initialized) { + og->thread_data_init(); + thread_data_initialized = true; + } } void OSLShaderManager::device_free(Device *device, DeviceScene *dscene) @@ -114,12 +119,15 @@ void OSLShaderManager::device_free(Device *device, DeviceScene *dscene) og->use = false; og->ss = NULL; - tls_delete(OSLGlobals::ThreadData, og->thread_data); - og->surface_state.clear(); og->volume_state.clear(); og->displacement_state.clear(); og->background_state.reset(); + + if(thread_data_initialized) { + og->thread_data_free(); + thread_data_initialized = false; + } } void OSLShaderManager::texture_system_init() diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h index cee37c58d74..b4b3f59e02a 100644 --- a/intern/cycles/render/osl.h +++ b/intern/cycles/render/osl.h @@ -73,6 +73,8 @@ protected: OSLRenderServices *services; OSL::ErrorHandler errhandler; set<string> loaded_shaders; + + bool thread_data_initialized; }; #endif diff --git a/intern/cycles/render/particles.cpp b/intern/cycles/render/particles.cpp index 9f951d9673f..2a1570f7a0d 100644 --- a/intern/cycles/render/particles.cpp +++ b/intern/cycles/render/particles.cpp @@ -57,8 +57,7 @@ void ParticleSystemManager::device_update_particles(Device *device, DeviceScene { /* count particles. * adds one dummy particle at the beginning to avoid invalid lookups, - * in case a shader uses particle info without actual particle data. - */ + * in case a shader uses particle info without actual particle data. */ int num_particles = 1; foreach(ParticleSystem *psys, scene->particle_systems) num_particles += psys->particles.size(); diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 15031b9500c..7834aa701ea 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -44,6 +44,10 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_) device = NULL; memset(&dscene.data, 0, sizeof(dscene.data)); + /* OSL only works on the CPU */ + if(device_info_.type != DEVICE_CPU) + params.shadingsystem = SceneParams::SVM; + camera = new Camera(); filter = new Filter(); film = new Film(); @@ -62,33 +66,11 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_) Scene::~Scene() { - if(device) camera->device_free(device, &dscene); - delete camera; - - if(device) filter->device_free(device, &dscene); - delete filter; - - if(device) film->device_free(device, &dscene); - delete film; - - if(device) background->device_free(device, &dscene); - delete background; - - if(device) mesh_manager->device_free(device, &dscene); - delete mesh_manager; - - if(device) object_manager->device_free(device, &dscene); - delete object_manager; - - if(device) integrator->device_free(device, &dscene); - delete integrator; - - if(device) shader_manager->device_free(device, &dscene); - delete shader_manager; - - if(device) light_manager->device_free(device, &dscene); - delete light_manager; + free_memory(true); +} +void Scene::free_memory(bool final) +{ foreach(Shader *s, shaders) delete s; foreach(Mesh *m, meshes) @@ -100,11 +82,44 @@ Scene::~Scene() foreach(ParticleSystem *p, particle_systems) delete p; - if(device) image_manager->device_free(device, &dscene); - delete image_manager; - - if(device) particle_system_manager->device_free(device, &dscene); - delete particle_system_manager; + if(device) { + camera->device_free(device, &dscene); + filter->device_free(device, &dscene); + film->device_free(device, &dscene); + background->device_free(device, &dscene); + integrator->device_free(device, &dscene); + + object_manager->device_free(device, &dscene); + mesh_manager->device_free(device, &dscene); + shader_manager->device_free(device, &dscene); + light_manager->device_free(device, &dscene); + + particle_system_manager->device_free(device, &dscene); + + if(!params.persistent_images || final) + image_manager->device_free(device, &dscene); + } + + if(final) { + delete filter; + delete camera; + delete film; + delete background; + delete integrator; + delete object_manager; + delete mesh_manager; + delete shader_manager; + delete light_manager; + delete particle_system_manager; + delete image_manager; + } + else { + shaders.clear(); + meshes.clear(); + objects.clear(); + lights.clear(); + particle_systems.clear(); + } } void Scene::device_update(Device *device_, Progress& progress) @@ -229,5 +244,22 @@ bool Scene::need_reset() || particle_system_manager->need_update); } +void Scene::reset() +{ + shader_manager->add_default(this); + + /* ensure all objects are updated */ + camera->tag_update(); + filter->tag_update(this); + film->tag_update(this); + background->tag_update(this); + integrator->tag_update(this); +} + +void Scene::device_free() +{ + free_memory(false); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index bd45c1c04e6..92ef692b4b9 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -120,6 +120,7 @@ public: bool use_bvh_cache; bool use_bvh_spatial_split; bool use_qbvh; + bool persistent_images; SceneParams() { @@ -139,7 +140,8 @@ public: && bvh_type == params.bvh_type && use_bvh_cache == params.use_bvh_cache && use_bvh_spatial_split == params.use_bvh_spatial_split - && use_qbvh == params.use_qbvh); } + && use_qbvh == params.use_qbvh + && persistent_images == params.persistent_images); } }; /* Scene */ @@ -198,6 +200,12 @@ public: bool need_update(); bool need_reset(); + + void reset(); + void device_free(); + +protected: + void free_memory(bool final); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 7303cb52ad8..41212c2db84 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -49,7 +49,7 @@ Session::Session(const SessionParams& params_) TaskScheduler::init(params.threads); - device = Device::create(params.device, stats, params.background, params.threads); + device = Device::create(params.device, stats, params.background); if(params.background) { buffers = NULL; @@ -818,7 +818,7 @@ bool Session::update_progressive_refine(bool cancel) double current_time = time_dt(); - if (current_time - last_update_time < 1.0f) { + if (current_time - last_update_time < 1.0) { /* if last sample was processed, we need to write buffers anyway */ if (!write) return false; @@ -842,4 +842,18 @@ bool Session::update_progressive_refine(bool cancel) return write; } +void Session::device_free() +{ + scene->device_free(); + + foreach(RenderBuffers *buffers, tile_buffers) + delete buffers; + + tile_buffers.clear(); + + /* used from background render only, so no need to + * re-create render/display buffers here + */ +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 7bb0cd1ae01..cfc1502287d 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -130,6 +130,7 @@ public: void set_samples(int samples); void set_pause(bool pause); + void device_free(); protected: struct DelayedReset { thread_mutex mutex; diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h index b35c4c12bb8..a0cdf1761ad 100644 --- a/intern/cycles/util/util_boundbox.h +++ b/intern/cycles/util/util_boundbox.h @@ -31,6 +31,8 @@ using namespace std; CCL_NAMESPACE_BEGIN +/* 3D BoundBox */ + class BoundBox { public: @@ -160,6 +162,75 @@ __forceinline BoundBox intersect(const BoundBox& a, const BoundBox& b, const Bou return intersect(a, intersect(b, c)); } +/* 2D BoundBox */ + +class BoundBox2D { +public: + float left; + float right; + float bottom; + float top; + + BoundBox2D() + : left(0.0f), right(1.0f), bottom(0.0f), top(1.0f) + { + } + + bool operator==(const BoundBox2D& other) const + { + return (left == other.left && right == other.right && + bottom == other.bottom && top == other.top); + } + + BoundBox2D operator*(float f) const + { + BoundBox2D result; + + result.left = left*f; + result.right = right*f; + result.bottom = bottom*f; + result.top = top*f; + + return result; + } + + BoundBox2D subset(const BoundBox2D& other) const + { + BoundBox2D subset; + + subset.left = left + other.left*(right - left); + subset.right = left + other.right*(right - left); + subset.bottom = bottom + other.bottom*(top - bottom); + subset.top = bottom + other.top*(top - bottom); + + return subset; + } + + BoundBox2D make_relative_to(const BoundBox2D& other) const + { + BoundBox2D result; + + result.left = ((left - other.left) / (other.right - other.left)); + result.right = ((right - other.left) / (other.right - other.left)); + result.bottom = ((bottom - other.bottom) / (other.top - other.bottom)); + result.top = ((top - other.bottom) / (other.top - other.bottom)); + + return result; + } + + BoundBox2D clamp(float mn = 0.0f, float mx = 1.0f) + { + BoundBox2D result; + + result.left = ccl::clamp(left, mn, mx); + result.right = ccl::clamp(right, mn, mx); + result.bottom = ccl::clamp(bottom, mn, mx); + result.top = ccl::clamp(top, mn, mx); + + return result; + } +}; + CCL_NAMESPACE_END #endif /* __UTIL_BOUNDBOX_H__ */ diff --git a/intern/cycles/util/util_progress.h b/intern/cycles/util/util_progress.h index c97379d8776..03e25d4d132 100644 --- a/intern/cycles/util/util_progress.h +++ b/intern/cycles/util/util_progress.h @@ -68,6 +68,21 @@ public: return *this; } + void reset() + { + tile = 0; + sample = 0; + start_time = time_dt(); + total_time = 0.0f; + tile_time = 0.0f; + status = "Initializing"; + substatus = ""; + sync_status = ""; + sync_substatus = ""; + cancel = false; + cancel_message = ""; + } + /* cancel */ void set_cancel(const string& cancel_message_) { diff --git a/intern/cycles/util/util_stats.h b/intern/cycles/util/util_stats.h index 405c81a1e1f..27638015f40 100644 --- a/intern/cycles/util/util_stats.h +++ b/intern/cycles/util/util_stats.h @@ -19,31 +19,22 @@ #ifndef __UTIL_STATS_H__ #define __UTIL_STATS_H__ -#include "util_thread.h" - CCL_NAMESPACE_BEGIN class Stats { public: - Stats() : lock(), mem_used(0), mem_peak(0) {} + Stats() : mem_used(0), mem_peak(0) {} void mem_alloc(size_t size) { - lock.lock(); - mem_used += size; if(mem_used > mem_peak) mem_peak = mem_used; - - lock.unlock(); } void mem_free(size_t size) { - lock.lock(); mem_used -= size; - lock.unlock(); } - spin_lock lock; size_t mem_used; size_t mem_peak; }; diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp index ea0abd6f54f..8c4ec312256 100644 --- a/intern/cycles/util/util_task.cpp +++ b/intern/cycles/util/util_task.cpp @@ -168,10 +168,16 @@ void TaskScheduler::init(int num_threads) if(users == 0) { do_exit = false; - /* launch threads that will be waiting for work */ - if(num_threads == 0) + if(num_threads == 0) { + /* automatic number of threads will be main thread + num cores */ num_threads = system_cpu_thread_count(); + } + else { + /* main thread will also work, for fixed threads we count it too */ + num_threads -= 1; + } + /* launch threads that will be waiting for work */ threads.resize(num_threads); thread_level.resize(num_threads); diff --git a/intern/cycles/util/util_task.h b/intern/cycles/util/util_task.h index a2f284479c7..b795ca7524b 100644 --- a/intern/cycles/util/util_task.h +++ b/intern/cycles/util/util_task.h @@ -94,7 +94,10 @@ public: static void init(int num_threads = 0); static void exit(); - static int num_threads() { return threads.size(); } + /* number of threads that can work on tasks, main thread counts too */ + static int num_threads() { return threads.size() + 1; } + + /* test if any session is using the scheduler */ static bool active() { return users != 0; } protected: diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h index 6d1bd0023a7..843764ca9d6 100644 --- a/intern/cycles/util/util_thread.h +++ b/intern/cycles/util/util_thread.h @@ -33,9 +33,6 @@ typedef boost::mutex thread_mutex; typedef boost::mutex::scoped_lock thread_scoped_lock; typedef boost::condition_variable thread_condition_variable; -/* use boost for spinlocks as well */ -typedef boost::detail::spinlock spin_lock; - /* own pthread based implementation, to avoid boost version conflicts with * dynamically loaded blender plugins */ diff --git a/intern/cycles/util/util_transform.cpp b/intern/cycles/util/util_transform.cpp index 70ee13d96d7..4eee024990f 100644 --- a/intern/cycles/util/util_transform.cpp +++ b/intern/cycles/util/util_transform.cpp @@ -251,6 +251,13 @@ void transform_motion_decompose(MotionTransform *decomp, const MotionTransform * transform_decompose(&decomp->pre, &motion->pre); transform_decompose(&decomp->mid, mid); transform_decompose(&decomp->post, &motion->post); + + /* ensure rotation around shortest angle, negated quaternions are the same + * but this means we don't have to do the check in quat_interpolate */ + if(dot(decomp->mid.x, decomp->post.x) < 0.0f) + decomp->mid.x = -decomp->mid.x; + if(dot(decomp->pre.x, decomp->mid.x) < 0.0f) + decomp->pre.x = -decomp->pre.x; } CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index df525542207..65162ebf4e6 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -39,16 +39,16 @@ typedef struct Transform { #endif } Transform; +/* transform decomposed in rotation/translation/scale. we use the same data + * structure as Transform, and tightly pack decomposition into it. first the + * rotation (4), then translation (3), then 3x3 scale matrix (9) */ + typedef struct MotionTransform { Transform pre; Transform mid; Transform post; } MotionTransform; -/* transform decomposed in rotation/translation/scale. we use the same data - * structure as Transform, and tightly pack decomposition into it. first the - * rotation (4), then translation (3), then 3x3 scale matrix (9) */ - /* Functions */ __device_inline float3 transform_perspective(const Transform *t, const float3 a) @@ -303,13 +303,11 @@ __device_inline Transform transform_clear_scale(const Transform& tfm) __device_inline float4 quat_interpolate(float4 q1, float4 q2, float t) { + /* note: this does not ensure rotation around shortest angle, q1 and q2 + * are assumed to be matched already in transform_motion_decompose */ float costheta = dot(q1, q2); - /* rotate around shortest angle */ - if(costheta < 0.0f) { - costheta = -costheta; - q1 = -q1; - } + /* possible optimization: it might be possible to precompute theta/qperp */ if(costheta > 0.9995f) { /* linear interpolation in degenerate case */ @@ -318,14 +316,17 @@ __device_inline float4 quat_interpolate(float4 q1, float4 q2, float t) else { /* slerp */ float theta = acosf(clamp(costheta, -1.0f, 1.0f)); - float thetap = theta * t; float4 qperp = normalize(q2 - q1 * costheta); + float thetap = theta * t; return q1 * cosf(thetap) + qperp * sinf(thetap); } } __device_inline Transform transform_quick_inverse(Transform M) { + /* possible optimization: can we avoid doing this altogether and construct + * the inverse matrix directly from negated translation, transposed rotation, + * scale can be inverted but what about shearing? */ Transform R; float det = M.x.x*(M.z.z*M.y.y - M.z.y*M.y.z) - M.y.x*(M.z.z*M.x.y - M.z.y*M.x.z) + M.z.x*(M.y.z*M.x.y - M.y.y*M.x.z); @@ -380,10 +381,17 @@ __device_inline void transform_compose(Transform *tfm, const Transform *decomp) tfm->w = make_float4(0.0f, 0.0f, 0.0f, 1.0f); } +/* Disabled for now, need arc-length parametrization for constant speed motion. + * #define CURVED_MOTION_INTERPOLATE */ + __device void transform_motion_interpolate(Transform *tfm, const MotionTransform *motion, float t) { + /* possible optimization: is it worth it adding a check to skip scaling? + * it's probably quite uncommon to have scaling objects. or can we skip + * just shearing perhaps? */ Transform decomp; +#ifdef CURVED_MOTION_INTERPOLATE /* 3 point bezier curve interpolation for position */ float3 Ppre = float4_to_float3(motion->pre.y); float3 Pmid = float4_to_float3(motion->mid.y); @@ -395,13 +403,18 @@ __device void transform_motion_interpolate(Transform *tfm, const MotionTransform decomp.y.x = P.x; decomp.y.y = P.y; decomp.y.z = P.z; +#endif /* linear interpolation for rotation and scale */ if(t < 0.5f) { t *= 2.0f; decomp.x = quat_interpolate(motion->pre.x, motion->mid.x, t); +#ifdef CURVED_MOTION_INTERPOLATE decomp.y.w = (1.0f - t)*motion->pre.y.w + t*motion->mid.y.w; +#else + decomp.y = (1.0f - t)*motion->pre.y + t*motion->mid.y; +#endif decomp.z = (1.0f - t)*motion->pre.z + t*motion->mid.z; decomp.w = (1.0f - t)*motion->pre.w + t*motion->mid.w; } @@ -409,7 +422,11 @@ __device void transform_motion_interpolate(Transform *tfm, const MotionTransform t = (t - 0.5f)*2.0f; decomp.x = quat_interpolate(motion->mid.x, motion->post.x, t); +#ifdef CURVED_MOTION_INTERPOLATE decomp.y.w = (1.0f - t)*motion->mid.y.w + t*motion->post.y.w; +#else + decomp.y = (1.0f - t)*motion->mid.y + t*motion->post.y; +#endif decomp.z = (1.0f - t)*motion->mid.z + t*motion->post.z; decomp.w = (1.0f - t)*motion->mid.w + t*motion->post.w; } diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index e52ac0af2ed..ea09987c564 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -189,7 +189,6 @@ elseif(APPLE) if(WITH_INPUT_NDOF) list(APPEND SRC intern/GHOST_NDOFManagerCocoa.mm - intern/GHOST_NDOFManagerCocoa.h ) endif() diff --git a/intern/guardedalloc/cpp/mallocn.cpp b/intern/guardedalloc/cpp/mallocn.cpp index da77f0e1c83..8b05d25018f 100644 --- a/intern/guardedalloc/cpp/mallocn.cpp +++ b/intern/guardedalloc/cpp/mallocn.cpp @@ -28,6 +28,9 @@ #include <new> #include "../MEM_guardedalloc.h" +void *operator new(size_t size, const char *str) throw(std::bad_alloc); +void *operator new[](size_t size, const char *str) throw(std::bad_alloc); + /* not default but can be used when needing to set a string */ void *operator new(size_t size, const char *str) throw(std::bad_alloc) { diff --git a/intern/itasc/CMakeLists.txt b/intern/itasc/CMakeLists.txt index 99c64d956cb..bc3ea0cf24c 100644 --- a/intern/itasc/CMakeLists.txt +++ b/intern/itasc/CMakeLists.txt @@ -22,7 +22,7 @@ # Contributor(s): Jacques Beaurain. # # ***** END GPL LICENSE BLOCK ***** - +remove_strict_flags() set(INC ) diff --git a/intern/itasc/kdl/chain.hpp b/intern/itasc/kdl/chain.hpp index 24e40858bff..fde9d4ed23e 100644 --- a/intern/itasc/kdl/chain.hpp +++ b/intern/itasc/kdl/chain.hpp @@ -35,11 +35,16 @@ namespace KDL { */ class Chain { private: -#if !defined(__APPLE__) +#if defined(__APPLE__) +# if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_5 + std::vector<Segment> segments; +# else // Eigen allocator is needed for alignment of Eigen data types std::vector<Segment, Eigen::aligned_allocator<Segment> > segments; +# endif /* MAC_OS_X_VERSION_MIN_REQUIRED */ #else - std::vector<Segment> segments; + // Eigen allocator is needed for alignment of Eigen data types + std::vector<Segment, Eigen::aligned_allocator<Segment> > segments; #endif unsigned int nrOfJoints; unsigned int nrOfSegments; diff --git a/intern/itasc/kdl/tree.hpp b/intern/itasc/kdl/tree.hpp index 4da764ac6d6..a020c6cf2cf 100644 --- a/intern/itasc/kdl/tree.hpp +++ b/intern/itasc/kdl/tree.hpp @@ -27,19 +27,30 @@ #include <string> #include <map> -#if !defined(__APPLE__) -#include <Eigen/Core> +#if defined(__APPLE__) +# if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_5 + //no include +# else +# include <Eigen/Core> +# endif /* MAC_OS_X_VERSION_MIN_REQUIRED */ +#else +# include <Eigen/Core> #endif namespace KDL { //Forward declaration class TreeElement; -#if !defined(__APPLE__) +#if defined(__APPLE__) +# if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_5 + typedef std::map<std::string,TreeElement> SegmentMap; +# else // Eigen allocator is needed for alignment of Eigen data types typedef std::map<std::string,TreeElement, std::less<std::string>, Eigen::aligned_allocator<std::pair<std::string, TreeElement> > > SegmentMap; +# endif /* MAC_OS_X_VERSION_MIN_REQUIRED */ #else - typedef std::map<std::string,TreeElement> SegmentMap; + // Eigen allocator is needed for alignment of Eigen data types + typedef std::map<std::string,TreeElement, std::less<std::string>, Eigen::aligned_allocator<std::pair<std::string, TreeElement> > > SegmentMap; #endif class TreeElement { diff --git a/intern/locale/CMakeLists.txt b/intern/locale/CMakeLists.txt new file mode 100644 index 00000000000..f3356bcda49 --- /dev/null +++ b/intern/locale/CMakeLists.txt @@ -0,0 +1,44 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2012, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Bastien Montagne. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . +) + +set(INC_SYS +) + +set(SRC + boost_locale_wrapper.cpp +) + +if(WITH_INTERNATIONAL) + list(APPEND INC_SYS + ${BOOST_INCLUDE_DIR} + ) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +blender_add_lib(bf_intern_locale "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/locale/SConscript b/intern/locale/SConscript new file mode 100644 index 00000000000..4a1357b76e4 --- /dev/null +++ b/intern/locale/SConscript @@ -0,0 +1,14 @@ +#!/usr/bin/python + +Import('env') + +sources = env.Glob('*.cpp') + +incs = '.' +defs = [] + +if env['WITH_BF_INTERNATIONAL']: + defs.append('WITH_INTERNATIONAL') + incs += ' ' + env['BF_BOOST_INC'] + +env.BlenderLib( 'bf_intern_locale', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185]) diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp new file mode 100644 index 00000000000..ec2976f19b9 --- /dev/null +++ b/intern/locale/boost_locale_wrapper.cpp @@ -0,0 +1,87 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#include <boost/locale.hpp> + +#include "boost_locale_wrapper.h" + +static std::string messages_path; +static std::string default_domain; + +void bl_locale_init(const char *_messages_path, const char *_default_domain) +{ + // Avoid using ICU backend, we do not need its power and it's rather heavy! + boost::locale::localization_backend_manager lman = boost::locale::localization_backend_manager::global(); +#if defined (_WIN32) + lman.select("winapi"); +#else + lman.select("posix"); +#endif + boost::locale::localization_backend_manager::global(lman); + + messages_path = _messages_path; + default_domain = _default_domain; +} + +void bl_locale_set(const char *locale) +{ + boost::locale::generator gen; + // Specify location of dictionaries. + gen.add_messages_path(messages_path); + gen.add_messages_domain(default_domain); + //gen.set_default_messages_domain(default_domain); + + if (locale && locale[0]) { + std::locale::global(gen(locale)); + } + else { + std::locale::global(gen("")); + } + // Note: boost always uses "C" LC_NUMERIC by default! +} + +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 + // once deleted (which happens as soons they are out of scope of this func). + typedef boost::locale::message_format<char> char_message_facet; + try { + std::locale l; + char_message_facet const &facet = std::use_facet<char_message_facet>(l); + char const *r = facet.get(0, msgctxt, msgid); + if(r) + return r; + return msgid; + } + catch(std::exception const &e) { +// std::cout << "boost_locale_pgettext: " << e.what() << " \n"; + return msgid; + } +} + diff --git a/intern/locale/boost_locale_wrapper.h b/intern/locale/boost_locale_wrapper.h new file mode 100644 index 00000000000..e7956d216f1 --- /dev/null +++ b/intern/locale/boost_locale_wrapper.h @@ -0,0 +1,49 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Bastien Montagne. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file locale/boost_locale_wrapper.h + * \ingroup locale + * A thin C wrapper around boost::locale... + */ + +#ifndef __BOOST_LOCALE_WRAPPER_H__ +#define __BOOST_LOCALE_WRAPPER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +void bl_locale_init(const char *messages_path, const char *default_domain); +void bl_locale_set(const char *locale); +const char* bl_locale_pgettext(const char *msgctxt, const char *msgid); + +#ifdef __cplusplus +} +#endif + +#endif /* __BOOST_LOCALE_WRAPPER_H__ */ diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py index a8f4aa30e95..7747ef45c4d 100644 --- a/release/scripts/startup/bl_ui/properties_data_curve.py +++ b/release/scripts/startup/bl_ui/properties_data_curve.py @@ -174,11 +174,14 @@ class DATA_PT_geometry_curve(CurveButtonsPanel, Panel): col.prop(curve, "bevel_object", text="") col = layout.column(align=True) - col.active = (curve.bevel_object is not None) - col.prop(curve, "use_fill_caps") col.prop(curve, "bevel_factor_start") col.prop(curve, "bevel_factor_end") + row = col.row() + row.active = (curve.bevel_object is not None) + row.prop(curve, "use_fill_caps") + row.prop(curve, "use_map_taper") + class DATA_PT_pathanim(CurveButtonsPanelCurve, Panel): bl_label = "Path Animation" diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 902358813df..ea8ffbe6c9f 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -625,6 +625,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "wrap_method", text="") if md.wrap_method == 'PROJECT': + col.prop(md, "project_limit", text="Limit") split = layout.split(percentage=0.25) col = split.column() @@ -642,8 +643,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.label(text="Cull Faces:") col.prop(md, "cull_face", expand=True) - layout.label(text="Auxiliary Target:") - layout.prop(md, "auxiliary_target", text="") + layout.prop(md, "auxiliary_target") elif md.wrap_method == 'NEAREST_SURFACEPOINT': layout.prop(md, "use_keep_above_surface") diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 5302ad9b471..18eb8f8d9dd 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -684,7 +684,7 @@ class IMAGE_PT_paint(Panel, ImagePaintPanel): if brush: col = layout.column() - col.template_color_wheel(brush, "color", value_slider=True) + col.template_color_picker(brush, "color", value_slider=True) col.prop(brush, "color", text="") row = col.row(align=True) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index cba45d4c2b7..ad4074d9744 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -31,21 +31,21 @@ def act_strip(context): def draw_color_balance(layout, color_balance): col = layout.column() col.label(text="Lift:") - col.template_color_wheel(color_balance, "lift", value_slider=True, cubic=True) + col.template_color_picker(color_balance, "lift", value_slider=True, cubic=True) row = col.row() row.prop(color_balance, "lift", text="") row.prop(color_balance, "invert_lift", text="Inverse") col = layout.column() col.label(text="Gamma:") - col.template_color_wheel(color_balance, "gamma", value_slider=True, lock_luminosity=True, cubic=True) + col.template_color_picker(color_balance, "gamma", value_slider=True, lock_luminosity=True, cubic=True) row = col.row() row.prop(color_balance, "gamma", text="") row.prop(color_balance, "invert_gamma", text="Inverse") col = layout.column() col.label(text="Gain:") - col.template_color_wheel(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True) + col.template_color_picker(color_balance, "gain", value_slider=True, lock_luminosity=True, cubic=True) row = col.row() row.prop(color_balance, "gain", text="") row.prop(color_balance, "invert_gain", text="Inverse") diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 455bf210ac2..1a66d67bce5 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -422,7 +422,7 @@ class USERPREF_PT_system(Panel): col.separator() col.separator() - if hasattr(system, "compute_device"): + if hasattr(system, "compute_device_type"): col.label(text="Compute Device:") col.row().prop(system, "compute_device_type", expand=True) sub = col.row() @@ -446,6 +446,7 @@ class USERPREF_PT_system(Panel): #~ col.prop(system, "use_antialiasing") col.label(text="Window Draw Method:") col.prop(system, "window_draw_method", text="") + col.prop(system, "multi_sample", text="") col.label(text="Text Draw Options:") col.prop(system, "use_text_antialiasing") col.label(text="Textures:") @@ -728,6 +729,29 @@ class USERPREF_PT_theme(Panel): colsub = padding.column() colsub.row().prop(ui, "header") + col.separator() + col.separator() + + ui = theme.user_interface + col.label("Axis Colors:") + + row = col.row() + + subsplit = row.split(percentage=0.95) + + padding = subsplit.split(percentage=0.15) + colsub = padding.column() + colsub = padding.column() + colsub.row().prop(ui, "axis_x") + colsub.row().prop(ui, "axis_y") + colsub.row().prop(ui, "axis_z") + + subsplit = row.split(percentage=0.85) + + padding = subsplit.split(percentage=0.15) + colsub = padding.column() + colsub = padding.column() + layout.separator() layout.separator() elif theme.theme_area == 'BONE_COLOR_SETS': diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 01e9e627f76..26d99b02729 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -168,6 +168,8 @@ class VIEW3D_MT_transform(VIEW3D_MT_transform_base): # generic... layout = self.layout + layout.operator("transform.shrink_fatten", text="Shrink Fatten") + layout.separator() layout.operator("transform.translate", text="Move Texture Space").texture_space = True diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 9bb8255356c..91132a72b07 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -633,7 +633,7 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): elif context.image_paint_object and brush: col = layout.column() - col.template_color_wheel(brush, "color", value_slider=True) + col.template_color_picker(brush, "color", value_slider=True) col.prop(brush, "color", text="") row = col.row(align=True) @@ -681,7 +681,7 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel): # Vertex Paint Mode # elif context.vertex_paint_object and brush: col = layout.column() - col.template_color_wheel(brush, "color", value_slider=True) + col.template_color_picker(brush, "color", value_slider=True) col.prop(brush, "color", text="") row = col.row(align=True) diff --git a/source/blender/avi/intern/avi.c b/source/blender/avi/intern/avi.c index e1732b0caae..d6301b723a7 100644 --- a/source/blender/avi/intern/avi.c +++ b/source/blender/avi/intern/avi.c @@ -665,13 +665,13 @@ AviError AVI_open_movie(const char *name, AviMovie *movie) } } -/* Some AVI's have offset entries in absolute coordinates - * instead of an offset from the movie beginning... this is... - * wacky, but we need to handle it. The wacky offset always - * starts at movi_offset it seems... so we'll check that. - * Note the the offset needs an extra 4 bytes for some - * undetermined reason */ - + /* Some AVI's have offset entries in absolute coordinates + * instead of an offset from the movie beginning... this is... + * wacky, but we need to handle it. The wacky offset always + * starts at movi_offset it seems... so we'll check that. + * Note the the offset needs an extra 4 bytes for some + * undetermined reason */ + if (movie->entries[0].Offset == movie->movi_offset) movie->read_offset = 4; } diff --git a/source/blender/blenfont/BLF_translation.h b/source/blender/blenfont/BLF_translation.h index b01ce93cb65..d0b5d824bb3 100644 --- a/source/blender/blenfont/BLF_translation.h +++ b/source/blender/blenfont/BLF_translation.h @@ -35,16 +35,6 @@ #define TEXT_DOMAIN_NAME "blender" -/* blf_translation.c */ - -#ifdef WITH_INTERNATIONAL -unsigned char *BLF_get_unifont(int *unifont_size); -void BLF_free_unifont(void); -#endif - -const char *BLF_gettext(const char *msgid); -const char *BLF_pgettext(const char *context, const char *message); - /* blf_lang.c */ /* Search the path directory to the locale files, this try all @@ -61,17 +51,23 @@ void BLF_lang_set(const char *); /* Get the current locale (short code, e.g. es_ES). */ const char *BLF_lang_get(void); -/* Set the current encoding name. */ -void BLF_lang_encoding(const char *str); - /* Get EnumPropertyItem's for translations menu. */ struct EnumPropertyItem *BLF_RNA_lang_enum_properties(void); +/* blf_translation.c */ + +#ifdef WITH_INTERNATIONAL +unsigned char *BLF_get_unifont(int *unifont_size); +void BLF_free_unifont(void); +#endif + +const char *BLF_pgettext(const char *msgctxt, const char *msgid); + /* translation */ int BLF_translate_iface(void); int BLF_translate_tooltips(void); -const char *BLF_translate_do_iface(const char *contex, const char *msgid); -const char *BLF_translate_do_tooltip(const char *contex, const char *msgid); +const char *BLF_translate_do_iface(const char *msgctxt, const char *msgid); +const char *BLF_translate_do_tooltip(const char *msgctxt, const char *msgid); /* The "translation-marker" macro. */ diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index 022dfd282b0..90baef14a74 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -31,6 +31,7 @@ set(INC ../makesrna ../imbuf ../../../intern/guardedalloc + ../../../intern/locale ) set(INC_SYS @@ -54,9 +55,6 @@ set(SRC ) if(WITH_INTERNATIONAL) - list(APPEND INC_SYS - ${GETTEXT_INCLUDE_DIRS} - ) add_definitions(-DWITH_INTERNATIONAL) endif() diff --git a/source/blender/blenfont/SConscript b/source/blender/blenfont/SConscript index 075da58b116..c0591c877ef 100644 --- a/source/blender/blenfont/SConscript +++ b/source/blender/blenfont/SConscript @@ -4,11 +4,10 @@ Import ('env') sources = env.Glob('intern/*.c') -incs = '. intern #/intern/guardedalloc ../blenkernel ../blenlib ../blenloader' +incs = '. intern #/intern/guardedalloc #/intern/locale ../blenkernel ../blenlib ../blenloader' incs += ' ../makesdna ../makesrna ../imbuf ../editors/include' incs += ' #/extern/glew/include' incs += ' ' + env['BF_FREETYPE_INC'] -incs += ' ' + env['BF_GETTEXT_INC'] defs = ['GLEW_STATIC'] diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index f3cc92e7a27..778b6c11e5a 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -28,7 +28,6 @@ * \ingroup blf */ - #include <stdio.h> #include <stdlib.h> #include <string.h> diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c index 501f8cd2958..0ed48623dd5 100644 --- a/source/blender/blenfont/intern/blf_lang.c +++ b/source/blender/blenfont/intern/blf_lang.c @@ -28,20 +28,17 @@ */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "BKE_global.h" - -#include "BLF_api.h" #include "BLF_translation.h" /* own include */ #ifdef WITH_INTERNATIONAL -#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> -#include "libintl.h" +#include "boost_locale_wrapper.h" + +#include "BKE_global.h" #include "DNA_userdef_types.h" @@ -49,52 +46,33 @@ #include "MEM_guardedalloc.h" -#include "BLI_string.h" -#include "BLI_utildefines.h" -#include "BLI_path_util.h" #include "BLI_fileops.h" #include "BLI_linklist.h" +#include "BLI_path_util.h" #include "BLI_string.h" - -#define SYSTEM_ENCODING_DEFAULT "UTF-8" -#define FONT_SIZE_DEFAULT 12 +#include "BLI_utildefines.h" /* Locale options. */ -static char global_messagepath[1024]; -static char global_language[32]; -static char global_encoding_name[32]; - static const char **locales = NULL; -static char **long_locales = NULL; /* XXX Temp fix until we get a final solution with modern intl lib under windows! */ static int num_locales = 0; static EnumPropertyItem *locales_menu = NULL; static int num_locales_menu = 0; #define ULANGUAGE ((U.language >= 0 && U.language < num_locales) ? U.language : 0) #define LOCALE(_id) (locales ? locales[_id] : "") -#define LONG_LOCALE(_id) (long_locales ? long_locales[_id] : "") static void free_locales(void) { if (locales) { int idx = num_locales_menu - 1; /* Last item does not need to be freed! */ while (idx--) { - MEM_freeN((void*)locales_menu[idx].identifier); - MEM_freeN((void*)locales_menu[idx].name); - MEM_freeN((void*)locales_menu[idx].description); /* Also frees locales's relevant value! */ - } - - idx = num_locales; - while (idx--) { - if (long_locales[idx]) { - MEM_freeN(long_locales[idx]); - } + MEM_freeN((void *)locales_menu[idx].identifier); + MEM_freeN((void *)locales_menu[idx].name); + MEM_freeN((void *)locales_menu[idx].description); /* Also frees locales's relevant value! */ } MEM_freeN(locales); locales = NULL; - MEM_freeN(long_locales); - long_locales = NULL; } if (locales_menu) { MEM_freeN(locales_menu); @@ -140,7 +118,6 @@ static void fill_locales(void) /* 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__); - long_locales = MEM_callocN(num_locales * sizeof(char*), __func__); while (line) { int id; char *loc, *sep1, *sep2, *sep3; @@ -163,26 +140,28 @@ static void fill_locales(void) sep2++; sep3 = strchr(sep2, ':'); + if (sep3) { locales_menu[idx].identifier = loc = BLI_strdupn(sep2, sep3 - sep2); + } + else { + locales_menu[idx].identifier = loc = BLI_strdup(sep2); + } - if (id == 0) { - /* The DEFAULT item... */ - if (BLI_strnlen(loc, 2)) { - locales[id] = locales_menu[idx].description = BLI_strdup(""); - long_locales[id] = BLI_strdup(""); - } - /* Menu "label", not to be stored in locales! */ - else { - locales_menu[idx].description = BLI_strdup(""); - } + if (id == 0) { + /* The DEFAULT item... */ + if (BLI_strnlen(loc, 2)) { + locales[id] = locales_menu[idx].description = BLI_strdup(""); } + /* Menu "label", not to be stored in locales! */ else { - locales[id] = locales_menu[idx].description = BLI_strdup(loc); - long_locales[id] = BLI_strdup(sep3 + 1); + locales_menu[idx].description = BLI_strdup(""); } - idx++; } + else { + locales[id] = locales_menu[idx].description = BLI_strdup(loc); + } + idx++; } } @@ -207,15 +186,12 @@ void BLF_lang_init(void) { char *messagepath = BLI_get_folder(BLENDER_DATAFILES, "locale"); - BLI_strncpy(global_encoding_name, SYSTEM_ENCODING_DEFAULT, sizeof(global_encoding_name)); - if (messagepath) { - BLI_strncpy(global_messagepath, messagepath, sizeof(global_messagepath)); + bl_locale_init(messagepath, TEXT_DOMAIN_NAME); fill_locales(); } else { printf("%s: 'locale' data path for translations not found, continuing\n", __func__); - global_messagepath[0] = '\0'; } } @@ -224,159 +200,37 @@ void BLF_lang_free(void) free_locales(); } -/* Get LANG/LANGUAGE environment variable. */ -static void get_language_variable(const char *varname, char *var, const size_t maxlen) -{ - char *env = getenv(varname); - - if (env) { - char *s; - - /* Store defaul locale. */ - BLI_strncpy(var, env, maxlen); - - /* Use first language as default. */ - s = strchr(var, ':'); - if (s) - s[0] = 0; - } -} - -/* Get language to be used based on locale (which might be empty when using default language) and - * LANG environment variable. - */ -static void get_language(const char *locale, const char *lang, char *language, const size_t maxlen) -{ - if (locale[0]) { - BLI_strncpy(language, locale, maxlen); - } - else { - char *s; - - BLI_strncpy(language, lang, maxlen); - - s = strchr(language, '.'); - if (s) - s[0] = 0; - } -} - -/* XXX WARNING!!! In osx somehow the previous function call jumps in this one??? (ton, ppc) */ void BLF_lang_set(const char *str) { - char *locreturn; - int ok = TRUE; int ulang = ULANGUAGE; + const char *short_locale = str ? str : LOCALE(ulang); + const char *short_locale_utf8 = NULL; if ((U.transopts & USER_DOTRANSLATE) == 0) return; -#if defined(_WIN32) && !defined(FREE_WINDOWS) - { - const char *long_locale = str ? str : LONG_LOCALE(ulang); - if (long_locale) { - char *envStr; - - if (ulang) - envStr = BLI_sprintfN("LANG=%s", long_locale); - else /* Use system setting. */ - envStr = BLI_sprintfN("LANG=%s", getenv("LANG")); - - gettext_putenv(envStr); - MEM_freeN(envStr); - } - - locreturn = setlocale(LC_ALL, long_locale); - - if (locreturn == NULL) { - if (G.debug & G_DEBUG) - printf("Could not change locale to %s\n", long_locale); - - ok = FALSE; - } - } -#else - { - const char *short_locale = str ? str : LOCALE(ulang); - static char default_lang[64] = "\0"; - static char default_language[64] = "\0"; - - if (default_lang[0] == 0) - get_language_variable("LANG", default_lang, sizeof(default_lang)); - - if (default_language[0] == 0) - get_language_variable("LANGUAGE", default_language, sizeof(default_language)); - - if (short_locale[0]) { - char *short_locale_utf8 = BLI_sprintfN("%s.UTF-8", short_locale); - - if (G.debug & G_DEBUG) - printf("Setting LANG and LANGUAGE to %s\n", short_locale_utf8); - - locreturn = setlocale(LC_ALL, short_locale_utf8); - - if (locreturn != NULL) { - BLI_setenv("LANG", short_locale_utf8); - BLI_setenv("LANGUAGE", short_locale_utf8); - } - else { - if (G.debug & G_DEBUG) - printf("Setting LANG and LANGUAGE to %s\n", short_locale); - - locreturn = setlocale(LC_ALL, short_locale); - - if (locreturn != NULL) { - BLI_setenv("LANG", short_locale); - BLI_setenv("LANGUAGE", short_locale); - } - } - - if (G.debug & G_DEBUG && locreturn == NULL) - printf("Could not change locale to %s nor %s\n", short_locale, short_locale_utf8); - - MEM_freeN(short_locale_utf8); + /* We want to avoid locales like '.UTF-8'! */ + if (short_locale[0]) { + /* Hurrey! encoding needs to be placed *before* variant! */ + char *variant = strchr(short_locale, '@'); + if (variant) { + char *locale = BLI_strdupn(short_locale, variant - short_locale); + short_locale_utf8 = BLI_sprintfN("%s.UTF-8%s", locale, variant); + MEM_freeN(locale); } else { - if (G.debug & G_DEBUG) - printf("Setting LANG=%s and LANGUAGE=%s\n", default_lang, default_language); - - BLI_setenv("LANG", default_lang); - BLI_setenv("LANGUAGE", default_language); - locreturn = setlocale(LC_ALL, ""); - - if (G.debug & G_DEBUG && locreturn == NULL) - printf("Could not reset locale\n"); - } - - if (locreturn == NULL) { - char language[65]; - - get_language(short_locale, default_lang, language, sizeof(language)); - - if (G.debug & G_DEBUG) - printf("Fallback to LANG=%s and LANGUAGE=%s\n", default_lang, language); - - /* Fallback to default settings. */ - BLI_setenv("LANG", default_lang); - BLI_setenv("LANGUAGE", language); - - locreturn = setlocale(LC_ALL, ""); - - ok = FALSE; + short_locale_utf8 = BLI_sprintfN("%s.UTF-8", short_locale); } } -#endif - - if (ok) { - /*printf("Change locale to %s\n", locreturn ); */ - BLI_strncpy(global_language, locreturn, sizeof(global_language)); + else { + short_locale_utf8 = short_locale; } - setlocale(LC_NUMERIC, "C"); + bl_locale_set(short_locale_utf8); - textdomain(TEXT_DOMAIN_NAME); - bindtextdomain(TEXT_DOMAIN_NAME, global_messagepath); - bind_textdomain_codeset(TEXT_DOMAIN_NAME, global_encoding_name); + if (short_locale[0]) { + MEM_freeN((void*)short_locale_utf8); + } } const char *BLF_lang_get(void) @@ -385,12 +239,6 @@ const char *BLF_lang_get(void) return LOCALE(uilang); } -void BLF_lang_encoding(const char *str) -{ - BLI_strncpy(global_encoding_name, str, sizeof(global_encoding_name)); - /* bind_textdomain_codeset(TEXT_DOMAIN_NAME, encoding_name); */ -} - #undef LOCALE #undef ULANGUAGE @@ -406,12 +254,6 @@ void BLF_lang_free(void) return; } -void BLF_lang_encoding(const char *str) -{ - (void)str; - return; -} - void BLF_lang_set(const char *str) { (void)str; diff --git a/source/blender/blenfont/intern/blf_translation.c b/source/blender/blenfont/intern/blf_translation.c index 9c863da9eba..5d4b631688a 100644 --- a/source/blender/blenfont/intern/blf_translation.c +++ b/source/blender/blenfont/intern/blf_translation.c @@ -31,18 +31,11 @@ #include <stdlib.h> #include <string.h> -#ifdef WITH_INTERNATIONAL -#include <libintl.h> -#include <locale.h> - -#define GETTEXT_CONTEXT_GLUE "\004" +#include "BLF_translation.h" -/* needed for windows version of gettext */ -#ifndef LC_MESSAGES -# define LC_MESSAGES 1729 -#endif +#ifdef WITH_INTERNATIONAL -#endif +#include "boost_locale_wrapper.h" #include "MEM_guardedalloc.h" @@ -52,11 +45,8 @@ #include "BLI_path_util.h" #include "BLI_fileops.h" -#include "BLF_translation.h" - #include "DNA_userdef_types.h" /* For user settings. */ -#ifdef WITH_INTERNATIONAL static const char unifont_filename[] = "droidsans.ttf.gz"; static unsigned char *unifont_ttf = NULL; static int unifont_size = 0; @@ -90,55 +80,19 @@ void BLF_free_unifont(void) #endif -const char *BLF_gettext(const char *msgid) +const char *BLF_pgettext(const char *msgctxt, const char *msgid) { #ifdef WITH_INTERNATIONAL - if (msgid && msgid[0]) - return gettext(msgid); + if (msgid && msgid[0]) { + return bl_locale_pgettext(msgctxt, msgid); + } return ""; #else + (void)msgctxt; return msgid; #endif } -const char *BLF_pgettext(const char *context, const char *message) -{ -#ifdef WITH_INTERNATIONAL - char static_msg_ctxt_id[1024]; - char *dynamic_msg_ctxt_id = NULL; - char *msg_ctxt_id; - const char *translation; - - size_t overall_length = strlen(context) + strlen(message) + sizeof(GETTEXT_CONTEXT_GLUE) + 1; - - if (!message || !context || !message[0]) - return ""; - - if (overall_length > sizeof(static_msg_ctxt_id)) { - dynamic_msg_ctxt_id = malloc(overall_length); - msg_ctxt_id = dynamic_msg_ctxt_id; - } - else { - msg_ctxt_id = static_msg_ctxt_id; - } - - sprintf(msg_ctxt_id, "%s%s%s", context, GETTEXT_CONTEXT_GLUE, message); - - translation = (char *)dcgettext(TEXT_DOMAIN_NAME, msg_ctxt_id, LC_MESSAGES); - - if (dynamic_msg_ctxt_id) - free(dynamic_msg_ctxt_id); - - if (translation == msg_ctxt_id) - translation = message; - - return translation; -#else - (void)context; - return message; -#endif -} - int BLF_translate_iface(void) { #ifdef WITH_INTERNATIONAL @@ -157,36 +111,32 @@ int BLF_translate_tooltips(void) #endif } -const char *BLF_translate_do_iface(const char *context, const char *msgid) +const char *BLF_translate_do_iface(const char *msgctxt, const char *msgid) { #ifdef WITH_INTERNATIONAL if (BLF_translate_iface()) { - if (context) - return BLF_pgettext(context, msgid); - else - return BLF_gettext(msgid); + return BLF_pgettext(msgctxt, msgid); } - else + else { return msgid; + } #else - (void)context; + (void)msgctxt; return msgid; #endif } -const char *BLF_translate_do_tooltip(const char *context, const char *msgid) +const char *BLF_translate_do_tooltip(const char *msgctxt, const char *msgid) { #ifdef WITH_INTERNATIONAL if (BLF_translate_tooltips()) { - if (context) - return BLF_pgettext(context, msgid); - else - return BLF_gettext(msgid); + return BLF_pgettext(msgctxt, msgid); } - else + else { return msgid; + } #else - (void)context; + (void)msgctxt; return msgid; #endif } diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index e7033d8648d..3c210877de7 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 264 -#define BLENDER_SUBVERSION 8 +#define BLENDER_SUBVERSION 9 /* 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_lamp.h b/source/blender/blenkernel/BKE_lamp.h index 3acd4d1986e..244decf9d52 100644 --- a/source/blender/blenkernel/BKE_lamp.h +++ b/source/blender/blenkernel/BKE_lamp.h @@ -37,6 +37,7 @@ extern "C" { #endif struct Lamp; +struct Scene; struct Lamp *BKE_lamp_add(const char *name) WARN_UNUSED; struct Lamp *BKE_lamp_copy(struct Lamp *la) WARN_UNUSED; @@ -44,6 +45,8 @@ struct Lamp *localize_lamp(struct Lamp *la) WARN_UNUSED; void BKE_lamp_make_local(struct Lamp *la); void BKE_lamp_free(struct Lamp *la); +void lamp_drivers_update(struct Scene *scene, struct Lamp *la, float ctime); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 2f889084d0e..e53d0efffbd 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -283,9 +283,9 @@ typedef struct IndexNode { void create_vert_poly_map(MeshElemMap **map, int **mem, const struct MPoly *mface, const struct MLoop *mloop, int totvert, int totface, int totloop); - + void create_vert_edge_map(MeshElemMap **map, int **mem, - const struct MEdge *medge, int totvert, int totedge); + const struct MEdge *medge, int totvert, int totedge); /* vertex level transformations & checks (no derived mesh) */ diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index 8fa20eb2cc2..bee2c374f27 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -48,7 +48,7 @@ struct Scene; void multires_customdata_delete(struct Mesh *me); void multires_set_tot_level(struct Object *ob, - struct MultiresModifierData *mmd, int lvl); + struct MultiresModifierData *mmd, int lvl); void multires_mark_as_modified(struct Object *ob, enum MultiresModifiedFlags flags); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index fd92b7b5d69..cca425a63d8 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1680,8 +1680,8 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos nextmask &= ~CD_MASK_ORCO; DM_set_only_copy(orcodm, nextmask | CD_MASK_ORIGINDEX | - (mti->requiredDataMask ? - mti->requiredDataMask(ob, md) : 0)); + (mti->requiredDataMask ? + mti->requiredDataMask(ob, md) : 0)); ndm = mti->applyModifier(md, ob, orcodm, app_flags & ~MOD_APPLY_USECACHE); if (ndm) { diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index dffe26bd782..f5c0660371b 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -76,8 +76,8 @@ /* --------------------- */ /* forward declarations */ -static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index, - int level, short flag); +static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], + int persistent_id[MAX_DUPLI_RECUR], int level, int index, short flag); /* ******************************************************************** */ /* Animation Visualization */ @@ -706,31 +706,45 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua #define DUPLILIST_FOR_RENDER 2 #define DUPLILIST_ANIMATED 4 -static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int par_index, int type, short flag) +static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, + int persistent_id[MAX_DUPLI_RECUR], int level, int index, int type, short flag) { DupliObject *dob = MEM_callocN(sizeof(DupliObject), "dupliobject"); - + int i; + BLI_addtail(lb, dob); dob->ob = ob; copy_m4_m4(dob->mat, mat); copy_m4_m4(dob->omat, ob->obmat); dob->origlay = ob->lay; - dob->index = index; - dob->particle_index = par_index; dob->type = type; dob->animated = (type == OB_DUPLIGROUP) && (flag & DUPLILIST_ANIMATED); ob->lay = lay; + + /* set persistent id, which is an array with a persistent index for each level + * (particle number, vertex number, ..). by comparing this we can find the same + * dupli object between frames, which is needed for motion blur. last level + * goes first in the array. */ + dob->persistent_id[0] = index; + for (i = 1; i < level; i++) + dob->persistent_id[i] = persistent_id[level - 1 - i]; + + /* metaballs never draw in duplis, they are instead merged into one by the basis + * mball outside of the group. this does mean that if that mball is not in the + * scene, they will not show up at all, limitation that should be solved once. */ + if (ob->type == OB_MBALL) + dob->no_draw = TRUE; return dob; } -static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, +static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { DupliObject *dob; Group *group; GroupObject *go; - float mat[4][4], tmat[4][4]; + float mat[4][4], tmat[4][4], id; if (ob->dup_group == NULL) return; group = ob->dup_group; @@ -750,7 +764,7 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_inde if (group_is_animated(ob, group)) flag |= DUPLILIST_ANIMATED; - for (go = group->gobject.first; go; go = go->next) { + for (go = group->gobject.first, id = 0; go; go = go->next, id++) { /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */ if (go->ob != ob) { @@ -764,7 +778,7 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_inde mult_m4_m4m4(mat, ob->obmat, go->ob->obmat); } - dob = new_dupli_object(lb, go->ob, mat, ob->lay, 0, par_index, OB_DUPLIGROUP, flag); + dob = new_dupli_object(lb, go->ob, mat, ob->lay, persistent_id, level, id, OB_DUPLIGROUP, flag); /* check the group instance and object layers match, also that the object visible flags are ok. */ if ((dob->origlay & group->layer) == 0 || @@ -773,20 +787,17 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_inde { dob->no_draw = TRUE; } - else { - dob->no_draw = FALSE; - } if (go->ob->transflag & OB_DUPLI) { copy_m4_m4(dob->ob->obmat, dob->mat); - object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, par_index, level + 1, flag); + object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, persistent_id, level + 1, id, flag); copy_m4_m4(dob->ob->obmat, dob->omat); } } } } -static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, int level, short flag) +static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { extern int enable_cu_speed; /* object.c */ Object copyob; @@ -834,7 +845,7 @@ static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_ind BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra); - dob = new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, par_index, OB_DUPLIFRAMES, flag); + dob = new_dupli_object(lb, ob, ob->obmat, ob->lay, persistent_id, level, scene->r.cfra, OB_DUPLIFRAMES, flag); copy_m4_m4(dob->omat, copyob.obmat); } } @@ -865,7 +876,7 @@ typedef struct VertexDupliData { Scene *scene; Object *ob, *par; float (*orco)[3]; - int par_index; + int *persistent_id; } VertexDupliData; /* ------------- */ @@ -902,7 +913,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], origlay = vdd->ob->lay; - dob = new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, vdd->par_index, OB_DUPLIVERTS, vdd->flag); + dob = new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, vdd->persistent_id, vdd->level, index, OB_DUPLIVERTS, vdd->flag); /* restore the original layer so that each dupli will have proper dob->origlay */ vdd->ob->lay = origlay; @@ -914,12 +925,12 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], float tmpmat[4][4]; copy_m4_m4(tmpmat, vdd->ob->obmat); copy_m4_m4(vdd->ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->par_index, vdd->level + 1, vdd->flag); + object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->persistent_id, vdd->level + 1, index, vdd->flag); copy_m4_m4(vdd->ob->obmat, tmpmat); } } -static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index, +static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { Object *ob, *ob_iter; @@ -1004,7 +1015,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl vdd.scene = scene; vdd.par = par; copy_m4_m4(vdd.pmat, pmat); - vdd.par_index = par_index; + vdd.persistent_id = persistent_id; /* mballs have a different dupli handling */ if (ob->type != OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ @@ -1043,7 +1054,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl dm->release(dm); } -static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index, +static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { Object *ob, *ob_iter; @@ -1186,7 +1197,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa copy_m4_m4(tmat, obmat); mul_m4_m4m3(obmat, tmat, mat); - dob = new_dupli_object(lb, ob, obmat, par->lay, a, par_index, OB_DUPLIFACES, (flag & DUPLILIST_ANIMATED)); + dob = new_dupli_object(lb, ob, obmat, par->lay, persistent_id, level, a, OB_DUPLIFACES, (flag & DUPLILIST_ANIMATED)); if (flag & DUPLILIST_FOR_RENDER) { w = 1.0f / (float)mp->totloop; @@ -1209,7 +1220,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa float tmpmat[4][4]; copy_m4_m4(tmpmat, ob->obmat); copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, par_index, level + 1, flag); + object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, persistent_id, level + 1, a, flag); copy_m4_m4(ob->obmat, tmpmat); } } @@ -1229,7 +1240,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa dm->release(dm); } -static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int UNUSED(par_index), ParticleSystem *psys, +static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int persistent_id[MAX_DUPLI_RECUR], ParticleSystem *psys, int level, short flag) { GroupObject *go; @@ -1244,7 +1255,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4], (*oldobmat)[4]; - int a, b, counter, index, hair = 0; + int a, b, hair = 0; int totpart, totchild, totgroup = 0 /*, pa_num */; int no_draw_flag = PARS_UNEXIST; @@ -1360,8 +1371,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p else a = totpart; - index = 0; - for (pa = psys->particles, counter = 0; a < totpart + totchild; a++, pa++, counter++) { + for (pa = psys->particles; a < totpart + totchild; a++, pa++) { if (a < totpart) { /* handle parent particle */ if (pa->flag & no_draw_flag) @@ -1456,7 +1466,8 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p else copy_m4_m4(mat, tmat); - dob = new_dupli_object(lb, go->ob, mat, par->lay, counter, index, OB_DUPLIPARTS, (flag & DUPLILIST_ANIMATED)); + dob = new_dupli_object(lb, go->ob, mat, par->lay, persistent_id, level, a, OB_DUPLIPARTS, (flag & DUPLILIST_ANIMATED)); + dob->particle_system = psys; copy_m4_m4(dob->omat, obcopylist[b].obmat); if (flag & DUPLILIST_FOR_RENDER) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); @@ -1516,14 +1527,12 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); - dob = new_dupli_object(lb, ob, mat, ob->lay, counter, index, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, (flag & DUPLILIST_ANIMATED)); + dob = new_dupli_object(lb, ob, mat, ob->lay, persistent_id, level, a, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, (flag & DUPLILIST_ANIMATED)); + dob->particle_system = psys; copy_m4_m4(dob->omat, oldobmat); if (flag & DUPLILIST_FOR_RENDER) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } - - /* only counts visible particles */ - index++; } /* restore objects since they were changed in BKE_object_where_is_calc_time */ @@ -1570,7 +1579,7 @@ static Object *find_family_object(Object **obar, char *family, char ch) } -static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_index, int level, short flag) +static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int persistent_id[MAX_DUPLI_RECUR], int level, short flag) { Object *ob, *obar[256] = {NULL}; Curve *cu; @@ -1609,7 +1618,7 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_inde copy_m4_m4(obmat, par->obmat); copy_v3_v3(obmat[3], vec); - new_dupli_object(lb, ob, obmat, par->lay, a, par_index, OB_DUPLIVERTS, flag); + new_dupli_object(lb, ob, obmat, par->lay, persistent_id, level, a, OB_DUPLIVERTS, flag); } } @@ -1618,8 +1627,8 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_inde /* ------------- */ -static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index, - int level, short flag) +static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], + int persistent_id[MAX_DUPLI_RECUR], int level, int index, short flag) { if ((ob->transflag & OB_DUPLI) == 0) return; @@ -1636,34 +1645,45 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas } } + /* keep track of persistent id */ + if (level > 0) + persistent_id[level - 1] = index; + if (ob->transflag & OB_DUPLIPARTS) { ParticleSystem *psys = ob->particlesystem.first; - for (; psys; psys = psys->next) - new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, psys, level + 1, flag); + int psysid = 0; + + /* particle system take up one level in id, the particles another */ + for (; psys; psys = psys->next, psysid++) { + persistent_id[level] = psysid; + new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, persistent_id, psys, level + 2, flag); + } + + persistent_id[level] = 0; } else if (ob->transflag & OB_DUPLIVERTS) { if (ob->type == OB_MESH) { - vertex_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, flag); + vertex_duplilist(duplilist, id, scene, ob, par_space_mat, persistent_id, level + 1, flag); } else if (ob->type == OB_FONT) { if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ - font_duplilist(duplilist, scene, ob, par_index, level + 1, flag); + font_duplilist(duplilist, scene, ob, persistent_id, level + 1, flag); } } } else if (ob->transflag & OB_DUPLIFACES) { if (ob->type == OB_MESH) - face_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, flag); + face_duplilist(duplilist, id, scene, ob, par_space_mat, persistent_id, level + 1, flag); } else if (ob->transflag & OB_DUPLIFRAMES) { if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ - frames_duplilist(duplilist, scene, ob, par_index, level + 1, flag); + frames_duplilist(duplilist, scene, ob, persistent_id, level + 1, flag); } } else if (ob->transflag & OB_DUPLIGROUP) { DupliObject *dob; - group_duplilist(duplilist, scene, ob, par_index, level + 1, flag); /* now recursive */ + group_duplilist(duplilist, scene, ob, persistent_id, level + 1, flag); /* now recursive */ if (level == 0) { for (dob = duplilist->first; dob; dob = dob->next) @@ -1671,6 +1691,10 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas copy_m4_m4(dob->ob->obmat, dob->mat); } } + + /* clear persistent id */ + if (level > 0) + persistent_id[level - 1] = 0; } /* Returns a list of DupliObject @@ -1678,13 +1702,14 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas ListBase *object_duplilist_ex(Scene *sce, Object *ob, int update, int for_render) { ListBase *duplilist = MEM_mallocN(sizeof(ListBase), "duplilist"); + int persistent_id[MAX_DUPLI_RECUR] = {0}; int flag = 0; if (update) flag |= DUPLILIST_DO_UPDATE; if (for_render) flag |= DUPLILIST_FOR_RENDER; duplilist->first = duplilist->last = NULL; - object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0, flag); + object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, persistent_id, 0, 0, flag); return duplilist; } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 1aec4195354..9c94e267a7e 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -782,7 +782,7 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u ANIMDATA_NODETREE_IDS_CB(mainptr->tex.first, Tex); /* lamps */ - ANIMDATA_IDS_CB(mainptr->lamp.first); + ANIMDATA_NODETREE_IDS_CB(mainptr->lamp.first, Lamp); /* materials */ ANIMDATA_NODETREE_IDS_CB(mainptr->mat.first, Material); @@ -824,7 +824,7 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u ANIMDATA_IDS_CB(mainptr->mask.first); /* worlds */ - ANIMDATA_IDS_CB(mainptr->world.first); + ANIMDATA_NODETREE_IDS_CB(mainptr->world.first, World); /* scenes */ ANIMDATA_NODETREE_IDS_CB(mainptr->scene.first, Scene); @@ -872,7 +872,7 @@ void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const cha RENAMEFIX_ANIM_NODETREE_IDS(mainptr->tex.first, Tex); /* lamps */ - RENAMEFIX_ANIM_IDS(mainptr->lamp.first); + RENAMEFIX_ANIM_NODETREE_IDS(mainptr->lamp.first, Lamp); /* materials */ RENAMEFIX_ANIM_NODETREE_IDS(mainptr->mat.first, Material); @@ -914,7 +914,7 @@ void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const cha RENAMEFIX_ANIM_IDS(mainptr->mask.first); /* worlds */ - RENAMEFIX_ANIM_IDS(mainptr->world.first); + RENAMEFIX_ANIM_NODETREE_IDS(mainptr->world.first, World); /* linestyles */ RENAMEFIX_ANIM_IDS(mainptr->linestyle.first); diff --git a/source/blender/blenkernel/intern/bmfont.c b/source/blender/blenkernel/intern/bmfont.c index df7fb2c1807..0495e729937 100644 --- a/source/blender/blenkernel/intern/bmfont.c +++ b/source/blender/blenkernel/intern/bmfont.c @@ -247,12 +247,13 @@ int locateGlyph(bmFont *bmfont, unsigned short unicode) return(current); } -void matrixGlyph(ImBuf * ibuf, unsigned short unicode, - float *centerx, float *centery, - float *sizex, float *sizey, - float *transx, float *transy, - float *movex, float *movey, - float *advance) +void matrixGlyph( + ImBuf * ibuf, unsigned short unicode, + float *centerx, float *centery, + float *sizex, float *sizey, + float *transx, float *transy, + float *movex, float *movey, + float *advance) { int index; bmFont *bmfont; diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 2e0b3a3c64a..3ade51d13eb 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -828,8 +828,6 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, mcol = DM_get_tessface_data_layer(dm, colType); } - printf("%s: %p(%d/%d)\n", __func__, mcol, CD_ID_MCOL, colType); - cdDM_update_normals_from_pbvh(dm); /* back-buffer always uses legacy since VBO's would need the @@ -1956,12 +1954,11 @@ static DerivedMesh *cddm_from_bmesh_ex(struct BMesh *bm, int use_mdisps, /* avoid this where possiblem, takes extra memory */ if (use_tessface) { - int *polyindex; BM_mesh_elem_index_ensure(bm, BM_FACE); index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); - for (i = 0; i < dm->numTessFaceData; i++, index++, polyindex++) { + for (i = 0; i < dm->numTessFaceData; i++, index++) { MFace *mf = &mface[i]; const BMLoop **l = em_looptris[i]; efa = l[0]->f; @@ -2257,6 +2254,11 @@ void CDDM_calc_normals_tessface(DerivedMesh *dm) * this is a really horribly written function. ger. - joeedh * * note, CDDM_recalc_tessellation has to run on the returned DM if you want to access tessfaces. + * + * Note: This function is currently only used by the Mirror modifier, so it + * skips any faces that have all vertices merged (to avoid creating pairs + * of faces sharing the same set of vertices). If used elsewhere, it may + * be necessary to make this functionality optional. */ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap) { @@ -2300,14 +2302,11 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap) newv[i] = newv[vtargetmap[i]]; } } - - /* find-replace merged vertices with target vertices */ - ml = cddm->mloop; - for (i = 0; i < totloop; i++, ml++) { - if (vtargetmap[ml->v] != -1) { - ml->v = vtargetmap[ml->v]; - } - } + + /* Don't remap vertices in cddm->mloop, because we need to know the original + * indices in order to skip faces with all vertices merged. + * The "update loop indices..." section further down remaps vertices in mloop. + */ /* now go through and fix edges and faces */ med = cddm->medge; @@ -2341,6 +2340,24 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap) ml = cddm->mloop + mp->loopstart; + /* skip faces with all vertices merged */ + { + int all_vertices_merged = TRUE; + + for (j = 0; j < mp->totloop; j++, ml++) { + if (vtargetmap[ml->v] == -1) { + all_vertices_merged = FALSE; + break; + } + } + + if (UNLIKELY(all_vertices_merged)) { + continue; + } + } + + ml = cddm->mloop + mp->loopstart; + c = 0; for (j = 0; j < mp->totloop; j++, ml++) { med = cddm->medge + ml->e; diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 67aaaceaa38..f2cd695d64a 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -1117,12 +1117,12 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float * sumdiv += *fp; } if (sumdiv != 0.0f) if (sumdiv < 0.999f || sumdiv > 1.001f) { - /* is normalizing needed? */ - fp = sum; - for (i = istart; i <= iend; i++, fp++) { - *fp /= sumdiv; - } + /* is normalizing needed? */ + fp = sum; + for (i = istart; i <= iend; i++, fp++) { + *fp /= sumdiv; } + } /* one! (1.0) real point */ fp = sum; @@ -2481,8 +2481,8 @@ void BKE_curve_bevelList_make(Object *ob) else bevp2 = bevp1 + 1; - inp = (bevp1->vec[0] - bevp0->vec[0]) * (bevp0->vec[1] - bevp2->vec[1]) + - (bevp0->vec[1] - bevp1->vec[1]) * (bevp0->vec[0] - bevp2->vec[0]); + inp = ((bevp1->vec[0] - bevp0->vec[0]) * (bevp0->vec[1] - bevp2->vec[1]) + + (bevp0->vec[1] - bevp1->vec[1]) * (bevp0->vec[0] - bevp2->vec[0])); if (inp > 0.0f) sd->dir = 1; diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 44b3917df7f..9d3a7ec57cf 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -45,6 +45,7 @@ #include "DNA_anim_types.h" #include "DNA_camera_types.h" #include "DNA_group_types.h" +#include "DNA_lamp_types.h" #include "DNA_lattice_types.h" #include "DNA_key_types.h" #include "DNA_material_types.h" @@ -350,8 +351,8 @@ static void dag_add_driver_relation(AnimData *adt, DagForest *dag, DagNode *node /* XXX: forward def for material driver handling... */ static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Material *ma); -/* recursive handling for material nodetree drivers */ -static void dag_add_material_nodetree_driver_relations(DagForest *dag, DagNode *node, bNodeTree *ntree) +/* recursive handling for shader nodetree drivers */ +static void dag_add_shader_nodetree_driver_relations(DagForest *dag, DagNode *node, bNodeTree *ntree) { bNode *n; @@ -367,7 +368,7 @@ static void dag_add_material_nodetree_driver_relations(DagForest *dag, DagNode * dag_add_material_driver_relations(dag, node, (Material *)n->id); } else if (n->type == NODE_GROUP) { - dag_add_material_nodetree_driver_relations(dag, node, (bNodeTree *)n->id); + dag_add_shader_nodetree_driver_relations(dag, node, (bNodeTree *)n->id); } } } @@ -386,18 +387,41 @@ static void dag_add_material_driver_relations(DagForest *dag, DagNode *node, Mat ma->id.flag |= LIB_DOIT; /* material itself */ - if (ma->adt) { + if (ma->adt) dag_add_driver_relation(ma->adt, dag, node, 1); - } /* textures */ // TODO... //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id); /* material's nodetree */ - if (ma->nodetree) { - dag_add_material_nodetree_driver_relations(dag, node, ma->nodetree); - } + if (ma->nodetree) + dag_add_shader_nodetree_driver_relations(dag, node, ma->nodetree); +} + +/* recursive handling for lamp drivers */ +static void dag_add_lamp_driver_relations(DagForest *dag, DagNode *node, Lamp *la) +{ + /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited + * already (see build_dag()). This assumes la->id.flag & LIB_DOIT isn't set by anything else + * in the meantime... [#32017] + */ + if (la->id.flag & LIB_DOIT) + return; + else + la->id.flag |= LIB_DOIT; + + /* lamp itself */ + if (la->adt) + dag_add_driver_relation(la->adt, dag, node, 1); + + /* textures */ + // TODO... + //dag_add_texture_driver_relations(DagForest *dag, DagNode *node, ID *id); + + /* lamp's nodetree */ + if (la->nodetree) + dag_add_shader_nodetree_driver_relations(dag, node, la->nodetree); } static void dag_add_collision_field_relation(DagForest *dag, Scene *scene, Object *ob, DagNode *node, int skip_forcefield) @@ -647,6 +671,8 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O } } } + else if(ob->type == OB_LAMP) + dag_add_lamp_driver_relations(dag, node, ob->data); /* particles */ psys = ob->particlesystem.first; @@ -817,6 +843,7 @@ DagForest *build_dag(Main *bmain, Scene *sce, short mask) /* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later [#32017] */ tag_main_idcode(bmain, ID_MA, FALSE); + tag_main_idcode(bmain, ID_LA, FALSE); /* add base node for scene. scene is always the first node in DAG */ scenenode = dag_add_node(dag, sce); diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index e13d05d0a2f..a78a9af54ae 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -630,7 +630,7 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis * - first point left, last point right * - based on subdivided points in original curve, not on points in taper curve (still) */ -float BKE_displist_calc_taper(Scene *scene, Object *taperobj, int cur, int tot) +static float displist_calc_taper(Scene *scene, Object *taperobj, float fac) { DispList *dl; @@ -643,7 +643,6 @@ float BKE_displist_calc_taper(Scene *scene, Object *taperobj, int cur, int tot) dl = taperobj->disp.first; } if (dl) { - float fac = ((float)cur) / (float)(tot - 1); float minx, dx, *fp; int a; @@ -671,6 +670,13 @@ float BKE_displist_calc_taper(Scene *scene, Object *taperobj, int cur, int tot) return 1.0; } +float BKE_displist_calc_taper(Scene *scene, Object *taperobj, int cur, int tot) +{ + float fac = ((float)cur) / (float)(tot - 1); + + return displist_calc_taper(scene, taperobj, fac); +} + void BKE_displist_make_mball(Scene *scene, Object *ob) { if (!ob || ob->type != OB_MBALL) @@ -1240,7 +1246,7 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase, } } -static void rotateBevelPiece(Curve *cu, BevPoint *bevp, DispList *dlb, float widfac, float fac, float **data_r) +static void rotateBevelPiece(Curve *cu, BevPoint *bevp, BevPoint *nbevp, DispList *dlb, float bev_blend, float widfac, float fac, float **data_r) { float *fp, *data = *data_r; int b; @@ -1248,22 +1254,48 @@ static void rotateBevelPiece(Curve *cu, BevPoint *bevp, DispList *dlb, float wid fp = dlb->verts; for (b = 0; b < dlb->nr; b++, fp += 3, data += 3) { if (cu->flag & CU_3D) { - float vec[3]; + float vec[3], quat[4]; vec[0] = fp[1] + widfac; vec[1] = fp[2]; vec[2] = 0.0; - mul_qt_v3(bevp->quat, vec); + if (nbevp == NULL) { + copy_v3_v3(data, bevp->vec); + copy_qt_qt(quat, bevp->quat); + } + else { + interp_v3_v3v3(data, bevp->vec, nbevp->vec, bev_blend); + interp_qt_qtqt(quat, bevp->quat, nbevp->quat, bev_blend); + } + + mul_qt_v3(quat, vec); - data[0] = bevp->vec[0] + fac * vec[0]; - data[1] = bevp->vec[1] + fac * vec[1]; - data[2] = bevp->vec[2] + fac * vec[2]; + data[0] += fac * vec[0]; + data[1] += fac * vec[1]; + data[2] += fac * vec[2]; } else { - data[0] = bevp->vec[0] + fac * (widfac + fp[1]) * bevp->sina; - data[1] = bevp->vec[1] + fac * (widfac + fp[1]) * bevp->cosa; - data[2] = bevp->vec[2] + fac * fp[2]; + float sina, cosa; + + if (nbevp == NULL) { + copy_v3_v3(data, bevp->vec); + sina = bevp->sina; + cosa = bevp->cosa; + } + else { + interp_v3_v3v3(data, bevp->vec, nbevp->vec, bev_blend); + + /* perhaps we need to interpolate angles instead. but the thing is + * cosa and sina are not actually sine and cosine + */ + sina = nbevp->sina * bev_blend + bevp->sina * (1.0f - bev_blend); + cosa = nbevp->cosa * bev_blend + bevp->cosa * (1.0f - bev_blend); + } + + data[0] += fac * (widfac + fp[1]) * sina; + data[1] += fac * (widfac + fp[1]) * cosa; + data[2] += fac * fp[2]; } } @@ -1399,8 +1431,8 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba firstblend = 1.0f - (bevfac1 * (bl->nr - 1) - (int)(bevfac1 * (bl->nr - 1))); lastblend = bevfac2 * (bl->nr - 1) - (int)(bevfac2 * (bl->nr - 1)); - if (steps > bl->nr) { - steps = bl->nr; + if (start + steps > bl->nr) { + steps = bl->nr - start; lastblend = 1.0f; } @@ -1438,7 +1470,29 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba fac = bevp->radius; } else { - fac = BKE_displist_calc_taper(scene, cu->taperobj, i, bl->nr); + float len, taper_fac; + + if (cu->flag & CU_MAP_TAPER) { + len = (steps - 3) + firstblend + lastblend; + + if (a == 0) + taper_fac = 0.0f; + else if (a == steps - 1) + taper_fac = 1.0f; + else + taper_fac = ((float) a - (1.0f - firstblend)) / len; + } + else { + len = bl->nr - 1; + taper_fac = (float) i / len; + + if (a == 0) + taper_fac += (1.0f - firstblend) / len; + else if (a == steps - 1) + taper_fac -= (1.0f - lastblend) / len; + } + + fac = displist_calc_taper(scene, cu->taperobj, taper_fac); } if (bevp->split_tag) { @@ -1446,27 +1500,12 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } /* rotate bevel piece and write in data */ - rotateBevelPiece(cu, bevp, dlb, widfac, fac, &data); - - if (a == 1 || a == steps - 1) { - float *cur_fp = cur_data, *prev_fp = cur_data - 3 * dlb->nr; - int b; - - for (b = 0; b < dlb->nr; b++, prev_fp += 3, cur_fp += 3) { - float cur[3], prev[3]; - - copy_v3_v3(cur, cur_fp); - copy_v3_v3(prev, prev_fp); - - if (a == 1) - interp_v3_v3v3(prev, cur_fp, prev_fp, firstblend); - if (a == steps - 1) - interp_v3_v3v3(cur, prev_fp, cur_fp, lastblend); - - copy_v3_v3(cur_fp, cur); - copy_v3_v3(prev_fp, prev); - } - } + if (a == 0) + rotateBevelPiece(cu, bevp, bevp + 1, dlb, 1.0f - firstblend, widfac, fac, &data); + else if (a == steps - 1) + rotateBevelPiece(cu, bevp, bevp - 1, dlb, 1.0f - lastblend, widfac, fac, &data); + else + rotateBevelPiece(cu, bevp, NULL, dlb, 0.0f, widfac, fac, &data); if (cu->bevobj && (cu->flag & CU_FILL_CAPS)) { if (a == 1) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index ef751ce3493..55d37c91859 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1561,7 +1561,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* also a little of space to the background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); /* and draw the text. */ BLF_position(mono, x, y + y_ofs, 0.0); @@ -1578,7 +1578,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* and space for background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); BLF_draw_buffer(mono, stamp_data.note); @@ -1594,7 +1594,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* and space for background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); BLF_draw_buffer(mono, stamp_data.date); @@ -1610,7 +1610,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* and space for background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); BLF_draw_buffer(mono, stamp_data.rendertime); @@ -1625,7 +1625,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* extra space for background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); @@ -1641,7 +1641,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* extra space for background */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - x - BUFF_MARGIN_X, y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + x - BUFF_MARGIN_X, y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); @@ -1656,7 +1656,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* extra space for background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); @@ -1671,7 +1671,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* extra space for background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); BLF_draw_buffer(mono, stamp_data.camera); @@ -1684,7 +1684,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* extra space for background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); BLF_draw_buffer(mono, stamp_data.cameralens); } @@ -1697,7 +1697,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* extra space for background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); @@ -1713,7 +1713,7 @@ void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rec /* extra space for background. */ buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, - x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); + x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); BLF_draw_buffer(mono, stamp_data.strip); diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 4782d09a7c8..2f37db846f3 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -33,9 +33,12 @@ #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" +#include "DNA_node_types.h" #include "DNA_object_types.h" +#include "DNA_scene_types.h" #include "DNA_texture_types.h" #include "BLI_listbase.h" @@ -73,7 +76,7 @@ Lamp *BKE_lamp_add(const char *name) la->soft = 3.0f; la->compressthresh = 0.05f; la->ray_samp = la->ray_sampy = la->ray_sampz = 1; - la->area_size = la->area_sizey = la->area_sizez = 1.0f; + la->area_size = la->area_sizey = la->area_sizez = 0.1f; la->buffers = 1; la->buftype = LA_SHADBUF_HALFWAY; la->ray_samp_method = LA_SAMP_HALTON; @@ -232,3 +235,38 @@ void BKE_lamp_free(Lamp *la) la->id.icon_id = 0; } +/* Calculate all drivers for lamps, see material_drivers_update for why this is a bad hack */ + +static void lamp_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime) +{ + bNode *node; + + /* nodetree itself */ + if (ntree->adt && ntree->adt->drivers.first) + BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS); + + /* nodes */ + for (node = ntree->nodes.first; node; node = node->next) + if (node->id && node->type == NODE_GROUP) + lamp_node_drivers_update(scene, (bNodeTree *)node->id, ctime); +} + +void lamp_drivers_update(Scene *scene, Lamp *la, float ctime) +{ + /* Prevent infinite recursion by checking (and tagging the lamp) as having been visited already + * (see BKE_scene_update_tagged()). This assumes la->id.flag & LIB_DOIT isn't set by anything else + * in the meantime... [#32017] */ + if (la->id.flag & LIB_DOIT) + return; + else + la->id.flag |= LIB_DOIT; + + /* lamp itself */ + if (la->adt && la->adt->drivers.first) + BKE_animsys_evaluate_animdata(scene, &la->id, la->adt, ctime, ADT_RECALC_DRIVERS); + + /* nodes */ + if (la->nodetree) + lamp_node_drivers_update(scene, la->nodetree, ctime); +} + diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c index e67df9c6419..7d89678d36f 100644 --- a/source/blender/blenkernel/intern/mask_evaluate.c +++ b/source/blender/blenkernel/intern/mask_evaluate.c @@ -245,7 +245,7 @@ static void feather_bucket_add_edge(FeatherEdgesBucket *bucket, int start, int e } else { bucket->segments = MEM_reallocN(bucket->segments, - (alloc_delta + bucket->tot_segment) * sizeof(*bucket->segments)); + (alloc_delta + bucket->tot_segment) * sizeof(*bucket->segments)); } bucket->alloc_segment += alloc_delta; diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 6d44473583f..068059dc29a 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2388,7 +2388,7 @@ void create_vert_poly_map(MeshElemMap **map, int **mem, * of edges that use that vertex as an endpoint. The lists are allocated * from one memory pool. */ void create_vert_edge_map(MeshElemMap **map, int **mem, - const MEdge *medge, int totvert, int totedge) + const MEdge *medge, int totvert, int totedge) { int i, *indices; diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 66f2ff12258..c737dccc5d2 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -984,7 +984,7 @@ static void grid_tangent(const CCGKey *key, int x, int y, int axis, CCGElem *gri /* Construct 3x3 tangent-space matrix in 'mat' */ static void grid_tangent_matrix(float mat[3][3], const CCGKey *key, - int x, int y, CCGElem *grid) + int x, int y, CCGElem *grid) { grid_tangent(key, x, y, 0, grid, mat[0]); normalize_v3(mat[0]); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 04dae942d5b..7e3808512b6 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2664,6 +2664,8 @@ void BKE_object_handle_update(Scene *scene, Object *ob) } } } + else if (ob->type == OB_LAMP) + lamp_drivers_update(scene, ob->data, ctime); /* particles */ if (ob->particlesystem.first) { diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 7bc736d394e..e694a7e7eb3 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -183,7 +183,7 @@ MINLINE float catrom(float p0, float p1, float p2, float p3, float f) MINLINE float omega(float k, float depth) { - return sqrt(GRAVITY * k * tanh(k * depth)); + return sqrtf(GRAVITY * k * tanhf(k * depth)); } // modified Phillips spectrum @@ -256,8 +256,8 @@ static void add_comlex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl static void mul_complex_f(fftw_complex res, fftw_complex cmpl, float f) { - res[0] = cmpl[0] * f; - res[1] = cmpl[1] * f; + res[0] = cmpl[0] * (double)f; + res[1] = cmpl[1] * (double)f; } static void mul_complex_c(fftw_complex res, fftw_complex cmpl1, fftw_complex cmpl2) @@ -289,8 +289,8 @@ static void exp_complex(fftw_complex res, fftw_complex cmpl) { float r = expf(cmpl[0]); - res[0] = cos(cmpl[1]) * r; - res[1] = sin(cmpl[1]) * r; + res[0] = cosf(cmpl[1]) * r; + res[1] = sinf(cmpl[1]) * r; } float BKE_ocean_jminus_to_foam(float jminus, float coverage) @@ -462,7 +462,7 @@ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j) i = abs(i) % oc->_M; j = abs(j) % oc->_N; - ocr->disp[1] = oc->_do_disp_y ? oc->_disp_y[i * oc->_N + j] : 0.0f; + ocr->disp[1] = oc->_do_disp_y ? (float)oc->_disp_y[i * oc->_N + j] : 0.0f; if (oc->_do_chop) { ocr->disp[0] = oc->_disp_x[i * oc->_N + j]; @@ -546,7 +546,7 @@ 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.0 ? 0.0 : 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)); } } @@ -568,7 +568,7 @@ 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.0 ? 0.0 : 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)); } } @@ -589,7 +589,7 @@ 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, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0 ? 0.0 : 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)); } } @@ -616,7 +616,7 @@ 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, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, (o->_k[i * (1 + o->_N / 2) + j] == 0.0 ? 0.0 : 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)); } } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 49b405379eb..3ce66f23d81 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -58,8 +58,10 @@ #include "BKE_anim.h" #include "BKE_animsys.h" +#include "BKE_action.h" #include "BKE_colortools.h" #include "BKE_depsgraph.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_group.h" #include "BKE_idprop.h" @@ -117,6 +119,24 @@ void free_qtcodecdata(QuicktimeCodecData *qcd) } } +static void remove_sequencer_fcurves(Scene *sce) +{ + AnimData *adt = BKE_animdata_from_id(&sce->id); + + if (adt && adt->action) { + FCurve *fcu, *nextfcu; + + for (fcu = adt->action->curves.first; fcu; fcu = nextfcu) { + nextfcu = fcu->next; + + if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) { + action_groups_remove_channel(adt->action, fcu); + free_fcurve(fcu); + } + } + } +} + Scene *BKE_scene_copy(Scene *sce, int type) { Scene *scen; @@ -181,6 +201,10 @@ Scene *BKE_scene_copy(Scene *sce, int type) BLI_strncpy(scen->sequencer_colorspace_settings.name, sce->sequencer_colorspace_settings.name, sizeof(scen->sequencer_colorspace_settings.name)); + + /* remove animation used by sequencer */ + if (type != SCE_COPY_FULL) + remove_sequencer_fcurves(scen); } /* tool settings */ @@ -1057,6 +1081,7 @@ void BKE_scene_update_tagged(Main *bmain, Scene *scene) * when trying to find materials with drivers that need evaluating [#32017] */ tag_main_idcode(bmain, ID_MA, FALSE); + tag_main_idcode(bmain, ID_LA, FALSE); /* update all objects: drivers, matrices, displists, etc. flags set * by depgraph or manual, no layer check here, gets correct flushed @@ -1126,6 +1151,7 @@ void BKE_scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay) * when trying to find materials with drivers that need evaluating [#32017] */ tag_main_idcode(bmain, ID_MA, FALSE); + tag_main_idcode(bmain, ID_LA, FALSE); /* BKE_object_handle_update() on all objects, groups and sets */ scene_update_tagged_recursive(bmain, sce, sce); diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c index b0dcad64722..609724e802f 100644 --- a/source/blender/blenkernel/intern/seqmodifier.c +++ b/source/blender/blenkernel/intern/seqmodifier.c @@ -349,9 +349,9 @@ static void hue_correct_apply_threaded(int width, int height, unsigned char *rec hsv_to_rgb(hsv[0], hsv[1], hsv[2], result, result + 1, result + 2); if (mask_rect_float) - copy_v3_v3(mask, mask_rect_float + pixel_index); + copy_v3_v3(mask, mask_rect_float + pixel_index); else if (mask_rect) - rgb_uchar_to_float(mask, mask_rect + pixel_index); + rgb_uchar_to_float(mask, mask_rect + pixel_index); result[0] = pixel[0] * (1.0f - mask[0]) + result[0] * mask[0]; result[1] = pixel[1] * (1.0f - mask[1]) + result[1] * mask[1]; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index af0cab98fe0..547ca96e10a 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -2344,6 +2344,7 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float int do_seq; int have_seq = FALSE; Scene *scene; + int is_thread_main = BLI_thread_is_main(); /* don't refer to seq->scene above this point!, it can be NULL */ if (seq->scene == NULL) { @@ -2373,7 +2374,7 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float /* prevent eternal loop */ do_seq = context.scene->r.scemode & R_DOSEQ; - context.scene->r.scemode &= ~R_DOSEQ; + scene->r.scemode &= ~R_DOSEQ; #ifdef DURIAN_CAMERA_SWITCH /* stooping to new low's in hackyness :( */ @@ -2383,10 +2384,7 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float (void)oldmarkers; #endif - if ((sequencer_view3d_cb && do_seq_gl && camera) && - (BLI_thread_is_main() == TRUE) && - ((have_seq == FALSE) || (scene == context.scene))) - { + if ((sequencer_view3d_cb && do_seq_gl && camera) && is_thread_main) { char err_out[256] = "unknown"; /* for old scened this can be uninitialized, * should probably be added to do_versions at some point if the functionality stays */ @@ -2405,8 +2403,12 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float Render *re = RE_GetRender(scene->id.name); RenderResult rres; - /* XXX: this if can be removed when sequence preview rendering uses the job system */ - if (is_rendering || context.scene != scene) { + /* XXX: this if can be removed when sequence preview rendering uses the job system + * + * disable rendered preview for sequencer while rendering -- it's very much possible + * that preview render will went into conflict with final render + */ + if (!is_thread_main || is_rendering == FALSE) { if (re == NULL) re = RE_NewRender(scene->id.name); @@ -2440,7 +2442,7 @@ static ImBuf *seq_render_scene_strip(SeqRenderData context, Sequence *seq, float } /* restore */ - context.scene->r.scemode |= do_seq; + scene->r.scemode |= do_seq; scene->r.cfra = oldcfra; diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 96faec389df..72db34d339c 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -56,33 +56,16 @@ #include "BKE_mesh.h" #include "BKE_tessmesh.h" -/* Util macros */ -#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n")) - -/* Benchmark macros */ -#if !defined(_WIN32) && 0 - -#include <sys/time.h> - -#define BENCH(a) \ - do { \ - double _t1, _t2; \ - struct timeval _tstart, _tend; \ - clock_t _clock_init = clock(); \ - gettimeofday ( &_tstart, NULL); \ - (a); \ - gettimeofday ( &_tend, NULL); \ - _t1 = ( double ) _tstart.tv_sec + ( double ) _tstart.tv_usec/ ( 1000*1000 ); \ - _t2 = ( double ) _tend.tv_sec + ( double ) _tend.tv_usec/ ( 1000*1000 ); \ - printf("%s: %fs (real) %fs (cpu)\n", #a, _t2-_t1, (float)(clock()-_clock_init)/CLOCKS_PER_SEC);\ - } while (0) - +/* for timing... */ +#if 0 +# include "PIL_time.h" #else - -#define BENCH(a) (a) - +# define TIMEIT_BENCH(expr, id) (expr) #endif +/* Util macros */ +#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n")) + /* get derived mesh */ /* TODO is anyfunction that does this? returning the derivedFinal without we caring if its in edit mode or not? */ DerivedMesh *object_get_derived_final(Object *ob) @@ -143,7 +126,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) BVHTreeNearest nearest = NULL_BVHTreeNearest; - BENCH(bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6)); + TIMEIT_BENCH(bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6), bvhtree_verts); if (treeData.tree == NULL) { OUT_OF_MEMORY(); return; @@ -294,6 +277,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) /* Options about projection direction */ const char use_normal = calc->smd->shrinkOpts; + const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit; float proj_axis[3] = {0.0f, 0.0f, 0.0f}; /* Raycast and tree stuff */ @@ -410,6 +394,13 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) treeData.raycast_callback, &treeData); } + /* don't set the initial dist (which is more efficient), + * because its calculated in the targets space, we want the dist in our own space */ + if (proj_limit_squared != 0.0f) { + if (len_squared_v3v3(hit.co, co) > proj_limit_squared) { + hit.index = -1; + } + } if (hit.index != -1) { madd_v3_v3v3fl(hit.co, hit.co, tmp_no, calc->keepDist); @@ -437,7 +428,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) BVHTreeNearest nearest = NULL_BVHTreeNearest; /* Create a bvh-tree of the given target */ - BENCH(bvhtree_from_mesh_faces(&treeData, calc->target, 0.0, 2, 6)); + TIMEIT_BENCH(bvhtree_from_mesh_faces(&treeData, calc->target, 0.0, 2, 6), bvhtree_faces); if (treeData.tree == NULL) { OUT_OF_MEMORY(); return; @@ -584,15 +575,15 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM if (calc.target) { switch (smd->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: - BENCH(shrinkwrap_calc_nearest_surface_point(&calc)); + TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface); break; case MOD_SHRINKWRAP_PROJECT: - BENCH(shrinkwrap_calc_normal_projection(&calc)); + TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project); break; case MOD_SHRINKWRAP_NEAREST_VERTEX: - BENCH(shrinkwrap_calc_nearest_vertex(&calc)); + TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), deform_vertex); break; } } diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index f9925a41177..d96bece2b11 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -262,21 +262,21 @@ static void smoke_set_domain_from_derivedmesh(SmokeDomainSettings *sds, Object * scale = res / size[0]; sds->scale = size[0] / ob->size[0]; sds->base_res[0] = res; - sds->base_res[1] = (int)(size[1] * scale + 0.5); - sds->base_res[2] = (int)(size[2] * scale + 0.5); + sds->base_res[1] = (int)(size[1] * scale + 0.5f); + sds->base_res[2] = (int)(size[2] * scale + 0.5f); } else if (size[1] > MAX2(size[0], size[2])) { scale = res / size[1]; sds->scale = size[1] / ob->size[1]; - sds->base_res[0] = (int)(size[0] * scale + 0.5); + sds->base_res[0] = (int)(size[0] * scale + 0.5f); sds->base_res[1] = res; - sds->base_res[2] = (int)(size[2] * scale + 0.5); + sds->base_res[2] = (int)(size[2] * scale + 0.5f); } else { scale = res / size[2]; sds->scale = size[2] / ob->size[2]; - sds->base_res[0] = (int)(size[0] * scale + 0.5); - sds->base_res[1] = (int)(size[1] * scale + 0.5); + sds->base_res[0] = (int)(size[0] * scale + 0.5f); + sds->base_res[1] = (int)(size[1] * scale + 0.5f); sds->base_res[2] = res; } @@ -1581,7 +1581,7 @@ BLI_INLINE void apply_inflow_fields(SmokeFlowSettings *sfs, float emission_value if (fuel && fuel[index]) { /* instead of using 1.0 for all new fuel add slight falloff * to reduce flow blockiness */ - float value = 1.0f - pow(1.0f - emission_value, 2.0f); + float value = 1.0f - powf(1.0f - emission_value, 2.0f); if (value > react[index]) { float f = fuel_flow / fuel[index]; @@ -1944,9 +1944,9 @@ static void update_effectors(Scene *scene, Object *ob, SmokeDomainSettings *sds, mul_v3_fl(retvel, mag); // TODO dg - do in force! - force_x[index] = MIN2(MAX2(-1.0, retvel[0] * 0.2), 1.0); - force_y[index] = MIN2(MAX2(-1.0, retvel[1] * 0.2), 1.0); - force_z[index] = MIN2(MAX2(-1.0, retvel[2] * 0.2), 1.0); + force_x[index] = min_ff(max_ff(-1.0f, retvel[0] * 0.2f), 1.0f); + force_y[index] = min_ff(max_ff(-1.0f, retvel[1] * 0.2f), 1.0f); + force_z[index] = min_ff(max_ff(-1.0f, retvel[2] * 0.2f), 1.0f); } } } @@ -1999,7 +1999,7 @@ static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh * /* adapt timestep for different framerates, dt = 0.1 is at 25fps */ dt = DT_DEFAULT * (25.0f / fps); // maximum timestep/"CFL" constraint: dt < 5.0 *dx / maxVel - maxVel = (sds->dx * 5.0); + maxVel = (sds->dx * 5.0f); #if 0 for (i = 0; i < size; i++) { @@ -2009,7 +2009,7 @@ static void step(Scene *scene, Object *ob, SmokeModifierData *smd, DerivedMesh * } #endif - maxVelMag = sqrt(maxVelMag) * dt * sds->time_scale; + maxVelMag = sqrtf(maxVelMag) * dt * sds->time_scale; totalSubsteps = (int)((maxVelMag / maxVel) + 1.0f); /* always round up */ totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; @@ -2286,7 +2286,7 @@ static float calc_voxel_transp(float *result, float *input, int res[3], int *pix const size_t index = smoke_get_index(pixel[0], res[0], pixel[1], res[1], pixel[2]); // T_ray *= T_vox - *tRay *= exp(input[index] * correct); + *tRay *= expf(input[index] * correct); if (result[index] < 0.0f) { @@ -2386,7 +2386,7 @@ static void smoke_calc_transparency(SmokeDomainSettings *sds, Scene *scene) float light[3]; int a, z, slabsize = sds->res[0] * sds->res[1], size = sds->res[0] * sds->res[1] * sds->res[2]; float *density = smoke_get_density(sds->fluid); - float correct = -7.0 * sds->dx; + float correct = -7.0f * sds->dx; if (!get_lamp(scene, light)) return; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index aad205bb5bf..af9d21d8cbc 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -353,17 +353,17 @@ void sound_load(struct Main *bmain, bSound *sound) } // XXX unused currently #if 0 - break; + break; + } + case SOUND_TYPE_BUFFER: + if (sound->child_sound && sound->child_sound->handle) + sound->handle = AUD_bufferSound(sound->child_sound->handle); + break; + case SOUND_TYPE_LIMITER: + if (sound->child_sound && sound->child_sound->handle) + sound->handle = AUD_limitSound(sound->child_sound, sound->start, sound->end); + break; } - case SOUND_TYPE_BUFFER: - if (sound->child_sound && sound->child_sound->handle) - sound->handle = AUD_bufferSound(sound->child_sound->handle); - break; - case SOUND_TYPE_LIMITER: - if (sound->child_sound && sound->child_sound->handle) - sound->handle = AUD_limitSound(sound->child_sound, sound->start, sound->end); - break; -} #endif if (sound->flags & SOUND_FLAGS_MONO) { void *handle = AUD_monoSound(sound->handle); diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 469b012f9c3..f76b480c423 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -3025,7 +3025,8 @@ 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); + BLI_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void **)ccgdm->gridFaces, + ccgdm->gridFlagMats, ccgdm->gridHidden); } ccgdm->pbvh = ob->sculpt->pbvh; diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 3a8a14290dc..da9c919c109 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -478,9 +478,7 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex c->time_base.den = 2997; c->time_base.num = 100; } - else if ((double) ((int) rd->frs_sec_base) == - rd->frs_sec_base) - { + else if ((float) ((int) rd->frs_sec_base) == rd->frs_sec_base) { c->time_base.den = rd->frs_sec; c->time_base.num = (int) rd->frs_sec_base; } @@ -999,7 +997,7 @@ int BKE_ffmpeg_append(RenderData *rd, int start_frame, int frame, int *pixels, i } #ifdef WITH_AUDASPACE - write_audio_frames((frame - rd->sfra) / (((double)rd->frs_sec) / rd->frs_sec_base)); + write_audio_frames((frame - rd->sfra) / (((double)rd->frs_sec) / (double)rd->frs_sec_base)); #endif return success; } diff --git a/source/blender/blenlib/BLI_math.h b/source/blender/blenlib/BLI_math.h index 89c37daae84..db2fed433da 100644 --- a/source/blender/blenlib/BLI_math.h +++ b/source/blender/blenlib/BLI_math.h @@ -58,6 +58,7 @@ #include "BLI_math_rotation.h" #include "BLI_math_vector.h" #include "BLI_math_geom.h" +#include "BLI_math_interp.h" #endif /* __BLI_MATH_H__ */ diff --git a/source/blender/blenlib/BLI_math_interp.h b/source/blender/blenlib/BLI_math_interp.h new file mode 100644 index 00000000000..21975763779 --- /dev/null +++ b/source/blender/blenlib/BLI_math_interp.h @@ -0,0 +1,44 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#ifndef BLI_MATH_INTERP +#define BLI_MATH_INTERP + +void BLI_bicubic_interpolation_fl(const float *buffer, float *output, int width, int height, + int components, float u, float v); + +void BLI_bicubic_interpolation_char(const unsigned char *buffer, unsigned char *output, int width, int height, + int components, float u, float v); + +void BLI_bilinear_interpolation_fl(const float *buffer, float *output, int width, int height, + int components, float u, float v); + +void BLI_bilinear_interpolation_char(const unsigned char *buffer, unsigned char *output, int width, int height, + int components, float u, float v); + +#endif diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 0783a7981ea..f51bd1cf840 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -36,14 +36,18 @@ extern "C" { /********************************* Init **************************************/ -#define MAT4_UNITY {{ 1.0, 0.0, 0.0, 0.0}, \ - { 0.0, 1.0, 0.0, 0.0}, \ - { 0.0, 0.0, 1.0, 0.0}, \ - { 0.0, 0.0, 0.0, 1.0}} - -#define MAT3_UNITY {{ 1.0, 0.0, 0.0}, \ - { 0.0, 1.0, 0.0}, \ - { 0.0, 0.0, 1.0}} +#define MAT4_UNITY { \ + { 1.0, 0.0, 0.0, 0.0}, \ + { 0.0, 1.0, 0.0, 0.0}, \ + { 0.0, 0.0, 1.0, 0.0}, \ + { 0.0, 0.0, 0.0, 1.0} \ +} + +#define MAT3_UNITY { \ + { 1.0, 0.0, 0.0}, \ + { 0.0, 1.0, 0.0}, \ + { 0.0, 0.0, 1.0} \ +} void zero_m3(float R[3][3]); void zero_m4(float R[4][4]); diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h index 9483d068bb9..59ecdb359c9 100644 --- a/source/blender/blenlib/BLI_pbvh.h +++ b/source/blender/blenlib/BLI_pbvh.h @@ -153,7 +153,8 @@ 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, - struct DMGridAdjacency *gridadj, void **gridfaces); + struct DMGridAdjacency *gridadj, void **gridfaces, + struct DMFlagMat *flagmats, unsigned int **grid_hidden); /* vertex deformer */ float (*BLI_pbvh_get_vertCos(struct PBVH *pbvh))[3]; diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h index 73f138a750d..ecbc4cb1cd4 100644 --- a/source/blender/blenlib/BLI_string_utf8.h +++ b/source/blender/blenlib/BLI_string_utf8.h @@ -37,6 +37,7 @@ int BLI_utf8_invalid_byte(const char *str, int length); int BLI_utf8_invalid_strip(char *str, int length); int BLI_str_utf8_size(const char *p); /* warning, can return -1 on bad chars */ +int BLI_str_utf8_size_safe(const char *p); /* copied from glib */ unsigned int BLI_str_utf8_as_unicode(const char *p); unsigned int BLI_str_utf8_as_unicode_and_size(const char *__restrict p, size_t *__restrict index); diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 3aa0ffc3eaa..cd3a934d816 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -71,6 +71,7 @@ set(SRC intern/math_color_inline.c intern/math_geom.c intern/math_geom_inline.c + intern/math_interp.c intern/math_matrix.c intern/math_rotation.c intern/math_vector.c diff --git a/source/blender/blenlib/PIL_time.h b/source/blender/blenlib/PIL_time.h index b8f895c5c82..c3e7e8486d9 100644 --- a/source/blender/blenlib/PIL_time.h +++ b/source/blender/blenlib/PIL_time.h @@ -20,7 +20,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Campbell Barton * * ***** END GPL LICENSE BLOCK ***** */ @@ -76,6 +76,17 @@ void PIL_sleep_ms(int ms); fflush(stdout); \ } (void)0 +/** + * Given some function/expression: + * TIMEIT_BENCH(some_function(), some_unique_description); + */ +#define TIMEIT_BENCH(expr, id) \ + { \ + TIMEIT_START(id); \ + (expr); \ + TIMEIT_END(id); \ + } (void)0 + #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index f520b2318e5..4c8bd43ef73 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -164,7 +164,11 @@ MINLINE void linearrgb_to_srgb_ushort4_predivide(unsigned short srgb[4], const f for (i = 0; i < 3; ++i) { t = linear[i] * inv_alpha; - srgb[i] = (t < 1.0f) ? (unsigned short) (to_srgb_table_lookup(t) * alpha) : FTOUSHORT(linearrgb_to_srgb(t) * 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]); diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c new file mode 100644 index 00000000000..59a1c1f649c --- /dev/null +++ b/source/blender/blenlib/intern/math_interp.c @@ -0,0 +1,351 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2012 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#include <math.h> + +#include "BLI_math.h" + +/************************************************************************** + * INTERPOLATIONS + * + * Reference and docs: + * http://wiki.blender.org/index.php/User:Damiles#Interpolations_Algorithms + ***************************************************************************/ + +/* BICUBIC Interpolation functions + * More info: http://wiki.blender.org/index.php/User:Damiles#Bicubic_pixel_interpolation + * function assumes out to be zero'ed, only does RGBA */ + +static float P(float k) +{ + float p1, p2, p3, p4; + p1 = MAX2(k + 2.0f, 0); + p2 = MAX2(k + 1.0f, 0); + p3 = MAX2(k, 0); + p4 = MAX2(k - 1.0f, 0); + return (float)(1.0f / 6.0f) * (p1 * p1 * p1 - 4.0f * p2 * p2 * p2 + 6.0f * p3 * p3 * p3 - 4.0f * p4 * p4 * p4); +} + + +#if 0 +/* older, slower function, works the same as above */ +static float P(float k) +{ + return (float)(1.0f / 6.0f) * (pow(MAX2(k + 2.0f, 0), 3.0f) - 4.0f * pow(MAX2(k + 1.0f, 0), 3.0f) + 6.0f * pow(MAX2(k, 0), 3.0f) - 4.0f * pow(MAX2(k - 1.0f, 0), 3.0f)); +} +#endif + +static void vector_from_float(const float *data, float vector[4], int components) +{ + if (components == 1) { + vector[0] = data[0]; + } + else if (components == 3) { + copy_v3_v3(vector, data); + } + else { + copy_v4_v4(vector, data); + } +} + +static void vector_from_byte(const unsigned char *data, float vector[4], int components) +{ + if (components == 1) { + vector[0] = data[0]; + } + else if (components == 3) { + vector[0] = data[0]; + vector[1] = data[1]; + vector[2] = data[2]; + } + else { + vector[0] = data[0]; + vector[1] = data[1]; + vector[2] = data[2]; + vector[3] = data[3]; + } +} + +/* BICUBIC INTERPOLATION */ +BLI_INLINE void bicubic_interpolation(const unsigned char *byte_buffer, const float *float_buffer, + unsigned char *byte_output, float *float_output, int width, int height, + int components, float u, float v) +{ + int i, j, n, m, x1, y1; + float a, b, w, wx, wy[4], out[4]; + + /* sample area entirely outside image? */ + if (ceil(u) < 0 || floor(u) > width - 1 || ceil(v) < 0 || floor(v) > height - 1) { + return; + } + + i = (int)floor(u); + j = (int)floor(v); + a = u - i; + b = v - j; + + zero_v4(out); + +/* Optimized and not so easy to read */ + + /* avoid calling multiple times */ + wy[0] = P(b - (-1)); + wy[1] = P(b - 0); + wy[2] = P(b - 1); + wy[3] = P(b - 2); + + for (n = -1; n <= 2; n++) { + x1 = i + n; + CLAMP(x1, 0, width - 1); + wx = P(n - a); + for (m = -1; m <= 2; m++) { + float data[4]; + + y1 = j + m; + CLAMP(y1, 0, height - 1); + /* normally we could do this */ + /* w = P(n-a) * P(b-m); */ + /* except that would call P() 16 times per pixel therefor pow() 64 times, better precalc these */ + w = wx * wy[m + 1]; + + if (float_output) { + const float *float_data = float_buffer + width * y1 * 4 + 4 * x1; + + vector_from_float(float_data, data, components); + } + else { + const unsigned char *byte_data = byte_buffer + width * y1 * 4 + 4 * x1; + + vector_from_byte(byte_data, data, components); + } + + if (components == 1) { + out[0] += data[0] * w; + } + else if (components == 3) { + out[0] += data[0] * w; + out[1] += data[1] * w; + out[2] += data[2] * w; + } + else { + out[0] += data[0] * w; + out[1] += data[1] * w; + out[2] += data[2] * w; + out[3] += data[3] * w; + } + } + } + +/* Done with optimized part */ + +#if 0 + /* older, slower function, works the same as above */ + for (n = -1; n <= 2; n++) { + for (m = -1; m <= 2; m++) { + x1 = i + n; + y1 = j + m; + if (x1 > 0 && x1 < width && y1 > 0 && y1 < height) { + float data[4]; + + if (float_output) { + const float *float_data = float_buffer + width * y1 * 4 + 4 * x1; + + vector_from_float(float_data, data, components); + } + else { + const unsigned char *byte_data = byte_buffer + width * y1 * 4 + 4 * x1; + + vector_from_byte(byte_data, data, components); + } + + if (components == 1) { + out[0] += data[0] * P(n - a) * P(b - m); + } + else if (components == 3) { + out[0] += data[0] * P(n - a) * P(b - m); + out[1] += data[1] * P(n - a) * P(b - m); + out[2] += data[2] * P(n - a) * P(b - m); + } + else { + out[0] += data[0] * P(n - a) * P(b - m); + out[1] += data[1] * P(n - a) * P(b - m); + out[2] += data[2] * P(n - a) * P(b - m); + out[3] += data[3] * P(n - a) * P(b - m); + } + } + } + } +#endif + + if (float_output) { + if (components == 1) { + float_output[0] = out[0]; + } + else if (components == 3) { + copy_v3_v3(float_output, out); + } + else { + copy_v4_v4(float_output, out); + } + } + else { + if (components == 1) { + byte_output[0] = out[0]; + } + else if (components == 3) { + byte_output[0] = out[0]; + byte_output[1] = out[1]; + byte_output[2] = out[2]; + } + else { + byte_output[0] = out[0]; + byte_output[1] = out[1]; + byte_output[2] = out[2]; + byte_output[3] = out[3]; + } + } +} + +void BLI_bicubic_interpolation_fl(const float *buffer, float *output, int width, int height, + int components, float u, float v) +{ + bicubic_interpolation(NULL, buffer, NULL, output, width, height, components, u, v); +} + +void BLI_bicubic_interpolation_char(const unsigned char *buffer, unsigned char *output, int width, int height, + int components, float u, float v) +{ + bicubic_interpolation(buffer, NULL, output, NULL, width, height, components, u, v); +} + +/* BILINEAR INTERPOLATION */ +BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const float *float_buffer, + unsigned char *byte_output, float *float_output, int width, int height, + int components, float u, float v) +{ + float a, b; + float a_b, ma_b, a_mb, ma_mb; + int y1, y2, x1, x2; + + /* ImBuf in must have a valid rect or rect_float, assume this is already checked */ + + x1 = (int)floor(u); + x2 = (int)ceil(u); + y1 = (int)floor(v); + y2 = (int)ceil(v); + + /* sample area entirely outside image? */ + if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) { + return; + } + + if (float_output) { + const float *row1, *row2, *row3, *row4; + float empty[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + /* sample including outside of edges of image */ + if (x1 < 0 || y1 < 0) row1 = empty; + else row1 = float_buffer + width * y1 * 4 + 4 * x1; + + if (x1 < 0 || y2 > height - 1) row2 = empty; + else row2 = float_buffer + width * y2 * 4 + 4 * x1; + + if (x2 > width - 1 || y1 < 0) row3 = empty; + else row3 = float_buffer + width * y1 * 4 + 4 * x2; + + if (x2 > width - 1 || y2 > height - 1) row4 = empty; + else row4 = float_buffer + width * y2 * 4 + 4 * x2; + + a = u - floorf(u); + b = v - floorf(v); + a_b = a * b; ma_b = (1.0f - a) * b; a_mb = a * (1.0f - b); ma_mb = (1.0f - a) * (1.0f - b); + + if (components == 1) { + float_output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0]; + } + else if (components == 3) { + float_output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0]; + float_output[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1]; + float_output[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2]; + } + else { + float_output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0]; + float_output[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1]; + float_output[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2]; + float_output[3] = ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3]; + } + } + else { + const unsigned char *row1, *row2, *row3, *row4; + unsigned char empty[4] = {0, 0, 0, 0}; + + /* sample including outside of edges of image */ + if (x1 < 0 || y1 < 0) row1 = empty; + else row1 = byte_buffer + width * y1 * 4 + 4 * x1; + + if (x1 < 0 || y2 > height - 1) row2 = empty; + else row2 = byte_buffer + width * y2 * 4 + 4 * x1; + + if (x2 > width - 1 || y1 < 0) row3 = empty; + else row3 = byte_buffer + width * y1 * 4 + 4 * x2; + + if (x2 > width - 1 || y2 > height - 1) row4 = empty; + else row4 = byte_buffer + width * y2 * 4 + 4 * x2; + + a = u - floorf(u); + b = v - floorf(v); + a_b = a * b; ma_b = (1.0f - a) * b; a_mb = a * (1.0f - b); ma_mb = (1.0f - a) * (1.0f - b); + + if (components == 1) { + byte_output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0]; + } + else if (components == 3) { + byte_output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0]; + byte_output[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1]; + byte_output[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2]; + } + else { + byte_output[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0]; + byte_output[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1]; + byte_output[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2]; + byte_output[3] = ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3]; + } + } +} + +void BLI_bilinear_interpolation_fl(const float *buffer, float *output, int width, int height, + int components, float u, float v) +{ + bilinear_interpolation(NULL, buffer, NULL, output, width, height, components, u, v); +} + +void BLI_bilinear_interpolation_char(const unsigned char *buffer, unsigned char *output, int width, int height, + int components, float u, float v) +{ + bilinear_interpolation(buffer, NULL, output, NULL, width, height, components, u, v); +} diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c index 7637c60ec16..e21ce0716d2 100644 --- a/source/blender/blenlib/intern/pbvh.c +++ b/source/blender/blenlib/intern/pbvh.c @@ -1707,11 +1707,19 @@ void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], } } -void BLI_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces) +void BLI_pbvh_grids_update(PBVH *bvh, CCGElem **grids, DMGridAdjacency *gridadj, void **gridfaces, + DMFlagMat *flagmats, BLI_bitmap *grid_hidden) { + int a; + bvh->grids = grids; bvh->gridadj = gridadj; bvh->gridfaces = gridfaces; + bvh->grid_flag_mats = flagmats; + bvh->grid_hidden = grid_hidden; + + for (a = 0; a < bvh->totnode; ++a) + BLI_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]); } float (*BLI_pbvh_get_vertCos(PBVH * pbvh))[3] diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c index 0b737e0eff5..e80f96ee0fe 100644 --- a/source/blender/blenlib/intern/string_utf8.c +++ b/source/blender/blenlib/intern/string_utf8.c @@ -317,12 +317,12 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *dst_w, const char *src_c, const size /* end wchar_t / utf8 functions */ /* --------------------------------------------------------------------------*/ -/* copied from glib's gutf8.c */ +/* copied from glib's gutf8.c, added 'Err' arg */ /* note, glib uses unsigned int for unicode, best we do the same, * though we don't typedef it - campbell */ -#define UTF8_COMPUTE(Char, Mask, Len) \ +#define UTF8_COMPUTE(Char, Mask, Len, Err) \ if (Char < 128) { \ Len = 1; \ Mask = 0x7f; \ @@ -348,7 +348,7 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *dst_w, const char *src_c, const size Mask = 0x01; \ } \ else { \ - Len = -1; \ + Len = Err; /* -1 is the typical error value or 1 to skip */ \ } (void)0 /* same as glib define but added an 'Err' arg */ @@ -371,7 +371,20 @@ int BLI_str_utf8_size(const char *p) int mask = 0, len; unsigned char c = (unsigned char) *p; - UTF8_COMPUTE (c, mask, len); + UTF8_COMPUTE (c, mask, len, -1); + + (void)mask; /* quiet warning */ + + return len; +} + +/* use when we want to skip errors */ +int BLI_str_utf8_size_safe(const char *p) +{ + int mask = 0, len; + unsigned char c = (unsigned char) *p; + + UTF8_COMPUTE (c, mask, len, 1); (void)mask; /* quiet warning */ @@ -397,7 +410,7 @@ unsigned int BLI_str_utf8_as_unicode(const char *p) unsigned int result; unsigned char c = (unsigned char) *p; - UTF8_COMPUTE (c, mask, len); + UTF8_COMPUTE (c, mask, len, -1); if (len == -1) return BLI_UTF8_ERR; UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR); @@ -412,7 +425,7 @@ unsigned int BLI_str_utf8_as_unicode_and_size(const char *p, size_t *index) unsigned int result; unsigned char c = (unsigned char) *p; - UTF8_COMPUTE (c, mask, len); + UTF8_COMPUTE (c, mask, len, -1); if (len == -1) return BLI_UTF8_ERR; UTF8_GET (result, p, i, mask, len, BLI_UTF8_ERR); @@ -431,7 +444,7 @@ unsigned int BLI_str_utf8_as_unicode_step(const char *p, size_t *index) p += *index; c = (unsigned char) *p; - UTF8_COMPUTE (c, mask, len); + UTF8_COMPUTE (c, mask, len, -1); if (len == -1) { /* when called with NULL end, result will never be NULL, * checks for a NULL character */ diff --git a/source/blender/blenlib/intern/voronoi.c b/source/blender/blenlib/intern/voronoi.c index 0d411038b3e..601b07c9a5d 100644 --- a/source/blender/blenlib/intern/voronoi.c +++ b/source/blender/blenlib/intern/voronoi.c @@ -609,9 +609,9 @@ static int voronoi_getNextSideCoord(ListBase *edges, float coord[2], int dim, in static void voronoi_createBoundaryEdges(ListBase *edges, int width, int height) { const float corners[4][2] = {{width - 1, 0.0f}, - {width - 1, height - 1}, - {0.0f, height - 1}, - {0.0f, 0.0f}}; + {width - 1, height - 1}, + {0.0f, height - 1}, + {0.0f, 0.0f}}; int i, dim = 0, dir = 1; float coord[2] = {0.0f, 0.0f}; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index bef97a4ab6a..1a16615616d 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -361,36 +361,39 @@ static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr) } /* for libdata, nr has ID code, no increment */ -static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib) +static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib) { - int i; - - if (addr == NULL) return NULL; - + if (addr == NULL) { + return NULL; + } + /* lasthit works fine for non-libdata, linking there is done in same sequence as writing */ if (onm->sorted) { OldNew entry_s, *entry; - + entry_s.old = addr; - + entry = bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap); if (entry) { ID *id = entry->newp; - + if (id && (!lib || id->lib)) { - return entry->newp; + return id; } } } - - for (i = 0; i < onm->nentries; i++) { - OldNew *entry = &onm->entries[i]; - - if (entry->old == addr) { - ID *id = entry->newp; - - if (id && (!lib || id->lib)) { - return entry->newp; + else { + /* note, this can be a bottle neck when loading some files */ + unsigned int nentries = (unsigned int)onm->nentries; + unsigned int i; + OldNew *entry; + + for (i = 0, entry = onm->entries; i < nentries; i++, entry++) { + if (entry->old == addr) { + ID *id = id = entry->newp; + if (id && (!lib || id->lib)) { + return id; + } } } } diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 645e4e348e8..64fa1ea399d 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -397,11 +397,11 @@ BMFace *BM_face_create_ngon_vcloud(BMesh *bm, BMVert **vert_arr, int totv, int n /* more of a weight then a distance */ far_cross_dist = (/* first we want to have a value close to zero mapped to 1 */ - 1.0f - fabsf(dot_v3v3(far_vec, far_cross_vec)) * + 1.0f - fabsf(dot_v3v3(far_vec, far_cross_vec)) * - /* second we multiply by the distance - * so points close to the center are not preferred */ - far_cross_dist); + /* second we multiply by the distance + * so points close to the center are not preferred */ + far_cross_dist); if (far_cross_dist > far_cross_best || far_cross == NULL) { far_cross = vert_arr[i]->co; diff --git a/source/blender/bmesh/intern/bmesh_decimate_collapse.c b/source/blender/bmesh/intern/bmesh_decimate_collapse.c index 1f92a8f9227..74792d1d558 100644 --- a/source/blender/bmesh/intern/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/intern/bmesh_decimate_collapse.c @@ -52,6 +52,7 @@ #define BOUNDARY_PRESERVE_WEIGHT 100.0f #define OPTIMIZE_EPS 0.01f /* FLT_EPSILON is too small, see [#33106] */ +#define COST_INVALID FLT_MAX typedef enum CD_UseFlag { CD_DO_VERT = (1 << 0), @@ -132,6 +133,56 @@ static void bm_decim_calc_target_co(BMEdge *e, float optimize_co[3], } } +static int bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_co[3]) +{ + BMIter liter; + BMLoop *l; + unsigned int i; + + for (i = 0; i < 2; i++) { + /* loop over both verts */ + BMVert *v = *((&e->v1) + i); + + BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { + if (l->e != e && l->prev->e != e) { + float *co_prev = l->prev->v->co; + float *co_next = l->next->v->co; + float cross_exist[3]; + float cross_optim[3]; + +#if 1 + float vec_other[3]; /* line between the two outer verts, re-use for both cross products */ + float vec_exist[3]; /* before collapse */ + float vec_optim[3]; /* after collapse */ + + sub_v3_v3v3(vec_other, co_prev, co_next); + sub_v3_v3v3(vec_exist, co_prev, v->co); + sub_v3_v3v3(vec_optim, co_prev, optimize_co); + + cross_v3_v3v3(cross_exist, vec_other, vec_exist); + cross_v3_v3v3(cross_optim, vec_other, vec_optim); + + /* normalize isn't really needed, but ensures the value at a unit we can compare against */ + normalize_v3(cross_exist); + normalize_v3(cross_optim); +#else + normal_tri_v3(cross_exist, v->co, co_prev, co_next); + normal_tri_v3(cross_optim, optimize_co, co_prev, co_next); +#endif + + /* use a small value rather then zero so we don't flip a face in multiple steps + * (first making it zero area, then flipping again)*/ + if (dot_v3v3(cross_exist, cross_optim) <= FLT_EPSILON) { + //printf("no flip\n"); + return TRUE; + } + } + } + } + + return FALSE; +} + static void bm_decim_build_edge_cost_single(BMEdge *e, const Quadric *vquadrics, const float *vweights, Heap *eheap, HeapNode **eheap_table) @@ -200,6 +251,16 @@ static void bm_decim_build_edge_cost_single(BMEdge *e, eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, cost, e); } + +/* use this for degenerate cases - add back to the heap with an invalid cost, + * this way it may be calculated again if surrounding geometry changes */ +static void bm_decim_invalid_edge_cost_single(BMEdge *e, + Heap *eheap, HeapNode **eheap_table) +{ + BLI_assert(eheap_table[BM_elem_index_get(e)] == NULL); + eheap_table[BM_elem_index_get(e)] = BLI_heap_insert(eheap, COST_INVALID, e); +} + static void bm_decim_build_edge_cost(BMesh *bm, const Quadric *vquadrics, const float *vweights, Heap *eheap, HeapNode **eheap_table) @@ -525,7 +586,7 @@ BLI_INLINE int bm_edge_is_manifold_or_boundary(BMLoop *l) #endif } -static int bm_edge_collapse_is_degenerate(BMEdge *e_first) +static int bm_edge_collapse_is_degenerate_topology(BMEdge *e_first) { /* simply check that there is no overlap between faces and edges of each vert, * (excluding the 2 faces attached to 'e' and 'e' its self) */ @@ -629,11 +690,6 @@ static int bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e { BMVert *v_other; - /* disallow collapsing which results in degenerate cases */ - if (bm_edge_collapse_is_degenerate(e_clear)) { - return FALSE; - } - v_other = BM_edge_other_vert(e_clear, v_clear); BLI_assert(v_other != NULL); @@ -704,8 +760,11 @@ static int bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e BM_edge_kill(bm, e_clear); + v_other->head.hflag |= v_clear->head.hflag; BM_vert_splice(bm, v_clear, v_other); + e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag; + e_b_other[1]->head.hflag |= e_b_other[0]->head.hflag; BM_edge_splice(bm, e_a_other[0], e_a_other[1]); BM_edge_splice(bm, e_b_other[0], e_b_other[1]); @@ -750,8 +809,10 @@ static int bm_edge_collapse(BMesh *bm, BMEdge *e_clear, BMVert *v_clear, int r_e BM_edge_kill(bm, e_clear); + v_other->head.hflag |= v_clear->head.hflag; BM_vert_splice(bm, v_clear, v_other); + e_a_other[1]->head.hflag |= e_a_other[0]->head.hflag; BM_edge_splice(bm, e_a_other[0], e_a_other[1]); // BM_mesh_validate(bm); @@ -781,12 +842,23 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e, copy_v3_v3(v_clear_no, e->v2->no); #endif + /* disallow collapsing which results in degenerate cases */ + if (UNLIKELY(bm_edge_collapse_is_degenerate_topology(e))) { + bm_decim_invalid_edge_cost_single(e, eheap, eheap_table); /* add back with a high cost */ + return; + } + bm_decim_calc_target_co(e, optimize_co, vquadrics); + /* check if this would result in an overlapping face */ + if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) { + bm_decim_invalid_edge_cost_single(e, eheap, eheap_table); /* add back with a high cost */ + return; + } + /* use for customdata merging */ if (LIKELY(compare_v3v3(e->v1->co, e->v2->co, FLT_EPSILON) == FALSE)) { customdata_fac = line_point_factor_v3(optimize_co, e->v1->co, e->v2->co); - #if 0 /* simple test for stupid collapse */ if (customdata_fac < 0.0 - FLT_EPSILON || customdata_fac > 1.0f + FLT_EPSILON) { @@ -848,7 +920,10 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e, } while ((e_iter = bmesh_disk_edge_next(e_iter, v_other)) != e_first); } -#if 0 + /* this block used to be disabled, + * but enable now since surrounding faces may have been + * set to COST_INVALID because of a face overlap that no longer occurs */ +#if 1 /* optional, update edges around the vertex face fan */ { BMIter liter; @@ -863,13 +938,17 @@ static void bm_decim_edge_collapse(BMesh *bm, BMEdge *e, BLI_assert(BM_vert_in_edge(e_outer, l->v) == FALSE); - bm_decim_build_edge_cost_single(e_outer, vquadrics, eheap, eheap_table); + bm_decim_build_edge_cost_single(e_outer, vquadrics, vweights, eheap, eheap_table); } } } /* end optional update */ #endif } + else { + /* add back with a high cost */ + bm_decim_invalid_edge_cost_single(e, eheap, eheap_table); + } } @@ -925,7 +1004,10 @@ void BM_mesh_decimate_collapse(BMesh *bm, const float factor, float *vweights, c #endif /* iterative edge collapse and maintain the eheap */ - while ((bm->totface > face_tot_target) && (BLI_heap_is_empty(eheap) == FALSE)) { + while ((bm->totface > face_tot_target) && + (BLI_heap_is_empty(eheap) == FALSE) && + (BLI_heap_node_value(BLI_heap_top(eheap)) != COST_INVALID)) + { // const float value = BLI_heap_node_value(BLI_heap_top(eheap)); BMEdge *e = BLI_heap_popmin(eheap); BLI_assert(BM_elem_index_get(e) < tot_edge_orig); /* handy to detect corruptions elsewhere */ diff --git a/source/blender/bmesh/intern/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/intern/bmesh_decimate_unsubdivide.c index 68c0652d2c4..1ec13010d80 100644 --- a/source/blender/bmesh/intern/bmesh_decimate_unsubdivide.c +++ b/source/blender/bmesh/intern/bmesh_decimate_unsubdivide.c @@ -247,9 +247,9 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const int #ifdef USE_WALKER /* Walk over selected elements starting at active */ BMW_init(&walker, bm, BMW_CONNECTED_VERTEX, - ELE_VERT_TAG, BMW_MASK_NOP, BMW_MASK_NOP, - BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */ - BMW_NIL_LAY); + ELE_VERT_TAG, BMW_MASK_NOP, BMW_MASK_NOP, + BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */ + BMW_NIL_LAY); BLI_assert(walker.order == BMW_BREADTH_FIRST); for (v = BMW_begin(&walker, v_first); v != NULL; v = BMW_step(&walker)) { diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 62374d8b7bb..dc8b52423ab 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -118,7 +118,7 @@ int BM_disk_dissolve(BMesh *bm, BMVert *v) e = v->e; do { e = bmesh_disk_edge_next(e, v); - if (!(BM_edge_share_face_count(e, v->e))) { + if (!(BM_edge_share_face_check(e, v->e))) { keepedge = e; baseedge = v->e; break; diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index 31698f0abc1..398e6bbedcf 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1064,6 +1064,7 @@ static BMOpDefine bmo_create_cube_def = { 0, }; +#define NEW_BEVEL 1 /* * Bevel * @@ -1071,6 +1072,12 @@ static BMOpDefine bmo_create_cube_def = { */ static BMOpDefine bmo_bevel_def = { "bevel", +#ifdef NEW_BEVEL + {{BMO_OP_SLOT_ELEMENT_BUF, "geom"}, /* input edges and vertices */ + {BMO_OP_SLOT_FLT, "offset"}, /* amount to offset beveled edge */ + {BMO_OP_SLOT_INT, "segments"}, /* number of segments in bevel */ + {0} /* null-terminating sentinel */}, +#else {{BMO_OP_SLOT_ELEMENT_BUF, "geom"}, /* input edges and vertices */ {BMO_OP_SLOT_ELEMENT_BUF, "face_spans"}, /* new geometry */ {BMO_OP_SLOT_ELEMENT_BUF, "face_holes"}, /* new geometry */ @@ -1081,6 +1088,7 @@ static BMOpDefine bmo_bevel_def = { {BMO_OP_SLOT_INT, "lengthlayer"}, /* which PROP_FLT layer to us */ {BMO_OP_SLOT_FLT, "percent"}, /* percentage to expand beveled edge */ {0} /* null-terminating sentinel */}, +#endif bmo_bevel_exec, BMO_OP_FLAG_UNTAN_MULTIRES }; diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index 4cc946a3a40..9d1054dc042 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -354,7 +354,7 @@ void BMO_slot_mat_set(BMOperator *op, const char *slot_name, const float *mat, i else { fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size); - memset(slot->data.p, 0, sizeof(float) * 4 * 4); + zero_m4(slot->data.p); } } @@ -365,7 +365,12 @@ void BMO_slot_mat4_get(BMOperator *op, const char *slot_name, float r_mat[4][4]) if (!(slot->slot_type == BMO_OP_SLOT_MAT)) return; - copy_m4_m4(r_mat, (float (*)[4])slot->data.p); + if (slot->data.p) { + copy_m4_m4(r_mat, (float (*)[4])slot->data.p); + } + else { + unit_m4(r_mat); + } } void BMO_slot_mat3_set(BMOperator *op, const char *slot_name, float r_mat[3][3]) @@ -375,7 +380,12 @@ void BMO_slot_mat3_set(BMOperator *op, const char *slot_name, float r_mat[3][3]) if (!(slot->slot_type == BMO_OP_SLOT_MAT)) return; - copy_m3_m4(r_mat, slot->data.p); + if (slot->data.p) { + copy_m3_m4(r_mat, slot->data.p); + } + else { + unit_m3(r_mat); + } } void BMO_slot_ptr_set(BMOperator *op, const char *slot_name, void *p) diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 4b07dd74eef..1e1d7d1becb 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -401,6 +401,7 @@ BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step) } else { BLI_assert(0); + return NULL; } if (BM_edge_is_manifold(e_next)) { @@ -724,6 +725,47 @@ int BM_edge_is_boundary(BMEdge *e) #endif /** + * Returns the number of faces that are adjacent to both f1 and f2, + * \note Could be sped up a bit by not using iterators and by tagging + * faces on either side, then count the tags rather then searching. + */ +int BM_face_share_face_count(BMFace *f1, BMFace *f2) +{ + BMIter iter1, iter2; + BMEdge *e; + BMFace *f; + int count = 0; + + BM_ITER_ELEM (e, &iter1, f1, BM_EDGES_OF_FACE) { + BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) { + if (f != f1 && f != f2 && BM_face_share_edge_check(f, f2)) + count++; + } + } + + return count; +} + +/** + * same as #BM_face_share_face_count but returns a bool + */ +int BM_face_share_face_check(BMFace *f1, BMFace *f2) +{ + BMIter iter1, iter2; + BMEdge *e; + BMFace *f; + + BM_ITER_ELEM (e, &iter1, f1, BM_EDGES_OF_FACE) { + BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) { + if (f != f1 && f != f2 && BM_face_share_edge_check(f, f2)) + return TRUE; + } + } + + return FALSE; +} + +/** * Counts the number of edges two faces share (if any) */ int BM_face_share_edge_count(BMFace *f1, BMFace *f2) @@ -743,9 +785,27 @@ int BM_face_share_edge_count(BMFace *f1, BMFace *f2) } /** + * Returns TRUE if the faces share an edge + */ +int BM_face_share_edge_check(BMFace *f1, BMFace *f2) +{ + BMLoop *l_iter; + BMLoop *l_first; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f1); + do { + if (bmesh_radial_face_find(l_iter->e, f2)) { + return TRUE; + } + } while ((l_iter = l_iter->next) != l_first); + + return FALSE; +} + +/** * Test if e1 shares any faces with e2 */ -int BM_edge_share_face_count(BMEdge *e1, BMEdge *e2) +int BM_edge_share_face_check(BMEdge *e1, BMEdge *e2) { BMLoop *l; BMFace *f; @@ -766,7 +826,7 @@ int BM_edge_share_face_count(BMEdge *e1, BMEdge *e2) /** * Tests to see if e1 shares a vertex with e2 */ -int BM_edge_share_vert_count(BMEdge *e1, BMEdge *e2) +int BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2) { return (e1->v1 == e2->v1 || e1->v1 == e2->v2 || @@ -1023,7 +1083,12 @@ float BM_vert_calc_shell_factor(BMVert *v) accum_angle += face_angle; } - return accum_shell / accum_angle; + if (accum_angle != 0.0f) { + return accum_shell / accum_angle; + } + else { + return 1.0f; + } } /** @@ -1044,7 +1109,12 @@ float BM_vert_calc_mean_tagged_edge_length(BMVert *v) } } - return length / (float)tot; + if (tot) { + return length / (float)tot; + } + else { + return 0.0f; + } } diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 34d0747676c..579a1397b0c 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -84,9 +84,13 @@ int BM_face_exists(BMesh *bm, BMVert **varr, int len, BMFace **r_existface); int BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len); int BM_face_exists_multi_edge(BMEdge **earr, int len); +int BM_face_share_face_count(BMFace *f1, BMFace *f2); int BM_face_share_edge_count(BMFace *f1, BMFace *f2); -int BM_edge_share_face_count(BMEdge *e1, BMEdge *e2); -int BM_edge_share_vert_count(BMEdge *e1, BMEdge *e2); + +int BM_face_share_face_check(BMFace *f1, BMFace *f2); +int BM_face_share_edge_check(BMFace *f1, BMFace *f2); +int BM_edge_share_face_check(BMEdge *e1, BMEdge *e2); +int BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2); BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2); BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v); diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c index c5120571755..7df5aa8fe9c 100644 --- a/source/blender/bmesh/operators/bmo_bevel.c +++ b/source/blender/bmesh/operators/bmo_bevel.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): Joseph Eagar. + * Contributor(s): Joseph Eagar, Aleksandr Mokhov, Howard Trickey * * ***** END GPL LICENSE BLOCK ***** */ @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_listbase.h" #include "BLI_array.h" #include "BLI_math.h" #include "BLI_smallhash.h" @@ -36,14 +37,1358 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define BEVEL_FLAG 1 -#define BEVEL_DEL 2 -#define FACE_NEW 4 -#define EDGE_OLD 8 -#define FACE_OLD 16 -#define VERT_OLD 32 -#define FACE_SPAN 64 -#define FACE_HOLE 128 +#define NEW_BEVEL 1 + +#ifdef NEW_BEVEL +#define BEVEL_FLAG 1 +#define EDGE_SELECTED 2 + +#define BEVEL_EPSILON 1e-6 + +/* Constructed vertex, sometimes later instantiated as BMVert */ +typedef struct NewVert { + float co[3]; + BMVert *v; +} NewVert; + +struct BoundVert; + +/* Data for one end of an edge involved in a bevel */ +typedef struct EdgeHalf { + struct EdgeHalf *next, *prev; /* in CCW order */ + BMEdge *e; /* original mesh edge */ + int isbev; /* is this edge beveled? */ + int isrev; /* is e->v2 the vertex at this end? */ + int seg; /* how many segments for the bevel */ + float offset; /* offset for this edge */ + BMFace *fprev; /* face between this edge and previous, if any */ + BMFace *fnext; /* face between this edge and next, if any */ + struct BoundVert *leftv; /* left boundary vert (looking along edge to end) */ + struct BoundVert *rightv; /* right boundary vert, if beveled */ +} EdgeHalf; + +/* An element in a cyclic boundary of a Vertex Mesh (VMesh) */ +typedef struct BoundVert { + struct BoundVert *next, *prev; /* in CCW order */ + int index; /* used for vmesh indexing */ + NewVert nv; + EdgeHalf *efirst; /* first of edges attached here: in CCW order */ + EdgeHalf *elast; + EdgeHalf *ebev; /* beveled edge whose left side is attached here, if any */ +} BoundVert; + +/* Mesh structure replacing a vertex */ +typedef struct VMesh { + enum { + M_NONE, /* no polygon mesh needed */ + M_POLY, /* a simple polygon */ + M_ADJ, /* "adjacent edges" mesh pattern */ + M_CROSS, /* "cross edges" mesh pattern */ + } mesh_kind; + int count; /* number of vertices in the boundary */ + int seg; /* common # of segments for segmented edges */ + BoundVert *boundstart; /* start of boundary double-linked list */ + NewVert *mesh; /* allocated array - size and structure depends on kind */ +} VMesh; + +/* Data for a vertex involved in a bevel */ +typedef struct BevVert { + struct BevVert *next, *prev; + BMVert *v; /* original mesh vertex */ + int edgecount; /* total number of edges around the vertex */ + int selcount; /* number of selected edges around the vertex */ + EdgeHalf *edges; /* array of size edgecount; CCW order from vertex normal side */ + VMesh *vmesh; /* mesh structure for replacing vertex */ +} BevVert; + +/* + * Bevel parameters and state + */ +typedef struct BevelParams { + ListBase vertList; /* list of BevVert for each vertex involved in bevel */ + float offset; /* blender units to offset each side of a beveled edge */ + int seg; /* number of segments in beveled edge profile */ + + BMOperator *op; +} BevelParams; + +/* Make a new BoundVert of the given kind, insert it at the end of the circular linked + * list with entry point bv->boundstart, and return it. */ +static BoundVert *add_new_bound_vert(VMesh *vm, float co[3]) +{ + BoundVert *ans = (BoundVert *) MEM_callocN(sizeof(BoundVert), "BoundVert"); + copy_v3_v3(ans->nv.co, co); + if (!vm->boundstart) { + ans->index = 0; + vm->boundstart = ans; + ans->next = ans->prev = ans; + } + else { + BoundVert *tail = vm->boundstart->prev; + ans->index = tail->index + 1; + ans->prev = tail; + ans->next = vm->boundstart; + tail->next = ans; + vm->boundstart->prev = ans; + } + vm->count++; + return ans; +} + +/* Mesh verts are indexed (i, j, k) where + * i = boundvert index (0 <= i < nv) + * j = ring index (0 <= j <= ns2) + * k = segment index (0 <= k <= ns) + * Not all of these are used, and some will share BMVerts */ +static NewVert *mesh_vert(VMesh *vm, int i, int j, int k) +{ + int nj = (vm->seg / 2) + 1; + int nk = vm->seg + 1; + + return &vm->mesh[i * nk * nj + j * nk + k]; +} + +static void create_mesh_bmvert(BMesh *bm, VMesh *vm, int i, int j, int k, BMVert *eg) +{ + NewVert *nv = mesh_vert(vm, i, j, k); + nv->v = BM_vert_create(bm, nv->co, eg); +} + +static void copy_mesh_vert(VMesh *vm, int ito, int jto, int kto, + int ifrom, int jfrom, int kfrom) +{ + NewVert *nvto, *nvfrom; + + nvto = mesh_vert(vm, ito, jto, kto); + nvfrom = mesh_vert(vm, ifrom, jfrom, kfrom); + nvto->v = nvfrom->v; + copy_v3_v3(nvto->co, nvfrom->co); +} + +/* find the EdgeHalf in bv's array that has edge bme */ +static EdgeHalf *find_edge_half(BevVert *bv, BMEdge *bme) +{ + int i; + + for (i = 0; i < bv->edgecount; i++) { + if (bv->edges[i].e == bme) + return &bv->edges[i]; + } + return NULL; +} + +/* Return the next EdgeHalf after from_e that is beveled. + * If from_e is NULL, find the first beveled edge. */ +static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e) +{ + EdgeHalf *e; + + if (from_e == NULL) + from_e = &bv->edges[bv->edgecount - 1]; + e = from_e; + do { + if (e->isbev) + return e; + e = e->next; + } while (e != from_e); + return NULL; +} + +/* find the BevVert corresponding to BMVert bmv */ +static BevVert *find_bevvert(BevelParams *bp, BMVert *bmv) +{ + BevVert *bv; + + for (bv = bp->vertList.first; bv; bv = bv->next) { + if (bv->v == bmv) + return bv; + } + return NULL; +} + +/* Return a good respresentative face (for materials, etc.) for faces + * created around/near BoundVert v */ +static BMFace *boundvert_rep_face(BoundVert *v) +{ + BMFace *fans = NULL; + BMFace *firstf = NULL; + BMEdge *e1, *e2; + BMFace *f1, *f2; + BMIter iter1, iter2; + + BLI_assert(v->efirst != NULL && v->elast != NULL); + e1 = v->efirst->e; + e2 = v->elast->e; + BM_ITER_ELEM (f1, &iter1, e1, BM_FACES_OF_EDGE) { + if (!firstf) + firstf = f1; + BM_ITER_ELEM (f2, &iter2, e2, BM_FACES_OF_EDGE) { + if (f1 == f2) { + fans = f1; + break; + } + } + } + if (!fans) + fans = firstf; + + return fans; +} + +/* Make ngon from verts alone. + * Make sure to properly copy face attributes and do custom data interpolation from + * example face, facerep. */ +static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, int totv, BMFace *facerep) +{ + BMIter iter; + BMLoop *l; + BMFace *f; + + if (totv == 3) { + f = BM_face_create_quad_tri(bm, + vert_arr[0], vert_arr[1], vert_arr[2], NULL, facerep, 0); + } + else if (totv == 4) { + f = BM_face_create_quad_tri(bm, + vert_arr[0], vert_arr[1], vert_arr[2], vert_arr[3], facerep, 0); + } + else { + int i; + BMEdge *e; + BMEdge **ee = NULL; + BLI_array_staticdeclare(ee, 30); + + for (i = 0; i < totv; i++) { + e = BM_edge_create(bm, vert_arr[i], vert_arr[(i + 1) % totv], NULL, TRUE); + BLI_array_append(ee, e); + } + f = BM_face_create_ngon(bm, vert_arr[0], vert_arr[1], ee, totv, FALSE); + BLI_array_free(ee); + } + if (facerep && f) { + int has_mdisps = CustomData_has_layer(&bm->ldata, CD_MDISPS); + BM_elem_attrs_copy(bm, bm, facerep, f); + BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { + BM_loop_interp_from_face(bm, l, facerep, TRUE, TRUE); + if (has_mdisps) + BM_loop_interp_multires(bm, l, facerep); + } + } + return f; +} + +static BMFace *bev_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, + BMFace *facerep) +{ + BMVert *varr[4]; + + varr[0] = v1; + varr[1] = v2; + varr[2] = v3; + varr[3] = v4; + return bev_create_ngon(bm, varr, v4 ? 4 : 3, facerep); +} + +/* + * Calculate the meeting point between the offset edges for e1 and e2, putting answer in meetco. + * e1 and e2 share vertex v and face f (may be NULL) and viewed from the normal side of + * the bevel vertex, e1 precedes e2 in CCW order. + * If on_right is true, offset edge is on right of both edges, where e1 enters v and + * e2 leave it. If on_right is false, then the offset edge is on the left. + * When offsets are equal, the new point is on the edge bisector, with length offset/sin(angle/2), + * but if the offsets are not equal (allowing for this, as bevel modifier has edge weights that may + * lead to different offsets) then meeting point can be found be intersecting offset lines. + */ +static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, + int on_right, float meetco[3]) +{ + float dir1[3], dir2[3], norm_v[3], norm_perp1[3], norm_perp2[3], + off1a[3], off1b[3], off2a[3], off2b[3], isect2[3]; + + /* get direction vectors for two offset lines */ + sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co); + sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co); + + /* get normal to plane where meet point should be */ + cross_v3_v3v3(norm_v, dir2, dir1); + normalize_v3(norm_v); + if (!on_right) + negate_v3(norm_v); + if (is_zero_v3(norm_v)) { + /* special case: e1 and e2 are parallel; put offset point perp to both, from v. + * need to find a suitable plane. + * if offsets are different, we're out of luck: just use e1->offset */ + if (f) + copy_v3_v3(norm_v, f->no); + else + copy_v3_v3(norm_v, v->no); + cross_v3_v3v3(norm_perp1, dir1, norm_v); + normalize_v3(norm_perp1); + copy_v3_v3(off1a, v->co); + madd_v3_v3fl(off1a, norm_perp1, e1->offset); + copy_v3_v3(meetco, off1a); + } + else { + /* get vectors perp to each edge, perp to norm_v, and pointing into face */ + if (f) { + copy_v3_v3(norm_v, f->no); + normalize_v3(norm_v); + } + cross_v3_v3v3(norm_perp1, dir1, norm_v); + cross_v3_v3v3(norm_perp2, dir2, norm_v); + normalize_v3(norm_perp1); + normalize_v3(norm_perp2); + + /* get points that are offset distances from each line, then another point on each line */ + copy_v3_v3(off1a, v->co); + madd_v3_v3fl(off1a, norm_perp1, e1->offset); + add_v3_v3v3(off1b, off1a, dir1); + copy_v3_v3(off2a, v->co); + madd_v3_v3fl(off2a, norm_perp2, e2->offset); + add_v3_v3v3(off2b, off2a, dir2); + + /* intersect the lines; by construction they should be on the same plane and not parallel */ + if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) { + BLI_assert(!"offset_meet failure"); + copy_v3_v3(meetco, off1a); /* just to do something */ + } + } +} + +/* Like offset_meet, but here f1 and f2 must not be NULL and give the + * planes in which to run the offset lines. They may not meet exactly, + * but the line intersection routine will find the closest approach point. */ +static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, + BMFace *f1, BMFace *f2, float meetco[3]) +{ + float dir1[3], dir2[3], norm_perp1[3], norm_perp2[3], + off1a[3], off1b[3], off2a[3], off2b[3], isect2[3]; + + BLI_assert(f1 != NULL && f2 != NULL); + + /* get direction vectors for two offset lines */ + sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co); + sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co); + + /* get directions into offset planes */ + cross_v3_v3v3(norm_perp1, dir1, f1->no); + normalize_v3(norm_perp1); + cross_v3_v3v3(norm_perp2, dir2, f2->no); + normalize_v3(norm_perp2); + + /* get points that are offset distances from each line, then another point on each line */ + copy_v3_v3(off1a, v->co); + madd_v3_v3fl(off1a, norm_perp1, e1->offset); + add_v3_v3v3(off1b, off1a, dir1); + copy_v3_v3(off2a, v->co); + madd_v3_v3fl(off2a, norm_perp2, e2->offset); + add_v3_v3v3(off2b, off2a, dir2); + + /* intersect the lines; by construction they should be on the same plane and not parallel */ + if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) { + BLI_assert(!"offset_meet failure"); + copy_v3_v3(meetco, off1a); /* just to do something */ + } +} + +/* Offset by e->offset in plane with normal plane_no, on left if left==TRUE, + * else on right. If no is NULL, choose an arbitrary plane different + * from eh's direction. */ +static void offset_in_plane(EdgeHalf *e, float plane_no[3], int left, float r[3]) +{ + float dir[3], no[3]; + BMVert *v; + + v = e->isrev ? e->e->v1 : e->e->v2; + + sub_v3_v3v3(dir, BM_edge_other_vert(e->e, v)->co, v->co); + normalize_v3(dir); + if (plane_no) { + copy_v3_v3(no, plane_no); + } + else { + zero_v3(no); + if (fabs(dir[0]) < fabs(dir[1])) + no[0] = 1.0f; + else + no[1] = 1.0f; + } + if (left) + cross_v3_v3v3(r, no, dir); + else + cross_v3_v3v3(r, dir, no); + normalize_v3(r); + mul_v3_fl(r, e->offset); +} + +/* Calculate coordinates of a point a distance d from v on e->e and return it in slideco */ +static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3]) +{ + float dir[3], len; + + sub_v3_v3v3(dir, v->co, BM_edge_other_vert(e->e, v)->co); + len = len_v3(dir); + normalize_v3(dir); + if (d > len) + d = len - (float)(50 * BEVEL_EPSILON); + copy_v3_v3(slideco, v->co); + madd_v3_v3fl(slideco, dir, -d); +} + +/* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco */ +static void project_to_edge(BMEdge *e, float co_a[3], float co_b[3], float projco[3]) +{ + float otherco[3]; + + if (!isect_line_line_v3(e->v1->co, e->v2->co, co_a, co_b, + projco, otherco)) { + BLI_assert(!"project meet failure"); + copy_v3_v3(projco, e->v1->co); + } +} + + +/* return 1 if a and b are in CCW order on the normal side of f, + * and -1 if they are reversed, and 0 if there is no shared face f */ +static int bev_ccw_test(BMEdge *a, BMEdge *b, BMFace *f) +{ + BMLoop *la, *lb; + + if (!f) + return 0; + la = BM_face_edge_share_loop(f, a); + lb = BM_face_edge_share_loop(f, b); + if (!la || !lb) + return 0; + return lb->next == la ? 1 : -1; +} + +/* + * calculation of points on the round profile + * r - result, coordinate of point on round profile + * method: + * Inscribe a circle in angle va - v -vb + * such that it touches the arms at offset from v. + * Rotate the center-va segment by (i/n) of the + * angle va - center -vb, and put the endpoint + * of that segment in r. + */ +static void get_point_on_round_profile(float r[3], float offset, int i, int count, + float va[3], float v[3], float vb[3]) +{ + float vva[3], vvb[3], angle, center[3], rv[3], axis[3], co[3]; + + sub_v3_v3v3(vva, va, v); + sub_v3_v3v3(vvb, vb, v); + normalize_v3(vva); + normalize_v3(vvb); + angle = angle_v3v3(vva, vvb); + + add_v3_v3v3(center, vva, vvb); + normalize_v3(center); + mul_v3_fl(center, offset * (1.0f / cosf(0.5f * angle))); + add_v3_v3(center, v); /* coordinates of the center of the inscribed circle */ + + + sub_v3_v3v3(rv, va, center); /* radius vector */ + + + sub_v3_v3v3(co, v, center); + cross_v3_v3v3(axis, rv, co); /* calculate axis */ + + sub_v3_v3v3(vva, va, center); + sub_v3_v3v3(vvb, vb, center); + angle = angle_v3v3(vva, vvb); + + rotate_v3_v3v3fl(co, rv, axis, angle * (float)(i) / (float)(count)); + + add_v3_v3(co, center); + copy_v3_v3(r, co); +} + +/* + * Find the point (i/n) of the way around the round profile for e, + * where start point is va, midarc point is vmid, and end point is vb. + * Return the answer in profileco. + * Method: + * Adjust va and vb (along edge direction) so that they are perpendicular + * to edge at v, then use get_point_on_round_profile, then project + * back onto original va - vmid - vb plane. + * If va, vmid, and vb are all on the same plane, just interpolate between va and vb. + */ +static void get_point_on_round_edge(EdgeHalf *e, int i, + float va[3], float vmid[3], float vb[3], float profileco[3]) +{ + float vva[3], vvb[3], point[3], dir[3], vaadj[3], vbadj[3], p2[3], pn[3]; + int n = e->seg; + + sub_v3_v3v3(vva, va, vmid); + sub_v3_v3v3(vvb, vb, vmid); + if (e->isrev) + sub_v3_v3v3(dir, e->e->v1->co, e->e->v2->co); + else + sub_v3_v3v3(dir, e->e->v2->co, e->e->v1->co); + normalize_v3(dir); + if (fabsf(angle_v3v3(vva, vvb) - (float)M_PI) > (float)BEVEL_EPSILON) { + copy_v3_v3(vaadj, va); + madd_v3_v3fl(vaadj, dir, -len_v3(vva) * cosf(angle_v3v3(vva, dir))); + copy_v3_v3(vbadj, vb); + madd_v3_v3fl(vbadj, dir, -len_v3(vvb) * cosf(angle_v3v3(vvb, dir))); + + get_point_on_round_profile(point, e->offset, i, n, vaadj, vmid, vbadj); + + add_v3_v3v3(p2, profileco, dir); + cross_v3_v3v3(pn, vva, vvb); + if (!isect_line_plane_v3(profileco, point, p2, vmid, pn, 0)) { + BLI_assert(!"bevel: unexpected non-intersection"); + copy_v3_v3(profileco, point); + } + } + else { + /* planar case */ + interp_v3_v3v3(profileco, va, vb, (float) i / (float) n); + } +} + +static void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3]) +{ + v[0] = (v1[0] + v2[0] + v3[0]) / 3.0f; + v[1] = (v1[1] + v2[1] + v3[1]) / 3.0f; + v[2] = (v1[2] + v2[2] + v3[2]) / 3.0f; +} + +/* Make a circular list of BoundVerts for bv, each of which has the coordinates + * 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(BevVert *bv) +{ + EdgeHalf *efirst, *e; + BoundVert *v; + VMesh *vm; + float co[3], *no; + float lastd; + + e = efirst = next_bev(bv, NULL); + vm = bv->vmesh; + + BLI_assert(bv->edgecount >= 2); /* since bevel edges incident to 2 faces */ + + if (bv->edgecount == 2 && bv->selcount == 1) { + /* special case: beveled edge meets non-beveled one at valence 2 vert */ + no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL); + offset_in_plane(e, no, TRUE, co); + v = add_new_bound_vert(vm, co); + v->efirst = v->elast = v->ebev = e; + e->leftv = v; + no = e->fnext ? e->fnext->no : (e->fprev ? e->fprev->no : NULL); + offset_in_plane(e, no, FALSE, co); + v = add_new_bound_vert(vm, co); + v->efirst = v->elast = e; + e->rightv = v; + /* make artifical extra point along unbeveled edge, and form triangle */ + slide_dist(e->next, bv->v, e->offset, co); + v = add_new_bound_vert(vm, co); + v->efirst = v->elast = e->next; + vm->mesh_kind = M_POLY; + return; + } + + lastd = e->offset; + vm->boundstart = NULL; + do { + if (e->isbev) { + /* handle only left side of beveled edge e here: next iteration should do right side */ + if (e->prev->isbev) { + BLI_assert(e->prev != e); /* see: wire edge special case */ + offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); + v = add_new_bound_vert(vm, co); + v->efirst = e->prev; + v->elast = v->ebev = e; + e->leftv = v; + e->prev->rightv = v; + } + else { + /* e->prev is not beveled */ + if (e->prev->prev->isbev) { + BLI_assert(e->prev->prev != e); /* see: edgecount 2, selcount 1 case */ + /* find meet point between e->prev->prev and e and attach e->prev there */ + /* TODO: fix case when one or both faces in following are NULL */ + offset_in_two_planes(e->prev->prev, e, bv->v, + e->prev->prev->fnext, e->fprev, co); + v = add_new_bound_vert(vm, co); + v->efirst = e->prev->prev; + v->elast = v->ebev = e; + e->leftv = v; + e->prev->leftv = v; + e->prev->prev->rightv = v; + } + else { + /* neither e->prev nor e->prev->prev are beveled: make on-edge on e->prev */ + offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); + v = add_new_bound_vert(vm, co); + v->efirst = e->prev; + v->elast = v->ebev = e; + e->leftv = v; + e->prev->leftv = v; + } + } + lastd = len_v3v3(bv->v->co, v->nv.co); + } + else { + /* e is not beveled */ + if (e->next->isbev) { + /* next iteration will place e between beveled previous and next edges */ + e = e->next; + continue; + } + if (e->prev->isbev) { + /* on-edge meet between e->prev and e */ + offset_meet(e->prev, e, bv->v, e->fprev, TRUE, co); + v = add_new_bound_vert(vm, co); + v->efirst = e->prev; + v->elast = e; + e->leftv = v; + e->prev->rightv = v; + } + else { + /* None of e->prev, e, e->next are beveled. + * could either leave alone or add slide points to make + * one polygon around bv->v. For now, we choose latter. + * Could slide to make an even bevel plane but for now will + * just use last distance a meet point moved from bv->v. */ + slide_dist(e, bv->v, lastd, co); + v = add_new_bound_vert(vm, co); + v->efirst = v->elast = e; + e->leftv = v; + } + } + e = e->next; + } while (e != efirst); + + BLI_assert(vm->count >= 2); + if (vm->count == 2 && bv->edgecount == 3) + vm->mesh_kind = M_NONE; + else if (efirst->seg == 1 || bv->selcount < 3) + vm->mesh_kind = M_POLY; + else + vm->mesh_kind = M_ADJ; + /* TODO: if vm->count == 4 and bv->selcount == 4, use M_CROSS pattern */ +} + +/* + * Given that the boundary is built and the boundary BMVerts have been made, + * calculate the positions of the interior mesh points for the M_ADJ pattern, + * then make the BMVerts and the new faces. */ +static void bevel_build_rings(BMesh *bm, BevVert *bv) +{ + int k, ring, i, n, ns, ns2, nn; + VMesh *vm = bv->vmesh; + BoundVert *v, *vprev, *vnext; + NewVert *nv, *nvprev, *nvnext; + BMVert *bmv, *bmv1, *bmv2, *bmv3, *bmv4; + BMFace *f; + float co[3], coa[3], cob[3], midco[3]; + + n = vm->count; + ns = vm->seg; + ns2 = ns / 2; + BLI_assert(n > 2 && ns > 1); + + /* Make initial rings, going between points on neighbors */ + for (ring = 1; ring <= ns2; ring++) { + v = vm->boundstart; + do { + i = v->index; + if (v->ebev) { + /* get points coords of points a and b, on outer rings + * of prev and next edges, k away from this edge */ + vprev = v->prev; + vnext = v->next; + + if (vprev->ebev) + nvprev = mesh_vert(vm, vprev->index, 0, ns - ring); + else + nvprev = mesh_vert(vm, vprev->index, 0, ns); + copy_v3_v3(coa, nvprev->co); + nv = mesh_vert(vm, i, ring, 0); + copy_v3_v3(nv->co, coa); + nv->v = nvprev->v; + + if (vnext->ebev) + nvnext = mesh_vert(vm, vnext->index, 0, ring); + else + nvnext = mesh_vert(vm, vnext->index, 0, 0); + copy_v3_v3(cob, nvnext->co); + nv = mesh_vert(vm, i, ring, ns); + copy_v3_v3(nv->co, cob); + nv->v = nvnext->v; + + /* TODO: better calculation of new midarc point? */ + project_to_edge(v->ebev->e, coa, cob, midco); + + for (k = 1; k < ns; k++) { + get_point_on_round_edge(v->ebev, k, coa, midco, cob, co); + copy_v3_v3(mesh_vert(vm, i, ring, k)->co, co); + } + } + v = v->next; + } while (v != vm->boundstart); + } + + /* Now make sure cross points of rings share coordinates and vertices */ + v = vm->boundstart; + do { + i = v->index; + if (v->ebev) { + vprev = v->prev; + vnext = v->next; + if (vprev->ebev) { + for (ring = 1; ring <= ns2; ring++) { + for (k = 1; k <= ns2; k++) { + if (ns % 2 == 0 && (k == ns2 || ring == ns2)) + continue; /* center line is special case: do after the rest are done */ + nv = mesh_vert(vm, i, ring, k); + nvprev = mesh_vert(vm, vprev->index, k, ns - ring); + mid_v3_v3v3(co, nv->co, nvprev->co); + copy_v3_v3(nv->co, co); + BLI_assert(nv->v == NULL && nvprev->v == NULL); + create_mesh_bmvert(bm, vm, i, ring, k, bv->v); + copy_mesh_vert(vm, vprev->index, k, ns - ring, i, ring, k); + } + } + if (!vprev->prev->ebev) { + for (ring = 1; ring <= ns2; ring++) { + for (k = 1; k <= ns2; k++) { + if (ns % 2 == 0 && (k == ns2 || ring == ns2)) + continue; + create_mesh_bmvert(bm, vm, vprev->index, ring, k, bv->v); + } + } + } + if (!vnext->ebev) { + for (ring = 1; ring <= ns2; ring++) { + for (k = ns - ns2; k < ns; k++) { + if (ns % 2 == 0 && (k == ns2 || ring == ns2)) + continue; + create_mesh_bmvert(bm, vm, i, ring, k, bv->v); + } + } + } + } + } + v = v->next; + } while (v != vm->boundstart); + + if (ns % 2 == 0) { + /* do special case center lines */ + v = vm->boundstart; + do { + i = v->index; + if (v->ebev) { + vprev = v->prev; + vnext = v->next; + for (k = 1; k < ns2; k++) { + nv = mesh_vert(vm, i, k, ns2); + if (vprev->ebev) + nvprev = mesh_vert(vm, vprev->index, ns2, ns - k); + if (vnext->ebev) + nvnext = mesh_vert(vm, vnext->index, ns2, k); + if (vprev->ebev && vnext->ebev) { + mid_v3_v3v3v3(co, nvprev->co, nv->co, nvnext->co); + copy_v3_v3(nv->co, co); + create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); + copy_mesh_vert(vm, vprev->index, ns2, ns - k, i, k, ns2); + copy_mesh_vert(vm, vnext->index, ns2, k, i, k, ns2); + + } + else if (vprev->ebev) { + mid_v3_v3v3(co, nvprev->co, nv->co); + copy_v3_v3(nv->co, co); + create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); + copy_mesh_vert(vm, vprev->index, ns2, ns - k, i, k, ns2); + } + else if (vnext->ebev) { + mid_v3_v3v3(co, nv->co, nvnext->co); + copy_v3_v3(nv->co, co); + create_mesh_bmvert(bm, vm, i, k, ns2, bv->v); + copy_mesh_vert(vm, vnext->index, ns2, k, i, k, ns2); + } + } + } + v = v->next; + } while (v != vm->boundstart); + + /* center point need to be average of all centers of rings */ + /* TODO: this is wrong if not all verts have ebev: could have + * several disconnected sections of mesh. */ + zero_v3(midco); + nn = 0; + v = vm->boundstart; + do { + i = v->index; + if (v->ebev) { + nv = mesh_vert(vm, i, ns2, ns2); + add_v3_v3(midco, nv->co); + nn++; + } + v = v->next; + } while (v != vm->boundstart); + mul_v3_fl(midco, 1.0f / nn); + bmv = BM_vert_create(bm, midco, NULL); + v = vm->boundstart; + do { + i = v->index; + if (v->ebev) { + nv = mesh_vert(vm, i, ns2, ns2); + copy_v3_v3(nv->co, midco); + nv->v = bmv; + } + v = v->next; + } while (v != vm->boundstart); + } + + /* Make the ring quads */ + for (ring = 0; ring < ns2; ring++) { + v = vm->boundstart; + do { + i = v->index; + f = boundvert_rep_face(v); + if (v->ebev && (v->prev->ebev || v->next->ebev)) { + for (k = 0; k < ns2 + (ns % 2); k++) { + bmv1 = mesh_vert(vm, i, ring, k)->v; + bmv2 = mesh_vert(vm, i, ring, k + 1)->v; + bmv3 = mesh_vert(vm, i, ring + 1, k + 1)->v; + bmv4 = mesh_vert(vm, i, ring + 1, k)->v; + BLI_assert(bmv1 && bmv2 && bmv3 && bmv4); + if (bmv3 == bmv4 || bmv1 == bmv4) + bmv4 = NULL; + bev_create_quad_tri(bm, bmv1, bmv2, bmv3, bmv4, f); + } + } + else if (v->prev->ebev && v->prev->prev->ebev) { + /* finish off a sequence of beveled edges */ + i = v->prev->index; + f = boundvert_rep_face(v->prev); + for (k = ns2 + (ns % 2); k < ns; k++) { + bmv1 = mesh_vert(vm, i, ring + 1, k)->v; + bmv2 = mesh_vert(vm, i, ring, k)->v; + bmv3 = mesh_vert(vm, i, ring, k + 1)->v; + BLI_assert(bmv1 && bmv2 && bmv3); + bev_create_quad_tri(bm, bmv1, bmv2, bmv3, NULL, f); + } + } + v = v->next; + } while (v != vm->boundstart); + } + + /* Make center ngon if odd number of segments and fully beveled */ + if (ns % 2 == 1 && vm->count == bv->selcount) { + BMVert **vv = NULL; + BLI_array_declare(vv); + + v = vm->boundstart; + do { + i = v->index; + BLI_assert(v->ebev); + BLI_array_append(vv, mesh_vert(vm, i, ns2, ns2)->v); + v = v->next; + } while (v != vm->boundstart); + f = boundvert_rep_face(vm->boundstart); + bev_create_ngon(bm, vv, BLI_array_count(vv), f); + + BLI_array_free(vv); + } + + /* Make 'rest-of-vmesh' polygon if not fully beveled */ + if (vm->count > bv->selcount) { + int j; + BMVert **vv = NULL; + BLI_array_declare(vv); + + v = vm->boundstart; + f = boundvert_rep_face(v); + j = 0; + do { + i = v->index; + if (v->ebev) { + if (!v->prev->ebev) { + for (k = 0; k < ns2; k++) { + bmv1 = mesh_vert(vm, i, ns2, k)->v; + if (!(j > 0 && bmv1 == vv[j - 1])) { + BLI_array_append(vv, bmv1); + j++; + } + } + } + bmv1 = mesh_vert(vm, i, ns2, ns2)->v; + if (!(j > 0 && bmv1 == vv[j - 1])) { + BLI_array_append(vv, bmv1); + j++; + } + if (!v->next->ebev) { + for (k = ns - ns2; k < ns; k++) { + bmv1 = mesh_vert(vm, i, ns2, k)->v; + if (!(j > 0 && bmv1 == vv[j - 1])) { + BLI_array_append(vv, bmv1); + j++; + } + } + } + } + else { + BLI_array_append(vv, mesh_vert(vm, i, 0, 0)->v); + j++; + } + v = v->next; + } while (v != vm->boundstart); + if (vv[0] == vv[j - 1]) + j--; + bev_create_ngon(bm, vv, j, f); + + BLI_array_free(vv); + } +} + +static void bevel_build_poly(BMesh *bm, BevVert *bv) +{ + int n, k; + VMesh *vm = bv->vmesh; + BoundVert *v; + BMVert **vv = NULL; + BLI_array_declare(vv); + + v = vm->boundstart; + n = 0; + do { + /* accumulate vertices for vertex ngon */ + BLI_array_append(vv, v->nv.v); + n++; + if (v->ebev && v->ebev->seg > 1) { + for (k = 1; k < v->ebev->seg; k++) { + BLI_array_append(vv, mesh_vert(vm, v->index, 0, k)->v); + n++; + } + } + v = v->next; + } while (v != vm->boundstart); + if (n > 2) + bev_create_ngon(bm, vv, n, boundvert_rep_face(v)); + BLI_array_free(vv); +} + +/* 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(BMesh *bm, BevVert *bv) +{ + VMesh *vm = bv->vmesh; + BoundVert *v, *weld1, *weld2; + int n, ns, ns2, i, k, weld; + float *va, *vb, co[3], midco[3]; + + n = vm->count; + ns = vm->seg; + ns2 = ns / 2; + + vm->mesh = (NewVert *)MEM_callocN(n * (ns2 + 1) * (ns + 1) * sizeof(NewVert), "NewVert"); + + /* special case: two beveled ends welded together */ + weld = (bv->selcount == 2) && (vm->count == 2); + weld1 = weld2 = NULL; /* will hold two BoundVerts involved in weld */ + + /* make (i, 0, 0) mesh verts for all i */ + v = vm->boundstart; + do { + i = v->index; + copy_v3_v3(mesh_vert(vm, i, 0, 0)->co, v->nv.co); + create_mesh_bmvert(bm, vm, i, 0, 0, bv->v); + v->nv.v = mesh_vert(vm, i, 0, 0)->v; + if (weld && v->ebev) { + if (!weld1) + weld1 = v; + else + weld2 = v; + } + v = v->next; + } while (v != vm->boundstart); + + /* copy other ends to (i, 0, ns) for all i, and fill in profiles for beveled edges */ + v = vm->boundstart; + do { + i = v->index; + copy_mesh_vert(vm, i, 0, ns, v->next->index, 0, 0); + if (v->ebev) { + va = mesh_vert(vm, i, 0, 0)->co; + vb = mesh_vert(vm, i, 0, ns)->co; + project_to_edge(v->ebev->e, va, vb, midco); + for (k = 1; k < ns; k++) { + get_point_on_round_edge(v->ebev, k, va, midco, vb, co); + copy_v3_v3(mesh_vert(vm, i, 0, k)->co, co); + if (!weld) + create_mesh_bmvert(bm, vm, i, 0, k, bv->v); + } + } + v = v->next; + } while (v != vm->boundstart); + + if (weld) { + for (k = 1; k < ns; k++) { + mid_v3_v3v3(co, mesh_vert(vm, weld1->index, 0, k)->co, + mesh_vert(vm, weld2->index, 0, ns - k)->co); + copy_v3_v3(mesh_vert(vm, weld1->index, 0, k)->co, co); + create_mesh_bmvert(bm, vm, weld1->index, 0, k, bv->v); + } + for (k = 1; k < ns; k++) + copy_mesh_vert(vm, weld2->index, 0, ns - k, weld1->index, 0, k); + } + + if (vm->mesh_kind == M_ADJ) + bevel_build_rings(bm, bv); + else if (vm->mesh_kind == M_POLY) + bevel_build_poly(bm, bv); +} + +/* + * Construction around the vertex + */ +static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMOperator *op, BMVert *v) +{ + + BMOIter siter; + BMEdge *bme; + BevVert *bv; + BMEdge *bme2, *unflagged_bme; + BMFace *f; + BMIter iter, iter2; + EdgeHalf *e; + int i, ntot, found_shared_face, ccw_test_sum; + int nsel = 0; + + /* Gather input selected edges. + * Only bevel selected edges that have exactly two incident faces. */ + BMO_ITER (bme, &siter, bm, op, "geom", BM_EDGE) { + if ((bme->v1 == v) || (BM_edge_other_vert(bme, bme->v1) == v)) { + if (BM_edge_face_count(bme) == 2) { + BMO_elem_flag_enable(bm, bme, EDGE_SELECTED); + nsel++; + } + } + } + + if (nsel == 0) + return; + + ntot = BM_vert_edge_count(v); + bv = (BevVert *)MEM_callocN(sizeof(BevVert), "BevVert"); + bv->v = v; + bv->edgecount = ntot; + bv->selcount = nsel; + bv->edges = (EdgeHalf *)MEM_callocN(ntot * sizeof(EdgeHalf), "EdgeHalf"); + bv->vmesh = (VMesh *)MEM_callocN(sizeof(VMesh), "VMesh"); + bv->vmesh->seg = bp->seg; + BLI_addtail(&bp->vertList, bv); + + /* add edges to bv->edges in order that keeps adjacent edges sharing + * a face, if possible */ + i = 0; + bme = v->e; + BMO_elem_flag_enable(bm, bme, BEVEL_FLAG); + e = &bv->edges[0]; + e->e = bme; + for (i = 0; i < ntot; i++) { + if (i > 0) { + /* find an unflagged edge bme2 that shares a face f with previous bme */ + found_shared_face = 0; + unflagged_bme = NULL; + BM_ITER_ELEM (bme2, &iter, v, BM_EDGES_OF_VERT) { + if (BMO_elem_flag_test(bm, bme2, BEVEL_FLAG)) + continue; + if (!unflagged_bme) + unflagged_bme = bme2; + BM_ITER_ELEM (f, &iter2, bme2, BM_FACES_OF_EDGE) { + if (BM_face_edge_share_loop(f, bme)) { + found_shared_face = 1; + break; + } + } + if (found_shared_face) + break; + } + e = &bv->edges[i]; + if (found_shared_face) { + e->e = bme2; + e->fprev = f; + bv->edges[i - 1].fnext = f; + } + else { + e->e = unflagged_bme; + } + } + bme = e->e; + BMO_elem_flag_enable(bm, bme, BEVEL_FLAG); + if (BMO_elem_flag_test(bm, bme, EDGE_SELECTED)) { + e->isbev = 1; + e->seg = bp->seg; + } + else { + e->isbev = 0; + e->seg = 0; + } + e->isrev = (bme->v2 == v); + e->offset = e->isbev ? bp->offset : 0.0f; + } + /* find wrap-around shared face */ + BM_ITER_ELEM (f, &iter2, bme, BM_FACES_OF_EDGE) { + if (BM_face_edge_share_loop(f, bv->edges[0].e)) { + if (bv->edges[0].fnext == f) + continue; /* if two shared faces, want the other one now */ + bv->edges[ntot - 1].fnext = f; + bv->edges[0].fprev = f; + break; + } + } + + /* remove BEVEL_FLAG now that we are finished with it*/ + for (i = 0; i < ntot; i++) + BMO_elem_flag_disable(bm, bv->edges[i].e, BEVEL_FLAG); + + /* if edge array doesn't go CCW around vertex from average normal side, + * reverse the array, being careful to reverse face pointers too */ + if (ntot > 1) { + ccw_test_sum = 0; + for (i = 0; i < ntot; i++) + ccw_test_sum += bev_ccw_test(bv->edges[i].e, bv->edges[(i + 1) % ntot].e, + bv->edges[i].fnext); + if (ccw_test_sum < 0) { + for (i = 0; i <= (ntot / 2) - 1; i++) { + SWAP(EdgeHalf, bv->edges[i], bv->edges[ntot - i - 1]); + SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext); + SWAP(BMFace *, bv->edges[ntot - i - 1].fprev, bv->edges[ntot - i - 1].fnext); + } + if (ntot % 2 == 1) { + i = ntot / 2; + SWAP(BMFace *, bv->edges[i].fprev, bv->edges[i].fnext); + } + } + } + + for (i = 0; i < ntot; i++) { + e = &bv->edges[i]; + e->next = &bv->edges[(i + 1) % ntot]; + e->prev = &bv->edges[(i + ntot - 1) % ntot]; + } + + build_boundary(bv); + build_vmesh(bm, bv); +} + +/* Face f has at least one beveled vertex. Rebuild f */ +static void rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) +{ + BMIter liter; + BMLoop *l, *lprev; + BevVert *bv; + BoundVert *v, *vstart, *vend; + EdgeHalf *e, *eprev; + VMesh *vm; + int i, k; + BMVert *bmv; + BMVert **vv = NULL; + BLI_array_declare(vv); + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + bv = find_bevvert(bp, l->v); + if (bv) { + lprev = l->prev; + e = find_edge_half(bv, l->e); + eprev = find_edge_half(bv, lprev->e); + BLI_assert(e != NULL && eprev != NULL); + vstart = eprev->leftv; + if (e->isbev) + vend = e->rightv; + else + vend = e->leftv; + v = vstart; + vm = bv->vmesh; + BLI_array_append(vv, v->nv.v); + while (v != vend) { + if (vm->mesh_kind == M_NONE && v->ebev && v->ebev->seg > 1 && v->ebev != e && v->ebev != eprev) { + /* case of 3rd face opposite a beveled edge, with no vmesh */ + i = v->index; + e = v->ebev; + for (k = 1; k < e->seg; k++) { + bmv = mesh_vert(vm, i, 0, k)->v; + BLI_array_append(vv, bmv); + } + } + v = v->prev; + BLI_array_append(vv, v->nv.v); + } + } + else { + BLI_array_append(vv, l->v); + } + } + bev_create_ngon(bm, vv, BLI_array_count(vv), f); + BLI_array_free(vv); +} + +/* All polygons touching v need rebuilding because beveling v has made new vertices */ +static void bevel_rebuild_existing_polygons(BMesh *bm, BevelParams *bp, BMVert *v) +{ + BMFace *f; + BMIter iter; + + /* TODO: don't iterate through all faces, but just local geometry around v */ + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + BMLoop *l = f->l_first; + do { + if (l->v == v) { + rebuild_polygon(bm, bp, f); + BM_face_kill(bm, f); + } + l = l->next; + } while (l != f->l_first); + } +} + + + +/* + * Build the polygons along the selected Edge + */ +static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme) +{ + BevVert *bv1, *bv2; + BMVert *bmv1, *bmv2, *bmv3, *bmv4, *bmv1i, *bmv2i, *bmv3i, *bmv4i; + VMesh *vm1, *vm2; + EdgeHalf *e1, *e2; + BMFace *f1, *f2, *f; + int k, nseg, i1, i2; + + if (BM_edge_face_count(bme) != 2) + return; + + bv1 = find_bevvert(bp, bme->v1); + bv2 = find_bevvert(bp, bme->v2); + + BLI_assert(bv1 && bv2); + + e1 = find_edge_half(bv1, bme); + e2 = find_edge_half(bv2, bme); + + BLI_assert(e1 && e2); + + /* v4 v3 + * \ / + * e->v1 - e->v2 + * / \ + * v1 v2 */ + + nseg = e1->seg; + BLI_assert(nseg > 0 && nseg == e2->seg); + + bmv1 = e1->leftv->nv.v; + bmv4 = e1->rightv->nv.v; + bmv2 = e2->rightv->nv.v; + bmv3 = e2->leftv->nv.v; + + BLI_assert(bmv1 && bmv2 && bmv3 && bmv4); + + f1 = boundvert_rep_face(e1->leftv); + f2 = boundvert_rep_face(e1->rightv); + + if (nseg == 1) { + bev_create_quad_tri(bm, bmv1, bmv2, bmv3, bmv4, f1); + } + else { + i1 = e1->leftv->index; + i2 = e2->leftv->index; + vm1 = bv1->vmesh; + vm2 = bv2->vmesh; + bmv1i = bmv1; + bmv2i = bmv2; + for (k = 1; k <= nseg; k++) { + bmv4i = mesh_vert(vm1, i1, 0, k)->v; + bmv3i = mesh_vert(vm2, i2, 0, nseg - k)->v; + f = (k <= nseg / 2 + (nseg % 2)) ? f1 : f2; + bev_create_quad_tri(bm, bmv1i, bmv2i, bmv3i, bmv4i, f); + bmv1i = bmv4i; + bmv2i = bmv3i; + } + } +} + + +static void free_bevel_params(BevelParams *bp) +{ + BevVert *bv; + VMesh *vm; + BoundVert *v, *vnext; + + for (bv = bp->vertList.first; bv; bv = bv->next) { + MEM_freeN(bv->edges); + vm = bv->vmesh; + v = vm->boundstart; + if (v) { + do { + vnext = v->next; + MEM_freeN(v); + v = vnext; + } while (v != vm->boundstart); + } + if (vm->mesh) + MEM_freeN(vm->mesh); + MEM_freeN(vm); + } + BLI_freelistN(&bp->vertList); +} + +void bmo_bevel_exec(BMesh *bm, BMOperator *op) +{ + BMOIter siter; + BMVert *v; + BMEdge *e; + BevelParams bp; + + bp.offset = BMO_slot_float_get(op, "offset"); + bp.op = op; + bp.seg = BMO_slot_int_get(op, "segments"); + + if (bp.offset > 0) { + bp.vertList.first = bp.vertList.last = NULL; + + /* The analysis of the input vertices and execution additional constructions */ + BMO_ITER (v, &siter, bm, op, "geom", BM_VERT) { + bevel_vert_construct(bm, &bp, op, v); + } + /* Build polygons for edges */ + BMO_ITER (e, &siter, bm, op, "geom", BM_EDGE) { + bevel_build_edge_polygons(bm, &bp, e); + } + + BMO_ITER (v, &siter, bm, op, "geom", BM_VERT) { + bevel_rebuild_existing_polygons(bm, &bp, v); + } + + BMO_ITER (v, &siter, bm, op, "geom", BM_VERT) { + if (find_bevvert(&bp, v)) + BM_vert_kill(bm, v); + } + free_bevel_params(&bp); + } + +} + +#else +#define BEVEL_FLAG 1 +#define BEVEL_DEL 2 +#define FACE_NEW 4 +#define EDGE_OLD 8 +#define FACE_OLD 16 +#define VERT_OLD 32 +#define FACE_SPAN 64 +#define FACE_HOLE 128 typedef struct LoopTag { BMVert *newv; @@ -56,7 +1401,7 @@ typedef struct EdgeTag { static void calc_corner_co(BMLoop *l, const float fac, float r_co[3], const short do_dist, const short do_even) { - float no[3], l_vec_prev[3], l_vec_next[3], l_co_prev[3], l_co[3], l_co_next[3], co_ofs[3]; + float no[3], l_vec_prev[3], l_vec_next[3], l_co_prev[3], l_co[3], l_co_next[3], co_ofs[3]; int is_concave; /* first get the prev/next verts */ @@ -299,7 +1644,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) /* find all faces surrounding e->v1 and, e->v2 */ for (i = 0; i < 2; i++) { - BM_ITER_ELEM (l, &liter, i ? e->v2:e->v1, BM_LOOPS_OF_VERT) { + BM_ITER_ELEM (l, &liter, i ? e->v2 : e->v1, BM_LOOPS_OF_VERT) { BMLoop *l2; BMIter liter2; @@ -886,3 +2231,4 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op) BMO_slot_buffer_from_enabled_flag(bm, op, "face_spans", BM_FACE, FACE_SPAN); BMO_slot_buffer_from_enabled_flag(bm, op, "face_holes", BM_FACE, FACE_HOLE); } +#endif /* NEW_BEVEL */ diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c index bd1c0f809bd..093f567d995 100644 --- a/source/blender/bmesh/operators/bmo_create.c +++ b/source/blender/bmesh/operators/bmo_create.c @@ -1177,10 +1177,10 @@ void bmo_edgenet_prepare(BMesh *bm, BMOperator *op) } if (edges1 && BLI_array_count(edges1) > 2 && - BM_edge_share_vert_count(edges1[0], edges1[BLI_array_count(edges1) - 1])) + BM_edge_share_vert_check(edges1[0], edges1[BLI_array_count(edges1) - 1])) { if (edges2 && BLI_array_count(edges2) > 2 && - BM_edge_share_vert_count(edges2[0], edges2[BLI_array_count(edges2) - 1])) + BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1])) { BLI_array_free(edges1); BLI_array_free(edges2); @@ -1193,7 +1193,7 @@ void bmo_edgenet_prepare(BMesh *bm, BMOperator *op) } if (edges2 && BLI_array_count(edges2) > 2 && - BM_edge_share_vert_count(edges2[0], edges2[BLI_array_count(edges2) - 1])) + BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1])) { edges2 = NULL; } diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index 013b6183f84..b9c9398fbfa 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -426,12 +426,12 @@ static int hull_input_vert_count(BMesh *bm, BMOperator *op) } static BMVert **hull_input_verts_copy(BMesh *bm, BMOperator *op, - const int num_input_verts) + const int num_input_verts) { BMOIter oiter; BMVert *v; BMVert **input_verts = MEM_callocN(sizeof(*input_verts) * - num_input_verts, AT); + num_input_verts, AT); int i = 0; BMO_ITER (v, &oiter, bm, op, "input", BM_VERT) { @@ -442,7 +442,7 @@ static BMVert **hull_input_verts_copy(BMesh *bm, BMOperator *op, } static float (*hull_verts_for_bullet(BMVert **input_verts, - const int num_input_verts))[3] + const int num_input_verts))[3] { float (*coords)[3] = MEM_callocN(sizeof(*coords) * num_input_verts, AT); int i; @@ -455,12 +455,12 @@ static float (*hull_verts_for_bullet(BMVert **input_verts, } static BMVert **hull_verts_from_bullet(plConvexHull hull, - BMVert **input_verts, - const int num_input_verts) + BMVert **input_verts, + const int num_input_verts) { const int num_verts = plConvexHullNumVertices(hull); BMVert **hull_verts = MEM_mallocN(sizeof(*hull_verts) * - num_verts, AT); + num_verts, AT); int i; for (i = 0; i < num_verts; i++) { @@ -479,8 +479,8 @@ static BMVert **hull_verts_from_bullet(plConvexHull hull, } static void hull_from_bullet(BMesh *bm, BMOperator *op, - GHash *hull_triangles, - BLI_mempool *pool) + GHash *hull_triangles, + BLI_mempool *pool) { int *fvi = NULL; BLI_array_declare(fvi); @@ -523,7 +523,7 @@ static void hull_from_bullet(BMesh *bm, BMOperator *op, fv[2] = hull_verts[fvi[j]]; hull_add_triangle(bm, hull_triangles, pool, - fv[0], fv[1], fv[2]); + fv[0], fv[1], fv[2]); } } } diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c index 51b9adb5de3..362123e412d 100644 --- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c +++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c @@ -43,8 +43,8 @@ #include "intern/bmesh_operators_private.h" /* own include */ -#define SMOOTH_LAPLACIAN_AREA_FACTOR 4.0f -#define SMOOTH_LAPLACIAN_EDGE_FACTOR 2.0f +// #define SMOOTH_LAPLACIAN_AREA_FACTOR 4.0f /* UNUSED */ +// #define SMOOTH_LAPLACIAN_EDGE_FACTOR 2.0f /* UNUSED */ #define SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE 1.8f #define SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE 0.15f diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c index 346daf830d0..f6b9b18d716 100644 --- a/source/blender/bmesh/operators/bmo_subdivide.c +++ b/source/blender/bmesh/operators/bmo_subdivide.c @@ -825,7 +825,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) } /* make sure the two edges have a valid angle to each other */ - if (totesel == 2 && BM_edge_share_vert_count(e1, e2)) { + if (totesel == 2 && BM_edge_share_vert_check(e1, e2)) { sub_v3_v3v3(vec1, e1->v2->co, e1->v1->co); sub_v3_v3v3(vec2, e2->v2->co, e2->v1->co); normalize_v3(vec1); diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index e311b383b86..aa514a5c0a7 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -282,7 +282,7 @@ void bmo_region_extend_exec(BMesh *bm, BMOperator *op) #define FACE_VIS 1 #define FACE_FLAG 2 -#define FACE_MARK 4 +// #define FACE_MARK 4 /* UNUSED */ #define FACE_FLIP 8 /* NOTE: these are the original recalc_face_normals comment in editmesh_mods.c, diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cpp b/source/blender/compositor/nodes/COM_ScaleNode.cpp index c51782b77af..d535e71a33c 100644 --- a/source/blender/compositor/nodes/COM_ScaleNode.cpp +++ b/source/blender/compositor/nodes/COM_ScaleNode.cpp @@ -26,6 +26,7 @@ #include "COM_ExecutionSystem.h" #include "BKE_node.h" #include "COM_SetValueOperation.h" +#include "COM_SetSamplerOperation.h" ScaleNode::ScaleNode(bNode *editorNode) : Node(editorNode) { @@ -38,7 +39,9 @@ void ScaleNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c InputSocket *inputXSocket = this->getInputSocket(1); InputSocket *inputYSocket = this->getInputSocket(2); OutputSocket *outputSocket = this->getOutputSocket(0); + BaseScaleOperation *scaleoperation; bNode *bnode = this->getbNode(); + switch (bnode->custom1) { case CMP_SCALE_RELATIVE: { ScaleOperation *operation = new ScaleOperation(); @@ -46,8 +49,8 @@ void ScaleNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c inputSocket->relinkConnections(operation->getInputSocket(0), 0, graph); inputXSocket->relinkConnections(operation->getInputSocket(1), 1, graph); inputYSocket->relinkConnections(operation->getInputSocket(2), 2, graph); - outputSocket->relinkConnections(operation->getOutputSocket(0)); - graph->addOperation(operation); + + scaleoperation = operation; } break; case CMP_SCALE_SCENEPERCENT: { @@ -57,9 +60,9 @@ void ScaleNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c inputSocket->relinkConnections(operation->getInputSocket(0), 0, graph); addLink(graph, scaleFactorOperation->getOutputSocket(), operation->getInputSocket(1)); addLink(graph, scaleFactorOperation->getOutputSocket(), operation->getInputSocket(2)); - outputSocket->relinkConnections(operation->getOutputSocket(0)); graph->addOperation(scaleFactorOperation); - graph->addOperation(operation); + + scaleoperation = operation; } break; @@ -75,9 +78,9 @@ void ScaleNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c operation->setNewWidth(rd->xsch * rd->size / 100.0f); operation->setNewHeight(rd->ysch * rd->size / 100.0f); inputSocket->relinkConnections(operation->getInputSocket(0), 0, graph); - outputSocket->relinkConnections(operation->getOutputSocket(0)); operation->getInputSocket(0)->getConnection()->setIgnoreResizeCheck(true); - graph->addOperation(operation); + + scaleoperation = operation; } break; @@ -87,9 +90,12 @@ void ScaleNode::convertToOperations(ExecutionSystem *graph, CompositorContext *c inputSocket->relinkConnections(operation->getInputSocket(0), 0, graph); inputXSocket->relinkConnections(operation->getInputSocket(1), 1, graph); inputYSocket->relinkConnections(operation->getInputSocket(2), 2, graph); - outputSocket->relinkConnections(operation->getOutputSocket(0)); - graph->addOperation(operation); + + scaleoperation = operation; } break; } + + outputSocket->relinkConnections(scaleoperation->getOutputSocket(0)); + graph->addOperation(scaleoperation); } diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp b/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp index b28ee3eade1..a579503a829 100644 --- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp +++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp @@ -72,6 +72,8 @@ void Stabilize2dNode::convertToOperations(ExecutionSystem *graph, CompositorCont addLink(graph, scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(1)); addLink(graph, scaleAttribute->getOutputSocket(), scaleOperation->getInputSocket(2)); + scaleOperation->setSampler((PixelSampler)this->getbNode()->custom1); + addLink(graph, scaleOperation->getOutputSocket(), rotateOperation->getInputSocket(0)); addLink(graph, angleAttribute->getOutputSocket(), rotateOperation->getInputSocket(1)); rotateOperation->setDoDegree2RadConversion(false); diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp index df48c7a6716..68a61dff801 100644 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp @@ -50,6 +50,7 @@ MovieDistortionOperation::MovieDistortionOperation(bool distortion) : NodeOperat this->m_cache = NULL; this->m_distortion = distortion; } + void MovieDistortionOperation::initExecution() { this->m_inputOperation = this->getInputSocketReader(0); @@ -105,21 +106,9 @@ void MovieDistortionOperation::executePixel(float output[4], float x, float y, P if (this->m_cache != NULL) { float u, v; this->m_cache->getUV(&this->m_movieClip->tracking, x, y, &u, &v); - this->m_inputOperation->read(output, u, v, sampler); + this->m_inputOperation->read(output, u, v, COM_PS_BILINEAR); } else { - this->m_inputOperation->read(output, x, y, sampler); + this->m_inputOperation->read(output, x, y, COM_PS_BILINEAR); } } - -bool MovieDistortionOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) -{ - rcti newInput; - - newInput.xmax = input->xmax + 100; - newInput.xmin = input->xmin - 100; - newInput.ymax = input->ymax + 100; - newInput.ymin = input->ymin - 100; - - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); -} diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.h b/source/blender/compositor/operations/COM_MovieDistortionOperation.h index 93cc555fdbc..9f8aa065e3e 100644 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.h +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.h @@ -155,7 +155,6 @@ protected: public: MovieDistortionOperation(bool distortion); - bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output); void executePixel(float output[4], float x, float y, PixelSampler sampler); void initExecution(); diff --git a/source/blender/compositor/operations/COM_RenderLayersBaseProg.cpp b/source/blender/compositor/operations/COM_RenderLayersBaseProg.cpp index a4015c6283f..2ca499683d3 100644 --- a/source/blender/compositor/operations/COM_RenderLayersBaseProg.cpp +++ b/source/blender/compositor/operations/COM_RenderLayersBaseProg.cpp @@ -69,6 +69,46 @@ void RenderLayersBaseProg::initExecution() } } +void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, PixelSampler sampler) +{ + unsigned int offset; + int ix, iy; + int width = this->getWidth(), height = this->getHeight(); + + switch (sampler) { + case COM_PS_NEAREST: + ix = x; + iy = y; + offset = (iy * width + ix) * this->m_elementsize; + + if (this->m_elementsize == 1) + output[0] = this->m_inputBuffer[offset]; + else if (this->m_elementsize == 3) + copy_v3_v3(output, &this->m_inputBuffer[offset]); + else + copy_v4_v4(output, &this->m_inputBuffer[offset]); + + break; + + case COM_PS_BILINEAR: + BLI_bilinear_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); + break; + + case COM_PS_BICUBIC: + BLI_bicubic_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x, y); + break; + } + + if (this->m_elementsize == 1) { + output[1] = 0.0f; + output[2] = 0.0f; + output[3] = 0.0f; + } + else if (this->m_elementsize == 3) { + output[3] = 1.0f; + } +} + void RenderLayersBaseProg::executePixel(float output[4], float x, float y, PixelSampler sampler) { int ix = x; @@ -78,20 +118,7 @@ void RenderLayersBaseProg::executePixel(float output[4], float x, float y, Pixel zero_v4(output); } else { - unsigned int offset = (iy * this->getWidth() + ix) * this->m_elementsize; - if (this->m_elementsize == 1) { - output[0] = this->m_inputBuffer[offset]; - output[1] = 0.0f; - output[2] = 0.0f; - output[3] = 0.0f; - } - else if (this->m_elementsize == 3) { - copy_v3_v3(output, &this->m_inputBuffer[offset]); - output[3] = 1.0f; - } - else { - copy_v4_v4(output, &this->m_inputBuffer[offset]); - } + doInterpolation(output, x, y, sampler); } } diff --git a/source/blender/compositor/operations/COM_RenderLayersBaseProg.h b/source/blender/compositor/operations/COM_RenderLayersBaseProg.h index ea57d4bc421..3916862a0b3 100644 --- a/source/blender/compositor/operations/COM_RenderLayersBaseProg.h +++ b/source/blender/compositor/operations/COM_RenderLayersBaseProg.h @@ -80,6 +80,7 @@ protected: */ inline float *getInputBuffer() { return this->m_inputBuffer; } + void doInterpolation(float output[4], float x, float y, PixelSampler sampler); public: /** * setter for the scene field. Will be called from diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cpp index 276b2f54b6e..9e8f5af0ef0 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cpp +++ b/source/blender/compositor/operations/COM_ScaleOperation.cpp @@ -29,7 +29,16 @@ * note: use bilinear because bicubic makes fuzzy even when not scaling at all (1:1) */ -ScaleOperation::ScaleOperation() : NodeOperation() +BaseScaleOperation::BaseScaleOperation() +{ +#ifdef USE_FORCE_BILINEAR + m_sampler = (int) COM_PS_BILINEAR; +#else + m_sampler = -1; +#endif +} + +ScaleOperation::ScaleOperation() : BaseScaleOperation() { this->addInputSocket(COM_DT_COLOR); this->addInputSocket(COM_DT_VALUE); @@ -59,22 +68,20 @@ void ScaleOperation::deinitExecution() void ScaleOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) { -#ifdef USE_FORCE_BILINEAR - sampler = COM_PS_BILINEAR; -#endif + PixelSampler effective_sampler = getEffectiveSampler(sampler); float scaleX[4]; float scaleY[4]; - this->m_inputXOperation->read(scaleX, x, y, sampler); - this->m_inputYOperation->read(scaleY, x, y, sampler); + this->m_inputXOperation->read(scaleX, x, y, effective_sampler); + this->m_inputYOperation->read(scaleY, x, y, effective_sampler); const float scx = scaleX[0]; const float scy = scaleY[0]; float nx = this->m_centerX + (x - this->m_centerX) / scx; float ny = this->m_centerY + (y - this->m_centerY) / scy; - this->m_inputOperation->read(output, nx, ny, sampler); + this->m_inputOperation->read(output, nx, ny, effective_sampler); } bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) @@ -94,12 +101,12 @@ bool ScaleOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOpe newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / scy; newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / scy; - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } // SCALE ABSOLUTE -ScaleAbsoluteOperation::ScaleAbsoluteOperation() : NodeOperation() +ScaleAbsoluteOperation::ScaleAbsoluteOperation() : BaseScaleOperation() { this->addInputSocket(COM_DT_COLOR); this->addInputSocket(COM_DT_VALUE); @@ -129,15 +136,13 @@ void ScaleAbsoluteOperation::deinitExecution() void ScaleAbsoluteOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) { -#ifdef USE_FORCE_BILINEAR - sampler = COM_PS_BILINEAR; -#endif + PixelSampler effective_sampler = getEffectiveSampler(sampler); float scaleX[4]; float scaleY[4]; - this->m_inputXOperation->read(scaleX, x, y, sampler); - this->m_inputYOperation->read(scaleY, x, y, sampler); + this->m_inputXOperation->read(scaleX, x, y, effective_sampler); + this->m_inputYOperation->read(scaleY, x, y, effective_sampler); const float scx = scaleX[0]; // target absolute scale const float scy = scaleY[0]; // target absolute scale @@ -151,7 +156,7 @@ void ScaleAbsoluteOperation::executePixel(float output[4], float x, float y, Pix float nx = this->m_centerX + (x - this->m_centerX) / relativeXScale; float ny = this->m_centerY + (y - this->m_centerY) / relativeYScale; - this->m_inputOperation->read(output, nx, ny, sampler); + this->m_inputOperation->read(output, nx, ny, effective_sampler); } bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) @@ -176,12 +181,12 @@ bool ScaleAbsoluteOperation::determineDependingAreaOfInterest(rcti *input, ReadB newInput.ymax = this->m_centerY + (input->ymax - this->m_centerY) / relateveYScale; newInput.ymin = this->m_centerY + (input->ymin - this->m_centerY) / relateveYScale; - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } // Absolute fixed siez -ScaleFixedSizeOperation::ScaleFixedSizeOperation() : NodeOperation() +ScaleFixedSizeOperation::ScaleFixedSizeOperation() : BaseScaleOperation() { this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE); this->addOutputSocket(COM_DT_COLOR); @@ -250,17 +255,15 @@ void ScaleFixedSizeOperation::deinitExecution() void ScaleFixedSizeOperation::executePixel(float output[4], float x, float y, PixelSampler sampler) { -#ifdef USE_FORCE_BILINEAR - sampler = COM_PS_BILINEAR; -#endif + PixelSampler effective_sampler = getEffectiveSampler(sampler); if (this->m_is_offset) { float nx = ((x - this->m_offsetX) * this->m_relX); float ny = ((y - this->m_offsetY) * this->m_relY); - this->m_inputOperation->read(output, nx, ny, sampler); + this->m_inputOperation->read(output, nx, ny, effective_sampler); } else { - this->m_inputOperation->read(output, x * this->m_relX, y * this->m_relY, sampler); + this->m_inputOperation->read(output, x * this->m_relX, y * this->m_relY, effective_sampler); } } @@ -273,7 +276,7 @@ bool ScaleFixedSizeOperation::determineDependingAreaOfInterest(rcti *input, Read newInput.ymax = input->ymax * this->m_relY; newInput.ymin = input->ymin * this->m_relY; - return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); + return BaseScaleOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); } void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]) @@ -281,7 +284,7 @@ void ScaleFixedSizeOperation::determineResolution(unsigned int resolution[2], un unsigned int nr[2]; nr[0] = this->m_newWidth; nr[1] = this->m_newHeight; - NodeOperation::determineResolution(resolution, nr); + BaseScaleOperation::determineResolution(resolution, nr); resolution[0] = this->m_newWidth; resolution[1] = this->m_newHeight; } diff --git a/source/blender/compositor/operations/COM_ScaleOperation.h b/source/blender/compositor/operations/COM_ScaleOperation.h index 4239ff063fb..f42cdbd78ed 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.h +++ b/source/blender/compositor/operations/COM_ScaleOperation.h @@ -25,7 +25,19 @@ #include "COM_NodeOperation.h" -class ScaleOperation : public NodeOperation { +class BaseScaleOperation : public NodeOperation { +public: + void setSampler(PixelSampler sampler) { this->m_sampler = (int) sampler; } + +protected: + BaseScaleOperation(); + + PixelSampler getEffectiveSampler(PixelSampler sampler) { return (m_sampler == -1) ? sampler : (PixelSampler) m_sampler; } + + int m_sampler; +}; + +class ScaleOperation : public BaseScaleOperation { private: SocketReader *m_inputOperation; SocketReader *m_inputXOperation; @@ -41,7 +53,7 @@ public: void deinitExecution(); }; -class ScaleAbsoluteOperation : public NodeOperation { +class ScaleAbsoluteOperation : public BaseScaleOperation { SocketReader *m_inputOperation; SocketReader *m_inputXOperation; SocketReader *m_inputYOperation; @@ -57,7 +69,7 @@ public: void deinitExecution(); }; -class ScaleFixedSizeOperation : public NodeOperation { +class ScaleFixedSizeOperation : public BaseScaleOperation { SocketReader *m_inputOperation; int m_newWidth; int m_newHeight; diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp index d41d1c128da..8b5288321c1 100644 --- a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp +++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cpp @@ -92,7 +92,7 @@ void TrackPositionOperation::initExecution() } else if (this->m_position == POSITION_RELATIVE_FRAME) { int relative_clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, - this->m_relativeFrame); + this->m_relativeFrame); marker = BKE_tracking_marker_get(track, relative_clip_framenr); copy_v2_v2(this->m_relativePos, marker->pos); diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 01c0a95e200..0f0584ad8fe 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -381,7 +381,7 @@ float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short rest return RAD2DEGF(1.0f); /* radians to degrees */ } } - + /* TODO: other rotation types here as necessary */ } } diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index f1fc93db60e..dffef5c131f 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -176,7 +176,7 @@ static short actedit_get_context(bAnimContext *ac, SpaceAction *saction) return 1; case SACTCONT_MASK: /* Mask */ /* XXX review how this mode is handled... */ -{ + { /* TODO, other methods to get the mask */ // Sequence *seq = BKE_sequencer_active_get(ac->scene); //MovieClip *clip = ac->scene->clip; @@ -190,7 +190,7 @@ static short actedit_get_context(bAnimContext *ac, SpaceAction *saction) ac->mode = saction->mode; return 1; -} + } case SACTCONT_DOPESHEET: /* DopeSheet */ /* update scene-pointer (no need to check for pinning yet, as not implemented) */ saction->ads.source = (ID *)ac->scene; @@ -925,14 +925,16 @@ static short skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_i /* only consider if F-Curve involves sequence_editor.sequences */ if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) { Editing *ed = BKE_sequencer_editing_get(scene, FALSE); - Sequence *seq; + Sequence *seq = NULL; char *seq_name; - - /* get strip name, and check if this strip is selected */ - seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); - seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, FALSE); - if (seq_name) MEM_freeN(seq_name); - + + if (ed) { + /* get strip name, and check if this strip is selected */ + seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["); + seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, FALSE); + if (seq_name) MEM_freeN(seq_name); + } + /* can only add this F-Curve if it is selected */ if (ads->filterflag & ADS_FILTER_ONLYSEL) { if ((seq == NULL) || (seq->flag & SELECT) == 0) diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index da8fc328343..f9cf4a29269 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -2104,15 +2104,15 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch, if (sketch->depth_peels.first != NULL) { float colors[8][3] = { - {1, 0, 0}, - {0, 1, 0}, - {0, 0, 1}, - {1, 1, 0}, - {1, 0, 1}, - {0, 1, 1}, - {1, 1, 1}, - {0, 0, 0} - }; + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + {1, 1, 0}, + {1, 0, 1}, + {0, 1, 1}, + {1, 1, 1}, + {0, 0, 0} + }; DepthPeel *p; GLUquadric *quad = gluNewQuadric(); gluQuadricNormals(quad, GLU_SMOOTH); diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 485d73974cd..957dcfbd848 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -6465,8 +6465,8 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type fac = (float)b - 1.5f; bp->vec[1] += fac * grid; if (a == 1 || a == 2) if (b == 1 || b == 2) { - bp->vec[2] += grid; - } + bp->vec[2] += grid; + } mul_m4_v3(mat, bp->vec); bp->vec[3] = 1.0; bp++; diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index ed8a1ea8280..1defcf65ae8 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -40,8 +40,10 @@ #include "BLI_math.h" #include "BLI_blenlib.h" +#include "BLI_rand.h" #include "BLI_utildefines.h" +#include "DNA_anim_types.h" #include "DNA_curve_types.h" #include "DNA_object_types.h" #include "DNA_node_types.h" @@ -51,14 +53,19 @@ #include "DNA_view3d_types.h" #include "DNA_gpencil_types.h" +#include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_fcurve.h" +#include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_library.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_tracking.h" +#include "UI_interface.h" #include "WM_api.h" #include "WM_types.h" @@ -71,6 +78,7 @@ #include "ED_gpencil.h" #include "ED_view3d.h" #include "ED_clip.h" +#include "ED_keyframing.h" #include "gpencil_intern.h" @@ -387,6 +395,14 @@ enum { GP_STROKECONVERT_CURVE, }; +/* Defines for possible timing modes */ +enum { + GP_STROKECONVERT_TIMING_NONE = 1, + GP_STROKECONVERT_TIMING_LINEAR = 2, + GP_STROKECONVERT_TIMING_FULL = 3, + GP_STROKECONVERT_TIMING_CUSTOMGAP = 4, +}; + /* RNA enum define */ static EnumPropertyItem prop_gpencil_convertmodes[] = { {GP_STROKECONVERT_PATH, "PATH", 0, "Path", ""}, @@ -394,6 +410,31 @@ static EnumPropertyItem prop_gpencil_convertmodes[] = { {0, NULL, 0, NULL, NULL} }; +static EnumPropertyItem prop_gpencil_convert_timingmodes_restricted[] = { + {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"}, + {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"}, + {0, NULL, 0, NULL, NULL}, +}; + +static EnumPropertyItem prop_gpencil_convert_timingmodes[] = { + {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"}, + {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"}, + {GP_STROKECONVERT_TIMING_FULL, "FULL", 0, "Original", "Use the original timing, gaps included"}, + {GP_STROKECONVERT_TIMING_CUSTOMGAP, "CUSTOMGAP", 0, "Custom Gaps", + "Use the original timing, but with custom gap lengths (in frames)"}, + {0, NULL, 0, NULL, NULL}, +}; + +static EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), + int *free) +{ + *free = FALSE; + if (RNA_boolean_get(ptr, "use_timing_data")) { + return prop_gpencil_convert_timingmodes; + } + return prop_gpencil_convert_timingmodes_restricted; +} + /* --- */ /* convert the coordinates from the given stroke point into 3d-coordinates @@ -440,40 +481,487 @@ static void gp_strokepoint_convertcoords(bContext *C, bGPDstroke *gps, bGPDspoin /* --- */ +/* temp struct for gp_stroke_path_animation() */ +typedef struct tGpTimingData { + /* Data set from operator settings */ + int mode; + int frame_range; /* Number of frames evaluated for path animation */ + int start_frame, end_frame; + int realtime; /* A bool, actually, will overwrite end_frame in case of Original or CustomGap timing... */ + float gap_duration, gap_randomness; /* To be used with CustomGap mode*/ + int seed; + + /* Data set from points, used to compute final timing FCurve */ + int num_points, cur_point; + + /* Distances */ + float *dists; + float tot_dist; + + /* Times */ + float *times; /* Note: Gap times will be negative! */ + float tot_time, gap_tot_time; + double inittime; +} tGpTimingData; + +static void _gp_timing_data_set_nbr(tGpTimingData *gtd, int nbr) +{ + float *tmp; + + BLI_assert(nbr > gtd->num_points); + + tmp = gtd->dists; + gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__); + if (tmp) { + memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points); + MEM_freeN(tmp); + } + + tmp = gtd->times; + gtd->times = MEM_callocN(sizeof(float) * nbr, __func__); + if (tmp) { + memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points); + MEM_freeN(tmp); + } + + gtd->num_points = nbr; +} + +static void gp_timing_data_add_point(tGpTimingData *gtd, double stroke_inittime, float time, float delta_dist) +{ + if (time < 0.0f) { + /* This is a gap, negative value! */ + gtd->tot_time = -(gtd->times[gtd->cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time)); + gtd->gap_tot_time += gtd->times[gtd->cur_point] - gtd->times[gtd->cur_point - 1]; + } + else + gtd->tot_time = (gtd->times[gtd->cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time)); + gtd->dists[gtd->cur_point] = (gtd->tot_dist += delta_dist); + gtd->cur_point++; +} + +/* In frames! Binary search for FCurve keys have a threshold of 0.01, so we can’t set + * arbitrarily close points - this is esp. important with NoGaps mode! + */ +#define MIN_TIME_DELTA 0.02f + +/* Loop over next points to find the end of the stroke, and compute */ +static int gp_find_end_of_stroke_idx(tGpTimingData *gtd, int idx, int nbr_gaps, int *nbr_done_gaps, + float tot_gaps_time, float delta_time, float *next_delta_time) +{ + int j; + + for (j = idx + 1; j < gtd->num_points; j++) { + if (gtd->times[j] < 0) { + gtd->times[j] = -gtd->times[j]; + if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { + /* In this mode, gap time between this stroke and the next should be 0 currently... + * So we have to compute its final duration! + */ + if (gtd->gap_randomness > 0.0f) { + /* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range, + * and which sum to exactly tot_gaps_time... + */ + int rem_gaps = nbr_gaps - *nbr_done_gaps; + if (rem_gaps < 2) { + /* Last gap, just give remaining time! */ + *next_delta_time = tot_gaps_time; + } + else { + float delta, min, max; + /* This code ensures that if the first gaps have been shorter than average gap_duration, + * next gaps will tend to be longer (i.e. try to recover the lateness), and vice-versa! + */ + delta = delta_time - (gtd->gap_duration * *nbr_done_gaps); + /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */ + min = -gtd->gap_randomness - delta; + CLAMP(min, -gtd->gap_randomness, 0.0f); + /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */ + max = gtd->gap_randomness - delta; + CLAMP(max, 0.0f, gtd->gap_randomness); + *next_delta_time += gtd->gap_duration + (BLI_frand() * (max - min)) + min; + } + } + else { + *next_delta_time += gtd->gap_duration; + } + } + (*nbr_done_gaps)++; + break; + } + } + + return j - 1; +} + +static void gp_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, int *nbr_gaps, float *tot_gaps_time) +{ + int i; + float delta_time = 0.0f; + + for (i = 0; i < gtd->num_points; i++) { + if (gtd->times[i] < 0 && i) { + (*nbr_gaps)++; + gtd->times[i] = -gtd->times[i] - delta_time; + delta_time += gtd->times[i] - gtd->times[i - 1]; + gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */ + } + else { + gtd->times[i] -= delta_time; + } + } + gtd->tot_time -= delta_time; + + *tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration; + gtd->tot_time += *tot_gaps_time; + if (G.debug & G_DEBUG) { + printf("%f, %f, %f, %d\n", gtd->tot_time, delta_time, *tot_gaps_time, *nbr_gaps); + } + if (gtd->gap_randomness > 0.0f) { + BLI_srandom(gtd->seed); + } +} + +static void gp_stroke_path_animation_add_keyframes(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, + Curve *cu, tGpTimingData *gtd, float time_range, + int nbr_gaps, float tot_gaps_time) +{ + /* Use actual recorded timing! */ + float time_start = (float)gtd->start_frame; + + float last_valid_time = 0.0f; + int end_stroke_idx = -1, start_stroke_idx = 0; + float end_stroke_time = 0.0f; + + /* CustomGaps specific */ + float delta_time = 0.0f, next_delta_time = 0.0f; + int nbr_done_gaps = 0; + + int i; + float cfra; + + /* This is a bit tricky, as: + * - We can't add arbitrarily close points on FCurve (in time). + * - We *must* have all "caps" points of all strokes in FCurve, as much as possible! + */ + for (i = 0; i < gtd->num_points; i++) { + /* If new stroke... */ + if (i > end_stroke_idx) { + start_stroke_idx = i; + delta_time = next_delta_time; + /* find end of that new stroke */ + end_stroke_idx = gp_find_end_of_stroke_idx(gtd, i, nbr_gaps, &nbr_done_gaps, + tot_gaps_time, delta_time, &next_delta_time); + /* This one should *never* be negative! */ + end_stroke_time = time_start + ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range); + } + + /* Simple proportional stuff... */ + cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen; + cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range); + + /* And now, the checks about timing... */ + if (i == start_stroke_idx) { + /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and + * that the end point of the stroke is far enough! + * In case it is not, we keep the end point... + * Note that with CustomGaps mode, this is here we set the actual gap timing! + */ + if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) { + if ((cfra - last_valid_time) < MIN_TIME_DELTA) { + cfra = last_valid_time + MIN_TIME_DELTA; + } + insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST); + last_valid_time = cfra; + } + else if (G.debug & G_DEBUG) { + printf("\t Skipping start point %d, too close from end point %d\n", i, end_stroke_idx); + } + } + else if (i == end_stroke_idx) { + /* Always try to insert end point of a curve (should be safe enough, anyway...) */ + if ((cfra - last_valid_time) < MIN_TIME_DELTA) { + cfra = last_valid_time + MIN_TIME_DELTA; + } + insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST); + last_valid_time = cfra; + } + else { + /* Else ("middle" point), we only insert it if it's far enough from last keyframe, + * and also far enough from (not yet added!) end_stroke keyframe! + */ + if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) { + insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST); + last_valid_time = cfra; + } + else if (G.debug & G_DEBUG) { + printf("\t Skipping \"middle\" point %d, too close from last added point or end point %d\n", + i, end_stroke_idx); + } + } + } +} + +static void gp_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd) +{ + Scene *scene = CTX_data_scene(C); + bAction *act; + FCurve *fcu; + PointerRNA ptr; + PropertyRNA *prop = NULL; + + int nbr_gaps = 0, i; + + if (gtd->mode == GP_STROKECONVERT_TIMING_NONE) + return; + + /* gap_duration and gap_randomness are in frames, but we need seconds!!! */ + gtd->gap_duration = FRA2TIME(gtd->gap_duration); + gtd->gap_randomness = FRA2TIME(gtd->gap_randomness); + + /* Enable path! */ + cu->flag |= CU_PATH; + cu->pathlen = gtd->frame_range; + + /* Get or create default action to add F-Curve+keyframe to */ + act = verify_adt_action((ID*)cu, TRUE); + /* Create RNA stuff */ + RNA_id_pointer_create((ID*)cu, &ptr); + prop = RNA_struct_find_property(&ptr, "eval_time"); + /* Get or create fcurve */ + fcu = verify_fcurve(act, NULL, &ptr, "eval_time", 0, TRUE); + + if (G.debug & G_DEBUG) { + printf("%s: tot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time); + for (i = 0; i < gtd->num_points; i++) { + printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]); + } + } + + if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) { + float cfra; + + /* Linear extrapolation! */ + fcu->extend = FCURVE_EXTRAPOLATE_LINEAR; + + cu->ctime = 0.0f; + cfra = (float)gtd->start_frame; + insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST); + + cu->ctime = cu->pathlen; + if (gtd->realtime) { + cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */ + } + else { + cfra = (float)gtd->end_frame; + } + insert_keyframe_direct(reports, ptr, prop, fcu, cfra, INSERTKEY_FAST); + } + else { + /* Use actual recorded timing! */ + float time_range; + + /* CustomGaps specific */ + float tot_gaps_time = 0.0f; + + /* Pre-process gaps, in case we don't want to keep their org timing */ + if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { + gp_stroke_path_animation_preprocess_gaps(gtd, &nbr_gaps, &tot_gaps_time); + } + + if (gtd->realtime) { + time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */ + } + else { + time_range = (float)(gtd->end_frame - gtd->start_frame); + } + + if (G.debug & G_DEBUG) { + printf("Starting keying!\n"); + } + + gp_stroke_path_animation_add_keyframes(reports, ptr, prop, fcu, cu, gtd, time_range, + nbr_gaps, tot_gaps_time); + + } + + /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */ + calchandles_fcurve(fcu); + + if (G.debug & G_DEBUG) { + printf("%s: \ntot len: %f\t\ttot time: %f\n", __func__, gtd->tot_dist, gtd->tot_time); + for (i = 0; i < gtd->num_points; i++) { + printf("\tpoint %d:\t\tlen: %f\t\ttime: %f\n", i, gtd->dists[i], gtd->times[i]); + } + printf("\n\n"); + } + + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + + /* send updates */ + DAG_id_tag_update((ID*)cu, 0); +} + +#undef MIN_TIME_DELTA + +#define GAP_DFAC 0.05f +#define WIDTH_CORR_FAC 0.1f +#define BEZT_HANDLE_FAC 0.3f + /* convert stroke to 3d path */ -static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect) +static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, + float minmax_weights[2], float rad_fac, int stitch, tGpTimingData *gtd) { bGPDspoint *pt; - Nurb *nu; - BPoint *bp; - int i; + Nurb *nu = curnu ? *curnu : NULL; + BPoint *bp, *prev_bp = NULL; + int i, old_nbp = 0; + const int do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE); + + /* create new 'nurb' or extend current one within the curve */ + if (nu) { + old_nbp = nu->pntsu; + /* If stitch, the first point of this stroke is already present in current nu. + * Else, we have to add to additional points to make the zero-radius link between strokes. + */ + BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2)); + } + else { + nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)"); + + nu->pntsu = gps->totpoints; + nu->pntsv = 1; + nu->orderu = 2; /* point-to-point! */ + nu->type = CU_NURBS; + nu->flagu = CU_NURB_ENDPOINT; + nu->resolu = cu->resolu; + nu->resolv = cu->resolv; + nu->knotsu = NULL; + + nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints"); + + stitch = FALSE; /* Security! */ + } - /* create new 'nurb' within the curve */ - nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)"); - - nu->pntsu = gps->totpoints; - nu->pntsv = 1; - nu->orderu = gps->totpoints; - nu->flagu = CU_NURB_ENDPOINT; - nu->resolu = 32; - - nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * gps->totpoints, "bpoints"); - + if (do_gtd) { + _gp_timing_data_set_nbr(gtd, nu->pntsu); + } + + /* If needed, make the link between both strokes with two zero-radius additional points */ + /* About "zero-radius" point interpolations: + * - If we have at least two points in current curve (most common case), we linearly extrapolate + * the last segment to get the first point (p1) position and timing. + * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point + * with the first point of the current stroke. + * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated + * if it exists, else (if the stroke is a single point), linear interpolation with last curve point... + */ + if (curnu && !stitch && old_nbp) { + float p1[3], p2[3], p[3], next_p[3]; + float delta_time; + + prev_bp = NULL; + if (old_nbp > 1 && gps->prev && gps->prev->totpoints > 1) { + /* Only use last curve segment if previous stroke was not a single-point one! */ + prev_bp = nu->bp + old_nbp - 2; + } + bp = nu->bp + old_nbp - 1; + /* XXX We do this twice... Not sure it's worth to bother about this! */ + gp_strokepoint_convertcoords(C, gps, gps->points, p, subrect); + if (prev_bp) { + interp_v3_v3v3(p1, prev_bp->vec, bp->vec, 1.0f + GAP_DFAC); + } + else { + interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC); + } + if (gps->totpoints > 1) { + /* XXX We do this twice... Not sure it's worth to bother about this! */ + gp_strokepoint_convertcoords(C, gps, gps->points + 1, next_p, subrect); + interp_v3_v3v3(p2, p, next_p, -GAP_DFAC); + } + else { + interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC); + } + + /* First point */ + bp++; + copy_v3_v3(bp->vec, p1); + bp->vec[3] = 1.0f; + bp->f1 = SELECT; + minmax_weights[0] = bp->radius = bp->weight = 0.0f; + if (do_gtd) { + if (prev_bp) { + delta_time = gtd->tot_time + (gtd->tot_time - gtd->times[gtd->cur_point - 1]) * GAP_DFAC; + } + else { + delta_time = gtd->tot_time + (((float)(gps->inittime - gtd->inittime)) - gtd->tot_time) * GAP_DFAC; + } + gp_timing_data_add_point(gtd, gtd->inittime, delta_time, len_v3v3((bp - 1)->vec, p1)); + } + + /* Second point */ + bp++; + copy_v3_v3(bp->vec, p2); + bp->vec[3] = 1.0f; + bp->f1 = SELECT; + minmax_weights[0] = bp->radius = bp->weight = 0.0f; + if (do_gtd) { + /* This negative delta_time marks the gap! */ + if (gps->totpoints > 1) { + delta_time = ((gps->points + 1)->time - gps->points->time) * -GAP_DFAC; + } + else { + delta_time = -(((float)(gps->inittime - gtd->inittime)) - gtd->tot_time) * GAP_DFAC; + } + gp_timing_data_add_point(gtd, gps->inittime, delta_time, len_v3v3(p1, p2)); + } + + old_nbp += 2; + } + if (old_nbp && do_gtd) { + prev_bp = nu->bp + old_nbp - 1; + } /* add points */ - for (i = 0, pt = gps->points, bp = nu->bp; i < gps->totpoints; i++, pt++, bp++) { + for (i = stitch ? 1 : 0, pt = gps->points + (stitch ? 1 : 0), bp = nu->bp + old_nbp; + i < gps->totpoints; + i++, pt++, bp++) + { float p3d[3]; - + float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC; + /* get coordinates to add at */ gp_strokepoint_convertcoords(C, gps, pt, p3d, subrect); copy_v3_v3(bp->vec, p3d); - + bp->vec[3] = 1.0f; + /* set settings */ bp->f1 = SELECT; - bp->radius = bp->weight = pt->pressure * gpl->thickness; + bp->radius = width * rad_fac; + bp->weight = width; + CLAMP(bp->weight, 0.0f, 1.0f); + if (bp->weight < minmax_weights[0]) { + minmax_weights[0] = bp->weight; + } + else if (bp->weight > minmax_weights[1]) { + minmax_weights[1] = bp->weight; + } + + /* Update timing data */ + if (do_gtd) { + gp_timing_data_add_point(gtd, gps->inittime, pt->time, prev_bp ? len_v3v3(prev_bp->vec, p3d) : 0.0f); + } + prev_bp = bp; } - + /* add nurb to curve */ - BLI_addtail(&cu->nurb, nu); + if (!curnu || !*curnu) { + BLI_addtail(&cu->nurb, nu); + } + if (curnu) { + *curnu = nu; + } + + BKE_nurb_knot_calc_u(nu); } static int gp_camera_view_subrect(bContext *C, rctf *subrect) @@ -496,77 +984,288 @@ static int gp_camera_view_subrect(bContext *C, rctf *subrect) } /* convert stroke to 3d bezier */ -static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect) +static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, + float minmax_weights[2], float rad_fac, int stitch, tGpTimingData *gtd) { bGPDspoint *pt; - Nurb *nu; - BezTriple *bezt; - int i, tot; + Nurb *nu = curnu ? *curnu : NULL; + BezTriple *bezt, *prev_bezt = NULL; + int i, tot, old_nbezt = 0; float p3d_cur[3], p3d_prev[3], p3d_next[3]; + const int do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE); + + /* create new 'nurb' or extend current one within the curve */ + if (nu) { + old_nbezt = nu->pntsu; + /* If we do stitch, first point of current stroke is assumed the same as last point of previous stroke, + * so no need to add it. + * If no stitch, we want to add two additional points to make a "zero-radius" link between both strokes. + */ + BKE_nurb_bezierPoints_add(nu, gps->totpoints + (stitch ? -1 : 2)); + } + else { + nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)"); - /* create new 'nurb' within the curve */ - nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)"); + nu->pntsu = gps->totpoints; + nu->resolu = 12; + nu->resolv = 12; + nu->type = CU_BEZIER; + nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints * sizeof(BezTriple), "bezts"); - nu->pntsu = gps->totpoints; - nu->resolu = 12; - nu->resolv = 12; - nu->type = CU_BEZIER; - nu->bezt = (BezTriple *)MEM_callocN(gps->totpoints * sizeof(BezTriple), "bezts"); + stitch = FALSE; /* Security! */ + } + + if (do_gtd) { + _gp_timing_data_set_nbr(gtd, nu->pntsu); + } tot = gps->totpoints; /* get initial coordinates */ pt = gps->points; if (tot) { - gp_strokepoint_convertcoords(C, gps, pt, p3d_cur, subrect); + gp_strokepoint_convertcoords(C, gps, pt, stitch ? p3d_prev : p3d_cur, subrect); if (tot > 1) { - gp_strokepoint_convertcoords(C, gps, pt + 1, p3d_next, subrect); + gp_strokepoint_convertcoords(C, gps, pt + 1, stitch ? p3d_cur : p3d_next, subrect); + } + if (stitch && tot > 2) { + gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect); } } + /* If needed, make the link between both strokes with two zero-radius additional points */ + if (curnu && old_nbezt) { + /* Update last point's second handle! */ + if (stitch) { + float h2[3]; + bezt = nu->bezt + old_nbezt - 1; + interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC); + copy_v3_v3(bezt->vec[2], h2); + pt++; + } + /* Create "link points" */ + /* About "zero-radius" point interpolations: + * - If we have at least two points in current curve (most common case), we linearly extrapolate + * the last segment to get the first point (p1) position and timing. + * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point + * with the first point of the current stroke. + * The same goes for the second point, first segment of the current stroke is "negatively" extrapolated + * if it exists, else (if the stroke is a single point), linear interpolation with last curve point... + */ + else { + float h1[3], h2[3], p1[3], p2[3]; + float delta_time; + + prev_bezt = NULL; + if (old_nbezt > 1 && gps->prev && gps->prev->totpoints > 1) { + /* Only use last curve segment if previous stroke was not a single-point one! */ + prev_bezt = nu->bezt + old_nbezt - 2; + } + bezt = nu->bezt + old_nbezt - 1; + if (prev_bezt) { + interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC); + } + else { + interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC); + } + if (tot > 1) { + interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC); + } + else { + interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC); + } + + /* Second handle of last point */ + interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC); + copy_v3_v3(bezt->vec[2], h2); + + /* First point */ + interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC); + interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC); + + bezt++; + copy_v3_v3(bezt->vec[0], h1); + copy_v3_v3(bezt->vec[1], p1); + copy_v3_v3(bezt->vec[2], h2); + bezt->h1 = bezt->h2 = HD_FREE; + bezt->f1 = bezt->f2 = bezt->f3 = SELECT; + minmax_weights[0] = bezt->radius = bezt->weight = 0.0f; + + if (do_gtd) { + if (prev_bezt) { + delta_time = gtd->tot_time + (gtd->tot_time - gtd->times[gtd->cur_point - 1]) * GAP_DFAC; + } + else { + delta_time = gtd->tot_time + (((float)(gps->inittime - gtd->inittime)) - gtd->tot_time) * GAP_DFAC; + } + gp_timing_data_add_point(gtd, gtd->inittime, delta_time, len_v3v3((bezt - 1)->vec[1], p1)); + } + + /* Second point */ + interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC); + interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC); + + bezt++; + copy_v3_v3(bezt->vec[0], h1); + copy_v3_v3(bezt->vec[1], p2); + copy_v3_v3(bezt->vec[2], h2); + bezt->h1 = bezt->h2 = HD_FREE; + bezt->f1 = bezt->f2 = bezt->f3 = SELECT; + minmax_weights[0] = bezt->radius = bezt->weight = 0.0f; + + if (do_gtd) { + /* This negative delta_time marks the gap! */ + if (tot > 1) { + delta_time = ((gps->points + 1)->time - gps->points->time) * -GAP_DFAC; + } + else { + delta_time = -(((float)(gps->inittime - gtd->inittime)) - gtd->tot_time) * GAP_DFAC; + } + gp_timing_data_add_point(gtd, gps->inittime, delta_time, len_v3v3(p1, p2)); + } + + old_nbezt += 2; + copy_v3_v3(p3d_prev, p2); + } + } + if (old_nbezt && do_gtd) { + prev_bezt = nu->bezt + old_nbezt - 1; + } /* add points */ - for (i = 0, bezt = nu->bezt; i < tot; i++, pt++, bezt++) { + for (i = stitch ? 1 : 0, bezt = nu->bezt + old_nbezt; i < tot; i++, pt++, bezt++) { float h1[3], h2[3]; - - if (i) interp_v3_v3v3(h1, p3d_cur, p3d_prev, 0.3); - else interp_v3_v3v3(h1, p3d_cur, p3d_next, -0.3); - - if (i < tot - 1) interp_v3_v3v3(h2, p3d_cur, p3d_next, 0.3); - else interp_v3_v3v3(h2, p3d_cur, p3d_prev, -0.3); - + float width = pt->pressure * gpl->thickness * WIDTH_CORR_FAC; + + if (i || old_nbezt) { + interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC); + } + else { + interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC); + } + + if (i < tot - 1) { + interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC); + } + else { + interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC); + } + copy_v3_v3(bezt->vec[0], h1); copy_v3_v3(bezt->vec[1], p3d_cur); copy_v3_v3(bezt->vec[2], h2); - + /* set settings */ bezt->h1 = bezt->h2 = HD_FREE; bezt->f1 = bezt->f2 = bezt->f3 = SELECT; - bezt->radius = bezt->weight = pt->pressure * gpl->thickness * 0.1f; - + bezt->radius = width * rad_fac; + bezt->weight = width; + CLAMP(bezt->weight, 0.0f, 1.0f); + if (bezt->weight < minmax_weights[0]) { + minmax_weights[0] = bezt->weight; + } + else if (bezt->weight > minmax_weights[1]) { + minmax_weights[1] = bezt->weight; + } + + /* Update timing data */ + if (do_gtd) { + gp_timing_data_add_point(gtd, gps->inittime, pt->time, prev_bezt ? len_v3v3(prev_bezt->vec[1], p3d_cur) : 0.0f); + } + /* shift coord vects */ copy_v3_v3(p3d_prev, p3d_cur); copy_v3_v3(p3d_cur, p3d_next); - + if (i + 2 < tot) { gp_strokepoint_convertcoords(C, gps, pt + 2, p3d_next, subrect); } + + prev_bezt = bezt; } /* must calculate handles or else we crash */ BKE_nurb_handles_calc(nu); - /* add nurb to curve */ - BLI_addtail(&cu->nurb, nu); + if (!curnu || !*curnu) { + BLI_addtail(&cu->nurb, nu); + } + if (curnu) { + *curnu = nu; + } +} + +#undef GAP_DFAC +#undef WIDTH_CORR_FAC +#undef BEZT_HANDLE_FAC + +static void gp_stroke_finalize_curve_endpoints(Curve *cu) +{ + Nurb *nu = cu->nurb.first; + int i = 0; + if (nu->bezt) { + BezTriple *bezt = nu->bezt; + if (bezt) { + bezt[i].weight = bezt[i].radius = 0.0f; + } + } + else if (nu->bp) { + BPoint *bp = nu->bp; + if (bp) { + bp[i].weight = bp[i].radius = 0.0f; + } + } + + nu = cu->nurb.last; + i = nu->pntsu - 1; + if (nu->bezt) { + BezTriple *bezt = nu->bezt; + if (bezt) { + bezt[i].weight = bezt[i].radius = 0.0f; + } + } + else if (nu->bp) { + BPoint *bp = nu->bp; + if (bp) { + bp[i].weight = bp[i].radius = 0.0f; + } + } +} + +static void gp_stroke_norm_curve_weights(Curve *cu, float minmax_weights[2]) +{ + Nurb *nu; + const float delta = minmax_weights[0]; + const float fac = 1.0f / (minmax_weights[1] - delta); + int i; + + for (nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->bezt) { + BezTriple *bezt = nu->bezt; + for (i = 0; i < nu->pntsu; i++, bezt++) { + bezt->weight = (bezt->weight - delta) * fac; + } + } + else if (nu->bp) { + BPoint *bp = nu->bp; + for (i = 0; i < nu->pntsu; i++, bp++) { + bp->weight = (bp->weight - delta) * fac; + } + } + } } /* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */ -static void gp_layer_to_curve(bContext *C, bGPdata *gpd, bGPDlayer *gpl, short mode) +static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, int mode, + int norm_weights, float rad_fac, int link_strokes, tGpTimingData *gtd) { Scene *scene = CTX_data_scene(C); bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0); - bGPDstroke *gps; + bGPDstroke *gps, *prev_gps = NULL; Object *ob; Curve *cu; + Nurb *nu = NULL; + Base *base = BASACT, *newbase = NULL; + float minmax_weights[2] = {1.0f, 0.0f}; /* camera framing */ rctf subrect, *subrect_ptr = NULL; @@ -574,7 +1273,7 @@ static void gp_layer_to_curve(bContext *C, bGPdata *gpd, bGPDlayer *gpl, short m /* error checking */ if (ELEM3(NULL, gpd, gpl, gpf)) return; - + /* only convert if there are any strokes on this layer's frame to convert */ if (gpf->strokes.first == NULL) return; @@ -592,29 +1291,116 @@ static void gp_layer_to_curve(bContext *C, bGPdata *gpd, bGPDlayer *gpl, short m zero_v3(ob->rot); cu = ob->data; cu->flag |= CU_3D; - + /* rename object and curve to layer name */ rename_id((ID *)ob, gpl->info); rename_id((ID *)cu, gpl->info); - + + gtd->inittime = ((bGPDstroke*)gpf->strokes.first)->inittime; + /* add points to curve */ for (gps = gpf->strokes.first; gps; gps = gps->next) { + /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached, + * and stitch them to previous one. + */ + int stitch = FALSE; + if (prev_gps) { + bGPDspoint *pt1 = prev_gps->points + prev_gps->totpoints - 1; + bGPDspoint *pt2 = gps->points; + if (pt1->x == pt2->x && pt1->y == pt2->y) + stitch = TRUE; + } + /* Decide whether we connect this stroke to previous one */ + if (!(stitch || link_strokes)) + nu = NULL; switch (mode) { case GP_STROKECONVERT_PATH: - gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr); + gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch, gtd); break; case GP_STROKECONVERT_CURVE: - gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr); + gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch, gtd); break; default: BLI_assert(!"invalid mode"); break; } + prev_gps = gps; } + + /* If link_strokes, be sure first and last points have a zero weight/size! */ + if (link_strokes) + gp_stroke_finalize_curve_endpoints(cu); + + /* Update curve's weights, if needed */ + if (norm_weights && (minmax_weights[0] > 0.0f || minmax_weights[1] < 1.0f)) + gp_stroke_norm_curve_weights(cu, minmax_weights); + + /* Create the path animation, if needed */ + gp_stroke_path_animation(C, reports, cu, gtd); + + /* Reset org object as active, else we can't edit operator's settings!!! */ + /* set layers OK */ + newbase = BASACT; + newbase->lay = base->lay; + ob->lay = newbase->lay; + /* restore, BKE_object_add sets active */ + BASACT = base; + base->flag |= SELECT; } /* --- */ +/* Check a GP layer has valid timing data! Else, most timing options are hidden in the operator. + * op may be NULL. + */ +static int gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0); + bGPDstroke *gps = gpf->strokes.first; + bGPDspoint *pt; + double base_time, cur_time, prev_time = -1.0; + int i, valid = TRUE; + + do { + base_time = cur_time = gps->inittime; + if (cur_time <= prev_time) { + valid = FALSE; + break; + } + prev_time = cur_time; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + cur_time = base_time + (double)pt->time; + /* First point of a stroke should have the same time as stroke's inittime, + * so it's the only case where equality is allowed! + */ + if ((i && cur_time <= prev_time) || (cur_time < prev_time)) { + valid = FALSE; + break; + } + prev_time = cur_time; + } + if (!valid) { + break; + } + } while ((gps = gps->next)); + + if (op) { + RNA_boolean_set(op->ptr, "use_timing_data", valid); + } + return valid; +} + +/* Check end_frame is always > start frame! */ +static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UNUSED(scene), struct PointerRNA *ptr) +{ + int start_frame = RNA_int_get(ptr, "start_frame"); + int end_frame = RNA_int_get(ptr, "end_frame"); + if (end_frame <= start_frame) { + RNA_int_set(ptr, "end_frame", start_frame + 1); + } +} + static int gp_convert_poll(bContext *C) { bGPdata *gpd = gpencil_data_get_active(C); @@ -627,10 +1413,16 @@ static int gp_convert_poll(bContext *C) static int gp_convert_layer_exec(bContext *C, wmOperator *op) { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data"); bGPdata *gpd = gpencil_data_get_active(C); bGPDlayer *gpl = gpencil_layer_getactive(gpd); Scene *scene = CTX_data_scene(C); int mode = RNA_enum_get(op->ptr, "type"); + int norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights"); + float rad_fac = RNA_float_get(op->ptr, "radius_multiplier"); + int link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes"); + int valid_timing; + tGpTimingData gtd; /* check if there's data to work with */ if (gpd == NULL) { @@ -638,7 +1430,36 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - gp_layer_to_curve(C, gpd, gpl, mode); + if (!RNA_property_is_set(op->ptr, prop) && !gp_convert_check_has_valid_timing(C, gpl, op)) { + BKE_report(op->reports, RPT_WARNING, + "Current grease pencil strokes have no valid timing data, most timing options will be hidden!"); + } + valid_timing = RNA_property_boolean_get(op->ptr, prop); + + gtd.mode = RNA_enum_get(op->ptr, "timing_mode"); + /* Check for illegal timing mode! */ + if (!valid_timing && !ELEM(gtd.mode, GP_STROKECONVERT_TIMING_NONE, GP_STROKECONVERT_TIMING_LINEAR)) { + gtd.mode = GP_STROKECONVERT_TIMING_LINEAR; + RNA_enum_set(op->ptr, "timing_mode", gtd.mode); + } + if (!link_strokes) { + gtd.mode = GP_STROKECONVERT_TIMING_NONE; + } + + gtd.frame_range = RNA_int_get(op->ptr, "frame_range"); + gtd.start_frame = RNA_int_get(op->ptr, "start_frame"); + gtd.realtime = valid_timing ? RNA_boolean_get(op->ptr, "use_realtime") : FALSE; + gtd.end_frame = RNA_int_get(op->ptr, "end_frame"); + gtd.gap_duration = RNA_float_get(op->ptr, "gap_duration"); + gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness"); + gtd.gap_randomness = min_ff(gtd.gap_randomness, gtd.gap_duration); + gtd.seed = RNA_int_get(op->ptr, "seed"); + gtd.num_points = gtd.cur_point = 0; + gtd.dists = gtd.times = NULL; + gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f; + gtd.inittime = 0.0; + + gp_layer_to_curve(C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, >d); /* notifiers */ WM_event_add_notifier(C, NC_OBJECT | NA_ADDED, NULL); @@ -648,24 +1469,131 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + int link_strokes = RNA_boolean_get(ptr, "use_link_strokes"); + int timing_mode = RNA_enum_get(ptr, "timing_mode"); + int realtime = RNA_boolean_get(ptr, "use_realtime"); + float gap_duration = RNA_float_get(ptr, "gap_duration"); + float gap_randomness = RNA_float_get(ptr, "gap_randomness"); + int valid_timing = RNA_boolean_get(ptr, "use_timing_data"); + + /* Always show those props */ + if (strcmp(prop_id, "type") == 0 || + strcmp(prop_id, "use_normalize_weights") == 0 || + strcmp(prop_id, "radius_multiplier") == 0 || + strcmp(prop_id, "use_link_strokes") == 0) + { + return TRUE; + } + + /* Never show this prop */ + if (strcmp(prop_id, "use_timing_data") == 0) + return FALSE; + + if (link_strokes) { + /* Only show when link_stroke is TRUE */ + if (strcmp(prop_id, "timing_mode") == 0) + return TRUE; + + if (timing_mode != GP_STROKECONVERT_TIMING_NONE) { + /* Only show when link_stroke is TRUE and stroke timing is enabled */ + if (strcmp(prop_id, "frame_range") == 0 || + strcmp(prop_id, "start_frame") == 0) + { + return TRUE; + } + + /* Only show if we have valid timing data! */ + if (valid_timing && strcmp(prop_id, "use_realtime") == 0) + return TRUE; + + /* Only show if realtime or valid_timing is FALSE! */ + if ((!realtime || !valid_timing) && strcmp(prop_id, "end_frame") == 0) + return TRUE; + + if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { + /* Only show for custom gaps! */ + if (strcmp(prop_id, "gap_duration") == 0) + return TRUE; + + /* Only show randomness for non-null custom gaps! */ + if (strcmp(prop_id, "gap_randomness") == 0 && gap_duration > 0.0f) + return TRUE; + + /* Only show seed for randomize action! */ + if (strcmp(prop_id, "seed") == 0 && gap_duration > 0.0f && gap_randomness > 0.0f) + return TRUE; + } + } + } + + /* Else, hidden! */ + return FALSE; +} + +static void gp_convert_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + /* Main auto-draw call */ + uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, '\0'); +} + void GPENCIL_OT_convert(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Convert Grease Pencil"; ot->idname = "GPENCIL_OT_convert"; - ot->description = "Convert the active Grease Pencil layer to a new Object"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->description = "Convert the active Grease Pencil layer to a new Curve Object"; /* callbacks */ ot->invoke = WM_menu_invoke; ot->exec = gp_convert_layer_exec; ot->poll = gp_convert_poll; + ot->ui = gp_convert_ui; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to"); + RNA_def_boolean(ot->srna, "use_normalize_weights", TRUE, "Normalize Weight", + "Normalize weight (set from stroke width)"); + RNA_def_float(ot->srna, "radius_multiplier", 1.0f, 0.0f, 1000.0f, "Radius Fac", + "Multiplier for the points' radii (set from stroke width)", 0.0f, 10.0f); + RNA_def_boolean(ot->srna, "use_link_strokes", TRUE, "Link Strokes", + "Whether to link strokes with zero-radius sections of curves"); + prop = RNA_def_enum(ot->srna, "timing_mode", prop_gpencil_convert_timingmodes, GP_STROKECONVERT_TIMING_FULL, + "Timing Mode", "How to use timing data stored in strokes"); + RNA_def_enum_funcs(prop, rna_GPConvert_mode_items); + RNA_def_int(ot->srna, "frame_range", 100, 1, 10000, "Frame Range", + "The duration of evaluation of the path control curve", 1, 1000); + RNA_def_int(ot->srna, "start_frame", 1, 1, 100000, "Start Frame", + "The start frame of the path control curve", 1, 100000); + RNA_def_boolean(ot->srna, "use_realtime", FALSE, "Realtime", + "Whether the path control curve reproduces the drawing in realtime, starting from Start Frame"); + prop = RNA_def_int(ot->srna, "end_frame", 250, 1, 100000, "End Frame", + "The end frame of the path control curve (if Realtime is not set)", 1, 100000); + RNA_def_property_update_runtime(prop, gp_convert_set_end_frame); + RNA_def_float(ot->srna, "gap_duration", 0.0f, 0.0f, 10000.0f, "Gap Duration", + "Custom Gap mode: (Average) length of gaps, in frames " + "(note: realtime value, will be scaled if Realtime is not set)", 0.0f, 1000.0f); + RNA_def_float(ot->srna, "gap_randomness", 0.0f, 0.0f, 10000.0f, "Gap Randomness", + "Custom Gap mode: Number of frames that gap lengths can vary", 0.0f, 1000.0f); + RNA_def_int(ot->srna, "seed", 0, 0, 1000, "Random Seed", + "Custom Gap mode: Random generator seed", 0, 100); + /* Note: Internal use, this one will always be hidden by UI code... */ + prop = RNA_def_boolean(ot->srna, "use_timing_data", FALSE, "Has Valid Timing", + "Whether the converted grease pencil layer has valid timing data (internal use)"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* ************************************************ */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 9bfd89075af..fcead283033 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -39,6 +39,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "PIL_time.h" + #include "BKE_gpencil.h" #include "BKE_context.h" #include "BKE_global.h" @@ -99,6 +101,14 @@ typedef struct tGPsdata { short radius; /* radius of influence for eraser */ short flags; /* flags that can get set during runtime */ + /* Those needs to be doubles, as (at least under unix) they are in seconds since epoch, + * float (and its 7 digits precision) is definitively not enough here! + * double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least. + */ + double inittime; /* Used when converting to path */ + double curtime; /* Used when converting to path */ + double ocurtime; /* Used when converting to path */ + float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space * to region space */ @@ -201,7 +211,7 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3]) float *fp = give_cursor(p->scene, v3d); /* the reference point used depends on the owner... */ -#if 0 // XXX: disabled for now, since we can't draw relative to the owner yet +#if 0 /* XXX: disabled for now, since we can't draw relative to the owner yet */ if (p->ownerPtr.type == &RNA_Object) { Object *ob = (Object *)p->ownerPtr.data; @@ -249,7 +259,7 @@ static short gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2]) } /* convert screen-coordinates to buffer-coordinates */ -// XXX this method needs a total overhaul! +/* XXX this method needs a total overhaul! */ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth) { bGPdata *gpd = p->gpd; @@ -310,7 +320,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] } /* add current stroke-point to buffer (returns whether point was successfully added) */ -static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure) +static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, double curtime) { bGPdata *gpd = p->gpd; tGPspoint *pt; @@ -325,6 +335,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure) /* store settings */ copy_v2_v2_int(&pt->x, mval); pt->pressure = pressure; + pt->time = (float)(curtime - p->inittime); /* increment buffer size */ gpd->sbuffer_size++; @@ -338,6 +349,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure) /* store settings */ copy_v2_v2_int(&pt->x, mval); pt->pressure = pressure; + pt->time = (float)(curtime - p->inittime); /* if this is just the second point we've added, increment the buffer size * so that it will be drawn properly... @@ -361,6 +373,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure) /* store settings */ copy_v2_v2_int(&pt->x, mval); pt->pressure = pressure; + pt->time = (float)(curtime - p->inittime); /* increment counters */ gpd->sbuffer_size++; @@ -378,10 +391,11 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure) /* store settings */ copy_v2_v2_int(&pt->x, mval); pt->pressure = pressure; + pt->time = (float)(curtime - p->inittime); /* if there's stroke for this poly line session add (or replace last) point * to stroke. This allows to draw lines more interactively (see new segment - * during mouse slide, i.e.) + * during mouse slide, e.g.) */ if (gp_stroke_added_check(p)) { bGPDstroke *gps = p->gpf->strokes.last; @@ -410,8 +424,9 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure) /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL); - /* copy pressure */ + /* copy pressure and time */ pts->pressure = pt->pressure; + pts->time = pt->time; } /* increment counters */ @@ -425,18 +440,11 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure) return GP_STROKEADD_INVALID; } - -/* temp struct for gp_stroke_smooth() */ -typedef struct tGpSmoothCo { - int x; - int y; -} tGpSmoothCo; - /* smooth a stroke (in buffer) before storing it */ static void gp_stroke_smooth(tGPsdata *p) { bGPdata *gpd = p->gpd; - tGpSmoothCo *smoothArray, *spc; + tGPspoint *spt, tmp_spt[3]; int i = 0, cmx = gpd->sbuffer_size; /* only smooth if smoothing is enabled, and we're not doing a straight line */ @@ -447,30 +455,26 @@ static void gp_stroke_smooth(tGPsdata *p) if ((cmx <= 2) || (gpd->sbuffer == NULL)) return; - /* create a temporary smoothing coordinates buffer, use to store calculated values to prevent sequential error */ - smoothArray = MEM_callocN(sizeof(tGpSmoothCo) * cmx, "gp_stroke_smooth smoothArray"); - - /* first pass: calculate smoothing coordinates using weighted-averages */ - for (i = 0, spc = smoothArray; i < gpd->sbuffer_size; i++, spc++) { - const tGPspoint *pc = (((tGPspoint *)gpd->sbuffer) + i); - const tGPspoint *pb = (i - 1 > 0) ? (pc - 1) : (pc); - const tGPspoint *pa = (i - 2 > 0) ? (pc - 2) : (pb); - const tGPspoint *pd = (i + 1 < cmx) ? (pc + 1) : (pc); + /* Calculate smoothing coordinates using weighted-averages */ + /* XXX DO NOT smooth first and last points! */ + spt = (tGPspoint *)gpd->sbuffer; + /* This small array stores the last two points' org coordinates, we don't want to use already averaged ones! + * Note it is used as a cyclic buffer... + */ + tmp_spt[0] = *spt; + for (i = 1, spt++; i < cmx - 1; i++, spt++) { + const tGPspoint *pc = spt; + const tGPspoint *pb = &tmp_spt[(i - 1) % 3]; + const tGPspoint *pa = (i - 1 > 0) ? (&tmp_spt[(i - 2) % 3]) : (pb); + const tGPspoint *pd = pc + 1; const tGPspoint *pe = (i + 2 < cmx) ? (pc + 2) : (pd); - spc->x = (int)(0.1 * pa->x + 0.2 * pb->x + 0.4 * pc->x + 0.2 * pd->x + 0.1 * pe->x); - spc->y = (int)(0.1 * pa->y + 0.2 * pb->y + 0.4 * pc->y + 0.2 * pd->y + 0.1 * pe->y); - } - - /* second pass: apply smoothed coordinates */ - for (i = 0, spc = smoothArray; i < gpd->sbuffer_size; i++, spc++) { - tGPspoint *pc = (((tGPspoint *)gpd->sbuffer) + i); + /* Store current point's org state for the two next points! */ + tmp_spt[i % 3] = *spt; - copy_v2_v2_int(&pc->x, &spc->x); + spt->x = (int)(0.1 * pa->x + 0.2 * pb->x + 0.4 * pc->x + 0.2 * pd->x + 0.1 * pe->x); + spt->y = (int)(0.1 * pa->y + 0.2 * pb->y + 0.4 * pc->y + 0.2 * pd->y + 0.1 * pe->y); } - - /* free temp array */ - MEM_freeN(smoothArray); } /* simplify a stroke (in buffer) before storing it @@ -492,7 +496,7 @@ static void gp_stroke_simplify(tGPsdata *p) /* don't simplify if less than 4 points in buffer */ if ((num_points <= 4) || (old_points == NULL)) return; - + /* clear buffer (but don't free mem yet) so that we can write to it * - firstly set sbuffer to NULL, so a new one is allocated * - secondly, reset flag after, as it gets cleared auto @@ -509,17 +513,21 @@ static void gp_stroke_simplify(tGPsdata *p) co[0] += (float)(old_points[offs].x * sfac); \ co[1] += (float)(old_points[offs].y * sfac); \ pressure += old_points[offs].pressure * sfac; \ + time += old_points[offs].time * sfac; \ } (void)0 + /* XXX Here too, do not lose start and end points! */ + gp_stroke_addpoint(p, &old_points->x, old_points->pressure, p->inittime + (double)old_points->time); for (i = 0, j = 0; i < num_points; i++) { if (i - j == 3) { - float co[2], pressure; + float co[2], pressure, time; int mco[2]; /* initialize values */ - co[0] = 0; - co[1] = 0; - pressure = 0; + co[0] = 0.0f; + co[1] = 0.0f; + pressure = 0.0f; + time = 0.0f; /* using macro, calculate new point */ GP_SIMPLIFY_AVPOINT(j, -0.25f); @@ -532,11 +540,13 @@ static void gp_stroke_simplify(tGPsdata *p) mco[1] = (int)co[1]; /* ignore return values on this... assume to be ok for now */ - gp_stroke_addpoint(p, mco, pressure); + gp_stroke_addpoint(p, mco, pressure, p->inittime + (double)time); j += 2; } } + gp_stroke_addpoint(p, &old_points[num_points - 1].x, old_points[num_points - 1].pressure, + p->inittime + (double)old_points[num_points - 1].time); /* free old buffer */ MEM_freeN(old_points); @@ -571,7 +581,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* special case for poly line -- for already added stroke during session * coordinates are getting added to stroke immediately to allow more - * interactive behavior */ + * interactive behavior + */ if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { if (gp_stroke_added_check(p)) { return; @@ -585,6 +596,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) gps->totpoints = totelem; gps->thickness = p->gpl->thickness; gps->flag = gpd->sbuffer_sflag; + gps->inittime = p->inittime; /* allocate enough memory for a continuous array for storage points */ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); @@ -602,8 +614,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - /* copy pressure */ + /* copy pressure and time */ pt->pressure = ptc->pressure; + pt->time = ptc->time; pt++; } @@ -615,8 +628,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - /* copy pressure */ + /* copy pressure and time */ pt->pressure = ptc->pressure; + pt->time = ptc->time; } } else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { @@ -626,8 +640,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - /* copy pressure */ + /* copy pressure and time */ pt->pressure = ptc->pressure; + pt->time = ptc->time; } else { float *depth_arr = NULL; @@ -699,8 +714,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); - /* copy pressure */ + /* copy pressure and time */ pt->pressure = ptc->pressure; + pt->time = ptc->time; } if (depth_arr) @@ -750,6 +766,25 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i) gps->totpoints--; gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint) * gps->totpoints); + + /* We must adjust timings! + * Each point's timing data is a delta from stroke's inittime, so as we erase the first + * point of the stroke, we have to offset this inittime and all remaing points' delta values. + * This way we get a new stroke with exactly the same timing as if user had started drawing from + * the second point... + */ + { + bGPDspoint *pts; + float delta = pt_tmp[1].time; + int j; + + gps->inittime += delta; + + pts = gps->points; + for (j = 0; j < gps->totpoints; j++, pts++) { + pts->time -= delta; + } + } /* free temp buffer */ MEM_freeN(pt_tmp); @@ -769,6 +804,25 @@ static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i) gsn->points = MEM_callocN(sizeof(bGPDspoint) * gsn->totpoints, "gp_stroke_points"); memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint) * gsn->totpoints); + /* We must adjust timings of this new stroke! + * Each point's timing data is a delta from stroke's inittime, so as we erase the first + * point of the stroke, we have to offset this inittime and all remaing points' delta values. + * This way we get a new stroke with exactly the same timing as if user had started drawing from + * the second point... + */ + { + bGPDspoint *pts; + float delta = pt_tmp[i].time; + int j; + + gsn->inittime += delta; + + pts = gsn->points; + for (j = 0; j < gsn->totpoints; j++, pts++) { + pts->time -= delta; + } + } + /* adjust existing stroke */ gps->totpoints = i; gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); @@ -831,7 +885,7 @@ static void gp_point_to_xy(ARegion *ar, View2D *v2d, rctf *subrect, bGPDstroke * /* eraser tool - evaluation per stroke */ -// TODO: this could really do with some optimization (KD-Tree/BVH?) +/* TODO: this could really do with some optimization (KD-Tree/BVH?) */ static void gp_stroke_eraser_dostroke(tGPsdata *p, const int mval[], const int mvalo[], short rad, const rcti *rect, bGPDframe *gpf, bGPDstroke *gps) @@ -919,11 +973,11 @@ static void gp_session_validatebuffer(tGPsdata *p) /* clear memory of buffer (or allocate it if starting a new session) */ if (gpd->sbuffer) { - //printf("\t\tGP - reset sbuffer\n"); + /* printf("\t\tGP - reset sbuffer\n"); */ memset(gpd->sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX); } else { - //printf("\t\tGP - allocate sbuffer\n"); + /* printf("\t\tGP - allocate sbuffer\n"); */ gpd->sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer"); } @@ -932,6 +986,9 @@ static void gp_session_validatebuffer(tGPsdata *p) /* reset flags */ gpd->sbuffer_sflag = 0; + + /* reset inittime */ + p->inittime = 0.0; } /* (re)init new painting data */ @@ -959,8 +1016,8 @@ static int gp_session_initdata(bContext *C, tGPsdata *p) /* supported views first */ case SPACE_VIEW3D: { - // View3D *v3d = curarea->spacedata.first; - // RegionView3D *rv3d = ar->regiondata; + /* View3D *v3d = curarea->spacedata.first; */ + /* RegionView3D *rv3d = ar->regiondata; */ /* set current area * - must verify that region data is 3D-view (and not something else) @@ -979,7 +1036,7 @@ static int gp_session_initdata(bContext *C, tGPsdata *p) case SPACE_NODE: { - //SpaceNode *snode = curarea->spacedata.first; + /* SpaceNode *snode = curarea->spacedata.first; */ /* set current area */ p->sa = curarea; @@ -1007,7 +1064,7 @@ static int gp_session_initdata(bContext *C, tGPsdata *p) break; case SPACE_IMAGE: { - //SpaceImage *sima = curarea->spacedata.first; + /* SpaceImage *sima = curarea->spacedata.first; */ /* set the current area */ p->sa = curarea; @@ -1072,7 +1129,8 @@ static int gp_session_initdata(bContext *C, tGPsdata *p) if (ED_gpencil_session_active() == 0) { /* initialize undo stack, - * also, existing undo stack would make buffer drawn */ + * also, existing undo stack would make buffer drawn + */ gpencil_undo_init(p->gpd); } @@ -1107,7 +1165,7 @@ static void gp_session_cleanup(tGPsdata *p) /* free stroke buffer */ if (gpd->sbuffer) { - //printf("\t\tGP - free sbuffer\n"); + /* printf("\t\tGP - free sbuffer\n"); */ MEM_freeN(gpd->sbuffer); gpd->sbuffer = NULL; } @@ -1115,6 +1173,7 @@ static void gp_session_cleanup(tGPsdata *p) /* clear flags */ gpd->sbuffer_size = 0; gpd->sbuffer_sflag = 0; + p->inittime = 0.0; } /* init new stroke */ @@ -1259,7 +1318,8 @@ static void gp_paint_strokeend(tGPsdata *p) static void gp_paint_cleanup(tGPsdata *p) { /* p->gpd==NULL happens when stroke failed to initialize, - * for example. when GP is hidden in current space (sergey) */ + * for example when GP is hidden in current space (sergey) + */ if (p->gpd) { /* finish off a stroke */ gp_paint_strokeend(p); @@ -1307,7 +1367,7 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en else if (enable) { /* enable cursor */ p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C), - NULL, // XXX + NULL, /* XXX */ gpencil_draw_eraser, p); } } @@ -1448,16 +1508,26 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p) /* only add current point to buffer if mouse moved (even though we got an event, it might be just noise) */ else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) { /* try to add point */ - short ok = gp_stroke_addpoint(p, p->mval, p->pressure); + short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); /* handle errors while adding point */ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) { /* finish off old stroke */ gp_paint_strokeend(p); + /* And start a new one!!! Else, projection errors! */ + gp_paint_initstroke(p, p->paintmode); /* start a new stroke, starting from previous point */ - gp_stroke_addpoint(p, p->mvalo, p->opressure); - gp_stroke_addpoint(p, p->mval, p->pressure); + /* XXX Must manually reset inittime... */ + /* XXX We only need to reuse previous point if overflow! */ + if (ok == GP_STROKEADD_OVERFLOW) { + p->inittime = p->ocurtime; + gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime); + } + else { + p->inittime = p->curtime; + } + gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); } else if (ok == GP_STROKEADD_INVALID) { /* the painting operation cannot continue... */ @@ -1473,6 +1543,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p) p->mvalo[0] = p->mval[0]; p->mvalo[1] = p->mval[1]; p->opressure = p->pressure; + p->ocurtime = p->curtime; } } @@ -1485,10 +1556,11 @@ static void gpencil_draw_apply_event(wmOperator *op, wmEvent *event) int tablet = 0; /* convert from window-space to area-space mouse coordinates - * NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding... + * NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding... */ p->mval[0] = event->mval[0] + 1; p->mval[1] = event->mval[1] + 1; + p->curtime = PIL_check_seconds_timer(); /* handle pressure sensitivity (which is supplied by tablets) */ if (event->custom == EVT_DATA_TABLET) { @@ -1497,8 +1569,8 @@ static void gpencil_draw_apply_event(wmOperator *op, wmEvent *event) tablet = (wmtab->Active != EVT_TABLET_NONE); p->pressure = wmtab->Pressure; - //if (wmtab->Active == EVT_TABLET_ERASER) - // TODO... this should get caught by the keymaps which call drawing in the first place + /* if (wmtab->Active == EVT_TABLET_ERASER) */ + /* TODO... this should get caught by the keymaps which call drawing in the first place */ } else p->pressure = 1.0f; @@ -1519,14 +1591,17 @@ static void gpencil_draw_apply_event(wmOperator *op, wmEvent *event) p->mvalo[0] = p->mval[0]; p->mvalo[1] = p->mval[1]; p->opressure = p->pressure; - + p->inittime = p->ocurtime = p->curtime; + /* special exception here for too high pressure values on first touch in - * windows for some tablets, then we just skip first touch .. + * windows for some tablets, then we just skip first touch... */ if (tablet && (p->pressure >= 0.99f)) return; } + RNA_float_set(&itemptr, "time", p->curtime - p->inittime); + /* apply the current latest drawing point */ gpencil_draw_apply(op, p); @@ -1541,18 +1616,18 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) { tGPsdata *p = NULL; - //printf("GPencil - Starting Re-Drawing\n"); + /* printf("GPencil - Starting Re-Drawing\n"); */ /* try to initialize context data needed while drawing */ if (!gpencil_draw_init(C, op)) { if (op->customdata) MEM_freeN(op->customdata); - //printf("\tGP - no valid data\n"); + /* printf("\tGP - no valid data\n"); */ return OPERATOR_CANCELLED; } else p = op->customdata; - //printf("\tGP - Start redrawing stroke\n"); + /* printf("\tGP - Start redrawing stroke\n"); */ /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement), * setting the relevant values in context at each step, then applying @@ -1561,20 +1636,21 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) { float mousef[2]; - //printf("\t\tGP - stroke elem\n"); + /* printf("\t\tGP - stroke elem\n"); */ /* get relevant data for this point from stroke */ RNA_float_get_array(&itemptr, "mouse", mousef); p->mval[0] = (int)mousef[0]; p->mval[1] = (int)mousef[1]; p->pressure = RNA_float_get(&itemptr, "pressure"); + p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime; if (RNA_boolean_get(&itemptr, "is_start")) { /* if first-run flag isn't set already (i.e. not true first stroke), * then we must terminate the previous one first before continuing */ if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) { - // TODO: both of these ops can set error-status, but we probably don't need to worry + /* TODO: both of these ops can set error-status, but we probably don't need to worry */ gp_paint_strokeend(p); gp_paint_initstroke(p, p->paintmode); } @@ -1587,6 +1663,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) p->mvalo[0] = p->mval[0]; p->mvalo[1] = p->mval[1]; p->opressure = p->pressure; + p->ocurtime = p->curtime; } /* apply this data as necessary now (as per usual) */ @@ -1594,7 +1671,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) } RNA_END; - //printf("\tGP - done\n"); + /* printf("\tGP - done\n"); */ /* cleanup */ gpencil_draw_exit(C, op); @@ -1640,7 +1717,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, wmEvent *event) /* set cursor */ if (p->paintmode == GP_PAINTMODE_ERASER) - WM_cursor_modal(win, BC_CROSSCURSOR); // XXX need a better cursor + WM_cursor_modal(win, BC_CROSSCURSOR); /* XXX need a better cursor */ else WM_cursor_modal(win, BC_PAINTBRUSHCURSOR); @@ -1650,7 +1727,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, wmEvent *event) */ if (event->val == KM_PRESS) { /* hotkey invoked - start drawing */ - //printf("\tGP - set first spot\n"); + /* printf("\tGP - set first spot\n"); */ p->status = GP_STATUS_PAINTING; /* handle the initial drawing - i.e. for just doing a simple dot */ @@ -1658,7 +1735,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, wmEvent *event) } else { /* toolbar invoked - don't start drawing yet... */ - //printf("\tGP - hotkey invoked... waiting for click-drag\n"); + /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */ } WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); @@ -1686,7 +1763,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) p->status = GP_STATUS_ERROR; } - //printf("\t\tGP - start stroke\n"); + /* printf("\t\tGP - start stroke\n"); */ /* we may need to set up paint env again if we're resuming */ /* XXX: watch it with the paintmode! in future, @@ -1723,7 +1800,7 @@ static void gpencil_stroke_end(wmOperator *op) static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) { tGPsdata *p = op->customdata; - int estate = OPERATOR_RUNNING_MODAL; /* default exit state - we don't pass on events, GP is used with key-modifiers */ + int estate = OPERATOR_PASS_THROUGH; /* default exit state */ /* if (event->type == NDOF_MOTION) * return OPERATOR_PASS_THROUGH; @@ -1735,8 +1812,13 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) * the stroke is converted to 3D only after * it is finished. This approach should work * better in tools that immediately apply - * in 3D space. */ + * in 3D space. + */ + /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */ + if (ISKEYBOARD(event->type)) + estate = OPERATOR_RUNNING_MODAL; + //printf("\tGP - handle modal event...\n"); /* exit painting mode (and/or end current stroke) @@ -1744,7 +1826,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) */ if (ELEM4(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) { /* exit() ends the current stroke before cleaning up */ - //printf("\t\tGP - end of paint op + end of stroke\n"); + /* printf("\t\tGP - end of paint op + end of stroke\n"); */ p->status = GP_STATUS_DONE; estate = OPERATOR_FINISHED; } @@ -1768,7 +1850,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) if (sketch) { /* end stroke only, and then wait to resume painting soon */ - //printf("\t\tGP - end stroke only\n"); + /* printf("\t\tGP - end stroke only\n"); */ gpencil_stroke_end(op); /* we've just entered idling state, so this event was processed (but no others yet) */ @@ -1778,7 +1860,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); } else { - //printf("\t\tGP - end of stroke + op\n"); + /* printf("\t\tGP - end of stroke + op\n"); */ p->status = GP_STATUS_DONE; estate = OPERATOR_FINISHED; } @@ -1801,7 +1883,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) /* handle painting mouse-movements? */ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) { /* handle drawing event */ - //printf("\t\tGP - add point\n"); + /* printf("\t\tGP - add point\n"); */ gpencil_draw_apply_event(op, event); /* finish painting operation if anything went wrong just now */ @@ -1811,7 +1893,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) } else { /* event handled, so just tag as running modal */ - //printf("\t\t\t\tGP - add point handled!\n"); + /* printf("\t\t\t\tGP - add point handled!\n"); */ estate = OPERATOR_RUNNING_MODAL; } } @@ -1822,7 +1904,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event) /* just resize the brush (local version) * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys */ - //printf("\t\tGP - resize eraser\n"); + /* printf("\t\tGP - resize eraser\n"); */ switch (event->type) { case WHEELUPMOUSE: /* larger */ case PADPLUSKEY: diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 1d461f797d6..39dd8822267 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -56,6 +56,7 @@ struct wmKeyConfig; typedef struct tGPspoint { int x, y; /* x and y coordinates of cursor (in relative to area) */ float pressure; /* pressure of tablet at this point */ + float time; /* Time relative to stroke start (used when converting to path) */ } tGPspoint; diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index ed4b4ae027f..3645f13f27a 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -807,7 +807,7 @@ void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *p void uiTemplateWaveform(uiLayout *layout, struct PointerRNA *ptr, const char *propname); void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char *propname); void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, int levels, int brush); -void uiTemplateColorWheel(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic); +void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic); void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *propname, PointerRNA *used_ptr, const char *used_propname, int active_layer); void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *propname, diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 77aa2ce154d..7391d29c9bf 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -218,7 +218,11 @@ enum { TH_NLA_META, TH_NLA_META_SEL, TH_NLA_SOUND, - TH_NLA_SOUND_SEL + TH_NLA_SOUND_SEL, + + TH_AXIS_X, /* X/Y/Z Axis */ + TH_AXIS_Y, + TH_AXIS_Z }; /* XXX WARNING: previous is saved in file, so do not change order! */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index c6e25ab9a34..e2f105b5761 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -2424,7 +2424,7 @@ void uiBlockEndAlign(uiBlock *block) int ui_but_can_align(uiBut *but) { - return !ELEM3(but->type, LABEL, OPTION, OPTIONN); + return !ELEM4(but->type, LABEL, OPTION, OPTIONN, SEPR); } static void ui_block_do_align_but(uiBut *first, short nr) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index ecb161714ee..5f01255b8e0 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -279,12 +279,7 @@ static int ui_is_a_warp_but(uiBut *but) static float ui_mouse_scale_warp_factor(const short shift) { - if (U.uiflag & USER_CONTINUOUS_MOUSE) { - return shift ? 0.05f : 1.0f; - } - else { - return 1.0f; - } + return shift ? 0.05f : 1.0f; } static void ui_mouse_scale_warp(uiHandleButtonData *data, @@ -292,16 +287,11 @@ static void ui_mouse_scale_warp(uiHandleButtonData *data, float *r_mx, float *r_my, const short shift) { - if (U.uiflag & USER_CONTINUOUS_MOUSE) { - const float fac = ui_mouse_scale_warp_factor(shift); - /* slow down the mouse, this is fairly picky */ - *r_mx = (data->dragstartx * (1.0f - fac) + mx * fac); - *r_my = (data->dragstarty * (1.0f - fac) + my * fac); - } - else { - *r_mx = mx; - *r_my = my; - } + const float fac = ui_mouse_scale_warp_factor(shift); + + /* slow down the mouse, this is fairly picky */ + *r_mx = (data->dragstartx * (1.0f - fac) + mx * fac); + *r_my = (data->dragstarty * (1.0f - fac) + my * fac); } /* file selectors are exempt from utf-8 checks */ @@ -6050,38 +6040,22 @@ static int ui_handle_button_event(bContext *C, wmEvent *event, uiBut *but) switch (event->type) { case MOUSEMOVE: { - /* if the mouse is over the button, do nothing */ - if (ui_mouse_inside_button(data->region, but, event->x, event->y)) { - break; - } + uiBut *bt; - /* if the mouse is over the menu, also do nothing */ if (data->menu && data->menu->region) { if (ui_mouse_inside_region(data->menu->region, event->x, event->y)) { break; } - else { - /* make a rectangle between the menu and the button that opened it, - * this avoids any space between them exiting the popup. see [#29072] - campbell */ - rctf rct_all = but->rect; - rctf rct_win; - - ui_block_to_window_fl(ar, block, &rct_all.xmin, &rct_all.ymin); - ui_block_to_window_fl(ar, block, &rct_all.xmax, &rct_all.ymax); - - BLI_rctf_rcti_copy(&rct_win, &data->menu->region->winrct); - BLI_rctf_union(&rct_all, &rct_win); - - if (BLI_rctf_isect_pt(&rct_all, event->x, event->y)) { - break; - } - } } - if (but->type != COLOR) { /* exception */ - data->cancel = TRUE; + bt = ui_but_find_mouse_over(ar, event->x, event->y); + + if (bt && bt->active != data) { + if (but->type != COLOR) { /* exception */ + data->cancel = TRUE; + } + button_activate_state(C, but, BUTTON_STATE_EXIT); } - button_activate_state(C, but, BUTTON_STATE_EXIT); break; } } diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 28e361ccf5a..9b77072dee1 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -2254,13 +2254,11 @@ uiBlock *ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_ show_picker = (but->block->flag & UI_BLOCK_POPUP) == 0; } - uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT); - copy_v3_v3(handle->retvec, but->editvec); uiBlockPicker(block, handle->retvec, &but->rnapoin, but->rnaprop, show_picker); - block->flag = UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_KEEP_OPEN | UI_BLOCK_OUT_1; + block->flag = UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_KEEP_OPEN | UI_BLOCK_OUT_1 | UI_BLOCK_MOVEMOUSE_QUIT; uiBoundsBlock(block, 10); block->block_event_func = ui_picker_small_wheel_cb; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index c7e6a5f2882..68d85aab80f 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1952,11 +1952,12 @@ void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propn MEM_freeN(cb); } -/********************* ColorWheel Template ************************/ +/********************* ColorPicker Template ************************/ #define WHEEL_SIZE 100 -void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic) +/* This template now follows User Preference for type - name is not correct anymore... */ +void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic) { PropertyRNA *prop = RNA_struct_find_property(ptr, propname); uiBlock *block = uiLayoutGetBlock(layout); @@ -1971,10 +1972,24 @@ void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propnam RNA_property_float_ui_range(ptr, prop, &softmin, &softmax, &step, &precision); - col = uiLayoutColumn(layout, FALSE); + col = uiLayoutColumn(layout, TRUE); row = uiLayoutRow(col, TRUE); - but = uiDefButR_prop(block, HSVCIRCLE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, 0, 0, ""); + switch (U.color_picker_type) { + case USER_CP_CIRCLE: + but = uiDefButR_prop(block, HSVCIRCLE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, 0, 0, ""); + break; + case USER_CP_SQUARE_SV: + but = uiDefButR_prop(block, HSVCUBE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, UI_GRAD_SV, 0, ""); + break; + case USER_CP_SQUARE_HS: + but = uiDefButR_prop(block, HSVCUBE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, UI_GRAD_HS, 0, ""); + break; + case USER_CP_SQUARE_HV: + but = uiDefButR_prop(block, HSVCUBE, 0, "", 0, 0, WHEEL_SIZE, WHEEL_SIZE, ptr, prop, -1, 0.0, 0.0, UI_GRAD_HV, 0, ""); + break; + } + if (lock) { but->flag |= UI_BUT_COLOR_LOCK; @@ -1990,10 +2005,29 @@ void uiTemplateColorWheel(uiLayout *layout, PointerRNA *ptr, const char *propnam if (cubic) but->flag |= UI_BUT_COLOR_CUBIC; - uiItemS(row); - if (value_slider) - uiDefButR_prop(block, HSVCUBE, 0, "", WHEEL_SIZE + 6, 0, 14, WHEEL_SIZE, ptr, prop, -1, softmin, softmax, UI_GRAD_V_ALT, 0, ""); + if (value_slider) { + + switch (U.color_picker_type) { + case USER_CP_CIRCLE: + uiItemS(row); + uiDefButR_prop(block, HSVCUBE, 0, "", WHEEL_SIZE + 6, 0, 14, WHEEL_SIZE, ptr, prop, -1, softmin, softmax, UI_GRAD_V_ALT, 0, ""); + break; + case USER_CP_SQUARE_SV: + uiItemS(col); + uiDefButR_prop(block, HSVCUBE, 0, "", 0, 4, WHEEL_SIZE, 18, ptr, prop, -1, softmin, softmax, UI_GRAD_SV + 3, 0, ""); + break; + case USER_CP_SQUARE_HS: + uiItemS(col); + uiDefButR_prop(block, HSVCUBE, 0, "", 0, 4, WHEEL_SIZE, 18, ptr, prop, -1, softmin, softmax, UI_GRAD_HS + 3, 0, ""); + break; + case USER_CP_SQUARE_HV: + uiItemS(col); + uiDefButR_prop(block, HSVCUBE, 0, "", 0, 4, WHEEL_SIZE, 18, ptr, prop, -1, softmin, softmax, UI_GRAD_HV + 3, 0, ""); + break; + } + + } } /********************* Layer Buttons Template ************************/ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index f41abce947e..c836d62021e 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1044,6 +1044,8 @@ static void ui_text_clip_cursor(uiFontStyle *fstyle, uiBut *but, rcti *rect) ui_text_clip_give_prev_off(but); len = strlen(but->drawstr); bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->drawstr, but->drawstr + len)); + if (bytes < 0) + bytes = 1; but->drawstr[len - bytes] = 0; } @@ -2057,7 +2059,7 @@ void ui_draw_gradient(rcti *rect, const float hsv[3], const int type, const floa /* old below */ - for (dx = 0.0f; dx < 1.0f; dx += color_step) { + for (dx = 0.0f; dx < 0.999f; dx += color_step) { /* 0.999 = prevent float inaccuracy for steps */ /* previous color */ copy_v3_v3(col0[0], col1[0]); copy_v3_v3(col0[1], col1[1]); @@ -2112,7 +2114,7 @@ void ui_draw_gradient(rcti *rect, const float hsv[3], const int type, const floa sx1 = rect->xmin + dx * BLI_rcti_size_x(rect); sx2 = rect->xmin + (dx + color_step) * BLI_rcti_size_x(rect); sy = rect->ymin; - dy = BLI_rcti_size_y(rect) / 3.0; + dy = (float)BLI_rcti_size_y(rect) / 3.0f; glBegin(GL_QUADS); for (a = 0; a < 3; a++, sy += dy) { diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index de79a290cb3..d0189e0f5b4 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -236,7 +236,7 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->shade2; break; case TH_HILITE: cp = ts->hilite; break; - + case TH_GRID: cp = ts->grid; break; case TH_WIRE: @@ -514,6 +514,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo case TH_NLA_SOUND_SEL: cp = ts->nla_sound_sel; break; + + case TH_AXIS_X: + cp = btheme->tui.xaxis; break; + case TH_AXIS_Y: + cp = btheme->tui.yaxis; break; + case TH_AXIS_Z: + cp = btheme->tui.zaxis; break; } } } @@ -659,9 +666,14 @@ void ui_theme_init_default(void) /* UI buttons */ ui_widget_color_init(&btheme->tui); + btheme->tui.iconfile[0] = 0; btheme->tui.panel.show_header = FALSE; rgba_char_args_set(btheme->tui.panel.header, 0, 0, 0, 25); + + rgba_char_args_set(btheme->tui.xaxis, 220, 0, 0, 255); + rgba_char_args_set(btheme->tui.yaxis, 0, 220, 0, 255); + rgba_char_args_set(btheme->tui.zaxis, 0, 0, 220, 255); /* Bone Color Sets */ ui_theme_init_boneColorSets(btheme); @@ -1078,7 +1090,6 @@ float UI_GetThemeValuef(int colorid) cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); return ((float)cp[0]); - } /* get individual values, not scaled */ @@ -1088,7 +1099,6 @@ int UI_GetThemeValue(int colorid) cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); return ((int) cp[0]); - } @@ -1250,21 +1260,20 @@ void UI_ThemeClearColor(int colorid) void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3], const char axis) { + unsigned char col[3]; + switch (axis) { case 'X': - dst_col[0] = src_col[0] > 219 ? 255 : src_col[0] + 36; - dst_col[1] = src_col[1] < 26 ? 0 : src_col[1] - 26; - dst_col[2] = src_col[2] < 26 ? 0 : src_col[2] - 26; + UI_GetThemeColor3ubv(TH_AXIS_X, col); + UI_GetColorPtrBlendShade3ubv(src_col, col, dst_col, 0.5f, -10); break; case 'Y': - dst_col[0] = src_col[0] < 46 ? 0 : src_col[0] - 36; - dst_col[1] = src_col[1] > 189 ? 255 : src_col[1] + 66; - dst_col[2] = src_col[2] < 46 ? 0 : src_col[2] - 36; + UI_GetThemeColor3ubv(TH_AXIS_Y, col); + UI_GetColorPtrBlendShade3ubv(src_col, col, dst_col, 0.5f, -10); break; case 'Z': - dst_col[0] = src_col[0] < 26 ? 0 : src_col[0] - 26; - dst_col[1] = src_col[1] < 26 ? 0 : src_col[1] - 26; - dst_col[2] = src_col[2] > 209 ? 255 : src_col[2] + 46; + UI_GetThemeColor3ubv(TH_AXIS_Z, col); + UI_GetColorPtrBlendShade3ubv(src_col, col, dst_col, 0.5f, -10); break; default: BLI_assert(!"invalid axis arg"); @@ -1952,6 +1961,16 @@ void init_userdef_do_versions(void) rgba_char_args_set(btheme->tv3d.skin_root, 180, 77, 77, 255); } } + + if (bmain->versionfile < 264 || (bmain->versionfile == 264 && bmain->subversionfile < 9)) { + bTheme *btheme; + + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + rgba_char_args_set(btheme->tui.xaxis, 220, 0, 0, 255); + rgba_char_args_set(btheme->tui.yaxis, 0, 220, 0, 255); + rgba_char_args_set(btheme->tui.zaxis, 0, 0, 220, 255); + } + } /* Freestyle color settings */ { diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 8e5c89adfca..bf4ee0eb61f 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -261,7 +261,7 @@ static void edgering_sel(RingSelOpData *lcd, int previewlines, int select) lasteed = eed; } - if (lasteed != startedge && BM_edge_share_face_count(lasteed, startedge)) { + if (lasteed != startedge && BM_edge_share_face_check(lasteed, startedge)) { v[1][0] = v[0][0]; v[1][1] = v[0][1]; diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 3e985a9779c..c2f2e97b86a 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -1177,19 +1177,17 @@ void MESH_OT_edgering_select(wmOperatorType *ot) RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring"); } -/* ******************* edgetag_shortest_path and helpers ****************** */ +/* ******************* generic tag_shortest_path and helpers ****************** */ -static float edgetag_cut_cost(BMEditMesh *UNUSED(em), BMEdge *e1, BMEdge *e2, BMVert *v) +static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3[3]) { - BMVert *v1 = (e1->v1 == v) ? e1->v2 : e1->v1; - BMVert *v2 = (e2->v1 == v) ? e2->v2 : e2->v1; float cost, d1[3], d2[3]; + /* The cost is based on the simple sum of the length of the two edgees... */ - sub_v3_v3v3(d1, v->co, v1->co); - sub_v3_v3v3(d2, v2->co, v->co); - cost = len_v3(d1); - cost += len_v3(d2); + sub_v3_v3v3(d1, v2, v1); + sub_v3_v3v3(d2, v3, v2); + cost = len_v3(d1) + len_v3(d2); /* but is biased to give higher values to sharp turns, so that it will take * paths with fewer "turns" when selecting between equal-weighted paths between @@ -1199,39 +1197,49 @@ static float edgetag_cut_cost(BMEditMesh *UNUSED(em), BMEdge *e1, BMEdge *e2, BM return cost; } -static void edgetag_add_adjacent(BMEditMesh *em, SmallHash *visithash, Heap *heap, int mednum, int vertnum, - int *nedges, int *edges, int *prevedge, float *cost) -{ - BMEdge *e1 = EDBM_edge_at_index(em, mednum); - BMVert *v = EDBM_vert_at_index(em, vertnum); - int startadj, endadj = nedges[vertnum + 1]; - - for (startadj = nedges[vertnum]; startadj < endadj; startadj++) { - int adjnum = edges[startadj]; - BMEdge *e2 = EDBM_edge_at_index(em, adjnum); - float newcost; - float cutcost; +/* ******************* edgetag_shortest_path and helpers ****************** */ - if (BLI_smallhash_haskey(visithash, (uintptr_t)e2)) - continue; +static float edgetag_cut_cost(BMEdge *e1, BMEdge *e2, BMVert *v) +{ + BMVert *v1 = BM_edge_other_vert(e1, v); + BMVert *v2 = BM_edge_other_vert(e2, v); + return step_cost_3_v3(v1->co, v->co, v2->co); +} - cutcost = edgetag_cut_cost(em, e1, e2, v); - newcost = cost[mednum] + cutcost; +static void edgetag_add_adjacent(Heap *heap, BMEdge *e1, BMEdge **edges_prev, float *cost) +{ + BMIter viter; + BMVert *v; - if (cost[adjnum] > newcost) { - cost[adjnum] = newcost; - prevedge[adjnum] = mednum; - BLI_heap_insert(heap, newcost, SET_INT_IN_POINTER(adjnum)); + BMIter eiter; + BMEdge *e2; + + const int e1_index = BM_elem_index_get(e1); + + BM_ITER_ELEM (v, &viter, e1, BM_VERTS_OF_EDGE) { + BM_ITER_ELEM (e2, &eiter, v, BM_EDGES_OF_VERT) { + if (!BM_elem_flag_test(e2, BM_ELEM_TAG)) { + /* we know 'e2' is not visited, check it out! */ + const int e2_index = BM_elem_index_get(e2); + const float cost_cut = edgetag_cut_cost(e1, e2, v); + const float cost_new = cost[e1_index] + cost_cut; + + if (cost[e2_index] > cost_new) { + cost[e2_index] = cost_new; + edges_prev[e2_index] = e1; + BLI_heap_insert(heap, cost_new, e2); + } + } } } } -static void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *e, int val) +static void edgetag_context_set(BMesh *bm, Scene *scene, BMEdge *e, int val) { switch (scene->toolsettings->edge_mode) { case EDGE_MODE_SELECT: - BM_edge_select_set(em->bm, e, val); + BM_edge_select_set(bm, e, val); break; case EDGE_MODE_TAG_SEAM: BM_elem_flag_set(e, BM_ELEM_SEAM, val); @@ -1243,25 +1251,19 @@ static void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *e, int val BM_elem_flag_set(e, BM_ELEM_FREESTYLE, val); break; case EDGE_MODE_TAG_CREASE: - { - float *crease = CustomData_bmesh_get(&em->bm->edata, e->head.data, CD_CREASE); - *crease = (val) ? 1.0f : 0.0f; + BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (val) ? 1.0f : 0.0f); break; - } case EDGE_MODE_TAG_BEVEL: - { - float *bweight = CustomData_bmesh_get(&em->bm->edata, e->head.data, CD_BWEIGHT); - *bweight = (val) ? 1.0f : 0.0f; + BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f); break; - } } } -static int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *e) +static int edgetag_context_check(Scene *scene, BMesh *bm, BMEdge *e) { switch (scene->toolsettings->edge_mode) { case EDGE_MODE_SELECT: - return BM_elem_flag_test(e, BM_ELEM_SELECT) ? 1 : 0; + return BM_elem_flag_test(e, BM_ELEM_SELECT) ? TRUE : FALSE; case EDGE_MODE_TAG_SEAM: return BM_elem_flag_test(e, BM_ELEM_SEAM); case EDGE_MODE_TAG_SHARP: @@ -1269,74 +1271,48 @@ static int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *e) case EDGE_MODE_TAG_FREESTYLE: return !BM_elem_flag_test(e, BM_ELEM_FREESTYLE); case EDGE_MODE_TAG_CREASE: - return BM_elem_float_data_get(&em->bm->edata, e, CD_CREASE) ? 1 : 0; + return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? TRUE : FALSE; case EDGE_MODE_TAG_BEVEL: - return BM_elem_float_data_get(&em->bm->edata, e, CD_BWEIGHT) ? 1 : 0; + return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? TRUE : FALSE; } return 0; } -static int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target) +static int edgetag_shortest_path(Scene *scene, BMesh *bm, BMEdge *e_src, BMEdge *e_dst) { + /* BM_ELEM_TAG flag is used to store visited edges */ BMEdge *e; - BMIter iter; + BMIter eiter; Heap *heap; - SmallHash visithash; float *cost; - int i, totvert = 0, totedge = 0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0; - int targetnum; - - BLI_smallhash_init(&visithash); + BMEdge **edges_prev; + int i, totedge; /* note, would pass BM_EDGE except we are looping over all edges anyway */ - BM_mesh_elem_index_ensure(em->bm, BM_VERT /* | BM_EDGE */); + BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - BLI_smallhash_insert(&visithash, (uintptr_t)e, NULL); + BM_ITER_MESH_INDEX (e, &eiter, bm, BM_EDGES_OF_MESH, i) { + if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == FALSE) { + BM_elem_flag_disable(e, BM_ELEM_TAG); + } + else { + BM_elem_flag_enable(e, BM_ELEM_TAG); } - BM_elem_index_set(e, totedge); /* set_inline */ - totedge++; + BM_elem_index_set(e, i); /* set_inline */ } - em->bm->elem_index_dirty &= ~BM_EDGE; + bm->elem_index_dirty &= ~BM_EDGE; /* alloc */ - totvert = em->bm->totvert; - nedges = MEM_callocN(sizeof(*nedges) * totvert + 1, "SeamPathNEdges"); - edges = MEM_mallocN(sizeof(*edges) * totedge * 2, "SeamPathEdges"); - prevedge = MEM_mallocN(sizeof(*prevedge) * totedge, "SeamPathPrevious"); + totedge = bm->totedge; + edges_prev = MEM_callocN(sizeof(*edges_prev) * totedge, "SeamPathPrevious"); cost = MEM_mallocN(sizeof(*cost) * totedge, "SeamPathCost"); - /* count edges, compute adjacent edges offsets and fill adjacent */ - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - nedges[BM_elem_index_get(e->v1) + 1]++; - nedges[BM_elem_index_get(e->v2) + 1]++; - } - - for (i = 1; i < totvert; i++) { - int newswap = nedges[i + 1]; - nedges[i + 1] = nedgeswap + nedges[i]; - nedgeswap = newswap; - } - nedges[0] = nedges[1] = 0; - - i = 0; - BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - edges[nedges[BM_elem_index_get(e->v1) + 1]++] = i; - edges[nedges[BM_elem_index_get(e->v2) + 1]++] = i; - - cost[i] = 1e20f; - prevedge[i] = -1; - i++; - } + fill_vn_fl(cost, totedge, 1e20f); /* * Arrays are now filled as follows: * - * nedges[n] = sum of the # of edges incident to all vertices numbered 0 through n - 1 - * edges[edges[n]..edges[n - 1]] = the indices of of the edges incident to vertex n - * * As the search continues, prevedge[n] will be the previous edge on the shortest * path found so far to edge n. The visitedhash will of course contain entries * for edges that have been visited, cost[n] will contain the length of the shortest @@ -1347,61 +1323,46 @@ static int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, B /* regular dijkstra shortest path, but over edges instead of vertices */ heap = BLI_heap_new(); - BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(BM_elem_index_get(source))); - cost[BM_elem_index_get(source)] = 0.0f; - EDBM_index_arrays_init(em, 1, 1, 0); - targetnum = BM_elem_index_get(target); + BLI_heap_insert(heap, 0.0f, e_src); + cost[BM_elem_index_get(e_src)] = 0.0f; + + e = NULL; while (!BLI_heap_is_empty(heap)) { - mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap)); - e = EDBM_edge_at_index(em, mednum); + e = BLI_heap_popmin(heap); - if (mednum == targetnum) + if (e == e_dst) break; - if (BLI_smallhash_haskey(&visithash, (uintptr_t)e)) - continue; - - BLI_smallhash_insert(&visithash, (uintptr_t)e, NULL); - - edgetag_add_adjacent(em, &visithash, heap, mednum, BM_elem_index_get(e->v1), nedges, edges, prevedge, cost); - edgetag_add_adjacent(em, &visithash, heap, mednum, BM_elem_index_get(e->v2), nedges, edges, prevedge, cost); + if (!BM_elem_flag_test(e, BM_ELEM_TAG)) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + edgetag_add_adjacent(heap, e, edges_prev, cost); + } } - if (mednum == targetnum) { - short allseams = 1; + if (e == e_dst) { + short all_set = TRUE; /* Check whether the path is already completely tagged. * if it is, the tags will be cleared instead of set. */ - mednum = targetnum; + e = e_dst; do { - e = EDBM_edge_at_index(em, mednum); - if (!edgetag_context_check(scene, em, e)) { - allseams = 0; + if (!edgetag_context_check(scene, bm, e)) { + all_set = FALSE; break; } - mednum = prevedge[mednum]; - } while (mednum != BM_elem_index_get(source)); + } while ((e = edges_prev[BM_elem_index_get(e)])); /* Follow path back and source and add or remove tags */ - mednum = targetnum; + e = e_dst; do { - e = EDBM_edge_at_index(em, mednum); - if (allseams) - edgetag_context_set(em, scene, e, 0); - else - edgetag_context_set(em, scene, e, 1); - mednum = prevedge[mednum]; - } while (mednum != -1); + edgetag_context_set(bm, scene, e, !all_set); + } while ((e = edges_prev[BM_elem_index_get(e)])); } - EDBM_index_arrays_free(em); - MEM_freeN(nedges); - MEM_freeN(edges); - MEM_freeN(prevedge); + MEM_freeN(edges_prev); MEM_freeN(cost); BLI_heap_free(heap, NULL); - BLI_smallhash_release(&visithash); return 1; } @@ -1409,21 +1370,15 @@ static int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, B /* ******************* mesh shortest path select, uses prev-selected edge ****************** */ /* since you want to create paths with multiple selects, it doesn't have extend option */ -static int mouse_mesh_shortest_path(bContext *C, int mval[2]) +static int mouse_mesh_shortest_path_edge(bContext *C, ViewContext *vc) { - ViewContext vc; - BMEditMesh *em; - BMEdge *e; + BMEditMesh *em = vc->em; + BMEdge *e_dst; float dist = 75.0f; - em_setup_viewcontext(C, &vc); - vc.mval[0] = mval[0]; - vc.mval[1] = mval[1]; - em = vc.em; - - e = EDBM_edge_find_nearest(&vc, &dist); - if (e) { - Mesh *me = vc.obedit->data; + e_dst = EDBM_edge_find_nearest(vc, &dist); + if (e_dst) { + Mesh *me = vc->obedit->data; int path = 0; if (em->bm->selected.last) { @@ -1432,8 +1387,8 @@ static int mouse_mesh_shortest_path(bContext *C, int mval[2]) if (ese && ese->htype == BM_EDGE) { BMEdge *e_act; e_act = (BMEdge *)ese->ele; - if (e_act != e) { - if (edgetag_shortest_path(vc.scene, em, e_act, e)) { + if (e_act != e_dst) { + if (edgetag_shortest_path(vc->scene, em->bm, e_act, e_dst)) { BM_select_history_remove(em->bm, e_act); path = 1; } @@ -1441,24 +1396,24 @@ static int mouse_mesh_shortest_path(bContext *C, int mval[2]) } } if (path == 0) { - int act = (edgetag_context_check(vc.scene, em, e) == 0); - edgetag_context_set(em, vc.scene, e, act); /* switch the edge option */ + int act = (edgetag_context_check(vc->scene, em->bm, e_dst) == 0); + edgetag_context_set(em->bm, vc->scene, e_dst, act); /* switch the edge option */ } EDBM_selectmode_flush(em); /* even if this is selected it may not be in the selection list */ - if (edgetag_context_check(vc.scene, em, e) == 0) - BM_select_history_remove(em->bm, e); + if (edgetag_context_check(vc->scene, em->bm, e_dst) == 0) + BM_select_history_remove(em->bm, e_dst); else - BM_select_history_store(em->bm, e); + BM_select_history_store(em->bm, e_dst); /* force drawmode for mesh */ switch (CTX_data_tool_settings(C)->edge_mode) { case EDGE_MODE_TAG_SEAM: me->drawflag |= ME_DRAWSEAMS; - ED_uvedit_live_unwrap(vc.scene, vc.obedit); + ED_uvedit_live_unwrap(vc->scene, vc->obedit); break; case EDGE_MODE_TAG_SHARP: me->drawflag |= ME_DRAWSHARP; @@ -1484,17 +1439,229 @@ static int mouse_mesh_shortest_path(bContext *C, int mval[2]) } +/* ******************* facetag_shortest_path and helpers ****************** */ + + +static float facetag_cut_cost(BMFace *f1, BMFace *f2, BMEdge *e) +{ + float f1_cent[3]; + float f2_cent[3]; + float e_cent[3]; + + BM_face_calc_center_mean(f1, f1_cent); + BM_face_calc_center_mean(f2, f2_cent); + mid_v3_v3v3(e_cent, e->v1->co, e->v2->co); + + return step_cost_3_v3(f1_cent, e_cent, f2_cent); +} + +static void facetag_add_adjacent(Heap *heap, BMFace *f1, BMFace **faces_prev, float *cost) +{ + BMIter liter; + BMLoop *l2; + BMFace *f2; + + const int f1_index = BM_elem_index_get(f1); + + /* loop over faces of face, but do so by first looping over loops */ + BM_ITER_ELEM (l2, &liter, f1, BM_LOOPS_OF_FACE) { + BMLoop *l_first; + BMLoop *l_iter; + + l_iter = l_first = l2; + do { + f2 = l_iter->f; + if (!BM_elem_flag_test(f2, BM_ELEM_TAG)) { + /* we know 'f2' is not visited, check it out! */ + const int f2_index = BM_elem_index_get(f2); + const float cost_cut = facetag_cut_cost(f1, f2, l_iter->e); + const float cost_new = cost[f1_index] + cost_cut; + + if (cost[f2_index] > cost_new) { + cost[f2_index] = cost_new; + faces_prev[f2_index] = f1; + BLI_heap_insert(heap, cost_new, f2); + } + } + } while ((l_iter = l_iter->radial_next) != l_first); + } +} + +static void facetag_context_set(BMesh *bm, Scene *UNUSED(scene), BMFace *f, int val) +{ + BM_face_select_set(bm, f, val); +} + +static int facetag_context_check(Scene *UNUSED(scene), BMesh *UNUSED(bm), BMFace *f) +{ + return BM_elem_flag_test(f, BM_ELEM_SELECT) ? 1 : 0; +} + +static int facetag_shortest_path(Scene *scene, BMesh *bm, BMFace *f_src, BMFace *f_dst) +{ + /* BM_ELEM_TAG flag is used to store visited edges */ + BMFace *f; + BMIter fiter; + Heap *heap; + float *cost; + BMFace **faces_prev; + int i, totface; + + /* note, would pass BM_EDGE except we are looping over all faces anyway */ + // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG + + BM_ITER_MESH_INDEX (f, &fiter, bm, BM_FACES_OF_MESH, i) { + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == FALSE) { + BM_elem_flag_disable(f, BM_ELEM_TAG); + } + else { + BM_elem_flag_enable(f, BM_ELEM_TAG); + } + + BM_elem_index_set(f, i); /* set_inline */ + } + bm->elem_index_dirty &= ~BM_FACE; + + /* alloc */ + totface = bm->totface; + faces_prev = MEM_callocN(sizeof(*faces_prev) * totface, "SeamPathPrevious"); + cost = MEM_mallocN(sizeof(*cost) * totface, "SeamPathCost"); + + fill_vn_fl(cost, totface, 1e20f); + + /* + * Arrays are now filled as follows: + * + * As the search continues, faces_prev[n] will be the previous face on the shortest + * path found so far to face n. The visitedhash will of course contain entries + * for faces that have been visited, cost[n] will contain the length of the shortest + * path to face n found so far, Finally, heap is a priority heap which is built on the + * the same data as the cost array, but inverted: it is a worklist of faces prioritized + * by the shortest path found so far to the face. + */ + + /* regular dijkstra shortest path, but over faces instead of vertices */ + heap = BLI_heap_new(); + BLI_heap_insert(heap, 0.0f, f_src); + cost[BM_elem_index_get(f_src)] = 0.0f; + + f = NULL; + + while (!BLI_heap_is_empty(heap)) { + f = BLI_heap_popmin(heap); + + if (f == f_dst) + break; + + if (!BM_elem_flag_test(f, BM_ELEM_TAG)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + facetag_add_adjacent(heap, f, faces_prev, cost); + } + } + + if (f == f_dst) { + short all_set = TRUE; + + /* Check whether the path is already completely tagged. + * if it is, the tags will be cleared instead of set. */ + f = f_dst; + do { + if (!facetag_context_check(scene, bm, f)) { + all_set = FALSE; + break; + } + } while ((f = faces_prev[BM_elem_index_get(f)])); + + /* Follow path back and source and add or remove tags */ + f = f_dst; + do { + facetag_context_set(bm, scene, f, !all_set); + } while ((f = faces_prev[BM_elem_index_get(f)])); + } + + MEM_freeN(faces_prev); + MEM_freeN(cost); + BLI_heap_free(heap, NULL); + + return 1; +} + +static int mouse_mesh_shortest_path_face(bContext *C, ViewContext *vc) +{ + BMEditMesh *em = vc->em; + BMFace *f_dst; + float dist = 75.0f; + + f_dst = EDBM_face_find_nearest(vc, &dist); + if (f_dst) { + int path = 0; + BMFace *f_act = BM_active_face_get(em->bm, FALSE, TRUE); + + if (f_act) { + if (f_act != f_dst) { + if (facetag_shortest_path(vc->scene, em->bm, f_act, f_dst)) { + BM_select_history_remove(em->bm, f_act); + path = 1; + } + } + } + if (path == 0) { + int act = (facetag_context_check(vc->scene, em->bm, f_dst) == 0); + facetag_context_set(em->bm, vc->scene, f_dst, act); /* switch the face option */ + } + + EDBM_selectmode_flush(em); + + /* even if this is selected it may not be in the selection list */ + if (facetag_context_check(vc->scene, em->bm, f_dst) == 0) + BM_select_history_remove(em->bm, f_dst); + else + BM_select_history_store(em->bm, f_dst); + + BM_active_face_set(em->bm, f_dst); + + EDBM_update_generic(C, em, FALSE); + + return TRUE; + } + else { + return FALSE; + } +} + + +/* ******************* operator for edge and face tag ****************** */ + static int edbm_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) { - + ViewContext vc; + BMEditMesh *em; + view3d_operator_needs_opengl(C); - if (mouse_mesh_shortest_path(C, event->mval)) { - return OPERATOR_FINISHED; + em_setup_viewcontext(C, &vc); + vc.mval[0] = event->mval[0]; + vc.mval[1] = event->mval[1]; + em = vc.em; + + if (em->selectmode & SCE_SELECT_EDGE) { + if (mouse_mesh_shortest_path_edge(C, &vc)) { + return OPERATOR_FINISHED; + } + else { + return OPERATOR_PASS_THROUGH; + } } - else { - return OPERATOR_PASS_THROUGH; + else if (em->selectmode & SCE_SELECT_FACE) { + if (mouse_mesh_shortest_path_face(C, &vc)) { + return OPERATOR_FINISHED; + } + else { + return OPERATOR_PASS_THROUGH; + } } + + return OPERATOR_PASS_THROUGH; } static int edbm_shortest_path_select_poll(bContext *C) @@ -1502,7 +1669,7 @@ static int edbm_shortest_path_select_poll(bContext *C) if (ED_operator_editmesh_region_view3d(C)) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BMEdit_FromObject(obedit); - return (em->selectmode & SCE_SELECT_EDGE) != 0; + return (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_FACE)) != 0; } return 0; } diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index df22cbcb294..82eb9457147 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -1736,12 +1736,12 @@ void MESH_OT_vertices_smooth_laplacian(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - 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, - "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); + 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, + "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); RNA_def_boolean(ot->srna, "use_x", 1, "Smooth X Axis", "Smooth object along X axis"); RNA_def_boolean(ot->srna, "use_y", 1, "Smooth Y Axis", "Smooth object along Y axis"); RNA_def_boolean(ot->srna, "use_z", 1, "Smooth Z Axis", "Smooth object along Z axis"); @@ -4602,11 +4602,15 @@ void MESH_OT_noise(wmOperatorType *ot) RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f); } +#define NEW_BEVEL 1 + typedef struct { BMEditMesh *em; BMBackup mesh_backup; +#ifndef NEW_BEVEL float *weights; int li; +#endif int mcenter[2]; float initial_length; float pixel_size; /* use when mouse input is interpreted as spatial distance */ @@ -4619,13 +4623,25 @@ typedef struct { static void edbm_bevel_update_header(wmOperator *op, bContext *C) { +#ifdef NEW_BEVEL + static char str[] = "Confirm: Enter/LClick, Cancel: (Esc/RMB), offset: %s, segments: %d"; +#else static char str[] = "Confirm: Enter/LClick, Cancel: (Esc/RMB), factor: %s, Use Dist (D): %s: Use Even (E): %s"; + BevelData *opdata = op->customdata; +#endif char msg[HEADER_LENGTH]; ScrArea *sa = CTX_wm_area(C); - BevelData *opdata = op->customdata; if (sa) { +#ifdef NEW_BEVEL + char offset_str[NUM_STR_REP_LEN]; + BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset")); + BLI_snprintf(msg, HEADER_LENGTH, str, + offset_str, + RNA_int_get(op->ptr, "segments") + ); +#else char factor_str[NUM_STR_REP_LEN]; if (hasNumInput(&opdata->num_input)) outputNumInput(&opdata->num_input, factor_str); @@ -4636,11 +4652,13 @@ static void edbm_bevel_update_header(wmOperator *op, bContext *C) RNA_boolean_get(op->ptr, "use_dist") ? "On" : "Off", RNA_boolean_get(op->ptr, "use_even") ? "On" : "Off" ); +#endif ED_area_headerprint(sa, msg); } } +#ifndef NEW_BEVEL static void edbm_bevel_recalc_weights(wmOperator *op) { float df, s, ftot; @@ -4668,15 +4686,20 @@ static void edbm_bevel_recalc_weights(wmOperator *op) mul_vn_fl(opdata->weights, recursion, 1.0f / (float)ftot); } +#endif static int edbm_bevel_init(bContext *C, wmOperator *op, int is_modal) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BMEdit_FromObject(obedit); +#ifdef NEW_BEVEL + BevelData *opdata; +#else BMIter iter; BMEdge *eed; BevelData *opdata; int li; +#endif if (em == NULL) { return 0; @@ -4684,6 +4707,7 @@ static int edbm_bevel_init(bContext *C, wmOperator *op, int is_modal) op->customdata = opdata = MEM_mallocN(sizeof(BevelData), "beveldata_mesh_operator"); +#ifndef NEW_BEVEL BM_data_layer_add(em->bm, &em->bm->edata, CD_PROP_FLT); li = CustomData_number_of_layers(&em->bm->edata, CD_PROP_FLT) - 1; @@ -4693,10 +4717,12 @@ static int edbm_bevel_init(bContext *C, wmOperator *op, int is_modal) *dv = d; } - - opdata->em = em; + opdata->li = li; opdata->weights = NULL; +#endif + + opdata->em = em; opdata->is_modal = is_modal; opdata->shift_factor = -1.0f; @@ -4706,7 +4732,9 @@ static int edbm_bevel_init(bContext *C, wmOperator *op, int is_modal) /* avoid the cost of allocating a bm copy */ if (is_modal) opdata->mesh_backup = EDBM_redo_state_store(em); +#ifndef NEW_BEVEL edbm_bevel_recalc_weights(op); +#endif return 1; } @@ -4716,6 +4744,26 @@ static int edbm_bevel_calc(bContext *C, wmOperator *op) BevelData *opdata = op->customdata; BMEditMesh *em = opdata->em; BMOperator bmop; +#ifdef NEW_BEVEL + float offset = RNA_float_get(op->ptr, "offset"); + int segments = RNA_int_get(op->ptr, "segments"); + + /* revert to original mesh */ + if (opdata->is_modal) { + EDBM_redo_state_restore(opdata->mesh_backup, em, FALSE); + } + + if (!EDBM_op_init(em, &bmop, op, + "bevel geom=%hev offset=%f segments=%i", + BM_ELEM_SELECT, offset, segments)) + { + return 0; + } + + BMO_op_exec(em->bm, &bmop); + if (!EDBM_op_finish(em, &bmop, op, TRUE)) + return 0; +#else int i; float factor = RNA_float_get(op->ptr, "percent") /*, dfac */ /* UNUSED */; @@ -4743,6 +4791,7 @@ static int edbm_bevel_calc(bContext *C, wmOperator *op) if (!EDBM_op_finish(em, &bmop, op, TRUE)) return 0; } +#endif EDBM_mesh_normals_update(opdata->em); @@ -4760,10 +4809,12 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op) if (sa) { ED_area_headerprint(sa, NULL); } +#ifndef NEW_BEVEL BM_data_layer_free_n(opdata->em->bm, &opdata->em->bm->edata, CD_PROP_FLT, opdata->li); if (opdata->weights) MEM_freeN(opdata->weights); +#endif if (opdata->is_modal) { EDBM_redo_state_free(&opdata->mesh_backup, NULL, FALSE); } @@ -4844,7 +4895,11 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, wmEvent *event) static float edbm_bevel_mval_factor(wmOperator *op, wmEvent *event) { BevelData *opdata = op->customdata; +#ifdef NEW_BEVEL + int use_dist = TRUE; +#else int use_dist = RNA_boolean_get(op->ptr, "use_dist"); +#endif float mdiff[2]; float factor; @@ -4882,9 +4937,21 @@ static float edbm_bevel_mval_factor(wmOperator *op, wmEvent *event) static int edbm_bevel_modal(bContext *C, wmOperator *op, wmEvent *event) { BevelData *opdata = op->customdata; + int segments = RNA_int_get(op->ptr, "segments"); if (event->val == KM_PRESS) { /* Try to handle numeric inputs... */ +#ifdef NEW_BEVEL + float value; + + if (handleNumInput(&opdata->num_input, event)) { + applyNumInput(&opdata->num_input, &value); + RNA_float_set(op->ptr, "offset", value); + edbm_bevel_calc(C, op); + edbm_bevel_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } +#else float factor; if (handleNumInput(&opdata->num_input, event)) { @@ -4896,6 +4963,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, wmEvent *event) edbm_bevel_update_header(op, C); return OPERATOR_RUNNING_MODAL; } +#endif } switch (event->type) { @@ -4907,7 +4975,11 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, wmEvent *event) case MOUSEMOVE: if (!hasNumInput(&opdata->num_input)) { const float factor = edbm_bevel_mval_factor(op, event); +#ifdef NEW_BEVEL + RNA_float_set(op->ptr, "offset", factor); +#else RNA_float_set(op->ptr, "percent", factor); +#endif edbm_bevel_calc(C, op); edbm_bevel_update_header(op, C); @@ -4921,6 +4993,28 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, wmEvent *event) edbm_bevel_exit(C, op); return OPERATOR_FINISHED; +#ifdef NEW_BEVEL + case WHEELUPMOUSE: /* change number of segments */ + if (event->val == KM_RELEASE) + break; + + segments++; + RNA_int_set(op->ptr, "segments", segments); + edbm_bevel_calc(C, op); + edbm_bevel_update_header(op, C); + break; + + case WHEELDOWNMOUSE: /* change number of segments */ + if (event->val == KM_RELEASE) + break; + + segments = max_ii(segments - 1, 1); + RNA_int_set(op->ptr, "segments", segments); + edbm_bevel_calc(C, op); + edbm_bevel_update_header(op, C); + break; + +#else case EKEY: if (event->val == KM_PRESS) { int use_even = RNA_boolean_get(op->ptr, "use_even"); @@ -4945,6 +5039,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, wmEvent *event) edbm_bevel_update_header(op, C); } break; +#endif } return OPERATOR_RUNNING_MODAL; @@ -4967,6 +5062,10 @@ void MESH_OT_bevel(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING; +#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); +#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); /* XXX, disabled for 2.63 release, needs to work much better without overlap before we can give to users. */ @@ -4974,6 +5073,7 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_even", FALSE, "Even", "Calculate evenly spaced bevel"); RNA_def_boolean(ot->srna, "use_dist", FALSE, "Distance", "Interpret the percent in blender units"); +#endif } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 9fc4e0a906d..4d1f2bbc4e9 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1136,7 +1136,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (dupli_gh) BLI_ghash_insert(dupli_gh, dob, ob); if (parent_gh) - BLI_ghash_insert(parent_gh, BLI_ghashutil_pairalloc(dob->ob, SET_INT_IN_POINTER(dob->index)), ob); + BLI_ghash_insert(parent_gh, BLI_ghashutil_pairalloc(dob->ob, SET_INT_IN_POINTER(dob->persistent_id[0])), ob); } if (use_hierarchy) { @@ -1150,7 +1150,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, /* find parent that was also made real */ if (ob_src_par) { - GHashPair *pair = BLI_ghashutil_pairalloc(ob_src_par, SET_INT_IN_POINTER(dob->index)); + GHashPair *pair = BLI_ghashutil_pairalloc(ob_src_par, SET_INT_IN_POINTER(dob->persistent_id[0])); ob_dst_par = BLI_ghash_lookup(parent_gh, pair); BLI_ghashutil_pairfree(pair); } diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 0a2ca379518..5155f1001ab 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -58,6 +58,7 @@ #include "GPU_material.h" #include "RE_engine.h" +#include "RE_pipeline.h" #include "ED_node.h" #include "ED_render.h" @@ -157,6 +158,8 @@ void ED_render_engine_changed(Main *bmain) for (sc = bmain->screen.first; sc; sc = sc->id.next) for (sa = sc->areabase.first; sa; sa = sa->next) ED_render_engine_area_exit(sa); + + RE_FreePersistentData(); } /***************************** Updates *********************************** diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 0ecac5fc497..ca85daadf3b 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -35,6 +35,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_math.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -52,6 +53,7 @@ #include "BKE_writeavi.h" #include "BIF_gl.h" +#include "BIF_glutil.h" #include "RNA_access.h" #include "RNA_define.h" @@ -278,6 +280,7 @@ void SCREEN_OT_screenshot(wmOperatorType *ot) typedef struct ScreenshotJob { Main *bmain; Scene *scene; + wmWindowManager *wm; unsigned int *dumprect; int x, y, dumpsx, dumpsy; short *stop; @@ -395,6 +398,54 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float BKE_report(&sj->reports, RPT_INFO, "Screencast job stopped"); } +/* Helper callback for drawing the cursor itself */ +static void screencast_draw_cursor(bContext *UNUSED(C), int x, int y, void *UNUSED(p_ptr)) +{ + + glPushMatrix(); + + glTranslatef((float)x, (float)y, 0.0f); + + + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + + glColor4ub(0, 0, 0, 32); + glutil_draw_filled_arc(0.0, M_PI * 2.0, 20, 40); + + glColor4ub(255, 255, 255, 128); + glutil_draw_lined_arc(0.0, M_PI * 2.0, 20, 40); + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + + glPopMatrix(); +} + +/* Turn brush cursor in 3D view on/off */ +static void screencast_cursor_toggle(wmWindowManager *wm, short enable) +{ + static void *cursor = NULL; + + if (cursor && !enable) { + /* clear cursor */ + WM_paint_cursor_end(wm, cursor); + cursor = NULL; + } + else if (enable) { + /* enable cursor */ + cursor = WM_paint_cursor_activate(wm, NULL, screencast_draw_cursor, NULL); + } +} + +static void screenshot_endjob(void *sjv) +{ + ScreenshotJob *sj = sjv; + + screencast_cursor_toggle(sj->wm, 0); +} + + static int screencast_exec(bContext *C, wmOperator *op) { bScreen *screen = CTX_wm_screen(C); @@ -418,15 +469,18 @@ static int screencast_exec(bContext *C, wmOperator *op) } sj->bmain = CTX_data_main(C); sj->scene = CTX_data_scene(C); - + sj->wm = CTX_wm_manager(C); + BKE_reports_init(&sj->reports, RPT_PRINT); /* setup job */ WM_jobs_customdata_set(wm_job, sj, screenshot_freejob); WM_jobs_timer(wm_job, 0.1, 0, NC_SCREEN | ND_SCREENCAST); - WM_jobs_callbacks(wm_job, screenshot_startjob, NULL, screenshot_updatejob, NULL); + WM_jobs_callbacks(wm_job, screenshot_startjob, NULL, screenshot_updatejob, screenshot_endjob); + + WM_jobs_start(sj->wm, wm_job); - WM_jobs_start(CTX_wm_manager(C), wm_job); + screencast_cursor_toggle(sj->wm, 1); WM_event_add_notifier(C, NC_SCREEN | ND_SCREENCAST, screen); diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index bd6852c4344..4b400623920 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -109,19 +109,25 @@ #include "paint_intern.h" /* Defines and Structs */ +/* FTOCHAR as inline function */ +BLI_INLINE unsigned char f_to_char(const float val) +{ + return FTOCHAR(val); +} + #define IMAPAINT_CHAR_TO_FLOAT(c) ((c) / 255.0f) #define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { \ - (c)[0] = FTOCHAR((f)[0]); \ - (c)[1] = FTOCHAR((f)[1]); \ - (c)[2] = FTOCHAR((f)[2]); \ + (c)[0] = f_to_char((f)[0]); \ + (c)[1] = f_to_char((f)[1]); \ + (c)[2] = f_to_char((f)[2]); \ } (void)0 #define IMAPAINT_FLOAT_RGBA_TO_CHAR(c, f) { \ - (c)[0] = FTOCHAR((f)[0]); \ - (c)[1] = FTOCHAR((f)[1]); \ - (c)[2] = FTOCHAR((f)[2]); \ - (c)[3] = FTOCHAR((f)[3]); \ + (c)[0] = f_to_char((f)[0]); \ + (c)[1] = f_to_char((f)[1]); \ + (c)[2] = f_to_char((f)[2]); \ + (c)[3] = f_to_char((f)[3]); \ } (void)0 #define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { \ (f)[0] = IMAPAINT_CHAR_TO_FLOAT((c)[0]); \ @@ -3905,16 +3911,20 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo } } +BLI_INLINE void rgba_float_to_uchar__mul_v3(unsigned char rgba_ub[4], const float rgba[4], const float rgb[3]) +{ + rgba_ub[0] = f_to_char(rgba[0] * rgb[0]); + rgba_ub[1] = f_to_char(rgba[1] * rgb[1]); + rgba_ub[2] = f_to_char(rgba[2] * rgb[3]); + rgba_ub[3] = f_to_char(rgba[3]); +} static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float rgba[4], float alpha, float mask) { unsigned char rgba_ub[4]; if (ps->is_texbrush) { - rgba_ub[0] = FTOCHAR(rgba[0] * ps->brush->rgb[0]); - rgba_ub[1] = FTOCHAR(rgba[1] * ps->brush->rgb[1]); - rgba_ub[2] = FTOCHAR(rgba[2] * ps->brush->rgb[2]); - rgba_ub[3] = FTOCHAR(rgba[3]); + rgba_float_to_uchar__mul_v3(rgba_ub, rgba, ps->brush->rgb); } else { IMAPAINT_FLOAT_RGB_TO_CHAR(rgba_ub, ps->brush->rgb); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 6396a0c2cbc..9ebeb61a7bb 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -195,7 +195,7 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev /* Returns zero if no sculpt changes should be made, non-zero otherwise */ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], - const PaintSample *sample) + const PaintSample *sample) { output[0] = sample->mouse[0]; output[1] = sample->mouse[1]; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 56d46a22e10..94b00101dc2 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -125,9 +125,11 @@ static void update_tessface_data(Object *ob, Mesh *me) if (!me->mcol || !me->mface) { /* should always be true */ /* XXX Why this clearing? tessface_calc will reset it anyway! */ -/* if (me->mcol) {*/ -/* memset(me->mcol, 255, 4 * sizeof(MCol) * me->totface);*/ -/* }*/ +#if 0 + if (me->mcol) { + memset(me->mcol, 255, 4 * sizeof(MCol) * me->totface); + } +#endif /* create tessfaces because they will be used for drawing & fast updates */ BKE_mesh_tessface_calc(me); /* does own call to update pointers */ diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 24e9effa9eb..a7f18c9de53 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -681,9 +681,9 @@ void buttons_context_compute(const bContext *C, SpaceButs *sbuts) /************************* Context Callback ************************/ const char *buttons_context_dir[] = { - "world", "object", "mesh", "armature", "lattice", "curve", + "texture_slot", "world", "object", "mesh", "armature", "lattice", "curve", "meta_ball", "lamp", "speaker", "camera", "material", "material_slot", - "texture", "texture_slot", "texture_user", "bone", "edit_bone", + "texture", "texture_user", "bone", "edit_bone", "pose_bone", "particle_system", "particle_system_editable", "particle_settings", "cloth", "soft_body", "fluid", "smoke", "collision", "brush", "dynamic_paint", NULL }; @@ -698,7 +698,12 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r /* here we handle context, getting data from precomputed path */ if (CTX_data_dir(member)) { - CTX_data_dir_set(result, buttons_context_dir); + /* in case of new shading system we skip texture_slot, complex python + * UI script logic depends on checking if this is available */ + if (sbuts->texuser) + CTX_data_dir_set(result, buttons_context_dir + 1); + else + CTX_data_dir_set(result, buttons_context_dir); return 1; } else if (CTX_data_equals(member, "world")) { diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index a2e4da719e9..02716c20588 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -252,7 +252,6 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, int width, int height, float zoomx, float zoomy) { int x, y; - MovieClip *clip = ED_space_clip_get_clip(sc); /* find window pixel coordinates of origin */ UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y); @@ -306,6 +305,15 @@ static void draw_movieclip_buffer(const bContext *C, SpaceClip *sc, ARegion *ar, IMB_display_buffer_release(cache_handle); } +} + +static void draw_stabilization_border(SpaceClip *sc, ARegion *ar, int width, int height, float zoomx, float zoomy) +{ + int x, y; + MovieClip *clip = ED_space_clip_get_clip(sc); + + /* find window pixel coordinates of origin */ + UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y); /* draw boundary border for frame if stabilization is enabled */ if (sc->flag & SC_SHOW_STABLE && clip->tracking.stabilization.flag & TRACKING_2D_STABILIZATION) { @@ -1469,6 +1477,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar) } if (width && height) { + draw_stabilization_border(sc, ar, width, height, zoomx, zoomy); draw_tracking_tracks(sc, ar, clip, width, height, zoomx, zoomy); draw_distortion(sc, ar, clip, width, height, zoomx, zoomy); } diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 9ec2ad82bef..4e53f34359e 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1065,7 +1065,7 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) if (clip->anim) { pj->index_context = IMB_anim_index_rebuild_context(clip->anim, clip->proxy.build_tc_flag, - clip->proxy.build_size_flag, clip->proxy.quality); + clip->proxy.build_size_flag, clip->proxy.quality); } WM_jobs_customdata_set(wm_job, pj, proxy_freejob); diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index ddc624b4cdf..d7a9b1c0cb6 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -63,11 +63,12 @@ #include "clip_intern.h" // own include -void clip_graph_tracking_values_iterate_track(SpaceClip *sc, MovieTrackingTrack *track, void *userdata, - void (*func)(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker, int coord, - int scene_framenr, float val), - void (*segment_start)(void *userdata, MovieTrackingTrack *track, int coord), - void (*segment_end)(void *userdata)) +void clip_graph_tracking_values_iterate_track( + SpaceClip *sc, MovieTrackingTrack *track, void *userdata, + void (*func)(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker, int coord, + int scene_framenr, float val), + void (*segment_start)(void *userdata, MovieTrackingTrack *track, int coord), + void (*segment_end)(void *userdata)) { MovieClip *clip = ED_space_clip_get_clip(sc); int width, height, coord; @@ -122,11 +123,12 @@ void clip_graph_tracking_values_iterate_track(SpaceClip *sc, MovieTrackingTrack } } -void clip_graph_tracking_values_iterate(SpaceClip *sc, int selected_only, int include_hidden, void *userdata, - void (*func)(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker, - int coord, int scene_framenr, float val), - void (*segment_start)(void *userdata, MovieTrackingTrack *track, int coord), - void (*segment_end)(void *userdata)) +void clip_graph_tracking_values_iterate( + SpaceClip *sc, int selected_only, int include_hidden, void *userdata, + void (*func)(void *userdata, MovieTrackingTrack *track, MovieTrackingMarker *marker, + int coord, int scene_framenr, float val), + void (*segment_start)(void *userdata, MovieTrackingTrack *track, int coord), + void (*segment_end)(void *userdata)) { MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index f41169b6c39..fa7c6bd472a 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -563,13 +563,13 @@ static void graph_refresh(const bContext *C, ScrArea *sa) switch (fcu->array_index) { case 0: - col[0] = 1.0f; col[1] = 0.0f; col[2] = 0.0f; + UI_GetThemeColor3fv(TH_AXIS_X, col); break; case 1: - col[0] = 0.0f; col[1] = 1.0f; col[2] = 0.0f; + UI_GetThemeColor3fv(TH_AXIS_Y, col); break; case 2: - col[0] = 0.0f; col[1] = 0.0f; col[2] = 1.0f; + UI_GetThemeColor3fv(TH_AXIS_Z, col); break; default: /* 'unknown' color - bluish so as to not conflict with handles */ diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index aafd4abb25e..8d44da2e367 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -319,7 +319,7 @@ static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr RNA_property_collection_lookup_int(ptr, prop, 0, &sockptr); col = uiLayoutColumn(layout, FALSE); - uiTemplateColorWheel(col, &sockptr, "default_value", 1, 0, 0, 0); + uiTemplateColorPicker(col, &sockptr, "default_value", 1, 0, 0, 0); uiItemR(col, &sockptr, "default_value", 0, "", ICON_NONE); } @@ -2258,17 +2258,17 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C split = uiLayoutSplit(layout, 0.0f, FALSE); col = uiLayoutColumn(split, FALSE); - uiTemplateColorWheel(col, ptr, "lift", 1, 1, 0, 1); + uiTemplateColorPicker(col, ptr, "lift", 1, 1, 0, 1); row = uiLayoutRow(col, FALSE); uiItemR(row, ptr, "lift", 0, NULL, ICON_NONE); col = uiLayoutColumn(split, FALSE); - uiTemplateColorWheel(col, ptr, "gamma", 1, 1, 1, 1); + uiTemplateColorPicker(col, ptr, "gamma", 1, 1, 1, 1); row = uiLayoutRow(col, FALSE); uiItemR(row, ptr, "gamma", 0, NULL, ICON_NONE); col = uiLayoutColumn(split, FALSE); - uiTemplateColorWheel(col, ptr, "gain", 1, 1, 1, 1); + uiTemplateColorPicker(col, ptr, "gain", 1, 1, 1, 1); row = uiLayoutRow(col, FALSE); uiItemR(row, ptr, "gain", 0, NULL, ICON_NONE); @@ -2277,17 +2277,17 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C split = uiLayoutSplit(layout, 0.0f, FALSE); col = uiLayoutColumn(split, FALSE); - uiTemplateColorWheel(col, ptr, "offset", 1, 1, 0, 1); + uiTemplateColorPicker(col, ptr, "offset", 1, 1, 0, 1); row = uiLayoutRow(col, FALSE); uiItemR(row, ptr, "offset", 0, NULL, ICON_NONE); col = uiLayoutColumn(split, FALSE); - uiTemplateColorWheel(col, ptr, "power", 1, 1, 0, 1); + uiTemplateColorPicker(col, ptr, "power", 1, 1, 0, 1); row = uiLayoutRow(col, FALSE); uiItemR(row, ptr, "power", 0, NULL, ICON_NONE); col = uiLayoutColumn(split, FALSE); - uiTemplateColorWheel(col, ptr, "slope", 1, 1, 0, 1); + uiTemplateColorPicker(col, ptr, "slope", 1, 1, 0, 1); row = uiLayoutRow(col, FALSE); uiItemR(row, ptr, "slope", 0, NULL, ICON_NONE); } @@ -2299,23 +2299,23 @@ static void node_composit_buts_colorbalance_but(uiLayout *layout, bContext *UNUS if (RNA_enum_get(ptr, "correction_method") == 0) { - uiTemplateColorWheel(layout, ptr, "lift", 1, 1, 0, 1); + uiTemplateColorPicker(layout, ptr, "lift", 1, 1, 0, 1); uiItemR(layout, ptr, "lift", 0, NULL, ICON_NONE); - uiTemplateColorWheel(layout, ptr, "gamma", 1, 1, 1, 1); + uiTemplateColorPicker(layout, ptr, "gamma", 1, 1, 1, 1); uiItemR(layout, ptr, "gamma", 0, NULL, ICON_NONE); - uiTemplateColorWheel(layout, ptr, "gain", 1, 1, 1, 1); + uiTemplateColorPicker(layout, ptr, "gain", 1, 1, 1, 1); uiItemR(layout, ptr, "gain", 0, NULL, ICON_NONE); } else { - uiTemplateColorWheel(layout, ptr, "offset", 1, 1, 0, 1); + uiTemplateColorPicker(layout, ptr, "offset", 1, 1, 0, 1); uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE); - uiTemplateColorWheel(layout, ptr, "power", 1, 1, 0, 1); + uiTemplateColorPicker(layout, ptr, "power", 1, 1, 0, 1); uiItemR(layout, ptr, "power", 0, NULL, ICON_NONE); - uiTemplateColorWheel(layout, ptr, "slope", 1, 1, 0, 1); + uiTemplateColorPicker(layout, ptr, "slope", 1, 1, 0, 1); uiItemR(layout, ptr, "slope", 0, NULL, ICON_NONE); } } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 5dd005e9ddf..62e941d3148 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2226,7 +2226,7 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op) data.text = CTX_data_pointer_get_type(C, "edit_text", &RNA_Text).data; if (data.text) { - bNodeTreeType *ntreetype = ntreeGetType(NTREE_SHADER); + bNodeTreeType *ntreetype = ntreeGetType(NTREE_SHADER); if (ntreetype && ntreetype->foreach_nodetree) ntreetype->foreach_nodetree(bmain, &data, node_shader_script_update_text); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index c4afe32e85f..2c40e0e656d 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1042,7 +1042,7 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto /* Default */ case eModifierType_None: case eModifierType_ShapeKey: - case NUM_MODIFIER_TYPES: + case NUM_MODIFIER_TYPES: UI_icon_draw(x, y, ICON_DOT); break; } break; diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index a8103fe2630..37e57a1e850 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -913,6 +913,13 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq unsigned char *display_buffer; void *cache_handle = NULL; + if (G.is_rendering == FALSE) { + /* stop all running jobs, except screen one. currently previews frustrate Render + * needed to make so sequencer's rendering doesn't conflict with compositor + */ + WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); + } + render_size = sseq->render_size; if (render_size == 0) { render_size = scene->r.size; diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 94f64563fd8..f463b015bf5 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -95,7 +95,7 @@ static int text_font_draw_character(SpaceText *st, int x, int y, char c) 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(c); + size_t len = BLI_str_utf8_size_safe(c); memcpy(str, c, len); str[len] = '\0'; @@ -158,7 +158,7 @@ int flatten_string(SpaceText *st, FlattenString *fs, const char *in) in++; } else { - size_t len = BLI_str_utf8_size(in); + size_t len = BLI_str_utf8_size_safe(in); flatten_string_append(fs, in, r, len); in += len; total++; @@ -342,7 +342,7 @@ static void txt_format_line(SpaceText *st, TextLine *line, int do_next) if (*str == '\\') { *fmt = prev; fmt++; str++; if (*str == '\0') break; - *fmt = prev; fmt++; str += BLI_str_utf8_size(str); + *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str); continue; } /* Handle continuations */ @@ -363,14 +363,14 @@ static void txt_format_line(SpaceText *st, TextLine *line, int do_next) } *fmt = 'l'; - str += BLI_str_utf8_size(str) - 1; + str += BLI_str_utf8_size_safe(str) - 1; } /* Not in a string... */ else { /* Deal with comments first */ if (prev == '#' || *str == '#') { *fmt = '#'; - str += BLI_str_utf8_size(str) - 1; + str += BLI_str_utf8_size_safe(str) - 1; } else if (*str == '"' || *str == '\'') { /* Strings */ @@ -399,7 +399,7 @@ static void txt_format_line(SpaceText *st, TextLine *line, int do_next) *fmt = 'n'; } else { - str += BLI_str_utf8_size(str) - 1; + str += BLI_str_utf8_size_safe(str) - 1; *fmt = 'q'; } /* Punctuation */ @@ -407,7 +407,7 @@ static void txt_format_line(SpaceText *st, TextLine *line, int do_next) *fmt = '!'; /* Identifiers and other text (no previous ws. or delims. so text continues) */ else if (prev == 'q') { - str += BLI_str_utf8_size(str) - 1; + str += BLI_str_utf8_size_safe(str) - 1; *fmt = 'q'; } /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */ @@ -427,7 +427,7 @@ static void txt_format_line(SpaceText *st, TextLine *line, int do_next) *fmt = prev; } else { - str += BLI_str_utf8_size(str) - 1; + str += BLI_str_utf8_size_safe(str) - 1; *fmt = 'q'; } } @@ -575,7 +575,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int * end = max; chop = 1; *offc = 0; - for (i = 0, j = 0; linep->line[j]; j += BLI_str_utf8_size(linep->line + j)) { + for (i = 0, j = 0; linep->line[j]; j += BLI_str_utf8_size_safe(linep->line + j)) { int chars; /* Mimic replacement of tabs */ @@ -640,7 +640,7 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi *offc = 0; cursin = txt_utf8_offset_to_index(linein->line, cursin); - for (i = 0, j = 0; linein->line[j]; j += BLI_str_utf8_size(linein->line + j)) { + for (i = 0, j = 0; linein->line[j]; j += BLI_str_utf8_size_safe(linein->line + j)) { /* Mimic replacement of tabs */ ch = linein->line[j]; @@ -685,7 +685,7 @@ int text_get_char_pos(SpaceText *st, const char *line, int cur) { int a = 0, i; - for (i = 0; i < cur && line[i]; i += BLI_str_utf8_size(line + i)) { + for (i = 0; i < cur && line[i]; i += BLI_str_utf8_size_safe(line + i)) { if (line[i] == '\t') a += st->tabnumber - a % st->tabnumber; else @@ -698,7 +698,7 @@ static const char *txt_utf8_get_nth(const char *str, int n) { int pos = 0; while (str[pos] && n--) { - pos += BLI_str_utf8_size(str + pos); + pos += BLI_str_utf8_size_safe(str + pos); } return str + pos; } @@ -719,7 +719,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w start = 0; mstart = 0; end = max; mend = txt_utf8_get_nth(str, max) - str; - for (i = 0, mi = 0; str[mi]; i++, mi += BLI_str_utf8_size(str + mi)) { + for (i = 0, mi = 0; str[mi]; i++, mi += BLI_str_utf8_size_safe(str + mi)) { if (i - start >= max) { /* skip hidden part of line */ if (skip) { @@ -730,7 +730,7 @@ 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(str + ma)) { + 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]); x += text_font_draw_character_utf8(st, x, y, str + ma); } @@ -748,7 +748,7 @@ 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(str + ma)) { + 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]); @@ -786,7 +786,7 @@ static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int dra for (a = 0; a < amount; a++) { format_draw_color(format[a]); x += text_font_draw_character_utf8(st, x, y, in + str_shift); - str_shift += BLI_str_utf8_size(in + str_shift); + str_shift += BLI_str_utf8_size_safe(in + str_shift); } } else text_font_draw(st, x, y, in); @@ -1016,7 +1016,7 @@ int text_get_visible_lines(SpaceText *st, ARegion *ar, const char *str) lines = 1; start = 0; end = max; - for (i = 0, j = 0; str[j]; j += BLI_str_utf8_size(str + j)) { + for (i = 0, j = 0; str[j]; j += BLI_str_utf8_size_safe(str + j)) { /* Mimic replacement of tabs */ ch = str[j]; if (ch == '\t') { @@ -1639,7 +1639,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar) if (b > 0) { /* opening bracket, search forward for close */ fc++; - c += BLI_str_utf8_size(linep->line + c); + 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] != '#') { @@ -1657,7 +1657,7 @@ static void draw_brackets(SpaceText *st, ARegion *ar) } } fc++; - c += BLI_str_utf8_size(linep->line + c); + c += BLI_str_utf8_size_safe(linep->line + c); } if (endl) break; linep = linep->next; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 2d902c4586a..1be50a54b68 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -1503,7 +1503,7 @@ static int text_get_cursor_rel(SpaceText *st, ARegion *ar, TextLine *linein, int end = max; chop = loop = 1; - for (i = 0, j = 0; loop; j += BLI_str_utf8_size(linein->line + j)) { + for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe(linein->line + j)) { int chars; /* Mimic replacement of tabs */ ch = linein->line[j]; @@ -1682,7 +1682,7 @@ static void txt_wrap_move_bol(SpaceText *st, ARegion *ar, short sel) chop = loop = 1; *charp = 0; - for (i = 0, j = 0; loop; j += BLI_str_utf8_size((*linep)->line + j)) { + for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) { int chars; /* Mimic replacement of tabs */ ch = (*linep)->line[j]; @@ -1750,7 +1750,7 @@ static void txt_wrap_move_eol(SpaceText *st, ARegion *ar, short sel) chop = loop = 1; *charp = 0; - for (i = 0, j = 0; loop; j += BLI_str_utf8_size((*linep)->line + j)) { + for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) { int chars; /* Mimic replacement of tabs */ ch = (*linep)->line[j]; @@ -2462,7 +2462,7 @@ static int flatten_len(SpaceText *st, const char *str) { int i, total = 0; - for (i = 0; str[i]; i += BLI_str_utf8_size(str + i)) { + for (i = 0; str[i]; i += BLI_str_utf8_size_safe(str + i)) { if (str[i] == '\t') { total += st->tabnumber - total % st->tabnumber; } @@ -2475,7 +2475,7 @@ static int flatten_len(SpaceText *st, const char *str) static int flatten_index_to_offset(SpaceText *st, const char *str, int index) { int i, j; - for (i = 0, j = 0; i < index; j += BLI_str_utf8_size(str + j)) + for (i = 0, j = 0; i < index; j += BLI_str_utf8_size_safe(str + j)) if (str[j] == '\t') i += st->tabnumber - i % st->tabnumber; else @@ -2519,7 +2519,7 @@ static void text_cursor_set_to_pos_wrapped(SpaceText *st, ARegion *ar, int x, in int j = 0, curs = 0, endj = 0; /* mem */ int chop = 1; /* flags */ - for (; loop; j += BLI_str_utf8_size(linep->line + j)) { + for (; loop; j += BLI_str_utf8_size_safe(linep->line + j)) { int chars; /* Mimic replacement of tabs */ @@ -2945,7 +2945,7 @@ static int text_insert_invoke(bContext *C, wmOperator *op, wmEvent *event) size_t len; if (event->utf8_buf[0]) { - len = BLI_str_utf8_size(event->utf8_buf); + len = BLI_str_utf8_size_safe(event->utf8_buf); memcpy(str, event->utf8_buf, len); } else { diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 6818c78bbd6..3413377c7b9 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -945,7 +945,7 @@ static void view3d_buttons_area_listener(ARegion *ar, wmNotifier *wmn) ED_region_tag_redraw(ar); break; case NC_GPENCIL: - if (wmn->data == ND_DATA) + if (wmn->data == ND_DATA || wmn->action == NA_EDITED) ED_region_tag_redraw(ar); break; } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 4d4fad47698..24fc6adae6d 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -545,12 +545,8 @@ static void drawfloor(Scene *scene, View3D *v3d, const char **grid_unit) } } } - - - - - if (v3d->zbuf && scene->obedit) glDepthMask(1); + if (v3d->zbuf && scene->obedit) glDepthMask(1); } static void drawcursor(Scene *scene, ARegion *ar, View3D *v3d) @@ -600,8 +596,8 @@ static void draw_view_axis(RegionView3D *rv3d) mul_qt_v3(rv3d->viewquat, vec); dx = vec[0] * k; dy = vec[1] * k; - - glColor4ub(220, 0, 0, bright); + + UI_ThemeColorShadeAlpha(TH_AXIS_X, 0, bright); glBegin(GL_LINES); glVertex2f(start, start + ydisp); glVertex2f(start + dx, start + dy + ydisp); @@ -620,8 +616,8 @@ static void draw_view_axis(RegionView3D *rv3d) mul_qt_v3(rv3d->viewquat, vec); dx = vec[0] * k; dy = vec[1] * k; - - glColor4ub(0, 220, 0, bright); + + UI_ThemeColorShadeAlpha(TH_AXIS_Y, 0, bright); glBegin(GL_LINES); glVertex2f(start, start + ydisp); glVertex2f(start + dx, start + dy + ydisp); @@ -640,7 +636,7 @@ static void draw_view_axis(RegionView3D *rv3d) dx = vec[0] * k; dy = vec[1] * k; - glColor4ub(30, 30, 220, bright); + UI_ThemeColorShadeAlpha(TH_AXIS_Z, 0, bright); glBegin(GL_LINES); glVertex2f(start, start + ydisp); glVertex2f(start + dx, start + dy + ydisp); @@ -1218,7 +1214,7 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) hmargin = 0.1f * (x2 - x1); vmargin = 0.05f * (y2 - y1); - uiDrawBox(GL_LINE_LOOP, x1 + hmargin, y1+vmargin, x2 - hmargin, y2 - vmargin, 2.0f); + uiDrawBox(GL_LINE_LOOP, x1 + hmargin, y1 + vmargin, x2 - hmargin, y2 - vmargin, 2.0f); hmargin = 0.035f * (x2 - x1); vmargin = 0.035f * (y2 - y1); @@ -2989,10 +2985,10 @@ static void view3d_main_area_draw_objects(const bContext *C, ARegion *ar, const v3d->zbuf = FALSE; /* enables anti-aliasing for 3D view drawing */ -#if 0 - if (!(U.gameflags & USER_DISABLE_AA)) - glEnable(GL_MULTISAMPLE_ARB); -#endif + if (U.ogl_multisamples) + if (!(U.gameflags & USER_DISABLE_AA)) + glEnable(GL_MULTISAMPLE_ARB); + /* needs to be done always, gridview is adjusted in drawgrid() now */ rv3d->gridview = v3d->grid; @@ -3105,12 +3101,12 @@ static void view3d_main_area_draw_objects(const bContext *C, ARegion *ar, const BIF_draw_manipulator(C); -#if 0 /* Disable back anti-aliasing */ - if (!(U.gameflags & USER_DISABLE_AA)) - glDisable(GL_MULTISAMPLE_ARB); -#endif + if (U.ogl_multisamples) + if (!(U.gameflags & USER_DISABLE_AA)) + glDisable(GL_MULTISAMPLE_ARB); + if (v3d->zbuf) { v3d->zbuf = FALSE; glDisable(GL_DEPTH_TEST); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 43626b058d6..53f983912ac 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1064,11 +1064,11 @@ static EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, PointerRNA * static int object_select_menu_exec(bContext *C, wmOperator *op) { int name_index = RNA_enum_get(op->ptr, "name"); - short extend = RNA_boolean_get(op->ptr, "extend"); + short toggle = RNA_boolean_get(op->ptr, "toggle"); short changed = 0; const char *name = object_mouse_select_menu_data[name_index].idname; - if (!extend) { + if (!toggle) { CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { if (base->flag & SELECT) { @@ -1125,7 +1125,7 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); ot->prop = prop; - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first"); + RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "Toggle selection instead of deselecting everything first"); } static void deselectall_except(Scene *scene, Base *b) /* deselect all except b */ @@ -1141,7 +1141,7 @@ static void deselectall_except(Scene *scene, Base *b) /* deselect all except b } } -static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], short extend) +static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], short toggle) { short baseCount = 0; short ok; @@ -1207,7 +1207,7 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int PointerRNA ptr; WM_operator_properties_create(&ptr, "VIEW3D_OT_select_menu"); - RNA_boolean_set(&ptr, "extend", extend); + RNA_boolean_set(&ptr, "toggle", toggle); WM_operator_name_call(C, "VIEW3D_OT_select_menu", WM_OP_INVOKE_DEFAULT, &ptr); WM_operator_properties_free(&ptr); } @@ -1440,7 +1440,7 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese /* note; shift+alt goes to group-flush-selecting */ if (enumerate) { - basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, extend); + basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, toggle); } else { base = startbase; @@ -1480,7 +1480,7 @@ static int mouse_select(bContext *C, const int mval[2], short extend, short dese /* note; shift+alt goes to group-flush-selecting */ if (has_bones == 0 && enumerate) { - basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, extend); + basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle); } else { basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index c16f04f01f3..714898fed21 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -247,9 +247,9 @@ void view3d_smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera copy_qt_qt(rv3d->viewquat, sms.new_quat); rv3d->dist = sms.new_dist; v3d->lens = sms.new_lens; - } - ED_view3d_camera_lock_sync(v3d, rv3d); + ED_view3d_camera_lock_sync(v3d, rv3d); + } if (rv3d->viewlock & RV3D_BOXVIEW) view3d_boxview_copy(sa, ar); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 3b9fe22d6a1..23c764f9252 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -526,6 +526,10 @@ static void viewRedrawPost(bContext *C, TransInfo *t) /* if autokeying is enabled, send notifiers that keyframes were added */ if (IS_AUTOKEY_ON(t->scene)) WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + + /* redraw UV editor */ + if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) + WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); /* XXX temp, first hack to get auto-render in compositor work (ton) */ WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C)); @@ -1220,8 +1224,10 @@ int transformEvent(TransInfo *t, wmEvent *event) break; case LEFTALTKEY: case RIGHTALTKEY: - if (t->spacetype == SPACE_SEQ) + if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) { t->flag |= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + } break; default: @@ -1259,8 +1265,10 @@ int transformEvent(TransInfo *t, wmEvent *event) // break; case LEFTALTKEY: case RIGHTALTKEY: - if (t->spacetype == SPACE_SEQ) + if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) { t->flag &= ~T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + } break; default: @@ -3947,10 +3955,8 @@ void initShrinkFatten(TransInfo *t) } - int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) { - float vec[3]; float distance; int i; char str[64]; @@ -3978,17 +3984,20 @@ int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) t->values[0] = -distance; for (i = 0; i < t->total; i++, td++) { + float tdistance; /* temp dist */ if (td->flag & TD_NOACTION) break; if (td->flag & TD_SKIP) continue; - copy_v3_v3(vec, td->axismtx[2]); - mul_v3_fl(vec, distance); - mul_v3_fl(vec, td->factor); + /* get the final offset */ + tdistance = distance * td->factor; + if (td->ext && (t->flag & T_ALT_TRANSFORM)) { + tdistance *= td->ext->isize[0]; /* shell factor */ + } - add_v3_v3v3(td->loc, td->iloc, vec); + madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance); } recalcData(t); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index f6b888d4881..9bbd3f59cbf 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -1917,6 +1917,10 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx tx->size = vs->radius; td->val = vs->radius; } + else if (t->mode == TFM_SHRINKFATTEN) { + td->ext = tx; + tx->isize[0] = BM_vert_calc_shell_factor(eve); + } } static void createTransEditVerts(TransInfo *t) @@ -2029,7 +2033,11 @@ static void createTransEditVerts(TransInfo *t) else t->total = countsel; tob = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Mesh EditMode)"); - if (t->mode == TFM_SKIN_RESIZE) { + if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) { + /* warning, this is overkill, we only need 2 extra floats, + * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill + * since we may not use the 'alt' transform mode to maintain shell thickness, + * but with generic transform code its hard to lazy init vars */ tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "TransObData ext"); } @@ -5029,9 +5037,10 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t) if (t->scene->nodetree) { /* tracks can be used for stabilization nodes, * flush update for such nodes */ - //if (nodeUpdateID(t->scene->nodetree, &mask->id)) { + //if (nodeUpdateID(t->scene->nodetree, &mask->id)) + { WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id); - //} + } } /* TODO - dont key all masks... */ diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 0780b8f90b5..a3f45acc02e 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -744,7 +744,7 @@ static char axisBlendAngle(float angle) return (char)(255.0f * (angle - 5) / 15.0f); } -/* three colors can be set; +/* three colors can be set: * gray for ghosting * moving: in transform theme color * else the red/green/blue @@ -776,15 +776,13 @@ static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned c } break; case 'X': - col[0] = 220; + UI_GetThemeColor3ubv(TH_AXIS_X, col); break; case 'Y': - col[1] = 220; + UI_GetThemeColor3ubv(TH_AXIS_Y, col); break; case 'Z': - col[0] = 30; - col[1] = 30; - col[2] = 220; + UI_GetThemeColor3ubv(TH_AXIS_Z, col); break; default: BLI_assert(!"invalid axis arg"); diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index aadf547260d..b9774a9f7b0 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -890,7 +890,7 @@ void colormanage_imbuf_make_linear(ImBuf *ibuf, const char *from_colorspace) { ColorSpace *colorspace = colormanage_colorspace_get_named(from_colorspace); - if (colorspace->is_data) { + if (colorspace && colorspace->is_data) { ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; return; } @@ -1083,7 +1083,7 @@ void IMB_colormanagement_check_is_data(ImBuf *ibuf, const char *name) { ColorSpace *colorspace = colormanage_colorspace_get_named(name); - if (colorspace->is_data) + if (colorspace && colorspace->is_data) ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; else ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA; @@ -1095,7 +1095,7 @@ void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name) ibuf->float_colorspace = colorspace; - if (colorspace->is_data) + if (colorspace && colorspace->is_data) ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; else ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA; @@ -1107,7 +1107,7 @@ void IMB_colormanagement_assign_rect_colorspace(ImBuf *ibuf, const char *name) ibuf->rect_colorspace = colorspace; - if (colorspace->is_data) + if (colorspace && colorspace->is_data) ibuf->colormanage_flag |= IMB_COLORMANAGE_IS_DATA; else ibuf->colormanage_flag &= ~IMB_COLORMANAGE_IS_DATA; diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h index 9b90b744b67..0291816cd03 100644 --- a/source/blender/imbuf/intern/dds/BlockDXT.h +++ b/source/blender/imbuf/intern/dds/BlockDXT.h @@ -173,24 +173,24 @@ struct AlphaBlockDXT5 }; */ uint64 u; - uint8 alpha0() const { return u & 0xffLL; }; - uint8 alpha1() const { return (u >> 8) & 0xffLL; }; - uint8 bits0() const { return (u >> 16) & 0x7LL; }; - uint8 bits1() const { return (u >> 19) & 0x7LL; }; - uint8 bits2() const { return (u >> 22) & 0x7LL; }; - uint8 bits3() const { return (u >> 25) & 0x7LL; }; - uint8 bits4() const { return (u >> 28) & 0x7LL; }; - uint8 bits5() const { return (u >> 31) & 0x7LL; }; - uint8 bits6() const { return (u >> 34) & 0x7LL; }; - uint8 bits7() const { return (u >> 37) & 0x7LL; }; - uint8 bits8() const { return (u >> 40) & 0x7LL; }; - uint8 bits9() const { return (u >> 43) & 0x7LL; }; - uint8 bitsA() const { return (u >> 46) & 0x7LL; }; - uint8 bitsB() const { return (u >> 49) & 0x7LL; }; - uint8 bitsC() const { return (u >> 52) & 0x7LL; }; - uint8 bitsD() const { return (u >> 55) & 0x7LL; }; - uint8 bitsE() const { return (u >> 58) & 0x7LL; }; - uint8 bitsF() const { return (u >> 61) & 0x7LL; }; + uint8 alpha0() const { return u & 0xffLL; } + uint8 alpha1() const { return (u >> 8) & 0xffLL; } + uint8 bits0() const { return (u >> 16) & 0x7LL; } + uint8 bits1() const { return (u >> 19) & 0x7LL; } + uint8 bits2() const { return (u >> 22) & 0x7LL; } + uint8 bits3() const { return (u >> 25) & 0x7LL; } + uint8 bits4() const { return (u >> 28) & 0x7LL; } + uint8 bits5() const { return (u >> 31) & 0x7LL; } + uint8 bits6() const { return (u >> 34) & 0x7LL; } + uint8 bits7() const { return (u >> 37) & 0x7LL; } + uint8 bits8() const { return (u >> 40) & 0x7LL; } + uint8 bits9() const { return (u >> 43) & 0x7LL; } + uint8 bitsA() const { return (u >> 46) & 0x7LL; } + uint8 bitsB() const { return (u >> 49) & 0x7LL; } + uint8 bitsC() const { return (u >> 52) & 0x7LL; } + uint8 bitsD() const { return (u >> 55) & 0x7LL; } + uint8 bitsE() const { return (u >> 58) & 0x7LL; } + uint8 bitsF() const { return (u >> 61) & 0x7LL; } void evaluatePalette(uint8 alpha[8]) const; void evaluatePalette8(uint8 alpha[8]) const; diff --git a/source/blender/imbuf/intern/dds/FlipDXT.cpp b/source/blender/imbuf/intern/dds/FlipDXT.cpp index ee7a0ebb2f7..05821b27ca6 100644 --- a/source/blender/imbuf/intern/dds/FlipDXT.cpp +++ b/source/blender/imbuf/intern/dds/FlipDXT.cpp @@ -140,10 +140,10 @@ static void FlipDXT5BlockFull(uint8_t *block) unsigned int line_2_3 = block[5] + 256 * (block[6] + 256 * block[7]); // swap lines 0 and 1 in line_0_1. unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) | - ((line_0_1 & 0xfff000) >> 12); + ((line_0_1 & 0xfff000) >> 12); // swap lines 2 and 3 in line_2_3. unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) | - ((line_2_3 & 0xfff000) >> 12); + ((line_2_3 & 0xfff000) >> 12); block[2] = line_3_2 & 0xff; block[3] = (line_3_2 & 0xff00) >> 8; @@ -162,7 +162,7 @@ static void FlipDXT5BlockHalf(uint8_t *block) // See layout above. unsigned int line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]); unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) | - ((line_0_1 & 0xfff000) >> 12); + ((line_0_1 & 0xfff000) >> 12); block[2] = line_1_0 & 0xff; block[3] = (line_1_0 & 0xff00) >> 8; block[4] = (line_1_0 & 0xff0000) >> 8; diff --git a/source/blender/imbuf/intern/dds/Stream.h b/source/blender/imbuf/intern/dds/Stream.h index 7fed4ca89e7..a1ac49b58da 100644 --- a/source/blender/imbuf/intern/dds/Stream.h +++ b/source/blender/imbuf/intern/dds/Stream.h @@ -35,7 +35,7 @@ struct Stream unsigned char *mem; // location in memory unsigned int size; // size unsigned int pos; // current position - Stream(unsigned char *m, unsigned int s) : mem(m), size(s), pos(0) {}; + Stream(unsigned char *m, unsigned int s) : mem(m), size(s), pos(0) {} unsigned int seek(unsigned int p); }; diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c index 55c1b02e90b..8d289de9970 100644 --- a/source/blender/imbuf/intern/divers.c +++ b/source/blender/imbuf/intern/divers.c @@ -583,23 +583,23 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w if (is_data) { /* exception for non-color data, just copy float */ IMB_buffer_float_from_float(buffer, rect_float, - ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, 0, - w, h, w, ibuf->x); + ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, 0, + w, h, w, ibuf->x); /* 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, - w, h, ibuf->x, w); + 4, ibuf->dither, IB_PROFILE_SRGB, profile_from, predivide, + w, h, ibuf->x, w); } else { IMB_buffer_float_from_float(buffer, rect_float, - ibuf->channels, IB_PROFILE_SRGB, profile_from, predivide, - w, h, w, ibuf->x); + ibuf->channels, IB_PROFILE_SRGB, profile_from, predivide, + w, h, w, ibuf->x); /* XXX: need to convert to image buffer's rect space */ IMB_buffer_byte_from_float(rect_byte, buffer, - 4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0, - w, h, ibuf->x, w); + 4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0, + w, h, ibuf->x, w); } /* ensure user flag is reset */ diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c index 57fbce710a1..a185c4ee3e0 100644 --- a/source/blender/imbuf/intern/imageprocess.c +++ b/source/blender/imbuf/intern/imageprocess.c @@ -43,6 +43,7 @@ #include "BLI_utildefines.h" #include "BLI_threads.h" #include "BLI_listbase.h" +#include "BLI_math.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -95,132 +96,15 @@ static void pixel_from_buffer(struct ImBuf *ibuf, unsigned char **outI, float ** *outF = ibuf->rect_float + offset; } -/************************************************************************** - * INTERPOLATIONS - * - * Reference and docs: - * http://wiki.blender.org/index.php/User:Damiles#Interpolations_Algorithms - ***************************************************************************/ - -/* BICUBIC Interpolation functions - * More info: http://wiki.blender.org/index.php/User:Damiles#Bicubic_pixel_interpolation - * function assumes out to be zero'ed, only does RGBA */ - -static float P(float k) -{ - float p1, p2, p3, p4; - p1 = MAX2(k + 2.0f, 0); - p2 = MAX2(k + 1.0f, 0); - p3 = MAX2(k, 0); - p4 = MAX2(k - 1.0f, 0); - return (float)(1.0f / 6.0f) * (p1 * p1 * p1 - 4.0f * p2 * p2 * p2 + 6.0f * p3 * p3 * p3 - 4.0f * p4 * p4 * p4); -} - - -#if 0 -/* older, slower function, works the same as above */ -static float P(float k) -{ - return (float)(1.0f / 6.0f) * (pow(MAX2(k + 2.0f, 0), 3.0f) - 4.0f * pow(MAX2(k + 1.0f, 0), 3.0f) + 6.0f * pow(MAX2(k, 0), 3.0f) - 4.0f * pow(MAX2(k - 1.0f, 0), 3.0f)); -} -#endif +/* BICUBIC Interpolation */ void bicubic_interpolation_color(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v) { - int i, j, n, m, x1, y1; - unsigned char *dataI; - float a, b, w, wx, wy[4], outR, outG, outB, outA, *dataF; - - /* sample area entirely outside image? */ - if (ceil(u) < 0 || floor(u) > in->x - 1 || ceil(v) < 0 || floor(v) > in->y - 1) { - return; - } - - /* ImBuf in must have a valid rect or rect_float, assume this is already checked */ - - i = (int)floor(u); - j = (int)floor(v); - a = u - i; - b = v - j; - - outR = outG = outB = outA = 0.0f; - -/* Optimized and not so easy to read */ - - /* avoid calling multiple times */ - wy[0] = P(b - (-1)); - wy[1] = P(b - 0); - wy[2] = P(b - 1); - wy[3] = P(b - 2); - - for (n = -1; n <= 2; n++) { - x1 = i + n; - CLAMP(x1, 0, in->x - 1); - wx = P(n - a); - for (m = -1; m <= 2; m++) { - y1 = j + m; - CLAMP(y1, 0, in->y - 1); - /* normally we could do this */ - /* w = P(n-a) * P(b-m); */ - /* except that would call P() 16 times per pixel therefor pow() 64 times, better precalc these */ - w = wx * wy[m + 1]; - - if (outF) { - dataF = in->rect_float + in->x * y1 * 4 + 4 * x1; - outR += dataF[0] * w; - outG += dataF[1] * w; - outB += dataF[2] * w; - outA += dataF[3] * w; - } - if (outI) { - dataI = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x1; - outR += dataI[0] * w; - outG += dataI[1] * w; - outB += dataI[2] * w; - outA += dataI[3] * w; - } - } - } - -/* Done with optimized part */ - -#if 0 - /* older, slower function, works the same as above */ - for (n = -1; n <= 2; n++) { - for (m = -1; m <= 2; m++) { - x1 = i + n; - y1 = j + m; - if (x1 > 0 && x1 < in->x && y1 > 0 && y1 < in->y) { - if (do_float) { - dataF = in->rect_float + in->x * y1 * 4 + 4 * x1; - outR += dataF[0] * P(n - a) * P(b - m); - outG += dataF[1] * P(n - a) * P(b - m); - outB += dataF[2] * P(n - a) * P(b - m); - outA += dataF[3] * P(n - a) * P(b - m); - } - if (do_rect) { - dataI = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x1; - outR += dataI[0] * P(n - a) * P(b - m); - outG += dataI[1] * P(n - a) * P(b - m); - outB += dataI[2] * P(n - a) * P(b - m); - outA += dataI[3] * P(n - a) * P(b - m); - } - } - } - } -#endif - - if (outI) { - outI[0] = (int)outR; - outI[1] = (int)outG; - outI[2] = (int)outB; - outI[3] = (int)outA; - } if (outF) { - outF[0] = outR; - outF[1] = outG; - outF[2] = outB; - outF[3] = outA; + 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); } } @@ -239,77 +123,14 @@ void bicubic_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, in bicubic_interpolation_color(in, outI, outF, u, v); } -/* function assumes out to be zero'ed, only does RGBA */ /* BILINEAR INTERPOLATION */ void bilinear_interpolation_color(struct ImBuf *in, unsigned char outI[4], float outF[4], float u, float v) { - float *row1, *row2, *row3, *row4, a, b; - unsigned char *row1I, *row2I, *row3I, *row4I; - float a_b, ma_b, a_mb, ma_mb; - float empty[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - unsigned char emptyI[4] = {0, 0, 0, 0}; - int y1, y2, x1, x2; - - - /* ImBuf in must have a valid rect or rect_float, assume this is already checked */ - - x1 = (int)floor(u); - x2 = (int)ceil(u); - y1 = (int)floor(v); - y2 = (int)ceil(v); - - /* sample area entirely outside image? */ - if (x2 < 0 || x1 > in->x - 1 || y2 < 0 || y1 > in->y - 1) { - return; - } - if (outF) { - /* sample including outside of edges of image */ - if (x1 < 0 || y1 < 0) row1 = empty; - else row1 = in->rect_float + in->x * y1 * 4 + 4 * x1; - - if (x1 < 0 || y2 > in->y - 1) row2 = empty; - else row2 = in->rect_float + in->x * y2 * 4 + 4 * x1; - - if (x2 > in->x - 1 || y1 < 0) row3 = empty; - else row3 = in->rect_float + in->x * y1 * 4 + 4 * x2; - - if (x2 > in->x - 1 || y2 > in->y - 1) row4 = empty; - else row4 = in->rect_float + in->x * y2 * 4 + 4 * x2; - - a = u - floorf(u); - b = v - floorf(v); - a_b = a * b; ma_b = (1.0f - a) * b; a_mb = a * (1.0f - b); ma_mb = (1.0f - a) * (1.0f - b); - - outF[0] = ma_mb * row1[0] + a_mb * row3[0] + ma_b * row2[0] + a_b * row4[0]; - outF[1] = ma_mb * row1[1] + a_mb * row3[1] + ma_b * row2[1] + a_b * row4[1]; - outF[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2]; - outF[3] = ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3]; + BLI_bilinear_interpolation_fl(in->rect_float, outF, in->x, in->y, 4, u, v); } - if (outI) { - /* sample including outside of edges of image */ - if (x1 < 0 || y1 < 0) row1I = emptyI; - else row1I = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x1; - - if (x1 < 0 || y2 > in->y - 1) row2I = emptyI; - else row2I = (unsigned char *)in->rect + in->x * y2 * 4 + 4 * x1; - - if (x2 > in->x - 1 || y1 < 0) row3I = emptyI; - else row3I = (unsigned char *)in->rect + in->x * y1 * 4 + 4 * x2; - - if (x2 > in->x - 1 || y2 > in->y - 1) row4I = emptyI; - else row4I = (unsigned char *)in->rect + in->x * y2 * 4 + 4 * x2; - - a = u - floorf(u); - b = v - floorf(v); - a_b = a * b; ma_b = (1.0f - a) * b; a_mb = a * (1.0f - b); ma_mb = (1.0f - a) * (1.0f - b); - - /* need to add 0.5 to avoid rounding down (causes darken with the smear brush) - * tested with white images and this should not wrap back to zero */ - outI[0] = (ma_mb * row1I[0] + a_mb * row3I[0] + ma_b * row2I[0] + a_b * row4I[0]) + 0.5f; - outI[1] = (ma_mb * row1I[1] + a_mb * row3I[1] + ma_b * row2I[1] + a_b * row4I[1]) + 0.5f; - outI[2] = (ma_mb * row1I[2] + a_mb * row3I[2] + ma_b * row2I[2] + a_b * row4I[2]) + 0.5f; - outI[3] = (ma_mb * row1I[3] + a_mb * row3I[3] + ma_b * row2I[3] + a_b * row4I[3]) + 0.5f; + else { + BLI_bilinear_interpolation_char((unsigned char*) in->rect, outI, in->x, in->y, 4, u, v); } } diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index 5dda33dfd62..38bd28452f3 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -872,7 +872,7 @@ static void index_rebuild_ffmpeg_proc_decoded_frame( context->frameno = floor((pts - context->start_pts) * context->pts_time_base * - context->frame_rate + 0.5f); + context->frame_rate + 0.5); /* decoding starts *always* on I-Frames, * so: P-Frames won't work, even if all the diff --git a/source/blender/imbuf/intern/jp2.c b/source/blender/imbuf/intern/jp2.c index 692ba3c49ea..d94f6368298 100644 --- a/source/blender/imbuf/intern/jp2.c +++ b/source/blender/imbuf/intern/jp2.c @@ -41,7 +41,7 @@ #include "openjpeg.h" -#define JP2_FILEHEADER_SIZE 14 +// #define JP2_FILEHEADER_SIZE 14 /* UNUSED */ static char JP2_HEAD[] = {0x0, 0x0, 0x0, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A}; static char J2K_HEAD[] = {0xFF, 0x4F, 0xFF, 0x51, 0x00}; diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c index 61275a8937c..d96a01d7093 100644 --- a/source/blender/imbuf/intern/jpeg.c +++ b/source/blender/imbuf/intern/jpeg.c @@ -235,19 +235,19 @@ static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, size_t */ #define INPUT_BYTE(cinfo, V, action) \ MAKESTMT(MAKE_BYTE_AVAIL(cinfo,action); \ - bytes_in_buffer--; \ - V = GETJOCTET(*next_input_byte++); ) + bytes_in_buffer--; \ + V = GETJOCTET(*next_input_byte++); ) /* As above, but read two bytes interpreted as an unsigned 16-bit integer. * V should be declared unsigned int or perhaps INT32. */ #define INPUT_2BYTES(cinfo, V, action) \ MAKESTMT(MAKE_BYTE_AVAIL(cinfo,action); \ - bytes_in_buffer--; \ - V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ - MAKE_BYTE_AVAIL(cinfo, action); \ - bytes_in_buffer--; \ - V += GETJOCTET(*next_input_byte++); ) + bytes_in_buffer--; \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo, action); \ + bytes_in_buffer--; \ + V += GETJOCTET(*next_input_byte++); ) static boolean diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp index 7262656d4e8..21fa878c08a 100644 --- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp @@ -33,25 +33,25 @@ #include "openexr_multi.h" -void * IMB_exr_get_handle (void) {return NULL;} -void IMB_exr_add_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; } +void *IMB_exr_get_handle (void) {return NULL;} +void IMB_exr_add_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; } -int IMB_exr_begin_read (void *handle, const char *filename, int *width, int *height) { (void)handle; (void)filename; (void)width; (void)height; return 0;} -int IMB_exr_begin_write (void *handle, const char *filename, int width, int height, int compress) { (void)handle; (void)filename; (void)width; (void)height; (void)compress; return 0;} -void IMB_exrtile_begin_write (void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley) { (void)handle; (void)filename; (void)mipmap; (void)width; (void)height; (void)tilex; (void)tiley; } +int IMB_exr_begin_read (void *handle, const char *filename, int *width, int *height) { (void)handle; (void)filename; (void)width; (void)height; return 0;} +int IMB_exr_begin_write (void *handle, const char *filename, int width, int height, int compress) { (void)handle; (void)filename; (void)width; (void)height; (void)compress; return 0;} +void IMB_exrtile_begin_write (void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley) { (void)handle; (void)filename; (void)mipmap; (void)width; (void)height; (void)tilex; (void)tiley; } -void IMB_exr_set_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; } +void IMB_exr_set_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) { (void)handle; (void)layname; (void)channame; (void)xstride; (void)ystride; (void)rect; } -void IMB_exr_read_channels (void *handle) { (void)handle; } -void IMB_exr_write_channels (void *handle) { (void)handle; } -void IMB_exrtile_write_channels (void *handle, int partx, int party, int level) { (void)handle; (void)partx; (void)party; (void)level; } -void IMB_exrtile_clear_channels (void *handle) { (void)handle; } +void IMB_exr_read_channels (void *handle) { (void)handle; } +void IMB_exr_write_channels (void *handle) { (void)handle; } +void IMB_exrtile_write_channels (void *handle, int partx, int party, int level) { (void)handle; (void)partx; (void)party; (void)level; } +void IMB_exrtile_clear_channels (void *handle) { (void)handle; } -void IMB_exr_multilayer_convert (void *handle, void *base, - void * (*addlayer)(void *base, const char *str), - void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id)) - { - (void)handle; (void)base; (void)addlayer; (void)addpass; - } +void IMB_exr_multilayer_convert (void *handle, void *base, + void * (*addlayer)(void *base, const char *str), + void (*addpass)(void *base, void *lay, const char *str, float *rect, int totchan, const char *chan_id)) +{ + (void)handle; (void)base; (void)addlayer; (void)addpass; +} -void IMB_exr_close (void *handle) { (void)handle; } +void IMB_exr_close (void *handle) { (void)handle; } diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c index 72cec0e3749..03ed1bb8008 100644 --- a/source/blender/imbuf/intern/radiance_hdr.c +++ b/source/blender/imbuf/intern/radiance_hdr.c @@ -65,7 +65,6 @@ #define BLU 2 #define EXP 3 #define COLXS 128 -#define STR_MAX 540 typedef unsigned char RGBE[4]; typedef float fCOLOR[3]; diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c index 8e072361583..d2b0645cf93 100644 --- a/source/blender/imbuf/intern/rectop.c +++ b/source/blender/imbuf/intern/rectop.c @@ -587,7 +587,7 @@ void IMB_rectfill_area(struct ImBuf *ibuf, const float col[4], int x1, int y1, i { if (!ibuf) return; buf_rectfill_area((unsigned char *) ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, col, display, - x1, y1, x2, y2); + x1, y1, x2, y2); } diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c index 527f334d6a4..b9525ccccf1 100644 --- a/source/blender/imbuf/intern/scaling.c +++ b/source/blender/imbuf/intern/scaling.c @@ -331,13 +331,13 @@ void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1) for (y = ibuf2->y; y > 0; y--) { p2f = p1f + (ibuf1->x << 2); for (x = ibuf2->x; x > 0; x--) { - destf[0] = 0.25f * (p1f[0] + p2f[0] + p1f[4] + p2f[4]); - destf[1] = 0.25f * (p1f[1] + p2f[1] + p1f[5] + p2f[5]); - destf[2] = 0.25f * (p1f[2] + p2f[2] + p1f[6] + p2f[6]); - destf[3] = 0.25f * (p1f[3] + p2f[3] + p1f[7] + p2f[7]); - p1f += 8; - p2f += 8; - destf += 4; + destf[0] = 0.25f * (p1f[0] + p2f[0] + p1f[4] + p2f[4]); + destf[1] = 0.25f * (p1f[1] + p2f[1] + p1f[5] + p2f[5]); + destf[2] = 0.25f * (p1f[2] + p2f[2] + p1f[6] + p2f[6]); + destf[3] = 0.25f * (p1f[3] + p2f[3] + p1f[7] + p2f[7]); + p1f += 8; + p2f += 8; + destf += 4; } p1f = p2f; if (ibuf1->x & 1) p1f += 4; diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 3cf84648ea6..deb9902c35d 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -201,8 +201,8 @@ typedef struct Curve { float twist_smooth, smallcaps_scale; int pathlen; - short pad, totcol; - short flag, bevresol; + short bevresol, totcol; + int flag; float width, ext1, ext2; /* default */ @@ -269,6 +269,7 @@ typedef struct Curve { #define CU_PATH_RADIUS 4096 /* make use of the path radius if this is enabled (default for new curves) */ #define CU_DEFORM_FILL 8192 /* fill 2d curve after deformation */ #define CU_FILL_CAPS 16384 /* fill bevel caps */ +#define CU_MAP_TAPER 32768 /* map taper object to bevelled area */ /* twist mode */ #define CU_TWIST_Z_UP 0 diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 100968e7257..b7c1ee675b3 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -41,6 +41,7 @@ typedef struct bGPDspoint { float x, y, z; /* co-ordinates of point (usually 2d, but can be 3d as well) */ float pressure; /* pressure of input device (from 0 to 1) at this point */ + float time; /* seconds since start of stroke */ } bGPDspoint; /* Grease-Pencil Annotations - 'Stroke' @@ -55,6 +56,7 @@ typedef struct bGPDstroke { short thickness; /* thickness of stroke (currently not used) */ short flag; /* various settings about this stroke */ + double inittime; /* Init time of stroke */ } bGPDstroke; /* bGPDstroke->flag */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index c9e929ce41b..2c896e4893f 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -665,7 +665,8 @@ typedef struct ShrinkwrapModifierData { float keepDist; /* distance offset to keep from mesh/projection point */ short shrinkType; /* shrink type projection */ short shrinkOpts; /* shrink options */ - char projAxis; /* axis to project over */ + float projLimit; /* limit the projection ray cast */ + char projAxis; /* axis to project over */ /* * if using projection over vertex normal this controls the @@ -674,7 +675,7 @@ typedef struct ShrinkwrapModifierData { */ char subsurfLevels; - char pad[6]; + char pad[2]; } ShrinkwrapModifierData; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 29f6499986c..89328c33674 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -297,22 +297,19 @@ typedef struct ObHook { typedef struct DupliObject { struct DupliObject *next, *prev; struct Object *ob; - unsigned int origlay; - int index; + unsigned int origlay, pad; float mat[4][4], omat[4][4]; float orco[3], uv[2]; short type; /* from Object.transflag */ char no_draw, animated; - /* Lowest-level particle index. - * Note: This is needed for particle info in shaders. - * Otherwise dupli groups in particle systems would override the - * index value from higher dupli levels. Would be nice to have full generic access - * to all dupli levels somehow, but for now this should cover most use-cases. - */ - int particle_index; - int pad; + /* persistent identifier for a dupli object, for inter-frame matching of + * objects with motion blur, or inter-update matching for syncing */ + int persistent_id[8]; /* MAX_DUPLI_RECUR */ + + /* particle this dupli was generated from */ + struct ParticleSystem *particle_system; } DupliObject; /* **************** OBJECT ********************* */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index facddd8c718..c9e00e5f545 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1196,11 +1196,12 @@ typedef struct Scene { /* Use the same flag for autothreads */ #define R_FIXED_THREADS 0x80000 -#define R_SPEED 0x100000 -#define R_SSS 0x200000 -#define R_NO_OVERWRITE 0x400000 /* skip existing files */ -#define R_TOUCH 0x800000 /* touch files before rendering */ -#define R_SIMPLIFY 0x1000000 +#define R_SPEED 0x100000 +#define R_SSS 0x200000 +#define R_NO_OVERWRITE 0x400000 /* skip existing files */ +#define R_TOUCH 0x800000 /* touch files before rendering */ +#define R_SIMPLIFY 0x1000000 +#define R_PERSISTENT_DATA 0x2000000 /* keep data around for re-render */ #define R_EDGE_FRS 0x2000000 /* R_EDGE for Freestyle */ /* seq_flag */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 98c135fcf53..1770a6e497c 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -162,7 +162,8 @@ typedef struct ThemeUI { char iconfile[256]; // FILE_MAXFILE length float icon_alpha; - float pad; + /* Axis Colors */ + char xaxis[4], yaxis[4], zaxis[4]; } ThemeUI; /* try to put them all in one, if needed a special struct can be created as well @@ -418,9 +419,11 @@ typedef struct UserDef { float ndof_sensitivity; /* overall sensitivity of 3D mouse */ float ndof_orbit_sensitivity; - float pad4; int ndof_flag; /* flags for 3D mouse */ + short ogl_multisamples; /* amount of samples for OpenGL FSA, if zero no FSA */ + short pad4; + float glalphaclip; short autokey_mode; /* autokeying mode */ @@ -703,6 +706,17 @@ typedef enum eCompute_Device_Type { USER_COMPUTE_DEVICE_CUDA = 2, } eCompute_Device_Type; + +typedef enum eMultiSample_Type { + USER_MULTISAMPLE_NONE = 0, + USER_MULTISAMPLE_2 = 2, + USER_MULTISAMPLE_4 = 4, + USER_MULTISAMPLE_8 = 8, + USER_MULTISAMPLE_16 = 16, +} eMultiSample_Type; + + + #ifdef __cplusplus } #endif diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 188c11911b1..de91c17553e 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -1003,7 +1003,7 @@ static int make_structDNA(char *baseDirectory, FILE *file) /* FOR DEBUG */ if (debugSDNA > 1) { int a, b; -/* short *elem; */ + /* short *elem; */ short num_types; printf("nr_names %d nr_types %d nr_structs %d\n", nr_names, nr_types, nr_structs); diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 317204b36dc..c057739a28f 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -80,13 +80,15 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F const char *name_override, int close_prototype); /* helpers */ -#define WRITE_COMMA { \ +#define WRITE_COMMA \ + { \ if (!first) \ fprintf(f, ", "); \ first = 0; \ } (void)0 -#define WRITE_PARAM(param) { \ +#define WRITE_PARAM(param) \ + { \ WRITE_COMMA; \ fprintf(f, param); \ } @@ -3580,10 +3582,10 @@ static void rna_generate_header_class_cpp(StructDefRNA *ds, FILE *f) fprintf(f, "class %s : public %s {\n", srna->identifier, (srna->base) ? srna->base->identifier : "Pointer"); fprintf(f, "public:\n"); fprintf(f, "\t%s(const PointerRNA &ptr_arg) :\n\t\t%s(ptr_arg)", srna->identifier, - (srna->base) ? srna->base->identifier : "Pointer"); + (srna->base) ? srna->base->identifier : "Pointer"); for (dp = ds->cont.properties.first; dp; dp = dp->next) if (rna_is_collection_prop(dp->prop)) - fprintf(f, ",\n\t\t%s(ptr_arg)", dp->prop->identifier); + fprintf(f, ",\n\t\t%s(ptr_arg)", dp->prop->identifier); fprintf(f, "\n\t\t{}\n\n"); for (dp = ds->cont.properties.first; dp; dp = dp->next) diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 1fe46342819..81e738ed82f 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1224,10 +1224,10 @@ void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA if (prop->translation_context) nitem[i].name = BLF_pgettext(prop->translation_context, nitem[i].name); else - nitem[i].name = BLF_gettext(nitem[i].name); + nitem[i].name = BLF_pgettext(NULL, nitem[i].name); } if (nitem[i].description) - nitem[i].description = BLF_gettext(nitem[i].description); + nitem[i].description = BLF_pgettext(NULL, nitem[i].description); } *item = nitem; @@ -4011,12 +4011,15 @@ static char *rna_idp_path(PointerRNA *ptr, IDProperty *haystack, IDProperty *nee BLI_assert(haystack->type == IDP_GROUP); link.up = parent_link; + /* always set both name and index, + * else a stale value might get used */ link.name = NULL; link.index = -1; for (i = 0, iter = haystack->data.group.first; iter; iter = iter->next, i++) { if (needle == iter) { /* found! */ link.name = iter->name; + link.index = -1; path = rna_idp_path_create(&link); break; } @@ -4026,6 +4029,7 @@ static char *rna_idp_path(PointerRNA *ptr, IDProperty *haystack, IDProperty *nee PointerRNA child_ptr = RNA_pointer_get(ptr, iter->name); if (child_ptr.type) { link.name = iter->name; + link.index = -1; if ((path = rna_idp_path(&child_ptr, iter, needle, &link))) { break; } diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index e96ed4f38d3..7bdebd620ee 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -146,8 +146,8 @@ static int rna_SculptCapabilities_has_overlay_get(PointerRNA *ptr) { Brush *br = (Brush *)ptr->data; return ELEM(br->mtex.brush_map_mode, - MTEX_MAP_MODE_VIEW, - MTEX_MAP_MODE_TILED); + MTEX_MAP_MODE_VIEW, + MTEX_MAP_MODE_TILED); } static int rna_SculptCapabilities_has_persistence_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index a3cff99ddc8..1e1a8c82b8e 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -1422,6 +1422,11 @@ static void rna_def_curve(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Fill Caps", "Fill caps for beveled curves"); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); + prop = RNA_def_property(srna, "use_map_taper", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CU_MAP_TAPER); + RNA_def_property_ui_text(prop, "Map Taper", "Map effect of taper object on actually bevelled curve"); + RNA_def_property_update(prop, 0, "rna_Curve_update_data"); + /* texture space */ prop = RNA_def_property(srna, "use_auto_texspace", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "texflag", CU_AUTOSPACE); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index a6f4a88e6c3..d939b1073fc 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -2824,7 +2824,7 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "skin_vertices", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "vdata.layers", "vdata.totlayer"); RNA_def_property_collection_funcs(prop, "rna_Mesh_skin_vertices_begin", NULL, NULL, NULL, - "rna_Mesh_skin_vertices_length", NULL, NULL, NULL); + "rna_Mesh_skin_vertices_length", NULL, NULL, NULL); RNA_def_property_struct_type(prop, "MeshSkinVertexLayer"); RNA_def_property_ui_text(prop, "Skin Vertices", "All skin vertices"); rna_def_skin_vertices(brna, prop); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index d421eb697a3..2e3f8feda44 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -2400,6 +2400,13 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Offset", "Distance to keep from the target"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "project_limit", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "projLimit"); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_range(prop, 0, 100, 1, 2); + RNA_def_property_ui_text(prop, "Project Limit", "Limit the distance used for projection (zero disables)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "use_project_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "projAxis", MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS); RNA_def_property_ui_text(prop, "X", ""); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index d241f697be0..a68bcf62df8 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -220,6 +220,7 @@ EnumPropertyItem prop_wave_items[] = { #include "ED_node.h" +#include "RE_engine.h" #include "RE_pipeline.h" #include "DNA_scene_types.h" @@ -1133,6 +1134,22 @@ static IDProperty *rna_ShaderNodeScript_idprops(PointerRNA *ptr, int create) return nss->prop; } +static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + bNodeTree *ntree = (bNodeTree *)ptr->id.data; + bNode *node = (bNode *)ptr->data; + RenderEngineType *engine_type = RE_engines_find(scene->r.engine); + + if (engine_type && engine_type->update_script_node) { + /* auto update node */ + RenderEngine *engine = RE_engine_create(engine_type); + engine_type->update_script_node(engine, ntree, node); + RE_engine_free(engine); + } + + node_update(bmain, scene, ntree, node); +} + #else static EnumPropertyItem prop_image_layer_items[] = { @@ -1204,7 +1221,7 @@ typedef struct NodeInfo { static NodeInfo nodes[MaxNodes]; static void reg_node(int ID, int category, const char *enum_name, const char *struct_name, - const char *base_name, const char *ui_name, const char *ui_desc) + const char *base_name, const char *ui_name, const char *ui_desc) { NodeInfo *ni = nodes + ID; @@ -1930,14 +1947,14 @@ static void def_sh_script(StructRNA *srna) RNA_def_property_struct_type(prop, "Text"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Script", "Internal shader script to define the shader"); - RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodeScript_update"); RNA_def_struct_sdna_from(srna, "NodeShaderScript", "storage"); RNA_def_struct_idprops_func(srna, "rna_ShaderNodeScript_idprops"); prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); RNA_def_property_ui_text(prop, "File Path", "Shader script path"); - RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodeScript_update"); prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_funcs(prop, NULL, "rna_ShaderNodeScript_mode_set", NULL); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 82f27b953cf..d436e4719ea 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1419,6 +1419,12 @@ int rna_Camera_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value) return ((Object *)value.id.data)->type == OB_CAMERA; } +int rna_DupliObject_index_get(PointerRNA *ptr) +{ + DupliObject *dob = (DupliObject *)ptr->data; + return dob->persistent_id[0]; +} + #else static int rna_matrix_dimsize_4x4[] = {4, 4}; @@ -2653,22 +2659,23 @@ static void rna_def_dupli_object(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hide", "Don't show dupli object in viewport or render"); prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "index"); + RNA_def_property_int_funcs(prop, "rna_DupliObject_index_get", NULL, NULL); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); RNA_def_property_ui_text(prop, "Index", "Index in the lowest-level dupli list"); - - prop = RNA_def_property(srna, "particle_index", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "particle_index"); + + prop = RNA_def_property(srna, "persistent_id", PROP_INT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Persistent ID", "Persistent identifier for inter-frame matching of objects with motion blur"); + + prop = RNA_def_property(srna, "particle_system", PROP_POINTER, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Particle Index", "Index in the lowest-level particle dupli list"); + RNA_def_property_ui_text(prop, "Particle System", "Particle system that this dupli object was instanced from"); prop = RNA_def_property(srna, "orco", PROP_FLOAT, PROP_TRANSLATION); - RNA_def_property_float_sdna(prop, NULL, "orco"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); RNA_def_property_ui_text(prop, "Generated Coordinates", "Generated coordinates in parent object space"); prop = RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "uv"); RNA_def_property_array(prop, 2); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); RNA_def_property_ui_text(prop, "UV Coordinates", "UV coordinates in parent object space"); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 516f619d910..6011af2626e 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1257,6 +1257,12 @@ static void rna_Scene_simplify_update(Main *bmain, Scene *scene, PointerRNA *ptr rna_Scene_use_simplify_update(bmain, scene, ptr); } +static void rna_Scene_use_persistent_data_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) +{ + if (!(scene->r.mode & R_PERSISTENT_DATA)) + RE_FreePersistentData(); +} + static int rna_Scene_use_audio_get(PointerRNA *ptr) { Scene *scene = (Scene *)ptr->data; @@ -4483,6 +4489,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "simplify_flag", R_SIMPLE_NO_TRIANGULATE); RNA_def_property_ui_text(prop, "Skip Quad to Triangles", "Disable non-planar quads being triangulated"); + /* persistent data */ + prop = RNA_def_property(srna, "use_persistent_data", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", R_PERSISTENT_DATA); + RNA_def_property_ui_text(prop, "Persistent Data", "Keep render data around for faster re-renders"); + RNA_def_property_update(prop, 0, "rna_Scene_use_persistent_data_update"); + /* Freestyle line thickness options */ prop = RNA_def_property(srna, "line_thickness_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "line_thickness_mode"); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 2a8f1b90d4e..548539e3395 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -390,7 +390,7 @@ void RNA_api_ui_layout(StructRNA *srna) parm = RNA_def_int(func, "active_layer", 0, 0, INT_MAX, "Active Layer", "", 0, INT_MAX); RNA_def_property_flag(parm, PROP_REQUIRED); - func = RNA_def_function(srna, "template_color_wheel", "uiTemplateColorWheel"); + func = RNA_def_function(srna, "template_color_picker", "uiTemplateColorPicker"); RNA_def_function_ui_description(func, "Item. A color wheel widget to pick colors"); api_ui_item_rna_common(func); RNA_def_boolean(func, "value_slider", 0, "", "Display the value slider to the right of the color wheel"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 52953144261..de53ef1f90a 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -395,7 +395,7 @@ static EnumPropertyItem *rna_userdef_compute_device_itemf(bContext *UNUSED(C), P int a; if (devices) { - for (a = 0; devices[a].name; a++) { + for (a = 0; devices[a].identifier[0]; a++) { tmp.value = devices[a].value; tmp.identifier = devices[a].identifier; tmp.name = devices[a].name; @@ -770,6 +770,25 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna) prop = RNA_def_property(srna, "icon_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_ui_text(prop, "Icon Alpha", "Transparency of icons in the interface, to reduce contrast"); RNA_def_property_update(prop, 0, "rna_userdef_update"); + + /* axis */ + prop = RNA_def_property(srna, "axis_x", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "xaxis"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "X Axis", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "axis_y", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "yaxis"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Y Axis", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + + prop = RNA_def_property(srna, "axis_z", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "zaxis"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Z Axis", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); } static void rna_def_userdef_theme_space_generic(BlenderRNA *brna) @@ -3009,6 +3028,15 @@ static void rna_def_userdef_system(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem multi_sample_levels[] = { + {USER_MULTISAMPLE_NONE, "NONE", 0, "No MultiSample", "Do not use OpenGL MultiSample"}, + {USER_MULTISAMPLE_2, "2", 0, "MultiSample: 2", "Use 2x OpenGL MultiSample (requires restart)"}, + {USER_MULTISAMPLE_4, "4", 0, "MultiSample: 4", "Use 4x OpenGL MultiSample (requires restart)"}, + {USER_MULTISAMPLE_8, "8", 0, "MultiSample: 8", "Use 8x OpenGL MultiSample (requires restart)"}, + {USER_MULTISAMPLE_16, "16", 0, "MultiSample: 16", "Use 16x OpenGL MultiSample (requires restart)"}, + {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 */ @@ -3153,6 +3181,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_enum_items(prop, color_picker_types); RNA_def_property_enum_sdna(prop, NULL, "color_picker_type"); RNA_def_property_ui_text(prop, "Color Picker Type", "Different styles of displaying the color picker widget"); + RNA_def_property_update(prop, 0, "rna_userdef_update"); prop = RNA_def_property(srna, "use_preview_images", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ALLWINCODECS); @@ -3302,6 +3331,12 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased"); RNA_def_property_update(prop, 0, "rna_userdef_text_update"); + /* Full scene anti-aliasing */ + prop = RNA_def_property(srna, "multi_sample", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "ogl_multisamples"); + RNA_def_property_enum_items(prop, multi_sample_levels); + RNA_def_property_ui_text(prop, "MultiSample", "Enable OpenGL multi-sampling, only for systems that support it, requires restart"); + #ifdef WITH_CYCLES prop = RNA_def_property(srna, "compute_device_type", PROP_ENUM, PROP_NONE); RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); @@ -3431,7 +3466,7 @@ static void rna_def_userdef_input(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_SHOW_GUIDE); RNA_def_property_ui_text(prop, "Show Navigation Guide", "Display the center and axis during rotation"); /* TODO: update description when fly-mode visuals are in place ("projected position in fly mode")*/ - + /* 3D view */ prop = RNA_def_property(srna, "ndof_view_rotate_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "ndof_flag"); diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 92ad6faa3ce..1298d281de8 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -205,7 +205,8 @@ static MFace *get_dface(DerivedMesh *dm, DerivedMesh *split, int cur, int i, MFa return df; } -#define SET_VERTS(a, b, c, d) { \ +#define SET_VERTS(a, b, c, d) \ + { \ v[0] = mf->v##a; uv[0] = a - 1; \ v[1] = mf->v##b; uv[1] = b - 1; \ v[2] = mf->v##c; uv[2] = c - 1; \ diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 8a4d70da6e8..38ec0e8bb4c 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -644,8 +644,8 @@ typedef struct { } EdgeStackElem; static void build_emats_stack(BLI_Stack *stack, int *visited_e, EMat *emat, - const MeshElemMap *emap, const MEdge *medge, - const MVertSkin *vs, const MVert *mvert) + const MeshElemMap *emap, const MEdge *medge, + const MVertSkin *vs, const MVert *mvert) { EdgeStackElem stack_elem; float axis[3], angle; @@ -673,7 +673,7 @@ static void build_emats_stack(BLI_Stack *stack, int *visited_e, EMat *emat, /* If parent is a branch node, start a new edge chain */ if (parent_is_branch) { calc_edge_mat(emat[e].mat, mvert[parent_v].co, - mvert[v].co); + mvert[v].co); } else { /* Build edge matrix guided by parent matrix */ @@ -959,12 +959,12 @@ static void add_poly(SkinOutput *so, static void connect_frames(SkinOutput *so, BMVert *frame1[4], - BMVert *frame2[4]) +BMVert *frame2[4]) { BMVert *q[4][4] = {{frame2[0], frame2[1], frame1[1], frame1[0]}, - {frame2[1], frame2[2], frame1[2], frame1[1]}, - {frame2[2], frame2[3], frame1[3], frame1[2]}, - {frame2[3], frame2[0], frame1[0], frame1[3]}}; + {frame2[1], frame2[2], frame1[2], frame1[1]}, + {frame2[2], frame2[3], frame1[3], frame1[2]}, + {frame2[3], frame2[0], frame1[0], frame1[3]}}; float p[3], no[3]; int i, swap; @@ -1354,24 +1354,6 @@ static void add_quad_from_tris(SkinOutput *so, BMEdge *e, BMFace *adj[2]) add_poly(so, quad[0], quad[1], quad[2], quad[3]); } -/* Returns the number of faces that are adjacent to both f1 and f2 */ -static int BM_face_share_face_count(BMFace *f1, BMFace *f2) -{ - BMIter iter1, iter2; - BMEdge *e; - BMFace *f; - int count = 0; - - BM_ITER_ELEM (e, &iter1, f1, BM_EDGES_OF_FACE) { - BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) { - if (f != f1 && f != f2 && BM_face_share_edge_count(f, f2)) - count++; - } - } - - return count; -} - static void hull_merge_triangles(SkinOutput *so, const SkinModifierData *smd) { BMIter iter; @@ -1434,7 +1416,7 @@ static void hull_merge_triangles(SkinOutput *so, const SkinModifierData *smd) * share a border with another face, output as a quad */ if (!BM_elem_flag_test(adj[0], BM_ELEM_TAG) && !BM_elem_flag_test(adj[1], BM_ELEM_TAG) && - !BM_face_share_face_count(adj[0], adj[1])) + !BM_face_share_face_check(adj[0], adj[1])) { add_quad_from_tris(so, e, adj); BM_elem_flag_enable(adj[0], BM_ELEM_TAG); diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index cc77d73a736..fbd3c084e70 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -207,9 +207,10 @@ BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f) r[2] += (float)a[2] * f; } -static DerivedMesh *applyModifier(ModifierData *md, Object *ob, - DerivedMesh *dm, - ModifierApplyFlag UNUSED(flag)) +static DerivedMesh *applyModifier( + ModifierData *md, Object *ob, + DerivedMesh *dm, + ModifierApplyFlag UNUSED(flag)) { int i; DerivedMesh *result; diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.c b/source/blender/nodes/composite/nodes/node_composite_colorSpill.c index e8965d50b47..44a5ac9e968 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.c +++ b/source/blender/nodes/composite/nodes/node_composite_colorSpill.c @@ -29,12 +29,8 @@ * \ingroup cmpnodes */ - - #include "node_composite_util.h" -#define AVG(a, b) ((a + b) / 2) - /* ******************* Color Spill Supression ********************************* */ static bNodeSocketTemplate cmp_node_color_spill_in[] = { {SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, @@ -49,6 +45,9 @@ static bNodeSocketTemplate cmp_node_color_spill_out[] = { #ifdef WITH_COMPOSITOR_LEGACY +#define AVG(a, b) ((a + b) / 2) + + static void do_simple_spillmap_red(bNode *node, float* out, float *in) { NodeColorspill *ncs; diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c index 24ed825c36e..b0605f9b248 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bump.c +++ b/source/blender/nodes/shader/nodes/node_shader_bump.c @@ -36,7 +36,7 @@ /* **************** BUMP ******************** */ static bNodeSocketTemplate sh_node_bump_in[] = { - { SOCK_FLOAT, 1, "Strength", 0.1f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f}, + { SOCK_FLOAT, 1, "Strength", 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f}, { SOCK_FLOAT, 1, "Height", 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE}, { -1, 0, "" } }; diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c index 39fd8a5decc..ee83699abdb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c @@ -30,6 +30,7 @@ /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_normal_map_in[] = { + { SOCK_FLOAT, 1, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.0f}, { SOCK_RGBA, 0, N_("Color"), 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f}, { -1, 0, "" } }; diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 3b8193c422d..b8537a1359f 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -504,7 +504,7 @@ void PyC_SetHomePath(const char *py_path_bundle) * but current Python lib (release 3.1.1) doesn't handle these correctly */ if (strchr(py_path_bundle, ':')) printf("Warning : Blender application is located in a path containing : or / chars\ - \nThis may make python import function fail\n"); + \nThis may make python import function fail\n"); #endif diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index f5c77d49c21..9d1e2b8e620 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -170,6 +170,8 @@ void RE_FreeRender (struct Render *re); void RE_FreeAllRender (void); /* only call on file load */ void RE_FreeAllRenderResults(void); +/* for external render engines that can keep persistent data */ +void RE_FreePersistentData(void); /* get results and statistics */ void RE_FreeRenderResult(struct RenderResult *rr); diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 7f785eb3d8b..f7a5a930ac6 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -59,6 +59,7 @@ struct RenderBuckets; struct ObjectInstanceRen; struct RayObject; struct RayFace; +struct RenderEngine; struct ReportList; struct Main; @@ -183,6 +184,9 @@ struct Render ListBase parts; + /* render engine */ + struct RenderEngine *engine; + /* octree tables and variables for raytrace */ struct RayObject *raytree; struct RayFace *rayfaces; diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index bb7c1bdf94b..47bff762d13 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -4561,7 +4561,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject * ParticleSystem *psys; int show_emitter, allow_render= 1, index, psysindex, i; - index= (dob)? dob->index: 0; + index= (dob)? dob->persistent_id[0]: 0; /* the emitter has to be processed first (render levels of modifiers) */ /* so here we only check if the emitter should be rendered */ @@ -4960,7 +4960,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, 0))) { mult_m4_m4m4(mat, re->viewmat, dob->mat); /* ob = particle system, use that layer */ - obi= RE_addRenderInstance(re, NULL, obd, ob, dob->index, 0, mat, ob->lay); + obi= RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], 0, mat, ob->lay); /* fill in instance variables for texturing */ set_dupli_tex_mat(re, obi, dob); @@ -4987,7 +4987,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp if (dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, psysindex))) { if (obi == NULL) mult_m4_m4m4(mat, re->viewmat, dob->mat); - obi= RE_addRenderInstance(re, NULL, obd, ob, dob->index, psysindex++, mat, obd->lay); + obi= RE_addRenderInstance(re, NULL, obd, ob, dob->persistent_id[0], psysindex++, mat, obd->lay); set_dupli_tex_mat(re, obi, dob); if (dob->type != OB_DUPLIGROUP) { diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index e2f347c05f1..8bdb805ada2 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -349,7 +349,12 @@ int RE_engine_render(Render *re, int do_all) re->i.totface = re->i.totvert = re->i.totstrand = re->i.totlamp = re->i.tothalo = 0; /* render */ - engine = RE_engine_create(type); + if (!re->engine) + re->engine = RE_engine_create(type); + + engine = re->engine; + + /* TODO: actually link to a parent which shouldn't happen */ engine->re = re; if (re->flag & R_ANIMATION) @@ -377,6 +382,11 @@ int RE_engine_render(Render *re, int do_all) if (type->render) type->render(engine, re->scene); + if (!(re->r.mode & R_PERSISTENT_DATA)) { + RE_engine_free(re->engine); + re->engine = NULL; + } + if (re->result->do_exr_tile) { BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); render_result_exr_file_end(re); @@ -389,8 +399,6 @@ int RE_engine_render(Render *re, int do_all) render_result_free_list(&engine->fullresult, engine->fullresult.first); - RE_engine_free(engine); - if (BKE_reports_contain(re->reports, RPT_ERROR)) G.is_break = TRUE; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 9dab18b3c2c..aab7f442249 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -247,6 +247,7 @@ Render *RE_GetRender(const char *name) return re; } + /* if you want to know exactly what has been done */ RenderResult *RE_AcquireResultRead(Render *re) { @@ -390,6 +391,9 @@ void RE_InitRenderCB(Render *re) /* only call this while you know it will remove the link too */ void RE_FreeRender(Render *re) { + if (re->engine) + RE_engine_free(re->engine); + BLI_rw_mutex_end(&re->resultmutex); free_renderdata_tables(re); @@ -424,6 +428,19 @@ void RE_FreeAllRenderResults(void) } } +void RE_FreePersistentData(void) +{ + Render *re; + + /* render engines can be kept around for quick re-render, this clears all */ + for (re = RenderGlobal.renderlist.first; re; re = re->next) { + if (re->engine) { + RE_engine_free(re->engine); + re->engine = NULL; + } + } +} + /* ********* initialize state ******** */ diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index b486407c61c..42849a01971 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -265,7 +265,7 @@ static void init_frame_smoke(VoxelData *vd, float cfra) /* map velocities between 0 and 0.3f */ for (i = 0; i < totRes; i++) { - vd->dataset[i] = sqrt(xvel[i] * xvel[i] + yvel[i] * yvel[i] + zvel[i] * zvel[i]) * 3.0f; + vd->dataset[i] = sqrtf(xvel[i] * xvel[i] + yvel[i] * yvel[i] + zvel[i] * zvel[i]) * 3.0f; } } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index d7285ec4380..60e3f7d6164 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -711,12 +711,14 @@ static int wm_automatic_draw_method(wmWindow *win) if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) return USER_DRAW_OVERLAP; /* also Intel drivers are slow */ + /* 2.64 BCon3 period, let's try if intel now works... else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_UNIX, GPU_DRIVER_ANY)) return USER_DRAW_OVERLAP; else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) return USER_DRAW_OVERLAP_FLIP; else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY)) return USER_DRAW_OVERLAP_FLIP; + */ /* Windows software driver darkens color on each redraw */ else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE)) return USER_DRAW_OVERLAP_FLIP; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 7cfa3ce9396..54e61df4f6a 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1279,74 +1279,6 @@ int WM_userdef_event_map(int kmitype) return kmitype; } -static void wm_eventemulation(wmEvent *event) -{ - /* Store last mmb event value to make emulation work when modifier keys are released first. */ - static int mmb_emulated = 0; /* this should be in a data structure somwhere */ - - /* middlemouse emulation */ - if (U.flag & USER_TWOBUTTONMOUSE) { - if (event->type == LEFTMOUSE) { - - if (event->val == KM_PRESS && event->alt) { - event->type = MIDDLEMOUSE; - event->alt = 0; - mmb_emulated = 1; - } - else if (event->val == KM_RELEASE) { - /* only send middle-mouse release if emulated */ - if (mmb_emulated) { - event->type = MIDDLEMOUSE; - event->alt = 0; - } - mmb_emulated = 0; - } - } - - } - -#ifdef __APPLE__ - - /* rightmouse emulation */ - if (U.flag & USER_TWOBUTTONMOUSE) { - if (event->type == LEFTMOUSE) { - - if (event->val == KM_PRESS && event->oskey) { - event->type = RIGHTMOUSE; - event->oskey = 0; - mmb_emulated = 1; - } - else if (event->val == KM_RELEASE) { - if (mmb_emulated) { - event->oskey = RIGHTMOUSE; - event->alt = 0; - } - mmb_emulated = 0; - } - } - - } -#endif - - /* numpad emulation */ - if (U.flag & USER_NONUMPAD) { - switch (event->type) { - case ZEROKEY: event->type = PAD0; break; - case ONEKEY: event->type = PAD1; break; - case TWOKEY: event->type = PAD2; break; - case THREEKEY: event->type = PAD3; break; - case FOURKEY: event->type = PAD4; break; - case FIVEKEY: event->type = PAD5; break; - case SIXKEY: event->type = PAD6; break; - case SEVENKEY: event->type = PAD7; break; - case EIGHTKEY: event->type = PAD8; break; - case NINEKEY: event->type = PAD9; break; - case MINUSKEY: event->type = PADMINUS; break; - case EQUALKEY: event->type = PADPLUSKEY; break; - case BACKSLASHKEY: event->type = PADSLASHKEY; break; - } - } -} static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi) { @@ -2113,8 +2045,6 @@ void wm_event_do_handlers(bContext *C) } #endif - wm_eventemulation(event); - CTX_wm_window_set(C, win); /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */ @@ -2616,6 +2546,75 @@ static int convert_key(GHOST_TKey key) } } +static void wm_eventemulation(wmEvent *event) +{ + /* Store last mmb event value to make emulation work when modifier keys are released first. */ + static int mmb_emulated = 0; /* this should be in a data structure somwhere */ + + /* middlemouse emulation */ + if (U.flag & USER_TWOBUTTONMOUSE) { + if (event->type == LEFTMOUSE) { + + if (event->val == KM_PRESS && event->alt) { + event->type = MIDDLEMOUSE; + event->alt = 0; + mmb_emulated = 1; + } + else if (event->val == KM_RELEASE) { + /* only send middle-mouse release if emulated */ + if (mmb_emulated) { + event->type = MIDDLEMOUSE; + event->alt = 0; + } + mmb_emulated = 0; + } + } + + } + +#ifdef __APPLE__ + + /* rightmouse emulation */ + if (U.flag & USER_TWOBUTTONMOUSE) { + if (event->type == LEFTMOUSE) { + + if (event->val == KM_PRESS && event->oskey) { + event->type = RIGHTMOUSE; + event->oskey = 0; + mmb_emulated = 1; + } + else if (event->val == KM_RELEASE) { + if (mmb_emulated) { + event->oskey = RIGHTMOUSE; + event->alt = 0; + } + mmb_emulated = 0; + } + } + + } +#endif + + /* numpad emulation */ + if (U.flag & USER_NONUMPAD) { + switch (event->type) { + case ZEROKEY: event->type = PAD0; break; + case ONEKEY: event->type = PAD1; break; + case TWOKEY: event->type = PAD2; break; + case THREEKEY: event->type = PAD3; break; + case FOURKEY: event->type = PAD4; break; + case FIVEKEY: event->type = PAD5; break; + case SIXKEY: event->type = PAD6; break; + case SEVENKEY: event->type = PAD7; break; + case EIGHTKEY: event->type = PAD8; break; + case NINEKEY: event->type = PAD9; break; + case MINUSKEY: event->type = PADMINUS; break; + case EQUALKEY: event->type = PADPLUSKEY; break; + case BACKSLASHKEY: event->type = PADSLASHKEY; break; + } + } +} + /* adds customdata to event */ static void update_tablet_data(wmWindow *win, wmEvent *event) { @@ -2825,6 +2824,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U else event.type = MIDDLEMOUSE; + wm_eventemulation(&event); + /* copy previous state to prev event state (two old!) */ evt->prevval = evt->val; evt->prevtype = evt->type; @@ -2890,6 +2891,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf)); /* might be not null terminated*/ event.val = (type == GHOST_kEventKeyDown) ? KM_PRESS : KM_RELEASE; + wm_eventemulation(&event); + /* copy previous state to prev event state (two old!) */ evt->prevval = evt->val; evt->prevtype = evt->type; @@ -2978,9 +2981,13 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U if (event.keymodifier == UNKNOWNKEY) event.keymodifier = 0; - /* if test_break set, it catches this. XXX Keep global for now? */ - if (event.type == ESCKEY && event.val == KM_PRESS) + /* if test_break set, it catches this. Do not set with modifier presses. XXX Keep global for now? */ + if ((event.type == ESCKEY && event.val == KM_PRESS) && + /* check other modifiers because ms-windows uses these to bring up the task manager */ + (event.shift == 0 && event.ctrl == 0 && event.alt == 0)) + { G.is_break = TRUE; + } /* double click test - only for press */ if (event.val == KM_PRESS) { diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 616567e8184..a965cbf82d6 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -333,8 +333,14 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win) static void wm_window_add_ghostwindow(const char *title, wmWindow *win) { GHOST_WindowHandle ghostwin; + static int multisamples = -1; int scr_w, scr_h, posy; + /* force setting multisamples only once, it requires restart - and you cannot + mix it, either all windows have it, or none (tested in OSX opengl) */ + if (multisamples == -1) + multisamples = U.ogl_multisamples; + wm_get_screensize(&scr_w, &scr_h); posy = (scr_h - win->posy - win->sizey); @@ -345,7 +351,7 @@ static void wm_window_add_ghostwindow(const char *title, wmWindow *win) (GHOST_TWindowState)win->windowstate, GHOST_kDrawingContextTypeOpenGL, 0 /* no stereo */, - 0 /* no AA */); + multisamples /* AA */); if (ghostwin) { /* needed so we can detect the graphics card below */ @@ -373,7 +379,6 @@ static void wm_window_add_ghostwindow(const char *title, wmWindow *win) /* standard state vars for window */ glEnable(GL_SCISSOR_TEST); - GPU_state_init(); } } @@ -749,6 +754,11 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr state = GHOST_GetWindowState(win->ghostwin); win->windowstate = state; + /* stop screencast if resize */ + if (type == GHOST_kEventWindowSize) { + WM_jobs_stop(CTX_wm_manager(C), win->screen, NULL); + } + /* win32: gives undefined window size when minimized */ if (state != GHOST_kWindowStateMinimized) { GHOST_RectangleHandle client_rect; diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index 828b7f5066c..11e790451cd 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -191,6 +191,10 @@ endif() list(APPEND BLENDER_SORTED_LIBS bf_intern_guardedalloc_cpp) endif() + if(WITH_INTERNATIONAL) + list(APPEND BLENDER_SORTED_LIBS bf_intern_locale) + endif() + foreach(SORTLIB ${BLENDER_SORTED_LIBS}) set(REMLIB ${SORTLIB}) foreach(SEARCHLIB ${BLENDER_LINK_LIBS}) diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 2d37b0e1401..8274585cdb1 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -425,7 +425,7 @@ void uiTemplateEditModeSelection(struct uiLayout *layout, struct bContext *C) {} void uiTemplateTextureImage(struct uiLayout *layout, struct bContext *C, struct Tex *tex) {} void uiTemplateImage(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, struct PointerRNA *userptr, int compact) {} void uiTemplateDopeSheetFilter(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr) {} -void uiTemplateColorWheel(struct uiLayout *layout, struct PointerRNA *ptr, char *propname, int value_slider) {} +void uiTemplateColorPicker(struct uiLayout *layout, struct PointerRNA *ptr, char *propname, int value_slider) {} void uiTemplateHistogram(struct uiLayout *layout, struct PointerRNA *ptr, char *propname, int expand) {} void uiTemplateReportsBanner(struct uiLayout *layout, struct bContext *C, struct wmOperator *op) {} void uiTemplateWaveform(struct uiLayout *layout, struct PointerRNA *ptr, char *propname, int expand) {} @@ -464,6 +464,8 @@ ListBase R_engines = {NULL, NULL}; void RE_engine_free(struct RenderEngine *engine) {} struct RenderEngineType *RE_engines_find(const char *idname) { return NULL; } void RE_engine_update_memory_stats(struct RenderEngine *engine, float mem_used, float mem_peak) {}; +struct RenderEngine *RE_engine_create(struct RenderEngineType *type) { return NULL; }; +void RE_FreePersistentData(void) {} /* python */ struct wmOperatorType *WM_operatortype_find(const char *idname, int quiet) {return (struct wmOperatorType *) NULL;} diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index f986e30b10c..5da08cf67da 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -470,20 +470,6 @@ elseif(WIN32) DESTINATION ${TARGETDIR} ) - if(WITH_INTERNATIONAL AND (NOT WITH_MINGW64)) - install( - FILES ${LIBDIR}/gettext/lib/gnu_gettext.dll - DESTINATION ${TARGETDIR} - ) - - if(NOT CMAKE_CL_64) - install( - FILES ${LIBDIR}/iconv/lib/iconv.dll - DESTINATION ${TARGETDIR} - ) - endif() - endif() - if(WITH_PYTHON) set_lib_path(PYLIB "python") install( @@ -531,7 +517,7 @@ elseif(WIN32) endif() if(CMAKE_CL_64) - # gettext and png are statically linked on win64 + # png is statically linked on win64 install( FILES ${LIBDIR}/zlib/lib/zlib.dll DESTINATION ${TARGETDIR} @@ -989,6 +975,10 @@ endif() list_insert_after(BLENDER_SORTED_LIBS "cycles_kernel" "cycles_kernel_osl") endif() + if(WITH_INTERNATIONAL) + list(APPEND BLENDER_SORTED_LIBS bf_intern_locale) + endif() + foreach(SORTLIB ${BLENDER_SORTED_LIBS}) set(REMLIB ${SORTLIB}) foreach(SEARCHLIB ${BLENDER_LINK_LIBS}) diff --git a/source/gameengine/Converter/BL_ArmatureChannel.cpp b/source/gameengine/Converter/BL_ArmatureChannel.cpp index 7cf895255ba..11e90e1797d 100644 --- a/source/gameengine/Converter/BL_ArmatureChannel.cpp +++ b/source/gameengine/Converter/BL_ArmatureChannel.cpp @@ -95,7 +95,7 @@ BL_ArmatureChannel::~BL_ArmatureChannel() // PYTHON PyMethodDef BL_ArmatureChannel::Methods[] = { - {NULL,NULL} //Sentinel + {NULL,NULL} //Sentinel }; // order of definition of attributes, must match Attributes[] array diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.cpp b/source/gameengine/Converter/BL_ArmatureConstraint.cpp index b8ad117a220..379be91b523 100644 --- a/source/gameengine/Converter/BL_ArmatureConstraint.cpp +++ b/source/gameengine/Converter/BL_ArmatureConstraint.cpp @@ -246,7 +246,7 @@ void BL_ArmatureConstraint::SetSubtarget(KX_GameObject* subtarget) // PYTHON PyMethodDef BL_ArmatureConstraint::Methods[] = { - {NULL,NULL} //Sentinel + {NULL,NULL} //Sentinel }; // order of definition of attributes, must match Attributes[] array diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index ed97b9ff73f..1f1c404efcb 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -639,7 +639,6 @@ PyTypeObject BL_ArmatureObject::Type = { }; PyMethodDef BL_ArmatureObject::Methods[] = { - KX_PYMETHODTABLE_NOARGS(BL_ArmatureObject, update), {NULL,NULL} //Sentinel }; diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 58ae415e9d3..eb695e624e4 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -423,64 +423,55 @@ static void SetDefaultLightMode(Scene* scene) // -- -static void GetRGB(short type, - MFace* mface, - MCol* mmcol, - Material *mat, - unsigned int &c0, - unsigned int &c1, - unsigned int &c2, - unsigned int &c3) +static void GetRGB( + const bool use_mcol, + MFace *mface, + MCol *mmcol, + Material *mat, + unsigned int &c0, + unsigned int &c1, + unsigned int &c2, + unsigned int &c3) { unsigned int color = 0xFFFFFFFFL; - switch (type) { - case 0: // vertex colors - { - if (mmcol) { - c0 = KX_Mcol2uint_new(mmcol[0]); - c1 = KX_Mcol2uint_new(mmcol[1]); - c2 = KX_Mcol2uint_new(mmcol[2]); - if (mface->v4) - c3 = KX_Mcol2uint_new(mmcol[3]); - } - else { // backup white - c0 = KX_rgbaint2uint_new(color); - c1 = KX_rgbaint2uint_new(color); - c2 = KX_rgbaint2uint_new(color); - if (mface->v4) - c3 = KX_rgbaint2uint_new( color ); - } - } break; - - - case 1: // material rgba - { - if (mat) { - union { - unsigned char cp[4]; - unsigned int integer; - } col_converter; - col_converter.cp[3] = (unsigned char) (mat->r * 255.0f); - col_converter.cp[2] = (unsigned char) (mat->g * 255.0f); - col_converter.cp[1] = (unsigned char) (mat->b * 255.0f); - col_converter.cp[0] = (unsigned char) (mat->alpha * 255.0f); - color = col_converter.integer; - } - c0 = KX_rgbaint2uint_new(color); - c1 = KX_rgbaint2uint_new(color); - c2 = KX_rgbaint2uint_new(color); + if (use_mcol) { + // vertex colors + + if (mmcol) { + c0 = KX_Mcol2uint_new(mmcol[0]); + c1 = KX_Mcol2uint_new(mmcol[1]); + c2 = KX_Mcol2uint_new(mmcol[2]); if (mface->v4) - c3 = KX_rgbaint2uint_new(color); - } break; - - default: // white - { + c3 = KX_Mcol2uint_new(mmcol[3]); + } + else { // backup white c0 = KX_rgbaint2uint_new(color); c1 = KX_rgbaint2uint_new(color); c2 = KX_rgbaint2uint_new(color); if (mface->v4) - c3 = KX_rgbaint2uint_new(color); - } break; + c3 = KX_rgbaint2uint_new( color ); + } + } + else { + // material rgba + if (mat) { + union { + unsigned char cp[4]; + unsigned int integer; + } col_converter; + col_converter.cp[3] = (unsigned char) (mat->r * 255.0f); + col_converter.cp[2] = (unsigned char) (mat->g * 255.0f); + col_converter.cp[1] = (unsigned char) (mat->b * 255.0f); + col_converter.cp[0] = (unsigned char) (mat->alpha * 255.0f); + color = col_converter.integer; + } + // backup white is fallback + + c0 = KX_rgbaint2uint_new(color); + c1 = KX_rgbaint2uint_new(color); + c2 = KX_rgbaint2uint_new(color); + if (mface->v4) + c3 = KX_rgbaint2uint_new(color); } } @@ -489,6 +480,45 @@ typedef struct MTF_localLayer { const char *name; } MTF_localLayer; +static void tface_to_uv_bge(const MFace *mface, const MTFace *tface, MT_Point2 uv[4]) +{ + uv[0].setValue(tface->uv[0]); + uv[1].setValue(tface->uv[1]); + uv[2].setValue(tface->uv[2]); + if (mface->v4) { + uv[3].setValue(tface->uv[3]); + } +} + +static void GetUV( + MFace *mface, + MTFace *tface, + MTF_localLayer *layers, + const int layer_uv[2], + MT_Point2 uv[4], + MT_Point2 uv2[4]) +{ + bool validface = (tface != NULL); + + uv2[0] = uv2[1] = uv2[2] = uv2[3] = MT_Point2(0.0f, 0.0f); + + /* No material, what to do? let's see what is in the UV and set the material accordingly + * light and visible is always on */ + if (layer_uv[0] != -1) { + tface_to_uv_bge(mface, layers[layer_uv[0]].face, uv); + if (layer_uv[1] != -1) { + tface_to_uv_bge(mface, layers[layer_uv[1]].face, uv2); + } + } + else if (validface) { + tface_to_uv_bge(mface, tface, uv); + } + else { + // nothing at all + uv[0] = uv[1] = uv[2] = uv[3] = MT_Point2(0.0f, 0.0f); + } +} + // ------------------------------------ static bool ConvertMaterial( BL_Material *material, @@ -496,30 +526,25 @@ static bool ConvertMaterial( MTFace* tface, const char *tfaceName, MFace* mface, - MCol* mmcol, + MCol* mmcol, /* only for text, use first mcol, weak */ MTF_localLayer *layers, - bool glslmat) + int layer_uv[2], + const bool glslmat) { material->Initialize(); int numchan = -1, texalpha = 0; bool validmat = (mat!=0); bool validface = (tface!=0); - short type = 0; - if ( validmat ) - type = 1; // material color - material->IdMode = DEFAULT_BLENDER; material->glslmat = (validmat)? glslmat: false; material->materialindex = mface->mat_nr; + /* default value for being unset */ + layer_uv[0] = layer_uv[1] = -1; + // -------------------------------- if (validmat) { - - // use vertex colors by explicitly setting - if (mat->mode &MA_VERTEXCOLP || glslmat) - type = 0; - // use lighting? material->ras_mode |= ( mat->mode & MA_SHLESS )?0:USE_LIGHT; material->ras_mode |= ( mat->game.flag & GEMAT_BACKCULL )?0:TWOSIDED; @@ -772,33 +797,19 @@ static bool ConvertMaterial( // No material - old default TexFace properties material->ras_mode |= USE_LIGHT; } - MT_Point2 uv[4]; - MT_Point2 uv2[4]; - const char *uvName = "", *uv2Name = ""; - - uv2[0] = uv2[1] = uv2[2] = uv2[3] = MT_Point2(0.0f, 0.0f); + const char *uvName = "", *uv2Name = ""; /* No material, what to do? let's see what is in the UV and set the material accordingly * light and visible is always on */ if ( validface ) { material->tile = tface->tile; - - uv[0].setValue(tface->uv[0]); - uv[1].setValue(tface->uv[1]); - uv[2].setValue(tface->uv[2]); - - if (mface->v4) - uv[3].setValue(tface->uv[3]); - uvName = tfaceName; } else { // nothing at all material->alphablend = GEMAT_SOLID; material->tile = 0; - - uv[0] = uv[1] = uv[2] = uv[3] = MT_Point2(0.0f, 0.0f); } if (validmat && validface) { @@ -816,49 +827,30 @@ static bool ConvertMaterial( } // get uv sets - if (validmat) - { + if (validmat) { bool isFirstSet = true; // only two sets implemented, but any of the eight // sets can make up the two layers - for (int vind = 0; vind<material->num_enabled; vind++) - { + for (int vind = 0; vind<material->num_enabled; vind++) { BL_Mapping &map = material->mapping[vind]; - if (map.uvCoName.IsEmpty()) + if (map.uvCoName.IsEmpty()) { isFirstSet = false; - else - { - for (int lay=0; lay<MAX_MTFACE; lay++) - { + } + else { + for (int lay=0; lay<MAX_MTFACE; lay++) { MTF_localLayer& layer = layers[lay]; if (layer.face == 0) break; - if (strcmp(map.uvCoName.ReadPtr(), layer.name)==0) - { - MT_Point2 uvSet[4]; - - uvSet[0].setValue(layer.face->uv[0]); - uvSet[1].setValue(layer.face->uv[1]); - uvSet[2].setValue(layer.face->uv[2]); - - if (mface->v4) - uvSet[3].setValue(layer.face->uv[3]); - else - uvSet[3].setValue(0.0f, 0.0f); - - if (isFirstSet) - { - uv[0] = uvSet[0]; uv[1] = uvSet[1]; - uv[2] = uvSet[2]; uv[3] = uvSet[3]; + if (strcmp(map.uvCoName.ReadPtr(), layer.name)==0) { + if (isFirstSet) { + layer_uv[0] = lay; isFirstSet = false; uvName = layer.name; } - else if (strcmp(layer.name, uvName) != 0) - { - uv2[0] = uvSet[0]; uv2[1] = uvSet[1]; - uv2[2] = uvSet[2]; uv2[3] = uvSet[3]; + else if (strcmp(layer.name, uvName) != 0) { + layer_uv[1] = lay; map.mapping |= USECUSTOMUV; uv2Name = layer.name; } @@ -868,21 +860,11 @@ static bool ConvertMaterial( } } - unsigned int rgb[4]; - GetRGB(type,mface,mmcol,mat,rgb[0],rgb[1],rgb[2], rgb[3]); - - // swap the material color, so MCol on bitmap font works - if (validmat && type==1 && (mat->game.flag & GEMAT_TEXT)) - { - rgb[0] = KX_rgbaint2uint_new(rgb[0]); - rgb[1] = KX_rgbaint2uint_new(rgb[1]); - rgb[2] = KX_rgbaint2uint_new(rgb[2]); - rgb[3] = KX_rgbaint2uint_new(rgb[3]); + if (validmat && mmcol) { /* color is only for text */ + material->m_mcol = *(unsigned int *)mmcol; } - - material->SetConversionRGB(rgb); - material->SetConversionUV(uvName, uv); - material->SetConversionUV2(uv2Name, uv2); + material->SetUVLayerName(uvName); + material->SetUVLayerName2(uv2Name); if (validmat) material->matname =(mat->id.name); @@ -928,6 +910,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene, // Extract avaiable layers MTF_localLayer *layers = new MTF_localLayer[MAX_MTFACE]; + int layer_uv[2]; /* store uv1, uv2 layers */ for (int lay=0; lay<MAX_MTFACE; lay++) { layers[lay].face = 0; layers[lay].name = ""; @@ -1025,34 +1008,43 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene, bool twoside = false; if (converter->GetMaterials()) { + const bool is_bl_mat_new = (bl_mat == NULL); + //const bool is_kx_blmat_new = (kx_blmat == NULL); + const bool glslmat = converter->GetGLSLMaterials(); + const bool use_mcol = ma ? (ma->mode & MA_VERTEXCOLP || glslmat) : true; /* do Blender Multitexture and Blender GLSL materials */ - unsigned int rgb[4]; - MT_Point2 uv[4]; + MT_Point2 uv_1[4]; + MT_Point2 uv_2[4]; /* first is the BL_Material */ - if (!bl_mat) + if (!bl_mat) { bl_mat = new BL_Material(); - ConvertMaterial(bl_mat, ma, tface, tfaceName, mface, mcol, - layers, converter->GetGLSLMaterials()); + } + + /* only */ + if (is_bl_mat_new || (bl_mat->material != ma)) { + ConvertMaterial(bl_mat, ma, tface, tfaceName, mface, mcol, + layers, layer_uv, glslmat); + } - /* vertex colors and uv's were stored in bl_mat temporarily */ - bl_mat->GetConversionRGB(rgb); - rgb0 = rgb[0]; rgb1 = rgb[1]; - rgb2 = rgb[2]; rgb3 = rgb[3]; + /* vertex colors and uv's from the faces */ + GetRGB(use_mcol, mface, mcol, ma, rgb0, rgb1, rgb2, rgb3); + GetUV(mface, tface, layers, layer_uv, uv_1, uv_2); - bl_mat->GetConversionUV(uv); - uv0 = uv[0]; uv1 = uv[1]; - uv2 = uv[2]; uv3 = uv[3]; + uv0 = uv_1[0]; uv1 = uv_1[1]; + uv2 = uv_1[2]; uv3 = uv_1[3]; - bl_mat->GetConversionUV2(uv); - uv20 = uv[0]; uv21 = uv[1]; - uv22 = uv[2]; uv23 = uv[3]; + uv20 = uv_2[0]; uv21 = uv_2[1]; + uv22 = uv_2[2]; uv23 = uv_2[3]; /* then the KX_BlenderMaterial */ if (kx_blmat == NULL) kx_blmat = new KX_BlenderMaterial(); - kx_blmat->Initialize(scene, bl_mat, (ma?&ma->game:NULL)); + //if (is_kx_blmat_new || !kx_blmat->IsMaterial(bl_mat)) { + kx_blmat->Initialize(scene, bl_mat, (ma ? &ma->game : NULL)); + //} + polymat = static_cast<RAS_IPolyMaterial*>(kx_blmat); } else { diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index 30a4209965e..d1684db0f5a 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -103,6 +103,7 @@ extern "C" #include "KX_MeshProxy.h" #include "RAS_MeshObject.h" extern "C" { + #include "PIL_time.h" #include "BKE_context.h" #include "BLO_readfile.h" #include "BKE_idcode.h" @@ -957,10 +958,12 @@ static void load_datablocks(Main *main_newlib, BlendHandle *bpy_openlib, const c bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) { Main *main_newlib; /* stored as a dynamic 'main' until we free it */ - int idcode= BKE_idcode_from_name(group); + const int idcode = BKE_idcode_from_name(group); ReportList reports; static char err_local[255]; - + +// TIMEIT_START(bge_link_blend_file); + /* only scene and mesh supported right now */ if (idcode!=ID_SCE && idcode!=ID_ME &&idcode!=ID_AC) { snprintf(err_local, sizeof(err_local), "invalid ID type given \"%s\"\n", group); @@ -1059,7 +1062,9 @@ bool KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const cha } } } - + +// TIMEIT_END(bge_link_blend_file); + return true; } diff --git a/source/gameengine/Expressions/IntValue.cpp b/source/gameengine/Expressions/IntValue.cpp index cb6bc556bab..0261a4a2d02 100644 --- a/source/gameengine/Expressions/IntValue.cpp +++ b/source/gameengine/Expressions/IntValue.cpp @@ -286,7 +286,7 @@ cInt CIntValue::GetInt() double CIntValue::GetNumber() { - return (float) m_int; + return (double) m_int; } diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index bb1d0a31c1f..77c76ca8153 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -259,7 +259,7 @@ void PyObjectPlus::py_base_dealloc(PyObject *self) // python wrapper * PyObjectPlus Methods -- Every class, even the abstract one should have a Methods ------------------------------*/ PyMethodDef PyObjectPlus::Methods[] = { - {NULL, NULL} /* Sentinel */ + {NULL, NULL} /* Sentinel */ }; #define BGE_PY_ATTR_INVALID (&(PyObjectPlus::Attributes[0])) @@ -486,8 +486,8 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * static bool py_check_attr_float(float *var, PyObject *value, const PyAttributeDef *attrdef) { - double val = PyFloat_AsDouble(value); - if (val == -1.0 && PyErr_Occurred()) + float val = PyFloat_AsDouble(value); + if (val == -1.0f && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name); return false; @@ -664,13 +664,13 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt { float *var = reinterpret_cast<float*>(ptr); ptr += sizeof(float); - double val = PyFloat_AsDouble(item); - if (val == -1.0 && PyErr_Occurred()) + float val = PyFloat_AsDouble(item); + if (val == -1.0f && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name); goto UNDO_AND_ERROR; } - else if (attrdef->m_clamp) + else if (attrdef->m_clamp) { if (val < attrdef->m_fmin) val = attrdef->m_fmin; @@ -985,10 +985,10 @@ int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAtt for (int i=0; i<3; i++) { item = PySequence_GetItem(value, i); /* new ref */ - double val = PyFloat_AsDouble(item); + float val = PyFloat_AsDouble(item); Py_DECREF(item); item = NULL; - if (val == -1.0 && PyErr_Occurred()) + if (val == -1.0f && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); goto RESTORE_AND_ERROR; diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp index ab0e6c5edcb..4916d8a0a57 100644 --- a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp +++ b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp @@ -202,7 +202,7 @@ PyTypeObject SCA_ILogicBrick::Type = { }; PyMethodDef SCA_ILogicBrick::Methods[] = { - {NULL,NULL} //Sentinel + {NULL,NULL} //Sentinel }; PyAttributeDef SCA_ILogicBrick::Attributes[] = { diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp index 5dd4cc501ca..f02ac495233 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp +++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp @@ -126,7 +126,6 @@ bool SCA_PropertySensor::Evaluate() bool SCA_PropertySensor::CheckPropertyCondition() { - m_recentresult=false; bool result=false; bool reverse = false; @@ -153,13 +152,11 @@ bool SCA_PropertySensor::CheckPropertyCondition() */ if (result==false && dynamic_cast<CFloatValue *>(orgprop) != NULL) { float f; - - if (EOF == sscanf(m_checkpropval.ReadPtr(), "%f", &f)) - { - //error + if (sscanf(m_checkpropval.ReadPtr(), "%f", &f) == 1) { + result = (f == ((CFloatValue *)orgprop)->GetFloat()); } else { - result = (f == ((CFloatValue *)orgprop)->GetFloat()); + /* error */ } } /* end patch */ @@ -174,7 +171,7 @@ bool SCA_PropertySensor::CheckPropertyCondition() case KX_PROPSENSOR_EXPRESSION: { - /* +#if 0 if (m_rightexpr) { CValue* resultval = m_rightexpr->Calculate(); @@ -189,7 +186,7 @@ bool SCA_PropertySensor::CheckPropertyCondition() result = resultval->GetNumber() != 0; } } - */ +#endif break; } case KX_PROPSENSOR_INTERVAL: @@ -197,7 +194,16 @@ bool SCA_PropertySensor::CheckPropertyCondition() CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); if (!orgprop->IsError()) { - float val = orgprop->GetText().ToFloat(), min = m_checkpropval.ToFloat(), max = m_checkpropmaxval.ToFloat(); + const float min = m_checkpropval.ToFloat(); + const float max = m_checkpropmaxval.ToFloat(); + float val; + + if (dynamic_cast<CStringValue *>(orgprop) == NULL) { + val = orgprop->GetNumber(); + } + else { + val = orgprop->GetText().ToFloat(); + } result = (min <= val) && (val <= max); } diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.cpp b/source/gameengine/GameLogic/SCA_RandomActuator.cpp index 2d51a45fe55..01995b13ad7 100644 --- a/source/gameengine/GameLogic/SCA_RandomActuator.cpp +++ b/source/gameengine/GameLogic/SCA_RandomActuator.cpp @@ -220,11 +220,11 @@ bool SCA_RandomActuator::Update() * this will be quite sufficient here. */ do { - x = 2.0 * m_base->DrawFloat() - 1.0; - y = 2.0 * m_base->DrawFloat() - 1.0; - s = x*x + y*y; - } while ( (s >= 1.0) || (s == 0.0) ); - t = x * sqrt( (-2.0 * log(s)) / s); + x = 2.0f * m_base->DrawFloat() - 1.0f; + y = 2.0f * m_base->DrawFloat() - 1.0f; + s = x * x + y * y; + } while ((s >= 1.0f) || (s == 0.0f)); + t = x * sqrtf((-2.0 * log(s)) / s); tmpval = new CFloatValue(m_parameter1 + m_parameter2 * t); } } diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index 725c23c60e3..3e8755c41ce 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -172,7 +172,7 @@ static BOOL scr_saver_init(int argc, char **argv) #endif /* WIN32 */ -void usage(const char* program, bool isBlenderPlayer) +static void usage(const char* program, bool isBlenderPlayer) { const char * consoleoption; const char * example_filename = ""; @@ -332,7 +332,7 @@ static BlendFileData *load_game_data(const char *progname, char *filename = NULL return bfd; } -bool GPG_NextFrame(GHOST_ISystem* system, GPG_Application *app, int &exitcode, STR_String &exitstring, GlobalSettings *gs) +static bool GPG_NextFrame(GHOST_ISystem* system, GPG_Application *app, int &exitcode, STR_String &exitstring, GlobalSettings *gs) { bool run = true; system->processEvents(false); @@ -352,7 +352,7 @@ struct GPG_NextFrameState { GlobalSettings *gs; } gpg_nextframestate; -int GPG_PyNextFrame(void *state0) +static int GPG_PyNextFrame(void *state0) { GPG_NextFrameState *state = (GPG_NextFrameState *) state0; int exitcode; @@ -450,7 +450,6 @@ int main(int argc, char** argv) // Setup builtin font for BLF (mostly copied from creator.c, wm_init_exit.c and interface_style.c) BLF_init(11, U.dpi); BLF_lang_init(); - BLF_lang_encoding(""); BLF_lang_set(""); BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size); diff --git a/source/gameengine/Ketsji/BL_Material.cpp b/source/gameengine/Ketsji/BL_Material.cpp index 4c7518769e1..0954aa0f7ab 100644 --- a/source/gameengine/Ketsji/BL_Material.cpp +++ b/source/gameengine/Ketsji/BL_Material.cpp @@ -36,10 +36,7 @@ BL_Material::BL_Material() void BL_Material::Initialize() { - rgb[0] = 0; - rgb[1] = 0; - rgb[2] = 0; - rgb[3] = 0; + m_mcol = 0xFFFFFFFFL; IdMode = 0; ras_mode = 0; glslmat = 0; @@ -66,11 +63,6 @@ void BL_Material::Initialize() share = false; int i; - for (i=0; i<4; i++) - { - uv[i] = MT_Point2(0.f,1.f); - uv2[i] = MT_Point2(0.f, 1.f); - } for (i=0; i<MAXTEX; i++) // :( { @@ -98,56 +90,15 @@ void BL_Material::Initialize() } } -void BL_Material::SetConversionRGB(unsigned int *nrgb) -{ - rgb[0]=*nrgb++; - rgb[1]=*nrgb++; - rgb[2]=*nrgb++; - rgb[3]=*nrgb; -} - -void BL_Material::GetConversionRGB(unsigned int *nrgb) -{ - *nrgb++ = rgb[0]; - *nrgb++ = rgb[1]; - *nrgb++ = rgb[2]; - *nrgb = rgb[3]; -} - -void BL_Material::SetConversionUV(const STR_String& name, MT_Point2 *nuv) +void BL_Material::SetUVLayerName(const STR_String& name) { uvName = name; - uv[0] = *nuv++; - uv[1] = *nuv++; - uv[2] = *nuv++; - uv[3] = *nuv; } - -void BL_Material::GetConversionUV(MT_Point2 *nuv) -{ - *nuv++ = uv[0]; - *nuv++ = uv[1]; - *nuv++ = uv[2]; - *nuv = uv[3]; -} -void BL_Material::SetConversionUV2(const STR_String& name, MT_Point2 *nuv) +void BL_Material::SetUVLayerName2(const STR_String& name) { uv2Name = name; - uv2[0] = *nuv++; - uv2[1] = *nuv++; - uv2[2] = *nuv++; - uv2[3] = *nuv; } -void BL_Material::GetConversionUV2(MT_Point2 *nuv) -{ - *nuv++ = uv2[0]; - *nuv++ = uv2[1]; - *nuv++ = uv2[2]; - *nuv = uv2[3]; -} - - void BL_Material::SetSharedMaterial(bool v) { if ((v && num_users == -1) || num_users > 1 ) diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h index b67bd95f878..ef180ed2126 100644 --- a/source/gameengine/Ketsji/BL_Material.h +++ b/source/gameengine/Ketsji/BL_Material.h @@ -87,22 +87,13 @@ public: MTFace tface; /* copy of the derived meshes tface */ Image* img[MAXTEX]; EnvMap* cubemap[MAXTEX]; - - unsigned int rgb[4]; - MT_Point2 uv[4]; - MT_Point2 uv2[4]; + unsigned int m_mcol; /* for text color (only) */ STR_String uvName; STR_String uv2Name; - void SetConversionRGB(unsigned int *rgb); - void GetConversionRGB(unsigned int *rgb); - - void SetConversionUV(const STR_String& name, MT_Point2 *uv); - void GetConversionUV(MT_Point2 *uv); - - void SetConversionUV2(const STR_String& name, MT_Point2 *uv); - void GetConversionUV2(MT_Point2 *uv); + void SetUVLayerName(const STR_String &name); + void SetUVLayerName2(const STR_String &name); void SetSharedMaterial(bool v); bool IsShared(); diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp index fb8e7beb157..b047588df5a 100644 --- a/source/gameengine/Ketsji/BL_Shader.cpp +++ b/source/gameengine/Ketsji/BL_Shader.cpp @@ -571,41 +571,39 @@ void BL_Shader::Update( const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) } -int BL_Shader::GetAttribLocation(const STR_String& name) +int BL_Shader::GetAttribLocation(const char *name) { - if ( GLEW_ARB_fragment_shader && - GLEW_ARB_vertex_shader && - GLEW_ARB_shader_objects - ) + if (GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects) { - return glGetAttribLocationARB(mShader, name.ReadPtr()); + return glGetAttribLocationARB(mShader, name); } return -1; } -void BL_Shader::BindAttribute(const STR_String& attr, int loc) +void BL_Shader::BindAttribute(const char *attr, int loc) { - if ( GLEW_ARB_fragment_shader && - GLEW_ARB_vertex_shader && - GLEW_ARB_shader_objects - ) + if (GLEW_ARB_fragment_shader && + GLEW_ARB_vertex_shader && + GLEW_ARB_shader_objects ) { - glBindAttribLocationARB(mShader, loc, attr.ReadPtr()); + glBindAttribLocationARB(mShader, loc, attr); } } -int BL_Shader::GetUniformLocation(const STR_String& name) +int BL_Shader::GetUniformLocation(const char *name) { if ( GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && - GLEW_ARB_shader_objects + GLEW_ARB_shader_objects ) { MT_assert(mShader!=0); - int location = glGetUniformLocationARB(mShader, name.ReadPtr()); + int location = glGetUniformLocationARB(mShader, name); if (location == -1) - spit("Invalid uniform value: " << name.ReadPtr() << "."); + spit("Invalid uniform value: " << name << "."); return location; } @@ -900,7 +898,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setSampler, "setSampler(name, index)" ) Py_RETURN_NONE; } - const char *uniform=""; + const char *uniform; int index=-1; if (PyArg_ParseTuple(args, "si:setSampler", &uniform, &index)) { @@ -941,7 +939,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1f, "setUniform1f(name, fx)" ) Py_RETURN_NONE; } - const char *uniform=""; + const char *uniform; float value=0; if (PyArg_ParseTuple(args, "sf:setUniform1f", &uniform, &value )) { @@ -965,7 +963,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2f, "setUniform2f(name, fx, fy)") if (mError) { Py_RETURN_NONE; } - const char *uniform=""; + const char *uniform; float array[2] = {0, 0}; if (PyArg_ParseTuple(args, "sff:setUniform2f", &uniform, &array[0],&array[1] )) { @@ -989,7 +987,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ") if (mError) { Py_RETURN_NONE; } - const char *uniform=""; + const char *uniform; float array[3] = {0, 0, 0}; if (PyArg_ParseTuple(args, "sfff:setUniform3f", &uniform, &array[0],&array[1],&array[2])) { @@ -1014,7 +1012,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) " if (mError) { Py_RETURN_NONE; } - const char *uniform=""; + const char *uniform; float array[4] = {0, 0, 0, 0}; if (PyArg_ParseTuple(args, "sffff:setUniform4f", &uniform, &array[0],&array[1],&array[2], &array[3])) { @@ -1038,7 +1036,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform1i, "setUniform1i(name, ix)" ) if (mError) { Py_RETURN_NONE; } - const char *uniform=""; + const char *uniform; int value=0; if (PyArg_ParseTuple(args, "si:setUniform1i", &uniform, &value )) { @@ -1062,7 +1060,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform2i, "setUniform2i(name, ix, iy)") if (mError) { Py_RETURN_NONE; } - const char *uniform=""; + const char *uniform; int array[2] = {0, 0}; if (PyArg_ParseTuple(args, "sii:setUniform2i", &uniform, &array[0],&array[1] )) { @@ -1087,7 +1085,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ") Py_RETURN_NONE; } - const char *uniform=""; + const char *uniform; int array[3] = {0, 0, 0}; if (PyArg_ParseTuple(args, "siii:setUniform3i", &uniform, &array[0],&array[1],&array[2])) { @@ -1110,7 +1108,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) " if (mError) { Py_RETURN_NONE; } - const char *uniform=""; + const char *uniform; int array[4] = {0, 0, 0, 0}; if (PyArg_ParseTuple(args, "siiii:setUniform4i", &uniform, &array[0],&array[1],&array[2], &array[3] )) { @@ -1296,7 +1294,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix4, 0,0,0,1 }; - const char *uniform=""; + const char *uniform; PyObject *matrix=0; int transp=0; // python use column major by default, so no transpose.... @@ -1342,7 +1340,7 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformMatrix3, 0,0,1, }; - const char *uniform=""; + const char *uniform; PyObject *matrix=0; int transp=0; // python use column major by default, so no transpose.... if (!PyArg_ParseTuple(args, "sO|i:setUniformMatrix3",&uniform, &matrix,&transp)) @@ -1404,9 +1402,9 @@ KX_PYMETHODDEF_DOC( BL_Shader, setUniformDef, "setUniformDef(name, enum)" ) Py_RETURN_NONE; } - const char *uniform=""; + const char *uniform; int nloc=0; - if (PyArg_ParseTuple(args, "si:setUniformDef",&uniform, &nloc)) + if (PyArg_ParseTuple(args, "si:setUniformDef", &uniform, &nloc)) { int loc = GetUniformLocation(uniform); if (loc != -1) diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h index 82476873b85..243445d95c5 100644 --- a/source/gameengine/Ketsji/BL_Shader.h +++ b/source/gameengine/Ketsji/BL_Shader.h @@ -205,9 +205,9 @@ public: void SetUniformfv(int location,int type, float *param, int size,bool transpose=false); void SetUniformiv(int location,int type, int *param, int size,bool transpose=false); - int GetAttribLocation(const STR_String& name); - void BindAttribute(const STR_String& attr, int loc); - int GetUniformLocation(const STR_String& name); + int GetAttribLocation(const char *name); + void BindAttribute(const char *attr, int loc); + int GetUniformLocation(const char *name); void SetUniform(int uniform, const MT_Tuple2& vec); void SetUniform(int uniform, const MT_Tuple3& vec); diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index 2154beeb205..88e26fd9a55 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -124,7 +124,7 @@ MTFace* KX_BlenderMaterial::GetMTFace(void) const unsigned int* KX_BlenderMaterial::GetMCol(void) const { // fonts on polys - return mMaterial->rgb; + return &mMaterial->m_mcol; } void KX_BlenderMaterial::GetMaterialRGBAColor(unsigned char *rgba) const @@ -138,6 +138,11 @@ void KX_BlenderMaterial::GetMaterialRGBAColor(unsigned char *rgba) const RAS_IPolyMaterial::GetMaterialRGBAColor(rgba); } +bool KX_BlenderMaterial::IsMaterial(const BL_Material *bl_mat) const +{ + return (mMaterial == bl_mat); +} + Material *KX_BlenderMaterial::GetBlenderMaterial() const { return mMaterial->material; diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index 1653669ebcc..7bc9c7c3863 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -76,6 +76,8 @@ public: TCachingInfo& cachingInfo )const; + /* mMaterial is private, but need this for conversion */ + bool IsMaterial(const BL_Material *bl_mat) const; Material* GetBlenderMaterial() const; MTFace* GetMTFace(void) const; unsigned int* GetMCol(void) const; diff --git a/source/gameengine/Ketsji/KX_CharacterWrapper.h b/source/gameengine/Ketsji/KX_CharacterWrapper.h index cc99aba99f6..3b0058aca6f 100644 --- a/source/gameengine/Ketsji/KX_CharacterWrapper.h +++ b/source/gameengine/Ketsji/KX_CharacterWrapper.h @@ -32,4 +32,4 @@ private: PHY_ICharacter* m_character; }; -#endif //__KX_CHARACTERWRAPPER_H__ +#endif /* __KX_CHARACTERWRAPPER_H__ */ diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index a669f4346ea..4f3d020a3d9 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -99,6 +99,7 @@ KX_GameObject::KX_GameObject( m_bSuspendDynamics(false), m_bUseObjectColor(false), m_bIsNegativeScaling(false), + m_objectColor(1.0, 1.0, 1.0, 1.0), m_bVisible(true), m_bCulled(true), m_bOccluder(false), diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp index 87c366046ad..9430179e344 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.cpp +++ b/source/gameengine/Ketsji/KX_MeshProxy.cpp @@ -70,13 +70,15 @@ PyTypeObject KX_MeshProxy::Type = { }; PyMethodDef KX_MeshProxy::Methods[] = { -{"getMaterialName", (PyCFunction)KX_MeshProxy::sPyGetMaterialName,METH_VARARGS}, -{"getTextureName", (PyCFunction)KX_MeshProxy::sPyGetTextureName,METH_VARARGS}, -{"getVertexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetVertexArrayLength,METH_VARARGS}, -{"getVertex", (PyCFunction)KX_MeshProxy::sPyGetVertex,METH_VARARGS}, -{"getPolygon", (PyCFunction)KX_MeshProxy::sPyGetPolygon,METH_VARARGS}, -//{"getIndexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetIndexArrayLength,METH_VARARGS}, - {NULL,NULL} //Sentinel + {"getMaterialName", (PyCFunction)KX_MeshProxy::sPyGetMaterialName,METH_VARARGS}, + {"getTextureName", (PyCFunction)KX_MeshProxy::sPyGetTextureName,METH_VARARGS}, + {"getVertexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetVertexArrayLength,METH_VARARGS}, + {"getVertex", (PyCFunction)KX_MeshProxy::sPyGetVertex,METH_VARARGS}, + {"getPolygon", (PyCFunction)KX_MeshProxy::sPyGetPolygon,METH_VARARGS}, + {"transform", (PyCFunction)KX_MeshProxy::sPyTransform,METH_VARARGS}, + {"transform_uv", (PyCFunction)KX_MeshProxy::sPyTransformUV,METH_VARARGS}, + //{"getIndexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetIndexArrayLength,METH_VARARGS}, + {NULL,NULL} //Sentinel }; PyAttributeDef KX_MeshProxy::Attributes[] = { @@ -218,6 +220,160 @@ PyObject *KX_MeshProxy::PyGetPolygon(PyObject *args, PyObject *kwds) return polyob; } +PyObject *KX_MeshProxy::PyTransform(PyObject *args, PyObject *kwds) +{ + int matindex; + PyObject *pymat; + bool ok = false; + + MT_Matrix4x4 transform; + + if (!PyArg_ParseTuple(args,"iO:transform", &matindex, &pymat) || + !PyMatTo(pymat, transform)) + { + return NULL; + } + + MT_Matrix4x4 ntransform = transform.inverse().transposed(); + ntransform[0][3] = ntransform[1][3] = ntransform[2][3] = 0.0f; + + /* transform mesh verts */ + unsigned int mit_index = 0; + for (list<RAS_MeshMaterial>::iterator mit = m_meshobj->GetFirstMaterial(); + (mit != m_meshobj->GetLastMaterial()); + ++mit, ++mit_index) + { + if (matindex == -1) { + /* always transform */ + } + else if (matindex == mit_index) { + /* we found the right index! */ + } + else { + continue; + } + + RAS_MeshSlot *slot = mit->m_baseslot; + RAS_MeshSlot::iterator it; + ok = true; + + for (slot->begin(it); !slot->end(it); slot->next(it)) { + size_t i; + for (i = it.startvertex; i < it.endvertex; i++) { + RAS_TexVert *vert = &it.vertex[i]; + vert->Transform(transform, ntransform); + } + } + + /* if we set a material index, quit when done */ + if (matindex == mit_index) { + break; + } + } + + if (ok == false) { + PyErr_Format(PyExc_ValueError, + "mesh.transform(...): invalid material index %d", matindex); + return NULL; + } + + m_meshobj->SetMeshModified(true); + + Py_RETURN_NONE; +} + +PyObject *KX_MeshProxy::PyTransformUV(PyObject *args, PyObject *kwds) +{ + int matindex; + PyObject *pymat; + int uvindex = -1; + int uvindex_from = -1; + bool ok = false; + + MT_Matrix4x4 transform; + + if (!PyArg_ParseTuple(args,"iO|iii:transform_uv", &matindex, &pymat, &uvindex, &uvindex_from) || + !PyMatTo(pymat, transform)) + { + return NULL; + } + + if (uvindex < -1 || uvindex > 1) { + PyErr_Format(PyExc_ValueError, + "mesh.transform_uv(...): invalid uv_index %d", uvindex); + return NULL; + } + if (uvindex_from < -1 || uvindex_from > 1 || uvindex == -1) { + PyErr_Format(PyExc_ValueError, + "mesh.transform_uv(...): invalid uv_index_from %d", uvindex); + return NULL; + } + if (uvindex_from == uvindex) { + uvindex_from = -1; + } + + /* transform mesh verts */ + unsigned int mit_index = 0; + for (list<RAS_MeshMaterial>::iterator mit = m_meshobj->GetFirstMaterial(); + (mit != m_meshobj->GetLastMaterial()); + ++mit, ++mit_index) + { + if (matindex == -1) { + /* always transform */ + } + else if (matindex == mit_index) { + /* we found the right index! */ + } + else { + continue; + } + + RAS_MeshSlot *slot = mit->m_baseslot; + RAS_MeshSlot::iterator it; + ok = true; + + for (slot->begin(it); !slot->end(it); slot->next(it)) { + size_t i; + + for (i = it.startvertex; i < it.endvertex; i++) { + RAS_TexVert *vert = &it.vertex[i]; + if (uvindex_from != -1) { + if (uvindex_from == 0) vert->SetUV2(vert->getUV1()); + else vert->SetUV1(vert->getUV2()); + } + + switch (uvindex) { + case 0: + vert->TransformUV1(transform); + break; + case 1: + vert->TransformUV2(transform); + break; + case -1: + vert->TransformUV1(transform); + vert->TransformUV2(transform); + break; + } + } + } + + /* if we set a material index, quit when done */ + if (matindex == mit_index) { + break; + } + } + + if (ok == false) { + PyErr_Format(PyExc_ValueError, + "mesh.transform_uv(...): invalid material index %d", matindex); + return NULL; + } + + m_meshobj->SetMeshModified(true); + + Py_RETURN_NONE; +} + PyObject *KX_MeshProxy::pyattr_get_materials(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { KX_MeshProxy* self = static_cast<KX_MeshProxy*>(self_v); diff --git a/source/gameengine/Ketsji/KX_MeshProxy.h b/source/gameengine/Ketsji/KX_MeshProxy.h index 98e73aa626f..5366634ef98 100644 --- a/source/gameengine/Ketsji/KX_MeshProxy.h +++ b/source/gameengine/Ketsji/KX_MeshProxy.h @@ -71,8 +71,10 @@ public: KX_PYMETHOD(KX_MeshProxy,GetVertexArrayLength); KX_PYMETHOD(KX_MeshProxy,GetVertex); KX_PYMETHOD(KX_MeshProxy,GetPolygon); + KX_PYMETHOD(KX_MeshProxy,Transform); + KX_PYMETHOD(KX_MeshProxy,TransformUV); - static PyObject* pyattr_get_materials(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_materials(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); static PyObject *pyattr_get_numMaterials(void * self, const KX_PYATTRIBUTE_DEF * attrdef); static PyObject *pyattr_get_numPolygons(void * self, const KX_PYATTRIBUTE_DEF * attrdef); }; diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp index 36c94dc997b..f89b918f31b 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp @@ -109,7 +109,7 @@ void KX_PolygonMaterial::Initialize( m_mcol = *mcol; } else { - memset(&m_mcol, 0, sizeof(m_mcol)); + m_mcol = 0; } m_material = ma; diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.h b/source/gameengine/Ketsji/KX_PolygonMaterial.h index 89bfb4ff9fb..2ce8f480c1c 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.h +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.h @@ -60,7 +60,7 @@ class KX_PolygonMaterial : public PyObjectPlus, public RAS_IPolyMaterial private: /** Blender texture face structure. */ mutable MTFace m_tface; - mutable unsigned int m_mcol; + mutable unsigned int m_mcol; /* for text color (only) */ Material* m_material; #ifdef WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp index d850168afdf..56dccc1d045 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp @@ -190,8 +190,8 @@ PyTypeObject KX_SCA_AddObjectActuator::Type = { }; PyMethodDef KX_SCA_AddObjectActuator::Methods[] = { - {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_NOARGS,"instantAddObject() : immediately add object without delay\n"}, - {NULL,NULL} //Sentinel + {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_NOARGS, NULL}, + {NULL,NULL} //Sentinel }; PyAttributeDef KX_SCA_AddObjectActuator::Attributes[] = { diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp index e6209d2d47b..81c9dc91603 100644 --- a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp @@ -113,7 +113,7 @@ PyTypeObject KX_SCA_EndObjectActuator::Type = { }; PyMethodDef KX_SCA_EndObjectActuator::Methods[] = { - {NULL,NULL} //Sentinel + {NULL,NULL} //Sentinel }; PyAttributeDef KX_SCA_EndObjectActuator::Attributes[] = { diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 96b4a21a36c..72be5f57b95 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -55,7 +55,7 @@ #include "SCA_BasicEventManager.h" #include "KX_Camera.h" #include "SCA_JoystickManager.h" - +#include "KX_PyMath.h" #include "RAS_MeshObject.h" #include "RAS_IRasterizer.h" @@ -1706,6 +1706,17 @@ void KX_Scene::SetGravity(const MT_Vector3& gravity) GetPhysicsEnvironment()->setGravity(gravity[0],gravity[1],gravity[2]); } +MT_Vector3 KX_Scene::GetGravity() +{ + PHY__Vector3 gravity; + MT_Vector3 vec; + + GetPhysicsEnvironment()->getGravity(gravity); + vec = gravity.m_vec; + + return vec; +} + void KX_Scene::SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter) { m_sceneConverter = sceneConverter; @@ -2270,6 +2281,25 @@ int KX_Scene::pyattr_set_drawing_callback_post(void *self_v, const KX_PYATTRIBUT return PY_SET_ATTR_SUCCESS; } +PyObject *KX_Scene::pyattr_get_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene* self = static_cast<KX_Scene*>(self_v); + + return PyObjectFrom(self->GetGravity()); +} + +int KX_Scene::pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_Scene* self = static_cast<KX_Scene*>(self_v); + + MT_Vector3 vec; + if (!PyVecTo(value, vec)) + return PY_SET_ATTR_FAIL; + + self->SetGravity(vec); + return PY_SET_ATTR_SUCCESS; +} + PyAttributeDef KX_Scene::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("name", KX_Scene, pyattr_get_name), KX_PYATTRIBUTE_RO_FUNCTION("objects", KX_Scene, pyattr_get_objects), @@ -2280,6 +2310,7 @@ PyAttributeDef KX_Scene::Attributes[] = { KX_PYATTRIBUTE_RW_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera, pyattr_set_active_camera), KX_PYATTRIBUTE_RW_FUNCTION("pre_draw", KX_Scene, pyattr_get_drawing_callback_pre, pyattr_set_drawing_callback_pre), KX_PYATTRIBUTE_RW_FUNCTION("post_draw", KX_Scene, pyattr_get_drawing_callback_post, pyattr_set_drawing_callback_post), + KX_PYATTRIBUTE_RW_FUNCTION("gravity", KX_Scene, pyattr_get_gravity, pyattr_set_gravity), KX_PYATTRIBUTE_BOOL_RO("suspended", KX_Scene, m_suspend), KX_PYATTRIBUTE_BOOL_RO("activity_culling", KX_Scene, m_activity_culling), KX_PYATTRIBUTE_FLOAT_RW("activity_culling_radius", 0.5f, FLT_MAX, KX_Scene, m_activity_box_radius), diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index c2e468e6da6..29473949535 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -573,6 +573,7 @@ public: void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv); void SetGravity(const MT_Vector3& gravity); + MT_Vector3 GetGravity(); short GetAnimationFPS(); @@ -616,6 +617,8 @@ public: static int pyattr_set_drawing_callback_pre(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); static PyObject* pyattr_get_drawing_callback_post(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); static int pyattr_set_drawing_callback_post(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + 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); virtual PyObject *py_repr(void) { return PyUnicode_From_STR_String(GetName()); } diff --git a/source/gameengine/Ketsji/KX_VertexProxy.cpp b/source/gameengine/Ketsji/KX_VertexProxy.cpp index dabb79b357d..82e414d7c42 100644 --- a/source/gameengine/Ketsji/KX_VertexProxy.cpp +++ b/source/gameengine/Ketsji/KX_VertexProxy.cpp @@ -61,19 +61,19 @@ PyTypeObject KX_VertexProxy::Type = { }; PyMethodDef KX_VertexProxy::Methods[] = { -{"getXYZ", (PyCFunction)KX_VertexProxy::sPyGetXYZ,METH_NOARGS}, -{"setXYZ", (PyCFunction)KX_VertexProxy::sPySetXYZ,METH_O}, -{"getUV", (PyCFunction)KX_VertexProxy::sPyGetUV,METH_NOARGS}, -{"setUV", (PyCFunction)KX_VertexProxy::sPySetUV,METH_O}, - -{"getUV2", (PyCFunction)KX_VertexProxy::sPyGetUV2,METH_NOARGS}, -{"setUV2", (PyCFunction)KX_VertexProxy::sPySetUV2,METH_VARARGS}, - -{"getRGBA", (PyCFunction)KX_VertexProxy::sPyGetRGBA,METH_NOARGS}, -{"setRGBA", (PyCFunction)KX_VertexProxy::sPySetRGBA,METH_O}, -{"getNormal", (PyCFunction)KX_VertexProxy::sPyGetNormal,METH_NOARGS}, -{"setNormal", (PyCFunction)KX_VertexProxy::sPySetNormal,METH_O}, - {NULL,NULL} //Sentinel + {"getXYZ", (PyCFunction)KX_VertexProxy::sPyGetXYZ,METH_NOARGS}, + {"setXYZ", (PyCFunction)KX_VertexProxy::sPySetXYZ,METH_O}, + {"getUV", (PyCFunction)KX_VertexProxy::sPyGetUV1, METH_NOARGS}, + {"setUV", (PyCFunction)KX_VertexProxy::sPySetUV1, METH_O}, + + {"getUV2", (PyCFunction)KX_VertexProxy::sPyGetUV2,METH_NOARGS}, + {"setUV2", (PyCFunction)KX_VertexProxy::sPySetUV2,METH_VARARGS}, + + {"getRGBA", (PyCFunction)KX_VertexProxy::sPyGetRGBA,METH_NOARGS}, + {"setRGBA", (PyCFunction)KX_VertexProxy::sPySetRGBA,METH_O}, + {"getNormal", (PyCFunction)KX_VertexProxy::sPyGetNormal,METH_NOARGS}, + {"setNormal", (PyCFunction)KX_VertexProxy::sPySetNormal,METH_O}, + {NULL,NULL} //Sentinel }; PyAttributeDef KX_VertexProxy::Attributes[] = { @@ -247,7 +247,7 @@ int KX_VertexProxy::pyattr_set_u(void *self_v, const struct KX_PYATTRIBUTE_DEF * float val = PyFloat_AsDouble(value); MT_Point2 uv = self->m_vertex->getUV1(); uv[0] = val; - self->m_vertex->SetUV(uv); + self->m_vertex->SetUV1(uv); self->m_mesh->SetMeshModified(true); return PY_SET_ATTR_SUCCESS; } @@ -262,7 +262,7 @@ int KX_VertexProxy::pyattr_set_v(void *self_v, const struct KX_PYATTRIBUTE_DEF * float val = PyFloat_AsDouble(value); MT_Point2 uv = self->m_vertex->getUV1(); uv[1] = val; - self->m_vertex->SetUV(uv); + self->m_vertex->SetUV1(uv); self->m_mesh->SetMeshModified(true); return PY_SET_ATTR_SUCCESS; } @@ -389,9 +389,8 @@ int KX_VertexProxy::pyattr_set_UV(void *self_v, const struct KX_PYATTRIBUTE_DEF if (PySequence_Check(value)) { MT_Point2 vec; - if (PyVecTo(value, vec)) - { - self->m_vertex->SetUV(vec); + if (PyVecTo(value, vec)) { + self->m_vertex->SetUV1(vec); self->m_mesh->SetMeshModified(true); return PY_SET_ATTR_SUCCESS; } @@ -521,18 +520,18 @@ PyObject *KX_VertexProxy::PySetRGBA(PyObject *value) } -PyObject *KX_VertexProxy::PyGetUV() +PyObject *KX_VertexProxy::PyGetUV1() { return PyObjectFrom(MT_Vector2(m_vertex->getUV1())); } -PyObject *KX_VertexProxy::PySetUV(PyObject *value) +PyObject *KX_VertexProxy::PySetUV1(PyObject *value) { MT_Point2 vec; if (!PyVecTo(value, vec)) return NULL; - m_vertex->SetUV(vec); + m_vertex->SetUV1(vec); m_mesh->SetMeshModified(true); Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_VertexProxy.h b/source/gameengine/Ketsji/KX_VertexProxy.h index 6e193d35b4c..4247d138a66 100644 --- a/source/gameengine/Ketsji/KX_VertexProxy.h +++ b/source/gameengine/Ketsji/KX_VertexProxy.h @@ -92,8 +92,8 @@ public: KX_PYMETHOD_NOARGS(KX_VertexProxy,GetXYZ); KX_PYMETHOD_O(KX_VertexProxy,SetXYZ); - KX_PYMETHOD_NOARGS(KX_VertexProxy,GetUV); - KX_PYMETHOD_O(KX_VertexProxy,SetUV); + KX_PYMETHOD_NOARGS(KX_VertexProxy,GetUV1); + KX_PYMETHOD_O(KX_VertexProxy,SetUV1); KX_PYMETHOD_NOARGS(KX_VertexProxy,GetUV2); KX_PYMETHOD_VARARGS(KX_VertexProxy,SetUV2); diff --git a/source/gameengine/Network/NG_NetworkDeviceInterface.h b/source/gameengine/Network/NG_NetworkDeviceInterface.h index 48edbdfc7fe..6da478ecda5 100644 --- a/source/gameengine/Network/NG_NetworkDeviceInterface.h +++ b/source/gameengine/Network/NG_NetworkDeviceInterface.h @@ -43,8 +43,8 @@ private: // candidates for shared/common implementation class bool m_online; public: - NG_NetworkDeviceInterface() {}; - virtual ~NG_NetworkDeviceInterface() {}; + NG_NetworkDeviceInterface() {} + virtual ~NG_NetworkDeviceInterface() {} virtual void NextFrame()=0; diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp index d1a8143fa88..d1fabba18f9 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp @@ -85,8 +85,9 @@ void DummyPhysicsEnvironment::setGravity(float x,float y,float z) { } - - +void DummyPhysicsEnvironment::getGravity(PHY__Vector3& grav) +{ +} diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h index 233c4412d9e..5ce34bdf7cf 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h @@ -56,6 +56,7 @@ public: virtual float getFixedTimeStep(); virtual void setGravity(float x,float y,float z); + virtual void getGravity(PHY__Vector3& grav); virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, float pivotX,float pivotY,float pivotZ, diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h index 077d225903c..bfbe570ad0c 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h @@ -143,6 +143,7 @@ class PHY_IPhysicsEnvironment virtual void setUseEpa(bool epa) {} virtual void setGravity(float x,float y,float z)=0; + virtual void getGravity(PHY__Vector3& grav) = 0; virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, float pivotX,float pivotY,float pivotZ, diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.h b/source/gameengine/Rasterizer/RAS_ICanvas.h index 53195d79768..60b9f052075 100644 --- a/source/gameengine/Rasterizer/RAS_ICanvas.h +++ b/source/gameengine/Rasterizer/RAS_ICanvas.h @@ -59,7 +59,7 @@ public: virtual ~RAS_ICanvas( ) { - }; + } virtual void diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.h b/source/gameengine/Rasterizer/RAS_MaterialBucket.h index 16ecffb9a32..4c72f128817 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.h +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.h @@ -189,6 +189,8 @@ class RAS_MeshMaterial public: RAS_MeshSlot *m_baseslot; class RAS_MaterialBucket *m_bucket; + + /* the KX_GameObject is used as a key here */ CTR_Map<CTR_HashedPtr,RAS_MeshSlot*> m_slots; diff --git a/source/gameengine/Rasterizer/RAS_TexVert.cpp b/source/gameengine/Rasterizer/RAS_TexVert.cpp index b60fae73e2a..945644ff3e6 100644 --- a/source/gameengine/Rasterizer/RAS_TexVert.cpp +++ b/source/gameengine/Rasterizer/RAS_TexVert.cpp @@ -63,10 +63,10 @@ const MT_Point3& RAS_TexVert::xyz() void RAS_TexVert::SetRGBA(const MT_Vector4& rgba) { unsigned char *colp = (unsigned char*) &m_rgba; - colp[0] = (unsigned char) (rgba[0]*255.0f); - colp[1] = (unsigned char) (rgba[1]*255.0f); - colp[2] = (unsigned char) (rgba[2]*255.0f); - colp[3] = (unsigned char) (rgba[3]*255.0f); + colp[0] = (unsigned char) (rgba[0] * 255.0); + colp[1] = (unsigned char) (rgba[1] * 255.0); + colp[2] = (unsigned char) (rgba[2] * 255.0); + colp[3] = (unsigned char) (rgba[3] * 255.0); } @@ -75,21 +75,32 @@ void RAS_TexVert::SetXYZ(const MT_Point3& xyz) xyz.getValue(m_localxyz); } -void RAS_TexVert::SetXYZ(const float *xyz) +void RAS_TexVert::SetXYZ(const float xyz[3]) { m_localxyz[0] = xyz[0]; m_localxyz[1] = xyz[1]; m_localxyz[2] = xyz[2]; } -void RAS_TexVert::SetUV(const MT_Point2& uv) +void RAS_TexVert::SetUV1(const MT_Point2& uv) { uv.getValue(m_uv1); } +void RAS_TexVert::SetUV1(const float uv[3]) +{ + m_uv1[0] = uv[0]; + m_uv1[1] = uv[1]; +} + void RAS_TexVert::SetUV2(const MT_Point2& uv) { uv.getValue(m_uv2); } +void RAS_TexVert::SetUV2(const float uv[3]) +{ + m_uv2[0] = uv[0]; + m_uv2[1] = uv[1]; +} void RAS_TexVert::SetRGBA(const unsigned int rgba) { @@ -151,3 +162,12 @@ void RAS_TexVert::Transform(const MT_Matrix4x4& mat, const MT_Matrix4x4& nmat) SetTangent((nmat*MT_Vector4(m_tangent[0], m_tangent[1], m_tangent[2], 1.0)).getValue()); } +void RAS_TexVert::TransformUV1(const MT_Matrix4x4& mat) +{ + SetUV1((mat * MT_Vector4(m_uv1[0], m_uv1[1], 0.0, 1.0)).getValue()); +} + +void RAS_TexVert::TransformUV2(const MT_Matrix4x4& mat) +{ + SetUV2((mat * MT_Vector4(m_uv2[0], m_uv2[1], 0.0, 1.0)).getValue()); +} diff --git a/source/gameengine/Rasterizer/RAS_TexVert.h b/source/gameengine/Rasterizer/RAS_TexVert.h index 889769da5ed..98ea4dd60aa 100644 --- a/source/gameengine/Rasterizer/RAS_TexVert.h +++ b/source/gameengine/Rasterizer/RAS_TexVert.h @@ -122,9 +122,11 @@ public: } void SetXYZ(const MT_Point3& xyz); - void SetXYZ(const float *xyz); - void SetUV(const MT_Point2& uv); + void SetXYZ(const float xyz[3]); + void SetUV1(const MT_Point2& uv); void SetUV2(const MT_Point2& uv); + void SetUV1(const float uv[2]); + void SetUV2(const float uv[2]); void SetRGBA(const unsigned int rgba); void SetNormal(const MT_Vector3& normal); @@ -137,6 +139,8 @@ public: void Transform(const class MT_Matrix4x4& mat, const class MT_Matrix4x4& nmat); + void TransformUV1(const MT_Matrix4x4& mat); + void TransformUV2(const MT_Matrix4x4& mat); // compare two vertices, to test if they can be shared, used for // splitting up based on uv's, colors, etc diff --git a/source/gameengine/SceneGraph/SG_IObject.h b/source/gameengine/SceneGraph/SG_IObject.h index 885eb8e1e90..6b57db1a467 100644 --- a/source/gameengine/SceneGraph/SG_IObject.h +++ b/source/gameengine/SceneGraph/SG_IObject.h @@ -127,8 +127,8 @@ struct SG_Callbacks m_schedulefunc(NULL), m_reschedulefunc(NULL) { - }; - + } + SG_Callbacks( SG_ReplicationNewCallback repfunc, SG_DestructionNewCallback destructfunc, @@ -142,7 +142,7 @@ struct SG_Callbacks m_schedulefunc(schedulefunc), m_reschedulefunc(reschedulefunc) { - }; + } SG_ReplicationNewCallback m_replicafunc; SG_DestructionNewCallback m_destructionfunc; diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index 85857165403..2cc2cfb6bfc 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -375,7 +375,7 @@ static PyMethodDef imageRenderMethods[] = static PyGetSetDef imageRenderGetSets[] = { {(char*)"background", (getter)getBackground, (setter)setBackground, (char*)"background color", NULL}, - // attribute from ImageViewport + // attribute from ImageViewport {(char*)"capsize", (getter)ImageViewport_getCaptureSize, (setter)ImageViewport_setCaptureSize, (char*)"size of render area", NULL}, {(char*)"alpha", (getter)ImageViewport_getAlpha, (setter)ImageViewport_setAlpha, (char*)"use alpha in texture", NULL}, {(char*)"whole", (getter)ImageViewport_getWhole, (setter)ImageViewport_setWhole, (char*)"use whole viewport to render", NULL}, |