diff options
author | Joshua Leung <aligorith@gmail.com> | 2015-12-12 07:43:00 +0300 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2015-12-12 07:43:00 +0300 |
commit | 50fde02b422a1a1dbc71a7bc95a061e46ce73b33 (patch) | |
tree | 631d2de1db5a6321241685f8015f740da64c7a85 | |
parent | 85bbf7e04f2694a160219e07fb44711f157e6237 (diff) | |
parent | dc98a3b0a74b0e91ad424195ce488a9b14f13e73 (diff) |
Merge branch 'master' into GPencil_Editing_Stage3
Conflicts:
source/blender/editors/transform/transform_manipulator.c
576 files changed, 15019 insertions, 25455 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f7be4ebdb61..354e4adb0d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -267,6 +267,10 @@ if(NOT WITH_AUDASPACE) endif() option(WITH_OPENMP "Enable OpenMP (has to be supported by the compiler)" ON) +if(UNIX AND NOT APPLE) + option(WITH_OPENMP_STATIC "Link OpenMP statically (only used by the release environment)" OFF) + mark_as_advanced(WITH_OPENMP_STATIC) +endif() if(WITH_X11) option(WITH_X11_XINPUT "Enable X11 Xinput (tablet support and unicode input)" ON) @@ -358,7 +362,6 @@ if(WIN32) endif() option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ${_init_INPUT_NDOF}) option(WITH_RAYOPTIMIZATION "Enable use of SIMD (SSE) optimizations for the raytracer" ON) -option(WITH_OPENNL "Enable use of Open Numerical Library" ON) if(UNIX AND NOT APPLE) option(WITH_INSTALL_PORTABLE "Install redistributeable runtime, otherwise install into CMAKE_INSTALL_PREFIX" ON) option(WITH_STATIC_LIBS "Try to link with static libraries, as much as possible, to make blender more portable across distributions" OFF) @@ -810,14 +813,14 @@ set(PLATFORM_LINKFLAGS_DEBUG "") # For alternate Python locations the commandline can be used to override detected/default cache settings, e.g: # On Unix: # cmake ../blender \ -# -D PYTHON_VERSION=3.4 \ -# -D PYTHON_INCLUDE_DIR=/opt/py34/include/python3.4d \ -# -D PYTHON_LIBRARY=/opt/py34/lib/libpython3.4d.so +# -D PYTHON_VERSION=3.5 \ +# -D PYTHON_INCLUDE_DIR=/opt/py35/include/python3.5d \ +# -D PYTHON_LIBRARY=/opt/py35/lib/libpython3.5d.so # # On Macs: # cmake ../blender \ -# -D PYTHON_INCLUDE_DIR=/System/Library/Frameworks/Python.framework/Versions/3.4/include/python3.4 \ -# -D PYTHON_LIBPATH=/System/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/config \ +# -D PYTHON_INCLUDE_DIR=/System/Library/Frameworks/Python.framework/Versions/3.5/include/python3.5 \ +# -D PYTHON_LIBPATH=/System/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/config \ # -G Xcode # # When changing any of this remember to update the notes in doc/build_systems/cmake.txt @@ -865,13 +868,9 @@ endif() if(UNIX AND NOT APPLE) macro(find_package_wrapper) if(WITH_STATIC_LIBS) - set(_cmake_find_library_suffixes_back ${CMAKE_FIND_LIBRARY_SUFFIXES}) - set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) - endif() - find_package(${ARGV}) - if(WITH_STATIC_LIBS) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${_cmake_find_library_suffixes_back}) - unset(_cmake_find_library_suffixes_back) + find_package_static(${ARGV}) + else() + find_package(${ARGV}) endif() endmacro() @@ -896,10 +895,10 @@ if(UNIX AND NOT APPLE) # else values are set below for all platforms if(WITH_PYTHON) - # No way to set py34. remove for now. + # No way to set py35, remove for now. # find_package(PythonLibs) - # Use our own instead, since wothout py is such a rare case, + # Use our own instead, since without py is such a rare case, # require this package # XXX Linking errors with debian static python :/ # find_package_wrapper(PythonLibsUnix REQUIRED) @@ -1292,13 +1291,22 @@ elseif(WIN32) set(PLATFORM_LINKFLAGS_DEBUG "/IGNORE:4099 /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libc.lib") if(NOT DEFINED LIBDIR) + # Setup 64bit and 64bit windows systems if(CMAKE_CL_64) message(STATUS "64 bit compiler detected.") - set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/win64_vc12) + set(LIBDIR_BASE "win64") else() message(STATUS "32 bit compiler detected.") - set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/windows_vc12) + set(LIBDIR_BASE "windows") + endif() + + if(MSVC_VERSION EQUAL 1900) + message(STATUS "Visual Studio 2015 detected.") + set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14) + else() + message(STATUS "Visual Studio 2013 detected.") + set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc12) endif() else() message(STATUS using LIBDIR ${LIBDIR}) @@ -1734,7 +1742,7 @@ elseif(WIN32) if(WITH_PYTHON) # normally cached but not since we include them with blender - set(PYTHON_VERSION 3.4) # CACHE STRING) + set(PYTHON_VERSION 3.5) # CACHE STRING) string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION}) set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}") # CACHE PATH) set(PYTHON_LIBRARY "${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}mw.lib") # CACHE FILEPATH) @@ -1939,7 +1947,7 @@ elseif(APPLE) endif() if(WITH_PYTHON) - # we use precompiled libraries for py 3.4 and up by default + # we use precompiled libraries for py 3.5 and up by default set(PYTHON_VERSION 3.5) if(NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK) # normally cached but not since we include them with blender @@ -2458,8 +2466,18 @@ endif() if(WITH_OPENMP) find_package(OpenMP) if(OPENMP_FOUND) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + if(NOT WITH_OPENMP_STATIC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + else() + # Typically avoid adding flags as defines but we can't + # ass OpenMP flags to the linker for static builds, meaning + # we can't add any OpenMP related flags to CFLAGS variables + # since they're passed to the linker as well. + add_definitions("${OpenMP_C_FLAGS}") + + find_library_static(OpenMP_LIBRARIES gomp ${CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES}) + endif() else() set(WITH_OPENMP OFF) endif() @@ -2973,9 +2991,6 @@ if(FIRST_RUN) info_cfg_option(WITH_GL_ANGLE) endif() - info_cfg_text("Other:") - info_cfg_option(WITH_OPENNL) - # debug message(STATUS "HAVE_STDBOOL_H = ${HAVE_STDBOOL_H}") diff --git a/SConstruct b/SConstruct index 29f539236c2..de265df5b02 100644 --- a/SConstruct +++ b/SConstruct @@ -555,7 +555,6 @@ else: # TODO, make optional (as with CMake) env['CPPFLAGS'].append('-DWITH_AVI') -env['CPPFLAGS'].append('-DWITH_OPENNL') if env['OURPLATFORM'] not in ('win32-vc', 'win64-vc'): env['CPPFLAGS'].append('-DHAVE_STDBOOL_H') @@ -797,8 +796,8 @@ if B.targets != ['cudakernels']: data_to_c_simple("source/blender/gpu/shaders/gpu_program_smoke_frag.glsl") data_to_c_simple("source/blender/gpu/shaders/gpu_program_smoke_color_frag.glsl") - data_to_c_simple("source/blender/gpu/shaders/gpu_shader_simple_frag.glsl") - data_to_c_simple("source/blender/gpu/shaders/gpu_shader_simple_vert.glsl") + data_to_c_simple("source/blender/gpu/shaders/gpu_shader_basic_frag.glsl") + data_to_c_simple("source/blender/gpu/shaders/gpu_shader_basic_vert.glsl") data_to_c_simple("source/blender/gpu/shaders/gpu_shader_material.glsl") data_to_c_simple("source/blender/gpu/shaders/gpu_shader_material.glsl") data_to_c_simple("source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_frag.glsl") diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 8c38a766002..e98a84f8888 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -249,19 +249,19 @@ DO_SHOW_DEPS=false SUDO="sudo" -PYTHON_VERSION="3.4.0" -PYTHON_VERSION_MIN="3.4" +PYTHON_VERSION="3.5.1" +PYTHON_VERSION_MIN="3.5" PYTHON_FORCE_BUILD=false PYTHON_FORCE_REBUILD=false PYTHON_SKIP=false -NUMPY_VERSION="1.9.1" +NUMPY_VERSION="1.10.1" NUMPY_VERSION_MIN="1.8" NUMPY_FORCE_BUILD=false NUMPY_FORCE_REBUILD=false NUMPY_SKIP=false -BOOST_VERSION="1.51.0" +BOOST_VERSION="1.55.0" BOOST_VERSION_MIN="1.49" BOOST_FORCE_BUILD=false BOOST_FORCE_REBUILD=false @@ -731,7 +731,7 @@ download() { done if [ $error -eq 1 ]; then - ERROR "wget could not find $1, or could not write it to $2, exiting" + ERROR "wget could not find ${sources[@]}, or could not write it to $2, exiting" exit 1 fi } @@ -1527,7 +1527,7 @@ clean_LLVM() { compile_LLVM() { # To be changed each time we make edits that would modify the compiled result! - llvm_magic=2 + llvm_magic=3 _init_llvm # Clean install if needed! @@ -1700,7 +1700,7 @@ compile_OSL() { if [ ! -z $LLVM_VERSION_FOUND ]; then cmake_d="$cmake_d -D LLVM_VERSION=$LLVM_VERSION_FOUND" if [ -d $INST/llvm ]; then - cmake_d="$cmake_d -D LLVM_ROOT_DIR=$INST/llvm" + cmake_d="$cmake_d -D LLVM_DIRECTORY=$INST/llvm" cmake_d="$cmake_d -D LLVM_STATIC=ON" fi fi @@ -2209,6 +2209,13 @@ install_DEB() { PRINT "" install_packages_DEB $_packages + PRINT"" + SNDFILE_DEV="libsndfile1-dev" + check_package_DEB $SNDFILE_DEV + if [ $? -eq 0 ]; then + install_packages_DEB $SNDFILE_DEV + fi + PRINT "" X264_DEV="libx264-dev" check_package_version_ge_DEB $X264_DEV $X264_VERSION_MIN @@ -2762,6 +2769,13 @@ install_RPM() { fi fi + PRINT"" + SNDFILE_DEV="libsndfile-devel" + check_package_RPM $SNDFILE_DEV + if [ $? -eq 0 ]; then + install_packages_RMP $SNDFILE_DEV + fi + if [ "$WITH_ALL" = true ]; then PRINT "" VPX_DEV="libvpx-devel" @@ -2924,7 +2938,7 @@ install_RPM() { PRINT "" - _do_compile_osl=true + _do_compile_osl=false if [ "$OSL_SKIP" = true ]; then WARNING "Skipping OpenShadingLanguage installation, as requested..." elif [ "$OSL_FORCE_BUILD" = true ]; then @@ -3125,6 +3139,13 @@ install_ARCH() { PRINT "" install_packages_ARCH $_packages + PRINT"" + SNDFILE_DEV="libsndfile" + check_package_ARCH $SNDFILE_DEV + if [ $? -eq 0 ]; then + install_packages_ARCH $SNDFILE_DEV + fi + PRINT "" X264_DEV="x264" check_package_version_ge_ARCH $X264_DEV $X264_VERSION_MIN @@ -3664,6 +3685,13 @@ print_info() { _buildargs="" + _1="-D WITH_CODEC_SNDFILE=ON" + PRINT " $_1" + _buildargs="$_buildargs -U *SNDFILE* $_1" + + _1="-D PYTHON_VERSION=$PYTHON_VERSION_MIN" + PRINT " $_1" + _buildargs="$_buildargs -U *PYTHON* $_1" if [ -d $INST/python-$PYTHON_VERSION_MIN ]; then _1="-D PYTHON_ROOT_DIR=$INST/python-$PYTHON_VERSION_MIN" PRINT " $_1" @@ -3675,25 +3703,25 @@ print_info() { _2="-D Boost_NO_SYSTEM_PATHS=ON" PRINT " $_1" PRINT " $_2" - _buildargs="$_buildargs $_1 $_2" + _buildargs="$_buildargs -U *BOOST* -U *Boost* $_1 $_2" fi if [ -d $INST/ocio ]; then _1="-D OPENCOLORIO_ROOT_DIR=$INST/ocio" PRINT " $_1" - _buildargs="$_buildargs $_1" + _buildargs="$_buildargs -U *OPENCOLORIO* $_1" fi if [ -d $INST/openexr ]; then _1="-D OPENEXR_ROOT_DIR=$INST/openexr" PRINT " $_1" - _buildargs="$_buildargs $_1" + _buildargs="$_buildargs -U *OPENEXR* $_1" fi if [ -d $INST/oiio ]; then _1="-D OPENIMAGEIO_ROOT_DIR=$INST/oiio" PRINT " $_1" - _buildargs="$_buildargs $_1" + _buildargs="$_buildargs -U *OPENIMAGEIO* $_1" fi if [ "$OSL_SKIP" = false ]; then @@ -3703,7 +3731,7 @@ print_info() { PRINT " $_1" PRINT " $_2" PRINT " $_3" - _buildargs="$_buildargs $_1 $_2 $_3" + _buildargs="$_buildargs -U *LLVM* -U *CYCLES* $_1 $_2 $_3" if [ -d $INST/osl ]; then _1="-D CYCLES_OSL=$INST/osl" PRINT " $_1" @@ -3729,13 +3757,13 @@ print_info() { _2="-D OPENSUBDIV_ROOT_DIR=$INST/osd" PRINT " $_1" PRINT " $_2" - _buildargs="$_buildargs $_1 $_2" + _buildargs="$_buildargs -U *OPENSUBDIV* $_1 $_2" fi if [ "$WITH_OPENCOLLADA" = true ]; then _1="-D WITH_OPENCOLLADA=ON" PRINT " $_1" - _buildargs="$_buildargs $_1" + _buildargs="$_buildargs -U *COLLADA* $_1" fi if [ "$FFMPEG_SKIP" = false ]; then @@ -3743,7 +3771,7 @@ print_info() { _2="-D FFMPEG_LIBRARIES='avformat;avcodec;avutil;avdevice;swscale;rt;`print_info_ffmpeglink`'" PRINT " $_1" PRINT " $_2" - _buildargs="$_buildargs $_1 $_2" + _buildargs="$_buildargs -U *FFMPEG* $_1 $_2" if [ -d $INST/ffmpeg ]; then _1="-D FFMPEG=$INST/ffmpeg" PRINT " $_1" @@ -3758,6 +3786,9 @@ print_info() { PRINT "" PRINT "If you're using SCons add this to your user-config:" + PRINT "WITH_BF_SNDFILE = True" + + PRINT "BF_PYTHON_VERSION = '$PYTHON_VERSION_MIN'" if [ -d $INST/python-$PYTHON_VERSION_MIN ]; then PRINT "BF_PYTHON = '$INST/python-$PYTHON_VERSION_MIN'" PRINT "BF_PYTHON_ABI_FLAGS = 'm'" diff --git a/build_files/buildbot/config/blender_linux.cmake b/build_files/buildbot/config/blender_linux.cmake new file mode 100644 index 00000000000..d4895ce26d7 --- /dev/null +++ b/build_files/buildbot/config/blender_linux.cmake @@ -0,0 +1,102 @@ +# ######## Global feature set settings ######## + +include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/config/blender_full.cmake") + +# Default to only build Blender, not the player +set(WITH_BLENDER ON CACHE BOOL "" FORCE) +set(WITH_PLAYER OFF CACHE BOOL "" FORCE) + +# ######## Linux-specific build options ######## +# Options which are specific to Linux-only platforms +set(WITH_DOC_MANPAGE OFF CACHE BOOL "" FORCE) + +# ######## Official release-specific build options ######## +# Options which are specific to Linux release builds only +set(WITH_JACK_DYNLOAD ON CACHE BOOL "" FORCE) +set(WITH_SDL_DYNLOAD ON CACHE BOOL "" FORCE) +set(WITH_SYSTEM_GLEW OFF CACHE BOOL "" FORCE) + +set(WITH_OPENMP_STATIC ON CACHE BOOL "" FORCE) + +set(WITH_PYTHON_INSTALL_NUMPY ON CACHE BOOL "" FORCE) +set(WITH_PYTHON_INSTALL_REQUESTS ON CACHE BOOL "" FORCE) + +# ######## Release environment specific settings ######## +# All the hardcoded libraru paths and such + +# LLVM libraries +set(LLVM_VERSION "3.4" CACHE STRING "" FORCE) +set(LLVM_ROOT_DIR "/opt/lib/llvm-${LLVM_VERSION}" CACHE STRING "" FORCE) +set(LLVM_STATIC ON CACHE BOOL "" FORCE) + +# BOOST libraries +set(BOOST_ROOT "/opt/lib/boost" CACHE STRING "" FORCE) +set(Boost_USE_STATIC_LIBS ON CACHE BOOL "" FORCE) + +# FFmpeg libraries +set(FFMPEG "/opt/lib/ffmpeg" CACHE STRING "" FORCE) +set(FFMPEG_LIBRARIES + avdevice avformat avcodec avutil avfilter swscale swresample + /usr/lib/libxvidcore.a + /usr/lib/libx264.a + /usr/lib/libmp3lame.a + /usr/lib/libvpx.a + /usr/lib/libvorbis.a + /usr/lib/libogg.a + /usr/lib/libvorbisenc.a + /usr/lib/libtheora.a + /usr/lib/libschroedinger-1.0.a + /usr/lib/liborc-0.4.a + CACHE STRING "" FORCE +) + +# SndFile libraries +set(SNDFILE_LIBRARY "/usr/lib/libsndfile.a;/usr/lib/libFLAC.a" CACHE STRING "" FORCE) + +# OpenAL libraries +set(OPENAL_ROOT_DIR "/opt/lib/openal" CACHE STRING "" FORCE) +set(OPENAL_INCLUDE_DIR "${OPENAL_ROOT_DIR}/include" CACHE STRING "" FORCE) +set(OPENAL_LIBRARY + ${OPENAL_ROOT_DIR}/lib/libopenal.a + ${OPENAL_ROOT_DIR}/lib/libcommon.a + CACHE STRING "" FORCE +) + +# OpenCollada libraries +set(OPENCOLLADA_UTF_LIBRARY "" CACHE STRING "" FORCE) +set(PCRE_INCLUDE_DIR "/usr/include" CACHE STRING "" FORCE) +set(PCRE_LIBRARY "/usr/lib/libpcre.a" CACHE STRING "" FORCE) +set(XML2_INCLUDE_DIR "/usr/include" CACHE STRING "" FORCE) +set(XML2_LIBRARY "/usr/lib/libxml2.a" CACHE STRING "" FORCE) + +# OpenColorIO libraries +set(OPENCOLORIO_ROOT_DIR "/opt/lib/ocio" CACHE STRING "" FORCE) +set(OPENCOLORIO_OPENCOLORIO_LIBRARY "${OPENCOLORIO_ROOT_DIR}/lib/libOpenColorIO.a" CACHE STRING "" FORCE) +set(OPENCOLORIO_TINYXML_LIBRARY "${OPENCOLORIO_ROOT_DIR}/lib/libtinyxml.a" CACHE STRING "" FORCE) +set(OPENCOLORIO_YAML-CPP_LIBRARY "${OPENCOLORIO_ROOT_DIR}/lib/libyaml-cpp.a" CACHE STRING "" FORCE) + +# OpenSubdiv libraries +set(OPENSUBDIV_ROOT_DIR "/opt/lib/opensubdiv" CACHE STRING "" FORCE) +set(OPENSUBDIV_OSDCPU_LIBRARY "${OPENSUBDIV_ROOT_DIR}/lib/libosdCPU.a" CACHE STRING "" FORCE) +set(OPENSUBDIV_OSDGPU_LIBRARY "${OPENSUBDIV_ROOT_DIR}/lib/libosdGPU.a" CACHE STRING "" FORCE) + +# OpenEXR libraries +set(OPENEXR_ROOT_DIR "/opt/lib/openexr" CACHE STRING "" FORCE) +set(OPENEXR_HALF_LIBRARY "/opt/lib/openexr/lib/libHalf.a" CACHE STRING "" FORCE) +set(OPENEXR_IEX_LIBRARY "/opt/lib/openexr/lib/libIex.a" CACHE STRING "" FORCE) +set(OPENEXR_ILMIMF_LIBRARY "/opt/lib/openexr/lib/libIlmImf.a" CACHE STRING "" FORCE) +set(OPENEXR_ILMTHREAD_LIBRARY "/opt/lib/openexr/lib/libIlmThread.a" CACHE STRING "" FORCE) +set(OPENEXR_IMATH_LIBRARY "/opt/lib/openexr/lib/libImath.a" CACHE STRING "" FORCE) + +# JeMalloc library +set(JEMALLOC_LIBRARY "/opt/lib/jemalloc/lib/libjemalloc.a" CACHE STRING "" FORCE) + +# Foce some system libraries to be static +set(FFTW3_LIBRARY "/usr/lib/libfftw3.a" CACHE STRING "" FORCE) +set(JPEG_LIBRARY "/usr/lib/libjpeg.a" CACHE STRING "" FORCE) +set(PNG_LIBRARY "/usr/lib/libpng.a" CACHE STRING "" FORCE) +set(TIFF_LIBRARY "/usr/lib/libtiff.a" CACHE STRING "" FORCE) +set(ZLIB_LIBRARY "/usr/lib/libz.a" CACHE STRING "" FORCE) + +# Additional linking libraries +set(CMAKE_EXE_LINKER_FLAGS "-lrt" CACHE STRING "" FORCE) diff --git a/build_files/buildbot/config/blender_linux_player.cmake b/build_files/buildbot/config/blender_linux_player.cmake new file mode 100644 index 00000000000..2fb31192002 --- /dev/null +++ b/build_files/buildbot/config/blender_linux_player.cmake @@ -0,0 +1,12 @@ +# This is applied as an ovveride on top of blender_linux.config +# Disables all the areas which are not needed for the player. +set(WITH_COMPOSITOR OFF CACHE BOOL "" FORCE) +set(WITH_CYCLES OFF CACHE BOOL "" FORCE) +set(WITH_FREESTYLE OFF CACHE BOOL "" FORCE) +set(WITH_GHOST_XDND OFF CACHE BOOL "" FORCE) +set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE) +set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE) +set(WITH_LIBMV OFF CACHE BOOL "" FORCE) + +set(WITH_BLENDER OFF CACHE BOOL "" FORCE) +set(WITH_PLAYER ON CACHE BOOL "" FORCE) diff --git a/build_files/buildbot/config/user-config-cuda-glibc211-i686.py b/build_files/buildbot/config/user-config-cuda-glibc211-i686.py deleted file mode 100644 index 580e67ee7e3..00000000000 --- a/build_files/buildbot/config/user-config-cuda-glibc211-i686.py +++ /dev/null @@ -1,6 +0,0 @@ -BF_BUILDDIR = '../blender-build/linux-glibc211-i686' -BF_INSTALLDIR = '../blender-install/linux-glibc211-i686' -BF_NUMJOBS = 1 - -#BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52'] -BF_CYCLES_CUDA_BINARIES_ARCH = [] diff --git a/build_files/buildbot/config/user-config-cuda-glibc211-x86_64.py b/build_files/buildbot/config/user-config-cuda-glibc211-x86_64.py deleted file mode 100644 index 29b1b9f1ad7..00000000000 --- a/build_files/buildbot/config/user-config-cuda-glibc211-x86_64.py +++ /dev/null @@ -1,5 +0,0 @@ -BF_BUILDDIR = '../blender-build/linux-glibc211-x86_64' -BF_INSTALLDIR = '../blender-install/linux-glibc211-x86_64' -BF_NUMJOBS = 1 - -BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52'] diff --git a/build_files/buildbot/config/user-config-glibc211-i686.py b/build_files/buildbot/config/user-config-glibc211-i686.py deleted file mode 100644 index 88eae57431a..00000000000 --- a/build_files/buildbot/config/user-config-glibc211-i686.py +++ /dev/null @@ -1,185 +0,0 @@ -BF_BUILDDIR = '../blender-build/linux-glibc211-i686' -BF_INSTALLDIR = '../blender-install/linux-glibc211-i686' -BF_NUMJOBS = 4 -WITHOUT_BF_OVERWRITE_INSTALL = True - -# Python configuration -BF_PYTHON_VERSION = '3.5' -BF_PYTHON_ABI_FLAGS = 'm' -BF_PYTHON = '/opt/lib/python-3.5' -WITH_BF_PYTHON_INSTALL_NUMPY = True -WITH_BF_PYTHON_INSTALL_REQUESTS = True - -WITH_BF_STATICPYTHON = True - -# OpenCollada configuration -WITH_BF_COLLADA = True -WITH_BF_STATICOPENCOLLADA=True -BF_OPENCOLLADA = '/opt/lib/opencollada' -BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include' -BF_OPENCOLLADA_LIB_STATIC = '${BF_OPENCOLLADA}/lib/libOpenCOLLADAStreamWriter.a ' + \ - '${BF_OPENCOLLADA}/lib/libOpenCOLLADASaxFrameworkLoader.a ' + \ - '${BF_OPENCOLLADA}/lib/libOpenCOLLADAFramework.a ' + \ - '${BF_OPENCOLLADA}/lib/libOpenCOLLADABaseUtils.a ' + \ - '${BF_OPENCOLLADA}/lib/libGeneratedSaxParser.a ' + \ - '${BF_OPENCOLLADA}/lib/libMathMLSolver.a ' + \ - '${BF_OPENCOLLADA}/lib/libbuffer.a ${BF_OPENCOLLADA}/lib/libftoa.a ' + \ - '/usr/lib/libxml2.a /usr/lib/libexpat.a /usr/lib/libpcre.a' -BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib /home/sources/staticlibs/lib64' -BF_PCRE_LIB = '' -BF_EXPAT_LIB = '' - -# FFMPEG configuration -WITH_BF_FFMPEG = True -WITH_BF_STATICFFMPEG = True - -BF_FFMPEG = '/opt/lib/ffmpeg' -BF_FFMPEG_LIBPATH = '${BF_FFMPEG}/lib' -BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/libavdevice.a ' + \ - '${BF_FFMPEG_LIBPATH}/libavfilter.a ${BF_FFMPEG_LIBPATH}/libavcodec.a ${BF_FFMPEG_LIBPATH}/libavutil.a ' + \ - '${BF_FFMPEG_LIBPATH}/libswscale.a ${BF_FFMPEG_LIBPATH}/libswresample.a ' + \ - '/usr/lib/libxvidcore.a /usr/lib/libx264.a /usr/lib/libmp3lame.a /usr/lib/libvpx.a /usr/lib/libvorbis.a ' + \ - '/usr/lib/libogg.a /usr/lib/libvorbisenc.a /usr/lib/libtheora.a /usr/lib/libschroedinger-1.0.a ' + \ - '/usr/lib/liborc-0.4.a' - -# Don't depend on system's libstdc++ -WITH_BF_STATICCXX = True -BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.7.1/libstdc++.a' - -WITH_BF_OPENAL = True -WITH_BF_STATICOPENAL = True -BF_OPENAL = '/opt/lib/openal' -BF_OPENAL_LIB_STATIC = '/opt/lib/openal/lib/libopenal.a /opt/lib/openal/lib/libcommon.a' - -WITH_BF_GETTEXT_STATIC = True - -WITH_BF_FREETYPE_STATIC = False - -WITH_BF_OPENEXR = True -BF_OPENEXR = '/opt/lib/openexr' -BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include' -WITH_BF_STATICOPENEXR = True - -WITH_BF_TIFF = True -WITH_BF_STATICTIFF = True -BF_TIFF_LIB_STATIC = '${BF_TIFF}/lib/libtiff.a' - -WITH_BF_JPEG = True -WITH_BF_STATICJPEG = True -BF_JPEG_LIB_STATIC= '${BF_JPEG}/lib/libjpeg.a' - -WITH_BF_PNG = True -WITH_BF_STATICPNG = True -BF_PNG_LIB_STATIC = '${BF_PNG}/lib/libpng.a' - -WITH_BF_STATICLIBSAMPLERATE = True - -WITH_BF_ZLIB = True -WITH_BF_STATICZLIB = True -BF_ZLIB_LIB_STATIC = '${BF_ZLIB}/lib/libz.a' - -WITH_BF_SDL = True -WITH_BF_SDL_DYNLOAD = True - -WITH_BF_OGG = True - -WITH_BF_OPENMP = True -WITH_BF_STATICOPENMP = True -BF_OPENMP_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.7/libgomp.a' - -WITH_BF_GAMEENGINE = True -WITH_BF_BULLET = True - -# Blender player (would be enabled in it's own config) -WITH_BF_PLAYER = False - -# Use jemalloc memory manager -WITH_BF_JEMALLOC = True -WITH_BF_STATICJEMALLOC = True -BF_JEMALLOC = '/opt/lib/jemalloc' -BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib' - -# Use 3d mouse library -WITH_BF_3DMOUSE = True -WITH_BF_STATIC3DMOUSE = True -BF_3DMOUSE = '/opt/lib/libspnav' -BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib' - -# FFT -WITH_BF_FFTW3 = True -WITH_BF_STATICFFTW3 = True - -# JACK -WITH_BF_JACK = True -WITH_BF_JACK_DYNLOAD = True - -# Cycles -WITH_BF_CYCLES = True -WITH_BF_CYCLES_CUDA_BINARIES = False - -WITH_BF_OIIO = True -WITH_BF_STATICOIIO = True -BF_OIIO = '/opt/lib/oiio' -BF_OIIO_INC = '${BF_OIIO}/include' -BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/libOpenImageIO.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_JPEG}/lib/libjpeg.a' -BF_OIIO_LIBPATH = '${BF_OIIO}/lib' - -BF_IS_NEW_OSL = False -WITH_BF_CYCLES_OSL = True -WITH_BF_STATICOSL = BF_IS_NEW_OSL -BF_OSL = '/opt/lib/osl' -BF_OSL_INC = '${BF_OSL}/include' -# note oslexec would passed via program linkflags, which is needed to -# make llvm happy with osl_allocate_closure_component -BF_OSL_LIB = 'oslcomp oslexec oslquery' -BF_OSL_LIB_STATIC = '${BF_OSL}/lib/liboslcomp.a ${BF_OSL}/lib/liboslexec.a ${BF_OSL}/lib/liboslquery.a' -BF_OSL_LIBPATH = '${BF_OSL}/lib' -BF_OSL_COMPILER = '${BF_OSL}/bin/oslc' - -WITH_BF_LLVM = True -WITH_BF_STATICLLVM = False -BF_LLVM = '/opt/lib/llvm-3.4.2' -BF_LLVM_LIB = 'LLVMBitReader LLVMJIT LLVMipo LLVMVectorize LLVMBitWriter LLVMX86CodeGen LLVMX86Desc LLVMObject LLVMX86Info LLVMX86AsmPrinter ' + \ - 'LLVMX86Utils LLVMSelectionDAG LLVMCodeGen LLVMScalarOpts LLVMInstCombine LLVMTransformUtils LLVMipa LLVMAnalysis LLVMExecutionEngine ' + \ - 'LLVMTarget LLVMMC LLVMCore LLVMSupport' -BF_LLVM_LIBPATH = '${BF_LLVM}/lib' - -# Color management -WITH_BF_OCIO = True -WITH_BF_STATICOCIO = True -BF_OCIO = '/opt/lib/ocio' -BF_OCIO_INC = '${BF_OCIO}/include' -BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/libOpenColorIO.a ${BF_OCIO_LIBPATH}/libtinyxml.a ${BF_OCIO_LIBPATH}/libyaml-cpp.a' -BF_OCIO_LIBPATH = '${BF_OCIO}/lib' - -WITH_BF_BOOST = True -WITH_BF_STATICBOOST = True -BF_BOOST = '/opt/lib/boost' -BF_BOOST_INC = '${BF_BOOST}/include' -BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ' + \ - '${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_locale.a ${BF_BOOST_LIBPATH}/libboost_system.a \ - ${BF_BOOST_LIBPATH}/libboost_thread.a' -if BF_IS_NEW_OSL: - BF_BOOST_LIB_STATIC += ' ${BF_BOOST_LIBPATH}/libboost_wave.a' -BF_BOOST_LIBPATH = '${BF_BOOST}/lib' - -# Ocean Simulation -WITH_BF_OCEANSIM = True - -# OpenSubdiv -WITH_BF_OPENSUBDIV = True -WITH_BF_STATICOPENSUBDIV = True -BF_OPENSUBDIV = '/opt/lib/opensubdiv' -BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include' -BF_OPENSUBDIV_LIB = 'osdCPU osdGPU' -BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib' -BF_OPENSUBDIV_LIB_STATIC = '${BF_OPENSUBDIV}/lib/libosdCPU.a ${BF_OPENSUBDIV}/lib/libosdGPU.a' - -# Compilation and optimization -BF_DEBUG = False -REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++ -PLATFORM_LINKFLAGS = ['-lrt'] -if BF_IS_NEW_OSL: - BF_PROGRAM_LINKFLAGS = ['-Wl,--version-script=source/creator/blender.map'] -else: - BF_PROGRAM_LINKFLAGS = ['-Wl,--whole-archive', '-loslexec', '-Wl,--no-whole-archive', '-Wl,--version-script=source/creator/blender.map'] diff --git a/build_files/buildbot/config/user-config-glibc211-x86_64.py b/build_files/buildbot/config/user-config-glibc211-x86_64.py deleted file mode 100644 index 7059d50f208..00000000000 --- a/build_files/buildbot/config/user-config-glibc211-x86_64.py +++ /dev/null @@ -1,185 +0,0 @@ -BF_BUILDDIR = '../blender-build/linux-glibc211-x86_64' -BF_INSTALLDIR = '../blender-install/linux-glibc211-x86_64' -BF_NUMJOBS = 4 -WITHOUT_BF_OVERWRITE_INSTALL = True - -# Python configuration -BF_PYTHON_VERSION = '3.5' -BF_PYTHON_ABI_FLAGS = 'm' -BF_PYTHON = '/opt/lib/python-3.5' -WITH_BF_PYTHON_INSTALL_NUMPY = True -WITH_BF_PYTHON_INSTALL_REQUESTS = True - -WITH_BF_STATICPYTHON = True - -# OpenCollada configuration -WITH_BF_COLLADA = True -WITH_BF_STATICOPENCOLLADA=True -BF_OPENCOLLADA = '/opt/lib/opencollada' -BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include' -BF_OPENCOLLADA_LIB_STATIC = '${BF_OPENCOLLADA}/lib/libOpenCOLLADAStreamWriter.a ' + \ - '${BF_OPENCOLLADA}/lib/libOpenCOLLADASaxFrameworkLoader.a ' + \ - '${BF_OPENCOLLADA}/lib/libOpenCOLLADAFramework.a ' + \ - '${BF_OPENCOLLADA}/lib/libOpenCOLLADABaseUtils.a ' + \ - '${BF_OPENCOLLADA}/lib/libGeneratedSaxParser.a ' + \ - '${BF_OPENCOLLADA}/lib/libMathMLSolver.a ' + \ - '${BF_OPENCOLLADA}/lib/libbuffer.a ${BF_OPENCOLLADA}/lib/libftoa.a ' + \ - '/usr/lib/libxml2.a /usr/lib/libexpat.a /usr/lib/libpcre.a' -BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib /home/sources/staticlibs/lib64' -BF_PCRE_LIB = '' -BF_EXPAT_LIB = '' - -# FFMPEG configuration -WITH_BF_FFMPEG = True -WITH_BF_STATICFFMPEG = True - -BF_FFMPEG = '/opt/lib/ffmpeg' -BF_FFMPEG_LIBPATH = '${BF_FFMPEG}/lib' -BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/libavdevice.a ' + \ - '${BF_FFMPEG_LIBPATH}/libavfilter.a ${BF_FFMPEG_LIBPATH}/libavcodec.a ${BF_FFMPEG_LIBPATH}/libavutil.a ' + \ - '${BF_FFMPEG_LIBPATH}/libswscale.a ${BF_FFMPEG_LIBPATH}/libswresample.a ' + \ - '/usr/lib/libxvidcore.a /usr/lib/libx264.a /usr/lib/libmp3lame.a /usr/lib/libvpx.a /usr/lib/libvorbis.a ' + \ - '/usr/lib/libogg.a /usr/lib/libvorbisenc.a /usr/lib/libtheora.a /usr/lib/libschroedinger-1.0.a ' + \ - '/usr/lib/liborc-0.4.a' - -# Don't depend on system's libstdc++ -WITH_BF_STATICCXX = True -BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.7.1/libstdc++.a' - -WITH_BF_OPENAL = True -WITH_BF_STATICOPENAL = True -BF_OPENAL = '/opt/lib/openal' -BF_OPENAL_LIB_STATIC = '/opt/lib/openal/lib/libopenal.a /opt/lib/openal/lib/libcommon.a' - -WITH_BF_GETTEXT_STATIC = True - -WITH_BF_FREETYPE_STATIC = False - -WITH_BF_OPENEXR = True -BF_OPENEXR = '/opt/lib/openexr' -BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include' -WITH_BF_STATICOPENEXR = True - -WITH_BF_TIFF = True -WITH_BF_STATICTIFF = True -BF_TIFF_LIB_STATIC = '${BF_TIFF}/lib/libtiff.a' - -WITH_BF_JPEG = True -WITH_BF_STATICJPEG = True -BF_JPEG_LIB_STATIC= '${BF_JPEG}/lib/libjpeg.a' - -WITH_BF_PNG = True -WITH_BF_STATICPNG = True -BF_PNG_LIB_STATIC = '${BF_PNG}/lib/libpng.a' - -WITH_BF_STATICLIBSAMPLERATE = True - -WITH_BF_ZLIB = True -WITH_BF_STATICZLIB = True -BF_ZLIB_LIB_STATIC = '${BF_ZLIB}/lib/libz.a' - -WITH_BF_SDL = True -WITH_BF_SDL_DYNLOAD = True - -WITH_BF_OGG = True - -WITH_BF_OPENMP = True -WITH_BF_STATICOPENMP = True -BF_OPENMP_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.7/libgomp.a' - -WITH_BF_GAMEENGINE = True -WITH_BF_BULLET = True - -# Blender player (would be enabled in it's own config) -WITH_BF_PLAYER = False - -# Use jemalloc memory manager -WITH_BF_JEMALLOC = True -WITH_BF_STATICJEMALLOC = True -BF_JEMALLOC = '/opt/lib/jemalloc' -BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib' - -# Use 3d mouse library -WITH_BF_3DMOUSE = True -WITH_BF_STATIC3DMOUSE = True -BF_3DMOUSE = '/opt/lib/libspnav' -BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib' - -# FFT -WITH_BF_FFTW3 = True -WITH_BF_STATICFFTW3 = True - -# JACK -WITH_BF_JACK = True -WITH_BF_JACK_DYNLOAD = True - -# Cycles -WITH_BF_CYCLES = True -WITH_BF_CYCLES_CUDA_BINARIES = False - -WITH_BF_OIIO = True -WITH_BF_STATICOIIO = True -BF_OIIO = '/opt/lib/oiio' -BF_OIIO_INC = '${BF_OIIO}/include' -BF_OIIO_LIB_STATIC = '${BF_OIIO_LIBPATH}/libOpenImageIO.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_JPEG}/lib/libjpeg.a' -BF_OIIO_LIBPATH = '${BF_OIIO}/lib' - -BF_IS_NEW_OSL = False -WITH_BF_CYCLES_OSL = True -WITH_BF_STATICOSL = BF_IS_NEW_OSL -BF_OSL = '/opt/lib/osl' -BF_OSL_INC = '${BF_OSL}/include' -# note oslexec would passed via program linkflags, which is needed to -# make llvm happy with osl_allocate_closure_component -BF_OSL_LIB = 'oslcomp oslexec oslquery' -BF_OSL_LIB_STATIC = '${BF_OSL}/lib/liboslcomp.a ${BF_OSL}/lib/liboslexec.a ${BF_OSL}/lib/liboslquery.a' -BF_OSL_LIBPATH = '${BF_OSL}/lib' -BF_OSL_COMPILER = '${BF_OSL}/bin/oslc' - -WITH_BF_LLVM = True -WITH_BF_STATICLLVM = False -BF_LLVM = '/opt/lib/llvm-3.4.2' -BF_LLVM_LIB = 'LLVMBitReader LLVMJIT LLVMipo LLVMVectorize LLVMBitWriter LLVMX86CodeGen LLVMX86Desc LLVMObject LLVMX86Info LLVMX86AsmPrinter ' + \ - 'LLVMX86Utils LLVMSelectionDAG LLVMCodeGen LLVMScalarOpts LLVMInstCombine LLVMTransformUtils LLVMipa LLVMAnalysis LLVMExecutionEngine ' + \ - 'LLVMTarget LLVMMC LLVMCore LLVMSupport' -BF_LLVM_LIBPATH = '${BF_LLVM}/lib' - -# Color management -WITH_BF_OCIO = True -WITH_BF_STATICOCIO = True -BF_OCIO = '/opt/lib/ocio' -BF_OCIO_INC = '${BF_OCIO}/include' -BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/libOpenColorIO.a ${BF_OCIO_LIBPATH}/libtinyxml.a ${BF_OCIO_LIBPATH}/libyaml-cpp.a' -BF_OCIO_LIBPATH = '${BF_OCIO}/lib' - -WITH_BF_BOOST = True -WITH_BF_STATICBOOST = True -BF_BOOST = '/opt/lib/boost' -BF_BOOST_INC = '${BF_BOOST}/include' -BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ' + \ - '${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_locale.a ${BF_BOOST_LIBPATH}/libboost_system.a \ - ${BF_BOOST_LIBPATH}/libboost_thread.a' -if BF_IS_NEW_OSL: - BF_BOOST_LIB_STATIC += ' ${BF_BOOST_LIBPATH}/libboost_wave.a' -BF_BOOST_LIBPATH = '${BF_BOOST}/lib' - -# Ocean Simulation -WITH_BF_OCEANSIM = True - -# OpenSubdiv -WITH_BF_OPENSUBDIV = True -WITH_BF_STATICOPENSUBDIV = True -BF_OPENSUBDIV = '/opt/lib/opensubdiv' -BF_OPENSUBDIV_INC = '${BF_OPENSUBDIV}/include' -BF_OPENSUBDIV_LIB = 'osdCPU osdGPU' -BF_OPENSUBDIV_LIBPATH = '${BF_OPENSUBDIV}/lib' -BF_OPENSUBDIV_LIB_STATIC = '${BF_OPENSUBDIV}/lib/libosdCPU.a ${BF_OPENSUBDIV}/lib/libosdGPU.a' - -# Compilation and optimization -BF_DEBUG = False -REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++ -PLATFORM_LINKFLAGS = ['-lrt'] -if BF_IS_NEW_OSL: - BF_PROGRAM_LINKFLAGS = ['-Wl,--version-script=source/creator/blender.map'] -else: - BF_PROGRAM_LINKFLAGS = ['-Wl,--whole-archive', '-loslexec', '-Wl,--no-whole-archive', '-Wl,--version-script=source/creator/blender.map'] diff --git a/build_files/buildbot/config/user-config-player-glibc211-i686.py b/build_files/buildbot/config/user-config-player-glibc211-i686.py deleted file mode 100644 index 47898002ae6..00000000000 --- a/build_files/buildbot/config/user-config-player-glibc211-i686.py +++ /dev/null @@ -1,126 +0,0 @@ -BF_BUILDDIR = '../blender-build/linux-glibc211-i686' -BF_INSTALLDIR = '../blender-install/linux-glibc211-i686' -BF_NUMJOBS = 4 - -# Python configuration -BF_PYTHON_VERSION = '3.5' -BF_PYTHON_ABI_FLAGS = 'm' -BF_PYTHON = '/opt/lib/python-3.5' -WITH_BF_PYTHON_INSTALL_NUMPY = True -WITH_BF_PYTHON_INSTALL_REQUESTS = True - -WITH_BF_STATICPYTHON = True - -# OpenCollada configuration -WITH_BF_COLLADA = False - -# FFMPEG configuration -WITH_BF_FFMPEG = True -WITH_BF_STATICFFMPEG = True - -BF_FFMPEG = '/opt/lib/ffmpeg' -BF_FFMPEG_LIBPATH = '${BF_FFMPEG}/lib' -BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/libavdevice.a ' + \ - '${BF_FFMPEG_LIBPATH}/libavfilter.a ${BF_FFMPEG_LIBPATH}/libavcodec.a ${BF_FFMPEG_LIBPATH}/libavutil.a ' + \ - '${BF_FFMPEG_LIBPATH}/libswscale.a ${BF_FFMPEG_LIBPATH}/libswresample.a ' + \ - '/usr/lib/libxvidcore.a /usr/lib/libx264.a /usr/lib/libmp3lame.a /usr/lib/libvpx.a /usr/lib/libvorbis.a ' + \ - '/usr/lib/libogg.a /usr/lib/libvorbisenc.a /usr/lib/libtheora.a /usr/lib/libschroedinger-1.0.a ' + \ - '/usr/lib/liborc-0.4.a' - -# Don't depend on system's libstdc++ -WITH_BF_STATICCXX = True -BF_CXX_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.7.1/libstdc++.a' - -WITH_BF_OPENAL = True -WITH_BF_STATICOPENAL = True -BF_OPENAL = '/opt/lib/openal' -BF_OPENAL_LIB_STATIC = '/opt/lib/openal/lib/libopenal.a /opt/lib/openal/lib/libcommon.a' - -WITH_BF_GETTEXT_STATIC = True - -WITH_BF_FREETYPE_STATIC = False - -WITH_BF_OPENEXR = True -BF_OPENEXR = '/opt/lib/openexr' -BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include' -WITH_BF_STATICOPENEXR = True - -WITH_BF_TIFF = True -WITH_BF_STATICTIFF = True -BF_TIFF_LIB_STATIC = '${BF_TIFF}/lib/libtiff.a' - -WITH_BF_JPEG = True -WITH_BF_STATICJPEG = True -BF_JPEG_LIB_STATIC= '${BF_JPEG}/lib/libjpeg.a' - -WITH_BF_STATICLIBSAMPLERATE = True - -WITH_BF_PNG = True -WITH_BF_STATICPNG = True -BF_PNG_LIB_STATIC = '${BF_PNG}/lib/libpng.a' - -WITH_BF_ZLIB = True -WITH_BF_STATICZLIB = True -BF_ZLIB_LIB_STATIC = '${BF_ZLIB}/lib/libz.a' - -WITH_BF_SDL = True -WITH_BF_SDL_DYNLOAD = True - -WITH_BF_OGG = False - -WITH_BF_OPENMP = True -WITH_BF_STATICOPENMP = True -BF_OPENMP_LIB_STATIC = '/usr/lib/gcc/i486-linux-gnu/4.7/libgomp.a' - -WITH_BF_GAMEENGINE = True -WITH_BF_BULLET = True - -# Do not build blender when building blenderplayer -WITH_BF_NOBLENDER = True -WITH_BF_PLAYER = True - -# Use jemalloc memory manager -WITH_BF_JEMALLOC = True -WITH_BF_STATICJEMALLOC = True -BF_JEMALLOC = '/opt/lib/jemalloc' -BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib' - -# Use 3d mouse library -WITH_BF_3DMOUSE = True -WITH_BF_STATIC3DMOUSE = True -BF_3DMOUSE = '/opt/lib/libspnav' -BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib' - -# Color management -WITH_BF_OCIO = True -WITH_BF_STATICOCIO = True -BF_OCIO = '/opt/lib/ocio' -BF_OCIO_INC = '${BF_OCIO}/include' -BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/libOpenColorIO.a ${BF_OCIO_LIBPATH}/libtinyxml.a ${BF_OCIO_LIBPATH}/libyaml-cpp.a' -BF_OCIO_LIBPATH = '${BF_OCIO}/lib' - -WITH_BF_BOOST = True -WITH_BF_STATICBOOST = True -BF_BOOST = '/opt/lib/boost' -BF_BOOST_INC = '${BF_BOOST}/include' -BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ' + \ - '${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_locale.a ${BF_BOOST_LIBPATH}/libboost_system.a \ - ${BF_BOOST_LIBPATH}/libboost_thread.a' -BF_BOOST_LIBPATH = '${BF_BOOST}/lib' - -# JACK -WITH_BF_JACK = True -WITH_BF_JACK_DYNLOAD = True - -# Motion Tracking -WITH_BF_LIBMV = False - -# Ocean Simulation -WITH_BF_FFTW3 = True -WITH_BF_STATICFFTW3 = True -WITH_BF_OCEANSIM = True - -# Compilation and optimization -BF_DEBUG = False -REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++ -PLATFORM_LINKFLAGS = ['-lrt'] diff --git a/build_files/buildbot/config/user-config-player-glibc211-x86_64.py b/build_files/buildbot/config/user-config-player-glibc211-x86_64.py deleted file mode 100644 index 42068834879..00000000000 --- a/build_files/buildbot/config/user-config-player-glibc211-x86_64.py +++ /dev/null @@ -1,126 +0,0 @@ -BF_BUILDDIR = '../blender-build/linux-glibc211-x86_64' -BF_INSTALLDIR = '../blender-install/linux-glibc211-x86_64' -BF_NUMJOBS = 4 - -# Python configuration -BF_PYTHON_VERSION = '3.5' -BF_PYTHON_ABI_FLAGS = 'm' -BF_PYTHON = '/opt/lib/python-3.5' -WITH_BF_PYTHON_INSTALL_NUMPY = True -WITH_BF_PYTHON_INSTALL_REQUESTS = True - -WITH_BF_STATICPYTHON = True - -# OpenCollada configuration -WITH_BF_COLLADA = False - -# FFMPEG configuration -WITH_BF_FFMPEG = True -WITH_BF_STATICFFMPEG = True - -BF_FFMPEG = '/opt/lib/ffmpeg' -BF_FFMPEG_LIBPATH = '${BF_FFMPEG}/lib' -BF_FFMPEG_LIB_STATIC = '${BF_FFMPEG_LIBPATH}/libavformat.a ${BF_FFMPEG_LIBPATH}/libavdevice.a ' + \ - '${BF_FFMPEG_LIBPATH}/libavfilter.a ${BF_FFMPEG_LIBPATH}/libavcodec.a ${BF_FFMPEG_LIBPATH}/libavutil.a ' + \ - '${BF_FFMPEG_LIBPATH}/libswscale.a ${BF_FFMPEG_LIBPATH}/libswresample.a ' + \ - '/usr/lib/libxvidcore.a /usr/lib/libx264.a /usr/lib/libmp3lame.a /usr/lib/libvpx.a /usr/lib/libvorbis.a ' + \ - '/usr/lib/libogg.a /usr/lib/libvorbisenc.a /usr/lib/libtheora.a /usr/lib/libschroedinger-1.0.a ' + \ - '/usr/lib/liborc-0.4.a' - -# Don't depend on system's libstdc++ -WITH_BF_STATICCXX = True -BF_CXX_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.7.1/libstdc++.a' - -WITH_BF_OPENAL = True -WITH_BF_STATICOPENAL = True -BF_OPENAL = '/opt/lib/openal' -BF_OPENAL_LIB_STATIC = '/opt/lib/openal/lib/libopenal.a /opt/lib/openal/lib/libcommon.a' - -WITH_BF_GETTEXT_STATIC = True - -WITH_BF_FREETYPE_STATIC = False - -WITH_BF_OPENEXR = True -BF_OPENEXR = '/opt/lib/openexr' -BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include' -WITH_BF_STATICOPENEXR = True - -WITH_BF_TIFF = True -WITH_BF_STATICTIFF = True -BF_TIFF_LIB_STATIC = '${BF_TIFF}/lib/libtiff.a' - -WITH_BF_JPEG = True -WITH_BF_STATICJPEG = True -BF_JPEG_LIB_STATIC= '${BF_JPEG}/lib/libjpeg.a' - -WITH_BF_STATICLIBSAMPLERATE = True - -WITH_BF_PNG = True -WITH_BF_STATICPNG = True -BF_PNG_LIB_STATIC = '${BF_PNG}/lib/libpng.a' - -WITH_BF_ZLIB = True -WITH_BF_STATICZLIB = True -BF_ZLIB_LIB_STATIC = '${BF_ZLIB}/lib/libz.a' - -WITH_BF_SDL = True -WITH_BF_SDL_DYNLOAD = True - -WITH_BF_OGG = False - -WITH_BF_OPENMP = True -WITH_BF_STATICOPENMP = True -BF_OPENMP_LIB_STATIC = '/usr/lib/gcc/x86_64-linux-gnu/4.7/libgomp.a' - -WITH_BF_GAMEENGINE = True -WITH_BF_BULLET = True - -# Do not build blender when building blenderplayer -WITH_BF_NOBLENDER = True -WITH_BF_PLAYER = True - -# Use jemalloc memory manager -WITH_BF_JEMALLOC = True -WITH_BF_STATICJEMALLOC = True -BF_JEMALLOC = '/opt/lib/jemalloc' -BF_JEMALLOC_LIBPATH = '${BF_JEMALLOC}/lib' - -# Use 3d mouse library -WITH_BF_3DMOUSE = True -WITH_BF_STATIC3DMOUSE = True -BF_3DMOUSE = '/opt/lib/libspnav' -BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib' - -# Color management -WITH_BF_OCIO = True -WITH_BF_STATICOCIO = True -BF_OCIO = '/opt/lib/ocio' -BF_OCIO_INC = '${BF_OCIO}/include' -BF_OCIO_LIB_STATIC = '${BF_OCIO_LIBPATH}/libOpenColorIO.a ${BF_OCIO_LIBPATH}/libtinyxml.a ${BF_OCIO_LIBPATH}/libyaml-cpp.a' -BF_OCIO_LIBPATH = '${BF_OCIO}/lib' - -WITH_BF_BOOST = True -WITH_BF_STATICBOOST = True -BF_BOOST = '/opt/lib/boost' -BF_BOOST_INC = '${BF_BOOST}/include' -BF_BOOST_LIB_STATIC = '${BF_BOOST_LIBPATH}/libboost_filesystem.a ${BF_BOOST_LIBPATH}/libboost_date_time.a ' + \ - '${BF_BOOST_LIBPATH}/libboost_regex.a ${BF_BOOST_LIBPATH}/libboost_locale.a ${BF_BOOST_LIBPATH}/libboost_system.a \ - ${BF_BOOST_LIBPATH}/libboost_thread.a' -BF_BOOST_LIBPATH = '${BF_BOOST}/lib' - -# JACK -WITH_BF_JACK = True -WITH_BF_JACK_DYNLOAD = True - -# Motion Tracking -WITH_BF_LIBMV = False - -# Ocean Simulation -WITH_BF_FFTW3 = True -WITH_BF_STATICFFTW3 = True -WITH_BF_OCEANSIM = True - -# Compilation and optimization -BF_DEBUG = False -REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++ -PLATFORM_LINKFLAGS = ['-lrt'] diff --git a/build_files/buildbot/master.cfg b/build_files/buildbot/master.cfg index 7b8dd175453..b506f12b21b 100644 --- a/build_files/buildbot/master.cfg +++ b/build_files/buildbot/master.cfg @@ -282,11 +282,6 @@ def generic_builder(id, libdir='', branch='', rsync=False): descriptionDone='packaged')) if rsync: f.addStep(rsync_step(id, branch, rsync_script)) - elif id.find('cmake') != -1: - f.addStep(FileUpload(name='upload', - slavesrc='buildbot_upload.zip', - masterdest=filename, - maxsize=150 * 1024 * 1024)) else: f.addStep(FileUpload(name='upload', slavesrc='buildbot_upload.zip', @@ -303,8 +298,10 @@ def generic_builder(id, libdir='', branch='', rsync=False): add_builder(c, 'mac_x86_64_10_6_scons', 'darwin-9.x.universal', generic_builder, hour=5) add_builder(c, 'mac_i386_10_6_scons', 'darwin-9.x.universal', generic_builder, hour=11) -add_builder(c, 'linux_glibc211_i386_scons', '', generic_builder, hour=1) -add_builder(c, 'linux_glibc211_x86_64_scons', '', generic_builder, hour=2) +#add_builder(c, 'linux_glibc211_i386_scons', '', generic_builder, hour=1) +#add_builder(c, 'linux_glibc211_x86_64_scons', '', generic_builder, hour=2) +add_builder(c, 'linux_glibc211_i386_cmake', '', generic_builder, hour=1) +add_builder(c, 'linux_glibc211_x86_64_cmake', '', generic_builder, hour=2) #add_builder(c, 'win32_scons_vc2013', 'windows_vc12', generic_builder, hour=1) #add_builder(c, 'win64_scons_vc2013', 'win64_vc12', generic_builder, hour=2) add_builder(c, 'win32_cmake_vc2013', 'windows_vc12', generic_builder, hour=3) diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index ee89bc90225..0afbd9f372e 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -31,47 +31,125 @@ if len(sys.argv) < 2: builder = sys.argv[1] # we run from build/ directory -blender_dir = '../blender.git' +blender_dir = os.path.join('..', 'blender.git') if 'cmake' in builder: # cmake - # set build options + # Some fine-tuning configuration + blender_dir = os.path.join('..', blender_dir) + build_dir = os.path.abspath(os.path.join('..', 'build', builder)) + install_dir = os.path.abspath(os.path.join('..', 'install', builder)) + targets = ['blender'] + + chroot_name = None # If not None command will be delegated to that chroot + build_cubins = True # Whether to build Cycles CUDA kernels + remove_cache = False # Remove CMake cache to be sure config is totally up-to-date + remove_install_dir = False # Remove installation folder before building + + # Config file to be used (relative to blender's sources root) + cmake_config_file = "build_files/cmake/config/blender_full.cmake" + cmake_player_config_file = None + cmake_cuda_config_file = None + + # Set build options. cmake_options = ['-DCMAKE_BUILD_TYPE:STRING=Release'] - if builder.endswith('mac_x86_64_cmake'): - cmake_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64') - elif builder.endswith('mac_i386_cmake'): - cmake_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=i386') - elif builder.endswith('mac_ppc_cmake'): - cmake_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=ppc') - - if 'win64' in builder: - cmake_options.append(['-G', '"Visual Studio 12 2013 Win64"']) - elif 'win32' in builder: - cmake_options.append(['-G', '"Visual Studio 12 2013"']) - - cmake_options.append("-C../blender.git/build_files/cmake/config/blender_full.cmake") - if 'win32' not in builder: - cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=1") - else: - cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=0") - # configure and make - retcode = subprocess.call(['cmake', blender_dir] + cmake_options) - if retcode != 0: - sys.exit(retcode) - - if 'win32' in builder: - retcode = subprocess.call(['msbuild', 'INSTALL.vcxproj', '/Property:PlatformToolset=v120_xp', '/p:Configuration=Release']) - elif 'win64' in builder: - retcode = subprocess.call(['msbuild', 'INSTALL.vcxproj', '/p:Configuration=Release']) + if builder.startswith('mac'): + # Set up OSX architecture + if builder.endswith('x86_64_cmake'): + cmake_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64') + elif builder.endswith('i386_cmake'): + cmake_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=i386') + elif builder.endswith('ppc_cmake'): + cmake_options.append('-DCMAKE_OSX_ARCHITECTURES:STRING=ppc') + + elif builder.startswith('win'): + install_dir = None + if builder.startswith('win64'): + cmake_options.append(['-G', '"Visual Studio 12 2013 Win64"']) + elif builder.startswith('win32'): + cmake_options.append(['-G', '"Visual Studio 12 2013"']) + build_cubins = False + + elif builder.startswith('linux'): + remove_cache = True + remove_install_dir = True + cmake_config_file = "build_files/buildbot/config/blender_linux.cmake" + cmake_player_config_file = "build_files/buildbot/config/blender_linux_player.cmake" + # Currently unused + # cmake_cuda_config_file = "build_files/buildbot/config/blender_linux_cuda.cmake" + if builder.endswith('x86_64_cmake'): + chroot_name = 'buildbot_squeeze_x86_64' + build_cubins = True + targets = ['player', 'blender'] + elif builder.endswith('i386_cmake'): + chroot_name = 'buildbot_squeeze_i686' + build_cubins = False + targets = ['player', 'blender'] + + cmake_options.append("-DWITH_CYCLES_CUDA_BINARIES=%d" % (build_cubins)) + + if install_dir: + cmake_options.append("-DCMAKE_INSTALL_PREFIX=%s" % (install_dir)) + + cmake_options.append("-C" + os.path.join(blender_dir, cmake_config_file)) + + # Prepare chroot command prefix if needed + + if chroot_name: + chroot_prefix = ['schroot', '-c', chroot_name, '--'] else: - retcode = subprocess.call(['make', '-s', '-j4', 'install']) - sys.exit(retcode) + chroot_prefix = [] + + # Make sure no garbage remained from the previous run + # (only do it if builder requested this) + if remove_install_dir: + if os.path.isdir(install_dir): + shutil.rmtree(install_dir) + + for target in targets: + print("Building target %s" % (target)) + # Construct build directory name based on the target + target_build_dir = build_dir + if target != 'blender': + target_build_dir += '_' + target + # Make sure build directory exists and enter it + if not os.path.isdir(target_build_dir): + os.mkdir(target_build_dir) + os.chdir(target_build_dir) + # Tweaking CMake options to respect the target + target_cmake_options = cmake_options[:] + if target == 'player': + target_cmake_options.append("-C" + os.path.join(blender_dir, cmake_player_config_file)) + elif target == 'cuda': + target_cmake_options.append("-C" + os.path.join(blender_dir, cmake_cuda_config_file)) + # Configure the build + print("CMake options:") + print(target_cmake_options) + if remove_cache and os.path.exists('CMakeCache.txt'): + print("Removing CMake cache") + os.remove('CMakeCache.txt') + retcode = subprocess.call(chroot_prefix + ['cmake', blender_dir] + target_cmake_options) + if retcode != 0: + print('Condifuration FAILED!') + sys.exit(retcode) + + if 'win32' in builder: + command = ['msbuild', 'INSTALL.vcxproj', '/Property:PlatformToolset=v120_xp', '/p:Configuration=Release'] + elif 'win64' in builder: + command = ['msbuild', 'INSTALL.vcxproj', '/p:Configuration=Release'] + else: + command = chroot_prefix + ['make', '-s', '-j2', 'install'] + + print("Executing command:") + print(command) + retcode = subprocess.call(command) + + if retcode != 0: + sys.exit(retcode) else: python_bin = 'python' - if builder.find('linux') != -1: - python_bin = '/opt/lib/python-2.7/bin/python2.7' # scons os.chdir(blender_dir) @@ -91,108 +169,14 @@ else: buildbot_dir = os.path.dirname(os.path.realpath(__file__)) config_dir = os.path.join(buildbot_dir, 'config') - if builder.find('linux') != -1: - configs = [] - if builder.endswith('linux_glibc211_x86_64_scons'): - configs = ['user-config-player-glibc211-x86_64.py', - 'user-config-cuda-glibc211-x86_64.py', - 'user-config-glibc211-x86_64.py' - ] - chroot_name = 'buildbot_squeeze_x86_64' - cuda_chroot = 'buildbot_squeeze_x86_64' - elif builder.endswith('linux_glibc211_i386_scons'): - configs = ['user-config-player-glibc211-i686.py', - 'user-config-cuda-glibc211-i686.py', - 'user-config-glibc211-i686.py'] - chroot_name = 'buildbot_squeeze_i686' - - # use 64bit cuda toolkit, so there'll be no memory limit issues - cuda_chroot = 'buildbot_squeeze_x86_64' - - # Compilation will happen inside of chroot environment - prog_scons_cmd = ['schroot', '-c', chroot_name, '--'] + scons_cmd - cuda_scons_cmd = ['schroot', '-c', cuda_chroot, '--'] + scons_cmd - - common_options = ['BF_INSTALLDIR=' + install_dir] + scons_options - - for config in configs: - config_fpath = os.path.join(config_dir, config) - - scons_options = [] + if builder.find('mac') != -1: + if builder.find('x86_64') != -1: + config = 'user-config-mac-x86_64.py' + else: + config = 'user-config-mac-i386.py' - if config.find('player') != -1: - scons_options.append('BF_BUILDDIR=%s_player' % (build_dir)) - elif config.find('cuda') != -1: - scons_options.append('BF_BUILDDIR=%s_cuda' % (build_dir)) - else: - scons_options.append('BF_BUILDDIR=%s' % (build_dir)) + scons_options.append('BF_CONFIG=' + os.path.join(config_dir, config)) - scons_options += common_options + retcode = subprocess.call([python_bin, 'scons/scons.py'] + scons_options) - if config.find('player') != -1: - scons_options.append('blenderplayer') - cur_scons_cmd = prog_scons_cmd - elif config.find('cuda') != -1: - scons_options.append('cudakernels') - cur_scons_cmd = cuda_scons_cmd - - if config.find('i686') != -1: - scons_options.append('BF_BITNESS=32') - elif config.find('x86_64') != -1: - scons_options.append('BF_BITNESS=64') - else: - scons_options.append('blender') - cur_scons_cmd = prog_scons_cmd - - scons_options.append('BF_CONFIG=' + config_fpath) - - retcode = subprocess.call(cur_scons_cmd + scons_options) - if retcode != 0: - print('Error building rules with config ' + config) - sys.exit(retcode) - - sys.exit(0) - else: - if builder.find('win') != -1: - bitness = '32' - - if builder.find('win64') != -1: - bitness = '64' - - scons_options.append('BF_INSTALLDIR=' + install_dir) - scons_options.append('BF_BUILDDIR=' + build_dir) - scons_options.append('BF_BITNESS=' + bitness) - scons_options.append('WITH_BF_CYCLES_CUDA_BINARIES=True') - scons_options.append('BF_CYCLES_CUDA_NVCC=nvcc.exe') - if builder.find('mingw') != -1: - scons_options.append('BF_TOOLSET=mingw') - if builder.endswith('vc2013'): - scons_options.append('MSVS_VERSION=12.0') - scons_options.append('MSVC_VERSION=12.0') - scons_options.append('WITH_BF_CYCLES_CUDA_BINARIES=1') - scons_options.append('BF_CYCLES_CUDA_NVCC=nvcc.exe') - scons_options.append('BF_NUMJOBS=1') - - elif builder.find('mac') != -1: - if builder.find('x86_64') != -1: - config = 'user-config-mac-x86_64.py' - else: - config = 'user-config-mac-i386.py' - - scons_options.append('BF_CONFIG=' + os.path.join(config_dir, config)) - - if builder.find('win') != -1: - if not os.path.exists(install_dir): - os.makedirs(install_dir) - if builder.endswith('vc2013'): - dlls = ('msvcp120.dll', 'msvcr120.dll', 'vcomp120.dll') - if builder.find('win64') == -1: - dlls_path = '..\\..\\..\\redist\\x86' - else: - dlls_path = '..\\..\\..\\redist\\amd64' - for dll in dlls: - shutil.copyfile(os.path.join(dlls_path, dll), os.path.join(install_dir, dll)) - - retcode = subprocess.call([python_bin, 'scons/scons.py'] + scons_options) - - sys.exit(retcode) + sys.exit(retcode) diff --git a/build_files/buildbot/slave_pack.py b/build_files/buildbot/slave_pack.py index aec7cdca80a..c0f9a84ea18 100644 --- a/build_files/buildbot/slave_pack.py +++ b/build_files/buildbot/slave_pack.py @@ -36,95 +36,83 @@ builder = sys.argv[1] # Never write branch if it is master. branch = sys.argv[2] if (len(sys.argv) >= 3 and sys.argv[2] != 'master') else '' +blender_dir = os.path.join('..', 'blender.git') +build_dir = os.path.join('..', 'build', builder) +install_dir = os.path.join('..', 'install', builder) +buildbot_upload_zip = os.path.abspath(os.path.join(os.path.dirname(install_dir), "buildbot_upload.zip")) + +upload_filename = None # Name of the archive to be uploaded + # (this is the name of archive which will appear on the + # download page) +upload_filepath = None # Filepath to be uploaded to the server + # (this folder will be packed) + + +def parse_header_file(filename, define): + import re + regex = re.compile("^#\s*define\s+%s\s+(.*)" % define) + with open(filename, "r") as file: + for l in file: + match = regex.match(l) + if match: + return match.group(1) + return None + + +# Make sure install directory always exists +if not os.path.exists(install_dir): + os.makedirs(install_dir) + + +def create_tar_bz2(src, dest, package_name): + # One extra to remove leading os.sep when cleaning root for package_root + ln = len(src) + 1 + flist = list() + + # Create list of tuples containing file and archive name + for root, dirs, files in os.walk(src): + package_root = os.path.join(package_name, root[ln:]) + flist.extend([(os.path.join(root, file), os.path.join(package_root, file)) for file in files]) + + import tarfile + package = tarfile.open(dest, 'w:bz2') + for entry in flist: + package.add(entry[0], entry[1], recursive=False) + package.close() + + # scons does own packaging if builder.find('scons') != -1: python_bin = 'python' - if builder.find('linux') != -1: - python_bin = '/opt/lib/python-2.7/bin/python2.7' os.chdir('../blender.git') scons_options = ['BF_QUICK=slnt', 'BUILDBOT_BRANCH=' + branch, 'buildslave', 'BF_FANCY=False'] buildbot_dir = os.path.dirname(os.path.realpath(__file__)) config_dir = os.path.join(buildbot_dir, 'config') - build_dir = os.path.join('..', 'build', builder) - install_dir = os.path.join('..', 'install', builder) - - if builder.find('linux') != -1: - scons_options += ['WITH_BF_NOBLENDER=True', 'WITH_BF_PLAYER=False', - 'BF_BUILDDIR=' + build_dir, - 'BF_INSTALLDIR=' + install_dir, - 'WITHOUT_BF_INSTALL=True'] - - config = None - bits = None - - if builder.endswith('linux_glibc211_x86_64_scons'): - config = 'user-config-glibc211-x86_64.py' - chroot_name = 'buildbot_squeeze_x86_64' - bits = 64 - elif builder.endswith('linux_glibc211_i386_scons'): - config = 'user-config-glibc211-i686.py' - chroot_name = 'buildbot_squeeze_i686' - bits = 32 - - if config is not None: - config_fpath = os.path.join(config_dir, config) - scons_options.append('BF_CONFIG=' + config_fpath) - blender = os.path.join(install_dir, 'blender') - blenderplayer = os.path.join(install_dir, 'blenderplayer') - subprocess.call(['schroot', '-c', chroot_name, '--', 'strip', '--strip-all', blender, blenderplayer]) + if builder.find('mac') != -1: + if builder.find('x86_64') != -1: + config = 'user-config-mac-x86_64.py' + else: + config = 'user-config-mac-i386.py' - extra = '/' + os.path.join('home', 'sources', 'release-builder', 'extra') - mesalibs = os.path.join(extra, 'mesalibs' + str(bits) + '.tar.bz2') - software_gl = os.path.join(extra, 'blender-softwaregl') + scons_options.append('BF_CONFIG=' + os.path.join(config_dir, config)) - os.system('tar -xpf %s -C %s' % (mesalibs, install_dir)) - os.system('cp %s %s' % (software_gl, install_dir)) - os.system('chmod 755 %s' % (os.path.join(install_dir, 'blender-softwaregl'))) - - retcode = subprocess.call(['schroot', '-c', chroot_name, '--', python_bin, 'scons/scons.py'] + scons_options) - - sys.exit(retcode) - else: - if builder.find('win') != -1: - bitness = '32' - - if builder.find('win64') != -1: - bitness = '64' - - scons_options.append('BF_INSTALLDIR=' + install_dir) - scons_options.append('BF_BUILDDIR=' + build_dir) - scons_options.append('BF_BITNESS=' + bitness) - scons_options.append('WITH_BF_CYCLES_CUDA_BINARIES=True') - scons_options.append('BF_CYCLES_CUDA_NVCC=nvcc.exe') - if builder.find('mingw') != -1: - scons_options.append('BF_TOOLSET=mingw') - if builder.endswith('vc2013'): - scons_options.append('MSVS_VERSION=12.0') - scons_options.append('MSVC_VERSION=12.0') - - elif builder.find('mac') != -1: - if builder.find('x86_64') != -1: - config = 'user-config-mac-x86_64.py' - else: - config = 'user-config-mac-i386.py' - - scons_options.append('BF_CONFIG=' + os.path.join(config_dir, config)) - - retcode = subprocess.call([python_bin, 'scons/scons.py'] + scons_options) - sys.exit(retcode) + retcode = subprocess.call([python_bin, 'scons/scons.py'] + scons_options) + sys.exit(retcode) else: # CMake if 'win' in builder: + os.chdir(build_dir) + files = [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.zip')] for f in files: os.remove(f) retcode = subprocess.call(['cpack', '-G', 'ZIP']) result_file = [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.zip')][0] - # TODO(sergey): Such magic usually happens in SCon's packaging bu we don't have it + # TODO(sergey): Such magic usually happens in SCon's packaging but we don't have it # in the CMake yet. For until then we do some magic here. tokens = result_file.split('-') blender_version = tokens[1].split('.') @@ -138,10 +126,9 @@ else: os.rename(result_file, "{}.zip".format(builderified_name)) # create zip file try: - upload_zip = "buildbot_upload.zip" - if os.path.exists(upload_zip): - os.remove(upload_zip) - z = zipfile.ZipFile(upload_zip, "w", compression=zipfile.ZIP_STORED) + if os.path.exists(buildbot_upload_zip): + os.remove(buildbot_upload_zip) + z = zipfile.ZipFile(buildbot_upload_zip, "w", compression=zipfile.ZIP_STORED) z.write("{}.zip".format(builderified_name)) z.close() sys.exit(retcode) @@ -149,48 +136,111 @@ else: sys.stderr.write('Create buildbot_upload.zip failed' + str(ex) + '\n') sys.exit(1) + elif builder.startswith('linux_'): + blender = os.path.join(install_dir, 'blender') + blenderplayer = os.path.join(install_dir, 'blenderplayer') + + buildinfo_h = os.path.join(build_dir, "source", "creator", "buildinfo.h") + blender_h = os.path.join(blender_dir, "source", "blender", "blenkernel", "BKE_blender.h") -# clean release directory if it already exists -release_dir = 'release' + # Get version information + blender_version = int(parse_header_file(blender_h, 'BLENDER_VERSION')) + blender_version = "%d.%d" % (blender_version // 100, blender_version % 100) + blender_hash = parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1] + blender_glibc = builder.split('_')[1] -if os.path.exists(release_dir): - for f in os.listdir(release_dir): - if os.path.isfile(os.path.join(release_dir, f)): - os.remove(os.path.join(release_dir, f)) + if builder.endswith('x86_64_cmake'): + chroot_name = 'buildbot_squeeze_x86_64' + bits = 64 + blender_arch = 'x86_64' + elif builder.endswith('i386_cmake'): + chroot_name = 'buildbot_squeeze_i686' + bits = 32 + blender_arch = 'i686' -# create release package -try: - subprocess.call(['make', 'package_archive']) -except Exception as ex: - sys.stderr.write('Make package release failed' + str(ex) + '\n') - sys.exit(1) + # Strip all unused symbols from the binaries + print("Stripping binaries...") + chroot_prefix = ['schroot', '-c', chroot_name, '--'] + subprocess.call(chroot_prefix + ['strip', '--strip-all', blender, blenderplayer]) -# find release directory, must exist this time -if not os.path.exists(release_dir): - sys.stderr.write("Failed to find release directory %r.\n" % release_dir) - sys.exit(1) + print("Stripping python...") + py_target = os.path.join(install_dir, blender_version) + subprocess.call(chroot_prefix + ['find', py_target, '-iname', '*.so', '-exec', 'strip', '-s', '{}', ';']) -# find release package -file = None -filepath = None + # Copy all specific files which are too specific to be copied by + # the CMake rules themselves + print("Copying extra scripts and libs...") -for f in os.listdir(release_dir): - rf = os.path.join(release_dir, f) - if os.path.isfile(rf) and f.startswith('blender'): - file = f - filepath = rf + extra = '/' + os.path.join('home', 'sources', 'release-builder', 'extra') + mesalibs = os.path.join(extra, 'mesalibs' + str(bits) + '.tar.bz2') + software_gl = os.path.join(blender_dir, 'release', 'bin', 'blender-softwaregl') + icons = os.path.join(blender_dir, 'release', 'freedesktop', 'icons') -if not file: - sys.stderr.write("Failed to find release package.\n") - sys.exit(1) + os.system('tar -xpf %s -C %s' % (mesalibs, install_dir)) + os.system('cp %s %s' % (software_gl, install_dir)) + os.system('cp -r %s %s' % (icons, install_dir)) + os.system('chmod 755 %s' % (os.path.join(install_dir, 'blender-softwaregl'))) + + # Construct archive name + package_name = 'blender-%s-%s-linux-%s-%s' % (blender_version, + blender_hash, + blender_glibc, + blender_arch) + if branch != '': + package_name = branch + "-" + package_name + + upload_filename = package_name + ".tar.bz2" + + print("Creating .tar.bz2 archive") + upload_filepath = install_dir + '.tar.bz2' + create_tar_bz2(install_dir, upload_filepath, package_name) + + +if upload_filepath is None: + # clean release directory if it already exists + release_dir = 'release' + + if os.path.exists(release_dir): + for f in os.listdir(release_dir): + if os.path.isfile(os.path.join(release_dir, f)): + os.remove(os.path.join(release_dir, f)) + + # create release package + try: + subprocess.call(['make', 'package_archive']) + except Exception as ex: + sys.stderr.write('Make package release failed' + str(ex) + '\n') + sys.exit(1) + + # find release directory, must exist this time + if not os.path.exists(release_dir): + sys.stderr.write("Failed to find release directory %r.\n" % release_dir) + sys.exit(1) + + # find release package + file = None + filepath = None + + for f in os.listdir(release_dir): + rf = os.path.join(release_dir, f) + if os.path.isfile(rf) and f.startswith('blender'): + file = f + filepath = rf + + if not file: + sys.stderr.write("Failed to find release package.\n") + sys.exit(1) + + upload_filename = file + upload_filepath = filepath # create zip file try: - upload_zip = "buildbot_upload.zip" + upload_zip = os.path.join(buildbot_upload_zip) if os.path.exists(upload_zip): os.remove(upload_zip) z = zipfile.ZipFile(upload_zip, "w", compression=zipfile.ZIP_STORED) - z.write(filepath, arcname=file) + z.write(upload_filepath, arcname=upload_filename) z.close() except Exception as ex: sys.stderr.write('Create buildbot_upload.zip failed' + str(ex) + '\n') diff --git a/build_files/buildbot/slave_test.py b/build_files/buildbot/slave_test.py index ef7a4b23d04..973e17a1f3b 100644 --- a/build_files/buildbot/slave_test.py +++ b/build_files/buildbot/slave_test.py @@ -19,6 +19,7 @@ # <pep8 compliant> import subprocess +import os import sys # get builder name @@ -33,7 +34,24 @@ blender_dir = '../blender.git' if "cmake" in builder: # cmake - retcode = subprocess.call(['ctest', '.' '--output-on-failure']) + + if "linux" in builder: + print("Automated tests are still DISABLED!") + sys.exit(0) + + build_dir = os.path.abspath(os.path.join('..', 'build', builder)) + chroot_name = None + chroot_prefix = [] + + if builder.endswith('x86_64_cmake'): + chroot_name = 'buildbot_squeeze_x86_64' + elif builder.endswith('i386_cmake'): + chroot_name = 'buildbot_squeeze_i686' + if chroot_name: + chroot_prefix = ['schroot', '-c', chroot_name, '--'] + + os.chdir(build_dir) + retcode = subprocess.call(chroot_prefix + ['ctest', '--output-on-failure']) sys.exit(retcode) else: # scons diff --git a/build_files/cmake/Modules/FindPythonLibsUnix.cmake b/build_files/cmake/Modules/FindPythonLibsUnix.cmake index e4236fb4c24..9d79bdd778d 100644 --- a/build_files/cmake/Modules/FindPythonLibsUnix.cmake +++ b/build_files/cmake/Modules/FindPythonLibsUnix.cmake @@ -38,7 +38,7 @@ IF(NOT PYTHON_ROOT_DIR AND NOT $ENV{PYTHON_ROOT_DIR} STREQUAL "") SET(PYTHON_ROOT_DIR $ENV{PYTHON_ROOT_DIR}) ENDIF() -SET(PYTHON_VERSION 3.4 CACHE STRING "Python Version (major and minor only)") +SET(PYTHON_VERSION 3.5 CACHE STRING "Python Version (major and minor only)") MARK_AS_ADVANCED(PYTHON_VERSION) @@ -199,7 +199,7 @@ IF(PYTHONLIBSUNIX_FOUND) ) # we need this for installation - # XXX No more valid with debian-like py3.4 packages... + # XXX No more valid with debian-like py3.5 packages... # GET_FILENAME_COMPONENT(PYTHON_LIBPATH ${PYTHON_LIBRARY} PATH) # not required for build, just used when bundling Python. diff --git a/build_files/cmake/cmake_consistency_check_config.py b/build_files/cmake/cmake_consistency_check_config.py index 1f75b9884bc..5345f682f58 100644 --- a/build_files/cmake/cmake_consistency_check_config.py +++ b/build_files/cmake/cmake_consistency_check_config.py @@ -10,9 +10,6 @@ IGNORE = ( "/ik_glut_test/", # specific source files - "extern/Eigen2/Eigen/src/Cholesky/CholeskyInstantiations.cpp", - "extern/Eigen2/Eigen/src/Core/CoreInstantiations.cpp", - "extern/Eigen2/Eigen/src/QR/QrInstantiations.cpp", "extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp", "extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp", "extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp", diff --git a/build_files/cmake/cmake_static_check_clang_array.py b/build_files/cmake/cmake_static_check_clang_array.py index 45b262a13ce..597d1d2b980 100644 --- a/build_files/cmake/cmake_static_check_clang_array.py +++ b/build_files/cmake/cmake_static_check_clang_array.py @@ -32,7 +32,6 @@ USE_QUIET = (os.environ.get("QUIET", None) is not None) CHECKER_IGNORE_PREFIX = [ "extern", "intern/moto", - "blender/intern/opennl", ] CHECKER_BIN = "python2" diff --git a/build_files/cmake/cmake_static_check_cppcheck.py b/build_files/cmake/cmake_static_check_cppcheck.py index 9f012cb7f6d..3504b005adc 100644 --- a/build_files/cmake/cmake_static_check_cppcheck.py +++ b/build_files/cmake/cmake_static_check_cppcheck.py @@ -32,7 +32,6 @@ USE_QUIET = (os.environ.get("QUIET", None) is not None) CHECKER_IGNORE_PREFIX = [ "extern", "intern/moto", - "blender/intern/opennl", ] CHECKER_BIN = "cppcheck" diff --git a/build_files/cmake/cmake_static_check_smatch.py b/build_files/cmake/cmake_static_check_smatch.py index de13d141276..f525187e22c 100644 --- a/build_files/cmake/cmake_static_check_smatch.py +++ b/build_files/cmake/cmake_static_check_smatch.py @@ -25,7 +25,6 @@ CHECKER_IGNORE_PREFIX = [ "extern", "intern/moto", - "blender/intern/opennl", ] CHECKER_BIN = "smatch" diff --git a/build_files/cmake/cmake_static_check_sparse.py b/build_files/cmake/cmake_static_check_sparse.py index 2ee99925adb..6d1c4e3d6a2 100644 --- a/build_files/cmake/cmake_static_check_sparse.py +++ b/build_files/cmake/cmake_static_check_sparse.py @@ -25,7 +25,6 @@ CHECKER_IGNORE_PREFIX = [ "extern", "intern/moto", - "blender/intern/opennl", ] CHECKER_BIN = "sparse" diff --git a/build_files/cmake/cmake_static_check_splint.py b/build_files/cmake/cmake_static_check_splint.py index 5a967ecc7a3..46d8808e89d 100644 --- a/build_files/cmake/cmake_static_check_splint.py +++ b/build_files/cmake/cmake_static_check_splint.py @@ -25,7 +25,6 @@ CHECKER_IGNORE_PREFIX = [ "extern", "intern/moto", - "blender/intern/opennl", ] CHECKER_BIN = "splint" diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake index 881dc515499..ad8a6815675 100644 --- a/build_files/cmake/config/blender_full.cmake +++ b/build_files/cmake/config/blender_full.cmake @@ -10,6 +10,7 @@ set(WITH_CODEC_AVI ON CACHE BOOL "" FORCE) set(WITH_CODEC_FFMPEG ON CACHE BOOL "" FORCE) set(WITH_CODEC_SNDFILE ON CACHE BOOL "" FORCE) set(WITH_CYCLES ON CACHE BOOL "" FORCE) +set(WITH_CYCLES_OSL ON CACHE BOOL "" FORCE) set(WITH_FFTW3 ON CACHE BOOL "" FORCE) set(WITH_LIBMV ON CACHE BOOL "" FORCE) set(WITH_LIBMV_SCHUR_SPECIALIZATIONS ON CACHE BOOL "" FORCE) @@ -42,7 +43,6 @@ set(WITH_OPENAL ON CACHE BOOL "" FORCE) set(WITH_OPENCOLLADA ON CACHE BOOL "" FORCE) set(WITH_OPENCOLORIO ON CACHE BOOL "" FORCE) set(WITH_OPENMP ON CACHE BOOL "" FORCE) -set(WITH_OPENNL ON CACHE BOOL "" FORCE) set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE) set(WITH_RAYOPTIMIZATION ON CACHE BOOL "" FORCE) set(WITH_SDL ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake index 9e7b4dcf39b..99e90caf793 100644 --- a/build_files/cmake/config/blender_lite.cmake +++ b/build_files/cmake/config/blender_lite.cmake @@ -47,7 +47,6 @@ set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE) set(WITH_OPENCOLORIO OFF CACHE BOOL "" FORCE) set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE) set(WITH_OPENMP OFF CACHE BOOL "" FORCE) -set(WITH_OPENNL OFF CACHE BOOL "" FORCE) set(WITH_RAYOPTIMIZATION OFF CACHE BOOL "" FORCE) set(WITH_SDL OFF CACHE BOOL "" FORCE) set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 90c4fbd5674..4ba15c72677 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -103,6 +103,23 @@ macro(file_list_suffix endmacro() +if(UNIX AND NOT APPLE) + macro(find_package_static) + set(_cmake_find_library_suffixes_back ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + find_package(${ARGV}) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_cmake_find_library_suffixes_back}) + unset(_cmake_find_library_suffixes_back) + endmacro() + + macro(find_library_static) + set(_cmake_find_library_suffixes_back ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + find_library(${ARGV}) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${_cmake_find_library_suffixes_back}) + unset(_cmake_find_library_suffixes_back) + endmacro() +endif() function(target_link_libraries_optimized TARGET @@ -452,6 +469,11 @@ function(setup_liblinks if(WIN32 AND NOT UNIX) target_link_libraries(${target} ${PTHREADS_LIBRARIES}) endif() + if(UNIX AND NOT APPLE) + if(WITH_OPENMP_STATIC) + target_link_libraries(${target} ${OpenMP_LIBRARIES}) + endif() + endif() # We put CLEW and CUEW here because OPENSUBDIV_LIBRARIES dpeends on them.. if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV) @@ -574,7 +596,6 @@ function(SETUP_BLENDER_SORTED_LIBS) ge_phys_bullet bf_intern_smoke extern_lzma - extern_colamd ge_logic_ketsji extern_recastnavigation ge_logic @@ -604,12 +625,12 @@ function(SETUP_BLENDER_SORTED_LIBS) cycles_subd bf_intern_raskter bf_intern_opencolorio + bf_intern_eigen extern_rangetree extern_wcwidth extern_libmv extern_glog extern_sdlew - extern_eigen3 bf_intern_glew_mx ) @@ -676,10 +697,6 @@ function(SETUP_BLENDER_SORTED_LIBS) list(APPEND BLENDER_SORTED_LIBS bf_intern_locale) endif() - if(WITH_OPENNL) - list_insert_after(BLENDER_SORTED_LIBS "bf_render" "bf_intern_opennl") - endif() - if(WITH_BULLET) list_insert_after(BLENDER_SORTED_LIBS "bf_blenkernel" "bf_intern_rigidbody") endif() diff --git a/build_files/scons/Modules/FindPython.py b/build_files/scons/Modules/FindPython.py index a0ead88ebb4..9f652b73585 100644 --- a/build_files/scons/Modules/FindPython.py +++ b/build_files/scons/Modules/FindPython.py @@ -6,7 +6,7 @@ def FindPython(): python = "/usr" abi_flags = "m" # Most common for linux distros - version = "3.4" + version = "3.5" _arch = platform.uname()[4] + "-linux-gnu" diff --git a/build_files/scons/config/win32-mingw-config.py b/build_files/scons/config/win32-mingw-config.py index f4b709dda81..bb28deaade2 100644 --- a/build_files/scons/config/win32-mingw-config.py +++ b/build_files/scons/config/win32-mingw-config.py @@ -2,7 +2,7 @@ LCGDIR = '#../lib/mingw32' LIBDIR = "${LCGDIR}" BF_PYTHON = LIBDIR + '/python' -BF_PYTHON_VERSION = '3.4' +BF_PYTHON_VERSION = '3.5' WITH_BF_STATICPYTHON = False BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' BF_PYTHON_BINARY = 'python' diff --git a/build_files/scons/config/win64-mingw-config.py b/build_files/scons/config/win64-mingw-config.py index 6106f2ac631..f5659a99ff5 100644 --- a/build_files/scons/config/win64-mingw-config.py +++ b/build_files/scons/config/win64-mingw-config.py @@ -2,7 +2,7 @@ LCGDIR = '#../lib/mingw64' LIBDIR = "${LCGDIR}" BF_PYTHON = LIBDIR + '/python' -BF_PYTHON_VERSION = '3.4' +BF_PYTHON_VERSION = '3.5' WITH_BF_STATICPYTHON = False BF_PYTHON_INC = '${BF_PYTHON}/include/python${BF_PYTHON_VERSION}' BF_PYTHON_BINARY = 'python' diff --git a/doc/doxygen/doxygen.intern.h b/doc/doxygen/doxygen.intern.h index 2c8ecae0ead..e3cc11b3404 100644 --- a/doc/doxygen/doxygen.intern.h +++ b/doc/doxygen/doxygen.intern.h @@ -38,7 +38,7 @@ * \ingroup intern */ -/** \defgroup opennl opennl +/** \defgroup eigen eigen * \ingroup intern */ diff --git a/doc/python_api/rst/bge.logic.rst b/doc/python_api/rst/bge.logic.rst index b119bdd1ba1..3f35901234a 100644 --- a/doc/python_api/rst/bge.logic.rst +++ b/doc/python_api/rst/bge.logic.rst @@ -378,6 +378,76 @@ General functions Render next frame (if Python has control) +********************** +Time related functions +********************** + +.. function:: getClockTime() + + Get the current BGE render time, in seconds. The BGE render time is the + simulation time corresponding to the next scene that will be rendered. + + :rtype: double + +.. function:: getFrameTime() + + Get the current BGE frame time, in seconds. The BGE frame time is the + simulation time corresponding to the current call of the logic system. + Generally speaking, it is what the user is interested in. + + :rtype: double + +.. function:: getRealTime() + + Get the number of real (system-clock) seconds elapsed since the beginning + of the simulation. + + :rtype: double + +.. function:: getTimeScale() + + Get the time multiplier between real-time and simulation time. The default + value is 1.0. A value greater than 1.0 means that the simulation is going + faster than real-time, a value lower than 1.0 means that the simulation is + going slower than real-time. + + :rtype: double + +.. function:: setTimeScale(time_scale) + + Set the time multiplier between real-time and simulation time. A value + greater than 1.0 means that the simulation is going faster than real-time, + a value lower than 1.0 means that the simulation is going slower than + real-time. Note that a too large value may lead to some physics + instabilities. + + :arg time_scale: The new time multiplier. + +.. function:: getUseExternalClock() + + Get if the BGE use the inner BGE clock, or rely or on an external + clock. The default is to use the inner BGE clock. + + :rtype: bool + +.. function:: setUseExternalClock(use_external_clock) + + Set if the BGE use the inner BGE clock, or rely or on an external + clock. If the user selects the use of an external clock, he should call + regularly the setClockTime method. + + :arg use_external_clock: the new setting + +.. function:: setClockTime(new_time) + + Set the next value of the simulation clock. It is preferable to use this + method from a custom main function in python, as calling it in the logic + block can easily lead to a blocked system (if the time does not advance + enough to run at least the next logic step). + + :arg new_time: the next value of the BGE clock (in second). + + ***************** Utility functions ***************** diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 93f57b04d4e..640de9d80e7 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -29,11 +29,6 @@ remove_strict_flags() add_subdirectory(rangetree) add_subdirectory(wcwidth) add_subdirectory(libmv) -add_subdirectory(Eigen3) - -if(WITH_OPENNL) - add_subdirectory(colamd) -endif() if(WITH_BULLET) if(NOT WITH_SYSTEM_BULLET) diff --git a/extern/Eigen3/Eigen/Core b/extern/Eigen3/Eigen/Core index 9131cc3fc9d..509c529e13d 100644 --- a/extern/Eigen3/Eigen/Core +++ b/extern/Eigen3/Eigen/Core @@ -95,7 +95,7 @@ extern "C" { // In theory we should only include immintrin.h and not the other *mmintrin.h header files directly. // Doing so triggers some issues with ICC. However old gcc versions seems to not have this file, thus: - #ifdef __INTEL_COMPILER + #if defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1110 #include <immintrin.h> #else #include <emmintrin.h> @@ -123,7 +123,7 @@ #undef bool #undef vector #undef pixel - #elif defined __ARM_NEON__ + #elif defined __ARM_NEON #define EIGEN_VECTORIZE #define EIGEN_VECTORIZE_NEON #include <arm_neon.h> @@ -165,7 +165,7 @@ #endif // required for __cpuid, needs to be included after cmath -#if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64)) +#if defined(_MSC_VER) && (defined(_M_IX86)||defined(_M_X64)) && (!defined(_WIN32_WCE)) #include <intrin.h> #endif diff --git a/extern/Eigen3/Eigen/SparseCore b/extern/Eigen3/Eigen/SparseCore index 9b5be5e15a9..24bcf0156b3 100644 --- a/extern/Eigen3/Eigen/SparseCore +++ b/extern/Eigen3/Eigen/SparseCore @@ -14,7 +14,7 @@ /** * \defgroup SparseCore_Module SparseCore module * - * This module provides a sparse matrix representation, and basic associatd matrix manipulations + * This module provides a sparse matrix representation, and basic associated matrix manipulations * and operations. * * See the \ref TutorialSparse "Sparse tutorial" diff --git a/extern/Eigen3/Eigen/src/Cholesky/LDLT.h b/extern/Eigen3/Eigen/src/Cholesky/LDLT.h index d026418f8a9..abd30bd916d 100644 --- a/extern/Eigen3/Eigen/src/Cholesky/LDLT.h +++ b/extern/Eigen3/Eigen/src/Cholesky/LDLT.h @@ -235,6 +235,11 @@ template<typename _MatrixType, int _UpLo> class LDLT } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } /** \internal * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. @@ -274,30 +279,13 @@ template<> struct ldlt_inplace<Lower> return true; } - RealScalar cutoff(0), biggest_in_corner; - for (Index k = 0; k < size; ++k) { // Find largest diagonal element Index index_of_biggest_in_corner; - biggest_in_corner = mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); + mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); index_of_biggest_in_corner += k; - if(k == 0) - { - // The biggest overall is the point of reference to which further diagonals - // are compared; if any diagonal is negligible compared - // to the largest overall, the algorithm bails. - cutoff = abs(NumTraits<Scalar>::epsilon() * biggest_in_corner); - } - - // Finish early if the matrix is not full rank. - if(biggest_in_corner < cutoff) - { - for(Index i = k; i < size; i++) transpositions.coeffRef(i) = i; - break; - } - transpositions.coeffRef(k) = index_of_biggest_in_corner; if(k != index_of_biggest_in_corner) { @@ -328,15 +316,20 @@ template<> struct ldlt_inplace<Lower> if(k>0) { - temp.head(k) = mat.diagonal().head(k).asDiagonal() * A10.adjoint(); + temp.head(k) = mat.diagonal().real().head(k).asDiagonal() * A10.adjoint(); mat.coeffRef(k,k) -= (A10 * temp.head(k)).value(); if(rs>0) A21.noalias() -= A20 * temp.head(k); } - if((rs>0) && (abs(mat.coeffRef(k,k)) > cutoff)) - A21 /= mat.coeffRef(k,k); - + + // In some previous versions of Eigen (e.g., 3.2.1), the scaling was omitted if the pivot + // was smaller than the cutoff value. However, soince LDLT is not rank-revealing + // we should only make sure we do not introduce INF or NaN values. + // LAPACK also uses 0 as the cutoff value. RealScalar realAkk = numext::real(mat.coeffRef(k,k)); + if((rs>0) && (abs(realAkk) > RealScalar(0))) + A21 /= realAkk; + if (sign == PositiveSemiDef) { if (realAkk < 0) sign = Indefinite; } else if (sign == NegativeSemiDef) { @@ -446,6 +439,8 @@ template<typename MatrixType> struct LDLT_Traits<MatrixType,Upper> template<typename MatrixType, int _UpLo> LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const MatrixType& a) { + check_template_parameters(); + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); @@ -454,6 +449,7 @@ LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const MatrixType& a) m_transpositions.resize(size); m_isInitialized = false; m_temporary.resize(size); + m_sign = internal::ZeroSign; internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, m_sign); @@ -468,7 +464,7 @@ LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const MatrixType& a) */ template<typename MatrixType, int _UpLo> template<typename Derived> -LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::rankUpdate(const MatrixBase<Derived>& w, const typename NumTraits<typename MatrixType::Scalar>::Real& sigma) +LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::rankUpdate(const MatrixBase<Derived>& w, const typename LDLT<MatrixType,_UpLo>::RealScalar& sigma) { const Index size = w.rows(); if (m_isInitialized) @@ -514,16 +510,21 @@ struct solve_retval<LDLT<_MatrixType,_UpLo>, Rhs> using std::abs; using std::max; typedef typename LDLTType::MatrixType MatrixType; - typedef typename LDLTType::Scalar Scalar; typedef typename LDLTType::RealScalar RealScalar; - const Diagonal<const MatrixType> vectorD = dec().vectorD(); - RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() * NumTraits<Scalar>::epsilon(), - RealScalar(1) / NumTraits<RealScalar>::highest()); // motivated by LAPACK's xGELSS + const typename Diagonal<const MatrixType>::RealReturnType vectorD(dec().vectorD()); + // In some previous versions, tolerance was set to the max of 1/highest and the maximal diagonal entry * epsilon + // as motivated by LAPACK's xGELSS: + // RealScalar tolerance = (max)(vectorD.array().abs().maxCoeff() *NumTraits<RealScalar>::epsilon(),RealScalar(1) / NumTraits<RealScalar>::highest()); + // However, LDLT is not rank revealing, and so adjusting the tolerance wrt to the highest + // diagonal element is not well justified and to numerical issues in some cases. + // Moreover, Lapack's xSYTRS routines use 0 for the tolerance. + RealScalar tolerance = RealScalar(1) / NumTraits<RealScalar>::highest(); + for (Index i = 0; i < vectorD.size(); ++i) { if(abs(vectorD(i)) > tolerance) - dst.row(i) /= vectorD(i); + dst.row(i) /= vectorD(i); else - dst.row(i).setZero(); + dst.row(i).setZero(); } // dst = L^-T (D^-1 L^-1 P b) @@ -576,7 +577,7 @@ MatrixType LDLT<MatrixType,_UpLo>::reconstructedMatrix() const // L^* P res = matrixU() * res; // D(L^*P) - res = vectorD().asDiagonal() * res; + res = vectorD().real().asDiagonal() * res; // L(DL^*P) res = matrixL() * res; // P^T (LDL^*P) diff --git a/extern/Eigen3/Eigen/src/Cholesky/LLT.h b/extern/Eigen3/Eigen/src/Cholesky/LLT.h index 2e6189f7dab..7c11a2dc29a 100644 --- a/extern/Eigen3/Eigen/src/Cholesky/LLT.h +++ b/extern/Eigen3/Eigen/src/Cholesky/LLT.h @@ -174,6 +174,12 @@ template<typename _MatrixType, int _UpLo> class LLT LLT rankUpdate(const VectorType& vec, const RealScalar& sigma = 1); protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + /** \internal * Used to compute and store L * The strict upper part is not used and even not initialized. @@ -283,7 +289,7 @@ template<typename Scalar> struct llt_inplace<Scalar, Lower> return k; mat.coeffRef(k,k) = x = sqrt(x); if (k>0 && rs>0) A21.noalias() -= A20 * A10.adjoint(); - if (rs>0) A21 *= RealScalar(1)/x; + if (rs>0) A21 /= x; } return -1; } @@ -384,6 +390,8 @@ template<typename MatrixType> struct LLT_Traits<MatrixType,Upper> template<typename MatrixType, int _UpLo> LLT<MatrixType,_UpLo>& LLT<MatrixType,_UpLo>::compute(const MatrixType& a) { + check_template_parameters(); + eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); m_matrix.resize(size, size); diff --git a/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h b/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h index 64daa445cf7..66675d7476d 100644 --- a/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h +++ b/extern/Eigen3/Eigen/src/Cholesky/LLT_MKL.h @@ -60,7 +60,7 @@ template<> struct mkl_llt<EIGTYPE> \ lda = m.outerStride(); \ \ info = LAPACKE_##MKLPREFIX##potrf( matrix_order, uplo, size, (MKLTYPE*)a, lda ); \ - info = (info==0) ? Success : NumericalIssue; \ + info = (info==0) ? -1 : info>0 ? info-1 : size; \ return info; \ } \ }; \ diff --git a/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h b/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h index c449960de4a..99dbe171c36 100644 --- a/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h +++ b/extern/Eigen3/Eigen/src/CholmodSupport/CholmodSupport.h @@ -78,7 +78,7 @@ cholmod_sparse viewAsCholmod(SparseMatrix<_Scalar,_Options,_Index>& mat) { res.itype = CHOLMOD_INT; } - else if (internal::is_same<_Index,UF_long>::value) + else if (internal::is_same<_Index,SuiteSparse_long>::value) { res.itype = CHOLMOD_LONG; } @@ -395,7 +395,7 @@ class CholmodSimplicialLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimpl CholmodSimplicialLLT(const MatrixType& matrix) : Base() { init(); - compute(matrix); + Base::compute(matrix); } ~CholmodSimplicialLLT() {} @@ -442,7 +442,7 @@ class CholmodSimplicialLDLT : public CholmodBase<_MatrixType, _UpLo, CholmodSimp CholmodSimplicialLDLT(const MatrixType& matrix) : Base() { init(); - compute(matrix); + Base::compute(matrix); } ~CholmodSimplicialLDLT() {} @@ -487,7 +487,7 @@ class CholmodSupernodalLLT : public CholmodBase<_MatrixType, _UpLo, CholmodSuper CholmodSupernodalLLT(const MatrixType& matrix) : Base() { init(); - compute(matrix); + Base::compute(matrix); } ~CholmodSupernodalLLT() {} @@ -534,7 +534,7 @@ class CholmodDecomposition : public CholmodBase<_MatrixType, _UpLo, CholmodDecom CholmodDecomposition(const MatrixType& matrix) : Base() { init(); - compute(matrix); + Base::compute(matrix); } ~CholmodDecomposition() {} diff --git a/extern/Eigen3/Eigen/src/Core/Array.h b/extern/Eigen3/Eigen/src/Core/Array.h index 0ab03eff0f0..0b9c38c8219 100644 --- a/extern/Eigen3/Eigen/src/Core/Array.h +++ b/extern/Eigen3/Eigen/src/Core/Array.h @@ -124,6 +124,21 @@ class Array } #endif +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + Array(Array&& other) + : Base(std::move(other)) + { + Base::_check_template_params(); + if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) + Base::_set_noalias(other); + } + Array& operator=(Array&& other) + { + other.swap(*this); + return *this; + } +#endif + /** Constructs a vector or row-vector with given dimension. \only_for_vectors * * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, diff --git a/extern/Eigen3/Eigen/src/Core/ArrayBase.h b/extern/Eigen3/Eigen/src/Core/ArrayBase.h index 38852600dc2..33ff553712e 100644 --- a/extern/Eigen3/Eigen/src/Core/ArrayBase.h +++ b/extern/Eigen3/Eigen/src/Core/ArrayBase.h @@ -46,9 +46,6 @@ template<typename Derived> class ArrayBase typedef ArrayBase Eigen_BaseClassForSpecializationOfGlobalMathFuncImpl; - using internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar, - typename NumTraits<typename internal::traits<Derived>::Scalar>::Real>::operator*; - typedef typename internal::traits<Derived>::StorageKind StorageKind; typedef typename internal::traits<Derived>::Index Index; typedef typename internal::traits<Derived>::Scalar Scalar; @@ -56,6 +53,7 @@ template<typename Derived> class ArrayBase typedef typename NumTraits<Scalar>::Real RealScalar; typedef DenseBase<Derived> Base; + using Base::operator*; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; using Base::SizeAtCompileTime; diff --git a/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h b/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h index a791bc3581a..b4641e2a01f 100644 --- a/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h +++ b/extern/Eigen3/Eigen/src/Core/ArrayWrapper.h @@ -29,6 +29,11 @@ struct traits<ArrayWrapper<ExpressionType> > : public traits<typename remove_all<typename ExpressionType::Nested>::type > { typedef ArrayXpr XprKind; + // Let's remove NestByRefBit + enum { + Flags0 = traits<typename remove_all<typename ExpressionType::Nested>::type >::Flags, + Flags = Flags0 & ~NestByRefBit + }; }; } @@ -149,6 +154,11 @@ struct traits<MatrixWrapper<ExpressionType> > : public traits<typename remove_all<typename ExpressionType::Nested>::type > { typedef MatrixXpr XprKind; + // Let's remove NestByRefBit + enum { + Flags0 = traits<typename remove_all<typename ExpressionType::Nested>::type >::Flags, + Flags = Flags0 & ~NestByRefBit + }; }; } diff --git a/extern/Eigen3/Eigen/src/Core/Assign.h b/extern/Eigen3/Eigen/src/Core/Assign.h index 1dccc2f4212..f4817317279 100644 --- a/extern/Eigen3/Eigen/src/Core/Assign.h +++ b/extern/Eigen3/Eigen/src/Core/Assign.h @@ -439,19 +439,26 @@ struct assign_impl<Derived1, Derived2, SliceVectorizedTraversal, NoUnrolling, Ve typedef typename Derived1::Index Index; static inline void run(Derived1 &dst, const Derived2 &src) { - typedef packet_traits<typename Derived1::Scalar> PacketTraits; + typedef typename Derived1::Scalar Scalar; + typedef packet_traits<Scalar> PacketTraits; enum { packetSize = PacketTraits::size, alignable = PacketTraits::AlignedOnScalar, - dstAlignment = alignable ? Aligned : int(assign_traits<Derived1,Derived2>::DstIsAligned) , + dstIsAligned = assign_traits<Derived1,Derived2>::DstIsAligned, + dstAlignment = alignable ? Aligned : int(dstIsAligned), srcAlignment = assign_traits<Derived1,Derived2>::JointAlignment }; + const Scalar *dst_ptr = &dst.coeffRef(0,0); + if((!bool(dstIsAligned)) && (size_t(dst_ptr) % sizeof(Scalar))>0) + { + // the pointer is not aligend-on scalar, so alignment is not possible + return assign_impl<Derived1,Derived2,DefaultTraversal,NoUnrolling>::run(dst, src); + } const Index packetAlignedMask = packetSize - 1; const Index innerSize = dst.innerSize(); const Index outerSize = dst.outerSize(); const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0; - Index alignedStart = ((!alignable) || assign_traits<Derived1,Derived2>::DstIsAligned) ? 0 - : internal::first_aligned(&dst.coeffRef(0,0), innerSize); + Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned(dst_ptr, innerSize); for(Index outer = 0; outer < outerSize; ++outer) { diff --git a/extern/Eigen3/Eigen/src/Core/Block.h b/extern/Eigen3/Eigen/src/Core/Block.h index 358b3188b38..82789444327 100644 --- a/extern/Eigen3/Eigen/src/Core/Block.h +++ b/extern/Eigen3/Eigen/src/Core/Block.h @@ -66,8 +66,9 @@ struct traits<Block<XprType, BlockRows, BlockCols, InnerPanel> > : traits<XprTyp : ColsAtCompileTime != Dynamic ? int(ColsAtCompileTime) : int(traits<XprType>::MaxColsAtCompileTime), XprTypeIsRowMajor = (int(traits<XprType>::Flags)&RowMajorBit) != 0, - IsRowMajor = (MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 - : (MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 + IsDense = is_same<StorageKind,Dense>::value, + IsRowMajor = (IsDense&&MaxRowsAtCompileTime==1&&MaxColsAtCompileTime!=1) ? 1 + : (IsDense&&MaxColsAtCompileTime==1&&MaxRowsAtCompileTime!=1) ? 0 : XprTypeIsRowMajor, HasSameStorageOrderAsXprType = (IsRowMajor == XprTypeIsRowMajor), InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime), @@ -81,7 +82,7 @@ struct traits<Block<XprType, BlockRows, BlockCols, InnerPanel> > : traits<XprTyp && (InnerStrideAtCompileTime == 1) ? PacketAccessBit : 0, MaskAlignedBit = (InnerPanel && (OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, - FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, + FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 || (InnerPanel && (traits<XprType>::Flags&LinearAccessBit))) ? LinearAccessBit : 0, FlagsLvalueBit = is_lvalue<XprType>::value ? LvalueBit : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, Flags0 = traits<XprType>::Flags & ( (HereditaryBits & ~RowMajorBit) | diff --git a/extern/Eigen3/Eigen/src/Core/CommaInitializer.h b/extern/Eigen3/Eigen/src/Core/CommaInitializer.h index a96867af4d5..a036d8c3bc9 100644 --- a/extern/Eigen3/Eigen/src/Core/CommaInitializer.h +++ b/extern/Eigen3/Eigen/src/Core/CommaInitializer.h @@ -43,6 +43,17 @@ struct CommaInitializer m_xpr.block(0, 0, other.rows(), other.cols()) = other; } + /* Copy/Move constructor which transfers ownership. This is crucial in + * absence of return value optimization to avoid assertions during destruction. */ + // FIXME in C++11 mode this could be replaced by a proper RValue constructor + inline CommaInitializer(const CommaInitializer& o) + : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) { + // Mark original object as finished. In absence of R-value references we need to const_cast: + const_cast<CommaInitializer&>(o).m_row = m_xpr.rows(); + const_cast<CommaInitializer&>(o).m_col = m_xpr.cols(); + const_cast<CommaInitializer&>(o).m_currentBlockRows = 0; + } + /* inserts a scalar value in the target matrix */ CommaInitializer& operator,(const Scalar& s) { diff --git a/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h b/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h index 586f77aaf32..519a866e605 100644 --- a/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h +++ b/extern/Eigen3/Eigen/src/Core/CwiseBinaryOp.h @@ -81,7 +81,8 @@ struct traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> > ) ), Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit), - CoeffReadCost = LhsCoeffReadCost + RhsCoeffReadCost + functor_traits<BinaryOp>::Cost + Cost0 = EIGEN_ADD_COST(LhsCoeffReadCost,RhsCoeffReadCost), + CoeffReadCost = EIGEN_ADD_COST(Cost0,functor_traits<BinaryOp>::Cost) }; }; } // end namespace internal diff --git a/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h b/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h index f2de749f92b..f7ee60e9879 100644 --- a/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h +++ b/extern/Eigen3/Eigen/src/Core/CwiseUnaryOp.h @@ -47,7 +47,7 @@ struct traits<CwiseUnaryOp<UnaryOp, XprType> > Flags = _XprTypeNested::Flags & ( HereditaryBits | LinearAccessBit | AlignedBit | (functor_traits<UnaryOp>::PacketAccess ? PacketAccessBit : 0)), - CoeffReadCost = _XprTypeNested::CoeffReadCost + functor_traits<UnaryOp>::Cost + CoeffReadCost = EIGEN_ADD_COST(_XprTypeNested::CoeffReadCost, functor_traits<UnaryOp>::Cost) }; }; } diff --git a/extern/Eigen3/Eigen/src/Core/DenseBase.h b/extern/Eigen3/Eigen/src/Core/DenseBase.h index c5800f6c8c8..4b371b075b8 100644 --- a/extern/Eigen3/Eigen/src/Core/DenseBase.h +++ b/extern/Eigen3/Eigen/src/Core/DenseBase.h @@ -40,15 +40,14 @@ static inline void check_DenseIndex_is_signed() { */ template<typename Derived> class DenseBase #ifndef EIGEN_PARSED_BY_DOXYGEN - : public internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar, - typename NumTraits<typename internal::traits<Derived>::Scalar>::Real> + : public internal::special_scalar_op_base<Derived, typename internal::traits<Derived>::Scalar, + typename NumTraits<typename internal::traits<Derived>::Scalar>::Real, + DenseCoeffsBase<Derived> > #else : public DenseCoeffsBase<Derived> #endif // not EIGEN_PARSED_BY_DOXYGEN { public: - using internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar, - typename NumTraits<typename internal::traits<Derived>::Scalar>::Real>::operator*; class InnerIterator; @@ -63,8 +62,9 @@ template<typename Derived> class DenseBase typedef typename internal::traits<Derived>::Scalar Scalar; typedef typename internal::packet_traits<Scalar>::type PacketScalar; typedef typename NumTraits<Scalar>::Real RealScalar; + typedef internal::special_scalar_op_base<Derived,Scalar,RealScalar, DenseCoeffsBase<Derived> > Base; - typedef DenseCoeffsBase<Derived> Base; + using Base::operator*; using Base::derived; using Base::const_cast_derived; using Base::rows; @@ -183,10 +183,6 @@ template<typename Derived> class DenseBase /** \returns the number of nonzero coefficients which is in practice the number * of stored coefficients. */ inline Index nonZeros() const { return size(); } - /** \returns true if either the number of rows or the number of columns is equal to 1. - * In other words, this function returns - * \code rows()==1 || cols()==1 \endcode - * \sa rows(), cols(), IsVectorAtCompileTime. */ /** \returns the outer size. * @@ -266,11 +262,13 @@ template<typename Derived> class DenseBase template<typename OtherDerived> Derived& operator=(const ReturnByValue<OtherDerived>& func); -#ifndef EIGEN_PARSED_BY_DOXYGEN - /** Copies \a other into *this without evaluating other. \returns a reference to *this. */ + /** \internal Copies \a other into *this without evaluating other. \returns a reference to *this. */ template<typename OtherDerived> Derived& lazyAssign(const DenseBase<OtherDerived>& other); -#endif // not EIGEN_PARSED_BY_DOXYGEN + + /** \internal Evaluates \a other into *this. \returns a reference to *this. */ + template<typename OtherDerived> + Derived& lazyAssign(const ReturnByValue<OtherDerived>& other); CommaInitializer<Derived> operator<< (const Scalar& s); @@ -462,8 +460,10 @@ template<typename Derived> class DenseBase template<int p> RealScalar lpNorm() const; template<int RowFactor, int ColFactor> - const Replicate<Derived,RowFactor,ColFactor> replicate() const; - const Replicate<Derived,Dynamic,Dynamic> replicate(Index rowFacor,Index colFactor) const; + inline const Replicate<Derived,RowFactor,ColFactor> replicate() const; + + typedef Replicate<Derived,Dynamic,Dynamic> ReplicateReturnType; + inline const ReplicateReturnType replicate(Index rowFacor,Index colFactor) const; typedef Reverse<Derived, BothDirections> ReverseReturnType; typedef const Reverse<const Derived, BothDirections> ConstReverseReturnType; diff --git a/extern/Eigen3/Eigen/src/Core/DenseStorage.h b/extern/Eigen3/Eigen/src/Core/DenseStorage.h index 3e7f9c1b7a7..568493cbae0 100644 --- a/extern/Eigen3/Eigen/src/Core/DenseStorage.h +++ b/extern/Eigen3/Eigen/src/Core/DenseStorage.h @@ -24,6 +24,14 @@ namespace internal { struct constructor_without_unaligned_array_assert {}; +template<typename T, int Size> void check_static_allocation_size() +{ + // if EIGEN_STACK_ALLOCATION_LIMIT is defined to 0, then no limit + #if EIGEN_STACK_ALLOCATION_LIMIT + EIGEN_STATIC_ASSERT(Size * sizeof(T) <= EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + #endif +} + /** \internal * Static array. If the MatrixOrArrayOptions require auto-alignment, the array will be automatically aligned: * to 16 bytes boundary if the total size is a multiple of 16 bytes. @@ -38,12 +46,12 @@ struct plain_array plain_array() { - EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + check_static_allocation_size<T,Size>(); } plain_array(constructor_without_unaligned_array_assert) { - EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + check_static_allocation_size<T,Size>(); } }; @@ -76,12 +84,12 @@ struct plain_array<T, Size, MatrixOrArrayOptions, 16> plain_array() { EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf); - EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + check_static_allocation_size<T,Size>(); } plain_array(constructor_without_unaligned_array_assert) { - EIGEN_STATIC_ASSERT(Size * sizeof(T) <= 128 * 128 * 8, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG); + check_static_allocation_size<T,Size>(); } }; @@ -114,33 +122,41 @@ template<typename T, int Size, int _Rows, int _Cols, int _Options> class DenseSt { internal::plain_array<T,Size,_Options> m_data; public: - inline DenseStorage() {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) + DenseStorage() {} + DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()) {} - inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} - inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } - static inline DenseIndex rows(void) {return _Rows;} - static inline DenseIndex cols(void) {return _Cols;} - inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} - inline void resize(DenseIndex,DenseIndex,DenseIndex) {} - inline const T *data() const { return m_data.array; } - inline T *data() { return m_data.array; } + DenseStorage(const DenseStorage& other) : m_data(other.m_data) {} + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) m_data = other.m_data; + return *this; + } + DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); } + static DenseIndex rows(void) {return _Rows;} + static DenseIndex cols(void) {return _Cols;} + void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} + void resize(DenseIndex,DenseIndex,DenseIndex) {} + const T *data() const { return m_data.array; } + T *data() { return m_data.array; } }; // null matrix template<typename T, int _Rows, int _Cols, int _Options> class DenseStorage<T, 0, _Rows, _Cols, _Options> { public: - inline DenseStorage() {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) {} - inline DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} - inline void swap(DenseStorage& ) {} - static inline DenseIndex rows(void) {return _Rows;} - static inline DenseIndex cols(void) {return _Cols;} - inline void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} - inline void resize(DenseIndex,DenseIndex,DenseIndex) {} - inline const T *data() const { return 0; } - inline T *data() { return 0; } + DenseStorage() {} + DenseStorage(internal::constructor_without_unaligned_array_assert) {} + DenseStorage(const DenseStorage&) {} + DenseStorage& operator=(const DenseStorage&) { return *this; } + DenseStorage(DenseIndex,DenseIndex,DenseIndex) {} + void swap(DenseStorage& ) {} + static DenseIndex rows(void) {return _Rows;} + static DenseIndex cols(void) {return _Cols;} + void conservativeResize(DenseIndex,DenseIndex,DenseIndex) {} + void resize(DenseIndex,DenseIndex,DenseIndex) {} + const T *data() const { return 0; } + T *data() { return 0; } }; // more specializations for null matrices; these are necessary to resolve ambiguities @@ -160,18 +176,29 @@ template<typename T, int Size, int _Options> class DenseStorage<T, Size, Dynamic DenseIndex m_rows; DenseIndex m_cols; public: - inline DenseStorage() : m_rows(0), m_cols(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) + DenseStorage() : m_rows(0), m_cols(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0), m_cols(0) {} - inline DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {} - inline void swap(DenseStorage& other) + DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows), m_cols(other.m_cols) {} + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_rows = other.m_rows; + m_cols = other.m_cols; + } + return *this; + } + DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) : m_rows(nbRows), m_cols(nbCols) {} + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } - inline DenseIndex rows() const {return m_rows;} - inline DenseIndex cols() const {return m_cols;} - inline void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } - inline void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } - inline const T *data() const { return m_data.array; } - inline T *data() { return m_data.array; } + DenseIndex rows() const {return m_rows;} + DenseIndex cols() const {return m_cols;} + void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } + void resize(DenseIndex, DenseIndex nbRows, DenseIndex nbCols) { m_rows = nbRows; m_cols = nbCols; } + const T *data() const { return m_data.array; } + T *data() { return m_data.array; } }; // dynamic-size matrix with fixed-size storage and fixed width @@ -180,17 +207,27 @@ template<typename T, int Size, int _Cols, int _Options> class DenseStorage<T, Si internal::plain_array<T,Size,_Options> m_data; DenseIndex m_rows; public: - inline DenseStorage() : m_rows(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) + DenseStorage() : m_rows(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_rows(0) {} - inline DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {} - inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } - inline DenseIndex rows(void) const {return m_rows;} - inline DenseIndex cols(void) const {return _Cols;} - inline void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } - inline void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } - inline const T *data() const { return m_data.array; } - inline T *data() { return m_data.array; } + DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_rows(other.m_rows) {} + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_rows = other.m_rows; + } + return *this; + } + DenseStorage(DenseIndex, DenseIndex nbRows, DenseIndex) : m_rows(nbRows) {} + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + DenseIndex rows(void) const {return m_rows;} + DenseIndex cols(void) const {return _Cols;} + void conservativeResize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } + void resize(DenseIndex, DenseIndex nbRows, DenseIndex) { m_rows = nbRows; } + const T *data() const { return m_data.array; } + T *data() { return m_data.array; } }; // dynamic-size matrix with fixed-size storage and fixed height @@ -199,17 +236,27 @@ template<typename T, int Size, int _Rows, int _Options> class DenseStorage<T, Si internal::plain_array<T,Size,_Options> m_data; DenseIndex m_cols; public: - inline DenseStorage() : m_cols(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) + DenseStorage() : m_cols(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(internal::constructor_without_unaligned_array_assert()), m_cols(0) {} - inline DenseStorage(DenseIndex, DenseIndex, DenseIndex nbCols) : m_cols(nbCols) {} - inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } - inline DenseIndex rows(void) const {return _Rows;} - inline DenseIndex cols(void) const {return m_cols;} - inline void conservativeResize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } - inline void resize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } - inline const T *data() const { return m_data.array; } - inline T *data() { return m_data.array; } + DenseStorage(const DenseStorage& other) : m_data(other.m_data), m_cols(other.m_cols) {} + DenseStorage& operator=(const DenseStorage& other) + { + if (this != &other) + { + m_data = other.m_data; + m_cols = other.m_cols; + } + return *this; + } + DenseStorage(DenseIndex, DenseIndex, DenseIndex nbCols) : m_cols(nbCols) {} + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + DenseIndex rows(void) const {return _Rows;} + DenseIndex cols(void) const {return m_cols;} + void conservativeResize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } + void resize(DenseIndex, DenseIndex, DenseIndex nbCols) { m_cols = nbCols; } + const T *data() const { return m_data.array; } + T *data() { return m_data.array; } }; // purely dynamic matrix. @@ -219,18 +266,35 @@ template<typename T, int _Options> class DenseStorage<T, Dynamic, Dynamic, Dynam DenseIndex m_rows; DenseIndex m_cols; public: - inline DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) + DenseStorage() : m_data(0), m_rows(0), m_cols(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0), m_cols(0) {} - inline DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(nbRows), m_cols(nbCols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } - inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, m_rows*m_cols); } - inline void swap(DenseStorage& other) +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + DenseStorage(DenseStorage&& other) + : m_data(std::move(other.m_data)) + , m_rows(std::move(other.m_rows)) + , m_cols(std::move(other.m_cols)) + { + other.m_data = nullptr; + } + DenseStorage& operator=(DenseStorage&& other) + { + using std::swap; + swap(m_data, other.m_data); + swap(m_rows, other.m_rows); + swap(m_cols, other.m_cols); + return *this; + } +#endif + ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, m_rows*m_cols); } + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); std::swap(m_cols,other.m_cols); } - inline DenseIndex rows(void) const {return m_rows;} - inline DenseIndex cols(void) const {return m_cols;} - inline void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) + DenseIndex rows(void) const {return m_rows;} + DenseIndex cols(void) const {return m_cols;} + void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex nbCols) { m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, m_rows*m_cols); m_rows = nbRows; @@ -250,8 +314,11 @@ template<typename T, int _Options> class DenseStorage<T, Dynamic, Dynamic, Dynam m_rows = nbRows; m_cols = nbCols; } - inline const T *data() const { return m_data; } - inline T *data() { return m_data; } + const T *data() const { return m_data; } + T *data() { return m_data; } + private: + DenseStorage(const DenseStorage&); + DenseStorage& operator=(const DenseStorage&); }; // matrix with dynamic width and fixed height (so that matrix has dynamic size). @@ -260,15 +327,30 @@ template<typename T, int _Rows, int _Options> class DenseStorage<T, Dynamic, _Ro T *m_data; DenseIndex m_cols; public: - inline DenseStorage() : m_data(0), m_cols(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} - inline DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_cols(nbCols) + DenseStorage() : m_data(0), m_cols(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_cols(0) {} + DenseStorage(DenseIndex size, DenseIndex, DenseIndex nbCols) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_cols(nbCols) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } - inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Rows*m_cols); } - inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } - static inline DenseIndex rows(void) {return _Rows;} - inline DenseIndex cols(void) const {return m_cols;} - inline void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols) +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + DenseStorage(DenseStorage&& other) + : m_data(std::move(other.m_data)) + , m_cols(std::move(other.m_cols)) + { + other.m_data = nullptr; + } + DenseStorage& operator=(DenseStorage&& other) + { + using std::swap; + swap(m_data, other.m_data); + swap(m_cols, other.m_cols); + return *this; + } +#endif + ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Rows*m_cols); } + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_cols,other.m_cols); } + static DenseIndex rows(void) {return _Rows;} + DenseIndex cols(void) const {return m_cols;} + void conservativeResize(DenseIndex size, DenseIndex, DenseIndex nbCols) { m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, _Rows*m_cols); m_cols = nbCols; @@ -286,8 +368,11 @@ template<typename T, int _Rows, int _Options> class DenseStorage<T, Dynamic, _Ro } m_cols = nbCols; } - inline const T *data() const { return m_data; } - inline T *data() { return m_data; } + const T *data() const { return m_data; } + T *data() { return m_data; } + private: + DenseStorage(const DenseStorage&); + DenseStorage& operator=(const DenseStorage&); }; // matrix with dynamic height and fixed width (so that matrix has dynamic size). @@ -296,15 +381,30 @@ template<typename T, int _Cols, int _Options> class DenseStorage<T, Dynamic, Dyn T *m_data; DenseIndex m_rows; public: - inline DenseStorage() : m_data(0), m_rows(0) {} - inline DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} - inline DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(nbRows) + DenseStorage() : m_data(0), m_rows(0) {} + DenseStorage(internal::constructor_without_unaligned_array_assert) : m_data(0), m_rows(0) {} + DenseStorage(DenseIndex size, DenseIndex nbRows, DenseIndex) : m_data(internal::conditional_aligned_new_auto<T,(_Options&DontAlign)==0>(size)), m_rows(nbRows) { EIGEN_INTERNAL_DENSE_STORAGE_CTOR_PLUGIN } - inline ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Cols*m_rows); } - inline void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } - inline DenseIndex rows(void) const {return m_rows;} - static inline DenseIndex cols(void) {return _Cols;} - inline void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex) +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + DenseStorage(DenseStorage&& other) + : m_data(std::move(other.m_data)) + , m_rows(std::move(other.m_rows)) + { + other.m_data = nullptr; + } + DenseStorage& operator=(DenseStorage&& other) + { + using std::swap; + swap(m_data, other.m_data); + swap(m_rows, other.m_rows); + return *this; + } +#endif + ~DenseStorage() { internal::conditional_aligned_delete_auto<T,(_Options&DontAlign)==0>(m_data, _Cols*m_rows); } + void swap(DenseStorage& other) { std::swap(m_data,other.m_data); std::swap(m_rows,other.m_rows); } + DenseIndex rows(void) const {return m_rows;} + static DenseIndex cols(void) {return _Cols;} + void conservativeResize(DenseIndex size, DenseIndex nbRows, DenseIndex) { m_data = internal::conditional_aligned_realloc_new_auto<T,(_Options&DontAlign)==0>(m_data, size, m_rows*_Cols); m_rows = nbRows; @@ -322,8 +422,11 @@ template<typename T, int _Cols, int _Options> class DenseStorage<T, Dynamic, Dyn } m_rows = nbRows; } - inline const T *data() const { return m_data; } - inline T *data() { return m_data; } + const T *data() const { return m_data; } + T *data() { return m_data; } + private: + DenseStorage(const DenseStorage&); + DenseStorage& operator=(const DenseStorage&); }; } // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/Core/Diagonal.h b/extern/Eigen3/Eigen/src/Core/Diagonal.h index aab8007b3fc..68cf6d4b044 100644 --- a/extern/Eigen3/Eigen/src/Core/Diagonal.h +++ b/extern/Eigen3/Eigen/src/Core/Diagonal.h @@ -190,18 +190,18 @@ MatrixBase<Derived>::diagonal() const * * \sa MatrixBase::diagonal(), class Diagonal */ template<typename Derived> -inline typename MatrixBase<Derived>::template DiagonalIndexReturnType<DynamicIndex>::Type +inline typename MatrixBase<Derived>::DiagonalDynamicIndexReturnType MatrixBase<Derived>::diagonal(Index index) { - return typename DiagonalIndexReturnType<DynamicIndex>::Type(derived(), index); + return DiagonalDynamicIndexReturnType(derived(), index); } /** This is the const version of diagonal(Index). */ template<typename Derived> -inline typename MatrixBase<Derived>::template ConstDiagonalIndexReturnType<DynamicIndex>::Type +inline typename MatrixBase<Derived>::ConstDiagonalDynamicIndexReturnType MatrixBase<Derived>::diagonal(Index index) const { - return typename ConstDiagonalIndexReturnType<DynamicIndex>::Type(derived(), index); + return ConstDiagonalDynamicIndexReturnType(derived(), index); } /** \returns an expression of the \a DiagIndex-th sub or super diagonal of the matrix \c *this diff --git a/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h b/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h index c03a0c2e12b..cc6b536e199 100644 --- a/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h +++ b/extern/Eigen3/Eigen/src/Core/DiagonalProduct.h @@ -34,8 +34,9 @@ struct traits<DiagonalProduct<MatrixType, DiagonalType, ProductOrder> > _Vectorizable = bool(int(MatrixType::Flags)&PacketAccessBit) && _SameTypes && (_ScalarAccessOnDiag || (bool(int(DiagonalType::DiagonalVectorType::Flags)&PacketAccessBit))), _LinearAccessMask = (RowsAtCompileTime==1 || ColsAtCompileTime==1) ? LinearAccessBit : 0, - Flags = ((HereditaryBits|_LinearAccessMask) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0) | AlignedBit,//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), - CoeffReadCost = NumTraits<Scalar>::MulCost + MatrixType::CoeffReadCost + DiagonalType::DiagonalVectorType::CoeffReadCost + Flags = ((HereditaryBits|_LinearAccessMask|AlignedBit) & (unsigned int)(MatrixType::Flags)) | (_Vectorizable ? PacketAccessBit : 0),//(int(MatrixType::Flags)&int(DiagonalType::DiagonalVectorType::Flags)&AlignedBit), + Cost0 = EIGEN_ADD_COST(NumTraits<Scalar>::MulCost, MatrixType::CoeffReadCost), + CoeffReadCost = EIGEN_ADD_COST(Cost0,DiagonalType::DiagonalVectorType::CoeffReadCost) }; }; } diff --git a/extern/Eigen3/Eigen/src/Core/Functors.h b/extern/Eigen3/Eigen/src/Core/Functors.h index 04fb217323d..5f14c6587e0 100644 --- a/extern/Eigen3/Eigen/src/Core/Functors.h +++ b/extern/Eigen3/Eigen/src/Core/Functors.h @@ -259,6 +259,47 @@ template<> struct functor_traits<scalar_boolean_or_op> { }; }; +/** \internal + * \brief Template functors for comparison of two scalars + * \todo Implement packet-comparisons + */ +template<typename Scalar, ComparisonName cmp> struct scalar_cmp_op; + +template<typename Scalar, ComparisonName cmp> +struct functor_traits<scalar_cmp_op<Scalar, cmp> > { + enum { + Cost = NumTraits<Scalar>::AddCost, + PacketAccess = false + }; +}; + +template<ComparisonName Cmp, typename Scalar> +struct result_of<scalar_cmp_op<Scalar, Cmp>(Scalar,Scalar)> { + typedef bool type; +}; + + +template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_EQ> { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a==b;} +}; +template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_LT> { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a<b;} +}; +template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_LE> { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a<=b;} +}; +template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_UNORD> { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return !(a<=b || b<=a);} +}; +template<typename Scalar> struct scalar_cmp_op<Scalar, cmp_NEQ> { + EIGEN_EMPTY_STRUCT_CTOR(scalar_cmp_op) + EIGEN_STRONG_INLINE bool operator()(const Scalar& a, const Scalar& b) const {return a!=b;} +}; + // unary functors: /** \internal @@ -589,7 +630,7 @@ struct linspaced_op_impl<Scalar,true> template<typename Index> EIGEN_STRONG_INLINE const Packet packetOp(Index i) const - { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1<Packet>(i),m_interPacket))); } + { return internal::padd(m_lowPacket, pmul(m_stepPacket, padd(pset1<Packet>(Scalar(i)),m_interPacket))); } const Scalar m_low; const Scalar m_step; @@ -609,7 +650,7 @@ template <typename Scalar, bool RandomAccess> struct functor_traits< linspaced_o template <typename Scalar, bool RandomAccess> struct linspaced_op { typedef typename packet_traits<Scalar>::type Packet; - linspaced_op(const Scalar& low, const Scalar& high, DenseIndex num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/(num_steps-1))) {} + linspaced_op(const Scalar& low, const Scalar& high, DenseIndex num_steps) : impl((num_steps==1 ? high : low), (num_steps==1 ? Scalar() : (high-low)/Scalar(num_steps-1))) {} template<typename Index> EIGEN_STRONG_INLINE const Scalar operator() (Index i) const { return impl(i); } diff --git a/extern/Eigen3/Eigen/src/Core/GeneralProduct.h b/extern/Eigen3/Eigen/src/Core/GeneralProduct.h index 2a59d94645e..0eae529909f 100644 --- a/extern/Eigen3/Eigen/src/Core/GeneralProduct.h +++ b/extern/Eigen3/Eigen/src/Core/GeneralProduct.h @@ -232,7 +232,7 @@ EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& // FIXME not very good if rhs is real and lhs complex while alpha is real too const Index cols = dest.cols(); for (Index j=0; j<cols; ++j) - func(dest.col(j), prod.rhs().coeff(j) * prod.lhs()); + func(dest.col(j), prod.rhs().coeff(0,j) * prod.lhs()); } // Row major @@ -243,7 +243,7 @@ EIGEN_DONT_INLINE void outer_product_selector_run(const ProductType& prod, Dest& // FIXME not very good if lhs is real and rhs complex while alpha is real too const Index rows = dest.rows(); for (Index i=0; i<rows; ++i) - func(dest.row(i), prod.lhs().coeff(i) * prod.rhs()); + func(dest.row(i), prod.lhs().coeff(i,0) * prod.rhs()); } template<typename Lhs, typename Rhs> @@ -257,7 +257,7 @@ template<typename Lhs, typename Rhs> class GeneralProduct<Lhs, Rhs, OuterProduct> : public ProductBase<GeneralProduct<Lhs,Rhs,OuterProduct>, Lhs, Rhs> { - template<typename T> struct IsRowMajor : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; + template<typename T> struct is_row_major : internal::conditional<(int(T::Flags)&RowMajorBit), internal::true_type, internal::false_type>::type {}; public: EIGEN_PRODUCT_PUBLIC_INTERFACE(GeneralProduct) @@ -281,22 +281,22 @@ class GeneralProduct<Lhs, Rhs, OuterProduct> template<typename Dest> inline void evalTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, set(), IsRowMajor<Dest>()); + internal::outer_product_selector_run(*this, dest, set(), is_row_major<Dest>()); } template<typename Dest> inline void addTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, add(), IsRowMajor<Dest>()); + internal::outer_product_selector_run(*this, dest, add(), is_row_major<Dest>()); } template<typename Dest> inline void subTo(Dest& dest) const { - internal::outer_product_selector_run(*this, dest, sub(), IsRowMajor<Dest>()); + internal::outer_product_selector_run(*this, dest, sub(), is_row_major<Dest>()); } template<typename Dest> void scaleAndAddTo(Dest& dest, const Scalar& alpha) const { - internal::outer_product_selector_run(*this, dest, adds(alpha), IsRowMajor<Dest>()); + internal::outer_product_selector_run(*this, dest, adds(alpha), is_row_major<Dest>()); } }; diff --git a/extern/Eigen3/Eigen/src/Core/MapBase.h b/extern/Eigen3/Eigen/src/Core/MapBase.h index 6876de588c0..a9828f7f4b2 100644 --- a/extern/Eigen3/Eigen/src/Core/MapBase.h +++ b/extern/Eigen3/Eigen/src/Core/MapBase.h @@ -123,7 +123,7 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors> return internal::ploadt<PacketScalar, LoadMode>(m_data + index * innerStride()); } - inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) + explicit inline MapBase(PointerType dataPtr) : m_data(dataPtr), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) { EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) checkSanity(); @@ -157,7 +157,7 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors> internal::inner_stride_at_compile_time<Derived>::ret==1), PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); eigen_assert(EIGEN_IMPLIES(internal::traits<Derived>::Flags&AlignedBit, (size_t(m_data) % 16) == 0) - && "data is not aligned"); + && "input pointer is not aligned on a 16 byte boundary"); } PointerType m_data; @@ -168,6 +168,7 @@ template<typename Derived> class MapBase<Derived, ReadOnlyAccessors> template<typename Derived> class MapBase<Derived, WriteAccessors> : public MapBase<Derived, ReadOnlyAccessors> { + typedef MapBase<Derived, ReadOnlyAccessors> ReadOnlyMapBase; public: typedef MapBase<Derived, ReadOnlyAccessors> Base; @@ -230,13 +231,17 @@ template<typename Derived> class MapBase<Derived, WriteAccessors> Derived& operator=(const MapBase& other) { - Base::Base::operator=(other); + ReadOnlyMapBase::Base::operator=(other); return derived(); } - using Base::Base::operator=; + // In theory we could simply refer to Base:Base::operator=, but MSVC does not like Base::Base, + // see bugs 821 and 920. + using ReadOnlyMapBase::Base::operator=; }; +#undef EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS + } // end namespace Eigen #endif // EIGEN_MAPBASE_H diff --git a/extern/Eigen3/Eigen/src/Core/MathFunctions.h b/extern/Eigen3/Eigen/src/Core/MathFunctions.h index 2bfc5ebd98a..adf2f9c511b 100644 --- a/extern/Eigen3/Eigen/src/Core/MathFunctions.h +++ b/extern/Eigen3/Eigen/src/Core/MathFunctions.h @@ -294,7 +294,7 @@ struct hypot_impl RealScalar _x = abs(x); RealScalar _y = abs(y); RealScalar p = (max)(_x, _y); - if(p==RealScalar(0)) return 0; + if(p==RealScalar(0)) return RealScalar(0); RealScalar q = (min)(_x, _y); RealScalar qp = q/p; return p * sqrt(RealScalar(1) + qp*qp); diff --git a/extern/Eigen3/Eigen/src/Core/Matrix.h b/extern/Eigen3/Eigen/src/Core/Matrix.h index d7d0b5b9a4f..02be142d8cc 100644 --- a/extern/Eigen3/Eigen/src/Core/Matrix.h +++ b/extern/Eigen3/Eigen/src/Core/Matrix.h @@ -211,6 +211,21 @@ class Matrix : Base(internal::constructor_without_unaligned_array_assert()) { Base::_check_template_params(); EIGEN_INITIALIZE_COEFFS_IF_THAT_OPTION_IS_ENABLED } +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + Matrix(Matrix&& other) + : Base(std::move(other)) + { + Base::_check_template_params(); + if (RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic) + Base::_set_noalias(other); + } + Matrix& operator=(Matrix&& other) + { + other.swap(*this); + return *this; + } +#endif + /** \brief Constructs a vector or row-vector with given dimension. \only_for_vectors * * Note that this is only useful for dynamic-size vectors. For fixed-size vectors, diff --git a/extern/Eigen3/Eigen/src/Core/MatrixBase.h b/extern/Eigen3/Eigen/src/Core/MatrixBase.h index 344b38f2fc7..e83ef4dc056 100644 --- a/extern/Eigen3/Eigen/src/Core/MatrixBase.h +++ b/extern/Eigen3/Eigen/src/Core/MatrixBase.h @@ -159,13 +159,11 @@ template<typename Derived> class MatrixBase template<typename OtherDerived> Derived& operator=(const ReturnByValue<OtherDerived>& other); -#ifndef EIGEN_PARSED_BY_DOXYGEN template<typename ProductDerived, typename Lhs, typename Rhs> Derived& lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other); template<typename MatrixPower, typename Lhs, typename Rhs> Derived& lazyAssign(const MatrixPowerProduct<MatrixPower, Lhs,Rhs>& other); -#endif // not EIGEN_PARSED_BY_DOXYGEN template<typename OtherDerived> Derived& operator+=(const MatrixBase<OtherDerived>& other); @@ -215,7 +213,7 @@ template<typename Derived> class MatrixBase typedef Diagonal<Derived> DiagonalReturnType; DiagonalReturnType diagonal(); - typedef typename internal::add_const<Diagonal<const Derived> >::type ConstDiagonalReturnType; + typedef typename internal::add_const<Diagonal<const Derived> >::type ConstDiagonalReturnType; ConstDiagonalReturnType diagonal() const; template<int Index> struct DiagonalIndexReturnType { typedef Diagonal<Derived,Index> Type; }; @@ -223,16 +221,12 @@ template<typename Derived> class MatrixBase template<int Index> typename DiagonalIndexReturnType<Index>::Type diagonal(); template<int Index> typename ConstDiagonalIndexReturnType<Index>::Type diagonal() const; + + typedef Diagonal<Derived,DynamicIndex> DiagonalDynamicIndexReturnType; + typedef typename internal::add_const<Diagonal<const Derived,DynamicIndex> >::type ConstDiagonalDynamicIndexReturnType; - // Note: The "MatrixBase::" prefixes are added to help MSVC9 to match these declarations with the later implementations. - // On the other hand they confuse MSVC8... - #if (defined _MSC_VER) && (_MSC_VER >= 1500) // 2008 or later - typename MatrixBase::template DiagonalIndexReturnType<DynamicIndex>::Type diagonal(Index index); - typename MatrixBase::template ConstDiagonalIndexReturnType<DynamicIndex>::Type diagonal(Index index) const; - #else - typename DiagonalIndexReturnType<DynamicIndex>::Type diagonal(Index index); - typename ConstDiagonalIndexReturnType<DynamicIndex>::Type diagonal(Index index) const; - #endif + DiagonalDynamicIndexReturnType diagonal(Index index); + ConstDiagonalDynamicIndexReturnType diagonal(Index index) const; #ifdef EIGEN2_SUPPORT template<unsigned int Mode> typename internal::eigen2_part_return_type<Derived, Mode>::type part(); @@ -446,6 +440,15 @@ template<typename Derived> class MatrixBase template<typename OtherScalar> void applyOnTheRight(Index p, Index q, const JacobiRotation<OtherScalar>& j); +///////// SparseCore module ///////// + + template<typename OtherDerived> + EIGEN_STRONG_INLINE const typename SparseMatrixBase<OtherDerived>::template CwiseProductDenseReturnType<Derived>::Type + cwiseProduct(const SparseMatrixBase<OtherDerived> &other) const + { + return other.cwiseProduct(derived()); + } + ///////// MatrixFunctions module ///////// typedef typename internal::stem_function<Scalar>::type StemFunction; diff --git a/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h b/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h index 1297b8413fb..85ffae2653b 100644 --- a/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/PermutationMatrix.h @@ -250,6 +250,35 @@ class PermutationBase : public EigenBase<Derived> template<typename Other> friend inline PlainPermutationType operator*(const Transpose<PermutationBase<Other> >& other, const PermutationBase& perm) { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } + + /** \returns the determinant of the permutation matrix, which is either 1 or -1 depending on the parity of the permutation. + * + * This function is O(\c n) procedure allocating a buffer of \c n booleans. + */ + Index determinant() const + { + Index res = 1; + Index n = size(); + Matrix<bool,RowsAtCompileTime,1,0,MaxRowsAtCompileTime> mask(n); + mask.fill(false); + Index r = 0; + while(r < n) + { + // search for the next seed + while(r<n && mask[r]) r++; + if(r>=n) + break; + // we got one, let's follow it until we are back to the seed + Index k0 = r++; + mask.coeffRef(k0) = true; + for(Index k=indices().coeff(k0); k!=k0; k=indices().coeff(k)) + { + mask.coeffRef(k) = true; + res = -res; + } + } + return res; + } protected: @@ -555,7 +584,10 @@ struct permut_matrix_product_retval const Index n = Side==OnTheLeft ? rows() : cols(); // FIXME we need an is_same for expression that is not sensitive to constness. For instance // is_same_xpr<Block<const Matrix>, Block<Matrix> >::value should be true. - if(is_same<MatrixTypeNestedCleaned,Dest>::value && extract_data(dst) == extract_data(m_matrix)) + if( is_same<MatrixTypeNestedCleaned,Dest>::value + && blas_traits<MatrixTypeNestedCleaned>::HasUsableDirectAccess + && blas_traits<Dest>::HasUsableDirectAccess + && extract_data(dst) == extract_data(m_matrix)) { // apply the permutation inplace Matrix<bool,PermutationType::RowsAtCompileTime,1,0,PermutationType::MaxRowsAtCompileTime> mask(m_permutation.size()); diff --git a/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h b/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h index dd34b59e541..a4e4af4a7b2 100644 --- a/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h +++ b/extern/Eigen3/Eigen/src/Core/PlainObjectBase.h @@ -437,6 +437,36 @@ class PlainObjectBase : public internal::dense_xpr_base<Derived>::type } #endif +#ifdef EIGEN_HAVE_RVALUE_REFERENCES + PlainObjectBase(PlainObjectBase&& other) + : m_storage( std::move(other.m_storage) ) + { + } + + PlainObjectBase& operator=(PlainObjectBase&& other) + { + using std::swap; + swap(m_storage, other.m_storage); + return *this; + } +#endif + + /** Copy constructor */ + EIGEN_STRONG_INLINE PlainObjectBase(const PlainObjectBase& other) + : m_storage() + { + _check_template_params(); + lazyAssign(other); + } + + template<typename OtherDerived> + EIGEN_STRONG_INLINE PlainObjectBase(const DenseBase<OtherDerived> &other) + : m_storage() + { + _check_template_params(); + lazyAssign(other); + } + EIGEN_STRONG_INLINE PlainObjectBase(Index a_size, Index nbRows, Index nbCols) : m_storage(a_size, nbRows, nbCols) { @@ -573,6 +603,8 @@ class PlainObjectBase : public internal::dense_xpr_base<Derived>::type : (rows() == other.rows() && cols() == other.cols()))) && "Size mismatch. Automatic resizing is disabled because EIGEN_NO_AUTOMATIC_RESIZING is defined"); EIGEN_ONLY_USED_FOR_DEBUG(other); + if(this->size()==0) + resizeLike(other); #else resizeLike(other); #endif diff --git a/extern/Eigen3/Eigen/src/Core/ProductBase.h b/extern/Eigen3/Eigen/src/Core/ProductBase.h index a494b5f8703..cf74470a9a1 100644 --- a/extern/Eigen3/Eigen/src/Core/ProductBase.h +++ b/extern/Eigen3/Eigen/src/Core/ProductBase.h @@ -85,7 +85,14 @@ class ProductBase : public MatrixBase<Derived> public: +#ifndef EIGEN_NO_MALLOC + typedef typename Base::PlainObject BasePlainObject; + typedef Matrix<Scalar,RowsAtCompileTime==1?1:Dynamic,ColsAtCompileTime==1?1:Dynamic,BasePlainObject::Options> DynPlainObject; + typedef typename internal::conditional<(BasePlainObject::SizeAtCompileTime==Dynamic) || (BasePlainObject::SizeAtCompileTime*int(sizeof(Scalar)) < int(EIGEN_STACK_ALLOCATION_LIMIT)), + BasePlainObject, DynPlainObject>::type PlainObject; +#else typedef typename Base::PlainObject PlainObject; +#endif ProductBase(const Lhs& a_lhs, const Rhs& a_rhs) : m_lhs(a_lhs), m_rhs(a_rhs) @@ -180,7 +187,12 @@ namespace internal { template<typename Lhs, typename Rhs, int Mode, int N, typename PlainObject> struct nested<GeneralProduct<Lhs,Rhs,Mode>, N, PlainObject> { - typedef PlainObject const& type; + typedef typename GeneralProduct<Lhs,Rhs,Mode>::PlainObject const& type; +}; +template<typename Lhs, typename Rhs, int Mode, int N, typename PlainObject> +struct nested<const GeneralProduct<Lhs,Rhs,Mode>, N, PlainObject> +{ + typedef typename GeneralProduct<Lhs,Rhs,Mode>::PlainObject const& type; }; } diff --git a/extern/Eigen3/Eigen/src/Core/Redux.h b/extern/Eigen3/Eigen/src/Core/Redux.h index 50548fa9a0e..9b8662a6f9a 100644 --- a/extern/Eigen3/Eigen/src/Core/Redux.h +++ b/extern/Eigen3/Eigen/src/Core/Redux.h @@ -247,8 +247,9 @@ struct redux_impl<Func, Derived, LinearVectorizedTraversal, NoUnrolling> } }; -template<typename Func, typename Derived> -struct redux_impl<Func, Derived, SliceVectorizedTraversal, NoUnrolling> +// NOTE: for SliceVectorizedTraversal we simply bypass unrolling +template<typename Func, typename Derived, int Unrolling> +struct redux_impl<Func, Derived, SliceVectorizedTraversal, Unrolling> { typedef typename Derived::Scalar Scalar; typedef typename packet_traits<Scalar>::type PacketScalar; diff --git a/extern/Eigen3/Eigen/src/Core/Ref.h b/extern/Eigen3/Eigen/src/Core/Ref.h index 00d9e6d2b41..7a3becaf882 100644 --- a/extern/Eigen3/Eigen/src/Core/Ref.h +++ b/extern/Eigen3/Eigen/src/Core/Ref.h @@ -101,14 +101,15 @@ struct traits<Ref<_PlainObjectType, _Options, _StrideType> > template<typename Derived> struct match { enum { HasDirectAccess = internal::has_direct_access<Derived>::ret, - StorageOrderMatch = PlainObjectType::IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)), + StorageOrderMatch = PlainObjectType::IsVectorAtCompileTime || Derived::IsVectorAtCompileTime || ((PlainObjectType::Flags&RowMajorBit)==(Derived::Flags&RowMajorBit)), InnerStrideMatch = int(StrideType::InnerStrideAtCompileTime)==int(Dynamic) || int(StrideType::InnerStrideAtCompileTime)==int(Derived::InnerStrideAtCompileTime) || (int(StrideType::InnerStrideAtCompileTime)==0 && int(Derived::InnerStrideAtCompileTime)==1), OuterStrideMatch = Derived::IsVectorAtCompileTime || int(StrideType::OuterStrideAtCompileTime)==int(Dynamic) || int(StrideType::OuterStrideAtCompileTime)==int(Derived::OuterStrideAtCompileTime), AlignmentMatch = (_Options!=Aligned) || ((PlainObjectType::Flags&AlignedBit)==0) || ((traits<Derived>::Flags&AlignedBit)==AlignedBit), - MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch + ScalarTypeMatch = internal::is_same<typename PlainObjectType::Scalar, typename Derived::Scalar>::value, + MatchAtCompileTime = HasDirectAccess && StorageOrderMatch && InnerStrideMatch && OuterStrideMatch && AlignmentMatch && ScalarTypeMatch }; typedef typename internal::conditional<MatchAtCompileTime,internal::true_type,internal::false_type>::type type; }; @@ -172,8 +173,12 @@ protected: } else ::new (static_cast<Base*>(this)) Base(expr.data(), expr.rows(), expr.cols()); - ::new (&m_stride) StrideBase(StrideType::OuterStrideAtCompileTime==0?0:expr.outerStride(), - StrideType::InnerStrideAtCompileTime==0?0:expr.innerStride()); + + if(Expression::IsVectorAtCompileTime && (!PlainObjectType::IsVectorAtCompileTime) && ((Expression::Flags&RowMajorBit)!=(PlainObjectType::Flags&RowMajorBit))) + ::new (&m_stride) StrideBase(expr.innerStride(), StrideType::InnerStrideAtCompileTime==0?0:1); + else + ::new (&m_stride) StrideBase(StrideType::OuterStrideAtCompileTime==0?0:expr.outerStride(), + StrideType::InnerStrideAtCompileTime==0?0:expr.innerStride()); } StrideBase m_stride; @@ -183,7 +188,11 @@ protected: template<typename PlainObjectType, int Options, typename StrideType> class Ref : public RefBase<Ref<PlainObjectType, Options, StrideType> > { + private: typedef internal::traits<Ref> Traits; + template<typename Derived> + inline Ref(const PlainObjectBase<Derived>& expr, + typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0); public: typedef RefBase<Ref> Base; @@ -195,17 +204,20 @@ template<typename PlainObjectType, int Options, typename StrideType> class Ref inline Ref(PlainObjectBase<Derived>& expr, typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0) { - Base::construct(expr); + EIGEN_STATIC_ASSERT(static_cast<bool>(Traits::template match<Derived>::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + Base::construct(expr.derived()); } template<typename Derived> inline Ref(const DenseBase<Derived>& expr, - typename internal::enable_if<bool(internal::is_lvalue<Derived>::value&&bool(Traits::template match<Derived>::MatchAtCompileTime)),Derived>::type* = 0, - int = Derived::ThisConstantIsPrivateInPlainObjectBase) + typename internal::enable_if<bool(Traits::template match<Derived>::MatchAtCompileTime),Derived>::type* = 0) #else template<typename Derived> inline Ref(DenseBase<Derived>& expr) #endif { + EIGEN_STATIC_ASSERT(static_cast<bool>(internal::is_lvalue<Derived>::value), THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY); + EIGEN_STATIC_ASSERT(static_cast<bool>(Traits::template match<Derived>::MatchAtCompileTime), STORAGE_LAYOUT_DOES_NOT_MATCH); + enum { THIS_EXPRESSION_IS_NOT_A_LVALUE__IT_IS_READ_ONLY = Derived::ThisConstantIsPrivateInPlainObjectBase}; Base::construct(expr.const_cast_derived()); } @@ -224,13 +236,23 @@ template<typename TPlainObjectType, int Options, typename StrideType> class Ref< EIGEN_DENSE_PUBLIC_INTERFACE(Ref) template<typename Derived> - inline Ref(const DenseBase<Derived>& expr) + inline Ref(const DenseBase<Derived>& expr, + typename internal::enable_if<bool(Traits::template match<Derived>::ScalarTypeMatch),Derived>::type* = 0) { // std::cout << match_helper<Derived>::HasDirectAccess << "," << match_helper<Derived>::OuterStrideMatch << "," << match_helper<Derived>::InnerStrideMatch << "\n"; // std::cout << int(StrideType::OuterStrideAtCompileTime) << " - " << int(Derived::OuterStrideAtCompileTime) << "\n"; // std::cout << int(StrideType::InnerStrideAtCompileTime) << " - " << int(Derived::InnerStrideAtCompileTime) << "\n"; construct(expr.derived(), typename Traits::template match<Derived>::type()); } + + inline Ref(const Ref& other) : Base(other) { + // copy constructor shall not copy the m_object, to avoid unnecessary malloc and copy + } + + template<typename OtherRef> + inline Ref(const RefBase<OtherRef>& other) { + construct(other.derived(), typename Traits::template match<OtherRef>::type()); + } protected: diff --git a/extern/Eigen3/Eigen/src/Core/Replicate.h b/extern/Eigen3/Eigen/src/Core/Replicate.h index dde86a8349b..ac4537c1422 100644 --- a/extern/Eigen3/Eigen/src/Core/Replicate.h +++ b/extern/Eigen3/Eigen/src/Core/Replicate.h @@ -135,7 +135,7 @@ template<typename MatrixType,int RowFactor,int ColFactor> class Replicate */ template<typename Derived> template<int RowFactor, int ColFactor> -inline const Replicate<Derived,RowFactor,ColFactor> +const Replicate<Derived,RowFactor,ColFactor> DenseBase<Derived>::replicate() const { return Replicate<Derived,RowFactor,ColFactor>(derived()); @@ -150,7 +150,7 @@ DenseBase<Derived>::replicate() const * \sa VectorwiseOp::replicate(), DenseBase::replicate<int,int>(), class Replicate */ template<typename Derived> -inline const Replicate<Derived,Dynamic,Dynamic> +const typename DenseBase<Derived>::ReplicateReturnType DenseBase<Derived>::replicate(Index rowFactor,Index colFactor) const { return Replicate<Derived,Dynamic,Dynamic>(derived(),rowFactor,colFactor); diff --git a/extern/Eigen3/Eigen/src/Core/ReturnByValue.h b/extern/Eigen3/Eigen/src/Core/ReturnByValue.h index d66c24ba0f8..f635598dccf 100644 --- a/extern/Eigen3/Eigen/src/Core/ReturnByValue.h +++ b/extern/Eigen3/Eigen/src/Core/ReturnByValue.h @@ -72,6 +72,8 @@ template<typename Derived> class ReturnByValue const Unusable& coeff(Index,Index) const { return *reinterpret_cast<const Unusable*>(this); } Unusable& coeffRef(Index) { return *reinterpret_cast<Unusable*>(this); } Unusable& coeffRef(Index,Index) { return *reinterpret_cast<Unusable*>(this); } + template<int LoadMode> Unusable& packet(Index) const; + template<int LoadMode> Unusable& packet(Index, Index) const; #endif }; @@ -83,6 +85,15 @@ Derived& DenseBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other) return derived(); } +template<typename Derived> +template<typename OtherDerived> +Derived& DenseBase<Derived>::lazyAssign(const ReturnByValue<OtherDerived>& other) +{ + other.evalTo(derived()); + return derived(); +} + + } // end namespace Eigen #endif // EIGEN_RETURNBYVALUE_H diff --git a/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h b/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h index 22f3047b43f..0956475af51 100644 --- a/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h +++ b/extern/Eigen3/Eigen/src/Core/SelfCwiseBinaryOp.h @@ -180,15 +180,9 @@ inline Derived& DenseBase<Derived>::operator*=(const Scalar& other) template<typename Derived> inline Derived& DenseBase<Derived>::operator/=(const Scalar& other) { - typedef typename internal::conditional<NumTraits<Scalar>::IsInteger, - internal::scalar_quotient_op<Scalar>, - internal::scalar_product_op<Scalar> >::type BinOp; typedef typename Derived::PlainObject PlainObject; - SelfCwiseBinaryOp<BinOp, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); - Scalar actual_other; - if(NumTraits<Scalar>::IsInteger) actual_other = other; - else actual_other = Scalar(1)/other; - tmp = PlainObject::Constant(rows(),cols(), actual_other); + SelfCwiseBinaryOp<internal::scalar_quotient_op<Scalar>, Derived, typename PlainObject::ConstantReturnType> tmp(derived()); + tmp = PlainObject::Constant(rows(),cols(), other); return derived(); } diff --git a/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h b/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h index fba07365f6f..4d65392c685 100644 --- a/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/TriangularMatrix.h @@ -278,21 +278,21 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularView /** Efficient triangular matrix times vector/matrix product */ template<typename OtherDerived> - TriangularProduct<Mode,true,MatrixType,false,OtherDerived, OtherDerived::IsVectorAtCompileTime> + TriangularProduct<Mode, true, MatrixType, false, OtherDerived, OtherDerived::ColsAtCompileTime==1> operator*(const MatrixBase<OtherDerived>& rhs) const { return TriangularProduct - <Mode,true,MatrixType,false,OtherDerived,OtherDerived::IsVectorAtCompileTime> + <Mode, true, MatrixType, false, OtherDerived, OtherDerived::ColsAtCompileTime==1> (m_matrix, rhs.derived()); } /** Efficient vector/matrix times triangular matrix product */ template<typename OtherDerived> friend - TriangularProduct<Mode,false,OtherDerived,OtherDerived::IsVectorAtCompileTime,MatrixType,false> + TriangularProduct<Mode, false, OtherDerived, OtherDerived::RowsAtCompileTime==1, MatrixType, false> operator*(const MatrixBase<OtherDerived>& lhs, const TriangularView& rhs) { return TriangularProduct - <Mode,false,OtherDerived,OtherDerived::IsVectorAtCompileTime,MatrixType,false> + <Mode, false, OtherDerived, OtherDerived::RowsAtCompileTime==1, MatrixType, false> (lhs.derived(),rhs.m_matrix); } @@ -380,19 +380,19 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularView EIGEN_STRONG_INLINE TriangularView& operator=(const ProductBase<ProductDerived, Lhs,Rhs>& other) { setZero(); - return assignProduct(other,1); + return assignProduct(other.derived(),1); } template<typename ProductDerived, typename Lhs, typename Rhs> EIGEN_STRONG_INLINE TriangularView& operator+=(const ProductBase<ProductDerived, Lhs,Rhs>& other) { - return assignProduct(other,1); + return assignProduct(other.derived(),1); } template<typename ProductDerived, typename Lhs, typename Rhs> EIGEN_STRONG_INLINE TriangularView& operator-=(const ProductBase<ProductDerived, Lhs,Rhs>& other) { - return assignProduct(other,-1); + return assignProduct(other.derived(),-1); } @@ -400,25 +400,34 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularView EIGEN_STRONG_INLINE TriangularView& operator=(const ScaledProduct<ProductDerived>& other) { setZero(); - return assignProduct(other,other.alpha()); + return assignProduct(other.derived(),other.alpha()); } template<typename ProductDerived> EIGEN_STRONG_INLINE TriangularView& operator+=(const ScaledProduct<ProductDerived>& other) { - return assignProduct(other,other.alpha()); + return assignProduct(other.derived(),other.alpha()); } template<typename ProductDerived> EIGEN_STRONG_INLINE TriangularView& operator-=(const ScaledProduct<ProductDerived>& other) { - return assignProduct(other,-other.alpha()); + return assignProduct(other.derived(),-other.alpha()); } protected: template<typename ProductDerived, typename Lhs, typename Rhs> EIGEN_STRONG_INLINE TriangularView& assignProduct(const ProductBase<ProductDerived, Lhs,Rhs>& prod, const Scalar& alpha); + + template<int Mode, bool LhsIsTriangular, + typename Lhs, bool LhsIsVector, + typename Rhs, bool RhsIsVector> + EIGEN_STRONG_INLINE TriangularView& assignProduct(const TriangularProduct<Mode, LhsIsTriangular, Lhs, LhsIsVector, Rhs, RhsIsVector>& prod, const Scalar& alpha) + { + lazyAssign(alpha*prod.eval()); + return *this; + } MatrixTypeNested m_matrix; }; diff --git a/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h b/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h index f183d31de2a..8d9255eef6a 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h +++ b/extern/Eigen3/Eigen/src/Core/arch/NEON/Complex.h @@ -110,7 +110,7 @@ template<> EIGEN_STRONG_INLINE Packet2cf ploaddup<Packet2cf>(const std::complex< template<> EIGEN_STRONG_INLINE void pstore <std::complex<float> >(std::complex<float> * to, const Packet2cf& from) { EIGEN_DEBUG_ALIGNED_STORE pstore((float*)to, from.v); } template<> EIGEN_STRONG_INLINE void pstoreu<std::complex<float> >(std::complex<float> * to, const Packet2cf& from) { EIGEN_DEBUG_UNALIGNED_STORE pstoreu((float*)to, from.v); } -template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> * addr) { __pld((float *)addr); } +template<> EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float> * addr) { EIGEN_ARM_PREFETCH((float *)addr); } template<> EIGEN_STRONG_INLINE std::complex<float> pfirst<Packet2cf>(const Packet2cf& a) { diff --git a/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h b/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h index 163bac215e6..d49670e0410 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h +++ b/extern/Eigen3/Eigen/src/Core/arch/NEON/PacketMath.h @@ -48,9 +48,18 @@ typedef uint32x4_t Packet4ui; #define EIGEN_INIT_NEON_PACKET2(X, Y) {X, Y} #define EIGEN_INIT_NEON_PACKET4(X, Y, Z, W) {X, Y, Z, W} #endif - -#ifndef __pld -#define __pld(x) asm volatile ( " pld [%[addr]]\n" :: [addr] "r" (x) : "cc" ); + +// arm64 does have the pld instruction. If available, let's trust the __builtin_prefetch built-in function +// which available on LLVM and GCC (at least) +#if EIGEN_HAS_BUILTIN(__builtin_prefetch) || defined(__GNUC__) + #define EIGEN_ARM_PREFETCH(ADDR) __builtin_prefetch(ADDR); +#elif defined __pld + #define EIGEN_ARM_PREFETCH(ADDR) __pld(ADDR) +#elif !defined(__aarch64__) + #define EIGEN_ARM_PREFETCH(ADDR) __asm__ __volatile__ ( " pld [%[addr]]\n" :: [addr] "r" (ADDR) : "cc" ); +#else + // by default no explicit prefetching + #define EIGEN_ARM_PREFETCH(ADDR) #endif template<> struct packet_traits<float> : default_packet_traits @@ -209,8 +218,8 @@ template<> EIGEN_STRONG_INLINE void pstore<int>(int* to, const Packet4i& f template<> EIGEN_STRONG_INLINE void pstoreu<float>(float* to, const Packet4f& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_f32(to, from); } template<> EIGEN_STRONG_INLINE void pstoreu<int>(int* to, const Packet4i& from) { EIGEN_DEBUG_UNALIGNED_STORE vst1q_s32(to, from); } -template<> EIGEN_STRONG_INLINE void prefetch<float>(const float* addr) { __pld(addr); } -template<> EIGEN_STRONG_INLINE void prefetch<int>(const int* addr) { __pld(addr); } +template<> EIGEN_STRONG_INLINE void prefetch<float>(const float* addr) { EIGEN_ARM_PREFETCH(addr); } +template<> EIGEN_STRONG_INLINE void prefetch<int>(const int* addr) { EIGEN_ARM_PREFETCH(addr); } // FIXME only store the 2 first elements ? template<> EIGEN_STRONG_INLINE float pfirst<Packet4f>(const Packet4f& a) { float EIGEN_ALIGN16 x[4]; vst1q_f32(x, a); return x[0]; } @@ -375,6 +384,7 @@ template<> EIGEN_STRONG_INLINE int predux_max<Packet4i>(const Packet4i& a) a_lo = vget_low_s32(a); a_hi = vget_high_s32(a); max = vpmax_s32(a_lo, a_hi); + max = vpmax_s32(max, max); return vget_lane_s32(max, 0); } diff --git a/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h b/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h index 99cbd0d95be..2b07168ae4f 100644 --- a/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h +++ b/extern/Eigen3/Eigen/src/Core/arch/SSE/MathFunctions.h @@ -52,7 +52,7 @@ Packet4f plog<Packet4f>(const Packet4f& _x) Packet4i emm0; - Packet4f invalid_mask = _mm_cmplt_ps(x, _mm_setzero_ps()); + Packet4f invalid_mask = _mm_cmpnge_ps(x, _mm_setzero_ps()); // not greater equal is true if x is NaN Packet4f iszero_mask = _mm_cmpeq_ps(x, _mm_setzero_ps()); x = pmax(x, p4f_min_norm_pos); /* cut off denormalized stuff */ @@ -126,7 +126,7 @@ Packet4f pexp<Packet4f>(const Packet4f& _x) _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p4, 1.6666665459E-1f); _EIGEN_DECLARE_CONST_Packet4f(cephes_exp_p5, 5.0000001201E-1f); - Packet4f tmp = _mm_setzero_ps(), fx; + Packet4f tmp, fx; Packet4i emm0; // clamp x @@ -166,7 +166,7 @@ Packet4f pexp<Packet4f>(const Packet4f& _x) emm0 = _mm_cvttps_epi32(fx); emm0 = _mm_add_epi32(emm0, p4i_0x7f); emm0 = _mm_slli_epi32(emm0, 23); - return pmul(y, _mm_castsi128_ps(emm0)); + return pmax(pmul(y, Packet4f(_mm_castsi128_ps(emm0))), _x); } template<> EIGEN_DEFINE_FUNCTION_ALLOWING_MULTIPLE_DEFINITIONS EIGEN_UNUSED Packet2d pexp<Packet2d>(const Packet2d& _x) @@ -195,7 +195,7 @@ Packet2d pexp<Packet2d>(const Packet2d& _x) _EIGEN_DECLARE_CONST_Packet2d(cephes_exp_C2, 1.42860682030941723212e-6); static const __m128i p4i_1023_0 = _mm_setr_epi32(1023, 1023, 0, 0); - Packet2d tmp = _mm_setzero_pd(), fx; + Packet2d tmp, fx; Packet4i emm0; // clamp x @@ -239,7 +239,7 @@ Packet2d pexp<Packet2d>(const Packet2d& _x) emm0 = _mm_add_epi32(emm0, p4i_1023_0); emm0 = _mm_slli_epi32(emm0, 20); emm0 = _mm_shuffle_epi32(emm0, _MM_SHUFFLE(1,2,0,3)); - return pmul(x, _mm_castsi128_pd(emm0)); + return pmax(pmul(x, Packet2d(_mm_castsi128_pd(emm0))), _x); } /* evaluation of 4 sines at onces, using SSE2 intrinsics. @@ -279,7 +279,7 @@ Packet4f psin<Packet4f>(const Packet4f& _x) _EIGEN_DECLARE_CONST_Packet4f(coscof_p2, 4.166664568298827E-002f); _EIGEN_DECLARE_CONST_Packet4f(cephes_FOPI, 1.27323954473516f); // 4 / M_PI - Packet4f xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y; + Packet4f xmm1, xmm2, xmm3, sign_bit, y; Packet4i emm0, emm2; sign_bit = x; @@ -378,7 +378,7 @@ Packet4f pcos<Packet4f>(const Packet4f& _x) _EIGEN_DECLARE_CONST_Packet4f(coscof_p2, 4.166664568298827E-002f); _EIGEN_DECLARE_CONST_Packet4f(cephes_FOPI, 1.27323954473516f); // 4 / M_PI - Packet4f xmm1, xmm2 = _mm_setzero_ps(), xmm3, y; + Packet4f xmm1, xmm2, xmm3, y; Packet4i emm0, emm2; x = pabs(x); diff --git a/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h b/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h index c06a0df1c21..2a9d65b9473 100644 --- a/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/extern/Eigen3/Eigen/src/Core/products/CoeffBasedProduct.h @@ -90,6 +90,7 @@ struct traits<CoeffBasedProduct<LhsNested,RhsNested,NestingFlags> > | (SameType && (CanVectorizeLhs || CanVectorizeRhs) ? PacketAccessBit : 0), CoeffReadCost = InnerSize == Dynamic ? Dynamic + : InnerSize == 0 ? 0 : InnerSize * (NumTraits<Scalar>::MulCost + LhsCoeffReadCost + RhsCoeffReadCost) + (InnerSize - 1) * NumTraits<Scalar>::AddCost, @@ -133,7 +134,7 @@ class CoeffBasedProduct }; typedef internal::product_coeff_impl<CanVectorizeInner ? InnerVectorizedTraversal : DefaultTraversal, - Unroll ? InnerSize-1 : Dynamic, + Unroll ? InnerSize : Dynamic, _LhsNested, _RhsNested, Scalar> ScalarCoeffImpl; typedef CoeffBasedProduct<LhsNested,RhsNested,NestByRefBit> LazyCoeffBasedProductType; @@ -184,7 +185,7 @@ class CoeffBasedProduct { PacketScalar res; internal::product_packet_impl<Flags&RowMajorBit ? RowMajor : ColMajor, - Unroll ? InnerSize-1 : Dynamic, + Unroll ? InnerSize : Dynamic, _LhsNested, _RhsNested, PacketScalar, LoadMode> ::run(row, col, m_lhs, m_rhs, res); return res; @@ -242,12 +243,12 @@ struct product_coeff_impl<DefaultTraversal, UnrollingIndex, Lhs, Rhs, RetScalar> static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) { product_coeff_impl<DefaultTraversal, UnrollingIndex-1, Lhs, Rhs, RetScalar>::run(row, col, lhs, rhs, res); - res += lhs.coeff(row, UnrollingIndex) * rhs.coeff(UnrollingIndex, col); + res += lhs.coeff(row, UnrollingIndex-1) * rhs.coeff(UnrollingIndex-1, col); } }; template<typename Lhs, typename Rhs, typename RetScalar> -struct product_coeff_impl<DefaultTraversal, 0, Lhs, Rhs, RetScalar> +struct product_coeff_impl<DefaultTraversal, 1, Lhs, Rhs, RetScalar> { typedef typename Lhs::Index Index; static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) @@ -257,15 +258,22 @@ struct product_coeff_impl<DefaultTraversal, 0, Lhs, Rhs, RetScalar> }; template<typename Lhs, typename Rhs, typename RetScalar> +struct product_coeff_impl<DefaultTraversal, 0, Lhs, Rhs, RetScalar> +{ + typedef typename Lhs::Index Index; + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, RetScalar &res) + { + res = RetScalar(0); + } +}; + +template<typename Lhs, typename Rhs, typename RetScalar> struct product_coeff_impl<DefaultTraversal, Dynamic, Lhs, Rhs, RetScalar> { typedef typename Lhs::Index Index; static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar& res) { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = lhs.coeff(row, 0) * rhs.coeff(0, col); - for(Index i = 1; i < lhs.cols(); ++i) - res += lhs.coeff(row, i) * rhs.coeff(i, col); + res = (lhs.row(row).transpose().cwiseProduct( rhs.col(col) )).sum(); } }; @@ -295,6 +303,16 @@ struct product_coeff_vectorized_unroller<0, Lhs, Rhs, Packet> } }; +template<typename Lhs, typename Rhs, typename RetScalar> +struct product_coeff_impl<InnerVectorizedTraversal, 0, Lhs, Rhs, RetScalar> +{ + typedef typename Lhs::Index Index; + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, RetScalar &res) + { + res = 0; + } +}; + template<int UnrollingIndex, typename Lhs, typename Rhs, typename RetScalar> struct product_coeff_impl<InnerVectorizedTraversal, UnrollingIndex, Lhs, Rhs, RetScalar> { @@ -304,8 +322,7 @@ struct product_coeff_impl<InnerVectorizedTraversal, UnrollingIndex, Lhs, Rhs, Re static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, RetScalar &res) { Packet pres; - product_coeff_vectorized_unroller<UnrollingIndex+1-PacketSize, Lhs, Rhs, Packet>::run(row, col, lhs, rhs, pres); - product_coeff_impl<DefaultTraversal,UnrollingIndex,Lhs,Rhs,RetScalar>::run(row, col, lhs, rhs, res); + product_coeff_vectorized_unroller<UnrollingIndex-PacketSize, Lhs, Rhs, Packet>::run(row, col, lhs, rhs, pres); res = predux(pres); } }; @@ -373,7 +390,7 @@ struct product_packet_impl<RowMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode> static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) { product_packet_impl<RowMajor, UnrollingIndex-1, Lhs, Rhs, Packet, LoadMode>::run(row, col, lhs, rhs, res); - res = pmadd(pset1<Packet>(lhs.coeff(row, UnrollingIndex)), rhs.template packet<LoadMode>(UnrollingIndex, col), res); + res = pmadd(pset1<Packet>(lhs.coeff(row, UnrollingIndex-1)), rhs.template packet<LoadMode>(UnrollingIndex-1, col), res); } }; @@ -384,12 +401,12 @@ struct product_packet_impl<ColMajor, UnrollingIndex, Lhs, Rhs, Packet, LoadMode> static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) { product_packet_impl<ColMajor, UnrollingIndex-1, Lhs, Rhs, Packet, LoadMode>::run(row, col, lhs, rhs, res); - res = pmadd(lhs.template packet<LoadMode>(row, UnrollingIndex), pset1<Packet>(rhs.coeff(UnrollingIndex, col)), res); + res = pmadd(lhs.template packet<LoadMode>(row, UnrollingIndex-1), pset1<Packet>(rhs.coeff(UnrollingIndex-1, col)), res); } }; template<typename Lhs, typename Rhs, typename Packet, int LoadMode> -struct product_packet_impl<RowMajor, 0, Lhs, Rhs, Packet, LoadMode> +struct product_packet_impl<RowMajor, 1, Lhs, Rhs, Packet, LoadMode> { typedef typename Lhs::Index Index; static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) @@ -399,7 +416,7 @@ struct product_packet_impl<RowMajor, 0, Lhs, Rhs, Packet, LoadMode> }; template<typename Lhs, typename Rhs, typename Packet, int LoadMode> -struct product_packet_impl<ColMajor, 0, Lhs, Rhs, Packet, LoadMode> +struct product_packet_impl<ColMajor, 1, Lhs, Rhs, Packet, LoadMode> { typedef typename Lhs::Index Index; static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet &res) @@ -409,15 +426,34 @@ struct product_packet_impl<ColMajor, 0, Lhs, Rhs, Packet, LoadMode> }; template<typename Lhs, typename Rhs, typename Packet, int LoadMode> +struct product_packet_impl<RowMajor, 0, Lhs, Rhs, Packet, LoadMode> +{ + typedef typename Lhs::Index Index; + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Packet &res) + { + res = pset1<Packet>(0); + } +}; + +template<typename Lhs, typename Rhs, typename Packet, int LoadMode> +struct product_packet_impl<ColMajor, 0, Lhs, Rhs, Packet, LoadMode> +{ + typedef typename Lhs::Index Index; + static EIGEN_STRONG_INLINE void run(Index /*row*/, Index /*col*/, const Lhs& /*lhs*/, const Rhs& /*rhs*/, Packet &res) + { + res = pset1<Packet>(0); + } +}; + +template<typename Lhs, typename Rhs, typename Packet, int LoadMode> struct product_packet_impl<RowMajor, Dynamic, Lhs, Rhs, Packet, LoadMode> { typedef typename Lhs::Index Index; static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = pmul(pset1<Packet>(lhs.coeff(row, 0)),rhs.template packet<LoadMode>(0, col)); - for(Index i = 1; i < lhs.cols(); ++i) - res = pmadd(pset1<Packet>(lhs.coeff(row, i)), rhs.template packet<LoadMode>(i, col), res); + res = pset1<Packet>(0); + for(Index i = 0; i < lhs.cols(); ++i) + res = pmadd(pset1<Packet>(lhs.coeff(row, i)), rhs.template packet<LoadMode>(i, col), res); } }; @@ -427,10 +463,9 @@ struct product_packet_impl<ColMajor, Dynamic, Lhs, Rhs, Packet, LoadMode> typedef typename Lhs::Index Index; static EIGEN_STRONG_INLINE void run(Index row, Index col, const Lhs& lhs, const Rhs& rhs, Packet& res) { - eigen_assert(lhs.cols()>0 && "you are using a non initialized matrix"); - res = pmul(lhs.template packet<LoadMode>(row, 0), pset1<Packet>(rhs.coeff(0, col))); - for(Index i = 1; i < lhs.cols(); ++i) - res = pmadd(lhs.template packet<LoadMode>(row, i), pset1<Packet>(rhs.coeff(i, col)), res); + res = pset1<Packet>(0); + for(Index i = 0; i < lhs.cols(); ++i) + res = pmadd(lhs.template packet<LoadMode>(row, i), pset1<Packet>(rhs.coeff(i, col)), res); } }; diff --git a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h index 3f5ffcf51c7..a36c7c7a61c 100644 --- a/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -140,8 +140,14 @@ static void run(Index rows, Index cols, Index depth, // Release all the sub blocks B'_j of B' for the current thread, // i.e., we simply decrement the number of users by 1 for(Index j=0; j<threads; ++j) + { #pragma omp atomic +#if defined(_MSC_VER) && _MSC_VER >= 1900 + (info[j].users) -= 1; +#else --(info[j].users); +#endif + } } } else diff --git a/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h b/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h index 5c3e9b7ac15..6937ee33284 100644 --- a/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h +++ b/extern/Eigen3/Eigen/src/Core/products/Parallelizer.h @@ -125,19 +125,22 @@ void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpos if(transpose) std::swap(rows,cols); - Index blockCols = (cols / threads) & ~Index(0x3); - Index blockRows = (rows / threads) & ~Index(0x7); - GemmParallelInfo<Index>* info = new GemmParallelInfo<Index>[threads]; - #pragma omp parallel for schedule(static,1) num_threads(threads) - for(Index i=0; i<threads; ++i) + #pragma omp parallel num_threads(threads) { + Index i = omp_get_thread_num(); + // Note that the actual number of threads might be lower than the number of request ones. + Index actual_threads = omp_get_num_threads(); + + Index blockCols = (cols / actual_threads) & ~Index(0x3); + Index blockRows = (rows / actual_threads) & ~Index(0x7); + Index r0 = i*blockRows; - Index actualBlockRows = (i+1==threads) ? rows-r0 : blockRows; + Index actualBlockRows = (i+1==actual_threads) ? rows-r0 : blockRows; Index c0 = i*blockCols; - Index actualBlockCols = (i+1==threads) ? cols-c0 : blockCols; + Index actualBlockCols = (i+1==actual_threads) ? cols-c0 : blockCols; info[i].rhs_start = c0; info[i].rhs_length = actualBlockCols; diff --git a/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h index ba41a1c99f6..4cc56a42fd5 100644 --- a/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h +++ b/extern/Eigen3/Eigen/src/Core/products/TriangularMatrixMatrix_MKL.h @@ -109,7 +109,7 @@ struct product_triangular_matrix_matrix_trmm<EIGTYPE,Index,Mode,true, \ /* Non-square case - doesn't fit to MKL ?TRMM. Fall to default triangular product or call MKL ?GEMM*/ \ if (rows != depth) { \ \ - int nthr = mkl_domain_get_max_threads(MKL_BLAS); \ + int nthr = mkl_domain_get_max_threads(EIGEN_MKL_DOMAIN_BLAS); \ \ if (((nthr==1) && (((std::max)(rows,depth)-diagSize)/(double)diagSize < 0.5))) { \ /* Most likely no benefit to call TRMM or GEMM from MKL*/ \ @@ -223,7 +223,7 @@ struct product_triangular_matrix_matrix_trmm<EIGTYPE,Index,Mode,false, \ /* Non-square case - doesn't fit to MKL ?TRMM. Fall to default triangular product or call MKL ?GEMM*/ \ if (cols != depth) { \ \ - int nthr = mkl_domain_get_max_threads(MKL_BLAS); \ + int nthr = mkl_domain_get_max_threads(EIGEN_MKL_DOMAIN_BLAS); \ \ if ((nthr==1) && (((std::max)(cols,depth)-diagSize)/(double)diagSize < 0.5)) { \ /* Most likely no benefit to call TRMM or GEMM from MKL*/ \ diff --git a/extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h b/extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h index f103eae72c0..04240ab5032 100644 --- a/extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h +++ b/extern/Eigen3/Eigen/src/Core/products/TriangularSolverMatrix.h @@ -302,9 +302,12 @@ EIGEN_DONT_INLINE void triangular_solve_matrix<Scalar,Index,OnTheRight,Mode,Conj for (Index i=0; i<actual_mc; ++i) r[i] -= a[i] * b; } - Scalar b = (Mode & UnitDiag) ? Scalar(1) : Scalar(1)/conj(rhs(j,j)); - for (Index i=0; i<actual_mc; ++i) - r[i] *= b; + if((Mode & UnitDiag)==0) + { + Scalar b = conj(rhs(j,j)); + for (Index i=0; i<actual_mc; ++i) + r[i] /= b; + } } // pack the just computed part of lhs to A diff --git a/extern/Eigen3/Eigen/src/Core/util/Constants.h b/extern/Eigen3/Eigen/src/Core/util/Constants.h index 14b9624e1d9..1e6277c4f96 100644 --- a/extern/Eigen3/Eigen/src/Core/util/Constants.h +++ b/extern/Eigen3/Eigen/src/Core/util/Constants.h @@ -433,6 +433,19 @@ struct MatrixXpr {}; /** The type used to identify an array expression */ struct ArrayXpr {}; +namespace internal { + /** \internal + * Constants for comparison functors + */ + enum ComparisonName { + cmp_EQ = 0, + cmp_LT = 1, + cmp_LE = 2, + cmp_UNORD = 3, + cmp_NEQ = 4 + }; +} + } // end namespace Eigen #endif // EIGEN_CONSTANTS_H diff --git a/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h b/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h index d6a814586d3..f277720077b 100644 --- a/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h +++ b/extern/Eigen3/Eigen/src/Core/util/ForwardDeclarations.h @@ -235,6 +235,9 @@ template<typename Scalar> class Rotation2D; template<typename Scalar> class AngleAxis; template<typename Scalar,int Dim> class Translation; +// Sparse module: +template<typename Derived> class SparseMatrixBase; + #ifdef EIGEN2_SUPPORT template<typename Derived, int _Dim> class eigen2_RotationBase; template<typename Lhs, typename Rhs> class eigen2_Cross; diff --git a/extern/Eigen3/Eigen/src/Core/util/MKL_support.h b/extern/Eigen3/Eigen/src/Core/util/MKL_support.h index 1e6e355d626..1ef3b61db14 100644 --- a/extern/Eigen3/Eigen/src/Core/util/MKL_support.h +++ b/extern/Eigen3/Eigen/src/Core/util/MKL_support.h @@ -54,11 +54,60 @@ #endif #if defined EIGEN_USE_MKL +# include <mkl.h> +/*Check IMKL version for compatibility: < 10.3 is not usable with Eigen*/ +# ifndef INTEL_MKL_VERSION +# undef EIGEN_USE_MKL /* INTEL_MKL_VERSION is not even defined on older versions */ +# elif INTEL_MKL_VERSION < 100305 /* the intel-mkl-103-release-notes say this was when the lapacke.h interface was added*/ +# undef EIGEN_USE_MKL +# endif +# ifndef EIGEN_USE_MKL + /*If the MKL version is too old, undef everything*/ +# undef EIGEN_USE_MKL_ALL +# undef EIGEN_USE_BLAS +# undef EIGEN_USE_LAPACKE +# undef EIGEN_USE_MKL_VML +# undef EIGEN_USE_LAPACKE_STRICT +# undef EIGEN_USE_LAPACKE +# endif +#endif -#include <mkl.h> +#if defined EIGEN_USE_MKL #include <mkl_lapacke.h> #define EIGEN_MKL_VML_THRESHOLD 128 +/* MKL_DOMAIN_BLAS, etc are defined only in 10.3 update 7 */ +/* MKL_BLAS, etc are not defined in 11.2 */ +#ifdef MKL_DOMAIN_ALL +#define EIGEN_MKL_DOMAIN_ALL MKL_DOMAIN_ALL +#else +#define EIGEN_MKL_DOMAIN_ALL MKL_ALL +#endif + +#ifdef MKL_DOMAIN_BLAS +#define EIGEN_MKL_DOMAIN_BLAS MKL_DOMAIN_BLAS +#else +#define EIGEN_MKL_DOMAIN_BLAS MKL_BLAS +#endif + +#ifdef MKL_DOMAIN_FFT +#define EIGEN_MKL_DOMAIN_FFT MKL_DOMAIN_FFT +#else +#define EIGEN_MKL_DOMAIN_FFT MKL_FFT +#endif + +#ifdef MKL_DOMAIN_VML +#define EIGEN_MKL_DOMAIN_VML MKL_DOMAIN_VML +#else +#define EIGEN_MKL_DOMAIN_VML MKL_VML +#endif + +#ifdef MKL_DOMAIN_PARDISO +#define EIGEN_MKL_DOMAIN_PARDISO MKL_DOMAIN_PARDISO +#else +#define EIGEN_MKL_DOMAIN_PARDISO MKL_PARDISO +#endif + namespace Eigen { typedef std::complex<double> dcomplex; diff --git a/extern/Eigen3/Eigen/src/Core/util/Macros.h b/extern/Eigen3/Eigen/src/Core/util/Macros.h index 0088621acf7..53fb5fae420 100644 --- a/extern/Eigen3/Eigen/src/Core/util/Macros.h +++ b/extern/Eigen3/Eigen/src/Core/util/Macros.h @@ -13,7 +13,7 @@ #define EIGEN_WORLD_VERSION 3 #define EIGEN_MAJOR_VERSION 2 -#define EIGEN_MINOR_VERSION 1 +#define EIGEN_MINOR_VERSION 7 #define EIGEN_VERSION_AT_LEAST(x,y,z) (EIGEN_WORLD_VERSION>x || (EIGEN_WORLD_VERSION>=x && \ (EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \ @@ -96,6 +96,27 @@ #define EIGEN_DEFAULT_DENSE_INDEX_TYPE std::ptrdiff_t #endif +// A Clang feature extension to determine compiler features. +// We use it to determine 'cxx_rvalue_references' +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +// Do we support r-value references? +#if (__has_feature(cxx_rvalue_references) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__) || \ + (defined(_MSC_VER) && _MSC_VER >= 1600)) + #define EIGEN_HAVE_RVALUE_REFERENCES +#endif + + +// Cross compiler wrapper around LLVM's __has_builtin +#ifdef __has_builtin +# define EIGEN_HAS_BUILTIN(x) __has_builtin(x) +#else +# define EIGEN_HAS_BUILTIN(x) 0 +#endif + /** Allows to disable some optimizations which might affect the accuracy of the result. * Such optimization are enabled by default, and set EIGEN_FAST_MATH to 0 to disable them. * They currently include: @@ -247,7 +268,7 @@ namespace Eigen { #if !defined(EIGEN_ASM_COMMENT) #if (defined __GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) - #define EIGEN_ASM_COMMENT(X) asm("#" X) + #define EIGEN_ASM_COMMENT(X) __asm__("#" X) #else #define EIGEN_ASM_COMMENT(X) #endif @@ -271,6 +292,7 @@ namespace Eigen { #error Please tell me what is the equivalent of __attribute__((aligned(n))) for your compiler #endif +#define EIGEN_ALIGN8 EIGEN_ALIGN_TO_BOUNDARY(8) #define EIGEN_ALIGN16 EIGEN_ALIGN_TO_BOUNDARY(16) #if EIGEN_ALIGN_STATICALLY @@ -289,7 +311,8 @@ namespace Eigen { #endif #ifndef EIGEN_STACK_ALLOCATION_LIMIT -#define EIGEN_STACK_ALLOCATION_LIMIT 20000 +// 131072 == 128 KB +#define EIGEN_STACK_ALLOCATION_LIMIT 131072 #endif #ifndef EIGEN_DEFAULT_IO_FORMAT @@ -305,7 +328,7 @@ namespace Eigen { // just an empty macro ! #define EIGEN_EMPTY -#if defined(_MSC_VER) && (!defined(__INTEL_COMPILER)) +#if defined(_MSC_VER) && (_MSC_VER < 1900) && (!defined(__INTEL_COMPILER)) #define EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) \ using Base::operator =; #elif defined(__clang__) // workaround clang bug (see http://forum.kde.org/viewtopic.php?f=74&t=102653) @@ -324,8 +347,11 @@ namespace Eigen { } #endif -#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ - EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) +/** \internal + * \brief Macro to manually inherit assignment operators. + * This is necessary, because the implicitly defined assignment operator gets deleted when a custom operator= is defined. + */ +#define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Derived) /** * Just a side note. Commenting within defines works only by documenting @@ -397,6 +423,8 @@ namespace Eigen { #define EIGEN_SIZE_MAX(a,b) (((int)a == Dynamic || (int)b == Dynamic) ? Dynamic \ : ((int)a >= (int)b) ? (int)a : (int)b) +#define EIGEN_ADD_COST(a,b) int(a)==Dynamic || int(b)==Dynamic ? Dynamic : int(a)+int(b) + #define EIGEN_LOGICAL_XOR(a,b) (((a) || (b)) && !((a) && (b))) #define EIGEN_IMPLIES(a,b) (!(a) || (b)) diff --git a/extern/Eigen3/Eigen/src/Core/util/Memory.h b/extern/Eigen3/Eigen/src/Core/util/Memory.h index cacbd02fd12..b9af5cf8c7b 100644 --- a/extern/Eigen3/Eigen/src/Core/util/Memory.h +++ b/extern/Eigen3/Eigen/src/Core/util/Memory.h @@ -63,7 +63,7 @@ // Currently, let's include it only on unix systems: #if defined(__unix__) || defined(__unix) #include <unistd.h> - #if ((defined __QNXNTO__) || (defined _GNU_SOURCE) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))) && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0) + #if ((defined __QNXNTO__) || (defined _GNU_SOURCE) || (defined __PGI) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))) && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0) #define EIGEN_HAS_POSIX_MEMALIGN 1 #endif #endif @@ -272,12 +272,12 @@ inline void* aligned_realloc(void *ptr, size_t new_size, size_t old_size) // The defined(_mm_free) is just here to verify that this MSVC version // implements _mm_malloc/_mm_free based on the corresponding _aligned_ // functions. This may not always be the case and we just try to be safe. - #if defined(_MSC_VER) && defined(_mm_free) + #if defined(_MSC_VER) && (!defined(_WIN32_WCE)) && defined(_mm_free) result = _aligned_realloc(ptr,new_size,16); #else result = generic_aligned_realloc(ptr,new_size,old_size); #endif -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && (!defined(_WIN32_WCE)) result = _aligned_realloc(ptr,new_size,16); #else result = handmade_aligned_realloc(ptr,new_size,old_size); @@ -417,6 +417,8 @@ template<typename T, bool Align> inline T* conditional_aligned_realloc_new(T* pt template<typename T, bool Align> inline T* conditional_aligned_new_auto(size_t size) { + if(size==0) + return 0; // short-cut. Also fixes Bug 884 check_size_for_overflow<T>(size); T *result = reinterpret_cast<T*>(conditional_aligned_malloc<Align>(sizeof(T)*size)); if(NumTraits<T>::RequireInitialization) @@ -464,9 +466,8 @@ template<typename T, bool Align> inline void conditional_aligned_delete_auto(T * template<typename Scalar, typename Index> static inline Index first_aligned(const Scalar* array, Index size) { - enum { PacketSize = packet_traits<Scalar>::size, - PacketAlignedMask = PacketSize-1 - }; + static const Index PacketSize = packet_traits<Scalar>::size; + static const Index PacketAlignedMask = PacketSize-1; if(PacketSize==1) { @@ -522,7 +523,7 @@ template<typename T> struct smart_copy_helper<T,false> { // you can overwrite Eigen's default behavior regarding alloca by defining EIGEN_ALLOCA // to the appropriate stack allocation function #ifndef EIGEN_ALLOCA - #if (defined __linux__) + #if (defined __linux__) || (defined __APPLE__) || (defined alloca) #define EIGEN_ALLOCA alloca #elif defined(_MSC_VER) #define EIGEN_ALLOCA _alloca @@ -612,7 +613,6 @@ template<typename T> class aligned_stack_memory_handler void* operator new(size_t size, const std::nothrow_t&) throw() { \ try { return Eigen::internal::conditional_aligned_malloc<NeedsToAlign>(size); } \ catch (...) { return 0; } \ - return 0; \ } #else #define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_NOTHROW(NeedsToAlign) \ @@ -777,9 +777,9 @@ namespace internal { #ifdef EIGEN_CPUID -inline bool cpuid_is_vendor(int abcd[4], const char* vendor) +inline bool cpuid_is_vendor(int abcd[4], const int vendor[3]) { - return abcd[1]==(reinterpret_cast<const int*>(vendor))[0] && abcd[3]==(reinterpret_cast<const int*>(vendor))[1] && abcd[2]==(reinterpret_cast<const int*>(vendor))[2]; + return abcd[1]==vendor[0] && abcd[3]==vendor[1] && abcd[2]==vendor[2]; } inline void queryCacheSizes_intel_direct(int& l1, int& l2, int& l3) @@ -921,13 +921,16 @@ inline void queryCacheSizes(int& l1, int& l2, int& l3) { #ifdef EIGEN_CPUID int abcd[4]; + const int GenuineIntel[] = {0x756e6547, 0x49656e69, 0x6c65746e}; + const int AuthenticAMD[] = {0x68747541, 0x69746e65, 0x444d4163}; + const int AMDisbetter_[] = {0x69444d41, 0x74656273, 0x21726574}; // "AMDisbetter!" // identify the CPU vendor EIGEN_CPUID(abcd,0x0,0); int max_std_funcs = abcd[1]; - if(cpuid_is_vendor(abcd,"GenuineIntel")) + if(cpuid_is_vendor(abcd,GenuineIntel)) queryCacheSizes_intel(l1,l2,l3,max_std_funcs); - else if(cpuid_is_vendor(abcd,"AuthenticAMD") || cpuid_is_vendor(abcd,"AMDisbetter!")) + else if(cpuid_is_vendor(abcd,AuthenticAMD) || cpuid_is_vendor(abcd,AMDisbetter_)) queryCacheSizes_amd(l1,l2,l3); else // by default let's use Intel's API diff --git a/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h b/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h index 8872c5b648e..bac5d9fe92b 100644 --- a/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h +++ b/extern/Eigen3/Eigen/src/Core/util/StaticAssert.h @@ -90,7 +90,9 @@ YOU_PASSED_A_COLUMN_VECTOR_BUT_A_ROW_VECTOR_WAS_EXPECTED, THE_INDEX_TYPE_MUST_BE_A_SIGNED_TYPE, THE_STORAGE_ORDER_OF_BOTH_SIDES_MUST_MATCH, - OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG + OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG, + IMPLICIT_CONVERSION_TO_SCALAR_IS_FOR_INNER_PRODUCT_ONLY, + STORAGE_LAYOUT_DOES_NOT_MATCH }; }; diff --git a/extern/Eigen3/Eigen/src/Core/util/XprHelper.h b/extern/Eigen3/Eigen/src/Core/util/XprHelper.h index 3c4773054b4..d05f8e5f6f4 100644 --- a/extern/Eigen3/Eigen/src/Core/util/XprHelper.h +++ b/extern/Eigen3/Eigen/src/Core/util/XprHelper.h @@ -341,7 +341,7 @@ template<typename T, int n=1, typename PlainObject = typename eval<T>::type> str }; template<typename T> -T* const_cast_ptr(const T* ptr) +inline T* const_cast_ptr(const T* ptr) { return const_cast<T*>(ptr); } @@ -366,17 +366,17 @@ struct dense_xpr_base<Derived, ArrayXpr> /** \internal Helper base class to add a scalar multiple operator * overloads for complex types */ -template<typename Derived,typename Scalar,typename OtherScalar, +template<typename Derived, typename Scalar, typename OtherScalar, typename BaseType, bool EnableIt = !is_same<Scalar,OtherScalar>::value > -struct special_scalar_op_base : public DenseCoeffsBase<Derived> +struct special_scalar_op_base : public BaseType { // dummy operator* so that the // "using special_scalar_op_base::operator*" compiles void operator*() const; }; -template<typename Derived,typename Scalar,typename OtherScalar> -struct special_scalar_op_base<Derived,Scalar,OtherScalar,true> : public DenseCoeffsBase<Derived> +template<typename Derived,typename Scalar,typename OtherScalar, typename BaseType> +struct special_scalar_op_base<Derived,Scalar,OtherScalar,BaseType,true> : public BaseType { const CwiseUnaryOp<scalar_multiple2_op<Scalar,OtherScalar>, Derived> operator*(const OtherScalar& scalar) const diff --git a/extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h b/extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h index 0e6fdb4889d..7992d494425 100644 --- a/extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h +++ b/extern/Eigen3/Eigen/src/Eigen2Support/LeastSquares.h @@ -147,7 +147,6 @@ void fitHyperplane(int numPoints, // compute the covariance matrix CovMatrixType covMat = CovMatrixType::Zero(size, size); - VectorType remean = VectorType::Zero(size); for(int i = 0; i < numPoints; ++i) { VectorType diff = (*(points[i]) - mean).conjugate(); diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h index af434bc9bd6..417c72944e1 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -234,6 +234,12 @@ template<typename _MatrixType> class ComplexEigenSolver } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + EigenvectorType m_eivec; EigenvalueType m_eivalues; ComplexSchur<MatrixType> m_schur; @@ -251,6 +257,8 @@ template<typename MatrixType> ComplexEigenSolver<MatrixType>& ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors) { + check_template_parameters(); + // this code is inspired from Jampack eigen_assert(matrix.cols() == matrix.rows()); diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h index 6e7150685a2..20c59a7a2e6 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/EigenSolver.h @@ -298,6 +298,13 @@ template<typename _MatrixType> class EigenSolver void doComputeEigenvectors(); protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL); + } + MatrixType m_eivec; EigenvalueType m_eivalues; bool m_isInitialized; @@ -364,6 +371,8 @@ template<typename MatrixType> EigenSolver<MatrixType>& EigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors) { + check_template_parameters(); + using std::sqrt; using std::abs; eigen_assert(matrix.cols() == matrix.rows()); diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h index dc240e13e13..956e80d9edc 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/GeneralizedEigenSolver.h @@ -263,6 +263,13 @@ template<typename _MatrixType> class GeneralizedEigenSolver } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL); + } + MatrixType m_eivec; ComplexVectorType m_alphas; VectorType m_betas; @@ -290,6 +297,8 @@ template<typename MatrixType> GeneralizedEigenSolver<MatrixType>& GeneralizedEigenSolver<MatrixType>::compute(const MatrixType& A, const MatrixType& B, bool computeEigenvectors) { + check_template_parameters(); + using std::sqrt; using std::abs; eigen_assert(A.cols() == A.rows() && B.cols() == A.rows() && B.cols() == B.rows()); diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/RealQZ.h b/extern/Eigen3/Eigen/src/Eigenvalues/RealQZ.h index 5706eeebe91..aa3833ebad1 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/RealQZ.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/RealQZ.h @@ -240,10 +240,10 @@ namespace Eigen { m_S.coeffRef(i,j) = Scalar(0.0); m_S.rightCols(dim-j-1).applyOnTheLeft(i-1,i,G.adjoint()); m_T.rightCols(dim-i+1).applyOnTheLeft(i-1,i,G.adjoint()); + // update Q + if (m_computeQZ) + m_Q.applyOnTheRight(i-1,i,G); } - // update Q - if (m_computeQZ) - m_Q.applyOnTheRight(i-1,i,G); // kill T(i,i-1) if(m_T.coeff(i,i-1)!=Scalar(0)) { @@ -251,10 +251,10 @@ namespace Eigen { m_T.coeffRef(i,i-1) = Scalar(0.0); m_S.applyOnTheRight(i,i-1,G); m_T.topRows(i).applyOnTheRight(i,i-1,G); + // update Z + if (m_computeQZ) + m_Z.applyOnTheLeft(i,i-1,G.adjoint()); } - // update Z - if (m_computeQZ) - m_Z.applyOnTheLeft(i,i-1,G.adjoint()); } } } @@ -313,7 +313,7 @@ namespace Eigen { using std::abs; using std::sqrt; const Index dim=m_S.cols(); - if (abs(m_S.coeff(i+1,i)==Scalar(0))) + if (abs(m_S.coeff(i+1,i))==Scalar(0)) return; Index z = findSmallDiagEntry(i,i+1); if (z==i-1) diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h b/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h index 64d13634141..16d3875372e 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/RealSchur.h @@ -234,7 +234,7 @@ template<typename _MatrixType> class RealSchur typedef Matrix<Scalar,3,1> Vector3s; Scalar computeNormOfT(); - Index findSmallSubdiagEntry(Index iu, const Scalar& norm); + Index findSmallSubdiagEntry(Index iu); void splitOffTwoRows(Index iu, bool computeU, const Scalar& exshift); void computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo); void initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector); @@ -286,7 +286,7 @@ RealSchur<MatrixType>& RealSchur<MatrixType>::computeFromHessenberg(const HessMa { while (iu >= 0) { - Index il = findSmallSubdiagEntry(iu, norm); + Index il = findSmallSubdiagEntry(iu); // Check for convergence if (il == iu) // One root found @@ -343,16 +343,14 @@ inline typename MatrixType::Scalar RealSchur<MatrixType>::computeNormOfT() /** \internal Look for single small sub-diagonal element and returns its index */ template<typename MatrixType> -inline typename MatrixType::Index RealSchur<MatrixType>::findSmallSubdiagEntry(Index iu, const Scalar& norm) +inline typename MatrixType::Index RealSchur<MatrixType>::findSmallSubdiagEntry(Index iu) { using std::abs; Index res = iu; while (res > 0) { Scalar s = abs(m_matT.coeff(res-1,res-1)) + abs(m_matT.coeff(res,res)); - if (s == 0.0) - s = norm; - if (abs(m_matT.coeff(res,res-1)) < NumTraits<Scalar>::epsilon() * s) + if (abs(m_matT.coeff(res,res-1)) <= NumTraits<Scalar>::epsilon() * s) break; res--; } @@ -457,9 +455,7 @@ inline void RealSchur<MatrixType>::initFrancisQRStep(Index il, Index iu, const V const Scalar lhs = m_matT.coeff(im,im-1) * (abs(v.coeff(1)) + abs(v.coeff(2))); const Scalar rhs = v.coeff(0) * (abs(m_matT.coeff(im-1,im-1)) + abs(Tmm) + abs(m_matT.coeff(im+1,im+1))); if (abs(lhs) < NumTraits<Scalar>::epsilon() * rhs) - { break; - } } } diff --git a/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 3993046a88e..1131c8af8ad 100644 --- a/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/extern/Eigen3/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -80,6 +80,8 @@ template<typename _MatrixType> class SelfAdjointEigenSolver /** \brief Scalar type for matrices of type \p _MatrixType. */ typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Index Index; + + typedef Matrix<Scalar,Size,Size,ColMajor,MaxColsAtCompileTime,MaxColsAtCompileTime> EigenvectorsType; /** \brief Real scalar type for \p _MatrixType. * @@ -225,7 +227,7 @@ template<typename _MatrixType> class SelfAdjointEigenSolver * * \sa eigenvalues() */ - const MatrixType& eigenvectors() const + const EigenvectorsType& eigenvectors() const { eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); @@ -351,7 +353,12 @@ template<typename _MatrixType> class SelfAdjointEigenSolver #endif // EIGEN2_SUPPORT protected: - MatrixType m_eivec; + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + + EigenvectorsType m_eivec; RealVectorType m_eivalues; typename TridiagonalizationType::SubDiagonalType m_subdiag; ComputationInfo m_info; @@ -376,7 +383,7 @@ template<typename _MatrixType> class SelfAdjointEigenSolver * "implicit symmetric QR step with Wilkinson shift" */ namespace internal { -template<int StorageOrder,typename RealScalar, typename Scalar, typename Index> +template<typename RealScalar, typename Scalar, typename Index> static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n); } @@ -384,6 +391,8 @@ template<typename MatrixType> SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType> ::compute(const MatrixType& matrix, int options) { + check_template_parameters(); + using std::abs; eigen_assert(matrix.cols() == matrix.rows()); eigen_assert((options&~(EigVecMask|GenEigMask))==0 @@ -406,7 +415,7 @@ SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType> // declare some aliases RealVectorType& diag = m_eivalues; - MatrixType& mat = m_eivec; + EigenvectorsType& mat = m_eivec; // map the matrix coefficients to [-1:1] to avoid over- and underflow. mat = matrix.template triangularView<Lower>(); @@ -442,7 +451,7 @@ SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType> while (start>0 && m_subdiag[start-1]!=0) start--; - internal::tridiagonal_qr_step<MatrixType::Flags&RowMajorBit ? RowMajor : ColMajor>(diag.data(), m_subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n); + internal::tridiagonal_qr_step(diag.data(), m_subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n); } if (iter <= m_maxIterations * n) @@ -490,7 +499,13 @@ template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,3 typedef typename SolverType::MatrixType MatrixType; typedef typename SolverType::RealVectorType VectorType; typedef typename SolverType::Scalar Scalar; + typedef typename MatrixType::Index Index; + typedef typename SolverType::EigenvectorsType EigenvectorsType; + /** \internal + * Computes the roots of the characteristic polynomial of \a m. + * For numerical stability m.trace() should be near zero and to avoid over- or underflow m should be normalized. + */ static inline void computeRoots(const MatrixType& m, VectorType& roots) { using std::sqrt; @@ -510,148 +525,123 @@ template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,3 // Construct the parameters used in classifying the roots of the equation // and in solving the equation for the roots in closed form. Scalar c2_over_3 = c2*s_inv3; - Scalar a_over_3 = (c1 - c2*c2_over_3)*s_inv3; - if (a_over_3 > Scalar(0)) + Scalar a_over_3 = (c2*c2_over_3 - c1)*s_inv3; + if(a_over_3<Scalar(0)) a_over_3 = Scalar(0); Scalar half_b = Scalar(0.5)*(c0 + c2_over_3*(Scalar(2)*c2_over_3*c2_over_3 - c1)); - Scalar q = half_b*half_b + a_over_3*a_over_3*a_over_3; - if (q > Scalar(0)) + Scalar q = a_over_3*a_over_3*a_over_3 - half_b*half_b; + if(q<Scalar(0)) q = Scalar(0); // Compute the eigenvalues by solving for the roots of the polynomial. - Scalar rho = sqrt(-a_over_3); - Scalar theta = atan2(sqrt(-q),half_b)*s_inv3; + Scalar rho = sqrt(a_over_3); + Scalar theta = atan2(sqrt(q),half_b)*s_inv3; // since sqrt(q) > 0, atan2 is in [0, pi] and theta is in [0, pi/3] Scalar cos_theta = cos(theta); Scalar sin_theta = sin(theta); - roots(0) = c2_over_3 + Scalar(2)*rho*cos_theta; - roots(1) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta); - roots(2) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta); - - // Sort in increasing order. - if (roots(0) >= roots(1)) - std::swap(roots(0),roots(1)); - if (roots(1) >= roots(2)) - { - std::swap(roots(1),roots(2)); - if (roots(0) >= roots(1)) - std::swap(roots(0),roots(1)); - } + // roots are already sorted, since cos is monotonically decreasing on [0, pi] + roots(0) = c2_over_3 - rho*(cos_theta + s_sqrt3*sin_theta); // == 2*rho*cos(theta+2pi/3) + roots(1) = c2_over_3 - rho*(cos_theta - s_sqrt3*sin_theta); // == 2*rho*cos(theta+ pi/3) + roots(2) = c2_over_3 + Scalar(2)*rho*cos_theta; } - + + static inline bool extract_kernel(MatrixType& mat, Ref<VectorType> res, Ref<VectorType> representative) + { + using std::abs; + Index i0; + // Find non-zero column i0 (by construction, there must exist a non zero coefficient on the diagonal): + mat.diagonal().cwiseAbs().maxCoeff(&i0); + // mat.col(i0) is a good candidate for an orthogonal vector to the current eigenvector, + // so let's save it: + representative = mat.col(i0); + Scalar n0, n1; + VectorType c0, c1; + n0 = (c0 = representative.cross(mat.col((i0+1)%3))).squaredNorm(); + n1 = (c1 = representative.cross(mat.col((i0+2)%3))).squaredNorm(); + if(n0>n1) res = c0/std::sqrt(n0); + else res = c1/std::sqrt(n1); + + return true; + } + static inline void run(SolverType& solver, const MatrixType& mat, int options) { - using std::sqrt; eigen_assert(mat.cols() == 3 && mat.cols() == mat.rows()); eigen_assert((options&~(EigVecMask|GenEigMask))==0 && (options&EigVecMask)!=EigVecMask && "invalid option parameter"); bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors; - MatrixType& eivecs = solver.m_eivec; + EigenvectorsType& eivecs = solver.m_eivec; VectorType& eivals = solver.m_eivalues; - // map the matrix coefficients to [-1:1] to avoid over- and underflow. - Scalar scale = mat.cwiseAbs().maxCoeff(); - MatrixType scaledMat = mat / scale; + // Shift the matrix to the mean eigenvalue and map the matrix coefficients to [-1:1] to avoid over- and underflow. + Scalar shift = mat.trace() / Scalar(3); + // TODO Avoid this copy. Currently it is necessary to suppress bogus values when determining maxCoeff and for computing the eigenvectors later + MatrixType scaledMat = mat.template selfadjointView<Lower>(); + scaledMat.diagonal().array() -= shift; + Scalar scale = scaledMat.cwiseAbs().maxCoeff(); + if(scale > 0) scaledMat /= scale; // TODO for scale==0 we could save the remaining operations // compute the eigenvalues computeRoots(scaledMat,eivals); - // compute the eigen vectors + // compute the eigenvectors if(computeEigenvectors) { - Scalar safeNorm2 = Eigen::NumTraits<Scalar>::epsilon(); - safeNorm2 *= safeNorm2; if((eivals(2)-eivals(0))<=Eigen::NumTraits<Scalar>::epsilon()) { + // All three eigenvalues are numerically the same eivecs.setIdentity(); } else { - scaledMat = scaledMat.template selfadjointView<Lower>(); MatrixType tmp; tmp = scaledMat; + // Compute the eigenvector of the most distinct eigenvalue Scalar d0 = eivals(2) - eivals(1); Scalar d1 = eivals(1) - eivals(0); - int k = d0 > d1 ? 2 : 0; - d0 = d0 > d1 ? d1 : d0; - - tmp.diagonal().array () -= eivals(k); - VectorType cross; - Scalar n; - n = (cross = tmp.row(0).cross(tmp.row(1))).squaredNorm(); - - if(n>safeNorm2) - eivecs.col(k) = cross / sqrt(n); - else + Index k(0), l(2); + if(d0 > d1) { - n = (cross = tmp.row(0).cross(tmp.row(2))).squaredNorm(); - - if(n>safeNorm2) - eivecs.col(k) = cross / sqrt(n); - else - { - n = (cross = tmp.row(1).cross(tmp.row(2))).squaredNorm(); - - if(n>safeNorm2) - eivecs.col(k) = cross / sqrt(n); - else - { - // the input matrix and/or the eigenvaues probably contains some inf/NaN, - // => exit - // scale back to the original size. - eivals *= scale; - - solver.m_info = NumericalIssue; - solver.m_isInitialized = true; - solver.m_eigenvectorsOk = computeEigenvectors; - return; - } - } + std::swap(k,l); + d0 = d1; } - tmp = scaledMat; - tmp.diagonal().array() -= eivals(1); + // Compute the eigenvector of index k + { + tmp.diagonal().array () -= eivals(k); + // By construction, 'tmp' is of rank 2, and its kernel corresponds to the respective eigenvector. + extract_kernel(tmp, eivecs.col(k), eivecs.col(l)); + } - if(d0<=Eigen::NumTraits<Scalar>::epsilon()) - eivecs.col(1) = eivecs.col(k).unitOrthogonal(); + // Compute eigenvector of index l + if(d0<=2*Eigen::NumTraits<Scalar>::epsilon()*d1) + { + // If d0 is too small, then the two other eigenvalues are numerically the same, + // and thus we only have to ortho-normalize the near orthogonal vector we saved above. + eivecs.col(l) -= eivecs.col(k).dot(eivecs.col(l))*eivecs.col(l); + eivecs.col(l).normalize(); + } else { - n = (cross = eivecs.col(k).cross(tmp.row(0).normalized())).squaredNorm(); - if(n>safeNorm2) - eivecs.col(1) = cross / sqrt(n); - else - { - n = (cross = eivecs.col(k).cross(tmp.row(1))).squaredNorm(); - if(n>safeNorm2) - eivecs.col(1) = cross / sqrt(n); - else - { - n = (cross = eivecs.col(k).cross(tmp.row(2))).squaredNorm(); - if(n>safeNorm2) - eivecs.col(1) = cross / sqrt(n); - else - { - // we should never reach this point, - // if so the last two eigenvalues are likely to ve very closed to each other - eivecs.col(1) = eivecs.col(k).unitOrthogonal(); - } - } - } - - // make sure that eivecs[1] is orthogonal to eivecs[2] - Scalar d = eivecs.col(1).dot(eivecs.col(k)); - eivecs.col(1) = (eivecs.col(1) - d * eivecs.col(k)).normalized(); + tmp = scaledMat; + tmp.diagonal().array () -= eivals(l); + + VectorType dummy; + extract_kernel(tmp, eivecs.col(l), dummy); } - eivecs.col(k==2 ? 0 : 2) = eivecs.col(k).cross(eivecs.col(1)).normalized(); + // Compute last eigenvector from the other two + eivecs.col(1) = eivecs.col(2).cross(eivecs.col(0)).normalized(); } } + // Rescale back to the original size. eivals *= scale; + eivals.array() += shift; solver.m_info = Success; solver.m_isInitialized = true; @@ -665,11 +655,12 @@ template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,2 typedef typename SolverType::MatrixType MatrixType; typedef typename SolverType::RealVectorType VectorType; typedef typename SolverType::Scalar Scalar; + typedef typename SolverType::EigenvectorsType EigenvectorsType; static inline void computeRoots(const MatrixType& m, VectorType& roots) { using std::sqrt; - const Scalar t0 = Scalar(0.5) * sqrt( numext::abs2(m(0,0)-m(1,1)) + Scalar(4)*m(1,0)*m(1,0)); + const Scalar t0 = Scalar(0.5) * sqrt( numext::abs2(m(0,0)-m(1,1)) + Scalar(4)*numext::abs2(m(1,0))); const Scalar t1 = Scalar(0.5) * (m(0,0) + m(1,1)); roots(0) = t1 - t0; roots(1) = t1 + t0; @@ -678,13 +669,15 @@ template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,2 static inline void run(SolverType& solver, const MatrixType& mat, int options) { using std::sqrt; + using std::abs; + eigen_assert(mat.cols() == 2 && mat.cols() == mat.rows()); eigen_assert((options&~(EigVecMask|GenEigMask))==0 && (options&EigVecMask)!=EigVecMask && "invalid option parameter"); bool computeEigenvectors = (options&ComputeEigenvectors)==ComputeEigenvectors; - MatrixType& eivecs = solver.m_eivec; + EigenvectorsType& eivecs = solver.m_eivec; VectorType& eivals = solver.m_eivalues; // map the matrix coefficients to [-1:1] to avoid over- and underflow. @@ -698,22 +691,29 @@ template<typename SolverType> struct direct_selfadjoint_eigenvalues<SolverType,2 // compute the eigen vectors if(computeEigenvectors) { - scaledMat.diagonal().array () -= eivals(1); - Scalar a2 = numext::abs2(scaledMat(0,0)); - Scalar c2 = numext::abs2(scaledMat(1,1)); - Scalar b2 = numext::abs2(scaledMat(1,0)); - if(a2>c2) + if((eivals(1)-eivals(0))<=abs(eivals(1))*Eigen::NumTraits<Scalar>::epsilon()) { - eivecs.col(1) << -scaledMat(1,0), scaledMat(0,0); - eivecs.col(1) /= sqrt(a2+b2); + eivecs.setIdentity(); } else { - eivecs.col(1) << -scaledMat(1,1), scaledMat(1,0); - eivecs.col(1) /= sqrt(c2+b2); - } + scaledMat.diagonal().array () -= eivals(1); + Scalar a2 = numext::abs2(scaledMat(0,0)); + Scalar c2 = numext::abs2(scaledMat(1,1)); + Scalar b2 = numext::abs2(scaledMat(1,0)); + if(a2>c2) + { + eivecs.col(1) << -scaledMat(1,0), scaledMat(0,0); + eivecs.col(1) /= sqrt(a2+b2); + } + else + { + eivecs.col(1) << -scaledMat(1,1), scaledMat(1,0); + eivecs.col(1) /= sqrt(c2+b2); + } - eivecs.col(0) << eivecs.col(1).unitOrthogonal(); + eivecs.col(0) << eivecs.col(1).unitOrthogonal(); + } } // Rescale back to the original size. @@ -736,7 +736,7 @@ SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType> } namespace internal { -template<int StorageOrder,typename RealScalar, typename Scalar, typename Index> +template<typename RealScalar, typename Scalar, typename Index> static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n) { using std::abs; @@ -788,8 +788,7 @@ static void tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index sta // apply the givens rotation to the unit matrix Q = Q * G if (matrixQ) { - // FIXME if StorageOrder == RowMajor this operation is not very efficient - Map<Matrix<Scalar,Dynamic,Dynamic,StorageOrder> > q(matrixQ,n,n); + Map<Matrix<Scalar,Dynamic,Dynamic,ColMajor> > q(matrixQ,n,n); q.applyOnTheRight(k,k+1,rot); } } diff --git a/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h b/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h index 8e186d57a34..7e1cd9eb79c 100644 --- a/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h +++ b/extern/Eigen3/Eigen/src/Geometry/AlignedBox.h @@ -19,10 +19,12 @@ namespace Eigen { * * \brief An axis aligned box * - * \param _Scalar the type of the scalar coefficients - * \param _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic. + * \tparam _Scalar the type of the scalar coefficients + * \tparam _AmbientDim the dimension of the ambient space, can be a compile time value or Dynamic. * * This class represents an axis aligned box as a pair of the minimal and maximal corners. + * \warning The result of most methods is undefined when applied to an empty box. You can check for empty boxes using isEmpty(). + * \sa alignedboxtypedefs */ template <typename _Scalar, int _AmbientDim> class AlignedBox @@ -40,18 +42,21 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) /** Define constants to name the corners of a 1D, 2D or 3D axis aligned bounding box */ enum CornerType { - /** 1D names */ + /** 1D names @{ */ Min=0, Max=1, + /** @} */ - /** Added names for 2D */ + /** Identifier for 2D corner @{ */ BottomLeft=0, BottomRight=1, TopLeft=2, TopRight=3, + /** @} */ - /** Added names for 3D */ + /** Identifier for 3D corner @{ */ BottomLeftFloor=0, BottomRightFloor=1, TopLeftFloor=2, TopRightFloor=3, BottomLeftCeil=4, BottomRightCeil=5, TopLeftCeil=6, TopRightCeil=7 + /** @} */ }; @@ -63,34 +68,33 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) inline explicit AlignedBox(Index _dim) : m_min(_dim), m_max(_dim) { setEmpty(); } - /** Constructs a box with extremities \a _min and \a _max. */ + /** Constructs a box with extremities \a _min and \a _max. + * \warning If either component of \a _min is larger than the same component of \a _max, the constructed box is empty. */ template<typename OtherVectorType1, typename OtherVectorType2> inline AlignedBox(const OtherVectorType1& _min, const OtherVectorType2& _max) : m_min(_min), m_max(_max) {} /** Constructs a box containing a single point \a p. */ template<typename Derived> - inline explicit AlignedBox(const MatrixBase<Derived>& a_p) - { - typename internal::nested<Derived,2>::type p(a_p.derived()); - m_min = p; - m_max = p; - } + inline explicit AlignedBox(const MatrixBase<Derived>& p) : m_min(p), m_max(m_min) + { } ~AlignedBox() {} /** \returns the dimension in which the box holds */ inline Index dim() const { return AmbientDimAtCompileTime==Dynamic ? m_min.size() : Index(AmbientDimAtCompileTime); } - /** \deprecated use isEmpty */ + /** \deprecated use isEmpty() */ inline bool isNull() const { return isEmpty(); } - /** \deprecated use setEmpty */ + /** \deprecated use setEmpty() */ inline void setNull() { setEmpty(); } - /** \returns true if the box is empty. */ + /** \returns true if the box is empty. + * \sa setEmpty */ inline bool isEmpty() const { return (m_min.array() > m_max.array()).any(); } - /** Makes \c *this an empty box. */ + /** Makes \c *this an empty box. + * \sa isEmpty */ inline void setEmpty() { m_min.setConstant( ScalarTraits::highest() ); @@ -159,7 +163,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) * a uniform distribution */ inline VectorType sample() const { - VectorType r; + VectorType r(dim()); for(Index d=0; d<dim(); ++d) { if(!ScalarTraits::IsInteger) @@ -175,27 +179,34 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) /** \returns true if the point \a p is inside the box \c *this. */ template<typename Derived> - inline bool contains(const MatrixBase<Derived>& a_p) const + inline bool contains(const MatrixBase<Derived>& p) const { - typename internal::nested<Derived,2>::type p(a_p.derived()); - return (m_min.array()<=p.array()).all() && (p.array()<=m_max.array()).all(); + typename internal::nested<Derived,2>::type p_n(p.derived()); + return (m_min.array()<=p_n.array()).all() && (p_n.array()<=m_max.array()).all(); } /** \returns true if the box \a b is entirely inside the box \c *this. */ inline bool contains(const AlignedBox& b) const { return (m_min.array()<=(b.min)().array()).all() && ((b.max)().array()<=m_max.array()).all(); } - /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this. */ + /** \returns true if the box \a b is intersecting the box \c *this. + * \sa intersection, clamp */ + inline bool intersects(const AlignedBox& b) const + { return (m_min.array()<=(b.max)().array()).all() && ((b.min)().array()<=m_max.array()).all(); } + + /** Extends \c *this such that it contains the point \a p and returns a reference to \c *this. + * \sa extend(const AlignedBox&) */ template<typename Derived> - inline AlignedBox& extend(const MatrixBase<Derived>& a_p) + inline AlignedBox& extend(const MatrixBase<Derived>& p) { - typename internal::nested<Derived,2>::type p(a_p.derived()); - m_min = m_min.cwiseMin(p); - m_max = m_max.cwiseMax(p); + typename internal::nested<Derived,2>::type p_n(p.derived()); + m_min = m_min.cwiseMin(p_n); + m_max = m_max.cwiseMax(p_n); return *this; } - /** Extends \c *this such that it contains the box \a b and returns a reference to \c *this. */ + /** Extends \c *this such that it contains the box \a b and returns a reference to \c *this. + * \sa merged, extend(const MatrixBase&) */ inline AlignedBox& extend(const AlignedBox& b) { m_min = m_min.cwiseMin(b.m_min); @@ -203,7 +214,9 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) return *this; } - /** Clamps \c *this by the box \a b and returns a reference to \c *this. */ + /** Clamps \c *this by the box \a b and returns a reference to \c *this. + * \note If the boxes don't intersect, the resulting box is empty. + * \sa intersection(), intersects() */ inline AlignedBox& clamp(const AlignedBox& b) { m_min = m_min.cwiseMax(b.m_min); @@ -211,11 +224,15 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) return *this; } - /** Returns an AlignedBox that is the intersection of \a b and \c *this */ + /** Returns an AlignedBox that is the intersection of \a b and \c *this + * \note If the boxes don't intersect, the resulting box is empty. + * \sa intersects(), clamp, contains() */ inline AlignedBox intersection(const AlignedBox& b) const {return AlignedBox(m_min.cwiseMax(b.m_min), m_max.cwiseMin(b.m_max)); } - /** Returns an AlignedBox that is the union of \a b and \c *this */ + /** Returns an AlignedBox that is the union of \a b and \c *this. + * \note Merging with an empty box may result in a box bigger than \c *this. + * \sa extend(const AlignedBox&) */ inline AlignedBox merged(const AlignedBox& b) const { return AlignedBox(m_min.cwiseMin(b.m_min), m_max.cwiseMax(b.m_max)); } @@ -231,20 +248,20 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) /** \returns the squared distance between the point \a p and the box \c *this, * and zero if \a p is inside the box. - * \sa exteriorDistance() + * \sa exteriorDistance(const MatrixBase&), squaredExteriorDistance(const AlignedBox&) */ template<typename Derived> - inline Scalar squaredExteriorDistance(const MatrixBase<Derived>& a_p) const; + inline Scalar squaredExteriorDistance(const MatrixBase<Derived>& p) const; /** \returns the squared distance between the boxes \a b and \c *this, * and zero if the boxes intersect. - * \sa exteriorDistance() + * \sa exteriorDistance(const AlignedBox&), squaredExteriorDistance(const MatrixBase&) */ inline Scalar squaredExteriorDistance(const AlignedBox& b) const; /** \returns the distance between the point \a p and the box \c *this, * and zero if \a p is inside the box. - * \sa squaredExteriorDistance() + * \sa squaredExteriorDistance(const MatrixBase&), exteriorDistance(const AlignedBox&) */ template<typename Derived> inline NonInteger exteriorDistance(const MatrixBase<Derived>& p) const @@ -252,7 +269,7 @@ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_AmbientDim) /** \returns the distance between the boxes \a b and \c *this, * and zero if the boxes intersect. - * \sa squaredExteriorDistance() + * \sa squaredExteriorDistance(const AlignedBox&), exteriorDistance(const MatrixBase&) */ inline NonInteger exteriorDistance(const AlignedBox& b) const { using std::sqrt; return sqrt(NonInteger(squaredExteriorDistance(b))); } diff --git a/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h b/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h index 553d38c7449..bbf6a7ed8ed 100644 --- a/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h +++ b/extern/Eigen3/Eigen/src/Geometry/AngleAxis.h @@ -131,7 +131,7 @@ public: m_angle = Scalar(other.angle()); } - static inline const AngleAxis Identity() { return AngleAxis(0, Vector3::UnitX()); } + static inline const AngleAxis Identity() { return AngleAxis(Scalar(0), Vector3::UnitX()); } /** \returns \c true if \c *this is approximately equal to \a other, within the precision * determined by \a prec. @@ -165,8 +165,8 @@ AngleAxis<Scalar>& AngleAxis<Scalar>::operator=(const QuaternionBase<QuatDerived Scalar n2 = q.vec().squaredNorm(); if (n2 < NumTraits<Scalar>::dummy_precision()*NumTraits<Scalar>::dummy_precision()) { - m_angle = 0; - m_axis << 1, 0, 0; + m_angle = Scalar(0); + m_axis << Scalar(1), Scalar(0), Scalar(0); } else { diff --git a/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h b/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h index 00e71d190c3..372e422b92c 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h +++ b/extern/Eigen3/Eigen/src/Geometry/Homogeneous.h @@ -79,7 +79,7 @@ template<typename MatrixType,int _Direction> class Homogeneous { if( (int(Direction)==Vertical && row==m_matrix.rows()) || (int(Direction)==Horizontal && col==m_matrix.cols())) - return 1; + return Scalar(1); return m_matrix.coeff(row, col); } diff --git a/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h b/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h index aeff43fefa6..00b7c4300fd 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h +++ b/extern/Eigen3/Eigen/src/Geometry/Hyperplane.h @@ -100,7 +100,17 @@ public: { EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(VectorType, 3) Hyperplane result(p0.size()); - result.normal() = (p2 - p0).cross(p1 - p0).normalized(); + VectorType v0(p2 - p0), v1(p1 - p0); + result.normal() = v0.cross(v1); + RealScalar norm = result.normal().norm(); + if(norm <= v0.norm() * v1.norm() * NumTraits<RealScalar>::epsilon()) + { + Matrix<Scalar,2,3> m; m << v0.transpose(), v1.transpose(); + JacobiSVD<Matrix<Scalar,2,3> > svd(m, ComputeFullV); + result.normal() = svd.matrixV().col(2); + } + else + result.normal() /= norm; result.offset() = -p0.dot(result.normal()); return result; } diff --git a/extern/Eigen3/Eigen/src/Geometry/Quaternion.h b/extern/Eigen3/Eigen/src/Geometry/Quaternion.h index 9fee0c91980..25ed17bb690 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Quaternion.h +++ b/extern/Eigen3/Eigen/src/Geometry/Quaternion.h @@ -102,11 +102,11 @@ public: /** \returns a quaternion representing an identity rotation * \sa MatrixBase::Identity() */ - static inline Quaternion<Scalar> Identity() { return Quaternion<Scalar>(1, 0, 0, 0); } + static inline Quaternion<Scalar> Identity() { return Quaternion<Scalar>(Scalar(1), Scalar(0), Scalar(0), Scalar(0)); } /** \sa QuaternionBase::Identity(), MatrixBase::setIdentity() */ - inline QuaternionBase& setIdentity() { coeffs() << 0, 0, 0, 1; return *this; } + inline QuaternionBase& setIdentity() { coeffs() << Scalar(0), Scalar(0), Scalar(0), Scalar(1); return *this; } /** \returns the squared norm of the quaternion's coefficients * \sa QuaternionBase::norm(), MatrixBase::squaredNorm() @@ -161,7 +161,7 @@ public: { return coeffs().isApprox(other.coeffs(), prec); } /** return the result vector of \a v through the rotation*/ - EIGEN_STRONG_INLINE Vector3 _transformVector(Vector3 v) const; + EIGEN_STRONG_INLINE Vector3 _transformVector(const Vector3& v) const; /** \returns \c *this with scalar type casted to \a NewScalarType * @@ -203,6 +203,8 @@ public: * \li \c Quaternionf for \c float * \li \c Quaterniond for \c double * + * \warning Operations interpreting the quaternion as rotation have undefined behavior if the quaternion is not normalized. + * * \sa class AngleAxis, class Transform */ @@ -229,7 +231,7 @@ class Quaternion : public QuaternionBase<Quaternion<_Scalar,_Options> > public: typedef _Scalar Scalar; - EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Quaternion) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Quaternion) using Base::operator*=; typedef typename internal::traits<Quaternion>::Coefficients Coefficients; @@ -339,12 +341,12 @@ class Map<const Quaternion<_Scalar>, _Options > public: typedef _Scalar Scalar; typedef typename internal::traits<Map>::Coefficients Coefficients; - EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Map) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map) using Base::operator*=; /** Constructs a Mapped Quaternion object from the pointer \a coeffs * - * The pointer \a coeffs must reference the four coeffecients of Quaternion in the following order: + * The pointer \a coeffs must reference the four coefficients of Quaternion in the following order: * \code *coeffs == {x, y, z, w} \endcode * * If the template parameter _Options is set to #Aligned, then the pointer coeffs must be aligned. */ @@ -376,7 +378,7 @@ class Map<Quaternion<_Scalar>, _Options > public: typedef _Scalar Scalar; typedef typename internal::traits<Map>::Coefficients Coefficients; - EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Map) + EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Map) using Base::operator*=; /** Constructs a Mapped Quaternion object from the pointer \a coeffs @@ -459,12 +461,12 @@ EIGEN_STRONG_INLINE Derived& QuaternionBase<Derived>::operator*= (const Quaterni */ template <class Derived> EIGEN_STRONG_INLINE typename QuaternionBase<Derived>::Vector3 -QuaternionBase<Derived>::_transformVector(Vector3 v) const +QuaternionBase<Derived>::_transformVector(const Vector3& v) const { // Note that this algorithm comes from the optimization by hand // of the conversion to a Matrix followed by a Matrix/Vector product. // It appears to be much faster than the common algorithm found - // in the litterature (30 versus 39 flops). It also requires two + // in the literature (30 versus 39 flops). It also requires two // Vector3 as temporaries. Vector3 uv = this->vec().cross(v); uv += uv; @@ -584,7 +586,7 @@ inline Derived& QuaternionBase<Derived>::setFromTwoVectors(const MatrixBase<Deri // which yields a singular value problem if (c < Scalar(-1)+NumTraits<Scalar>::dummy_precision()) { - c = max<Scalar>(c,-1); + c = (max)(c,Scalar(-1)); Matrix<Scalar,2,3> m; m << v0.transpose(), v1.transpose(); JacobiSVD<Matrix<Scalar,2,3> > svd(m, ComputeFullV); Vector3 axis = svd.matrixV().col(2); @@ -635,7 +637,7 @@ inline Quaternion<typename internal::traits<Derived>::Scalar> QuaternionBase<Der { // FIXME should this function be called multiplicativeInverse and conjugate() be called inverse() or opposite() ?? Scalar n2 = this->squaredNorm(); - if (n2 > 0) + if (n2 > Scalar(0)) return Quaternion<Scalar>(conjugate().coeffs() / n2); else { @@ -665,12 +667,10 @@ template <class OtherDerived> inline typename internal::traits<Derived>::Scalar QuaternionBase<Derived>::angularDistance(const QuaternionBase<OtherDerived>& other) const { - using std::acos; + using std::atan2; using std::abs; - double d = abs(this->dot(other)); - if (d>=1.0) - return Scalar(0); - return static_cast<Scalar>(2 * acos(d)); + Quaternion<Scalar> d = (*this) * other.conjugate(); + return Scalar(2) * atan2( d.vec().norm(), abs(d.w()) ); } @@ -710,7 +710,7 @@ QuaternionBase<Derived>::slerp(const Scalar& t, const QuaternionBase<OtherDerive scale0 = sin( ( Scalar(1) - t ) * theta) / sinTheta; scale1 = sin( ( t * theta) ) / sinTheta; } - if(d<0) scale1 = -scale1; + if(d<Scalar(0)) scale1 = -scale1; return Quaternion<Scalar>(scale0 * coeffs() + scale1 * other.coeffs()); } diff --git a/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h b/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h index 1cac343a5ee..a2d59fce10f 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h +++ b/extern/Eigen3/Eigen/src/Geometry/Rotation2D.h @@ -60,6 +60,9 @@ public: /** Construct a 2D counter clock wise rotation from the angle \a a in radian. */ inline Rotation2D(const Scalar& a) : m_angle(a) {} + + /** Default constructor wihtout initialization. The represented rotation is undefined. */ + Rotation2D() {} /** \returns the rotation angle */ inline Scalar angle() const { return m_angle; } @@ -81,10 +84,10 @@ public: /** Applies the rotation to a 2D vector */ Vector2 operator* (const Vector2& vec) const { return toRotationMatrix() * vec; } - + template<typename Derived> Rotation2D& fromRotationMatrix(const MatrixBase<Derived>& m); - Matrix2 toRotationMatrix(void) const; + Matrix2 toRotationMatrix() const; /** \returns the spherical interpolation between \c *this and \a other using * parameter \a t. It is in fact equivalent to a linear interpolation. diff --git a/extern/Eigen3/Eigen/src/Geometry/Transform.h b/extern/Eigen3/Eigen/src/Geometry/Transform.h index 498fea41a90..e786e535695 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Transform.h +++ b/extern/Eigen3/Eigen/src/Geometry/Transform.h @@ -62,6 +62,8 @@ struct transform_construct_from_matrix; template<typename TransformType> struct transform_take_affine_part; +template<int Mode> struct transform_make_affine; + } // end namespace internal /** \geometry_module \ingroup Geometry_Module @@ -194,9 +196,9 @@ public: /** type of the matrix used to represent the linear part of the transformation */ typedef Matrix<Scalar,Dim,Dim,Options> LinearMatrixType; /** type of read/write reference to the linear part of the transformation */ - typedef Block<MatrixType,Dim,Dim,int(Mode)==(AffineCompact)> LinearPart; + typedef Block<MatrixType,Dim,Dim,int(Mode)==(AffineCompact) && (Options&RowMajor)==0> LinearPart; /** type of read reference to the linear part of the transformation */ - typedef const Block<ConstMatrixType,Dim,Dim,int(Mode)==(AffineCompact)> ConstLinearPart; + typedef const Block<ConstMatrixType,Dim,Dim,int(Mode)==(AffineCompact) && (Options&RowMajor)==0> ConstLinearPart; /** type of read/write reference to the affine part of the transformation */ typedef typename internal::conditional<int(Mode)==int(AffineCompact), MatrixType&, @@ -230,8 +232,7 @@ public: inline Transform() { check_template_params(); - if (int(Mode)==Affine) - makeAffine(); + internal::transform_make_affine<(int(Mode)==Affine) ? Affine : AffineCompact>::run(m_matrix); } inline Transform(const Transform& other) @@ -591,11 +592,7 @@ public: */ void makeAffine() { - if(int(Mode)!=int(AffineCompact)) - { - matrix().template block<1,Dim>(Dim,0).setZero(); - matrix().coeffRef(Dim,Dim) = Scalar(1); - } + internal::transform_make_affine<int(Mode)>::run(m_matrix); } /** \internal @@ -1079,6 +1076,24 @@ Transform<Scalar,Dim,Mode,Options>::fromPositionOrientationScale(const MatrixBas namespace internal { +template<int Mode> +struct transform_make_affine +{ + template<typename MatrixType> + static void run(MatrixType &mat) + { + static const int Dim = MatrixType::ColsAtCompileTime-1; + mat.template block<1,Dim>(Dim,0).setZero(); + mat.coeffRef(Dim,Dim) = typename MatrixType::Scalar(1); + } +}; + +template<> +struct transform_make_affine<AffineCompact> +{ + template<typename MatrixType> static void run(MatrixType &) { } +}; + // selector needed to avoid taking the inverse of a 3x4 matrix template<typename TransformType, int Mode=TransformType::Mode> struct projective_transform_inverse diff --git a/extern/Eigen3/Eigen/src/Geometry/Umeyama.h b/extern/Eigen3/Eigen/src/Geometry/Umeyama.h index 345b47e0c37..5e20662f803 100644 --- a/extern/Eigen3/Eigen/src/Geometry/Umeyama.h +++ b/extern/Eigen3/Eigen/src/Geometry/Umeyama.h @@ -113,7 +113,7 @@ umeyama(const MatrixBase<Derived>& src, const MatrixBase<OtherDerived>& dst, boo const Index n = src.cols(); // number of measurements // required for demeaning ... - const RealScalar one_over_n = 1 / static_cast<RealScalar>(n); + const RealScalar one_over_n = RealScalar(1) / static_cast<RealScalar>(n); // computation of mean const VectorType src_mean = src.rowwise().sum() * one_over_n; @@ -136,16 +136,16 @@ umeyama(const MatrixBase<Derived>& src, const MatrixBase<OtherDerived>& dst, boo // Eq. (39) VectorType S = VectorType::Ones(m); - if (sigma.determinant()<0) S(m-1) = -1; + if (sigma.determinant()<Scalar(0)) S(m-1) = Scalar(-1); // Eq. (40) and (43) const VectorType& d = svd.singularValues(); Index rank = 0; for (Index i=0; i<m; ++i) if (!internal::isMuchSmallerThan(d.coeff(i),d.coeff(0))) ++rank; if (rank == m-1) { - if ( svd.matrixU().determinant() * svd.matrixV().determinant() > 0 ) { + if ( svd.matrixU().determinant() * svd.matrixV().determinant() > Scalar(0) ) { Rt.block(0,0,m,m).noalias() = svd.matrixU()*svd.matrixV().transpose(); } else { - const Scalar s = S(m-1); S(m-1) = -1; + const Scalar s = S(m-1); S(m-1) = Scalar(-1); Rt.block(0,0,m,m).noalias() = svd.matrixU() * S.asDiagonal() * svd.matrixV().transpose(); S(m-1) = s; } @@ -156,7 +156,7 @@ umeyama(const MatrixBase<Derived>& src, const MatrixBase<OtherDerived>& dst, boo if (with_scaling) { // Eq. (42) - const Scalar c = 1/src_var * svd.singularValues().dot(S); + const Scalar c = Scalar(1)/src_var * svd.singularValues().dot(S); // Eq. (41) Rt.col(m).head(m) = dst_mean; diff --git a/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h b/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h index 1991c652738..60dbea5f56a 100644 --- a/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h +++ b/extern/Eigen3/Eigen/src/Householder/BlockHouseholder.h @@ -48,7 +48,7 @@ void apply_block_householder_on_the_left(MatrixType& mat, const VectorsType& vec typedef typename MatrixType::Index Index; enum { TFactorSize = MatrixType::ColsAtCompileTime }; Index nbVecs = vectors.cols(); - Matrix<typename MatrixType::Scalar, TFactorSize, TFactorSize> T(nbVecs,nbVecs); + Matrix<typename MatrixType::Scalar, TFactorSize, TFactorSize, ColMajor> T(nbVecs,nbVecs); make_block_householder_triangular_factor(T, vectors, hCoeffs); const TriangularView<const VectorsType, UnitLower>& V(vectors); diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h index 73ca9bfde6a..1f3c060d028 100644 --- a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h +++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BasicPreconditioners.h @@ -65,10 +65,10 @@ class DiagonalPreconditioner { typename MatType::InnerIterator it(mat,j); while(it && it.index()!=j) ++it; - if(it && it.index()==j) + if(it && it.index()==j && it.value()!=Scalar(0)) m_invdiag(j) = Scalar(1)/it.value(); else - m_invdiag(j) = 0; + m_invdiag(j) = Scalar(1); } m_isInitialized = true; return *this; diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h index 6fc6ab85225..5512219076b 100644 --- a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h +++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/BiCGSTAB.h @@ -39,7 +39,6 @@ bool bicgstab(const MatrixType& mat, const Rhs& rhs, Dest& x, int maxIters = iters; int n = mat.cols(); - x = precond.solve(x); VectorType r = rhs - mat * x; VectorType r0 = r; @@ -61,6 +60,7 @@ bool bicgstab(const MatrixType& mat, const Rhs& rhs, Dest& x, VectorType s(n), t(n); RealScalar tol2 = tol*tol; + RealScalar eps2 = NumTraits<Scalar>::epsilon()*NumTraits<Scalar>::epsilon(); int i = 0; int restarts = 0; @@ -69,7 +69,7 @@ bool bicgstab(const MatrixType& mat, const Rhs& rhs, Dest& x, Scalar rho_old = rho; rho = r0.dot(r); - if (internal::isMuchSmallerThan(rho,r0_sqnorm)) + if (abs(rho) < eps2*r0_sqnorm) { // The new residual vector became too orthogonal to the arbitrarily choosen direction r0 // Let's restart with a new r0: @@ -142,7 +142,7 @@ struct traits<BiCGSTAB<_MatrixType,_Preconditioner> > * SparseMatrix<double> A(n,n); * // fill A and b * BiCGSTAB<SparseMatrix<double> > solver; - * solver(A); + * solver.compute(A); * x = solver.solve(b); * std::cout << "#iterations: " << solver.iterations() << std::endl; * std::cout << "estimated error: " << solver.error() << std::endl; @@ -151,20 +151,7 @@ struct traits<BiCGSTAB<_MatrixType,_Preconditioner> > * \endcode * * By default the iterations start with x=0 as an initial guess of the solution. - * One can control the start using the solveWithGuess() method. Here is a step by - * step execution example starting with a random guess and printing the evolution - * of the estimated error: - * * \code - * x = VectorXd::Random(n); - * solver.setMaxIterations(1); - * int i = 0; - * do { - * x = solver.solveWithGuess(b,x); - * std::cout << i << " : " << solver.error() << std::endl; - * ++i; - * } while (solver.info()!=Success && i<100); - * \endcode - * Note that such a step by step excution is slightly slower. + * One can control the start using the solveWithGuess() method. * * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner */ @@ -199,7 +186,8 @@ public: * this class becomes invalid. Call compute() to update it with the new * matrix A, or modify a copy of A. */ - BiCGSTAB(const MatrixType& A) : Base(A) {} + template<typename MatrixDerived> + explicit BiCGSTAB(const EigenBase<MatrixDerived>& A) : Base(A.derived()) {} ~BiCGSTAB() {} diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h index a74a8155e68..1a7e569c806 100644 --- a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h +++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/ConjugateGradient.h @@ -112,9 +112,9 @@ struct traits<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> > * This class allows to solve for A.x = b sparse linear problems using a conjugate gradient algorithm. * The sparse matrix A must be selfadjoint. The vectors x and b can be either dense or sparse. * - * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix. - * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower - * or Upper. Default is Lower. + * \tparam _MatrixType the type of the matrix A, can be a dense or a sparse matrix. + * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower, + * Upper, or Lower|Upper in which the full matrix entries will be considered. Default is Lower. * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner * * The maximal number of iterations and tolerance value can be controlled via the setMaxIterations() @@ -137,20 +137,7 @@ struct traits<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> > * \endcode * * By default the iterations start with x=0 as an initial guess of the solution. - * One can control the start using the solveWithGuess() method. Here is a step by - * step execution example starting with a random guess and printing the evolution - * of the estimated error: - * * \code - * x = VectorXd::Random(n); - * cg.setMaxIterations(1); - * int i = 0; - * do { - * x = cg.solveWithGuess(b,x); - * std::cout << i << " : " << cg.error() << std::endl; - * ++i; - * } while (cg.info()!=Success && i<100); - * \endcode - * Note that such a step by step excution is slightly slower. + * One can control the start using the solveWithGuess() method. * * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner */ @@ -189,7 +176,8 @@ public: * this class becomes invalid. Call compute() to update it with the new * matrix A, or modify a copy of A. */ - ConjugateGradient(const MatrixType& A) : Base(A) {} + template<typename MatrixDerived> + explicit ConjugateGradient(const EigenBase<MatrixDerived>& A) : Base(A.derived()) {} ~ConjugateGradient() {} @@ -213,6 +201,10 @@ public: template<typename Rhs,typename Dest> void _solveWithGuess(const Rhs& b, Dest& x) const { + typedef typename internal::conditional<UpLo==(Lower|Upper), + const MatrixType&, + SparseSelfAdjointView<const MatrixType, UpLo> + >::type MatrixWrapperType; m_iterations = Base::maxIterations(); m_error = Base::m_tolerance; @@ -222,8 +214,7 @@ public: m_error = Base::m_tolerance; typename Dest::ColXpr xj(x,j); - internal::conjugate_gradient(mp_matrix->template selfadjointView<UpLo>(), b.col(j), xj, - Base::m_preconditioner, m_iterations, m_error); + internal::conjugate_gradient(MatrixWrapperType(*mp_matrix), b.col(j), xj, Base::m_preconditioner, m_iterations, m_error); } m_isInitialized = true; @@ -234,7 +225,7 @@ public: template<typename Rhs,typename Dest> void _solve(const Rhs& b, Dest& x) const { - x.setOnes(); + x.setZero(); _solveWithGuess(b,x); } diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h index b55afc13636..d3f37fea2a1 100644 --- a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h +++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IncompleteLUT.h @@ -150,7 +150,6 @@ class IncompleteLUT : internal::noncopyable { analyzePattern(amat); factorize(amat); - m_isInitialized = m_factorizationIsOk; return *this; } @@ -160,7 +159,7 @@ class IncompleteLUT : internal::noncopyable template<typename Rhs, typename Dest> void _solve(const Rhs& b, Dest& x) const { - x = m_Pinv * b; + x = m_Pinv * b; x = m_lu.template triangularView<UnitLower>().solve(x); x = m_lu.template triangularView<Upper>().solve(x); x = m_P * x; @@ -223,18 +222,29 @@ template<typename _MatrixType> void IncompleteLUT<Scalar>::analyzePattern(const _MatrixType& amat) { // Compute the Fill-reducing permutation + // Since ILUT does not perform any numerical pivoting, + // it is highly preferable to keep the diagonal through symmetric permutations. +#ifndef EIGEN_MPL2_ONLY + // To this end, let's symmetrize the pattern and perform AMD on it. SparseMatrix<Scalar,ColMajor, Index> mat1 = amat; SparseMatrix<Scalar,ColMajor, Index> mat2 = amat.transpose(); - // Symmetrize the pattern // FIXME for a matrix with nearly symmetric pattern, mat2+mat1 is the appropriate choice. // on the other hand for a really non-symmetric pattern, mat2*mat1 should be prefered... SparseMatrix<Scalar,ColMajor, Index> AtA = mat2 + mat1; - AtA.prune(keep_diag()); - internal::minimum_degree_ordering<Scalar, Index>(AtA, m_P); // Then compute the AMD ordering... - - m_Pinv = m_P.inverse(); // ... and the inverse permutation + AMDOrdering<Index> ordering; + ordering(AtA,m_P); + m_Pinv = m_P.inverse(); // cache the inverse permutation +#else + // If AMD is not available, (MPL2-only), then let's use the slower COLAMD routine. + SparseMatrix<Scalar,ColMajor, Index> mat1 = amat; + COLAMDOrdering<Index> ordering; + ordering(mat1,m_Pinv); + m_P = m_Pinv.inverse(); +#endif m_analysisIsOk = true; + m_factorizationIsOk = false; + m_isInitialized = false; } template <typename Scalar> @@ -442,6 +452,7 @@ void IncompleteLUT<Scalar>::factorize(const _MatrixType& amat) m_lu.makeCompressed(); m_factorizationIsOk = true; + m_isInitialized = m_factorizationIsOk; m_info = Success; } diff --git a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h index 2036922d69c..501ef2f8d87 100644 --- a/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h +++ b/extern/Eigen3/Eigen/src/IterativeLinearSolvers/IterativeSolverBase.h @@ -49,10 +49,11 @@ public: * this class becomes invalid. Call compute() to update it with the new * matrix A, or modify a copy of A. */ - IterativeSolverBase(const MatrixType& A) + template<typename InputDerived> + IterativeSolverBase(const EigenBase<InputDerived>& A) { init(); - compute(A); + compute(A.derived()); } ~IterativeSolverBase() {} @@ -62,9 +63,11 @@ public: * Currently, this function mostly call analyzePattern on the preconditioner. In the future * we might, for instance, implement column reodering for faster matrix vector products. */ - Derived& analyzePattern(const MatrixType& A) + template<typename InputDerived> + Derived& analyzePattern(const EigenBase<InputDerived>& A) { - m_preconditioner.analyzePattern(A); + grabInput(A.derived()); + m_preconditioner.analyzePattern(*mp_matrix); m_isInitialized = true; m_analysisIsOk = true; m_info = Success; @@ -80,11 +83,12 @@ public: * this class becomes invalid. Call compute() to update it with the new * matrix A, or modify a copy of A. */ - Derived& factorize(const MatrixType& A) + template<typename InputDerived> + Derived& factorize(const EigenBase<InputDerived>& A) { + grabInput(A.derived()); eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); - mp_matrix = &A; - m_preconditioner.factorize(A); + m_preconditioner.factorize(*mp_matrix); m_factorizationIsOk = true; m_info = Success; return derived(); @@ -100,10 +104,11 @@ public: * this class becomes invalid. Call compute() to update it with the new * matrix A, or modify a copy of A. */ - Derived& compute(const MatrixType& A) + template<typename InputDerived> + Derived& compute(const EigenBase<InputDerived>& A) { - mp_matrix = &A; - m_preconditioner.compute(A); + grabInput(A.derived()); + m_preconditioner.compute(*mp_matrix); m_isInitialized = true; m_analysisIsOk = true; m_factorizationIsOk = true; @@ -212,6 +217,28 @@ public: } protected: + + template<typename InputDerived> + void grabInput(const EigenBase<InputDerived>& A) + { + // we const cast to prevent the creation of a MatrixType temporary by the compiler. + grabInput_impl(A.const_cast_derived()); + } + + template<typename InputDerived> + void grabInput_impl(const EigenBase<InputDerived>& A) + { + m_copyMatrix = A; + mp_matrix = &m_copyMatrix; + } + + void grabInput_impl(MatrixType& A) + { + if(MatrixType::RowsAtCompileTime==Dynamic && MatrixType::ColsAtCompileTime==Dynamic) + m_copyMatrix.resize(0,0); + mp_matrix = &A; + } + void init() { m_isInitialized = false; @@ -220,6 +247,7 @@ protected: m_maxIterations = -1; m_tolerance = NumTraits<Scalar>::epsilon(); } + MatrixType m_copyMatrix; const MatrixType* mp_matrix; Preconditioner m_preconditioner; diff --git a/extern/Eigen3/Eigen/src/LU/FullPivLU.h b/extern/Eigen3/Eigen/src/LU/FullPivLU.h index dfe25f424d7..26bc714475c 100644 --- a/extern/Eigen3/Eigen/src/LU/FullPivLU.h +++ b/extern/Eigen3/Eigen/src/LU/FullPivLU.h @@ -20,10 +20,11 @@ namespace Eigen { * * \param MatrixType the type of the matrix of which we are computing the LU decomposition * - * This class represents a LU decomposition of any matrix, with complete pivoting: the matrix A - * is decomposed as A = PLUQ where L is unit-lower-triangular, U is upper-triangular, and P and Q - * are permutation matrices. This is a rank-revealing LU decomposition. The eigenvalues (diagonal - * coefficients) of U are sorted in such a way that any zeros are at the end. + * This class represents a LU decomposition of any matrix, with complete pivoting: the matrix A is + * decomposed as \f$ A = P^{-1} L U Q^{-1} \f$ where L is unit-lower-triangular, U is + * upper-triangular, and P and Q are permutation matrices. This is a rank-revealing LU + * decomposition. The eigenvalues (diagonal coefficients) of U are sorted in such a way that any + * zeros are at the end. * * This decomposition provides the generic approach to solving systems of linear equations, computing * the rank, invertibility, inverse, kernel, and determinant. @@ -373,6 +374,12 @@ template<typename _MatrixType> class FullPivLU inline Index cols() const { return m_lu.cols(); } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_lu; PermutationPType m_p; PermutationQType m_q; @@ -417,6 +424,8 @@ FullPivLU<MatrixType>::FullPivLU(const MatrixType& matrix) template<typename MatrixType> FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix) { + check_template_parameters(); + // the permutations are stored as int indices, so just to be sure: eigen_assert(matrix.rows()<=NumTraits<int>::highest() && matrix.cols()<=NumTraits<int>::highest()); @@ -511,8 +520,8 @@ typename internal::traits<MatrixType>::Scalar FullPivLU<MatrixType>::determinant } /** \returns the matrix represented by the decomposition, - * i.e., it returns the product: P^{-1} L U Q^{-1}. - * This function is provided for debug purpose. */ + * i.e., it returns the product: \f$ P^{-1} L U Q^{-1} \f$. + * This function is provided for debug purposes. */ template<typename MatrixType> MatrixType FullPivLU<MatrixType>::reconstructedMatrix() const { diff --git a/extern/Eigen3/Eigen/src/LU/PartialPivLU.h b/extern/Eigen3/Eigen/src/LU/PartialPivLU.h index 740ee694c45..7d1db948c0a 100644 --- a/extern/Eigen3/Eigen/src/LU/PartialPivLU.h +++ b/extern/Eigen3/Eigen/src/LU/PartialPivLU.h @@ -171,6 +171,12 @@ template<typename _MatrixType> class PartialPivLU inline Index cols() const { return m_lu.cols(); } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_lu; PermutationType m_p; TranspositionType m_rowsTranspositions; @@ -386,6 +392,8 @@ void partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, t template<typename MatrixType> PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const MatrixType& matrix) { + check_template_parameters(); + // the row permutation is stored as int indices, so just to be sure: eigen_assert(matrix.rows()<NumTraits<int>::highest()); diff --git a/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h b/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h index 41b4fd7e392..70550b8a90a 100644 --- a/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h +++ b/extern/Eigen3/Eigen/src/OrderingMethods/Amd.h @@ -137,22 +137,27 @@ void minimum_degree_ordering(SparseMatrix<Scalar,ColMajor,Index>& C, Permutation degree[i] = len[i]; // degree of node i } mark = internal::cs_wclear<Index>(0, 0, w, n); /* clear w */ - elen[n] = -2; /* n is a dead element */ - Cp[n] = -1; /* n is a root of assembly tree */ - w[n] = 0; /* n is a dead element */ /* --- Initialize degree lists ------------------------------------------ */ for(i = 0; i < n; i++) { + bool has_diag = false; + for(p = Cp[i]; p<Cp[i+1]; ++p) + if(Ci[p]==i) + { + has_diag = true; + break; + } + d = degree[i]; - if(d == 0) /* node i is empty */ + if(d == 1 && has_diag) /* node i is empty */ { elen[i] = -2; /* element i is dead */ nel++; Cp[i] = -1; /* i is a root of assembly tree */ w[i] = 0; } - else if(d > dense) /* node i is dense */ + else if(d > dense || !has_diag) /* node i is dense or has no structural diagonal element */ { nv[i] = 0; /* absorb i into element n */ elen[i] = -1; /* node i is dead */ @@ -168,6 +173,10 @@ void minimum_degree_ordering(SparseMatrix<Scalar,ColMajor,Index>& C, Permutation } } + elen[n] = -2; /* n is a dead element */ + Cp[n] = -1; /* n is a root of assembly tree */ + w[n] = 0; /* n is a dead element */ + while (nel < n) /* while (selecting pivots) do */ { /* --- Select node of minimum approximate degree -------------------- */ diff --git a/extern/Eigen3/Eigen/src/OrderingMethods/Ordering.h b/extern/Eigen3/Eigen/src/OrderingMethods/Ordering.h index b4da6531a1d..f3c31f9cbfc 100644 --- a/extern/Eigen3/Eigen/src/OrderingMethods/Ordering.h +++ b/extern/Eigen3/Eigen/src/OrderingMethods/Ordering.h @@ -109,7 +109,7 @@ class NaturalOrdering * \class COLAMDOrdering * * Functor computing the \em column \em approximate \em minimum \em degree ordering - * The matrix should be in column-major format + * The matrix should be in column-major and \b compressed format (see SparseMatrix::makeCompressed()). */ template<typename Index> class COLAMDOrdering @@ -118,10 +118,14 @@ class COLAMDOrdering typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType; typedef Matrix<Index, Dynamic, 1> IndexVector; - /** Compute the permutation vector form a sparse matrix */ + /** Compute the permutation vector \a perm form the sparse matrix \a mat + * \warning The input sparse matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()). + */ template <typename MatrixType> void operator() (const MatrixType& mat, PermutationType& perm) { + eigen_assert(mat.isCompressed() && "COLAMDOrdering requires a sparse matrix in compressed mode. Call .makeCompressed() before passing it to COLAMDOrdering"); + Index m = mat.rows(); Index n = mat.cols(); Index nnz = mat.nonZeros(); @@ -132,12 +136,12 @@ class COLAMDOrdering Index stats [COLAMD_STATS]; internal::colamd_set_defaults(knobs); - Index info; IndexVector p(n+1), A(Alen); for(Index i=0; i <= n; i++) p(i) = mat.outerIndexPtr()[i]; for(Index i=0; i < nnz; i++) A(i) = mat.innerIndexPtr()[i]; // Call Colamd routine to compute the ordering - info = internal::colamd(m, n, Alen, A.data(), p.data(), knobs, stats); + Index info = internal::colamd(m, n, Alen, A.data(), p.data(), knobs, stats); + EIGEN_UNUSED_VARIABLE(info); eigen_assert( info && "COLAMD failed " ); perm.resize(n); diff --git a/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h b/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h index 1c48f0df7b5..18cd7d88aea 100644 --- a/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h +++ b/extern/Eigen3/Eigen/src/PardisoSupport/PardisoSupport.h @@ -219,7 +219,7 @@ class PardisoImpl void pardisoInit(int type) { m_type = type; - bool symmetric = abs(m_type) < 10; + bool symmetric = std::abs(m_type) < 10; m_iparm[0] = 1; // No solver default m_iparm[1] = 3; // use Metis for the ordering m_iparm[2] = 1; // Numbers of processors, value of OMP_NUM_THREADS diff --git a/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h b/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h index bec85810ccc..567eab7cda5 100644 --- a/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h +++ b/extern/Eigen3/Eigen/src/QR/ColPivHouseholderQR.h @@ -76,7 +76,8 @@ template<typename _MatrixType> class ColPivHouseholderQR m_colsTranspositions(), m_temp(), m_colSqNorms(), - m_isInitialized(false) {} + m_isInitialized(false), + m_usePrescribedThreshold(false) {} /** \brief Default Constructor with memory preallocation * @@ -383,6 +384,12 @@ template<typename _MatrixType> class ColPivHouseholderQR } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_qr; HCoeffsType m_hCoeffs; PermutationType m_colsPermutation; @@ -421,6 +428,8 @@ typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::logAbsDetermina template<typename MatrixType> ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix) { + check_template_parameters(); + using std::abs; Index rows = matrix.rows(); Index cols = matrix.cols(); @@ -462,20 +471,10 @@ ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const // we store that back into our table: it can't hurt to correct our table. m_colSqNorms.coeffRef(biggest_col_index) = biggest_col_sq_norm; - // if the current biggest column is smaller than epsilon times the initial biggest column, - // terminate to avoid generating nan/inf values. - // Note that here, if we test instead for "biggest == 0", we get a failure every 1000 (or so) - // repetitions of the unit test, with the result of solve() filled with large values of the order - // of 1/(size*epsilon). - if(biggest_col_sq_norm < threshold_helper * RealScalar(rows-k)) - { + // Track the number of meaningful pivots but do not stop the decomposition to make + // sure that the initial matrix is properly reproduced. See bug 941. + if(m_nonzero_pivots==size && biggest_col_sq_norm < threshold_helper * RealScalar(rows-k)) m_nonzero_pivots = k; - m_hCoeffs.tail(size-k).setZero(); - m_qr.bottomRightCorner(rows-k,cols-k) - .template triangularView<StrictlyLower>() - .setZero(); - break; - } // apply the transposition to the columns m_colsTranspositions.coeffRef(k) = biggest_col_index; @@ -504,7 +503,7 @@ ColPivHouseholderQR<MatrixType>& ColPivHouseholderQR<MatrixType>::compute(const } m_colsPermutation.setIdentity(PermIndexType(cols)); - for(PermIndexType k = 0; k < m_nonzero_pivots; ++k) + for(PermIndexType k = 0; k < size/*m_nonzero_pivots*/; ++k) m_colsPermutation.applyTranspositionOnTheRight(k, PermIndexType(m_colsTranspositions.coeff(k))); m_det_pq = (number_of_transpositions%2) ? -1 : 1; @@ -554,13 +553,15 @@ struct solve_retval<ColPivHouseholderQR<_MatrixType>, Rhs> } // end namespace internal -/** \returns the matrix Q as a sequence of householder transformations */ +/** \returns the matrix Q as a sequence of householder transformations. + * You can extract the meaningful part only by using: + * \code qr.householderQ().setLength(qr.nonzeroPivots()) \endcode*/ template<typename MatrixType> typename ColPivHouseholderQR<MatrixType>::HouseholderSequenceType ColPivHouseholderQR<MatrixType> ::householderQ() const { eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized."); - return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()).setLength(m_nonzero_pivots); + return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()); } /** \return the column-pivoting Householder QR decomposition of \c *this. diff --git a/extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h b/extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h index 6168e7abfb4..0b39966e145 100644 --- a/extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h +++ b/extern/Eigen3/Eigen/src/QR/FullPivHouseholderQR.h @@ -368,6 +368,12 @@ template<typename _MatrixType> class FullPivHouseholderQR RealScalar maxPivot() const { return m_maxpivot; } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_qr; HCoeffsType m_hCoeffs; IntDiagSizeVectorType m_rows_transpositions; @@ -407,6 +413,8 @@ typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::logAbsDetermin template<typename MatrixType> FullPivHouseholderQR<MatrixType>& FullPivHouseholderQR<MatrixType>::compute(const MatrixType& matrix) { + check_template_parameters(); + using std::abs; Index rows = matrix.rows(); Index cols = matrix.cols(); diff --git a/extern/Eigen3/Eigen/src/QR/HouseholderQR.h b/extern/Eigen3/Eigen/src/QR/HouseholderQR.h index abc61bcbbe1..343a6649934 100644 --- a/extern/Eigen3/Eigen/src/QR/HouseholderQR.h +++ b/extern/Eigen3/Eigen/src/QR/HouseholderQR.h @@ -189,6 +189,12 @@ template<typename _MatrixType> class HouseholderQR const HCoeffsType& hCoeffs() const { return m_hCoeffs; } protected: + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } + MatrixType m_qr; HCoeffsType m_hCoeffs; RowVectorType m_temp; @@ -251,56 +257,62 @@ void householder_qr_inplace_unblocked(MatrixQR& mat, HCoeffs& hCoeffs, typename } /** \internal */ -template<typename MatrixQR, typename HCoeffs> -void householder_qr_inplace_blocked(MatrixQR& mat, HCoeffs& hCoeffs, - typename MatrixQR::Index maxBlockSize=32, - typename MatrixQR::Scalar* tempData = 0) +template<typename MatrixQR, typename HCoeffs, + typename MatrixQRScalar = typename MatrixQR::Scalar, + bool InnerStrideIsOne = (MatrixQR::InnerStrideAtCompileTime == 1 && HCoeffs::InnerStrideAtCompileTime == 1)> +struct householder_qr_inplace_blocked { - typedef typename MatrixQR::Index Index; - typedef typename MatrixQR::Scalar Scalar; - typedef Block<MatrixQR,Dynamic,Dynamic> BlockType; - - Index rows = mat.rows(); - Index cols = mat.cols(); - Index size = (std::min)(rows, cols); - - typedef Matrix<Scalar,Dynamic,1,ColMajor,MatrixQR::MaxColsAtCompileTime,1> TempType; - TempType tempVector; - if(tempData==0) + // This is specialized for MKL-supported Scalar types in HouseholderQR_MKL.h + static void run(MatrixQR& mat, HCoeffs& hCoeffs, + typename MatrixQR::Index maxBlockSize=32, + typename MatrixQR::Scalar* tempData = 0) { - tempVector.resize(cols); - tempData = tempVector.data(); - } - - Index blockSize = (std::min)(maxBlockSize,size); + typedef typename MatrixQR::Index Index; + typedef typename MatrixQR::Scalar Scalar; + typedef Block<MatrixQR,Dynamic,Dynamic> BlockType; - Index k = 0; - for (k = 0; k < size; k += blockSize) - { - Index bs = (std::min)(size-k,blockSize); // actual size of the block - Index tcols = cols - k - bs; // trailing columns - Index brows = rows-k; // rows of the block + Index rows = mat.rows(); + Index cols = mat.cols(); + Index size = (std::min)(rows, cols); - // partition the matrix: - // A00 | A01 | A02 - // mat = A10 | A11 | A12 - // A20 | A21 | A22 - // and performs the qr dec of [A11^T A12^T]^T - // and update [A21^T A22^T]^T using level 3 operations. - // Finally, the algorithm continue on A22 - - BlockType A11_21 = mat.block(k,k,brows,bs); - Block<HCoeffs,Dynamic,1> hCoeffsSegment = hCoeffs.segment(k,bs); + typedef Matrix<Scalar,Dynamic,1,ColMajor,MatrixQR::MaxColsAtCompileTime,1> TempType; + TempType tempVector; + if(tempData==0) + { + tempVector.resize(cols); + tempData = tempVector.data(); + } - householder_qr_inplace_unblocked(A11_21, hCoeffsSegment, tempData); + Index blockSize = (std::min)(maxBlockSize,size); - if(tcols) + Index k = 0; + for (k = 0; k < size; k += blockSize) { - BlockType A21_22 = mat.block(k,k+bs,brows,tcols); - apply_block_householder_on_the_left(A21_22,A11_21,hCoeffsSegment.adjoint()); + Index bs = (std::min)(size-k,blockSize); // actual size of the block + Index tcols = cols - k - bs; // trailing columns + Index brows = rows-k; // rows of the block + + // partition the matrix: + // A00 | A01 | A02 + // mat = A10 | A11 | A12 + // A20 | A21 | A22 + // and performs the qr dec of [A11^T A12^T]^T + // and update [A21^T A22^T]^T using level 3 operations. + // Finally, the algorithm continue on A22 + + BlockType A11_21 = mat.block(k,k,brows,bs); + Block<HCoeffs,Dynamic,1> hCoeffsSegment = hCoeffs.segment(k,bs); + + householder_qr_inplace_unblocked(A11_21, hCoeffsSegment, tempData); + + if(tcols) + { + BlockType A21_22 = mat.block(k,k+bs,brows,tcols); + apply_block_householder_on_the_left(A21_22,A11_21,hCoeffsSegment.adjoint()); + } } } -} +}; template<typename _MatrixType, typename Rhs> struct solve_retval<HouseholderQR<_MatrixType>, Rhs> @@ -343,6 +355,8 @@ struct solve_retval<HouseholderQR<_MatrixType>, Rhs> template<typename MatrixType> HouseholderQR<MatrixType>& HouseholderQR<MatrixType>::compute(const MatrixType& matrix) { + check_template_parameters(); + Index rows = matrix.rows(); Index cols = matrix.cols(); Index size = (std::min)(rows,cols); @@ -352,7 +366,7 @@ HouseholderQR<MatrixType>& HouseholderQR<MatrixType>::compute(const MatrixType& m_temp.resize(cols); - internal::householder_qr_inplace_blocked(m_qr, m_hCoeffs, 48, m_temp.data()); + internal::householder_qr_inplace_blocked<MatrixType, HCoeffsType>::run(m_qr, m_hCoeffs, 48, m_temp.data()); m_isInitialized = true; return *this; diff --git a/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h b/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h index 5313de604d2..b80f1b48dac 100644 --- a/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h +++ b/extern/Eigen3/Eigen/src/QR/HouseholderQR_MKL.h @@ -34,28 +34,30 @@ #ifndef EIGEN_QR_MKL_H #define EIGEN_QR_MKL_H -#include "Eigen/src/Core/util/MKL_support.h" +#include "../Core/util/MKL_support.h" namespace Eigen { -namespace internal { + namespace internal { -/** \internal Specialization for the data types supported by MKL */ + /** \internal Specialization for the data types supported by MKL */ #define EIGEN_MKL_QR_NOPIV(EIGTYPE, MKLTYPE, MKLPREFIX) \ template<typename MatrixQR, typename HCoeffs> \ -void householder_qr_inplace_blocked(MatrixQR& mat, HCoeffs& hCoeffs, \ - typename MatrixQR::Index maxBlockSize=32, \ - EIGTYPE* tempData = 0) \ +struct householder_qr_inplace_blocked<MatrixQR, HCoeffs, EIGTYPE, true> \ { \ - lapack_int m = mat.rows(); \ - lapack_int n = mat.cols(); \ - lapack_int lda = mat.outerStride(); \ - lapack_int matrix_order = (MatrixQR::IsRowMajor) ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ - LAPACKE_##MKLPREFIX##geqrf( matrix_order, m, n, (MKLTYPE*)mat.data(), lda, (MKLTYPE*)hCoeffs.data()); \ - hCoeffs.adjointInPlace(); \ -\ -} + static void run(MatrixQR& mat, HCoeffs& hCoeffs, \ + typename MatrixQR::Index = 32, \ + typename MatrixQR::Scalar* = 0) \ + { \ + lapack_int m = (lapack_int) mat.rows(); \ + lapack_int n = (lapack_int) mat.cols(); \ + lapack_int lda = (lapack_int) mat.outerStride(); \ + lapack_int matrix_order = (MatrixQR::IsRowMajor) ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR; \ + LAPACKE_##MKLPREFIX##geqrf( matrix_order, m, n, (MKLTYPE*)mat.data(), lda, (MKLTYPE*)hCoeffs.data()); \ + hCoeffs.adjointInPlace(); \ + } \ +}; EIGEN_MKL_QR_NOPIV(double, double, d) EIGEN_MKL_QR_NOPIV(float, float, s) diff --git a/extern/Eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h b/extern/Eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h index a2cc2a9e261..36138101d74 100644 --- a/extern/Eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h +++ b/extern/Eigen3/Eigen/src/SPQRSupport/SuiteSparseQRSupport.h @@ -47,7 +47,7 @@ namespace Eigen { * You can then apply it to a vector. * * R is the sparse triangular factor. Use matrixQR() to get it as SparseMatrix. - * NOTE : The Index type of R is always UF_long. You can get it with SPQR::Index + * NOTE : The Index type of R is always SuiteSparse_long. You can get it with SPQR::Index * * \tparam _MatrixType The type of the sparse matrix A, must be a column-major SparseMatrix<> * NOTE @@ -59,24 +59,18 @@ class SPQR public: typedef typename _MatrixType::Scalar Scalar; typedef typename _MatrixType::RealScalar RealScalar; - typedef UF_long Index ; + typedef SuiteSparse_long Index ; typedef SparseMatrix<Scalar, ColMajor, Index> MatrixType; typedef PermutationMatrix<Dynamic, Dynamic> PermutationType; public: SPQR() - : m_isInitialized(false), - m_ordering(SPQR_ORDERING_DEFAULT), - m_allow_tol(SPQR_DEFAULT_TOL), - m_tolerance (NumTraits<Scalar>::epsilon()) + : m_isInitialized(false), m_ordering(SPQR_ORDERING_DEFAULT), m_allow_tol(SPQR_DEFAULT_TOL), m_tolerance (NumTraits<Scalar>::epsilon()), m_useDefaultThreshold(true) { cholmod_l_start(&m_cc); } - SPQR(const _MatrixType& matrix) - : m_isInitialized(false), - m_ordering(SPQR_ORDERING_DEFAULT), - m_allow_tol(SPQR_DEFAULT_TOL), - m_tolerance (NumTraits<Scalar>::epsilon()) + SPQR(const _MatrixType& matrix) + : m_isInitialized(false), m_ordering(SPQR_ORDERING_DEFAULT), m_allow_tol(SPQR_DEFAULT_TOL), m_tolerance (NumTraits<Scalar>::epsilon()), m_useDefaultThreshold(true) { cholmod_l_start(&m_cc); compute(matrix); @@ -101,10 +95,26 @@ class SPQR if(m_isInitialized) SPQR_free(); MatrixType mat(matrix); + + /* Compute the default threshold as in MatLab, see: + * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing + * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3 + */ + RealScalar pivotThreshold = m_tolerance; + if(m_useDefaultThreshold) + { + using std::max; + RealScalar max2Norm = 0.0; + for (int j = 0; j < mat.cols(); j++) max2Norm = (max)(max2Norm, mat.col(j).norm()); + if(max2Norm==RealScalar(0)) + max2Norm = RealScalar(1); + pivotThreshold = 20 * (mat.rows() + mat.cols()) * max2Norm * NumTraits<RealScalar>::epsilon(); + } + cholmod_sparse A; A = viewAsCholmod(mat); Index col = matrix.cols(); - m_rank = SuiteSparseQR<Scalar>(m_ordering, m_tolerance, col, &A, + m_rank = SuiteSparseQR<Scalar>(m_ordering, pivotThreshold, col, &A, &m_cR, &m_E, &m_H, &m_HPinv, &m_HTau, &m_cc); if (!m_cR) @@ -120,7 +130,7 @@ class SPQR /** * Get the number of rows of the input matrix and the Q matrix */ - inline Index rows() const {return m_H->nrow; } + inline Index rows() const {return m_cR->nrow; } /** * Get the number of columns of the input matrix. @@ -145,16 +155,25 @@ class SPQR { eigen_assert(m_isInitialized && " The QR factorization should be computed first, call compute()"); eigen_assert(b.cols()==1 && "This method is for vectors only"); - + //Compute Q^T * b - typename Dest::PlainObject y; + typename Dest::PlainObject y, y2; y = matrixQ().transpose() * b; - // Solves with the triangular matrix R + + // Solves with the triangular matrix R Index rk = this->rank(); - y.topRows(rk) = this->matrixR().topLeftCorner(rk, rk).template triangularView<Upper>().solve(y.topRows(rk)); - y.bottomRows(cols()-rk).setZero(); + y2 = y; + y.resize((std::max)(cols(),Index(y.rows())),y.cols()); + y.topRows(rk) = this->matrixR().topLeftCorner(rk, rk).template triangularView<Upper>().solve(y2.topRows(rk)); + // Apply the column permutation - dest.topRows(cols()) = colsPermutation() * y.topRows(cols()); + // colsPermutation() performs a copy of the permutation, + // so let's apply it manually: + for(Index i = 0; i < rk; ++i) dest.row(m_E[i]) = y.row(i); + for(Index i = rk; i < cols(); ++i) dest.row(m_E[i]).setZero(); + +// y.bottomRows(y.rows()-rk).setZero(); +// dest = colsPermutation() * y.topRows(cols()); m_info = Success; } @@ -197,7 +216,11 @@ class SPQR /// Set the fill-reducing ordering method to be used void setSPQROrdering(int ord) { m_ordering = ord;} /// Set the tolerance tol to treat columns with 2-norm < =tol as zero - void setPivotThreshold(const RealScalar& tol) { m_tolerance = tol; } + void setPivotThreshold(const RealScalar& tol) + { + m_useDefaultThreshold = false; + m_tolerance = tol; + } /** \returns a pointer to the SPQR workspace */ cholmod_common *cholmodCommon() const { return &m_cc; } @@ -230,6 +253,7 @@ class SPQR mutable cholmod_dense *m_HTau; // The Householder coefficients mutable Index m_rank; // The rank of the matrix mutable cholmod_common m_cc; // Workspace and parameters + bool m_useDefaultThreshold; // Use default threshold template<typename ,typename > friend struct SPQR_QProduct; }; diff --git a/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h b/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h index f44995cd39c..1b29774190a 100644 --- a/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h +++ b/extern/Eigen3/Eigen/src/SVD/JacobiSVD.h @@ -375,17 +375,19 @@ struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, true> Scalar z; JacobiRotation<Scalar> rot; RealScalar n = sqrt(numext::abs2(work_matrix.coeff(p,p)) + numext::abs2(work_matrix.coeff(q,p))); + if(n==0) { z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q); work_matrix.row(p) *= z; if(svd.computeU()) svd.m_matrixU.col(p) *= conj(z); if(work_matrix.coeff(q,q)!=Scalar(0)) + { z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q); - else - z = Scalar(0); - work_matrix.row(q) *= z; - if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z); + work_matrix.row(q) *= z; + if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z); + } + // otherwise the second row is already zero, so we have nothing to do. } else { @@ -415,6 +417,7 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q, JacobiRotation<RealScalar> *j_right) { using std::sqrt; + using std::abs; Matrix<RealScalar,2,2> m; m << numext::real(matrix.coeff(p,p)), numext::real(matrix.coeff(p,q)), numext::real(matrix.coeff(q,p)), numext::real(matrix.coeff(q,q)); @@ -428,9 +431,11 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q, } else { - RealScalar u = d / t; - rot1.c() = RealScalar(1) / sqrt(RealScalar(1) + numext::abs2(u)); - rot1.s() = rot1.c() * u; + RealScalar t2d2 = numext::hypot(t,d); + rot1.c() = abs(t)/t2d2; + rot1.s() = d/t2d2; + if(t<RealScalar(0)) + rot1.s() = -rot1.s(); } m.applyOnTheLeft(0,1,rot1); j_right->makeJacobi(m,0,1); @@ -531,8 +536,9 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD JacobiSVD() : m_isInitialized(false), m_isAllocated(false), + m_usePrescribedThreshold(false), m_computationOptions(0), - m_rows(-1), m_cols(-1) + m_rows(-1), m_cols(-1), m_diagSize(0) {} @@ -545,6 +551,7 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD JacobiSVD(Index rows, Index cols, unsigned int computationOptions = 0) : m_isInitialized(false), m_isAllocated(false), + m_usePrescribedThreshold(false), m_computationOptions(0), m_rows(-1), m_cols(-1) { @@ -564,6 +571,7 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD JacobiSVD(const MatrixType& matrix, unsigned int computationOptions = 0) : m_isInitialized(false), m_isAllocated(false), + m_usePrescribedThreshold(false), m_computationOptions(0), m_rows(-1), m_cols(-1) { @@ -665,23 +673,92 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); return m_nonzeroSingularValues; } + + /** \returns the rank of the matrix of which \c *this is the SVD. + * + * \note This method has to determine which singular values should be considered nonzero. + * For that, it uses the threshold value that you can control by calling + * setThreshold(const RealScalar&). + */ + inline Index rank() const + { + using std::abs; + eigen_assert(m_isInitialized && "JacobiSVD is not initialized."); + if(m_singularValues.size()==0) return 0; + RealScalar premultiplied_threshold = m_singularValues.coeff(0) * threshold(); + Index i = m_nonzeroSingularValues-1; + while(i>=0 && m_singularValues.coeff(i) < premultiplied_threshold) --i; + return i+1; + } + + /** Allows to prescribe a threshold to be used by certain methods, such as rank() and solve(), + * which need to determine when singular values are to be considered nonzero. + * This is not used for the SVD decomposition itself. + * + * When it needs to get the threshold value, Eigen calls threshold(). + * The default is \c NumTraits<Scalar>::epsilon() + * + * \param threshold The new value to use as the threshold. + * + * A singular value will be considered nonzero if its value is strictly greater than + * \f$ \vert singular value \vert \leqslant threshold \times \vert max singular value \vert \f$. + * + * If you want to come back to the default behavior, call setThreshold(Default_t) + */ + JacobiSVD& setThreshold(const RealScalar& threshold) + { + m_usePrescribedThreshold = true; + m_prescribedThreshold = threshold; + return *this; + } + + /** Allows to come back to the default behavior, letting Eigen use its default formula for + * determining the threshold. + * + * You should pass the special object Eigen::Default as parameter here. + * \code svd.setThreshold(Eigen::Default); \endcode + * + * See the documentation of setThreshold(const RealScalar&). + */ + JacobiSVD& setThreshold(Default_t) + { + m_usePrescribedThreshold = false; + return *this; + } + + /** Returns the threshold that will be used by certain methods such as rank(). + * + * See the documentation of setThreshold(const RealScalar&). + */ + RealScalar threshold() const + { + eigen_assert(m_isInitialized || m_usePrescribedThreshold); + return m_usePrescribedThreshold ? m_prescribedThreshold + : (std::max<Index>)(1,m_diagSize)*NumTraits<Scalar>::epsilon(); + } inline Index rows() const { return m_rows; } inline Index cols() const { return m_cols; } private: void allocate(Index rows, Index cols, unsigned int computationOptions); + + static void check_template_parameters() + { + EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar); + } protected: MatrixUType m_matrixU; MatrixVType m_matrixV; SingularValuesType m_singularValues; WorkMatrixType m_workMatrix; - bool m_isInitialized, m_isAllocated; + bool m_isInitialized, m_isAllocated, m_usePrescribedThreshold; bool m_computeFullU, m_computeThinU; bool m_computeFullV, m_computeThinV; unsigned int m_computationOptions; Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize; + RealScalar m_prescribedThreshold; template<typename __MatrixType, int _QRPreconditioner, bool _IsComplex> friend struct internal::svd_precondition_2x2_block_to_be_real; @@ -690,6 +767,7 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreColsThanRows> m_qr_precond_morecols; internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreRowsThanCols> m_qr_precond_morerows; + MatrixType m_scaledMatrix; }; template<typename MatrixType, int QRPreconditioner> @@ -736,14 +814,17 @@ void JacobiSVD<MatrixType, QRPreconditioner>::allocate(Index rows, Index cols, u : 0); m_workMatrix.resize(m_diagSize, m_diagSize); - if(m_cols>m_rows) m_qr_precond_morecols.allocate(*this); - if(m_rows>m_cols) m_qr_precond_morerows.allocate(*this); + if(m_cols>m_rows) m_qr_precond_morecols.allocate(*this); + if(m_rows>m_cols) m_qr_precond_morerows.allocate(*this); + if(m_cols!=m_cols) m_scaledMatrix.resize(rows,cols); } template<typename MatrixType, int QRPreconditioner> JacobiSVD<MatrixType, QRPreconditioner>& JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsigned int computationOptions) { + check_template_parameters(); + using std::abs; allocate(matrix.rows(), matrix.cols(), computationOptions); @@ -754,11 +835,21 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig // limit for very small denormal numbers to be considered zero in order to avoid infinite loops (see bug 286) const RealScalar considerAsZero = RealScalar(2) * std::numeric_limits<RealScalar>::denorm_min(); + // Scaling factor to reduce over/under-flows + RealScalar scale = matrix.cwiseAbs().maxCoeff(); + if(scale==RealScalar(0)) scale = RealScalar(1); + /*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */ - if(!m_qr_precond_morecols.run(*this, matrix) && !m_qr_precond_morerows.run(*this, matrix)) + if(m_rows!=m_cols) { - m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize); + m_scaledMatrix = matrix / scale; + m_qr_precond_morecols.run(*this, m_scaledMatrix); + m_qr_precond_morerows.run(*this, m_scaledMatrix); + } + else + { + m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize) / scale; if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows); if(m_computeThinU) m_matrixU.setIdentity(m_rows,m_diagSize); if(m_computeFullV) m_matrixV.setIdentity(m_cols,m_cols); @@ -784,7 +875,8 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig using std::max; RealScalar threshold = (max)(considerAsZero, precision * (max)(abs(m_workMatrix.coeff(p,p)), abs(m_workMatrix.coeff(q,q)))); - if((max)(abs(m_workMatrix.coeff(p,q)),abs(m_workMatrix.coeff(q,p))) > threshold) + // We compare both values to threshold instead of calling max to be robust to NaN (See bug 791) + if(abs(m_workMatrix.coeff(p,q))>threshold || abs(m_workMatrix.coeff(q,p)) > threshold) { finished = false; @@ -833,6 +925,8 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig if(computeV()) m_matrixV.col(pos).swap(m_matrixV.col(i)); } } + + m_singularValues *= scale; m_isInitialized = true; return *this; @@ -854,11 +948,11 @@ struct solve_retval<JacobiSVD<_MatrixType, QRPreconditioner>, Rhs> // So A^{-1} = V S^{-1} U^* Matrix<Scalar, Dynamic, Rhs::ColsAtCompileTime, 0, _MatrixType::MaxRowsAtCompileTime, Rhs::MaxColsAtCompileTime> tmp; - Index nonzeroSingVals = dec().nonzeroSingularValues(); + Index rank = dec().rank(); - tmp.noalias() = dec().matrixU().leftCols(nonzeroSingVals).adjoint() * rhs(); - tmp = dec().singularValues().head(nonzeroSingVals).asDiagonal().inverse() * tmp; - dst = dec().matrixV().leftCols(nonzeroSingVals) * tmp; + tmp.noalias() = dec().matrixU().leftCols(rank).adjoint() * rhs(); + tmp = dec().singularValues().head(rank).asDiagonal().inverse() * tmp; + dst = dec().matrixV().leftCols(rank) * tmp; } }; } // end namespace internal diff --git a/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h b/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h index f41d7e010f7..e1f96ba5a14 100644 --- a/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h +++ b/extern/Eigen3/Eigen/src/SparseCholesky/SimplicialCholesky.h @@ -37,6 +37,7 @@ class SimplicialCholeskyBase : internal::noncopyable { public: typedef typename internal::traits<Derived>::MatrixType MatrixType; + typedef typename internal::traits<Derived>::OrderingType OrderingType; enum { UpLo = internal::traits<Derived>::UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; @@ -240,15 +241,16 @@ class SimplicialCholeskyBase : internal::noncopyable RealScalar m_shiftScale; }; -template<typename _MatrixType, int _UpLo = Lower> class SimplicialLLT; -template<typename _MatrixType, int _UpLo = Lower> class SimplicialLDLT; -template<typename _MatrixType, int _UpLo = Lower> class SimplicialCholesky; +template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::Index> > class SimplicialLLT; +template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::Index> > class SimplicialLDLT; +template<typename _MatrixType, int _UpLo = Lower, typename _Ordering = AMDOrdering<typename _MatrixType::Index> > class SimplicialCholesky; namespace internal { -template<typename _MatrixType, int _UpLo> struct traits<SimplicialLLT<_MatrixType,_UpLo> > +template<typename _MatrixType, int _UpLo, typename _Ordering> struct traits<SimplicialLLT<_MatrixType,_UpLo,_Ordering> > { typedef _MatrixType MatrixType; + typedef _Ordering OrderingType; enum { UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Index Index; @@ -259,9 +261,10 @@ template<typename _MatrixType, int _UpLo> struct traits<SimplicialLLT<_MatrixTyp static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } }; -template<typename _MatrixType,int _UpLo> struct traits<SimplicialLDLT<_MatrixType,_UpLo> > +template<typename _MatrixType,int _UpLo, typename _Ordering> struct traits<SimplicialLDLT<_MatrixType,_UpLo,_Ordering> > { typedef _MatrixType MatrixType; + typedef _Ordering OrderingType; enum { UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Index Index; @@ -272,9 +275,10 @@ template<typename _MatrixType,int _UpLo> struct traits<SimplicialLDLT<_MatrixTyp static inline MatrixU getU(const MatrixType& m) { return m.adjoint(); } }; -template<typename _MatrixType, int _UpLo> struct traits<SimplicialCholesky<_MatrixType,_UpLo> > +template<typename _MatrixType, int _UpLo, typename _Ordering> struct traits<SimplicialCholesky<_MatrixType,_UpLo,_Ordering> > { typedef _MatrixType MatrixType; + typedef _Ordering OrderingType; enum { UpLo = _UpLo }; }; @@ -294,11 +298,12 @@ template<typename _MatrixType, int _UpLo> struct traits<SimplicialCholesky<_Matr * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. + * \tparam _Ordering The ordering method to use, either AMDOrdering<> or NaturalOrdering<>. Default is AMDOrdering<> * - * \sa class SimplicialLDLT + * \sa class SimplicialLDLT, class AMDOrdering, class NaturalOrdering */ -template<typename _MatrixType, int _UpLo> - class SimplicialLLT : public SimplicialCholeskyBase<SimplicialLLT<_MatrixType,_UpLo> > +template<typename _MatrixType, int _UpLo, typename _Ordering> + class SimplicialLLT : public SimplicialCholeskyBase<SimplicialLLT<_MatrixType,_UpLo,_Ordering> > { public: typedef _MatrixType MatrixType; @@ -382,11 +387,12 @@ public: * \tparam _MatrixType the type of the sparse matrix A, it must be a SparseMatrix<> * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower * or Upper. Default is Lower. + * \tparam _Ordering The ordering method to use, either AMDOrdering<> or NaturalOrdering<>. Default is AMDOrdering<> * - * \sa class SimplicialLLT + * \sa class SimplicialLLT, class AMDOrdering, class NaturalOrdering */ -template<typename _MatrixType, int _UpLo> - class SimplicialLDLT : public SimplicialCholeskyBase<SimplicialLDLT<_MatrixType,_UpLo> > +template<typename _MatrixType, int _UpLo, typename _Ordering> + class SimplicialLDLT : public SimplicialCholeskyBase<SimplicialLDLT<_MatrixType,_UpLo,_Ordering> > { public: typedef _MatrixType MatrixType; @@ -467,8 +473,8 @@ public: * * \sa class SimplicialLDLT, class SimplicialLLT */ -template<typename _MatrixType, int _UpLo> - class SimplicialCholesky : public SimplicialCholeskyBase<SimplicialCholesky<_MatrixType,_UpLo> > +template<typename _MatrixType, int _UpLo, typename _Ordering> + class SimplicialCholesky : public SimplicialCholeskyBase<SimplicialCholesky<_MatrixType,_UpLo,_Ordering> > { public: typedef _MatrixType MatrixType; @@ -612,15 +618,13 @@ void SimplicialCholeskyBase<Derived>::ordering(const MatrixType& a, CholMatrixTy { eigen_assert(a.rows()==a.cols()); const Index size = a.rows(); - // TODO allows to configure the permutation // Note that amd compute the inverse permutation { CholMatrixType C; C = a.template selfadjointView<UpLo>(); - // remove diagonal entries: - // seems not to be needed - // C.prune(keep_diag()); - internal::minimum_degree_ordering(C, m_Pinv); + + OrderingType ordering; + ordering(C,m_Pinv); } if(m_Pinv.size()>0) diff --git a/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h b/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h index 17fff96a78b..220c6451cb9 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h +++ b/extern/Eigen3/Eigen/src/SparseCore/AmbiVector.h @@ -69,7 +69,7 @@ class AmbiVector delete[] m_buffer; if (size<1000) { - Index allocSize = (size * sizeof(ListEl))/sizeof(Scalar); + Index allocSize = (size * sizeof(ListEl) + sizeof(Scalar) - 1)/sizeof(Scalar); m_allocatedElements = (allocSize*sizeof(Scalar))/sizeof(ListEl); m_buffer = new Scalar[allocSize]; } @@ -88,7 +88,7 @@ class AmbiVector Index copyElements = m_allocatedElements; m_allocatedElements = (std::min)(Index(m_allocatedElements*1.5),m_size); Index allocSize = m_allocatedElements * sizeof(ListEl); - allocSize = allocSize/sizeof(Scalar) + (allocSize%sizeof(Scalar)>0?1:0); + allocSize = (allocSize + sizeof(Scalar) - 1)/sizeof(Scalar); Scalar* newBuffer = new Scalar[allocSize]; memcpy(newBuffer, m_buffer, copyElements * sizeof(ListEl)); delete[] m_buffer; diff --git a/extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h b/extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h index 3321fab4a8a..a667cb56ebe 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h +++ b/extern/Eigen3/Eigen/src/SparseCore/CompressedStorage.h @@ -51,8 +51,8 @@ class CompressedStorage CompressedStorage& operator=(const CompressedStorage& other) { resize(other.size()); - memcpy(m_values, other.m_values, m_size * sizeof(Scalar)); - memcpy(m_indices, other.m_indices, m_size * sizeof(Index)); + internal::smart_copy(other.m_values, other.m_values + m_size, m_values); + internal::smart_copy(other.m_indices, other.m_indices + m_size, m_indices); return *this; } @@ -83,10 +83,10 @@ class CompressedStorage reallocate(m_size); } - void resize(size_t size, float reserveSizeFactor = 0) + void resize(size_t size, double reserveSizeFactor = 0) { if (m_allocatedSize<size) - reallocate(size + size_t(reserveSizeFactor*size)); + reallocate(size + size_t(reserveSizeFactor*double(size))); m_size = size; } diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h b/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h index 16a20a5744e..0c90bafbeab 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseBlock.h @@ -57,6 +57,16 @@ public: inline BlockImpl(const XprType& xpr, int startRow, int startCol, int blockRows, int blockCols) : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols) {} + + inline const Scalar coeff(int row, int col) const + { + return m_matrix.coeff(row + IsRowMajor ? m_outerStart : 0, col +IsRowMajor ? 0 : m_outerStart); + } + + inline const Scalar coeff(int index) const + { + return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart); + } EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } @@ -68,6 +78,8 @@ public: const internal::variable_if_dynamic<Index, OuterSize> m_outerSize; EIGEN_INHERIT_ASSIGNMENT_OPERATORS(BlockImpl) + private: + Index nonZeros() const; }; @@ -82,6 +94,7 @@ class BlockImpl<SparseMatrix<_Scalar, _Options, _Index>,BlockRows,BlockCols,true typedef SparseMatrix<_Scalar, _Options, _Index> SparseMatrixType; typedef typename internal::remove_all<typename SparseMatrixType::Nested>::type _MatrixTypeNested; typedef Block<SparseMatrixType, BlockRows, BlockCols, true> BlockType; + typedef Block<const SparseMatrixType, BlockRows, BlockCols, true> ConstBlockType; public: enum { IsRowMajor = internal::traits<BlockType>::IsRowMajor }; EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) @@ -223,6 +236,118 @@ public: else return Map<const Matrix<Index,OuterSize,1> >(m_matrix.innerNonZeroPtr()+m_outerStart, m_outerSize.value()).sum(); } + + inline Scalar& coeffRef(int row, int col) + { + return m_matrix.const_cast_derived().coeffRef(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); + } + + inline const Scalar coeff(int row, int col) const + { + return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); + } + + inline const Scalar coeff(int index) const + { + return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart); + } + + const Scalar& lastCoeff() const + { + EIGEN_STATIC_ASSERT_VECTOR_ONLY(BlockImpl); + eigen_assert(nonZeros()>0); + if(m_matrix.isCompressed()) + return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart+1]-1]; + else + return m_matrix.valuePtr()[m_matrix.outerIndexPtr()[m_outerStart]+m_matrix.innerNonZeroPtr()[m_outerStart]-1]; + } + + EIGEN_STRONG_INLINE Index rows() const { return IsRowMajor ? m_outerSize.value() : m_matrix.rows(); } + EIGEN_STRONG_INLINE Index cols() const { return IsRowMajor ? m_matrix.cols() : m_outerSize.value(); } + + protected: + + typename SparseMatrixType::Nested m_matrix; + Index m_outerStart; + const internal::variable_if_dynamic<Index, OuterSize> m_outerSize; + +}; + + +template<typename _Scalar, int _Options, typename _Index, int BlockRows, int BlockCols> +class BlockImpl<const SparseMatrix<_Scalar, _Options, _Index>,BlockRows,BlockCols,true,Sparse> + : public SparseMatrixBase<Block<const SparseMatrix<_Scalar, _Options, _Index>,BlockRows,BlockCols,true> > +{ + typedef SparseMatrix<_Scalar, _Options, _Index> SparseMatrixType; + typedef typename internal::remove_all<typename SparseMatrixType::Nested>::type _MatrixTypeNested; + typedef Block<const SparseMatrixType, BlockRows, BlockCols, true> BlockType; +public: + enum { IsRowMajor = internal::traits<BlockType>::IsRowMajor }; + EIGEN_SPARSE_PUBLIC_INTERFACE(BlockType) +protected: + enum { OuterSize = IsRowMajor ? BlockRows : BlockCols }; +public: + + class InnerIterator: public SparseMatrixType::InnerIterator + { + public: + inline InnerIterator(const BlockType& xpr, Index outer) + : SparseMatrixType::InnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) + {} + inline Index row() const { return IsRowMajor ? m_outer : this->index(); } + inline Index col() const { return IsRowMajor ? this->index() : m_outer; } + protected: + Index m_outer; + }; + class ReverseInnerIterator: public SparseMatrixType::ReverseInnerIterator + { + public: + inline ReverseInnerIterator(const BlockType& xpr, Index outer) + : SparseMatrixType::ReverseInnerIterator(xpr.m_matrix, xpr.m_outerStart + outer), m_outer(outer) + {} + inline Index row() const { return IsRowMajor ? m_outer : this->index(); } + inline Index col() const { return IsRowMajor ? this->index() : m_outer; } + protected: + Index m_outer; + }; + + inline BlockImpl(const SparseMatrixType& xpr, int i) + : m_matrix(xpr), m_outerStart(i), m_outerSize(OuterSize) + {} + + inline BlockImpl(const SparseMatrixType& xpr, int startRow, int startCol, int blockRows, int blockCols) + : m_matrix(xpr), m_outerStart(IsRowMajor ? startRow : startCol), m_outerSize(IsRowMajor ? blockRows : blockCols) + {} + + inline const Scalar* valuePtr() const + { return m_matrix.valuePtr() + m_matrix.outerIndexPtr()[m_outerStart]; } + + inline const Index* innerIndexPtr() const + { return m_matrix.innerIndexPtr() + m_matrix.outerIndexPtr()[m_outerStart]; } + + inline const Index* outerIndexPtr() const + { return m_matrix.outerIndexPtr() + m_outerStart; } + + Index nonZeros() const + { + if(m_matrix.isCompressed()) + return std::size_t(m_matrix.outerIndexPtr()[m_outerStart+m_outerSize.value()]) + - std::size_t(m_matrix.outerIndexPtr()[m_outerStart]); + else if(m_outerSize.value()==0) + return 0; + else + return Map<const Matrix<Index,OuterSize,1> >(m_matrix.innerNonZeroPtr()+m_outerStart, m_outerSize.value()).sum(); + } + + inline const Scalar coeff(int row, int col) const + { + return m_matrix.coeff(row + (IsRowMajor ? m_outerStart : 0), col + (IsRowMajor ? 0 : m_outerStart)); + } + + inline const Scalar coeff(int index) const + { + return m_matrix.coeff(IsRowMajor ? m_outerStart : index, IsRowMajor ? index : m_outerStart); + } const Scalar& lastCoeff() const { @@ -265,7 +390,8 @@ const typename SparseMatrixBase<Derived>::ConstInnerVectorReturnType SparseMatri * is col-major (resp. row-major). */ template<typename Derived> -Block<Derived,Dynamic,Dynamic,true> SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize) +typename SparseMatrixBase<Derived>::InnerVectorsReturnType +SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize) { return Block<Derived,Dynamic,Dynamic,true>(derived(), IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, @@ -277,7 +403,8 @@ Block<Derived,Dynamic,Dynamic,true> SparseMatrixBase<Derived>::innerVectors(Inde * is col-major (resp. row-major). Read-only. */ template<typename Derived> -const Block<const Derived,Dynamic,Dynamic,true> SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize) const +const typename SparseMatrixBase<Derived>::ConstInnerVectorsReturnType +SparseMatrixBase<Derived>::innerVectors(Index outerStart, Index outerSize) const { return Block<const Derived,Dynamic,Dynamic,true>(derived(), IsRowMajor ? outerStart : 0, IsRowMajor ? 0 : outerStart, @@ -304,8 +431,8 @@ public: : m_matrix(xpr), m_startRow( (BlockRows==1) && (BlockCols==XprType::ColsAtCompileTime) ? i : 0), m_startCol( (BlockRows==XprType::RowsAtCompileTime) && (BlockCols==1) ? i : 0), - m_blockRows(xpr.rows()), - m_blockCols(xpr.cols()) + m_blockRows(BlockRows==1 ? 1 : xpr.rows()), + m_blockCols(BlockCols==1 ? 1 : xpr.cols()) {} /** Dynamic-size constructor @@ -407,3 +534,4 @@ public: } // end namespace Eigen #endif // EIGEN_SPARSE_BLOCK_H + diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h b/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h index ec86ca933c2..4ca9128337f 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseCwiseBinaryOp.h @@ -73,7 +73,8 @@ class CwiseBinaryOpImpl<BinaryOp,Lhs,Rhs,Sparse>::InnerIterator typedef internal::sparse_cwise_binary_op_inner_iterator_selector< BinaryOp,Lhs,Rhs, InnerIterator> Base; - EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, Index outer) + // NOTE: we have to prefix Index by "typename Lhs::" to avoid an ICE with VC11 + EIGEN_STRONG_INLINE InnerIterator(const CwiseBinaryOpImpl& binOp, typename Lhs::Index outer) : Base(binOp.derived(),outer) {} }; @@ -313,10 +314,10 @@ SparseMatrixBase<Derived>::operator+=(const SparseMatrixBase<OtherDerived>& othe template<typename Derived> template<typename OtherDerived> -EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE +EIGEN_STRONG_INLINE const typename SparseMatrixBase<Derived>::template CwiseProductDenseReturnType<OtherDerived>::Type SparseMatrixBase<Derived>::cwiseProduct(const MatrixBase<OtherDerived> &other) const { - return EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE(derived(), other.derived()); + return typename CwiseProductDenseReturnType<OtherDerived>::Type(derived(), other.derived()); } } // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h b/extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h index 54fd633a10c..ccb6ae7b788 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseDenseProduct.h @@ -19,7 +19,10 @@ template<typename Lhs, typename Rhs, int InnerSize> struct SparseDenseProductRet template<typename Lhs, typename Rhs> struct SparseDenseProductReturnType<Lhs,Rhs,1> { - typedef SparseDenseOuterProduct<Lhs,Rhs,false> Type; + typedef typename internal::conditional< + Lhs::IsRowMajor, + SparseDenseOuterProduct<Rhs,Lhs,true>, + SparseDenseOuterProduct<Lhs,Rhs,false> >::type Type; }; template<typename Lhs, typename Rhs, int InnerSize> struct DenseSparseProductReturnType @@ -29,7 +32,10 @@ template<typename Lhs, typename Rhs, int InnerSize> struct DenseSparseProductRet template<typename Lhs, typename Rhs> struct DenseSparseProductReturnType<Lhs,Rhs,1> { - typedef SparseDenseOuterProduct<Rhs,Lhs,true> Type; + typedef typename internal::conditional< + Rhs::IsRowMajor, + SparseDenseOuterProduct<Rhs,Lhs,true>, + SparseDenseOuterProduct<Lhs,Rhs,false> >::type Type; }; namespace internal { @@ -114,17 +120,30 @@ class SparseDenseOuterProduct<Lhs,Rhs,Transpose>::InnerIterator : public _LhsNes typedef typename SparseDenseOuterProduct::Index Index; public: EIGEN_STRONG_INLINE InnerIterator(const SparseDenseOuterProduct& prod, Index outer) - : Base(prod.lhs(), 0), m_outer(outer), m_factor(prod.rhs().coeff(outer)) - { - } + : Base(prod.lhs(), 0), m_outer(outer), m_factor(get(prod.rhs(), outer, typename internal::traits<Rhs>::StorageKind() )) + { } inline Index outer() const { return m_outer; } - inline Index row() const { return Transpose ? Base::row() : m_outer; } - inline Index col() const { return Transpose ? m_outer : Base::row(); } + inline Index row() const { return Transpose ? m_outer : Base::index(); } + inline Index col() const { return Transpose ? Base::index() : m_outer; } inline Scalar value() const { return Base::value() * m_factor; } protected: + static Scalar get(const _RhsNested &rhs, Index outer, Dense = Dense()) + { + return rhs.coeff(outer); + } + + static Scalar get(const _RhsNested &rhs, Index outer, Sparse = Sparse()) + { + typename Traits::_RhsNested::InnerIterator it(rhs, outer); + if (it && it.index()==0) + return it.value(); + + return Scalar(0); + } + Index m_outer; Scalar m_factor; }; @@ -161,7 +180,7 @@ struct sparse_time_dense_product_impl<SparseLhsType,DenseRhsType,DenseResType, R typename Res::Scalar tmp(0); for(LhsInnerIterator it(lhs,j); it ;++it) tmp += it.value() * rhs.coeff(it.index(),c); - res.coeffRef(j,c) = alpha * tmp; + res.coeffRef(j,c) += alpha * tmp; } } } @@ -287,15 +306,6 @@ class DenseTimeSparseProduct DenseTimeSparseProduct& operator=(const DenseTimeSparseProduct&); }; -// sparse * dense -template<typename Derived> -template<typename OtherDerived> -inline const typename SparseDenseProductReturnType<Derived,OtherDerived>::Type -SparseMatrixBase<Derived>::operator*(const MatrixBase<OtherDerived> &other) const -{ - return typename SparseDenseProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived()); -} - } // end namespace Eigen #endif // EIGEN_SPARSEDENSEPRODUCT_H diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h index 01ce0dcfee3..2ff2015512f 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrix.h @@ -691,7 +691,8 @@ class SparseMatrix m_data.swap(other.m_data); } - /** Sets *this to the identity matrix */ + /** Sets *this to the identity matrix. + * This function also turns the matrix into compressed mode, and drop any reserved memory. */ inline void setIdentity() { eigen_assert(rows() == cols() && "ONLY FOR SQUARED MATRICES"); @@ -699,6 +700,8 @@ class SparseMatrix Eigen::Map<Matrix<Index, Dynamic, 1> >(&this->m_data.index(0), rows()).setLinSpaced(0, rows()-1); Eigen::Map<Matrix<Scalar, Dynamic, 1> >(&this->m_data.value(0), rows()).setOnes(); Eigen::Map<Matrix<Index, Dynamic, 1> >(this->m_outerIndex, rows()+1).setLinSpaced(0, rows()); + std::free(m_innerNonZeros); + m_innerNonZeros = 0; } inline SparseMatrix& operator=(const SparseMatrix& other) { @@ -940,7 +943,7 @@ void set_from_triplets(const InputIterator& begin, const InputIterator& end, Spa enum { IsRowMajor = SparseMatrixType::IsRowMajor }; typedef typename SparseMatrixType::Scalar Scalar; typedef typename SparseMatrixType::Index Index; - SparseMatrix<Scalar,IsRowMajor?ColMajor:RowMajor> trMat(mat.rows(),mat.cols()); + SparseMatrix<Scalar,IsRowMajor?ColMajor:RowMajor,Index> trMat(mat.rows(),mat.cols()); if(begin!=end) { @@ -1178,7 +1181,7 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse size_t p = m_outerIndex[outer+1]; ++m_outerIndex[outer+1]; - float reallocRatio = 1; + double reallocRatio = 1; if (m_data.allocatedSize()<=m_data.size()) { // if there is no preallocated memory, let's reserve a minimum of 32 elements @@ -1190,13 +1193,13 @@ EIGEN_DONT_INLINE typename SparseMatrix<_Scalar,_Options,_Index>::Scalar& Sparse { // we need to reallocate the data, to reduce multiple reallocations // we use a smart resize algorithm based on the current filling ratio - // in addition, we use float to avoid integers overflows - float nnzEstimate = float(m_outerIndex[outer])*float(m_outerSize)/float(outer+1); - reallocRatio = (nnzEstimate-float(m_data.size()))/float(m_data.size()); + // in addition, we use double to avoid integers overflows + double nnzEstimate = double(m_outerIndex[outer])*double(m_outerSize)/double(outer+1); + reallocRatio = (nnzEstimate-double(m_data.size()))/double(m_data.size()); // furthermore we bound the realloc ratio to: // 1) reduce multiple minor realloc when the matrix is almost filled // 2) avoid to allocate too much memory when the matrix is almost empty - reallocRatio = (std::min)((std::max)(reallocRatio,1.5f),8.f); + reallocRatio = (std::min)((std::max)(reallocRatio,1.5),8.); } } m_data.resize(m_data.size()+1,reallocRatio); diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h index bbcf7fb1c62..9341d9ad2c0 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseMatrixBase.h @@ -23,7 +23,14 @@ namespace Eigen { * This class can be extended with the help of the plugin mechanism described on the page * \ref TopicCustomizingEigen by defining the preprocessor symbol \c EIGEN_SPARSEMATRIXBASE_PLUGIN. */ -template<typename Derived> class SparseMatrixBase : public EigenBase<Derived> +template<typename Derived> class SparseMatrixBase +#ifndef EIGEN_PARSED_BY_DOXYGEN + : public internal::special_scalar_op_base<Derived,typename internal::traits<Derived>::Scalar, + typename NumTraits<typename internal::traits<Derived>::Scalar>::Real, + EigenBase<Derived> > +#else + : public EigenBase<Derived> +#endif // not EIGEN_PARSED_BY_DOXYGEN { public: @@ -36,7 +43,6 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived> >::type PacketReturnType; typedef SparseMatrixBase StorageBaseType; - typedef EigenBase<Derived> Base; template<typename OtherDerived> Derived& operator=(const EigenBase<OtherDerived> &other) @@ -132,6 +138,9 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived> inline Derived& derived() { return *static_cast<Derived*>(this); } inline Derived& const_cast_derived() const { return *static_cast<Derived*>(const_cast<SparseMatrixBase*>(this)); } + + typedef internal::special_scalar_op_base<Derived, Scalar, RealScalar, EigenBase<Derived> > Base; + using Base::operator*; #endif // not EIGEN_PARSED_BY_DOXYGEN #define EIGEN_CURRENT_STORAGE_BASE_CLASS Eigen::SparseMatrixBase @@ -317,20 +326,18 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived> Derived& operator*=(const Scalar& other); Derived& operator/=(const Scalar& other); - #define EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE \ - CwiseBinaryOp< \ - internal::scalar_product_op< \ - typename internal::scalar_product_traits< \ - typename internal::traits<Derived>::Scalar, \ - typename internal::traits<OtherDerived>::Scalar \ - >::ReturnType \ - >, \ - const Derived, \ - const OtherDerived \ - > + template<typename OtherDerived> struct CwiseProductDenseReturnType { + typedef CwiseBinaryOp<internal::scalar_product_op<typename internal::scalar_product_traits< + typename internal::traits<Derived>::Scalar, + typename internal::traits<OtherDerived>::Scalar + >::ReturnType>, + const Derived, + const OtherDerived + > Type; + }; template<typename OtherDerived> - EIGEN_STRONG_INLINE const EIGEN_SPARSE_CWISE_PRODUCT_RETURN_TYPE + EIGEN_STRONG_INLINE const typename CwiseProductDenseReturnType<OtherDerived>::Type cwiseProduct(const MatrixBase<OtherDerived> &other) const; // sparse * sparse @@ -358,7 +365,8 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived> /** sparse * dense (returns a dense object unless it is an outer product) */ template<typename OtherDerived> const typename SparseDenseProductReturnType<Derived,OtherDerived>::Type - operator*(const MatrixBase<OtherDerived> &other) const; + operator*(const MatrixBase<OtherDerived> &other) const + { return typename SparseDenseProductReturnType<Derived,OtherDerived>::Type(derived(), other.derived()); } /** \returns an expression of P H P^-1 where H is the matrix represented by \c *this */ SparseSymmetricPermutationProduct<Derived,Upper|Lower> twistedBy(const PermutationMatrix<Dynamic,Dynamic,Index>& perm) const @@ -403,8 +411,10 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived> const ConstInnerVectorReturnType innerVector(Index outer) const; // set of inner-vectors - Block<Derived,Dynamic,Dynamic,true> innerVectors(Index outerStart, Index outerSize); - const Block<const Derived,Dynamic,Dynamic,true> innerVectors(Index outerStart, Index outerSize) const; + typedef Block<Derived,Dynamic,Dynamic,true> InnerVectorsReturnType; + typedef Block<const Derived,Dynamic,Dynamic,true> ConstInnerVectorsReturnType; + InnerVectorsReturnType innerVectors(Index outerStart, Index outerSize); + const ConstInnerVectorsReturnType innerVectors(Index outerStart, Index outerSize) const; /** \internal use operator= */ template<typename DenseDerived> diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h b/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h index b85be93f6f9..75e21000959 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h +++ b/extern/Eigen3/Eigen/src/SparseCore/SparsePermutation.h @@ -61,7 +61,7 @@ struct permut_sparsematrix_product_retval for(Index j=0; j<m_matrix.outerSize(); ++j) { Index jp = m_permutation.indices().coeff(j); - sizes[((Side==OnTheLeft) ^ Transposed) ? jp : j] = m_matrix.innerVector(((Side==OnTheRight) ^ Transposed) ? jp : j).size(); + sizes[((Side==OnTheLeft) ^ Transposed) ? jp : j] = m_matrix.innerVector(((Side==OnTheRight) ^ Transposed) ? jp : j).nonZeros(); } tmp.reserve(sizes); for(Index j=0; j<m_matrix.outerSize(); ++j) diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h b/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h index 7c300ee8dbc..76d031d52c8 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseTranspose.h @@ -26,7 +26,7 @@ template<typename MatrixType> class TransposeImpl<MatrixType,Sparse> inline Index nonZeros() const { return derived().nestedExpression().nonZeros(); } }; -// NOTE: VC10 trigger an ICE if don't put typename TransposeImpl<MatrixType,Sparse>:: in front of Index, +// NOTE: VC10 and VC11 trigger an ICE if don't put typename TransposeImpl<MatrixType,Sparse>:: in front of Index, // a typedef typename TransposeImpl<MatrixType,Sparse>::Index Index; // does not fix the issue. // An alternative is to define the nested class in the parent class itself. @@ -40,8 +40,8 @@ template<typename MatrixType> class TransposeImpl<MatrixType,Sparse>::InnerItera EIGEN_STRONG_INLINE InnerIterator(const TransposeImpl& trans, typename TransposeImpl<MatrixType,Sparse>::Index outer) : Base(trans.derived().nestedExpression(), outer) {} - Index row() const { return Base::col(); } - Index col() const { return Base::row(); } + typename TransposeImpl<MatrixType,Sparse>::Index row() const { return Base::col(); } + typename TransposeImpl<MatrixType,Sparse>::Index col() const { return Base::row(); } }; template<typename MatrixType> class TransposeImpl<MatrixType,Sparse>::ReverseInnerIterator @@ -54,8 +54,8 @@ template<typename MatrixType> class TransposeImpl<MatrixType,Sparse>::ReverseInn EIGEN_STRONG_INLINE ReverseInnerIterator(const TransposeImpl& xpr, typename TransposeImpl<MatrixType,Sparse>::Index outer) : Base(xpr.derived().nestedExpression(), outer) {} - Index row() const { return Base::col(); } - Index col() const { return Base::row(); } + typename TransposeImpl<MatrixType,Sparse>::Index row() const { return Base::col(); } + typename TransposeImpl<MatrixType,Sparse>::Index col() const { return Base::row(); } }; } // end namespace Eigen diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h b/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h index 05023858b16..d627546def0 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseUtil.h @@ -67,7 +67,6 @@ const int InnerRandomAccessPattern = 0x2 | CoherentAccessPattern; const int OuterRandomAccessPattern = 0x4 | CoherentAccessPattern; const int RandomAccessPattern = 0x8 | OuterRandomAccessPattern | InnerRandomAccessPattern; -template<typename Derived> class SparseMatrixBase; template<typename _Scalar, int _Flags = 0, typename _Index = int> class SparseMatrix; template<typename _Scalar, int _Flags = 0, typename _Index = int> class DynamicSparseMatrix; template<typename _Scalar, int _Flags = 0, typename _Index = int> class SparseVector; @@ -84,8 +83,10 @@ template<typename Lhs, typename Rhs> class DenseTimeSparseProduct; template<typename Lhs, typename Rhs, bool Transpose> class SparseDenseOuterProduct; template<typename Lhs, typename Rhs> struct SparseSparseProductReturnType; -template<typename Lhs, typename Rhs, int InnerSize = internal::traits<Lhs>::ColsAtCompileTime> struct DenseSparseProductReturnType; -template<typename Lhs, typename Rhs, int InnerSize = internal::traits<Lhs>::ColsAtCompileTime> struct SparseDenseProductReturnType; +template<typename Lhs, typename Rhs, + int InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(internal::traits<Lhs>::ColsAtCompileTime,internal::traits<Rhs>::RowsAtCompileTime)> struct DenseSparseProductReturnType; +template<typename Lhs, typename Rhs, + int InnerSize = EIGEN_SIZE_MIN_PREFER_FIXED(internal::traits<Lhs>::ColsAtCompileTime,internal::traits<Rhs>::RowsAtCompileTime)> struct SparseDenseProductReturnType; template<typename MatrixType,int UpLo> class SparseSymmetricPermutationProduct; namespace internal { diff --git a/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h b/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h index 7e15c814b6f..49865d0e72f 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h +++ b/extern/Eigen3/Eigen/src/SparseCore/SparseVector.h @@ -158,6 +158,7 @@ class SparseVector Index inner = IsColVector ? row : col; Index outer = IsColVector ? col : row; + EIGEN_ONLY_USED_FOR_DEBUG(outer); eigen_assert(outer==0); return insert(inner); } diff --git a/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h b/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h index cb8ad82b4f6..ccc12af7962 100644 --- a/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h +++ b/extern/Eigen3/Eigen/src/SparseCore/TriangularSolver.h @@ -69,7 +69,7 @@ struct sparse_solve_triangular_selector<Lhs,Rhs,Mode,Upper,RowMajor> for(int i=lhs.rows()-1 ; i>=0 ; --i) { Scalar tmp = other.coeff(i,col); - Scalar l_ii = 0; + Scalar l_ii(0); typename Lhs::InnerIterator it(lhs, i); while(it && it.index()<i) ++it; diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU.h index 1d592f2c8c7..bdc4f193ddb 100644 --- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU.h +++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU.h @@ -260,16 +260,16 @@ class SparseLU : public internal::SparseLUImpl<typename _MatrixType::Scalar, typ eigen_assert(m_factorizationIsOk && "The matrix should be factorized first."); // Initialize with the determinant of the row matrix Scalar det = Scalar(1.); - //Note that the diagonal blocks of U are stored in supernodes, + // Note that the diagonal blocks of U are stored in supernodes, // which are available in the L part :) for (Index j = 0; j < this->cols(); ++j) { for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it) { - if(it.row() < j) continue; - if(it.row() == j) + if(it.index() == j) { - det *= (std::abs)(it.value()); + using std::abs; + det *= abs(it.value()); break; } } @@ -296,7 +296,8 @@ class SparseLU : public internal::SparseLUImpl<typename _MatrixType::Scalar, typ if(it.row() < j) continue; if(it.row() == j) { - det += (std::log)((std::abs)(it.value())); + using std::log; using std::abs; + det += log(abs(it.value())); break; } } @@ -304,21 +305,64 @@ class SparseLU : public internal::SparseLUImpl<typename _MatrixType::Scalar, typ return det; } - /** \returns A number representing the sign of the determinant - * - * \sa absDeterminant(), logAbsDeterminant() - */ - Scalar signDeterminant() - { - eigen_assert(m_factorizationIsOk && "The matrix should be factorized first."); - return Scalar(m_detPermR); - } + /** \returns A number representing the sign of the determinant + * + * \sa absDeterminant(), logAbsDeterminant() + */ + Scalar signDeterminant() + { + eigen_assert(m_factorizationIsOk && "The matrix should be factorized first."); + // Initialize with the determinant of the row matrix + Index det = 1; + // Note that the diagonal blocks of U are stored in supernodes, + // which are available in the L part :) + for (Index j = 0; j < this->cols(); ++j) + { + for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it) + { + if(it.index() == j) + { + if(it.value()<0) + det = -det; + else if(it.value()==0) + return 0; + break; + } + } + } + return det * m_detPermR * m_detPermC; + } + + /** \returns The determinant of the matrix. + * + * \sa absDeterminant(), logAbsDeterminant() + */ + Scalar determinant() + { + eigen_assert(m_factorizationIsOk && "The matrix should be factorized first."); + // Initialize with the determinant of the row matrix + Scalar det = Scalar(1.); + // Note that the diagonal blocks of U are stored in supernodes, + // which are available in the L part :) + for (Index j = 0; j < this->cols(); ++j) + { + for (typename SCMatrix::InnerIterator it(m_Lstore, j); it; ++it) + { + if(it.index() == j) + { + det *= it.value(); + break; + } + } + } + return det * Scalar(m_detPermR * m_detPermC); + } protected: // Functions void initperfvalues() { - m_perfv.panel_size = 1; + m_perfv.panel_size = 16; m_perfv.relax = 1; m_perfv.maxsuper = 128; m_perfv.rowblk = 16; @@ -346,8 +390,8 @@ class SparseLU : public internal::SparseLUImpl<typename _MatrixType::Scalar, typ // values for performance internal::perfvalues<Index> m_perfv; RealScalar m_diagpivotthresh; // Specifies the threshold used for a diagonal entry to be an acceptable pivot - Index m_nnzL, m_nnzU; // Nonzeros in L and U factors - Index m_detPermR; // Determinant of the coefficient matrix + Index m_nnzL, m_nnzU; // Nonzeros in L and U factors + Index m_detPermR, m_detPermC; // Determinants of the permutation matrices private: // Disable copy constructor SparseLU (const SparseLU& ); @@ -623,7 +667,8 @@ void SparseLU<MatrixType, OrderingType>::factorize(const MatrixType& matrix) } // Update the determinant of the row permutation matrix - if (pivrow != jj) m_detPermR *= -1; + // FIXME: the following test is not correct, we should probably take iperm_c into account and pivrow is not directly the row pivot. + if (pivrow != jj) m_detPermR = -m_detPermR; // Prune columns (0:jj-1) using column jj Base::pruneL(jj, m_perm_r.indices(), pivrow, nseg, segrep, repfnz_k, xprune, m_glu); @@ -638,10 +683,13 @@ void SparseLU<MatrixType, OrderingType>::factorize(const MatrixType& matrix) jcol += panel_size; // Move to the next panel } // end for -- end elimination + m_detPermR = m_perm_r.determinant(); + m_detPermC = m_perm_c.determinant(); + // Count the number of nonzeros in factors Base::countnz(n, m_nnzL, m_nnzU, m_glu); // Apply permutation to the L subscripts - Base::fixupL(n, m_perm_r.indices(), m_glu); + Base::fixupL(n, m_perm_r.indices(), m_glu); // Create supernode matrix L m_Lstore.setInfos(m, n, m_glu.lusup, m_glu.xlusup, m_glu.lsub, m_glu.xlsub, m_glu.supno, m_glu.xsup); @@ -701,8 +749,8 @@ struct SparseLUMatrixUReturnType : internal::no_assignment_operator } else { - Map<const Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A( &(m_mapL.valuePtr()[luptr]), nsupc, nsupc, OuterStride<>(lda) ); - Map< Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) ); + Map<const Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > A( &(m_mapL.valuePtr()[luptr]), nsupc, nsupc, OuterStride<>(lda) ); + Map< Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) ); U = A.template triangularView<Upper>().solve(U); } diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLUImpl.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLUImpl.h index 14d70897df7..99d651e40d3 100644 --- a/extern/Eigen3/Eigen/src/SparseLU/SparseLUImpl.h +++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLUImpl.h @@ -21,6 +21,8 @@ class SparseLUImpl { public: typedef Matrix<Scalar,Dynamic,1> ScalarVector; + typedef Matrix<Scalar,Dynamic,Dynamic,ColMajor> ScalarMatrix; + typedef Map<ScalarMatrix, 0, OuterStride<> > MappedMatrixBlock; typedef Matrix<Index,Dynamic,1> IndexVector; typedef typename ScalarVector::RealScalar RealScalar; typedef Ref<Matrix<Scalar,Dynamic,1> > BlockScalarVector; diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_Memory.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_Memory.h index 1ffa7d54e96..45f96d16a8e 100644 --- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_Memory.h +++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_Memory.h @@ -153,8 +153,8 @@ Index SparseLUImpl<Scalar,Index>::memInit(Index m, Index n, Index annz, Index lw { Index& num_expansions = glu.num_expansions; //No memory expansions so far num_expansions = 0; - glu.nzumax = glu.nzlumax = (std::min)(fillratio * annz / n, m) * n; // estimated number of nonzeros in U - glu.nzlmax = (std::max)(Index(4), fillratio) * annz / 4; // estimated nnz in L factor + glu.nzumax = glu.nzlumax = (std::min)(fillratio * (annz+1) / n, m) * n; // estimated number of nonzeros in U + glu.nzlmax = (std::max)(Index(4), fillratio) * (annz+1) / 4; // estimated nnz in L factor // Return the estimated size to the user if necessary Index tempSpace; tempSpace = (2*panel_size + 4 + LUNoMarker) * m * sizeof(Index) + (panel_size + 1) * m * sizeof(Scalar); diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h index ad6f2183fed..54a56940861 100644 --- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h +++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_SupernodalMatrix.h @@ -189,8 +189,8 @@ class MappedSuperNodalMatrix<Scalar,Index>::InnerIterator m_idval(mat.colIndexPtr()[outer]), m_startidval(m_idval), m_endidval(mat.colIndexPtr()[outer+1]), - m_idrow(mat.rowIndexPtr()[outer]), - m_endidrow(mat.rowIndexPtr()[outer+1]) + m_idrow(mat.rowIndexPtr()[mat.supToCol()[mat.colToSup()[outer]]]), + m_endidrow(mat.rowIndexPtr()[mat.supToCol()[mat.colToSup()[outer]]+1]) {} inline InnerIterator& operator++() { @@ -236,7 +236,7 @@ void MappedSuperNodalMatrix<Scalar,Index>::solveInPlace( MatrixBase<Dest>&X) con Index n = X.rows(); Index nrhs = X.cols(); const Scalar * Lval = valuePtr(); // Nonzero values - Matrix<Scalar,Dynamic,Dynamic> work(n, nrhs); // working vector + Matrix<Scalar,Dynamic,Dynamic, ColMajor> work(n, nrhs); // working vector work.setZero(); for (Index k = 0; k <= nsuper(); k ++) { @@ -267,12 +267,12 @@ void MappedSuperNodalMatrix<Scalar,Index>::solveInPlace( MatrixBase<Dest>&X) con Index lda = colIndexPtr()[fsupc+1] - luptr; // Triangular solve - Map<const Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A( &(Lval[luptr]), nsupc, nsupc, OuterStride<>(lda) ); - Map< Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) ); + Map<const Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > A( &(Lval[luptr]), nsupc, nsupc, OuterStride<>(lda) ); + Map< Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > U (&(X(fsupc,0)), nsupc, nrhs, OuterStride<>(n) ); U = A.template triangularView<UnitLower>().solve(U); // Matrix-vector product - new (&A) Map<const Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > ( &(Lval[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) ); + new (&A) Map<const Matrix<Scalar,Dynamic,Dynamic, ColMajor>, 0, OuterStride<> > ( &(Lval[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) ); work.block(0, 0, nrow, nrhs) = A * U; //Begin Scatter diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h index f24bd87d3e9..cacc7e98712 100644 --- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h +++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_column_bmod.h @@ -162,11 +162,11 @@ Index SparseLUImpl<Scalar,Index>::column_bmod(const Index jcol, const Index nseg // points to the beginning of jcol in snode L\U(jsupno) ufirst = glu.xlusup(jcol) + d_fsupc; Index lda = glu.xlusup(jcol+1) - glu.xlusup(jcol); - Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A( &(glu.lusup.data()[luptr]), nsupc, nsupc, OuterStride<>(lda) ); + MappedMatrixBlock A( &(glu.lusup.data()[luptr]), nsupc, nsupc, OuterStride<>(lda) ); VectorBlock<ScalarVector> u(glu.lusup, ufirst, nsupc); u = A.template triangularView<UnitLower>().solve(u); - new (&A) Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > ( &(glu.lusup.data()[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) ); + new (&A) MappedMatrixBlock ( &(glu.lusup.data()[luptr+nsupc]), nrow, nsupc, OuterStride<>(lda) ); VectorBlock<ScalarVector> l(glu.lusup, ufirst+nsupc, nrow); l.noalias() -= A * u; diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h index 0d0283b132b..6af02675429 100644 --- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h +++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_kernel_bmod.h @@ -56,7 +56,7 @@ EIGEN_DONT_INLINE void LU_kernel_bmod<SegSizeAtCompileTime>::run(const int segsi // Dense triangular solve -- start effective triangle luptr += lda * no_zeros + no_zeros; // Form Eigen matrix and vector - Map<Matrix<Scalar,SegSizeAtCompileTime,SegSizeAtCompileTime>, 0, OuterStride<> > A( &(lusup.data()[luptr]), segsize, segsize, OuterStride<>(lda) ); + Map<Matrix<Scalar,SegSizeAtCompileTime,SegSizeAtCompileTime, ColMajor>, 0, OuterStride<> > A( &(lusup.data()[luptr]), segsize, segsize, OuterStride<>(lda) ); Map<Matrix<Scalar,SegSizeAtCompileTime,1> > u(tempv.data(), segsize); u = A.template triangularView<UnitLower>().solve(u); @@ -65,7 +65,7 @@ EIGEN_DONT_INLINE void LU_kernel_bmod<SegSizeAtCompileTime>::run(const int segsi luptr += segsize; const Index PacketSize = internal::packet_traits<Scalar>::size; Index ldl = internal::first_multiple(nrow, PacketSize); - Map<Matrix<Scalar,Dynamic,SegSizeAtCompileTime>, 0, OuterStride<> > B( &(lusup.data()[luptr]), nrow, segsize, OuterStride<>(lda) ); + Map<Matrix<Scalar,Dynamic,SegSizeAtCompileTime, ColMajor>, 0, OuterStride<> > B( &(lusup.data()[luptr]), nrow, segsize, OuterStride<>(lda) ); Index aligned_offset = internal::first_aligned(tempv.data()+segsize, PacketSize); Index aligned_with_B_offset = (PacketSize-internal::first_aligned(B.data(), PacketSize))%PacketSize; Map<Matrix<Scalar,Dynamic,1>, 0, OuterStride<> > l(tempv.data()+segsize+aligned_offset+aligned_with_B_offset, nrow, OuterStride<>(ldl) ); diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h index da0e0fc3c60..9d2ff290635 100644 --- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h +++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_panel_bmod.h @@ -102,7 +102,7 @@ void SparseLUImpl<Scalar,Index>::panel_bmod(const Index m, const Index w, const if(nsupc >= 2) { Index ldu = internal::first_multiple<Index>(u_rows, PacketSize); - Map<Matrix<Scalar,Dynamic,Dynamic>, Aligned, OuterStride<> > U(tempv.data(), u_rows, u_cols, OuterStride<>(ldu)); + Map<ScalarMatrix, Aligned, OuterStride<> > U(tempv.data(), u_rows, u_cols, OuterStride<>(ldu)); // gather U Index u_col = 0; @@ -136,17 +136,17 @@ void SparseLUImpl<Scalar,Index>::panel_bmod(const Index m, const Index w, const Index lda = glu.xlusup(fsupc+1) - glu.xlusup(fsupc); no_zeros = (krep - u_rows + 1) - fsupc; luptr += lda * no_zeros + no_zeros; - Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > A(glu.lusup.data()+luptr, u_rows, u_rows, OuterStride<>(lda) ); + MappedMatrixBlock A(glu.lusup.data()+luptr, u_rows, u_rows, OuterStride<>(lda) ); U = A.template triangularView<UnitLower>().solve(U); // update luptr += u_rows; - Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > B(glu.lusup.data()+luptr, nrow, u_rows, OuterStride<>(lda) ); + MappedMatrixBlock B(glu.lusup.data()+luptr, nrow, u_rows, OuterStride<>(lda) ); eigen_assert(tempv.size()>w*ldu + nrow*w + 1); Index ldl = internal::first_multiple<Index>(nrow, PacketSize); Index offset = (PacketSize-internal::first_aligned(B.data(), PacketSize)) % PacketSize; - Map<Matrix<Scalar,Dynamic,Dynamic>, 0, OuterStride<> > L(tempv.data()+w*ldu+offset, nrow, u_cols, OuterStride<>(ldl)); + MappedMatrixBlock L(tempv.data()+w*ldu+offset, nrow, u_cols, OuterStride<>(ldl)); L.setZero(); internal::sparselu_gemm<Scalar>(L.rows(), L.cols(), B.cols(), B.data(), B.outerStride(), U.data(), U.outerStride(), L.data(), L.outerStride()); diff --git a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h index ddcd4ec98f8..2e49ef667f4 100644 --- a/extern/Eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h +++ b/extern/Eigen3/Eigen/src/SparseLU/SparseLU_pivotL.h @@ -71,13 +71,14 @@ Index SparseLUImpl<Scalar,Index>::pivotL(const Index jcol, const RealScalar& dia // Determine the largest abs numerical value for partial pivoting Index diagind = iperm_c(jcol); // diagonal index - RealScalar pivmax = 0.0; + RealScalar pivmax(-1.0); Index pivptr = nsupc; Index diag = emptyIdxLU; RealScalar rtemp; Index isub, icol, itemp, k; for (isub = nsupc; isub < nsupr; ++isub) { - rtemp = std::abs(lu_col_ptr[isub]); + using std::abs; + rtemp = abs(lu_col_ptr[isub]); if (rtemp > pivmax) { pivmax = rtemp; pivptr = isub; @@ -86,8 +87,9 @@ Index SparseLUImpl<Scalar,Index>::pivotL(const Index jcol, const RealScalar& dia } // Test for singularity - if ( pivmax == 0.0 ) { - pivrow = lsub_ptr[pivptr]; + if ( pivmax <= RealScalar(0.0) ) { + // if pivmax == -1, the column is structurally empty, otherwise it is only numerically zero + pivrow = pivmax < RealScalar(0.0) ? diagind : lsub_ptr[pivptr]; perm_r(pivrow) = jcol; return (jcol+1); } @@ -101,7 +103,8 @@ Index SparseLUImpl<Scalar,Index>::pivotL(const Index jcol, const RealScalar& dia if (diag >= 0 ) { // Diagonal element exists - rtemp = std::abs(lu_col_ptr[diag]); + using std::abs; + rtemp = abs(lu_col_ptr[diag]); if (rtemp != 0.0 && rtemp >= thresh) pivptr = diag; } pivrow = lsub_ptr[pivptr]; diff --git a/extern/Eigen3/Eigen/src/SparseQR/SparseQR.h b/extern/Eigen3/Eigen/src/SparseQR/SparseQR.h index afda43bfc67..a00bd5db124 100644 --- a/extern/Eigen3/Eigen/src/SparseQR/SparseQR.h +++ b/extern/Eigen3/Eigen/src/SparseQR/SparseQR.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2012-2013 Desire Nuentsa <desire.nuentsa_wakam@inria.fr> -// Copyright (C) 2012-2013 Gael Guennebaud <gael.guennebaud@inria.fr> +// Copyright (C) 2012-2014 Gael Guennebaud <gael.guennebaud@inria.fr> // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed @@ -58,6 +58,7 @@ namespace internal { * \tparam _OrderingType The fill-reducing ordering method. See the \link OrderingMethods_Module * OrderingMethods \endlink module for the list of built-in and external ordering methods. * + * \warning The input sparse matrix A must be in compressed mode (see SparseMatrix::makeCompressed()). * */ template<typename _MatrixType, typename _OrderingType> @@ -74,13 +75,26 @@ class SparseQR typedef Matrix<Scalar, Dynamic, 1> ScalarVector; typedef PermutationMatrix<Dynamic, Dynamic, Index> PermutationType; public: - SparseQR () : m_isInitialized(false), m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false) + SparseQR () : m_isInitialized(false), m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false) { } - SparseQR(const MatrixType& mat) : m_isInitialized(false), m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false) + /** Construct a QR factorization of the matrix \a mat. + * + * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()). + * + * \sa compute() + */ + SparseQR(const MatrixType& mat) : m_isInitialized(false), m_analysisIsok(false), m_lastError(""), m_useDefaultThreshold(true),m_isQSorted(false),m_isEtreeOk(false) { compute(mat); } + + /** Computes the QR factorization of the sparse matrix \a mat. + * + * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()). + * + * \sa analyzePattern(), factorize() + */ void compute(const MatrixType& mat) { analyzePattern(mat); @@ -166,7 +180,7 @@ class SparseQR y.bottomRows(y.rows()-rank).setZero(); // Apply the column permutation - if (m_perm_c.size()) dest.topRows(cols()) = colsPermutation() * y.topRows(cols()); + if (m_perm_c.size()) dest = colsPermutation() * y.topRows(cols()); else dest = y.topRows(cols()); m_info = Success; @@ -206,7 +220,7 @@ class SparseQR /** \brief Reports whether previous computation was successful. * - * \returns \c Success if computation was succesful, + * \returns \c Success if computation was successful, * \c NumericalIssue if the QR factorization reports a numerical problem * \c InvalidInput if the input matrix is invalid * @@ -248,6 +262,7 @@ class SparseQR IndexVector m_etree; // Column elimination tree IndexVector m_firstRowElt; // First element in each row bool m_isQSorted; // whether Q is sorted or not + bool m_isEtreeOk; // whether the elimination tree match the initial input matrix template <typename, typename > friend struct SparseQR_QProduct; template <typename > friend struct SparseQRMatrixQReturnType; @@ -256,19 +271,25 @@ class SparseQR /** \brief Preprocessing step of a QR factorization * + * \warning The matrix \a mat must be in compressed mode (see SparseMatrix::makeCompressed()). + * * In this step, the fill-reducing permutation is computed and applied to the columns of A - * and the column elimination tree is computed as well. Only the sparcity pattern of \a mat is exploited. + * and the column elimination tree is computed as well. Only the sparsity pattern of \a mat is exploited. * * \note In this step it is assumed that there is no empty row in the matrix \a mat. */ template <typename MatrixType, typename OrderingType> void SparseQR<MatrixType,OrderingType>::analyzePattern(const MatrixType& mat) { + eigen_assert(mat.isCompressed() && "SparseQR requires a sparse matrix in compressed mode. Call .makeCompressed() before passing it to SparseQR"); + // Copy to a column major matrix if the input is rowmajor + typename internal::conditional<MatrixType::IsRowMajor,QRMatrixType,const MatrixType&>::type matCpy(mat); // Compute the column fill reducing ordering OrderingType ord; - ord(mat, m_perm_c); + ord(matCpy, m_perm_c); Index n = mat.cols(); Index m = mat.rows(); + Index diagSize = (std::min)(m,n); if (!m_perm_c.size()) { @@ -278,22 +299,23 @@ void SparseQR<MatrixType,OrderingType>::analyzePattern(const MatrixType& mat) // Compute the column elimination tree of the permuted matrix m_outputPerm_c = m_perm_c.inverse(); - internal::coletree(mat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data()); + internal::coletree(matCpy, m_etree, m_firstRowElt, m_outputPerm_c.indices().data()); + m_isEtreeOk = true; - m_R.resize(n, n); - m_Q.resize(m, n); + m_R.resize(m, n); + m_Q.resize(m, diagSize); // Allocate space for nonzero elements : rough estimation m_R.reserve(2*mat.nonZeros()); //FIXME Get a more accurate estimation through symbolic factorization with the etree m_Q.reserve(2*mat.nonZeros()); - m_hcoeffs.resize(n); + m_hcoeffs.resize(diagSize); m_analysisIsok = true; } /** \brief Performs the numerical QR factorization of the input matrix * * The function SparseQR::analyzePattern(const MatrixType&) must have been called beforehand with - * a matrix having the same sparcity pattern than \a mat. + * a matrix having the same sparsity pattern than \a mat. * * \param mat The sparse column-major matrix */ @@ -306,23 +328,47 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat) eigen_assert(m_analysisIsok && "analyzePattern() should be called before this step"); Index m = mat.rows(); Index n = mat.cols(); - IndexVector mark(m); mark.setConstant(-1); // Record the visited nodes - IndexVector Ridx(n), Qidx(m); // Store temporarily the row indexes for the current column of R and Q - Index nzcolR, nzcolQ; // Number of nonzero for the current column of R and Q - ScalarVector tval(m); // The dense vector used to compute the current column - bool found_diag; - + Index diagSize = (std::min)(m,n); + IndexVector mark((std::max)(m,n)); mark.setConstant(-1); // Record the visited nodes + IndexVector Ridx(n), Qidx(m); // Store temporarily the row indexes for the current column of R and Q + Index nzcolR, nzcolQ; // Number of nonzero for the current column of R and Q + ScalarVector tval(m); // The dense vector used to compute the current column + RealScalar pivotThreshold = m_threshold; + + m_R.setZero(); + m_Q.setZero(); m_pmat = mat; + if(!m_isEtreeOk) + { + m_outputPerm_c = m_perm_c.inverse(); + internal::coletree(m_pmat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data()); + m_isEtreeOk = true; + } + m_pmat.uncompress(); // To have the innerNonZeroPtr allocated + // Apply the fill-in reducing permutation lazily: - for (int i = 0; i < n; i++) { - Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i; - m_pmat.outerIndexPtr()[p] = mat.outerIndexPtr()[i]; - m_pmat.innerNonZeroPtr()[p] = mat.outerIndexPtr()[i+1] - mat.outerIndexPtr()[i]; + // If the input is row major, copy the original column indices, + // otherwise directly use the input matrix + // + IndexVector originalOuterIndicesCpy; + const Index *originalOuterIndices = mat.outerIndexPtr(); + if(MatrixType::IsRowMajor) + { + originalOuterIndicesCpy = IndexVector::Map(m_pmat.outerIndexPtr(),n+1); + originalOuterIndices = originalOuterIndicesCpy.data(); + } + + for (int i = 0; i < n; i++) + { + Index p = m_perm_c.size() ? m_perm_c.indices()(i) : i; + m_pmat.outerIndexPtr()[p] = originalOuterIndices[i]; + m_pmat.innerNonZeroPtr()[p] = originalOuterIndices[i+1] - originalOuterIndices[i]; + } } - /* Compute the default threshold, see : + /* Compute the default threshold as in MatLab, see: * Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing * Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3 */ @@ -330,33 +376,35 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat) { RealScalar max2Norm = 0.0; for (int j = 0; j < n; j++) max2Norm = (max)(max2Norm, m_pmat.col(j).norm()); - m_threshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon(); + if(max2Norm==RealScalar(0)) + max2Norm = RealScalar(1); + pivotThreshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon(); } // Initialize the numerical permutation m_pivotperm.setIdentity(n); Index nonzeroCol = 0; // Record the number of valid pivots - + m_Q.startVec(0); + // Left looking rank-revealing QR factorization: compute a column of R and Q at a time - for (Index col = 0; col < (std::min)(n,m); ++col) + for (Index col = 0; col < n; ++col) { mark.setConstant(-1); m_R.startVec(col); - m_Q.startVec(col); mark(nonzeroCol) = col; Qidx(0) = nonzeroCol; nzcolR = 0; nzcolQ = 1; - found_diag = col>=m; + bool found_diag = nonzeroCol>=m; tval.setZero(); // Symbolic factorization: find the nonzero locations of the column k of the factors R and Q, i.e., // all the nodes (with indexes lower than rank) reachable through the column elimination tree (etree) rooted at node k. // Note: if the diagonal entry does not exist, then its contribution must be explicitly added, // thus the trick with found_diag that permits to do one more iteration on the diagonal element if this one has not been found. - for (typename MatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp) + for (typename QRMatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp) { - Index curIdx = nonzeroCol ; + Index curIdx = nonzeroCol; if(itp) curIdx = itp.row(); if(curIdx == nonzeroCol) found_diag = true; @@ -398,7 +446,7 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat) // Browse all the indexes of R(:,col) in reverse order for (Index i = nzcolR-1; i >= 0; i--) { - Index curIdx = m_pivotperm.indices()(Ridx(i)); + Index curIdx = Ridx(i); // Apply the curIdx-th householder vector to the current column (temporarily stored into tval) Scalar tdot(0); @@ -427,33 +475,36 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat) } } } // End update current column - - // Compute the Householder reflection that eliminate the current column - // FIXME this step should call the Householder module. - Scalar tau; - RealScalar beta; - Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0); - // First, the squared norm of Q((col+1):m, col) - RealScalar sqrNorm = 0.; - for (Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq))); + Scalar tau = 0; + RealScalar beta = 0; - if(sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0)) - { - tau = RealScalar(0); - beta = numext::real(c0); - tval(Qidx(0)) = 1; - } - else + if(nonzeroCol < diagSize) { - beta = std::sqrt(numext::abs2(c0) + sqrNorm); - if(numext::real(c0) >= RealScalar(0)) - beta = -beta; - tval(Qidx(0)) = 1; - for (Index itq = 1; itq < nzcolQ; ++itq) - tval(Qidx(itq)) /= (c0 - beta); - tau = numext::conj((beta-c0) / beta); - + // Compute the Householder reflection that eliminate the current column + // FIXME this step should call the Householder module. + Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0); + + // First, the squared norm of Q((col+1):m, col) + RealScalar sqrNorm = 0.; + for (Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq))); + if(sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0)) + { + beta = numext::real(c0); + tval(Qidx(0)) = 1; + } + else + { + using std::sqrt; + beta = sqrt(numext::abs2(c0) + sqrNorm); + if(numext::real(c0) >= RealScalar(0)) + beta = -beta; + tval(Qidx(0)) = 1; + for (Index itq = 1; itq < nzcolQ; ++itq) + tval(Qidx(itq)) /= (c0 - beta); + tau = numext::conj((beta-c0) / beta); + + } } // Insert values in R @@ -467,45 +518,49 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat) } } - if(abs(beta) >= m_threshold) + if(nonzeroCol < diagSize && abs(beta) >= pivotThreshold) { m_R.insertBackByOuterInner(col, nonzeroCol) = beta; - nonzeroCol++; // The householder coefficient - m_hcoeffs(col) = tau; + m_hcoeffs(nonzeroCol) = tau; // Record the householder reflections for (Index itq = 0; itq < nzcolQ; ++itq) { Index iQ = Qidx(itq); - m_Q.insertBackByOuterInnerUnordered(col,iQ) = tval(iQ); + m_Q.insertBackByOuterInnerUnordered(nonzeroCol,iQ) = tval(iQ); tval(iQ) = Scalar(0.); - } + } + nonzeroCol++; + if(nonzeroCol<diagSize) + m_Q.startVec(nonzeroCol); } else { // Zero pivot found: move implicitly this column to the end - m_hcoeffs(col) = Scalar(0); for (Index j = nonzeroCol; j < n-1; j++) std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j+1]); // Recompute the column elimination tree internal::coletree(m_pmat, m_etree, m_firstRowElt, m_pivotperm.indices().data()); + m_isEtreeOk = false; } } + m_hcoeffs.tail(diagSize-nonzeroCol).setZero(); + // Finalize the column pointers of the sparse matrices R and Q m_Q.finalize(); m_Q.makeCompressed(); m_R.finalize(); m_R.makeCompressed(); m_isQSorted = false; - + m_nonzeropivots = nonzeroCol; if(nonzeroCol<n) { // Permute the triangular factor to put the 'dead' columns to the end - MatrixType tempR(m_R); + QRMatrixType tempR(m_R); m_R = tempR * m_pivotperm; // Update the column permutation @@ -561,14 +616,16 @@ struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived template<typename DesType> void evalTo(DesType& res) const { + Index m = m_qr.rows(); Index n = m_qr.cols(); + Index diagSize = (std::min)(m,n); res = m_other; if (m_transpose) { eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes"); //Compute res = Q' * other column by column for(Index j = 0; j < res.cols(); j++){ - for (Index k = 0; k < n; k++) + for (Index k = 0; k < diagSize; k++) { Scalar tau = Scalar(0); tau = m_qr.m_Q.col(k).dot(res.col(j)); @@ -581,10 +638,10 @@ struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived else { eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes"); - // Compute res = Q' * other column by column + // Compute res = Q * other column by column for(Index j = 0; j < res.cols(); j++) { - for (Index k = n-1; k >=0; k--) + for (Index k = diagSize-1; k >=0; k--) { Scalar tau = Scalar(0); tau = m_qr.m_Q.col(k).dot(res.col(j)); @@ -618,7 +675,7 @@ struct SparseQRMatrixQReturnType : public EigenBase<SparseQRMatrixQReturnType<Sp return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr); } inline Index rows() const { return m_qr.rows(); } - inline Index cols() const { return m_qr.cols(); } + inline Index cols() const { return (std::min)(m_qr.rows(),m_qr.cols()); } // To use for operations with the transpose of Q SparseQRMatrixQTransposeReturnType<SparseQRType> transpose() const { diff --git a/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h b/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h index 4ee8e5c10a5..aaf66330b17 100644 --- a/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h +++ b/extern/Eigen3/Eigen/src/StlSupport/StdDeque.h @@ -11,7 +11,7 @@ #ifndef EIGEN_STDDEQUE_H #define EIGEN_STDDEQUE_H -#include "Eigen/src/StlSupport/details.h" +#include "details.h" // Define the explicit instantiation (e.g. necessary for the Intel compiler) #if defined(__INTEL_COMPILER) || defined(__GNUC__) diff --git a/extern/Eigen3/Eigen/src/StlSupport/StdList.h b/extern/Eigen3/Eigen/src/StlSupport/StdList.h index 627381ecec0..3c742430c12 100644 --- a/extern/Eigen3/Eigen/src/StlSupport/StdList.h +++ b/extern/Eigen3/Eigen/src/StlSupport/StdList.h @@ -10,7 +10,7 @@ #ifndef EIGEN_STDLIST_H #define EIGEN_STDLIST_H -#include "Eigen/src/StlSupport/details.h" +#include "details.h" // Define the explicit instantiation (e.g. necessary for the Intel compiler) #if defined(__INTEL_COMPILER) || defined(__GNUC__) diff --git a/extern/Eigen3/Eigen/src/StlSupport/StdVector.h b/extern/Eigen3/Eigen/src/StlSupport/StdVector.h index 40a9abefa82..611664a2e8a 100644 --- a/extern/Eigen3/Eigen/src/StlSupport/StdVector.h +++ b/extern/Eigen3/Eigen/src/StlSupport/StdVector.h @@ -11,7 +11,7 @@ #ifndef EIGEN_STDVECTOR_H #define EIGEN_STDVECTOR_H -#include "Eigen/src/StlSupport/details.h" +#include "details.h" /** * This section contains a convenience MACRO which allows an easy specialization of diff --git a/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h b/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h index 3a48cecf769..29c60c37875 100644 --- a/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h +++ b/extern/Eigen3/Eigen/src/UmfPackSupport/UmfPackSupport.h @@ -107,6 +107,16 @@ inline int umfpack_get_determinant(std::complex<double> *Mx, double *Ex, void *N return umfpack_zi_get_determinant(&mx_real,0,Ex,NumericHandle,User_Info); } +namespace internal { + template<typename T> struct umfpack_helper_is_sparse_plain : false_type {}; + template<typename Scalar, int Options, typename StorageIndex> + struct umfpack_helper_is_sparse_plain<SparseMatrix<Scalar,Options,StorageIndex> > + : true_type {}; + template<typename Scalar, int Options, typename StorageIndex> + struct umfpack_helper_is_sparse_plain<MappedSparseMatrix<Scalar,Options,StorageIndex> > + : true_type {}; +} + /** \ingroup UmfPackSupport_Module * \brief A sparse LU factorization and solver based on UmfPack * @@ -192,10 +202,14 @@ class UmfPackLU : internal::noncopyable * Note that the matrix should be column-major, and in compressed format for best performance. * \sa SparseMatrix::makeCompressed(). */ - void compute(const MatrixType& matrix) + template<typename InputMatrixType> + void compute(const InputMatrixType& matrix) { - analyzePattern(matrix); - factorize(matrix); + if(m_symbolic) umfpack_free_symbolic(&m_symbolic,Scalar()); + if(m_numeric) umfpack_free_numeric(&m_numeric,Scalar()); + grapInput(matrix.derived()); + analyzePattern_impl(); + factorize_impl(); } /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A. @@ -230,23 +244,15 @@ class UmfPackLU : internal::noncopyable * * \sa factorize(), compute() */ - void analyzePattern(const MatrixType& matrix) + template<typename InputMatrixType> + void analyzePattern(const InputMatrixType& matrix) { - if(m_symbolic) - umfpack_free_symbolic(&m_symbolic,Scalar()); - if(m_numeric) - umfpack_free_numeric(&m_numeric,Scalar()); + if(m_symbolic) umfpack_free_symbolic(&m_symbolic,Scalar()); + if(m_numeric) umfpack_free_numeric(&m_numeric,Scalar()); - grapInput(matrix); - - int errorCode = 0; - errorCode = umfpack_symbolic(matrix.rows(), matrix.cols(), m_outerIndexPtr, m_innerIndexPtr, m_valuePtr, - &m_symbolic, 0, 0); + grapInput(matrix.derived()); - m_isInitialized = true; - m_info = errorCode ? InvalidInput : Success; - m_analysisIsOk = true; - m_factorizationIsOk = false; + analyzePattern_impl(); } /** Performs a numeric decomposition of \a matrix @@ -255,20 +261,16 @@ class UmfPackLU : internal::noncopyable * * \sa analyzePattern(), compute() */ - void factorize(const MatrixType& matrix) + template<typename InputMatrixType> + void factorize(const InputMatrixType& matrix) { eigen_assert(m_analysisIsOk && "UmfPackLU: you must first call analyzePattern()"); if(m_numeric) umfpack_free_numeric(&m_numeric,Scalar()); - grapInput(matrix); - - int errorCode; - errorCode = umfpack_numeric(m_outerIndexPtr, m_innerIndexPtr, m_valuePtr, - m_symbolic, &m_numeric, 0, 0); - - m_info = errorCode ? NumericalIssue : Success; - m_factorizationIsOk = true; + grapInput(matrix.derived()); + + factorize_impl(); } #ifndef EIGEN_PARSED_BY_DOXYGEN @@ -283,19 +285,20 @@ class UmfPackLU : internal::noncopyable protected: - void init() { - m_info = InvalidInput; - m_isInitialized = false; - m_numeric = 0; - m_symbolic = 0; - m_outerIndexPtr = 0; - m_innerIndexPtr = 0; - m_valuePtr = 0; + m_info = InvalidInput; + m_isInitialized = false; + m_numeric = 0; + m_symbolic = 0; + m_outerIndexPtr = 0; + m_innerIndexPtr = 0; + m_valuePtr = 0; + m_extractedDataAreDirty = true; } - void grapInput(const MatrixType& mat) + template<typename InputMatrixType> + void grapInput_impl(const InputMatrixType& mat, internal::true_type) { m_copyMatrix.resize(mat.rows(), mat.cols()); if( ((MatrixType::Flags&RowMajorBit)==RowMajorBit) || sizeof(typename MatrixType::Index)!=sizeof(int) || !mat.isCompressed() ) @@ -313,6 +316,45 @@ class UmfPackLU : internal::noncopyable m_valuePtr = mat.valuePtr(); } } + + template<typename InputMatrixType> + void grapInput_impl(const InputMatrixType& mat, internal::false_type) + { + m_copyMatrix = mat; + m_outerIndexPtr = m_copyMatrix.outerIndexPtr(); + m_innerIndexPtr = m_copyMatrix.innerIndexPtr(); + m_valuePtr = m_copyMatrix.valuePtr(); + } + + template<typename InputMatrixType> + void grapInput(const InputMatrixType& mat) + { + grapInput_impl(mat, internal::umfpack_helper_is_sparse_plain<InputMatrixType>()); + } + + void analyzePattern_impl() + { + int errorCode = 0; + errorCode = umfpack_symbolic(m_copyMatrix.rows(), m_copyMatrix.cols(), m_outerIndexPtr, m_innerIndexPtr, m_valuePtr, + &m_symbolic, 0, 0); + + m_isInitialized = true; + m_info = errorCode ? InvalidInput : Success; + m_analysisIsOk = true; + m_factorizationIsOk = false; + m_extractedDataAreDirty = true; + } + + void factorize_impl() + { + int errorCode; + errorCode = umfpack_numeric(m_outerIndexPtr, m_innerIndexPtr, m_valuePtr, + m_symbolic, &m_numeric, 0, 0); + + m_info = errorCode ? NumericalIssue : Success; + m_factorizationIsOk = true; + m_extractedDataAreDirty = true; + } // cached data to reduce reallocation, etc. mutable LUMatrixType m_l; diff --git a/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h b/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h index 5c8c476eecf..1951286f3ae 100644 --- a/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h +++ b/extern/Eigen3/Eigen/src/plugins/ArrayCwiseBinaryOps.h @@ -70,6 +70,43 @@ max return (max)(Derived::PlainObject::Constant(rows(), cols(), other)); } + +#define EIGEN_MAKE_CWISE_COMP_OP(OP, COMPARATOR) \ +template<typename OtherDerived> \ +EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const Derived, const OtherDerived> \ +OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const \ +{ \ + return CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const Derived, const OtherDerived>(derived(), other.derived()); \ +}\ +typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const Derived, const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> > Cmp ## COMPARATOR ## ReturnType; \ +typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_ ## COMPARATOR>, const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject>, const Derived > RCmp ## COMPARATOR ## ReturnType; \ +EIGEN_STRONG_INLINE const Cmp ## COMPARATOR ## ReturnType \ +OP(const Scalar& s) const { \ + return this->OP(Derived::PlainObject::Constant(rows(), cols(), s)); \ +} \ +friend EIGEN_STRONG_INLINE const RCmp ## COMPARATOR ## ReturnType \ +OP(const Scalar& s, const Derived& d) { \ + return Derived::PlainObject::Constant(d.rows(), d.cols(), s).OP(d); \ +} + +#define EIGEN_MAKE_CWISE_COMP_R_OP(OP, R_OP, RCOMPARATOR) \ +template<typename OtherDerived> \ +EIGEN_STRONG_INLINE const CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_##RCOMPARATOR>, const OtherDerived, const Derived> \ +OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const \ +{ \ + return CwiseBinaryOp<internal::scalar_cmp_op<Scalar, internal::cmp_##RCOMPARATOR>, const OtherDerived, const Derived>(other.derived(), derived()); \ +} \ +\ +inline const RCmp ## RCOMPARATOR ## ReturnType \ +OP(const Scalar& s) const { \ + return Derived::PlainObject::Constant(rows(), cols(), s).R_OP(*this); \ +} \ +friend inline const Cmp ## RCOMPARATOR ## ReturnType \ +OP(const Scalar& s, const Derived& d) { \ + return d.R_OP(Derived::PlainObject::Constant(d.rows(), d.cols(), s)); \ +} + + /** \returns an expression of the coefficient-wise \< operator of *this and \a other * * Example: \include Cwise_less.cpp @@ -77,7 +114,7 @@ max * * \sa all(), any(), operator>(), operator<=() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator<,std::less) +EIGEN_MAKE_CWISE_COMP_OP(operator<, LT) /** \returns an expression of the coefficient-wise \<= operator of *this and \a other * @@ -86,7 +123,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator<,std::less) * * \sa all(), any(), operator>=(), operator<() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator<=,std::less_equal) +EIGEN_MAKE_CWISE_COMP_OP(operator<=, LE) /** \returns an expression of the coefficient-wise \> operator of *this and \a other * @@ -95,7 +132,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator<=,std::less_equal) * * \sa all(), any(), operator>=(), operator<() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator>,std::greater) +EIGEN_MAKE_CWISE_COMP_R_OP(operator>, operator<, LT) /** \returns an expression of the coefficient-wise \>= operator of *this and \a other * @@ -104,7 +141,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator>,std::greater) * * \sa all(), any(), operator>(), operator<=() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator>=,std::greater_equal) +EIGEN_MAKE_CWISE_COMP_R_OP(operator>=, operator<=, LE) /** \returns an expression of the coefficient-wise == operator of *this and \a other * @@ -118,7 +155,7 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator>=,std::greater_equal) * * \sa all(), any(), isApprox(), isMuchSmallerThan() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator==,std::equal_to) +EIGEN_MAKE_CWISE_COMP_OP(operator==, EQ) /** \returns an expression of the coefficient-wise != operator of *this and \a other * @@ -132,7 +169,10 @@ EIGEN_MAKE_CWISE_BINARY_OP(operator==,std::equal_to) * * \sa all(), any(), isApprox(), isMuchSmallerThan() */ -EIGEN_MAKE_CWISE_BINARY_OP(operator!=,std::not_equal_to) +EIGEN_MAKE_CWISE_COMP_OP(operator!=, NEQ) + +#undef EIGEN_MAKE_CWISE_COMP_OP +#undef EIGEN_MAKE_CWISE_COMP_R_OP // scalar addition @@ -209,3 +249,5 @@ operator||(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const THIS_METHOD_IS_ONLY_FOR_EXPRESSIONS_OF_BOOL); return CwiseBinaryOp<internal::scalar_boolean_or_op, const Derived, const OtherDerived>(derived(),other.derived()); } + + diff --git a/extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h b/extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h index a596367906f..1c3ed3fcd70 100644 --- a/extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h +++ b/extern/Eigen3/Eigen/src/plugins/ArrayCwiseUnaryOps.h @@ -185,19 +185,3 @@ cube() const { return derived(); } - -#define EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(METHOD_NAME,FUNCTOR) \ - inline const CwiseUnaryOp<std::binder2nd<FUNCTOR<Scalar> >, const Derived> \ - METHOD_NAME(const Scalar& s) const { \ - return CwiseUnaryOp<std::binder2nd<FUNCTOR<Scalar> >, const Derived> \ - (derived(), std::bind2nd(FUNCTOR<Scalar>(), s)); \ - } - -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator==, std::equal_to) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator!=, std::not_equal_to) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<, std::less) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator<=, std::less_equal) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>, std::greater) -EIGEN_MAKE_SCALAR_CWISE_UNARY_OP(operator>=, std::greater_equal) - - diff --git a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h index 7f62149e04b..c4a042b7027 100644 --- a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h +++ b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseBinaryOps.h @@ -124,3 +124,20 @@ cwiseQuotient(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const { return CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, const Derived, const OtherDerived>(derived(), other.derived()); } + +typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar,internal::cmp_EQ>, const Derived, const ConstantReturnType> CwiseScalarEqualReturnType; + +/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s + * + * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. + * In order to check for equality between two vectors or matrices with floating-point coefficients, it is + * generally a far better idea to use a fuzzy comparison as provided by isApprox() and + * isMuchSmallerThan(). + * + * \sa cwiseEqual(const MatrixBase<OtherDerived> &) const + */ +inline const CwiseScalarEqualReturnType +cwiseEqual(const Scalar& s) const +{ + return CwiseScalarEqualReturnType(derived(), Derived::Constant(rows(), cols(), s), internal::scalar_cmp_op<Scalar,internal::cmp_EQ>()); +} diff --git a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h index 0cf0640bae6..8de10935d55 100644 --- a/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h +++ b/extern/Eigen3/Eigen/src/plugins/MatrixCwiseUnaryOps.h @@ -50,18 +50,3 @@ cwiseSqrt() const { return derived(); } inline const CwiseUnaryOp<internal::scalar_inverse_op<Scalar>, const Derived> cwiseInverse() const { return derived(); } -/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s - * - * \warning this performs an exact comparison, which is generally a bad idea with floating-point types. - * In order to check for equality between two vectors or matrices with floating-point coefficients, it is - * generally a far better idea to use a fuzzy comparison as provided by isApprox() and - * isMuchSmallerThan(). - * - * \sa cwiseEqual(const MatrixBase<OtherDerived> &) const - */ -inline const CwiseUnaryOp<std::binder1st<std::equal_to<Scalar> >, const Derived> -cwiseEqual(const Scalar& s) const -{ - return CwiseUnaryOp<std::binder1st<std::equal_to<Scalar> >,const Derived> - (derived(), std::bind1st(std::equal_to<Scalar>(), s)); -} diff --git a/extern/Eigen3/eigen-update.sh b/extern/Eigen3/eigen-update.sh index 1cf0337adf6..9d22098c4fd 100755 --- a/extern/Eigen3/eigen-update.sh +++ b/extern/Eigen3/eigen-update.sh @@ -17,7 +17,7 @@ if [ -d eigen ] then cd eigen # put here the version you want to use - hg up 3.2.1 + hg up 3.2.7 rm -f `find Eigen/ -type f -name "CMakeLists.txt"` cp -r Eigen .. cd .. diff --git a/extern/SConscript b/extern/SConscript index 484c0e959c2..a5d8c1f078e 100644 --- a/extern/SConscript +++ b/extern/SConscript @@ -7,11 +7,9 @@ if env['WITH_BF_GLEW_ES']: else: SConscript(['glew/SConscript']) -SConscript(['colamd/SConscript']) SConscript(['rangetree/SConscript']) SConscript(['wcwidth/SConscript']) SConscript(['libmv/SConscript']) -SConscript(['Eigen3/SConscript']) if env['WITH_BF_GAMEENGINE']: SConscript(['recastnavigation/SConscript']) diff --git a/extern/colamd/CMakeLists.txt b/extern/colamd/CMakeLists.txt deleted file mode 100644 index 3019ee5904e..00000000000 --- a/extern/colamd/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# The Original Code is Copyright (C) 2011, Blender Foundation -# All rights reserved. -# -# Contributor(s): Blender Foundation, -# Sergey Sharybin -# -# ***** END GPL LICENSE BLOCK ***** - -set(INC - Include -) - -set(INC_SYS - -) - -set(SRC - Source/colamd.c - Source/colamd_global.c - - Include/colamd.h - Include/UFconfig.h -) - -blender_add_lib(extern_colamd "${SRC}" "${INC}" "${INC_SYS}") diff --git a/extern/colamd/Doc/ChangeLog b/extern/colamd/Doc/ChangeLog deleted file mode 100644 index 29308e9ad01..00000000000 --- a/extern/colamd/Doc/ChangeLog +++ /dev/null @@ -1,129 +0,0 @@ -May 31, 2007: version 2.7.0 - - * ported to 64-bit MATLAB - - * subdirectories added (Source/, Include/, Lib/, Doc/, MATLAB/, Demo/) - -Dec 12, 2006, version 2.5.2 - - * minor MATLAB cleanup. MATLAB functions renamed colamd2 and symamd2, - so that they do not conflict with the built-in versions. Note that - the MATLAB built-in functions colamd and symamd are identical to - the colamd and symamd functions here. - -Aug 31, 2006: Version 2.5.1 - - * minor change to colamd.m and symamd.m, to use etree instead - of sparsfun. - -Apr. 30, 2006: Version 2.5 - - * colamd_recommended modified, to do more careful integer overflow - checking. It now returns size_t, not int. colamd_l_recommended - also returns size_t. A zero is returned if an error occurs. A - postive return value denotes success. In v2.4 and earlier, - -1 was returned on error (an int or long). - - * long replaced with UF_long integer, which is long except on WIN64. - -Nov 15, 2005: - - * minor editting of comments; version number (2.4) unchanged. - -Changes from Version 2.3 to 2.4 (Aug 30, 2005) - - * Makefile now relies on ../UFconfig/UFconfig.mk - - * changed the dense row/col detection. The meaning of the knobs - has thus changed. - - * added an option to turn off aggressive absorption. It was - always on in versions 2.3 and earlier. - - * added a #define'd version number - - * added a function pointer (colamd_printf) for COLAMD's printing. - - * added a -DNPRINT option, to turn off printing at compile-time. - - * added a check for integer overflow in colamd_recommended - - * minor changes to allow for more simpler 100% test coverage - - * bug fix. If symamd v2.3 fails to allocate its copy of the input - matrix, then it erroneously frees a calloc'd workspace twice. - This bug has no effect on the MATLAB symamd mexFunction, since - mxCalloc terminates the mexFunction if it fails to allocate - memory. Similarly, UMFPACK is not affected because it does not - use symamd. The bug has no effect on the colamd ordering - routine in v2.3. - -Changes from Version 2.2 to 2.3 (Sept. 8, 2003) - - * removed the call to the MATLAB spparms ('spumoni') function. - This can take a lot of time if you are ordering many small - matrices. Only affects the MATLAB interface (colamdmex.c, - symamdmex.c, colamdtestmex.c, and symamdtestmex.c). The - usage of the optional 2nd argument to the colamd and symamd - mexFunctions was changed accordingly. - -Changes from Version 2.1 to 2.2 (Sept. 23, 2002) - - * extensive testing routines added (colamd_test.m, colamdtestmex.c, - and symamdtestmex.c), and the Makefile modified accordingly. - - * a few typos in the comments corrected - - * use of the MATLAB "flops" command removed from colamd_demo, and an - m-file routine luflops.m added. - - * an explicit typecast from unsigned to int added, for COLAMD_C and - COLAMD_R in colamd.h. - - * #include <stdio.h> added to colamd_example.c - - -Changes from Version 2.0 to 2.1 (May 4, 2001) - - * TRUE and FALSE are predefined on some systems, so they are defined - here only if not already defined. - - * web site changed - - * UNIX Makefile modified, to handle the case if "." is not in your path. - - -Changes from Version 1.0 to 2.0 (January 31, 2000) - - No bugs were found in version 1.1. These changes merely add new - functionality. - - * added the COLAMD_RECOMMENDED (nnz, n_row, n_col) macro. - - * moved the output statistics, from A, to a separate output argument. - The arguments changed for the C-callable routines. - - * added colamd_report and symamd_report. - - * added a C-callable symamd routine. Formerly, symamd was only - available as a mexFunction from MATLAB. - - * added error-checking to symamd. Formerly, it assumed its input - was error-free. - - * added the optional stats and knobs arguments to the symamd mexFunction - - * deleted colamd_help. A help message is still available from - "help colamd" and "help symamd" in MATLAB. - - * deleted colamdtree.m and symamdtree.m. Now, colamd.m and symamd.m - also do the elimination tree post-ordering. The Version 1.1 - colamd and symamd mexFunctions, which do not do the post- - ordering, are now visible as colamdmex and symamdmex from - MATLAB. Essentialy, the post-ordering is now the default - behavior of colamd.m and symamd.m, to match the behavior of - colmmd and symmmd. The post-ordering is only available in the - MATLAB interface, not the C-callable interface. - - * made a slight change to the dense row/column detection in symamd, - to match the stated specifications. diff --git a/extern/colamd/Doc/lesser.txt b/extern/colamd/Doc/lesser.txt deleted file mode 100644 index 8add30ad590..00000000000 --- a/extern/colamd/Doc/lesser.txt +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - <one line to give the library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/extern/colamd/Include/UFconfig.h b/extern/colamd/Include/UFconfig.h deleted file mode 100644 index 7b5e79e544f..00000000000 --- a/extern/colamd/Include/UFconfig.h +++ /dev/null @@ -1,118 +0,0 @@ -/* ========================================================================== */ -/* === UFconfig.h =========================================================== */ -/* ========================================================================== */ - -/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages - * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others). - * - * UFconfig.h provides the definition of the long integer. On most systems, - * a C program can be compiled in LP64 mode, in which long's and pointers are - * both 64-bits, and int's are 32-bits. Windows 64, however, uses the LLP64 - * model, in which int's and long's are 32-bits, and long long's and pointers - * are 64-bits. - * - * SuiteSparse packages that include long integer versions are - * intended for the LP64 mode. However, as a workaround for Windows 64 - * (and perhaps other systems), the long integer can be redefined. - * - * If _WIN64 is defined, then the __int64 type is used instead of long. - * - * The long integer can also be defined at compile time. For example, this - * could be added to UFconfig.mk: - * - * CFLAGS = -O -D'UF_long=long long' -D'UF_long_max=9223372036854775801' \ - * -D'UF_long_id="%lld"' - * - * This file defines UF_long as either long (on all but _WIN64) or - * __int64 on Windows 64. The intent is that a UF_long is always a 64-bit - * integer in a 64-bit code. ptrdiff_t might be a better choice than long; - * it is always the same size as a pointer. - * - * This file also defines the SUITESPARSE_VERSION and related definitions. - * - * Copyright (c) 2007, University of Florida. No licensing restrictions - * apply to this file or to the UFconfig directory. Author: Timothy A. Davis. - */ - -#ifndef _UFCONFIG_H -#define _UFCONFIG_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <limits.h> - -/* ========================================================================== */ -/* === UF_long ============================================================== */ -/* ========================================================================== */ - -#ifndef UF_long - -#ifdef _WIN64 - -#define UF_long __int64 -#define UF_long_max _I64_MAX -#define UF_long_id "%I64d" - -#else - -#define UF_long long -#define UF_long_max LONG_MAX -#define UF_long_id "%ld" - -#endif -#endif - -/* ========================================================================== */ -/* === SuiteSparse version ================================================== */ -/* ========================================================================== */ - -/* SuiteSparse is not a package itself, but a collection of packages, some of - * which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD, - * COLAMD, CAMD, and CCOLAMD, etc). A version number is provided here for the - * collection itself. The versions of packages within each version of - * SuiteSparse are meant to work together. Combining one packge from one - * version of SuiteSparse, with another package from another version of - * SuiteSparse, may or may not work. - * - * SuiteSparse Version 3.4.0 contains the following packages: - * - * AMD version 2.2.0 - * CAMD version 2.2.0 - * COLAMD version 2.7.1 - * CCOLAMD version 2.7.1 - * CHOLMOD version 1.7.1 - * CSparse version 2.2.3 - * CXSparse version 2.2.3 - * KLU version 1.1.0 - * BTF version 1.1.0 - * LDL version 2.0.1 - * UFconfig version number is the same as SuiteSparse - * UMFPACK version 5.4.0 - * RBio version 1.1.2 - * UFcollection version 1.2.0 - * LINFACTOR version 1.1.0 - * MESHND version 1.1.1 - * SSMULT version 2.0.0 - * MATLAB_Tools no specific version number - * SuiteSparseQR version 1.1.2 - * - * Other package dependencies: - * BLAS required by CHOLMOD and UMFPACK - * LAPACK required by CHOLMOD - * METIS 4.0.1 required by CHOLMOD (optional) and KLU (optional) - */ - -#define SUITESPARSE_DATE "May 20, 2009" -#define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub)) -#define SUITESPARSE_MAIN_VERSION 3 -#define SUITESPARSE_SUB_VERSION 4 -#define SUITESPARSE_SUBSUB_VERSION 0 -#define SUITESPARSE_VERSION \ - SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/extern/colamd/Include/colamd.h b/extern/colamd/Include/colamd.h deleted file mode 100644 index 26372d8fa96..00000000000 --- a/extern/colamd/Include/colamd.h +++ /dev/null @@ -1,255 +0,0 @@ -/* ========================================================================== */ -/* === colamd/symamd prototypes and definitions ============================= */ -/* ========================================================================== */ - -/* COLAMD / SYMAMD include file - - You must include this file (colamd.h) in any routine that uses colamd, - symamd, or the related macros and definitions. - - Authors: - - The authors of the code itself are Stefan I. Larimore and Timothy A. - Davis (davis at cise.ufl.edu), University of Florida. The algorithm was - developed in collaboration with John Gilbert, Xerox PARC, and Esmond - Ng, Oak Ridge National Laboratory. - - Acknowledgements: - - This work was supported by the National Science Foundation, under - grants DMS-9504974 and DMS-9803599. - - Notice: - - Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. - - THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY - EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - - Permission is hereby granted to use, copy, modify, and/or distribute - this program, provided that the Copyright, this License, and the - Availability of the original version is retained on all copies and made - accessible to the end-user of any code or package that includes COLAMD - or any modified version of COLAMD. - - Availability: - - The colamd/symamd library is available at - - http://www.cise.ufl.edu/research/sparse/colamd/ - - This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.h - file. It is required by the colamd.c, colamdmex.c, and symamdmex.c - files, and by any C code that calls the routines whose prototypes are - listed below, or that uses the colamd/symamd definitions listed below. - -*/ - -#ifndef COLAMD_H -#define COLAMD_H - -/* make it easy for C++ programs to include COLAMD */ -#ifdef __cplusplus -extern "C" { -#endif - -/* ========================================================================== */ -/* === Include files ======================================================== */ -/* ========================================================================== */ - -#include <stdlib.h> - -/* ========================================================================== */ -/* === COLAMD version ======================================================= */ -/* ========================================================================== */ - -/* COLAMD Version 2.4 and later will include the following definitions. - * As an example, to test if the version you are using is 2.4 or later: - * - * #ifdef COLAMD_VERSION - * if (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) ... - * #endif - * - * This also works during compile-time: - * - * #if defined(COLAMD_VERSION) && (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) - * printf ("This is version 2.4 or later\n") ; - * #else - * printf ("This is an early version\n") ; - * #endif - * - * Versions 2.3 and earlier of COLAMD do not include a #define'd version number. - */ - -#define COLAMD_DATE "Nov 1, 2007" -#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) -#define COLAMD_MAIN_VERSION 2 -#define COLAMD_SUB_VERSION 7 -#define COLAMD_SUBSUB_VERSION 1 -#define COLAMD_VERSION \ - COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION) - -/* ========================================================================== */ -/* === Knob and statistics definitions ====================================== */ -/* ========================================================================== */ - -/* size of the knobs [ ] array. Only knobs [0..1] are currently used. */ -#define COLAMD_KNOBS 20 - -/* number of output statistics. Only stats [0..6] are currently used. */ -#define COLAMD_STATS 20 - -/* knobs [0] and stats [0]: dense row knob and output statistic. */ -#define COLAMD_DENSE_ROW 0 - -/* knobs [1] and stats [1]: dense column knob and output statistic. */ -#define COLAMD_DENSE_COL 1 - -/* knobs [2]: aggressive absorption */ -#define COLAMD_AGGRESSIVE 2 - -/* stats [2]: memory defragmentation count output statistic */ -#define COLAMD_DEFRAG_COUNT 2 - -/* stats [3]: colamd status: zero OK, > 0 warning or notice, < 0 error */ -#define COLAMD_STATUS 3 - -/* stats [4..6]: error info, or info on jumbled columns */ -#define COLAMD_INFO1 4 -#define COLAMD_INFO2 5 -#define COLAMD_INFO3 6 - -/* error codes returned in stats [3]: */ -#define COLAMD_OK (0) -#define COLAMD_OK_BUT_JUMBLED (1) -#define COLAMD_ERROR_A_not_present (-1) -#define COLAMD_ERROR_p_not_present (-2) -#define COLAMD_ERROR_nrow_negative (-3) -#define COLAMD_ERROR_ncol_negative (-4) -#define COLAMD_ERROR_nnz_negative (-5) -#define COLAMD_ERROR_p0_nonzero (-6) -#define COLAMD_ERROR_A_too_small (-7) -#define COLAMD_ERROR_col_length_negative (-8) -#define COLAMD_ERROR_row_index_out_of_bounds (-9) -#define COLAMD_ERROR_out_of_memory (-10) -#define COLAMD_ERROR_internal_error (-999) - - -/* ========================================================================== */ -/* === Prototypes of user-callable routines ================================= */ -/* ========================================================================== */ - -/* define UF_long */ -#include "UFconfig.h" - -size_t colamd_recommended /* returns recommended value of Alen, */ - /* or 0 if input arguments are erroneous */ -( - int nnz, /* nonzeros in A */ - int n_row, /* number of rows in A */ - int n_col /* number of columns in A */ -) ; - -size_t colamd_l_recommended /* returns recommended value of Alen, */ - /* or 0 if input arguments are erroneous */ -( - UF_long nnz, /* nonzeros in A */ - UF_long n_row, /* number of rows in A */ - UF_long n_col /* number of columns in A */ -) ; - -void colamd_set_defaults /* sets default parameters */ -( /* knobs argument is modified on output */ - double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ -) ; - -void colamd_l_set_defaults /* sets default parameters */ -( /* knobs argument is modified on output */ - double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ -) ; - -int colamd /* returns (1) if successful, (0) otherwise*/ -( /* A and p arguments are modified on output */ - int n_row, /* number of rows in A */ - int n_col, /* number of columns in A */ - int Alen, /* size of the array A */ - int A [], /* row indices of A, of size Alen */ - int p [], /* column pointers of A, of size n_col+1 */ - double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ - int stats [COLAMD_STATS] /* colamd output statistics and error codes */ -) ; - -UF_long colamd_l /* returns (1) if successful, (0) otherwise*/ -( /* A and p arguments are modified on output */ - UF_long n_row, /* number of rows in A */ - UF_long n_col, /* number of columns in A */ - UF_long Alen, /* size of the array A */ - UF_long A [], /* row indices of A, of size Alen */ - UF_long p [], /* column pointers of A, of size n_col+1 */ - double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ - UF_long stats [COLAMD_STATS]/* colamd output statistics and error codes */ -) ; - -int symamd /* return (1) if OK, (0) otherwise */ -( - int n, /* number of rows and columns of A */ - int A [], /* row indices of A */ - int p [], /* column pointers of A */ - int perm [], /* output permutation, size n_col+1 */ - double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ - int stats [COLAMD_STATS], /* output statistics and error codes */ - void * (*allocate) (size_t, size_t), - /* pointer to calloc (ANSI C) or */ - /* mxCalloc (for MATLAB mexFunction) */ - void (*release) (void *) - /* pointer to free (ANSI C) or */ - /* mxFree (for MATLAB mexFunction) */ -) ; - -UF_long symamd_l /* return (1) if OK, (0) otherwise */ -( - UF_long n, /* number of rows and columns of A */ - UF_long A [], /* row indices of A */ - UF_long p [], /* column pointers of A */ - UF_long perm [], /* output permutation, size n_col+1 */ - double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ - UF_long stats [COLAMD_STATS], /* output statistics and error codes */ - void * (*allocate) (size_t, size_t), - /* pointer to calloc (ANSI C) or */ - /* mxCalloc (for MATLAB mexFunction) */ - void (*release) (void *) - /* pointer to free (ANSI C) or */ - /* mxFree (for MATLAB mexFunction) */ -) ; - -void colamd_report -( - int stats [COLAMD_STATS] -) ; - -void colamd_l_report -( - UF_long stats [COLAMD_STATS] -) ; - -void symamd_report -( - int stats [COLAMD_STATS] -) ; - -void symamd_l_report -( - UF_long stats [COLAMD_STATS] -) ; - -#ifndef EXTERN -#define EXTERN extern -#endif - -EXTERN int (*colamd_printf) (const char *, ...) ; - -#ifdef __cplusplus -} -#endif - -#endif /* COLAMD_H */ diff --git a/extern/colamd/README.txt b/extern/colamd/README.txt deleted file mode 100644 index 5ed81c71d02..00000000000 --- a/extern/colamd/README.txt +++ /dev/null @@ -1,127 +0,0 @@ -The COLAMD ordering method - Version 2.7 -------------------------------------------------------------------------------- - -The COLAMD column approximate minimum degree ordering algorithm computes -a permutation vector P such that the LU factorization of A (:,P) -tends to be sparser than that of A. The Cholesky factorization of -(A (:,P))'*(A (:,P)) will also tend to be sparser than that of A'*A. -SYMAMD is a symmetric minimum degree ordering method based on COLAMD, -available as a MATLAB-callable function. It constructs a matrix M such -that M'*M has the same pattern as A, and then uses COLAMD to compute a column -ordering of M. Colamd and symamd tend to be faster and generate better -orderings than their MATLAB counterparts, colmmd and symmmd. - -To compile and test the colamd m-files and mexFunctions, just unpack the -COLAMD/ directory from the COLAMD.tar.gz file, and run MATLAB from -within that directory. Next, type colamd_test to compile and test colamd -and symamd. This will work on any computer with MATLAB (Unix, PC, or Mac). -Alternatively, type "make" (in Unix) to compile and run a simple example C -code, without using MATLAB. - -To compile and install the colamd m-files and mexFunctions, just cd to -COLAMD/MATLAB and type colamd_install in the MATLAB command window. -A short demo will run. Optionally, type colamd_test to run an extensive tests. -Type "make" in Unix in the COLAMD directory to compile the C-callable -library and to run a short demo. - -If you have MATLAB 7.2 or earlier, you must first edit UFconfig/UFconfig.h to -remove the "-largeArrayDims" option from the MEX command (or just use -colamd_make.m inside MATLAB). - -Colamd is a built-in routine in MATLAB, available from The -Mathworks, Inc. Under most cases, the compiled COLAMD from Versions 2.0 to the -current version do not differ. Colamd Versions 2.2 and 2.3 differ only in their -mexFunction interaces to MATLAB. v2.4 fixes a bug in the symamd routine in -v2.3. The bug (in v2.3 and earlier) has no effect on the MATLAB symamd -mexFunction. v2.5 adds additional checks for integer overflow, so that -the "int" version can be safely used with 64-bit pointers. Refer to the -ChangeLog for more details. - -To use colamd and symamd within an application written in C, all you need are -colamd.c, colamd_global.c, and colamd.h, which are the C-callable -colamd/symamd codes. See colamd.c for more information on how to call -colamd from a C program. - -Requires UFconfig, in the ../UFconfig directory relative to this directory. - - Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. - - See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c - file) for the License. - - -Related papers: - - T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column - minimum degree ordering algorithm, ACM Transactions on Mathematical - Software, vol. 30, no. 3., pp. 353-376, 2004. - - T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, - an approximate column minimum degree ordering algorithm, ACM - Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380, - 2004. - - "An approximate minimum degree column ordering algorithm", - S. I. Larimore, MS Thesis, Dept. of Computer and Information - Science and Engineering, University of Florida, Gainesville, FL, - 1998. CISE Tech Report TR-98-016. Available at - ftp://ftp.cise.ufl.edu/cis/tech-reports/tr98/tr98-016.ps - via anonymous ftp. - - Approximate Deficiency for Ordering the Columns of a Matrix, - J. L. Kern, Senior Thesis, Dept. of Computer and Information - Science and Engineering, University of Florida, Gainesville, FL, - 1999. Available at http://www.cise.ufl.edu/~davis/Kern/kern.ps - - -Authors: Stefan I. Larimore and Timothy A. Davis, University of Florida, -in collaboration with John Gilbert, Xerox PARC (now at UC Santa Barbara), -and Esmong Ng, Lawrence Berkeley National Laboratory (much of this work -he did while at Oak Ridge National Laboratory). - -COLAMD files: - - Demo simple demo - Doc additional documentation (see colamd.c for more) - Include include file - Lib compiled C-callable library - Makefile primary Unix Makefile - MATLAB MATLAB functions - README.txt this file - Source C source code - - ./Demo: - colamd_example.c simple example - colamd_example.out output of colamd_example.c - colamd_l_example.c simple example, long integers - colamd_l_example.out output of colamd_l_example.c - Makefile Makefile for C demos - - ./Doc: - ChangeLog change log - lesser.txt license - - ./Include: - colamd.h include file - - ./Lib: - Makefile Makefile for C-callable library - - ./MATLAB: - colamd2.m MATLAB interface for colamd2 - colamd_demo.m simple demo - colamd_install.m compile and install colamd2 and symamd2 - colamd_make.m compile colamd2 and symamd2 - colamdmex.ca MATLAB mexFunction for colamd2 - colamd_test.m extensive test - colamdtestmex.c test function for colamd - Contents.m contents of the MATLAB directory - luflops.m test code - Makefile Makefile for MATLAB functions - symamd2.m MATLAB interface for symamd2 - symamdmex.c MATLAB mexFunction for symamd2 - symamdtestmex.c test function for symamd - - ./Source: - colamd.c primary source code - colamd_global.c globally defined function pointers (malloc, free, ...) diff --git a/extern/colamd/SConscript b/extern/colamd/SConscript deleted file mode 100644 index 7930e3ace2d..00000000000 --- a/extern/colamd/SConscript +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/python -import sys -import os - -Import('env') - -defs = '' -cflags = [] - -src = env.Glob('Source/*.c') - -incs = './Include' - -env.BlenderLib ( libname = 'extern_colamd', sources=src, includes=Split(incs), defines=Split(defs), libtype=['extern', 'player'], priority=[20,137], compileflags=cflags ) diff --git a/extern/colamd/Source/colamd.c b/extern/colamd/Source/colamd.c deleted file mode 100644 index 5fe20d62822..00000000000 --- a/extern/colamd/Source/colamd.c +++ /dev/null @@ -1,3611 +0,0 @@ -/* ========================================================================== */ -/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */ -/* ========================================================================== */ - -/* COLAMD / SYMAMD - - colamd: an approximate minimum degree column ordering algorithm, - for LU factorization of symmetric or unsymmetric matrices, - QR factorization, least squares, interior point methods for - linear programming problems, and other related problems. - - symamd: an approximate minimum degree ordering algorithm for Cholesky - factorization of symmetric matrices. - - Purpose: - - Colamd computes a permutation Q such that the Cholesky factorization of - (AQ)'(AQ) has less fill-in and requires fewer floating point operations - than A'A. This also provides a good ordering for sparse partial - pivoting methods, P(AQ) = LU, where Q is computed prior to numerical - factorization, and P is computed during numerical factorization via - conventional partial pivoting with row interchanges. Colamd is the - column ordering method used in SuperLU, part of the ScaLAPACK library. - It is also available as built-in function in MATLAB Version 6, - available from MathWorks, Inc. (http://www.mathworks.com). This - routine can be used in place of colmmd in MATLAB. - - Symamd computes a permutation P of a symmetric matrix A such that the - Cholesky factorization of PAP' has less fill-in and requires fewer - floating point operations than A. Symamd constructs a matrix M such - that M'M has the same nonzero pattern of A, and then orders the columns - of M using colmmd. The column ordering of M is then returned as the - row and column ordering P of A. - - Authors: - - The authors of the code itself are Stefan I. Larimore and Timothy A. - Davis (davis at cise.ufl.edu), University of Florida. The algorithm was - developed in collaboration with John Gilbert, Xerox PARC, and Esmond - Ng, Oak Ridge National Laboratory. - - Acknowledgements: - - This work was supported by the National Science Foundation, under - grants DMS-9504974 and DMS-9803599. - - Copyright and License: - - Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. - COLAMD is also available under alternate licenses, contact T. Davis - for details. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 - USA - - Permission is hereby granted to use or copy this program under the - terms of the GNU LGPL, provided that the Copyright, this License, - and the Availability of the original version is retained on all copies. - User documentation of any code that uses this code or any modified - version of this code must cite the Copyright, this License, the - Availability note, and "Used by permission." Permission to modify - the code and to distribute modified code is granted, provided the - Copyright, this License, and the Availability note are retained, - and a notice that the code was modified is included. - - Availability: - - The colamd/symamd library is available at - - http://www.cise.ufl.edu/research/sparse/colamd/ - - This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c - file. It requires the colamd.h file. It is required by the colamdmex.c - and symamdmex.c files, for the MATLAB interface to colamd and symamd. - Appears as ACM Algorithm 836. - - See the ChangeLog file for changes since Version 1.0. - - References: - - T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column - minimum degree ordering algorithm, ACM Transactions on Mathematical - Software, vol. 30, no. 3., pp. 353-376, 2004. - - T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, - an approximate column minimum degree ordering algorithm, ACM - Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380, - 2004. - -*/ - -/* ========================================================================== */ -/* === Description of user-callable routines ================================ */ -/* ========================================================================== */ - -/* COLAMD includes both int and UF_long versions of all its routines. The - * description below is for the int version. For UF_long, all int arguments - * become UF_long. UF_long is normally defined as long, except for WIN64. - - ---------------------------------------------------------------------------- - colamd_recommended: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - size_t colamd_recommended (int nnz, int n_row, int n_col) ; - size_t colamd_l_recommended (UF_long nnz, UF_long n_row, - UF_long n_col) ; - - Purpose: - - Returns recommended value of Alen for use by colamd. Returns 0 - if any input argument is negative. The use of this routine - is optional. Not needed for symamd, which dynamically allocates - its own memory. - - Note that in v2.4 and earlier, these routines returned int or long. - They now return a value of type size_t. - - Arguments (all input arguments): - - int nnz ; Number of nonzeros in the matrix A. This must - be the same value as p [n_col] in the call to - colamd - otherwise you will get a wrong value - of the recommended memory to use. - - int n_row ; Number of rows in the matrix A. - - int n_col ; Number of columns in the matrix A. - - ---------------------------------------------------------------------------- - colamd_set_defaults: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - colamd_set_defaults (double knobs [COLAMD_KNOBS]) ; - colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ; - - Purpose: - - Sets the default parameters. The use of this routine is optional. - - Arguments: - - double knobs [COLAMD_KNOBS] ; Output only. - - NOTE: the meaning of the dense row/col knobs has changed in v2.4 - - knobs [0] and knobs [1] control dense row and col detection: - - Colamd: rows with more than - max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col)) - entries are removed prior to ordering. Columns with more than - max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col))) - entries are removed prior to - ordering, and placed last in the output column ordering. - - Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0]. - Rows and columns with more than - max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n)) - entries are removed prior to ordering, and placed last in the - output ordering. - - COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1, - respectively, in colamd.h. Default values of these two knobs - are both 10. Currently, only knobs [0] and knobs [1] are - used, but future versions may use more knobs. If so, they will - be properly set to their defaults by the future version of - colamd_set_defaults, so that the code that calls colamd will - not need to change, assuming that you either use - colamd_set_defaults, or pass a (double *) NULL pointer as the - knobs array to colamd or symamd. - - knobs [2]: aggressive absorption - - knobs [COLAMD_AGGRESSIVE] controls whether or not to do - aggressive absorption during the ordering. Default is TRUE. - - - ---------------------------------------------------------------------------- - colamd: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - int colamd (int n_row, int n_col, int Alen, int *A, int *p, - double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ; - UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen, - UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS], - UF_long stats [COLAMD_STATS]) ; - - Purpose: - - Computes a column ordering (Q) of A such that P(AQ)=LU or - (AQ)'AQ=LL' have less fill-in and require fewer floating point - operations than factorizing the unpermuted matrix A or A'A, - respectively. - - Returns: - - TRUE (1) if successful, FALSE (0) otherwise. - - Arguments: - - int n_row ; Input argument. - - Number of rows in the matrix A. - Restriction: n_row >= 0. - Colamd returns FALSE if n_row is negative. - - int n_col ; Input argument. - - Number of columns in the matrix A. - Restriction: n_col >= 0. - Colamd returns FALSE if n_col is negative. - - int Alen ; Input argument. - - Restriction (see note): - Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col - Colamd returns FALSE if these conditions are not met. - - Note: this restriction makes an modest assumption regarding - the size of the two typedef's structures in colamd.h. - We do, however, guarantee that - - Alen >= colamd_recommended (nnz, n_row, n_col) - - will be sufficient. Note: the macro version does not check - for integer overflow, and thus is not recommended. Use - the colamd_recommended routine instead. - - int A [Alen] ; Input argument, undefined on output. - - A is an integer array of size Alen. Alen must be at least as - large as the bare minimum value given above, but this is very - low, and can result in excessive run time. For best - performance, we recommend that Alen be greater than or equal to - colamd_recommended (nnz, n_row, n_col), which adds - nnz/5 to the bare minimum value given above. - - On input, the row indices of the entries in column c of the - matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices - in a given column c need not be in ascending order, and - duplicate row indices may be be present. However, colamd will - work a little faster if both of these conditions are met - (Colamd puts the matrix into this format, if it finds that the - the conditions are not met). - - The matrix is 0-based. That is, rows are in the range 0 to - n_row-1, and columns are in the range 0 to n_col-1. Colamd - returns FALSE if any row index is out of range. - - The contents of A are modified during ordering, and are - undefined on output. - - int p [n_col+1] ; Both input and output argument. - - p is an integer array of size n_col+1. On input, it holds the - "pointers" for the column form of the matrix A. Column c of - the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first - entry, p [0], must be zero, and p [c] <= p [c+1] must hold - for all c in the range 0 to n_col-1. The value p [n_col] is - thus the total number of entries in the pattern of the matrix A. - Colamd returns FALSE if these conditions are not met. - - On output, if colamd returns TRUE, the array p holds the column - permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is - the first column index in the new ordering, and p [n_col-1] is - the last. That is, p [k] = j means that column j of A is the - kth pivot column, in AQ, where k is in the range 0 to n_col-1 - (p [0] = j means that column j of A is the first column in AQ). - - If colamd returns FALSE, then no permutation is returned, and - p is undefined on output. - - double knobs [COLAMD_KNOBS] ; Input argument. - - See colamd_set_defaults for a description. - - int stats [COLAMD_STATS] ; Output argument. - - Statistics on the ordering, and error status. - See colamd.h for related definitions. - Colamd returns FALSE if stats is not present. - - stats [0]: number of dense or empty rows ignored. - - stats [1]: number of dense or empty columns ignored (and - ordered last in the output permutation p) - Note that a row can become "empty" if it - contains only "dense" and/or "empty" columns, - and similarly a column can become "empty" if it - only contains "dense" and/or "empty" rows. - - stats [2]: number of garbage collections performed. - This can be excessively high if Alen is close - to the minimum required value. - - stats [3]: status code. < 0 is an error code. - > 1 is a warning or notice. - - 0 OK. Each column of the input matrix contained - row indices in increasing order, with no - duplicates. - - 1 OK, but columns of input matrix were jumbled - (unsorted columns or duplicate entries). Colamd - had to do some extra work to sort the matrix - first and remove duplicate entries, but it - still was able to return a valid permutation - (return value of colamd was TRUE). - - stats [4]: highest numbered column that - is unsorted or has duplicate - entries. - stats [5]: last seen duplicate or - unsorted row index. - stats [6]: number of duplicate or - unsorted row indices. - - -1 A is a null pointer - - -2 p is a null pointer - - -3 n_row is negative - - stats [4]: n_row - - -4 n_col is negative - - stats [4]: n_col - - -5 number of nonzeros in matrix is negative - - stats [4]: number of nonzeros, p [n_col] - - -6 p [0] is nonzero - - stats [4]: p [0] - - -7 A is too small - - stats [4]: required size - stats [5]: actual size (Alen) - - -8 a column has a negative number of entries - - stats [4]: column with < 0 entries - stats [5]: number of entries in col - - -9 a row index is out of bounds - - stats [4]: column with bad row index - stats [5]: bad row index - stats [6]: n_row, # of rows of matrx - - -10 (unused; see symamd.c) - - -999 (unused; see symamd.c) - - Future versions may return more statistics in the stats array. - - Example: - - See http://www.cise.ufl.edu/research/sparse/colamd/example.c - for a complete example. - - To order the columns of a 5-by-4 matrix with 11 nonzero entries in - the following nonzero pattern - - x 0 x 0 - x 0 x x - 0 x x 0 - 0 0 x x - x x 0 0 - - with default knobs and no output statistics, do the following: - - #include "colamd.h" - #define ALEN 100 - int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ; - int p [ ] = {0, 3, 5, 9, 11} ; - int stats [COLAMD_STATS] ; - colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ; - - The permutation is returned in the array p, and A is destroyed. - - ---------------------------------------------------------------------------- - symamd: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - int symamd (int n, int *A, int *p, int *perm, - double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS], - void (*allocate) (size_t, size_t), void (*release) (void *)) ; - UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm, - double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS], - void (*allocate) (size_t, size_t), void (*release) (void *)) ; - - Purpose: - - The symamd routine computes an ordering P of a symmetric sparse - matrix A such that the Cholesky factorization PAP' = LL' remains - sparse. It is based on a column ordering of a matrix M constructed - so that the nonzero pattern of M'M is the same as A. The matrix A - is assumed to be symmetric; only the strictly lower triangular part - is accessed. You must pass your selected memory allocator (usually - calloc/free or mxCalloc/mxFree) to symamd, for it to allocate - memory for the temporary matrix M. - - Returns: - - TRUE (1) if successful, FALSE (0) otherwise. - - Arguments: - - int n ; Input argument. - - Number of rows and columns in the symmetrix matrix A. - Restriction: n >= 0. - Symamd returns FALSE if n is negative. - - int A [nnz] ; Input argument. - - A is an integer array of size nnz, where nnz = p [n]. - - The row indices of the entries in column c of the matrix are - held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a - given column c need not be in ascending order, and duplicate - row indices may be present. However, symamd will run faster - if the columns are in sorted order with no duplicate entries. - - The matrix is 0-based. That is, rows are in the range 0 to - n-1, and columns are in the range 0 to n-1. Symamd - returns FALSE if any row index is out of range. - - The contents of A are not modified. - - int p [n+1] ; Input argument. - - p is an integer array of size n+1. On input, it holds the - "pointers" for the column form of the matrix A. Column c of - the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first - entry, p [0], must be zero, and p [c] <= p [c+1] must hold - for all c in the range 0 to n-1. The value p [n] is - thus the total number of entries in the pattern of the matrix A. - Symamd returns FALSE if these conditions are not met. - - The contents of p are not modified. - - int perm [n+1] ; Output argument. - - On output, if symamd returns TRUE, the array perm holds the - permutation P, where perm [0] is the first index in the new - ordering, and perm [n-1] is the last. That is, perm [k] = j - means that row and column j of A is the kth column in PAP', - where k is in the range 0 to n-1 (perm [0] = j means - that row and column j of A are the first row and column in - PAP'). The array is used as a workspace during the ordering, - which is why it must be of length n+1, not just n. - - double knobs [COLAMD_KNOBS] ; Input argument. - - See colamd_set_defaults for a description. - - int stats [COLAMD_STATS] ; Output argument. - - Statistics on the ordering, and error status. - See colamd.h for related definitions. - Symamd returns FALSE if stats is not present. - - stats [0]: number of dense or empty row and columns ignored - (and ordered last in the output permutation - perm). Note that a row/column can become - "empty" if it contains only "dense" and/or - "empty" columns/rows. - - stats [1]: (same as stats [0]) - - stats [2]: number of garbage collections performed. - - stats [3]: status code. < 0 is an error code. - > 1 is a warning or notice. - - 0 OK. Each column of the input matrix contained - row indices in increasing order, with no - duplicates. - - 1 OK, but columns of input matrix were jumbled - (unsorted columns or duplicate entries). Symamd - had to do some extra work to sort the matrix - first and remove duplicate entries, but it - still was able to return a valid permutation - (return value of symamd was TRUE). - - stats [4]: highest numbered column that - is unsorted or has duplicate - entries. - stats [5]: last seen duplicate or - unsorted row index. - stats [6]: number of duplicate or - unsorted row indices. - - -1 A is a null pointer - - -2 p is a null pointer - - -3 (unused, see colamd.c) - - -4 n is negative - - stats [4]: n - - -5 number of nonzeros in matrix is negative - - stats [4]: # of nonzeros (p [n]). - - -6 p [0] is nonzero - - stats [4]: p [0] - - -7 (unused) - - -8 a column has a negative number of entries - - stats [4]: column with < 0 entries - stats [5]: number of entries in col - - -9 a row index is out of bounds - - stats [4]: column with bad row index - stats [5]: bad row index - stats [6]: n_row, # of rows of matrx - - -10 out of memory (unable to allocate temporary - workspace for M or count arrays using the - "allocate" routine passed into symamd). - - Future versions may return more statistics in the stats array. - - void * (*allocate) (size_t, size_t) - - A pointer to a function providing memory allocation. The - allocated memory must be returned initialized to zero. For a - C application, this argument should normally be a pointer to - calloc. For a MATLAB mexFunction, the routine mxCalloc is - passed instead. - - void (*release) (size_t, size_t) - - A pointer to a function that frees memory allocated by the - memory allocation routine above. For a C application, this - argument should normally be a pointer to free. For a MATLAB - mexFunction, the routine mxFree is passed instead. - - - ---------------------------------------------------------------------------- - colamd_report: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - colamd_report (int stats [COLAMD_STATS]) ; - colamd_l_report (UF_long stats [COLAMD_STATS]) ; - - Purpose: - - Prints the error status and statistics recorded in the stats - array on the standard error output (for a standard C routine) - or on the MATLAB output (for a mexFunction). - - Arguments: - - int stats [COLAMD_STATS] ; Input only. Statistics from colamd. - - - ---------------------------------------------------------------------------- - symamd_report: - ---------------------------------------------------------------------------- - - C syntax: - - #include "colamd.h" - symamd_report (int stats [COLAMD_STATS]) ; - symamd_l_report (UF_long stats [COLAMD_STATS]) ; - - Purpose: - - Prints the error status and statistics recorded in the stats - array on the standard error output (for a standard C routine) - or on the MATLAB output (for a mexFunction). - - Arguments: - - int stats [COLAMD_STATS] ; Input only. Statistics from symamd. - - -*/ - -/* ========================================================================== */ -/* === Scaffolding code definitions ======================================== */ -/* ========================================================================== */ - -/* Ensure that debugging is turned off: */ -#ifndef NDEBUG -#define NDEBUG -#endif - -/* turn on debugging by uncommenting the following line - #undef NDEBUG -*/ - -/* - Our "scaffolding code" philosophy: In our opinion, well-written library - code should keep its "debugging" code, and just normally have it turned off - by the compiler so as not to interfere with performance. This serves - several purposes: - - (1) assertions act as comments to the reader, telling you what the code - expects at that point. All assertions will always be true (unless - there really is a bug, of course). - - (2) leaving in the scaffolding code assists anyone who would like to modify - the code, or understand the algorithm (by reading the debugging output, - one can get a glimpse into what the code is doing). - - (3) (gasp!) for actually finding bugs. This code has been heavily tested - and "should" be fully functional and bug-free ... but you never know... - - The code will become outrageously slow when debugging is - enabled. To control the level of debugging output, set an environment - variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging, - you should see the following message on the standard output: - - colamd: debug version, D = 1 (THIS WILL BE SLOW!) - - or a similar message for symamd. If you don't, then debugging has not - been enabled. - -*/ - -/* ========================================================================== */ -/* === Include files ======================================================== */ -/* ========================================================================== */ - -#include "colamd.h" -#include <limits.h> -#include <math.h> - -#ifdef MATLAB_MEX_FILE -#include "mex.h" -#include "matrix.h" -#endif /* MATLAB_MEX_FILE */ - -#if !defined (NPRINT) || !defined (NDEBUG) -#include <stdio.h> -#endif - -#ifndef NULL -#define NULL ((void *) 0) -#endif - -/* ========================================================================== */ -/* === int or UF_long ======================================================= */ -/* ========================================================================== */ - -/* define UF_long */ -#include "UFconfig.h" - -#ifdef DLONG - -#define Int UF_long -#define ID UF_long_id -#define Int_MAX UF_long_max - -#define COLAMD_recommended colamd_l_recommended -#define COLAMD_set_defaults colamd_l_set_defaults -#define COLAMD_MAIN colamd_l -#define SYMAMD_MAIN symamd_l -#define COLAMD_report colamd_l_report -#define SYMAMD_report symamd_l_report - -#else - -#define Int int -#define ID "%d" -#define Int_MAX INT_MAX - -#define COLAMD_recommended colamd_recommended -#define COLAMD_set_defaults colamd_set_defaults -#define COLAMD_MAIN colamd -#define SYMAMD_MAIN symamd -#define COLAMD_report colamd_report -#define SYMAMD_report symamd_report - -#endif - -/* ========================================================================== */ -/* === Row and Column structures ============================================ */ -/* ========================================================================== */ - -/* User code that makes use of the colamd/symamd routines need not directly */ -/* reference these structures. They are used only for colamd_recommended. */ - -typedef struct Colamd_Col_struct -{ - Int start ; /* index for A of first row in this column, or DEAD */ - /* if column is dead */ - Int length ; /* number of rows in this column */ - union - { - Int thickness ; /* number of original columns represented by this */ - /* col, if the column is alive */ - Int parent ; /* parent in parent tree super-column structure, if */ - /* the column is dead */ - } shared1 ; - union - { - Int score ; /* the score used to maintain heap, if col is alive */ - Int order ; /* pivot ordering of this column, if col is dead */ - } shared2 ; - union - { - Int headhash ; /* head of a hash bucket, if col is at the head of */ - /* a degree list */ - Int hash ; /* hash value, if col is not in a degree list */ - Int prev ; /* previous column in degree list, if col is in a */ - /* degree list (but not at the head of a degree list) */ - } shared3 ; - union - { - Int degree_next ; /* next column, if col is in a degree list */ - Int hash_next ; /* next column, if col is in a hash list */ - } shared4 ; - -} Colamd_Col ; - -typedef struct Colamd_Row_struct -{ - Int start ; /* index for A of first col in this row */ - Int length ; /* number of principal columns in this row */ - union - { - Int degree ; /* number of principal & non-principal columns in row */ - Int p ; /* used as a row pointer in init_rows_cols () */ - } shared1 ; - union - { - Int mark ; /* for computing set differences and marking dead rows*/ - Int first_column ;/* first column in row (used in garbage collection) */ - } shared2 ; - -} Colamd_Row ; - -/* ========================================================================== */ -/* === Definitions ========================================================== */ -/* ========================================================================== */ - -/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */ -#define PUBLIC -#define PRIVATE static - -#define DENSE_DEGREE(alpha,n) \ - ((Int) MAX (16.0, (alpha) * sqrt ((double) (n)))) - -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) - -#define ONES_COMPLEMENT(r) (-(r)-1) - -/* -------------------------------------------------------------------------- */ -/* Change for version 2.1: define TRUE and FALSE only if not yet defined */ -/* -------------------------------------------------------------------------- */ - -#ifndef TRUE -#define TRUE (1) -#endif - -#ifndef FALSE -#define FALSE (0) -#endif - -/* -------------------------------------------------------------------------- */ - -#define EMPTY (-1) - -/* Row and column status */ -#define ALIVE (0) -#define DEAD (-1) - -/* Column status */ -#define DEAD_PRINCIPAL (-1) -#define DEAD_NON_PRINCIPAL (-2) - -/* Macros for row and column status update and checking. */ -#define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark) -#define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE) -#define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE) -#define COL_IS_DEAD(c) (Col [c].start < ALIVE) -#define COL_IS_ALIVE(c) (Col [c].start >= ALIVE) -#define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL) -#define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; } -#define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; } -#define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; } - -/* ========================================================================== */ -/* === Colamd reporting mechanism =========================================== */ -/* ========================================================================== */ - -#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS) -/* In MATLAB, matrices are 1-based to the user, but 0-based internally */ -#define INDEX(i) ((i)+1) -#else -/* In C, matrices are 0-based and indices are reported as such in *_report */ -#define INDEX(i) (i) -#endif - -/* All output goes through the PRINTF macro. */ -#define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; } - -/* ========================================================================== */ -/* === Prototypes of PRIVATE routines ======================================= */ -/* ========================================================================== */ - -PRIVATE Int init_rows_cols -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int p [], - Int stats [COLAMD_STATS] -) ; - -PRIVATE void init_scoring -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int head [], - double knobs [COLAMD_KNOBS], - Int *p_n_row2, - Int *p_n_col2, - Int *p_max_deg -) ; - -PRIVATE Int find_ordering -( - Int n_row, - Int n_col, - Int Alen, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int head [], - Int n_col2, - Int max_deg, - Int pfree, - Int aggressive -) ; - -PRIVATE void order_children -( - Int n_col, - Colamd_Col Col [], - Int p [] -) ; - -PRIVATE void detect_super_cols -( - -#ifndef NDEBUG - Int n_col, - Colamd_Row Row [], -#endif /* NDEBUG */ - - Colamd_Col Col [], - Int A [], - Int head [], - Int row_start, - Int row_length -) ; - -PRIVATE Int garbage_collection -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int *pfree -) ; - -PRIVATE Int clear_mark -( - Int tag_mark, - Int max_mark, - Int n_row, - Colamd_Row Row [] -) ; - -PRIVATE void print_report -( - char *method, - Int stats [COLAMD_STATS] -) ; - -/* ========================================================================== */ -/* === Debugging prototypes and definitions ================================= */ -/* ========================================================================== */ - -#ifndef NDEBUG - -#include <assert.h> - -/* colamd_debug is the *ONLY* global variable, and is only */ -/* present when debugging */ - -PRIVATE Int colamd_debug = 0 ; /* debug print level */ - -#define DEBUG0(params) { PRINTF (params) ; } -#define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; } -#define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; } -#define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; } -#define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; } - -#ifdef MATLAB_MEX_FILE -#define ASSERT(expression) (mxAssert ((expression), "")) -#else -#define ASSERT(expression) (assert (expression)) -#endif /* MATLAB_MEX_FILE */ - -PRIVATE void colamd_get_debug /* gets the debug print level from getenv */ -( - char *method -) ; - -PRIVATE void debug_deg_lists -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int head [], - Int min_score, - Int should, - Int max_deg -) ; - -PRIVATE void debug_mark -( - Int n_row, - Colamd_Row Row [], - Int tag_mark, - Int max_mark -) ; - -PRIVATE void debug_matrix -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [] -) ; - -PRIVATE void debug_structures -( - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int n_col2 -) ; - -#else /* NDEBUG */ - -/* === No debugging ========================================================= */ - -#define DEBUG0(params) ; -#define DEBUG1(params) ; -#define DEBUG2(params) ; -#define DEBUG3(params) ; -#define DEBUG4(params) ; - -#define ASSERT(expression) - -#endif /* NDEBUG */ - -/* ========================================================================== */ -/* === USER-CALLABLE ROUTINES: ============================================== */ -/* ========================================================================== */ - -/* ========================================================================== */ -/* === colamd_recommended =================================================== */ -/* ========================================================================== */ - -/* - The colamd_recommended routine returns the suggested size for Alen. This - value has been determined to provide good balance between the number of - garbage collections and the memory requirements for colamd. If any - argument is negative, or if integer overflow occurs, a 0 is returned as an - error condition. 2*nnz space is required for the row and column - indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is - required for the Col and Row arrays, respectively, which are internal to - colamd (roughly 6*n_col + 4*n_row). An additional n_col space is the - minimal amount of "elbow room", and nnz/5 more space is recommended for - run time efficiency. - - Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10. - - This function is not needed when using symamd. -*/ - -/* add two values of type size_t, and check for integer overflow */ -static size_t t_add (size_t a, size_t b, int *ok) -{ - (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ; - return ((*ok) ? (a + b) : 0) ; -} - -/* compute a*k where k is a small integer, and check for integer overflow */ -static size_t t_mult (size_t a, size_t k, int *ok) -{ - size_t i, s = 0 ; - for (i = 0 ; i < k ; i++) - { - s = t_add (s, a, ok) ; - } - return (s) ; -} - -/* size of the Col and Row structures */ -#define COLAMD_C(n_col,ok) \ - ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int))) - -#define COLAMD_R(n_row,ok) \ - ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int))) - - -PUBLIC size_t COLAMD_recommended /* returns recommended value of Alen. */ -( - /* === Parameters ======================================================= */ - - Int nnz, /* number of nonzeros in A */ - Int n_row, /* number of rows in A */ - Int n_col /* number of columns in A */ -) -{ - size_t s, c, r ; - int ok = TRUE ; - if (nnz < 0 || n_row < 0 || n_col < 0) - { - return (0) ; - } - s = t_mult (nnz, 2, &ok) ; /* 2*nnz */ - c = COLAMD_C (n_col, &ok) ; /* size of column structures */ - r = COLAMD_R (n_row, &ok) ; /* size of row structures */ - s = t_add (s, c, &ok) ; - s = t_add (s, r, &ok) ; - s = t_add (s, n_col, &ok) ; /* elbow room */ - s = t_add (s, nnz/5, &ok) ; /* elbow room */ - ok = ok && (s < Int_MAX) ; - return (ok ? s : 0) ; -} - - -/* ========================================================================== */ -/* === colamd_set_defaults ================================================== */ -/* ========================================================================== */ - -/* - The colamd_set_defaults routine sets the default values of the user- - controllable parameters for colamd and symamd: - - Colamd: rows with more than max (16, knobs [0] * sqrt (n_col)) - entries are removed prior to ordering. Columns with more than - max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed - prior to ordering, and placed last in the output column ordering. - - Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n)) - entries are removed prior to ordering, and placed last in the - output ordering. - - knobs [0] dense row control - - knobs [1] dense column control - - knobs [2] if nonzero, do aggresive absorption - - knobs [3..19] unused, but future versions might use this - -*/ - -PUBLIC void COLAMD_set_defaults -( - /* === Parameters ======================================================= */ - - double knobs [COLAMD_KNOBS] /* knob array */ -) -{ - /* === Local variables ================================================== */ - - Int i ; - - if (!knobs) - { - return ; /* no knobs to initialize */ - } - for (i = 0 ; i < COLAMD_KNOBS ; i++) - { - knobs [i] = 0 ; - } - knobs [COLAMD_DENSE_ROW] = 10 ; - knobs [COLAMD_DENSE_COL] = 10 ; - knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/ -} - - -/* ========================================================================== */ -/* === symamd =============================================================== */ -/* ========================================================================== */ - -PUBLIC Int SYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */ -( - /* === Parameters ======================================================= */ - - Int n, /* number of rows and columns of A */ - Int A [], /* row indices of A */ - Int p [], /* column pointers of A */ - Int perm [], /* output permutation, size n+1 */ - double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ - Int stats [COLAMD_STATS], /* output statistics and error codes */ - void * (*allocate) (size_t, size_t), - /* pointer to calloc (ANSI C) or */ - /* mxCalloc (for MATLAB mexFunction) */ - void (*release) (void *) - /* pointer to free (ANSI C) or */ - /* mxFree (for MATLAB mexFunction) */ -) -{ - /* === Local variables ================================================== */ - - Int *count ; /* length of each column of M, and col pointer*/ - Int *mark ; /* mark array for finding duplicate entries */ - Int *M ; /* row indices of matrix M */ - size_t Mlen ; /* length of M */ - Int n_row ; /* number of rows in M */ - Int nnz ; /* number of entries in A */ - Int i ; /* row index of A */ - Int j ; /* column index of A */ - Int k ; /* row index of M */ - Int mnz ; /* number of nonzeros in M */ - Int pp ; /* index into a column of A */ - Int last_row ; /* last row seen in the current column */ - Int length ; /* number of nonzeros in a column */ - - double cknobs [COLAMD_KNOBS] ; /* knobs for colamd */ - double default_knobs [COLAMD_KNOBS] ; /* default knobs for colamd */ - -#ifndef NDEBUG - colamd_get_debug ("symamd") ; -#endif /* NDEBUG */ - - /* === Check the input arguments ======================================== */ - - if (!stats) - { - DEBUG0 (("symamd: stats not present\n")) ; - return (FALSE) ; - } - for (i = 0 ; i < COLAMD_STATS ; i++) - { - stats [i] = 0 ; - } - stats [COLAMD_STATUS] = COLAMD_OK ; - stats [COLAMD_INFO1] = -1 ; - stats [COLAMD_INFO2] = -1 ; - - if (!A) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; - DEBUG0 (("symamd: A not present\n")) ; - return (FALSE) ; - } - - if (!p) /* p is not present */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; - DEBUG0 (("symamd: p not present\n")) ; - return (FALSE) ; - } - - if (n < 0) /* n must be >= 0 */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; - stats [COLAMD_INFO1] = n ; - DEBUG0 (("symamd: n negative %d\n", n)) ; - return (FALSE) ; - } - - nnz = p [n] ; - if (nnz < 0) /* nnz must be >= 0 */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; - stats [COLAMD_INFO1] = nnz ; - DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ; - return (FALSE) ; - } - - if (p [0] != 0) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; - stats [COLAMD_INFO1] = p [0] ; - DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ; - return (FALSE) ; - } - - /* === If no knobs, set default knobs =================================== */ - - if (!knobs) - { - COLAMD_set_defaults (default_knobs) ; - knobs = default_knobs ; - } - - /* === Allocate count and mark ========================================== */ - - count = (Int *) ((*allocate) (n+1, sizeof (Int))) ; - if (!count) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; - DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ; - return (FALSE) ; - } - - mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ; - if (!mark) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; - (*release) ((void *) count) ; - DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ; - return (FALSE) ; - } - - /* === Compute column counts of M, check if A is valid ================== */ - - stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ - - for (i = 0 ; i < n ; i++) - { - mark [i] = -1 ; - } - - for (j = 0 ; j < n ; j++) - { - last_row = -1 ; - - length = p [j+1] - p [j] ; - if (length < 0) - { - /* column pointers must be non-decreasing */ - stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; - stats [COLAMD_INFO1] = j ; - stats [COLAMD_INFO2] = length ; - (*release) ((void *) count) ; - (*release) ((void *) mark) ; - DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ; - return (FALSE) ; - } - - for (pp = p [j] ; pp < p [j+1] ; pp++) - { - i = A [pp] ; - if (i < 0 || i >= n) - { - /* row index i, in column j, is out of bounds */ - stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; - stats [COLAMD_INFO1] = j ; - stats [COLAMD_INFO2] = i ; - stats [COLAMD_INFO3] = n ; - (*release) ((void *) count) ; - (*release) ((void *) mark) ; - DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ; - return (FALSE) ; - } - - if (i <= last_row || mark [i] == j) - { - /* row index is unsorted or repeated (or both), thus col */ - /* is jumbled. This is a notice, not an error condition. */ - stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ; - stats [COLAMD_INFO1] = j ; - stats [COLAMD_INFO2] = i ; - (stats [COLAMD_INFO3]) ++ ; - DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ; - } - - if (i > j && mark [i] != j) - { - /* row k of M will contain column indices i and j */ - count [i]++ ; - count [j]++ ; - } - - /* mark the row as having been seen in this column */ - mark [i] = j ; - - last_row = i ; - } - } - - /* v2.4: removed free(mark) */ - - /* === Compute column pointers of M ===================================== */ - - /* use output permutation, perm, for column pointers of M */ - perm [0] = 0 ; - for (j = 1 ; j <= n ; j++) - { - perm [j] = perm [j-1] + count [j-1] ; - } - for (j = 0 ; j < n ; j++) - { - count [j] = perm [j] ; - } - - /* === Construct M ====================================================== */ - - mnz = perm [n] ; - n_row = mnz / 2 ; - Mlen = COLAMD_recommended (mnz, n_row, n) ; - M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ; - DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n", - n_row, n, mnz, (double) Mlen)) ; - - if (!M) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; - (*release) ((void *) count) ; - (*release) ((void *) mark) ; - DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ; - return (FALSE) ; - } - - k = 0 ; - - if (stats [COLAMD_STATUS] == COLAMD_OK) - { - /* Matrix is OK */ - for (j = 0 ; j < n ; j++) - { - ASSERT (p [j+1] - p [j] >= 0) ; - for (pp = p [j] ; pp < p [j+1] ; pp++) - { - i = A [pp] ; - ASSERT (i >= 0 && i < n) ; - if (i > j) - { - /* row k of M contains column indices i and j */ - M [count [i]++] = k ; - M [count [j]++] = k ; - k++ ; - } - } - } - } - else - { - /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */ - DEBUG0 (("symamd: Duplicates in A.\n")) ; - for (i = 0 ; i < n ; i++) - { - mark [i] = -1 ; - } - for (j = 0 ; j < n ; j++) - { - ASSERT (p [j+1] - p [j] >= 0) ; - for (pp = p [j] ; pp < p [j+1] ; pp++) - { - i = A [pp] ; - ASSERT (i >= 0 && i < n) ; - if (i > j && mark [i] != j) - { - /* row k of M contains column indices i and j */ - M [count [i]++] = k ; - M [count [j]++] = k ; - k++ ; - mark [i] = j ; - } - } - } - /* v2.4: free(mark) moved below */ - } - - /* count and mark no longer needed */ - (*release) ((void *) count) ; - (*release) ((void *) mark) ; /* v2.4: free (mark) moved here */ - ASSERT (k == n_row) ; - - /* === Adjust the knobs for M =========================================== */ - - for (i = 0 ; i < COLAMD_KNOBS ; i++) - { - cknobs [i] = knobs [i] ; - } - - /* there are no dense rows in M */ - cknobs [COLAMD_DENSE_ROW] = -1 ; - cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ; - - /* === Order the columns of M =========================================== */ - - /* v2.4: colamd cannot fail here, so the error check is removed */ - (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ; - - /* Note that the output permutation is now in perm */ - - /* === get the statistics for symamd from colamd ======================== */ - - /* a dense column in colamd means a dense row and col in symamd */ - stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ; - - /* === Free M =========================================================== */ - - (*release) ((void *) M) ; - DEBUG0 (("symamd: done.\n")) ; - return (TRUE) ; - -} - -/* ========================================================================== */ -/* === colamd =============================================================== */ -/* ========================================================================== */ - -/* - The colamd routine computes a column ordering Q of a sparse matrix - A such that the LU factorization P(AQ) = LU remains sparse, where P is - selected via partial pivoting. The routine can also be viewed as - providing a permutation Q such that the Cholesky factorization - (AQ)'(AQ) = LL' remains sparse. -*/ - -PUBLIC Int COLAMD_MAIN /* returns TRUE if successful, FALSE otherwise*/ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows in A */ - Int n_col, /* number of columns in A */ - Int Alen, /* length of A */ - Int A [], /* row indices of A */ - Int p [], /* pointers to columns in A */ - double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */ - Int stats [COLAMD_STATS] /* output statistics and error codes */ -) -{ - /* === Local variables ================================================== */ - - Int i ; /* loop index */ - Int nnz ; /* nonzeros in A */ - size_t Row_size ; /* size of Row [], in integers */ - size_t Col_size ; /* size of Col [], in integers */ - size_t need ; /* minimum required length of A */ - Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */ - Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */ - Int n_col2 ; /* number of non-dense, non-empty columns */ - Int n_row2 ; /* number of non-dense, non-empty rows */ - Int ngarbage ; /* number of garbage collections performed */ - Int max_deg ; /* maximum row degree */ - double default_knobs [COLAMD_KNOBS] ; /* default knobs array */ - Int aggressive ; /* do aggressive absorption */ - int ok ; - -#ifndef NDEBUG - colamd_get_debug ("colamd") ; -#endif /* NDEBUG */ - - /* === Check the input arguments ======================================== */ - - if (!stats) - { - DEBUG0 (("colamd: stats not present\n")) ; - return (FALSE) ; - } - for (i = 0 ; i < COLAMD_STATS ; i++) - { - stats [i] = 0 ; - } - stats [COLAMD_STATUS] = COLAMD_OK ; - stats [COLAMD_INFO1] = -1 ; - stats [COLAMD_INFO2] = -1 ; - - if (!A) /* A is not present */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; - DEBUG0 (("colamd: A not present\n")) ; - return (FALSE) ; - } - - if (!p) /* p is not present */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; - DEBUG0 (("colamd: p not present\n")) ; - return (FALSE) ; - } - - if (n_row < 0) /* n_row must be >= 0 */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ; - stats [COLAMD_INFO1] = n_row ; - DEBUG0 (("colamd: nrow negative %d\n", n_row)) ; - return (FALSE) ; - } - - if (n_col < 0) /* n_col must be >= 0 */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; - stats [COLAMD_INFO1] = n_col ; - DEBUG0 (("colamd: ncol negative %d\n", n_col)) ; - return (FALSE) ; - } - - nnz = p [n_col] ; - if (nnz < 0) /* nnz must be >= 0 */ - { - stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; - stats [COLAMD_INFO1] = nnz ; - DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ; - return (FALSE) ; - } - - if (p [0] != 0) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; - stats [COLAMD_INFO1] = p [0] ; - DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ; - return (FALSE) ; - } - - /* === If no knobs, set default knobs =================================== */ - - if (!knobs) - { - COLAMD_set_defaults (default_knobs) ; - knobs = default_knobs ; - } - - aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ; - - /* === Allocate the Row and Col arrays from array A ===================== */ - - ok = TRUE ; - Col_size = COLAMD_C (n_col, &ok) ; /* size of Col array of structs */ - Row_size = COLAMD_R (n_row, &ok) ; /* size of Row array of structs */ - - /* need = 2*nnz + n_col + Col_size + Row_size ; */ - need = t_mult (nnz, 2, &ok) ; - need = t_add (need, n_col, &ok) ; - need = t_add (need, Col_size, &ok) ; - need = t_add (need, Row_size, &ok) ; - - if (!ok || need > (size_t) Alen || need > Int_MAX) - { - /* not enough space in array A to perform the ordering */ - stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ; - stats [COLAMD_INFO1] = need ; - stats [COLAMD_INFO2] = Alen ; - DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen)); - return (FALSE) ; - } - - Alen -= Col_size + Row_size ; - Col = (Colamd_Col *) &A [Alen] ; - Row = (Colamd_Row *) &A [Alen + Col_size] ; - - /* === Construct the row and column data structures ===================== */ - - if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats)) - { - /* input matrix is invalid */ - DEBUG0 (("colamd: Matrix invalid\n")) ; - return (FALSE) ; - } - - /* === Initialize scores, kill dense rows/columns ======================= */ - - init_scoring (n_row, n_col, Row, Col, A, p, knobs, - &n_row2, &n_col2, &max_deg) ; - - /* === Order the supercolumns =========================================== */ - - ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p, - n_col2, max_deg, 2*nnz, aggressive) ; - - /* === Order the non-principal columns ================================== */ - - order_children (n_col, Col, p) ; - - /* === Return statistics in stats ======================================= */ - - stats [COLAMD_DENSE_ROW] = n_row - n_row2 ; - stats [COLAMD_DENSE_COL] = n_col - n_col2 ; - stats [COLAMD_DEFRAG_COUNT] = ngarbage ; - DEBUG0 (("colamd: done.\n")) ; - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === colamd_report ======================================================== */ -/* ========================================================================== */ - -PUBLIC void COLAMD_report -( - Int stats [COLAMD_STATS] -) -{ - print_report ("colamd", stats) ; -} - - -/* ========================================================================== */ -/* === symamd_report ======================================================== */ -/* ========================================================================== */ - -PUBLIC void SYMAMD_report -( - Int stats [COLAMD_STATS] -) -{ - print_report ("symamd", stats) ; -} - - - -/* ========================================================================== */ -/* === NON-USER-CALLABLE ROUTINES: ========================================== */ -/* ========================================================================== */ - -/* There are no user-callable routines beyond this point in the file */ - - -/* ========================================================================== */ -/* === init_rows_cols ======================================================= */ -/* ========================================================================== */ - -/* - Takes the column form of the matrix in A and creates the row form of the - matrix. Also, row and column attributes are stored in the Col and Row - structs. If the columns are un-sorted or contain duplicate row indices, - this routine will also sort and remove duplicate row indices from the - column form of the matrix. Returns FALSE if the matrix is invalid, - TRUE otherwise. Not user-callable. -*/ - -PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows of A */ - Int n_col, /* number of columns of A */ - Colamd_Row Row [], /* of size n_row+1 */ - Colamd_Col Col [], /* of size n_col+1 */ - Int A [], /* row indices of A, of size Alen */ - Int p [], /* pointers to columns in A, of size n_col+1 */ - Int stats [COLAMD_STATS] /* colamd statistics */ -) -{ - /* === Local variables ================================================== */ - - Int col ; /* a column index */ - Int row ; /* a row index */ - Int *cp ; /* a column pointer */ - Int *cp_end ; /* a pointer to the end of a column */ - Int *rp ; /* a row pointer */ - Int *rp_end ; /* a pointer to the end of a row */ - Int last_row ; /* previous row */ - - /* === Initialize columns, and check column pointers ==================== */ - - for (col = 0 ; col < n_col ; col++) - { - Col [col].start = p [col] ; - Col [col].length = p [col+1] - p [col] ; - - if (Col [col].length < 0) - { - /* column pointers must be non-decreasing */ - stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; - stats [COLAMD_INFO1] = col ; - stats [COLAMD_INFO2] = Col [col].length ; - DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ; - return (FALSE) ; - } - - Col [col].shared1.thickness = 1 ; - Col [col].shared2.score = 0 ; - Col [col].shared3.prev = EMPTY ; - Col [col].shared4.degree_next = EMPTY ; - } - - /* p [0..n_col] no longer needed, used as "head" in subsequent routines */ - - /* === Scan columns, compute row degrees, and check row indices ========= */ - - stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ - - for (row = 0 ; row < n_row ; row++) - { - Row [row].length = 0 ; - Row [row].shared2.mark = -1 ; - } - - for (col = 0 ; col < n_col ; col++) - { - last_row = -1 ; - - cp = &A [p [col]] ; - cp_end = &A [p [col+1]] ; - - while (cp < cp_end) - { - row = *cp++ ; - - /* make sure row indices within range */ - if (row < 0 || row >= n_row) - { - stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; - stats [COLAMD_INFO1] = col ; - stats [COLAMD_INFO2] = row ; - stats [COLAMD_INFO3] = n_row ; - DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ; - return (FALSE) ; - } - - if (row <= last_row || Row [row].shared2.mark == col) - { - /* row index are unsorted or repeated (or both), thus col */ - /* is jumbled. This is a notice, not an error condition. */ - stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ; - stats [COLAMD_INFO1] = col ; - stats [COLAMD_INFO2] = row ; - (stats [COLAMD_INFO3]) ++ ; - DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col)); - } - - if (Row [row].shared2.mark != col) - { - Row [row].length++ ; - } - else - { - /* this is a repeated entry in the column, */ - /* it will be removed */ - Col [col].length-- ; - } - - /* mark the row as having been seen in this column */ - Row [row].shared2.mark = col ; - - last_row = row ; - } - } - - /* === Compute row pointers ============================================= */ - - /* row form of the matrix starts directly after the column */ - /* form of matrix in A */ - Row [0].start = p [n_col] ; - Row [0].shared1.p = Row [0].start ; - Row [0].shared2.mark = -1 ; - for (row = 1 ; row < n_row ; row++) - { - Row [row].start = Row [row-1].start + Row [row-1].length ; - Row [row].shared1.p = Row [row].start ; - Row [row].shared2.mark = -1 ; - } - - /* === Create row form ================================================== */ - - if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED) - { - /* if cols jumbled, watch for repeated row indices */ - for (col = 0 ; col < n_col ; col++) - { - cp = &A [p [col]] ; - cp_end = &A [p [col+1]] ; - while (cp < cp_end) - { - row = *cp++ ; - if (Row [row].shared2.mark != col) - { - A [(Row [row].shared1.p)++] = col ; - Row [row].shared2.mark = col ; - } - } - } - } - else - { - /* if cols not jumbled, we don't need the mark (this is faster) */ - for (col = 0 ; col < n_col ; col++) - { - cp = &A [p [col]] ; - cp_end = &A [p [col+1]] ; - while (cp < cp_end) - { - A [(Row [*cp++].shared1.p)++] = col ; - } - } - } - - /* === Clear the row marks and set row degrees ========================== */ - - for (row = 0 ; row < n_row ; row++) - { - Row [row].shared2.mark = 0 ; - Row [row].shared1.degree = Row [row].length ; - } - - /* === See if we need to re-create columns ============================== */ - - if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED) - { - DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ; - -#ifndef NDEBUG - /* make sure column lengths are correct */ - for (col = 0 ; col < n_col ; col++) - { - p [col] = Col [col].length ; - } - for (row = 0 ; row < n_row ; row++) - { - rp = &A [Row [row].start] ; - rp_end = rp + Row [row].length ; - while (rp < rp_end) - { - p [*rp++]-- ; - } - } - for (col = 0 ; col < n_col ; col++) - { - ASSERT (p [col] == 0) ; - } - /* now p is all zero (different than when debugging is turned off) */ -#endif /* NDEBUG */ - - /* === Compute col pointers ========================================= */ - - /* col form of the matrix starts at A [0]. */ - /* Note, we may have a gap between the col form and the row */ - /* form if there were duplicate entries, if so, it will be */ - /* removed upon the first garbage collection */ - Col [0].start = 0 ; - p [0] = Col [0].start ; - for (col = 1 ; col < n_col ; col++) - { - /* note that the lengths here are for pruned columns, i.e. */ - /* no duplicate row indices will exist for these columns */ - Col [col].start = Col [col-1].start + Col [col-1].length ; - p [col] = Col [col].start ; - } - - /* === Re-create col form =========================================== */ - - for (row = 0 ; row < n_row ; row++) - { - rp = &A [Row [row].start] ; - rp_end = rp + Row [row].length ; - while (rp < rp_end) - { - A [(p [*rp++])++] = row ; - } - } - } - - /* === Done. Matrix is not (or no longer) jumbled ====================== */ - - return (TRUE) ; -} - - -/* ========================================================================== */ -/* === init_scoring ========================================================= */ -/* ========================================================================== */ - -/* - Kills dense or empty columns and rows, calculates an initial score for - each column, and places all columns in the degree lists. Not user-callable. -*/ - -PRIVATE void init_scoring -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows of A */ - Int n_col, /* number of columns of A */ - Colamd_Row Row [], /* of size n_row+1 */ - Colamd_Col Col [], /* of size n_col+1 */ - Int A [], /* column form and row form of A */ - Int head [], /* of size n_col+1 */ - double knobs [COLAMD_KNOBS],/* parameters */ - Int *p_n_row2, /* number of non-dense, non-empty rows */ - Int *p_n_col2, /* number of non-dense, non-empty columns */ - Int *p_max_deg /* maximum row degree */ -) -{ - /* === Local variables ================================================== */ - - Int c ; /* a column index */ - Int r, row ; /* a row index */ - Int *cp ; /* a column pointer */ - Int deg ; /* degree of a row or column */ - Int *cp_end ; /* a pointer to the end of a column */ - Int *new_cp ; /* new column pointer */ - Int col_length ; /* length of pruned column */ - Int score ; /* current column score */ - Int n_col2 ; /* number of non-dense, non-empty columns */ - Int n_row2 ; /* number of non-dense, non-empty rows */ - Int dense_row_count ; /* remove rows with more entries than this */ - Int dense_col_count ; /* remove cols with more entries than this */ - Int min_score ; /* smallest column score */ - Int max_deg ; /* maximum row degree */ - Int next_col ; /* Used to add to degree list.*/ - -#ifndef NDEBUG - Int debug_count ; /* debug only. */ -#endif /* NDEBUG */ - - /* === Extract knobs ==================================================== */ - - /* Note: if knobs contains a NaN, this is undefined: */ - if (knobs [COLAMD_DENSE_ROW] < 0) - { - /* only remove completely dense rows */ - dense_row_count = n_col-1 ; - } - else - { - dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ; - } - if (knobs [COLAMD_DENSE_COL] < 0) - { - /* only remove completely dense columns */ - dense_col_count = n_row-1 ; - } - else - { - dense_col_count = - DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ; - } - - DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ; - max_deg = 0 ; - n_col2 = n_col ; - n_row2 = n_row ; - - /* === Kill empty columns =============================================== */ - - /* Put the empty columns at the end in their natural order, so that LU */ - /* factorization can proceed as far as possible. */ - for (c = n_col-1 ; c >= 0 ; c--) - { - deg = Col [c].length ; - if (deg == 0) - { - /* this is a empty column, kill and order it last */ - Col [c].shared2.order = --n_col2 ; - KILL_PRINCIPAL_COL (c) ; - } - } - DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ; - - /* === Kill dense columns =============================================== */ - - /* Put the dense columns at the end, in their natural order */ - for (c = n_col-1 ; c >= 0 ; c--) - { - /* skip any dead columns */ - if (COL_IS_DEAD (c)) - { - continue ; - } - deg = Col [c].length ; - if (deg > dense_col_count) - { - /* this is a dense column, kill and order it last */ - Col [c].shared2.order = --n_col2 ; - /* decrement the row degrees */ - cp = &A [Col [c].start] ; - cp_end = cp + Col [c].length ; - while (cp < cp_end) - { - Row [*cp++].shared1.degree-- ; - } - KILL_PRINCIPAL_COL (c) ; - } - } - DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ; - - /* === Kill dense and empty rows ======================================== */ - - for (r = 0 ; r < n_row ; r++) - { - deg = Row [r].shared1.degree ; - ASSERT (deg >= 0 && deg <= n_col) ; - if (deg > dense_row_count || deg == 0) - { - /* kill a dense or empty row */ - KILL_ROW (r) ; - --n_row2 ; - } - else - { - /* keep track of max degree of remaining rows */ - max_deg = MAX (max_deg, deg) ; - } - } - DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ; - - /* === Compute initial column scores ==================================== */ - - /* At this point the row degrees are accurate. They reflect the number */ - /* of "live" (non-dense) columns in each row. No empty rows exist. */ - /* Some "live" columns may contain only dead rows, however. These are */ - /* pruned in the code below. */ - - /* now find the initial matlab score for each column */ - for (c = n_col-1 ; c >= 0 ; c--) - { - /* skip dead column */ - if (COL_IS_DEAD (c)) - { - continue ; - } - score = 0 ; - cp = &A [Col [c].start] ; - new_cp = cp ; - cp_end = cp + Col [c].length ; - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - /* skip if dead */ - if (ROW_IS_DEAD (row)) - { - continue ; - } - /* compact the column */ - *new_cp++ = row ; - /* add row's external degree */ - score += Row [row].shared1.degree - 1 ; - /* guard against integer overflow */ - score = MIN (score, n_col) ; - } - /* determine pruned column length */ - col_length = (Int) (new_cp - &A [Col [c].start]) ; - if (col_length == 0) - { - /* a newly-made null column (all rows in this col are "dense" */ - /* and have already been killed) */ - DEBUG2 (("Newly null killed: %d\n", c)) ; - Col [c].shared2.order = --n_col2 ; - KILL_PRINCIPAL_COL (c) ; - } - else - { - /* set column length and set score */ - ASSERT (score >= 0) ; - ASSERT (score <= n_col) ; - Col [c].length = col_length ; - Col [c].shared2.score = score ; - } - } - DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n", - n_col-n_col2)) ; - - /* At this point, all empty rows and columns are dead. All live columns */ - /* are "clean" (containing no dead rows) and simplicial (no supercolumns */ - /* yet). Rows may contain dead columns, but all live rows contain at */ - /* least one live column. */ - -#ifndef NDEBUG - debug_structures (n_row, n_col, Row, Col, A, n_col2) ; -#endif /* NDEBUG */ - - /* === Initialize degree lists ========================================== */ - -#ifndef NDEBUG - debug_count = 0 ; -#endif /* NDEBUG */ - - /* clear the hash buckets */ - for (c = 0 ; c <= n_col ; c++) - { - head [c] = EMPTY ; - } - min_score = n_col ; - /* place in reverse order, so low column indices are at the front */ - /* of the lists. This is to encourage natural tie-breaking */ - for (c = n_col-1 ; c >= 0 ; c--) - { - /* only add principal columns to degree lists */ - if (COL_IS_ALIVE (c)) - { - DEBUG4 (("place %d score %d minscore %d ncol %d\n", - c, Col [c].shared2.score, min_score, n_col)) ; - - /* === Add columns score to DList =============================== */ - - score = Col [c].shared2.score ; - - ASSERT (min_score >= 0) ; - ASSERT (min_score <= n_col) ; - ASSERT (score >= 0) ; - ASSERT (score <= n_col) ; - ASSERT (head [score] >= EMPTY) ; - - /* now add this column to dList at proper score location */ - next_col = head [score] ; - Col [c].shared3.prev = EMPTY ; - Col [c].shared4.degree_next = next_col ; - - /* if there already was a column with the same score, set its */ - /* previous pointer to this new column */ - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = c ; - } - head [score] = c ; - - /* see if this score is less than current min */ - min_score = MIN (min_score, score) ; - -#ifndef NDEBUG - debug_count++ ; -#endif /* NDEBUG */ - - } - } - -#ifndef NDEBUG - DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n", - debug_count, n_col, n_col-debug_count)) ; - ASSERT (debug_count == n_col2) ; - debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ; -#endif /* NDEBUG */ - - /* === Return number of remaining columns, and max row degree =========== */ - - *p_n_col2 = n_col2 ; - *p_n_row2 = n_row2 ; - *p_max_deg = max_deg ; -} - - -/* ========================================================================== */ -/* === find_ordering ======================================================== */ -/* ========================================================================== */ - -/* - Order the principal columns of the supercolumn form of the matrix - (no supercolumns on input). Uses a minimum approximate column minimum - degree ordering method. Not user-callable. -*/ - -PRIVATE Int find_ordering /* return the number of garbage collections */ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows of A */ - Int n_col, /* number of columns of A */ - Int Alen, /* size of A, 2*nnz + n_col or larger */ - Colamd_Row Row [], /* of size n_row+1 */ - Colamd_Col Col [], /* of size n_col+1 */ - Int A [], /* column form and row form of A */ - Int head [], /* of size n_col+1 */ - Int n_col2, /* Remaining columns to order */ - Int max_deg, /* Maximum row degree */ - Int pfree, /* index of first free slot (2*nnz on entry) */ - Int aggressive -) -{ - /* === Local variables ================================================== */ - - Int k ; /* current pivot ordering step */ - Int pivot_col ; /* current pivot column */ - Int *cp ; /* a column pointer */ - Int *rp ; /* a row pointer */ - Int pivot_row ; /* current pivot row */ - Int *new_cp ; /* modified column pointer */ - Int *new_rp ; /* modified row pointer */ - Int pivot_row_start ; /* pointer to start of pivot row */ - Int pivot_row_degree ; /* number of columns in pivot row */ - Int pivot_row_length ; /* number of supercolumns in pivot row */ - Int pivot_col_score ; /* score of pivot column */ - Int needed_memory ; /* free space needed for pivot row */ - Int *cp_end ; /* pointer to the end of a column */ - Int *rp_end ; /* pointer to the end of a row */ - Int row ; /* a row index */ - Int col ; /* a column index */ - Int max_score ; /* maximum possible score */ - Int cur_score ; /* score of current column */ - unsigned Int hash ; /* hash value for supernode detection */ - Int head_column ; /* head of hash bucket */ - Int first_col ; /* first column in hash bucket */ - Int tag_mark ; /* marker value for mark array */ - Int row_mark ; /* Row [row].shared2.mark */ - Int set_difference ; /* set difference size of row with pivot row */ - Int min_score ; /* smallest column score */ - Int col_thickness ; /* "thickness" (no. of columns in a supercol) */ - Int max_mark ; /* maximum value of tag_mark */ - Int pivot_col_thickness ; /* number of columns represented by pivot col */ - Int prev_col ; /* Used by Dlist operations. */ - Int next_col ; /* Used by Dlist operations. */ - Int ngarbage ; /* number of garbage collections performed */ - -#ifndef NDEBUG - Int debug_d ; /* debug loop counter */ - Int debug_step = 0 ; /* debug loop counter */ -#endif /* NDEBUG */ - - /* === Initialization and clear mark ==================================== */ - - max_mark = INT_MAX - n_col ; /* INT_MAX defined in <limits.h> */ - tag_mark = clear_mark (0, max_mark, n_row, Row) ; - min_score = 0 ; - ngarbage = 0 ; - DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ; - - /* === Order the columns ================================================ */ - - for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */) - { - -#ifndef NDEBUG - if (debug_step % 100 == 0) - { - DEBUG2 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ; - } - else - { - DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ; - } - debug_step++ ; - debug_deg_lists (n_row, n_col, Row, Col, head, - min_score, n_col2-k, max_deg) ; - debug_matrix (n_row, n_col, Row, Col, A) ; -#endif /* NDEBUG */ - - /* === Select pivot column, and order it ============================ */ - - /* make sure degree list isn't empty */ - ASSERT (min_score >= 0) ; - ASSERT (min_score <= n_col) ; - ASSERT (head [min_score] >= EMPTY) ; - -#ifndef NDEBUG - for (debug_d = 0 ; debug_d < min_score ; debug_d++) - { - ASSERT (head [debug_d] == EMPTY) ; - } -#endif /* NDEBUG */ - - /* get pivot column from head of minimum degree list */ - while (head [min_score] == EMPTY && min_score < n_col) - { - min_score++ ; - } - pivot_col = head [min_score] ; - ASSERT (pivot_col >= 0 && pivot_col <= n_col) ; - next_col = Col [pivot_col].shared4.degree_next ; - head [min_score] = next_col ; - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = EMPTY ; - } - - ASSERT (COL_IS_ALIVE (pivot_col)) ; - - /* remember score for defrag check */ - pivot_col_score = Col [pivot_col].shared2.score ; - - /* the pivot column is the kth column in the pivot order */ - Col [pivot_col].shared2.order = k ; - - /* increment order count by column thickness */ - pivot_col_thickness = Col [pivot_col].shared1.thickness ; - k += pivot_col_thickness ; - ASSERT (pivot_col_thickness > 0) ; - DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ; - - /* === Garbage_collection, if necessary ============================= */ - - needed_memory = MIN (pivot_col_score, n_col - k) ; - if (pfree + needed_memory >= Alen) - { - pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ; - ngarbage++ ; - /* after garbage collection we will have enough */ - ASSERT (pfree + needed_memory < Alen) ; - /* garbage collection has wiped out the Row[].shared2.mark array */ - tag_mark = clear_mark (0, max_mark, n_row, Row) ; - -#ifndef NDEBUG - debug_matrix (n_row, n_col, Row, Col, A) ; -#endif /* NDEBUG */ - } - - /* === Compute pivot row pattern ==================================== */ - - /* get starting location for this new merged row */ - pivot_row_start = pfree ; - - /* initialize new row counts to zero */ - pivot_row_degree = 0 ; - - /* tag pivot column as having been visited so it isn't included */ - /* in merged pivot row */ - Col [pivot_col].shared1.thickness = -pivot_col_thickness ; - - /* pivot row is the union of all rows in the pivot column pattern */ - cp = &A [Col [pivot_col].start] ; - cp_end = cp + Col [pivot_col].length ; - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ; - /* skip if row is dead */ - if (ROW_IS_ALIVE (row)) - { - rp = &A [Row [row].start] ; - rp_end = rp + Row [row].length ; - while (rp < rp_end) - { - /* get a column */ - col = *rp++ ; - /* add the column, if alive and untagged */ - col_thickness = Col [col].shared1.thickness ; - if (col_thickness > 0 && COL_IS_ALIVE (col)) - { - /* tag column in pivot row */ - Col [col].shared1.thickness = -col_thickness ; - ASSERT (pfree < Alen) ; - /* place column in pivot row */ - A [pfree++] = col ; - pivot_row_degree += col_thickness ; - } - } - } - } - - /* clear tag on pivot column */ - Col [pivot_col].shared1.thickness = pivot_col_thickness ; - max_deg = MAX (max_deg, pivot_row_degree) ; - -#ifndef NDEBUG - DEBUG3 (("check2\n")) ; - debug_mark (n_row, Row, tag_mark, max_mark) ; -#endif /* NDEBUG */ - - /* === Kill all rows used to construct pivot row ==================== */ - - /* also kill pivot row, temporarily */ - cp = &A [Col [pivot_col].start] ; - cp_end = cp + Col [pivot_col].length ; - while (cp < cp_end) - { - /* may be killing an already dead row */ - row = *cp++ ; - DEBUG3 (("Kill row in pivot col: %d\n", row)) ; - KILL_ROW (row) ; - } - - /* === Select a row index to use as the new pivot row =============== */ - - pivot_row_length = pfree - pivot_row_start ; - if (pivot_row_length > 0) - { - /* pick the "pivot" row arbitrarily (first row in col) */ - pivot_row = A [Col [pivot_col].start] ; - DEBUG3 (("Pivotal row is %d\n", pivot_row)) ; - } - else - { - /* there is no pivot row, since it is of zero length */ - pivot_row = EMPTY ; - ASSERT (pivot_row_length == 0) ; - } - ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ; - - /* === Approximate degree computation =============================== */ - - /* Here begins the computation of the approximate degree. The column */ - /* score is the sum of the pivot row "length", plus the size of the */ - /* set differences of each row in the column minus the pattern of the */ - /* pivot row itself. The column ("thickness") itself is also */ - /* excluded from the column score (we thus use an approximate */ - /* external degree). */ - - /* The time taken by the following code (compute set differences, and */ - /* add them up) is proportional to the size of the data structure */ - /* being scanned - that is, the sum of the sizes of each column in */ - /* the pivot row. Thus, the amortized time to compute a column score */ - /* is proportional to the size of that column (where size, in this */ - /* context, is the column "length", or the number of row indices */ - /* in that column). The number of row indices in a column is */ - /* monotonically non-decreasing, from the length of the original */ - /* column on input to colamd. */ - - /* === Compute set differences ====================================== */ - - DEBUG3 (("** Computing set differences phase. **\n")) ; - - /* pivot row is currently dead - it will be revived later. */ - - DEBUG3 (("Pivot row: ")) ; - /* for each column in pivot row */ - rp = &A [pivot_row_start] ; - rp_end = rp + pivot_row_length ; - while (rp < rp_end) - { - col = *rp++ ; - ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; - DEBUG3 (("Col: %d\n", col)) ; - - /* clear tags used to construct pivot row pattern */ - col_thickness = -Col [col].shared1.thickness ; - ASSERT (col_thickness > 0) ; - Col [col].shared1.thickness = col_thickness ; - - /* === Remove column from degree list =========================== */ - - cur_score = Col [col].shared2.score ; - prev_col = Col [col].shared3.prev ; - next_col = Col [col].shared4.degree_next ; - ASSERT (cur_score >= 0) ; - ASSERT (cur_score <= n_col) ; - ASSERT (cur_score >= EMPTY) ; - if (prev_col == EMPTY) - { - head [cur_score] = next_col ; - } - else - { - Col [prev_col].shared4.degree_next = next_col ; - } - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = prev_col ; - } - - /* === Scan the column ========================================== */ - - cp = &A [Col [col].start] ; - cp_end = cp + Col [col].length ; - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - row_mark = Row [row].shared2.mark ; - /* skip if dead */ - if (ROW_IS_MARKED_DEAD (row_mark)) - { - continue ; - } - ASSERT (row != pivot_row) ; - set_difference = row_mark - tag_mark ; - /* check if the row has been seen yet */ - if (set_difference < 0) - { - ASSERT (Row [row].shared1.degree <= max_deg) ; - set_difference = Row [row].shared1.degree ; - } - /* subtract column thickness from this row's set difference */ - set_difference -= col_thickness ; - ASSERT (set_difference >= 0) ; - /* absorb this row if the set difference becomes zero */ - if (set_difference == 0 && aggressive) - { - DEBUG3 (("aggressive absorption. Row: %d\n", row)) ; - KILL_ROW (row) ; - } - else - { - /* save the new mark */ - Row [row].shared2.mark = set_difference + tag_mark ; - } - } - } - -#ifndef NDEBUG - debug_deg_lists (n_row, n_col, Row, Col, head, - min_score, n_col2-k-pivot_row_degree, max_deg) ; -#endif /* NDEBUG */ - - /* === Add up set differences for each column ======================= */ - - DEBUG3 (("** Adding set differences phase. **\n")) ; - - /* for each column in pivot row */ - rp = &A [pivot_row_start] ; - rp_end = rp + pivot_row_length ; - while (rp < rp_end) - { - /* get a column */ - col = *rp++ ; - ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; - hash = 0 ; - cur_score = 0 ; - cp = &A [Col [col].start] ; - /* compact the column */ - new_cp = cp ; - cp_end = cp + Col [col].length ; - - DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ; - - while (cp < cp_end) - { - /* get a row */ - row = *cp++ ; - ASSERT(row >= 0 && row < n_row) ; - row_mark = Row [row].shared2.mark ; - /* skip if dead */ - if (ROW_IS_MARKED_DEAD (row_mark)) - { - DEBUG4 ((" Row %d, dead\n", row)) ; - continue ; - } - DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark)); - ASSERT (row_mark >= tag_mark) ; - /* compact the column */ - *new_cp++ = row ; - /* compute hash function */ - hash += row ; - /* add set difference */ - cur_score += row_mark - tag_mark ; - /* integer overflow... */ - cur_score = MIN (cur_score, n_col) ; - } - - /* recompute the column's length */ - Col [col].length = (Int) (new_cp - &A [Col [col].start]) ; - - /* === Further mass elimination ================================= */ - - if (Col [col].length == 0) - { - DEBUG4 (("further mass elimination. Col: %d\n", col)) ; - /* nothing left but the pivot row in this column */ - KILL_PRINCIPAL_COL (col) ; - pivot_row_degree -= Col [col].shared1.thickness ; - ASSERT (pivot_row_degree >= 0) ; - /* order it */ - Col [col].shared2.order = k ; - /* increment order count by column thickness */ - k += Col [col].shared1.thickness ; - } - else - { - /* === Prepare for supercolumn detection ==================== */ - - DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ; - - /* save score so far */ - Col [col].shared2.score = cur_score ; - - /* add column to hash table, for supercolumn detection */ - hash %= n_col + 1 ; - - DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ; - ASSERT (((Int) hash) <= n_col) ; - - head_column = head [hash] ; - if (head_column > EMPTY) - { - /* degree list "hash" is non-empty, use prev (shared3) of */ - /* first column in degree list as head of hash bucket */ - first_col = Col [head_column].shared3.headhash ; - Col [head_column].shared3.headhash = col ; - } - else - { - /* degree list "hash" is empty, use head as hash bucket */ - first_col = - (head_column + 2) ; - head [hash] = - (col + 2) ; - } - Col [col].shared4.hash_next = first_col ; - - /* save hash function in Col [col].shared3.hash */ - Col [col].shared3.hash = (Int) hash ; - ASSERT (COL_IS_ALIVE (col)) ; - } - } - - /* The approximate external column degree is now computed. */ - - /* === Supercolumn detection ======================================== */ - - DEBUG3 (("** Supercolumn detection phase. **\n")) ; - - detect_super_cols ( - -#ifndef NDEBUG - n_col, Row, -#endif /* NDEBUG */ - - Col, A, head, pivot_row_start, pivot_row_length) ; - - /* === Kill the pivotal column ====================================== */ - - KILL_PRINCIPAL_COL (pivot_col) ; - - /* === Clear mark =================================================== */ - - tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ; - -#ifndef NDEBUG - DEBUG3 (("check3\n")) ; - debug_mark (n_row, Row, tag_mark, max_mark) ; -#endif /* NDEBUG */ - - /* === Finalize the new pivot row, and column scores ================ */ - - DEBUG3 (("** Finalize scores phase. **\n")) ; - - /* for each column in pivot row */ - rp = &A [pivot_row_start] ; - /* compact the pivot row */ - new_rp = rp ; - rp_end = rp + pivot_row_length ; - while (rp < rp_end) - { - col = *rp++ ; - /* skip dead columns */ - if (COL_IS_DEAD (col)) - { - continue ; - } - *new_rp++ = col ; - /* add new pivot row to column */ - A [Col [col].start + (Col [col].length++)] = pivot_row ; - - /* retrieve score so far and add on pivot row's degree. */ - /* (we wait until here for this in case the pivot */ - /* row's degree was reduced due to mass elimination). */ - cur_score = Col [col].shared2.score + pivot_row_degree ; - - /* calculate the max possible score as the number of */ - /* external columns minus the 'k' value minus the */ - /* columns thickness */ - max_score = n_col - k - Col [col].shared1.thickness ; - - /* make the score the external degree of the union-of-rows */ - cur_score -= Col [col].shared1.thickness ; - - /* make sure score is less or equal than the max score */ - cur_score = MIN (cur_score, max_score) ; - ASSERT (cur_score >= 0) ; - - /* store updated score */ - Col [col].shared2.score = cur_score ; - - /* === Place column back in degree list ========================= */ - - ASSERT (min_score >= 0) ; - ASSERT (min_score <= n_col) ; - ASSERT (cur_score >= 0) ; - ASSERT (cur_score <= n_col) ; - ASSERT (head [cur_score] >= EMPTY) ; - next_col = head [cur_score] ; - Col [col].shared4.degree_next = next_col ; - Col [col].shared3.prev = EMPTY ; - if (next_col != EMPTY) - { - Col [next_col].shared3.prev = col ; - } - head [cur_score] = col ; - - /* see if this score is less than current min */ - min_score = MIN (min_score, cur_score) ; - - } - -#ifndef NDEBUG - debug_deg_lists (n_row, n_col, Row, Col, head, - min_score, n_col2-k, max_deg) ; -#endif /* NDEBUG */ - - /* === Resurrect the new pivot row ================================== */ - - if (pivot_row_degree > 0) - { - /* update pivot row length to reflect any cols that were killed */ - /* during super-col detection and mass elimination */ - Row [pivot_row].start = pivot_row_start ; - Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ; - ASSERT (Row [pivot_row].length > 0) ; - Row [pivot_row].shared1.degree = pivot_row_degree ; - Row [pivot_row].shared2.mark = 0 ; - /* pivot row is no longer dead */ - - DEBUG1 (("Resurrect Pivot_row %d deg: %d\n", - pivot_row, pivot_row_degree)) ; - } - } - - /* === All principal columns have now been ordered ====================== */ - - return (ngarbage) ; -} - - -/* ========================================================================== */ -/* === order_children ======================================================= */ -/* ========================================================================== */ - -/* - The find_ordering routine has ordered all of the principal columns (the - representatives of the supercolumns). The non-principal columns have not - yet been ordered. This routine orders those columns by walking up the - parent tree (a column is a child of the column which absorbed it). The - final permutation vector is then placed in p [0 ... n_col-1], with p [0] - being the first column, and p [n_col-1] being the last. It doesn't look - like it at first glance, but be assured that this routine takes time linear - in the number of columns. Although not immediately obvious, the time - taken by this routine is O (n_col), that is, linear in the number of - columns. Not user-callable. -*/ - -PRIVATE void order_children -( - /* === Parameters ======================================================= */ - - Int n_col, /* number of columns of A */ - Colamd_Col Col [], /* of size n_col+1 */ - Int p [] /* p [0 ... n_col-1] is the column permutation*/ -) -{ - /* === Local variables ================================================== */ - - Int i ; /* loop counter for all columns */ - Int c ; /* column index */ - Int parent ; /* index of column's parent */ - Int order ; /* column's order */ - - /* === Order each non-principal column ================================== */ - - for (i = 0 ; i < n_col ; i++) - { - /* find an un-ordered non-principal column */ - ASSERT (COL_IS_DEAD (i)) ; - if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY) - { - parent = i ; - /* once found, find its principal parent */ - do - { - parent = Col [parent].shared1.parent ; - } while (!COL_IS_DEAD_PRINCIPAL (parent)) ; - - /* now, order all un-ordered non-principal columns along path */ - /* to this parent. collapse tree at the same time */ - c = i ; - /* get order of parent */ - order = Col [parent].shared2.order ; - - do - { - ASSERT (Col [c].shared2.order == EMPTY) ; - - /* order this column */ - Col [c].shared2.order = order++ ; - /* collaps tree */ - Col [c].shared1.parent = parent ; - - /* get immediate parent of this column */ - c = Col [c].shared1.parent ; - - /* continue until we hit an ordered column. There are */ - /* guarranteed not to be anymore unordered columns */ - /* above an ordered column */ - } while (Col [c].shared2.order == EMPTY) ; - - /* re-order the super_col parent to largest order for this group */ - Col [parent].shared2.order = order ; - } - } - - /* === Generate the permutation ========================================= */ - - for (c = 0 ; c < n_col ; c++) - { - p [Col [c].shared2.order] = c ; - } -} - - -/* ========================================================================== */ -/* === detect_super_cols ==================================================== */ -/* ========================================================================== */ - -/* - Detects supercolumns by finding matches between columns in the hash buckets. - Check amongst columns in the set A [row_start ... row_start + row_length-1]. - The columns under consideration are currently *not* in the degree lists, - and have already been placed in the hash buckets. - - The hash bucket for columns whose hash function is equal to h is stored - as follows: - - if head [h] is >= 0, then head [h] contains a degree list, so: - - head [h] is the first column in degree bucket h. - Col [head [h]].headhash gives the first column in hash bucket h. - - otherwise, the degree list is empty, and: - - -(head [h] + 2) is the first column in hash bucket h. - - For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous - column" pointer. Col [c].shared3.hash is used instead as the hash number - for that column. The value of Col [c].shared4.hash_next is the next column - in the same hash bucket. - - Assuming no, or "few" hash collisions, the time taken by this routine is - linear in the sum of the sizes (lengths) of each column whose score has - just been computed in the approximate degree computation. - Not user-callable. -*/ - -PRIVATE void detect_super_cols -( - /* === Parameters ======================================================= */ - -#ifndef NDEBUG - /* these two parameters are only needed when debugging is enabled: */ - Int n_col, /* number of columns of A */ - Colamd_Row Row [], /* of size n_row+1 */ -#endif /* NDEBUG */ - - Colamd_Col Col [], /* of size n_col+1 */ - Int A [], /* row indices of A */ - Int head [], /* head of degree lists and hash buckets */ - Int row_start, /* pointer to set of columns to check */ - Int row_length /* number of columns to check */ -) -{ - /* === Local variables ================================================== */ - - Int hash ; /* hash value for a column */ - Int *rp ; /* pointer to a row */ - Int c ; /* a column index */ - Int super_c ; /* column index of the column to absorb into */ - Int *cp1 ; /* column pointer for column super_c */ - Int *cp2 ; /* column pointer for column c */ - Int length ; /* length of column super_c */ - Int prev_c ; /* column preceding c in hash bucket */ - Int i ; /* loop counter */ - Int *rp_end ; /* pointer to the end of the row */ - Int col ; /* a column index in the row to check */ - Int head_column ; /* first column in hash bucket or degree list */ - Int first_col ; /* first column in hash bucket */ - - /* === Consider each column in the row ================================== */ - - rp = &A [row_start] ; - rp_end = rp + row_length ; - while (rp < rp_end) - { - col = *rp++ ; - if (COL_IS_DEAD (col)) - { - continue ; - } - - /* get hash number for this column */ - hash = Col [col].shared3.hash ; - ASSERT (hash <= n_col) ; - - /* === Get the first column in this hash bucket ===================== */ - - head_column = head [hash] ; - if (head_column > EMPTY) - { - first_col = Col [head_column].shared3.headhash ; - } - else - { - first_col = - (head_column + 2) ; - } - - /* === Consider each column in the hash bucket ====================== */ - - for (super_c = first_col ; super_c != EMPTY ; - super_c = Col [super_c].shared4.hash_next) - { - ASSERT (COL_IS_ALIVE (super_c)) ; - ASSERT (Col [super_c].shared3.hash == hash) ; - length = Col [super_c].length ; - - /* prev_c is the column preceding column c in the hash bucket */ - prev_c = super_c ; - - /* === Compare super_c with all columns after it ================ */ - - for (c = Col [super_c].shared4.hash_next ; - c != EMPTY ; c = Col [c].shared4.hash_next) - { - ASSERT (c != super_c) ; - ASSERT (COL_IS_ALIVE (c)) ; - ASSERT (Col [c].shared3.hash == hash) ; - - /* not identical if lengths or scores are different */ - if (Col [c].length != length || - Col [c].shared2.score != Col [super_c].shared2.score) - { - prev_c = c ; - continue ; - } - - /* compare the two columns */ - cp1 = &A [Col [super_c].start] ; - cp2 = &A [Col [c].start] ; - - for (i = 0 ; i < length ; i++) - { - /* the columns are "clean" (no dead rows) */ - ASSERT (ROW_IS_ALIVE (*cp1)) ; - ASSERT (ROW_IS_ALIVE (*cp2)) ; - /* row indices will same order for both supercols, */ - /* no gather scatter nessasary */ - if (*cp1++ != *cp2++) - { - break ; - } - } - - /* the two columns are different if the for-loop "broke" */ - if (i != length) - { - prev_c = c ; - continue ; - } - - /* === Got it! two columns are identical =================== */ - - ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ; - - Col [super_c].shared1.thickness += Col [c].shared1.thickness ; - Col [c].shared1.parent = super_c ; - KILL_NON_PRINCIPAL_COL (c) ; - /* order c later, in order_children() */ - Col [c].shared2.order = EMPTY ; - /* remove c from hash bucket */ - Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ; - } - } - - /* === Empty this hash bucket ======================================= */ - - if (head_column > EMPTY) - { - /* corresponding degree list "hash" is not empty */ - Col [head_column].shared3.headhash = EMPTY ; - } - else - { - /* corresponding degree list "hash" is empty */ - head [hash] = EMPTY ; - } - } -} - - -/* ========================================================================== */ -/* === garbage_collection =================================================== */ -/* ========================================================================== */ - -/* - Defragments and compacts columns and rows in the workspace A. Used when - all avaliable memory has been used while performing row merging. Returns - the index of the first free position in A, after garbage collection. The - time taken by this routine is linear is the size of the array A, which is - itself linear in the number of nonzeros in the input matrix. - Not user-callable. -*/ - -PRIVATE Int garbage_collection /* returns the new value of pfree */ -( - /* === Parameters ======================================================= */ - - Int n_row, /* number of rows */ - Int n_col, /* number of columns */ - Colamd_Row Row [], /* row info */ - Colamd_Col Col [], /* column info */ - Int A [], /* A [0 ... Alen-1] holds the matrix */ - Int *pfree /* &A [0] ... pfree is in use */ -) -{ - /* === Local variables ================================================== */ - - Int *psrc ; /* source pointer */ - Int *pdest ; /* destination pointer */ - Int j ; /* counter */ - Int r ; /* a row index */ - Int c ; /* a column index */ - Int length ; /* length of a row or column */ - -#ifndef NDEBUG - Int debug_rows ; - DEBUG2 (("Defrag..\n")) ; - for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ; - debug_rows = 0 ; -#endif /* NDEBUG */ - - /* === Defragment the columns =========================================== */ - - pdest = &A[0] ; - for (c = 0 ; c < n_col ; c++) - { - if (COL_IS_ALIVE (c)) - { - psrc = &A [Col [c].start] ; - - /* move and compact the column */ - ASSERT (pdest <= psrc) ; - Col [c].start = (Int) (pdest - &A [0]) ; - length = Col [c].length ; - for (j = 0 ; j < length ; j++) - { - r = *psrc++ ; - if (ROW_IS_ALIVE (r)) - { - *pdest++ = r ; - } - } - Col [c].length = (Int) (pdest - &A [Col [c].start]) ; - } - } - - /* === Prepare to defragment the rows =================================== */ - - for (r = 0 ; r < n_row ; r++) - { - if (ROW_IS_DEAD (r) || (Row [r].length == 0)) - { - /* This row is already dead, or is of zero length. Cannot compact - * a row of zero length, so kill it. NOTE: in the current version, - * there are no zero-length live rows. Kill the row (for the first - * time, or again) just to be safe. */ - KILL_ROW (r) ; - } - else - { - /* save first column index in Row [r].shared2.first_column */ - psrc = &A [Row [r].start] ; - Row [r].shared2.first_column = *psrc ; - ASSERT (ROW_IS_ALIVE (r)) ; - /* flag the start of the row with the one's complement of row */ - *psrc = ONES_COMPLEMENT (r) ; -#ifndef NDEBUG - debug_rows++ ; -#endif /* NDEBUG */ - } - } - - /* === Defragment the rows ============================================== */ - - psrc = pdest ; - while (psrc < pfree) - { - /* find a negative number ... the start of a row */ - if (*psrc++ < 0) - { - psrc-- ; - /* get the row index */ - r = ONES_COMPLEMENT (*psrc) ; - ASSERT (r >= 0 && r < n_row) ; - /* restore first column index */ - *psrc = Row [r].shared2.first_column ; - ASSERT (ROW_IS_ALIVE (r)) ; - ASSERT (Row [r].length > 0) ; - /* move and compact the row */ - ASSERT (pdest <= psrc) ; - Row [r].start = (Int) (pdest - &A [0]) ; - length = Row [r].length ; - for (j = 0 ; j < length ; j++) - { - c = *psrc++ ; - if (COL_IS_ALIVE (c)) - { - *pdest++ = c ; - } - } - Row [r].length = (Int) (pdest - &A [Row [r].start]) ; - ASSERT (Row [r].length > 0) ; -#ifndef NDEBUG - debug_rows-- ; -#endif /* NDEBUG */ - } - } - /* ensure we found all the rows */ - ASSERT (debug_rows == 0) ; - - /* === Return the new value of pfree ==================================== */ - - return ((Int) (pdest - &A [0])) ; -} - - -/* ========================================================================== */ -/* === clear_mark =========================================================== */ -/* ========================================================================== */ - -/* - Clears the Row [].shared2.mark array, and returns the new tag_mark. - Return value is the new tag_mark. Not user-callable. -*/ - -PRIVATE Int clear_mark /* return the new value for tag_mark */ -( - /* === Parameters ======================================================= */ - - Int tag_mark, /* new value of tag_mark */ - Int max_mark, /* max allowed value of tag_mark */ - - Int n_row, /* number of rows in A */ - Colamd_Row Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */ -) -{ - /* === Local variables ================================================== */ - - Int r ; - - if (tag_mark <= 0 || tag_mark >= max_mark) - { - for (r = 0 ; r < n_row ; r++) - { - if (ROW_IS_ALIVE (r)) - { - Row [r].shared2.mark = 0 ; - } - } - tag_mark = 1 ; - } - - return (tag_mark) ; -} - - -/* ========================================================================== */ -/* === print_report ========================================================= */ -/* ========================================================================== */ - -PRIVATE void print_report -( - char *method, - Int stats [COLAMD_STATS] -) -{ - - Int i1, i2, i3 ; - - PRINTF (("\n%s version %d.%d, %s: ", method, - COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ; - - if (!stats) - { - PRINTF (("No statistics available.\n")) ; - return ; - } - - i1 = stats [COLAMD_INFO1] ; - i2 = stats [COLAMD_INFO2] ; - i3 = stats [COLAMD_INFO3] ; - - if (stats [COLAMD_STATUS] >= 0) - { - PRINTF (("OK. ")) ; - } - else - { - PRINTF (("ERROR. ")) ; - } - - switch (stats [COLAMD_STATUS]) - { - - case COLAMD_OK_BUT_JUMBLED: - - PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ; - - PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n", - method, i3)) ; - - PRINTF(("%s: last seen duplicate or out-of-order row index: %d\n", - method, INDEX (i2))) ; - - PRINTF(("%s: last seen in column: %d", - method, INDEX (i1))) ; - - /* no break - fall through to next case instead */ - - case COLAMD_OK: - - PRINTF(("\n")) ; - - PRINTF(("%s: number of dense or empty rows ignored: %d\n", - method, stats [COLAMD_DENSE_ROW])) ; - - PRINTF(("%s: number of dense or empty columns ignored: %d\n", - method, stats [COLAMD_DENSE_COL])) ; - - PRINTF(("%s: number of garbage collections performed: %d\n", - method, stats [COLAMD_DEFRAG_COUNT])) ; - break ; - - case COLAMD_ERROR_A_not_present: - - PRINTF(("Array A (row indices of matrix) not present.\n")) ; - break ; - - case COLAMD_ERROR_p_not_present: - - PRINTF(("Array p (column pointers for matrix) not present.\n")) ; - break ; - - case COLAMD_ERROR_nrow_negative: - - PRINTF(("Invalid number of rows (%d).\n", i1)) ; - break ; - - case COLAMD_ERROR_ncol_negative: - - PRINTF(("Invalid number of columns (%d).\n", i1)) ; - break ; - - case COLAMD_ERROR_nnz_negative: - - PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ; - break ; - - case COLAMD_ERROR_p0_nonzero: - - PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1)); - break ; - - case COLAMD_ERROR_A_too_small: - - PRINTF(("Array A too small.\n")) ; - PRINTF((" Need Alen >= %d, but given only Alen = %d.\n", - i1, i2)) ; - break ; - - case COLAMD_ERROR_col_length_negative: - - PRINTF - (("Column %d has a negative number of nonzero entries (%d).\n", - INDEX (i1), i2)) ; - break ; - - case COLAMD_ERROR_row_index_out_of_bounds: - - PRINTF - (("Row index (row %d) out of bounds (%d to %d) in column %d.\n", - INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ; - break ; - - case COLAMD_ERROR_out_of_memory: - - PRINTF(("Out of memory.\n")) ; - break ; - - /* v2.4: internal-error case deleted */ - } -} - - - - -/* ========================================================================== */ -/* === colamd debugging routines ============================================ */ -/* ========================================================================== */ - -/* When debugging is disabled, the remainder of this file is ignored. */ - -#ifndef NDEBUG - - -/* ========================================================================== */ -/* === debug_structures ===================================================== */ -/* ========================================================================== */ - -/* - At this point, all empty rows and columns are dead. All live columns - are "clean" (containing no dead rows) and simplicial (no supercolumns - yet). Rows may contain dead columns, but all live rows contain at - least one live column. -*/ - -PRIVATE void debug_structures -( - /* === Parameters ======================================================= */ - - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [], - Int n_col2 -) -{ - /* === Local variables ================================================== */ - - Int i ; - Int c ; - Int *cp ; - Int *cp_end ; - Int len ; - Int score ; - Int r ; - Int *rp ; - Int *rp_end ; - Int deg ; - - /* === Check A, Row, and Col ============================================ */ - - for (c = 0 ; c < n_col ; c++) - { - if (COL_IS_ALIVE (c)) - { - len = Col [c].length ; - score = Col [c].shared2.score ; - DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ; - ASSERT (len > 0) ; - ASSERT (score >= 0) ; - ASSERT (Col [c].shared1.thickness == 1) ; - cp = &A [Col [c].start] ; - cp_end = cp + len ; - while (cp < cp_end) - { - r = *cp++ ; - ASSERT (ROW_IS_ALIVE (r)) ; - } - } - else - { - i = Col [c].shared2.order ; - ASSERT (i >= n_col2 && i < n_col) ; - } - } - - for (r = 0 ; r < n_row ; r++) - { - if (ROW_IS_ALIVE (r)) - { - i = 0 ; - len = Row [r].length ; - deg = Row [r].shared1.degree ; - ASSERT (len > 0) ; - ASSERT (deg > 0) ; - rp = &A [Row [r].start] ; - rp_end = rp + len ; - while (rp < rp_end) - { - c = *rp++ ; - if (COL_IS_ALIVE (c)) - { - i++ ; - } - } - ASSERT (i > 0) ; - } - } -} - - -/* ========================================================================== */ -/* === debug_deg_lists ====================================================== */ -/* ========================================================================== */ - -/* - Prints the contents of the degree lists. Counts the number of columns - in the degree list and compares it to the total it should have. Also - checks the row degrees. -*/ - -PRIVATE void debug_deg_lists -( - /* === Parameters ======================================================= */ - - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int head [], - Int min_score, - Int should, - Int max_deg -) -{ - /* === Local variables ================================================== */ - - Int deg ; - Int col ; - Int have ; - Int row ; - - /* === Check the degree lists =========================================== */ - - if (n_col > 10000 && colamd_debug <= 0) - { - return ; - } - have = 0 ; - DEBUG4 (("Degree lists: %d\n", min_score)) ; - for (deg = 0 ; deg <= n_col ; deg++) - { - col = head [deg] ; - if (col == EMPTY) - { - continue ; - } - DEBUG4 (("%d:", deg)) ; - while (col != EMPTY) - { - DEBUG4 ((" %d", col)) ; - have += Col [col].shared1.thickness ; - ASSERT (COL_IS_ALIVE (col)) ; - col = Col [col].shared4.degree_next ; - } - DEBUG4 (("\n")) ; - } - DEBUG4 (("should %d have %d\n", should, have)) ; - ASSERT (should == have) ; - - /* === Check the row degrees ============================================ */ - - if (n_row > 10000 && colamd_debug <= 0) - { - return ; - } - for (row = 0 ; row < n_row ; row++) - { - if (ROW_IS_ALIVE (row)) - { - ASSERT (Row [row].shared1.degree <= max_deg) ; - } - } -} - - -/* ========================================================================== */ -/* === debug_mark =========================================================== */ -/* ========================================================================== */ - -/* - Ensures that the tag_mark is less that the maximum and also ensures that - each entry in the mark array is less than the tag mark. -*/ - -PRIVATE void debug_mark -( - /* === Parameters ======================================================= */ - - Int n_row, - Colamd_Row Row [], - Int tag_mark, - Int max_mark -) -{ - /* === Local variables ================================================== */ - - Int r ; - - /* === Check the Row marks ============================================== */ - - ASSERT (tag_mark > 0 && tag_mark <= max_mark) ; - if (n_row > 10000 && colamd_debug <= 0) - { - return ; - } - for (r = 0 ; r < n_row ; r++) - { - ASSERT (Row [r].shared2.mark < tag_mark) ; - } -} - - -/* ========================================================================== */ -/* === debug_matrix ========================================================= */ -/* ========================================================================== */ - -/* - Prints out the contents of the columns and the rows. -*/ - -PRIVATE void debug_matrix -( - /* === Parameters ======================================================= */ - - Int n_row, - Int n_col, - Colamd_Row Row [], - Colamd_Col Col [], - Int A [] -) -{ - /* === Local variables ================================================== */ - - Int r ; - Int c ; - Int *rp ; - Int *rp_end ; - Int *cp ; - Int *cp_end ; - - /* === Dump the rows and columns of the matrix ========================== */ - - if (colamd_debug < 3) - { - return ; - } - DEBUG3 (("DUMP MATRIX:\n")) ; - for (r = 0 ; r < n_row ; r++) - { - DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ; - if (ROW_IS_DEAD (r)) - { - continue ; - } - DEBUG3 (("start %d length %d degree %d\n", - Row [r].start, Row [r].length, Row [r].shared1.degree)) ; - rp = &A [Row [r].start] ; - rp_end = rp + Row [r].length ; - while (rp < rp_end) - { - c = *rp++ ; - DEBUG4 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ; - } - } - - for (c = 0 ; c < n_col ; c++) - { - DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ; - if (COL_IS_DEAD (c)) - { - continue ; - } - DEBUG3 (("start %d length %d shared1 %d shared2 %d\n", - Col [c].start, Col [c].length, - Col [c].shared1.thickness, Col [c].shared2.score)) ; - cp = &A [Col [c].start] ; - cp_end = cp + Col [c].length ; - while (cp < cp_end) - { - r = *cp++ ; - DEBUG4 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ; - } - } -} - -PRIVATE void colamd_get_debug -( - char *method -) -{ - FILE *f ; - colamd_debug = 0 ; /* no debug printing */ - f = fopen ("debug", "r") ; - if (f == (FILE *) NULL) - { - colamd_debug = 0 ; - } - else - { - fscanf (f, "%d", &colamd_debug) ; - fclose (f) ; - } - DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n", - method, colamd_debug)) ; -} - -#endif /* NDEBUG */ diff --git a/extern/colamd/Source/colamd_global.c b/extern/colamd/Source/colamd_global.c deleted file mode 100644 index 4d1ae22300c..00000000000 --- a/extern/colamd/Source/colamd_global.c +++ /dev/null @@ -1,24 +0,0 @@ -/* ========================================================================== */ -/* === colamd_global.c ====================================================== */ -/* ========================================================================== */ - -/* ---------------------------------------------------------------------------- - * COLAMD, Copyright (C) 2007, Timothy A. Davis. - * See License.txt for the Version 2.1 of the GNU Lesser General Public License - * http://www.cise.ufl.edu/research/sparse - * -------------------------------------------------------------------------- */ - -/* Global variables for COLAMD */ - -#ifndef NPRINT -#ifdef MATLAB_MEX_FILE -#include "mex.h" -int (*colamd_printf) (const char *, ...) = mexPrintf ; -#else -#include <stdio.h> -int (*colamd_printf) (const char *, ...) = printf ; -#endif -#else -int (*colamd_printf) (const char *, ...) = ((void *) 0) ; -#endif - diff --git a/extern/cuew/auto/cuda_extra.py b/extern/cuew/auto/cuda_extra.py index fd4f466df83..5fd2c179339 100644 --- a/extern/cuew/auto/cuda_extra.py +++ b/extern/cuew/auto/cuda_extra.py @@ -101,7 +101,7 @@ int cuewCompilerVersion(void) { while (!feof(pipe)) { if (fgets(buf, sizeof(buf), pipe) != NULL) { - strncat(output, buf, sizeof(output) - strlen(output)); + strncat(output, buf, sizeof(output) - strlen(output) - 1); } } diff --git a/extern/cuew/auto/cuew_gen.py b/extern/cuew/auto/cuew_gen.py index a94525c52b1..75e5bf876f4 100644 --- a/extern/cuew/auto/cuew_gen.py +++ b/extern/cuew/auto/cuew_gen.py @@ -276,7 +276,11 @@ def parse_files(): if line[0].isspace() and line.lstrip().startswith("#define"): line = line[12:-1] token = line.split() - if len(token) == 2 and token[1].endswith("_v2"): + if len(token) == 2 and (token[1].endswith("_v2") or + token[1].endswith("_v2)")): + if token[1].startswith('__CUDA_API_PTDS') or \ + token[1].startswith('__CUDA_API_PTSZ'): + token[1] = token[1][16:-1] DEFINES_V2.append(token) v = FuncDefVisitor() @@ -560,7 +564,8 @@ def print_implementation(): if error in CUDA_ERRORS: str = CUDA_ERRORS[error] else: - str = error[11:] + temp = error[11:].replace('_', ' ') + str = temp[0] + temp[1:].lower() print(" case %s: return \"%s\";" % (error, str)) print(" default: return \"Unknown CUDA error value\";") diff --git a/extern/cuew/include/cuew.h b/extern/cuew/include/cuew.h index fd03311ad41..1b12e5b4463 100644 --- a/extern/cuew/include/cuew.h +++ b/extern/cuew/include/cuew.h @@ -27,13 +27,16 @@ extern "C" { #define CUEW_VERSION_MAJOR 1 #define CUEW_VERSION_MINOR 2 -#define CUDA_VERSION 6000 +#define CUDA_VERSION 7050 #define CU_IPC_HANDLE_SIZE 64 +#define CU_STREAM_LEGACY ((CUstream)0x1) +#define CU_STREAM_PER_THREAD ((CUstream)0x2) #define CU_MEMHOSTALLOC_PORTABLE 0x01 #define CU_MEMHOSTALLOC_DEVICEMAP 0x02 #define CU_MEMHOSTALLOC_WRITECOMBINED 0x04 #define CU_MEMHOSTREGISTER_PORTABLE 0x01 #define CU_MEMHOSTREGISTER_DEVICEMAP 0x02 +#define CU_MEMHOSTREGISTER_IOMEMORY 0x04 #define CUDA_ARRAY3D_LAYERED 0x01 #define CUDA_ARRAY3D_2DARRAY 0x01 #define CUDA_ARRAY3D_SURFACE_LDST 0x02 @@ -100,10 +103,16 @@ extern "C" { #define cuCtxPushCurrent cuCtxPushCurrent_v2 #define cuStreamDestroy cuStreamDestroy_v2 #define cuEventDestroy cuEventDestroy_v2 +#define cuLinkCreate cuLinkCreate_v2 +#define cuLinkAddData cuLinkAddData_v2 +#define cuLinkAddFile cuLinkAddFile_v2 +#define cuMemHostRegister cuMemHostRegister_v2 +#define cuGraphicsResourceSetMapFlags cuGraphicsResourceSetMapFlags_v2 #define cuTexRefSetAddress2D cuTexRefSetAddress2D_v2 #define cuGLCtxCreate cuGLCtxCreate_v2 #define cuGLMapBufferObject cuGLMapBufferObject_v2 #define cuGLMapBufferObjectAsync cuGLMapBufferObjectAsync_v2 +#define cuGLGetDevices cuGLGetDevices_v2 /* Types. */ #if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) @@ -172,6 +181,11 @@ typedef enum CUevent_flags_enum { CU_EVENT_INTERPROCESS = 0x4, } CUevent_flags; +typedef enum CUoccupancy_flags_enum { + CU_OCCUPANCY_DEFAULT = 0x0, + CU_OCCUPANCY_DISABLE_CACHING_OVERRIDE = 0x1, +} CUoccupancy_flags; + typedef enum CUarray_format_enum { CU_AD_FORMAT_UNSIGNED_INT8 = 0x01, CU_AD_FORMAT_UNSIGNED_INT16 = 0x02, @@ -381,7 +395,9 @@ typedef enum CUjit_target_enum { CU_TARGET_COMPUTE_30 = 30, CU_TARGET_COMPUTE_32 = 32, CU_TARGET_COMPUTE_35 = 35, + CU_TARGET_COMPUTE_37 = 37, CU_TARGET_COMPUTE_50 = 50, + CU_TARGET_COMPUTE_52 = 52, } CUjit_target; typedef enum CUjit_fallback_enum { @@ -474,6 +490,7 @@ typedef enum cudaError_enum { CUDA_ERROR_CONTEXT_ALREADY_IN_USE = 216, CUDA_ERROR_PEER_ACCESS_UNSUPPORTED = 217, CUDA_ERROR_INVALID_PTX = 218, + CUDA_ERROR_INVALID_GRAPHICS_CONTEXT = 219, CUDA_ERROR_INVALID_SOURCE = 300, CUDA_ERROR_FILE_NOT_FOUND = 301, CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND = 302, @@ -506,6 +523,7 @@ typedef enum cudaError_enum { } CUresult; typedef void* CUstreamCallback; +typedef size_t* CUoccupancyB2DSize; typedef struct CUDA_MEMCPY2D_st { size_t srcXInBytes; @@ -730,6 +748,11 @@ typedef CUresult CUDAAPI tcuDeviceTotalMem_v2(size_t* bytes, CUdevice dev); typedef CUresult CUDAAPI tcuDeviceGetAttribute(int* pi, CUdevice_attribute attrib, CUdevice dev); typedef CUresult CUDAAPI tcuDeviceGetProperties(CUdevprop* prop, CUdevice dev); typedef CUresult CUDAAPI tcuDeviceComputeCapability(int* major, int* minor, CUdevice dev); +typedef CUresult CUDAAPI tcuDevicePrimaryCtxRetain(CUcontext* pctx, CUdevice dev); +typedef CUresult CUDAAPI tcuDevicePrimaryCtxRelease(CUdevice dev); +typedef CUresult CUDAAPI tcuDevicePrimaryCtxSetFlags(CUdevice dev, unsigned flags); +typedef CUresult CUDAAPI tcuDevicePrimaryCtxGetState(CUdevice dev, unsigned* flags, int* active); +typedef CUresult CUDAAPI tcuDevicePrimaryCtxReset(CUdevice dev); typedef CUresult CUDAAPI tcuCtxCreate_v2(CUcontext* pctx, unsigned flags, CUdevice dev); typedef CUresult CUDAAPI tcuCtxDestroy_v2(CUcontext ctx); typedef CUresult CUDAAPI tcuCtxPushCurrent_v2(CUcontext ctx); @@ -737,6 +760,7 @@ typedef CUresult CUDAAPI tcuCtxPopCurrent_v2(CUcontext* pctx); typedef CUresult CUDAAPI tcuCtxSetCurrent(CUcontext ctx); typedef CUresult CUDAAPI tcuCtxGetCurrent(CUcontext* pctx); typedef CUresult CUDAAPI tcuCtxGetDevice(CUdevice* device); +typedef CUresult CUDAAPI tcuCtxGetFlags(unsigned* flags); typedef CUresult CUDAAPI tcuCtxSynchronize(void); typedef CUresult CUDAAPI tcuCtxSetLimit(CUlimit limit, size_t value); typedef CUresult CUDAAPI tcuCtxGetLimit(size_t* pvalue, CUlimit limit); @@ -757,9 +781,9 @@ typedef CUresult CUDAAPI tcuModuleGetFunction(CUfunction* hfunc, CUmodule hmod, typedef CUresult CUDAAPI tcuModuleGetGlobal_v2(CUdeviceptr* dptr, size_t* bytes, CUmodule hmod, const char* name); typedef CUresult CUDAAPI tcuModuleGetTexRef(CUtexref* pTexRef, CUmodule hmod, const char* name); typedef CUresult CUDAAPI tcuModuleGetSurfRef(CUsurfref* pSurfRef, CUmodule hmod, const char* name); -typedef CUresult CUDAAPI tcuLinkCreate(unsigned numOptions, CUjit_option* options, void* optionValues, CUlinkState* stateOut); -typedef CUresult CUDAAPI tcuLinkAddData(CUlinkState state, CUjitInputType type, void* data, size_t size, const char* name, unsigned numOptions, CUjit_option* options, void* optionValues); -typedef CUresult CUDAAPI tcuLinkAddFile(CUlinkState state, CUjitInputType type, const char* path, unsigned numOptions, CUjit_option* options, void* optionValues); +typedef CUresult CUDAAPI tcuLinkCreate_v2(unsigned numOptions, CUjit_option* options, void* optionValues, CUlinkState* stateOut); +typedef CUresult CUDAAPI tcuLinkAddData_v2(CUlinkState state, CUjitInputType type, void* data, size_t size, const char* name, unsigned numOptions, CUjit_option* options, void* optionValues); +typedef CUresult CUDAAPI tcuLinkAddFile_v2(CUlinkState state, CUjitInputType type, const char* path, unsigned numOptions, CUjit_option* options, void* optionValues); typedef CUresult CUDAAPI tcuLinkComplete(CUlinkState state, void* cubinOut, size_t* sizeOut); typedef CUresult CUDAAPI tcuLinkDestroy(CUlinkState state); typedef CUresult CUDAAPI tcuMemGetInfo_v2(size_t* free, size_t* total); @@ -780,7 +804,7 @@ typedef CUresult CUDAAPI tcuIpcOpenEventHandle(CUevent* phEvent, CUipcEventHandl typedef CUresult CUDAAPI tcuIpcGetMemHandle(CUipcMemHandle* pHandle, CUdeviceptr dptr); typedef CUresult CUDAAPI tcuIpcOpenMemHandle(CUdeviceptr* pdptr, CUipcMemHandle handle, unsigned Flags); typedef CUresult CUDAAPI tcuIpcCloseMemHandle(CUdeviceptr dptr); -typedef CUresult CUDAAPI tcuMemHostRegister(void* p, size_t bytesize, unsigned Flags); +typedef CUresult CUDAAPI tcuMemHostRegister_v2(void* p, size_t bytesize, unsigned Flags); typedef CUresult CUDAAPI tcuMemHostUnregister(void* p); typedef CUresult CUDAAPI tcuMemcpy(CUdeviceptr dst, CUdeviceptr src, size_t ByteCount); typedef CUresult CUDAAPI tcuMemcpyPeer(CUdeviceptr dstDevice, CUcontext dstContext, CUdeviceptr srcDevice, CUcontext srcContext, size_t ByteCount); @@ -828,6 +852,7 @@ typedef CUresult CUDAAPI tcuMipmappedArrayGetLevel(CUarray* pLevelArray, CUmipma typedef CUresult CUDAAPI tcuMipmappedArrayDestroy(CUmipmappedArray hMipmappedArray); typedef CUresult CUDAAPI tcuPointerGetAttribute(void* data, CUpointer_attribute attribute, CUdeviceptr ptr); typedef CUresult CUDAAPI tcuPointerSetAttribute(const void* value, CUpointer_attribute attribute, CUdeviceptr ptr); +typedef CUresult CUDAAPI tcuPointerGetAttributes(unsigned numAttributes, CUpointer_attribute* attributes, void* data, CUdeviceptr ptr); typedef CUresult CUDAAPI tcuStreamCreate(CUstream* phStream, unsigned Flags); typedef CUresult CUDAAPI tcuStreamCreateWithPriority(CUstream* phStream, unsigned flags, int priority); typedef CUresult CUDAAPI tcuStreamGetPriority(CUstream hStream, int* priority); @@ -858,6 +883,10 @@ typedef CUresult CUDAAPI tcuLaunch(CUfunction f); typedef CUresult CUDAAPI tcuLaunchGrid(CUfunction f, int grid_width, int grid_height); typedef CUresult CUDAAPI tcuLaunchGridAsync(CUfunction f, int grid_width, int grid_height, CUstream hStream); typedef CUresult CUDAAPI tcuParamSetTexRef(CUfunction hfunc, int texunit, CUtexref hTexRef); +typedef CUresult CUDAAPI tcuOccupancyMaxActiveBlocksPerMultiprocessor(int* numBlocks, CUfunction func, int blockSize, size_t dynamicSMemSize); +typedef CUresult CUDAAPI tcuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags(int* numBlocks, CUfunction func, int blockSize, size_t dynamicSMemSize, unsigned flags); +typedef CUresult CUDAAPI tcuOccupancyMaxPotentialBlockSize(int* minGridSize, int* blockSize, CUfunction func, CUoccupancyB2DSize blockSizeToDynamicSMemSize, size_t dynamicSMemSize, int blockSizeLimit); +typedef CUresult CUDAAPI tcuOccupancyMaxPotentialBlockSizeWithFlags(int* minGridSize, int* blockSize, CUfunction func, CUoccupancyB2DSize blockSizeToDynamicSMemSize, size_t dynamicSMemSize, int blockSizeLimit, unsigned flags); typedef CUresult CUDAAPI tcuTexRefSetArray(CUtexref hTexRef, CUarray hArray, unsigned Flags); typedef CUresult CUDAAPI tcuTexRefSetMipmappedArray(CUtexref hTexRef, CUmipmappedArray hMipmappedArray, unsigned Flags); typedef CUresult CUDAAPI tcuTexRefSetAddress_v2(size_t* ByteOffset, CUtexref hTexRef, CUdeviceptr dptr, size_t bytes); @@ -900,14 +929,14 @@ typedef CUresult CUDAAPI tcuGraphicsUnregisterResource(CUgraphicsResource resour typedef CUresult CUDAAPI tcuGraphicsSubResourceGetMappedArray(CUarray* pArray, CUgraphicsResource resource, unsigned arrayIndex, unsigned mipLevel); typedef CUresult CUDAAPI tcuGraphicsResourceGetMappedMipmappedArray(CUmipmappedArray* pMipmappedArray, CUgraphicsResource resource); typedef CUresult CUDAAPI tcuGraphicsResourceGetMappedPointer_v2(CUdeviceptr* pDevPtr, size_t* pSize, CUgraphicsResource resource); -typedef CUresult CUDAAPI tcuGraphicsResourceSetMapFlags(CUgraphicsResource resource, unsigned flags); +typedef CUresult CUDAAPI tcuGraphicsResourceSetMapFlags_v2(CUgraphicsResource resource, unsigned flags); typedef CUresult CUDAAPI tcuGraphicsMapResources(unsigned count, CUgraphicsResource* resources, CUstream hStream); typedef CUresult CUDAAPI tcuGraphicsUnmapResources(unsigned count, CUgraphicsResource* resources, CUstream hStream); typedef CUresult CUDAAPI tcuGetExportTable(const void* ppExportTable, const CUuuid* pExportTableId); typedef CUresult CUDAAPI tcuGraphicsGLRegisterBuffer(CUgraphicsResource* pCudaResource, GLuint buffer, unsigned Flags); typedef CUresult CUDAAPI tcuGraphicsGLRegisterImage(CUgraphicsResource* pCudaResource, GLuint image, GLenum target, unsigned Flags); -typedef CUresult CUDAAPI tcuGLGetDevices(unsigned* pCudaDeviceCount, CUdevice* pCudaDevices, unsigned cudaDeviceCount, CUGLDeviceList deviceList); +typedef CUresult CUDAAPI tcuGLGetDevices_v2(unsigned* pCudaDeviceCount, CUdevice* pCudaDevices, unsigned cudaDeviceCount, CUGLDeviceList deviceList); typedef CUresult CUDAAPI tcuGLCtxCreate_v2(CUcontext* pCtx, unsigned Flags, CUdevice device); typedef CUresult CUDAAPI tcuGLInit(void); typedef CUresult CUDAAPI tcuGLRegisterBufferObject(GLuint buffer); @@ -931,6 +960,11 @@ extern tcuDeviceTotalMem_v2 *cuDeviceTotalMem_v2; extern tcuDeviceGetAttribute *cuDeviceGetAttribute; extern tcuDeviceGetProperties *cuDeviceGetProperties; extern tcuDeviceComputeCapability *cuDeviceComputeCapability; +extern tcuDevicePrimaryCtxRetain *cuDevicePrimaryCtxRetain; +extern tcuDevicePrimaryCtxRelease *cuDevicePrimaryCtxRelease; +extern tcuDevicePrimaryCtxSetFlags *cuDevicePrimaryCtxSetFlags; +extern tcuDevicePrimaryCtxGetState *cuDevicePrimaryCtxGetState; +extern tcuDevicePrimaryCtxReset *cuDevicePrimaryCtxReset; extern tcuCtxCreate_v2 *cuCtxCreate_v2; extern tcuCtxDestroy_v2 *cuCtxDestroy_v2; extern tcuCtxPushCurrent_v2 *cuCtxPushCurrent_v2; @@ -938,6 +972,7 @@ extern tcuCtxPopCurrent_v2 *cuCtxPopCurrent_v2; extern tcuCtxSetCurrent *cuCtxSetCurrent; extern tcuCtxGetCurrent *cuCtxGetCurrent; extern tcuCtxGetDevice *cuCtxGetDevice; +extern tcuCtxGetFlags *cuCtxGetFlags; extern tcuCtxSynchronize *cuCtxSynchronize; extern tcuCtxSetLimit *cuCtxSetLimit; extern tcuCtxGetLimit *cuCtxGetLimit; @@ -958,9 +993,9 @@ extern tcuModuleGetFunction *cuModuleGetFunction; extern tcuModuleGetGlobal_v2 *cuModuleGetGlobal_v2; extern tcuModuleGetTexRef *cuModuleGetTexRef; extern tcuModuleGetSurfRef *cuModuleGetSurfRef; -extern tcuLinkCreate *cuLinkCreate; -extern tcuLinkAddData *cuLinkAddData; -extern tcuLinkAddFile *cuLinkAddFile; +extern tcuLinkCreate_v2 *cuLinkCreate_v2; +extern tcuLinkAddData_v2 *cuLinkAddData_v2; +extern tcuLinkAddFile_v2 *cuLinkAddFile_v2; extern tcuLinkComplete *cuLinkComplete; extern tcuLinkDestroy *cuLinkDestroy; extern tcuMemGetInfo_v2 *cuMemGetInfo_v2; @@ -981,7 +1016,7 @@ extern tcuIpcOpenEventHandle *cuIpcOpenEventHandle; extern tcuIpcGetMemHandle *cuIpcGetMemHandle; extern tcuIpcOpenMemHandle *cuIpcOpenMemHandle; extern tcuIpcCloseMemHandle *cuIpcCloseMemHandle; -extern tcuMemHostRegister *cuMemHostRegister; +extern tcuMemHostRegister_v2 *cuMemHostRegister_v2; extern tcuMemHostUnregister *cuMemHostUnregister; extern tcuMemcpy *cuMemcpy; extern tcuMemcpyPeer *cuMemcpyPeer; @@ -1029,6 +1064,7 @@ extern tcuMipmappedArrayGetLevel *cuMipmappedArrayGetLevel; extern tcuMipmappedArrayDestroy *cuMipmappedArrayDestroy; extern tcuPointerGetAttribute *cuPointerGetAttribute; extern tcuPointerSetAttribute *cuPointerSetAttribute; +extern tcuPointerGetAttributes *cuPointerGetAttributes; extern tcuStreamCreate *cuStreamCreate; extern tcuStreamCreateWithPriority *cuStreamCreateWithPriority; extern tcuStreamGetPriority *cuStreamGetPriority; @@ -1059,6 +1095,10 @@ extern tcuLaunch *cuLaunch; extern tcuLaunchGrid *cuLaunchGrid; extern tcuLaunchGridAsync *cuLaunchGridAsync; extern tcuParamSetTexRef *cuParamSetTexRef; +extern tcuOccupancyMaxActiveBlocksPerMultiprocessor *cuOccupancyMaxActiveBlocksPerMultiprocessor; +extern tcuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags *cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags; +extern tcuOccupancyMaxPotentialBlockSize *cuOccupancyMaxPotentialBlockSize; +extern tcuOccupancyMaxPotentialBlockSizeWithFlags *cuOccupancyMaxPotentialBlockSizeWithFlags; extern tcuTexRefSetArray *cuTexRefSetArray; extern tcuTexRefSetMipmappedArray *cuTexRefSetMipmappedArray; extern tcuTexRefSetAddress_v2 *cuTexRefSetAddress_v2; @@ -1101,14 +1141,14 @@ extern tcuGraphicsUnregisterResource *cuGraphicsUnregisterResource; extern tcuGraphicsSubResourceGetMappedArray *cuGraphicsSubResourceGetMappedArray; extern tcuGraphicsResourceGetMappedMipmappedArray *cuGraphicsResourceGetMappedMipmappedArray; extern tcuGraphicsResourceGetMappedPointer_v2 *cuGraphicsResourceGetMappedPointer_v2; -extern tcuGraphicsResourceSetMapFlags *cuGraphicsResourceSetMapFlags; +extern tcuGraphicsResourceSetMapFlags_v2 *cuGraphicsResourceSetMapFlags_v2; extern tcuGraphicsMapResources *cuGraphicsMapResources; extern tcuGraphicsUnmapResources *cuGraphicsUnmapResources; extern tcuGetExportTable *cuGetExportTable; extern tcuGraphicsGLRegisterBuffer *cuGraphicsGLRegisterBuffer; extern tcuGraphicsGLRegisterImage *cuGraphicsGLRegisterImage; -extern tcuGLGetDevices *cuGLGetDevices; +extern tcuGLGetDevices_v2 *cuGLGetDevices_v2; extern tcuGLCtxCreate_v2 *cuGLCtxCreate_v2; extern tcuGLInit *cuGLInit; extern tcuGLRegisterBufferObject *cuGLRegisterBufferObject; diff --git a/extern/cuew/src/cuew.c b/extern/cuew/src/cuew.c index da892efc0f4..3058e29d89f 100644 --- a/extern/cuew/src/cuew.c +++ b/extern/cuew/src/cuew.c @@ -36,7 +36,7 @@ typedef HMODULE DynamicLibrary; -# define dynamic_library_open(path) LoadLibrary(path) +# define dynamic_library_open(path) LoadLibraryA(path) # define dynamic_library_close(lib) FreeLibrary(lib) # define dynamic_library_find(lib, symbol) GetProcAddress(lib, symbol) #else @@ -70,6 +70,11 @@ tcuDeviceTotalMem_v2 *cuDeviceTotalMem_v2; tcuDeviceGetAttribute *cuDeviceGetAttribute; tcuDeviceGetProperties *cuDeviceGetProperties; tcuDeviceComputeCapability *cuDeviceComputeCapability; +tcuDevicePrimaryCtxRetain *cuDevicePrimaryCtxRetain; +tcuDevicePrimaryCtxRelease *cuDevicePrimaryCtxRelease; +tcuDevicePrimaryCtxSetFlags *cuDevicePrimaryCtxSetFlags; +tcuDevicePrimaryCtxGetState *cuDevicePrimaryCtxGetState; +tcuDevicePrimaryCtxReset *cuDevicePrimaryCtxReset; tcuCtxCreate_v2 *cuCtxCreate_v2; tcuCtxDestroy_v2 *cuCtxDestroy_v2; tcuCtxPushCurrent_v2 *cuCtxPushCurrent_v2; @@ -77,6 +82,7 @@ tcuCtxPopCurrent_v2 *cuCtxPopCurrent_v2; tcuCtxSetCurrent *cuCtxSetCurrent; tcuCtxGetCurrent *cuCtxGetCurrent; tcuCtxGetDevice *cuCtxGetDevice; +tcuCtxGetFlags *cuCtxGetFlags; tcuCtxSynchronize *cuCtxSynchronize; tcuCtxSetLimit *cuCtxSetLimit; tcuCtxGetLimit *cuCtxGetLimit; @@ -97,9 +103,9 @@ tcuModuleGetFunction *cuModuleGetFunction; tcuModuleGetGlobal_v2 *cuModuleGetGlobal_v2; tcuModuleGetTexRef *cuModuleGetTexRef; tcuModuleGetSurfRef *cuModuleGetSurfRef; -tcuLinkCreate *cuLinkCreate; -tcuLinkAddData *cuLinkAddData; -tcuLinkAddFile *cuLinkAddFile; +tcuLinkCreate_v2 *cuLinkCreate_v2; +tcuLinkAddData_v2 *cuLinkAddData_v2; +tcuLinkAddFile_v2 *cuLinkAddFile_v2; tcuLinkComplete *cuLinkComplete; tcuLinkDestroy *cuLinkDestroy; tcuMemGetInfo_v2 *cuMemGetInfo_v2; @@ -120,7 +126,7 @@ tcuIpcOpenEventHandle *cuIpcOpenEventHandle; tcuIpcGetMemHandle *cuIpcGetMemHandle; tcuIpcOpenMemHandle *cuIpcOpenMemHandle; tcuIpcCloseMemHandle *cuIpcCloseMemHandle; -tcuMemHostRegister *cuMemHostRegister; +tcuMemHostRegister_v2 *cuMemHostRegister_v2; tcuMemHostUnregister *cuMemHostUnregister; tcuMemcpy *cuMemcpy; tcuMemcpyPeer *cuMemcpyPeer; @@ -168,6 +174,7 @@ tcuMipmappedArrayGetLevel *cuMipmappedArrayGetLevel; tcuMipmappedArrayDestroy *cuMipmappedArrayDestroy; tcuPointerGetAttribute *cuPointerGetAttribute; tcuPointerSetAttribute *cuPointerSetAttribute; +tcuPointerGetAttributes *cuPointerGetAttributes; tcuStreamCreate *cuStreamCreate; tcuStreamCreateWithPriority *cuStreamCreateWithPriority; tcuStreamGetPriority *cuStreamGetPriority; @@ -198,6 +205,10 @@ tcuLaunch *cuLaunch; tcuLaunchGrid *cuLaunchGrid; tcuLaunchGridAsync *cuLaunchGridAsync; tcuParamSetTexRef *cuParamSetTexRef; +tcuOccupancyMaxActiveBlocksPerMultiprocessor *cuOccupancyMaxActiveBlocksPerMultiprocessor; +tcuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags *cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags; +tcuOccupancyMaxPotentialBlockSize *cuOccupancyMaxPotentialBlockSize; +tcuOccupancyMaxPotentialBlockSizeWithFlags *cuOccupancyMaxPotentialBlockSizeWithFlags; tcuTexRefSetArray *cuTexRefSetArray; tcuTexRefSetMipmappedArray *cuTexRefSetMipmappedArray; tcuTexRefSetAddress_v2 *cuTexRefSetAddress_v2; @@ -240,14 +251,14 @@ tcuGraphicsUnregisterResource *cuGraphicsUnregisterResource; tcuGraphicsSubResourceGetMappedArray *cuGraphicsSubResourceGetMappedArray; tcuGraphicsResourceGetMappedMipmappedArray *cuGraphicsResourceGetMappedMipmappedArray; tcuGraphicsResourceGetMappedPointer_v2 *cuGraphicsResourceGetMappedPointer_v2; -tcuGraphicsResourceSetMapFlags *cuGraphicsResourceSetMapFlags; +tcuGraphicsResourceSetMapFlags_v2 *cuGraphicsResourceSetMapFlags_v2; tcuGraphicsMapResources *cuGraphicsMapResources; tcuGraphicsUnmapResources *cuGraphicsUnmapResources; tcuGetExportTable *cuGetExportTable; tcuGraphicsGLRegisterBuffer *cuGraphicsGLRegisterBuffer; tcuGraphicsGLRegisterImage *cuGraphicsGLRegisterImage; -tcuGLGetDevices *cuGLGetDevices; +tcuGLGetDevices_v2 *cuGLGetDevices_v2; tcuGLCtxCreate_v2 *cuGLCtxCreate_v2; tcuGLInit *cuGLInit; tcuGLRegisterBufferObject *cuGLRegisterBufferObject; @@ -328,6 +339,11 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuDeviceGetAttribute); CUDA_LIBRARY_FIND(cuDeviceGetProperties); CUDA_LIBRARY_FIND(cuDeviceComputeCapability); + CUDA_LIBRARY_FIND(cuDevicePrimaryCtxRetain); + CUDA_LIBRARY_FIND(cuDevicePrimaryCtxRelease); + CUDA_LIBRARY_FIND(cuDevicePrimaryCtxSetFlags); + CUDA_LIBRARY_FIND(cuDevicePrimaryCtxGetState); + CUDA_LIBRARY_FIND(cuDevicePrimaryCtxReset); CUDA_LIBRARY_FIND(cuCtxCreate_v2); CUDA_LIBRARY_FIND(cuCtxDestroy_v2); CUDA_LIBRARY_FIND(cuCtxPushCurrent_v2); @@ -335,6 +351,7 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuCtxSetCurrent); CUDA_LIBRARY_FIND(cuCtxGetCurrent); CUDA_LIBRARY_FIND(cuCtxGetDevice); + CUDA_LIBRARY_FIND(cuCtxGetFlags); CUDA_LIBRARY_FIND(cuCtxSynchronize); CUDA_LIBRARY_FIND(cuCtxSetLimit); CUDA_LIBRARY_FIND(cuCtxGetLimit); @@ -355,9 +372,9 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuModuleGetGlobal_v2); CUDA_LIBRARY_FIND(cuModuleGetTexRef); CUDA_LIBRARY_FIND(cuModuleGetSurfRef); - CUDA_LIBRARY_FIND(cuLinkCreate); - CUDA_LIBRARY_FIND(cuLinkAddData); - CUDA_LIBRARY_FIND(cuLinkAddFile); + CUDA_LIBRARY_FIND(cuLinkCreate_v2); + CUDA_LIBRARY_FIND(cuLinkAddData_v2); + CUDA_LIBRARY_FIND(cuLinkAddFile_v2); CUDA_LIBRARY_FIND(cuLinkComplete); CUDA_LIBRARY_FIND(cuLinkDestroy); CUDA_LIBRARY_FIND(cuMemGetInfo_v2); @@ -378,7 +395,7 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuIpcGetMemHandle); CUDA_LIBRARY_FIND(cuIpcOpenMemHandle); CUDA_LIBRARY_FIND(cuIpcCloseMemHandle); - CUDA_LIBRARY_FIND(cuMemHostRegister); + CUDA_LIBRARY_FIND(cuMemHostRegister_v2); CUDA_LIBRARY_FIND(cuMemHostUnregister); CUDA_LIBRARY_FIND(cuMemcpy); CUDA_LIBRARY_FIND(cuMemcpyPeer); @@ -426,6 +443,7 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuMipmappedArrayDestroy); CUDA_LIBRARY_FIND(cuPointerGetAttribute); CUDA_LIBRARY_FIND(cuPointerSetAttribute); + CUDA_LIBRARY_FIND(cuPointerGetAttributes); CUDA_LIBRARY_FIND(cuStreamCreate); CUDA_LIBRARY_FIND(cuStreamCreateWithPriority); CUDA_LIBRARY_FIND(cuStreamGetPriority); @@ -456,6 +474,10 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuLaunchGrid); CUDA_LIBRARY_FIND(cuLaunchGridAsync); CUDA_LIBRARY_FIND(cuParamSetTexRef); + CUDA_LIBRARY_FIND(cuOccupancyMaxActiveBlocksPerMultiprocessor); + CUDA_LIBRARY_FIND(cuOccupancyMaxActiveBlocksPerMultiprocessorWithFlags); + CUDA_LIBRARY_FIND(cuOccupancyMaxPotentialBlockSize); + CUDA_LIBRARY_FIND(cuOccupancyMaxPotentialBlockSizeWithFlags); CUDA_LIBRARY_FIND(cuTexRefSetArray); CUDA_LIBRARY_FIND(cuTexRefSetMipmappedArray); CUDA_LIBRARY_FIND(cuTexRefSetAddress_v2); @@ -498,14 +520,14 @@ int cuewInit(void) { CUDA_LIBRARY_FIND(cuGraphicsSubResourceGetMappedArray); CUDA_LIBRARY_FIND(cuGraphicsResourceGetMappedMipmappedArray); CUDA_LIBRARY_FIND(cuGraphicsResourceGetMappedPointer_v2); - CUDA_LIBRARY_FIND(cuGraphicsResourceSetMapFlags); + CUDA_LIBRARY_FIND(cuGraphicsResourceSetMapFlags_v2); CUDA_LIBRARY_FIND(cuGraphicsMapResources); CUDA_LIBRARY_FIND(cuGraphicsUnmapResources); CUDA_LIBRARY_FIND(cuGetExportTable); CUDA_LIBRARY_FIND(cuGraphicsGLRegisterBuffer); CUDA_LIBRARY_FIND(cuGraphicsGLRegisterImage); - CUDA_LIBRARY_FIND(cuGLGetDevices); + CUDA_LIBRARY_FIND(cuGLGetDevices_v2); CUDA_LIBRARY_FIND(cuGLCtxCreate_v2); CUDA_LIBRARY_FIND(cuGLInit); CUDA_LIBRARY_FIND(cuGLRegisterBufferObject); @@ -528,10 +550,10 @@ const char *cuewErrorString(CUresult result) { case CUDA_ERROR_OUT_OF_MEMORY: return "Out of memory"; case CUDA_ERROR_NOT_INITIALIZED: return "Driver not initialized"; case CUDA_ERROR_DEINITIALIZED: return "Driver deinitialized"; - case CUDA_ERROR_PROFILER_DISABLED: return "PROFILER_DISABLED"; - case CUDA_ERROR_PROFILER_NOT_INITIALIZED: return "PROFILER_NOT_INITIALIZED"; - case CUDA_ERROR_PROFILER_ALREADY_STARTED: return "PROFILER_ALREADY_STARTED"; - case CUDA_ERROR_PROFILER_ALREADY_STOPPED: return "PROFILER_ALREADY_STOPPED"; + case CUDA_ERROR_PROFILER_DISABLED: return "Profiler disabled"; + case CUDA_ERROR_PROFILER_NOT_INITIALIZED: return "Profiler not initialized"; + case CUDA_ERROR_PROFILER_ALREADY_STARTED: return "Profiler already started"; + case CUDA_ERROR_PROFILER_ALREADY_STOPPED: return "Profiler already stopped"; case CUDA_ERROR_NO_DEVICE: return "No CUDA-capable device available"; case CUDA_ERROR_INVALID_DEVICE: return "Invalid device"; case CUDA_ERROR_INVALID_IMAGE: return "Invalid kernel image"; @@ -548,37 +570,38 @@ const char *cuewErrorString(CUresult result) { case CUDA_ERROR_NOT_MAPPED_AS_POINTER: return "Mapped resource not available for access as a pointer"; case CUDA_ERROR_ECC_UNCORRECTABLE: return "Uncorrectable ECC error detected"; case CUDA_ERROR_UNSUPPORTED_LIMIT: return "CUlimit not supported by device"; - case CUDA_ERROR_CONTEXT_ALREADY_IN_USE: return "CONTEXT_ALREADY_IN_USE"; - case CUDA_ERROR_PEER_ACCESS_UNSUPPORTED: return "PEER_ACCESS_UNSUPPORTED"; - case CUDA_ERROR_INVALID_PTX: return "INVALID_PTX"; + case CUDA_ERROR_CONTEXT_ALREADY_IN_USE: return "Context already in use"; + case CUDA_ERROR_PEER_ACCESS_UNSUPPORTED: return "Peer access unsupported"; + case CUDA_ERROR_INVALID_PTX: return "Invalid ptx"; + case CUDA_ERROR_INVALID_GRAPHICS_CONTEXT: return "Invalid graphics context"; case CUDA_ERROR_INVALID_SOURCE: return "Invalid source"; case CUDA_ERROR_FILE_NOT_FOUND: return "File not found"; case CUDA_ERROR_SHARED_OBJECT_SYMBOL_NOT_FOUND: return "Link to a shared object failed to resolve"; case CUDA_ERROR_SHARED_OBJECT_INIT_FAILED: return "Shared object initialization failed"; - case CUDA_ERROR_OPERATING_SYSTEM: return "OPERATING_SYSTEM"; + case CUDA_ERROR_OPERATING_SYSTEM: return "Operating system"; case CUDA_ERROR_INVALID_HANDLE: return "Invalid handle"; case CUDA_ERROR_NOT_FOUND: return "Not found"; case CUDA_ERROR_NOT_READY: return "CUDA not ready"; - case CUDA_ERROR_ILLEGAL_ADDRESS: return "ILLEGAL_ADDRESS"; + case CUDA_ERROR_ILLEGAL_ADDRESS: return "Illegal address"; case CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES: return "Launch exceeded resources"; case CUDA_ERROR_LAUNCH_TIMEOUT: return "Launch exceeded timeout"; case CUDA_ERROR_LAUNCH_INCOMPATIBLE_TEXTURING: return "Launch with incompatible texturing"; - case CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED: return "PEER_ACCESS_ALREADY_ENABLED"; - case CUDA_ERROR_PEER_ACCESS_NOT_ENABLED: return "PEER_ACCESS_NOT_ENABLED"; - case CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE: return "PRIMARY_CONTEXT_ACTIVE"; - case CUDA_ERROR_CONTEXT_IS_DESTROYED: return "CONTEXT_IS_DESTROYED"; - case CUDA_ERROR_ASSERT: return "ASSERT"; - case CUDA_ERROR_TOO_MANY_PEERS: return "TOO_MANY_PEERS"; - case CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED: return "HOST_MEMORY_ALREADY_REGISTERED"; - case CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED: return "HOST_MEMORY_NOT_REGISTERED"; - case CUDA_ERROR_HARDWARE_STACK_ERROR: return "HARDWARE_STACK_ERROR"; - case CUDA_ERROR_ILLEGAL_INSTRUCTION: return "ILLEGAL_INSTRUCTION"; - case CUDA_ERROR_MISALIGNED_ADDRESS: return "MISALIGNED_ADDRESS"; - case CUDA_ERROR_INVALID_ADDRESS_SPACE: return "INVALID_ADDRESS_SPACE"; - case CUDA_ERROR_INVALID_PC: return "INVALID_PC"; + case CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED: return "Peer access already enabled"; + case CUDA_ERROR_PEER_ACCESS_NOT_ENABLED: return "Peer access not enabled"; + case CUDA_ERROR_PRIMARY_CONTEXT_ACTIVE: return "Primary context active"; + case CUDA_ERROR_CONTEXT_IS_DESTROYED: return "Context is destroyed"; + case CUDA_ERROR_ASSERT: return "Assert"; + case CUDA_ERROR_TOO_MANY_PEERS: return "Too many peers"; + case CUDA_ERROR_HOST_MEMORY_ALREADY_REGISTERED: return "Host memory already registered"; + case CUDA_ERROR_HOST_MEMORY_NOT_REGISTERED: return "Host memory not registered"; + case CUDA_ERROR_HARDWARE_STACK_ERROR: return "Hardware stack error"; + case CUDA_ERROR_ILLEGAL_INSTRUCTION: return "Illegal instruction"; + case CUDA_ERROR_MISALIGNED_ADDRESS: return "Misaligned address"; + case CUDA_ERROR_INVALID_ADDRESS_SPACE: return "Invalid address space"; + case CUDA_ERROR_INVALID_PC: return "Invalid pc"; case CUDA_ERROR_LAUNCH_FAILED: return "Launch failed"; - case CUDA_ERROR_NOT_PERMITTED: return "NOT_PERMITTED"; - case CUDA_ERROR_NOT_SUPPORTED: return "NOT_SUPPORTED"; + case CUDA_ERROR_NOT_PERMITTED: return "Not permitted"; + case CUDA_ERROR_NOT_SUPPORTED: return "Not supported"; case CUDA_ERROR_UNKNOWN: return "Unknown error"; default: return "Unknown CUDA error value"; } @@ -686,7 +709,7 @@ int cuewCompilerVersion(void) { while (!feof(pipe)) { if (fgets(buf, sizeof(buf), pipe) != NULL) { - strncat(output, buf, sizeof(output) - strlen(output) - 1 ); + strncat(output, buf, sizeof(output) - strlen(output) - 1); } } diff --git a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h index 6a3ade81089..1a8bf7a1c87 100644 --- a/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h +++ b/extern/libmv/libmv/simple_pipeline/camera_intrinsics.h @@ -197,7 +197,7 @@ class CameraIntrinsics { double *normalized_x, double *normalized_y) const = 0; - // Distort an image using the current camera instrinsics + // Distort an image using the current camera intrinsics // // The distorted image is computed in output_buffer using samples from // input_buffer. Both buffers should be width x height x channels sized. @@ -226,7 +226,7 @@ class CameraIntrinsics { int channels, PixelType *output_buffer); - // Undistort an image using the current camera instrinsics + // Undistort an image using the current camera intrinsics // // The undistorted image is computed in output_buffer using samples from // input_buffer. Both buffers should be width x height x channels sized. diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index 4ee3dff7695..275524f788f 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -32,6 +32,7 @@ add_subdirectory(opencolorio) add_subdirectory(mikktspace) add_subdirectory(raskter) add_subdirectory(glew-mx) +add_subdirectory(eigen) if(WITH_AUDASPACE) add_subdirectory(audaspace) @@ -73,10 +74,6 @@ if(WITH_BULLET) add_subdirectory(rigidbody) endif() -if(WITH_OPENNL) - add_subdirectory(opennl) -endif() - if(WITH_OPENSUBDIV) add_subdirectory(opensubdiv) endif() diff --git a/intern/SConscript b/intern/SConscript index 124afd4bbb9..736242102cc 100644 --- a/intern/SConscript +++ b/intern/SConscript @@ -35,8 +35,8 @@ SConscript(['string/SConscript', 'memutil/SConscript/', 'iksolver/SConscript', 'itasc/SConscript', + 'eigen/SConscript', 'opencolorio/SConscript', - 'opennl/SConscript', 'mikktspace/SConscript', 'smoke/SConscript', 'raskter/SConscript']) diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp index ba961f0cb78..ff2c526bf49 100644 --- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp +++ b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp @@ -389,9 +389,7 @@ void AUD_FFMPEGReader::seek(int position) int length = AUD_DEFAULT_BUFFER_SIZE; AUD_Buffer buffer(length * AUD_SAMPLE_SIZE(m_specs)); bool eos; - for(int len = position - m_position; - length == AUD_DEFAULT_BUFFER_SIZE; - len -= AUD_DEFAULT_BUFFER_SIZE) + for(int len = position - m_position; len > 0; len -= AUD_DEFAULT_BUFFER_SIZE) { if(len < AUD_DEFAULT_BUFFER_SIZE) length = len; diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 5bbdeb6061b..74dee206c0e 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -107,6 +107,32 @@ static ShaderSocketType convert_socket_type(BL::NodeSocket b_socket) } } +#ifdef WITH_OSL +static ShaderSocketType convert_osl_socket_type(OSL::OSLQuery& query, + BL::NodeSocket b_socket) +{ + ShaderSocketType socket_type = convert_socket_type(b_socket); +#if OSL_LIBRARY_VERSION_CODE < 10701 + (void) query; +#else + if(socket_type == SHADER_SOCKET_VECTOR) { + /* TODO(sergey): Do we need compatible_name() here? */ + const OSL::OSLQuery::Parameter *param = query.getparam(b_socket.name()); + assert(param != NULL); + if(param != NULL) { + if(param->type.vecsemantics == TypeDesc::POINT) { + socket_type = SHADER_SOCKET_POINT; + } + else if(param->type.vecsemantics == TypeDesc::NORMAL) { + socket_type = SHADER_SOCKET_NORMAL; + } + } + } +#endif + return socket_type; +} +#endif /* WITH_OSL */ + static void set_default_value(ShaderInput *input, BL::NodeSocket b_sock, BL::BlendData b_data, BL::ID b_id) { /* copy values for non linked inputs */ @@ -184,6 +210,7 @@ static ShaderNode *add_node(Scene *scene, BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene, + const bool background, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, BL::ShaderNode b_node) @@ -193,8 +220,13 @@ static ShaderNode *add_node(Scene *scene, /* existing blender nodes */ if(b_node.is_a(&RNA_ShaderNodeRGBCurve)) { BL::ShaderNodeRGBCurve b_curve_node(b_node); + BL::CurveMapping mapping(b_curve_node.mapping()); RGBCurvesNode *curves = new RGBCurvesNode(); - curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, true); + curvemapping_color_to_array(mapping, + curves->curves, + RAMP_TABLE_SIZE, + true); + curvemapping_minmax(mapping, true, &curves->min_x, &curves->max_x); node = curves; } if(b_node.is_a(&RNA_ShaderNodeVectorCurve)) { @@ -507,6 +539,23 @@ static ShaderNode *add_node(Scene *scene, BL::ShaderNodeScript b_script_node(b_node); OSLScriptNode *script_node = new OSLScriptNode(); + OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager; + string bytecode_hash = b_script_node.bytecode_hash(); + + /* Gather additional information from the shader, such as + * input/output type info needed for proper node construction. + */ + OSL::OSLQuery query; +#if OSL_LIBRARY_VERSION_CODE >= 10701 + if(!bytecode_hash.empty()) { + query.open_bytecode(b_script_node.bytecode()); + } + else { + !OSLShaderManager::osl_query(query, b_script_node.filepath()); + } + /* TODO(sergey): Add proper query info error parsing. */ +#endif + /* Generate inputs/outputs from node sockets * * Note: the node sockets are generated from OSL parameters, @@ -519,7 +568,7 @@ static ShaderNode *add_node(Scene *scene, for(b_script_node.inputs.begin(b_input); b_input != b_script_node.inputs.end(); ++b_input) { script_node->input_names.push_back(ustring(b_input->name())); ShaderInput *input = script_node->add_input(script_node->input_names.back().c_str(), - convert_socket_type(*b_input)); + convert_osl_socket_type(query, *b_input)); set_default_value(input, *b_input, b_data, b_ntree); } @@ -528,13 +577,10 @@ static ShaderNode *add_node(Scene *scene, for(b_script_node.outputs.begin(b_output); b_output != b_script_node.outputs.end(); ++b_output) { script_node->output_names.push_back(ustring(b_output->name())); script_node->add_output(script_node->output_names.back().c_str(), - convert_socket_type(*b_output)); + convert_osl_socket_type(query, *b_output)); } /* load bytecode or filepath */ - OSLShaderManager *manager = (OSLShaderManager*)scene->shader_manager; - string bytecode_hash = b_script_node.bytecode_hash(); - if(!bytecode_hash.empty()) { /* loaded bytecode if not already done */ if(!manager->shader_test_loaded(bytecode_hash)) @@ -763,6 +809,8 @@ static ShaderNode *add_node(Scene *scene, /* TODO(sergey): Use more proper update flag. */ if(true) { + int settings = background ? 1 : 0; /* 1 - render settings, 0 - vewport settings. */ + b_point_density_node.cache_point_density(b_scene, settings); scene->image_manager->tag_reload_image( point_density->filename, point_density->builtin_data, @@ -852,6 +900,7 @@ static void add_nodes(Scene *scene, BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene, + const bool background, ShaderGraph *graph, BL::ShaderNodeTree b_ntree, const ProxyMap &proxy_input_map, @@ -937,6 +986,7 @@ static void add_nodes(Scene *scene, b_engine, b_data, b_scene, + background, graph, b_group_ntree, group_proxy_input_map, @@ -984,6 +1034,7 @@ static void add_nodes(Scene *scene, b_engine, b_data, b_scene, + background, graph, b_ntree, BL::ShaderNode(*b_node)); @@ -1046,6 +1097,7 @@ static void add_nodes(Scene *scene, BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene, + const bool background, ShaderGraph *graph, BL::ShaderNodeTree b_ntree) { @@ -1054,6 +1106,7 @@ static void add_nodes(Scene *scene, b_engine, b_data, b_scene, + background, graph, b_ntree, empty_proxy_map, @@ -1083,7 +1136,7 @@ void BlenderSync::sync_materials(bool update_all) if(b_mat->use_nodes() && b_mat->node_tree()) { BL::ShaderNodeTree b_ntree(b_mat->node_tree()); - add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree); + add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); } else { ShaderNode *closure, *out; @@ -1126,7 +1179,7 @@ void BlenderSync::sync_world(bool update_all) if(b_world && b_world.use_nodes() && b_world.node_tree()) { BL::ShaderNodeTree b_ntree(b_world.node_tree()); - add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree); + add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); /* volume */ PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles"); @@ -1217,7 +1270,7 @@ void BlenderSync::sync_lamps(bool update_all) BL::ShaderNodeTree b_ntree(b_lamp->node_tree()); - add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree); + add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); } else { ShaderNode *closure, *out; diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 2e9e9266404..029d0af0fd2 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -62,6 +62,29 @@ static inline void colorramp_to_array(BL::ColorRamp ramp, float4 *data, int size } } +static inline void curvemap_minmax_curve(/*const*/ BL::CurveMap& curve, + float *min_x, + float *max_x) +{ + *min_x = min(*min_x, curve.points[0].location()[0]); + *max_x = max(*max_x, curve.points[curve.points.length() - 1].location()[0]); +} + +static inline void curvemapping_minmax(/*const*/ BL::CurveMapping& cumap, + bool rgb_curve, + float *min_x, + float *max_x) +{ + /* const int num_curves = cumap.curves.length(); */ /* Gives linking error so far. */ + const int num_curves = rgb_curve? 4: 3; + *min_x = FLT_MAX; + *max_x = -FLT_MAX; + for(int i = 0; i < num_curves; ++i) { + BL::CurveMap map(cumap.curves[i]); + curvemap_minmax_curve(map, min_x, max_x); + } +} + static inline void curvemapping_to_array(BL::CurveMapping cumap, float *data, int size) { cumap.update(); @@ -72,8 +95,29 @@ static inline void curvemapping_to_array(BL::CurveMapping cumap, float *data, in } } -static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *data, int size, bool rgb_curve) +static inline void curvemapping_color_to_array(BL::CurveMapping cumap, + float4 *data, + int size, + bool rgb_curve) { + float min_x = 0.0f, max_x = 1.0f; + /* TODO(sergey): Vector curve mapping is still clipping to 0..1. */ + if(rgb_curve) { + /* TODO(sergey): There is no easy way to automatically guess what is + * the range to be used here for the case when mapping is applied on + * top of another mapping (i.e. R curve applied on top of common + * one). + * + * Using largest possible range form all curves works correct for the + * cases like vector curves and should be good enough heuristic for + * the color curves as well. + * + * There might be some better estimations here tho. + */ + curvemapping_minmax(cumap, rgb_curve, &min_x, &max_x); + } + const float range_x = max_x - min_x; + cumap.update(); BL::CurveMap mapR = cumap.curves[0]; @@ -84,7 +128,7 @@ static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *d BL::CurveMap mapI = cumap.curves[3]; for(int i = 0; i < size; i++) { - float t = (float)i/(float)(size-1); + float t = min_x + (float)i/(float)(size-1) * range_x; data[i][0] = mapR.evaluate(mapI.evaluate(t)); data[i][1] = mapG.evaluate(mapI.evaluate(t)); @@ -93,7 +137,7 @@ static inline void curvemapping_color_to_array(BL::CurveMapping cumap, float4 *d } else { for(int i = 0; i < size; i++) { - float t = (float)i/(float)(size-1); + float t = min_x + (float)i/(float)(size-1) * range_x; data[i][0] = mapR.evaluate(t); data[i][1] = mapG.evaluate(t); diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index eea82b1f102..d9d6fd77ecb 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -304,8 +304,9 @@ public: } #endif - if(getenv("CYCLES_CUDA_EXTRA_CFLAGS")) { - command += string(" ") + getenv("CYCLES_CUDA_EXTRA_CFLAGS"); + const char* extra_cflags = getenv("CYCLES_CUDA_EXTRA_CFLAGS"); + if(extra_cflags) { + command += string(" ") + string(extra_cflags); } #ifdef WITH_CYCLES_DEBUG @@ -829,7 +830,7 @@ public: if(mem.data_type == TYPE_HALF) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, pmem.w, pmem.h, 0, GL_RGBA, GL_HALF_FLOAT, NULL); else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pmem.w, pmem.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, pmem.w, pmem.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/intern/cycles/kernel/geom/geom_qbvh.h b/intern/cycles/kernel/geom/geom_qbvh.h index 37deaac0800..2a2d7822eee 100644 --- a/intern/cycles/kernel/geom/geom_qbvh.h +++ b/intern/cycles/kernel/geom/geom_qbvh.h @@ -19,7 +19,7 @@ struct QBVHStackItem { float dist; }; -/* TOOD(sergey): Investigate if using instrinsics helps for both +/* TOOD(sergey): Investigate if using intrinsics helps for both * stack item swap and float comparison. */ ccl_device_inline void qbvh_item_swap(QBVHStackItem *__restrict a, diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index d37e593005c..5947945ccc6 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -382,7 +382,6 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, float3 D = ray->D; float t = isect->t; -#ifdef __INTERSECTION_REFINE__ if(isect->object != OBJECT_NONE) { #ifdef __OBJECT_MOTION__ Transform tfm = ccl_fetch(sd, ob_itfm); @@ -399,6 +398,7 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, P = P + D*t; +#ifdef __INTERSECTION_REFINE__ const float4 tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0), tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1), tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2); @@ -410,6 +410,7 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, float rt = dot(edge2, qvec) / dot(edge1, pvec); P = P + D*rt; +#endif /* __INTERSECTION_REFINE__ */ if(isect->object != OBJECT_NONE) { #ifdef __OBJECT_MOTION__ @@ -424,9 +425,6 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, } return P; -#else - return P + D*t; -#endif } #undef IDX diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index 2dc87fffcbc..29eca865384 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -339,6 +339,23 @@ ccl_device_inline void path_radiance_reset_indirect(PathRadiance *L) #endif } +ccl_device_inline void path_radiance_copy_indirect(PathRadiance *L, + const PathRadiance *L_src) +{ +#ifdef __PASSES__ + if(L->use_light_pass) { + L->path_diffuse = L_src->path_diffuse; + L->path_glossy = L_src->path_glossy; + L->path_transmission = L_src->path_transmission; + L->path_subsurface = L_src->path_subsurface; + L->path_scatter = L_src->path_scatter; + + L->direct_emission = L_src->direct_emission; + L->indirect = L_src->indirect; + } +#endif +} + ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadiance *L) { float3 L_sum; diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index 3efd7ecca5f..715c11c7ea0 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -65,6 +65,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian if((is_combined || is_sss_sample) && (sd->flag & SD_BSSRDF)) { /* when mixing BSSRDF and BSDF closures we should skip BSDF lighting if scattering was successful */ SubsurfaceIndirectRays ss_indirect; + kernel_path_subsurface_init_indirect(&ss_indirect); if(kernel_path_subsurface_scatter(kg, sd, &L_sample, @@ -77,10 +78,9 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian while(ss_indirect.num_rays) { kernel_path_subsurface_setup_indirect(kg, &ss_indirect, - &L_sample, &state, &ray, - &ray, + &L_sample, &throughput); kernel_path_indirect(kg, &rng, @@ -89,6 +89,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian state.num_samples, &state, &L_sample); + kernel_path_subsurface_accum_indirect(&ss_indirect, &L_sample); } is_sss_sample = true; } diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index de9e8d77ec8..3863cf221c5 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -99,23 +99,23 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, ShaderData *sd, return false; /* evaluate BSDF at shading point */ - float bsdf_pdf; #ifdef __VOLUME__ if(ccl_fetch(sd, prim) != PRIM_NONE) - shader_bsdf_eval(kg, sd, ls->D, eval, &bsdf_pdf); - else + shader_bsdf_eval(kg, sd, ls->D, eval, ls->pdf, ls->shader & SHADER_USE_MIS); + else { + float bsdf_pdf; shader_volume_phase_eval(kg, sd, ls->D, eval, &bsdf_pdf); + if(ls->shader & SHADER_USE_MIS) { + /* Multiple importance sampling. */ + float mis_weight = power_heuristic(ls->pdf, bsdf_pdf); + light_eval *= mis_weight; + } + } #else - shader_bsdf_eval(kg, sd, ls->D, eval, &bsdf_pdf); + shader_bsdf_eval(kg, sd, ls->D, eval, ls->pdf, ls->shader & SHADER_USE_MIS); #endif - if(ls->shader & SHADER_USE_MIS) { - /* multiple importance sampling */ - float mis_weight = power_heuristic(ls->pdf, bsdf_pdf); - light_eval *= mis_weight; - } - bsdf_eval_mul(eval, light_eval/ls->pdf); #ifdef __PASSES__ diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 885782f1a67..82cad788eb0 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -452,7 +452,7 @@ ccl_device bool kernel_path_subsurface_scatter( * the second one should be converted to a diffuse BSDF to * avoid this. */ - kernel_assert(ss_indirect->num_rays == 0); + kernel_assert(!ss_indirect->tracing); uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb); @@ -485,9 +485,10 @@ ccl_device bool kernel_path_subsurface_scatter( sc, false); - PathState *hit_state = &ss_indirect->state; + PathState *hit_state = &ss_indirect->state[ss_indirect->num_rays]; Ray *hit_ray = &ss_indirect->rays[ss_indirect->num_rays]; float3 *hit_tp = &ss_indirect->throughputs[ss_indirect->num_rays]; + PathRadiance *hit_L = &ss_indirect->L[ss_indirect->num_rays]; *hit_state = *state; *hit_ray = *ray; @@ -495,67 +496,97 @@ ccl_device bool kernel_path_subsurface_scatter( hit_state->rng_offset += PRNG_BOUNCE_NUM; - kernel_path_surface_connect_light(kg, rng, sd, *hit_tp, state, L); + path_radiance_init(hit_L, kernel_data.film.use_light_pass); + hit_L->direct_throughput = L->direct_throughput; + path_radiance_copy_indirect(hit_L, L); + + kernel_path_surface_connect_light(kg, rng, sd, *hit_tp, state, hit_L); if(kernel_path_surface_bounce(kg, rng, sd, hit_tp, hit_state, - L, + hit_L, hit_ray)) { #ifdef __LAMP_MIS__ hit_state->ray_t = 0.0f; #endif + +#ifdef __VOLUME__ + if(ss_indirect->need_update_volume_stack) { + Ray volume_ray = *ray; + /* Setup ray from previous surface point to the new one. */ + volume_ray.D = normalize_len(hit_ray->P - volume_ray.P, + &volume_ray.t); + + kernel_volume_stack_update_for_subsurface( + kg, + &volume_ray, + hit_state->volume_stack); + } +#endif + path_radiance_reset_indirect(L); ss_indirect->num_rays++; } + else { + path_radiance_accum_sample(L, hit_L, 1); + } } return true; } return false; } +ccl_device_inline void kernel_path_subsurface_init_indirect( + SubsurfaceIndirectRays *ss_indirect) +{ + ss_indirect->tracing = false; + ss_indirect->num_rays = 0; +} + +ccl_device void kernel_path_subsurface_accum_indirect( + SubsurfaceIndirectRays *ss_indirect, + PathRadiance *L) +{ + if(ss_indirect->tracing) { + path_radiance_sum_indirect(L); + path_radiance_accum_sample(&ss_indirect->direct_L, L, 1); + if(ss_indirect->num_rays == 0) { + *L = ss_indirect->direct_L; + } + } +} + ccl_device void kernel_path_subsurface_setup_indirect( KernelGlobals *kg, SubsurfaceIndirectRays *ss_indirect, - PathRadiance *L, PathState *state, - Ray *orig_ray, Ray *ray, + PathRadiance *L, float3 *throughput) { + if(!ss_indirect->tracing) { + ss_indirect->direct_L = *L; + } + ss_indirect->tracing = true; + /* Setup state, ray and throughput for indirect SSS rays. */ ss_indirect->num_rays--; Ray *indirect_ray = &ss_indirect->rays[ss_indirect->num_rays]; + PathRadiance *indirect_L = &ss_indirect->L[ss_indirect->num_rays]; - *state = ss_indirect->state; - *throughput = ss_indirect->throughputs[ss_indirect->num_rays]; - -#ifdef __VOLUME__ - if(ss_indirect->need_update_volume_stack) { - Ray volume_ray = *orig_ray; - - /* Setup ray from previous surface point to the new one. */ - volume_ray.D = normalize_len(indirect_ray->P - volume_ray.P, - &volume_ray.t); - - kernel_volume_stack_update_for_subsurface(kg, - &volume_ray, - state->volume_stack); - } -#endif - + *state = ss_indirect->state[ss_indirect->num_rays]; *ray = *indirect_ray; + *L = *indirect_L; + *throughput = ss_indirect->throughputs[ss_indirect->num_rays]; - /* For render passes, sum and reset indirect light pass variables - * for the next samples. - */ - path_radiance_sum_indirect(L); - path_radiance_reset_indirect(L); + state->rng_offset += ss_indirect->num_rays * PRNG_BOUNCE_NUM; } -#endif + +#endif /* __SUBSURFACE__ */ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, ccl_global float *buffer) { @@ -576,13 +607,7 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, #ifdef __SUBSURFACE__ SubsurfaceIndirectRays ss_indirect; - ss_indirect.num_rays = 0; - - /* TODO(sergey): Avoid having explicit copy of the pre-subsurface scatter - * ray by storing an updated version of state in the ss_indirect which will - * be updated to the new volume stack. - */ - Ray ss_orig_ray; + kernel_path_subsurface_init_indirect(&ss_indirect); for(;;) { #endif @@ -833,11 +858,10 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, &throughput, &ss_indirect)) { - ss_orig_ray = ray; break; } } -#endif +#endif /* __SUBSURFACE__ */ /* direct lighting */ kernel_path_surface_connect_light(kg, rng, &sd, throughput, &state, &L); @@ -848,23 +872,24 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, } #ifdef __SUBSURFACE__ + kernel_path_subsurface_accum_indirect(&ss_indirect, &L); + /* Trace indirect subsurface rays by restarting the loop. this uses less * stack memory than invoking kernel_path_indirect. */ if(ss_indirect.num_rays) { kernel_path_subsurface_setup_indirect(kg, &ss_indirect, - &L, &state, - &ss_orig_ray, &ray, + &L, &throughput); } else { break; } } -#endif +#endif /* __SUBSURFACE__ */ float3 L_sum = path_radiance_clamp_and_sum(kg, &L); diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 6b560f5fdb2..25e5822a21b 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -516,12 +516,52 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa *pdf = (sum_sample_weight > 0.0f)? sum_pdf/sum_sample_weight: 0.0f; } -ccl_device void shader_bsdf_eval(KernelGlobals *kg, ShaderData *sd, - const float3 omega_in, BsdfEval *eval, float *pdf) +#ifdef __BRANCHED_PATH__ +ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg, + const ShaderData *sd, + const float3 omega_in, + BsdfEval *result_eval, + float light_pdf, + bool use_mis) +{ + for(int i = 0; i < ccl_fetch(sd, num_closure); i++) { + const ShaderClosure *sc = ccl_fetch_array(sd, closure, i); + if(CLOSURE_IS_BSDF(sc->type)) { + float bsdf_pdf = 0.0f; + float3 eval = bsdf_eval(kg, sd, sc, omega_in, &bsdf_pdf); + if(bsdf_pdf != 0.0f) { + float mis_weight = use_mis? power_heuristic(light_pdf, bsdf_pdf): 1.0f; + bsdf_eval_accum(result_eval, + sc->type, + eval * sc->weight * mis_weight); + } + } + } +} +#endif + +ccl_device void shader_bsdf_eval(KernelGlobals *kg, + ShaderData *sd, + const float3 omega_in, + BsdfEval *eval, + float light_pdf, + bool use_mis) { bsdf_eval_init(eval, NBUILTIN_CLOSURES, make_float3(0.0f, 0.0f, 0.0f), kernel_data.film.use_light_pass); - _shader_bsdf_multi_eval(kg, sd, omega_in, pdf, -1, eval, 0.0f, 0.0f); +#ifdef __BRANCHED_PATH__ + if(kernel_data.integrator.branched) + _shader_bsdf_multi_eval_branched(kg, sd, omega_in, eval, light_pdf, use_mis); + else +#endif + { + float pdf; + _shader_bsdf_multi_eval(kg, sd, omega_in, &pdf, -1, eval, 0.0f, 0.0f); + if(use_mis) { + float weight = power_heuristic(light_pdf, pdf); + bsdf_eval_mul(eval, make_float3(weight, weight, weight)); + } + } } ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd, diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index b9928561791..27a341aa37a 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -288,14 +288,14 @@ ccl_device int subsurface_scatter_multi_intersect( sd->object, lcg_state, BSSRDF_MAX_HITS); - /* TODO(sergey): Investigate whether scene_intersect_subsurface() could - * indeed return more than BSSRDF_MAX_HITS hits. - */ int num_eval_hits = min(ss_isect->num_hits, BSSRDF_MAX_HITS); for(int hit = 0; hit < num_eval_hits; hit++) { /* Quickly retrieve P and Ng without setting up ShaderData. */ - float3 hit_P = ray->P + ss_isect->hits[hit].t * ray->D; + float3 hit_P = triangle_refine_subsurface(kg, + sd, + &ss_isect->hits[hit], + ray); float3 hit_Ng = ss_isect->Ng[hit]; if(ss_isect->hits[hit].object != OBJECT_NONE) { object_normal_transform(kg, sd, &hit_Ng); diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index bef00355c5e..04d013ceb9c 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -761,7 +761,7 @@ struct SubsurfaceIntersection float3 weight[BSSRDF_MAX_HITS]; int num_hits; - Intersection hits[BSSRDF_MAX_HITS]; + struct Intersection hits[BSSRDF_MAX_HITS]; float3 Ng[BSSRDF_MAX_HITS]; }; @@ -769,11 +769,14 @@ struct SubsurfaceIntersection struct SubsurfaceIndirectRays { bool need_update_volume_stack; - PathState state; + bool tracing; + PathState state[BSSRDF_MAX_HITS]; + struct PathRadiance direct_L; int num_rays; - Ray rays[BSSRDF_MAX_HITS]; + struct Ray rays[BSSRDF_MAX_HITS]; float3 throughputs[BSSRDF_MAX_HITS]; + struct PathRadiance L[BSSRDF_MAX_HITS]; }; /* Constant Kernel Data diff --git a/intern/cycles/kernel/kernels/cuda/kernel.cu b/intern/cycles/kernel/kernels/cuda/kernel.cu index bcd55b8c676..3929b676f07 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel.cu +++ b/intern/cycles/kernel/kernels/cuda/kernel.cu @@ -65,8 +65,8 @@ #define CUDA_KERNEL_MAX_REGISTERS 63 #define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63 -/* 5.0 and 5.2 */ -#elif __CUDA_ARCH__ == 500 || __CUDA_ARCH__ == 520 +/* 5.0, 5.2 and 5.3 */ +#elif __CUDA_ARCH__ == 500 || __CUDA_ARCH__ == 520 || __CUDA_ARCH__ == 530 #define CUDA_MULTIPRESSOR_MAX_REGISTERS 65536 #define CUDA_MULTIPROCESSOR_MAX_BLOCKS 32 #define CUDA_BLOCK_MAX_THREADS 1024 diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 81931463cad..568ea566bc8 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -102,7 +102,7 @@ foreach(_file ${SRC_OSL}) string(REPLACE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} _OSO_FILE ${_OSO_FILE}) add_custom_command( OUTPUT ${_OSO_FILE} - COMMAND ${OSL_COMPILER} -q -O2 -I"${CMAKE_CURRENT_SOURCE_DIR}" ${_OSL_FILE} + COMMAND ${OSL_COMPILER} -q -O2 -I"${CMAKE_CURRENT_SOURCE_DIR}" -o ${_OSO_FILE} ${_OSL_FILE} DEPENDS ${_OSL_FILE} ${SRC_OSL_HEADERS}) list(APPEND SRC_OSO ${_OSO_FILE} diff --git a/intern/cycles/kernel/shaders/node_rgb_curves.osl b/intern/cycles/kernel/shaders/node_rgb_curves.osl index 60cb273ba98..0427c001f6d 100644 --- a/intern/cycles/kernel/shaders/node_rgb_curves.osl +++ b/intern/cycles/kernel/shaders/node_rgb_curves.osl @@ -19,6 +19,21 @@ float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component) { + if (at < 0.0 || at > 1.0) { + float t0, dy; + if(at < 0.0) { + t0 = ramp[0][component]; + dy = t0 - ramp[1][component]; + at = -at; + } + else { + t0 = ramp[RAMP_TABLE_SIZE - 1][component]; + dy = t0 - ramp[RAMP_TABLE_SIZE - 2][component]; + at = at - 1.0; + } + return t0 + dy * at * (RAMP_TABLE_SIZE - 1); + } + float f = clamp(at, 0.0, 1.0) * (RAMP_TABLE_SIZE - 1); /* clamp int as well in case of NaN */ @@ -37,14 +52,18 @@ float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component) shader node_rgb_curves( color ramp[RAMP_TABLE_SIZE] = {0.0}, + float min_x = 0.0, + float max_x = 1.0, color ColorIn = 0.0, float Fac = 0.0, output color ColorOut = 0.0) { - ColorOut[0] = ramp_lookup(ramp, ColorIn[0], 0); - ColorOut[1] = ramp_lookup(ramp, ColorIn[1], 1); - ColorOut[2] = ramp_lookup(ramp, ColorIn[2], 2); + color c = (ColorIn - color(min_x, min_x, min_x)) / (max_x - min_x); + + ColorOut[0] = ramp_lookup(ramp, c[0], 0); + ColorOut[1] = ramp_lookup(ramp, c[1], 1); + ColorOut[2] = ramp_lookup(ramp, c[2], 2); ColorOut = mix(ColorIn, ColorOut, Fac); } diff --git a/intern/cycles/kernel/svm/svm_ramp.h b/intern/cycles/kernel/svm/svm_ramp.h index 062ab013b1f..48d969947f5 100644 --- a/intern/cycles/kernel/svm/svm_ramp.h +++ b/intern/cycles/kernel/svm/svm_ramp.h @@ -19,8 +19,27 @@ CCL_NAMESPACE_BEGIN -ccl_device float4 rgb_ramp_lookup(KernelGlobals *kg, int offset, float f, bool interpolate) +ccl_device float4 rgb_ramp_lookup(KernelGlobals *kg, + int offset, + float f, + bool interpolate, + bool extrapolate) { + if((f < 0.0f || f > 1.0f) && extrapolate) { + float4 t0, dy; + if(f < 0.0f) { + t0 = fetch_node_float(kg, offset); + dy = t0 - fetch_node_float(kg, offset + 1); + f = -f; + } + else { + t0 = fetch_node_float(kg, offset + RAMP_TABLE_SIZE - 1); + dy = t0 - fetch_node_float(kg, offset + RAMP_TABLE_SIZE - 2); + f = f - 1.0f; + } + return t0 + dy * f * (RAMP_TABLE_SIZE-1); + } + f = saturate(f)*(RAMP_TABLE_SIZE-1); /* clamp int as well in case of NaN */ @@ -43,7 +62,7 @@ ccl_device void svm_node_rgb_ramp(KernelGlobals *kg, ShaderData *sd, float *stac decode_node_uchar4(node.y, &fac_offset, &color_offset, &alpha_offset, NULL); float fac = stack_load_float(stack, fac_offset); - float4 color = rgb_ramp_lookup(kg, *offset, fac, interpolate); + float4 color = rgb_ramp_lookup(kg, *offset, fac, interpolate, false); if(stack_valid(color_offset)) stack_store_float3(stack, color_offset, float4_to_float3(color)); @@ -55,16 +74,24 @@ ccl_device void svm_node_rgb_ramp(KernelGlobals *kg, ShaderData *sd, float *stac ccl_device void svm_node_rgb_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) { - uint fac_offset = node.y; - uint color_offset = node.z; - uint out_offset = node.w; + uint fac_offset, color_offset, out_offset; + decode_node_uchar4(node.y, + &fac_offset, + &color_offset, + &out_offset, + NULL); float fac = stack_load_float(stack, fac_offset); float3 color = stack_load_float3(stack, color_offset); - float r = rgb_ramp_lookup(kg, *offset, color.x, true).x; - float g = rgb_ramp_lookup(kg, *offset, color.y, true).y; - float b = rgb_ramp_lookup(kg, *offset, color.z, true).z; + const float min_x = __int_as_float(node.z), + max_x = __int_as_float(node.w); + const float range_x = max_x - min_x; + color = (color - make_float3(min_x, min_x, min_x)) / range_x; + + float r = rgb_ramp_lookup(kg, *offset, color.x, true, true).x; + float g = rgb_ramp_lookup(kg, *offset, color.y, true, true).y; + float b = rgb_ramp_lookup(kg, *offset, color.z, true, true).z; color = (1.0f - fac)*color + fac*make_float3(r, g, b); stack_store_float3(stack, out_offset, color); @@ -81,9 +108,9 @@ ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float float fac = stack_load_float(stack, fac_offset); float3 color = stack_load_float3(stack, color_offset); - float r = rgb_ramp_lookup(kg, *offset, (color.x + 1.0f)*0.5f, true).x; - float g = rgb_ramp_lookup(kg, *offset, (color.y + 1.0f)*0.5f, true).y; - float b = rgb_ramp_lookup(kg, *offset, (color.z + 1.0f)*0.5f, true).z; + float r = rgb_ramp_lookup(kg, *offset, (color.x + 1.0f)*0.5f, true, false).x; + float g = rgb_ramp_lookup(kg, *offset, (color.y + 1.0f)*0.5f, true, false).y; + float b = rgb_ramp_lookup(kg, *offset, (color.z + 1.0f)*0.5f, true, false).z; color = (1.0f - fac)*color + fac*make_float3(r*2.0f - 1.0f, g*2.0f - 1.0f, b*2.0f - 1.0f); stack_store_float3(stack, out_offset, color); diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index e888cb37137..def43876ada 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -22,9 +22,37 @@ #include "util_algorithm.h" #include "util_debug.h" #include "util_foreach.h" +#include "util_queue.h" CCL_NAMESPACE_BEGIN +namespace { + +bool check_node_inputs_has_links(const ShaderNode *node) +{ + foreach(const ShaderInput *in, node->inputs) { + if(in->link) { + return true; + } + } + return false; +} + +bool check_node_inputs_traversed(const ShaderNode *node, + const ShaderNodeSet& done) +{ + foreach(const ShaderInput *in, node->inputs) { + if(in->link) { + if(done.find(in->link->parent) == done.end()) { + return false; + } + } + } + return true; +} + +} /* namespace */ + /* Input and Output */ ShaderInput::ShaderInput(ShaderNode *parent_, const char *name_, ShaderSocketType type_) @@ -297,7 +325,7 @@ void ShaderGraph::finalize(Scene *scene, finalized = true; } else if(do_simplify) { - simplify_nodes(scene); + simplify_settings(scene); } } @@ -562,11 +590,64 @@ void ShaderGraph::remove_unneeded_nodes() } } +/* Step 2: Constant folding. + * Try to constant fold some nodes, and pipe result directly to + * the input socket of connected nodes. + */ +void ShaderGraph::constant_fold() +{ + ShaderNodeSet done, scheduled; + queue<ShaderNode*> traverse_queue; + + /* Schedule nodes which doesn't have any dependencies. */ + foreach(ShaderNode *node, nodes) { + if(!check_node_inputs_has_links(node)) { + traverse_queue.push(node); + scheduled.insert(node); + } + } + + while(!traverse_queue.empty()) { + ShaderNode *node = traverse_queue.front(); + traverse_queue.pop(); + done.insert(node); + foreach(ShaderOutput *output, node->outputs) { + /* Schedule node which was depending on the value, + * when possible. Do it before disconnect. + */ + foreach(ShaderInput *input, output->links) { + if(scheduled.find(input->parent) != scheduled.end()) { + /* Node might not be optimized yet but scheduled already + * by other dependencies. No need to re-schedule it. + */ + continue; + } + /* Schedule node if its inputs are fully done. */ + if(check_node_inputs_traversed(input->parent, done)) { + traverse_queue.push(input->parent); + scheduled.insert(input->parent); + } + } + /* Optimize current node. */ + float3 optimized_value = make_float3(0.0f, 0.0f, 0.0f); + if(node->constant_fold(output, &optimized_value)) { + /* Apply optimized value to connected sockets. */ + vector<ShaderInput*> links(output->links); + foreach(ShaderInput *input, links) { + /* Assign value and disconnect the optimizedinput. */ + input->value = optimized_value; + disconnect(input); + } + } + } + } +} + /* Step 3: Simplification.*/ -void ShaderGraph::simplify_nodes(Scene *scene) +void ShaderGraph::simplify_settings(Scene *scene) { foreach(ShaderNode *node, nodes) { - node->optimize(scene); + node->simplify_settings(scene); } } @@ -597,7 +678,7 @@ void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<b void ShaderGraph::clean(Scene *scene) { /* Graph simplification: - * 1: Remove unnecesarry nodes + * 1: Remove unnecessary nodes * 2: Constant folding * 3: Simplification * 4: De-duplication @@ -607,10 +688,10 @@ void ShaderGraph::clean(Scene *scene) remove_unneeded_nodes(); /* 2: Constant folding. */ - /* TODO(dingto): Implement */ + constant_fold(); /* 3: Simplification. */ - simplify_nodes(scene); + simplify_settings(scene); /* 4: De-duplication. */ /* TODO(dingto): Implement */ diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index 6ad40720d4c..420648f6425 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -197,7 +197,15 @@ public: virtual void attributes(Shader *shader, AttributeRequestSet *attributes); virtual void compile(SVMCompiler& compiler) = 0; virtual void compile(OSLCompiler& compiler) = 0; - virtual void optimize(Scene * /*scene*/) {}; + + /* ** Node optimization ** */ + /* Check whether the node can be replaced with single constant. */ + virtual bool constant_fold(ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; } + + /* Simplify settings used by artists to the ones which are simpler to + * evaluate in the kernel but keep the final result unchanged. + */ + virtual void simplify_settings(Scene * /*scene*/) {}; virtual bool has_surface_emission() { return false; } virtual bool has_surface_transparent() { return false; } @@ -307,7 +315,8 @@ protected: void break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack); void clean(Scene *scene); - void simplify_nodes(Scene *scene); + void simplify_settings(Scene *scene); + void constant_fold(); void bump_from_displacement(); void refine_bump_nodes(); void default_inputs(bool do_osl); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index d89e74837c7..22eb3f239e6 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1881,7 +1881,7 @@ GlossyBsdfNode::GlossyBsdfNode() add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f); } -void GlossyBsdfNode::optimize(Scene *scene) +void GlossyBsdfNode::simplify_settings(Scene *scene) { if(distribution_orig == "") { distribution_orig = distribution; @@ -1950,7 +1950,7 @@ GlassBsdfNode::GlassBsdfNode() add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f); } -void GlassBsdfNode::optimize(Scene *scene) +void GlassBsdfNode::simplify_settings(Scene *scene) { if(distribution_orig == "") { distribution_orig = distribution; @@ -2019,7 +2019,7 @@ RefractionBsdfNode::RefractionBsdfNode() add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f); } -void RefractionBsdfNode::optimize(Scene *scene) +void RefractionBsdfNode::simplify_settings(Scene *scene) { if(distribution_orig == "") { distribution_orig = distribution; @@ -3177,6 +3177,13 @@ ValueNode::ValueNode() add_output("Value", SHADER_SOCKET_FLOAT); } +bool ValueNode::constant_fold(ShaderOutput * /*socket*/, + float3 *optimized_value) +{ + *optimized_value = make_float3(value, value, value); + return true; +} + void ValueNode::compile(SVMCompiler& compiler) { ShaderOutput *val_out = output("Value"); @@ -3201,6 +3208,13 @@ ColorNode::ColorNode() add_output("Color", SHADER_SOCKET_COLOR); } +bool ColorNode::constant_fold(ShaderOutput * /*socket*/, + float3 *optimized_value) +{ + *optimized_value = value; + return true; +} + void ColorNode::compile(SVMCompiler& compiler) { ShaderOutput *color_out = output("Color"); @@ -3955,6 +3969,21 @@ BlackbodyNode::BlackbodyNode() add_output("Color", SHADER_SOCKET_COLOR); } +bool BlackbodyNode::constant_fold(ShaderOutput *socket, float3 *optimized_value) +{ + ShaderInput *temperature_in = input("Temperature"); + + if(socket == output("Color")) { + if(temperature_in->link == NULL) { + *optimized_value = svm_math_blackbody_color(temperature_in->value.x); + + return true; + } + } + + return false; +} + void BlackbodyNode::compile(SVMCompiler& compiler) { ShaderInput *temperature_in = input("Temperature"); @@ -3962,15 +3991,8 @@ void BlackbodyNode::compile(SVMCompiler& compiler) compiler.stack_assign(color_out); - if(temperature_in->link == NULL) { - float3 color = svm_math_blackbody_color(temperature_in->value.x); - compiler.add_node(NODE_VALUE_V, color_out->stack_offset); - compiler.add_node(NODE_VALUE_V, color); - } - else { - compiler.stack_assign(temperature_in); - compiler.add_node(NODE_BLACKBODY, temperature_in->stack_offset, color_out->stack_offset); - } + compiler.stack_assign(temperature_in); + compiler.add_node(NODE_BLACKBODY, temperature_in->stack_offset, color_out->stack_offset); } void BlackbodyNode::compile(OSLCompiler& compiler) @@ -4054,28 +4076,36 @@ static ShaderEnum math_type_init() ShaderEnum MathNode::type_enum = math_type_init(); -void MathNode::compile(SVMCompiler& compiler) +bool MathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value) { ShaderInput *value1_in = input("Value1"); ShaderInput *value2_in = input("Value2"); - ShaderOutput *value_out = output("Value"); - compiler.stack_assign(value_out); + if(socket == output("Value")) { + /* Optimize math node without links to a single value. */ + if(value1_in->link == NULL && value2_in->link == NULL) { + optimized_value->x = svm_math((NodeMath)type_enum[type], + value1_in->value.x, + value2_in->value.x); - /* Optimize math node without links to a single value node. */ - if(value1_in->link == NULL && value2_in->link == NULL) { - float optimized_value = svm_math((NodeMath)type_enum[type], - value1_in->value.x, - value2_in->value.x); - if(use_clamp) { - optimized_value = saturate(optimized_value); + if(use_clamp) { + optimized_value->x = saturate(optimized_value->x); + } + + return true; } - compiler.add_node(NODE_VALUE_F, - __float_as_int(optimized_value), - value_out->stack_offset); - return; } + return false; +} + +void MathNode::compile(SVMCompiler& compiler) +{ + ShaderInput *value1_in = input("Value1"); + ShaderInput *value2_in = input("Value2"); + ShaderOutput *value_out = output("Value"); + + compiler.stack_assign(value_out); compiler.stack_assign(value1_in); compiler.stack_assign(value2_in); @@ -4124,6 +4154,35 @@ static ShaderEnum vector_math_type_init() ShaderEnum VectorMathNode::type_enum = vector_math_type_init(); +bool VectorMathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value) +{ + ShaderInput *vector1_in = input("Vector1"); + ShaderInput *vector2_in = input("Vector2"); + + float value; + float3 vector; + + /* Optimize vector math node without links to a single value node. */ + if(vector1_in->link == NULL && vector2_in->link == NULL) { + svm_vector_math(&value, + &vector, + (NodeVectorMath)type_enum[type], + vector1_in->value, + vector2_in->value); + + if(socket == output("Value")) { + optimized_value->x = value; + return true; + } + else if(socket == output("Vector")) { + *optimized_value = vector; + return true; + } + } + + return false; +} + void VectorMathNode::compile(SVMCompiler& compiler) { ShaderInput *vector1_in = input("Vector1"); @@ -4134,25 +4193,6 @@ void VectorMathNode::compile(SVMCompiler& compiler) compiler.stack_assign(value_out); compiler.stack_assign(vector_out); - /* Optimize vector math node without links to a single value node. */ - if(vector1_in->link == NULL && vector2_in->link == NULL) { - float optimized_value; - float3 optimized_vector; - svm_vector_math(&optimized_value, - &optimized_vector, - (NodeVectorMath)type_enum[type], - vector1_in->value, - vector2_in->value); - - compiler.add_node(NODE_VALUE_F, - __float_as_int(optimized_value), - value_out->stack_offset); - - compiler.add_node(NODE_VALUE_V, vector_out->stack_offset); - compiler.add_node(NODE_VALUE_V, optimized_vector); - return; - } - compiler.stack_assign(vector1_in); compiler.stack_assign(vector2_in); @@ -4290,6 +4330,9 @@ RGBCurvesNode::RGBCurvesNode() add_input("Fac", SHADER_SOCKET_FLOAT); add_input("Color", SHADER_SOCKET_COLOR); add_output("Color", SHADER_SOCKET_COLOR); + + min_x = 0.0f; + max_x = 1.0f; } void RGBCurvesNode::compile(SVMCompiler& compiler) @@ -4302,7 +4345,12 @@ void RGBCurvesNode::compile(SVMCompiler& compiler) compiler.stack_assign(color_in); compiler.stack_assign(color_out); - compiler.add_node(NODE_RGB_CURVES, fac_in->stack_offset, color_in->stack_offset, color_out->stack_offset); + compiler.add_node(NODE_RGB_CURVES, + compiler.encode_uchar4(fac_in->stack_offset, + color_in->stack_offset, + color_out->stack_offset), + __float_as_int(min_x), + __float_as_int(max_x)); compiler.add_array(curves, RAMP_TABLE_SIZE); } @@ -4317,6 +4365,8 @@ void RGBCurvesNode::compile(OSLCompiler& compiler) } compiler.parameter_color_array("ramp", ramp, RAMP_TABLE_SIZE); + compiler.parameter("min_x", min_x); + compiler.parameter("max_x", max_x); compiler.add(this, "node_rgb_curves"); } @@ -4452,6 +4502,7 @@ void OSLScriptNode::compile(SVMCompiler& /*compiler*/) void OSLScriptNode::compile(OSLCompiler& compiler) { +#if defined(WITH_OSL) && (OSL_LIBRARY_VERSION_CODE < 10701) /* XXX fix for #36790: * point and normal parameters are reflected as generic SOCK_VECTOR sockets * on the node. Socket fixed input values need to be copied explicitly here for @@ -4471,6 +4522,7 @@ void OSLScriptNode::compile(OSLCompiler& compiler) } } } +#endif if(!filepath.empty()) compiler.add(this, filepath.c_str(), true); diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 4f4061286cb..51efbc37f38 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -311,7 +311,7 @@ class GlossyBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(GlossyBsdfNode) - void optimize(Scene *scene); + void simplify_settings(Scene *scene); bool has_integrator_dependency(); ustring distribution, distribution_orig; @@ -322,7 +322,7 @@ class GlassBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(GlassBsdfNode) - void optimize(Scene *scene); + void simplify_settings(Scene *scene); bool has_integrator_dependency(); ustring distribution, distribution_orig; @@ -333,7 +333,7 @@ class RefractionBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(RefractionBsdfNode) - void optimize(Scene *scene); + void simplify_settings(Scene *scene); bool has_integrator_dependency(); ustring distribution, distribution_orig; @@ -485,6 +485,8 @@ class ValueNode : public ShaderNode { public: SHADER_NODE_CLASS(ValueNode) + bool constant_fold(ShaderOutput *socket, float3 *optimized_value); + float value; }; @@ -492,6 +494,8 @@ class ColorNode : public ShaderNode { public: SHADER_NODE_CLASS(ColorNode) + bool constant_fold(ShaderOutput *socket, float3 *optimized_value); + float3 value; }; @@ -636,6 +640,7 @@ public: class BlackbodyNode : public ShaderNode { public: SHADER_NODE_CLASS(BlackbodyNode) + bool constant_fold(ShaderOutput *socket, float3 *optimized_value); virtual int get_group() { return NODE_GROUP_LEVEL_3; } }; @@ -644,6 +649,7 @@ class MathNode : public ShaderNode { public: SHADER_NODE_CLASS(MathNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } + bool constant_fold(ShaderOutput *socket, float3 *optimized_value); bool use_clamp; @@ -663,6 +669,7 @@ class VectorMathNode : public ShaderNode { public: SHADER_NODE_CLASS(VectorMathNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } + bool constant_fold(ShaderOutput *socket, float3 *optimized_value); ustring type; static ShaderEnum type_enum; @@ -700,6 +707,7 @@ public: virtual int get_group() { return NODE_GROUP_LEVEL_3; } float4 curves[RAMP_TABLE_SIZE]; + float min_x, max_x; }; class VectorCurvesNode : public ShaderNode { diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 851e5ac0b72..a1ff6809f67 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -126,7 +126,6 @@ class SceneParams { public: ShadingSystem shadingsystem; enum BVHType { BVH_DYNAMIC, BVH_STATIC } bvh_type; - bool use_bvh_cache; bool use_bvh_spatial_split; bool use_qbvh; bool persistent_data; @@ -135,7 +134,6 @@ public: { shadingsystem = SHADINGSYSTEM_SVM; bvh_type = BVH_DYNAMIC; - use_bvh_cache = false; use_bvh_spatial_split = false; use_qbvh = false; persistent_data = false; @@ -144,7 +142,6 @@ public: bool modified(const SceneParams& params) { return !(shadingsystem == params.shadingsystem && 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 && persistent_data == params.persistent_data); } diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index a4c7e7ef969..b8a5b4d44e0 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -528,9 +528,11 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node, find_dependencies(cl1deps, done, cl1in); find_dependencies(cl2deps, done, cl2in); + ShaderNodeIDComparator node_id_comp; set_intersection(cl1deps.begin(), cl1deps.end(), cl2deps.begin(), cl2deps.end(), - std::inserter(shareddeps, shareddeps.begin())); + std::inserter(shareddeps, shareddeps.begin()), + node_id_comp); /* it's possible some nodes are not shared between this mix node * inputs, but still needed to be always executed, this mainly @@ -542,10 +544,12 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node, find_dependencies(rootdeps, done, in, node); set_intersection(rootdeps.begin(), rootdeps.end(), cl1deps.begin(), cl1deps.end(), - std::inserter(shareddeps, shareddeps.begin())); + std::inserter(shareddeps, shareddeps.begin()), + node_id_comp); set_intersection(rootdeps.begin(), rootdeps.end(), cl2deps.begin(), cl2deps.end(), - std::inserter(shareddeps, shareddeps.begin())); + std::inserter(shareddeps, shareddeps.begin()), + node_id_comp); } } diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index e103cfa4eee..47ac2800d6d 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -58,6 +58,7 @@ set(SRC_HEADERS util_param.h util_path.h util_progress.h + util_queue.h util_set.h util_simd.h util_sseb.h diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 7d6dfd34e0e..4a676d0d7b5 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -351,7 +351,7 @@ ccl_device_inline float2 normalize_len(const float2 a, float *t) ccl_device_inline float2 safe_normalize(const float2 a) { float t = len(a); - return (t)? a/t: a; + return (t != 0.0f)? a/t: a; } ccl_device_inline bool operator==(const float2 a, const float2 b) @@ -553,7 +553,7 @@ ccl_device_inline float3 normalize_len(const float3 a, float *t) ccl_device_inline float3 safe_normalize(const float3 a) { float t = len(a); - return (t)? a/t: a; + return (t != 0.0f)? a/t: a; } #ifndef __KERNEL_OPENCL__ @@ -866,7 +866,7 @@ ccl_device_inline float4 normalize(const float4 a) ccl_device_inline float4 safe_normalize(const float4 a) { float t = len(a); - return (t)? a/t: a; + return (t != 0.0f)? a/t: a; } ccl_device_inline float4 min(float4 a, float4 b) diff --git a/intern/cycles/util/util_math_fast.h b/intern/cycles/util/util_math_fast.h index 867de78e7a6..efe0698e1dc 100644 --- a/intern/cycles/util/util_math_fast.h +++ b/intern/cycles/util/util_math_fast.h @@ -247,7 +247,7 @@ ccl_device float fast_sinpif(float x) * The basic idea of this approximation starts with the coarse approximation: * sin(pi*x) ~= f(x) = 4 * (x - x * abs(x)) * - * This approximation always _over_ estimates the target. On the otherhand, + * This approximation always _over_ estimates the target. On the other hand, * the curve: * sin(pi*x) ~= f(x) * abs(f(x)) / 4 * diff --git a/intern/cycles/util/util_queue.h b/intern/cycles/util/util_queue.h new file mode 100644 index 00000000000..f4c802785f9 --- /dev/null +++ b/intern/cycles/util/util_queue.h @@ -0,0 +1,29 @@ +/* + * Copyright 2011-2015 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UTIL_QUEUE_H__ +#define __UTIL_QUEUE_H__ + +#include <queue> + +CCL_NAMESPACE_BEGIN + +using std::queue; + +CCL_NAMESPACE_END + +#endif /* __UTIL_LIST_H__ */ + diff --git a/extern/Eigen3/CMakeLists.txt b/intern/eigen/CMakeLists.txt index e3b63881aca..5811b71de94 100644 --- a/extern/Eigen3/CMakeLists.txt +++ b/intern/eigen/CMakeLists.txt @@ -28,16 +28,19 @@ set(INC ) set(INC_SYS + ${EIGEN3_INCLUDE_DIRS} ) set(SRC - eigen3_capi.h + eigen_capi.h intern/eigenvalues.cc + intern/linear_solver.cc intern/svd.cc intern/eigenvalues.h + intern/linear_solver.h intern/svd.h ) -blender_add_lib(extern_eigen3 "${SRC}" "${INC}" "${INC_SYS}") +blender_add_lib(bf_intern_eigen "${SRC}" "${INC}" "${INC_SYS}") diff --git a/extern/Eigen3/SConscript b/intern/eigen/SConscript index 2dc2d623768..0c98ec1837d 100644 --- a/extern/Eigen3/SConscript +++ b/intern/eigen/SConscript @@ -29,7 +29,7 @@ Import('env') sources = env.Glob('intern/*.cc') -incs = '.' +incs = '. #/extern/Eigen3' defs = [] -env.BlenderLib('extern_eigen3', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185]) +env.BlenderLib('bf_intern_eigen', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185]) diff --git a/extern/Eigen3/eigen3_capi.h b/intern/eigen/eigen_capi.h index f8a7b3cbb77..be42e340274 100644 --- a/extern/Eigen3/eigen3_capi.h +++ b/intern/eigen/eigen_capi.h @@ -24,10 +24,11 @@ * ***** END GPL LICENSE BLOCK ***** */ -#ifndef __EIGEN3_C_API_H__ -#define __EIGEN3_C_API_H__ +#ifndef __EIGEN_C_API_H__ +#define __EIGEN_C_API_H__ #include "intern/eigenvalues.h" +#include "intern/linear_solver.h" #include "intern/svd.h" -#endif /* __EIGEN3_C_API_H__ */ +#endif /* __EIGEN_C_API_H__ */ diff --git a/extern/Eigen3/intern/eigenvalues.cc b/intern/eigen/intern/eigenvalues.cc index dcaaee8e9c2..57942a4dc55 100644 --- a/extern/Eigen3/intern/eigenvalues.cc +++ b/intern/eigen/intern/eigenvalues.cc @@ -45,7 +45,7 @@ using Eigen::Map; using Eigen::Success; -bool EG3_self_adjoint_eigen_solve(const int size, const float *matrix, float *r_eigen_values, float *r_eigen_vectors) +bool EIG_self_adjoint_eigen_solve(const int size, const float *matrix, float *r_eigen_values, float *r_eigen_vectors) { SelfAdjointEigenSolver<MatrixXf> eigen_solver; diff --git a/extern/Eigen3/intern/eigenvalues.h b/intern/eigen/intern/eigenvalues.h index 93fc06c2339..5c08ab5be39 100644 --- a/extern/Eigen3/intern/eigenvalues.h +++ b/intern/eigen/intern/eigenvalues.h @@ -31,7 +31,7 @@ extern "C" { #endif -bool EG3_self_adjoint_eigen_solve(const int size, const float *matrix, float *r_eigen_values, float *r_eigen_vectors); +bool EIG_self_adjoint_eigen_solve(const int size, const float *matrix, float *r_eigen_values, float *r_eigen_vectors); #ifdef __cplusplus } diff --git a/intern/eigen/intern/linear_solver.cc b/intern/eigen/intern/linear_solver.cc new file mode 100644 index 00000000000..181b278b9c0 --- /dev/null +++ b/intern/eigen/intern/linear_solver.cc @@ -0,0 +1,354 @@ +/* + * Sparse linear solver. + * Copyright (C) 2004 Bruno Levy + * Copyright (C) 2005-2015 Blender Foundation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you modify this software, you should include a notice giving the + * name of the person performing the modification, the date of modification, + * and the reason for such modification. + */ + +#include "linear_solver.h" + +#include <Eigen/Sparse> + +#include <algorithm> +#include <cassert> +#include <cstdlib> +#include <iostream> +#include <vector> + +/* Eigen data structures */ + +typedef Eigen::SparseMatrix<double, Eigen::ColMajor> EigenSparseMatrix; +typedef Eigen::SparseLU<EigenSparseMatrix> EigenSparseLU; +typedef Eigen::VectorXd EigenVectorX; +typedef Eigen::Triplet<double> EigenTriplet; + +/* Linear Solver data structure */ + +struct LinearSolver +{ + struct Coeff + { + Coeff() + { + index = 0; + value = 0.0; + } + + int index; + double value; + }; + + struct Variable + { + Variable() + { + memset(value, 0, sizeof(value)); + locked = false; + index = 0; + } + + double value[4]; + bool locked; + int index; + std::vector<Coeff> a; + }; + + enum State + { + STATE_VARIABLES_CONSTRUCT, + STATE_MATRIX_CONSTRUCT, + STATE_MATRIX_SOLVED + }; + + LinearSolver(int num_rows_, int num_variables_, int num_rhs_, bool lsq_) + { + assert(num_variables_ > 0); + assert(num_rhs_ <= 4); + + state = STATE_VARIABLES_CONSTRUCT; + m = 0; + n = 0; + sparseLU = NULL; + num_variables = num_variables_; + num_rhs = num_rhs_; + num_rows = num_rows_; + least_squares = lsq_; + + variable.resize(num_variables); + } + + ~LinearSolver() + { + delete sparseLU; + } + + State state; + + int n; + int m; + + std::vector<EigenTriplet> Mtriplets; + EigenSparseMatrix M; + EigenSparseMatrix MtM; + std::vector<EigenVectorX> b; + std::vector<EigenVectorX> x; + + EigenSparseLU *sparseLU; + + int num_variables; + std::vector<Variable> variable; + + int num_rows; + int num_rhs; + + bool least_squares; +}; + +LinearSolver *EIG_linear_solver_new(int num_rows, int num_columns, int num_rhs) +{ + return new LinearSolver(num_rows, num_columns, num_rhs, false); +} + +LinearSolver *EIG_linear_least_squares_solver_new(int num_rows, int num_columns, int num_rhs) +{ + return new LinearSolver(num_rows, num_columns, num_rhs, true); +} + +void EIG_linear_solver_delete(LinearSolver *solver) +{ + delete solver; +} + +/* Variables */ + +void EIG_linear_solver_variable_set(LinearSolver *solver, int rhs, int index, double value) +{ + solver->variable[index].value[rhs] = value; +} + +double EIG_linear_solver_variable_get(LinearSolver *solver, int rhs, int index) +{ + return solver->variable[index].value[rhs]; +} + +void EIG_linear_solver_variable_lock(LinearSolver *solver, int index) +{ + if (!solver->variable[index].locked) { + assert(solver->state == LinearSolver::STATE_VARIABLES_CONSTRUCT); + solver->variable[index].locked = true; + } +} + +static void linear_solver_variables_to_vector(LinearSolver *solver) +{ + int num_rhs = solver->num_rhs; + + for (int i = 0; i < solver->num_variables; i++) { + LinearSolver::Variable* v = &solver->variable[i]; + if (!v->locked) { + for (int j = 0; j < num_rhs; j++) + solver->x[j][v->index] = v->value[j]; + } + } +} + +static void linear_solver_vector_to_variables(LinearSolver *solver) +{ + int num_rhs = solver->num_rhs; + + for (int i = 0; i < solver->num_variables; i++) { + LinearSolver::Variable* v = &solver->variable[i]; + if (!v->locked) { + for (int j = 0; j < num_rhs; j++) + v->value[j] = solver->x[j][v->index]; + } + } +} + +/* Matrix */ + +static void linear_solver_ensure_matrix_construct(LinearSolver *solver) +{ + /* transition to matrix construction if necessary */ + if (solver->state == LinearSolver::STATE_VARIABLES_CONSTRUCT) { + int n = 0; + + for (int i = 0; i < solver->num_variables; i++) { + if (solver->variable[i].locked) + solver->variable[i].index = ~0; + else + solver->variable[i].index = n++; + } + + int m = (solver->num_rows == 0)? n: solver->num_rows; + + solver->m = m; + solver->n = n; + + assert(solver->least_squares || m == n); + + /* reserve reasonable estimate */ + solver->Mtriplets.clear(); + solver->Mtriplets.reserve(std::max(m, n)*3); + + solver->b.resize(solver->num_rhs); + solver->x.resize(solver->num_rhs); + + for (int i = 0; i < solver->num_rhs; i++) { + solver->b[i].setZero(m); + solver->x[i].setZero(n); + } + + linear_solver_variables_to_vector(solver); + + solver->state = LinearSolver::STATE_MATRIX_CONSTRUCT; + } +} + +void EIG_linear_solver_matrix_add(LinearSolver *solver, int row, int col, double value) +{ + if (solver->state == LinearSolver::STATE_MATRIX_SOLVED) + return; + + linear_solver_ensure_matrix_construct(solver); + + if (!solver->least_squares && solver->variable[row].locked); + else if (solver->variable[col].locked) { + if (!solver->least_squares) + row = solver->variable[row].index; + + LinearSolver::Coeff coeff; + coeff.index = row; + coeff.value = value; + solver->variable[col].a.push_back(coeff); + } + else { + if (!solver->least_squares) + row = solver->variable[row].index; + col = solver->variable[col].index; + + /* direct insert into matrix is too slow, so use triplets */ + EigenTriplet triplet(row, col, value); + solver->Mtriplets.push_back(triplet); + } +} + +/* Right hand side */ + +void EIG_linear_solver_right_hand_side_add(LinearSolver *solver, int rhs, int index, double value) +{ + linear_solver_ensure_matrix_construct(solver); + + if (solver->least_squares) { + solver->b[rhs][index] += value; + } + else if (!solver->variable[index].locked) { + index = solver->variable[index].index; + solver->b[rhs][index] += value; + } +} + +/* Solve */ + +bool EIG_linear_solver_solve(LinearSolver *solver) +{ + bool result = true; + + assert(solver->state != LinearSolver::STATE_VARIABLES_CONSTRUCT); + + if (solver->state == LinearSolver::STATE_MATRIX_CONSTRUCT) { + /* create matrix from triplets */ + solver->M.resize(solver->m, solver->n); + solver->M.setFromTriplets(solver->Mtriplets.begin(), solver->Mtriplets.end()); + solver->Mtriplets.clear(); + + /* create least squares matrix */ + if (solver->least_squares) + solver->MtM = solver->M.transpose() * solver->M; + + /* convert M to compressed column format */ + EigenSparseMatrix& M = (solver->least_squares)? solver->MtM: solver->M; + M.makeCompressed(); + + /* perform sparse LU factorization */ + EigenSparseLU *sparseLU = new EigenSparseLU(); + solver->sparseLU = sparseLU; + + sparseLU->compute(M); + result = (sparseLU->info() == Eigen::Success); + + solver->state = LinearSolver::STATE_MATRIX_SOLVED; + } + + if (result) { + /* solve for each right hand side */ + for (int rhs = 0; rhs < solver->num_rhs; rhs++) { + /* modify for locked variables */ + EigenVectorX& b = solver->b[rhs]; + + for (int i = 0; i < solver->num_variables; i++) { + LinearSolver::Variable *variable = &solver->variable[i]; + + if (variable->locked) { + std::vector<LinearSolver::Coeff>& a = variable->a; + + for (int j = 0; j < a.size(); j++) + b[a[j].index] -= a[j].value*variable->value[rhs]; + } + } + + /* solve */ + if (solver->least_squares) { + EigenVectorX Mtb = solver->M.transpose() * b; + solver->x[rhs] = solver->sparseLU->solve(Mtb); + } + else { + EigenVectorX& b = solver->b[rhs]; + solver->x[rhs] = solver->sparseLU->solve(b); + } + + if (solver->sparseLU->info() != Eigen::Success) + result = false; + } + + if (result) + linear_solver_vector_to_variables(solver); + } + + /* clear for next solve */ + for (int rhs = 0; rhs < solver->num_rhs; rhs++) + solver->b[rhs].setZero(solver->m); + + return result; +} + +/* Debugging */ + +void EIG_linear_solver_print_matrix(LinearSolver *solver) +{ + std::cout << "A:" << solver->M << std::endl; + + for (int rhs = 0; rhs < solver->num_rhs; rhs++) + std::cout << "b " << rhs << ":" << solver->b[rhs] << std::endl; + + if (solver->MtM.rows() && solver->MtM.cols()) + std::cout << "AtA:" << solver->MtM << std::endl; +} + diff --git a/intern/eigen/intern/linear_solver.h b/intern/eigen/intern/linear_solver.h new file mode 100644 index 00000000000..2dbea4d6f68 --- /dev/null +++ b/intern/eigen/intern/linear_solver.h @@ -0,0 +1,71 @@ +/* + * Sparse linear solver. + * Copyright (C) 2004 Bruno Levy + * Copyright (C) 2005-2015 Blender Foundation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * If you modify this software, you should include a notice giving the + * name of the person performing the modification, the date of modification, + * and the reason for such modification. + */ + +#pragma once + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Solvers for Ax = b and AtAx = Atb */ + +typedef struct LinearSolver LinearSolver; + +LinearSolver *EIG_linear_solver_new( + int num_rows, + int num_columns, + int num_right_hand_sides); + +LinearSolver *EIG_linear_least_squares_solver_new( + int num_rows, + int num_columns, + int num_right_hand_sides); + +void EIG_linear_solver_delete(LinearSolver *solver); + +/* Variables (x). Any locking must be done before matrix construction. */ + +void EIG_linear_solver_variable_set(LinearSolver *solver, int rhs, int index, double value); +double EIG_linear_solver_variable_get(LinearSolver *solver, int rhs, int index); +void EIG_linear_solver_variable_lock(LinearSolver *solver, int index); + +/* Matrix (A) and right hand side (b) */ + +void EIG_linear_solver_matrix_add(LinearSolver *solver, int row, int col, double value); +void EIG_linear_solver_right_hand_side_add(LinearSolver *solver, int rhs, int index, double value); + +/* Solve. Repeated solves are supported, by changing b between solves. */ + +bool EIG_linear_solver_solve(LinearSolver *solver); + +/* Debugging */ + +void EIG_linear_solver_print_matrix(LinearSolver *solver); + +#ifdef __cplusplus +} +#endif + diff --git a/extern/Eigen3/intern/svd.cc b/intern/eigen/intern/svd.cc index e39a8261edb..04929cff798 100644 --- a/extern/Eigen3/intern/svd.cc +++ b/intern/eigen/intern/svd.cc @@ -32,6 +32,9 @@ # pragma GCC diagnostic ignored "-Wlogical-op" #endif +#ifdef __EIGEN3_SVD_C_API_CC__ /* quiet warning */ +#endif + #include <Eigen/Core> #include <Eigen/SVD> @@ -48,7 +51,7 @@ using Eigen::MatrixXf; using Eigen::VectorXf; using Eigen::Map; -void EG3_svd_square_matrix(const int size, const float *matrix, float *r_U, float *r_S, float *r_V) +void EIG_svd_square_matrix(const int size, const float *matrix, float *r_U, float *r_S, float *r_V) { /* Since our matrix is squared, we can use thinU/V. */ unsigned int flags = (r_U ? ComputeThinU : 0) | (r_V ? ComputeThinV : 0); diff --git a/extern/Eigen3/intern/svd.h b/intern/eigen/intern/svd.h index 0ac51108977..feadcc3520a 100644 --- a/extern/Eigen3/intern/svd.h +++ b/intern/eigen/intern/svd.h @@ -31,7 +31,7 @@ extern "C" { #endif -void EG3_svd_square_matrix(const int size, const float *matrix, float *r_U, float *r_S, float *r_V); +void EIG_svd_square_matrix(const int size, const float *matrix, float *r_U, float *r_S, float *r_V); #ifdef __cplusplus } diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 54ac9d27bc7..7247753c655 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -626,7 +626,7 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty m_wantNumOfAASamples, m_hWnd, m_hDC, - WGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 3, 2, GHOST_OPENGL_WGL_CONTEXT_FLAGS, GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); @@ -646,8 +646,14 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty m_wantNumOfAASamples, m_hWnd, m_hDC, +#if 1 0, // profile bit - 0, 0, + 2, 1, // GL version requested +#else + // switch to this for Blender 2.8 development + WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + 3, 2, +#endif GHOST_OPENGL_WGL_CONTEXT_FLAGS, GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); #else @@ -684,8 +690,14 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty m_wantNumOfAASamples, m_hWnd, m_hDC, +#if 1 0, // profile bit - 0, 0, + 2, 1, // GL version requested +#else + // switch to this for Blender 2.8 development + EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT, + 3, 2, +#endif GHOST_OPENGL_EGL_CONTEXT_FLAGS, GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, EGL_OPENGL_API); diff --git a/intern/iksolver/CMakeLists.txt b/intern/iksolver/CMakeLists.txt index 9476e0379e9..67e7aa6abd3 100644 --- a/intern/iksolver/CMakeLists.txt +++ b/intern/iksolver/CMakeLists.txt @@ -29,7 +29,7 @@ set(INC ) set(INC_SYS - ../moto/include + ${EIGEN3_INCLUDE_DIRS} ) set(SRC @@ -38,38 +38,12 @@ set(SRC intern/IK_QSegment.cpp intern/IK_QTask.cpp intern/IK_Solver.cpp - intern/MT_ExpMap.cpp extern/IK_solver.h intern/IK_QJacobian.h intern/IK_QJacobianSolver.h intern/IK_QSegment.h intern/IK_QTask.h - intern/MT_ExpMap.h - intern/TNT/cholesky.h - intern/TNT/cmat.h - intern/TNT/fcscmat.h - intern/TNT/fmat.h - intern/TNT/fortran.h - intern/TNT/fspvec.h - intern/TNT/index.h - intern/TNT/lapack.h - intern/TNT/lu.h - intern/TNT/qr.h - intern/TNT/region1d.h - intern/TNT/region2d.h - intern/TNT/stopwatch.h - intern/TNT/subscript.h - intern/TNT/svd.h - intern/TNT/tnt.h - intern/TNT/tntmath.h - intern/TNT/tntreqs.h - intern/TNT/transv.h - intern/TNT/triang.h - intern/TNT/trisolve.h - intern/TNT/vec.h - intern/TNT/vecadaptor.h - intern/TNT/version.h ) blender_add_lib(bf_intern_iksolver "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/iksolver/SConscript b/intern/iksolver/SConscript index ba973ad5fd5..12d9d14712b 100644 --- a/intern/iksolver/SConscript +++ b/intern/iksolver/SConscript @@ -29,7 +29,7 @@ Import ('env') sources = env.Glob('intern/*.cpp') -incs = 'intern ../moto/include ../memutil' +incs = 'intern #/extern/Eigen3' env.BlenderLib ('bf_intern_iksolver', sources, Split(incs), [], libtype=['intern','player'], priority=[100,90] ) diff --git a/intern/iksolver/intern/IK_Math.h b/intern/iksolver/intern/IK_Math.h new file mode 100644 index 00000000000..78d99837c43 --- /dev/null +++ b/intern/iksolver/intern/IK_Math.h @@ -0,0 +1,261 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Original author: Laurence + * Contributor(s): Brecht + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#pragma once + +#include <Eigen/Core> +#include <Eigen/Geometry> + +#include <cmath> + +using Eigen::Affine3d; +using Eigen::Matrix3d; +using Eigen::MatrixXd; +using Eigen::Vector3d; +using Eigen::VectorXd; + +static const double IK_EPSILON = 1e-20; + +static inline bool FuzzyZero(double x) +{ + return fabs(x) < IK_EPSILON; +} + +static inline double Clamp(const double x, const double min, const double max) +{ + return (x < min) ? min : (x > max) ? max : x; +} + +static inline Eigen::Matrix3d CreateMatrix(double xx, double xy, double xz, + double yx, double yy, double yz, + double zx, double zy, double zz) +{ + Eigen::Matrix3d M; + M(0, 0) = xx; M(0, 1) = xy; M(0, 2) = xz; + M(1, 0) = yx; M(1, 1) = yy; M(1, 2) = yz; + M(2, 0) = zx; M(2, 1) = zy; M(2, 2) = zz; + return M; +} + +static inline Eigen::Matrix3d RotationMatrix(double sine, double cosine, int axis) +{ + if (axis == 0) + return CreateMatrix(1.0, 0.0, 0.0, + 0.0, cosine, -sine, + 0.0, sine, cosine); + else if (axis == 1) + return CreateMatrix(cosine, 0.0, sine, + 0.0, 1.0, 0.0, + -sine, 0.0, cosine); + else + return CreateMatrix(cosine, -sine, 0.0, + sine, cosine, 0.0, + 0.0, 0.0, 1.0); +} + +static inline Eigen::Matrix3d RotationMatrix(double angle, int axis) +{ + return RotationMatrix(sin(angle), cos(angle), axis); +} + + +static inline double EulerAngleFromMatrix(const Eigen::Matrix3d& R, int axis) +{ + double t = sqrt(R(0, 0) * R(0, 0) + R(0, 1) * R(0, 1)); + + if (t > 16.0 * IK_EPSILON) { + if (axis == 0) return -atan2(R(1, 2), R(2, 2)); + else if (axis == 1) return atan2(-R(0, 2), t); + else return -atan2(R(0, 1), R(0, 0)); + } + else { + if (axis == 0) return -atan2(-R(2, 1), R(1, 1)); + else if (axis == 1) return atan2(-R(0, 2), t); + else return 0.0f; + } +} + +static inline double safe_acos(double f) +{ + // acos that does not return NaN with rounding errors + if (f <= -1.0) + return M_PI; + else if (f >= 1.0) + return 0.0; + else + return acos(f); +} + +static inline Eigen::Vector3d normalize(const Eigen::Vector3d& v) +{ + // a sane normalize function that doesn't give (1, 0, 0) in case + // of a zero length vector + double len = v.norm(); + return FuzzyZero(len) ? Eigen::Vector3d(0, 0, 0) : Eigen::Vector3d(v / len); +} + +static inline double angle(const Eigen::Vector3d& v1, const Eigen::Vector3d& v2) +{ + return safe_acos(v1.dot(v2)); +} + +static inline double ComputeTwist(const Eigen::Matrix3d& R) +{ + // qy and qw are the y and w components of the quaternion from R + double qy = R(0, 2) - R(2, 0); + double qw = R(0, 0) + R(1, 1) + R(2, 2) + 1; + + double tau = 2.0 * atan2(qy, qw); + + return tau; +} + +static inline Eigen::Matrix3d ComputeTwistMatrix(double tau) +{ + return RotationMatrix(tau, 1); +} + +static inline void RemoveTwist(Eigen::Matrix3d& R) +{ + // compute twist parameter + double tau = ComputeTwist(R); + + // compute twist matrix + Eigen::Matrix3d T = ComputeTwistMatrix(tau); + + // remove twist + R = R * T.transpose(); +} + +static inline Eigen::Vector3d SphericalRangeParameters(const Eigen::Matrix3d& R) +{ + // compute twist parameter + double tau = ComputeTwist(R); + + // compute swing parameters + double num = 2.0 * (1.0 + R(1, 1)); + + // singularity at pi + if (fabs(num) < IK_EPSILON) + // TODO: this does now rotation of size pi over z axis, but could + // be any axis, how to deal with this i'm not sure, maybe don't + // enforce limits at all then + return Eigen::Vector3d(0.0, tau, 1.0); + + num = 1.0 / sqrt(num); + double ax = -R(2, 1) * num; + double az = R(0, 1) * num; + + return Eigen::Vector3d(ax, tau, az); +} + +static inline Eigen::Matrix3d ComputeSwingMatrix(double ax, double az) +{ + // length of (ax, 0, az) = sin(theta/2) + double sine2 = ax * ax + az * az; + double cosine2 = sqrt((sine2 >= 1.0) ? 0.0 : 1.0 - sine2); + + // compute swing matrix + Eigen::Matrix3d S(Eigen::Quaterniond(-cosine2, ax, 0.0, az)); + + return S; +} + +static inline Eigen::Vector3d MatrixToAxisAngle(const Eigen::Matrix3d& R) +{ + Eigen::Vector3d delta = Eigen::Vector3d(R(2, 1) - R(1, 2), + R(0, 2) - R(2, 0), + R(1, 0) - R(0, 1)); + + double c = safe_acos((R(0, 0) + R(1, 1) + R(2, 2) - 1) / 2); + double l = delta.norm(); + + if (!FuzzyZero(l)) + delta *= c / l; + + return delta; +} + +static inline bool EllipseClamp(double& ax, double& az, double *amin, double *amax) +{ + double xlim, zlim, x, z; + + if (ax < 0.0) { + x = -ax; + xlim = -amin[0]; + } + else { + x = ax; + xlim = amax[0]; + } + + if (az < 0.0) { + z = -az; + zlim = -amin[1]; + } + else { + z = az; + zlim = amax[1]; + } + + if (FuzzyZero(xlim) || FuzzyZero(zlim)) { + if (x <= xlim && z <= zlim) + return false; + + if (x > xlim) + x = xlim; + if (z > zlim) + z = zlim; + } + else { + double invx = 1.0 / (xlim * xlim); + double invz = 1.0 / (zlim * zlim); + + if ((x * x * invx + z * z * invz) <= 1.0) + return false; + + if (FuzzyZero(x)) { + x = 0.0; + z = zlim; + } + else { + double rico = z / x; + double old_x = x; + x = sqrt(1.0 / (invx + invz * rico * rico)); + if (old_x < 0.0) + x = -x; + z = rico * x; + } + } + + ax = (ax < 0.0) ? -x : x; + az = (az < 0.0) ? -z : z; + + return true; +} + diff --git a/intern/iksolver/intern/IK_QJacobian.cpp b/intern/iksolver/intern/IK_QJacobian.cpp index bb7b7c5c0b8..2925cadf435 100644 --- a/intern/iksolver/intern/IK_QJacobian.cpp +++ b/intern/iksolver/intern/IK_QJacobian.cpp @@ -32,7 +32,6 @@ #include "IK_QJacobian.h" -#include "TNT/svd.h" IK_QJacobian::IK_QJacobian() : m_sdls(true), m_min_damp(1.0) @@ -48,74 +47,66 @@ void IK_QJacobian::ArmMatrices(int dof, int task_size) m_dof = dof; m_task_size = task_size; - m_jacobian.newsize(task_size, dof); - m_jacobian = 0; + m_jacobian.resize(task_size, dof); + m_jacobian.setZero(); - m_alpha.newsize(dof); - m_alpha = 0; + m_alpha.resize(dof); + m_alpha.setZero(); - m_null.newsize(dof, dof); + m_nullspace.resize(dof, dof); - m_d_theta.newsize(dof); - m_d_theta_tmp.newsize(dof); - m_d_norm_weight.newsize(dof); + m_d_theta.resize(dof); + m_d_theta_tmp.resize(dof); + m_d_norm_weight.resize(dof); - m_norm.newsize(dof); - m_norm = 0.0; + m_norm.resize(dof); + m_norm.setZero(); - m_beta.newsize(task_size); + m_beta.resize(task_size); - m_weight.newsize(dof); - m_weight_sqrt.newsize(dof); - m_weight = 1.0; - m_weight_sqrt = 1.0; + m_weight.resize(dof); + m_weight_sqrt.resize(dof); + m_weight.setOnes(); + m_weight_sqrt.setOnes(); if (task_size >= dof) { m_transpose = false; - m_jacobian_tmp.newsize(task_size, dof); + m_jacobian_tmp.resize(task_size, dof); - m_svd_u.newsize(task_size, dof); - m_svd_v.newsize(dof, dof); - m_svd_w.newsize(dof); + m_svd_u.resize(task_size, dof); + m_svd_v.resize(dof, dof); + m_svd_w.resize(dof); - m_work1.newsize(task_size); - m_work2.newsize(dof); - - m_svd_u_t.newsize(dof, task_size); - m_svd_u_beta.newsize(dof); + m_svd_u_beta.resize(dof); } else { // use the SVD of the transpose jacobian, it works just as well // as the original, and often allows using smaller matrices. m_transpose = true; - m_jacobian_tmp.newsize(dof, task_size); - - m_svd_u.newsize(task_size, task_size); - m_svd_v.newsize(dof, task_size); - m_svd_w.newsize(task_size); + m_jacobian_tmp.resize(dof, task_size); - m_work1.newsize(dof); - m_work2.newsize(task_size); + m_svd_u.resize(task_size, task_size); + m_svd_v.resize(dof, task_size); + m_svd_w.resize(task_size); - m_svd_u_t.newsize(task_size, task_size); - m_svd_u_beta.newsize(task_size); + m_svd_u_beta.resize(task_size); } } -void IK_QJacobian::SetBetas(int id, int, const MT_Vector3& v) +void IK_QJacobian::SetBetas(int id, int, const Vector3d& v) { m_beta[id + 0] = v.x(); m_beta[id + 1] = v.y(); m_beta[id + 2] = v.z(); } -void IK_QJacobian::SetDerivatives(int id, int dof_id, const MT_Vector3& v, MT_Scalar norm_weight) +void IK_QJacobian::SetDerivatives(int id, int dof_id, const Vector3d& v, double norm_weight) { - m_jacobian[id + 0][dof_id] = v.x() * m_weight_sqrt[dof_id]; - m_jacobian[id + 1][dof_id] = v.y() * m_weight_sqrt[dof_id]; - m_jacobian[id + 2][dof_id] = v.z() * m_weight_sqrt[dof_id]; + m_jacobian(id + 0, dof_id) = v.x() * m_weight_sqrt[dof_id]; + m_jacobian(id + 1, dof_id) = v.y() * m_weight_sqrt[dof_id]; + m_jacobian(id + 2, dof_id) = v.z() * m_weight_sqrt[dof_id]; m_d_norm_weight[dof_id] = norm_weight; } @@ -125,14 +116,18 @@ void IK_QJacobian::Invert() if (m_transpose) { // SVD will decompose Jt into V*W*Ut with U,V orthogonal and W diagonal, // so J = U*W*Vt and Jinv = V*Winv*Ut - TNT::transpose(m_jacobian, m_jacobian_tmp); - TNT::SVD(m_jacobian_tmp, m_svd_v, m_svd_w, m_svd_u, m_work1, m_work2); + Eigen::JacobiSVD<MatrixXd> svd(m_jacobian.transpose(), Eigen::ComputeThinU | Eigen::ComputeThinV); + m_svd_u = svd.matrixV(); + m_svd_w = svd.singularValues(); + m_svd_v = svd.matrixU(); } else { // SVD will decompose J into U*W*Vt with U,V orthogonal and W diagonal, // so Jinv = V*Winv*Ut - m_jacobian_tmp = m_jacobian; - TNT::SVD(m_jacobian_tmp, m_svd_u, m_svd_w, m_svd_v, m_work1, m_work2); + Eigen::JacobiSVD<MatrixXd> svd(m_jacobian, Eigen::ComputeThinU | Eigen::ComputeThinV); + m_svd_u = svd.matrixU(); + m_svd_w = svd.singularValues(); + m_svd_v = svd.matrixV(); } if (m_sdls) @@ -143,7 +138,7 @@ void IK_QJacobian::Invert() bool IK_QJacobian::ComputeNullProjection() { - MT_Scalar epsilon = 1e-10; + double epsilon = 1e-10; // compute null space projection based on V int i, j, rank = 0; @@ -154,26 +149,24 @@ bool IK_QJacobian::ComputeNullProjection() if (rank < m_task_size) return false; - TMatrix basis(m_svd_v.num_rows(), rank); - TMatrix basis_t(rank, m_svd_v.num_rows()); + MatrixXd basis(m_svd_v.rows(), rank); int b = 0; for (i = 0; i < m_svd_w.size(); i++) if (m_svd_w[i] > epsilon) { - for (j = 0; j < m_svd_v.num_rows(); j++) - basis[j][b] = m_svd_v[j][i]; + for (j = 0; j < m_svd_v.rows(); j++) + basis(j, b) = m_svd_v(j, i); b++; } - TNT::transpose(basis, basis_t); - TNT::matmult(m_null, basis, basis_t); + m_nullspace = basis * basis.transpose(); - for (i = 0; i < m_null.num_rows(); i++) - for (j = 0; j < m_null.num_cols(); j++) + for (i = 0; i < m_nullspace.rows(); i++) + for (j = 0; j < m_nullspace.cols(); j++) if (i == j) - m_null[i][j] = 1.0 - m_null[i][j]; + m_nullspace(i, j) = 1.0 - m_nullspace(i, j); else - m_null[i][j] = -m_null[i][j]; + m_nullspace(i, j) = -m_nullspace(i, j); return true; } @@ -184,7 +177,7 @@ void IK_QJacobian::SubTask(IK_QJacobian& jacobian) return; // restrict lower priority jacobian - jacobian.Restrict(m_d_theta, m_null); + jacobian.Restrict(m_d_theta, m_nullspace); // add angle update from lower priority jacobian.Invert(); @@ -197,19 +190,15 @@ void IK_QJacobian::SubTask(IK_QJacobian& jacobian) m_d_theta[i] = m_d_theta[i] + /*m_min_damp * */ jacobian.AngleUpdate(i); } -void IK_QJacobian::Restrict(TVector& d_theta, TMatrix& null) +void IK_QJacobian::Restrict(VectorXd& d_theta, MatrixXd& nullspace) { // subtract part already moved by higher task from beta - TVector beta_sub(m_beta.size()); - - TNT::matmult(beta_sub, m_jacobian, d_theta); - m_beta = m_beta - beta_sub; + m_beta = m_beta - m_jacobian * d_theta; // note: should we be using the norm of the unrestricted jacobian for SDLS? // project jacobian on to null space of higher priority task - TMatrix jacobian_copy(m_jacobian); - TNT::matmult(m_jacobian, jacobian_copy, null); + m_jacobian = m_jacobian * nullspace; } void IK_QJacobian::InvertSDLS() @@ -230,20 +219,20 @@ void IK_QJacobian::InvertSDLS() // DLS. The SDLS damps individual singular values, instead of using a single // damping term. - MT_Scalar max_angle_change = MT_PI / 4.0; - MT_Scalar epsilon = 1e-10; + double max_angle_change = M_PI / 4.0; + double epsilon = 1e-10; int i, j; - m_d_theta = 0; + m_d_theta.setZero(); m_min_damp = 1.0; for (i = 0; i < m_dof; i++) { m_norm[i] = 0.0; for (j = 0; j < m_task_size; j += 3) { - MT_Scalar n = 0.0; - n += m_jacobian[j][i] * m_jacobian[j][i]; - n += m_jacobian[j + 1][i] * m_jacobian[j + 1][i]; - n += m_jacobian[j + 2][i] * m_jacobian[j + 2][i]; + double n = 0.0; + n += m_jacobian(j, i) * m_jacobian(j, i); + n += m_jacobian(j + 1, i) * m_jacobian(j + 1, i); + n += m_jacobian(j + 2, i) * m_jacobian(j + 2, i); m_norm[i] += sqrt(n); } } @@ -252,40 +241,40 @@ void IK_QJacobian::InvertSDLS() if (m_svd_w[i] <= epsilon) continue; - MT_Scalar wInv = 1.0 / m_svd_w[i]; - MT_Scalar alpha = 0.0; - MT_Scalar N = 0.0; + double wInv = 1.0 / m_svd_w[i]; + double alpha = 0.0; + double N = 0.0; // compute alpha and N - for (j = 0; j < m_svd_u.num_rows(); j += 3) { - alpha += m_svd_u[j][i] * m_beta[j]; - alpha += m_svd_u[j + 1][i] * m_beta[j + 1]; - alpha += m_svd_u[j + 2][i] * m_beta[j + 2]; + for (j = 0; j < m_svd_u.rows(); j += 3) { + alpha += m_svd_u(j, i) * m_beta[j]; + alpha += m_svd_u(j + 1, i) * m_beta[j + 1]; + alpha += m_svd_u(j + 2, i) * m_beta[j + 2]; // note: for 1 end effector, N will always be 1, since U is // orthogonal, .. so could be optimized - MT_Scalar tmp; - tmp = m_svd_u[j][i] * m_svd_u[j][i]; - tmp += m_svd_u[j + 1][i] * m_svd_u[j + 1][i]; - tmp += m_svd_u[j + 2][i] * m_svd_u[j + 2][i]; + double tmp; + tmp = m_svd_u(j, i) * m_svd_u(j, i); + tmp += m_svd_u(j + 1, i) * m_svd_u(j + 1, i); + tmp += m_svd_u(j + 2, i) * m_svd_u(j + 2, i); N += sqrt(tmp); } alpha *= wInv; // compute M, dTheta and max_dtheta - MT_Scalar M = 0.0; - MT_Scalar max_dtheta = 0.0, abs_dtheta; + double M = 0.0; + double max_dtheta = 0.0, abs_dtheta; for (j = 0; j < m_d_theta.size(); j++) { - MT_Scalar v = m_svd_v[j][i]; - M += MT_abs(v) * m_norm[j]; + double v = m_svd_v(j, i); + M += fabs(v) * m_norm[j]; // compute tmporary dTheta's m_d_theta_tmp[j] = v * alpha; // find largest absolute dTheta // multiply with weight to prevent unnecessary damping - abs_dtheta = MT_abs(m_d_theta_tmp[j]) * m_weight_sqrt[j]; + abs_dtheta = fabs(m_d_theta_tmp[j]) * m_weight_sqrt[j]; if (abs_dtheta > max_dtheta) max_dtheta = abs_dtheta; } @@ -293,18 +282,18 @@ void IK_QJacobian::InvertSDLS() M *= wInv; // compute damping term and damp the dTheta's - MT_Scalar gamma = max_angle_change; + double gamma = max_angle_change; if (N < M) gamma *= N / M; - MT_Scalar damp = (gamma < max_dtheta) ? gamma / max_dtheta : 1.0; + double damp = (gamma < max_dtheta) ? gamma / max_dtheta : 1.0; for (j = 0; j < m_d_theta.size(); j++) { // slight hack: we do 0.80*, so that if there is some oscillation, // the system can still converge (for joint limits). also, it's // better to go a little to slow than to far - MT_Scalar dofdamp = damp / m_weight[j]; + double dofdamp = damp / m_weight[j]; if (dofdamp > 1.0) dofdamp = 1.0; m_d_theta[j] += 0.80 * dofdamp * m_d_theta_tmp[j]; @@ -315,19 +304,19 @@ void IK_QJacobian::InvertSDLS() } // weight + prevent from doing angle updates with angles > max_angle_change - MT_Scalar max_angle = 0.0, abs_angle; + double max_angle = 0.0, abs_angle; for (j = 0; j < m_dof; j++) { m_d_theta[j] *= m_weight[j]; - abs_angle = MT_abs(m_d_theta[j]); + abs_angle = fabs(m_d_theta[j]); if (abs_angle > max_angle) max_angle = abs_angle; } if (max_angle > max_angle_change) { - MT_Scalar damp = (max_angle_change) / (max_angle_change + max_angle); + double damp = (max_angle_change) / (max_angle_change + max_angle); for (j = 0; j < m_dof; j++) m_d_theta[j] *= damp; @@ -353,12 +342,12 @@ void IK_QJacobian::InvertDLS() // find the smallest non-zero W value, anything below epsilon is // treated as zero - MT_Scalar epsilon = 1e-10; - MT_Scalar max_angle_change = 0.1; - MT_Scalar x_length = sqrt(TNT::dot_prod(m_beta, m_beta)); + double epsilon = 1e-10; + double max_angle_change = 0.1; + double x_length = sqrt(m_beta.dot(m_beta)); int i, j; - MT_Scalar w_min = MT_INFINITY; + double w_min = std::numeric_limits<double>::max(); for (i = 0; i < m_svd_w.size(); i++) { if (m_svd_w[i] > epsilon && m_svd_w[i] < w_min) @@ -367,8 +356,8 @@ void IK_QJacobian::InvertDLS() // compute lambda damping term - MT_Scalar d = x_length / max_angle_change; - MT_Scalar lambda; + double d = x_length / max_angle_change; + double lambda; if (w_min <= d / 2) lambda = d / 2; @@ -386,20 +375,19 @@ void IK_QJacobian::InvertDLS() // rather than matrix*matrix products // compute Ut*Beta - TNT::transpose(m_svd_u, m_svd_u_t); - TNT::matmult(m_svd_u_beta, m_svd_u_t, m_beta); + m_svd_u_beta = m_svd_u.transpose() * m_beta; - m_d_theta = 0.0; + m_d_theta.setZero(); for (i = 0; i < m_svd_w.size(); i++) { if (m_svd_w[i] > epsilon) { - MT_Scalar wInv = m_svd_w[i] / (m_svd_w[i] * m_svd_w[i] + lambda); + double wInv = m_svd_w[i] / (m_svd_w[i] * m_svd_w[i] + lambda); // compute V*Winv*Ut*Beta m_svd_u_beta[i] *= wInv; for (j = 0; j < m_d_theta.size(); j++) - m_d_theta[j] += m_svd_v[j][i] * m_svd_u_beta[i]; + m_d_theta[j] += m_svd_v(j, i) * m_svd_u_beta[i]; } } @@ -407,31 +395,31 @@ void IK_QJacobian::InvertDLS() m_d_theta[j] *= m_weight[j]; } -void IK_QJacobian::Lock(int dof_id, MT_Scalar delta) +void IK_QJacobian::Lock(int dof_id, double delta) { int i; for (i = 0; i < m_task_size; i++) { - m_beta[i] -= m_jacobian[i][dof_id] * delta; - m_jacobian[i][dof_id] = 0.0; + m_beta[i] -= m_jacobian(i, dof_id) * delta; + m_jacobian(i, dof_id) = 0.0; } m_norm[dof_id] = 0.0; // unneeded m_d_theta[dof_id] = 0.0; } -MT_Scalar IK_QJacobian::AngleUpdate(int dof_id) const +double IK_QJacobian::AngleUpdate(int dof_id) const { return m_d_theta[dof_id]; } -MT_Scalar IK_QJacobian::AngleUpdateNorm() const +double IK_QJacobian::AngleUpdateNorm() const { int i; - MT_Scalar mx = 0.0, dtheta_abs; + double mx = 0.0, dtheta_abs; for (i = 0; i < m_d_theta.size(); i++) { - dtheta_abs = MT_abs(m_d_theta[i] * m_d_norm_weight[i]); + dtheta_abs = fabs(m_d_theta[i] * m_d_norm_weight[i]); if (dtheta_abs > mx) mx = dtheta_abs; } @@ -439,7 +427,7 @@ MT_Scalar IK_QJacobian::AngleUpdateNorm() const return mx; } -void IK_QJacobian::SetDoFWeight(int dof, MT_Scalar weight) +void IK_QJacobian::SetDoFWeight(int dof, double weight) { m_weight[dof] = weight; m_weight_sqrt[dof] = sqrt(weight); diff --git a/intern/iksolver/intern/IK_QJacobian.h b/intern/iksolver/intern/IK_QJacobian.h index b4b5a0402e6..f541866c6a7 100644 --- a/intern/iksolver/intern/IK_QJacobian.h +++ b/intern/iksolver/intern/IK_QJacobian.h @@ -31,44 +31,36 @@ * \ingroup iksolver */ +#pragma once -#ifndef __IK_QJACOBIAN_H__ - -#define __IK_QJACOBIAN_H__ - -#include "TNT/cmat.h" -#include <vector> -#include "MT_Vector3.h" +#include "IK_Math.h" class IK_QJacobian { public: - typedef TNT::Matrix<MT_Scalar> TMatrix; - typedef TNT::Vector<MT_Scalar> TVector; - IK_QJacobian(); ~IK_QJacobian(); // Call once to initialize void ArmMatrices(int dof, int task_size); - void SetDoFWeight(int dof, MT_Scalar weight); + void SetDoFWeight(int dof, double weight); // Iteratively called - void SetBetas(int id, int size, const MT_Vector3& v); - void SetDerivatives(int id, int dof_id, const MT_Vector3& v, MT_Scalar norm_weight); + void SetBetas(int id, int size, const Vector3d& v); + void SetDerivatives(int id, int dof_id, const Vector3d& v, double norm_weight); void Invert(); - MT_Scalar AngleUpdate(int dof_id) const; - MT_Scalar AngleUpdateNorm() const; + double AngleUpdate(int dof_id) const; + double AngleUpdateNorm() const; // DoF locking for inner clamping loop - void Lock(int dof_id, MT_Scalar delta); + void Lock(int dof_id, double delta); // Secondary task bool ComputeNullProjection(); - void Restrict(TVector& d_theta, TMatrix& null); + void Restrict(VectorXd& d_theta, MatrixXd& nullspace); void SubTask(IK_QJacobian& jacobian); private: @@ -80,41 +72,35 @@ private: bool m_transpose; // the jacobian matrix and it's null space projector - TMatrix m_jacobian, m_jacobian_tmp; - TMatrix m_null; + MatrixXd m_jacobian, m_jacobian_tmp; + MatrixXd m_nullspace; /// the vector of intermediate betas - TVector m_beta; + VectorXd m_beta; /// the vector of computed angle changes - TVector m_d_theta; - TVector m_d_norm_weight; + VectorXd m_d_theta; + VectorXd m_d_norm_weight; /// space required for SVD computation + VectorXd m_svd_w; + MatrixXd m_svd_v; + MatrixXd m_svd_u; - TVector m_svd_w; - TMatrix m_svd_v; - TMatrix m_svd_u; - TVector m_work1; - TVector m_work2; - - TMatrix m_svd_u_t; - TVector m_svd_u_beta; + VectorXd m_svd_u_beta; // space required for SDLS bool m_sdls; - TVector m_norm; - TVector m_d_theta_tmp; - MT_Scalar m_min_damp; + VectorXd m_norm; + VectorXd m_d_theta_tmp; + double m_min_damp; // null space task vector - TVector m_alpha; + VectorXd m_alpha; // dof weighting - TVector m_weight; - TVector m_weight_sqrt; + VectorXd m_weight; + VectorXd m_weight_sqrt; }; -#endif - diff --git a/intern/iksolver/intern/IK_QJacobianSolver.cpp b/intern/iksolver/intern/IK_QJacobianSolver.cpp index 75f51f566c9..b78270eb87f 100644 --- a/intern/iksolver/intern/IK_QJacobianSolver.cpp +++ b/intern/iksolver/intern/IK_QJacobianSolver.cpp @@ -32,8 +32,8 @@ #include <stdio.h> + #include "IK_QJacobianSolver.h" -#include "MT_Quaternion.h" //#include "analyze.h" IK_QJacobianSolver::IK_QJacobianSolver() @@ -43,10 +43,10 @@ IK_QJacobianSolver::IK_QJacobianSolver() m_rootmatrix.setIdentity(); } -MT_Scalar IK_QJacobianSolver::ComputeScale() +double IK_QJacobianSolver::ComputeScale() { std::vector<IK_QSegment *>::iterator seg; - MT_Scalar length = 0.0f; + double length = 0.0f; for (seg = m_segments.begin(); seg != m_segments.end(); seg++) length += (*seg)->MaxExtension(); @@ -57,7 +57,7 @@ MT_Scalar IK_QJacobianSolver::ComputeScale() return 1.0 / length; } -void IK_QJacobianSolver::Scale(MT_Scalar scale, std::list<IK_QTask *>& tasks) +void IK_QJacobianSolver::Scale(double scale, std::list<IK_QTask *>& tasks) { std::list<IK_QTask *>::iterator task; std::vector<IK_QSegment *>::iterator seg; @@ -68,7 +68,7 @@ void IK_QJacobianSolver::Scale(MT_Scalar scale, std::list<IK_QTask *>& tasks) for (seg = m_segments.begin(); seg != m_segments.end(); seg++) (*seg)->Scale(scale); - m_rootmatrix.getOrigin() *= scale; + m_rootmatrix.translation() *= scale; m_goal *= scale; m_polegoal *= scale; } @@ -102,7 +102,7 @@ bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask *>& tasks) // compute task id's and assing weights to task int primary_size = 0, primary = 0; int secondary_size = 0, secondary = 0; - MT_Scalar primary_weight = 0.0, secondary_weight = 0.0; + double primary_weight = 0.0, secondary_weight = 0.0; std::list<IK_QTask *>::iterator task; for (task = tasks.begin(); task != tasks.end(); task++) { @@ -122,15 +122,15 @@ bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask *>& tasks) } } - if (primary_size == 0 || MT_fuzzyZero(primary_weight)) + if (primary_size == 0 || FuzzyZero(primary_weight)) return false; m_secondary_enabled = (secondary > 0); // rescale weights of tasks to sum up to 1 - MT_Scalar primary_rescale = 1.0 / primary_weight; - MT_Scalar secondary_rescale; - if (MT_fuzzyZero(secondary_weight)) + double primary_rescale = 1.0 / primary_weight; + double secondary_rescale; + if (FuzzyZero(secondary_weight)) secondary_rescale = 0.0; else secondary_rescale = 1.0 / secondary_weight; @@ -159,7 +159,7 @@ bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask *>& tasks) return true; } -void IK_QJacobianSolver::SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& goal, MT_Vector3& polegoal, float poleangle, bool getangle) +void IK_QJacobianSolver::SetPoleVectorConstraint(IK_QSegment *tip, Vector3d& goal, Vector3d& polegoal, float poleangle, bool getangle) { m_poleconstraint = true; m_poletip = tip; @@ -169,27 +169,6 @@ void IK_QJacobianSolver::SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& g m_getpoleangle = getangle; } -static MT_Scalar safe_acos(MT_Scalar f) -{ - // acos that does not return NaN with rounding errors - if (f <= -1.0) return MT_PI; - else if (f >= 1.0) return 0.0; - else return acos(f); -} - -static MT_Vector3 normalize(const MT_Vector3& v) -{ - // a sane normalize function that doesn't give (1, 0, 0) in case - // of a zero length vector, like MT_Vector3.normalize - MT_Scalar len = v.length(); - return MT_fuzzyZero(len) ? MT_Vector3(0, 0, 0) : v / len; -} - -static float angle(const MT_Vector3& v1, const MT_Vector3& v2) -{ - return safe_acos(v1.dot(v2)); -} - void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTask *>& tasks) { // this function will be called before and after solving. calling it before @@ -215,37 +194,38 @@ void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTa // get positions and rotations root->UpdateTransform(m_rootmatrix); - const MT_Vector3 rootpos = root->GlobalStart(); - const MT_Vector3 endpos = m_poletip->GlobalEnd(); - const MT_Matrix3x3& rootbasis = root->GlobalTransform().getBasis(); + const Vector3d rootpos = root->GlobalStart(); + const Vector3d endpos = m_poletip->GlobalEnd(); + const Matrix3d& rootbasis = root->GlobalTransform().linear(); // construct "lookat" matrices (like gluLookAt), based on a direction and // an up vector, with the direction going from the root to the end effector // and the up vector going from the root to the pole constraint position. - MT_Vector3 dir = normalize(endpos - rootpos); - MT_Vector3 rootx = rootbasis.getColumn(0); - MT_Vector3 rootz = rootbasis.getColumn(2); - MT_Vector3 up = rootx * cos(m_poleangle) + rootz *sin(m_poleangle); + Vector3d dir = normalize(endpos - rootpos); + Vector3d rootx = rootbasis.col(0); + Vector3d rootz = rootbasis.col(2); + Vector3d up = rootx * cos(m_poleangle) + rootz *sin(m_poleangle); // in post, don't rotate towards the goal but only correct the pole up - MT_Vector3 poledir = (m_getpoleangle) ? dir : normalize(m_goal - rootpos); - MT_Vector3 poleup = normalize(m_polegoal - rootpos); + Vector3d poledir = (m_getpoleangle) ? dir : normalize(m_goal - rootpos); + Vector3d poleup = normalize(m_polegoal - rootpos); - MT_Matrix3x3 mat, polemat; + Matrix3d mat, polemat; - mat[0] = normalize(MT_cross(dir, up)); - mat[1] = MT_cross(mat[0], dir); - mat[2] = -dir; + mat.row(0) = normalize(dir.cross(up)); + mat.row(1) = mat.row(0).cross(dir); + mat.row(2) = -dir; - polemat[0] = normalize(MT_cross(poledir, poleup)); - polemat[1] = MT_cross(polemat[0], poledir); - polemat[2] = -poledir; + polemat.row(0) = normalize(poledir.cross(poleup)); + polemat.row(1) = polemat.row(0).cross(poledir); + polemat.row(2) = -poledir; if (m_getpoleangle) { // we compute the pole angle that to rotate towards the target - m_poleangle = angle(mat[1], polemat[1]); + m_poleangle = angle(mat.row(1), polemat.row(1)); - if (rootz.dot(mat[1] * cos(m_poleangle) + mat[0] * sin(m_poleangle)) > 0.0) + double dt = rootz.dot(mat.row(1) * cos(m_poleangle) + mat.row(0) * sin(m_poleangle)); + if (dt > 0.0) m_poleangle = -m_poleangle; // solve again, with the pole angle we just computed @@ -257,18 +237,20 @@ void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTa // desired rotation based on the pole vector constraint. we use // transpose instead of inverse because we have orthogonal matrices // anyway, and in case of a singular matrix we don't get NaN's. - MT_Transform trans(MT_Point3(0, 0, 0), polemat.transposed() * mat); + Affine3d trans; + trans.linear() = polemat.transpose() * mat; + trans.translation() = Vector3d(0, 0, 0); m_rootmatrix = trans * m_rootmatrix; } } -bool IK_QJacobianSolver::UpdateAngles(MT_Scalar& norm) +bool IK_QJacobianSolver::UpdateAngles(double& norm) { // assing each segment a unique id for the jacobian std::vector<IK_QSegment *>::iterator seg; IK_QSegment *qseg, *minseg = NULL; - MT_Scalar minabsdelta = 1e10, absdelta; - MT_Vector3 delta, mindelta; + double minabsdelta = 1e10, absdelta; + Vector3d delta, mindelta; bool locked = false, clamp[3]; int i, mindof = 0; @@ -280,9 +262,9 @@ bool IK_QJacobianSolver::UpdateAngles(MT_Scalar& norm) if (qseg->UpdateAngle(m_jacobian, delta, clamp)) { for (i = 0; i < qseg->NumberOfDoF(); i++) { if (clamp[i] && !qseg->Locked(i)) { - absdelta = MT_abs(delta[i]); + absdelta = fabs(delta[i]); - if (absdelta < MT_EPSILON) { + if (absdelta < IK_EPSILON) { qseg->Lock(i, m_jacobian, delta); locked = true; } @@ -320,7 +302,7 @@ bool IK_QJacobianSolver::UpdateAngles(MT_Scalar& norm) bool IK_QJacobianSolver::Solve( IK_QSegment *root, std::list<IK_QTask *> tasks, - const MT_Scalar, + const double, const int max_iterations ) { @@ -349,7 +331,7 @@ bool IK_QJacobianSolver::Solve( (*task)->ComputeJacobian(m_jacobian_sub); } - MT_Scalar norm = 0.0; + double norm = 0.0; do { // invert jacobian @@ -372,7 +354,7 @@ bool IK_QJacobianSolver::Solve( (*seg)->UnLock(); // compute angle update norm - MT_Scalar maxnorm = m_jacobian.AngleUpdateNorm(); + double maxnorm = m_jacobian.AngleUpdateNorm(); if (maxnorm > norm) norm = maxnorm; @@ -384,7 +366,7 @@ bool IK_QJacobianSolver::Solve( } if (m_poleconstraint) - root->PrependBasis(m_rootmatrix.getBasis()); + root->PrependBasis(m_rootmatrix.linear()); Scale(1.0f / scale, tasks); diff --git a/intern/iksolver/intern/IK_QJacobianSolver.h b/intern/iksolver/intern/IK_QJacobianSolver.h index 646f952b9ff..545ef91c710 100644 --- a/intern/iksolver/intern/IK_QJacobianSolver.h +++ b/intern/iksolver/intern/IK_QJacobianSolver.h @@ -30,10 +30,7 @@ * \ingroup iksolver */ - -#ifndef __IK_QJACOBIANSOLVER_H__ - -#define __IK_QJACOBIANSOLVER_H__ +#pragma once /** * @author Laurence Bourn @@ -43,8 +40,7 @@ #include <vector> #include <list> -#include "MT_Vector3.h" -#include "MT_Transform.h" +#include "IK_Math.h" #include "IK_QJacobian.h" #include "IK_QSegment.h" #include "IK_QTask.h" @@ -56,8 +52,8 @@ public: ~IK_QJacobianSolver() {} // setup pole vector constraint - void SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& goal, - MT_Vector3& polegoal, float poleangle, bool getangle); + void SetPoleVectorConstraint(IK_QSegment *tip, Vector3d& goal, + Vector3d& polegoal, float poleangle, bool getangle); float GetPoleAngle() { return m_poleangle; } // call setup once before solving, if it fails don't solve @@ -67,17 +63,17 @@ public: bool Solve( IK_QSegment *root, std::list<IK_QTask*> tasks, - const MT_Scalar tolerance, + const double tolerance, const int max_iterations ); private: void AddSegmentList(IK_QSegment *seg); - bool UpdateAngles(MT_Scalar& norm); + bool UpdateAngles(double& norm); void ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTask*>& tasks); - MT_Scalar ComputeScale(); - void Scale(MT_Scalar scale, std::list<IK_QTask*>& tasks); + double ComputeScale(); + void Scale(double scale, std::list<IK_QTask*>& tasks); private: @@ -88,15 +84,13 @@ private: std::vector<IK_QSegment*> m_segments; - MT_Transform m_rootmatrix; + Affine3d m_rootmatrix; bool m_poleconstraint; bool m_getpoleangle; - MT_Vector3 m_goal; - MT_Vector3 m_polegoal; + Vector3d m_goal; + Vector3d m_polegoal; float m_poleangle; IK_QSegment *m_poletip; }; -#endif - diff --git a/intern/iksolver/intern/IK_QSegment.cpp b/intern/iksolver/intern/IK_QSegment.cpp index e511d8233a2..23b094db279 100644 --- a/intern/iksolver/intern/IK_QSegment.cpp +++ b/intern/iksolver/intern/IK_QSegment.cpp @@ -32,192 +32,6 @@ #include "IK_QSegment.h" -#include <cmath> - -// Utility functions - -static MT_Matrix3x3 RotationMatrix(MT_Scalar sine, MT_Scalar cosine, int axis) -{ - if (axis == 0) - return MT_Matrix3x3(1.0, 0.0, 0.0, - 0.0, cosine, -sine, - 0.0, sine, cosine); - else if (axis == 1) - return MT_Matrix3x3(cosine, 0.0, sine, - 0.0, 1.0, 0.0, - -sine, 0.0, cosine); - else - return MT_Matrix3x3(cosine, -sine, 0.0, - sine, cosine, 0.0, - 0.0, 0.0, 1.0); -} - -static MT_Matrix3x3 RotationMatrix(MT_Scalar angle, int axis) -{ - return RotationMatrix(sin(angle), cos(angle), axis); -} - - -static MT_Scalar EulerAngleFromMatrix(const MT_Matrix3x3& R, int axis) -{ - MT_Scalar t = sqrt(R[0][0] * R[0][0] + R[0][1] * R[0][1]); - - if (t > 16.0 * MT_EPSILON) { - if (axis == 0) return -atan2(R[1][2], R[2][2]); - else if (axis == 1) return atan2(-R[0][2], t); - else return -atan2(R[0][1], R[0][0]); - } - else { - if (axis == 0) return -atan2(-R[2][1], R[1][1]); - else if (axis == 1) return atan2(-R[0][2], t); - else return 0.0f; - } -} - -static MT_Scalar safe_acos(MT_Scalar f) -{ - if (f <= -1.0) - return MT_PI; - else if (f >= 1.0) - return 0.0; - else - return acos(f); -} - -static MT_Scalar ComputeTwist(const MT_Matrix3x3& R) -{ - // qy and qw are the y and w components of the quaternion from R - MT_Scalar qy = R[0][2] - R[2][0]; - MT_Scalar qw = R[0][0] + R[1][1] + R[2][2] + 1; - - MT_Scalar tau = 2.0 * atan2(qy, qw); - - return tau; -} - -static MT_Matrix3x3 ComputeTwistMatrix(MT_Scalar tau) -{ - return RotationMatrix(tau, 1); -} - -static void RemoveTwist(MT_Matrix3x3& R) -{ - // compute twist parameter - MT_Scalar tau = ComputeTwist(R); - - // compute twist matrix - MT_Matrix3x3 T = ComputeTwistMatrix(tau); - - // remove twist - R = R * T.transposed(); -} - -static MT_Vector3 SphericalRangeParameters(const MT_Matrix3x3& R) -{ - // compute twist parameter - MT_Scalar tau = ComputeTwist(R); - - // compute swing parameters - MT_Scalar num = 2.0 * (1.0 + R[1][1]); - - // singularity at pi - if (MT_abs(num) < MT_EPSILON) - // TODO: this does now rotation of size pi over z axis, but could - // be any axis, how to deal with this i'm not sure, maybe don't - // enforce limits at all then - return MT_Vector3(0.0, tau, 1.0); - - num = 1.0 / sqrt(num); - MT_Scalar ax = -R[2][1] * num; - MT_Scalar az = R[0][1] * num; - - return MT_Vector3(ax, tau, az); -} - -static MT_Matrix3x3 ComputeSwingMatrix(MT_Scalar ax, MT_Scalar az) -{ - // length of (ax, 0, az) = sin(theta/2) - MT_Scalar sine2 = ax * ax + az * az; - MT_Scalar cosine2 = sqrt((sine2 >= 1.0) ? 0.0 : 1.0 - sine2); - - // compute swing matrix - MT_Matrix3x3 S(MT_Quaternion(ax, 0.0, az, -cosine2)); - - return S; -} - -static MT_Vector3 MatrixToAxisAngle(const MT_Matrix3x3& R) -{ - MT_Vector3 delta = MT_Vector3(R[2][1] - R[1][2], - R[0][2] - R[2][0], - R[1][0] - R[0][1]); - - MT_Scalar c = safe_acos((R[0][0] + R[1][1] + R[2][2] - 1) / 2); - MT_Scalar l = delta.length(); - - if (!MT_fuzzyZero(l)) - delta *= c / l; - - return delta; -} - -static bool EllipseClamp(MT_Scalar& ax, MT_Scalar& az, MT_Scalar *amin, MT_Scalar *amax) -{ - MT_Scalar xlim, zlim, x, z; - - if (ax < 0.0) { - x = -ax; - xlim = -amin[0]; - } - else { - x = ax; - xlim = amax[0]; - } - - if (az < 0.0) { - z = -az; - zlim = -amin[1]; - } - else { - z = az; - zlim = amax[1]; - } - - if (MT_fuzzyZero(xlim) || MT_fuzzyZero(zlim)) { - if (x <= xlim && z <= zlim) - return false; - - if (x > xlim) - x = xlim; - if (z > zlim) - z = zlim; - } - else { - MT_Scalar invx = 1.0 / (xlim * xlim); - MT_Scalar invz = 1.0 / (zlim * zlim); - - if ((x * x * invx + z * z * invz) <= 1.0) - return false; - - if (MT_fuzzyZero(x)) { - x = 0.0; - z = zlim; - } - else { - MT_Scalar rico = z / x; - MT_Scalar old_x = x; - x = sqrt(1.0 / (invx + invz * rico * rico)); - if (old_x < 0.0) - x = -x; - z = rico * x; - } - } - - ax = (ax < 0.0) ? -x : x; - az = (az < 0.0) ? -z : z; - - return true; -} // IK_QSegment @@ -230,10 +44,10 @@ IK_QSegment::IK_QSegment(int num_DoF, bool translational) m_max_extension = 0.0; - m_start = MT_Vector3(0, 0, 0); + m_start = Vector3d(0, 0, 0); m_rest_basis.setIdentity(); m_basis.setIdentity(); - m_translation = MT_Vector3(0, 0, 0); + m_translation = Vector3d(0, 0, 0); m_orig_basis = m_basis; m_orig_translation = m_translation; @@ -252,13 +66,13 @@ void IK_QSegment::Reset() } void IK_QSegment::SetTransform( - const MT_Vector3& start, - const MT_Matrix3x3& rest_basis, - const MT_Matrix3x3& basis, - const MT_Scalar length + const Vector3d& start, + const Matrix3d& rest_basis, + const Matrix3d& basis, + const double length ) { - m_max_extension = start.length() + length; + m_max_extension = start.norm() + length; m_start = start; m_rest_basis = rest_basis; @@ -266,16 +80,16 @@ void IK_QSegment::SetTransform( m_orig_basis = basis; SetBasis(basis); - m_translation = MT_Vector3(0, length, 0); + m_translation = Vector3d(0, length, 0); m_orig_translation = m_translation; } -MT_Matrix3x3 IK_QSegment::BasisChange() const +Matrix3d IK_QSegment::BasisChange() const { - return m_orig_basis.transposed() * m_basis; + return m_orig_basis.transpose() * m_basis; } -MT_Vector3 IK_QSegment::TranslationChange() const +Vector3d IK_QSegment::TranslationChange() const { return m_translation - m_orig_translation; } @@ -327,13 +141,13 @@ void IK_QSegment::RemoveChild(IK_QSegment *child) } } -void IK_QSegment::UpdateTransform(const MT_Transform& global) +void IK_QSegment::UpdateTransform(const Affine3d& global) { // compute the global transform at the end of the segment - m_global_start = global.getOrigin() + global.getBasis() * m_start; + m_global_start = global.translation() + global.linear() * m_start; - m_global_transform.setOrigin(m_global_start); - m_global_transform.setBasis(global.getBasis() * m_rest_basis * m_basis); + m_global_transform.translation() = m_global_start; + m_global_transform.linear() = global.linear() * m_rest_basis * m_basis; m_global_transform.translate(m_translation); // update child transforms @@ -341,18 +155,18 @@ void IK_QSegment::UpdateTransform(const MT_Transform& global) seg->UpdateTransform(m_global_transform); } -void IK_QSegment::PrependBasis(const MT_Matrix3x3& mat) +void IK_QSegment::PrependBasis(const Matrix3d& mat) { m_basis = m_rest_basis.inverse() * mat * m_rest_basis * m_basis; } -void IK_QSegment::Scale(MT_Scalar scale) +void IK_QSegment::Scale(double scale) { m_start *= scale; m_translation *= scale; m_orig_translation *= scale; m_global_start *= scale; - m_global_transform.getOrigin() *= scale; + m_global_transform.translation() *= scale; m_max_extension *= scale; } @@ -363,19 +177,19 @@ IK_QSphericalSegment::IK_QSphericalSegment() { } -MT_Vector3 IK_QSphericalSegment::Axis(int dof) const +Vector3d IK_QSphericalSegment::Axis(int dof) const { - return m_global_transform.getBasis().getColumn(dof); + return m_global_transform.linear().col(dof); } -void IK_QSphericalSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +void IK_QSphericalSegment::SetLimit(int axis, double lmin, double lmax) { if (lmin > lmax) return; if (axis == 1) { - lmin = MT_clamp(lmin, -MT_PI, MT_PI); - lmax = MT_clamp(lmax, -MT_PI, MT_PI); + lmin = Clamp(lmin, -M_PI, M_PI); + lmax = Clamp(lmax, -M_PI, M_PI); m_min_y = lmin; m_max_y = lmax; @@ -384,8 +198,8 @@ void IK_QSphericalSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) } else { // clamp and convert to axis angle parameters - lmin = MT_clamp(lmin, -MT_PI, MT_PI); - lmax = MT_clamp(lmax, -MT_PI, MT_PI); + lmin = Clamp(lmin, -M_PI, M_PI); + lmax = Clamp(lmax, -M_PI, M_PI); lmin = sin(lmin * 0.5); lmax = sin(lmax * 0.5); @@ -403,17 +217,17 @@ void IK_QSphericalSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) } } -void IK_QSphericalSegment::SetWeight(int axis, MT_Scalar weight) +void IK_QSphericalSegment::SetWeight(int axis, double weight) { m_weight[axis] = weight; } -bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp) { if (m_locked[0] && m_locked[1] && m_locked[2]) return false; - MT_Vector3 dq; + Vector3d dq; dq.x() = jacobian.AngleUpdate(m_DoF_id); dq.y() = jacobian.AngleUpdate(m_DoF_id + 1); dq.z() = jacobian.AngleUpdate(m_DoF_id + 2); @@ -421,27 +235,27 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& // Directly update the rotation matrix, with Rodrigues' rotation formula, // to avoid singularities and allow smooth integration. - MT_Scalar theta = dq.length(); + double theta = dq.norm(); - if (!MT_fuzzyZero(theta)) { - MT_Vector3 w = dq * (1.0 / theta); + if (!FuzzyZero(theta)) { + Vector3d w = dq * (1.0 / theta); - MT_Scalar sine = sin(theta); - MT_Scalar cosine = cos(theta); - MT_Scalar cosineInv = 1 - cosine; + double sine = sin(theta); + double cosine = cos(theta); + double cosineInv = 1 - cosine; - MT_Scalar xsine = w.x() * sine; - MT_Scalar ysine = w.y() * sine; - MT_Scalar zsine = w.z() * sine; + double xsine = w.x() * sine; + double ysine = w.y() * sine; + double zsine = w.z() * sine; - MT_Scalar xxcosine = w.x() * w.x() * cosineInv; - MT_Scalar xycosine = w.x() * w.y() * cosineInv; - MT_Scalar xzcosine = w.x() * w.z() * cosineInv; - MT_Scalar yycosine = w.y() * w.y() * cosineInv; - MT_Scalar yzcosine = w.y() * w.z() * cosineInv; - MT_Scalar zzcosine = w.z() * w.z() * cosineInv; + double xxcosine = w.x() * w.x() * cosineInv; + double xycosine = w.x() * w.y() * cosineInv; + double xzcosine = w.x() * w.z() * cosineInv; + double yycosine = w.y() * w.y() * cosineInv; + double yzcosine = w.y() * w.z() * cosineInv; + double zzcosine = w.z() * w.z() * cosineInv; - MT_Matrix3x3 M( + Matrix3d M = CreateMatrix( cosine + xxcosine, -zsine + xycosine, ysine + xzcosine, zsine + xycosine, cosine + yycosine, -xsine + yzcosine, -ysine + xzcosine, xsine + yzcosine, cosine + zzcosine); @@ -455,7 +269,7 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& if (m_limit_y == false && m_limit_x == false && m_limit_z == false) return false; - MT_Vector3 a = SphericalRangeParameters(m_new_basis); + Vector3d a = SphericalRangeParameters(m_new_basis); if (m_locked[0]) a.x() = m_locked_ax; @@ -464,7 +278,7 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& if (m_locked[2]) a.z() = m_locked_az; - MT_Scalar ax = a.x(), ay = a.y(), az = a.z(); + double ax = a.x(), ay = a.y(), az = a.z(); clamp[0] = clamp[1] = clamp[2] = false; @@ -512,7 +326,7 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& m_new_basis = ComputeSwingMatrix(ax, az) * ComputeTwistMatrix(ay); - delta = MatrixToAxisAngle(m_basis.transposed() * m_new_basis); + delta = MatrixToAxisAngle(m_basis.transpose() * m_new_basis); if (!(m_locked[0] || m_locked[2]) && (clamp[0] || clamp[2])) { m_locked_ax = ax; @@ -525,7 +339,7 @@ bool IK_QSphericalSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& return true; } -void IK_QSphericalSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta) +void IK_QSphericalSegment::Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta) { if (dof == 1) { m_locked[1] = true; @@ -557,7 +371,7 @@ IK_QRevoluteSegment::IK_QRevoluteSegment(int axis) { } -void IK_QRevoluteSegment::SetBasis(const MT_Matrix3x3& basis) +void IK_QRevoluteSegment::SetBasis(const Matrix3d& basis) { if (m_axis == 1) { m_angle = ComputeTwist(basis); @@ -569,12 +383,12 @@ void IK_QRevoluteSegment::SetBasis(const MT_Matrix3x3& basis) } } -MT_Vector3 IK_QRevoluteSegment::Axis(int) const +Vector3d IK_QRevoluteSegment::Axis(int) const { - return m_global_transform.getBasis().getColumn(m_axis); + return m_global_transform.linear().col(m_axis); } -bool IK_QRevoluteSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +bool IK_QRevoluteSegment::UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp) { if (m_locked[0]) return false; @@ -599,7 +413,7 @@ bool IK_QRevoluteSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& return true; } -void IK_QRevoluteSegment::Lock(int, IK_QJacobian& jacobian, MT_Vector3& delta) +void IK_QRevoluteSegment::Lock(int, IK_QJacobian& jacobian, Vector3d& delta) { m_locked[0] = true; jacobian.Lock(m_DoF_id, delta[0]); @@ -611,14 +425,14 @@ void IK_QRevoluteSegment::UpdateAngleApply() m_basis = RotationMatrix(m_angle, m_axis); } -void IK_QRevoluteSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +void IK_QRevoluteSegment::SetLimit(int axis, double lmin, double lmax) { if (lmin > lmax || m_axis != axis) return; // clamp and convert to axis angle parameters - lmin = MT_clamp(lmin, -MT_PI, MT_PI); - lmax = MT_clamp(lmax, -MT_PI, MT_PI); + lmin = Clamp(lmin, -M_PI, M_PI); + lmax = Clamp(lmax, -M_PI, M_PI); m_min = lmin; m_max = lmax; @@ -626,7 +440,7 @@ void IK_QRevoluteSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) m_limit = true; } -void IK_QRevoluteSegment::SetWeight(int axis, MT_Scalar weight) +void IK_QRevoluteSegment::SetWeight(int axis, double weight) { if (axis == m_axis) m_weight[0] = weight; @@ -639,23 +453,23 @@ IK_QSwingSegment::IK_QSwingSegment() { } -void IK_QSwingSegment::SetBasis(const MT_Matrix3x3& basis) +void IK_QSwingSegment::SetBasis(const Matrix3d& basis) { m_basis = basis; RemoveTwist(m_basis); } -MT_Vector3 IK_QSwingSegment::Axis(int dof) const +Vector3d IK_QSwingSegment::Axis(int dof) const { - return m_global_transform.getBasis().getColumn((dof == 0) ? 0 : 2); + return m_global_transform.linear().col((dof == 0) ? 0 : 2); } -bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp) { if (m_locked[0] && m_locked[1]) return false; - MT_Vector3 dq; + Vector3d dq; dq.x() = jacobian.AngleUpdate(m_DoF_id); dq.y() = 0.0; dq.z() = jacobian.AngleUpdate(m_DoF_id + 1); @@ -663,23 +477,23 @@ bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& del // Directly update the rotation matrix, with Rodrigues' rotation formula, // to avoid singularities and allow smooth integration. - MT_Scalar theta = dq.length(); + double theta = dq.norm(); - if (!MT_fuzzyZero(theta)) { - MT_Vector3 w = dq * (1.0 / theta); + if (!FuzzyZero(theta)) { + Vector3d w = dq * (1.0 / theta); - MT_Scalar sine = sin(theta); - MT_Scalar cosine = cos(theta); - MT_Scalar cosineInv = 1 - cosine; + double sine = sin(theta); + double cosine = cos(theta); + double cosineInv = 1 - cosine; - MT_Scalar xsine = w.x() * sine; - MT_Scalar zsine = w.z() * sine; + double xsine = w.x() * sine; + double zsine = w.z() * sine; - MT_Scalar xxcosine = w.x() * w.x() * cosineInv; - MT_Scalar xzcosine = w.x() * w.z() * cosineInv; - MT_Scalar zzcosine = w.z() * w.z() * cosineInv; + double xxcosine = w.x() * w.x() * cosineInv; + double xzcosine = w.x() * w.z() * cosineInv; + double zzcosine = w.z() * w.z() * cosineInv; - MT_Matrix3x3 M( + Matrix3d M = CreateMatrix( cosine + xxcosine, -zsine, xzcosine, zsine, cosine, -xsine, xzcosine, xsine, cosine + zzcosine); @@ -694,8 +508,8 @@ bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& del if (m_limit_x == false && m_limit_z == false) return false; - MT_Vector3 a = SphericalRangeParameters(m_new_basis); - MT_Scalar ax = 0, az = 0; + Vector3d a = SphericalRangeParameters(m_new_basis); + double ax = 0, az = 0; clamp[0] = clamp[1] = false; @@ -732,13 +546,13 @@ bool IK_QSwingSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& del m_new_basis = ComputeSwingMatrix(ax, az); - delta = MatrixToAxisAngle(m_basis.transposed() * m_new_basis); + delta = MatrixToAxisAngle(m_basis.transpose() * m_new_basis); delta[1] = delta[2]; delta[2] = 0.0; return true; } -void IK_QSwingSegment::Lock(int, IK_QJacobian& jacobian, MT_Vector3& delta) +void IK_QSwingSegment::Lock(int, IK_QJacobian& jacobian, Vector3d& delta) { m_locked[0] = m_locked[1] = true; jacobian.Lock(m_DoF_id, delta[0]); @@ -750,20 +564,20 @@ void IK_QSwingSegment::UpdateAngleApply() m_basis = m_new_basis; } -void IK_QSwingSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +void IK_QSwingSegment::SetLimit(int axis, double lmin, double lmax) { if (lmin > lmax) return; // clamp and convert to axis angle parameters - lmin = MT_clamp(lmin, -MT_PI, MT_PI); - lmax = MT_clamp(lmax, -MT_PI, MT_PI); + lmin = Clamp(lmin, -M_PI, M_PI); + lmax = Clamp(lmax, -M_PI, M_PI); lmin = sin(lmin * 0.5); lmax = sin(lmax * 0.5); // put center of ellispe in the middle between min and max - MT_Scalar offset = 0.5 * (lmin + lmax); + double offset = 0.5 * (lmin + lmax); //lmax = lmax - offset; if (axis == 0) { @@ -784,7 +598,7 @@ void IK_QSwingSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) } } -void IK_QSwingSegment::SetWeight(int axis, MT_Scalar weight) +void IK_QSwingSegment::SetWeight(int axis, double weight) { if (axis == 0) m_weight[0] = weight; @@ -800,7 +614,7 @@ IK_QElbowSegment::IK_QElbowSegment(int axis) { } -void IK_QElbowSegment::SetBasis(const MT_Matrix3x3& basis) +void IK_QElbowSegment::SetBasis(const Matrix3d& basis) { m_basis = basis; @@ -811,22 +625,22 @@ void IK_QElbowSegment::SetBasis(const MT_Matrix3x3& basis) m_basis = RotationMatrix(m_angle, m_axis) * ComputeTwistMatrix(m_twist); } -MT_Vector3 IK_QElbowSegment::Axis(int dof) const +Vector3d IK_QElbowSegment::Axis(int dof) const { if (dof == 0) { - MT_Vector3 v; + Vector3d v; if (m_axis == 0) - v = MT_Vector3(m_cos_twist, 0, m_sin_twist); + v = Vector3d(m_cos_twist, 0, m_sin_twist); else - v = MT_Vector3(-m_sin_twist, 0, m_cos_twist); + v = Vector3d(-m_sin_twist, 0, m_cos_twist); - return m_global_transform.getBasis() * v; + return m_global_transform.linear() * v; } else - return m_global_transform.getBasis().getColumn(1); + return m_global_transform.linear().col(1); } -bool IK_QElbowSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +bool IK_QElbowSegment::UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp) { if (m_locked[0] && m_locked[1]) return false; @@ -870,7 +684,7 @@ bool IK_QElbowSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& del return (clamp[0] || clamp[1]); } -void IK_QElbowSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta) +void IK_QElbowSegment::Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta) { if (dof == 0) { m_locked[0] = true; @@ -890,20 +704,20 @@ void IK_QElbowSegment::UpdateAngleApply() m_sin_twist = sin(m_twist); m_cos_twist = cos(m_twist); - MT_Matrix3x3 A = RotationMatrix(m_angle, m_axis); - MT_Matrix3x3 T = RotationMatrix(m_sin_twist, m_cos_twist, 1); + Matrix3d A = RotationMatrix(m_angle, m_axis); + Matrix3d T = RotationMatrix(m_sin_twist, m_cos_twist, 1); m_basis = A * T; } -void IK_QElbowSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +void IK_QElbowSegment::SetLimit(int axis, double lmin, double lmax) { if (lmin > lmax) return; // clamp and convert to axis angle parameters - lmin = MT_clamp(lmin, -MT_PI, MT_PI); - lmax = MT_clamp(lmax, -MT_PI, MT_PI); + lmin = Clamp(lmin, -M_PI, M_PI); + lmax = Clamp(lmax, -M_PI, M_PI); if (axis == 1) { m_min_twist = lmin; @@ -917,7 +731,7 @@ void IK_QElbowSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) } } -void IK_QElbowSegment::SetWeight(int axis, MT_Scalar weight) +void IK_QElbowSegment::SetWeight(int axis, double weight) { if (axis == m_axis) m_weight[0] = weight; @@ -963,16 +777,16 @@ IK_QTranslateSegment::IK_QTranslateSegment() m_limit[0] = m_limit[1] = m_limit[2] = false; } -MT_Vector3 IK_QTranslateSegment::Axis(int dof) const +Vector3d IK_QTranslateSegment::Axis(int dof) const { - return m_global_transform.getBasis().getColumn(m_axis[dof]); + return m_global_transform.linear().col(m_axis[dof]); } -bool IK_QTranslateSegment::UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp) +bool IK_QTranslateSegment::UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp) { int dof_id = m_DoF_id, dof = 0, i, clamped = false; - MT_Vector3 dx(0.0, 0.0, 0.0); + Vector3d dx(0.0, 0.0, 0.0); for (i = 0; i < 3; i++) { if (!m_axis_enabled[i]) { @@ -1011,13 +825,13 @@ void IK_QTranslateSegment::UpdateAngleApply() m_translation = m_new_translation; } -void IK_QTranslateSegment::Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta) +void IK_QTranslateSegment::Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta) { m_locked[dof] = true; jacobian.Lock(m_DoF_id + dof, delta[dof]); } -void IK_QTranslateSegment::SetWeight(int axis, MT_Scalar weight) +void IK_QTranslateSegment::SetWeight(int axis, double weight) { int i; @@ -1026,7 +840,7 @@ void IK_QTranslateSegment::SetWeight(int axis, MT_Scalar weight) m_weight[i] = weight; } -void IK_QTranslateSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) +void IK_QTranslateSegment::SetLimit(int axis, double lmin, double lmax) { if (lmax < lmin) return; @@ -1036,7 +850,7 @@ void IK_QTranslateSegment::SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax) m_limit[axis] = true; } -void IK_QTranslateSegment::Scale(MT_Scalar scale) +void IK_QTranslateSegment::Scale(double scale) { int i; diff --git a/intern/iksolver/intern/IK_QSegment.h b/intern/iksolver/intern/IK_QSegment.h index b40bf3739ff..74f157aa763 100644 --- a/intern/iksolver/intern/IK_QSegment.h +++ b/intern/iksolver/intern/IK_QSegment.h @@ -30,13 +30,9 @@ * \ingroup iksolver */ +#pragma once -#ifndef __IK_QSEGMENT_H__ -#define __IK_QSEGMENT_H__ - -#include "MT_Vector3.h" -#include "MT_Transform.h" -#include "MT_Matrix4x4.h" +#include "IK_Math.h" #include "IK_QJacobian.h" #include <vector> @@ -50,8 +46,7 @@ * Here we define the local coordinates of a joint as * local_transform = * translate(tr1) * rotation(A) * rotation(q) * translate(0,length,0) - * We use the standard moto column ordered matrices. You can read - * this as: + * You can read this as: * - first translate by (0,length,0) * - multiply by the rotation matrix derived from the current * angle parameterization q. @@ -73,10 +68,10 @@ public: // length: length of this segment void SetTransform( - const MT_Vector3& start, - const MT_Matrix3x3& rest_basis, - const MT_Matrix3x3& basis, - const MT_Scalar length + const Vector3d& start, + const Matrix3d& rest_basis, + const Matrix3d& basis, + const double length ); // tree structure access @@ -109,22 +104,22 @@ public: { m_DoF_id = dof_id; } // the max distance of the end of this bone from the local origin. - const MT_Scalar MaxExtension() const + const double MaxExtension() const { return m_max_extension; } // the change in rotation and translation w.r.t. the rest pose - MT_Matrix3x3 BasisChange() const; - MT_Vector3 TranslationChange() const; + Matrix3d BasisChange() const; + Vector3d TranslationChange() const; // the start and end of the segment - const MT_Point3 &GlobalStart() const + const Vector3d GlobalStart() const { return m_global_start; } - const MT_Point3 &GlobalEnd() const - { return m_global_transform.getOrigin(); } + const Vector3d GlobalEnd() const + { return m_global_transform.translation(); } // the global transformation at the end of the segment - const MT_Transform &GlobalTransform() const + const Affine3d &GlobalTransform() const { return m_global_transform; } // is a translational segment? @@ -139,38 +134,38 @@ public: { m_locked[0] = m_locked[1] = m_locked[2] = false; } // per dof joint weighting - MT_Scalar Weight(int dof) const + double Weight(int dof) const { return m_weight[dof]; } - void ScaleWeight(int dof, MT_Scalar scale) + void ScaleWeight(int dof, double scale) { m_weight[dof] *= scale; } // recursively update the global coordinates of this segment, 'global' // is the global transformation from the parent segment - void UpdateTransform(const MT_Transform &global); + void UpdateTransform(const Affine3d &global); // get axis from rotation matrix for derivative computation - virtual MT_Vector3 Axis(int dof) const=0; + virtual Vector3d Axis(int dof) const=0; // update the angles using the dTheta's computed using the jacobian matrix - virtual bool UpdateAngle(const IK_QJacobian&, MT_Vector3&, bool*)=0; - virtual void Lock(int, IK_QJacobian&, MT_Vector3&) {} + virtual bool UpdateAngle(const IK_QJacobian&, Vector3d&, bool*)=0; + virtual void Lock(int, IK_QJacobian&, Vector3d&) {} virtual void UpdateAngleApply()=0; // set joint limits - virtual void SetLimit(int, MT_Scalar, MT_Scalar) {} + virtual void SetLimit(int, double, double) {} // set joint weights (per axis) - virtual void SetWeight(int, MT_Scalar) {} + virtual void SetWeight(int, double) {} - virtual void SetBasis(const MT_Matrix3x3& basis) { m_basis = basis; } + virtual void SetBasis(const Matrix3d& basis) { m_basis = basis; } // functions needed for pole vector constraint - void PrependBasis(const MT_Matrix3x3& mat); + void PrependBasis(const Matrix3d& mat); void Reset(); // scale - virtual void Scale(MT_Scalar scale); + virtual void Scale(double scale); protected: @@ -188,28 +183,28 @@ protected: // full transform = // start * rest_basis * basis * translation - MT_Vector3 m_start; - MT_Matrix3x3 m_rest_basis; - MT_Matrix3x3 m_basis; - MT_Vector3 m_translation; + Vector3d m_start; + Matrix3d m_rest_basis; + Matrix3d m_basis; + Vector3d m_translation; // original basis - MT_Matrix3x3 m_orig_basis; - MT_Vector3 m_orig_translation; + Matrix3d m_orig_basis; + Vector3d m_orig_translation; // maximum extension of this segment - MT_Scalar m_max_extension; + double m_max_extension; // accumulated transformations starting from root - MT_Point3 m_global_start; - MT_Transform m_global_transform; + Vector3d m_global_start; + Affine3d m_global_transform; // number degrees of freedom, (first) id of this segments DOF's int m_num_DoF, m_DoF_id; bool m_locked[3]; bool m_translational; - MT_Scalar m_weight[3]; + double m_weight[3]; }; class IK_QSphericalSegment : public IK_QSegment @@ -217,23 +212,23 @@ class IK_QSphericalSegment : public IK_QSegment public: IK_QSphericalSegment(); - MT_Vector3 Axis(int dof) const; + Vector3d Axis(int dof) const; - bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); - void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + bool UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta); void UpdateAngleApply(); - bool ComputeClampRotation(MT_Vector3& clamp); + bool ComputeClampRotation(Vector3d& clamp); - void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); - void SetWeight(int axis, MT_Scalar weight); + void SetLimit(int axis, double lmin, double lmax); + void SetWeight(int axis, double weight); private: - MT_Matrix3x3 m_new_basis; + Matrix3d m_new_basis; bool m_limit_x, m_limit_y, m_limit_z; - MT_Scalar m_min[2], m_max[2]; - MT_Scalar m_min_y, m_max_y, m_max_x, m_max_z, m_offset_x, m_offset_z; - MT_Scalar m_locked_ax, m_locked_ay, m_locked_az; + double m_min[2], m_max[2]; + double m_min_y, m_max_y, m_max_x, m_max_z, m_offset_x, m_offset_z; + double m_locked_ax, m_locked_ay, m_locked_az; }; class IK_QNullSegment : public IK_QSegment @@ -241,11 +236,11 @@ class IK_QNullSegment : public IK_QSegment public: IK_QNullSegment(); - bool UpdateAngle(const IK_QJacobian&, MT_Vector3&, bool*) { return false; } + bool UpdateAngle(const IK_QJacobian&, Vector3d&, bool*) { return false; } void UpdateAngleApply() {} - MT_Vector3 Axis(int) const { return MT_Vector3(0, 0, 0); } - void SetBasis(const MT_Matrix3x3&) { m_basis.setIdentity(); } + Vector3d Axis(int) const { return Vector3d(0, 0, 0); } + void SetBasis(const Matrix3d&) { m_basis.setIdentity(); } }; class IK_QRevoluteSegment : public IK_QSegment @@ -254,21 +249,21 @@ public: // axis: the axis of the DoF, in range 0..2 IK_QRevoluteSegment(int axis); - MT_Vector3 Axis(int dof) const; + Vector3d Axis(int dof) const; - bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); - void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + bool UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta); void UpdateAngleApply(); - void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); - void SetWeight(int axis, MT_Scalar weight); - void SetBasis(const MT_Matrix3x3& basis); + void SetLimit(int axis, double lmin, double lmax); + void SetWeight(int axis, double weight); + void SetBasis(const Matrix3d& basis); private: int m_axis; - MT_Scalar m_angle, m_new_angle; + double m_angle, m_new_angle; bool m_limit; - MT_Scalar m_min, m_max; + double m_min, m_max; }; class IK_QSwingSegment : public IK_QSegment @@ -277,21 +272,21 @@ public: // XZ DOF, uses one direct rotation IK_QSwingSegment(); - MT_Vector3 Axis(int dof) const; + Vector3d Axis(int dof) const; - bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); - void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + bool UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta); void UpdateAngleApply(); - void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); - void SetWeight(int axis, MT_Scalar weight); - void SetBasis(const MT_Matrix3x3& basis); + void SetLimit(int axis, double lmin, double lmax); + void SetWeight(int axis, double weight); + void SetBasis(const Matrix3d& basis); private: - MT_Matrix3x3 m_new_basis; + Matrix3d m_new_basis; bool m_limit_x, m_limit_z; - MT_Scalar m_min[2], m_max[2]; - MT_Scalar m_max_x, m_max_z, m_offset_x, m_offset_z; + double m_min[2], m_max[2]; + double m_max_x, m_max_z, m_offset_x, m_offset_z; }; class IK_QElbowSegment : public IK_QSegment @@ -301,24 +296,24 @@ public: // X or Z, then rotate around Y (twist) IK_QElbowSegment(int axis); - MT_Vector3 Axis(int dof) const; + Vector3d Axis(int dof) const; - bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); - void Lock(int dof, IK_QJacobian& jacobian, MT_Vector3& delta); + bool UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp); + void Lock(int dof, IK_QJacobian& jacobian, Vector3d& delta); void UpdateAngleApply(); - void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); - void SetWeight(int axis, MT_Scalar weight); - void SetBasis(const MT_Matrix3x3& basis); + void SetLimit(int axis, double lmin, double lmax); + void SetWeight(int axis, double weight); + void SetBasis(const Matrix3d& basis); private: int m_axis; - MT_Scalar m_twist, m_angle, m_new_twist, m_new_angle; - MT_Scalar m_cos_twist, m_sin_twist; + double m_twist, m_angle, m_new_twist, m_new_angle; + double m_cos_twist, m_sin_twist; bool m_limit, m_limit_twist; - MT_Scalar m_min, m_max, m_min_twist, m_max_twist; + double m_min, m_max, m_min_twist, m_max_twist; }; class IK_QTranslateSegment : public IK_QSegment @@ -329,23 +324,21 @@ public: IK_QTranslateSegment(int axis1, int axis2); IK_QTranslateSegment(); - MT_Vector3 Axis(int dof) const; + Vector3d Axis(int dof) const; - bool UpdateAngle(const IK_QJacobian &jacobian, MT_Vector3& delta, bool *clamp); - void Lock(int, IK_QJacobian&, MT_Vector3&); + bool UpdateAngle(const IK_QJacobian &jacobian, Vector3d& delta, bool *clamp); + void Lock(int, IK_QJacobian&, Vector3d&); void UpdateAngleApply(); - void SetWeight(int axis, MT_Scalar weight); - void SetLimit(int axis, MT_Scalar lmin, MT_Scalar lmax); + void SetWeight(int axis, double weight); + void SetLimit(int axis, double lmin, double lmax); - void Scale(MT_Scalar scale); + void Scale(double scale); private: int m_axis[3]; bool m_axis_enabled[3], m_limit[3]; - MT_Vector3 m_new_translation; - MT_Scalar m_min[3], m_max[3]; + Vector3d m_new_translation; + double m_min[3], m_max[3]; }; -#endif - diff --git a/intern/iksolver/intern/IK_QTask.cpp b/intern/iksolver/intern/IK_QTask.cpp index 0ba716ff59d..d7c73865789 100644 --- a/intern/iksolver/intern/IK_QTask.cpp +++ b/intern/iksolver/intern/IK_QTask.cpp @@ -51,7 +51,7 @@ IK_QTask::IK_QTask( IK_QPositionTask::IK_QPositionTask( bool primary, const IK_QSegment *segment, - const MT_Vector3& goal + const Vector3d& goal ) : IK_QTask(3, primary, true, segment), m_goal(goal) { @@ -73,10 +73,10 @@ IK_QPositionTask::IK_QPositionTask( void IK_QPositionTask::ComputeJacobian(IK_QJacobian& jacobian) { // compute beta - const MT_Vector3& pos = m_segment->GlobalEnd(); + const Vector3d& pos = m_segment->GlobalEnd(); - MT_Vector3 d_pos = m_goal - pos; - MT_Scalar length = d_pos.length(); + Vector3d d_pos = m_goal - pos; + double length = d_pos.norm(); if (length > m_clamp_length) d_pos = (m_clamp_length / length) * d_pos; @@ -88,26 +88,26 @@ void IK_QPositionTask::ComputeJacobian(IK_QJacobian& jacobian) const IK_QSegment *seg; for (seg = m_segment; seg; seg = seg->Parent()) { - MT_Vector3 p = seg->GlobalStart() - pos; + Vector3d p = seg->GlobalStart() - pos; for (i = 0; i < seg->NumberOfDoF(); i++) { - MT_Vector3 axis = seg->Axis(i) * m_weight; + Vector3d axis = seg->Axis(i) * m_weight; if (seg->Translational()) jacobian.SetDerivatives(m_id, seg->DoFId() + i, axis, 1e2); else { - MT_Vector3 pa = p.cross(axis); + Vector3d pa = p.cross(axis); jacobian.SetDerivatives(m_id, seg->DoFId() + i, pa, 1e0); } } } } -MT_Scalar IK_QPositionTask::Distance() const +double IK_QPositionTask::Distance() const { - const MT_Vector3& pos = m_segment->GlobalEnd(); - MT_Vector3 d_pos = m_goal - pos; - return d_pos.length(); + const Vector3d& pos = m_segment->GlobalEnd(); + Vector3d d_pos = m_goal - pos; + return d_pos.norm(); } // IK_QOrientationTask @@ -115,7 +115,7 @@ MT_Scalar IK_QPositionTask::Distance() const IK_QOrientationTask::IK_QOrientationTask( bool primary, const IK_QSegment *segment, - const MT_Matrix3x3& goal + const Matrix3d& goal ) : IK_QTask(3, primary, true, segment), m_goal(goal), m_distance(0.0) { @@ -124,17 +124,16 @@ IK_QOrientationTask::IK_QOrientationTask( void IK_QOrientationTask::ComputeJacobian(IK_QJacobian& jacobian) { // compute betas - const MT_Matrix3x3& rot = m_segment->GlobalTransform().getBasis(); + const Matrix3d& rot = m_segment->GlobalTransform().linear(); - MT_Matrix3x3 d_rotm = m_goal * rot.transposed(); - d_rotm.transpose(); + Matrix3d d_rotm = (m_goal * rot.transpose()).transpose(); - MT_Vector3 d_rot; - d_rot = -0.5 * MT_Vector3(d_rotm[2][1] - d_rotm[1][2], - d_rotm[0][2] - d_rotm[2][0], - d_rotm[1][0] - d_rotm[0][1]); + Vector3d d_rot; + d_rot = -0.5 * Vector3d(d_rotm(2, 1) - d_rotm(1, 2), + d_rotm(0, 2) - d_rotm(2, 0), + d_rotm(1, 0) - d_rotm(0, 1)); - m_distance = d_rot.length(); + m_distance = d_rot.norm(); jacobian.SetBetas(m_id, m_size, m_weight * d_rot); @@ -146,9 +145,9 @@ void IK_QOrientationTask::ComputeJacobian(IK_QJacobian& jacobian) for (i = 0; i < seg->NumberOfDoF(); i++) { if (seg->Translational()) - jacobian.SetDerivatives(m_id, seg->DoFId() + i, MT_Vector3(0, 0, 0), 1e2); + jacobian.SetDerivatives(m_id, seg->DoFId() + i, Vector3d(0, 0, 0), 1e2); else { - MT_Vector3 axis = seg->Axis(i) * m_weight; + Vector3d axis = seg->Axis(i) * m_weight; jacobian.SetDerivatives(m_id, seg->DoFId() + i, axis, 1e0); } } @@ -160,18 +159,18 @@ void IK_QOrientationTask::ComputeJacobian(IK_QJacobian& jacobian) IK_QCenterOfMassTask::IK_QCenterOfMassTask( bool primary, const IK_QSegment *segment, - const MT_Vector3& goal_center + const Vector3d& goal_center ) : IK_QTask(3, primary, true, segment), m_goal_center(goal_center) { m_total_mass_inv = ComputeTotalMass(m_segment); - if (!MT_fuzzyZero(m_total_mass_inv)) + if (!FuzzyZero(m_total_mass_inv)) m_total_mass_inv = 1.0 / m_total_mass_inv; } -MT_Scalar IK_QCenterOfMassTask::ComputeTotalMass(const IK_QSegment *segment) +double IK_QCenterOfMassTask::ComputeTotalMass(const IK_QSegment *segment) { - MT_Scalar mass = /*seg->Mass()*/ 1.0; + double mass = /*seg->Mass()*/ 1.0; const IK_QSegment *seg; for (seg = segment->Child(); seg; seg = seg->Sibling()) @@ -180,9 +179,9 @@ MT_Scalar IK_QCenterOfMassTask::ComputeTotalMass(const IK_QSegment *segment) return mass; } -MT_Vector3 IK_QCenterOfMassTask::ComputeCenter(const IK_QSegment *segment) +Vector3d IK_QCenterOfMassTask::ComputeCenter(const IK_QSegment *segment) { - MT_Vector3 center = /*seg->Mass()**/ segment->GlobalStart(); + Vector3d center = /*seg->Mass()**/ segment->GlobalStart(); const IK_QSegment *seg; for (seg = segment->Child(); seg; seg = seg->Sibling()) @@ -191,19 +190,19 @@ MT_Vector3 IK_QCenterOfMassTask::ComputeCenter(const IK_QSegment *segment) return center; } -void IK_QCenterOfMassTask::JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& center, const IK_QSegment *segment) +void IK_QCenterOfMassTask::JacobianSegment(IK_QJacobian& jacobian, Vector3d& center, const IK_QSegment *segment) { int i; - MT_Vector3 p = center - segment->GlobalStart(); + Vector3d p = center - segment->GlobalStart(); for (i = 0; i < segment->NumberOfDoF(); i++) { - MT_Vector3 axis = segment->Axis(i) * m_weight; + Vector3d axis = segment->Axis(i) * m_weight; axis *= /*segment->Mass()**/ m_total_mass_inv; if (segment->Translational()) jacobian.SetDerivatives(m_id, segment->DoFId() + i, axis, 1e2); else { - MT_Vector3 pa = axis.cross(p); + Vector3d pa = axis.cross(p); jacobian.SetDerivatives(m_id, segment->DoFId() + i, pa, 1e0); } } @@ -215,12 +214,12 @@ void IK_QCenterOfMassTask::JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& c void IK_QCenterOfMassTask::ComputeJacobian(IK_QJacobian& jacobian) { - MT_Vector3 center = ComputeCenter(m_segment) * m_total_mass_inv; + Vector3d center = ComputeCenter(m_segment) * m_total_mass_inv; // compute beta - MT_Vector3 d_pos = m_goal_center - center; + Vector3d d_pos = m_goal_center - center; - m_distance = d_pos.length(); + m_distance = d_pos.norm(); #if 0 if (m_distance > m_clamp_length) @@ -233,7 +232,7 @@ void IK_QCenterOfMassTask::ComputeJacobian(IK_QJacobian& jacobian) JacobianSegment(jacobian, center, m_segment); } -MT_Scalar IK_QCenterOfMassTask::Distance() const +double IK_QCenterOfMassTask::Distance() const { return m_distance; } diff --git a/intern/iksolver/intern/IK_QTask.h b/intern/iksolver/intern/IK_QTask.h index baf1c346d62..141e6d41b47 100644 --- a/intern/iksolver/intern/IK_QTask.h +++ b/intern/iksolver/intern/IK_QTask.h @@ -30,13 +30,9 @@ * \ingroup iksolver */ +#pragma once -#ifndef __IK_QTASK_H__ -#define __IK_QTASK_H__ - -#include "MT_Vector3.h" -#include "MT_Transform.h" -#include "MT_Matrix4x4.h" +#include "IK_Math.h" #include "IK_QJacobian.h" #include "IK_QSegment.h" @@ -66,19 +62,19 @@ public: bool Active() const { return m_active; } - MT_Scalar Weight() const + double Weight() const { return m_weight*m_weight; } - void SetWeight(MT_Scalar weight) + void SetWeight(double weight) { m_weight = sqrt(weight); } virtual void ComputeJacobian(IK_QJacobian& jacobian)=0; - virtual MT_Scalar Distance() const=0; + virtual double Distance() const=0; virtual bool PositionTask() const { return false; } - virtual void Scale(MT_Scalar) {} + virtual void Scale(double) {} protected: int m_id; @@ -86,7 +82,7 @@ protected: bool m_primary; bool m_active; const IK_QSegment *m_segment; - MT_Scalar m_weight; + double m_weight; }; class IK_QPositionTask : public IK_QTask @@ -95,19 +91,19 @@ public: IK_QPositionTask( bool primary, const IK_QSegment *segment, - const MT_Vector3& goal + const Vector3d& goal ); void ComputeJacobian(IK_QJacobian& jacobian); - MT_Scalar Distance() const; + double Distance() const; bool PositionTask() const { return true; } - void Scale(MT_Scalar scale) { m_goal *= scale; m_clamp_length *= scale; } + void Scale(double scale) { m_goal *= scale; m_clamp_length *= scale; } private: - MT_Vector3 m_goal; - MT_Scalar m_clamp_length; + Vector3d m_goal; + double m_clamp_length; }; class IK_QOrientationTask : public IK_QTask @@ -116,15 +112,15 @@ public: IK_QOrientationTask( bool primary, const IK_QSegment *segment, - const MT_Matrix3x3& goal + const Matrix3d& goal ); - MT_Scalar Distance() const { return m_distance; } + double Distance() const { return m_distance; } void ComputeJacobian(IK_QJacobian& jacobian); private: - MT_Matrix3x3 m_goal; - MT_Scalar m_distance; + Matrix3d m_goal; + double m_distance; }; @@ -134,24 +130,22 @@ public: IK_QCenterOfMassTask( bool primary, const IK_QSegment *segment, - const MT_Vector3& center + const Vector3d& center ); void ComputeJacobian(IK_QJacobian& jacobian); - MT_Scalar Distance() const; + double Distance() const; - void Scale(MT_Scalar scale) { m_goal_center *= scale; m_distance *= scale; } + void Scale(double scale) { m_goal_center *= scale; m_distance *= scale; } private: - MT_Scalar ComputeTotalMass(const IK_QSegment *segment); - MT_Vector3 ComputeCenter(const IK_QSegment *segment); - void JacobianSegment(IK_QJacobian& jacobian, MT_Vector3& center, const IK_QSegment *segment); + double ComputeTotalMass(const IK_QSegment *segment); + Vector3d ComputeCenter(const IK_QSegment *segment); + void JacobianSegment(IK_QJacobian& jacobian, Vector3d& center, const IK_QSegment *segment); - MT_Vector3 m_goal_center; - MT_Scalar m_total_mass_inv; - MT_Scalar m_distance; + Vector3d m_goal_center; + double m_total_mass_inv; + double m_distance; }; -#endif - diff --git a/intern/iksolver/intern/IK_Solver.cpp b/intern/iksolver/intern/IK_Solver.cpp index eb18cde3356..cefb8c7ed7b 100644 --- a/intern/iksolver/intern/IK_Solver.cpp +++ b/intern/iksolver/intern/IK_Solver.cpp @@ -154,19 +154,19 @@ void IK_SetTransform(IK_Segment *seg, float start[3], float rest[][3], float bas { IK_QSegment *qseg = (IK_QSegment *)seg; - MT_Vector3 mstart(start); - // convert from blender column major to moto row major - MT_Matrix3x3 mbasis(basis[0][0], basis[1][0], basis[2][0], - basis[0][1], basis[1][1], basis[2][1], - basis[0][2], basis[1][2], basis[2][2]); - MT_Matrix3x3 mrest(rest[0][0], rest[1][0], rest[2][0], - rest[0][1], rest[1][1], rest[2][1], - rest[0][2], rest[1][2], rest[2][2]); - MT_Scalar mlength(length); + Vector3d mstart(start[0], start[1], start[2]); + // convert from blender column major + Matrix3d mbasis = CreateMatrix(basis[0][0], basis[1][0], basis[2][0], + basis[0][1], basis[1][1], basis[2][1], + basis[0][2], basis[1][2], basis[2][2]); + Matrix3d mrest = CreateMatrix(rest[0][0], rest[1][0], rest[2][0], + rest[0][1], rest[1][1], rest[2][1], + rest[0][2], rest[1][2], rest[2][2]); + double mlength(length); if (qseg->Composite()) { - MT_Vector3 cstart(0, 0, 0); - MT_Matrix3x3 cbasis; + Vector3d cstart(0, 0, 0); + Matrix3d cbasis; cbasis.setIdentity(); qseg->SetTransform(mstart, mrest, mbasis, 0.0); @@ -205,7 +205,7 @@ void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness) stiffness = (1.0 - IK_STRETCH_STIFF_EPS); IK_QSegment *qseg = (IK_QSegment *)seg; - MT_Scalar weight = 1.0f - stiffness; + double weight = 1.0f - stiffness; if (axis >= IK_TRANS_X) { if (!qseg->Translational()) { @@ -230,18 +230,18 @@ void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3]) if (qseg->Translational() && qseg->Composite()) qseg = qseg->Composite(); - const MT_Matrix3x3& change = qseg->BasisChange(); - - // convert from moto row major to blender column major - basis_change[0][0] = (float)change[0][0]; - basis_change[1][0] = (float)change[0][1]; - basis_change[2][0] = (float)change[0][2]; - basis_change[0][1] = (float)change[1][0]; - basis_change[1][1] = (float)change[1][1]; - basis_change[2][1] = (float)change[1][2]; - basis_change[0][2] = (float)change[2][0]; - basis_change[1][2] = (float)change[2][1]; - basis_change[2][2] = (float)change[2][2]; + const Matrix3d& change = qseg->BasisChange(); + + // convert to blender column major + basis_change[0][0] = (float)change(0, 0); + basis_change[1][0] = (float)change(0, 1); + basis_change[2][0] = (float)change(0, 2); + basis_change[0][1] = (float)change(1, 0); + basis_change[1][1] = (float)change(1, 1); + basis_change[2][1] = (float)change(1, 2); + basis_change[0][2] = (float)change(2, 0); + basis_change[1][2] = (float)change(2, 1); + basis_change[2][2] = (float)change(2, 2); } void IK_GetTranslationChange(IK_Segment *seg, float *translation_change) @@ -251,7 +251,7 @@ void IK_GetTranslationChange(IK_Segment *seg, float *translation_change) if (!qseg->Translational() && qseg->Composite()) qseg = qseg->Composite(); - const MT_Vector3& change = qseg->TranslationChange(); + const Vector3d& change = qseg->TranslationChange(); translation_change[0] = (float)change[0]; translation_change[1] = (float)change[1]; @@ -296,7 +296,7 @@ void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float w if (qtip->Composite()) qtip = qtip->Composite(); - MT_Vector3 pos(goal); + Vector3d pos(goal[0], goal[1], goal[2]); IK_QTask *ee = new IK_QPositionTask(true, qtip, pos); ee->SetWeight(weight); @@ -315,10 +315,10 @@ void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[ if (qtip->Composite()) qtip = qtip->Composite(); - // convert from blender column major to moto row major - MT_Matrix3x3 rot(goal[0][0], goal[1][0], goal[2][0], - goal[0][1], goal[1][1], goal[2][1], - goal[0][2], goal[1][2], goal[2][2]); + // convert from blender column major + Matrix3d rot = CreateMatrix(goal[0][0], goal[1][0], goal[2][0], + goal[0][1], goal[1][1], goal[2][1], + goal[0][2], goal[1][2], goal[2][2]); IK_QTask *orient = new IK_QOrientationTask(true, qtip, rot); orient->SetWeight(weight); @@ -337,8 +337,8 @@ void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float if (qtip->Composite()) qtip = qtip->Composite(); - MT_Vector3 qgoal(goal); - MT_Vector3 qpolegoal(polegoal); + Vector3d qgoal(goal[0], goal[1], goal[2]); + Vector3d qpolegoal(polegoal[0], polegoal[1], polegoal[2]); qsolver->solver.SetPoleVectorConstraint( qtip, qgoal, qpolegoal, poleangle, getangle); @@ -363,8 +363,8 @@ static void IK_SolverAddCenterOfMass(IK_Solver *solver, IK_Segment *root, float IK_QSolver *qsolver = (IK_QSolver *)solver; IK_QSegment *qroot = (IK_QSegment *)root; - // convert from blender column major to moto row major - MT_Vector3 center(goal); + // convert from blender column major + Vector3d center(goal); IK_QTask *com = new IK_QCenterOfMassTask(true, qroot, center); com->SetWeight(weight); @@ -382,7 +382,7 @@ int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations) IK_QSegment *root = qsolver->root; IK_QJacobianSolver& jacobian = qsolver->solver; std::list<IK_QTask *>& tasks = qsolver->tasks; - MT_Scalar tol = tolerance; + double tol = tolerance; if (!jacobian.Setup(root, tasks)) return 0; diff --git a/intern/iksolver/intern/MT_ExpMap.cpp b/intern/iksolver/intern/MT_ExpMap.cpp deleted file mode 100644 index b2b13acebeb..00000000000 --- a/intern/iksolver/intern/MT_ExpMap.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Original Author: Laurence - * Contributor(s): Brecht - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file iksolver/intern/MT_ExpMap.cpp - * \ingroup iksolver - */ - - -#include "MT_ExpMap.h" - -/** - * Set the exponential map from a quaternion. The quaternion must be non-zero. - */ - -void -MT_ExpMap:: -setRotation( - const MT_Quaternion &q) -{ - // ok first normalize the quaternion - // then compute theta the axis-angle and the normalized axis v - // scale v by theta and that's it hopefully! - - m_q = q.normalized(); - m_v = MT_Vector3(m_q.x(), m_q.y(), m_q.z()); - - MT_Scalar cosp = m_q.w(); - m_sinp = m_v.length(); - m_v /= m_sinp; - - m_theta = atan2(double(m_sinp), double(cosp)); - m_v *= m_theta; -} - -/** - * Convert from an exponential map to a quaternion - * representation - */ - -const MT_Quaternion& -MT_ExpMap:: -getRotation() const -{ - return m_q; -} - -/** - * Convert the exponential map to a 3x3 matrix - */ - -MT_Matrix3x3 -MT_ExpMap:: -getMatrix() const -{ - return MT_Matrix3x3(m_q); -} - -/** - * Update & reparameterizate the exponential map - */ - -void -MT_ExpMap:: -update( - const MT_Vector3& dv) -{ - m_v += dv; - - angleUpdated(); -} - -/** - * Compute the partial derivatives of the exponential - * map (dR/de - where R is a 3x3 rotation matrix formed - * from the map) and return them as a 3x3 matrix - */ - -void -MT_ExpMap:: -partialDerivatives( - MT_Matrix3x3& dRdx, - MT_Matrix3x3& dRdy, - MT_Matrix3x3& dRdz) const -{ - MT_Quaternion dQdx[3]; - - compute_dQdVi(dQdx); - - compute_dRdVi(dQdx[0], dRdx); - compute_dRdVi(dQdx[1], dRdy); - compute_dRdVi(dQdx[2], dRdz); -} - -void -MT_ExpMap:: -compute_dRdVi( - const MT_Quaternion &dQdvi, - MT_Matrix3x3 & dRdvi) const -{ - MT_Scalar prod[9]; - - /* This efficient formulation is arrived at by writing out the - * entire chain rule product dRdq * dqdv in terms of 'q' and - * noticing that all the entries are formed from sums of just - * nine products of 'q' and 'dqdv' */ - - prod[0] = -MT_Scalar(4) * m_q.x() * dQdvi.x(); - prod[1] = -MT_Scalar(4) * m_q.y() * dQdvi.y(); - prod[2] = -MT_Scalar(4) * m_q.z() * dQdvi.z(); - prod[3] = MT_Scalar(2) * (m_q.y() * dQdvi.x() + m_q.x() * dQdvi.y()); - prod[4] = MT_Scalar(2) * (m_q.w() * dQdvi.z() + m_q.z() * dQdvi.w()); - prod[5] = MT_Scalar(2) * (m_q.z() * dQdvi.x() + m_q.x() * dQdvi.z()); - prod[6] = MT_Scalar(2) * (m_q.w() * dQdvi.y() + m_q.y() * dQdvi.w()); - prod[7] = MT_Scalar(2) * (m_q.z() * dQdvi.y() + m_q.y() * dQdvi.z()); - prod[8] = MT_Scalar(2) * (m_q.w() * dQdvi.x() + m_q.x() * dQdvi.w()); - - /* first row, followed by second and third */ - dRdvi[0][0] = prod[1] + prod[2]; - dRdvi[0][1] = prod[3] - prod[4]; - dRdvi[0][2] = prod[5] + prod[6]; - - dRdvi[1][0] = prod[3] + prod[4]; - dRdvi[1][1] = prod[0] + prod[2]; - dRdvi[1][2] = prod[7] - prod[8]; - - dRdvi[2][0] = prod[5] - prod[6]; - dRdvi[2][1] = prod[7] + prod[8]; - dRdvi[2][2] = prod[0] + prod[1]; -} - -// compute partial derivatives dQ/dVi - -void -MT_ExpMap:: -compute_dQdVi( - MT_Quaternion *dQdX) const -{ - /* This is an efficient implementation of the derivatives given - * in Appendix A of the paper with common subexpressions factored out */ - - MT_Scalar sinc, termCoeff; - - if (m_theta < MT_EXPMAP_MINANGLE) { - sinc = 0.5 - m_theta * m_theta / 48.0; - termCoeff = (m_theta * m_theta / 40.0 - 1.0) / 24.0; - } - else { - MT_Scalar cosp = m_q.w(); - MT_Scalar ang = 1.0 / m_theta; - - sinc = m_sinp * ang; - termCoeff = ang * ang * (0.5 * cosp - sinc); - } - - for (int i = 0; i < 3; i++) { - MT_Quaternion& dQdx = dQdX[i]; - int i2 = (i + 1) % 3; - int i3 = (i + 2) % 3; - - MT_Scalar term = m_v[i] * termCoeff; - - dQdx[i] = term * m_v[i] + sinc; - dQdx[i2] = term * m_v[i2]; - dQdx[i3] = term * m_v[i3]; - dQdx.w() = -0.5 * m_v[i] * sinc; - } -} - -// reParametize away from singularity, updating -// m_v and m_theta - -void -MT_ExpMap:: -reParametrize() -{ - if (m_theta > MT_PI) { - MT_Scalar scl = m_theta; - if (m_theta > MT_2_PI) { /* first get theta into range 0..2PI */ - m_theta = MT_Scalar(fmod(m_theta, MT_2_PI)); - scl = m_theta / scl; - m_v *= scl; - } - if (m_theta > MT_PI) { - scl = m_theta; - m_theta = MT_2_PI - m_theta; - scl = MT_Scalar(1.0) - MT_2_PI / scl; - m_v *= scl; - } - } -} - -// compute cached variables - -void -MT_ExpMap:: -angleUpdated() -{ - m_theta = m_v.length(); - - reParametrize(); - - // compute quaternion, sinp and cosp - - if (m_theta < MT_EXPMAP_MINANGLE) { - m_sinp = MT_Scalar(0.0); - - /* Taylor Series for sinc */ - MT_Vector3 temp = m_v * MT_Scalar(MT_Scalar(.5) - m_theta * m_theta / MT_Scalar(48.0)); - m_q.x() = temp.x(); - m_q.y() = temp.y(); - m_q.z() = temp.z(); - m_q.w() = MT_Scalar(1.0); - } - else { - m_sinp = MT_Scalar(sin(.5 * m_theta)); - - /* Taylor Series for sinc */ - MT_Vector3 temp = m_v * (m_sinp / m_theta); - m_q.x() = temp.x(); - m_q.y() = temp.y(); - m_q.z() = temp.z(); - m_q.w() = MT_Scalar(cos(0.5 * m_theta)); - } -} - diff --git a/intern/iksolver/intern/MT_ExpMap.h b/intern/iksolver/intern/MT_ExpMap.h deleted file mode 100644 index 65bbe4d4ad5..00000000000 --- a/intern/iksolver/intern/MT_ExpMap.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Original author: Laurence - * Contributor(s): Brecht - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file iksolver/intern/MT_ExpMap.h - * \ingroup iksolver - */ - - -#ifndef MT_ExpMap_H -#define MT_ExpMap_H - -#include <MT_assert.h> - -#include "MT_Vector3.h" -#include "MT_Quaternion.h" -#include "MT_Matrix4x4.h" - -const MT_Scalar MT_EXPMAP_MINANGLE (1e-7); - -/** - * MT_ExpMap an exponential map parameterization of rotations - * in 3D. This implementation is derived from the paper - * "F. Sebastian Grassia. Practical parameterization of - * rotations using the exponential map. Journal of Graphics Tools, - * 3(3):29-48, 1998" Please go to http://www.acm.org/jgt/papers/Grassia98/ - * for a thorough description of the theory and sample code used - * to derive this class. - * - * Basic overview of why this class is used. - * In an IK system we need to paramterize the joint angles in some - * way. Typically 2 parameterizations are used. - * - Euler Angles - * These suffer from singularities in the parameterization known - * as gimbal lock. They also do not interpolate well. For every - * set of euler angles there is exactly 1 corresponding 3d rotation. - * - Quaternions. - * Great for interpolating. Only unit quaternions are valid rotations - * means that in a differential ik solver we often stray outside of - * this manifold into invalid rotations. Means we have to do a lot - * of nasty normalizations all the time. Does not suffer from - * gimbal lock problems. More expensive to compute partial derivatives - * as there are 4 of them. - * - * So exponential map is similar to a quaternion axis/angle - * representation but we store the angle as the length of the - * axis. So require only 3 parameters. Means that all exponential - * maps are valid rotations. Suffers from gimbal lock. But it's - * possible to detect when gimbal lock is near and reparameterize - * away from it. Also nice for interpolating. - * Exponential maps are share some of the useful properties of - * euler and quaternion parameterizations. And are very useful - * for differential IK solvers. - */ - -class MT_ExpMap { -public: - - /** - * Default constructor - * @warning there is no initialization in the - * default constructor - */ - - MT_ExpMap() {} - MT_ExpMap(const MT_Vector3& v) : m_v(v) { angleUpdated(); } - - MT_ExpMap(const float v[3]) : m_v(v) { angleUpdated(); } - MT_ExpMap(const double v[3]) : m_v(v) { angleUpdated(); } - - MT_ExpMap(MT_Scalar x, MT_Scalar y, MT_Scalar z) : - m_v(x, y, z) { angleUpdated(); } - - /** - * Construct an exponential map from a quaternion - */ - - MT_ExpMap( - const MT_Quaternion &q - ) { - setRotation(q); - } - - /** - * Accessors - * Decided not to inherit from MT_Vector3 but rather - * this class contains an MT_Vector3. This is because - * it is very dangerous to use MT_Vector3 functions - * on this class and some of them have no direct meaning. - */ - - const - MT_Vector3 & - vector( - ) const { - return m_v; - } - - /** - * Set the exponential map from a quaternion - */ - - void - setRotation( - const MT_Quaternion &q - ); - - /** - * Convert from an exponential map to a quaternion - * representation - */ - - const MT_Quaternion& - getRotation( - ) const; - - /** - * Convert the exponential map to a 3x3 matrix - */ - - MT_Matrix3x3 - getMatrix( - ) const; - - /** - * Update (and reparameterize) the expontial map - * @param dv delta update values. - */ - - void - update( - const MT_Vector3& dv - ); - - /** - * Compute the partial derivatives of the exponential - * map (dR/de - where R is a 4x4 matrix formed - * from the map) and return them as a 4x4 matrix - */ - - void - partialDerivatives( - MT_Matrix3x3& dRdx, - MT_Matrix3x3& dRdy, - MT_Matrix3x3& dRdz - ) const ; - -private : - - // m_v contains the exponential map, the other variables are - // cached for efficiency - - MT_Vector3 m_v; - MT_Scalar m_theta, m_sinp; - MT_Quaternion m_q; - - // private methods - - // Compute partial derivatives dR (3x3 rotation matrix) / dVi (EM vector) - // given the partial derivative dQ (Quaternion) / dVi (ith element of EM vector) - - void - compute_dRdVi( - const MT_Quaternion &dQdV, - MT_Matrix3x3 & dRdVi - ) const; - - // compute partial derivatives dQ/dVi - - void - compute_dQdVi( - MT_Quaternion *dQdX - ) const ; - - // reparametrize away from singularity - - void - reParametrize( - ); - - // (re-)compute cached variables - - void - angleUpdated( - ); -}; - -#endif - diff --git a/intern/iksolver/intern/TNT/cholesky.h b/intern/iksolver/intern/TNT/cholesky.h deleted file mode 100644 index 89c7dc64d5b..00000000000 --- a/intern/iksolver/intern/TNT/cholesky.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - */ - -/* -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - -#ifndef CHOLESKY_H -#define CHOLESKY_H - -#include <cmath> - -// index method - -namespace TNT -{ - - -// -// Only upper part of A is used. Cholesky factor is returned in -// lower part of L. Returns 0 if successful, 1 otherwise. -// -template <class SPDMatrix, class SymmMatrix> -int Cholesky_upper_factorization(SPDMatrix &A, SymmMatrix &L) -{ - Subscript M = A.dim(1); - Subscript N = A.dim(2); - - assert(M == N); // make sure A is square - - // readjust size of L, if necessary - - if (M != L.dim(1) || N != L.dim(2)) - L = SymmMatrix(N,N); - - Subscript i,j,k; - - - typename SPDMatrix::element_type dot=0; - - - for (j=1; j<=N; j++) // form column j of L - { - dot= 0; - - for (i=1; i<j; i++) // for k= 1 TO j-1 - dot = dot + L(j,i)*L(j,i); - - L(j,j) = A(j,j) - dot; - - for (i=j+1; i<=N; i++) - { - dot = 0; - for (k=1; k<j; k++) - dot = dot + L(i,k)*L(j,k); - L(i,j) = A(j,i) - dot; - } - - if (L(j,j) <= 0.0) return 1; - - L(j,j) = sqrt( L(j,j) ); - - for (i=j+1; i<=N; i++) - L(i,j) = L(i,j) / L(j,j); - - } - - return 0; -} - - - - -} -// namespace TNT - -#endif -// CHOLESKY_H - diff --git a/intern/iksolver/intern/TNT/cmat.h b/intern/iksolver/intern/TNT/cmat.h deleted file mode 100644 index fd3a1851262..00000000000 --- a/intern/iksolver/intern/TNT/cmat.h +++ /dev/null @@ -1,614 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -// C compatible matrix: row-oriented, 0-based [i][j] and 1-based (i,j) indexing -// - -#ifndef CMAT_H -#define CMAT_H - -#include "subscript.h" -#include "vec.h" -#include <stdlib.h> -#include <assert.h> -#include <iostream> -#ifdef TNT_USE_REGIONS -#include "region2d.h" -#endif - -namespace TNT -{ - -template <class T> -class Matrix -{ - - - public: - - typedef Subscript size_type; - typedef T value_type; - typedef T element_type; - typedef T* pointer; - typedef T* iterator; - typedef T& reference; - typedef const T* const_iterator; - typedef const T& const_reference; - - Subscript lbound() const { return 1;} - - protected: - Subscript m_; - Subscript n_; - Subscript mn_; // total size - T* v_; - T** row_; - T* vm1_ ; // these point to the same data, but are 1-based - T** rowm1_; - - // internal helper function to create the array - // of row pointers - - void initialize(Subscript M, Subscript N) - { - mn_ = M*N; - m_ = M; - n_ = N; - - v_ = new T[mn_]; - row_ = new T*[M]; - rowm1_ = new T*[M]; - - assert(v_ != NULL); - assert(row_ != NULL); - assert(rowm1_ != NULL); - - T* p = v_; - vm1_ = v_ - 1; - for (Subscript i=0; i<M; i++) - { - row_[i] = p; - rowm1_[i] = p-1; - p += N ; - - } - - rowm1_ -- ; // compensate for 1-based offset - } - - void copy(const T* v) - { - Subscript N = m_ * n_; - Subscript i; - -#ifdef TNT_UNROLL_LOOPS - Subscript Nmod4 = N & 3; - Subscript N4 = N - Nmod4; - - for (i=0; i<N4; i+=4) - { - v_[i] = v[i]; - v_[i+1] = v[i+1]; - v_[i+2] = v[i+2]; - v_[i+3] = v[i+3]; - } - - for (i=N4; i< N; i++) - v_[i] = v[i]; -#else - - for (i=0; i< N; i++) - v_[i] = v[i]; -#endif - } - - void set(const T& val) - { - Subscript N = m_ * n_; - Subscript i; - -#ifdef TNT_UNROLL_LOOPS - Subscript Nmod4 = N & 3; - Subscript N4 = N - Nmod4; - - for (i=0; i<N4; i+=4) - { - v_[i] = val; - v_[i+1] = val; - v_[i+2] = val; - v_[i+3] = val; - } - - for (i=N4; i< N; i++) - v_[i] = val; -#else - - for (i=0; i< N; i++) - v_[i] = val; - -#endif - } - - - - void destroy() - { - /* do nothing, if no memory has been previously allocated */ - if (v_ == NULL) return ; - - /* if we are here, then matrix was previously allocated */ - if (v_ != NULL) delete [] (v_); - if (row_ != NULL) delete [] (row_); - - /* return rowm1_ back to original value */ - rowm1_ ++; - if (rowm1_ != NULL ) delete [] (rowm1_); - } - - - public: - - operator T**(){ return row_; } - operator T**() const { return row_; } - - - Subscript size() const { return mn_; } - - // constructors - - Matrix() : m_(0), n_(0), mn_(0), v_(0), row_(0), vm1_(0), rowm1_(0) {} - - Matrix(const Matrix<T> &A) - { - initialize(A.m_, A.n_); - copy(A.v_); - } - - Matrix(Subscript M, Subscript N, const T& value = T()) - { - initialize(M,N); - set(value); - } - - Matrix(Subscript M, Subscript N, const T* v) - { - initialize(M,N); - copy(v); - } - - - // destructor - // - ~Matrix() - { - destroy(); - } - - - // reallocating - // - Matrix<T>& newsize(Subscript M, Subscript N) - { - if (num_rows() == M && num_cols() == N) - return *this; - - destroy(); - initialize(M,N); - - return *this; - } - - void - diagonal(Vector<T> &diag) - { - int sz = diag.dim(); - newsize(sz,sz); - set(0); - - Subscript i; - for (i = 0; i < sz; i++) { - row_[i][i] = diag[i]; - } - } - - - - // assignments - // - Matrix<T>& operator=(const Matrix<T> &A) - { - if (v_ == A.v_) - return *this; - - if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc - copy(A.v_); - - else - { - destroy(); - initialize(A.m_, A.n_); - copy(A.v_); - } - - return *this; - } - - Matrix<T>& operator=(const T& scalar) - { - set(scalar); - return *this; - } - - - Subscript dim(Subscript d) const - { -#ifdef TNT_BOUNDS_CHECK - assert( d >= 1); - assert( d <= 2); -#endif - return (d==1) ? m_ : ((d==2) ? n_ : 0); - } - - Subscript num_rows() const { return m_; } - Subscript num_cols() const { return n_; } - - - - - inline T* operator[](Subscript i) - { -#ifdef TNT_BOUNDS_CHECK - assert(0<=i); - assert(i < m_) ; -#endif - return row_[i]; - } - - inline const T* operator[](Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(0<=i); - assert(i < m_) ; -#endif - return row_[i]; - } - - inline reference operator()(Subscript i) - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i <= mn_) ; -#endif - return vm1_[i]; - } - - inline const_reference operator()(Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i <= mn_) ; -#endif - return vm1_[i]; - } - - - - inline reference operator()(Subscript i, Subscript j) - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i <= m_) ; - assert(1<=j); - assert(j <= n_); -#endif - return rowm1_[i][j]; - } - - - - inline const_reference operator() (Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i <= m_) ; - assert(1<=j); - assert(j <= n_); -#endif - return rowm1_[i][j]; - } - - - -#ifdef TNT_USE_REGIONS - - typedef Region2D<Matrix<T> > Region; - - - Region operator()(const Index1D &I, const Index1D &J) - { - return Region(*this, I,J); - } - - - typedef const_Region2D< Matrix<T> > const_Region; - const_Region operator()(const Index1D &I, const Index1D &J) const - { - return const_Region(*this, I,J); - } - -#endif - - -}; - - -/* *************************** I/O ********************************/ - -template <class T> -std::ostream& operator<<(std::ostream &s, const Matrix<T> &A) -{ - Subscript M=A.num_rows(); - Subscript N=A.num_cols(); - - s << M << " " << N << "\n"; - - for (Subscript i=0; i<M; i++) - { - for (Subscript j=0; j<N; j++) - { - s << A[i][j] << " "; - } - s << "\n"; - } - - - return s; -} - -template <class T> -std::istream& operator>>(std::istream &s, Matrix<T> &A) -{ - - Subscript M, N; - - s >> M >> N; - - if ( !(M == A.num_rows() && N == A.num_cols() )) - { - A.newsize(M,N); - } - - - for (Subscript i=0; i<M; i++) - for (Subscript j=0; j<N; j++) - { - s >> A[i][j]; - } - - - return s; -} - -// *******************[ basic matrix algorithms ]*************************** - -template <class T> -Matrix<T> operator+(const Matrix<T> &A, - const Matrix<T> &B) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(M==B.num_rows()); - assert(N==B.num_cols()); - - Matrix<T> tmp(M,N); - Subscript i,j; - - for (i=0; i<M; i++) - for (j=0; j<N; j++) - tmp[i][j] = A[i][j] + B[i][j]; - - return tmp; -} - -template <class T> -Matrix<T> operator-(const Matrix<T> &A, - const Matrix<T> &B) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(M==B.num_rows()); - assert(N==B.num_cols()); - - Matrix<T> tmp(M,N); - Subscript i,j; - - for (i=0; i<M; i++) - for (j=0; j<N; j++) - tmp[i][j] = A[i][j] - B[i][j]; - - return tmp; -} - -template <class T> -Matrix<T> mult_element(const Matrix<T> &A, - const Matrix<T> &B) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(M==B.num_rows()); - assert(N==B.num_cols()); - - Matrix<T> tmp(M,N); - Subscript i,j; - - for (i=0; i<M; i++) - for (j=0; j<N; j++) - tmp[i][j] = A[i][j] * B[i][j]; - - return tmp; -} - -template <class T> -void transpose(const Matrix<T> &A, Matrix<T> &S) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(M==S.num_cols()); - assert(N==S.num_rows()); - - Subscript i, j; - - for (i=0; i<M; i++) - for (j=0; j<N; j++) - S[j][i] = A[i][j]; - -} - - -template <class T> -inline void matmult(Matrix<T>& C, const Matrix<T> &A, - const Matrix<T> &B) -{ - - assert(A.num_cols() == B.num_rows()); - - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - Subscript K = B.num_cols(); - - C.newsize(M,K); - - T sum; - - const T* row_i; - const T* col_k; - - for (Subscript i=0; i<M; i++) - for (Subscript k=0; k<K; k++) - { - row_i = &(A[i][0]); - col_k = &(B[0][k]); - sum = 0; - for (Subscript j=0; j<N; j++) - { - sum += *row_i * *col_k; - row_i++; - col_k += K; - } - C[i][k] = sum; - } - -} - -template <class T> -void matmult(Vector<T> &y, const Matrix<T> &A, const Vector<T> &x) -{ - -#ifdef TNT_BOUNDS_CHECK - assert(A.num_cols() == x.dim()); - assert(A.num_rows() == y.dim()); -#endif - - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - T sum; - - for (Subscript i=0; i<M; i++) - { - sum = 0; - const T* rowi = A[i]; - for (Subscript j=0; j<N; j++) - sum = sum + rowi[j] * x[j]; - - y[i] = sum; - } -} - -template <class T> -inline void matmultdiag( - Matrix<T>& C, - const Matrix<T> &A, - const Vector<T> &diag -){ -#ifdef TNT_BOUNDS_CHECK - assert(A.num_cols() ==A.num_rows()== diag.dim()); -#endif - - Subscript M = A.num_rows(); - Subscript K = diag.dim(); - - C.newsize(M,K); - - const T* row_i; - const T* col_k; - - for (Subscript i=0; i<M; i++) { - for (Subscript k=0; k<K; k++) - { - C[i][k] = A[i][k] * diag[k]; - } - } -} - - -template <class T> -inline void matmultdiag( - Matrix<T>& C, - const Vector<T> &diag, - const Matrix<T> &A -){ -#ifdef TNT_BOUNDS_CHECK - assert(A.num_cols() ==A.num_rows()== diag.dim()); -#endif - - Subscript M = A.num_rows(); - Subscript K = diag.dim(); - - C.newsize(M,K); - - for (Subscript i=0; i<M; i++) { - - const T diag_element = diag[i]; - - for (Subscript k=0; k<K; k++) - { - C[i][k] = A[i][k] * diag_element; - } - } -} - -} // namespace TNT - -#endif // CMAT_H - diff --git a/intern/iksolver/intern/TNT/fcscmat.h b/intern/iksolver/intern/TNT/fcscmat.h deleted file mode 100644 index 8865dc7a039..00000000000 --- a/intern/iksolver/intern/TNT/fcscmat.h +++ /dev/null @@ -1,167 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -// Templated compressed sparse column matrix (Fortran conventions). -// uses 1-based offsets in storing row indices. -// Used primarily to interface with Fortran sparse matrix libaries. -// (CANNOT BE USED AS AN STL CONTAINER.) - - -#ifndef FCSCMAT_H -#define FCSCMAT_H - -#include <iostream> -#include <cassert> -#include "tnt.h" -#include "vec.h" - -using namespace std; - -namespace TNT -{ - -template <class T> -class Fortran_Sparse_Col_Matrix -{ - - protected: - - Vector<T> val_; // data values (nz_ elements) - Vector<Subscript> rowind_; // row_ind (nz_ elements) - Vector<Subscript> colptr_; // col_ptr (n_+1 elements) - - int nz_; // number of nonzeros - Subscript m_; // global dimensions - Subscript n_; - - public: - - - Fortran_Sparse_Col_Matrix(void); - Fortran_Sparse_Col_Matrix(const Fortran_Sparse_Col_Matrix<T> &S) - : val_(S.val_), rowind_(S.rowind_), colptr_(S.colptr_), nz_(S.nz_), - m_(S.m_), n_(S.n_) {}; - Fortran_Sparse_Col_Matrix(Subscript M, Subscript N, - Subscript nz, const T *val, const Subscript *r, - const Subscript *c) : val_(nz, val), rowind_(nz, r), - colptr_(N+1, c), nz_(nz), m_(M), n_(N) {}; - - Fortran_Sparse_Col_Matrix(Subscript M, Subscript N, - Subscript nz, char *val, char *r, - char *c) : val_(nz, val), rowind_(nz, r), - colptr_(N+1, c), nz_(nz), m_(M), n_(N) {}; - - Fortran_Sparse_Col_Matrix(Subscript M, Subscript N, - Subscript nz, const T *val, Subscript *r, Subscript *c) - : val_(nz, val), rowind_(nz, r), colptr_(N+1, c), nz_(nz), - m_(M), n_(N) {}; - - ~Fortran_Sparse_Col_Matrix() {}; - - - T & val(Subscript i) { return val_(i); } - const T & val(Subscript i) const { return val_(i); } - - Subscript & row_ind(Subscript i) { return rowind_(i); } - const Subscript & row_ind(Subscript i) const { return rowind_(i); } - - Subscript col_ptr(Subscript i) { return colptr_(i);} - const Subscript col_ptr(Subscript i) const { return colptr_(i);} - - - Subscript num_cols() const { return m_;} - Subscript num_rows() const { return n_; } - - Subscript dim(Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert( 1 <= i ); - assert( i <= 2 ); -#endif - if (i==1) return m_; - else if (i==2) return m_; - else return 0; - } - - Subscript num_nonzeros() const {return nz_;}; - Subscript lbound() const {return 1;} - - - - Fortran_Sparse_Col_Matrix& operator=(const - Fortran_Sparse_Col_Matrix &C) - { - val_ = C.val_; - rowind_ = C.rowind_; - colptr_ = C.colptr_; - nz_ = C.nz_; - m_ = C.m_; - n_ = C.n_; - - return *this; - } - - Fortran_Sparse_Col_Matrix& newsize(Subscript M, Subscript N, - Subscript nz) - { - val_.newsize(nz); - rowind_.newsize(nz); - colptr_.newsize(N+1); - return *this; - } -}; - -template <class T> -ostream& operator<<(ostream &s, const Fortran_Sparse_Col_Matrix<T> &A) -{ - Subscript M=A.num_rows(); - Subscript N=A.num_cols(); - - s << M << " " << N << " " << A.num_nonzeros() << endl; - - - for (Subscript k=1; k<=N; k++) - { - Subscript start = A.col_ptr(k); - Subscript end = A.col_ptr(k+1); - - for (Subscript i= start; i<end; i++) - { - s << A.row_ind(i) << " " << k << " " << A.val(i) << endl; - } - } - - return s; -} - - -} // namespace TNT - -#endif /* FCSCMAT_H */ - diff --git a/intern/iksolver/intern/TNT/fmat.h b/intern/iksolver/intern/TNT/fmat.h deleted file mode 100644 index edb64003143..00000000000 --- a/intern/iksolver/intern/TNT/fmat.h +++ /dev/null @@ -1,569 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -// Fortran-compatible matrix: column oriented, 1-based (i,j) indexing - -#ifndef FMAT_H -#define FMAT_H - -#include "subscript.h" -#include "vec.h" -#include <cstdlib> -#include <cassert> -#include <iostream> -#ifdef TNT_USE_REGIONS -#include "region2d.h" -#endif - -// simple 1-based, column oriented Matrix class - -namespace TNT -{ - -template <class T> -class Fortran_Matrix -{ - - - public: - - typedef T value_type; - typedef T element_type; - typedef T* pointer; - typedef T* iterator; - typedef T& reference; - typedef const T* const_iterator; - typedef const T& const_reference; - - Subscript lbound() const { return 1;} - - protected: - T* v_; // these are adjusted to simulate 1-offset - Subscript m_; - Subscript n_; - T** col_; // these are adjusted to simulate 1-offset - - // internal helper function to create the array - // of row pointers - - void initialize(Subscript M, Subscript N) - { - // adjust col_[] pointers so that they are 1-offset: - // col_[j][i] is really col_[j-1][i-1]; - // - // v_[] is the internal contiguous array, it is still 0-offset - // - v_ = new T[M*N]; - col_ = new T*[N]; - - assert(v_ != NULL); - assert(col_ != NULL); - - - m_ = M; - n_ = N; - T* p = v_ - 1; - for (Subscript i=0; i<N; i++) - { - col_[i] = p; - p += M ; - - } - col_ --; - } - - void copy(const T* v) - { - Subscript N = m_ * n_; - Subscript i; - -#ifdef TNT_UNROLL_LOOPS - Subscript Nmod4 = N & 3; - Subscript N4 = N - Nmod4; - - for (i=0; i<N4; i+=4) - { - v_[i] = v[i]; - v_[i+1] = v[i+1]; - v_[i+2] = v[i+2]; - v_[i+3] = v[i+3]; - } - - for (i=N4; i< N; i++) - v_[i] = v[i]; -#else - - for (i=0; i< N; i++) - v_[i] = v[i]; -#endif - } - - void set(const T& val) - { - Subscript N = m_ * n_; - Subscript i; - -#ifdef TNT_UNROLL_LOOPS - Subscript Nmod4 = N & 3; - Subscript N4 = N - Nmod4; - - for (i=0; i<N4; i+=4) - { - v_[i] = val; - v_[i+1] = val; - v_[i+2] = val; - v_[i+3] = val; - } - - for (i=N4; i< N; i++) - v_[i] = val; -#else - - for (i=0; i< N; i++) - v_[i] = val; - -#endif - } - - - - void destroy() - { - /* do nothing, if no memory has been previously allocated */ - if (v_ == NULL) return ; - - /* if we are here, then matrix was previously allocated */ - delete [] (v_); - col_ ++; // changed back to 0-offset - delete [] (col_); - } - - - public: - - T* begin() { return v_; } - const T* begin() const { return v_;} - - T* end() { return v_ + m_*n_; } - const T* end() const { return v_ + m_*n_; } - - - // constructors - - Fortran_Matrix() : v_(0), m_(0), n_(0), col_(0) {}; - Fortran_Matrix(const Fortran_Matrix<T> &A) - { - initialize(A.m_, A.n_); - copy(A.v_); - } - - Fortran_Matrix(Subscript M, Subscript N, const T& value = T()) - { - initialize(M,N); - set(value); - } - - Fortran_Matrix(Subscript M, Subscript N, const T* v) - { - initialize(M,N); - copy(v); - } - - - // destructor - ~Fortran_Matrix() - { - destroy(); - } - - - // assignments - // - Fortran_Matrix<T>& operator=(const Fortran_Matrix<T> &A) - { - if (v_ == A.v_) - return *this; - - if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc - copy(A.v_); - - else - { - destroy(); - initialize(A.m_, A.n_); - copy(A.v_); - } - - return *this; - } - - Fortran_Matrix<T>& operator=(const T& scalar) - { - set(scalar); - return *this; - } - - - Subscript dim(Subscript d) const - { -#ifdef TNT_BOUNDS_CHECK - assert( d >= 1); - assert( d <= 2); -#endif - return (d==1) ? m_ : ((d==2) ? n_ : 0); - } - - Subscript num_rows() const { return m_; } - Subscript num_cols() const { return n_; } - - Fortran_Matrix<T>& newsize(Subscript M, Subscript N) - { - if (num_rows() == M && num_cols() == N) - return *this; - - destroy(); - initialize(M,N); - - return *this; - } - - - - // 1-based element access - // - inline reference operator()(Subscript i, Subscript j) - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i <= m_) ; - assert(1<=j); - assert(j <= n_); -#endif - return col_[j][i]; - } - - inline const_reference operator() (Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i <= m_) ; - assert(1<=j); - assert(j <= n_); -#endif - return col_[j][i]; - } - - -#ifdef TNT_USE_REGIONS - - typedef Region2D<Fortran_Matrix<T> > Region; - typedef const_Region2D< Fortran_Matrix<T> > const_Region; - - Region operator()(const Index1D &I, const Index1D &J) - { - return Region(*this, I,J); - } - - const_Region operator()(const Index1D &I, const Index1D &J) const - { - return const_Region(*this, I,J); - } - -#endif - - -}; - - -/* *************************** I/O ********************************/ - -template <class T> -std::ostream& operator<<(std::ostream &s, const Fortran_Matrix<T> &A) -{ - Subscript M=A.num_rows(); - Subscript N=A.num_cols(); - - s << M << " " << N << "\n"; - - for (Subscript i=1; i<=M; i++) - { - for (Subscript j=1; j<=N; j++) - { - s << A(i,j) << " "; - } - s << "\n"; - } - - - return s; -} - -template <class T> -std::istream& operator>>(std::istream &s, Fortran_Matrix<T> &A) -{ - - Subscript M, N; - - s >> M >> N; - - if ( !(M == A.num_rows() && N == A.num_cols())) - { - A.newsize(M,N); - } - - - for (Subscript i=1; i<=M; i++) - for (Subscript j=1; j<=N; j++) - { - s >> A(i,j); - } - - - return s; -} - -// *******************[ basic matrix algorithms ]*************************** - - -template <class T> -Fortran_Matrix<T> operator+(const Fortran_Matrix<T> &A, - const Fortran_Matrix<T> &B) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(M==B.num_rows()); - assert(N==B.num_cols()); - - Fortran_Matrix<T> tmp(M,N); - Subscript i,j; - - for (i=1; i<=M; i++) - for (j=1; j<=N; j++) - tmp(i,j) = A(i,j) + B(i,j); - - return tmp; -} - -template <class T> -Fortran_Matrix<T> operator-(const Fortran_Matrix<T> &A, - const Fortran_Matrix<T> &B) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(M==B.num_rows()); - assert(N==B.num_cols()); - - Fortran_Matrix<T> tmp(M,N); - Subscript i,j; - - for (i=1; i<=M; i++) - for (j=1; j<=N; j++) - tmp(i,j) = A(i,j) - B(i,j); - - return tmp; -} - -// element-wise multiplication (use matmult() below for matrix -// multiplication in the linear algebra sense.) -// -// -template <class T> -Fortran_Matrix<T> mult_element(const Fortran_Matrix<T> &A, - const Fortran_Matrix<T> &B) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(M==B.num_rows()); - assert(N==B.num_cols()); - - Fortran_Matrix<T> tmp(M,N); - Subscript i,j; - - for (i=1; i<=M; i++) - for (j=1; j<=N; j++) - tmp(i,j) = A(i,j) * B(i,j); - - return tmp; -} - - -template <class T> -Fortran_Matrix<T> transpose(const Fortran_Matrix<T> &A) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - Fortran_Matrix<T> S(N,M); - Subscript i, j; - - for (i=1; i<=M; i++) - for (j=1; j<=N; j++) - S(j,i) = A(i,j); - - return S; -} - - - -template <class T> -inline Fortran_Matrix<T> matmult(const Fortran_Matrix<T> &A, - const Fortran_Matrix<T> &B) -{ - -#ifdef TNT_BOUNDS_CHECK - assert(A.num_cols() == B.num_rows()); -#endif - - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - Subscript K = B.num_cols(); - - Fortran_Matrix<T> tmp(M,K); - T sum; - - for (Subscript i=1; i<=M; i++) - for (Subscript k=1; k<=K; k++) - { - sum = 0; - for (Subscript j=1; j<=N; j++) - sum = sum + A(i,j) * B(j,k); - - tmp(i,k) = sum; - } - - return tmp; -} - -template <class T> -inline Fortran_Matrix<T> operator*(const Fortran_Matrix<T> &A, - const Fortran_Matrix<T> &B) -{ - return matmult(A,B); -} - -template <class T> -inline int matmult(Fortran_Matrix<T>& C, const Fortran_Matrix<T> &A, - const Fortran_Matrix<T> &B) -{ - - assert(A.num_cols() == B.num_rows()); - - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - Subscript K = B.num_cols(); - - C.newsize(M,K); // adjust shape of C, if necessary - - - T sum; - - const T* row_i; - const T* col_k; - - for (Subscript i=1; i<=M; i++) - { - for (Subscript k=1; k<=K; k++) - { - row_i = &A(i,1); - col_k = &B(1,k); - sum = 0; - for (Subscript j=1; j<=N; j++) - { - sum += *row_i * *col_k; - row_i += M; - col_k ++; - } - - C(i,k) = sum; - } - - } - - return 0; -} - - -template <class T> -Vector<T> matmult(const Fortran_Matrix<T> &A, const Vector<T> &x) -{ - -#ifdef TNT_BOUNDS_CHECK - assert(A.num_cols() == x.dim()); -#endif - - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - Vector<T> tmp(M); - T sum; - - for (Subscript i=1; i<=M; i++) - { - sum = 0; - for (Subscript j=1; j<=N; j++) - sum = sum + A(i,j) * x(j); - - tmp(i) = sum; - } - - return tmp; -} - -template <class T> -inline Vector<T> operator*(const Fortran_Matrix<T> &A, const Vector<T> &x) -{ - return matmult(A,x); -} - -template <class T> -inline Fortran_Matrix<T> operator*(const Fortran_Matrix<T> &A, const T &x) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - Subscript MN = M*N; - - Fortran_Matrix<T> res(M,N); - const T* a = A.begin(); - T* t = res.begin(); - T* tend = res.end(); - - for (t=res.begin(); t < tend; t++, a++) - *t = *a * x; - - return res; -} - -} // namespace TNT - -#endif // FMAT_H - diff --git a/intern/iksolver/intern/TNT/fortran.h b/intern/iksolver/intern/TNT/fortran.h deleted file mode 100644 index c58a859741b..00000000000 --- a/intern/iksolver/intern/TNT/fortran.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -// Header file to define C/Fortran conventions (Platform specific) - -#ifndef FORTRAN_H -#define FORTRAN_H - -// help map between C/C++ data types and Fortran types - -typedef int Fortran_integer; -typedef float Fortran_float; -typedef double Fortran_double; - - -typedef Fortran_double *fda_; // (in/out) double precision array -typedef const Fortran_double *cfda_; // (in) double precsion array - -typedef Fortran_double *fd_; // (in/out) single double precision -typedef const Fortran_double *cfd_; // (in) single double precision - -typedef Fortran_float *ffa_; // (in/out) float precision array -typedef const Fortran_float *cffa_; // (in) float precsion array - -typedef Fortran_float *ff_; // (in/out) single float precision -typedef const Fortran_float *cff_; // (in) single float precision - -typedef Fortran_integer *fia_; // (in/out) single integer array -typedef const Fortran_integer *cfia_; // (in) single integer array - -typedef Fortran_integer *fi_; // (in/out) single integer -typedef const Fortran_integer *cfi_; // (in) single integer - -typedef char *fch_; // (in/out) single character -typedef char *cfch_; // (in) single character - - -#ifndef TNT_SUBSCRIPT_TYPE -#define TNT_SUBSCRIPT_TYPE TNT::Fortran_integer -#endif - -#endif // FORTRAN_H - diff --git a/intern/iksolver/intern/TNT/fspvec.h b/intern/iksolver/intern/TNT/fspvec.h deleted file mode 100644 index 8b14fa89216..00000000000 --- a/intern/iksolver/intern/TNT/fspvec.h +++ /dev/null @@ -1,171 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - -// Templated sparse vector (Fortran conventions). -// Used primarily to interface with Fortran sparse matrix libaries. -// (CANNOT BE USED AS AN STL CONTAINER.) - -#ifndef FSPVEC_H -#define FSPVEC_H - -#include "tnt.h" -#include "vec.h" -#include <cstdlib> -#include <cassert> -#include <iostream> - -using namespace std; - -namespace TNT -{ - -template <class T> -class Fortran_Sparse_Vector -{ - - - public: - - typedef Subscript size_type; - typedef T value_type; - typedef T element_type; - typedef T* pointer; - typedef T* iterator; - typedef T& reference; - typedef const T* const_iterator; - typedef const T& const_reference; - - Subscript lbound() const { return 1;} - - protected: - Vector<T> val_; - Vector<Subscript> index_; - Subscript dim_; // prescribed dimension - - - public: - - // size and shape information - - Subscript dim() const { return dim_; } - Subscript num_nonzeros() const { return val_.dim(); } - - // access - - T& val(Subscript i) { return val_(i); } - const T& val(Subscript i) const { return val_(i); } - - Subscript &index(Subscript i) { return index_(i); } - const Subscript &index(Subscript i) const { return index_(i); } - - // constructors - - Fortran_Sparse_Vector() : val_(), index_(), dim_(0) {}; - Fortran_Sparse_Vector(Subscript N, Subscript nz) : val_(nz), - index_(nz), dim_(N) {}; - Fortran_Sparse_Vector(Subscript N, Subscript nz, const T *values, - const Subscript *indices): val_(nz, values), index_(nz, indices), - dim_(N) {} - - Fortran_Sparse_Vector(const Fortran_Sparse_Vector<T> &S): - val_(S.val_), index_(S.index_), dim_(S.dim_) {} - - // initialize from string, e.g. - // - // Fortran_Sparse_Vector<T> A(N, 2, "1.0 2.1", "1 3"); - // - Fortran_Sparse_Vector(Subscript N, Subscript nz, char *v, - char *ind) : val_(nz, v), index_(nz, ind), dim_(N) {} - - // assignments - - Fortran_Sparse_Vector<T> & newsize(Subscript N, Subscript nz) - { - val_.newsize(nz); - index_.newsize(nz); - dim_ = N; - return *this; - } - - Fortran_Sparse_Vector<T> & operator=( const Fortran_Sparse_Vector<T> &A) - { - val_ = A.val_; - index_ = A.index_; - dim_ = A.dim_; - - return *this; - } - - // methods - - - -}; - - -/* *************************** I/O ********************************/ - -template <class T> -ostream& operator<<(ostream &s, const Fortran_Sparse_Vector<T> &A) -{ - // output format is : N nz val1 ind1 val2 ind2 ... - Subscript nz=A.num_nonzeros(); - - s << A.dim() << " " << nz << endl; - - for (Subscript i=1; i<=nz; i++) - s << A.val(i) << " " << A.index(i) << endl; - s << endl; - - return s; -} - - -template <class T> -istream& operator>>(istream &s, Fortran_Sparse_Vector<T> &A) -{ - // output format is : N nz val1 ind1 val2 ind2 ... - - Subscript N; - Subscript nz; - - s >> N >> nz; - - A.newsize(N, nz); - - for (Subscript i=1; i<=nz; i++) - s >> A.val(i) >> A.index(i); - - - return s; -} - -} // namespace TNT - -#endif // FSPVEC_H - diff --git a/intern/iksolver/intern/TNT/index.h b/intern/iksolver/intern/TNT/index.h deleted file mode 100644 index 1abe20ba729..00000000000 --- a/intern/iksolver/intern/TNT/index.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -// Vector/Matrix/Array Index Module - -#ifndef INDEX_H -#define INDEX_H - -#include "subscript.h" - -namespace TNT -{ - -class Index1D -{ - Subscript lbound_; - Subscript ubound_; - - public: - - Subscript lbound() const { return lbound_; } - Subscript ubound() const { return ubound_; } - - Index1D(const Index1D &D) : lbound_(D.lbound_), ubound_(D.ubound_) {} - Index1D(Subscript i1, Subscript i2) : lbound_(i1), ubound_(i2) {} - - Index1D & operator=(const Index1D &D) - { - lbound_ = D.lbound_; - ubound_ = D.ubound_; - return *this; - } - -}; - -inline Index1D operator+(const Index1D &D, Subscript i) -{ - return Index1D(i+D.lbound(), i+D.ubound()); -} - -inline Index1D operator+(Subscript i, const Index1D &D) -{ - return Index1D(i+D.lbound(), i+D.ubound()); -} - - - -inline Index1D operator-(Index1D &D, Subscript i) -{ - return Index1D(D.lbound()-i, D.ubound()-i); -} - -inline Index1D operator-(Subscript i, Index1D &D) -{ - return Index1D(i-D.lbound(), i-D.ubound()); -} - -} // namespace TNT - -#endif - diff --git a/intern/iksolver/intern/TNT/lapack.h b/intern/iksolver/intern/TNT/lapack.h deleted file mode 100644 index e015fa9b617..00000000000 --- a/intern/iksolver/intern/TNT/lapack.h +++ /dev/null @@ -1,189 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -// Header file for Fortran Lapack - -#ifndef LAPACK_H -#define LAPACK_H - -// This file incomplete and included here to only demonstrate the -// basic framework for linking with the Fortran Lapack routines. - -#include "fortran.h" -#include "vec.h" -#include "fmat.h" - - -#define F77_DGESV dgesv_ -#define F77_DGELS dgels_ -#define F77_DSYEV dsyev_ -#define F77_DGEEV dgeev_ - -extern "C" -{ - - // linear equations (general) using LU factorizaiton - // - void F77_DGESV(cfi_ N, cfi_ nrhs, fda_ A, cfi_ lda, - fia_ ipiv, fda_ b, cfi_ ldb, fi_ info); - - // solve linear least squares using QR or LU factorization - // - void F77_DGELS(cfch_ trans, cfi_ M, - cfi_ N, cfi_ nrhs, fda_ A, cfi_ lda, fda_ B, cfi_ ldb, fda_ work, - cfi_ lwork, fi_ info); - - // solve symmetric eigenvalues - // - void F77_DSYEV( cfch_ jobz, cfch_ uplo, cfi_ N, fda_ A, cfi_ lda, - fda_ W, fda_ work, cfi_ lwork, fi_ info); - - // solve unsymmetric eigenvalues - // - void F77_DGEEV(cfch_ jobvl, cfch_ jobvr, cfi_ N, fda_ A, cfi_ lda, - fda_ wr, fda_ wi, fda_ vl, cfi_ ldvl, fda_ vr, - cfi_ ldvr, fda_ work, cfi_ lwork, fi_ info); - -} - -// solve linear equations using LU factorization - -using namespace TNT; - -Vector<double> Lapack_LU_linear_solve(const Fortran_Matrix<double> &A, - const Vector<double> &b) -{ - const Fortran_integer one=1; - Subscript M=A.num_rows(); - Subscript N=A.num_cols(); - - Fortran_Matrix<double> Tmp(A); - Vector<double> x(b); - Vector<Fortran_integer> index(M); - Fortran_integer info = 0; - - F77_DGESV(&N, &one, &Tmp(1,1), &M, &index(1), &x(1), &M, &info); - - if (info != 0) return Vector<double>(0); - else - return x; -} - -// solve linear least squares problem using QR factorization -// -Vector<double> Lapack_LLS_QR_linear_solve(const Fortran_Matrix<double> &A, - const Vector<double> &b) -{ - const Fortran_integer one=1; - Subscript M=A.num_rows(); - Subscript N=A.num_cols(); - - Fortran_Matrix<double> Tmp(A); - Vector<double> x(b); - Fortran_integer info = 0; - - char transp = 'N'; - Fortran_integer lwork = 5 * (M+N); // temporary work space - Vector<double> work(lwork); - - F77_DGELS(&transp, &M, &N, &one, &Tmp(1,1), &M, &x(1), &M, &work(1), - &lwork, &info); - - if (info != 0) return Vector<double>(0); - else - return x; -} - -// *********************** Eigenvalue problems ******************* - -// solve symmetric eigenvalue problem (eigenvalues only) -// -Vector<double> Upper_symmetric_eigenvalue_solve(const Fortran_Matrix<double> &A) -{ - char jobz = 'N'; - char uplo = 'U'; - Subscript N = A.num_rows(); - - assert(N == A.num_cols()); - - Vector<double> eigvals(N); - Fortran_integer worksize = 3*N; - Fortran_integer info = 0; - Vector<double> work(worksize); - Fortran_Matrix<double> Tmp = A; - - F77_DSYEV(&jobz, &uplo, &N, &Tmp(1,1), &N, eigvals.begin(), work.begin(), - &worksize, &info); - - if (info != 0) return Vector<double>(); - else - return eigvals; -} - - -// solve unsymmetric eigenvalue problems -// -int eigenvalue_solve(const Fortran_Matrix<double> &A, - Vector<double> &wr, Vector<double> &wi) -{ - char jobvl = 'N'; - char jobvr = 'N'; - - Fortran_integer N = A.num_rows(); - - - assert(N == A.num_cols()); - - if (N<1) return 1; - - Fortran_Matrix<double> vl(1,N); /* should be NxN ? **** */ - Fortran_Matrix<double> vr(1,N); - Fortran_integer one = 1; - - Fortran_integer worksize = 5*N; - Fortran_integer info = 0; - Vector<double> work(worksize, 0.0); - Fortran_Matrix<double> Tmp = A; - - wr.newsize(N); - wi.newsize(N); - -// void F77_DGEEV(cfch_ jobvl, cfch_ jobvr, cfi_ N, fda_ A, cfi_ lda, -// fda_ wr, fda_ wi, fda_ vl, cfi_ ldvl, fda_ vr, -// cfi_ ldvr, fda_ work, cfi_ lwork, fi_ info); - - F77_DGEEV(&jobvl, &jobvr, &N, &Tmp(1,1), &N, &(wr(1)), - &(wi(1)), &(vl(1,1)), &one, &(vr(1,1)), &one, - &(work(1)), &worksize, &info); - - return (info==0 ? 0: 1); -} - -#endif // LAPACK_H - diff --git a/intern/iksolver/intern/TNT/lu.h b/intern/iksolver/intern/TNT/lu.h deleted file mode 100644 index f64172bd31f..00000000000 --- a/intern/iksolver/intern/TNT/lu.h +++ /dev/null @@ -1,208 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -#ifndef LU_H -#define LU_H - -// Solve system of linear equations Ax = b. -// -// Typical usage: -// -// Matrix(double) A; -// Vector(Subscript) ipiv; -// Vector(double) b; -// -// 1) LU_Factor(A,ipiv); -// 2) LU_Solve(A,ipiv,b); -// -// Now b has the solution x. Note that both A and b -// are overwritten. If these values need to be preserved, -// one can make temporary copies, as in -// -// O) Matrix(double) T = A; -// 1) LU_Factor(T,ipiv); -// 1a) Vector(double) x=b; -// 2) LU_Solve(T,ipiv,x); -// -// See details below. -// - - -// for fabs() -// -#include <cmath> - -// right-looking LU factorization algorithm (unblocked) -// -// Factors matrix A into lower and upper triangular matrices -// (L and U respectively) in solving the linear equation Ax=b. -// -// -// Args: -// -// A (input/output) Matrix(1:n, 1:n) In input, matrix to be -// factored. On output, overwritten with lower and -// upper triangular factors. -// -// indx (output) Vector(1:n) Pivot vector. Describes how -// the rows of A were reordered to increase -// numerical stability. -// -// Return value: -// -// int (0 if successful, 1 otherwise) -// -// - - -namespace TNT -{ - -template <class MaTRiX, class VecToRSubscript> -int LU_factor( MaTRiX &A, VecToRSubscript &indx) -{ - assert(A.lbound() == 1); // currently for 1-offset - assert(indx.lbound() == 1); // vectors and matrices - - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - if (M == 0 || N==0) return 0; - if (indx.dim() != M) - indx.newsize(M); - - Subscript i=0,j=0,k=0; - Subscript jp=0; - - typename MaTRiX::element_type t; - - Subscript minMN = (M < N ? M : N) ; // min(M,N); - - for (j=1; j<= minMN; j++) - { - - // find pivot in column j and test for singularity. - - jp = j; - t = fabs(A(j,j)); - for (i=j+1; i<=M; i++) - if ( fabs(A(i,j)) > t) - { - jp = i; - t = fabs(A(i,j)); - } - - indx(j) = jp; - - // jp now has the index of maximum element - // of column j, below the diagonal - - if ( A(jp,j) == 0 ) - return 1; // factorization failed because of zero pivot - - - if (jp != j) // swap rows j and jp - for (k=1; k<=N; k++) - { - t = A(j,k); - A(j,k) = A(jp,k); - A(jp,k) =t; - } - - if (j<M) // compute elements j+1:M of jth column - { - // note A(j,j), was A(jp,p) previously which was - // guarranteed not to be zero (Label #1) - // - typename MaTRiX::element_type recp = 1.0 / A(j,j); - - for (k=j+1; k<=M; k++) - A(k,j) *= recp; - } - - - if (j < minMN) - { - // rank-1 update to trailing submatrix: E = E - x*y; - // - // E is the region A(j+1:M, j+1:N) - // x is the column vector A(j+1:M,j) - // y is row vector A(j,j+1:N) - - Subscript ii,jj; - - for (ii=j+1; ii<=M; ii++) - for (jj=j+1; jj<=N; jj++) - A(ii,jj) -= A(ii,j)*A(j,jj); - } - } - - return 0; -} - - - - -template <class MaTRiX, class VecToR, class VecToRSubscripts> -int LU_solve(const MaTRiX &A, const VecToRSubscripts &indx, VecToR &b) -{ - assert(A.lbound() == 1); // currently for 1-offset - assert(indx.lbound() == 1); // vectors and matrices - assert(b.lbound() == 1); - - Subscript i,ii=0,ip,j; - Subscript n = b.dim(); - typename MaTRiX::element_type sum = 0.0; - - for (i=1;i<=n;i++) - { - ip=indx(i); - sum=b(ip); - b(ip)=b(i); - if (ii) - for (j=ii;j<=i-1;j++) - sum -= A(i,j)*b(j); - else if (sum) ii=i; - b(i)=sum; - } - for (i=n;i>=1;i--) - { - sum=b(i); - for (j=i+1;j<=n;j++) - sum -= A(i,j)*b(j); - b(i)=sum/A(i,i); - } - - return 0; -} - -} // namespace TNT - -#endif // LU_H - diff --git a/intern/iksolver/intern/TNT/qr.h b/intern/iksolver/intern/TNT/qr.h deleted file mode 100644 index 9df34e2d7cc..00000000000 --- a/intern/iksolver/intern/TNT/qr.h +++ /dev/null @@ -1,233 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - -#ifndef QR_H -#define QR_H - -// Classical QR factorization example, based on Stewart[1973]. -// -// -// This algorithm computes the factorization of a matrix A -// into a product of an orthognal matrix (Q) and an upper triangular -// matrix (R), such that QR = A. -// -// Parameters: -// -// A (in): Matrix(1:N, 1:N) -// -// Q (output): Matrix(1:N, 1:N), collection of Householder -// column vectors Q1, Q2, ... QN -// -// R (output): upper triangular Matrix(1:N, 1:N) -// -// Returns: -// -// 0 if successful, 1 if A is detected to be singular -// - - -#include <cmath> //for sqrt() & fabs() -#include "tntmath.h" // for sign() - -// Classical QR factorization, based on Stewart[1973]. -// -// -// This algorithm computes the factorization of a matrix A -// into a product of an orthognal matrix (Q) and an upper triangular -// matrix (R), such that QR = A. -// -// Parameters: -// -// A (in/out): On input, A is square, Matrix(1:N, 1:N), that represents -// the matrix to be factored. -// -// On output, Q and R is encoded in the same Matrix(1:N,1:N) -// in the following manner: -// -// R is contained in the upper triangular section of A, -// except that R's main diagonal is in D. The lower -// triangular section of A represents Q, where each -// column j is the vector Qj = I - uj*uj'/pi_j. -// -// C (output): vector of Pi[j] -// D (output): main diagonal of R, i.e. D(i) is R(i,i) -// -// Returns: -// -// 0 if successful, 1 if A is detected to be singular -// - -namespace TNT -{ - -template <class MaTRiX, class Vector> -int QR_factor(MaTRiX &A, Vector& C, Vector &D) -{ - assert(A.lbound() == 1); // ensure these are all - assert(C.lbound() == 1); // 1-based arrays and vectors - assert(D.lbound() == 1); - - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(M == N); // make sure A is square - - Subscript i,j,k; - typename MaTRiX::element_type eta, sigma, sum; - - // adjust the shape of C and D, if needed... - - if (N != C.size()) C.newsize(N); - if (N != D.size()) D.newsize(N); - - for (k=1; k<N; k++) - { - // eta = max |M(i,k)|, for k <= i <= n - // - eta = 0; - for (i=k; i<=N; i++) - { - double absA = fabs(A(i,k)); - eta = ( absA > eta ? absA : eta ); - } - - if (eta == 0) // matrix is singular - { - cerr << "QR: k=" << k << "\n"; - return 1; - } - - // form Qk and premiltiply M by it - // - for(i=k; i<=N; i++) - A(i,k) = A(i,k) / eta; - - sum = 0; - for (i=k; i<=N; i++) - sum = sum + A(i,k)*A(i,k); - sigma = sign(A(k,k)) * sqrt(sum); - - - A(k,k) = A(k,k) + sigma; - C(k) = sigma * A(k,k); - D(k) = -eta * sigma; - - for (j=k+1; j<=N; j++) - { - sum = 0; - for (i=k; i<=N; i++) - sum = sum + A(i,k)*A(i,j); - sum = sum / C(k); - - for (i=k; i<=N; i++) - A(i,j) = A(i,j) - sum * A(i,k); - } - - D(N) = A(N,N); - } - - return 0; -} - -// modified form of upper triangular solve, except that the main diagonal -// of R (upper portion of A) is in D. -// -template <class MaTRiX, class Vector> -int R_solve(const MaTRiX &A, /*const*/ Vector &D, Vector &b) -{ - assert(A.lbound() == 1); // ensure these are all - assert(D.lbound() == 1); // 1-based arrays and vectors - assert(b.lbound() == 1); - - Subscript i,j; - Subscript N = A.num_rows(); - - assert(N == A.num_cols()); - assert(N == D.dim()); - assert(N == b.dim()); - - typename MaTRiX::element_type sum; - - if (D(N) == 0) - return 1; - - b(N) = b(N) / - D(N); - - for (i=N-1; i>=1; i--) - { - if (D(i) == 0) - return 1; - sum = 0; - for (j=i+1; j<=N; j++) - sum = sum + A(i,j)*b(j); - b(i) = ( b(i) - sum ) / - D(i); - } - - return 0; -} - - -template <class MaTRiX, class Vector> -int QR_solve(const MaTRiX &A, const Vector &c, /*const*/ Vector &d, - Vector &b) -{ - assert(A.lbound() == 1); // ensure these are all - assert(c.lbound() == 1); // 1-based arrays and vectors - assert(d.lbound() == 1); - - Subscript N=A.num_rows(); - - assert(N == A.num_cols()); - assert(N == c.dim()); - assert(N == d.dim()); - assert(N == b.dim()); - - Subscript i,j; - typename MaTRiX::element_type sum, tau; - - for (j=1; j<N; j++) - { - // form Q'*b - sum = 0; - for (i=j; i<=N; i++) - sum = sum + A(i,j)*b(i); - if (c(j) == 0) - return 1; - tau = sum / c(j); - for (i=j; i<=N; i++) - b(i) = b(i) - tau * A(i,j); - } - return R_solve(A, d, b); // solve Rx = Q'b -} - -} // namespace TNT - -#endif // QR_H - diff --git a/intern/iksolver/intern/TNT/region1d.h b/intern/iksolver/intern/TNT/region1d.h deleted file mode 100644 index 8acaac3ae23..00000000000 --- a/intern/iksolver/intern/TNT/region1d.h +++ /dev/null @@ -1,375 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - - -#ifndef REGION1D_H -#define REGION1D_H - - -#include "subscript.h" -#include "index.h" -#include <iostream> -#include <cassert> - -namespace TNT -{ - -template <class Array1D> -class const_Region1D; - -template <class Array1D> -class Region1D -{ - protected: - - Array1D & A_; - Subscript offset_; // 0-based - Subscript dim_; - - typedef typename Array1D::element_type T; - - public: - const Array1D & array() const { return A_; } - - Subscript offset() const { return offset_;} - Subscript dim() const { return dim_; } - - Subscript offset(Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(i==TNT_BASE_OFFSET); -#endif - return offset_; - } - - Subscript dim(Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(i== TNT_BASE_OFFSET); -#endif - return offset_; - } - - - Region1D(Array1D &A, Subscript i1, Subscript i2) : A_(A) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <= i1 ); - assert(i2 <= A.dim() + (TNT_BASE_OFFSET-1)); - assert(i1 <= i2); -#endif - offset_ = i1 - TNT_BASE_OFFSET; - dim_ = i2-i1 + 1; - } - - Region1D(Array1D &A, const Index1D &I) : A_(A) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <=I.lbound()); - assert(I.ubound() <= A.dim() + (TNT_BASE_OFFSET-1)); - assert(I.lbound() <= I.ubound()); -#endif - offset_ = I.lbound() - TNT_BASE_OFFSET; - dim_ = I.ubound() - I.lbound() + 1; - } - - Region1D(Region1D<Array1D> &A, Subscript i1, Subscript i2) : - A_(A.A_) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <= i1 ); - assert(i2 <= A.dim() + (TNT_BASE_OFFSET - 1)); - assert(i1 <= i2); -#endif - // (old-offset) (new-offset) - // - offset_ = (i1 - TNT_BASE_OFFSET) + A.offset_; - dim_ = i2-i1 + 1; - } - - Region1D<Array1D> operator()(Subscript i1, Subscript i2) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <= i1); - assert(i2 <= dim() + (TNT_BASE_OFFSET -1)); - assert(i1 <= i2); -#endif - // offset_ is 0-based, so no need for - // ( - TNT_BASE_OFFSET) - // - return Region1D<Array1D>(A_, i1+offset_, - offset_ + i2); - } - - - Region1D<Array1D> operator()(const Index1D &I) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET<=I.lbound()); - assert(I.ubound() <= dim() + (TNT_BASE_OFFSET-1)); - assert(I.lbound() <= I.ubound()); -#endif - return Region1D<Array1D>(A_, I.lbound()+offset_, - offset_ + I.ubound()); - } - - - - - T & operator()(Subscript i) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <= i); - assert(i <= dim() + (TNT_BASE_OFFSET-1)); -#endif - return A_(i+offset_); - } - - const T & operator() (Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <= i); - assert(i <= dim() + (TNT_BASE_OFFSET-1)); -#endif - return A_(i+offset_); - } - - - Region1D<Array1D> & operator=(const Region1D<Array1D> &R) - { - // make sure both sides conform - assert(dim() == R.dim()); - - Subscript N = dim(); - Subscript i; - Subscript istart = TNT_BASE_OFFSET; - Subscript iend = istart + N-1; - - for (i=istart; i<=iend; i++) - (*this)(i) = R(i); - - return *this; - } - - - - Region1D<Array1D> & operator=(const const_Region1D<Array1D> &R) - { - // make sure both sides conform - assert(dim() == R.dim()); - - Subscript N = dim(); - Subscript i; - Subscript istart = TNT_BASE_OFFSET; - Subscript iend = istart + N-1; - - for (i=istart; i<=iend; i++) - (*this)(i) = R(i); - - return *this; - - } - - - Region1D<Array1D> & operator=(const T& t) - { - Subscript N=dim(); - Subscript i; - Subscript istart = TNT_BASE_OFFSET; - Subscript iend = istart + N-1; - - for (i=istart; i<= iend; i++) - (*this)(i) = t; - - return *this; - - } - - - Region1D<Array1D> & operator=(const Array1D &R) - { - // make sure both sides conform - Subscript N = dim(); - assert(dim() == R.dim()); - - Subscript i; - Subscript istart = TNT_BASE_OFFSET; - Subscript iend = istart + N-1; - - for (i=istart; i<=iend; i++) - (*this)(i) = R(i); - - return *this; - - } - -}; - -template <class Array1D> -std::ostream& operator<<(std::ostream &s, Region1D<Array1D> &A) -{ - Subscript N=A.dim(); - Subscript istart = TNT_BASE_OFFSET; - Subscript iend = N - 1 + TNT_BASE_OFFSET; - - for (Subscript i=istart; i<=iend; i++) - s << A(i) << endl; - - return s; -} - - -/* --------- class const_Region1D ------------ */ - -template <class Array1D> -class const_Region1D -{ - protected: - - const Array1D & A_; - Subscript offset_; // 0-based - Subscript dim_; - typedef typename Array1D::element_type T; - - public: - const Array1D & array() const { return A_; } - - Subscript offset() const { return offset_;} - Subscript dim() const { return dim_; } - - Subscript offset(Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(i==TNT_BASE_OFFSET); -#endif - return offset_; - } - - Subscript dim(Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(i== TNT_BASE_OFFSET); -#endif - return offset_; - } - - - const_Region1D(const Array1D &A, Subscript i1, Subscript i2) : A_(A) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <= i1 ); - assert(i2 <= A.dim() + (TNT_BASE_OFFSET-1)); - assert(i1 <= i2); -#endif - offset_ = i1 - TNT_BASE_OFFSET; - dim_ = i2-i1 + 1; - } - - const_Region1D(const Array1D &A, const Index1D &I) : A_(A) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <=I.lbound()); - assert(I.ubound() <= A.dim() + (TNT_BASE_OFFSET-1)); - assert(I.lbound() <= I.ubound()); -#endif - offset_ = I.lbound() - TNT_BASE_OFFSET; - dim_ = I.ubound() - I.lbound() + 1; - } - - const_Region1D(const_Region1D<Array1D> &A, Subscript i1, Subscript i2) : - A_(A.A_) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <= i1 ); - assert(i2 <= A.dim() + (TNT_BASE_OFFSET - 1)); - assert(i1 <= i2); -#endif - // (old-offset) (new-offset) - // - offset_ = (i1 - TNT_BASE_OFFSET) + A.offset_; - dim_ = i2-i1 + 1; - } - - const_Region1D<Array1D> operator()(Subscript i1, Subscript i2) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <= i1); - assert(i2 <= dim() + (TNT_BASE_OFFSET -1)); - assert(i1 <= i2); -#endif - // offset_ is 0-based, so no need for - // ( - TNT_BASE_OFFSET) - // - return const_Region1D<Array1D>(A_, i1+offset_, - offset_ + i2); - } - - - const_Region1D<Array1D> operator()(const Index1D &I) - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET<=I.lbound()); - assert(I.ubound() <= dim() + (TNT_BASE_OFFSET-1)); - assert(I.lbound() <= I.ubound()); -#endif - return const_Region1D<Array1D>(A_, I.lbound()+offset_, - offset_ + I.ubound()); - } - - - const T & operator() (Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(TNT_BASE_OFFSET <= i); - assert(i <= dim() + (TNT_BASE_OFFSET-1)); -#endif - return A_(i+offset_); - } - - - - -}; - -template <class Array1D> -std::ostream& operator<<(std::ostream &s, const_Region1D<Array1D> &A) -{ - Subscript N=A.dim(); - - for (Subscript i=1; i<=N; i++) - s << A(i) << endl; - - return s; -} - - -} // namespace TNT - -#endif // const_Region1D_H - diff --git a/intern/iksolver/intern/TNT/region2d.h b/intern/iksolver/intern/TNT/region2d.h deleted file mode 100644 index 6af50262382..00000000000 --- a/intern/iksolver/intern/TNT/region2d.h +++ /dev/null @@ -1,471 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - -// 2D Regions for arrays and matrices - -#ifndef REGION2D_H -#define REGION2D_H - -#include "index.h" -#include <iostream> -#include <cassert> - -namespace TNT -{ - -template <class Array2D> -class const_Region2D; - - -template <class Array2D> -class Region2D -{ - protected: - - Array2D & A_; - Subscript offset_[2]; // 0-offset internally - Subscript dim_[2]; - - public: - typedef typename Array2D::value_type T; - typedef Subscript size_type; - typedef T value_type; - typedef T element_type; - typedef T* pointer; - typedef T* iterator; - typedef T& reference; - typedef const T* const_iterator; - typedef const T& const_reference; - - Array2D & array() { return A_; } - const Array2D & array() const { return A_; } - Subscript lbound() const { return A_.lbound(); } - Subscript num_rows() const { return dim_[0]; } - Subscript num_cols() const { return dim_[1]; } - Subscript offset(Subscript i) const // 1-offset - { -#ifdef TNT_BOUNDS_CHECK - assert( A_.lbound() <= i); - assert( i<= dim_[0] + A_.lbound()-1); -#endif - return offset_[i-A_.lbound()]; - } - - Subscript dim(Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert( A_.lbound() <= i); - assert( i<= dim_[0] + A_.lbound()-1); -#endif - return dim_[i-A_.lbound()]; - } - - - - Region2D(Array2D &A, Subscript i1, Subscript i2, Subscript j1, - Subscript j2) : A_(A) - { -#ifdef TNT_BOUNDS_CHECK - assert( i1 <= i2 ); - assert( j1 <= j2); - assert( A.lbound() <= i1); - assert( i2<= A.dim(A.lbound()) + A.lbound()-1); - assert( A.lbound() <= j1); - assert( j2<= A.dim(A.lbound()+1) + A.lbound()-1 ); -#endif - - - offset_[0] = i1-A.lbound(); - offset_[1] = j1-A.lbound(); - dim_[0] = i2-i1+1; - dim_[1] = j2-j1+1; - } - - Region2D(Array2D &A, const Index1D &I, const Index1D &J) : A_(A) - { -#ifdef TNT_BOUNDS_CHECK - assert( I.lbound() <= I.ubound() ); - assert( J.lbound() <= J.ubound() ); - assert( A.lbound() <= I.lbound()); - assert( I.ubound()<= A.dim(A.lbound()) + A.lbound()-1); - assert( A.lbound() <= J.lbound()); - assert( J.ubound() <= A.dim(A.lbound()+1) + A.lbound()-1 ); -#endif - - offset_[0] = I.lbound()-A.lbound(); - offset_[1] = J.lbound()-A.lbound(); - dim_[0] = I.ubound() - I.lbound() + 1; - dim_[1] = J.ubound() - J.lbound() + 1; - } - - Region2D(Region2D<Array2D> &A, Subscript i1, Subscript i2, - Subscript j1, Subscript j2) : A_(A.A_) - { -#ifdef TNT_BOUNDS_CHECK - assert( i1 <= i2 ); - assert( j1 <= j2); - assert( A.lbound() <= i1); - assert( i2<= A.dim(A.lbound()) + A.lbound()-1); - assert( A.lbound() <= j1); - assert( j2<= A.dim(A.lbound()+1) + A.lbound()-1 ); -#endif - offset_[0] = (i1 - A.lbound()) + A.offset_[0]; - offset_[1] = (j1 - A.lbound()) + A.offset_[1]; - dim_[0] = i2-i1 + 1; - dim_[1] = j2-j1+1; - } - - Region2D<Array2D> operator()(Subscript i1, Subscript i2, - Subscript j1, Subscript j2) - { -#ifdef TNT_BOUNDS_CHECK - assert( i1 <= i2 ); - assert( j1 <= j2); - assert( A_.lbound() <= i1); - assert( i2<= dim_[0] + A_.lbound()-1); - assert( A_.lbound() <= j1); - assert( j2<= dim_[1] + A_.lbound()-1 ); -#endif - return Region2D<Array2D>(A_, - i1+offset_[0], offset_[0] + i2, - j1+offset_[1], offset_[1] + j2); - } - - - Region2D<Array2D> operator()(const Index1D &I, - const Index1D &J) - { -#ifdef TNT_BOUNDS_CHECK - assert( I.lbound() <= I.ubound() ); - assert( J.lbound() <= J.ubound() ); - assert( A_.lbound() <= I.lbound()); - assert( I.ubound()<= dim_[0] + A_.lbound()-1); - assert( A_.lbound() <= J.lbound()); - assert( J.ubound() <= dim_[1] + A_.lbound()-1 ); -#endif - - return Region2D<Array2D>(A_, I.lbound()+offset_[0], - offset_[0] + I.ubound(), offset_[1]+J.lbound(), - offset_[1] + J.ubound()); - } - - inline T & operator()(Subscript i, Subscript j) - { -#ifdef TNT_BOUNDS_CHECK - assert( A_.lbound() <= i); - assert( i<= dim_[0] + A_.lbound()-1); - assert( A_.lbound() <= j); - assert( j<= dim_[1] + A_.lbound()-1 ); -#endif - return A_(i+offset_[0], j+offset_[1]); - } - - inline const T & operator() (Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert( A_.lbound() <= i); - assert( i<= dim_[0] + A_.lbound()-1); - assert( A_.lbound() <= j); - assert( j<= dim_[1] + A_.lbound()-1 ); -#endif - return A_(i+offset_[0], j+offset_[1]); - } - - - Region2D<Array2D> & operator=(const Region2D<Array2D> &R) - { - Subscript M = num_rows(); - Subscript N = num_cols(); - - // make sure both sides conform - assert(M == R.num_rows()); - assert(N == R.num_cols()); - - - Subscript start = R.lbound(); - Subscript Mend = start + M - 1; - Subscript Nend = start + N - 1; - for (Subscript i=start; i<=Mend; i++) - for (Subscript j=start; j<=Nend; j++) - (*this)(i,j) = R(i,j); - - return *this; - } - - Region2D<Array2D> & operator=(const const_Region2D<Array2D> &R) - { - Subscript M = num_rows(); - Subscript N = num_cols(); - - // make sure both sides conform - assert(M == R.num_rows()); - assert(N == R.num_cols()); - - - Subscript start = R.lbound(); - Subscript Mend = start + M - 1; - Subscript Nend = start + N - 1; - for (Subscript i=start; i<=Mend; i++) - for (Subscript j=start; j<=Nend; j++) - (*this)(i,j) = R(i,j); - - return *this; - } - - Region2D<Array2D> & operator=(const Array2D &R) - { - Subscript M = num_rows(); - Subscript N = num_cols(); - - // make sure both sides conform - assert(M == R.num_rows()); - assert(N == R.num_cols()); - - - Subscript start = R.lbound(); - Subscript Mend = start + M - 1; - Subscript Nend = start + N - 1; - for (Subscript i=start; i<=Mend; i++) - for (Subscript j=start; j<=Nend; j++) - (*this)(i,j) = R(i,j); - - return *this; - } - - Region2D<Array2D> & operator=(const T &scalar) - { - Subscript start = lbound(); - Subscript Mend = lbound() + num_rows() - 1; - Subscript Nend = lbound() + num_cols() - 1; - - - for (Subscript i=start; i<=Mend; i++) - for (Subscript j=start; j<=Nend; j++) - (*this)(i,j) = scalar; - - return *this; - } - -}; - -//************************ - -template <class Array2D> -class const_Region2D -{ - protected: - - const Array2D & A_; - Subscript offset_[2]; // 0-offset internally - Subscript dim_[2]; - - public: - typedef typename Array2D::value_type T; - typedef T value_type; - typedef T element_type; - typedef const T* const_iterator; - typedef const T& const_reference; - - const Array2D & array() const { return A_; } - Subscript lbound() const { return A_.lbound(); } - Subscript num_rows() const { return dim_[0]; } - Subscript num_cols() const { return dim_[1]; } - Subscript offset(Subscript i) const // 1-offset - { -#ifdef TNT_BOUNDS_CHECK - assert( TNT_BASE_OFFSET <= i); - assert( i<= dim_[0] + TNT_BASE_OFFSET-1); -#endif - return offset_[i-TNT_BASE_OFFSET]; - } - - Subscript dim(Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert( TNT_BASE_OFFSET <= i); - assert( i<= dim_[0] + TNT_BASE_OFFSET-1); -#endif - return dim_[i-TNT_BASE_OFFSET]; - } - - - const_Region2D(const Array2D &A, Subscript i1, Subscript i2, - Subscript j1, Subscript j2) : A_(A) - { -#ifdef TNT_BOUNDS_CHECK - assert( i1 <= i2 ); - assert( j1 <= j2); - assert( TNT_BASE_OFFSET <= i1); - assert( i2<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1); - assert( TNT_BASE_OFFSET <= j1); - assert( j2<= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 ); -#endif - - offset_[0] = i1-TNT_BASE_OFFSET; - offset_[1] = j1-TNT_BASE_OFFSET; - dim_[0] = i2-i1+1; - dim_[1] = j2-j1+1; - } - - const_Region2D(const Array2D &A, const Index1D &I, const Index1D &J) - : A_(A) - { -#ifdef TNT_BOUNDS_CHECK - assert( I.lbound() <= I.ubound() ); - assert( J.lbound() <= J.ubound() ); - assert( TNT_BASE_OFFSET <= I.lbound()); - assert( I.ubound()<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1); - assert( TNT_BASE_OFFSET <= J.lbound()); - assert( J.ubound() <= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 ); -#endif - - offset_[0] = I.lbound()-TNT_BASE_OFFSET; - offset_[1] = J.lbound()-TNT_BASE_OFFSET; - dim_[0] = I.ubound() - I.lbound() + 1; - dim_[1] = J.ubound() - J.lbound() + 1; - } - - - const_Region2D(const_Region2D<Array2D> &A, Subscript i1, - Subscript i2, - Subscript j1, Subscript j2) : A_(A.A_) - { -#ifdef TNT_BOUNDS_CHECK - assert( i1 <= i2 ); - assert( j1 <= j2); - assert( TNT_BASE_OFFSET <= i1); - assert( i2<= A.dim(TNT_BASE_OFFSET) + TNT_BASE_OFFSET-1); - assert( TNT_BASE_OFFSET <= j1); - assert( j2<= A.dim(TNT_BASE_OFFSET+1) + TNT_BASE_OFFSET-1 ); -#endif - offset_[0] = (i1 - TNT_BASE_OFFSET) + A.offset_[0]; - offset_[1] = (j1 - TNT_BASE_OFFSET) + A.offset_[1]; - dim_[0] = i2-i1 + 1; - dim_[1] = j2-j1+1; - } - - const_Region2D<Array2D> operator()(Subscript i1, Subscript i2, - Subscript j1, Subscript j2) - { -#ifdef TNT_BOUNDS_CHECK - assert( i1 <= i2 ); - assert( j1 <= j2); - assert( TNT_BASE_OFFSET <= i1); - assert( i2<= dim_[0] + TNT_BASE_OFFSET-1); - assert( TNT_BASE_OFFSET <= j1); - assert( j2<= dim_[0] + TNT_BASE_OFFSET-1 ); -#endif - return const_Region2D<Array2D>(A_, - i1+offset_[0], offset_[0] + i2, - j1+offset_[1], offset_[1] + j2); - } - - - const_Region2D<Array2D> operator()(const Index1D &I, - const Index1D &J) - { -#ifdef TNT_BOUNDS_CHECK - assert( I.lbound() <= I.ubound() ); - assert( J.lbound() <= J.ubound() ); - assert( TNT_BASE_OFFSET <= I.lbound()); - assert( I.ubound()<= dim_[0] + TNT_BASE_OFFSET-1); - assert( TNT_BASE_OFFSET <= J.lbound()); - assert( J.ubound() <= dim_[1] + TNT_BASE_OFFSET-1 ); -#endif - - return const_Region2D<Array2D>(A_, I.lbound()+offset_[0], - offset_[0] + I.ubound(), offset_[1]+J.lbound(), - offset_[1] + J.ubound()); - } - - - inline const T & operator() (Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert( TNT_BASE_OFFSET <= i); - assert( i<= dim_[0] + TNT_BASE_OFFSET-1); - assert( TNT_BASE_OFFSET <= j); - assert( j<= dim_[1] + TNT_BASE_OFFSET-1 ); -#endif - return A_(i+offset_[0], j+offset_[1]); - } - -}; - - -// ************** std::ostream algorithms ******************************* - -template <class Array2D> -std::ostream& operator<<(std::ostream &s, const const_Region2D<Array2D> &A) -{ - Subscript start = A.lbound(); - Subscript Mend=A.lbound()+ A.num_rows() - 1; - Subscript Nend=A.lbound() + A.num_cols() - 1; - - - s << A.num_rows() << " " << A.num_cols() << "\n"; - for (Subscript i=start; i<=Mend; i++) - { - for (Subscript j=start; j<=Nend; j++) - { - s << A(i,j) << " "; - } - s << "\n"; - } - - - return s; -} - -template <class Array2D> -std::ostream& operator<<(std::ostream &s, const Region2D<Array2D> &A) -{ - Subscript start = A.lbound(); - Subscript Mend=A.lbound()+ A.num_rows() - 1; - Subscript Nend=A.lbound() + A.num_cols() - 1; - - - s << A.num_rows() << " " << A.num_cols() << "\n"; - for (Subscript i=start; i<=Mend; i++) - { - for (Subscript j=start; j<=Nend; j++) - { - s << A(i,j) << " "; - } - s << "\n"; - } - - - return s; - -} - -} // namespace TNT - -#endif // REGION2D_H - diff --git a/intern/iksolver/intern/TNT/stopwatch.h b/intern/iksolver/intern/TNT/stopwatch.h deleted file mode 100644 index 55cd532d6a4..00000000000 --- a/intern/iksolver/intern/TNT/stopwatch.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - -#ifndef STPWATCH_H -#define STPWATCH_H - -// for clock() and CLOCKS_PER_SEC -#include <ctime> - -namespace TNT -{ - -/* Simple stopwatch object: - - void start() : start timing - double stop() : stop timing - void reset() : set elapsed time to 0.0 - double read() : read elapsed time (in seconds) - -*/ - -inline double seconds(void) -{ - static const double secs_per_tick = 1.0 / CLOCKS_PER_SEC; - return ( (double) clock() ) * secs_per_tick; -} - - -class stopwatch { - private: - int running; - double last_time; - double total; - - public: - stopwatch() : running(0), last_time(0.0), total(0.0) {} - void reset() { running = 0; last_time = 0.0; total=0.0; } - void start() { if (!running) { last_time = seconds(); running = 1;}} - double stop() { if (running) - { - total += seconds() - last_time; - running = 0; - } - return total; - } - double read() { if (running) - { - total+= seconds() - last_time; - last_time = seconds(); - } - return total; - } - -}; - -} // namespace TNT - -#endif - diff --git a/intern/iksolver/intern/TNT/subscript.h b/intern/iksolver/intern/TNT/subscript.h deleted file mode 100644 index 75555e1c0b6..00000000000 --- a/intern/iksolver/intern/TNT/subscript.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - -#ifndef SUBSCRPT_H -#define SUBSCRPT_H - - -//--------------------------------------------------------------------- -// This definition describes the default TNT data type used for -// indexing into TNT matrices and vectors. The data type should -// be wide enough to index into large arrays. It defaults to an -// "int", but can be overriden at compile time redefining TNT_SUBSCRIPT_TYPE, -// e.g. -// -// g++ -DTNT_SUBSCRIPT_TYPE='unsigned int' ... -// -//--------------------------------------------------------------------- -// - -#ifndef TNT_SUBSCRIPT_TYPE -#define TNT_SUBSCRIPT_TYPE int -#endif - -namespace TNT -{ - typedef TNT_SUBSCRIPT_TYPE Subscript; -} - - -// () indexing in TNT means 1-offset, i.e. x(1) and A(1,1) are the -// first elements. This offset is left as a macro for future -// purposes, but should not be changed in the current release. -// -// -#define TNT_BASE_OFFSET (1) - -#endif - diff --git a/intern/iksolver/intern/TNT/svd.h b/intern/iksolver/intern/TNT/svd.h deleted file mode 100644 index cfff73caa3f..00000000000 --- a/intern/iksolver/intern/TNT/svd.h +++ /dev/null @@ -1,435 +0,0 @@ -/** - */ - -#ifndef SVD_H - -#define SVD_H - -// Compute the Single Value Decomposition of an arbitrary matrix A -// That is compute the 3 matrices U,W,V with U column orthogonal (m,n) -// ,W a diagonal matrix and V an orthogonal square matrix s.t. -// A = U.W.Vt. From this decomposition it is trivial to compute the -// inverse of A as Ainv = V.Winv.tranpose(U). -// -// s = diagonal elements of W -// work1 = workspace, length must be A.num_rows -// work2 = workspace, length must be A.num_cols - -#include "tntmath.h" - -#define SVD_MAX_ITER 200 - -namespace TNT -{ - -template <class MaTRiX, class VecToR > -void SVD(MaTRiX &A, MaTRiX &U, VecToR &s, MaTRiX &V, VecToR &work1, VecToR &work2, int maxiter=SVD_MAX_ITER) { - - int m = A.num_rows(); - int n = A.num_cols(); - int nu = min(m,n); - - VecToR& work = work1; - VecToR& e = work2; - - U = 0; - s = 0; - - int i=0, j=0, k=0; - - // Reduce A to bidiagonal form, storing the diagonal elements - // in s and the super-diagonal elements in e. - - int nct = min(m-1,n); - int nrt = max(0,min(n-2,m)); - for (k = 0; k < max(nct,nrt); k++) { - if (k < nct) { - - // Compute the transformation for the k-th column and - // place the k-th diagonal in s[k]. - // Compute 2-norm of k-th column without under/overflow. - s[k] = 0; - for (i = k; i < m; i++) { - s[k] = hypot(s[k],A[i][k]); - } - if (s[k] != 0.0) { - if (A[k][k] < 0.0) { - s[k] = -s[k]; - } - for (i = k; i < m; i++) { - A[i][k] /= s[k]; - } - A[k][k] += 1.0; - } - s[k] = -s[k]; - } - for (j = k+1; j < n; j++) { - if ((k < nct) && (s[k] != 0.0)) { - - // Apply the transformation. - - typename MaTRiX::value_type t = 0; - for (i = k; i < m; i++) { - t += A[i][k]*A[i][j]; - } - t = -t/A[k][k]; - for (i = k; i < m; i++) { - A[i][j] += t*A[i][k]; - } - } - - // Place the k-th row of A into e for the - // subsequent calculation of the row transformation. - - e[j] = A[k][j]; - } - if (k < nct) { - - // Place the transformation in U for subsequent back - // multiplication. - - for (i = k; i < m; i++) - U[i][k] = A[i][k]; - } - if (k < nrt) { - - // Compute the k-th row transformation and place the - // k-th super-diagonal in e[k]. - // Compute 2-norm without under/overflow. - e[k] = 0; - for (i = k+1; i < n; i++) { - e[k] = hypot(e[k],e[i]); - } - if (e[k] != 0.0) { - if (e[k+1] < 0.0) { - e[k] = -e[k]; - } - for (i = k+1; i < n; i++) { - e[i] /= e[k]; - } - e[k+1] += 1.0; - } - e[k] = -e[k]; - if ((k+1 < m) & (e[k] != 0.0)) { - - // Apply the transformation. - - for (i = k+1; i < m; i++) { - work[i] = 0.0; - } - for (j = k+1; j < n; j++) { - for (i = k+1; i < m; i++) { - work[i] += e[j]*A[i][j]; - } - } - for (j = k+1; j < n; j++) { - typename MaTRiX::value_type t = -e[j]/e[k+1]; - for (i = k+1; i < m; i++) { - A[i][j] += t*work[i]; - } - } - } - - // Place the transformation in V for subsequent - // back multiplication. - - for (i = k+1; i < n; i++) - V[i][k] = e[i]; - } - } - - // Set up the final bidiagonal matrix or order p. - - int p = min(n,m+1); - if (nct < n) { - s[nct] = A[nct][nct]; - } - if (m < p) { - s[p-1] = 0.0; - } - if (nrt+1 < p) { - e[nrt] = A[nrt][p-1]; - } - e[p-1] = 0.0; - - // If required, generate U. - - for (j = nct; j < nu; j++) { - for (i = 0; i < m; i++) { - U[i][j] = 0.0; - } - U[j][j] = 1.0; - } - for (k = nct-1; k >= 0; k--) { - if (s[k] != 0.0) { - for (j = k+1; j < nu; j++) { - typename MaTRiX::value_type t = 0; - for (i = k; i < m; i++) { - t += U[i][k]*U[i][j]; - } - t = -t/U[k][k]; - for (i = k; i < m; i++) { - U[i][j] += t*U[i][k]; - } - } - for (i = k; i < m; i++ ) { - U[i][k] = -U[i][k]; - } - U[k][k] = 1.0 + U[k][k]; - for (i = 0; i < k-1; i++) { - U[i][k] = 0.0; - } - } else { - for (i = 0; i < m; i++) { - U[i][k] = 0.0; - } - U[k][k] = 1.0; - } - } - - // If required, generate V. - - for (k = n-1; k >= 0; k--) { - if ((k < nrt) & (e[k] != 0.0)) { - for (j = k+1; j < nu; j++) { - typename MaTRiX::value_type t = 0; - for (i = k+1; i < n; i++) { - t += V[i][k]*V[i][j]; - } - t = -t/V[k+1][k]; - for (i = k+1; i < n; i++) { - V[i][j] += t*V[i][k]; - } - } - } - for (i = 0; i < n; i++) { - V[i][k] = 0.0; - } - V[k][k] = 1.0; - } - - // Main iteration loop for the singular values. - - int pp = p-1; - int iter = 0; - typename MaTRiX::value_type eps = pow(2.0,-52.0); - while (p > 0) { - int kase=0; - k=0; - - // Test for maximum iterations to avoid infinite loop - if(maxiter == 0) - break; - maxiter--; - - // This section of the program inspects for - // negligible elements in the s and e arrays. On - // completion the variables kase and k are set as follows. - - // kase = 1 if s(p) and e[k-1] are negligible and k<p - // kase = 2 if s(k) is negligible and k<p - // kase = 3 if e[k-1] is negligible, k<p, and - // s(k), ..., s(p) are not negligible (qr step). - // kase = 4 if e(p-1) is negligible (convergence). - - for (k = p-2; k >= -1; k--) { - if (k == -1) { - break; - } - if (TNT::abs(e[k]) <= eps*(TNT::abs(s[k]) + TNT::abs(s[k+1]))) { - e[k] = 0.0; - break; - } - } - if (k == p-2) { - kase = 4; - } else { - int ks; - for (ks = p-1; ks >= k; ks--) { - if (ks == k) { - break; - } - typename MaTRiX::value_type t = (ks != p ? TNT::abs(e[ks]) : 0.) + - (ks != k+1 ? TNT::abs(e[ks-1]) : 0.); - if (TNT::abs(s[ks]) <= eps*t) { - s[ks] = 0.0; - break; - } - } - if (ks == k) { - kase = 3; - } else if (ks == p-1) { - kase = 1; - } else { - kase = 2; - k = ks; - } - } - k++; - - // Perform the task indicated by kase. - - switch (kase) { - - // Deflate negligible s(p). - - case 1: { - typename MaTRiX::value_type f = e[p-2]; - e[p-2] = 0.0; - for (j = p-2; j >= k; j--) { - typename MaTRiX::value_type t = hypot(s[j],f); - typename MaTRiX::value_type cs = s[j]/t; - typename MaTRiX::value_type sn = f/t; - s[j] = t; - if (j != k) { - f = -sn*e[j-1]; - e[j-1] = cs*e[j-1]; - } - - for (i = 0; i < n; i++) { - t = cs*V[i][j] + sn*V[i][p-1]; - V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1]; - V[i][j] = t; - } - } - } - break; - - // Split at negligible s(k). - - case 2: { - typename MaTRiX::value_type f = e[k-1]; - e[k-1] = 0.0; - for (j = k; j < p; j++) { - typename MaTRiX::value_type t = hypot(s[j],f); - typename MaTRiX::value_type cs = s[j]/t; - typename MaTRiX::value_type sn = f/t; - s[j] = t; - f = -sn*e[j]; - e[j] = cs*e[j]; - - for (i = 0; i < m; i++) { - t = cs*U[i][j] + sn*U[i][k-1]; - U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1]; - U[i][j] = t; - } - } - } - break; - - // Perform one qr step. - - case 3: { - - // Calculate the shift. - - typename MaTRiX::value_type scale = max(max(max(max( - TNT::abs(s[p-1]),TNT::abs(s[p-2])),TNT::abs(e[p-2])), - TNT::abs(s[k])),TNT::abs(e[k])); - typename MaTRiX::value_type sp = s[p-1]/scale; - typename MaTRiX::value_type spm1 = s[p-2]/scale; - typename MaTRiX::value_type epm1 = e[p-2]/scale; - typename MaTRiX::value_type sk = s[k]/scale; - typename MaTRiX::value_type ek = e[k]/scale; - typename MaTRiX::value_type b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0; - typename MaTRiX::value_type c = (sp*epm1)*(sp*epm1); - typename MaTRiX::value_type shift = 0.0; - if ((b != 0.0) || (c != 0.0)) { - shift = sqrt(b*b + c); - if (b < 0.0) { - shift = -shift; - } - shift = c/(b + shift); - } - typename MaTRiX::value_type f = (sk + sp)*(sk - sp) + shift; - typename MaTRiX::value_type g = sk*ek; - - // Chase zeros. - - for (j = k; j < p-1; j++) { - typename MaTRiX::value_type t = hypot(f,g); - /* division by zero checks added to avoid NaN (brecht) */ - typename MaTRiX::value_type cs = (t == 0.0f)? 0.0f: f/t; - typename MaTRiX::value_type sn = (t == 0.0f)? 0.0f: g/t; - if (j != k) { - e[j-1] = t; - } - f = cs*s[j] + sn*e[j]; - e[j] = cs*e[j] - sn*s[j]; - g = sn*s[j+1]; - s[j+1] = cs*s[j+1]; - - for (i = 0; i < n; i++) { - t = cs*V[i][j] + sn*V[i][j+1]; - V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1]; - V[i][j] = t; - } - - t = hypot(f,g); - /* division by zero checks added to avoid NaN (brecht) */ - cs = (t == 0.0f)? 0.0f: f/t; - sn = (t == 0.0f)? 0.0f: g/t; - s[j] = t; - f = cs*e[j] + sn*s[j+1]; - s[j+1] = -sn*e[j] + cs*s[j+1]; - g = sn*e[j+1]; - e[j+1] = cs*e[j+1]; - if (j < m-1) { - for (i = 0; i < m; i++) { - t = cs*U[i][j] + sn*U[i][j+1]; - U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1]; - U[i][j] = t; - } - } - } - e[p-2] = f; - iter = iter + 1; - } - break; - - // Convergence. - - case 4: { - - // Make the singular values positive. - - if (s[k] <= 0.0) { - s[k] = (s[k] < 0.0 ? -s[k] : 0.0); - - for (i = 0; i <= pp; i++) - V[i][k] = -V[i][k]; - } - - // Order the singular values. - - while (k < pp) { - if (s[k] >= s[k+1]) { - break; - } - typename MaTRiX::value_type t = s[k]; - s[k] = s[k+1]; - s[k+1] = t; - if (k < n-1) { - for (i = 0; i < n; i++) { - t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t; - } - } - if (k < m-1) { - for (i = 0; i < m; i++) { - t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t; - } - } - k++; - } - iter = 0; - p--; - } - break; - } - } -} - -} - -#endif - diff --git a/intern/iksolver/intern/TNT/tnt.h b/intern/iksolver/intern/TNT/tnt.h deleted file mode 100644 index c15ae27c547..00000000000 --- a/intern/iksolver/intern/TNT/tnt.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - -#ifndef TNT_H -#define TNT_H - -//--------------------------------------------------------------------- -// tnt.h TNT general header file. Defines default types -// and conventions. -//--------------------------------------------------------------------- - -//--------------------------------------------------------------------- -// Include current version -//--------------------------------------------------------------------- -#include "version.h" - -//--------------------------------------------------------------------- -// Define the data type used for matrix and vector Subscripts. -// This will default to "int", but it can be overriden at compile time, -// e.g. -// -// g++ -DTNT_SUBSCRIPT_TYPE='unsinged long' ... -// -// See subscript.h for details. -//--------------------------------------------------------------------- - -#include "subscript.h" - - - -//--------------------------------------------------------------------- -// Define this macro if you want TNT to ensure all refernces -// are within the bounds of the array. This encurs a run-time -// overhead, of course, but is recommended while developing -// code. It can be turned off for production runs. -// -// #define TNT_BOUNDS_CHECK -//--------------------------------------------------------------------- -// -#define TNT_BOUNDS_CHECK -#ifdef TNT_NO_BOUNDS_CHECK -#undef TNT_BOUNDS_CHECK -#endif - -//--------------------------------------------------------------------- -// Define this macro if you want to utilize matrix and vector -// regions. This is typically on, but you can save some -// compilation time by turning it off. If you do this and -// attempt to use regions you will get an error message. -// -// #define TNT_USE_REGIONS -//--------------------------------------------------------------------- -// -#define TNT_USE_REGIONS - -//--------------------------------------------------------------------- -// -//--------------------------------------------------------------------- -// if your system doesn't have abs() min(), and max() uncoment the following -//--------------------------------------------------------------------- -// -// -//#define __NEED_ABS_MIN_MAX_ - -#include "tntmath.h" - -#endif // TNT_H - diff --git a/intern/iksolver/intern/TNT/tntmath.h b/intern/iksolver/intern/TNT/tntmath.h deleted file mode 100644 index be72796da59..00000000000 --- a/intern/iksolver/intern/TNT/tntmath.h +++ /dev/null @@ -1,154 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -// Header file for scalar math functions - -#ifndef TNTMATH_H -#define TNTMATH_H - -// conventional functions required by several matrix algorithms - -#if defined(_MSC_VER) && (_MSC_VER < 1800) -#define hypot _hypot -#endif - -namespace TNT -{ - -struct TNTException { - int i; -}; - - -inline double abs(double t) -{ - return ( t > 0 ? t : -t); -} - -inline double min(double a, double b) -{ - return (a < b ? a : b); -} - -inline double max(double a, double b) -{ - return (a > b ? a : b); -} - -inline float abs(float t) -{ - return ( t > 0 ? t : -t); -} - -inline float min(float a, float b) -{ - return (a < b ? a : b); -} - -inline int min(int a, int b) -{ - return (a < b ? a : b); -} - -inline int max(int a, int b) -{ - return (a > b ? a : b); -} - -inline float max(float a, float b) -{ - return (a > b ? a : b); -} - -inline double sign(double a) -{ - return (a > 0 ? 1.0 : -1.0); -} - -inline double sign(double a,double b) { - return (b >= 0.0 ? TNT::abs(a) : -TNT::abs(a)); -} - -inline float sign(float a,float b) { - return (b >= 0.0f ? TNT::abs(a) : -TNT::abs(a)); -} - -inline float sign(float a) -{ - return (a > 0.0 ? 1.0f : -1.0f); -} - -inline float pythag(float a, float b) -{ - float absa,absb; - absa = abs(a); - absb = abs(b); - - if (absa > absb) { - float sqr = absb/absa; - sqr *= sqr; - return absa * float(sqrt(1 + sqr)); - } else { - if (absb > float(0)) { - float sqr = absa/absb; - sqr *= sqr; - return absb * float(sqrt(1 + sqr)); - } else { - return float(0); - } - } -} - -inline double pythag(double a, double b) -{ - double absa,absb; - absa = abs(a); - absb = abs(b); - - if (absa > absb) { - double sqr = absb/absa; - sqr *= sqr; - return absa * double(sqrt(1 + sqr)); - } else { - - if (absb > double(0)) { - double sqr = absa/absb; - sqr *= sqr; - return absb * double(sqrt(1 + sqr)); - } else { - return double(0); - } - } -} - - -} /* namespace TNT */ - -#endif /* TNTMATH_H */ - diff --git a/intern/iksolver/intern/TNT/tntreqs.h b/intern/iksolver/intern/TNT/tntreqs.h deleted file mode 100644 index 2ee124d5940..00000000000 --- a/intern/iksolver/intern/TNT/tntreqs.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - -// The requirements for a bare-bones vector class: -// -// -// o) must have 0-based [] indexing for const and -// non-const objects (i.e. operator[] defined) -// -// o) must have size() method to denote the number of -// elements -// o) must clean up after itself when destructed -// (i.e. no memory leaks) -// -// -) must have begin() and end() methods (The begin() -// method is necessary, because relying on -// &v_[0] may not work on a empty vector (i.e. v_ is NULL.) -// -// o) must be templated -// o) must have X::value_type defined to be the types of elements -// o) must have X::X(const &x) copy constructor (by *value*) -// o) must have X::X(int N) constructor to N-length vector -// (NOTE: this constructor need *NOT* initalize elements) -// -// -) must have X::X(int N, T scalar) constructor to initalize -// elements to value of "scalar". -// -// ( removed, because valarray<> class uses (scalar, N) rather -// than (N, scalar) ) -// -) must have X::X(int N, const T* scalars) constructor to copy from -// any C linear array -// -// ( removed, because of same reverse order of valarray<> ) -// -// o) must have assignment A=B, by value -// -// NOTE: this class is *NOT* meant to be derived from, -// so its methods (particularly indexing) need not be -// declared virtual. -// -// -// Some things it *DOES NOT* need to do are -// -// o) bounds checking -// o) array referencing (e.g. reference counting) -// o) support () indexing -// o) I/O -// - diff --git a/intern/iksolver/intern/TNT/transv.h b/intern/iksolver/intern/TNT/transv.h deleted file mode 100644 index 5500cecff40..00000000000 --- a/intern/iksolver/intern/TNT/transv.h +++ /dev/null @@ -1,164 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -// Matrix Transpose Views - -#ifndef TRANSV_H -#define TRANSV_H - -#include <iostream> -#include <cassert> -#include "vec.h" - -namespace TNT -{ - -template <class Array2D> -class Transpose_View -{ - protected: - - const Array2D & A_; - - public: - - typedef typename Array2D::element_type T; - typedef T value_type; - typedef T element_type; - typedef T* pointer; - typedef T* iterator; - typedef T& reference; - typedef const T* const_iterator; - typedef const T& const_reference; - - - const Array2D & array() const { return A_; } - Subscript num_rows() const { return A_.num_cols();} - Subscript num_cols() const { return A_.num_rows();} - Subscript lbound() const { return A_.lbound(); } - Subscript dim(Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert( A_.lbound() <= i); - assert( i<= A_.lbound()+1); -#endif - if (i== A_.lbound()) - return num_rows(); - else - return num_cols(); - } - - - Transpose_View(const Transpose_View<Array2D> &A) : A_(A.A_) {}; - Transpose_View(const Array2D &A) : A_(A) {}; - - - inline const typename Array2D::element_type & operator()( - Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(lbound()<=i); - assert(i<=A_.num_cols() + lbound() - 1); - assert(lbound()<=j); - assert(j<=A_.num_rows() + lbound() - 1); -#endif - - return A_(j,i); - } - - -}; - -template <class Matrix> -Transpose_View<Matrix> Transpose_view(const Matrix &A) -{ - return Transpose_View<Matrix>(A); -} - -template <class Matrix, class T> -Vector<T> matmult( - const Transpose_View<Matrix> & A, - const Vector<T> &B) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(B.dim() == N); - - Vector<T> x(N); - - Subscript i, j; - T tmp = 0; - - for (i=1; i<=M; i++) - { - tmp = 0; - for (j=1; j<=N; j++) - tmp += A(i,j) * B(j); - x(i) = tmp; - } - - return x; -} - -template <class Matrix, class T> -inline Vector<T> operator*(const Transpose_View<Matrix> & A, const Vector<T> &B) -{ - return matmult(A,B); -} - - -template <class Matrix> -std::ostream& operator<<(std::ostream &s, const Transpose_View<Matrix> &A) -{ - Subscript M=A.num_rows(); - Subscript N=A.num_cols(); - - Subscript start = A.lbound(); - Subscript Mend = M + A.lbound() - 1; - Subscript Nend = N + A.lbound() - 1; - - s << M << " " << N << endl; - for (Subscript i=start; i<=Mend; i++) - { - for (Subscript j=start; j<=Nend; j++) - { - s << A(i,j) << " "; - } - s << endl; - } - - - return s; -} - -} // namespace TNT - -#endif // TRANSV_H - diff --git a/intern/iksolver/intern/TNT/triang.h b/intern/iksolver/intern/TNT/triang.h deleted file mode 100644 index 10ec2cb18c3..00000000000 --- a/intern/iksolver/intern/TNT/triang.h +++ /dev/null @@ -1,637 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -// Triangular Matrices (Views and Adpators) - -#ifndef TRIANG_H -#define TRIANG_H - -// default to use lower-triangular portions of arrays -// for symmetric matrices. - -namespace TNT -{ - -template <class MaTRiX> -class LowerTriangularView -{ - protected: - - - const MaTRiX &A_; - const typename MaTRiX::element_type zero_; - - public: - - - typedef typename MaTRiX::const_reference const_reference; - typedef const typename MaTRiX::element_type element_type; - typedef const typename MaTRiX::element_type value_type; - typedef element_type T; - - Subscript dim(Subscript d) const { return A_.dim(d); } - Subscript lbound() const { return A_.lbound(); } - Subscript num_rows() const { return A_.num_rows(); } - Subscript num_cols() const { return A_.num_cols(); } - - - // constructors - - LowerTriangularView(/*const*/ MaTRiX &A) : A_(A), zero_(0) {} - - - inline const_reference get(Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(lbound()<=i); - assert(i<=A_.num_rows() + lbound() - 1); - assert(lbound()<=j); - assert(j<=A_.num_cols() + lbound() - 1); -#endif - if (i<j) - return zero_; - else - return A_(i,j); - } - - - inline const_reference operator() (Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(lbound()<=i); - assert(i<=A_.num_rows() + lbound() - 1); - assert(lbound()<=j); - assert(j<=A_.num_cols() + lbound() - 1); -#endif - if (i<j) - return zero_; - else - return A_(i,j); - } - -#ifdef TNT_USE_REGIONS - - typedef const_Region2D< LowerTriangularView<MaTRiX> > - const_Region; - - const_Region operator()(/*const*/ Index1D &I, - /*const*/ Index1D &J) const - { - return const_Region(*this, I, J); - } - - const_Region operator()(Subscript i1, Subscript i2, - Subscript j1, Subscript j2) const - { - return const_Region(*this, i1, i2, j1, j2); - } - - - -#endif -// TNT_USE_REGIONS - -}; - - -/* *********** Lower_triangular_view() algorithms ****************** */ - -template <class MaTRiX, class VecToR> -VecToR matmult(/*const*/ LowerTriangularView<MaTRiX> &A, VecToR &x) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(N == x.dim()); - - Subscript i, j; - typename MaTRiX::element_type sum=0.0; - VecToR result(M); - - Subscript start = A.lbound(); - Subscript Mend = M + A.lbound() -1 ; - - for (i=start; i<=Mend; i++) - { - sum = 0.0; - for (j=start; j<=i; j++) - sum = sum + A(i,j)*x(j); - result(i) = sum; - } - - return result; -} - -template <class MaTRiX, class VecToR> -inline VecToR operator*(/*const*/ LowerTriangularView<MaTRiX> &A, VecToR &x) -{ - return matmult(A,x); -} - -template <class MaTRiX> -class UnitLowerTriangularView -{ - protected: - - const MaTRiX &A_; - const typename MaTRiX::element_type zero; - const typename MaTRiX::element_type one; - - public: - - typedef typename MaTRiX::const_reference const_reference; - typedef typename MaTRiX::element_type element_type; - typedef typename MaTRiX::element_type value_type; - typedef element_type T; - - Subscript lbound() const { return 1; } - Subscript dim(Subscript d) const { return A_.dim(d); } - Subscript num_rows() const { return A_.num_rows(); } - Subscript num_cols() const { return A_.num_cols(); } - - - // constructors - - UnitLowerTriangularView(/*const*/ MaTRiX &A) : A_(A), zero(0), one(1) {} - - - inline const_reference get(Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i<=A_.dim(1)); - assert(1<=j); - assert(j<=A_.dim(2)); - assert(0<=i && i<A_.dim(0) && 0<=j && j<A_.dim(1)); -#endif - if (i>j) - return A_(i,j); - else if (i==j) - return one; - else - return zero; - } - - - inline const_reference operator() (Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i<=A_.dim(1)); - assert(1<=j); - assert(j<=A_.dim(2)); -#endif - if (i>j) - return A_(i,j); - else if (i==j) - return one; - else - return zero; - } - - -#ifdef TNT_USE_REGIONS - // These are the "index-aware" features - - typedef const_Region2D< UnitLowerTriangularView<MaTRiX> > - const_Region; - - const_Region operator()(/*const*/ Index1D &I, - /*const*/ Index1D &J) const - { - return const_Region(*this, I, J); - } - - const_Region operator()(Subscript i1, Subscript i2, - Subscript j1, Subscript j2) const - { - return const_Region(*this, i1, i2, j1, j2); - } -#endif -// TNT_USE_REGIONS -}; - -template <class MaTRiX> -LowerTriangularView<MaTRiX> Lower_triangular_view( - /*const*/ MaTRiX &A) -{ - return LowerTriangularView<MaTRiX>(A); -} - - -template <class MaTRiX> -UnitLowerTriangularView<MaTRiX> Unit_lower_triangular_view( - /*const*/ MaTRiX &A) -{ - return UnitLowerTriangularView<MaTRiX>(A); -} - -template <class MaTRiX, class VecToR> -VecToR matmult(/*const*/ UnitLowerTriangularView<MaTRiX> &A, VecToR &x) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(N == x.dim()); - - Subscript i, j; - typename MaTRiX::element_type sum=0.0; - VecToR result(M); - - Subscript start = A.lbound(); - Subscript Mend = M + A.lbound() -1 ; - - for (i=start; i<=Mend; i++) - { - sum = 0.0; - for (j=start; j<i; j++) - sum = sum + A(i,j)*x(j); - result(i) = sum + x(i); - } - - return result; -} - -template <class MaTRiX, class VecToR> -inline VecToR operator*(/*const*/ UnitLowerTriangularView<MaTRiX> &A, VecToR &x) -{ - return matmult(A,x); -} - - -//********************** Algorithms ************************************* - - - -template <class MaTRiX> -std::ostream& operator<<(std::ostream &s, const LowerTriangularView<MaTRiX>&A) -{ - Subscript M=A.num_rows(); - Subscript N=A.num_cols(); - - s << M << " " << N << endl; - - for (Subscript i=1; i<=M; i++) - { - for (Subscript j=1; j<=N; j++) - { - s << A(i,j) << " "; - } - s << endl; - } - - - return s; -} - -template <class MaTRiX> -std::ostream& operator<<(std::ostream &s, - const UnitLowerTriangularView<MaTRiX>&A) -{ - Subscript M=A.num_rows(); - Subscript N=A.num_cols(); - - s << M << " " << N << endl; - - for (Subscript i=1; i<=M; i++) - { - for (Subscript j=1; j<=N; j++) - { - s << A(i,j) << " "; - } - s << endl; - } - - - return s; -} - - - -// ******************* Upper Triangular Section ************************** - -template <class MaTRiX> -class UpperTriangularView -{ - protected: - - - /*const*/ MaTRiX &A_; - /*const*/ typename MaTRiX::element_type zero_; - - public: - - - typedef typename MaTRiX::const_reference const_reference; - typedef /*const*/ typename MaTRiX::element_type element_type; - typedef /*const*/ typename MaTRiX::element_type value_type; - typedef element_type T; - - Subscript dim(Subscript d) const { return A_.dim(d); } - Subscript lbound() const { return A_.lbound(); } - Subscript num_rows() const { return A_.num_rows(); } - Subscript num_cols() const { return A_.num_cols(); } - - - // constructors - - UpperTriangularView(/*const*/ MaTRiX &A) : A_(A), zero_(0) {} - - - inline const_reference get(Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(lbound()<=i); - assert(i<=A_.num_rows() + lbound() - 1); - assert(lbound()<=j); - assert(j<=A_.num_cols() + lbound() - 1); -#endif - if (i>j) - return zero_; - else - return A_(i,j); - } - - - inline const_reference operator() (Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(lbound()<=i); - assert(i<=A_.num_rows() + lbound() - 1); - assert(lbound()<=j); - assert(j<=A_.num_cols() + lbound() - 1); -#endif - if (i>j) - return zero_; - else - return A_(i,j); - } - -#ifdef TNT_USE_REGIONS - - typedef const_Region2D< UpperTriangularView<MaTRiX> > - const_Region; - - const_Region operator()(const Index1D &I, - const Index1D &J) const - { - return const_Region(*this, I, J); - } - - const_Region operator()(Subscript i1, Subscript i2, - Subscript j1, Subscript j2) const - { - return const_Region(*this, i1, i2, j1, j2); - } - - - -#endif -// TNT_USE_REGIONS - -}; - - -/* *********** Upper_triangular_view() algorithms ****************** */ - -template <class MaTRiX, class VecToR> -VecToR matmult(/*const*/ UpperTriangularView<MaTRiX> &A, VecToR &x) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(N == x.dim()); - - Subscript i, j; - typename VecToR::element_type sum=0.0; - VecToR result(M); - - Subscript start = A.lbound(); - Subscript Mend = M + A.lbound() -1 ; - - for (i=start; i<=Mend; i++) - { - sum = 0.0; - for (j=i; j<=N; j++) - sum = sum + A(i,j)*x(j); - result(i) = sum; - } - - return result; -} - -template <class MaTRiX, class VecToR> -inline VecToR operator*(/*const*/ UpperTriangularView<MaTRiX> &A, VecToR &x) -{ - return matmult(A,x); -} - -template <class MaTRiX> -class UnitUpperTriangularView -{ - protected: - - const MaTRiX &A_; - const typename MaTRiX::element_type zero; - const typename MaTRiX::element_type one; - - public: - - typedef typename MaTRiX::const_reference const_reference; - typedef typename MaTRiX::element_type element_type; - typedef typename MaTRiX::element_type value_type; - typedef element_type T; - - Subscript lbound() const { return 1; } - Subscript dim(Subscript d) const { return A_.dim(d); } - Subscript num_rows() const { return A_.num_rows(); } - Subscript num_cols() const { return A_.num_cols(); } - - - // constructors - - UnitUpperTriangularView(/*const*/ MaTRiX &A) : A_(A), zero(0), one(1) {} - - - inline const_reference get(Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i<=A_.dim(1)); - assert(1<=j); - assert(j<=A_.dim(2)); - assert(0<=i && i<A_.dim(0) && 0<=j && j<A_.dim(1)); -#endif - if (i<j) - return A_(i,j); - else if (i==j) - return one; - else - return zero; - } - - - inline const_reference operator() (Subscript i, Subscript j) const - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i<=A_.dim(1)); - assert(1<=j); - assert(j<=A_.dim(2)); -#endif - if (i<j) - return A_(i,j); - else if (i==j) - return one; - else - return zero; - } - - -#ifdef TNT_USE_REGIONS - // These are the "index-aware" features - - typedef const_Region2D< UnitUpperTriangularView<MaTRiX> > - const_Region; - - const_Region operator()(const Index1D &I, - const Index1D &J) const - { - return const_Region(*this, I, J); - } - - const_Region operator()(Subscript i1, Subscript i2, - Subscript j1, Subscript j2) const - { - return const_Region(*this, i1, i2, j1, j2); - } -#endif -// TNT_USE_REGIONS -}; - -template <class MaTRiX> -UpperTriangularView<MaTRiX> Upper_triangular_view( - /*const*/ MaTRiX &A) -{ - return UpperTriangularView<MaTRiX>(A); -} - - -template <class MaTRiX> -UnitUpperTriangularView<MaTRiX> Unit_upper_triangular_view( - /*const*/ MaTRiX &A) -{ - return UnitUpperTriangularView<MaTRiX>(A); -} - -template <class MaTRiX, class VecToR> -VecToR matmult(/*const*/ UnitUpperTriangularView<MaTRiX> &A, VecToR &x) -{ - Subscript M = A.num_rows(); - Subscript N = A.num_cols(); - - assert(N == x.dim()); - - Subscript i, j; - typename VecToR::element_type sum=0.0; - VecToR result(M); - - Subscript start = A.lbound(); - Subscript Mend = M + A.lbound() -1 ; - - for (i=start; i<=Mend; i++) - { - sum = x(i); - for (j=i+1; j<=N; j++) - sum = sum + A(i,j)*x(j); - result(i) = sum + x(i); - } - - return result; -} - -template <class MaTRiX, class VecToR> -inline VecToR operator*(/*const*/ UnitUpperTriangularView<MaTRiX> &A, VecToR &x) -{ - return matmult(A,x); -} - - -//********************** Algorithms ************************************* - - - -template <class MaTRiX> -std::ostream& operator<<(std::ostream &s, - /*const*/ UpperTriangularView<MaTRiX>&A) -{ - Subscript M=A.num_rows(); - Subscript N=A.num_cols(); - - s << M << " " << N << endl; - - for (Subscript i=1; i<=M; i++) - { - for (Subscript j=1; j<=N; j++) - { - s << A(i,j) << " "; - } - s << endl; - } - - - return s; -} - -template <class MaTRiX> -std::ostream& operator<<(std::ostream &s, - /*const*/ UnitUpperTriangularView<MaTRiX>&A) -{ - Subscript M=A.num_rows(); - Subscript N=A.num_cols(); - - s << M << " " << N << endl; - - for (Subscript i=1; i<=M; i++) - { - for (Subscript j=1; j<=N; j++) - { - s << A(i,j) << " "; - } - s << endl; - } - - - return s; -} - -} // namespace TNT - -#endif //TRIANG_H - diff --git a/intern/iksolver/intern/TNT/trisolve.h b/intern/iksolver/intern/TNT/trisolve.h deleted file mode 100644 index e6e2a0afe3a..00000000000 --- a/intern/iksolver/intern/TNT/trisolve.h +++ /dev/null @@ -1,188 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -// Triangular Solves - -#ifndef TRISLV_H -#define TRISLV_H - - -#include "triang.h" - -namespace TNT -{ - -template <class MaTriX, class VecToR> -VecToR Lower_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) -{ - Subscript N = A.num_rows(); - - // make sure matrix sizes agree; A must be square - - assert(A.num_cols() == N); - assert(b.dim() == N); - - VecToR x(N); - - Subscript i; - for (i=1; i<=N; i++) - { - typename MaTriX::element_type tmp=0; - - for (Subscript j=1; j<i; j++) - tmp = tmp + A(i,j)*x(j); - - x(i) = (b(i) - tmp)/ A(i,i); - } - - return x; -} - - -template <class MaTriX, class VecToR> -VecToR Unit_lower_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) -{ - Subscript N = A.num_rows(); - - // make sure matrix sizes agree; A must be square - - assert(A.num_cols() == N); - assert(b.dim() == N); - - VecToR x(N); - - Subscript i; - for (i=1; i<=N; i++) - { - - typename MaTriX::element_type tmp=0; - - for (Subscript j=1; j<i; j++) - tmp = tmp + A(i,j)*x(j); - - x(i) = b(i) - tmp; - } - - return x; -} - - -template <class MaTriX, class VecToR> -VecToR linear_solve(/*const*/ LowerTriangularView<MaTriX> &A, - /*const*/ VecToR &b) -{ - return Lower_triangular_solve(A, b); -} - -template <class MaTriX, class VecToR> -VecToR linear_solve(/*const*/ UnitLowerTriangularView<MaTriX> &A, - /*const*/ VecToR &b) -{ - return Unit_lower_triangular_solve(A, b); -} - - - -//********************** Upper triangular section **************** - -template <class MaTriX, class VecToR> -VecToR Upper_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) -{ - Subscript N = A.num_rows(); - - // make sure matrix sizes agree; A must be square - - assert(A.num_cols() == N); - assert(b.dim() == N); - - VecToR x(N); - - Subscript i; - for (i=N; i>=1; i--) - { - - typename MaTriX::element_type tmp=0; - - for (Subscript j=i+1; j<=N; j++) - tmp = tmp + A(i,j)*x(j); - - x(i) = (b(i) - tmp)/ A(i,i); - } - - return x; -} - - -template <class MaTriX, class VecToR> -VecToR Unit_upper_triangular_solve(/*const*/ MaTriX &A, /*const*/ VecToR &b) -{ - Subscript N = A.num_rows(); - - // make sure matrix sizes agree; A must be square - - assert(A.num_cols() == N); - assert(b.dim() == N); - - VecToR x(N); - - Subscript i; - for (i=N; i>=1; i--) - { - - typename MaTriX::element_type tmp=0; - - for (Subscript j=i+1; j<i; j++) - tmp = tmp + A(i,j)*x(j); - - x(i) = b(i) - tmp; - } - - return x; -} - - -template <class MaTriX, class VecToR> -VecToR linear_solve(/*const*/ UpperTriangularView<MaTriX> &A, - /*const*/ VecToR &b) -{ - return Upper_triangular_solve(A, b); -} - -template <class MaTriX, class VecToR> -VecToR linear_solve(/*const*/ UnitUpperTriangularView<MaTriX> &A, - /*const*/ VecToR &b) -{ - return Unit_upper_triangular_solve(A, b); -} - - -} // namespace TNT - -#endif // TRISLV_H - diff --git a/intern/iksolver/intern/TNT/vec.h b/intern/iksolver/intern/TNT/vec.h deleted file mode 100644 index 5d4ef14bf73..00000000000 --- a/intern/iksolver/intern/TNT/vec.h +++ /dev/null @@ -1,491 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - -// Basic TNT numerical vector (0-based [i] AND 1-based (i) indexing ) -// - -#ifndef VEC_H -#define VEC_H - -#include "subscript.h" -#include <stdlib.h> -#include <assert.h> -#include <iostream> - -namespace TNT -{ - -template <class T> -class Vector -{ - - - public: - - typedef Subscript size_type; - typedef T value_type; - typedef T element_type; - typedef T* pointer; - typedef T* iterator; - typedef T& reference; - typedef const T* const_iterator; - typedef const T& const_reference; - - Subscript lbound() const { return 1;} - - protected: - T* v_; - T* vm1_; // pointer adjustment for optimzied 1-offset indexing - Subscript n_; - - // internal helper function to create the array - // of row pointers - - void initialize(Subscript N) - { - // adjust pointers so that they are 1-offset: - // v_[] is the internal contiguous array, it is still 0-offset - // - assert(v_ == NULL); - v_ = new T[N]; - assert(v_ != NULL); - vm1_ = v_-1; - n_ = N; - } - - void copy(const T* v) - { - Subscript N = n_; - Subscript i; - -#ifdef TNT_UNROLL_LOOPS - Subscript Nmod4 = N & 3; - Subscript N4 = N - Nmod4; - - for (i=0; i<N4; i+=4) - { - v_[i] = v[i]; - v_[i+1] = v[i+1]; - v_[i+2] = v[i+2]; - v_[i+3] = v[i+3]; - } - - for (i=N4; i< N; i++) - v_[i] = v[i]; -#else - - for (i=0; i< N; i++) - v_[i] = v[i]; -#endif - } - - void set(const T& val) - { - Subscript N = n_; - Subscript i; - -#ifdef TNT_UNROLL_LOOPS - Subscript Nmod4 = N & 3; - Subscript N4 = N - Nmod4; - - for (i=0; i<N4; i+=4) - { - v_[i] = val; - v_[i+1] = val; - v_[i+2] = val; - v_[i+3] = val; - } - - for (i=N4; i< N; i++) - v_[i] = val; -#else - - for (i=0; i< N; i++) - v_[i] = val; - -#endif - } - - - - void destroy() - { - /* do nothing, if no memory has been previously allocated */ - if (v_ == NULL) return ; - - /* if we are here, then matrix was previously allocated */ - delete [] (v_); - - v_ = NULL; - vm1_ = NULL; - } - - - public: - - // access - - iterator begin() { return v_;} - iterator end() { return v_ + n_; } - const iterator begin() const { return v_;} - const iterator end() const { return v_ + n_; } - - // destructor - - ~Vector() - { - destroy(); - } - - // constructors - - Vector() : v_(0), vm1_(0), n_(0) {} - - Vector(const Vector<T> &A) : v_(0), vm1_(0), n_(0) - { - initialize(A.n_); - copy(A.v_); - } - - Vector(Subscript N, const T& value = T()) : v_(0), vm1_(0), n_(0) - { - initialize(N); - set(value); - } - - Vector(Subscript N, const T* v) : v_(0), vm1_(0), n_(0) - { - initialize(N); - copy(v); - } - - - // methods - // - Vector<T>& newsize(Subscript N) - { - if (n_ == N) return *this; - - destroy(); - initialize(N); - - return *this; - } - - - // assignments - // - Vector<T>& operator=(const Vector<T> &A) - { - if (v_ == A.v_) - return *this; - - if (n_ == A.n_) // no need to re-alloc - copy(A.v_); - - else - { - destroy(); - initialize(A.n_); - copy(A.v_); - } - - return *this; - } - - Vector<T>& operator=(const T& scalar) - { - set(scalar); - return *this; - } - - inline Subscript dim() const - { - return n_; - } - - inline Subscript size() const - { - return n_; - } - - - inline reference operator()(Subscript i) - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i <= n_) ; -#endif - return vm1_[i]; - } - - inline const_reference operator() (Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i <= n_) ; -#endif - return vm1_[i]; - } - - inline reference operator[](Subscript i) - { -#ifdef TNT_BOUNDS_CHECK - assert(0<=i); - assert(i < n_) ; -#endif - return v_[i]; - } - - inline const_reference operator[](Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(0<=i) ; - assert(i < n_) ; -#endif - return v_[i]; - } - - - -}; - - -/* *************************** I/O ********************************/ - -template <class T> -std::ostream& operator<<(std::ostream &s, const Vector<T> &A) -{ - Subscript N=A.dim(); - - s << N << std::endl; - - for (Subscript i=0; i<N; i++) - s << A[i] << " " << std::endl; - s << std::endl; - - return s; -} - -template <class T> -std::istream & operator>>(std::istream &s, Vector<T> &A) -{ - - Subscript N; - - s >> N; - - if ( !(N == A.size() )) - { - A.newsize(N); - } - - - for (Subscript i=0; i<N; i++) - s >> A[i]; - - - return s; -} - -// *******************[ basic matrix algorithms ]*************************** - - -template <class T> -Vector<T> operator+(const Vector<T> &A, - const Vector<T> &B) -{ - Subscript N = A.dim(); - - assert(N==B.dim()); - - Vector<T> tmp(N); - Subscript i; - - for (i=0; i<N; i++) - tmp[i] = A[i] + B[i]; - - return tmp; -} - -template <class T> -Vector<T> operator-(const Vector<T> &A, - const Vector<T> &B) -{ - Subscript N = A.dim(); - - assert(N==B.dim()); - - Vector<T> tmp(N); - Subscript i; - - for (i=0; i<N; i++) - tmp[i] = A[i] - B[i]; - - return tmp; -} - -template <class T> -Vector<T> operator*(const Vector<T> &A, - const Vector<T> &B) -{ - Subscript N = A.dim(); - - assert(N==B.dim()); - - Vector<T> tmp(N); - Subscript i; - - for (i=0; i<N; i++) - tmp[i] = A[i] * B[i]; - - return tmp; -} - -template <class T> -Vector<T> operator*(const Vector<T> &A, - const T &B) -{ - Subscript N = A.dim(); - - Vector<T> tmp(N); - Subscript i; - - for (i=0; i<N; i++) - tmp[i] = A[i] * B; - - return tmp; -} - - -template <class T> -T dot_prod(const Vector<T> &A, const Vector<T> &B) -{ - Subscript N = A.dim(); - assert(N == B.dim()); - - Subscript i; - T sum = 0; - - for (i=0; i<N; i++) - sum += A[i] * B[i]; - - return sum; -} - -// inplace versions of the above template functions - -// A = A + B - -template <class T> -void vectoradd( - Vector<T> &A, - const Vector<T> &B) -{ - const Subscript N = A.dim(); - assert(N==B.dim()); - Subscript i; - - for (i=0; i<N; i++) - A[i] += B[i]; -} - -// same with separate output vector - -template <class T> -void vectoradd( - Vector<T> &C, - const Vector<T> &A, - const Vector<T> &B) -{ - const Subscript N = A.dim(); - assert(N==B.dim()); - Subscript i; - - for (i=0; i<N; i++) - C[i] = A[i] + B[i]; -} - -// A = A - B - -template <class T> -void vectorsub( - Vector<T> &A, - const Vector<T> &B) -{ - const Subscript N = A.dim(); - assert(N==B.dim()); - Subscript i; - - for (i=0; i<N; i++) - A[i] -= B[i]; -} - -template <class T> -void vectorsub( - Vector<T> &C, - const Vector<T> &A, - const Vector<T> &B) -{ - const Subscript N = A.dim(); - assert(N==B.dim()); - Subscript i; - - for (i=0; i<N; i++) - C[i] = A[i] - B[i]; -} - -template <class T> -void vectorscale( - Vector<T> &C, - const Vector<T> &A, - const T &B) -{ - const Subscript N = A.dim(); - Subscript i; - - for (i=0; i<N; i++) - C[i] = A[i] * B; -} - -template <class T> -void vectorscale( - Vector<T> &A, - const T &B) -{ - const Subscript N = A.dim(); - Subscript i; - - for (i=0; i<N; i++) - A[i] *= B; -} - -} /* namespace TNT */ - -#endif // VEC_H - diff --git a/intern/iksolver/intern/TNT/vecadaptor.h b/intern/iksolver/intern/TNT/vecadaptor.h deleted file mode 100644 index 77d4e2c05a4..00000000000 --- a/intern/iksolver/intern/TNT/vecadaptor.h +++ /dev/null @@ -1,284 +0,0 @@ -/** - */ - -/* - -* -* Template Numerical Toolkit (TNT): Linear Algebra Module -* -* Mathematical and Computational Sciences Division -* National Institute of Technology, -* Gaithersburg, MD USA -* -* -* This software was developed at the National Institute of Standards and -* Technology (NIST) by employees of the Federal Government in the course -* of their official duties. Pursuant to title 17 Section 105 of the -* United States Code, this software is not subject to copyright protection -* and is in the public domain. The Template Numerical Toolkit (TNT) is -* an experimental system. NIST assumes no responsibility whatsoever for -* its use by other parties, and makes no guarantees, expressed or implied, -* about its quality, reliability, or any other characteristic. -* -* BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -* see http://math.nist.gov/tnt for latest updates. -* -*/ - - - -#ifndef VECADAPTOR_H -#define VECADAPTOR_H - -#include <cstdlib> -#include <iostream> -#include <cassert> - -#include "subscript.h" - -#ifdef TNT_USE_REGIONS -#include "region1d.h" -#endif - -namespace TNT -{ - -// see "tntreq.h" for TNT requirements for underlying vector -// class. This need NOT be the STL vector<> class, but a subset -// that provides minimal services. -// -// This is a container adaptor that provides the following services. -// -// o) adds 1-offset operator() access ([] is always 0 offset) -// o) adds TNT_BOUNDS_CHECK to () and [] -// o) adds initialization from strings, e.g. "1.0 2.0 3.0"; -// o) adds newsize(N) function (does not preserve previous values) -// o) adds dim() and dim(1) -// o) adds free() function to release memory used by vector -// o) adds regions, e.g. A(Index(1,10)) = ... -// o) add getVector() method to return adapted container -// o) adds simple I/O for ostreams - -template <class BBVec> -class Vector_Adaptor -{ - - public: - typedef typename BBVec::value_type T; - typedef T value_type; - typedef T element_type; - typedef T* pointer; - typedef T* iterator; - typedef T& reference; - typedef const T* const_iterator; - typedef const T& const_reference; - - Subscript lbound() const { return 1; } - - protected: - BBVec v_; - T* vm1_; - - public: - - Subscript size() const { return v_.size(); } - - // These were removed so that the ANSI C++ valarray class - // would work as a possible storage container. - // - // - //iterator begin() { return v_.begin();} - //iterator begin() { return &v_[0];} - // - //iterator end() { return v_.end(); } - //iterator end() { return &v_[0] + v_.size(); } - // - //const_iterator begin() const { return v_.begin();} - //const_iterator begin() const { return &v_[0];} - // - //const_iterator end() const { return v_.end(); } - //const_iterator end() const { return &v_[0] + v_.size(); } - - BBVec& getVector() { return v_; } - Subscript dim() const { return v_.size(); } - Subscript dim(Subscript i) - { -#ifdef TNT_BOUNDS_CHECK - assert(i==TNT_BASE_OFFSET); -#endif - return (i==TNT_BASE_OFFSET ? v_.size() : 0 ); - } - Vector_Adaptor() : v_() {}; - Vector_Adaptor(const Vector_Adaptor<BBVec> &A) : v_(A.v_) - { - vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); - - } - - Vector_Adaptor(Subscript N, const T& value = T()) : v_(N) - { - for (Subscript i=0; i<N; i++) - v_[i] = value; - - vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); - } - - Vector_Adaptor(Subscript N, const T* values) : v_(N) - { - for (Subscript i=0; i<N; i++) - v_[i] = values[i]; - vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); - } - Vector_Adaptor(const BBVec & A) : v_(A) - { - vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); - } - - // NOTE: this assumes that BBVec(0) constructor creates an - // null vector that does not take up space... It would be - // great to require that BBVec have a corresponding free() - // function, but in particular STL vectors do not. - // - Vector_Adaptor<BBVec>& free() - { - return *this = Vector_Adaptor<BBVec>(0); - } - - Vector_Adaptor<BBVec>& operator=(const Vector_Adaptor<BBVec> &A) - { - v_ = A.v_ ; - vm1_ = ( v_.size() > 0 ? &(v_[0]) -1 : NULL); - return *this; - } - - Vector_Adaptor<BBVec>& newsize(Subscript N) - { - // NOTE: this is not as efficient as it could be - // but to retain compatiblity with STL interface - // we cannot assume underlying implementation - // has a newsize() function. - - return *this = Vector_Adaptor<BBVec>(N); - - } - - Vector_Adaptor<BBVec>& operator=(const T &a) - { - Subscript i; - Subscript N = v_.size(); - for (i=0; i<N; i++) - v_[i] = a; - - return *this; - } - - Vector_Adaptor<BBVec>& resize(Subscript N) - { - if (N == size()) return *this; - - Vector_Adaptor<BBVec> tmp(N); - Subscript n = (N < size() ? N : size()); // min(N, size()); - Subscript i; - - for (i=0; i<n; i++) - tmp[i] = v_[i]; - - - return (*this = tmp); - - } - - - reference operator()(Subscript i) - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i<=dim()); -#endif - return vm1_[i]; - } - - const_reference operator()(Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(1<=i); - assert(i<=dim()); -#endif - return vm1_[i]; - } - - reference operator[](Subscript i) - { -#ifdef TNT_BOUNDS_CHECK - assert(0<=i); - assert(i<dim()); -#endif - return v_[i]; - } - - const_reference operator[](Subscript i) const - { -#ifdef TNT_BOUNDS_CHECK - assert(0<=i); - assert(i<dim()); -#endif - return v_[i]; - } - - -#ifdef TNT_USE_REGIONS - // "index-aware" features, all of these are 1-based offsets - - typedef Region1D<Vector_Adaptor<BBVec> > Region; - - typedef const_Region1D< Vector_Adaptor<BBVec> > const_Region; - - Region operator()(const Index1D &I) - { return Region(*this, I); } - - Region operator()(const Subscript i1, Subscript i2) - { return Region(*this, i1, i2); } - - const_Region operator()(const Index1D &I) const - { return const_Region(*this, I); } - - const_Region operator()(const Subscript i1, Subscript i2) const - { return const_Region(*this, i1, i2); } -#endif -// TNT_USE_REGIONS - - -}; - -#include <iostream> - -template <class BBVec> -std::ostream& operator<<(std::ostream &s, const Vector_Adaptor<BBVec> &A) -{ - Subscript M=A.size(); - - s << M << endl; - for (Subscript i=1; i<=M; i++) - s << A(i) << endl; - return s; -} - -template <class BBVec> -std::istream& operator>>(std::istream &s, Vector_Adaptor<BBVec> &A) -{ - Subscript N; - - s >> N; - - A.resize(N); - - for (Subscript i=1; i<=N; i++) - s >> A(i); - - return s; -} - -} // namespace TNT - -#endif - diff --git a/intern/iksolver/intern/TNT/version.h b/intern/iksolver/intern/TNT/version.h deleted file mode 100644 index 58017dd80f9..00000000000 --- a/intern/iksolver/intern/TNT/version.h +++ /dev/null @@ -1,25 +0,0 @@ -/** - */ - -// Template Numerical Toolkit (TNT) for Linear Algebra - -// -// BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE -// Please see http://math.nist.gov/tnt for updates -// -// R. Pozo -// Mathematical and Computational Sciences Division -// National Institute of Standards and Technology - - -#ifndef TNT_VERSION_H -#define TNT_VERSION_H - - -#define TNT_MAJOR_VERSION '0' -#define TNT_MINOR_VERSION '9' -#define TNT_SUBMINOR_VERSION '4' -#define TNT_VERSION_STRING "0.9.4" - -#endif - diff --git a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp deleted file mode 100644 index b138dd18725..00000000000 --- a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "GlutDrawer.h" - -#include "MT_assert.h" - -MEM_SmartPtr<GlutDrawManager> GlutDrawManager::m_s_instance = MEM_SmartPtr<GlutDrawManager>(); - - GlutDrawManager * -GlutDrawManager:: -Instance( -){ - if (m_s_instance == NULL) { - m_s_instance = new GlutDrawManager(); - } - - return m_s_instance; -} - - -// this is the function you should pass to glut - - void -GlutDrawManager:: -Draw( -){ - GlutDrawManager *manager = GlutDrawManager::Instance(); - - if (manager->m_drawer != NULL) { - manager->m_drawer->Draw(); - } -} - - void -GlutDrawManager:: -InstallDrawer( - GlutDrawer * drawer -){ - - MT_assert(m_drawer == NULL); - m_drawer = drawer; -} - - void -GlutDrawManager:: -ReleaseDrawer( -){ - m_drawer = NULL; -} - - -GlutDrawManager:: -~GlutDrawManager( -){ - - delete(m_drawer); -} - - - - - - - - - diff --git a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h b/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h deleted file mode 100644 index 05d2424dfea..00000000000 --- a/intern/iksolver/test/ik_glut_test/common/GlutDrawer.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __GLUTDRAWER_H__ -#define __GLUTDRAWER_H__ - -#include "MEM_NonCopyable.h" -#include "MEM_SmartPtr.h" - -// So pissed off with Glut callback stuff -// that is impossible to call objects unless they are global - -// inherit from GlutDrawer and installl the drawer in the singleton -// class GlutDrawManager. - -class GlutDrawer { -public : - - virtual - void - Draw( - )= 0; - - virtual - ~GlutDrawer( - ){}; -}; - -class GlutDrawManager : public MEM_NonCopyable{ - -public : - - static - GlutDrawManager * - Instance( - ); - - // this is the function you should pass to glut - - static - void - Draw( - ); - - void - InstallDrawer( - GlutDrawer * - ); - - void - ReleaseDrawer( - ); - - ~GlutDrawManager( - ); - -private : - - GlutDrawManager ( - ) : - m_drawer (0) - { - }; - - GlutDrawer * m_drawer; - - static MEM_SmartPtr<GlutDrawManager> m_s_instance; -}; - -#endif - diff --git a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp deleted file mode 100644 index 0b7a16b032b..00000000000 --- a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "GlutKeyboardManager.h" -#include "MT_assert.h" - -MEM_SmartPtr<GlutKeyboardManager> GlutKeyboardManager::m_s_instance = MEM_SmartPtr<GlutKeyboardManager>(); - - GlutKeyboardManager * -GlutKeyboardManager:: -Instance( -){ - if (m_s_instance == NULL) { - m_s_instance = new GlutKeyboardManager(); - } - - return m_s_instance; -} - - -// this is the function you should pass to glut - - void -GlutKeyboardManager:: -HandleKeyboard( - unsigned char key, - int x, - int y -){ - GlutKeyboardManager *manager = GlutKeyboardManager::Instance(); - - if (manager->m_handler != NULL) { - manager->m_handler->HandleKeyboard(key,x,y); - } -} - - void -GlutKeyboardManager:: -InstallHandler( - GlutKeyboardHandler * handler -){ - - MT_assert(m_handler == NULL); - m_handler = handler; -} - - void -GlutKeyboardManager:: -ReleaseHandler( -){ - m_handler = NULL; -} - - -GlutKeyboardManager:: -~GlutKeyboardManager( -){ - - delete(m_handler); -} diff --git a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h b/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h deleted file mode 100644 index ea39b6835f6..00000000000 --- a/intern/iksolver/test/ik_glut_test/common/GlutKeyboardManager.h +++ /dev/null @@ -1,101 +0,0 @@ -/** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __GLUTKEYBOARDMANAGER_H__ -#define __GLUTKEYBOARDMANAGER_H__ - -#include "MEM_NonCopyable.h" -#include "MEM_SmartPtr.h" - -// So pissed off with Glut callback stuff -// that is impossible to call objects unless they are global - -// inherit from GlutKeyboardHandler and installl the drawer in the singleton -// class GlutKeyboardManager. - -class GlutKeyboardHandler : public MEM_NonCopyable { -public : - - virtual - void - HandleKeyboard( - unsigned char key, - int x, - int y - )= 0; - - virtual - ~GlutKeyboardHandler( - ){}; -}; - -class GlutKeyboardManager : public MEM_NonCopyable{ - -public : - - static - GlutKeyboardManager * - Instance( - ); - - // this is the function you should pass to glut - - static - void - HandleKeyboard( - unsigned char key, - int x, - int y - ); - - void - InstallHandler( - GlutKeyboardHandler * - ); - - void - ReleaseHandler( - ); - - ~GlutKeyboardManager( - ); - -private : - - GlutKeyboardManager ( - ) : - m_handler (0) - { - }; - - GlutKeyboardHandler * m_handler; - - static MEM_SmartPtr<GlutKeyboardManager> m_s_instance; -}; - -#endif - diff --git a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp deleted file mode 100644 index c426f933e67..00000000000 --- a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "GlutMouseManager.h" -#include "MT_assert.h" - -MEM_SmartPtr<GlutMouseManager> GlutMouseManager::m_s_instance = MEM_SmartPtr<GlutMouseManager>(); - - - GlutMouseManager * -GlutMouseManager:: -Instance( -){ - if (m_s_instance == NULL) { - m_s_instance = new GlutMouseManager(); - } - - return m_s_instance; -} - -// these are the functions you should pass to GLUT - - void -GlutMouseManager:: -Mouse( - int button, - int state, - int x, - int y -){ - GlutMouseManager *manager = GlutMouseManager::Instance(); - - if (manager->m_handler != NULL) { - manager->m_handler->Mouse(button,state,x,y); - } -} - - void -GlutMouseManager:: -Motion( - int x, - int y -){ - GlutMouseManager *manager = GlutMouseManager::Instance(); - - if (manager->m_handler != NULL) { - manager->m_handler->Motion(x,y); - } -} - - void -GlutMouseManager:: -InstallHandler( - GlutMouseHandler *handler -){ - - MT_assert(m_handler == NULL); - m_handler = handler; -} - - void -GlutMouseManager:: -ReleaseHandler( -){ - m_handler = NULL; -} - -GlutMouseManager:: -~GlutMouseManager( -){ - - delete(m_handler); -} - - diff --git a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h b/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h deleted file mode 100644 index 4a2344b7c74..00000000000 --- a/intern/iksolver/test/ik_glut_test/common/GlutMouseManager.h +++ /dev/null @@ -1,111 +0,0 @@ -/** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __GLUTMOUSEMANAGER_H__ -#define __GLUTMOUSEMANAGER_H__ - -#include "MEM_NonCopyable.h" -#include "MEM_SmartPtr.h" - -class GlutMouseHandler { -public : - - virtual - void - Mouse( - int button, - int state, - int x, - int y - ) = 0; - - virtual - void - Motion( - int x, - int y - ) = 0; - - virtual - ~GlutMouseHandler( - ){}; -}; - -class GlutMouseManager : public MEM_NonCopyable{ - -public : - - static - GlutMouseManager * - Instance( - ); - - // these are the functions you should pass to GLUT - - static - void - Mouse( - int button, - int state, - int x, - int y - ); - - static - void - Motion( - int x, - int y - ); - - void - InstallHandler( - GlutMouseHandler * - ); - - void - ReleaseHandler( - ); - - ~GlutMouseManager( - ); - -private : - - GlutMouseManager ( - ) : - m_handler (0) - { - }; - - GlutMouseHandler * m_handler; - - static MEM_SmartPtr<GlutMouseManager> m_s_instance; -}; - -#endif - diff --git a/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h b/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h deleted file mode 100644 index f2863806112..00000000000 --- a/intern/iksolver/test/ik_glut_test/intern/ChainDrawer.h +++ /dev/null @@ -1,375 +0,0 @@ -/** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __CHAINDRAWER_H__ -#define __CHAINDRAWER_H__ - -#include "../common/GlutDrawer.h" -#include "MyGlutMouseHandler.h" -#include "MyGlutKeyHandler.h" -#include "MT_Transform.h" -# include "IK_Qsolver.h" -# include "../intern/IK_QChain.h" -# include "../intern/IK_QSolver_Class.h" -#include <GL/glut.h> - -class ChainDrawer : public GlutDrawer -{ -public : - static - ChainDrawer * - New( - ) { - return new ChainDrawer(); - } - - void - SetMouseHandler( - MyGlutMouseHandler *mouse_handler - ) { - m_mouse_handler = mouse_handler; - } - - void - SetKeyHandler ( - MyGlutKeyHandler *key_handler - ) { - m_key_handler = key_handler; - } - - void - SetChain( - IK_Chain_ExternPtr *chains,int chain_num - ) { - m_chain_num = chain_num; - m_chains = chains; - } - - - // inherited from GlutDrawer - void - Draw( - ) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glPopMatrix(); - glPushMatrix(); - glRotatef(m_mouse_handler->AngleX(), 0.0, 1.0, 0.0); - glRotatef(m_mouse_handler->AngleY(), 1.0, 0.0, 0.0); - - DrawScene(); - glutSwapBuffers(); - - } - - ~ChainDrawer( - ){ - // nothing to do - }; - -private : - - void - DrawScene( - ){ - - // draw a little cross at the position of the key handler - // coordinates - - MT_Vector3 line_x(4,0,0); - MT_Vector3 line_y(0.0,4,0); - MT_Vector3 line_z(0.0,0.0,4); - - MT_Vector3 cross_origin = m_mouse_handler->Position(); - MT_Vector3 temp; - - glDisable(GL_LIGHTING); - - - glBegin(GL_LINES); - - glColor3f (1.0f,1.0f,1.0f); - - temp = cross_origin - line_x; - glVertex3f(temp[0],temp[1],temp[2]); - temp = cross_origin + line_x; - glVertex3f(temp[0],temp[1],temp[2]); - - temp = cross_origin - line_y; - glVertex3f(temp[0],temp[1],temp[2]); - temp = cross_origin + line_y; - glVertex3f(temp[0],temp[1],temp[2]); - - temp = cross_origin - line_z; - glVertex3f(temp[0],temp[1],temp[2]); - temp = cross_origin + line_z; - glVertex3f(temp[0],temp[1],temp[2]); - - glEnd(); - glEnable(GL_LIGHTING); - - - IK_Chain_ExternPtr chain; - - int chain_num; - for (chain_num = 0; chain_num < m_chain_num; chain_num++) { - chain = m_chains[chain_num]; - - - IK_Segment_ExternPtr segs = chain->segments; - IK_Segment_ExternPtr seg_start = segs; - const IK_Segment_ExternPtr seg_end = segs + chain->num_segments; - float ogl_matrix[16]; - - glColor3f (0.0f,1.0f,0.0f); - - MT_Vector3 previous_origin(0,0,0); - - MT_Transform global_transform; - global_transform.setIdentity(); - - for (; seg_start != seg_end; ++seg_start) { - - glPushMatrix(); - - // fill ogl_matrix with zeros - - std::fill(ogl_matrix,ogl_matrix + 16,float(0)); - - // we have to do a bit of work here to compute the chain's - // bone values - - // first compute all the matrices we need - - MT_Transform translation; - translation.setIdentity(); - translation.translate(MT_Vector3(0,seg_start->length,0)); - - MT_Matrix3x3 seg_rot( - seg_start->basis_change[0],seg_start->basis_change[1],seg_start->basis_change[2], - seg_start->basis_change[3],seg_start->basis_change[4],seg_start->basis_change[5], - seg_start->basis_change[6],seg_start->basis_change[7],seg_start->basis_change[8] - ); - - seg_rot.transpose(); - - MT_Matrix3x3 seg_pre_rot( - seg_start->basis[0],seg_start->basis[1],seg_start->basis[2], - seg_start->basis[3],seg_start->basis[4],seg_start->basis[5], - seg_start->basis[6],seg_start->basis[7],seg_start->basis[8] - ); - - - MT_Transform seg_t_pre_rot( - MT_Point3( - seg_start->seg_start[0], - seg_start->seg_start[1], - seg_start->seg_start[2] - ), - seg_pre_rot - ); - // start of the bone is just the current global transform - // multiplied by the seg_start vector - - - - MT_Transform seg_t_rot(MT_Point3(0,0,0),seg_rot); - MT_Transform seg_local = seg_t_pre_rot * seg_t_rot * translation; - - MT_Vector3 bone_start = global_transform * - MT_Point3( - seg_start->seg_start[0], - seg_start->seg_start[1], - seg_start->seg_start[2] - ); - - - global_transform = global_transform * seg_local; - - global_transform.getValue(ogl_matrix); - MT_Vector3 bone_end = global_transform.getOrigin(); - - glMultMatrixf(ogl_matrix); -// glutSolidSphere(0.5,5,5); - - glPopMatrix(); - - glDisable(GL_LIGHTING); - - glBegin(GL_LINES); - - // draw lines of the principle axis of the local transform - - MT_Vector3 x_axis(1,0,0); - MT_Vector3 y_axis(0,1,0); - MT_Vector3 z_axis(0,0,1); - - x_axis = global_transform.getBasis() * x_axis * 5; - y_axis = global_transform.getBasis() * y_axis * 5; - z_axis = global_transform.getBasis() * z_axis * 5; - - - x_axis = x_axis + bone_start; - y_axis = y_axis + bone_start; - z_axis = z_axis + bone_start; - - glColor3f(1,0,0); - - glVertex3f(x_axis.x(),x_axis.y(),x_axis.z()); - glVertex3f( - bone_start.x(), - bone_start.y(), - bone_start.z() - ); - - glColor3f(0,1,0); - - glVertex3f(y_axis.x(),y_axis.y(),y_axis.z()); - glVertex3f( - bone_start.x(), - bone_start.y(), - bone_start.z() - ); - - glColor3f(0,1,1); - - glVertex3f(z_axis.x(),z_axis.y(),z_axis.z()); - glVertex3f( - bone_start.x(), - bone_start.y(), - bone_start.z() - ); - - glColor3f(0,0,1); - - glVertex3f( - bone_start.x(), - bone_start.y(), - bone_start.z() - ); - glVertex3f(bone_end[0],bone_end[1],bone_end[2]); - - glEnd(); - glEnable(GL_LIGHTING); - } -#if 0 - // draw jacobian column vectors - - // hack access to internals - - IK_Solver_Class * internals = static_cast<IK_Solver_Class *>(chain->intern); - - glDisable(GL_LIGHTING); - - glBegin(GL_LINES); - - const TNT::Matrix<MT_Scalar> & jac = internals->Chain().TransposedJacobian(); - - int i = 0; - for (i=0; i < jac.num_rows(); i++) { - glColor3f(1,1,1); - - previous_origin = internals->Chain().Segments()[i/3].GlobalSegmentStart(); - - glVertex3f(previous_origin[0],previous_origin[1],previous_origin[2]); - glVertex3f(jac[i][0] + previous_origin[0],jac[i][1] + previous_origin[1],jac[i][2] + previous_origin[2]); - - - } - glEnd(); - glEnable(GL_LIGHTING); -#endif - - } - - glColor3f(1.0,1.0,1.0); - - glDisable(GL_LIGHTING); - glBegin(GL_LINES); - - MT_Scalar cube_size = 50; - glVertex3f(cube_size,cube_size,cube_size); - glVertex3f(-cube_size,cube_size,cube_size); - - glVertex3f(cube_size,-cube_size,cube_size); - glVertex3f(-cube_size,-cube_size,cube_size); - - glVertex3f(cube_size,cube_size,-cube_size); - glVertex3f(-cube_size,cube_size,-cube_size); - - glVertex3f(cube_size,-cube_size,-cube_size); - glVertex3f(-cube_size,-cube_size,-cube_size); - - - glVertex3f(-cube_size,cube_size,cube_size); - glVertex3f(-cube_size,-cube_size,cube_size); - - glVertex3f(cube_size,cube_size,-cube_size); - glVertex3f(cube_size,-cube_size,-cube_size); - - glVertex3f(cube_size,cube_size,cube_size); - glVertex3f(cube_size,-cube_size,cube_size); - - glVertex3f(-cube_size,cube_size,-cube_size); - glVertex3f(-cube_size,-cube_size,-cube_size); - - - glVertex3f(cube_size,cube_size,cube_size); - glVertex3f(cube_size,cube_size,-cube_size); - - glVertex3f(cube_size,-cube_size,cube_size); - glVertex3f(cube_size,-cube_size,-cube_size); - - glVertex3f(-cube_size,cube_size,cube_size); - glVertex3f(-cube_size,cube_size,-cube_size); - - glVertex3f(-cube_size,-cube_size,cube_size); - glVertex3f(-cube_size,-cube_size,-cube_size); - glEnd(); - glEnable(GL_LIGHTING); - - }; - - - -private : - - MyGlutMouseHandler * m_mouse_handler; - MyGlutKeyHandler *m_key_handler; - IK_Chain_ExternPtr *m_chains; - - int m_chain_num; - ChainDrawer ( - ) : m_chains (NULL), - m_mouse_handler (NULL), - m_chain_num (0) - { - }; - -}; - -#endif - diff --git a/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h b/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h deleted file mode 100644 index 621e0d32869..00000000000 --- a/intern/iksolver/test/ik_glut_test/intern/MyGlutKeyHandler.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __MYGLUTKEYHANDLER_H__ -#define __MYGLUTKEYHANDLER_H__ - -#include "../common/GlutKeyboardManager.h" - -class MyGlutKeyHandler : public GlutKeyboardHandler -{ -public : - static - MyGlutKeyHandler * - New( - ) { - MEM_SmartPtr<MyGlutKeyHandler> output = new MyGlutKeyHandler(); - - if (output == NULL - ) { - return NULL; - } - return output.Release(); - - } - - void - HandleKeyboard( - unsigned char key, - int x, - int y - ){ - - switch (key) { - - case 27 : - - exit(0); - } - } - - ~MyGlutKeyHandler( - ) - { - }; - -private : - - MyGlutKeyHandler( - ) - { - } - -}; - -#endif - diff --git a/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h b/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h deleted file mode 100644 index 205ce38ac23..00000000000 --- a/intern/iksolver/test/ik_glut_test/intern/MyGlutMouseHandler.h +++ /dev/null @@ -1,206 +0,0 @@ -/** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __MYGLUTMOUSEHANDLER_H__ -#define __MYGLUTMOUSEHANDLER_H__ - -#include "../common/GlutMouseManager.h" -#include <GL/glut.h> -#include "IK_solver.h" - -class MyGlutMouseHandler : public GlutMouseHandler -{ - -public : - - static - MyGlutMouseHandler * - New( - ) { - MEM_SmartPtr<MyGlutMouseHandler> output = new MyGlutMouseHandler(); - if (output == NULL - ) { - return NULL; - } - return output.Release(); - - } - - void - SetChain( - IK_Chain_ExternPtr *chains, int num_chains - ){ - m_chains = chains; - m_num_chains = num_chains; - } - - void - Mouse( - int button, - int state, - int x, - int y - ){ - if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { - m_moving = true; - m_begin_x = x; - m_begin_y = y; - } - if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { - m_moving = false; - } - - if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) { - m_tracking = true; - } - if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP) { - m_tracking = false; - } - - if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) { - m_cg_on = true; - } - if (button == GLUT_MIDDLE_BUTTON && state == GLUT_UP) { - m_cg_on = false; - } - - } - - - void - Motion( - int x, - int y - ){ - if (m_moving) { - m_angle_x = m_angle_x + (x - m_begin_x); - m_begin_x = x; - - m_angle_y = m_angle_y + (y - m_begin_y); - m_begin_y = y; - - glutPostRedisplay(); - } - if (m_tracking) { - - int w_h = glutGet((GLenum)GLUT_WINDOW_HEIGHT); - - y = w_h - y; - - double mvmatrix[16]; - double projmatrix[16]; - GLint viewport[4]; - - double px, py, pz,sz; - - /* Get the matrices needed for gluUnProject */ - glGetIntegerv(GL_VIEWPORT, viewport); - glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix); - glGetDoublev(GL_PROJECTION_MATRIX, projmatrix); - - // work out the position of the end effector in screen space - - GLdouble ex,ey,ez; - ex = m_pos.x(); - ey = m_pos.y(); - ez = m_pos.z(); - - gluProject(ex, ey, ez, mvmatrix, projmatrix, viewport, &px, &py, &sz); - gluUnProject((GLdouble) x, (GLdouble) y, sz, mvmatrix, projmatrix, viewport, &px, &py, &pz); - - m_pos = MT_Vector3(px,py,pz); - - } - if (m_tracking || m_cg_on) { - float temp[3]; - m_pos.getValue(temp); - - IK_SolveChain(m_chains[0],temp,0.01,200,0.1,m_chains[1]->segments); - IK_LoadChain(m_chains[0],m_chains[0]->segments,m_chains[0]->num_segments); - - glutPostRedisplay(); - } - - - } - - const - float - AngleX( - ) const { - return m_angle_x; - } - - const - float - AngleY( - ) const { - return m_angle_y; - } - - const - MT_Vector3 - Position( - ) const { - return m_pos; - } - - -private : - - MyGlutMouseHandler ( - ) : - m_angle_x(0), - m_angle_y(0), - m_begin_x(0), - m_begin_y(0), - m_moving (false), - m_tracking (false), - m_pos(0,0,0), - m_cg_on (false), - m_chains(NULL), - m_num_chains(0) - { - }; - - float m_angle_x; - float m_angle_y; - float m_begin_x; - float m_begin_y; - - bool m_moving; - bool m_tracking; - bool m_cg_on; - MT_Vector3 m_pos; - - IK_Chain_ExternPtr *m_chains; - int m_num_chains; - -}; - -#endif - diff --git a/intern/iksolver/test/ik_glut_test/intern/main.cpp b/intern/iksolver/test/ik_glut_test/intern/main.cpp deleted file mode 100644 index bfb9d8fa1a0..00000000000 --- a/intern/iksolver/test/ik_glut_test/intern/main.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/** - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "MEM_SmartPtr.h" - -#ifdef USE_QUATERNIONS -#include "IK_Qsolver.h" -#else -#include "IK_solver.h" -#endif - -#include <GL/glut.h> -#include "MT_Vector3.h" -#include "MT_Quaternion.h" -#include "MT_Matrix3x3.h" -#include "MyGlutMouseHandler.h" -#include "MyGlutKeyHandler.h" -#include "ChainDrawer.h" - -void init(MT_Vector3 min,MT_Vector3 max) -{ - GLfloat light_diffuse0[] = {1.0, 0.0, 0.0, 1.0}; /* Red diffuse light. */ - GLfloat light_position0[] = {1.0, 1.0, 1.0, 0.0}; /* Infinite light location. */ - - GLfloat light_diffuse1[] = {1.0, 1.0, 1.0, 1.0}; /* Red diffuse light. */ - GLfloat light_position1[] = {1.0, 0, 0, 0.0}; /* Infinite light location. */ - - /* Enable a single OpenGL light. */ - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse0); - glLightfv(GL_LIGHT0, GL_POSITION, light_position0); - - glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse1); - glLightfv(GL_LIGHT1, GL_POSITION, light_position1); - - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - glEnable(GL_LIGHTING); - - /* Use depth buffering for hidden surface elimination. */ - glEnable(GL_DEPTH_TEST); - - /* Setup the view of the cube. */ - glMatrixMode(GL_PROJECTION); - - // center of the box + 3* depth of box - - MT_Vector3 center = (min + max) * 0.5; - MT_Vector3 diag = max - min; - - float depth = diag.length(); - float distance = 2; - - gluPerspective(/* field of view in degree */ 40.0, - /* aspect ratio */ 1.0, - /* Z near */ 1.0, - /* Z far */ distance * depth * 2 - ); - glMatrixMode(GL_MODELVIEW); - - - gluLookAt(center.x(), center.y(), center.z() + distance*depth, /* eye is at (0,0,5) */ - center.x(), center.y(), center.z(), /* center is at (0,0,0) */ - 0.0, 1.0, 0.); /* up is in positive Y direction */ - - glPushMatrix(); - - -} - -int main(int argc, char **argv) -{ - - - const int seg_num = 5; - const MT_Scalar seg_length = 15; - - const float seg_startA[3] = {0,0,0}; - const float seg_startB[3] = {0,-20,0}; - - // create some segments to solve with - - // First chain - ////////////// - - - IK_Segment_ExternPtr const segmentsA = new IK_Segment_Extern[seg_num]; - IK_Segment_ExternPtr const segmentsB = new IK_Segment_Extern[seg_num]; - - IK_Segment_ExternPtr seg_it = segmentsA; - IK_Segment_ExternPtr seg_itB = segmentsB; - - - { - -// MT_Quaternion qmat(MT_Vector3(0,0,1),-3.141/2); - MT_Quaternion qmat(MT_Vector3(0,0,1),0); - MT_Matrix3x3 mat(qmat); - - seg_it->seg_start[0] = seg_startA[0]; - seg_it->seg_start[1] = seg_startA[1]; - seg_it->seg_start[2] = seg_startA[2]; - - float temp[12]; - mat.getValue(temp); - - seg_it->basis[0] = temp[0]; - seg_it->basis[1] = temp[1]; - seg_it->basis[2] = temp[2]; - - seg_it->basis[3] = temp[4]; - seg_it->basis[4] = temp[5]; - seg_it->basis[5] = temp[6]; - - seg_it->basis[6] = temp[8]; - seg_it->basis[7] = temp[9]; - seg_it->basis[8] = temp[10]; - - seg_it->length = seg_length; - - MT_Quaternion q; - q.setEuler(0,0,0); - - - MT_Matrix3x3 qrot(q); - - seg_it->basis_change[0] = 1; - seg_it->basis_change[1] = 0; - seg_it->basis_change[2] = 0; - seg_it->basis_change[3] = 0; - seg_it->basis_change[4] = 1; - seg_it->basis_change[5] = 0; - seg_it->basis_change[6] = 0; - seg_it->basis_change[7] = 0; - seg_it->basis_change[8] = 1; - - - seg_it ++; - - seg_itB->seg_start[0] = seg_startA[0]; - seg_itB->seg_start[1] = seg_startA[1]; - seg_itB->seg_start[2] = seg_startA[2]; - - seg_itB->basis[0] = temp[0]; - seg_itB->basis[1] = temp[1]; - seg_itB->basis[2] = temp[2]; - - seg_itB->basis[3] = temp[4]; - seg_itB->basis[4] = temp[5]; - seg_itB->basis[5] = temp[6]; - - seg_itB->basis[6] = temp[8]; - seg_itB->basis[7] = temp[9]; - seg_itB->basis[8] = temp[10]; - - seg_itB->length = seg_length; - - seg_itB->basis_change[0] = 1; - seg_itB->basis_change[1] = 0; - seg_itB->basis_change[2] = 0; - seg_itB->basis_change[3] = 0; - seg_itB->basis_change[4] = 1; - seg_itB->basis_change[5] = 0; - seg_itB->basis_change[6] = 0; - seg_itB->basis_change[7] = 0; - seg_itB->basis_change[8] = 1; - - - seg_itB ++; - - - } - - - int i; - for (i=1; i < seg_num; ++i, ++seg_it,++seg_itB) { - - MT_Quaternion qmat(MT_Vector3(0,0,1),0.3); - MT_Matrix3x3 mat(qmat); - - seg_it->seg_start[0] = 0; - seg_it->seg_start[1] = 0; - seg_it->seg_start[2] = 0; - - float temp[12]; - mat.getValue(temp); - - seg_it->basis[0] = temp[0]; - seg_it->basis[1] = temp[1]; - seg_it->basis[2] = temp[2]; - - seg_it->basis[3] = temp[4]; - seg_it->basis[4] = temp[5]; - seg_it->basis[5] = temp[6]; - - seg_it->basis[6] = temp[8]; - seg_it->basis[7] = temp[9]; - seg_it->basis[8] = temp[10]; - - seg_it->length = seg_length; - - MT_Quaternion q; - q.setEuler(0,0,0); - - - MT_Matrix3x3 qrot(q); - - seg_it->basis_change[0] = 1; - seg_it->basis_change[1] = 0; - seg_it->basis_change[2] = 0; - seg_it->basis_change[3] = 0; - seg_it->basis_change[4] = 1; - seg_it->basis_change[5] = 0; - seg_it->basis_change[6] = 0; - seg_it->basis_change[7] = 0; - seg_it->basis_change[8] = 1; - - - /////////////////////////////// - - seg_itB->seg_start[0] = 0; - seg_itB->seg_start[1] = 0; - seg_itB->seg_start[2] = 0; - - seg_itB->basis[0] = temp[0]; - seg_itB->basis[1] = temp[1]; - seg_itB->basis[2] = temp[2]; - - seg_itB->basis[3] = temp[4]; - seg_itB->basis[4] = temp[5]; - seg_itB->basis[5] = temp[6]; - - seg_itB->basis[6] = temp[8]; - seg_itB->basis[7] = temp[9]; - seg_itB->basis[8] = temp[10]; - - seg_itB->length = seg_length; - - seg_itB->basis_change[0] = 1; - seg_itB->basis_change[1] = 0; - seg_itB->basis_change[2] = 0; - seg_itB->basis_change[3] = 0; - seg_itB->basis_change[4] = 1; - seg_itB->basis_change[5] = 0; - seg_itB->basis_change[6] = 0; - seg_itB->basis_change[7] = 0; - seg_itB->basis_change[8] = 1; - - - - } - - // create the chains - - const int num_chains = 2; - - IK_Chain_ExternPtr chains[num_chains]; - - chains[0] = IK_CreateChain(); - chains[1] = IK_CreateChain(); - - // load segments into chain - - IK_LoadChain(chains[0],segmentsA,seg_num); - IK_LoadChain(chains[1],segmentsB,seg_num); - - // make and install a mouse handler - - MEM_SmartPtr<MyGlutMouseHandler> mouse_handler (MyGlutMouseHandler::New()); - GlutMouseManager::Instance()->InstallHandler(mouse_handler); - - mouse_handler->SetChain(chains,num_chains); - - // make and install a keyhandler - MEM_SmartPtr<MyGlutKeyHandler> key_handler (MyGlutKeyHandler::New()); - GlutKeyboardManager::Instance()->InstallHandler(key_handler); - - // instantiate the drawing class - - MEM_SmartPtr<ChainDrawer> drawer (ChainDrawer::New()); - GlutDrawManager::Instance()->InstallDrawer(drawer); - - drawer->SetMouseHandler(mouse_handler); - drawer->SetChain(chains,num_chains); - drawer->SetKeyHandler(key_handler); - - glutInit(&argc, argv); - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); - glutCreateWindow("ik"); - glutDisplayFunc(GlutDrawManager::Draw); - glutMouseFunc(GlutMouseManager::Mouse); - glutMotionFunc(GlutMouseManager::Motion); - glutKeyboardFunc(GlutKeyboardManager::HandleKeyboard); - - init(MT_Vector3(-50,-50,-50),MT_Vector3(50,50,50)); - glutMainLoop(); - return 0; /* ANSI C requires main to return int. */ -} diff --git a/intern/memutil/CMakeLists.txt b/intern/memutil/CMakeLists.txt index 3f9f8d6fe25..82e968853f4 100644 --- a/intern/memutil/CMakeLists.txt +++ b/intern/memutil/CMakeLists.txt @@ -39,11 +39,8 @@ set(SRC MEM_Allocator.h MEM_CacheLimiter.h MEM_CacheLimiterC-Api.h - MEM_NonCopyable.h - MEM_RefCountPtr.h MEM_RefCounted.h MEM_RefCountedC-Api.h - MEM_SmartPtr.h ) blender_add_lib(bf_intern_memutil "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/memutil/MEM_NonCopyable.h b/intern/memutil/MEM_NonCopyable.h deleted file mode 100644 index 9378ea7b69d..00000000000 --- a/intern/memutil/MEM_NonCopyable.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file memutil/MEM_NonCopyable.h - * \ingroup memutil - */ - -/** - * @file MEM_NonCopyable.h - * Declaration of MEM_NonCopyable class. - */ - -#ifndef __MEM_NONCOPYABLE_H__ -#define __MEM_NONCOPYABLE_H__ - -/** - * Simple class that makes sure sub classes cannot - * generate standard copy constructors. - * If you want to make sure that your class does - * not have any of these cheesy hidden constructors - * inherit from this class. - */ - -class MEM_NonCopyable { -protected : - - MEM_NonCopyable( - ) { - }; - -private : - - MEM_NonCopyable (const MEM_NonCopyable *); - MEM_NonCopyable (const MEM_NonCopyable &); -}; - -#endif - diff --git a/intern/memutil/MEM_RefCountPtr.h b/intern/memutil/MEM_RefCountPtr.h deleted file mode 100644 index ea865eadd47..00000000000 --- a/intern/memutil/MEM_RefCountPtr.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file memutil/MEM_RefCountPtr.h - * \ingroup memutil - */ - -/** - * \file MEM_RefCountPtr.h - * Declaration of MEM_RefCounted and MEM_RefCountable classes. - * \author Laurence - */ - -#ifndef __MEM_REFCOUNTPTR_H__ -#define __MEM_REFCOUNTPTR_H__ - -#include <stdlib.h> // for NULL ! - -/** - * \section MEM_RefCountable - * This is a base class for reference countable objects. - * If you want an object to be shared using a reference - * counted system derrivce from this class. All subclasses - * should insist that they are created on the heap, this - * can be done by makeing all constructors private and - * defining a static New() method that returns a ref counted - * ptr to a new()ly allocated instance. - * - * \section Example subclass - * - * \code{.cpp} - * class MySharedObject : public MEM_RefCountable { - * - * private : - * MySharedObject() : MEM_RefCountable() { //class specific initialization}; - * MySharedObject(const MySharedObject &other) // not implemented - * public : - * static - * MEM_RefCountPtr<MySharedObject> - * New( - * ) { - * return MEM_RefCountPtr<MySharedObject>( new MySharedObject()); - * } - * - * // other member functions - * }; - * \endcode - * - * Alternitively you may first wish to define a fully functional - * class and then define a reference counting wrapper for this class. - * This is useful when the base type can be used without reference - * counting. - * - * E.g. - * - * \code{.cpp} - * class UsefullClass { - * private : - * ... - * public : - * - * UsefullClass() - * UsefullMethod(...) - * AnotherUsefullMethod(...) - * }; - * - * class RcUsefullClass : public UsefullClass, public MEM_RefCountable - * { - * private : - * // Override base class public constructor --- forces - * // use of New(...) - * RcUsefullClass(...) - * public : - * - * // Override each public constructor of UsefullClass with - * // an equivalent static New method returning a MEM_RefCountPtr - * - * static - * MEM_RefCountPtr<RcUsefullClass> - * New(...) { - * return MEM_RefCountPtr<RcUsefullClass> output( - * new UsefullClass(...) - * ); - * } - * - * // warning never call destructor directly allow ref counting - * // mechanism to handle object lifetime. - * ~RcUsefullClass(); - * }; - * \endcode - * - */ - -class MEM_RefCountable { -private : - - /** - * The reference count! - * We use mutable here because we would like to - * share references of const objects! - * Maybe should think about having decRef() - * another value because we should not be deleting - * non-const objects - */ - - mutable int m_count; - -protected : - - /** - * Protected constructors - * This class is not for direct instantiation. Sub classes - * should only be allocated on the heap. - */ - - MEM_RefCountable ( - ) : - m_count (0) - { - }; - - MEM_RefCountable ( - const MEM_RefCountable & - ) : - m_count (0) - { - } - -public : - - void - IncRef( - ) const { - m_count++; - } - - int - DecRef( - ) { - return (--m_count); - } - - ~MEM_RefCountable( - ) { - //nothing to do - } -}; - -/** - * \section MEM_RefCountPtr - */ - -template - < class T > -class MEM_RefCountPtr { - -public : - - /** - * Construction from reference - share ownership with - * the right hand side. - */ - - MEM_RefCountPtr( - const MEM_RefCountPtr &rhs - ) : m_val (NULL) { - ShareOwnership(rhs.m_val); - } - - /** - * Construction from ptr - this class shares - * ownership of object val. - */ - - MEM_RefCountPtr( - const T* val - ) : - m_val (NULL) - { - ShareOwnership(val); - } - - /** - * Default constructor - */ - - MEM_RefCountPtr( - ) : - m_val (NULL) - { - } - - /** - * Type conversion from this class to the type - * of a pointer to the template parameter. - * This means you can pass an instance of this class - * to a function expecting a ptr of type T. - */ - - operator T * () const { - return m_val; - } - - - MEM_RefCountPtr & operator=( - const MEM_RefCountPtr &rhs - ) { - if (this->m_val != rhs.m_val) { - ReleaseOwnership(); - ShareOwnership(rhs.m_val); - } - return *this; - } - - /** - * Overload the operator -> so that it's possible to access - * all the normal methods of the internal ptr. - */ - - T * operator->() const { - return m_val; - } - - /** - * Returrn a reference to the shared object. - */ - - T& - Ref( - ) { - return *m_val; - } - - - /** - * Destructor - deletes object if it's ref count is zero. - */ - - ~MEM_RefCountPtr( - ) { - ReleaseOwnership(); - } - -private : - - /// The ptr owned by this class. - T * m_val; - - void - ShareOwnership( - const T * val - ) { - if (val != NULL) { - val->IncRef(); - } - m_val = const_cast<T *>(val); - } - - void - ReleaseOwnership( - ) { - if (m_val) { - if (m_val->DecRef() == 0) { - delete(m_val); - m_val = NULL; - } - } - } - -}; - -#endif - diff --git a/intern/memutil/MEM_SmartPtr.h b/intern/memutil/MEM_SmartPtr.h deleted file mode 100644 index e0d7b81290f..00000000000 --- a/intern/memutil/MEM_SmartPtr.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file memutil/MEM_SmartPtr.h - * \ingroup memutil - */ - -/** - * @file MEM_SmartPtr.h - * Declaration of MEM_RefCounted and MEM_RefCountable classes. - * @author Laurence - */ - -#ifndef __MEM_SMARTPTR_H__ -#define __MEM_SMARTPTR_H__ - - -#include <stdlib.h> // for NULL ! - - -/** - * \section MEM_SmartPtr - * This class defines a smart pointer similar to that defined in - * the Standard Template Library but without the painful get() - * semantics to access the internal c style pointer. - * - * It is often useful to explicitly declare ownership of memory - * allocated on the heap within class or function scope. This - * class helps you to encapsulate this ownership within a value - * type. When an instance of this class goes out of scope it - * makes sure that any memory associated with it's internal pointer - * is deleted. It can help to inform users of an aggregate class - * that it owns instances of it's members and these instances - * should not be shared. This is not reliably enforceable in C++ - * but this class attempts to make the 1-1 relationship clear. - * - * \section Example usage - * - * \code{.cpp} - * class foo { - * ...constructors accessors etc. - * int x[1000]; - * } - * - * class bar { - * public : - * static - * bar * - * New( - * ) { - * MEM_SmartPtr<foo> afoo = new foo(); - * MEM_SmartPtr<bar> that = new bar(); - * - * if (foo == NULL || that == NULL) return NULL; - * - * that->m_foo = afoo.Release(); - * return that.Release(); - * } - * - * ~bar() { - * // smart ptr takes care of deletion - * } - * private : - * MEM_SmartPtr<foo> m_foo; - * } - * \endcode - * - * You may also safely construct vectors of MEM_SmartPtrs and - * have the vector own stuff you put into it. - * - * e.g. - * \code{.cpp} - * { - * std::vector<MEM_SmartPtr<foo> > foo_vector; - * foo_vector.push_back( new foo()); - * foo_vector.push_back( new foo()); - * - * foo_vector[0]->bla(); - * } // foo_vector out of scope => heap memory freed for both foos - * \endcode - * - * @warning this class should only be used for objects created - * on the heap via the new function. It will not behave correctly - * if you pass ptrs to objects created with new[] nor with - * objects declared on the stack. Doing this is likely to crash - * the program or lead to memory leaks. - */ - -template - < class T > -class MEM_SmartPtr { - -public : - - /** - * Construction from reference - this class - * always assumes ownership from the rhs. - */ - - MEM_SmartPtr( - const MEM_SmartPtr &rhs - ) { - m_val = rhs.Release(); - } - - /** - * Construction from ptr - this class always - * assumes that it now owns the memory associated with the - * ptr. - */ - - MEM_SmartPtr( - T* val - ) : - m_val (val) - { - } - - /** - * Defalut constructor - */ - - MEM_SmartPtr( - ) : - m_val (NULL) - { - } - - /** - * Type conversion from this class to the type - * of a pointer to the template parameter. - * This means you can pass an instance of this class - * to a function expecting a ptr of type T. - */ - - operator T * () const { - return m_val; - } - - /** - * Return a reference to the internal ptr class. - * Use with care when you now that the internal ptr - * is not NULL! - */ - - T & - Ref( - ) const { - return *m_val; - } - - /** - * Assignment operator - ownership is transferred from rhs to lhs. - * There is an intenional side-effect of function of transferring - * ownership from the const parameter rhs. This is to insure - * the 1-1 relationship. - * The object associated with this instance is deleted if it - * is not the same as that contained in the rhs. - */ - - MEM_SmartPtr & operator=( - const MEM_SmartPtr &rhs - ) { - if (this->m_val != rhs.m_val) { - delete this->m_val; - } - - this->m_val = rhs.Release(); - return *this; - } - - /** - * Overload the operator -> so that it's possible to access - * all the normal methods of the internal ptr. - */ - - T * operator->() const { - return m_val; - } - - /** - * Caller takes ownership of the object - the object will not - * be deleted when the ptr goes out of scope. - */ - - T * - Release( - ) const { - T* temp = m_val; - (const_cast<MEM_SmartPtr *>(this))->m_val = NULL; - return temp; - } - - /** - * Force destruction of the internal object. - */ - - void - Delete( - ) { - delete (m_val); - m_val = NULL; - } - - /** - * Destructor - deletes object if it exists - */ - - ~MEM_SmartPtr( - ) { - delete (m_val); - } - -private : - - /// The ptr owned by this class. - T * m_val; -}; - -#endif - diff --git a/intern/moto/CMakeLists.txt b/intern/moto/CMakeLists.txt index 8075c66b847..d17181c6809 100644 --- a/intern/moto/CMakeLists.txt +++ b/intern/moto/CMakeLists.txt @@ -36,7 +36,6 @@ set(SRC intern/MT_CmMatrix4x4.cpp intern/MT_Matrix3x3.cpp intern/MT_Matrix4x4.cpp - intern/MT_Plane3.cpp intern/MT_Point3.cpp intern/MT_Quaternion.cpp intern/MT_Transform.cpp @@ -45,14 +44,11 @@ set(SRC intern/MT_Vector4.cpp intern/MT_random.cpp - include/GEN_List.h - include/GEN_Map.h include/MT_CmMatrix4x4.h include/MT_Matrix3x3.h include/MT_Matrix4x4.h include/MT_MinMax.h include/MT_Optimize.h - include/MT_Plane3.h include/MT_Point2.h include/MT_Point3.h include/MT_Quaternion.h @@ -67,11 +63,9 @@ set(SRC include/MT_Vector4.h include/MT_assert.h include/MT_random.h - include/NM_Scalar.h include/MT_Matrix3x3.inl include/MT_Matrix4x4.inl - include/MT_Plane3.inl include/MT_Point2.inl include/MT_Point3.inl include/MT_Quaternion.inl diff --git a/intern/moto/include/GEN_List.h b/intern/moto/include/GEN_List.h deleted file mode 100644 index 3aefe5e060c..00000000000 --- a/intern/moto/include/GEN_List.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/GEN_List.h - * \ingroup moto - */ - - -#ifndef GEN_LIST_H -#define GEN_LIST_H - -class GEN_Link { -public: - GEN_Link() : m_next(0), m_prev(0) {} - GEN_Link(GEN_Link *next, GEN_Link *prev) : m_next(next), m_prev(prev) {} - - GEN_Link *getNext() const { return m_next; } - GEN_Link *getPrev() const { return m_prev; } - - bool isHead() const { return m_prev == 0; } - bool isTail() const { return m_next == 0; } - - void insertBefore(GEN_Link *link) { - m_next = link; - m_prev = link->m_prev; - m_next->m_prev = this; - m_prev->m_next = this; - } - - void insertAfter(GEN_Link *link) { - m_next = link->m_next; - m_prev = link; - m_next->m_prev = this; - m_prev->m_next = this; - } - - void remove() { - m_next->m_prev = m_prev; - m_prev->m_next = m_next; - } - -private: - GEN_Link *m_next; - GEN_Link *m_prev; -}; - -class GEN_List { -public: - GEN_List() : m_head(&m_tail, 0), m_tail(0, &m_head) {} - - GEN_Link *getHead() const { return m_head.getNext(); } - GEN_Link *getTail() const { return m_tail.getPrev(); } - - void addHead(GEN_Link *link) { link->insertAfter(&m_head); } - void addTail(GEN_Link *link) { link->insertBefore(&m_tail); } - -private: - GEN_Link m_head; - GEN_Link m_tail; -}; - -#endif - diff --git a/intern/moto/include/GEN_Map.h b/intern/moto/include/GEN_Map.h deleted file mode 100644 index 526bfdc8caf..00000000000 --- a/intern/moto/include/GEN_Map.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/GEN_Map.h - * \ingroup moto - */ - - -#ifndef GEN_MAP_H -#define GEN_MAP_H - -template <class Key, class Value> -class GEN_Map { -private: - struct Entry { - Entry (Entry *next, Key key, Value value) : - m_next(next), - m_key(key), - m_value(value) {} - - Entry *m_next; - Key m_key; - Value m_value; - }; - -public: - GEN_Map(int num_buckets = 100) : m_num_buckets(num_buckets) { - m_buckets = new Entry *[num_buckets]; - for (int i = 0; i < num_buckets; ++i) { - m_buckets[i] = 0; - } - } - - GEN_Map(const GEN_Map& map) - { - m_num_buckets = map.m_num_buckets; - m_buckets = new Entry *[m_num_buckets]; - - for (int i = 0; i < m_num_buckets; ++i) { - m_buckets[i] = 0; - - for(Entry *entry = map.m_buckets[i]; entry; entry=entry->m_next) - insert(entry->m_key, entry->m_value); - } - } - - int size() { - int count=0; - for (int i=0;i<m_num_buckets;i++) - { - Entry* bucket = m_buckets[i]; - while(bucket) - { - bucket = bucket->m_next; - count++; - } - } - return count; - } - - Value* at(int index) { - int count=0; - for (int i=0;i<m_num_buckets;i++) - { - Entry* bucket = m_buckets[i]; - while(bucket) - { - if (count==index) - { - return &bucket->m_value; - } - bucket = bucket->m_next; - count++; - } - } - return 0; - } - - Key* getKey(int index) { - int count=0; - for (int i=0;i<m_num_buckets;i++) - { - Entry* bucket = m_buckets[i]; - while(bucket) - { - if (count==index) - { - return &bucket->m_key; - } - bucket = bucket->m_next; - count++; - } - } - return 0; - } - - void clear() { - for (int i = 0; i < m_num_buckets; ++i) { - Entry *entry_ptr = m_buckets[i]; - - while (entry_ptr != 0) { - Entry *tmp_ptr = entry_ptr->m_next; - delete entry_ptr; - entry_ptr = tmp_ptr; - } - m_buckets[i] = 0; - } - } - - ~GEN_Map() { - clear(); - delete [] m_buckets; - } - - void insert(const Key& key, const Value& value) { - Entry *entry_ptr = m_buckets[key.hash() % m_num_buckets]; - while ((entry_ptr != 0) && !(key == entry_ptr->m_key)) { - entry_ptr = entry_ptr->m_next; - } - - if (entry_ptr != 0) { - entry_ptr->m_value = value; - } - else { - Entry **bucket = &m_buckets[key.hash() % m_num_buckets]; - *bucket = new Entry(*bucket, key, value); - } - } - - void remove(const Key& key) { - Entry **entry_ptr = &m_buckets[key.hash() % m_num_buckets]; - while ((*entry_ptr != 0) && !(key == (*entry_ptr)->m_key)) { - entry_ptr = &(*entry_ptr)->m_next; - } - - if (*entry_ptr != 0) { - Entry *tmp_ptr = (*entry_ptr)->m_next; - delete *entry_ptr; - *entry_ptr = tmp_ptr; - } - } - - Value *operator[](Key key) { - Entry *bucket = m_buckets[key.hash() % m_num_buckets]; - while ((bucket != 0) && !(key == bucket->m_key)) { - bucket = bucket->m_next; - } - return bucket != 0 ? &bucket->m_value : 0; - } - -private: - int m_num_buckets; - Entry **m_buckets; -}; - -#endif - diff --git a/intern/moto/include/MT_Plane3.h b/intern/moto/include/MT_Plane3.h deleted file mode 100644 index f208b377a81..00000000000 --- a/intern/moto/include/MT_Plane3.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Plane3.h - * \ingroup moto - */ - - -#ifndef MT_PLANE3 -#define MT_PLANE3 - -#include "MT_Tuple4.h" -#include "MT_Point3.h" - -/** - * A simple 3d plane class. - * - * This class represents a plane in 3d. The internal parameterization used - * is n.x + d =0 where n is a unit vector and d is a scalar. - * - * It inherits data from MT_Tuple4 please see this class for low level - * access to the internal representation. - * - */ - -class MT_Plane3 : public MT_Tuple4 -{ -public : - /** - * Constructor from 3 points - */ - - MT_Plane3( - const MT_Vector3 &a, - const MT_Vector3 &b, - const MT_Vector3 &c - ); - /** - * Construction from vector and a point. - */ - - MT_Plane3( - const MT_Vector3 &n, - const MT_Vector3 &p - ); - - /** - * Default constructor - */ - MT_Plane3( - ); - - /** - * Default constructor - */ - - MT_Plane3( - const MT_Plane3 & p - ): - MT_Tuple4(p) - { - } - - /** - * Return plane normal - */ - - MT_Vector3 - Normal( - ) const; - - /** - * Return plane scalar i.e the d from n.x + d = 0 - */ - - MT_Scalar - Scalar( - ) const ; - - /** - * Invert the plane - just swaps direction of normal. - */ - void - Invert( - ); - - /** - * Assignment operator - */ - - MT_Plane3 & - operator = ( - const MT_Plane3 & rhs - ); - - /** - * Return the signed perpendicular distance from a point to the plane - */ - - MT_Scalar - signedDistance( - const MT_Vector3 & - ) const; - - -}; - -#ifdef GEN_INLINED -#include "MT_Plane3.inl" -#endif - -#endif - diff --git a/intern/moto/include/MT_Plane3.inl b/intern/moto/include/MT_Plane3.inl deleted file mode 100644 index 77db9b35e1d..00000000000 --- a/intern/moto/include/MT_Plane3.inl +++ /dev/null @@ -1,128 +0,0 @@ -#include "MT_Optimize.h" - - -GEN_INLINE -MT_Plane3:: -MT_Plane3( - const MT_Vector3 &a, - const MT_Vector3 &b, - const MT_Vector3 &c -){ - MT_Vector3 l1 = b-a; - MT_Vector3 l2 = c-b; - - MT_Vector3 n = l1.cross(l2); - n = n.safe_normalized(); - MT_Scalar d = n.dot(a); - - m_co[0] = n.x(); - m_co[1] = n.y(); - m_co[2] = n.z(); - m_co[3] = -d; -} - -/** - * Construction from vector and a point. - */ -GEN_INLINE -MT_Plane3:: -MT_Plane3( - const MT_Vector3 &n, - const MT_Vector3 &p -){ - - MT_Vector3 mn = n.safe_normalized(); - MT_Scalar md = mn.dot(p); - - m_co[0] = mn.x(); - m_co[1] = mn.y(); - m_co[2] = mn.z(); - m_co[3] = -md; -} - - -/** - * Default constructor - */ -GEN_INLINE -MT_Plane3:: -MT_Plane3( -): - MT_Tuple4() -{ - m_co[0] = MT_Scalar(1); - m_co[1] = MT_Scalar(0); - m_co[2] = MT_Scalar(0); - m_co[3] = MT_Scalar(0); -} - -/** - * Return plane normal - */ - -GEN_INLINE - MT_Vector3 -MT_Plane3:: -Normal( -) const { - return MT_Vector3(m_co[0],m_co[1],m_co[2]); -} - -/** - * Return plane scalar i.e the d from n.x + d = 0 - */ - -GEN_INLINE - MT_Scalar -MT_Plane3:: -Scalar( -) const { - return m_co[3]; -} - -GEN_INLINE - void -MT_Plane3:: -Invert( -) { - m_co[0] = -m_co[0]; - m_co[1] = -m_co[1]; - m_co[2] = -m_co[2]; - m_co[3] = -m_co[3]; -} - - -/** - * Assignment operator - */ - -GEN_INLINE - MT_Plane3 & -MT_Plane3:: -operator = ( - const MT_Plane3 & rhs -) { - m_co[0] = rhs.m_co[0]; - m_co[1] = rhs.m_co[1]; - m_co[2] = rhs.m_co[2]; - m_co[3] = rhs.m_co[3]; - return *this; -} - -/** - * Return the distance from a point to the plane - */ - -GEN_INLINE - MT_Scalar -MT_Plane3:: -signedDistance( - const MT_Vector3 &v -) const { - return Normal().dot(v) + m_co[3]; -} - - - - - diff --git a/intern/moto/include/MT_Scalar.h b/intern/moto/include/MT_Scalar.h index 5c4a5c2a44a..5e516292d77 100644 --- a/intern/moto/include/MT_Scalar.h +++ b/intern/moto/include/MT_Scalar.h @@ -51,7 +51,6 @@ #include <float.h> #include "MT_random.h" -#include "NM_Scalar.h" typedef double MT_Scalar; //this should be float ! diff --git a/intern/moto/include/NM_Scalar.h b/intern/moto/include/NM_Scalar.h deleted file mode 100644 index 0e33979c521..00000000000 --- a/intern/moto/include/NM_Scalar.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/NM_Scalar.h - * \ingroup moto - */ - - -#include <math.h> -#include <iostream> - -template <class T> -class NM_Scalar { -public: - NM_Scalar() {} - explicit NM_Scalar(T value, T error = 0.0) : - m_value(value), m_error(error) {} - - T getValue() const { return m_value; } - T getError() const { return m_error; } - - operator T() const { return m_value; } - - NM_Scalar operator-() const { - return NM_Scalar<T>(-m_value, m_error); - } - - NM_Scalar& operator=(T value) { - m_value = value; - m_error = 0.0; - return *this; - } - - NM_Scalar& operator+=(const NM_Scalar& x) { - m_value += x.m_value; - m_error = (fabs(m_value) * (m_error + 1.0) + - fabs(x.m_value) * (x.m_error + 1.0)) / - fabs(m_value + x.m_value); - return *this; - } - - NM_Scalar& operator-=(const NM_Scalar& x) { - m_value -= x.m_value; - m_error = (fabs(m_value) * (m_error + 1.0) + - fabs(x.m_value) * (x.m_error + 1.0)) / - fabs(m_value - x.m_value); - return *this; - } - - NM_Scalar& operator*=(const NM_Scalar& x) { - m_value *= x.m_value; - m_error += x.m_error + 1.0; - return *this; - } - - NM_Scalar& operator/=(const NM_Scalar& x) { - m_value /= x.m_value; - m_error += x.m_error + 1.0; - return *this; - } - -private: - T m_value; - T m_error; -}; - -template <class T> -inline NM_Scalar<T> operator+(const NM_Scalar<T>& x, const NM_Scalar<T>& y) { - return x.getValue() == 0.0 && y.getValue() == 0.0 ? - NM_Scalar<T>(0.0, 0.0) : - NM_Scalar<T>(x.getValue() + y.getValue(), - (fabs(x.getValue()) * (x.getError() + 1.0) + - fabs(y.getValue()) * (y.getError() + 1.0)) / - fabs(x.getValue() + y.getValue())); -} - -template <class T> -inline NM_Scalar<T> operator-(const NM_Scalar<T>& x, const NM_Scalar<T>& y) { - return x.getValue() == 0.0 && y.getValue() == 0.0 ? - NM_Scalar<T>(0.0, 0.0) : - NM_Scalar<T>(x.getValue() - y.getValue(), - (fabs(x.getValue()) * (x.getError() + 1.0) + - fabs(y.getValue()) * (y.getError() + 1.0)) / - fabs(x.getValue() - y.getValue())); -} - -template <class T> -inline NM_Scalar<T> operator*(const NM_Scalar<T>& x, const NM_Scalar<T>& y) { - return NM_Scalar<T>(x.getValue() * y.getValue(), - x.getError() + y.getError() + 1.0); -} - -template <class T> -inline NM_Scalar<T> operator/(const NM_Scalar<T>& x, const NM_Scalar<T>& y) { - return NM_Scalar<T>(x.getValue() / y.getValue(), - x.getError() + y.getError() + 1.0); -} - -template <class T> -inline std::ostream& operator<<(std::ostream& os, const NM_Scalar<T>& x) { - return os << x.getValue() << '[' << x.getError() << ']'; -} - -template <class T> -inline NM_Scalar<T> sqrt(const NM_Scalar<T>& x) { - return NM_Scalar<T>(sqrt(x.getValue()), - 0.5 * x.getError() + 1.0); -} - -template <class T> -inline NM_Scalar<T> acos(const NM_Scalar<T>& x) { - return NM_Scalar<T>(acos(x.getValue()), x.getError() + 1.0); -} - -template <class T> -inline NM_Scalar<T> cos(const NM_Scalar<T>& x) { - return NM_Scalar<T>(cos(x.getValue()), x.getError() + 1.0); -} - -template <class T> -inline NM_Scalar<T> sin(const NM_Scalar<T>& x) { - return NM_Scalar<T>(sin(x.getValue()), x.getError() + 1.0); -} - -template <class T> -inline NM_Scalar<T> fabs(const NM_Scalar<T>& x) { - return NM_Scalar<T>(fabs(x.getValue()), x.getError()); -} - -template <class T> -inline NM_Scalar<T> pow(const NM_Scalar<T>& x, const NM_Scalar<T>& y) { - return NM_Scalar<T>(pow(x.getValue(), y.getValue()), - fabs(y.getValue()) * x.getError() + 1.0); -} - diff --git a/intern/moto/intern/MT_Plane3.cpp b/intern/moto/intern/MT_Plane3.cpp deleted file mode 100644 index 22f7cfdbded..00000000000 --- a/intern/moto/intern/MT_Plane3.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/intern/MT_Plane3.cpp - * \ingroup moto - */ - - -#ifndef GEN_INLINED -#include "MT_Plane3.h" -#include "MT_Plane3.inl" -#endif - diff --git a/intern/opennl/CMakeLists.txt b/intern/opennl/CMakeLists.txt deleted file mode 100644 index 9416bc2b9ea..00000000000 --- a/intern/opennl/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# The Original Code is Copyright (C) 2006, Blender Foundation -# All rights reserved. -# -# The Original Code is: all of this file. -# -# Contributor(s): Jacques Beaurain. -# -# ***** END GPL LICENSE BLOCK ***** - -# External project, better not fix warnings. -remove_strict_flags() - -# remove debug flag here since this is not a blender maintained library -# and debug gives a lot of prints on UV unwrapping. developers can enable if they need to. -if(MSVC) - remove_definitions(-DDEBUG) -else() - add_definitions(-UDEBUG) -endif() - - -# quiet compiler warnings about undefined defines -add_definitions( - -DDEBUGlevel=0 - -DPRNTlevel=0 -) - -set(INC - extern -) - -set(INC_SYS - ../../extern/colamd/Include - ../../extern/Eigen3 -) - -set(SRC - intern/opennl.cpp - extern/ONL_opennl.h -) - -blender_add_lib(bf_intern_opennl "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/opennl/SConscript b/intern/opennl/SConscript deleted file mode 100644 index 99df29b780a..00000000000 --- a/intern/opennl/SConscript +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -# -# ***** 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) 2006, Blender Foundation -# All rights reserved. -# -# The Original Code is: all of this file. -# -# Contributor(s): Nathan Letwory. -# -# ***** END GPL LICENSE BLOCK ***** - -Import ('env') - -sources = env.Glob('intern/*.cpp') - -incs = 'extern ../../extern/colamd/Include ../../extern/Eigen3' - -env.BlenderLib ('bf_intern_opennl', sources, Split(incs), [], libtype=['intern','player'], priority=[100,90] ) - diff --git a/intern/opennl/extern/ONL_opennl.h b/intern/opennl/extern/ONL_opennl.h deleted file mode 100644 index a414f40824b..00000000000 --- a/intern/opennl/extern/ONL_opennl.h +++ /dev/null @@ -1,113 +0,0 @@ -/** \file opennl/extern/ONL_opennl.h - * \ingroup opennlextern - */ -/* - * OpenNL: Numerical Library - * Copyright (C) 2004 Bruno Levy - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * If you modify this software, you should include a notice giving the - * name of the person performing the modification, the date of modification, - * and the reason for such modification. - * - * Contact: Bruno Levy - * - * levy@loria.fr - * - * ISA Project - * LORIA, INRIA Lorraine, - * Campus Scientifique, BP 239 - * 54506 VANDOEUVRE LES NANCY CEDEX - * FRANCE - * - * Note that the GNU General Public License does not permit incorporating - * the Software into proprietary programs. - */ - -#ifndef nlOPENNL_H -#define nlOPENNL_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Datatypes */ - -typedef unsigned int NLenum; -typedef unsigned char NLboolean; -typedef int NLint; /* 4-byte signed */ -typedef unsigned int NLuint; /* 4-byte unsigned */ -typedef double NLdouble; /* double precision float */ - -typedef struct NLContext NLContext; - -/* Constants */ - -#define NL_FALSE 0x0 -#define NL_TRUE 0x1 - -/* Primitives */ - -#define NL_SYSTEM 0x0 -#define NL_MATRIX 0x1 - -/* Solver Parameters */ - -#define NL_SOLVER 0x100 -#define NL_NB_VARIABLES 0x101 -#define NL_LEAST_SQUARES 0x102 -#define NL_ERROR 0x108 -#define NL_NB_ROWS 0x110 -#define NL_NB_RIGHT_HAND_SIDES 0x112 /* 4 max */ - -/* Contexts */ - -NLContext *nlNewContext(void); -void nlDeleteContext(NLContext *context); - -/* State get/set */ - -void nlSolverParameteri(NLContext *context, NLenum pname, NLint param); - -/* Variables */ - -void nlSetVariable(NLContext *context, NLuint rhsindex, NLuint index, NLdouble value); -NLdouble nlGetVariable(NLContext *context, NLuint rhsindex, NLuint index); -void nlLockVariable(NLContext *context, NLuint index); -void nlUnlockVariable(NLContext *context, NLuint index); - -/* Begin/End */ - -void nlBegin(NLContext *context, NLenum primitive); -void nlEnd(NLContext *context, NLenum primitive); - -/* Setting elements in matrix/vector */ - -void nlMatrixAdd(NLContext *context, NLuint row, NLuint col, NLdouble value); -void nlRightHandSideAdd(NLContext *context, NLuint rhsindex, NLuint index, NLdouble value); -void nlRightHandSideSet(NLContext *context, NLuint rhsindex, NLuint index, NLdouble value); - -/* Solve */ - -void nlPrintMatrix(NLContext *context); -NLboolean nlSolve(NLContext *context, NLboolean solveAgain); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/intern/opennl/intern/opennl.cpp b/intern/opennl/intern/opennl.cpp deleted file mode 100644 index 446a1a38f0d..00000000000 --- a/intern/opennl/intern/opennl.cpp +++ /dev/null @@ -1,479 +0,0 @@ -/** \file opennl/intern/opennl.c - * \ingroup opennlintern - */ -/* - * - * OpenNL: Numerical Library - * Copyright (C) 2004 Bruno Levy - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * If you modify this software, you should include a notice giving the - * name of the person performing the modification, the date of modification, - * and the reason for such modification. - * - * Contact: Bruno Levy - * - * levy@loria.fr - * - * ISA Project - * LORIA, INRIA Lorraine, - * Campus Scientifique, BP 239 - * 54506 VANDOEUVRE LES NANCY CEDEX - * FRANCE - * - * Note that the GNU General Public License does not permit incorporating - * the Software into proprietary programs. - */ - -#include "ONL_opennl.h" - -#include <Eigen/Sparse> - -#include <algorithm> -#include <cassert> -#include <cstdlib> -#include <iostream> -#include <vector> - -/* Eigen data structures */ - -typedef Eigen::SparseMatrix<double, Eigen::ColMajor> EigenSparseMatrix; -typedef Eigen::SparseLU<EigenSparseMatrix> EigenSparseSolver; -typedef Eigen::VectorXd EigenVectorX; -typedef Eigen::Triplet<double> EigenTriplet; - -/* NLContext data structure */ - -typedef struct { - NLuint index; - NLdouble value; -} NLCoeff; - -typedef struct { - NLdouble value[4]; - NLboolean locked; - NLuint index; - std::vector<NLCoeff> a; -} NLVariable; - -#define NL_STATE_INITIAL 0 -#define NL_STATE_SYSTEM 1 -#define NL_STATE_MATRIX 2 -#define NL_STATE_MATRIX_CONSTRUCTED 3 -#define NL_STATE_SYSTEM_CONSTRUCTED 4 -#define NL_STATE_SYSTEM_SOLVED 5 - -struct NLContext { - NLContext() - { - state = NL_STATE_INITIAL; - n = 0; - m = 0; - sparse_solver = NULL; - nb_variables = 0; - nb_rhs = 1; - nb_rows = 0; - least_squares = false; - solve_again = false; - } - - ~NLContext() - { - delete sparse_solver; - } - - NLenum state; - - NLuint n; - NLuint m; - - std::vector<EigenTriplet> Mtriplets; - EigenSparseMatrix M; - EigenSparseMatrix MtM; - std::vector<EigenVectorX> b; - std::vector<EigenVectorX> Mtb; - std::vector<EigenVectorX> x; - - EigenSparseSolver *sparse_solver; - - NLuint nb_variables; - std::vector<NLVariable> variable; - - NLuint nb_rows; - NLuint nb_rhs; - - NLboolean least_squares; - NLboolean solve_again; -}; - -NLContext *nlNewContext(void) -{ - return new NLContext(); -} - -void nlDeleteContext(NLContext *context) -{ - delete context; -} - -static void __nlCheckState(NLContext *context, NLenum state) -{ - assert(context->state == state); -} - -static void __nlTransition(NLContext *context, NLenum from_state, NLenum to_state) -{ - __nlCheckState(context, from_state); - context->state = to_state; -} - -/* Get/Set parameters */ - -void nlSolverParameteri(NLContext *context, NLenum pname, NLint param) -{ - __nlCheckState(context, NL_STATE_INITIAL); - switch(pname) { - case NL_NB_VARIABLES: { - assert(param > 0); - context->nb_variables = (NLuint)param; - } break; - case NL_NB_ROWS: { - assert(param > 0); - context->nb_rows = (NLuint)param; - } break; - case NL_LEAST_SQUARES: { - context->least_squares = (NLboolean)param; - } break; - case NL_NB_RIGHT_HAND_SIDES: { - context->nb_rhs = (NLuint)param; - } break; - default: { - assert(0); - } break; - } -} - -/* Get/Set Lock/Unlock variables */ - -void nlSetVariable(NLContext *context, NLuint rhsindex, NLuint index, NLdouble value) -{ - __nlCheckState(context, NL_STATE_SYSTEM); - context->variable[index].value[rhsindex] = value; -} - -NLdouble nlGetVariable(NLContext *context, NLuint rhsindex, NLuint index) -{ - assert(context->state != NL_STATE_INITIAL); - return context->variable[index].value[rhsindex]; -} - -void nlLockVariable(NLContext *context, NLuint index) -{ - __nlCheckState(context, NL_STATE_SYSTEM); - context->variable[index].locked = true; -} - -void nlUnlockVariable(NLContext *context, NLuint index) -{ - __nlCheckState(context, NL_STATE_SYSTEM); - context->variable[index].locked = false; -} - -/* System construction */ - -static void __nlVariablesToVector(NLContext *context) -{ - NLuint i, j, nb_rhs; - - nb_rhs= context->nb_rhs; - - for(i=0; i<context->nb_variables; i++) { - NLVariable* v = &(context->variable[i]); - if(!v->locked) { - for(j=0; j<nb_rhs; j++) - context->x[j][v->index] = v->value[j]; - } - } -} - -static void __nlVectorToVariables(NLContext *context) -{ - NLuint i, j, nb_rhs; - - nb_rhs= context->nb_rhs; - - for(i=0; i<context->nb_variables; i++) { - NLVariable* v = &(context->variable[i]); - if(!v->locked) { - for(j=0; j<nb_rhs; j++) - v->value[j] = context->x[j][v->index]; - } - } -} - -static void __nlBeginSystem(NLContext *context) -{ - assert(context->nb_variables > 0); - - if (context->solve_again) - __nlTransition(context, NL_STATE_SYSTEM_SOLVED, NL_STATE_SYSTEM); - else { - __nlTransition(context, NL_STATE_INITIAL, NL_STATE_SYSTEM); - - context->variable.resize(context->nb_variables); - } -} - -static void __nlEndSystem(NLContext *context) -{ - __nlTransition(context, NL_STATE_MATRIX_CONSTRUCTED, NL_STATE_SYSTEM_CONSTRUCTED); -} - -static void __nlBeginMatrix(NLContext *context) -{ - NLuint i; - NLuint m = 0, n = 0; - - __nlTransition(context, NL_STATE_SYSTEM, NL_STATE_MATRIX); - - if (!context->solve_again) { - for(i=0; i<context->nb_variables; i++) { - if(context->variable[i].locked) - context->variable[i].index = ~0; - else - context->variable[i].index = n++; - } - - m = (context->nb_rows == 0)? n: context->nb_rows; - - context->m = m; - context->n = n; - - /* reserve reasonable estimate */ - context->Mtriplets.clear(); - context->Mtriplets.reserve(std::max(m, n)*3); - - context->b.resize(context->nb_rhs); - context->x.resize(context->nb_rhs); - - for (i=0; i<context->nb_rhs; i++) { - context->b[i].setZero(m); - context->x[i].setZero(n); - } - } - else { - /* need to recompute b only, A is not constructed anymore */ - for (i=0; i<context->nb_rhs; i++) - context->b[i].setZero(context->m); - } - - __nlVariablesToVector(context); -} - -static void __nlEndMatrixRHS(NLContext *context, NLuint rhs) -{ - NLVariable *variable; - NLuint i, j; - - EigenVectorX& b = context->b[rhs]; - - for(i=0; i<context->nb_variables; i++) { - variable = &(context->variable[i]); - - if(variable->locked) { - std::vector<NLCoeff>& a = variable->a; - - for(j=0; j<a.size(); j++) { - b[a[j].index] -= a[j].value*variable->value[rhs]; - } - } - } - - if(context->least_squares) - context->Mtb[rhs] = context->M.transpose() * b; -} - -static void __nlEndMatrix(NLContext *context) -{ - __nlTransition(context, NL_STATE_MATRIX, NL_STATE_MATRIX_CONSTRUCTED); - - if(!context->solve_again) { - context->M.resize(context->m, context->n); - context->M.setFromTriplets(context->Mtriplets.begin(), context->Mtriplets.end()); - context->Mtriplets.clear(); - - if(context->least_squares) { - context->MtM = context->M.transpose() * context->M; - - context->Mtb.resize(context->nb_rhs); - for (NLuint rhs=0; rhs<context->nb_rhs; rhs++) - context->Mtb[rhs].setZero(context->n); - } - } - - for (NLuint rhs=0; rhs<context->nb_rhs; rhs++) - __nlEndMatrixRHS(context, rhs); -} - -void nlMatrixAdd(NLContext *context, NLuint row, NLuint col, NLdouble value) -{ - __nlCheckState(context, NL_STATE_MATRIX); - - if(context->solve_again) - return; - - if (!context->least_squares && context->variable[row].locked); - else if (context->variable[col].locked) { - if(!context->least_squares) - row = context->variable[row].index; - - NLCoeff coeff = {row, value}; - context->variable[col].a.push_back(coeff); - } - else { - if(!context->least_squares) - row = context->variable[row].index; - col = context->variable[col].index; - - // direct insert into matrix is too slow, so use triplets - EigenTriplet triplet(row, col, value); - context->Mtriplets.push_back(triplet); - } -} - -void nlRightHandSideAdd(NLContext *context, NLuint rhsindex, NLuint index, NLdouble value) -{ - __nlCheckState(context, NL_STATE_MATRIX); - - if(context->least_squares) { - context->b[rhsindex][index] += value; - } - else { - if(!context->variable[index].locked) { - index = context->variable[index].index; - context->b[rhsindex][index] += value; - } - } -} - -void nlRightHandSideSet(NLContext *context, NLuint rhsindex, NLuint index, NLdouble value) -{ - __nlCheckState(context, NL_STATE_MATRIX); - - if(context->least_squares) { - context->b[rhsindex][index] = value; - } - else { - if(!context->variable[index].locked) { - index = context->variable[index].index; - context->b[rhsindex][index] = value; - } - } -} - -void nlBegin(NLContext *context, NLenum prim) -{ - switch(prim) { - case NL_SYSTEM: { - __nlBeginSystem(context); - } break; - case NL_MATRIX: { - __nlBeginMatrix(context); - } break; - default: { - assert(0); - } - } -} - -void nlEnd(NLContext *context, NLenum prim) -{ - switch(prim) { - case NL_SYSTEM: { - __nlEndSystem(context); - } break; - case NL_MATRIX: { - __nlEndMatrix(context); - } break; - default: { - assert(0); - } - } -} - -void nlPrintMatrix(NLContext *context) -{ - std::cout << "A:" << context->M << std::endl; - - for(NLuint rhs=0; rhs<context->nb_rhs; rhs++) - std::cout << "b " << rhs << ":" << context->b[rhs] << std::endl; - - if (context->MtM.rows() && context->MtM.cols()) - std::cout << "AtA:" << context->MtM << std::endl; -} - -/* Solving */ - -NLboolean nlSolve(NLContext *context, NLboolean solveAgain) -{ - NLboolean result = true; - - __nlCheckState(context, NL_STATE_SYSTEM_CONSTRUCTED); - - if (!context->solve_again) { - EigenSparseMatrix& M = (context->least_squares)? context->MtM: context->M; - - assert(M.rows() == M.cols()); - - /* Convert M to compressed column format */ - M.makeCompressed(); - - /* Perform sparse LU factorization */ - EigenSparseSolver *sparse_solver = new EigenSparseSolver(); - context->sparse_solver = sparse_solver; - - sparse_solver->analyzePattern(M); - sparse_solver->factorize(M); - - result = (sparse_solver->info() == Eigen::Success); - - /* Free M, don't need it anymore at this point */ - M.resize(0, 0); - } - - if (result) { - /* Solve each right hand side */ - for(NLuint rhs=0; rhs<context->nb_rhs; rhs++) { - EigenVectorX& b = (context->least_squares)? context->Mtb[rhs]: context->b[rhs]; - context->x[rhs] = context->sparse_solver->solve(b); - - if (context->sparse_solver->info() != Eigen::Success) - result = false; - } - - if (result) { - __nlVectorToVariables(context); - - if (solveAgain) - context->solve_again = true; - - __nlTransition(context, NL_STATE_SYSTEM_CONSTRUCTED, NL_STATE_SYSTEM_SOLVED); - } - } - - return result; -} - diff --git a/intern/opensubdiv/gpu_shader_opensubd_display.glsl b/intern/opensubdiv/gpu_shader_opensubd_display.glsl index 57bbfa89714..51e8ed46c34 100644 --- a/intern/opensubdiv/gpu_shader_opensubd_display.glsl +++ b/intern/opensubdiv/gpu_shader_opensubd_display.glsl @@ -70,7 +70,8 @@ void main() #if __VERSION__ < 140 #extension GL_ARB_uniform_buffer_object: require - #extension GL_ARB_texture_buffer_object: require + #extension GL_ARB_texture_buffer_object: enable + #extension GL_EXT_texture_buffer_object: enable #endif uniform mat4 modelViewMatrix; diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc index f715bf32565..6c226d6cf6b 100644 --- a/intern/opensubdiv/opensubdiv_capi.cc +++ b/intern/opensubdiv/opensubdiv_capi.cc @@ -296,8 +296,9 @@ const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefine int openSubdiv_supportGPUDisplay(void) { // TODO: simplify extension check once Blender adopts GL 3.2 - return (GLEW_VERSION_3_2 && GLEW_ARB_compatibility) || - (GLEW_VERSION_3_1 && GLEW_ARB_compatibility && GLEW_EXT_geometry_shader4) || - (GLEW_VERSION_3_0 && GLEW_EXT_geometry_shader4 && GLEW_ARB_uniform_buffer_object && GLEW_ARB_texture_buffer_object); + return GPU_legacy_support() && + (GLEW_VERSION_3_2 || + (GLEW_VERSION_3_1 && GLEW_EXT_geometry_shader4) || + (GLEW_VERSION_3_0 && GLEW_EXT_geometry_shader4 && GLEW_ARB_uniform_buffer_object && (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object))); /* also ARB_explicit_attrib_location? */ } diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h index 8010c39647d..9d1c1b3795c 100644 --- a/intern/opensubdiv/opensubdiv_capi.h +++ b/intern/opensubdiv/opensubdiv_capi.h @@ -144,6 +144,8 @@ int openSubdiv_getAvailableEvaluators(void); void openSubdiv_init(void); void openSubdiv_cleanup(void); +extern bool GPU_legacy_support(void); + #ifdef __cplusplus } #endif diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc index fc46ad05f53..698fdfee00f 100644 --- a/intern/opensubdiv/opensubdiv_gpu_capi.cc +++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc @@ -186,24 +186,12 @@ void transpose_m3(float mat[3][3]) GLuint compileShader(GLenum shaderType, const char *section, + const char *version, const char *define) { char sdefine[64]; sprintf(sdefine, "#define %s\n", section); - const char *version; - if (GLEW_VERSION_3_2 && GLEW_ARB_compatibility) { - version = "#version 150 compatibility\n"; - } - else if (GLEW_VERSION_3_1 && GLEW_ARB_compatibility) { - version = "#version 140\n" - "#extension GL_ARB_compatibility: enable\n"; - } - else if (GLEW_VERSION_3_0) { - version = "#version 130\n"; - /* minimum supported for OpenSubdiv */ - } - const char *sources[] = { version, define, @@ -230,22 +218,25 @@ GLuint compileShader(GLenum shaderType, return shader; } -GLuint linkProgram(const char *define) +GLuint linkProgram(const char *version, const char *define) { GLuint vertexShader = compileShader(GL_VERTEX_SHADER, "VERTEX_SHADER", + version, define); if (vertexShader == 0) { return 0; } GLuint geometryShader = compileShader(GL_GEOMETRY_SHADER, "GEOMETRY_SHADER", + version, define); if (geometryShader == 0) { return 0; } GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, "FRAGMENT_SHADER", + version, define); if (fragmentShader == 0) { return 0; @@ -261,7 +252,7 @@ GLuint linkProgram(const char *define) glBindAttribLocation(program, 1, "normal"); - if (!(GLEW_VERSION_3_2 && GLEW_ARB_compatibility)) { + if (!GLEW_VERSION_3_2) { /* provide input/output layout info */ glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, @@ -381,11 +372,29 @@ bool openSubdiv_osdGLDisplayInit(void) static bool need_init = true; static bool init_success = false; if (need_init) { - g_flat_fill_solid_program = linkProgram("#define FLAT_SHADING\n"); - g_flat_fill_texture2d_program = linkProgram("#define USE_TEXTURE_2D\n#define FLAT_SHADING\n"); - g_smooth_fill_solid_program = linkProgram("#define SMOOTH_SHADING\n"); - g_smooth_fill_texture2d_program = linkProgram("#define USE_TEXTURE_2D\n#define SMOOTH_SHADING\n"); - g_wireframe_program = linkProgram("#define WIREFRAME\n"); + + if (!openSubdiv_supportGPUDisplay()) { + return false; + } + + const char *version = ""; + if (GLEW_VERSION_3_2) { + version = "#version 150 compatibility\n"; + } + else if (GLEW_VERSION_3_1) { + version = "#version 140\n" + "#extension GL_ARB_compatibility: enable\n"; + } + else { + version = "#version 130\n"; + /* minimum supported for OpenSubdiv */ + } + + g_flat_fill_solid_program = linkProgram(version, "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define FLAT_SHADING\n"); + g_smooth_fill_solid_program = linkProgram(version, "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_program = linkProgram(version, "#define USE_TEXTURE_2D\n#define SMOOTH_SHADING\n"); + g_wireframe_program = linkProgram(version, "#define WIREFRAME\n"); glGenBuffers(1, &g_lighting_ub); glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub); diff --git a/intern/opensubdiv/opensubdiv_utils_capi.cc b/intern/opensubdiv/opensubdiv_utils_capi.cc index aac1995bdfa..c993e347587 100644 --- a/intern/opensubdiv/opensubdiv_utils_capi.cc +++ b/intern/opensubdiv/opensubdiv_utils_capi.cc @@ -66,8 +66,7 @@ int openSubdiv_getAvailableEvaluators(void) #endif /* OPENSUBDIV_HAS_OPENCL */ #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK - if (GLEW_VERSION_3_0 || GLEW_ARB_texture_buffer_object) { - // TODO(merwin): remove extension check once Blender moves to 3.2 core + if (GLEW_VERSION_4_1) { flags |= OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK; } #endif /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */ diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py index 7e4c9e885e7..72233571702 100644 --- a/release/scripts/modules/bpy_extras/keyconfig_utils.py +++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py @@ -27,15 +27,11 @@ KM_HIERARCHY = [ ('Window', 'EMPTY', 'WINDOW', []), # file save, window change, exit ('Screen', 'EMPTY', 'WINDOW', [ # full screen, undo, screenshot ('Screen Editing', 'EMPTY', 'WINDOW', []), # re-sizing, action corners + ('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region) ]), ('View2D', 'EMPTY', 'WINDOW', []), # view 2d navigation (per region) ('View2D Buttons List', 'EMPTY', 'WINDOW', []), # view 2d with buttons navigation - ('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region) - - ('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region) - ('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []), - ]), ('3D View', 'VIEW_3D', 'WINDOW', [ # view 3d navigation and generic stuff (select, transform) ('Object Mode', 'EMPTY', 'WINDOW', []), @@ -73,10 +69,6 @@ KM_HIERARCHY = [ ('3D View Generic', 'VIEW_3D', 'WINDOW', []), # toolbar and properties ]), - ('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region) - ('Markers', 'EMPTY', 'WINDOW', []), # markers (per region) - ('Animation', 'EMPTY', 'WINDOW', []), # frame change on click, preview range (per region) - ('Animation Channels', 'EMPTY', 'WINDOW', []), ('Graph Editor', 'GRAPH_EDITOR', 'WINDOW', [ ('Graph Editor Generic', 'GRAPH_EDITOR', 'WINDOW', []), ]), @@ -85,15 +77,15 @@ KM_HIERARCHY = [ ('NLA Channels', 'NLA_EDITOR', 'WINDOW', []), ('NLA Generic', 'NLA_EDITOR', 'WINDOW', []), ]), + ('Timeline', 'TIMELINE', 'WINDOW', []), ('Image', 'IMAGE_EDITOR', 'WINDOW', [ - ('UV Editor', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image + ('UV Editor', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image) ('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d ('UV Sculpt', 'EMPTY', 'WINDOW', []), ('Image Generic', 'IMAGE_EDITOR', 'WINDOW', []), ]), - ('Timeline', 'TIMELINE', 'WINDOW', []), ('Outliner', 'OUTLINER', 'WINDOW', []), ('Node Editor', 'NODE_EDITOR', 'WINDOW', [ @@ -122,9 +114,17 @@ KM_HIERARCHY = [ ('Clip Editor', 'CLIP_EDITOR', 'WINDOW', []), ('Clip Graph Editor', 'CLIP_EDITOR', 'WINDOW', []), ('Clip Dopesheet Editor', 'CLIP_EDITOR', 'WINDOW', []), - ('Mask Editing', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image ]), + ('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region) + ('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []), + ]), + ('Mask Editing', 'EMPTY', 'WINDOW', []), + ('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region) + ('Markers', 'EMPTY', 'WINDOW', []), # markers (per region) + ('Animation', 'EMPTY', 'WINDOW', []), # frame change on click, preview range (per region) + ('Animation Channels', 'EMPTY', 'WINDOW', []), + ('View3D Gesture Circle', 'EMPTY', 'WINDOW', []), ('Gesture Straight Line', 'EMPTY', 'WINDOW', []), ('Gesture Zoom Border', 'EMPTY', 'WINDOW', []), @@ -163,13 +163,12 @@ def _export_properties(prefix, properties, kmi_id, lines=None): def string_value(value): if isinstance(value, str) or isinstance(value, bool) or isinstance(value, float) or isinstance(value, int): - result = repr(value) + return repr(value) elif getattr(value, '__len__', False): return repr(list(value)) - else: - print("Export key configuration: can't write ", value) - return result + print("Export key configuration: can't write ", value) + return "" for pname in properties.bl_rna.properties.keys(): if pname != "rna_type": diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 92dbd2dbd0e..4f71cdf7588 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -21,8 +21,8 @@ from _bpy import types as bpy_types import _bpy -StructRNA = bpy_types.Struct.__bases__[0] -StructMetaPropGroup = _bpy.StructMetaPropGroup +StructRNA = bpy_types.bpy_struct +StructMetaPropGroup = bpy_types.bpy_struct_meta_idprop # StructRNA = bpy_types.Struct bpy_types.BlendDataLibraries.load = _bpy._library_load diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py index 195b5767189..c0d92c331b7 100644 --- a/release/scripts/modules/rna_prop_ui.py +++ b/release/scripts/modules/rna_prop_ui.py @@ -41,7 +41,8 @@ def rna_idprop_ui_del(item): def rna_idprop_ui_prop_update(item, prop): prop_rna = item.path_resolve("[\"%s\"]" % prop.replace("\"", "\\\""), False) - prop_rna.update() + if isinstance(prop_rna, bpy.types.bpy_prop): + prop_rna.update() def rna_idprop_ui_prop_get(item, prop, create=True): diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py index 63c1945d2d2..daa8ab52766 100644 --- a/release/scripts/startup/bl_operators/presets.py +++ b/release/scripts/startup/bl_operators/presets.py @@ -169,14 +169,16 @@ class AddPresetBase: if not filepath: return {'CANCELLED'} - if hasattr(self, "remove"): - self.remove(context, filepath) - else: - try: + try: + if hasattr(self, "remove"): + self.remove(context, filepath) + else: os.remove(filepath) - except: - import traceback - traceback.print_exc() + except Exception as e: + self.report({'ERROR'}, "Unable to remove preset: %r" % e) + import traceback + traceback.print_exc() + return {'CANCELLED'} # XXX, stupid! preset_menu_class.bl_label = "Presets" diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py index 237c2d55672..750a5b0bf0f 100644 --- a/release/scripts/startup/bl_operators/rigidbody.py +++ b/release/scripts/startup/bl_operators/rigidbody.py @@ -163,7 +163,7 @@ class BakeToKeyframes(Operator): elif rot_mode == 'AXIS_ANGLE': # this is a little roundabout but there's no better way right now aa = mat.to_quaternion().to_axis_angle() - obj.rotation_axis_angle = (aa[1], ) + aa[0][:] + obj.rotation_axis_angle = (aa[1], *aa[0]) else: # euler # make sure euler rotation is compatible to previous frame # NOTE: assume that on first frame, the starting rotation is appropriate diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 58896e898c6..98570ca5280 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -156,6 +156,15 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.label(text="Object:") col.prop(md, "object", text="") + layout.prop(md, "use_bmesh") + if md.use_bmesh: + box = layout.box() + box.label("BMesh Options:") + box.prop(md, "use_bmesh_separate") + box.prop(md, "use_bmesh_dissolve") + box.prop(md, "use_bmesh_connect_regions") + box.prop(md, "threshold") + def BUILD(self, layout, ob, md): split = layout.split() diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index eb4625d2dac..b08bff13967 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -827,11 +827,13 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel): layout.template_ID(strip, "scene") scene = strip.scene + layout.prop(strip, "use_sequence") - layout.label(text="Camera Override") - layout.template_ID(strip, "scene_camera") + if not strip.use_sequence: + layout.label(text="Camera Override") + layout.template_ID(strip, "scene_camera") - layout.prop(strip, "use_grease_pencil", text="Show Grease Pencil") + layout.prop(strip, "use_grease_pencil", text="Show Grease Pencil") if scene: layout.prop(scene, "audio_volume", text="Audio Volume") diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index d8b033b94e3..70cfec9c9b3 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -527,6 +527,7 @@ class USERPREF_PT_system(Panel): column.separator() column.prop(system, "font_path_ui") + column.prop(system, "font_path_ui_mono") if bpy.app.build_options.international: column.prop(system, "use_international_fonts") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index a79e6d742ae..4dc4b667a63 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2416,6 +2416,7 @@ class VIEW3D_MT_edit_mesh_faces(Menu): layout.operator("mesh.bevel").vertex_only = False layout.operator("mesh.solidify") layout.operator("mesh.intersect") + layout.operator("mesh.intersect_boolean") layout.operator("mesh.wireframe") layout.separator() diff --git a/release/scripts/templates_py/operator_modal_view3d_raycast.py b/release/scripts/templates_py/operator_modal_view3d_raycast.py index b72b2f76750..c4d661b4c1f 100644 --- a/release/scripts/templates_py/operator_modal_view3d_raycast.py +++ b/release/scripts/templates_py/operator_modal_view3d_raycast.py @@ -2,7 +2,7 @@ import bpy from bpy_extras import view3d_utils -def main(context, event, ray_max=1000.0): +def main(context, event): """Run this function on left mouse, execute the ray cast""" # get the context arguments scene = context.scene @@ -14,7 +14,7 @@ def main(context, event, ray_max=1000.0): view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord) ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) - ray_target = ray_origin + (view_vector * ray_max) + ray_target = ray_origin + view_vector def visible_objects_and_duplis(): """Loop over (object, matrix) pairs (mesh only)""" @@ -39,17 +39,18 @@ def main(context, event, ray_max=1000.0): matrix_inv = matrix.inverted() ray_origin_obj = matrix_inv * ray_origin ray_target_obj = matrix_inv * ray_target + ray_direction_obj = ray_target_obj - ray_origin_obj # cast the ray - hit, normal, face_index = obj.ray_cast(ray_origin_obj, ray_target_obj) + success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj) - if face_index != -1: - return hit, normal, face_index + if success: + return location, normal, face_index else: return None, None, None # cast rays and find the closest object - best_length_squared = ray_max * ray_max + best_length_squared = -1.0 best_obj = None for obj, matrix in visible_objects_and_duplis(): @@ -59,7 +60,7 @@ def main(context, event, ray_max=1000.0): hit_world = matrix * hit scene.cursor_location = hit_world length_squared = (hit_world - ray_origin).length_squared - if length_squared < best_length_squared: + if best_obj is None or length_squared < best_length_squared: best_length_squared = length_squared best_obj = obj diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index b7d72bb28bb..6c3fd090d4a 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -55,6 +55,8 @@ #include "IMB_colormanagement.h" +#include "GPU_basic_shader.h" + #include "blf_internal_types.h" #include "blf_internal.h" @@ -486,7 +488,7 @@ void BLF_rotation_default(float angle) } } -static void blf_draw_gl__start(FontBLF *font, GLint *mode, GLint *param) +static void blf_draw_gl__start(FontBLF *font, GLint *mode) { /* * The pixmap alignment hack is handle @@ -494,9 +496,10 @@ static void blf_draw_gl__start(FontBLF *font, GLint *mode, GLint *param) */ glEnable(GL_BLEND); - glEnable(GL_TEXTURE_2D); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); + /* Save the current matrix mode. */ glGetIntegerv(GL_MATRIX_MODE, mode); @@ -523,19 +526,10 @@ static void blf_draw_gl__start(FontBLF *font, GLint *mode, GLint *param) /* always bind the texture for the first glyph */ font->tex_bind_state = -1; - - /* Save the current parameter to restore it later. */ - glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param); - if (*param != GL_MODULATE) - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } -static void blf_draw_gl__end(GLint mode, GLint param) +static void blf_draw_gl__end(GLint mode) { - /* and restore the original value. */ - if (param != GL_MODULATE) - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param); - glMatrixMode(GL_TEXTURE); glPopMatrix(); @@ -545,8 +539,8 @@ static void blf_draw_gl__end(GLint mode, GLint param) if (mode != GL_MODELVIEW) glMatrixMode(mode); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); } void BLF_draw_ex( @@ -554,19 +548,19 @@ void BLF_draw_ex( struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); - GLint mode, param; + GLint mode; BLF_RESULT_CHECK_INIT(r_info); if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode, ¶m); + blf_draw_gl__start(font, &mode); if (font->flags & BLF_WORD_WRAP) { blf_font_draw__wrap(font, str, len, r_info); } else { blf_font_draw(font, str, len, r_info); } - blf_draw_gl__end(mode, param); + blf_draw_gl__end(mode); } } void BLF_draw(int fontid, const char *str, size_t len) @@ -579,12 +573,12 @@ void BLF_draw_ascii_ex( struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); - GLint mode, param; + GLint mode; BLF_RESULT_CHECK_INIT(r_info); if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode, ¶m); + blf_draw_gl__start(font, &mode); if (font->flags & BLF_WORD_WRAP) { /* use non-ascii draw function for word-wrap */ blf_font_draw__wrap(font, str, len, r_info); @@ -592,7 +586,7 @@ void BLF_draw_ascii_ex( else { blf_font_draw_ascii(font, str, len, r_info); } - blf_draw_gl__end(mode, param); + blf_draw_gl__end(mode); } } void BLF_draw_ascii(int fontid, const char *str, size_t len) @@ -603,13 +597,13 @@ void BLF_draw_ascii(int fontid, const char *str, size_t len) int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) { FontBLF *font = blf_get(fontid); - GLint mode, param; + GLint mode; int columns = 0; if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode, ¶m); + blf_draw_gl__start(font, &mode); columns = blf_font_draw_mono(font, str, len, cwidth); - blf_draw_gl__end(mode, param); + blf_draw_gl__end(mode); } return columns; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 215d2484c18..1c13e42f70d 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -170,12 +170,12 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) glGenTextures(1, &gc->textures[gc->cur_tex]); glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = gc->textures[gc->cur_tex])); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL); } GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c) diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 2c6e37b9ed8..3eed4b5634b 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -151,7 +151,8 @@ typedef enum DMDrawFlag { DM_DRAW_USE_TEXPAINT_UV = (1 << 3), DM_DRAW_SKIP_HIDDEN = (1 << 4), DM_DRAW_SKIP_SELECT = (1 << 5), - DM_DRAW_SELECT_USE_EDITMODE = (1 << 6) + DM_DRAW_SELECT_USE_EDITMODE = (1 << 6), + DM_DRAW_NEED_NORMALS = (1 << 7) } DMDrawFlag; typedef enum DMForeachFlag { diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 607f2a98939..8734eac8f24 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 276 -#define BLENDER_SUBVERSION 2 +#define BLENDER_SUBVERSION 3 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 5 diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index ea63161e008..ff0b5a1d4bf 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -221,7 +221,7 @@ void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima); bool BKE_image_is_openexr(struct Image *ima); /* for multiple slot render, call this before render */ -void BKE_image_backup_render(struct Scene *scene, struct Image *ima); +void BKE_image_backup_render(struct Scene *scene, struct Image *ima, bool free_current_slot); /* for singlelayer openexr saving */ bool BKE_image_save_openexr_multiview(struct Image *ima, struct ImBuf *ibuf, const char *filepath, const int flags); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 08a55036a03..5d03a42d118 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -206,6 +206,8 @@ typedef struct bNodeType { /* can this node be added to a node tree */ int (*poll_instance)(struct bNode *node, struct bNodeTree *nodetree); + /* optional handling of link insertion */ + void (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); /* Update the internal links list, for muting and disconnect operators. */ void (*update_internal_links)(struct bNodeTree *, struct bNode *node); diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 5dc5ebbbd4c..5d69cb51ab1 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -98,7 +98,7 @@ void BKE_pbvh_raycast( bool original); bool BKE_pbvh_node_raycast( - PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco, + PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco, const float ray_start[3], const float ray_normal[3], float *dist); @@ -210,7 +210,7 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *bvh); void BKE_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]); void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]); -void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r_totface); +void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface); void BKE_pbvh_grids_update(PBVH *bvh, struct CCGElem **grid_elems, void **gridfaces, struct DMFlagMat *flagmats, unsigned int **grid_hidden); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 48616418e67..d05df3470b5 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -35,6 +35,7 @@ struct ARegion; struct Header; +struct ID; struct ListBase; struct Menu; struct Panel; diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 11f2d0e0816..3f2712e0ae1 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -237,6 +237,7 @@ void BKE_sequencer_base_clipboard_pointers_restore(struct ListBase *seqbase, str void BKE_sequence_free(struct Scene *scene, struct Sequence *seq); void BKE_sequence_free_anim(struct Sequence *seq); const char *BKE_sequence_give_name(struct Sequence *seq); +ListBase *BKE_sequence_seqbase_get(struct Sequence *seq, int *r_offset); void BKE_sequence_calc(struct Scene *scene, struct Sequence *seq); void BKE_sequence_calc_disp(struct Scene *scene, struct Sequence *seq); void BKE_sequence_reload_new_file(struct Scene *scene, struct Sequence *seq, const bool lock_range); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index c705c7adedb..e26e5148ff6 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -74,8 +74,8 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm); #include "BLI_sys_types.h" /* for intptr_t support */ #include "GPU_buffers.h" -#include "GPU_extensions.h" #include "GPU_glew.h" +#include "GPU_shader.h" #ifdef WITH_OPENSUBDIV # include "DNA_userdef_types.h" @@ -3529,14 +3529,11 @@ static void navmesh_drawColored(DerivedMesh *dm) #if 0 //UI_ThemeColor(TH_WIRE); - glDisable(GL_LIGHTING); glLineWidth(2.0); dm->drawEdges(dm, 0, 1); glLineWidth(1.0); - glEnable(GL_LIGHTING); #endif - glDisable(GL_LIGHTING); /* if (GPU_buffer_legacy(dm) ) */ /* TODO - VBO draw code, not high priority - campbell */ { DEBUG_VBO("Using legacy code. drawNavMeshColored\n"); @@ -3566,7 +3563,6 @@ static void navmesh_drawColored(DerivedMesh *dm) } glEnd(); } - glEnable(GL_LIGHTING); } static void navmesh_DM_drawFacesTex( diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index b925094d392..836072df67d 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -57,8 +57,8 @@ #include "GPU_buffers.h" #include "GPU_draw.h" -#include "GPU_extensions.h" #include "GPU_glew.h" +#include "GPU_shader.h" #include "WM_api.h" @@ -445,7 +445,7 @@ static void cdDM_drawFacesSolid( if (cddm->pbvh) { if (cddm->pbvh_draw && BKE_pbvh_has_faces(cddm->pbvh)) { - float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL); + float (*face_nors)[3] = CustomData_get_layer(&dm->polyData, CD_NORMAL); BKE_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, setMaterial, false, false); @@ -898,8 +898,7 @@ static void cdDM_drawMappedFacesGLSL( glShadeModel(GL_SMOOTH); - if (setDrawOptions != NULL) - { + if (setDrawOptions != NULL) { DMVertexAttribs attribs; DEBUG_VBO("Using legacy code. cdDM_drawMappedFacesGLSL\n"); memset(&attribs, 0, sizeof(attribs)); diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 7fd241eb8e3..dc50e39a862 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -55,8 +55,8 @@ #include "MEM_guardedalloc.h" -#include "GPU_extensions.h" #include "GPU_glew.h" +#include "GPU_shader.h" extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */ @@ -732,8 +732,7 @@ static void emDM_drawMappedFaces( const int lasttri = tottri - 1; /* compare agasint this a lot */ DMDrawOption draw_option; int i, flush; - const int skip_normals = !glIsEnabled(GL_LIGHTING); /* could be passed as an arg */ - + const int skip_normals = !(flag & DM_DRAW_NEED_NORMALS); const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); MLoopCol *lcol[3] = {NULL} /* , dummylcol = {0} */; unsigned char(*color_vert_array)[4] = em->derivedVertColor; @@ -755,7 +754,8 @@ static void emDM_drawMappedFaces( } if (has_vcol_preview || has_fcol_preview) { flag |= DM_DRAW_ALWAYS_SMOOTH; - glDisable(GL_LIGHTING); /* grr */ + /* weak, this logic should really be moved higher up */ + setMaterial = NULL; } if (bmdm->vertexCos) { diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index 2171f193bac..45ebada4d81 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -55,7 +55,7 @@ #include "BLI_sys_types.h" // for intptr_t support -#include "GPU_extensions.h" +#include "GPU_texture.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f4fce5c0019..6ff30134210 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2923,7 +2923,7 @@ bool BKE_image_is_openexr(struct Image *ima) return false; } -void BKE_image_backup_render(Scene *scene, Image *ima) +void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot) { /* called right before rendering, ima->renders contains render * result pointers for everything but the current render */ @@ -2931,13 +2931,18 @@ void BKE_image_backup_render(Scene *scene, Image *ima) int slot = ima->render_slot, last = ima->last_render_slot; if (slot != last) { - if (ima->renders[slot]) { - RE_FreeRenderResult(ima->renders[slot]); - ima->renders[slot] = NULL; - } - ima->renders[last] = NULL; RE_SwapResult(re, &ima->renders[last]); + + if (ima->renders[slot]) { + if (free_current_slot) { + RE_FreeRenderResult(ima->renders[slot]); + ima->renders[slot] = NULL; + } + else { + RE_SwapResult(re, &ima->renders[slot]); + } + } } ima->last_render_slot = slot; diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index a315a1f68ce..f1e0bc69dbc 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -192,7 +192,9 @@ void id_us_min(ID *id) const int limit = ID_FAKE_USERS(id); if (id->us <= limit) { printf("ID user decrement error: %s (from '%s')\n", id->name, id->lib ? id->lib->filepath : "[Main]"); - BLI_assert(0); + /* We cannot assert here, because of how we 'delete' datablocks currently (setting their usercount to zero), + * this is weak but it's how it works for now. */ + /* BLI_assert(0); */ id->us = limit; } else { diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 68e63c1ac92..d54f382f4c0 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -123,10 +123,11 @@ static void library_foreach_modifiersForeachIDLink( } static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID **id_pointer, - bool UNUSED(is_reference), void *user_data) + bool is_reference, void *user_data) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, IDWALK_NOP); + const int cd_flag = is_reference ? IDWALK_USER : IDWALK_NOP; + FOREACH_CALLBACK_INVOKE_ID_PP(data->self_id, id_pointer, data->flag, data->callback, data->user_data, cd_flag); } static void library_foreach_particlesystemsObjectLooper( @@ -223,9 +224,8 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(scene->set, IDWALK_NOP); CALLBACK_INVOKE(scene->clip, IDWALK_NOP); CALLBACK_INVOKE(scene->nodetree, IDWALK_NOP); - if (scene->basact) { - CALLBACK_INVOKE(scene->basact->object, IDWALK_NOP); - } + /* DO NOT handle scene->basact here, it’s doubling with the loop over whole scene->base later, + * since basact is just a pointer to one of those items. */ CALLBACK_INVOKE(scene->obedit, IDWALK_NOP); for (srl = scene->r.layers.first; srl; srl = srl->next) { diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 0adc894b2cc..b6895e619b0 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -1415,7 +1415,7 @@ void multires_stitch_grids(Object *ob) int totface; if (ccgdm->pbvh) { - BKE_pbvh_get_grid_updates(ccgdm->pbvh, 0, (void ***)&faces, &totface); + BKE_pbvh_get_grid_updates(ccgdm->pbvh, false, (void ***)&faces, &totface); if (totface) { ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface); @@ -2227,7 +2227,7 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3]) dGridSize = multires_side_tot[high_mmd.totlvl]; dSkip = (dGridSize - 1) / (gridSize - 1); -#pragma omp parallel for private(i) if (me->totface * gridSize * gridSize * 4 >= CCG_OMP_LIMIT) +#pragma omp parallel for private(i) if (me->totloop * gridSize * gridSize >= CCG_OMP_LIMIT) for (i = 0; i < me->totpoly; ++i) { const int numVerts = mpoly[i].totloop; MDisps *mdisp = &mdisps[mpoly[i].loopstart]; diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index 1a178fb2bdf..5a755058963 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -41,6 +41,7 @@ #include "BLI_math.h" #include "BLI_path_util.h" #include "BLI_rand.h" +#include "BLI_task.h" #include "BLI_threads.h" #include "BLI_utildefines.h" @@ -494,231 +495,296 @@ void BKE_ocean_eval_ij(struct Ocean *oc, struct OceanResult *ocr, int i, int j) BLI_rw_mutex_unlock(&oc->oceanmutex); } -void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount) +typedef struct OceanSimulateData { + Ocean *o; + float t; + float scale; + float chop_amount; +} OceanSimulateData; + +static void ocean_compute_htilda(void *userdata, void *UNUSED(userdata_chunk), int i) +{ + OceanSimulateData *osd = userdata; + const Ocean *o = osd->o; + const float scale = osd->scale; + const float t = osd->t; + + int j; + + /* note the <= _N/2 here, see the fftw doco about the mechanics of the complex->real fft storage */ + for (j = 0; j <= o->_N / 2; ++j) { + fftw_complex exp_param1; + fftw_complex exp_param2; + fftw_complex conj_param; + + init_complex(exp_param1, 0.0, omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t); + init_complex(exp_param2, 0.0, -omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t); + exp_complex(exp_param1, exp_param1); + exp_complex(exp_param2, exp_param2); + conj_complex(conj_param, o->_h0_minus[i * o->_N + j]); + + mul_complex_c(exp_param1, o->_h0[i * o->_N + j], exp_param1); + mul_complex_c(exp_param2, conj_param, exp_param2); + + add_comlex_c(o->_htilda[i * (1 + o->_N / 2) + j], exp_param1, exp_param2); + mul_complex_f(o->_fft_in[i * (1 + o->_N / 2) + j], o->_htilda[i * (1 + o->_N / 2) + j], scale); + } +} + +static void ocean_compute_displacement_y(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid)) +{ + OceanSimulateData *osd = BLI_task_pool_userdata(pool); + const Ocean *o = osd->o; + + fftw_execute(o->_disp_y_plan); +} + +static void ocean_compute_displacement_x(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid)) { + OceanSimulateData *osd = BLI_task_pool_userdata(pool); + const Ocean *o = osd->o; + const float scale = osd->scale; + const float chop_amount = osd->chop_amount; int i, j; - scale *= o->normalize_factor; + for (i = 0; i < o->_M; ++i) { + for (j = 0; j <= o->_N / 2; ++j) { + fftw_complex mul_param; + fftw_complex minus_i; + + init_complex(minus_i, 0.0, -1.0); + init_complex(mul_param, -scale, 0); + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, minus_i); + mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); + init_complex(o->_fft_in_x[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_disp_x_plan); +} - BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); +static void ocean_compute_displacement_z(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid)) +{ + OceanSimulateData *osd = BLI_task_pool_userdata(pool); + const Ocean *o = osd->o; + const float scale = osd->scale; + const float chop_amount = osd->chop_amount; + int i, j; - /* compute a new htilda */ -#pragma omp parallel for private(i, j) for (i = 0; i < o->_M; ++i) { - /* note the <= _N/2 here, see the fftw doco about the mechanics of the complex->real fft storage */ for (j = 0; j <= o->_N / 2; ++j) { - fftw_complex exp_param1; - fftw_complex exp_param2; - fftw_complex conj_param; + fftw_complex mul_param; + fftw_complex minus_i; + + init_complex(minus_i, 0.0, -1.0); + init_complex(mul_param, -scale, 0); + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, minus_i); + mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); + init_complex(o->_fft_in_z[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_disp_z_plan); +} + +static void ocean_compute_jacobian_jxx(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid)) +{ + OceanSimulateData *osd = BLI_task_pool_userdata(pool); + const Ocean *o = osd->o; + const float chop_amount = osd->chop_amount; + int i, j; + for (i = 0; i < o->_M; ++i) { + for (j = 0; j <= o->_N / 2; ++j) { + fftw_complex mul_param; + + /* init_complex(mul_param, -scale, 0); */ + init_complex(mul_param, -1, 0); + + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); + init_complex(o->_fft_in_jxx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_Jxx_plan); - init_complex(exp_param1, 0.0, omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t); - init_complex(exp_param2, 0.0, -omega(o->_k[i * (1 + o->_N / 2) + j], o->_depth) * t); - exp_complex(exp_param1, exp_param1); - exp_complex(exp_param2, exp_param2); - conj_complex(conj_param, o->_h0_minus[i * o->_N + j]); + for (i = 0; i < o->_M; ++i) { + for (j = 0; j < o->_N; ++j) { + o->_Jxx[i * o->_N + j] += 1.0; + } + } +} - mul_complex_c(exp_param1, o->_h0[i * o->_N + j], exp_param1); - mul_complex_c(exp_param2, conj_param, exp_param2); +static void ocean_compute_jacobian_jzz(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid)) +{ + OceanSimulateData *osd = BLI_task_pool_userdata(pool); + const Ocean *o = osd->o; + const float chop_amount = osd->chop_amount; + int i, j; - add_comlex_c(o->_htilda[i * (1 + o->_N / 2) + j], exp_param1, exp_param2); - mul_complex_f(o->_fft_in[i * (1 + o->_N / 2) + j], o->_htilda[i * (1 + o->_N / 2) + j], scale); + for (i = 0; i < o->_M; ++i) { + for (j = 0; j <= o->_N / 2; ++j) { + fftw_complex mul_param; + + /* init_complex(mul_param, -scale, 0); */ + init_complex(mul_param, -1, 0); + + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); + init_complex(o->_fft_in_jzz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); } } + fftw_execute(o->_Jzz_plan); -#pragma omp parallel sections private(i, j) - { + for (i = 0; i < o->_M; ++i) { + for (j = 0; j < o->_N; ++j) { + o->_Jzz[i * o->_N + j] += 1.0; + } + } +} -#pragma omp section - { - if (o->_do_disp_y) { - /* y displacement */ - fftw_execute(o->_disp_y_plan); - } - } /* section 1 */ - -#pragma omp section - { - if (o->_do_chop) { - /* x displacement */ - for (i = 0; i < o->_M; ++i) { - for (j = 0; j <= o->_N / 2; ++j) { - fftw_complex mul_param; - fftw_complex minus_i; - - init_complex(minus_i, 0.0, -1.0); - init_complex(mul_param, -scale, 0); - mul_complex_f(mul_param, mul_param, chop_amount); - mul_complex_c(mul_param, mul_param, minus_i); - mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, - ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? - 0.0f : - o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); - init_complex(o->_fft_in_x[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); - } - } - fftw_execute(o->_disp_x_plan); - } - } /* section 2 */ - -#pragma omp section - { - if (o->_do_chop) { - /* z displacement */ - for (i = 0; i < o->_M; ++i) { - for (j = 0; j <= o->_N / 2; ++j) { - fftw_complex mul_param; - fftw_complex minus_i; - - init_complex(minus_i, 0.0, -1.0); - init_complex(mul_param, -scale, 0); - mul_complex_f(mul_param, mul_param, chop_amount); - mul_complex_c(mul_param, mul_param, minus_i); - mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, - ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? - 0.0f : - o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); - init_complex(o->_fft_in_z[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); - } - } - fftw_execute(o->_disp_z_plan); - } - } /* section 3 */ - -#pragma omp section - { - if (o->_do_jacobian) { - /* Jxx */ - for (i = 0; i < o->_M; ++i) { - for (j = 0; j <= o->_N / 2; ++j) { - fftw_complex mul_param; - - /* init_complex(mul_param, -scale, 0); */ - init_complex(mul_param, -1, 0); - - mul_complex_f(mul_param, mul_param, chop_amount); - mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, - ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? - 0.0f : - o->_kx[i] * o->_kx[i] / o->_k[i * (1 + o->_N / 2) + j])); - init_complex(o->_fft_in_jxx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); - } - } - fftw_execute(o->_Jxx_plan); +static void ocean_compute_jacobian_jxz(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid)) +{ + OceanSimulateData *osd = BLI_task_pool_userdata(pool); + const Ocean *o = osd->o; + const float chop_amount = osd->chop_amount; + int i, j; - for (i = 0; i < o->_M; ++i) { - for (j = 0; j < o->_N; ++j) { - o->_Jxx[i * o->_N + j] += 1.0; - } - } - } - } /* section 4 */ - -#pragma omp section - { - if (o->_do_jacobian) { - /* Jzz */ - for (i = 0; i < o->_M; ++i) { - for (j = 0; j <= o->_N / 2; ++j) { - fftw_complex mul_param; - - /* init_complex(mul_param, -scale, 0); */ - init_complex(mul_param, -1, 0); - - mul_complex_f(mul_param, mul_param, chop_amount); - mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, - ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? - 0.0f : - o->_kz[j] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); - init_complex(o->_fft_in_jzz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); - } - } - fftw_execute(o->_Jzz_plan); - for (i = 0; i < o->_M; ++i) { - for (j = 0; j < o->_N; ++j) { - o->_Jzz[i * o->_N + j] += 1.0; - } - } - } - } /* section 5 */ - -#pragma omp section - { - if (o->_do_jacobian) { - /* Jxz */ - for (i = 0; i < o->_M; ++i) { - for (j = 0; j <= o->_N / 2; ++j) { - fftw_complex mul_param; - - /* init_complex(mul_param, -scale, 0); */ - init_complex(mul_param, -1, 0); - - mul_complex_f(mul_param, mul_param, chop_amount); - mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, - ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? - 0.0f : - o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); - init_complex(o->_fft_in_jxz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); - } - } - fftw_execute(o->_Jxz_plan); - } - } /* section 6 */ - -#pragma omp section - { - /* fft normals */ - if (o->_do_normals) { - for (i = 0; i < o->_M; ++i) { - for (j = 0; j <= o->_N / 2; ++j) { - fftw_complex mul_param; - - init_complex(mul_param, 0.0, -1.0); - mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, o->_kx[i]); - init_complex(o->_fft_in_nx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); - } - } - fftw_execute(o->_N_x_plan); + for (i = 0; i < o->_M; ++i) { + for (j = 0; j <= o->_N / 2; ++j) { + fftw_complex mul_param; + + /* init_complex(mul_param, -scale, 0); */ + init_complex(mul_param, -1, 0); + + mul_complex_f(mul_param, mul_param, chop_amount); + mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); + mul_complex_f(mul_param, mul_param, + ((o->_k[i * (1 + o->_N / 2) + j] == 0.0f) ? + 0.0f : + o->_kx[i] * o->_kz[j] / o->_k[i * (1 + o->_N / 2) + j])); + init_complex(o->_fft_in_jxz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_Jxz_plan); +} - } - } /* section 7 */ - -#pragma omp section - { - if (o->_do_normals) { - for (i = 0; i < o->_M; ++i) { - for (j = 0; j <= o->_N / 2; ++j) { - fftw_complex mul_param; - - init_complex(mul_param, 0.0, -1.0); - mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); - mul_complex_f(mul_param, mul_param, o->_kz[i]); - init_complex(o->_fft_in_nz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); - } - } - fftw_execute(o->_N_z_plan); +static void ocean_compute_normal_x(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid)) +{ + OceanSimulateData *osd = BLI_task_pool_userdata(pool); + const Ocean *o = osd->o; + int i, j; + + for (i = 0; i < o->_M; ++i) { + for (j = 0; j <= o->_N / 2; ++j) { + fftw_complex mul_param; + + init_complex(mul_param, 0.0, -1.0); + mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); + mul_complex_f(mul_param, mul_param, o->_kx[i]); + init_complex(o->_fft_in_nx[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_N_x_plan); +} + +static void ocean_compute_normal_z(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid)) +{ + OceanSimulateData *osd = BLI_task_pool_userdata(pool); + const Ocean *o = osd->o; + int i, j; + + for (i = 0; i < o->_M; ++i) { + for (j = 0; j <= o->_N / 2; ++j) { + fftw_complex mul_param; + + init_complex(mul_param, 0.0, -1.0); + mul_complex_c(mul_param, mul_param, o->_htilda[i * (1 + o->_N / 2) + j]); + mul_complex_f(mul_param, mul_param, o->_kz[i]); + init_complex(o->_fft_in_nz[i * (1 + o->_N / 2) + j], real_c(mul_param), image_c(mul_param)); + } + } + fftw_execute(o->_N_z_plan); +} + +void BKE_ocean_simulate(struct Ocean *o, float t, float scale, float chop_amount) +{ + TaskScheduler *scheduler = BLI_task_scheduler_get(); + TaskPool *pool; + + OceanSimulateData osd; + + scale *= o->normalize_factor; + + osd.o = o; + osd.t = t; + osd.scale = scale; + osd.chop_amount = chop_amount; + + pool = BLI_task_pool_create(scheduler, &osd); + + BLI_rw_mutex_lock(&o->oceanmutex, THREAD_LOCK_WRITE); + + /* Note about multi-threading here: we have to run a first set of computations (htilda one) before we can run + * all others, since they all depend on it. + * So we make a first parallelized forloop run for htilda, and then pack all other computations into + * a set of parallel tasks. + * This is not optimal in all cases, but remains reasonably simple and should be OK most of the time. */ + + /* compute a new htilda */ + BLI_task_parallel_range(0, o->_M, &osd, ocean_compute_htilda); + + if (o->_do_disp_y) { + BLI_task_pool_push(pool, ocean_compute_displacement_y, NULL, false, TASK_PRIORITY_HIGH); + } + + if (o->_do_chop) { + BLI_task_pool_push(pool, ocean_compute_displacement_x, NULL, false, TASK_PRIORITY_HIGH); + BLI_task_pool_push(pool, ocean_compute_displacement_z, NULL, false, TASK_PRIORITY_HIGH); + } + + if (o->_do_jacobian) { + BLI_task_pool_push(pool, ocean_compute_jacobian_jxx, NULL, false, TASK_PRIORITY_HIGH); + BLI_task_pool_push(pool, ocean_compute_jacobian_jzz, NULL, false, TASK_PRIORITY_HIGH); + BLI_task_pool_push(pool, ocean_compute_jacobian_jxz, NULL, false, TASK_PRIORITY_HIGH); + } + + if (o->_do_normals) { + BLI_task_pool_push(pool, ocean_compute_normal_x, NULL, false, TASK_PRIORITY_HIGH); + BLI_task_pool_push(pool, ocean_compute_normal_z, NULL, false, TASK_PRIORITY_HIGH); #if 0 - for (i = 0; i < o->_M; ++i) { - for (j = 0; j < o->_N; ++j) { - o->_N_y[i * o->_N + j] = 1.0f / scale; - } - } - (MEM01) -#endif - o->_N_y = 1.0f / scale; + for (i = 0; i < o->_M; ++i) { + for (j = 0; j < o->_N; ++j) { + o->_N_y[i * o->_N + j] = 1.0f / scale; } - } /* section 8 */ + } + (MEM01) +#endif + o->_N_y = 1.0f / scale; + } - } /* omp sections */ + BLI_task_pool_work_and_wait(pool); BLI_rw_mutex_unlock(&o->oceanmutex); + + BLI_task_pool_free(pool); } static void set_height_normalize_factor(struct Ocean *oc) diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 311e928c348..16ba25e3bef 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -63,7 +63,7 @@ typedef struct PBVHStack { PBVHNode *node; - int revisiting; + bool revisiting; } PBVHStack; typedef struct PBVHIter { @@ -87,8 +87,7 @@ void BB_reset(BB *bb) /* Expand the bounding box to include a new coordinate */ void BB_expand(BB *bb, const float co[3]) { - int i; - for (i = 0; i < 3; ++i) { + for (int i = 0; i < 3; ++i) { bb->bmin[i] = min_ff(bb->bmin[i], co[i]); bb->bmax[i] = max_ff(bb->bmax[i], co[i]); } @@ -97,8 +96,7 @@ void BB_expand(BB *bb, const float co[3]) /* Expand the bounding box to include another bounding box */ void BB_expand_with_bb(BB *bb, BB *bb2) { - int i; - for (i = 0; i < 3; ++i) { + for (int i = 0; i < 3; ++i) { bb->bmin[i] = min_ff(bb->bmin[i], bb2->bmin[i]); bb->bmax[i] = max_ff(bb->bmax[i], bb2->bmax[i]); } @@ -108,9 +106,8 @@ void BB_expand_with_bb(BB *bb, BB *bb2) int BB_widest_axis(const BB *bb) { float dim[3]; - int i; - for (i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) dim[i] = bb->bmax[i] - bb->bmin[i]; if (dim[0] > dim[1]) { @@ -129,8 +126,7 @@ int BB_widest_axis(const BB *bb) void BBC_update_centroid(BBC *bbc) { - int i; - for (i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) bbc->bcentroid[i] = (bbc->bmin[i] + bbc->bmax[i]) * 0.5f; } @@ -170,13 +166,13 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node) // BB_expand(&node->vb, co); //} -static int face_materials_match(const MPoly *f1, const MPoly *f2) +static bool face_materials_match(const MPoly *f1, const MPoly *f2) { return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && (f1->mat_nr == f2->mat_nr)); } -static int grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2) +static bool grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2) { return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && (f1->mat_nr == f2->mat_nr)); @@ -279,29 +275,24 @@ static int map_insert_vert(PBVH *bvh, GHash *map, /* Find vertices used by the faces in this node and update the draw buffers */ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) { - GHashIterator gh_iter; - GHash *map; - int i, j, totface; bool has_visible = false; - int (*face_vert_indices)[4]; - int *vert_indices; node->uniq_verts = node->face_verts = 0; - totface = node->totprim; + const int totface = node->totprim; /* reserve size is rough guess */ - map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface); + GHash *map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface); - face_vert_indices = MEM_callocN(sizeof(int[4]) * totface, - "bvh node face vert indices"); + int (*face_vert_indices)[4] = MEM_callocN(sizeof(int[4]) * totface, + "bvh node face vert indices"); node->face_vert_indices = (const int (*)[4])face_vert_indices; - for (i = 0; i < totface; ++i) { + for (int i = 0; i < totface; ++i) { const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]]; const int sides = 3; - for (j = 0; j < sides; ++j) { + for (int j = 0; j < sides; ++j) { face_vert_indices[i][j] = map_insert_vert(bvh, map, &node->face_verts, &node->uniq_verts, bvh->mloop[lt->tri[j]].v); @@ -312,12 +303,12 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) } } - vert_indices = MEM_callocN(sizeof(int) * - (node->uniq_verts + node->face_verts), - "bvh node vert indices"); + int *vert_indices = MEM_callocN(sizeof(int) * (node->uniq_verts + node->face_verts), + "bvh node vert indices"); node->vert_indices = vert_indices; /* Build the vertex list, unique verts first */ + GHashIterator gh_iter; GHASH_ITER (gh_iter, map) { void *value = BLI_ghashIterator_getValue(&gh_iter); int ndx = GET_INT_FROM_POINTER(value); @@ -329,10 +320,10 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter)); } - for (i = 0; i < totface; ++i) { + for (int i = 0; i < totface; ++i) { const int sides = 3; - for (j = 0; j < sides; ++j) { + for (int j = 0; j < sides; ++j) { if (face_vert_indices[i][j] < 0) face_vert_indices[i][j] = -face_vert_indices[i][j] + @@ -350,10 +341,8 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) static void update_vb(PBVH *bvh, PBVHNode *node, BBC *prim_bbc, int offset, int count) { - int i; - BB_reset(&node->vb); - for (i = offset + count - 1; i >= offset; --i) { + for (int i = offset + count - 1; i >= offset; --i) { BB_expand_with_bb(&node->vb, (BB *)(&prim_bbc[bvh->prim_indices[i]])); } node->orig_vb = node->vb; @@ -364,19 +353,19 @@ int BKE_pbvh_count_grid_quads(BLI_bitmap **grid_hidden, int *grid_indices, int totgrid, int gridsize) { - int gridarea = (gridsize - 1) * (gridsize - 1); - int i, x, y, totquad; + const int gridarea = (gridsize - 1) * (gridsize - 1); + int totquad = 0; /* grid hidden layer is present, so have to check each grid for * visibility */ - for (i = 0, totquad = 0; i < totgrid; i++) { + for (int i = 0; i < totgrid; i++) { const BLI_bitmap *gh = grid_hidden[grid_indices[i]]; if (gh) { /* grid hidden are present, have to check each element */ - for (y = 0; y < gridsize - 1; y++) { - for (x = 0; x < gridsize - 1; x++) { + for (int y = 0; y < gridsize - 1; y++) { + for (int x = 0; x < gridsize - 1; x++) { if (!paint_is_grid_face_hidden(gh, gridsize, x, y)) totquad++; } @@ -418,36 +407,34 @@ static void build_leaf(PBVH *bvh, int node_index, BBC *prim_bbc, /* Return zero if all primitives in the node can be drawn with the * same material (including flat/smooth shading), non-zero otherwise */ -static int leaf_needs_material_split(PBVH *bvh, int offset, int count) +static bool leaf_needs_material_split(PBVH *bvh, int offset, int count) { - int i; - if (count <= 1) - return 0; + return false; if (bvh->looptri) { const MLoopTri *first = &bvh->looptri[bvh->prim_indices[offset]]; const MPoly *mp = &bvh->mpoly[first->poly]; - for (i = offset + count - 1; i > offset; --i) { + for (int i = offset + count - 1; i > offset; --i) { int prim = bvh->prim_indices[i]; const MPoly *mp_other = &bvh->mpoly[bvh->looptri[prim].poly]; if (!face_materials_match(mp, mp_other)) { - return 1; + return true; } } } else { const DMFlagMat *first = &bvh->grid_flag_mats[bvh->prim_indices[offset]]; - for (i = offset + count - 1; i > offset; --i) { + for (int i = offset + count - 1; i > offset; --i) { int prim = bvh->prim_indices[i]; if (!grid_materials_match(first, &bvh->grid_flag_mats[prim])) - return 1; + return true; } } - return 0; + return false; } @@ -465,11 +452,11 @@ static int leaf_needs_material_split(PBVH *bvh, int offset, int count) static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, int offset, int count) { - int i, axis, end, below_leaf_limit; + int end; BB cb_backing; /* Decide whether this is a leaf or not */ - below_leaf_limit = count <= bvh->leaf_limit; + const bool below_leaf_limit = count <= bvh->leaf_limit; if (below_leaf_limit) { if (!leaf_needs_material_split(bvh, offset, count)) { build_leaf(bvh, node_index, prim_bbc, offset, count); @@ -489,10 +476,10 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, if (!cb) { cb = &cb_backing; BB_reset(cb); - for (i = offset + count - 1; i >= offset; --i) + for (int i = offset + count - 1; i >= offset; --i) BB_expand(cb, prim_bbc[bvh->prim_indices[i]].bcentroid); } - axis = BB_widest_axis(cb); + const int axis = BB_widest_axis(cb); /* Partition primitives along that axis */ end = partition_indices(bvh->prim_indices, @@ -515,15 +502,13 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc, static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim) { - int i; - if (totprim != bvh->totprim) { bvh->totprim = totprim; if (bvh->nodes) MEM_freeN(bvh->nodes); if (bvh->prim_indices) MEM_freeN(bvh->prim_indices); bvh->prim_indices = MEM_callocN(sizeof(int) * totprim, "bvh prim indices"); - for (i = 0; i < totprim; ++i) + for (int i = 0; i < totprim; ++i) bvh->prim_indices[i] = i; bvh->totnode = 0; if (bvh->node_mem_count < 100) { @@ -546,7 +531,6 @@ void BKE_pbvh_build_mesh( { BBC *prim_bbc = NULL; BB cb; - int i, j; bvh->type = PBVH_FACES; bvh->mpoly = mpoly; @@ -563,14 +547,14 @@ void BKE_pbvh_build_mesh( /* For each face, store the AABB and the AABB centroid */ prim_bbc = MEM_mallocN(sizeof(BBC) * looptri_num, "prim_bbc"); - for (i = 0; i < looptri_num; ++i) { + for (int i = 0; i < looptri_num; ++i) { const MLoopTri *lt = &looptri[i]; const int sides = 3; BBC *bbc = prim_bbc + i; BB_reset((BB *)bbc); - for (j = 0; j < sides; ++j) + for (int j = 0; j < sides; ++j) BB_expand((BB *)bbc, verts[bvh->mloop[lt->tri[j]].v].co); BBC_update_centroid(bbc); @@ -589,10 +573,7 @@ void BKE_pbvh_build_mesh( void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, int totgrid, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden) { - BBC *prim_bbc = NULL; - BB cb; - int gridsize = key->grid_size; - int i, j; + const int gridsize = key->grid_size; bvh->type = PBVH_GRIDS; bvh->grids = grids; @@ -603,18 +584,19 @@ void BKE_pbvh_build_grids(PBVH *bvh, CCGElem **grids, bvh->grid_hidden = grid_hidden; bvh->leaf_limit = max_ii(LEAF_LIMIT / ((gridsize - 1) * (gridsize - 1)), 1); + BB cb; BB_reset(&cb); /* For each grid, store the AABB and the AABB centroid */ - prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc"); + BBC *prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc"); - for (i = 0; i < totgrid; ++i) { + for (int i = 0; i < totgrid; ++i) { CCGElem *grid = grids[i]; BBC *bbc = prim_bbc + i; BB_reset((BB *)bbc); - for (j = 0; j < gridsize * gridsize; ++j) + for (int j = 0; j < gridsize * gridsize; ++j) BB_expand((BB *)bbc, CCG_elem_offset_co(key, grid, j)); BBC_update_centroid(bbc); @@ -637,11 +619,8 @@ PBVH *BKE_pbvh_new(void) void BKE_pbvh_free(PBVH *bvh) { - PBVHNode *node; - int i; - - for (i = 0; i < bvh->totnode; ++i) { - node = &bvh->nodes[i]; + for (int i = 0; i < bvh->totnode; ++i) { + PBVHNode *node = &bvh->nodes[i]; if (node->flag & PBVH_Leaf) { if (node->draw_buffers) @@ -684,8 +663,7 @@ void BKE_pbvh_free(PBVH *bvh) void BKE_pbvh_free_layer_disp(PBVH *bvh) { - int i; - for (i = 0; i < bvh->totnode; ++i) + for (int i = 0; i < bvh->totnode; ++i) BKE_pbvh_node_layer_disp_free(&bvh->nodes[i]); } @@ -699,7 +677,7 @@ static void pbvh_iter_begin(PBVHIter *iter, PBVH *bvh, BKE_pbvh_SearchCallback s iter->stackspace = STACK_FIXED_DEPTH; iter->stack[0].node = bvh->nodes; - iter->stack[0].revisiting = 0; + iter->stack[0].revisiting = false; iter->stacksize = 1; } @@ -709,7 +687,7 @@ static void pbvh_iter_end(PBVHIter *iter) MEM_freeN(iter->stack); } -static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, int revisiting) +static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, bool revisiting) { if (UNLIKELY(iter->stacksize == iter->stackspace)) { iter->stackspace *= 2; @@ -730,23 +708,20 @@ static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, int revisiting) static PBVHNode *pbvh_iter_next(PBVHIter *iter) { - PBVHNode *node; - int revisiting; - /* purpose here is to traverse tree, visiting child nodes before their * parents, this order is necessary for e.g. computing bounding boxes */ while (iter->stacksize) { /* pop node */ iter->stacksize--; - node = iter->stack[iter->stacksize].node; + PBVHNode *node = iter->stack[iter->stacksize].node; /* on a mesh with no faces this can happen * can remove this check if we know meshes have at least 1 face */ if (node == NULL) return NULL; - revisiting = iter->stack[iter->stacksize].revisiting; + bool revisiting = iter->stack[iter->stacksize].revisiting; /* revisiting node already checked */ if (revisiting) @@ -761,11 +736,11 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter) } else { /* come back later when children are done */ - pbvh_stack_push(iter, node, 1); + pbvh_stack_push(iter, node, true); /* push two child nodes on the stack */ - pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, 0); - pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, 0); + pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false); + pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false); } } @@ -774,12 +749,10 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter) static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter) { - PBVHNode *node; - while (iter->stacksize) { /* pop node */ iter->stacksize--; - node = iter->stack[iter->stacksize].node; + PBVHNode *node = iter->stack[iter->stacksize].node; /* on a mesh with no faces this can happen * can remove this check if we know meshes have at least 1 face */ @@ -792,8 +765,8 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter) return node; } else { - pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, 0); - pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, 0); + pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset + 1, false); + pbvh_stack_push(iter, iter->bvh->nodes + node->children_offset, false); } } @@ -957,7 +930,6 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, int totnode, float (*face_nors)[3]) { float (*vnor)[3]; - int n; if (bvh->type == PBVH_BMESH) { BLI_assert(face_nors == NULL); @@ -982,19 +954,19 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, * can only update vertices marked with ME_VERT_PBVH_UPDATE. */ + int n; #pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; if ((node->flag & PBVH_UpdateNormals)) { - int i, j, totface, *faces; unsigned int mpoly_prev = UINT_MAX; float fn[3]; - faces = node->prim_indices; - totface = node->totprim; + const int *faces = node->prim_indices; + const int totface = node->totprim; - for (i = 0; i < totface; ++i) { + for (int i = 0; i < totface; ++i) { const MLoopTri *lt = &bvh->looptri[faces[i]]; const unsigned int vtri[3] = { bvh->mloop[lt->tri[0]].v, @@ -1014,7 +986,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, } } - for (j = 0; j < sides; ++j) { + for (int j = 0; j < sides; ++j) { int v = vtri[j]; if (bvh->verts[v].flag & ME_VERT_PBVH_UPDATE) { @@ -1037,13 +1009,10 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, PBVHNode *node = nodes[n]; if (node->flag & PBVH_UpdateNormals) { - const int *verts; - int i, totvert; + const int *verts = node->vert_indices; + const int totvert = node->uniq_verts; - verts = node->vert_indices; - totvert = node->uniq_verts; - - for (i = 0; i < totvert; ++i) { + for (int i = 0; i < totvert; ++i) { const int v = verts[i]; MVert *mvert = &bvh->verts[v]; @@ -1067,9 +1036,8 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes, void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) { - int n; - /* update BB, redraw flag */ + int n; #pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT) for (n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; @@ -1088,12 +1056,9 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag) static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) { - PBVHNode *node; - int n; - /* can't be done in parallel with OpenGL */ - for (n = 0; n < totnode; n++) { - node = nodes[n]; + for (int n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; if (node->flag & PBVH_RebuildDrawBuffers) { GPU_free_pbvh_buffers(node->draw_buffers); @@ -1116,8 +1081,7 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) break; case PBVH_BMESH: node->draw_buffers = - GPU_build_bmesh_pbvh_buffers(bvh->flags & - PBVH_DYNTOPO_SMOOTH_SHADING); + GPU_build_bmesh_pbvh_buffers(bvh->flags & PBVH_DYNTOPO_SMOOTH_SHADING); break; } @@ -1163,13 +1127,10 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode) static void pbvh_draw_BB(PBVH *bvh) { - PBVHNode *node; - int a; - GPU_init_draw_pbvh_BB(); - for (a = 0; a < bvh->totnode; a++) { - node = &bvh->nodes[a]; + for (int a = 0; a < bvh->totnode; a++) { + PBVHNode *node = &bvh->nodes[a]; GPU_draw_pbvh_BB(node->vb.bmin, node->vb.bmax, ((node->flag & PBVH_Leaf) != 0)); } @@ -1210,12 +1171,12 @@ static int pbvh_flush_bb(PBVH *bvh, PBVHNode *node, int flag) void BKE_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3]) { - PBVHNode **nodes; - int totnode; - if (!bvh->nodes) return; + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(flag), &nodes, &totnode); @@ -1251,24 +1212,18 @@ void BKE_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]) copy_v3_v3(bb_max, bb.bmax); } -void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r_totface) +void BKE_pbvh_get_grid_updates(PBVH *bvh, bool clear, void ***r_gridfaces, int *r_totface) { - PBVHIter iter; + GSet *face_set = BLI_gset_ptr_new(__func__); PBVHNode *node; - GSetIterator gs_iter; - GSet *face_set; - void *face, **faces; - unsigned i; - int tot; - - face_set = BLI_gset_ptr_new(__func__); + PBVHIter iter; pbvh_iter_begin(&iter, bvh, NULL, NULL); while ((node = pbvh_iter_next(&iter))) { if (node->flag & PBVH_UpdateNormals) { - for (i = 0; i < node->totprim; ++i) { - face = bvh->gridfaces[node->prim_indices[i]]; + for (unsigned i = 0; i < node->totprim; ++i) { + void *face = bvh->gridfaces[node->prim_indices[i]]; if (!BLI_gset_haskey(face_set, face)) BLI_gset_insert(face_set, face); } @@ -1280,7 +1235,7 @@ void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r pbvh_iter_end(&iter); - tot = BLI_gset_size(face_set); + const int tot = BLI_gset_size(face_set); if (tot == 0) { *r_totface = 0; *r_gridfaces = NULL; @@ -1288,8 +1243,10 @@ void BKE_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***r_gridfaces, int *r return; } - faces = MEM_mallocN(sizeof(*faces) * tot, "PBVH Grid Faces"); + void **faces = MEM_mallocN(sizeof(*faces) * tot, "PBVH Grid Faces"); + GSetIterator gs_iter; + int i; GSET_ITER_INDEX (gs_iter, face_set, i) { faces[i] = BLI_gsetIterator_getKey(&gs_iter); } @@ -1589,12 +1546,11 @@ static bool pbvh_grids_node_raycast( const float ray_start[3], const float ray_normal[3], float *dist) { - int totgrid = node->totprim; - int gridsize = bvh->gridkey.grid_size; - int i, x, y; + const int totgrid = node->totprim; + const int gridsize = bvh->gridkey.grid_size; bool hit = false; - for (i = 0; i < totgrid; ++i) { + for (int i = 0; i < totgrid; ++i) { CCGElem *grid = bvh->grids[node->prim_indices[i]]; BLI_bitmap *gh; @@ -1603,8 +1559,8 @@ static bool pbvh_grids_node_raycast( gh = bvh->grid_hidden[node->prim_indices[i]]; - for (y = 0; y < gridsize - 1; ++y) { - for (x = 0; x < gridsize - 1; ++x) { + for (int y = 0; y < gridsize - 1; ++y) { + for (int x = 0; x < gridsize - 1; ++x) { /* check if grid face is hidden */ if (gh) { if (paint_is_grid_face_hidden(gh, gridsize, x, y)) @@ -1640,14 +1596,14 @@ static bool pbvh_grids_node_raycast( } bool BKE_pbvh_node_raycast( - PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco, + PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco, const float ray_start[3], const float ray_normal[3], float *dist) { bool hit = false; if (node->flag & PBVH_FullyHidden) - return 0; + return false; switch (bvh->type) { case PBVH_FACES: @@ -1713,9 +1669,6 @@ void BKE_pbvh_raycast_project_ray_root( } } - -//#include "GPU_glew.h" - typedef struct { DMSetMaterial setMaterial; bool wireframe; @@ -1728,18 +1681,19 @@ void BKE_pbvh_node_draw(PBVHNode *node, void *data_v) #if 0 /* XXX: Just some quick code to show leaf nodes in different colors */ - float col[3]; int i; + float col[3]; + float spec[3] = {0.0f, 0.0f, 0.0f}; if (0) { //is_partial) { col[0] = (rand() / (float)RAND_MAX); col[1] = col[2] = 0.6; } else { srand((long long)node); - for (i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) col[i] = (rand() / (float)RAND_MAX) * 0.3 + 0.7; } - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col); + GPU_basic_shader_colors(col, spec, 0, 1.0f); glColor3f(1, 0, 0); #endif @@ -1768,10 +1722,9 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3], { float vmin[3], vmax[3]; PlaneAABBIsect ret = ISECT_INSIDE; - int i, axis; - for (i = 0; i < 4; ++i) { - for (axis = 0; axis < 3; ++axis) { + for (int i = 0; i < 4; ++i) { + for (int axis = 0; axis < 3; ++axis) { if (planes[i][axis] > 0) { vmin[axis] = bb_min[axis]; vmax[axis] = bb_max[axis]; @@ -1821,9 +1774,9 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], { PBVHNodeDrawData draw_data = {setMaterial, wireframe, fast}; PBVHNode **nodes; - int a, totnode; + int totnode; - for (a = 0; a < bvh->totnode; a++) + for (int a = 0; a < bvh->totnode; a++) pbvh_node_check_diffuse_changed(bvh, &bvh->nodes[a]); BKE_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals | PBVH_UpdateDrawBuffers), @@ -1849,8 +1802,6 @@ void BKE_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces, DMFlagMat *flagmats, BLI_bitmap **grid_hidden) { - int a; - bvh->grids = grids; bvh->gridfaces = gridfaces; @@ -1858,7 +1809,7 @@ void BKE_pbvh_grids_update(PBVH *bvh, CCGElem **grids, void **gridfaces, bvh->grid_flag_mats = flagmats; bvh->grid_hidden = grid_hidden; - for (a = 0; a < bvh->totnode; ++a) + for (int a = 0; a < bvh->totnode; ++a) BKE_pbvh_node_mark_rebuild_draw(&bvh->nodes[a]); } } @@ -1885,17 +1836,15 @@ void BKE_pbvh_node_layer_disp_free(PBVHNode *node) float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3] { - int a; float (*vertCos)[3] = NULL; if (pbvh->verts) { - float *co; MVert *mvert = pbvh->verts; vertCos = MEM_callocN(3 * pbvh->totvert * sizeof(float), "BKE_pbvh_get_vertCoords"); - co = (float *)vertCos; + float *co = (float *)vertCos; - for (a = 0; a < pbvh->totvert; a++, mvert++, co += 3) { + for (int a = 0; a < pbvh->totvert; a++, mvert++, co += 3) { copy_v3_v3(co, mvert->co); } } @@ -1905,8 +1854,6 @@ float (*BKE_pbvh_get_vertCos(PBVH *pbvh))[3] void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) { - int a; - if (!pbvh->deformed) { if (pbvh->verts) { /* if pbvh is not already deformed, verts/faces points to the */ @@ -1916,14 +1863,14 @@ void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) pbvh->verts = MEM_dupallocN(pbvh->verts); pbvh->looptri = MEM_dupallocN(pbvh->looptri); - pbvh->deformed = 1; + pbvh->deformed = true; } } if (pbvh->verts) { MVert *mvert = pbvh->verts; /* copy new verts coords */ - for (a = 0; a < pbvh->totvert; ++a, ++mvert) { + for (int a = 0; a < pbvh->totvert; ++a, ++mvert) { copy_v3_v3(mvert->co, vertCos[a]); mvert->flag |= ME_VERT_PBVH_UPDATE; } @@ -1935,7 +1882,7 @@ void BKE_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3]) pbvh->looptri, pbvh->totprim, NULL); - for (a = 0; a < pbvh->totnode; ++a) + for (int a = 0; a < pbvh->totnode; ++a) BKE_pbvh_node_mark_update(&pbvh->nodes[a]); BKE_pbvh_update(pbvh, PBVH_UpdateBB, NULL); @@ -1956,7 +1903,6 @@ PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *bvh, PBVHNode *node) #pragma omp critical { - index = node->proxy_count; node->proxy_count++; @@ -1977,9 +1923,7 @@ void BKE_pbvh_node_free_proxies(PBVHNode *node) { #pragma omp critical { - int p; - - for (p = 0; p < node->proxy_count; p++) { + for (int p = 0; p < node->proxy_count; p++) { MEM_freeN(node->proxies[p].co); node->proxies[p].co = NULL; } @@ -1993,12 +1937,11 @@ void BKE_pbvh_node_free_proxies(PBVHNode *node) void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot) { - PBVHNode **array = NULL, *node; + PBVHNode **array = NULL; int tot = 0, space = 0; - int n; - for (n = 0; n < pbvh->totnode; n++) { - node = pbvh->nodes + n; + for (int n = 0; n < pbvh->totnode; n++) { + PBVHNode *node = pbvh->nodes + n; if (node->proxy_count > 0) { if (tot == space) { diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index ff4cae09437..88dc63d6cb2 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -87,17 +87,16 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_ver GSET_ITER (gs_iter, n->bm_faces) { BMFace *f = BLI_gsetIterator_getKey(&gs_iter); - BMLoop *l_iter; - BMLoop *l_first; - BMVert *v; /* Update ownership of faces */ BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index); - /* Update vertices */ - l_iter = l_first = BM_FACE_FIRST_LOOP(f); + /* Update vertices */ + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; + do { - v = l_iter->v; + BMVert *v = l_iter->v; if (!BLI_gset_haskey(n->bm_unique_verts, v)) { if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) { BLI_gset_add(n->bm_other_verts, v); @@ -131,15 +130,9 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_ver /* Recursively split the node if it exceeds the leaf_limit */ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_index) { - GSet *empty, *other; - GSetIterator gs_iter; - PBVHNode *n, *c1, *c2; - BB cb; - float mid; - int axis, children; const int cd_vert_node_offset = bvh->cd_vert_node_offset; const int cd_face_node_offset = bvh->cd_face_node_offset; - n = &bvh->nodes[node_index]; + PBVHNode *n = &bvh->nodes[node_index]; if (BLI_gset_size(n->bm_faces) <= bvh->leaf_limit) { /* Node limit not exceeded */ @@ -148,7 +141,9 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde } /* Calculate bounding box around primitive centroids */ + BB cb; BB_reset(&cb); + GSetIterator gs_iter; GSET_ITER (gs_iter, n->bm_faces) { const BMFace *f = BLI_gsetIterator_getKey(&gs_iter); const BBC *bbc = &bbc_array[BM_elem_index_get(f)]; @@ -157,11 +152,11 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde } /* Find widest axis and its midpoint */ - axis = BB_widest_axis(&cb); - mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f; + const int axis = BB_widest_axis(&cb); + const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f; /* Add two new child nodes */ - children = bvh->totnode; + const int children = bvh->totnode; n->children_offset = children; pbvh_grow_nodes(bvh, bvh->totnode + 2); @@ -169,8 +164,8 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde n = &bvh->nodes[node_index]; /* Initialize children */ - c1 = &bvh->nodes[children]; - c2 = &bvh->nodes[children + 1]; + PBVHNode *c1 = &bvh->nodes[children], + *c2 = &bvh->nodes[children + 1]; c1->flag |= PBVH_Leaf; c2->flag |= PBVH_Leaf; c1->bm_faces = BLI_gset_ptr_new_ex("bm_faces", BLI_gset_size(n->bm_faces) / 2); @@ -188,7 +183,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde } /* Enforce at least one primitive in each node */ - empty = NULL; + GSet *empty = NULL, *other; if (BLI_gset_size(c1->bm_faces) == 0) { empty = c1->bm_faces; other = c2->bm_faces; @@ -242,7 +237,6 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde n->flag &= ~PBVH_Leaf; /* Recurse */ - c1 = c2 = NULL; pbvh_bmesh_node_split(bvh, bbc_array, children); pbvh_bmesh_node_split(bvh, bbc_array, children + 1); @@ -259,30 +253,25 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde /* Recursively split the node if it exceeds the leaf_limit */ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) { - GSet *bm_faces; - int bm_faces_size; - GSetIterator gs_iter; - BBC *bbc_array; - unsigned int i; - - bm_faces = bvh->nodes[node_index].bm_faces; - bm_faces_size = BLI_gset_size(bm_faces); + GSet *bm_faces = bvh->nodes[node_index].bm_faces; + const int bm_faces_size = BLI_gset_size(bm_faces); if (bm_faces_size <= bvh->leaf_limit) { /* Node limit not exceeded */ return false; } /* For each BMFace, store the AABB and AABB centroid */ - bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC"); + BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC"); + GSetIterator gs_iter; + int i; GSET_ITER_INDEX (gs_iter, bm_faces, i) { BMFace *f = BLI_gsetIterator_getKey(&gs_iter); BBC *bbc = &bbc_array[i]; - BMLoop *l_iter; - BMLoop *l_first; BB_reset((BB *)bbc); - l_iter = l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; do { BB_expand((BB *)bbc, l_iter->v->co); } while ((l_iter = l_iter->next) != l_first); @@ -347,12 +336,11 @@ static BMVert *pbvh_bmesh_vert_create( const int cd_vert_mask_offset) { PBVHNode *node = &bvh->nodes[node_index]; - BMVert *v; BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode); /* avoid initializing customdata because its quite involved */ - v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD); + BMVert *v = BM_vert_create(bvh->bm, co, NULL, BM_CREATE_SKIP_CD); CustomData_bmesh_set_default(&bvh->bm->vdata, &v->head.data); /* This value is logged below */ @@ -374,13 +362,12 @@ static BMFace *pbvh_bmesh_face_create( BMVert *v_tri[3], BMEdge *e_tri[3], const BMFace *f_example) { - BMFace *f; PBVHNode *node = &bvh->nodes[node_index]; /* ensure we never add existing face */ BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); - f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE); + BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE); f->head.hflag = f_example->head.hflag; BLI_gset_insert(node->bm_faces, f); @@ -442,14 +429,10 @@ static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v) { BMIter bm_iter; BMFace *f; - PBVHNode *current_node; - - current_node = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *current_node = pbvh_bmesh_node_lookup(bvh, v); BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - PBVHNode *f_node; - - f_node = pbvh_bmesh_node_lookup(bvh, f); + PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); if (f_node != current_node) return f_node; @@ -462,13 +445,10 @@ static void pbvh_bmesh_vert_ownership_transfer( PBVH *bvh, PBVHNode *new_owner, BMVert *v) { - PBVHNode *current_owner; - - current_owner = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *current_owner = pbvh_bmesh_node_lookup(bvh, v); /* mark node for update */ current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; - BLI_assert(current_owner != new_owner); /* Remove current ownership */ @@ -486,21 +466,18 @@ static void pbvh_bmesh_vert_ownership_transfer( static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v) { - PBVHNode *v_node; - BMIter bm_iter; - BMFace *f; - /* never match for first time */ int f_node_index_prev = DYNTOPO_NODE_NONE; - v_node = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *v_node = pbvh_bmesh_node_lookup(bvh, v); BLI_gset_remove(v_node->bm_unique_verts, v, NULL); BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE); /* Have to check each neighboring face's node */ + BMIter bm_iter; + BMFace *f; BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { const int f_node_index = pbvh_bmesh_node_lookup_index(bvh, f); - PBVHNode *f_node; /* faces often share the same node, * quick check to avoid redundant #BLI_gset_remove calls */ @@ -508,7 +485,7 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v) continue; f_node_index_prev = f_node_index; - f_node = &bvh->nodes[f_node_index]; + PBVHNode *f_node = &bvh->nodes[f_node_index]; f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; /* Remove current ownership */ @@ -521,19 +498,14 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v) static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) { - PBVHNode *f_node; - BMVert *v; - - BMLoop *l_iter; - BMLoop *l_first; - - f_node = pbvh_bmesh_node_lookup(bvh, f); + PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); /* Check if any of this face's vertices need to be removed * from the node */ - l_iter = l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; do { - v = l_iter->v; + BMVert *v = l_iter->v; if (pbvh_bmesh_node_vert_use_count_is_equal(bvh, f_node, v, 1)) { if (BLI_gset_haskey(f_node->bm_unique_verts, v)) { /* Find a different node that uses 'v' */ @@ -630,12 +602,10 @@ typedef struct { * (it's a requirement that edges enter and leave a clean tag state) */ static void pbvh_bmesh_edge_tag_verify(PBVH *bvh) { - int n; - - for (n = 0; n < bvh->totnode; n++) { + for (int n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; - GSetIterator gs_iter; if (node->bm_faces) { + GSetIterator gs_iter; GSET_ITER (gs_iter, node->bm_faces) { BMFace *f = BLI_gsetIterator_getKey(&gs_iter); BMEdge *e_tri[3]; @@ -668,21 +638,19 @@ static bool edge_queue_tri_in_sphere(const EdgeQueue *q, BMFace *f) closest_on_tri_to_point_v3(c, q->center, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co); /* Check if triangle intersects the sphere */ - return ((len_squared_v3v3(q->center, c) <= q->radius_squared)); + return len_squared_v3v3(q->center, c) <= q->radius_squared; } /* Return true if the vertex mask is less than 1.0, false otherwise */ static bool check_mask(EdgeQueueContext *eq_ctx, BMVert *v) { - return (BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f); + return BM_ELEM_CD_GET_FLOAT(v, eq_ctx->cd_vert_mask_offset) < 1.0f; } static void edge_queue_insert( EdgeQueueContext *eq_ctx, BMEdge *e, float priority) { - BMVert **pair; - /* Don't let topology update affect fully masked vertices. This used to * have a 50% mask cutoff, with the reasoning that you can't do a 50% * topology update. But this gives an ugly border in the mesh. The mask @@ -694,7 +662,7 @@ static void edge_queue_insert( !(BM_elem_flag_test_bool(e->v1, BM_ELEM_HIDDEN) || BM_elem_flag_test_bool(e->v2, BM_ELEM_HIDDEN))) { - pair = BLI_mempool_alloc(eq_ctx->pool); + BMVert **pair = BLI_mempool_alloc(eq_ctx->pool); pair[0] = e->v1; pair[1] = e->v2; BLI_heap_insert(eq_ctx->q->heap, priority, pair); @@ -757,19 +725,15 @@ static void long_edge_queue_edge_add_recursive( #define EVEN_GENERATION_SCALE 1.6f const float len_sq_cmp = len_sq * EVEN_EDGELEN_THRESHOLD; - float limit_len_sq; - BMLoop *l_iter; limit_len *= EVEN_GENERATION_SCALE; - limit_len_sq = SQUARE(limit_len); + const float limit_len_sq = SQUARE(limit_len); - l_iter = l_edge; + BMLoop *l_iter = l_edge; do { - float len_sq_other; BMLoop *l_adjacent[2] = {l_iter->next, l_iter->prev}; - int i; - for (i = 0; i < ARRAY_SIZE(l_adjacent); i++) { - len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e); + for (int i = 0; i < ARRAY_SIZE(l_adjacent); i++) { + float len_sq_other = BM_edge_calc_length_squared(l_adjacent[i]->e); if (len_sq_other > max_ff(len_sq_cmp, limit_len_sq)) { // edge_queue_insert(eq_ctx, l_adjacent[i]->e, -len_sq_other); long_edge_queue_edge_add_recursive( @@ -813,24 +777,20 @@ static void long_edge_queue_face_add( #endif if (edge_queue_tri_in_sphere(eq_ctx->q, f)) { - BMLoop *l_iter; - BMLoop *l_first; - /* Check each edge of the face */ - l_iter = l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; do { - { #ifdef USE_EDGEQUEUE_EVEN_SUBDIV - const float len_sq = BM_edge_calc_length_squared(l_iter->e); - if (len_sq > eq_ctx->q->limit_len_squared) { - long_edge_queue_edge_add_recursive( - eq_ctx, l_iter->radial_next, l_iter, - len_sq, eq_ctx->q->limit_len); - } + const float len_sq = BM_edge_calc_length_squared(l_iter->e); + if (len_sq > eq_ctx->q->limit_len_squared) { + long_edge_queue_edge_add_recursive( + eq_ctx, l_iter->radial_next, l_iter, + len_sq, eq_ctx->q->limit_len); + } #else - long_edge_queue_edge_add(eq_ctx, l_iter->e); + long_edge_queue_edge_add(eq_ctx, l_iter->e); #endif - } } while ((l_iter = l_iter->next) != l_first); } } @@ -873,8 +833,6 @@ static void long_edge_queue_create( PBVH *bvh, const float center[3], const float view_normal[3], float radius) { - int n; - eq_ctx->q->heap = BLI_heap_new(); eq_ctx->q->center = center; eq_ctx->q->radius_squared = radius * radius; @@ -894,8 +852,7 @@ static void long_edge_queue_create( pbvh_bmesh_edge_tag_verify(bvh); #endif - - for (n = 0; n < bvh->totnode; n++) { + for (int n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; /* Check leaf nodes marked for topology update */ @@ -929,8 +886,6 @@ static void short_edge_queue_create( PBVH *bvh, const float center[3], const float view_normal[3], float radius) { - int n; - eq_ctx->q->heap = BLI_heap_new(); eq_ctx->q->center = center; eq_ctx->q->radius_squared = radius * radius; @@ -946,7 +901,7 @@ static void short_edge_queue_create( UNUSED_VARS(view_normal); #endif - for (n = 0; n < bvh->totnode; n++) { + for (int n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; /* Check leaf nodes marked for topology update */ @@ -979,9 +934,7 @@ static void pbvh_bmesh_split_edge( EdgeQueueContext *eq_ctx, PBVH *bvh, BMEdge *e, BLI_Buffer *edge_loops) { - BMVert *v_new; float co_mid[3], no_mid[3]; - int i, node_index; /* Get all faces adjacent to the edge */ pbvh_bmesh_edge_loops(edge_loops, e); @@ -991,8 +944,8 @@ static void pbvh_bmesh_split_edge( mid_v3_v3v3(no_mid, e->v1->no, e->v2->no); normalize_v3(no_mid); - node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset); - v_new = pbvh_bmesh_vert_create(bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset); + int node_index = BM_ELEM_CD_GET_INT(e->v1, eq_ctx->cd_vert_node_offset); + BMVert *v_new = pbvh_bmesh_vert_create(bvh, node_index, co_mid, no_mid, eq_ctx->cd_vert_mask_offset); /* update paint mask */ if (eq_ctx->cd_vert_mask_offset != -1) { @@ -1004,17 +957,16 @@ static void pbvh_bmesh_split_edge( } /* For each face, add two new triangles and delete the original */ - for (i = 0; i < edge_loops->count; i++) { + for (int i = 0; i < edge_loops->count; i++) { BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i); BMFace *f_adj = l_adj->f; BMFace *f_new; BMVert *v_opp, *v1, *v2; BMVert *v_tri[3]; BMEdge *e_tri[3]; - int ni; BLI_assert(f_adj->len == 3); - ni = BM_ELEM_CD_GET_INT(f_adj, eq_ctx->cd_face_node_offset); + int ni = BM_ELEM_CD_GET_INT(f_adj, eq_ctx->cd_face_node_offset); /* Find the vertex not in the edge */ v_opp = l_adj->prev->v; @@ -1153,11 +1105,7 @@ static void pbvh_bmesh_collapse_edge( BLI_Buffer *deleted_faces, EdgeQueueContext *eq_ctx) { - BMIter bm_iter; - BMFace *f; - BMLoop *l_adj; BMVert *v_del, *v_conn; - int i; float mask_v1 = BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset); /* one of the two vertices may be masked, select the correct one for deletion */ @@ -1174,6 +1122,7 @@ static void pbvh_bmesh_collapse_edge( pbvh_bmesh_vert_remove(bvh, v_del); /* Remove all faces adjacent to the edge */ + BMLoop *l_adj; while ((l_adj = e->l)) { BMFace *f_adj = l_adj->f; @@ -1192,16 +1141,17 @@ static void pbvh_bmesh_collapse_edge( * really buy anything. */ BLI_buffer_empty(deleted_faces); + BMIter bm_iter; + BMFace *f; + BM_ITER_ELEM (f, &bm_iter, v_del, BM_FACES_OF_VERT) { BMVert *v_tri[3]; BMFace *existing_face; - PBVHNode *n; - int ni; /* Get vertices, replace use of v_del with v_conn */ // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3); BM_face_as_array_vert_tri(f, v_tri); - for (i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { if (v_tri[i] == v_del) { v_tri[i] = v_conn; } @@ -1217,8 +1167,8 @@ static void pbvh_bmesh_collapse_edge( } else { BMEdge *e_tri[3]; - n = pbvh_bmesh_node_lookup(bvh, f); - ni = n - bvh->nodes; + PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f); + int ni = n - bvh->nodes; bm_edges_from_tri(bvh->bm, v_tri, e_tri); pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f); @@ -1232,16 +1182,14 @@ static void pbvh_bmesh_collapse_edge( } /* Delete the tagged faces */ - for (i = 0; i < deleted_faces->count; i++) { + for (int i = 0; i < deleted_faces->count; i++) { BMFace *f_del = BLI_buffer_at(deleted_faces, BMFace *, i); - BMLoop *l_iter; - BMVert *v_tri[3]; - BMEdge *e_tri[3]; - int j; /* Get vertices and edges of face */ BLI_assert(f_del->len == 3); - l_iter = BM_FACE_FIRST_LOOP(f_del); + BMLoop *l_iter = BM_FACE_FIRST_LOOP(f_del); + BMVert *v_tri[3]; + BMEdge *e_tri[3]; v_tri[0] = l_iter->v; e_tri[0] = l_iter->e; l_iter = l_iter->next; v_tri[1] = l_iter->v; e_tri[1] = l_iter->e; l_iter = l_iter->next; v_tri[2] = l_iter->v; e_tri[2] = l_iter->e; @@ -1252,14 +1200,14 @@ static void pbvh_bmesh_collapse_edge( /* Check if any of the face's edges are now unused by any * face, if so delete them */ - for (j = 0; j < 3; j++) { + for (int j = 0; j < 3; j++) { if (BM_edge_is_wire(e_tri[j])) BM_edge_kill(bvh->bm, e_tri[j]); } /* Check if any of the face's vertices are now unused, if so * remove them from the PBVH */ - for (j = 0; j < 3; j++) { + for (int j = 0; j < 3; j++) { if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) { BLI_gset_insert(deleted_verts, v_tri[j]); pbvh_bmesh_vert_remove(bvh, v_tri[j]); @@ -1291,17 +1239,13 @@ static bool pbvh_bmesh_collapse_short_edges( PBVH *bvh, BLI_Buffer *deleted_faces) { - float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; - GSet *deleted_verts; + const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; bool any_collapsed = false; - - deleted_verts = BLI_gset_ptr_new("deleted_verts"); + GSet *deleted_verts = BLI_gset_ptr_new("deleted_verts"); while (!BLI_heap_is_empty(eq_ctx->q->heap)) { BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap); BMVert *v1 = pair[0], *v2 = pair[1]; - BMEdge *e; - BLI_mempool_free(eq_ctx->pool, pair); pair = NULL; @@ -1313,6 +1257,7 @@ static bool pbvh_bmesh_collapse_short_edges( } /* Check that the edge still exists */ + BMEdge *e; if (!(e = BM_edge_exists(v1, v2))) { continue; } @@ -1355,8 +1300,7 @@ bool pbvh_bmesh_node_raycast( bool hit = false; if (use_original && node->bm_tot_ortri) { - int i; - for (i = 0; i < node->bm_tot_ortri; i++) { + for (int i = 0; i < node->bm_tot_ortri; i++) { const int *t = node->bm_ortri[i]; hit |= ray_face_intersection_tri( ray_start, ray_normal, @@ -1395,13 +1339,13 @@ bool BKE_pbvh_bmesh_node_raycast_detail( const float ray_start[3], const float ray_normal[3], float *dist, float *r_detail) { + if (node->flag & PBVH_FullyHidden) + return 0; + GSetIterator gs_iter; bool hit = false; BMFace *f_hit = NULL; - if (node->flag & PBVH_FullyHidden) - return 0; - GSET_ITER (gs_iter, node->bm_faces) { BMFace *f = BLI_gsetIterator_getKey(&gs_iter); @@ -1425,12 +1369,11 @@ bool BKE_pbvh_bmesh_node_raycast_detail( } if (hit) { - float len1, len2, len3; BMVert *v_tri[3]; BM_face_as_array_vert_tri(f_hit, v_tri); - len1 = len_squared_v3v3(v_tri[0]->co, v_tri[1]->co); - len2 = len_squared_v3v3(v_tri[1]->co, v_tri[2]->co); - len3 = len_squared_v3v3(v_tri[2]->co, v_tri[0]->co); + float len1 = len_squared_v3v3(v_tri[0]->co, v_tri[1]->co); + float len2 = len_squared_v3v3(v_tri[1]->co, v_tri[2]->co); + float len3 = len_squared_v3v3(v_tri[2]->co, v_tri[0]->co); /* detail returned will be set to the maximum allowed size, so take max here */ *r_detail = sqrtf(max_fff(len1, len2, len3)); @@ -1442,9 +1385,7 @@ bool BKE_pbvh_bmesh_node_raycast_detail( void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode) { - int n; - - for (n = 0; n < totnode; n++) { + for (int n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; if (node->flag & PBVH_UpdateNormals) { @@ -1476,25 +1417,18 @@ typedef struct FastNodeBuildInfo { * to a sub part of the arrays */ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena) { - BMFace *f; - BB cb; - BBC *bbc; - float mid; - int axis, i; - int end; FastNodeBuildInfo *child1, *child2; - int num_child1, num_child2; - BMFace *tmp; if (node->totface <= bvh->leaf_limit) { return; } /* Calculate bounding box around primitive centroids */ + BB cb; BB_reset(&cb); - for (i = 0; i < node->totface; i++) { - f = nodeinfo[i + node->start]; - bbc = &bbc_array[BM_elem_index_get(f)]; + for (int i = 0; i < node->totface; i++) { + BMFace *f = nodeinfo[i + node->start]; + BBC *bbc = &bbc_array[BM_elem_index_get(f)]; BB_expand(&cb, bbc->bcentroid); } @@ -1502,16 +1436,16 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC /* initialize the children */ /* Find widest axis and its midpoint */ - axis = BB_widest_axis(&cb); - mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f; + const int axis = BB_widest_axis(&cb); + const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f; - num_child1 = 0, num_child2 = 0; + int num_child1 = 0, num_child2 = 0; /* split vertices along the middle line */ - end = node->start + node->totface; - for (i = node->start; i < end - num_child2; i++) { - f = nodeinfo[i]; - bbc = &bbc_array[BM_elem_index_get(f)]; + const int end = node->start + node->totface; + for (int i = node->start; i < end - num_child2; i++) { + BMFace *f = nodeinfo[i]; + BBC *bbc = &bbc_array[BM_elem_index_get(f)]; if (bbc->bcentroid[axis] > mid) { int i_iter = end - num_child2 - 1; @@ -1531,7 +1465,7 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC } if (candidate != -1) { - tmp = nodeinfo[i]; + BMFace *tmp = nodeinfo[i]; nodeinfo[i] = nodeinfo[candidate]; nodeinfo[candidate] = tmp; /* increase both counts */ @@ -1574,8 +1508,6 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child1, arena); pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena); - - return; } static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index) @@ -1605,12 +1537,6 @@ static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, const int cd_face_node_offset = bvh->cd_face_node_offset; bool has_visible = false; - int i, end; - BMFace *f; - BMLoop *l_iter; - BMLoop *l_first; - BMVert *v; - BBC *bbc; n->flag = PBVH_Leaf; n->bm_faces = BLI_gset_ptr_new_ex("bm_faces", node->totface); @@ -1621,20 +1547,21 @@ static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BB_reset(&n->vb); - end = node->start + node->totface; + const int end = node->start + node->totface; - for (i = node->start; i < end; i++) { - f = nodeinfo[i]; - bbc = &bbc_array[BM_elem_index_get(f)]; + for (int i = node->start; i < end; i++) { + BMFace *f = nodeinfo[i]; + BBC *bbc = &bbc_array[BM_elem_index_get(f)]; /* Update ownership of faces */ BLI_gset_insert(n->bm_faces, f); BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index); /* Update vertices */ - l_iter = l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; do { - v = l_iter->v; + BMVert *v = l_iter->v; if (!BLI_gset_haskey(n->bm_unique_verts, v)) { if (BM_ELEM_CD_GET_INT(v, cd_vert_node_offset) != DYNTOPO_NODE_NONE) { BLI_gset_add(n->bm_other_verts, v); @@ -1654,8 +1581,8 @@ static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, } BLI_assert(n->vb.bmin[0] <= n->vb.bmax[0] && - n->vb.bmin[1] <= n->vb.bmax[1] && - n->vb.bmin[2] <= n->vb.bmax[2]); + n->vb.bmin[1] <= n->vb.bmax[1] && + n->vb.bmin[2] <= n->vb.bmax[2]); n->orig_vb = n->vb; @@ -1675,16 +1602,6 @@ void BKE_pbvh_build_bmesh( PBVH *bvh, BMesh *bm, bool smooth_shading, BMLog *log, const int cd_vert_node_offset, const int cd_face_node_offset) { - BMIter iter; - BMFace *f; - BMVert *v; - int i; - /* bounding box array of all faces, no need to recalculate every time */ - BBC *bbc_array; - BMFace **nodeinfo; - FastNodeBuildInfo rootnode = {0}; - MemArena *arena; - bvh->cd_vert_node_offset = cd_vert_node_offset; bvh->cd_face_node_offset = cd_face_node_offset; bvh->bm = bm; @@ -1700,18 +1617,20 @@ void BKE_pbvh_build_bmesh( if (smooth_shading) bvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING; - /* calculate all bounding boxes once for all faces */ - bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC"); - nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo"); - arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage"); + /* bounding box array of all faces, no need to recalculate every time */ + BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm->totface, "BBC"); + BMFace **nodeinfo = MEM_mallocN(sizeof(*nodeinfo) * bm->totface, "nodeinfo"); + MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage"); + BMIter iter; + BMFace *f; + int i; BM_ITER_MESH_INDEX(f, &iter, bm, BM_FACES_OF_MESH, i) { BBC *bbc = &bbc_array[i]; - BMLoop *l_iter; - BMLoop *l_first; + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; BB_reset((BB *)bbc); - l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { BB_expand((BB *)bbc, l_iter->v->co); } while ((l_iter = l_iter->next) != l_first); @@ -1723,6 +1642,7 @@ void BKE_pbvh_build_bmesh( BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE); } + BMVert *v; BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) { BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE); } @@ -1731,6 +1651,7 @@ void BKE_pbvh_build_bmesh( bm->elem_index_dirty |= BM_FACE; /* setup root node */ + FastNodeBuildInfo rootnode = {0}; rootnode.totface = bm->totface; /* start recursion, assign faces to nodes accordingly */ @@ -1764,7 +1685,6 @@ bool BKE_pbvh_bmesh_update_topology( const int cd_face_node_offset = bvh->cd_face_node_offset; bool modified = false; - int n; if (view_normal) { BLI_assert(len_squared_v3(view_normal) != 0.0f); @@ -1796,7 +1716,7 @@ bool BKE_pbvh_bmesh_update_topology( } /* Unmark nodes */ - for (n = 0; n < bvh->totnode; n++) { + for (int n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; if (node->flag & PBVH_Leaf && @@ -1832,23 +1752,21 @@ BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3]) * Skips triangles that are hidden. */ void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node) { - GSetIterator gs_iter; - int i, totvert, tottri; - /* Skip if original coords/triangles are already saved */ if (node->bm_orco) return; - totvert = (BLI_gset_size(node->bm_unique_verts) + - BLI_gset_size(node->bm_other_verts)); + const int totvert = BLI_gset_size(node->bm_unique_verts) + + BLI_gset_size(node->bm_other_verts); - tottri = BLI_gset_size(node->bm_faces); + const int tottri = BLI_gset_size(node->bm_faces); node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__); node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, __func__); /* Copy out the vertices and assign a temporary index */ - i = 0; + int i = 0; + GSetIterator gs_iter; GSET_ITER (gs_iter, node->bm_unique_verts) { BMVert *v = BLI_gsetIterator_getKey(&gs_iter); copy_v3_v3(node->bm_orco[i], v->co); @@ -1888,9 +1806,7 @@ void BKE_pbvh_bmesh_node_save_orig(PBVHNode *node) void BKE_pbvh_bmesh_after_stroke(PBVH *bvh) { - int i; - - for (i = 0; i < bvh->totnode; i++) { + for (int i = 0; i < bvh->totnode; i++) { PBVHNode *n = &bvh->nodes[i]; if (n->flag & PBVH_Leaf) { /* Free orco/ortri data */ @@ -1935,15 +1851,11 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node) static void pbvh_bmesh_print(PBVH *bvh) { - GSetIterator gs_iter; - int n; - BMIter iter; - BMFace *f; - BMVert *v; - fprintf(stderr, "\npbvh=%p\n", bvh); fprintf(stderr, "bm_face_to_node:\n"); + BMIter iter; + BMFace *f; BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), @@ -1951,17 +1863,19 @@ static void pbvh_bmesh_print(PBVH *bvh) } fprintf(stderr, "bm_vert_to_node:\n"); + BMVert *v; BM_ITER_MESH(v, &iter, bvh->bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_lookup_index(bvh, v)); } - for (n = 0; n < bvh->totnode; n++) { + for (int n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; if (!(node->flag & PBVH_Leaf)) continue; + GSetIterator gs_iter; fprintf(stderr, "node %d\n faces:\n", n); GSET_ITER (gs_iter, node->bm_faces) fprintf(stderr, " %d\n", @@ -1979,9 +1893,8 @@ static void pbvh_bmesh_print(PBVH *bvh) static void print_flag_factors(int flag) { - int i; printf("flag=0x%x:\n", flag); - for (i = 0; i < 32; i++) { + for (int i = 0; i < 32; i++) { if (flag & (1 << i)) { printf(" %d (1 << %d)\n", 1 << i, i); } @@ -1994,23 +1907,16 @@ static void print_flag_factors(int flag) static void pbvh_bmesh_verify(PBVH *bvh) { - GSetIterator gs_iter; - int i; - BMIter iter; - BMFace *f; - BMVert *v; - - GSet *faces_all; - GSet *verts_all; - - /* build list of faces & verts to lookup */ - faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface); - verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert); - + GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface); + BMFace *f; + BMIter iter; BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { BLI_gset_insert(faces_all, f); } + + GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert); + BMVert *v; BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) { BLI_gset_insert(verts_all, v); @@ -2020,7 +1926,7 @@ static void pbvh_bmesh_verify(PBVH *bvh) /* Check vert/face counts */ { int totface = 0, totvert = 0; - for (i = 0; i < bvh->totnode; i++) { + for (int i = 0; i < bvh->totnode; i++) { PBVHNode *n = &bvh->nodes[i]; totface += n->bm_faces ? BLI_gset_size(n->bm_faces) : 0; totvert += n->bm_unique_verts ? BLI_gset_size(n->bm_unique_verts) : 0; @@ -2062,16 +1968,12 @@ static void pbvh_bmesh_verify(PBVH *bvh) /* Check verts */ BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { - BMIter bm_iter; - PBVHNode *n; - bool found; - /* vertex isn't tracked */ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) { continue; } - n = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v); /* Check that the vert's node is a leaf */ BLI_assert(n->flag & PBVH_Leaf); @@ -2084,6 +1986,8 @@ static void pbvh_bmesh_verify(PBVH *bvh) /* Check that the vert's node also contains one of the vert's * adjacent faces */ + bool found = false; + BMIter bm_iter; BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { if (pbvh_bmesh_node_lookup(bvh, f) == n) { found = true; @@ -2095,13 +1999,12 @@ static void pbvh_bmesh_verify(PBVH *bvh) #if 1 /* total freak stuff, check if node exists somewhere else */ /* Slow */ - for (i = 0; i < bvh->totnode; i++) { + for (int i = 0; i < bvh->totnode; i++) { PBVHNode *n_other = &bvh->nodes[i]; if ((n != n_other) && (n_other->bm_unique_verts)) { BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v)); } } - #endif } @@ -2110,7 +2013,7 @@ static void pbvh_bmesh_verify(PBVH *bvh) /* Slow */ BM_ITER_MESH (vi, &iter, bvh->bm, BM_VERTS_OF_MESH) { bool has_unique = false; - for (i = 0; i < bvh->totnode; i++) { + for (int i = 0; i < bvh->totnode; i++) { PBVHNode *n = &bvh->nodes[i]; if ((n->bm_unique_verts != NULL) && BLI_gset_haskey(n->bm_unique_verts, vi)) has_unique = true; @@ -2124,9 +2027,10 @@ static void pbvh_bmesh_verify(PBVH *bvh) #endif /* Check that node elements are recorded in the top level */ - for (i = 0; i < bvh->totnode; i++) { + for (int i = 0; i < bvh->totnode; i++) { PBVHNode *n = &bvh->nodes[i]; if (n->flag & PBVH_Leaf) { + GSetIterator gs_iter; GSET_ITER (gs_iter, n->bm_faces) { BMFace *f = BLI_gsetIterator_getKey(&gs_iter); diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index a87935ae23b..7c420549a0d 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -91,6 +91,8 @@ # include AUD_SPECIAL_H #endif +#define USE_SCENE_RECURSIVE_HACK + static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seqbasep, float cfra, int chanshown); static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, float cfra); static void seq_free_animdata(Scene *scene, Sequence *seq); @@ -1149,6 +1151,33 @@ const char *BKE_sequence_give_name(Sequence *seq) return name; } +ListBase *BKE_sequence_seqbase_get(Sequence *seq, int *r_offset) +{ + ListBase *seqbase = NULL; + + switch (seq->type) { + case SEQ_TYPE_META: + { + seqbase = &seq->seqbase; + *r_offset = seq->start; + break; + } + case SEQ_TYPE_SCENE: + { + if (seq->flag & SEQ_SCENE_STRIPS) { + Editing *ed = BKE_sequencer_editing_get(seq->scene, false); + if (ed) { + seqbase = &ed->seqbase; + *r_offset = seq->scene->r.sfra; + } + } + break; + } + } + + return seqbase; +} + /*********************** DO THE SEQUENCE *************************/ static void make_black_ibuf(ImBuf *ibuf) @@ -3319,6 +3348,40 @@ finally: return ibuf; } +/** + * Used for meta-strips & scenes with #SEQ_SCENE_STRIPS flag set. + */ +static ImBuf *do_render_strip_seqbase( + const SeqRenderData *context, Sequence *seq, float nr, + bool use_preprocess) +{ + ImBuf *meta_ibuf = NULL, *ibuf = NULL; + ListBase *seqbase = NULL; + int offset; + + seqbase = BKE_sequence_seqbase_get(seq, &offset); + + if (seqbase && !BLI_listbase_is_empty(seqbase)) { + meta_ibuf = seq_render_strip_stack( + context, seqbase, + /* scene strips don't have their start taken into account */ + nr + offset, 0); + } + + if (meta_ibuf) { + ibuf = meta_ibuf; + if (ibuf && use_preprocess) { + ImBuf *i = IMB_dupImBuf(ibuf); + + IMB_freeImBuf(ibuf); + + ibuf = i; + } + } + + return ibuf; +} + static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *seq, float cfra) { ImBuf *ibuf = NULL; @@ -3329,22 +3392,38 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s switch (type) { case SEQ_TYPE_META: { - ImBuf *meta_ibuf = NULL; - - if (seq->seqbase.first) - meta_ibuf = seq_render_strip_stack(context, &seq->seqbase, seq->start + nr, 0); + ibuf = do_render_strip_seqbase(context, seq, nr, use_preprocess); + break; + } - if (meta_ibuf) { - ibuf = meta_ibuf; - if (ibuf && use_preprocess) { - ImBuf *i = IMB_dupImBuf(ibuf); + case SEQ_TYPE_SCENE: + { + if (seq->flag & SEQ_SCENE_STRIPS) { + if (seq->scene && (context->scene != seq->scene)) { +#ifdef USE_SCENE_RECURSIVE_HACK + /* weak recusrive check, same as T32017 */ + if (seq->scene->id.flag & LIB_DOIT) { + break; + } + seq->scene->id.flag |= LIB_DOIT; +#endif - IMB_freeImBuf(ibuf); + ibuf = do_render_strip_seqbase(context, seq, nr, use_preprocess); - ibuf = i; +#ifdef USE_SCENE_RECURSIVE_HACK + seq->scene->id.flag &= ~LIB_DOIT; +#endif } } + else { + /* scene can be NULL after deletions */ + ibuf = seq_render_scene_strip(context, seq, nr, cfra); + /* Scene strips update all animation, so we need to restore original state.*/ + BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra); + + copy_to_ibuf_still(context, seq, nr, ibuf); + } break; } @@ -3395,18 +3474,6 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s break; } - case SEQ_TYPE_SCENE: - { - /* scene can be NULL after deletions */ - ibuf = seq_render_scene_strip(context, seq, nr, cfra); - - /* Scene strips update all animation, so we need to restore original state.*/ - BKE_animsys_evaluate_all_animation(context->bmain, context->scene, cfra); - - copy_to_ibuf_still(context, seq, nr, ibuf); - break; - } - case SEQ_TYPE_MOVIECLIP: { ibuf = seq_render_movieclip_strip(context, seq, nr); @@ -3731,6 +3798,10 @@ ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int cha seqbasep = ed->seqbasep; } +#ifdef USE_SCENE_RECURSIVE_HACK + BKE_main_id_tag_idcode(context->bmain, ID_SCE, false); +#endif + return seq_render_strip_stack(context, seqbasep, cfra, chanshown); } @@ -4348,7 +4419,7 @@ bool BKE_sequence_base_shuffle_ex(ListBase *seqbasep, Sequence *test, Scene *evi test->machine += channel_delta; BKE_sequence_calc(evil_scene, test); while (BKE_sequence_test_overlap(seqbasep, test)) { - if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine <= 1)) { + if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) { break; } diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 86ffb541bf8..1c3ff3d3e02 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -81,7 +81,6 @@ variables on the UI for now #include "BKE_scene.h" #include "PIL_time.h" -// #include "ONL_opennl.h" remove linking to ONL for now /* callbacks for errors and interrupts and some goo */ static int (*SB_localInterruptCallBack)(void) = NULL; @@ -1811,14 +1810,14 @@ static void dfdx_spring(int ia, int ic, int op, float dir[3], float L, float len for (j=0;j<3;j++) { delta_ij = (i==j ? (1.0f): (0.0f)); m=factor*(dir[i]*dir[j] + (1-L/len)*(delta_ij - dir[i]*dir[j])); - nlMatrixAdd(ia+i, op+ic+j, m); + EIG_linear_solver_matrix_add(ia+i, op+ic+j, m); } } else { for (i=0;i<3;i++) for (j=0;j<3;j++) { m=factor*dir[i]*dir[j]; - nlMatrixAdd(ia+i, op+ic+j, m); + EIG_linear_solver_matrix_add(ia+i, op+ic+j, m); } } } @@ -1827,13 +1826,13 @@ static void dfdx_spring(int ia, int ic, int op, float dir[3], float L, float len static void dfdx_goal(int ia, int ic, int op, float factor) { int i; - for (i=0;i<3;i++) nlMatrixAdd(ia+i, op+ic+i, factor); + for (i=0;i<3;i++) EIG_linear_solver_matrix_add(ia+i, op+ic+i, factor); } static void dfdv_goal(int ia, int ic, float factor) { int i; - for (i=0;i<3;i++) nlMatrixAdd(ia+i, ic+i, factor); + for (i=0;i<3;i++) EIG_linear_solver_matrix_add(ia+i, ic+i, factor); } */ static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, float UNUSED(forcetime)) diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 7ff292efd8a..53da38b2da8 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -74,9 +74,9 @@ #endif #include "GPU_draw.h" -#include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_buffers.h" +#include "GPU_shader.h" #include "CCGSubSurf.h" @@ -2810,8 +2810,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, CCG_key_top_level(&key, ss); ccgdm_pbvh_update(ccgdm); - if (setDrawOptions != NULL) - { + if (setDrawOptions != NULL) { const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL); DMVertexAttribs attribs = {{{NULL}}}; int i; diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index a81fee2cdb7..9503da6e53e 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -116,14 +116,14 @@ BLI_INLINE bool BLI_ghashIterator_done(GHashIterator *ghi) { return !ghi # define _gh_Entry void #endif -#define GHASH_ITER(gh_iter_, ghash_) \ - for (BLI_ghashIterator_init(&gh_iter_, ghash_); \ - BLI_ghashIterator_done(&gh_iter_) == false; \ +#define GHASH_ITER(gh_iter_, ghash_) \ + for (BLI_ghashIterator_init(&gh_iter_, ghash_); \ + BLI_ghashIterator_done(&gh_iter_) == false; \ BLI_ghashIterator_step(&gh_iter_)) -#define GHASH_ITER_INDEX(gh_iter_, ghash_, i_) \ - for (BLI_ghashIterator_init(&gh_iter_, ghash_), i_ = 0; \ - BLI_ghashIterator_done(&gh_iter_) == false; \ +#define GHASH_ITER_INDEX(gh_iter_, ghash_, i_) \ + for (BLI_ghashIterator_init(&gh_iter_, ghash_), i_ = 0; \ + BLI_ghashIterator_done(&gh_iter_) == false; \ BLI_ghashIterator_step(&gh_iter_), i_++) /** \name Callbacks for GHash @@ -249,14 +249,14 @@ BLI_INLINE void *BLI_gsetIterator_getKey(GSetIterator *gsi) { return BLI_ghashIt BLI_INLINE void BLI_gsetIterator_step(GSetIterator *gsi) { BLI_ghashIterator_step((GHashIterator *)gsi); } BLI_INLINE bool BLI_gsetIterator_done(GSetIterator *gsi) { return BLI_ghashIterator_done((GHashIterator *)gsi); } -#define GSET_ITER(gs_iter_, gset_) \ - for (BLI_gsetIterator_init(&gs_iter_, gset_); \ - BLI_gsetIterator_done(&gs_iter_) == false; \ +#define GSET_ITER(gs_iter_, gset_) \ + for (BLI_gsetIterator_init(&gs_iter_, gset_); \ + BLI_gsetIterator_done(&gs_iter_) == false; \ BLI_gsetIterator_step(&gs_iter_)) -#define GSET_ITER_INDEX(gs_iter_, gset_, i_) \ - for (BLI_gsetIterator_init(&gs_iter_, gset_), i_ = 0; \ - BLI_gsetIterator_done(&gs_iter_) == false; \ +#define GSET_ITER_INDEX(gs_iter_, gset_, i_) \ + for (BLI_gsetIterator_init(&gs_iter_, gset_), i_ = 0; \ + BLI_gsetIterator_done(&gs_iter_) == false; \ BLI_gsetIterator_step(&gs_iter_), i_++) diff --git a/source/blender/blenlib/BLI_kdtree.h b/source/blender/blenlib/BLI_kdtree.h index d488dbce1fd..aa54e1c823c 100644 --- a/source/blender/blenlib/BLI_kdtree.h +++ b/source/blender/blenlib/BLI_kdtree.h @@ -58,6 +58,10 @@ int BLI_kdtree_find_nearest( #define BLI_kdtree_range_search(tree, co, r_nearest, range) \ BLI_kdtree_range_search__normal(tree, co, NULL, r_nearest, range) +int BLI_kdtree_find_nearest_cb( + const KDTree *tree, const float co[3], + int (*filter_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data, + KDTreeNearest *r_nearest); void BLI_kdtree_range_search_cb( const KDTree *tree, const float co[3], float range, bool (*search_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data); diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h index 67cb30e8d17..367f1bb9de5 100644 --- a/source/blender/blenlib/BLI_linklist.h +++ b/source/blender/blenlib/BLI_linklist.h @@ -58,8 +58,8 @@ typedef struct LinkNodePair { LinkNode *list, *last_node; } LinkNodePair; -int BLI_linklist_count(LinkNode *list) ATTR_WARN_UNUSED_RESULT; -int BLI_linklist_index(LinkNode *list, void *ptr) ATTR_WARN_UNUSED_RESULT; +int BLI_linklist_count(const LinkNode *list) ATTR_WARN_UNUSED_RESULT; +int BLI_linklist_index(const LinkNode *list, void *ptr) ATTR_WARN_UNUSED_RESULT; LinkNode *BLI_linklist_find(LinkNode *list, int index) ATTR_WARN_UNUSED_RESULT; @@ -91,5 +91,7 @@ LinkNode *BLI_linklist_sort_r(LinkNode *list, int (*cmp)(void *, const void *, c #define BLI_linklist_prepend_alloca(listp, ptr) \ BLI_linklist_prepend_nlink(listp, ptr, alloca(sizeof(LinkNode))) +#define BLI_linklist_append_alloca(list_pair, ptr) \ + BLI_linklist_append_nlink(list_pair, ptr, alloca(sizeof(LinkNode))) #endif /* __BLI_LINKLIST_H__ */ diff --git a/source/blender/blenlib/BLI_linklist_stack.h b/source/blender/blenlib/BLI_linklist_stack.h index c5f9be927d3..dd92dcec936 100644 --- a/source/blender/blenlib/BLI_linklist_stack.h +++ b/source/blender/blenlib/BLI_linklist_stack.h @@ -161,7 +161,7 @@ (_BLI_SMALLSTACK_CAST(var_src) ((_##var_src##_stack) ? \ (_BLI_SMALLSTACK_DEL_EX(var_src, var_dst), (_##var_dst##_free->link)) : NULL)) -#define BLI_SMALLSTACK_LAST(var) \ +#define BLI_SMALLSTACK_PEEK(var) \ (_BLI_SMALLSTACK_CAST(var) ((_##var##_stack) ? \ _##var##_stack->link : NULL)) diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index d804b57ffe1..b0421c39707 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -244,6 +244,11 @@ bool isect_ray_tri_watertight_v3_simple( const float v0[3], const float v1[3], const float v2[3], float *r_lambda, float r_uv[2]); +bool isect_ray_seg_v2( + const float p1[3], const float d[3], + const float v0[3], const float v1[3], + float *r_lambda, float *r_u); + /* point in polygon */ bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr, const bool use_holes); bool isect_point_poly_v2_int(const int pt[2], const int verts[][2], const unsigned int nr, const bool use_holes); @@ -417,7 +422,8 @@ void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3]); MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3]); MINLINE float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axis[3]) ATTR_WARN_UNUSED_RESULT; -MINLINE int axis_dominant_v3_single(const float vec[3]); +MINLINE int axis_dominant_v3_single(const float vec[3]); +MINLINE int axis_dominant_v3_ortho_single(const float vec[3]); MINLINE int max_axis_v3(const float vec[3]); MINLINE int min_axis_v3(const float vec[3]); diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 5900e391d3e..6fb983a622e 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -173,6 +173,10 @@ bool is_orthonormal_m4(float mat[4][4]); bool is_uniform_scaled_m3(float mat[3][3]); bool is_uniform_scaled_m4(float m[4][4]); +/* Note: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix! + * Nowadays 'adjoint' usually refers to the conjugate transpose, + * which for real-valued matrices is simply the transpose. + */ void adjoint_m2_m2(float R[2][2], float A[2][2]); void adjoint_m3_m3(float R[3][3], float A[3][3]); void adjoint_m4_m4(float R[4][4], float A[4][4]); diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index 81c277cd956..45a6e0b02c1 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -112,10 +112,12 @@ ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool); size_t BLI_task_pool_tasks_done(TaskPool *pool); /* Parallel for routines */ -typedef void (*TaskParallelRangeFunc)(void *userdata, int iter); +typedef void (*TaskParallelRangeFunc)(void *userdata, void *userdata_chunk, int iter); void BLI_task_parallel_range_ex( int start, int stop, void *userdata, + void *userdata_chunk, + const size_t userdata_chunk_size, TaskParallelRangeFunc func, const int range_threshold, const bool use_dynamic_scheduling); diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h index 8cf6f188e19..b421b7dbb90 100644 --- a/source/blender/blenlib/BLI_winstuff.h +++ b/source/blender/blenlib/BLI_winstuff.h @@ -90,7 +90,9 @@ extern "C" { #endif /* defines for using ISO C++ conformant names */ -#define snprintf _snprintf +#if !defined(_MSC_VER) || _MSC_VER < 1900 +# define snprintf _snprintf +#endif #if defined(_MSC_VER) || (defined(FREE_WINDOWS) && !defined(FREE_WINDOWS64)) # define R_OK 4 diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 0de614a5ca7..944ba60eb58 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -29,8 +29,8 @@ set(INC ../makesdna ../../../intern/guardedalloc ../../../intern/atomic + ../../../intern/eigen ../../../extern/wcwidth - ../../../extern/Eigen3 ) set(INC_SYS diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript index 0e4b9bf4efd..5f92741fde2 100644 --- a/source/blender/blenlib/SConscript +++ b/source/blender/blenlib/SConscript @@ -34,9 +34,9 @@ cflags='' incs = [ '.', '#/extern/wcwidth', - '#/extern/Eigen3', '#/intern/guardedalloc', '#/intern/atomic', + '#/intern/eigen', '../makesdna', env['BF_FREETYPE_INC'], env['BF_ZLIB_INC'], diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index 7e6dabdffef..29b07b37932 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -155,7 +155,7 @@ BLI_INLINE unsigned int ghash_entryhash(GHash *gh, const Entry *e) } /** - * Get the bucket-hash for an already-computed full hash. + * Get the bucket-index for an already-computed full hash. */ BLI_INLINE unsigned int ghash_bucket_index(GHash *gh, const unsigned int hash) { @@ -175,7 +175,6 @@ static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets) Entry **buckets_new; const unsigned int nbuckets_old = gh->nbuckets; unsigned int i; - Entry *e; BLI_assert((gh->nbuckets != nbuckets) || !gh->buckets); // printf("%s: %d -> %d\n", __func__, nbuckets_old, nbuckets); @@ -191,8 +190,7 @@ static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets) if (buckets_old) { if (nbuckets > nbuckets_old) { for (i = 0; i < nbuckets_old; i++) { - Entry *e_next; - for (e = buckets_old[i]; e; e = e_next) { + for (Entry *e = buckets_old[i], *e_next; e; e = e_next) { const unsigned hash = ghash_entryhash(gh, e); const unsigned bucket_index = ghash_bucket_index(gh, hash); e_next = e->next; @@ -204,8 +202,7 @@ static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets) else { for (i = 0; i < nbuckets_old; i++) { #ifdef GHASH_USE_MODULO_BUCKETS - Entry *e_next; - for (e = buckets_old[i]; e; e = e_next) { + for (Entry *e = buckets_old[i], *e_next; e; e = e_next) { const unsigned hash = ghash_entryhash(gh, e); const unsigned bucket_index = ghash_bucket_index(gh, hash); e_next = e->next; @@ -217,6 +214,7 @@ static void ghash_buckets_resize(GHash *gh, const unsigned int nbuckets) * will go in same new bucket (i & new_mask)! */ const unsigned bucket_index = ghash_bucket_index(gh, i); BLI_assert(!buckets_old[i] || (bucket_index == ghash_bucket_index(gh, ghash_entryhash(gh, buckets_old[i])))); + Entry *e; for (e = buckets_old[i]; e && e->next; e = e->next); if (e) { e->next = buckets_new[bucket_index]; @@ -376,17 +374,16 @@ BLI_INLINE Entry *ghash_lookup_entry_ex( /** * Internal lookup function, returns previous entry of target one too. - * Takes hash and bucket_index arguments to avoid calling #ghash_keyhash and #ghash_bucket_index multiple times. + * Takes bucket_index argument to avoid calling #ghash_keyhash and #ghash_bucket_index multiple times. * Useful when modifying buckets somehow (like removing an entry...). */ BLI_INLINE Entry *ghash_lookup_entry_prev_ex( - GHash *gh, const void *key, Entry **r_e_prev, const unsigned int bucket_index) + GHash *gh, const void *key, + Entry **r_e_prev, const unsigned int bucket_index) { - Entry *e, *e_prev = NULL; - /* If we do not store GHash, not worth computing it for each entry here! * Typically, comparison function will be quicker, and since it's needed in the end anyway... */ - for (e = gh->buckets[bucket_index]; e; e_prev = e, e = e->next) { + for (Entry *e_prev = NULL, *e = gh->buckets[bucket_index]; e; e_prev = e, e = e->next) { if (UNLIKELY(gh->cmpfp(key, e->key) == false)) { *r_e_prev = e_prev; return e; @@ -487,7 +484,8 @@ BLI_INLINE void ghash_insert(GHash *gh, void *key, void *val) } BLI_INLINE bool ghash_insert_safe( - GHash *gh, void *key, void *val, const bool override, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) + GHash *gh, void *key, void *val, const bool override, + GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) { const unsigned int hash = ghash_keyhash(gh, key); const unsigned int bucket_index = ghash_bucket_index(gh, hash); @@ -497,8 +495,12 @@ BLI_INLINE bool ghash_insert_safe( if (e) { if (override) { - if (keyfreefp) keyfreefp(e->e.key); - if (valfreefp) valfreefp(e->val); + if (keyfreefp) { + keyfreefp(e->e.key); + } + if (valfreefp) { + valfreefp(e->val); + } e->e.key = key; e->val = val; } @@ -510,7 +512,9 @@ BLI_INLINE bool ghash_insert_safe( } } -BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool override, GHashKeyFreeFP keyfreefp) +BLI_INLINE bool ghash_insert_safe_keyonly( + GHash *gh, void *key, const bool override, + GHashKeyFreeFP keyfreefp) { const unsigned int hash = ghash_keyhash(gh, key); const unsigned int bucket_index = ghash_bucket_index(gh, hash); @@ -520,7 +524,9 @@ BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool overr if (e) { if (override) { - if (keyfreefp) keyfreefp(e->key); + if (keyfreefp) { + keyfreefp(e->key); + } e->key = key; } return false; @@ -535,7 +541,8 @@ BLI_INLINE bool ghash_insert_safe_keyonly(GHash *gh, void *key, const bool overr * Remove the entry and return it, caller must free from gh->entrypool. */ static Entry *ghash_remove_ex( - GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, + GHash *gh, const void *key, + GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp, const unsigned int bucket_index) { Entry *e_prev; @@ -544,11 +551,19 @@ static Entry *ghash_remove_ex( BLI_assert(!valfreefp || !(gh->flag & GHASH_FLAG_IS_GSET)); if (e) { - if (keyfreefp) keyfreefp(e->key); - if (valfreefp) valfreefp(((GHashEntry *)e)->val); + if (keyfreefp) { + keyfreefp(e->key); + } + if (valfreefp) { + valfreefp(((GHashEntry *)e)->val); + } - if (e_prev) e_prev->next = e->next; - else gh->buckets[bucket_index] = e->next; + if (e_prev) { + e_prev->next = e->next; + } + else { + gh->buckets[bucket_index] = e->next; + } ghash_buckets_contract(gh, --gh->nentries, false, false); } @@ -559,7 +574,9 @@ static Entry *ghash_remove_ex( /** * Run free callbacks for freeing entries. */ -static void ghash_free_cb(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) +static void ghash_free_cb( + GHash *gh, + GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) { unsigned int i; @@ -570,8 +587,12 @@ static void ghash_free_cb(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP va Entry *e; for (e = gh->buckets[i]; e; e = e->next) { - if (keyfreefp) keyfreefp(e->key); - if (valfreefp) valfreefp(((GHashEntry *)e)->val); + if (keyfreefp) { + keyfreefp(e->key); + } + if (valfreefp) { + valfreefp(((GHashEntry *)e)->val); + } } } } diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c index fe822816be4..a81f9b28b83 100644 --- a/source/blender/blenlib/intern/BLI_kdtree.c +++ b/source/blender/blenlib/intern/BLI_kdtree.c @@ -291,6 +291,112 @@ int BLI_kdtree_find_nearest( return min_node->index; } + +/** + * A version of #BLI_kdtree_find_nearest which runs a callback + * to filter out values. + * + * \param filter_cb: Filter find results, + * Return codes: (1: accept, 0: skip, -1: immediate exit). + */ +int BLI_kdtree_find_nearest_cb( + const KDTree *tree, const float co[3], + int (*filter_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data, + KDTreeNearest *r_nearest) +{ + const KDTreeNode *nodes = tree->nodes; + const KDTreeNode *min_node = NULL; + + unsigned int *stack, defaultstack[KD_STACK_INIT]; + float min_dist = FLT_MAX, cur_dist; + unsigned int totstack, cur = 0; + +#ifdef DEBUG + BLI_assert(tree->is_balanced == true); +#endif + + if (UNLIKELY(tree->root == KD_NODE_UNSET)) + return -1; + + stack = defaultstack; + totstack = KD_STACK_INIT; + +#define NODE_TEST_NEAREST(node) \ +{ \ + const float dist_sq = len_squared_v3v3((node)->co, co); \ + if (dist_sq < min_dist) { \ + const int result = filter_cb(user_data, (node)->index, (node)->co, dist_sq); \ + if (result == 1) { \ + min_dist = dist_sq; \ + min_node = node; \ + } \ + else if (result == 0) { \ + /* pass */ \ + } \ + else { \ + BLI_assert(result == -1); \ + goto finally; \ + } \ + } \ +} ((void)0) + + stack[cur++] = tree->root; + + while (cur--) { + const KDTreeNode *node = &nodes[stack[cur]]; + + cur_dist = node->co[node->d] - co[node->d]; + + if (cur_dist < 0.0f) { + cur_dist = -cur_dist * cur_dist; + + if (-cur_dist < min_dist) { + NODE_TEST_NEAREST(node); + + if (node->left != KD_NODE_UNSET) + stack[cur++] = node->left; + } + if (node->right != KD_NODE_UNSET) + stack[cur++] = node->right; + } + else { + cur_dist = cur_dist * cur_dist; + + if (cur_dist < min_dist) { + NODE_TEST_NEAREST(node); + + if (node->right != KD_NODE_UNSET) + stack[cur++] = node->right; + } + if (node->left != KD_NODE_UNSET) + stack[cur++] = node->left; + } + if (UNLIKELY(cur + 3 > totstack)) { + stack = realloc_nodes(stack, &totstack, defaultstack != stack); + } + } + +#undef NODE_TEST_NEAREST + + +finally: + if (stack != defaultstack) + MEM_freeN(stack); + + if (min_node) { + if (r_nearest) { + r_nearest->index = min_node->index; + r_nearest->dist = sqrtf(min_dist); + copy_v3_v3(r_nearest->co, min_node->co); + } + + return min_node->index; + } + else { + return -1; + } +} + static void add_nearest(KDTreeNearest *ptn, unsigned int *found, unsigned int n, int index, float dist, const float *co) { @@ -448,7 +554,6 @@ int BLI_kdtree_range_search__normal( KDTreeNearest **r_nearest, float range) { const KDTreeNode *nodes = tree->nodes; - const KDTreeNode *root; unsigned int *stack, defaultstack[KD_STACK_INIT]; KDTreeNearest *foundstack = NULL; float range_sq = range * range, dist_sq; @@ -464,27 +569,7 @@ int BLI_kdtree_range_search__normal( stack = defaultstack; totstack = KD_STACK_INIT; - root = &nodes[tree->root]; - - if (co[root->d] + range < root->co[root->d]) { - if (root->left != KD_NODE_UNSET) - stack[cur++] = root->left; - } - else if (co[root->d] - range > root->co[root->d]) { - if (root->right != KD_NODE_UNSET) - stack[cur++] = root->right; - } - else { - dist_sq = squared_distance(root->co, co, nor); - if (dist_sq <= range_sq) { - add_in_range(&foundstack, &totfoundstack, found++, root->index, dist_sq, root->co); - } - - if (root->left != KD_NODE_UNSET) - stack[cur++] = root->left; - if (root->right != KD_NODE_UNSET) - stack[cur++] = root->right; - } + stack[cur++] = tree->root; while (cur--) { const KDTreeNode *node = &nodes[stack[cur]]; @@ -538,7 +623,7 @@ void BLI_kdtree_range_search_cb( bool (*search_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data) { const KDTreeNode *nodes = tree->nodes; - const KDTreeNode *root; + unsigned int *stack, defaultstack[KD_STACK_INIT]; float range_sq = range * range, dist_sq; unsigned int totstack, cur = 0; @@ -553,29 +638,7 @@ void BLI_kdtree_range_search_cb( stack = defaultstack; totstack = KD_STACK_INIT; - root = &nodes[tree->root]; - - if (co[root->d] + range < root->co[root->d]) { - if (root->left != KD_NODE_UNSET) - stack[cur++] = root->left; - } - else if (co[root->d] - range > root->co[root->d]) { - if (root->right != KD_NODE_UNSET) - stack[cur++] = root->right; - } - else { - dist_sq = len_squared_v3v3(root->co, co); - if (dist_sq <= range_sq) { - if (search_cb(user_data, root->index, root->co, dist_sq) == false) { - goto finally; - } - } - - if (root->left != KD_NODE_UNSET) - stack[cur++] = root->left; - if (root->right != KD_NODE_UNSET) - stack[cur++] = root->right; - } + stack[cur++] = tree->root; while (cur--) { const KDTreeNode *node = &nodes[stack[cur]]; diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c index 1da39967945..1500e23d72e 100644 --- a/source/blender/blenlib/intern/BLI_linklist.c +++ b/source/blender/blenlib/intern/BLI_linklist.c @@ -41,7 +41,7 @@ #include "BLI_strict_flags.h" -int BLI_linklist_count(LinkNode *list) +int BLI_linklist_count(const LinkNode *list) { int len; @@ -51,7 +51,7 @@ int BLI_linklist_count(LinkNode *list) return len; } -int BLI_linklist_index(LinkNode *list, void *ptr) +int BLI_linklist_index(const LinkNode *list, void *ptr) { int index; diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c index cde4a8bf59d..d6eae348d52 100644 --- a/source/blender/blenlib/intern/edgehash.c +++ b/source/blender/blenlib/intern/edgehash.c @@ -88,9 +88,9 @@ struct EdgeHash { * \{ */ /** - * Get the hash for a key. + * Compute the hash and get the bucket-index. */ -BLI_INLINE unsigned int edgehash_keyhash(EdgeHash *eh, unsigned int v0, unsigned int v1) +BLI_INLINE unsigned int edgehash_bucket_index(EdgeHash *eh, unsigned int v0, unsigned int v1) { BLI_assert(v0 < v1); @@ -114,7 +114,6 @@ BLI_INLINE void edgehash_resize_buckets(EdgeHash *eh, const unsigned int nbucket EdgeEntry **buckets_new; const unsigned int nbuckets_old = eh->nbuckets; unsigned int i; - EdgeEntry *e; BLI_assert(eh->nbuckets != nbuckets); @@ -122,12 +121,11 @@ BLI_INLINE void edgehash_resize_buckets(EdgeHash *eh, const unsigned int nbucket buckets_new = MEM_callocN(eh->nbuckets * sizeof(*eh->buckets), "eh buckets"); for (i = 0; i < nbuckets_old; i++) { - EdgeEntry *e_next; - for (e = buckets_old[i]; e; e = e_next) { - const unsigned hash = edgehash_keyhash(eh, e->v0, e->v1); + for (EdgeEntry *e = buckets_old[i], *e_next; e; e = e_next) { + const unsigned bucket_index = edgehash_bucket_index(eh, e->v0, e->v1); e_next = e->next; - e->next = buckets_new[hash]; - buckets_new[hash] = e; + e->next = buckets_new[bucket_index]; + buckets_new[bucket_index] = e; } } @@ -147,14 +145,15 @@ BLI_INLINE void edgehash_buckets_reserve(EdgeHash *eh, const unsigned int nentri /** * Internal lookup function. - * Takes a hash argument to avoid calling #edgehash_keyhash multiple times. + * Takes a \a bucket_index argument to avoid calling #edgehash_bucket_index multiple times. */ -BLI_INLINE EdgeEntry *edgehash_lookup_entry_ex(EdgeHash *eh, unsigned int v0, unsigned int v1, - const unsigned int hash) +BLI_INLINE EdgeEntry *edgehash_lookup_entry_ex( + EdgeHash *eh, unsigned int v0, unsigned int v1, + const unsigned int bucket_index) { EdgeEntry *e; BLI_assert(v0 < v1); - for (e = eh->buckets[hash]; e; e = e->next) { + for (e = eh->buckets[bucket_index]; e; e = e->next) { if (UNLIKELY(v0 == e->v0 && v1 == e->v1)) { return e; } @@ -163,14 +162,34 @@ BLI_INLINE EdgeEntry *edgehash_lookup_entry_ex(EdgeHash *eh, unsigned int v0, un } /** + * Internal lookup function, returns previous entry of target one too. + * Takes bucket_index argument to avoid calling #edgehash_bucket_index multiple times. + * Useful when modifying buckets somehow (like removing an entry...). + */ +BLI_INLINE EdgeEntry *edgehash_lookup_entry_prev_ex( + EdgeHash *eh, unsigned int v0, unsigned int v1, + EdgeEntry **r_e_prev, const unsigned int bucket_index) +{ + BLI_assert(v0 < v1); + for (EdgeEntry *e_prev = NULL, *e = eh->buckets[bucket_index]; e; e = e->next) { + if (UNLIKELY(v0 == e->v0 && v1 == e->v1)) { + *r_e_prev = e_prev; + return e; + } + } + + *r_e_prev = NULL; + return NULL; +} + +/** * Internal lookup function. Only wraps #edgehash_lookup_entry_ex */ BLI_INLINE EdgeEntry *edgehash_lookup_entry(EdgeHash *eh, unsigned int v0, unsigned int v1) { - unsigned int hash; - EDGE_ORD(v0, v1); /* ensure v0 is smaller */ - hash = edgehash_keyhash(eh, v0, v1); - return edgehash_lookup_entry_ex(eh, v0, v1, hash); + EDGE_ORD(v0, v1); + const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1); + return edgehash_lookup_entry_ex(eh, v0, v1, bucket_index); } @@ -198,10 +217,11 @@ static EdgeHash *edgehash_new(const char *info, /** * Internal insert function. - * Takes a hash argument to avoid calling #edgehash_keyhash multiple times. + * Takes a \a bucket_index argument to avoid calling #edgehash_bucket_index multiple times. */ -BLI_INLINE void edgehash_insert_ex(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val, - unsigned int hash) +BLI_INLINE void edgehash_insert_ex( + EdgeHash *eh, unsigned int v0, unsigned int v1, void *val, + const unsigned int bucket_index) { EdgeEntry *e = BLI_mempool_alloc(eh->epool); @@ -212,11 +232,11 @@ BLI_INLINE void edgehash_insert_ex(EdgeHash *eh, unsigned int v0, unsigned int v BLI_assert(v0 < v1); BLI_assert(v0 != v1); - e->next = eh->buckets[hash]; + e->next = eh->buckets[bucket_index]; e->v0 = v0; e->v1 = v1; e->val = val; - eh->buckets[hash] = e; + eh->buckets[bucket_index] = e; if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) { edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]); @@ -226,8 +246,9 @@ BLI_INLINE void edgehash_insert_ex(EdgeHash *eh, unsigned int v0, unsigned int v /** * Insert function that doesn't set the value (use for EdgeSet) */ -BLI_INLINE void edgehash_insert_ex_keyonly(EdgeHash *eh, unsigned int v0, unsigned int v1, - unsigned int hash) +BLI_INLINE void edgehash_insert_ex_keyonly( + EdgeHash *eh, unsigned int v0, unsigned int v1, + const unsigned int bucket_index) { EdgeEntry *e = BLI_mempool_alloc(eh->epool); @@ -237,10 +258,10 @@ BLI_INLINE void edgehash_insert_ex_keyonly(EdgeHash *eh, unsigned int v0, unsign BLI_assert(v0 < v1); BLI_assert(v0 != v1); - e->next = eh->buckets[hash]; + e->next = eh->buckets[bucket_index]; e->v0 = v0; e->v1 = v1; - eh->buckets[hash] = e; + eh->buckets[bucket_index] = e; if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) { edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]); @@ -252,7 +273,7 @@ BLI_INLINE void edgehash_insert_ex_keyonly(EdgeHash *eh, unsigned int v0, unsign */ BLI_INLINE void edgehash_insert_ex_keyonly_entry( EdgeHash *eh, unsigned int v0, unsigned int v1, - unsigned int hash, + const unsigned int bucket_index, EdgeEntry *e) { BLI_assert((eh->flag & EDGEHASH_FLAG_ALLOW_DUPES) || (BLI_edgehash_haskey(eh, v0, v1) == 0)); @@ -261,11 +282,11 @@ BLI_INLINE void edgehash_insert_ex_keyonly_entry( BLI_assert(v0 < v1); BLI_assert(v0 != v1); - e->next = eh->buckets[hash]; + e->next = eh->buckets[bucket_index]; e->v0 = v0; e->v1 = v1; /* intentionally leave value unset */ - eh->buckets[hash] = e; + eh->buckets[bucket_index] = e; if (UNLIKELY(edgehash_test_expand_buckets(++eh->nentries, eh->nbuckets))) { edgehash_resize_buckets(eh, _ehash_hashsizes[++eh->cursize]); @@ -274,39 +295,43 @@ BLI_INLINE void edgehash_insert_ex_keyonly_entry( BLI_INLINE void edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val) { - unsigned int hash; - EDGE_ORD(v0, v1); /* ensure v0 is smaller */ - hash = edgehash_keyhash(eh, v0, v1); - edgehash_insert_ex(eh, v0, v1, val, hash); + EDGE_ORD(v0, v1); + const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1); + edgehash_insert_ex(eh, v0, v1, val, bucket_index); } /** * Remove the entry and return it, caller must free from eh->epool. */ -static EdgeEntry *edgehash_remove_ex(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHashFreeFP valfreefp, - unsigned int hash) +BLI_INLINE EdgeEntry *edgehash_remove_ex( + EdgeHash *eh, unsigned int v0, unsigned int v1, + EdgeHashFreeFP valfreefp, + const unsigned int bucket_index) { - EdgeEntry *e; - EdgeEntry *e_prev = NULL; + EdgeEntry *e_prev; + EdgeEntry *e = edgehash_lookup_entry_prev_ex(eh, v0, v1, &e_prev, bucket_index); BLI_assert(v0 < v1); - for (e = eh->buckets[hash]; e; e = e->next) { - if (UNLIKELY(v0 == e->v0 && v1 == e->v1)) { - EdgeEntry *e_next = e->next; - - if (valfreefp) valfreefp(e->val); + if (e) { + EdgeEntry *e_next = e->next; - if (e_prev) e_prev->next = e_next; - else eh->buckets[hash] = e_next; + if (valfreefp) { + valfreefp(e->val); + } - eh->nentries--; - return e; + if (e_prev) { + e_prev->next = e_next; + } + else { + eh->buckets[bucket_index] = e_next; } - e_prev = e; + + eh->nentries--; + return e; } - return NULL; + return e; } /** @@ -366,21 +391,18 @@ void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *v */ bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val) { - unsigned int hash; - EdgeEntry *e; - IS_EDGEHASH_ASSERT(eh); - EDGE_ORD(v0, v1); /* ensure v0 is smaller */ - hash = edgehash_keyhash(eh, v0, v1); + EDGE_ORD(v0, v1); + const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1); - e = edgehash_lookup_entry_ex(eh, v0, v1, hash); + EdgeEntry *e = edgehash_lookup_entry_ex(eh, v0, v1, bucket_index); if (e) { e->val = val; return false; } else { - edgehash_insert_ex(eh, v0, v1, val, hash); + edgehash_insert_ex(eh, v0, v1, val, bucket_index); return true; } } @@ -412,18 +434,14 @@ void **BLI_edgehash_lookup_p(EdgeHash *eh, unsigned int v0, unsigned int v1) */ bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val) { - unsigned int hash; - EdgeEntry *e; - bool haskey; - - EDGE_ORD(v0, v1); /* ensure v0 is smaller */ - hash = edgehash_keyhash(eh, v0, v1); - e = edgehash_lookup_entry_ex(eh, v0, v1, hash); - haskey = (e != NULL); + EDGE_ORD(v0, v1); + const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1); + EdgeEntry *e = edgehash_lookup_entry_ex(eh, v0, v1, bucket_index); + const bool haskey = (e != NULL); if (!haskey) { e = BLI_mempool_alloc(eh->epool); - edgehash_insert_ex_keyonly_entry(eh, v0, v1, hash, e); + edgehash_insert_ex_keyonly_entry(eh, v0, v1, bucket_index, e); } *r_val = &e->val; @@ -462,12 +480,9 @@ void *BLI_edgehash_lookup_default(EdgeHash *eh, unsigned int v0, unsigned int v1 */ bool BLI_edgehash_remove(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHashFreeFP valfreefp) { - unsigned int hash; - EdgeEntry *e; - - EDGE_ORD(v0, v1); /* ensure v0 is smaller */ - hash = edgehash_keyhash(eh, v0, v1); - e = edgehash_remove_ex(eh, v0, v1, valfreefp, hash); + EDGE_ORD(v0, v1); + const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1); + EdgeEntry *e = edgehash_remove_ex(eh, v0, v1, valfreefp, bucket_index); if (e) { BLI_mempool_free(eh->epool, e); return true; @@ -487,12 +502,9 @@ bool BLI_edgehash_remove(EdgeHash *eh, unsigned int v0, unsigned int v1, EdgeHas */ void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) { - unsigned int hash; - EdgeEntry *e; - - EDGE_ORD(v0, v1); /* ensure v0 is smaller */ - hash = edgehash_keyhash(eh, v0, v1); - e = edgehash_remove_ex(eh, v0, v1, NULL, hash); + EDGE_ORD(v0, v1); + const unsigned int bucket_index = edgehash_bucket_index(eh, v0, v1); + EdgeEntry *e = edgehash_remove_ex(eh, v0, v1, NULL, bucket_index); IS_EDGEHASH_ASSERT(eh); if (e) { void *val = e->val; @@ -728,10 +740,9 @@ int BLI_edgeset_size(EdgeSet *es) */ void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1) { - unsigned int hash; - EDGE_ORD(v0, v1); /* ensure v0 is smaller */ - hash = edgehash_keyhash((EdgeHash *)es, v0, v1); - edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, hash); + EDGE_ORD(v0, v1); + const unsigned int bucket_index = edgehash_bucket_index((EdgeHash *)es, v0, v1); + edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, bucket_index); } /** @@ -742,18 +753,15 @@ void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1) */ bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1) { - unsigned int hash; - EdgeEntry *e; - - EDGE_ORD(v0, v1); /* ensure v0 is smaller */ - hash = edgehash_keyhash((EdgeHash *)es, v0, v1); + EDGE_ORD(v0, v1); + const unsigned int bucket_index = edgehash_bucket_index((EdgeHash *)es, v0, v1); - e = edgehash_lookup_entry_ex((EdgeHash *)es, v0, v1, hash); + EdgeEntry *e = edgehash_lookup_entry_ex((EdgeHash *)es, v0, v1, bucket_index); if (e) { return false; } else { - edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, hash); + edgehash_insert_ex_keyonly((EdgeHash *)es, v0, v1, bucket_index); return true; } } diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index f8bcbae00b0..5b809ab26cc 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -1495,6 +1495,51 @@ bool isect_ray_tri_threshold_v3( } #endif + +bool isect_ray_seg_v2( + const float p1[3], const float d[3], + const float v0[3], const float v1[3], + float *r_lambda, float *r_u) +{ + float v0_local[2], v1_local[2]; + sub_v2_v2v2(v0_local, v0, p1); + sub_v2_v2v2(v1_local, v1, p1); + + float s10[2]; + float det; + + sub_v2_v2v2(s10, v1_local, v0_local); + + det = cross_v2v2(d, s10); + if (det != 0.0f) { + const float v = cross_v2v2(v0_local, v1_local); + float p[2] = {(d[0] * v) / det, (d[1] * v) / det}; + + const float t = (dot_v2v2(p, d) / dot_v2v2(d, d)); + if ((t >= 0.0f) == 0) { + return false; + } + + float h[2]; + sub_v2_v2v2(h, v1_local, p); + const float u = (dot_v2v2(s10, h) / dot_v2v2(s10, s10)); + if ((u >= 0.0f && u <= 1.0f) == 0) { + return false; + } + + if (r_lambda) { + *r_lambda = t; + } + if (r_u) { + *r_u = u; + } + + return true; + } + + return false; +} + /** * Check if a point is behind all planes. */ @@ -2355,7 +2400,9 @@ static bool point_in_slice(const float p[3], const float v1[3], const float l1[3 sub_v3_v3v3(rp, p, v1); h = dot_v3v3(q, rp) / dot_v3v3(q, q); - return (h < 0.0f || h > 1.0f) ? false : true; + /* note: when 'h' is nan/-nan, this check returns false + * without explicit check - covering the degenerate case */ + return (h >= 0.0f && h <= 1.0f); } #if 0 @@ -2399,22 +2446,15 @@ bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], float r_vi[3]) { if (isect_point_tri_prism_v3(p, v1, v2, v3)) { - float no[3], n1[3], n2[3]; + float plane[4]; + float no[3]; /* Could use normal_tri_v3, but doesn't have to be unit-length */ - sub_v3_v3v3(n1, v1, v2); - sub_v3_v3v3(n2, v2, v3); - cross_v3_v3v3(no, n1, n2); - - if (LIKELY(len_squared_v3(no) != 0.0f)) { - float plane[4]; - plane_from_point_normal_v3(plane, v1, no); - closest_to_plane_v3(r_vi, plane, p); - } - else { - /* degenerate */ - copy_v3_v3(r_vi, p); - } + cross_tri_v3(no, v1, v2, v3); + BLI_assert(len_squared_v3(no) != 0.0f); + + plane_from_point_normal_v3(plane, v1, no); + closest_to_plane_v3(r_vi, plane, p); return true; } diff --git a/source/blender/blenlib/intern/math_geom_inline.c b/source/blender/blenlib/intern/math_geom_inline.c index 44b17681540..68a2e68db4f 100644 --- a/source/blender/blenlib/intern/math_geom_inline.c +++ b/source/blender/blenlib/intern/math_geom_inline.c @@ -199,6 +199,17 @@ MINLINE int axis_dominant_v3_single(const float vec[3]) ((y > z) ? 1 : 2)); } +/* the dominant axis of an orthogonal vector */ +MINLINE int axis_dominant_v3_ortho_single(const float vec[3]) +{ + const float x = fabsf(vec[0]); + const float y = fabsf(vec[1]); + const float z = fabsf(vec[2]); + return ((x < y) ? + ((x < z) ? 0 : 2) : + ((y < z) ? 1 : 2)); +} + MINLINE int max_axis_v3(const float vec[3]) { const float x = vec[0]; diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 19d116928fd..52ff6fd3e8a 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -1569,6 +1569,7 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], float wmat[4][4] * * See https://en.wikipedia.org/wiki/Polar_decomposition for more. */ +#ifndef MATH_STANDALONE void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3]) { /* From svd decomposition (M = WSV*), we have: @@ -1586,7 +1587,7 @@ void mat3_polar_decompose(float mat3[3][3], float r_U[3][3], float r_P[3][3]) mul_m3_m3m3(r_U, W, Vt); mul_m3_series(r_P, V, S, Vt); } - +#endif void scale_m3_fl(float m[3][3], float scale) { @@ -1727,6 +1728,8 @@ void blend_m4_m4m4(float out[4][4], float dst[4][4], float src[4][4], const floa loc_quat_size_to_mat4(out, floc, fquat, fsize); } +/* for builds without Eigen */ +#ifndef MATH_STANDALONE /** * A polar-decomposition-based interpolation between matrix A and matrix B. * @@ -1795,6 +1798,7 @@ void interp_m4_m4m4(float R[4][4], float A[4][4], float B[4][4], const float t) copy_m4_m3(R, R3); copy_v3_v3(R[3], loc); } +#endif /* MATH_STANDALONE */ bool is_negative_m3(float mat[3][3]) { diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c index d1dad9a6269..641e50c9bde 100644 --- a/source/blender/blenlib/intern/math_solvers.c +++ b/source/blender/blenlib/intern/math_solvers.c @@ -34,7 +34,7 @@ #include "BLI_strict_flags.h" -#include "eigen3_capi.h" +#include "eigen_capi.h" /********************************** Eigen Solvers *********************************/ @@ -57,7 +57,7 @@ bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3], float r_eigen_values[3 } #endif - return EG3_self_adjoint_eigen_solve(3, (const float *)m3, r_eigen_values, (float *)r_eigen_vectors); + return EIG_self_adjoint_eigen_solve(3, (const float *)m3, r_eigen_values, (float *)r_eigen_vectors); } /** @@ -70,5 +70,5 @@ bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3], float r_eigen_values[3 */ void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3]) { - EG3_svd_square_matrix(3, (const float *)m3, (float *)r_U, (float *)r_S, (float *)r_V); + EIG_svd_square_matrix(3, (const float *)m3, (float *)r_U, (float *)r_S, (float *)r_V); } diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 99e512475bb..fadfb64f1e1 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1761,7 +1761,7 @@ void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__r } /* inline BLI_add_slash */ - if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) { + if ((dirlen > 0) && !ELEM(dst[dirlen - 1], SEP, ALTSEP)) { dst[dirlen++] = SEP; dst[dirlen] = '\0'; } diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index 5803448a4c0..515da9cd95d 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -575,9 +575,15 @@ size_t BLI_task_pool_tasks_done(TaskPool *pool) * - Chunk iterations to reduce number of spin locks. */ +/* Allows to avoid using malloc for userdata_chunk in tasks, when small enough. */ +#define MALLOCA(_size) ((_size) <= 8192) ? alloca((_size)) : MEM_mallocN((_size), __func__) +#define MALLOCA_FREE(_mem, _size) if (((_mem) != NULL) && ((_size) > 8192)) MEM_freeN((_mem)) + typedef struct ParallelRangeState { int start, stop; void *userdata; + void *userdata_chunk; + size_t userdata_chunk_size; TaskParallelRangeFunc func; int iter; @@ -608,17 +614,45 @@ static void parallel_range_func( { ParallelRangeState * __restrict state = BLI_task_pool_userdata(pool); int iter, count; + + const bool use_userdata_chunk = (state->userdata_chunk_size != 0) && (state->userdata_chunk != NULL); + void *userdata_chunk = use_userdata_chunk ? MALLOCA(state->userdata_chunk_size) : NULL; + while (parallel_range_next_iter_get(state, &iter, &count)) { int i; + + if (use_userdata_chunk) { + memcpy(userdata_chunk, state->userdata_chunk, state->userdata_chunk_size); + } + for (i = 0; i < count; ++i) { - state->func(state->userdata, iter + i); + state->func(state->userdata, userdata_chunk, iter + i); } } + + MALLOCA_FREE(userdata_chunk, state->userdata_chunk_size); } +/** + * This function allows to parallelized for loops in a similar way to OpenMP's 'parallel for' statement. + * + * \param start First index to process. + * \param stop Index to stop looping (excluded). + * \param userdata Common userdata passed to all instances of \a func. + * \param userdata_chunk Optional, each instance of looping chunks will get a copy of this data + * (similar to OpenMP's firstprivate). + * \param userdata_chunk_size Memory size of \a userdata_chunk. + * \param func Callback function. + * \param range_threshold Minimum size of processed range to start using tasks + * (below this, loop is done in main thread only). + * \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently), + * otherwise whole range is split in a few big chunks (num_threads * 2 chunks currently). + */ void BLI_task_parallel_range_ex( int start, int stop, void *userdata, + void *userdata_chunk, + const size_t userdata_chunk_size, TaskParallelRangeFunc func, const int range_threshold, const bool use_dynamic_scheduling) @@ -634,9 +668,19 @@ void BLI_task_parallel_range_ex( * do everything from the main thread. */ if (stop - start < range_threshold) { + const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL); + void *userdata_chunk_local = NULL; + + if (use_userdata_chunk) { + userdata_chunk_local = MALLOCA(userdata_chunk_size); + memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size); + } + for (i = start; i < stop; ++i) { - func(userdata, i); + func(userdata, userdata_chunk_local, i); } + + MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size); return; } @@ -654,6 +698,8 @@ void BLI_task_parallel_range_ex( state.start = start; state.stop = stop; state.userdata = userdata; + state.userdata_chunk = userdata_chunk; + state.userdata_chunk_size = userdata_chunk_size; state.func = func; state.iter = start; if (use_dynamic_scheduling) { @@ -676,10 +722,18 @@ void BLI_task_parallel_range_ex( BLI_spin_end(&state.lock); } +/** + * A simpler version of \a BLI_task_parallel_range_ex, which does not use \a use_dynamic_scheduling, + * has a \a range_threshold of 64, and does not handle 'firstprivate'-like \a userdata_chunk. + */ void BLI_task_parallel_range( int start, int stop, void *userdata, TaskParallelRangeFunc func) { - BLI_task_parallel_range_ex(start, stop, userdata, func, 64, false); + BLI_task_parallel_range_ex(start, stop, userdata, NULL, 0, func, 64, false); } + +#undef MALLOCA +#undef MALLOCA_FREE + diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9004a5f92f7..177055e7206 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -622,6 +622,7 @@ static Main *blo_find_main(FileData *fd, const char *filepath, const char *relab /* Add library datablock itself to 'main' Main, since libraries are **never** linked data. * Fixes bug where you could end with all ID_LI datablocks having the same name... */ lib = BKE_libblock_alloc(mainlist->first, ID_LI, "Lib"); + lib->id.us = ID_FAKE_USERS(lib); /* Important, consistency with main ID reading code from read_libblock(). */ BLI_strncpy(lib->name, filepath, sizeof(lib->name)); BLI_strncpy(lib->filepath, name1, sizeof(lib->filepath)); @@ -1344,7 +1345,7 @@ bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, cha while ((slash = (char *)BLI_last_slash(r_dir))) { char tc = *slash; *slash = '\0'; - if (BLO_has_bfile_extension(r_dir)) { + if (BLO_has_bfile_extension(r_dir) && BLI_is_file(r_dir)) { break; } diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 9456c286c6f..77a4aefb7ac 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -1386,7 +1386,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main) SpaceClip *sclip = (SpaceClip *)sl; if (sclip->around == 0) { - sclip->around = V3D_CENTROID; + sclip->around = V3D_AROUND_CENTER_MEAN; } } } diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index e6005da23e4..8a2045ddacf 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -921,7 +921,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } - { + if (!MAIN_VERSION_ATLEAST(main, 276, 3)) { if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "CurveMapping", "mblur_shutter_curve")) { Scene *scene; for (scene = main->scene.first; scene != NULL; scene = scene->id.next) { diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt index 257768b0ac8..1afa98fd6f8 100644 --- a/source/blender/bmesh/CMakeLists.txt +++ b/source/blender/bmesh/CMakeLists.txt @@ -30,6 +30,7 @@ set(INC ../blentranslation ../makesdna ../../../intern/guardedalloc + ../../../intern/eigen ../../../extern/rangetree ) @@ -112,6 +113,8 @@ set(SRC intern/bmesh_operators_private.h intern/bmesh_polygon.c intern/bmesh_polygon.h + intern/bmesh_polygon_edgenet.c + intern/bmesh_polygon_edgenet.h intern/bmesh_private.h intern/bmesh_queries.c intern/bmesh_queries.h @@ -160,7 +163,7 @@ set(SRC ) if(MSVC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX /wd4101") endif() if(WITH_BULLET) @@ -174,13 +177,6 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() -if(WITH_OPENNL) - add_definitions(-DWITH_OPENNL) - list(APPEND INC_SYS - ../../../intern/opennl/extern - ) -endif() - if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() diff --git a/source/blender/bmesh/SConscript b/source/blender/bmesh/SConscript index c53974be1a7..6bf4fdf7c78 100644 --- a/source/blender/bmesh/SConscript +++ b/source/blender/bmesh/SConscript @@ -40,9 +40,9 @@ incs = [ '../makesdna', '../blenkernel', '#/intern/guardedalloc', + '#/intern/eigen', '#/extern/bullet2/src', '#/extern/rangetree', - '#/intern/opennl/extern' ] defs = [] diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h index 78c814af86e..f29d280d071 100644 --- a/source/blender/bmesh/bmesh.h +++ b/source/blender/bmesh/bmesh.h @@ -244,6 +244,7 @@ extern "C" { #include "intern/bmesh_mods.h" #include "intern/bmesh_operators.h" #include "intern/bmesh_polygon.h" +#include "intern/bmesh_polygon_edgenet.h" #include "intern/bmesh_queries.h" #include "intern/bmesh_walkers.h" diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 57107ed4e37..4ffa0bda71a 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -276,8 +276,16 @@ enum { #define BM_CHECK_TYPE_ELEM(ele) \ CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST, _BM_GENERIC_TYPE_ELEM_CONST) +/* Assignment from a void* to a typed pointer is not allowed in C++, + * casting the LHS to void works fine though. + */ +#ifdef __cplusplus +#define BM_CHECK_TYPE_ELEM_ASSIGN(ele) \ + (BM_CHECK_TYPE_ELEM(ele)), *((void **)&ele) +#else #define BM_CHECK_TYPE_ELEM_ASSIGN(ele) \ (BM_CHECK_TYPE_ELEM(ele)), ele +#endif /* BMHeader->hflag (char) */ enum { @@ -309,7 +317,11 @@ enum { struct BPy_BMGeneric; extern void bpy_bm_generic_invalidate(struct BPy_BMGeneric *self); -typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data); +typedef bool (*BMElemFilterFunc)(const BMElem *, void *user_data); +typedef bool (*BMVertFilterFunc)(const BMVert *, void *user_data); +typedef bool (*BMEdgeFilterFunc)(const BMEdge *, void *user_data); +typedef bool (*BMFaceFilterFunc)(const BMFace *, void *user_data); +typedef bool (*BMLoopFilterFunc)(const BMLoop *, void *user_data); /* defines */ #define BM_ELEM_CD_SET_INT(ele, offset, f) { CHECK_TYPE_NONCONST(ele); \ diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 7664108f348..3c2a85e9f52 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -116,7 +116,7 @@ BMFace *BM_face_create_quad_tri( */ void BM_face_copy_shared( BMesh *bm, BMFace *f, - BMElemFilterFunc filter_fn, void *user_data) + BMLoopFilterFunc filter_fn, void *user_data) { BMLoop *l_first; BMLoop *l_iter; @@ -149,7 +149,7 @@ void BM_face_copy_shared( for (j = 0; j < 2; j++) { BLI_assert(l_dst[j]->v == l_src[j]->v); if (BM_ELEM_API_FLAG_TEST(l_dst[j], _FLAG_OVERLAP) == 0) { - if ((filter_fn == NULL) || filter_fn((BMElem *)l_src[j], user_data)) { + if ((filter_fn == NULL) || filter_fn(l_src[j], user_data)) { bm_loop_attrs_copy(bm, bm, l_src[j], l_dst[j]); BM_ELEM_API_FLAG_ENABLE(l_dst[j], _FLAG_OVERLAP); } diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h index 29503679547..ce8b8dd8391 100644 --- a/source/blender/bmesh/intern/bmesh_construct.h +++ b/source/blender/bmesh/intern/bmesh_construct.h @@ -38,7 +38,7 @@ BMFace *BM_face_create_quad_tri( void BM_face_copy_shared( BMesh *bm, BMFace *f, - BMElemFilterFunc filter_fn, void *user_data); + BMLoopFilterFunc filter_fn, void *user_data); BMFace *BM_face_create_ngon( BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, const int len, diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 55a04767f51..7130d451ed7 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -823,6 +823,66 @@ void BM_face_kill(BMesh *bm, BMFace *f) bm_kill_only_face(bm, f); } + +/** + * A version of #BM_face_kill which removes edges and verts + * which have no remaining connected geometry. + */ +void BM_face_kill_loose(BMesh *bm, BMFace *f) +{ +#ifdef USE_BMESH_HOLES + BMLoopList *ls, *ls_next; +#endif + + BM_CHECK_ELEMENT(f); + +#ifdef USE_BMESH_HOLES + for (ls = f->loops.first; ls; ls = ls_next) +#else + if (f->l_first) +#endif + { + BMLoop *l_iter, *l_next, *l_first; + +#ifdef USE_BMESH_HOLES + ls_next = ls->next; + l_iter = l_first = ls->first; +#else + l_iter = l_first = f->l_first; +#endif + + do { + BMEdge *e; + l_next = l_iter->next; + + e = l_iter->e; + bmesh_radial_loop_remove(l_iter, e); + bm_kill_only_loop(bm, l_iter); + + if (e->l == NULL) { + BMVert *v1 = e->v1, *v2 = e->v2; + + bmesh_disk_edge_remove(e, e->v1); + bmesh_disk_edge_remove(e, e->v2); + bm_kill_only_edge(bm, e); + + if (v1->e == NULL) { + bm_kill_only_vert(bm, v1); + } + if (v2->e == NULL) { + bm_kill_only_vert(bm, v2); + } + } + } while ((l_iter = l_next) != l_first); + +#ifdef USE_BMESH_HOLES + BLI_mempool_free(bm->looplistpool, ls); +#endif + } + + bm_kill_only_face(bm, f); +} + /** * kills \a e and all faces that use it. */ diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h index a18d96824b7..08f916faf4f 100644 --- a/source/blender/bmesh/intern/bmesh_core.h +++ b/source/blender/bmesh/intern/bmesh_core.h @@ -58,6 +58,8 @@ BMFace *BM_face_create_verts( void BM_face_edges_kill(BMesh *bm, BMFace *f); void BM_face_verts_kill(BMesh *bm, BMFace *f); +void BM_face_kill_loose(BMesh *bm, BMFace *f); + void BM_face_kill(BMesh *bm, BMFace *f); void BM_edge_kill(BMesh *bm, BMEdge *e); void BM_vert_kill(BMesh *bm, BMVert *v); diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index b157237c7d0..b9cdc4ccf66 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -94,8 +94,26 @@ extern const BMAllocTemplate bm_mesh_chunksize_default; (bm)->totvert), (bm)->totedge, (bm)->totloop, (bm)->totface} #define BMALLOC_TEMPLATE_FROM_ME(me) { (CHECK_TYPE_INLINE(me, Mesh *), \ (me)->totvert), (me)->totedge, (me)->totloop, (me)->totpoly} -#define BMALLOC_TEMPLATE_FROM_DM(dm) { (CHECK_TYPE_INLINE(dm, DerivedMesh *), \ - (dm)->getNumVerts(dm)), (dm)->getNumEdges(dm), (dm)->getNumLoops(dm), (dm)->getNumPolys(dm)} + +#define _VA_BMALLOC_TEMPLATE_FROM_DM_1(dm) { \ + (CHECK_TYPE_INLINE(dm, DerivedMesh *), \ + (dm)->getNumVerts(dm)), \ + (dm)->getNumEdges(dm), \ + (dm)->getNumLoops(dm), \ + (dm)->getNumPolys(dm), \ + } +#define _VA_BMALLOC_TEMPLATE_FROM_DM_2(dm_a, dm_b) { \ + (CHECK_TYPE_INLINE(dm_a, DerivedMesh *), \ + CHECK_TYPE_INLINE(dm_b, DerivedMesh *), \ + (dm_a)->getNumVerts(dm_a)) + (dm_b)->getNumVerts(dm_b), \ + (dm_a)->getNumEdges(dm_a) + (dm_b)->getNumEdges(dm_b), \ + (dm_a)->getNumLoops(dm_a) + (dm_b)->getNumLoops(dm_b), \ + (dm_a)->getNumPolys(dm_a) + (dm_b)->getNumPolys(dm_b), \ + } + +#define BMALLOC_TEMPLATE_FROM_DM(...) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_DM_, __VA_ARGS__) + + enum { BM_MESH_CREATE_USE_TOOLFLAGS = (1 << 0) diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index cde231b4494..84588d957de 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -29,22 +29,14 @@ #include "MEM_guardedalloc.h" - #include "BLI_math.h" #include "BLI_array.h" -#include "BLI_alloca.h" -#include "BLI_stackdefines.h" -#include "BLI_linklist_stack.h" -#include "BLI_sort_utils.h" #include "BKE_customdata.h" #include "bmesh.h" #include "intern/bmesh_private.h" -// #define DEBUG_PRINT - - /** * \brief Dissolve Vert * @@ -425,549 +417,6 @@ BMFace *BM_face_split_n( return f_new; } - -/* -------------------------------------------------------------------- */ -/* Face Split Edge-Net */ - -/** \name BM_face_split_edgenet and helper functions. - * - * \note Don't use #BM_edge_is_wire or #BM_edge_is_boundary - * since we need to take flagged faces into account. - * Also take care accessing e->l directly. - * - * \{ */ - -/* Note: All these flags _must_ be cleared on exit */ - -/* face is apart of the edge-net (including the original face we're splitting) */ -#define FACE_NET _FLAG_WALK -/* edge is apart of the edge-net we're filling */ -#define EDGE_NET _FLAG_WALK -/* tag verts we've visit */ -#define VERT_VISIT _FLAG_WALK - -struct VertOrder { - float angle; - BMVert *v; -}; - -static unsigned int bm_edge_flagged_radial_count(BMEdge *e) -{ - unsigned int count = 0; - BMLoop *l; - - if ((l = e->l)) { - do { - if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) { - count++; - } - } while ((l = l->radial_next) != e->l); - } - return count; -} - -static BMLoop *bm_edge_flagged_radial_first(BMEdge *e) -{ - BMLoop *l; - - if ((l = e->l)) { - do { - if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) { - return l; - } - } while ((l = l->radial_next) != e->l); - } - return NULL; -} - -static bool bm_face_split_edgenet_find_loop_pair( - BMVert *v_init, const float face_normal[3], - BMEdge *e_pair[2]) -{ - /* Always find one boundary edge (to determine winding) - * and one wire (if available), otherwise another boundary. - */ - BMIter iter; - BMEdge *e; - - /* detect winding */ - BMLoop *l_walk; - bool swap; - - BLI_SMALLSTACK_DECLARE(edges_boundary, BMEdge *); - BLI_SMALLSTACK_DECLARE(edges_wire, BMEdge *); - int edges_boundary_len = 0; - int edges_wire_len = 0; - - BM_ITER_ELEM (e, &iter, v_init, BM_EDGES_OF_VERT) { - if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { - const unsigned int count = bm_edge_flagged_radial_count(e); - if (count == 1) { - BLI_SMALLSTACK_PUSH(edges_boundary, e); - edges_boundary_len++; - } - else if (count == 0) { - BLI_SMALLSTACK_PUSH(edges_wire, e); - edges_wire_len++; - } - } - } - - /* first edge should always be boundary */ - if (edges_boundary_len == 0) { - return false; - } - e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary); - - /* attempt one boundary and one wire, or 2 boundary */ - if (edges_wire_len == 0) { - if (edges_boundary_len >= 2) { - e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary); - } - else { - /* one boundary and no wire */ - return false; - } - } - else { - e_pair[1] = BLI_SMALLSTACK_POP(edges_wire); - - if (edges_wire_len > 1) { - BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); - BMVert *v_next; - float angle_best; - - v_next = BM_edge_other_vert(e_pair[1], v_init); - angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - - while ((e = BLI_SMALLSTACK_POP(edges_wire))) { - float angle_test; - v_next = BM_edge_other_vert(e, v_init); - angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - if (angle_test < angle_best) { - angle_best = angle_test; - e_pair[1] = e; - } - } - } - } - - - /* flip based on winding */ - l_walk = bm_edge_flagged_radial_first(e_pair[0]); - swap = false; - if (face_normal == l_walk->f->no) { - swap = !swap; - } - if (l_walk->v != v_init) { - swap = !swap; - } - if (swap) { - SWAP(BMEdge *, e_pair[0], e_pair[1]); - } - - return true; -} - -static bool bm_face_split_edgenet_find_loop_walk( - BMVert *v_init, const float face_normal[3], - /* cache to avoid realloc every time */ - struct VertOrder *edge_order, const unsigned int edge_order_len, - BMEdge *e_pair[2]) -{ - /* fast-path for the common case (avoid push-pop). - * Also avoids tagging as visited since we know we - * can't reach these verts some other way */ -#define USE_FASTPATH_NOFORK - - BMVert *v; - BMVert *v_dst; - bool found = false; - - struct VertOrder *eo; - STACK_DECLARE(edge_order); - - /* store visited verts so we can clear the visit flag after execution */ - BLI_SMALLSTACK_DECLARE(vert_visit, BMVert *); - - /* likely this will stay very small - * all verts pushed into this stack _must_ have their previous edges set! */ - BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *); - BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *); - - STACK_INIT(edge_order, edge_order_len); - - /* start stepping */ - v = BM_edge_other_vert(e_pair[0], v_init); - v->e = e_pair[0]; - BLI_SMALLSTACK_PUSH(vert_stack, v); - - v_dst = BM_edge_other_vert(e_pair[1], v_init); - -#ifdef DEBUG_PRINT - printf("%s: vert (search) %d\n", __func__, BM_elem_index_get(v_init)); -#endif - - /* This loop will keep stepping over the best possible edge, - * in most cases it finds the direct route to close the face. - * - * In cases where paths can't be closed, - * alternatives are stored in the 'vert_stack'. - */ - while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { - BMIter eiter; - BMEdge *e_next; - -#ifdef USE_FASTPATH_NOFORK -walk_nofork: -#else - BLI_SMALLSTACK_PUSH(vert_visit, v); - BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT); -#endif - - BLI_assert(STACK_SIZE(edge_order) == 0); - - /* check if we're done! */ - if (v == v_dst) { - found = true; - goto finally; - } - - BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { - if ((v->e != e_next) && - (BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && - (bm_edge_flagged_radial_count(e_next) < 2)) - { - BMVert *v_next; - - v_next = BM_edge_other_vert(e_next, v); - -#ifdef DEBUG_PRINT - /* indent and print */ - { - BMVert *_v = v; - do { - printf(" "); - } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); - printf("vert %d -> %d (add=%d)\n", - BM_elem_index_get(v), BM_elem_index_get(v_next), - BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); - } -#endif - - if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { - eo = STACK_PUSH_RET_PTR(edge_order); - eo->v = v_next; - - v_next->e = e_next; - } - } - } - -#ifdef USE_FASTPATH_NOFORK - if (STACK_SIZE(edge_order) == 1) { - eo = STACK_POP_PTR(edge_order); - v = eo->v; - - goto walk_nofork; - } -#endif - - /* sort by angle if needed */ - if (STACK_SIZE(edge_order) > 1) { - unsigned int j; - BMVert *v_prev = BM_edge_other_vert(v->e, v); - - for (j = 0; j < STACK_SIZE(edge_order); j++) { - edge_order[j].angle = angle_signed_on_axis_v3v3v3_v3(v_prev->co, v->co, edge_order[j].v->co, face_normal); - } - qsort(edge_order, STACK_SIZE(edge_order), sizeof(struct VertOrder), BLI_sortutil_cmp_float_reverse); - -#ifdef USE_FASTPATH_NOFORK - /* only tag forks */ - BLI_SMALLSTACK_PUSH(vert_visit, v); - BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT); -#endif - } - - while ((eo = STACK_POP_PTR(edge_order))) { - BLI_SMALLSTACK_PUSH(vert_stack_next, eo->v); - } - - if (!BLI_SMALLSTACK_IS_EMPTY(vert_stack_next)) { - BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next); - } - } - - -finally: - /* clear flag for next execution */ - while ((v = BLI_SMALLSTACK_POP(vert_visit))) { - BM_ELEM_API_FLAG_DISABLE(v, VERT_VISIT); - } - - return found; - -#undef USE_FASTPATH_NOFORK -} - -static bool bm_face_split_edgenet_find_loop( - BMVert *v_init, const float face_normal[3], - /* cache to avoid realloc every time */ - struct VertOrder *edge_order, const unsigned int edge_order_len, - BMVert **r_face_verts, int *r_face_verts_len) -{ - BMEdge *e_pair[2]; - BMVert *v; - - if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) { - return false; - } - - BLI_assert((bm_edge_flagged_radial_count(e_pair[0]) == 1) || - (bm_edge_flagged_radial_count(e_pair[1]) == 1)); - - if (bm_face_split_edgenet_find_loop_walk(v_init, face_normal, edge_order, edge_order_len, e_pair)) { - unsigned int i = 0; - - r_face_verts[i++] = v_init; - v = BM_edge_other_vert(e_pair[1], v_init); - do { - r_face_verts[i++] = v; - } while ((v = BM_edge_other_vert(v->e, v)) != v_init); - *r_face_verts_len = i; - return (i > 2) ? true : false; - } - else { - return false; - } -} - -/** - * Splits a face into many smaller faces defined by an edge-net. - * handle customdata and degenerate cases. - * - * - isolated holes or unsupported face configurations, will be ignored. - * - customdata calculations aren't efficient - * (need to calculate weights for each vert). - */ -bool BM_face_split_edgenet( - BMesh *bm, - BMFace *f, BMEdge **edge_net, const int edge_net_len, - BMFace ***r_face_arr, int *r_face_arr_len) -{ - /* re-use for new face verts */ - BMVert **face_verts; - int face_verts_len; - - BMFace **face_arr = NULL; - BLI_array_declare(face_arr); - - BMVert **vert_queue; - STACK_DECLARE(vert_queue); - int i; - - struct VertOrder *edge_order; - const unsigned int edge_order_len = edge_net_len + 2; - - BMVert *v; - - BMLoop *l_iter, *l_first; - - - if (!edge_net_len) { - if (r_face_arr) { - *r_face_arr = NULL; - *r_face_arr_len = 0; - } - return false; - } - - /* over-alloc (probably 2-4 is only used in most cases), for the biggest-fan */ - edge_order = BLI_array_alloca(edge_order, edge_order_len); - - /* use later */ - face_verts = BLI_array_alloca(face_verts, edge_net_len + f->len); - - vert_queue = BLI_array_alloca(vert_queue, edge_net_len + f->len); - STACK_INIT(vert_queue, f->len + edge_net_len); - - BLI_assert(BM_ELEM_API_FLAG_TEST(f, FACE_NET) == 0); - BM_ELEM_API_FLAG_ENABLE(f, FACE_NET); - -#ifdef DEBUG - for (i = 0; i < edge_net_len; i++) { - BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET) == 0); - BLI_assert(BM_edge_in_face(edge_net[i], f) == false); - } - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BLI_assert(BM_ELEM_API_FLAG_TEST(l_iter->e, EDGE_NET) == 0); - } while ((l_iter = l_iter->next) != l_first); -#endif - - - for (i = 0; i < edge_net_len; i++) { - BM_ELEM_API_FLAG_ENABLE(edge_net[i], EDGE_NET); - } - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET); - } while ((l_iter = l_iter->next) != l_first); - - - /* any vert can be used to begin with */ - STACK_PUSH(vert_queue, l_first->v); - - while ((v = STACK_POP(vert_queue))) { - if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) { - BMFace *f_new; - - f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false); - - for (i = 0; i < edge_net_len; i++) { - BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET)); - } - - if (f_new) { - bool l_prev_is_boundary; - BLI_array_append(face_arr, f_new); - copy_v3_v3(f_new->no, f->no); - - BM_ELEM_API_FLAG_ENABLE(f_new, FACE_NET); - - /* add new verts to keep finding loops for - * (verts between boundary and manifold edges) */ - l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); - l_prev_is_boundary = (bm_edge_flagged_radial_count(l_iter->prev->e) == 1); - do { - bool l_iter_is_boundary = (bm_edge_flagged_radial_count(l_iter->e) == 1); - if (l_prev_is_boundary != l_iter_is_boundary) { - STACK_PUSH(vert_queue, l_iter->v); - } - l_prev_is_boundary = l_iter_is_boundary; - } while ((l_iter = l_iter->next) != l_first); - } - } - } - - - if (CustomData_has_math(&bm->ldata)) { - /* reuse VERT_VISIT here to tag vert's already interpolated */ - BMIter iter; - BMLoop *l_other; - - /* see: #BM_loop_interp_from_face for similar logic */ - void **blocks = BLI_array_alloca(blocks, f->len); - float (*cos_2d)[2] = BLI_array_alloca(cos_2d, f->len); - float *w = BLI_array_alloca(w, f->len); - float axis_mat[3][3]; - float co[2]; - - /* interior loops */ - axis_dominant_v3_to_m3(axis_mat, f->no); - - - /* first simply copy from existing face */ - i = 0; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BM_ITER_ELEM (l_other, &iter, l_iter->v, BM_LOOPS_OF_VERT) { - if ((l_other->f != f) && BM_ELEM_API_FLAG_TEST(l_other->f, FACE_NET)) { - CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, - l_iter->head.data, &l_other->head.data); - } - } - /* tag not to interpolate */ - BM_ELEM_API_FLAG_ENABLE(l_iter->v, VERT_VISIT); - - - mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co); - blocks[i] = l_iter->head.data; - - } while (i++, (l_iter = l_iter->next) != l_first); - - - for (i = 0; i < edge_net_len; i++) { - BM_ITER_ELEM (v, &iter, edge_net[i], BM_VERTS_OF_EDGE) { - if (!BM_ELEM_API_FLAG_TEST(v, VERT_VISIT)) { - BMIter liter; - - BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT); - - /* interpolate this loop, then copy to the rest */ - l_first = NULL; - - BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) { - if (BM_ELEM_API_FLAG_TEST(l_iter->f, FACE_NET)) { - if (l_first == NULL) { - mul_v2_m3v3(co, axis_mat, v->co); - interp_weights_poly_v2(w, cos_2d, f->len, co); - CustomData_bmesh_interp( - &bm->ldata, (const void **)blocks, - w, NULL, f->len, l_iter->head.data); - l_first = l_iter; - } - else { - CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, - l_first->head.data, &l_iter->head.data); - } - } - } - } - } - } - } - - - - /* cleanup */ - for (i = 0; i < edge_net_len; i++) { - BM_ELEM_API_FLAG_DISABLE(edge_net[i], EDGE_NET); - /* from interp only */ - BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v1, VERT_VISIT); - BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v2, VERT_VISIT); - } - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BM_ELEM_API_FLAG_DISABLE(l_iter->e, EDGE_NET); - /* from interp only */ - BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_VISIT); - } while ((l_iter = l_iter->next) != l_first); - - if (BLI_array_count(face_arr)) { - bmesh_face_swap_data(f, face_arr[0]); - BM_face_kill(bm, face_arr[0]); - face_arr[0] = f; - } - else { - BM_ELEM_API_FLAG_DISABLE(f, FACE_NET); - } - - for (i = 0; i < BLI_array_count(face_arr); i++) { - BM_ELEM_API_FLAG_DISABLE(face_arr[i], FACE_NET); - } - - if (r_face_arr) { - *r_face_arr = face_arr; - *r_face_arr_len = BLI_array_count(face_arr); - } - else { - if (face_arr) { - MEM_freeN(face_arr); - } - } - - return true; -} - -#undef FACE_NET -#undef VERT_VISIT -#undef EDGE_NET - -/** \} */ - - /** * \brief Vert Collapse Faces * diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h index 142568e6e1a..2e557e3b606 100644 --- a/source/blender/bmesh/intern/bmesh_mods.h +++ b/source/blender/bmesh/intern/bmesh_mods.h @@ -27,14 +27,15 @@ * \ingroup bmesh */ -#include <stdio.h> - bool BM_vert_dissolve(BMesh *bm, BMVert *v); bool BM_disk_dissolve(BMesh *bm, BMVert *v); BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del); + +/** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */ + BMFace *BM_face_split( BMesh *bm, BMFace *f, BMLoop *l_a, BMLoop *l_b, @@ -47,11 +48,6 @@ BMFace *BM_face_split_n( float cos[][3], int n, BMLoop **r_l, BMEdge *example); -bool BM_face_split_edgenet( - BMesh *bm, BMFace *f, - BMEdge **edge_net, const int edge_net_len, - BMFace ***r_face_arr, int *r_face_arr_len); - BMEdge *BM_vert_collapse_faces( BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac, const bool do_del, const bool join_faces, const bool kill_degenerate_faces); diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index d92bdc6ea69..72a8dac534a 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -1567,6 +1567,7 @@ static BMOpDefine bmo_create_grid_def = { {"y_segments", BMO_OP_SLOT_INT}, /* number of y segments */ {"size", BMO_OP_SLOT_FLT}, /* size of the grid */ {"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */ + {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */ {{'\0'}}, }, /* slots_out */ @@ -1590,6 +1591,7 @@ static BMOpDefine bmo_create_uvsphere_def = { {"v_segments", BMO_OP_SLOT_INT}, /* number of v segment */ {"diameter", BMO_OP_SLOT_FLT}, /* diameter */ {"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */ + {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */ {{'\0'}}, }, /* slots_out */ @@ -1612,6 +1614,7 @@ static BMOpDefine bmo_create_icosphere_def = { {{"subdivisions", BMO_OP_SLOT_INT}, /* how many times to recursively subdivide the sphere */ {"diameter", BMO_OP_SLOT_FLT}, /* diameter */ {"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */ + {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */ {{'\0'}}, }, /* slots_out */ @@ -1658,6 +1661,7 @@ static BMOpDefine bmo_create_cone_def = { {"diameter2", BMO_OP_SLOT_FLT}, /* diameter of the opposite */ {"depth", BMO_OP_SLOT_FLT}, /* distance between ends */ {"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */ + {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */ {{'\0'}}, }, /* slots_out */ @@ -1680,6 +1684,7 @@ static BMOpDefine bmo_create_circle_def = { {"segments", BMO_OP_SLOT_INT}, {"diameter", BMO_OP_SLOT_FLT}, /* diameter of one end */ {"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */ + {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */ {{'\0'}}, }, /* slots_out */ @@ -1701,6 +1706,7 @@ static BMOpDefine bmo_create_cube_def = { /* slots_in */ {{"size", BMO_OP_SLOT_FLT}, /* size of the cube */ {"matrix", BMO_OP_SLOT_MAT}, /* matrix to multiply the new geometry with */ + {"calc_uvs", BMO_OP_SLOT_BOOL}, /* calculate default UVs */ {{'\0'}}, }, /* slots_out */ diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h index d9961e589da..0a4fb1d56a4 100644 --- a/source/blender/bmesh/intern/bmesh_operators.h +++ b/source/blender/bmesh/intern/bmesh_operators.h @@ -141,6 +141,14 @@ void BM_mesh_esubdivide( const short use_only_quads, const int seed); +void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag); +void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag); +void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag); +void BM_mesh_calc_uvs_cone( + BMesh *bm, float mat[4][4], + const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag); +void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag); + #include "intern/bmesh_operator_api_inline.h" #endif /* __BMESH_OPERATORS_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index af0331d7771..8d8db799afa 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -150,10 +150,14 @@ static void bm_face_calc_poly_center_mean_vertex_cos( /** * For tools that insist on using triangles, ideally we would cache this data. * - * \param r_loops Store face loop pointers, (f->len) - * \param r_index Store triangle triples, indices into \a r_loops, ((f->len - 2) * 3) + * \param use_fixed_quad: When true, always split quad along (0 -> 2) regardless of concave corners, + * (as done in #BM_mesh_calc_tessellation). + * \param r_loops: Store face loop pointers, (f->len) + * \param r_index: Store triangle triples, indices into \a r_loops, `((f->len - 2) * 3)` */ -void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (*r_index)[3]) +void BM_face_calc_tessellation( + const BMFace *f, const bool use_fixed_quad, + BMLoop **r_loops, unsigned int (*r_index)[3]) { BMLoop *l_first = BM_FACE_FIRST_LOOP(f); BMLoop *l_iter; @@ -167,7 +171,7 @@ void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int ( r_index[0][1] = 1; r_index[0][2] = 2; } - else if (f->len == 4) { + else if (f->len == 4 && use_fixed_quad) { *r_loops++ = (l_iter = l_first); *r_loops++ = (l_iter = l_iter->next); *r_loops++ = (l_iter = l_iter->next); @@ -202,6 +206,46 @@ void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int ( } /** + * Return a point inside the face. + */ +void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]) +{ + const BMLoop *l_tri[3]; + + if (f->len == 3) { + const BMLoop *l = BM_FACE_FIRST_LOOP(f); + ARRAY_SET_ITEMS(l_tri, l, l->next, l->prev); + } + else { + /* tessellation here seems overkill when in many cases this will be the center, + * but without this we can't be sure the point is inside a concave face. */ + const int tottri = f->len - 2; + BMLoop **loops = BLI_array_alloca(loops, f->len); + unsigned int (*index)[3] = BLI_array_alloca(index, tottri); + int j; + int j_best = 0; /* use as fallback when unset */ + float area_best = -1.0f; + + BM_face_calc_tessellation(f, false, loops, index); + + for (j = 0; j < tottri; j++) { + const float *p1 = loops[index[j][0]]->v->co; + const float *p2 = loops[index[j][1]]->v->co; + const float *p3 = loops[index[j][2]]->v->co; + const float area = area_squared_tri_v3(p1, p2, p3); + if (area > area_best) { + j_best = j; + area_best = area; + } + } + + ARRAY_SET_ITEMS(l_tri, loops[index[j_best][0]], loops[index[j_best][1]], loops[index[j_best][2]]); + } + + mid_v3_v3v3v3(r_co, l_tri[0]->v->co, l_tri[1]->v->co, l_tri[2]->v->co); +} + +/** * get the area of the face */ float BM_face_calc_area(const BMFace *f) diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index a1866bb010d..c84f4798ee4 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -34,7 +34,10 @@ struct Heap; void BM_bmesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot); -void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (*r_index)[3]); +void BM_face_calc_tessellation( + const BMFace *f, const bool use_fixed_quad, + BMLoop **r_loops, unsigned int (*r_index)[3]); +void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]); float BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL(); float BM_face_calc_normal_vcos( const BMesh *bm, const BMFace *f, float r_no[3], diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c new file mode 100644 index 00000000000..420fb26ca08 --- /dev/null +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -0,0 +1,1257 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/bmesh/intern/bmesh_polygon_edgenet.c + * \ingroup bmesh + * + * This file contains functions for splitting faces into isolated regions, + * defined by connected edges. + */ +// #define DEBUG_PRINT + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_array.h" +#include "BLI_alloca.h" +#include "BLI_stackdefines.h" +#include "BLI_linklist_stack.h" +#include "BLI_sort.h" +#include "BLI_sort_utils.h" +#include "BLI_kdopbvh.h" + +#include "BKE_customdata.h" + +#include "bmesh.h" +#include "intern/bmesh_private.h" + +/* -------------------------------------------------------------------- */ +/* Face Split Edge-Net */ + +/** \name BM_face_split_edgenet and helper functions. + * + * \note Don't use #BM_edge_is_wire or #BM_edge_is_boundary + * since we need to take flagged faces into account. + * Also take care accessing e->l directly. + * + * \{ */ + +/* Note: All these flags _must_ be cleared on exit */ + +/* face is apart of the edge-net (including the original face we're splitting) */ +#define FACE_NET _FLAG_WALK +/* edge is apart of the edge-net we're filling */ +#define EDGE_NET _FLAG_WALK +/* tag verts we've visit */ +#define VERT_VISIT _FLAG_WALK + +struct VertOrder { + float angle; + BMVert *v; +}; + +static unsigned int bm_edge_flagged_radial_count(BMEdge *e) +{ + unsigned int count = 0; + BMLoop *l; + + if ((l = e->l)) { + do { + if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) { + count++; + } + } while ((l = l->radial_next) != e->l); + } + return count; +} + +static BMLoop *bm_edge_flagged_radial_first(BMEdge *e) +{ + BMLoop *l; + + if ((l = e->l)) { + do { + if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) { + return l; + } + } while ((l = l->radial_next) != e->l); + } + return NULL; +} + +static bool bm_face_split_edgenet_find_loop_pair( + BMVert *v_init, const float face_normal[3], + BMEdge *e_pair[2]) +{ + /* Always find one boundary edge (to determine winding) + * and one wire (if available), otherwise another boundary. + */ + BMIter iter; + BMEdge *e; + + /* detect winding */ + BMLoop *l_walk; + bool swap; + + BLI_SMALLSTACK_DECLARE(edges_boundary, BMEdge *); + BLI_SMALLSTACK_DECLARE(edges_wire, BMEdge *); + int edges_boundary_len = 0; + int edges_wire_len = 0; + + BM_ITER_ELEM (e, &iter, v_init, BM_EDGES_OF_VERT) { + if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { + const unsigned int count = bm_edge_flagged_radial_count(e); + if (count == 1) { + BLI_SMALLSTACK_PUSH(edges_boundary, e); + edges_boundary_len++; + } + else if (count == 0) { + BLI_SMALLSTACK_PUSH(edges_wire, e); + edges_wire_len++; + } + } + } + + /* first edge should always be boundary */ + if (edges_boundary_len == 0) { + return false; + } + e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary); + + /* attempt one boundary and one wire, or 2 boundary */ + if (edges_wire_len == 0) { + if (edges_boundary_len >= 2) { + e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary); + } + else { + /* one boundary and no wire */ + return false; + } + } + else { + e_pair[1] = BLI_SMALLSTACK_POP(edges_wire); + + if (edges_wire_len > 1) { + BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); + BMVert *v_next; + float angle_best; + + v_next = BM_edge_other_vert(e_pair[1], v_init); + angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); + + while ((e = BLI_SMALLSTACK_POP(edges_wire))) { + float angle_test; + v_next = BM_edge_other_vert(e, v_init); + angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); + if (angle_test < angle_best) { + angle_best = angle_test; + e_pair[1] = e; + } + } + } + } + + + /* flip based on winding */ + l_walk = bm_edge_flagged_radial_first(e_pair[0]); + swap = false; + if (face_normal == l_walk->f->no) { + swap = !swap; + } + if (l_walk->v != v_init) { + swap = !swap; + } + if (swap) { + SWAP(BMEdge *, e_pair[0], e_pair[1]); + } + + return true; +} + +static bool bm_face_split_edgenet_find_loop_walk( + BMVert *v_init, const float face_normal[3], + /* cache to avoid realloc every time */ + struct VertOrder *edge_order, const unsigned int edge_order_len, + BMEdge *e_pair[2]) +{ + /* fast-path for the common case (avoid push-pop). + * Also avoids tagging as visited since we know we + * can't reach these verts some other way */ +#define USE_FASTPATH_NOFORK + + BMVert *v; + BMVert *v_dst; + bool found = false; + + struct VertOrder *eo; + STACK_DECLARE(edge_order); + + /* store visited verts so we can clear the visit flag after execution */ + BLI_SMALLSTACK_DECLARE(vert_visit, BMVert *); + + /* likely this will stay very small + * all verts pushed into this stack _must_ have their previous edges set! */ + BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *); + BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *); + + STACK_INIT(edge_order, edge_order_len); + + /* start stepping */ + v = BM_edge_other_vert(e_pair[0], v_init); + v->e = e_pair[0]; + BLI_SMALLSTACK_PUSH(vert_stack, v); + + v_dst = BM_edge_other_vert(e_pair[1], v_init); + +#ifdef DEBUG_PRINT + printf("%s: vert (search) %d\n", __func__, BM_elem_index_get(v_init)); +#endif + + /* This loop will keep stepping over the best possible edge, + * in most cases it finds the direct route to close the face. + * + * In cases where paths can't be closed, + * alternatives are stored in the 'vert_stack'. + */ + while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { + BMIter eiter; + BMEdge *e_next; + +#ifdef USE_FASTPATH_NOFORK +walk_nofork: +#else + BLI_SMALLSTACK_PUSH(vert_visit, v); + BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT); +#endif + + BLI_assert(STACK_SIZE(edge_order) == 0); + + /* check if we're done! */ + if (v == v_dst) { + found = true; + goto finally; + } + + BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { + if ((v->e != e_next) && + (BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && + (bm_edge_flagged_radial_count(e_next) < 2)) + { + BMVert *v_next; + + v_next = BM_edge_other_vert(e_next, v); + +#ifdef DEBUG_PRINT + /* indent and print */ + { + BMVert *_v = v; + do { + printf(" "); + } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); + printf("vert %d -> %d (add=%d)\n", + BM_elem_index_get(v), BM_elem_index_get(v_next), + BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); + } +#endif + + if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { + eo = STACK_PUSH_RET_PTR(edge_order); + eo->v = v_next; + + v_next->e = e_next; + } + } + } + +#ifdef USE_FASTPATH_NOFORK + if (STACK_SIZE(edge_order) == 1) { + eo = STACK_POP_PTR(edge_order); + v = eo->v; + + goto walk_nofork; + } +#endif + + /* sort by angle if needed */ + if (STACK_SIZE(edge_order) > 1) { + unsigned int j; + BMVert *v_prev = BM_edge_other_vert(v->e, v); + + for (j = 0; j < STACK_SIZE(edge_order); j++) { + edge_order[j].angle = angle_signed_on_axis_v3v3v3_v3(v_prev->co, v->co, edge_order[j].v->co, face_normal); + } + qsort(edge_order, STACK_SIZE(edge_order), sizeof(struct VertOrder), BLI_sortutil_cmp_float_reverse); + +#ifdef USE_FASTPATH_NOFORK + /* only tag forks */ + BLI_SMALLSTACK_PUSH(vert_visit, v); + BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT); +#endif + } + + while ((eo = STACK_POP_PTR(edge_order))) { + BLI_SMALLSTACK_PUSH(vert_stack_next, eo->v); + } + + if (!BLI_SMALLSTACK_IS_EMPTY(vert_stack_next)) { + BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next); + } + } + + +finally: + /* clear flag for next execution */ + while ((v = BLI_SMALLSTACK_POP(vert_visit))) { + BM_ELEM_API_FLAG_DISABLE(v, VERT_VISIT); + } + + return found; + +#undef USE_FASTPATH_NOFORK +} + +static bool bm_face_split_edgenet_find_loop( + BMVert *v_init, const float face_normal[3], + /* cache to avoid realloc every time */ + struct VertOrder *edge_order, const unsigned int edge_order_len, + BMVert **r_face_verts, int *r_face_verts_len) +{ + BMEdge *e_pair[2]; + BMVert *v; + + if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) { + return false; + } + + BLI_assert((bm_edge_flagged_radial_count(e_pair[0]) == 1) || + (bm_edge_flagged_radial_count(e_pair[1]) == 1)); + + if (bm_face_split_edgenet_find_loop_walk(v_init, face_normal, edge_order, edge_order_len, e_pair)) { + unsigned int i = 0; + + r_face_verts[i++] = v_init; + v = BM_edge_other_vert(e_pair[1], v_init); + do { + r_face_verts[i++] = v; + } while ((v = BM_edge_other_vert(v->e, v)) != v_init); + *r_face_verts_len = i; + return (i > 2) ? true : false; + } + else { + return false; + } +} + +/** + * Splits a face into many smaller faces defined by an edge-net. + * handle customdata and degenerate cases. + * + * - isolated holes or unsupported face configurations, will be ignored. + * - customdata calculations aren't efficient + * (need to calculate weights for each vert). + */ +bool BM_face_split_edgenet( + BMesh *bm, + BMFace *f, BMEdge **edge_net, const int edge_net_len, + BMFace ***r_face_arr, int *r_face_arr_len) +{ + /* re-use for new face verts */ + BMVert **face_verts; + int face_verts_len; + + BMFace **face_arr = NULL; + BLI_array_declare(face_arr); + + BMVert **vert_queue; + STACK_DECLARE(vert_queue); + int i; + + struct VertOrder *edge_order; + const unsigned int edge_order_len = edge_net_len + 2; + + BMVert *v; + + BMLoop *l_iter, *l_first; + + + if (!edge_net_len) { + if (r_face_arr) { + *r_face_arr = NULL; + *r_face_arr_len = 0; + } + return false; + } + + /* over-alloc (probably 2-4 is only used in most cases), for the biggest-fan */ + edge_order = BLI_array_alloca(edge_order, edge_order_len); + + /* use later */ + face_verts = BLI_array_alloca(face_verts, edge_net_len + f->len); + + vert_queue = BLI_array_alloca(vert_queue, edge_net_len + f->len); + STACK_INIT(vert_queue, f->len + edge_net_len); + + BLI_assert(BM_ELEM_API_FLAG_TEST(f, FACE_NET) == 0); + BM_ELEM_API_FLAG_ENABLE(f, FACE_NET); + +#ifdef DEBUG + for (i = 0; i < edge_net_len; i++) { + BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET) == 0); + BLI_assert(BM_edge_in_face(edge_net[i], f) == false); + } + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BLI_assert(BM_ELEM_API_FLAG_TEST(l_iter->e, EDGE_NET) == 0); + } while ((l_iter = l_iter->next) != l_first); +#endif + + + for (i = 0; i < edge_net_len; i++) { + BM_ELEM_API_FLAG_ENABLE(edge_net[i], EDGE_NET); + } + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET); + } while ((l_iter = l_iter->next) != l_first); + + + /* any vert can be used to begin with */ + STACK_PUSH(vert_queue, l_first->v); + + while ((v = STACK_POP(vert_queue))) { + if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) { + BMFace *f_new; + + f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false); + + for (i = 0; i < edge_net_len; i++) { + BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET)); + } + + if (f_new) { + bool l_prev_is_boundary; + BLI_array_append(face_arr, f_new); + copy_v3_v3(f_new->no, f->no); + + /* warning, normally don't do this, + * its needed for mesh intersection - which tracks face-sides based on selection */ + f_new->head.hflag = f->head.hflag; + if (f->head.hflag & BM_ELEM_SELECT) { + bm->totfacesel++; + } + + BM_ELEM_API_FLAG_ENABLE(f_new, FACE_NET); + + /* add new verts to keep finding loops for + * (verts between boundary and manifold edges) */ + l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); + l_prev_is_boundary = (bm_edge_flagged_radial_count(l_iter->prev->e) == 1); + do { + bool l_iter_is_boundary = (bm_edge_flagged_radial_count(l_iter->e) == 1); + if (l_prev_is_boundary != l_iter_is_boundary) { + STACK_PUSH(vert_queue, l_iter->v); + } + l_prev_is_boundary = l_iter_is_boundary; + } while ((l_iter = l_iter->next) != l_first); + } + } + } + + + if (CustomData_has_math(&bm->ldata)) { + /* reuse VERT_VISIT here to tag vert's already interpolated */ + BMIter iter; + BMLoop *l_other; + + /* see: #BM_loop_interp_from_face for similar logic */ + void **blocks = BLI_array_alloca(blocks, f->len); + float (*cos_2d)[2] = BLI_array_alloca(cos_2d, f->len); + float *w = BLI_array_alloca(w, f->len); + float axis_mat[3][3]; + float co[2]; + + /* interior loops */ + axis_dominant_v3_to_m3(axis_mat, f->no); + + + /* first simply copy from existing face */ + i = 0; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_ITER_ELEM (l_other, &iter, l_iter->v, BM_LOOPS_OF_VERT) { + if ((l_other->f != f) && BM_ELEM_API_FLAG_TEST(l_other->f, FACE_NET)) { + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, + l_iter->head.data, &l_other->head.data); + } + } + /* tag not to interpolate */ + BM_ELEM_API_FLAG_ENABLE(l_iter->v, VERT_VISIT); + + + mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co); + blocks[i] = l_iter->head.data; + + } while (i++, (l_iter = l_iter->next) != l_first); + + + for (i = 0; i < edge_net_len; i++) { + BM_ITER_ELEM (v, &iter, edge_net[i], BM_VERTS_OF_EDGE) { + if (!BM_ELEM_API_FLAG_TEST(v, VERT_VISIT)) { + BMIter liter; + + BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT); + + /* interpolate this loop, then copy to the rest */ + l_first = NULL; + + BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) { + if (BM_ELEM_API_FLAG_TEST(l_iter->f, FACE_NET)) { + if (l_first == NULL) { + mul_v2_m3v3(co, axis_mat, v->co); + interp_weights_poly_v2(w, cos_2d, f->len, co); + CustomData_bmesh_interp( + &bm->ldata, (const void **)blocks, + w, NULL, f->len, l_iter->head.data); + l_first = l_iter; + } + else { + CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, + l_first->head.data, &l_iter->head.data); + } + } + } + } + } + } + } + + + + /* cleanup */ + for (i = 0; i < edge_net_len; i++) { + BM_ELEM_API_FLAG_DISABLE(edge_net[i], EDGE_NET); + /* from interp only */ + BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v1, VERT_VISIT); + BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v2, VERT_VISIT); + } + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_ELEM_API_FLAG_DISABLE(l_iter->e, EDGE_NET); + /* from interp only */ + BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_VISIT); + } while ((l_iter = l_iter->next) != l_first); + + if (BLI_array_count(face_arr)) { + bmesh_face_swap_data(f, face_arr[0]); + BM_face_kill(bm, face_arr[0]); + face_arr[0] = f; + } + else { + BM_ELEM_API_FLAG_DISABLE(f, FACE_NET); + } + + for (i = 0; i < BLI_array_count(face_arr); i++) { + BM_ELEM_API_FLAG_DISABLE(face_arr[i], FACE_NET); + } + + if (r_face_arr) { + *r_face_arr = face_arr; + *r_face_arr_len = BLI_array_count(face_arr); + } + else { + if (face_arr) { + MEM_freeN(face_arr); + } + } + + return true; +} + +#undef FACE_NET +#undef VERT_VISIT +#undef EDGE_NET + +/** \} */ + + +/* -------------------------------------------------------------------- */ +/* Face Split Edge-Net Connect Islands */ + +/** \name BM_face_split_edgenet_connect_islands and helper functions. + * + * Connect isolated mesh 'islands' so they form legal regions from which we can create faces. + * + * Intended to be used as a pre-processing step for #BM_face_split_edgenet. + * + * \warning Currently this risks running out of stack memory (#alloca), + * likely we'll pass in a memory arena (cleared each use) eventually. + * + * \{ */ + +#define VERT_IS_VALID BM_ELEM_INTERNAL_TAG + +/* can be X or Y */ +#define SORT_AXIS 0 + +BLI_INLINE bool edge_isect_verts_point_2d( + const BMEdge *e, const BMVert *v_a, const BMVert *v_b, + float r_isect[2]) +{ + return ((isect_seg_seg_v2_point(v_a->co, v_b->co, e->v1->co, e->v2->co, r_isect) == 1) && + ((e->v1 != v_a) && (e->v2 != v_a) && (e->v1 != v_b) && (e->v2 != v_b))); +} + +/** + * Represents isolated edge-links, + * each island owns contiguous slices of the vert array. + * (edges remain in `edge_links`). + */ +struct EdgeGroupIsland { + LinkNode edge_links; /* keep first */ + unsigned int vert_len, edge_len; + + /* Set the following vars once we have >1 groups */ + + /* when when an edge in a previous group connects to this one, + * so theres no need to create one pointing back. */ + unsigned int has_prev_edge : 1; + + /* verts in the group which has the lowest & highest values, + * the lower vertex is connected to the first edge */ + struct { + BMVert *min, *max; + /* used for sorting only */ + float min_axis; + } vert_span; +}; + +static int group_min_cmp_fn(const void *p1, const void *p2) +{ + const struct EdgeGroupIsland *g1 = *(struct EdgeGroupIsland **)p1; + const struct EdgeGroupIsland *g2 = *(struct EdgeGroupIsland **)p2; + /* min->co[SORT_AXIS] hasn't been applied yet */ + const float f1 = g1->vert_span.min_axis; + const float f2 = g2->vert_span.min_axis; + + if (f1 < f2) return -1; + if (f1 > f2) return 1; + else return 0; +} + +struct Edges_VertVert_BVHTreeTest { + float dist_orig; + BMEdge **edge_arr; + + BMVert *v_origin; + BMVert *v_other; + + const unsigned int *vert_range; +}; + +struct Edges_VertRay_BVHTreeTest { + BMEdge **edge_arr; + + BMVert *v_origin; + + const unsigned int *vert_range; +}; + +static void bvhtree_test_edges_isect_2d_vert_cb( + void *user_data, int index, const BVHTreeRay *UNUSED(ray), BVHTreeRayHit *hit) +{ + struct Edges_VertVert_BVHTreeTest *data = user_data; + const BMEdge *e = data->edge_arr[index]; + const int v1_index = BM_elem_index_get(e->v1); + float co_isect[2]; + + if (edge_isect_verts_point_2d(e, data->v_origin, data->v_other, co_isect)) { + const float t = line_point_factor_v2(co_isect, data->v_origin->co, data->v_other->co); + const float dist_new = data->dist_orig * t; + /* avoid float precision issues, possible this is greater */ + if (LIKELY(dist_new < hit->dist)) { + /* v1/v2 will both be in the same group */ + if (v1_index < (int)data->vert_range[0] || + v1_index >= (int)data->vert_range[1]) + { + hit->dist = dist_new; + hit->index = index; + } + } + } +} + +static void bvhtree_test_edges_isect_2d_ray_cb( + void *user_data, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + struct Edges_VertRay_BVHTreeTest *data = user_data; + const BMEdge *e = data->edge_arr[index]; + + /* direction is normalized, so this will be the distance */ + float dist_new; + if (isect_ray_seg_v2(data->v_origin->co, ray->direction, e->v1->co, e->v2->co, &dist_new, NULL)) { + /* avoid float precision issues, possible this is greater */ + if (LIKELY(dist_new < hit->dist)) { + if (e->v1 != data->v_origin && e->v2 != data->v_origin) { + const int v1_index = BM_elem_index_get(e->v1); + /* v1/v2 will both be in the same group */ + if (v1_index < (int)data->vert_range[0] || + v1_index >= (int)data->vert_range[1]) + { + hit->dist = dist_new; + hit->index = index; + } + } + } + } +} + +/** + * Store values for: + * - #bm_face_split_edgenet_find_connection + * - #test_edges_isect_2d + * ... which don't change each call. + */ +struct EdgeGroup_FindConnection_Args { + BVHTree *bvhtree; + BMEdge **edge_arr; + unsigned int edge_arr_len; + + BMEdge **edge_arr_new; + unsigned int edge_arr_new_len; + + const unsigned int *vert_range; +}; + +static BMEdge *test_edges_isect_2d_vert( + const struct EdgeGroup_FindConnection_Args *args, + BMVert *v_origin, BMVert *v_other) +{ + int index; + + BVHTreeRayHit hit = {0}; + float dir[3]; + + sub_v2_v2v2(dir, v_other->co, v_origin->co); + dir[2] = 0.0f; + hit.index = -1; + hit.dist = normalize_v2(dir); + + struct Edges_VertVert_BVHTreeTest user_data = {0}; + user_data.dist_orig = hit.dist; + user_data.edge_arr = args->edge_arr; + user_data.v_origin = v_origin; + user_data.v_other = v_other; + user_data.vert_range = args->vert_range; + + index = BLI_bvhtree_ray_cast_ex( + args->bvhtree, v_origin->co, dir, 0.0f, &hit, + bvhtree_test_edges_isect_2d_vert_cb, &user_data, 0); + + BMEdge *e_hit = (index != -1) ? args->edge_arr[index] : NULL; + + /* check existing connections (no spatial optimization here since we're continually adding). */ + if (LIKELY(index == -1)) { + float t_best = 1.0f; + for (unsigned int i = 0; i < args->edge_arr_new_len; i++) { + float co_isect[2]; + if (UNLIKELY(edge_isect_verts_point_2d(args->edge_arr_new[i], v_origin, v_other, co_isect))) { + const float t_test = line_point_factor_v2(co_isect, v_origin->co, v_other->co); + if (t_test < t_best) { + t_best = t_test; + + e_hit = args->edge_arr_new[i]; + } + } + } + } + + return e_hit; +} + +/** + * Similar to #test_edges_isect_2d_vert but we're casting into a direction, + * (not to a vertex) + */ +static BMEdge *test_edges_isect_2d_ray( + const struct EdgeGroup_FindConnection_Args *args, + BMVert *v_origin, const float dir[3]) +{ + int index; + BVHTreeRayHit hit = {0}; + + BLI_ASSERT_UNIT_V2(dir); + + hit.index = -1; + hit.dist = FLT_MAX; + + struct Edges_VertRay_BVHTreeTest user_data = {0}; + user_data.edge_arr = args->edge_arr; + user_data.v_origin = v_origin; + user_data.vert_range = args->vert_range; + + index = BLI_bvhtree_ray_cast_ex( + args->bvhtree, v_origin->co, dir, 0.0f, &hit, + bvhtree_test_edges_isect_2d_ray_cb, &user_data, 0); + + BMEdge *e_hit = (index != -1) ? args->edge_arr[index] : NULL; + + /* check existing connections (no spatial optimization here since we're continually adding). */ + if (LIKELY(index != -1)) { + for (unsigned int i = 0; i < args->edge_arr_new_len; i++) { + BMEdge *e = args->edge_arr_new[i]; + float dist_new; + if (isect_ray_seg_v2(v_origin->co, dir, e->v1->co, e->v2->co, &dist_new, NULL)) { + if (e->v1 != v_origin && e->v2 != v_origin) { + /* avoid float precision issues, possible this is greater */ + if (LIKELY(dist_new < hit.dist)) { + hit.dist = dist_new; + + e_hit = args->edge_arr_new[i]; + } + } + } + } + } + + return e_hit; +} + +static int bm_face_split_edgenet_find_connection( + const struct EdgeGroup_FindConnection_Args *args, + BMVert *v_origin, + /* false = negative, true = positive */ + bool direction_sign) +{ + /** + * Method for finding connection is as follows: + * + * - Cast a ray along either the positive or negative directions. + * - Take the hit-edge, and cast rays to their vertices checking those rays don't intersect a closer edge. + * - Keep taking the hit-edge and testing its verts until a vertex is found which isn't blocked by an edge. + * + * \note It's possible none of the verts can be accessed (with self-intersecting lines). + * In that case theres no right answer (without subdividing edges), + * so return a fall-back vertex in that case. + */ + + const float dir[3] = {[SORT_AXIS] = direction_sign ? 1.0f : -1.0f}; + BMEdge *e_hit = test_edges_isect_2d_ray(args, v_origin, dir); + BMVert *v_other = NULL; + + if (e_hit) { + BMVert *v_other_fallback = NULL; + + BLI_SMALLSTACK_DECLARE(vert_search, BMVert *); + + /* ensure we never add verts multiple times (not all that likely - but possible) */ + BLI_SMALLSTACK_DECLARE(vert_blacklist, BMVert *); + + do { + BMVert *v_pair[2]; + /* ensure the closest vertex is popped back off the stack first */ + if (len_squared_v2v2(v_origin->co, e_hit->v1->co) > + len_squared_v2v2(v_origin->co, e_hit->v2->co)) + { + ARRAY_SET_ITEMS(v_pair, e_hit->v1, e_hit->v2); + } + else { + ARRAY_SET_ITEMS(v_pair, e_hit->v2, e_hit->v1); + } + + for (int j = 0; j < 2; j++) { + BMVert *v_iter = v_pair[j]; + if (BM_elem_flag_test(v_iter, VERT_IS_VALID)) { + if (direction_sign ? (v_iter->co[SORT_AXIS] >= v_origin->co[SORT_AXIS]) : + (v_iter->co[SORT_AXIS] <= v_origin->co[SORT_AXIS])) + { + BLI_SMALLSTACK_PUSH(vert_search, v_iter); + BLI_SMALLSTACK_PUSH(vert_blacklist, v_iter); + BM_elem_flag_disable(v_iter, VERT_IS_VALID); + } + } + } + v_other_fallback = v_other; + + } while ((v_other = BLI_SMALLSTACK_POP(vert_search)) && + (e_hit = test_edges_isect_2d_vert(args, v_origin, v_other))); + + if (v_other == NULL) { + printf("Using fallback\n"); + v_other = v_other_fallback; + } + + /* reset the blacklist flag, for future use */ + BMVert *v; + while ((v = BLI_SMALLSTACK_POP(vert_blacklist))) { + BM_elem_flag_enable(v, VERT_IS_VALID); + } + } + + /* if we reach this line, v_other is either the best vertex or its NULL */ + return v_other ? BM_elem_index_get(v_other) : -1; +} + +/** + * For when the edge-net has holes in it-this connects them. + * + * \param mem_arena: Avoids many small allocs & should be cleared after each use. + * take care since \a r_edge_net_new is stored in \a r_edge_net_new. + */ +bool BM_face_split_edgenet_connect_islands( + BMesh *bm, + BMFace *f, BMEdge **edge_net_init, const unsigned int edge_net_init_len, + MemArena *mem_arena, + BMEdge ***r_edge_net_new, unsigned int *r_edge_net_new_len) +{ + /* -------------------------------------------------------------------- */ + /* This function has 2 main parts. + * + * - Check if there are any holes. + * - Connect the holes with edges (if any are found). + * + * Keep the first part fast since it will run very often for edge-nets that have no holes. + * + * \note Don't use the mem_arena unless he have holes to fill. + * (avoid thrashing the area when the initial check isn't so intensive on the stack). + */ + + const unsigned int edge_arr_len = (unsigned int)edge_net_init_len + (unsigned int)f->len; + BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len); + bool ok = false; + + memcpy(edge_arr, edge_net_init, sizeof(*edge_arr) * (size_t)edge_net_init_len); + + /* _must_ clear on exit */ +#define EDGE_NOT_IN_STACK BM_ELEM_INTERNAL_TAG +#define VERT_NOT_IN_STACK BM_ELEM_INTERNAL_TAG + + { + unsigned int i = edge_net_init_len; + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + edge_arr[i++] = l_iter->e; + } while ((l_iter = l_iter->next) != l_first); + BLI_assert(i == edge_arr_len); + } + + for (unsigned int i = 0; i < edge_arr_len; i++) { + BM_elem_flag_enable(edge_arr[i], EDGE_NOT_IN_STACK); + BM_elem_flag_enable(edge_arr[i]->v1, VERT_NOT_IN_STACK); + BM_elem_flag_enable(edge_arr[i]->v2, VERT_NOT_IN_STACK); + } + + unsigned int group_arr_len = 0; + LinkNode *group_head = NULL; + { + /* scan 'edge_arr' backwards so the outer face boundary is handled first + * (since its likely to be the largest) */ + unsigned int edge_index = (edge_arr_len - 1); + unsigned int edge_in_group_tot = 0; + + BLI_SMALLSTACK_DECLARE(vstack, BMVert *); + + while (true) { + LinkNode *edge_links = NULL; + unsigned int unique_verts_in_group = 0, unique_edges_in_group = 0; + + /* list of groups */ + BLI_assert(BM_elem_flag_test(edge_arr[edge_index]->v1, VERT_NOT_IN_STACK)); + BLI_SMALLSTACK_PUSH(vstack, edge_arr[edge_index]->v1); + BM_elem_flag_disable(edge_arr[edge_index]->v1, VERT_NOT_IN_STACK); + + BMVert *v_iter; + while ((v_iter = BLI_SMALLSTACK_POP(vstack))) { + unique_verts_in_group++; + + BMEdge *e_iter = v_iter->e; + do { + if (BM_elem_flag_test(e_iter, EDGE_NOT_IN_STACK)) { + BM_elem_flag_disable(e_iter, EDGE_NOT_IN_STACK); + unique_edges_in_group++; + + BLI_linklist_prepend_alloca(&edge_links, e_iter); + + BMVert *v_other = BM_edge_other_vert(e_iter, v_iter); + if (BM_elem_flag_test(v_other, VERT_NOT_IN_STACK)) { + BLI_SMALLSTACK_PUSH(vstack, v_other); + BM_elem_flag_disable(v_other, VERT_NOT_IN_STACK); + } + } + } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v_iter)) != v_iter->e); + } + + struct EdgeGroupIsland *g = alloca(sizeof(*g)); + g->vert_len = unique_verts_in_group; + g->edge_len = unique_edges_in_group; + edge_in_group_tot += unique_edges_in_group; + + BLI_linklist_prepend_nlink(&group_head, edge_links, (LinkNode *)g); + + group_arr_len++; + + if (edge_in_group_tot == edge_arr_len) { + break; + } + + /* skip edges in the stack */ + while (BM_elem_flag_test(edge_arr[edge_index], EDGE_NOT_IN_STACK) == false) { + BLI_assert(edge_index != 0); + edge_index--; + } + } + } + + /* single group - no holes */ + if (group_arr_len == 1) { + goto finally; + } + + + /* -------------------------------------------------------------------- */ + /* Previous checks need to be kept fast, since they will run very often, + * now we know there are holes, so calculate a spatial lookup info and + * other per-group data. + */ + + float axis_mat[3][3]; + axis_dominant_v3_to_m3(axis_mat, f->no); + +#define VERT_IN_ARRAY BM_ELEM_INTERNAL_TAG + + struct EdgeGroupIsland **group_arr = BLI_memarena_alloc(mem_arena, sizeof(*group_arr) * group_arr_len); + unsigned int vert_arr_len = 0; + /* sort groups by lowest value vertex */ + { + /* fill 'groups_arr' in reverse order so the boundary face is first */ + struct EdgeGroupIsland **group_arr_p = &group_arr[group_arr_len]; + + for (struct EdgeGroupIsland *g = (void *)group_head; g; g = (struct EdgeGroupIsland *)g->edge_links.next) { + LinkNode *edge_links = g->edge_links.link; + + /* init with *any* different verts */ + g->vert_span.min = ((BMEdge *)edge_links->link)->v1; + g->vert_span.max = ((BMEdge *)edge_links->link)->v2; + float min_axis = FLT_MAX; + float max_axis = -FLT_MAX; + + do { + BMEdge *e = edge_links->link; + BLI_assert(e->head.htype == BM_EDGE); + + for (int j = 0; j < 2; j++) { + BMVert *v_iter = (&e->v1)[j]; + BLI_assert(v_iter->head.htype == BM_VERT); + /* ideally we could use 'v_iter->co[SORT_AXIS]' here, + * but we need to sort the groups before setting the vertex array order */ +#if SORT_AXIS == 0 + const float axis_value = dot_m3_v3_row_x(axis_mat, v_iter->co); +#else + const float axis_value = dot_m3_v3_row_y(axis_mat, v_iter->co); +#endif + + if (axis_value < min_axis) { + g->vert_span.min = v_iter; + min_axis = axis_value; + } + if (axis_value > max_axis ) { + g->vert_span.max = v_iter; + max_axis = axis_value; + } + } + } while ((edge_links = edge_links->next)); + + g->vert_span.min_axis = min_axis; + + g->has_prev_edge = false; + + vert_arr_len += g->vert_len; + + *(--group_arr_p) = g; + } + } + + qsort(group_arr, group_arr_len, sizeof(*group_arr), group_min_cmp_fn); + + /* we don't know how many unique verts there are connecting the edges, so over-alloc */ + BMVert **vert_arr = BLI_memarena_alloc(mem_arena, sizeof(*vert_arr) * vert_arr_len); + /* map vertex -> group index */ + unsigned int *verts_group_table = BLI_memarena_alloc(mem_arena, sizeof(*verts_group_table) * vert_arr_len); + + float (*vert_coords_backup)[3] = BLI_memarena_alloc(mem_arena, sizeof(*vert_coords_backup) * vert_arr_len); + + { + /* relative location, for higher precision calculations */ + const float f_co_ref[3] = {UNPACK3(BM_FACE_FIRST_LOOP(f)->v->co)}; + + int v_index = 0; /* global vert index */ + for (unsigned int g_index = 0; g_index < group_arr_len; g_index++) { + LinkNode *edge_links = group_arr[g_index]->edge_links.link; + do { + BMEdge *e = edge_links->link; + for (int j = 0; j < 2; j++) { + BMVert *v_iter = (&e->v1)[j]; + if (!BM_elem_flag_test(v_iter, VERT_IN_ARRAY)) { + BM_elem_flag_enable(v_iter, VERT_IN_ARRAY); + + /* not nice, but alternatives arent much better :S */ + { + copy_v3_v3(vert_coords_backup[v_index], v_iter->co); + + /* for higher precision */ + sub_v3_v3(v_iter->co, f_co_ref); + + float co_2d[2]; + mul_v2_m3v3(co_2d, axis_mat, v_iter->co); + v_iter->co[0] = co_2d[0]; + v_iter->co[1] = co_2d[1]; + v_iter->co[2] = 0.0f; + } + + BM_elem_index_set(v_iter, v_index); /* set_dirty */ + + vert_arr[v_index] = v_iter; + verts_group_table[v_index] = g_index; + v_index++; + } + } + } while ((edge_links = edge_links->next)); + } + } + + bm->elem_index_dirty |= BM_VERT; + + /* Now create bvh tree*/ + BVHTree *bvhtree = BLI_bvhtree_new(edge_arr_len, 0.0f, 8, 8); + for (unsigned int i = 0; i < edge_arr_len; i++) { + const float e_cos[2][3] = { + {UNPACK2(edge_arr[i]->v1->co), 0.0f}, + {UNPACK2(edge_arr[i]->v2->co), 0.0f}, + }; + BLI_bvhtree_insert(bvhtree, i, (const float *)e_cos, 2); + } + BLI_bvhtree_balance(bvhtree); + + /* Create connections between groups */ + + /* may be an over-alloc, but not by much */ + unsigned int edge_net_new_len = (unsigned int)edge_net_init_len + ((group_arr_len - 1) * 2); + BMEdge **edge_net_new = BLI_memarena_alloc(mem_arena, sizeof(*edge_net_new) * edge_net_new_len); + memcpy(edge_net_new, edge_net_init, sizeof(*edge_net_new) * (size_t)edge_net_init_len); + + { + unsigned int edge_net_new_index = edge_net_init_len; + /* start-end of the verts in the current group */ + + unsigned int vert_range[2]; + + vert_range[0] = 0; + vert_range[1] = group_arr[0]->vert_len; + + struct EdgeGroup_FindConnection_Args args = { + .bvhtree = bvhtree, + + /* use the new edge array so we can scan edges which have been added */ + .edge_arr = edge_arr, + .edge_arr_len = edge_arr_len, + + /* we only want to check newly created edges */ + .edge_arr_new = edge_net_new + edge_net_init_len, + .edge_arr_new_len = 0, + + .vert_range = vert_range, + }; + + for (unsigned int g_index = 1; g_index < group_arr_len; g_index++) { + struct EdgeGroupIsland *g = group_arr[g_index]; + + /* the range of verts this group uses in 'verts_arr' (not uncluding the last index) */ + vert_range[0] = vert_range[1]; + vert_range[1] += g->vert_len; + + if (g->has_prev_edge == false) { + BMVert *v_origin = g->vert_span.min; + + const int index_other = bm_face_split_edgenet_find_connection(&args, v_origin, false); + // BLI_assert(index_other >= 0 && index_other < (int)vert_arr_len); + + /* only for degenerate geometry */ + if (index_other != -1) { + BMVert *v_end = vert_arr[index_other]; + + edge_net_new[edge_net_new_index] = BM_edge_create(bm, v_origin, v_end, NULL, 0); + edge_net_new_index++; + args.edge_arr_new_len++; + } + } + + { + BMVert *v_origin = g->vert_span.max; + + const int index_other = bm_face_split_edgenet_find_connection(&args, v_origin, true); + // BLI_assert(index_other >= 0 && index_other < (int)vert_arr_len); + + /* only for degenerate geometry */ + if (index_other != -1) { + BMVert *v_end = vert_arr[index_other]; + + edge_net_new[edge_net_new_index] = BM_edge_create(bm, v_origin, v_end, NULL, 0); + edge_net_new_index++; + args.edge_arr_new_len++; + + /* tell the 'next' group it doesn't need to create its own back-link */ + unsigned int g_index_other = verts_group_table[index_other]; + group_arr[g_index_other]->has_prev_edge = true; + } + } + + } + BLI_assert(edge_net_new_len >= edge_net_new_index); + edge_net_new_len = edge_net_new_index; + } + + BLI_bvhtree_free(bvhtree); + + *r_edge_net_new = edge_net_new; + *r_edge_net_new_len = edge_net_new_len; + ok = true; + + for (unsigned int i = 0; i < vert_arr_len; i++) { + copy_v3_v3(vert_arr[i]->co, vert_coords_backup[i]); + } + +finally: + for (unsigned int i = 0; i < edge_arr_len; i++) { + BM_elem_flag_disable(edge_arr[i], EDGE_NOT_IN_STACK); + BM_elem_flag_disable(edge_arr[i]->v1, VERT_NOT_IN_STACK); + BM_elem_flag_disable(edge_arr[i]->v2, VERT_NOT_IN_STACK); + } + +#undef VERT_IN_ARRAY +#undef VERT_NOT_IN_STACK +#undef EDGE_NOT_IN_STACK + + return ok; +} + +#undef SORT_AXIS + +/** \} */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h index 9f2039b4c6f..b6642319fe6 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.h @@ -15,29 +15,26 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * * ***** END GPL LICENSE BLOCK ***** */ -/** \file RAS_GLExtensionManager.h - * \ingroup bgerastogl - */ +#ifndef __BMESH_POLYGON_EDGENET_H__ +#define __BMESH_POLYGON_EDGENET_H__ -#ifndef __RAS_GLEXTENSIONMANAGER_H__ -#define __RAS_GLEXTENSIONMANAGER_H__ +/** \file blender/bmesh/intern/bmesh_polygon_edgenet.h + * \ingroup bmesh + */ -/** Note: this used to have a lot more code, but now extension handling - * is done by GLEW, so it does mostly debug stuff */ +bool BM_face_split_edgenet( + BMesh *bm, BMFace *f, + BMEdge **edge_net, const int edge_net_len, + BMFace ***r_face_arr, int *r_face_arr_len); -namespace bgl -{ - void InitExtensions(bool debug); -} /* namespace bgl */ +bool BM_face_split_edgenet_connect_islands( + BMesh *bm, + BMFace *f, BMEdge **edge_net_init, const unsigned int edge_net_init_len, + struct MemArena *arena, + BMEdge ***r_edge_net_new, unsigned int *r_edge_net_new_len) +ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3, 5, 6, 7); -#endif /* __RAS_GLEXTENSIONMANAGER_H__ */ +#endif /* __BMESH_POLYGON_EDGENET_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 1a8ea1e3a0d..e7a93c6aad5 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -2299,7 +2299,7 @@ static void bm_mesh_calc_volume_face(const BMFace *f, float *r_vol) unsigned int (*index)[3] = BLI_array_alloca(index, tottri); int j; - BM_face_calc_tessellation(f, loops, index); + BM_face_calc_tessellation(f, false, loops, index); for (j = 0; j < tottri; j++) { const float *p1 = loops[index[j][0]]->v->co; @@ -2339,8 +2339,7 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed) * (or when hflag_test is set, the number of flagged faces). * \param r_group_index index, length pairs into \a r_groups_array, size of return value * int pairs: (array_start, array_length). - * \param filter_fn Filter the edges or verts we step over (depends on \a htype_step) - * as to which types we deal with. + * \param filter_fn Filter the edge-loops or vert-loops we step over (depends on \a htype_step). * \param user_data Optional user data for \a filter_fn, can be NULL. * \param hflag_test Optional flag to test faces, * use to exclude faces from the calculation, 0 for all faces. @@ -2350,7 +2349,7 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed) */ int BM_mesh_calc_face_groups( BMesh *bm, int *r_groups_array, int (**r_group_index)[2], - BMElemFilterFunc filter_fn, void *user_data, + BMLoopFilterFunc filter_fn, void *user_data, const char hflag_test, const char htype_step) { #ifdef DEBUG @@ -2443,7 +2442,7 @@ int BM_mesh_calc_face_groups( do { BMLoop *l_radial_iter = l_iter->radial_next; if ((l_radial_iter != l_iter) && - ((filter_fn == NULL) || filter_fn((BMElem *)l_iter->e, user_data))) + ((filter_fn == NULL) || filter_fn(l_iter, user_data))) { do { BMFace *f_other = l_radial_iter->f; @@ -2461,7 +2460,7 @@ int BM_mesh_calc_face_groups( /* search for other faces */ l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - if ((filter_fn == NULL) || filter_fn((BMElem *)l_iter->v, user_data)) { + if ((filter_fn == NULL) || filter_fn(l_iter, user_data)) { BMLoop *l_other; BM_ITER_ELEM (l_other, &liter, l_iter, BM_LOOPS_OF_LOOP) { BMFace *f_other = l_other->f; @@ -2508,7 +2507,7 @@ int BM_mesh_calc_face_groups( */ int BM_mesh_calc_edge_groups( BMesh *bm, int *r_groups_array, int (**r_group_index)[2], - BMElemFilterFunc filter_fn, void *user_data, + BMVertFilterFunc filter_fn, void *user_data, const char hflag_test) { #ifdef DEBUG @@ -2597,7 +2596,7 @@ int BM_mesh_calc_edge_groups( /* search for other edges */ BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { - if ((filter_fn == NULL) || filter_fn((BMElem *)v, user_data)) { + if ((filter_fn == NULL) || filter_fn(v, user_data)) { BMEdge *e_other; BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) { if (BM_elem_flag_test(e_other, BM_ELEM_TAG) == false) { diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 2b18a5c8641..cfe291732de 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -175,12 +175,12 @@ float BM_mesh_calc_volume(BMesh *bm, bool is_signed) ATTR_WARN_UNUSED_RESULT ATT int BM_mesh_calc_face_groups( BMesh *bm, int *r_groups_array, int (**r_group_index)[2], - BMElemFilterFunc filter_fn, void *user_data, + BMLoopFilterFunc filter_fn, void *user_data, const char hflag_test, const char htype_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3); int BM_mesh_calc_edge_groups( BMesh *bm, int *r_groups_array, int (**r_group_index)[2], - BMElemFilterFunc filter_fn, void *user_data, + BMVertFilterFunc filter_fn, void *user_data, const char hflag_test) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2, 3); diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c index 85bca744d86..233ed746ed4 100644 --- a/source/blender/bmesh/operators/bmo_fill_attribute.c +++ b/source/blender/bmesh/operators/bmo_fill_attribute.c @@ -53,9 +53,9 @@ static bool bm_loop_is_all_radial_tag(BMLoop *l) /** * Callback to run on source-loops for #BM_face_copy_shared */ -static bool bm_loop_is_face_untag(BMElem *ele, void *UNUSED(user_data)) +static bool bm_loop_is_face_untag(const BMLoop *l, void *UNUSED(user_data)) { - return (BM_elem_flag_test(((BMLoop *)ele)->f, BM_ELEM_TAG) == 0); + return (BM_elem_flag_test(l->f, BM_ELEM_TAG) == 0); } /** diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c index 1f50feb6d6d..6044960265b 100644 --- a/source/blender/bmesh/operators/bmo_normals.c +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -41,9 +41,9 @@ #define FACE_FLIP (1 << 1) #define FACE_TEMP (1 << 2) -static bool bmo_recalc_normal_edge_filter_cb(BMElem *ele, void *UNUSED(user_data)) +static bool bmo_recalc_normal_loop_filter_cb(const BMLoop *l, void *UNUSED(user_data)) { - return BM_edge_is_manifold((BMEdge *)ele); + return BM_edge_is_manifold(l->e); } /** @@ -229,7 +229,7 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f do { BMLoop *l_other = l_iter->radial_next; - if ((l_other != l_iter) && bmo_recalc_normal_edge_filter_cb((BMElem *)l_iter->e, NULL)) { + if ((l_other != l_iter) && bmo_recalc_normal_loop_filter_cb(l_iter, NULL)) { if (!BMO_elem_flag_test(bm, l_other->f, FACE_TEMP)) { BMO_elem_flag_enable(bm, l_other->f, FACE_TEMP); BMO_elem_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state); @@ -264,9 +264,10 @@ void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op) BMFace **faces_grp = MEM_mallocN(sizeof(*faces_grp) * bm->totface, __func__); int (*group_index)[2]; - const int group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index, - bmo_recalc_normal_edge_filter_cb, NULL, - 0, BM_EDGE); + const int group_tot = BM_mesh_calc_face_groups( + bm, groups_array, &group_index, + bmo_recalc_normal_loop_filter_cb, NULL, + 0, BM_EDGE); int i; BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces", BM_FACE, FACE_FLAG); diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index 2108a2c0589..33681c992a0 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -30,6 +30,10 @@ #include "BLI_math.h" +#include "BKE_customdata.h" + +#include "DNA_meshdata_types.h" + #include "bmesh.h" #include "intern/bmesh_operators_private.h" @@ -235,6 +239,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op) const unsigned int ytot = max_ii(2, BMO_slot_int_get(op->slots_in, "y_segments")); const float xtot_inv2 = 2.0f / (xtot - 1); const float ytot_inv2 = 2.0f / (ytot - 1); + const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); BMVert **varr; BMVert *vquad[4]; @@ -257,7 +262,9 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op) for (x = 0; x < xtot; x++) { vec[0] = ((x * xtot_inv2) - 1.0f) * dia; mul_v3_m4v3(tvec, mat, vec); - varr[i++] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); + varr[i] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); + BMO_elem_flag_enable(bm, varr[i], VERT_MARK); + i++; } } @@ -265,17 +272,86 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op) for (y = 1; y < ytot; y++) { for (x = 1; x < xtot; x++) { + BMFace *f; + vquad[0] = varr[XY(x - 1, y - 1)]; vquad[1] = varr[XY(x, y - 1)]; vquad[2] = varr[XY(x, y)]; vquad[3] = varr[XY(x - 1, y)]; - BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true); + f = BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true); + if (calc_uvs) { + BMO_elem_flag_enable(bm, f, FACE_MARK); + } } } #undef XY + if (calc_uvs) { + BM_mesh_calc_uvs_grid(bm, xtot, ytot, FACE_MARK); + } +} + +/** + * Fills first available UVmap with grid-like UVs for all faces OpFlag-ged by given flag. + * + * \param bm The BMesh to operate on + * \param x_segments The x-resolution of the grid + * \param y_segments The y-resolution of the grid + * \param oflag The flag to check faces with. + */ +void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsigned int y_segments, const short oflag) +{ + BMFace *f; + BMLoop *l; + BMIter iter, liter; + + const float dx = 1.0f / (float)(x_segments - 1); + const float dy = 1.0f / (float)(y_segments - 1); + float x = 0.0f; + float y = 0.0f; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + int loop_index; + + BLI_assert(cd_loop_uv_offset != -1); + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (!BMO_elem_flag_test(bm, f, oflag)) + continue; + + BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + switch (loop_index) { + case 0: + x += dx; + break; + case 1: + y += dy; + break; + case 2: + x -= dx; + break; + case 3: + y -= dy; + break; + default: + break; + } + + luv->uv[0] = x; + luv->uv[1] = y; + } + + x += dx; + if (x >= 1.0f) { + x = 0.0f; + y += dy; + } + } } void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) @@ -283,6 +359,7 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) const float dia = BMO_slot_float_get(op->slots_in, "diameter"); const int seg = BMO_slot_int_get(op->slots_in, "u_segments"); const int tot = BMO_slot_int_get(op->slots_in, "v_segments"); + const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); BMOperator bmop, prevop; BMVert *eve, *preveve; @@ -358,6 +435,31 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, min_ff(len, len2) / 3.0f); } + if (calc_uvs) { + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + + /* We cannot tag faces for UVs computing above, so we have to do it now, based on all its vertices + * being tagged. */ + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + bool valid = true; + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) { + valid = false; + break; + } + } + + if (valid) { + BMO_elem_flag_enable(bm, f, FACE_MARK); + } + } + + BM_mesh_calc_uvs_sphere(bm, FACE_MARK); + } + /* and now do imat */ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { if (BMO_elem_flag_test(bm, eve, VERT_MARK)) { @@ -373,6 +475,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) const float dia = BMO_slot_float_get(op->slots_in, "diameter"); const float dia_div = dia / 200.0f; const int subdiv = BMO_slot_int_get(op->slots_in, "subdivisions"); + const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); BMVert *eva[12]; BMVert *v; @@ -431,6 +534,30 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) BMO_op_finish(bm, &bmop); } + if (calc_uvs) { + BMFace *f; + BMIter fiter; + + /* We cannot tag faces for UVs computing above, so we have to do it now, based on all its vertices + * being tagged. */ + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + bool valid = true; + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) { + valid = false; + break; + } + } + + if (valid) { + BMO_elem_flag_enable(bm, f, FACE_MARK); + } + } + + BM_mesh_calc_uvs_sphere(bm, FACE_MARK); + } + /* must transform after because of sphere subdivision */ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { if (BMO_elem_flag_test(bm, v, VERT_MARK)) { @@ -441,6 +568,75 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } +static void bm_mesh_calc_uvs_sphere_face(BMFace *f, float mat_rot[3][3], const int cd_loop_uv_offset) +{ + float *uvs[4]; + BMLoop *l; + BMIter iter; + float dx; + int loop_index, loop_index_max_x; + + BLI_assert(f->len <= 4); + + BM_ITER_ELEM_INDEX (l, &iter, f, BM_LOOPS_OF_FACE, loop_index) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + float vco[3]; + + mul_v3_m3v3(vco, mat_rot, l->v->co); + map_to_sphere(&luv->uv[0], &luv->uv[1], vco[0], vco[1], vco[2]); + + uvs[loop_index] = luv->uv; + } + + /* Fix awkwardly-wrapping UVs */ + loop_index_max_x = 0; + for (loop_index = 1; loop_index < f->len; loop_index++) { + if (uvs[loop_index][0] > uvs[loop_index_max_x][0]) { + loop_index_max_x = loop_index; + } + } + + for (loop_index = 0; loop_index < f->len; loop_index++) { + if (loop_index != loop_index_max_x) { + dx = uvs[loop_index_max_x][0] - uvs[loop_index][0]; + if (dx > 0.5f) { + uvs[loop_index][0] += 1.0f; + } + } + } +} + +/** + * Fills first available UVmap with spherical projected UVs for all faces OpFlag-ged by given flag. + * + * \param bm The BMesh to operate on + * \param oflag The flag to check faces with. + */ +void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag) +{ + BMFace *f; + BMIter iter; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + /* We apply a 'magic' rotationto vcos before mapping them to sphere, + * those values seem to give best results for both ico and uv sphere projections. */ + float mat_rot[3][3]; + const float axis[3] = {0.806f, 0.329f, 0.491f}; + const float angle = DEG2RADF(120.0f); + + axis_angle_to_mat3(mat_rot, axis, angle); + + BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */ + + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + if (!BMO_elem_flag_test(bm, f, oflag)) + continue; + + bm_mesh_calc_uvs_sphere_face(f, mat_rot, cd_loop_uv_offset); + } +} + void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) { BMVert *eve; @@ -498,6 +694,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) const int segs = BMO_slot_int_get(op->slots_in, "segments"); const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); + const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); BMVert *v1, *lastv1 = NULL, *cent1, *firstv1 = NULL; float vec[3], mat[4][4], phi, phid; @@ -555,6 +752,10 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); BMO_elem_flag_enable(bm, f, FACE_NEW); + + if (calc_uvs) { + BM_mesh_calc_uvs_circle(bm, mat, dia, FACE_NEW); + } } if (!cap_tris) { @@ -564,9 +765,54 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } +/** + * Fills first available UVmap with 2D projected UVs for all faces OpFlag-ged by given flag. + * + * \param bm The BMesh to operate on. + * \param mat The transform matrix applied to the created circle. + * \param radius The size of the circle. + * \param oflag The flag to check faces with. + */ +void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, const short oflag) +{ + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + const float uv_scale = 0.5f / radius; + const float uv_center = 0.5f; + + float inv_mat[4][4]; + + BLI_assert(cd_loop_uv_offset != -1); /* caller must ensure we have UVs already */ + + invert_m4_m4(inv_mat, mat); + + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (!BMO_elem_flag_test(bm, f, oflag)) + continue; + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + float uv_vco[3]; + copy_v3_v3(uv_vco, l->v->co); + /* transform back into the unit circle flat on the Z-axis */ + mul_m4_v3(inv_mat, uv_vco); + + /* then just take those coords for UVs */ + luv->uv[0] = uv_center + uv_scale * uv_vco[0]; + luv->uv[1] = uv_center + uv_scale * uv_vco[1]; + } + } +} + void bmo_create_cone_exec(BMesh *bm, BMOperator *op) { BMVert *v1, *v2, *lastv1 = NULL, *lastv2 = NULL, *cent1, *cent2, *firstv1, *firstv2; + BMFace *f; float vec[3], mat[4][4], phi, phid; float dia1 = BMO_slot_float_get(op->slots_in, "diameter1"); float dia2 = BMO_slot_float_get(op->slots_in, "diameter2"); @@ -574,6 +820,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) int segs = BMO_slot_int_get(op->slots_in, "segments"); const bool cap_ends = BMO_slot_bool_get(op->slots_in, "cap_ends"); const bool cap_tris = BMO_slot_bool_get(op->slots_in, "cap_tris"); + const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); int a; if (!segs) @@ -620,14 +867,23 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) if (a) { if (cap_ends) { - BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_elem_flag_enable(bm, f, FACE_MARK); + } BMO_elem_flag_enable(bm, f, FACE_NEW); + f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_elem_flag_enable(bm, f, FACE_MARK); + } BMO_elem_flag_enable(bm, f, FACE_NEW); } - BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP); + + f = BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_elem_flag_enable(bm, f, FACE_MARK); + } } else { firstv1 = v1; @@ -642,29 +898,149 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) return; if (cap_ends) { - BMFace *f; - f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_elem_flag_enable(bm, f, FACE_MARK); + } BMO_elem_flag_enable(bm, f, FACE_NEW); + f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_elem_flag_enable(bm, f, FACE_MARK); + } BMO_elem_flag_enable(bm, f, FACE_NEW); } - + + f = BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP); + if (calc_uvs) { + BMO_elem_flag_enable(bm, f, FACE_MARK); + } + + if (calc_uvs) { + BM_mesh_calc_uvs_cone(bm, mat, dia2, dia1, segs, cap_ends, FACE_MARK); + } + if (!cap_tris) { BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW); } - BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP); - BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } +/** + * Fills first available UVmap with cylinder/cone-like UVs for all faces OpFlag-ged by given flag. + * + * \param bm The BMesh to operate on. + * \param mat The transform matrix applied to the created cone/cylinder. + * \param radius_top The size of the top end of the cone/cylinder. + * \param radius_bottom The size of the bottom end of the cone/cylinder. + * \param segments The number of subdivisions in the sides of the cone/cylinder. + * \param cap_ends Whether the ends of the cone/cylinder are filled or not. + * \param oflag The flag to check faces with. + */ +void BM_mesh_calc_uvs_cone( + BMesh *bm, float mat[4][4], + const float radius_top, const float radius_bottom, const int segments, const bool cap_ends, const short oflag) +{ + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + const float uv_width = 1.0f / (float)segments; + const float uv_height = cap_ends ? 0.5f : 1.0f; + + /* Note that all this allows us to handle all cases (real cone, truncated cone, with or without ends capped) + * with a single common code. */ + const float uv_center_y = cap_ends ? 0.25f : 0.5f; + const float uv_center_x_top = cap_ends ? 0.25f : 0.5f; + const float uv_center_x_bottom = cap_ends ? 0.75f : 0.5f; + const float uv_radius = cap_ends ? 0.24f : 0.5f; + + /* Using the opposite's end uv_scale as fallback allows us to handle 'real cone' case. */ + const float uv_scale_top = (radius_top != 0.0f) ? (uv_radius / radius_top) : + ((radius_bottom != 0.0f) ? (uv_radius / radius_bottom) : uv_radius); + const float uv_scale_bottom = (radius_bottom != 0.0f) ? (uv_radius / radius_bottom) : + uv_scale_top; + + float local_up[3] = {0.0f, 0.0f, 1.0f}; + + float x, y; + float inv_mat[4][4]; + int loop_index; + + mul_mat3_m4_v3(mat, local_up); /* transform the upvector like we did the cone itself, without location. */ + normalize_v3(local_up); /* remove global scaling... */ + + invert_m4_m4(inv_mat, mat); + + BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for ensuring the mesh has UVs */ + + x = 0.0f; + y = 1.0f - uv_height; + + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (!BMO_elem_flag_test(bm, f, oflag)) + continue; + + if (f->len == 4 && radius_top && radius_bottom) { + /* side face - so unwrap it in a rectangle */ + BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + switch (loop_index) { + case 0: + x += uv_width; + break; + case 1: + y += uv_height; + break; + case 2: + x -= uv_width; + break; + case 3: + y -= uv_height; + break; + default: + break; + } + + luv->uv[0] = x; + luv->uv[1] = y; + } + + x += uv_width; + } + else { + /* top or bottom face - so unwrap it by transforming back to a circle and using the X/Y coords */ + BM_face_normal_update(f); + + BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + float uv_vco[3]; + + mul_v3_m4v3(uv_vco, inv_mat, l->v->co); + + if (dot_v3v3(f->no, local_up) > 0.0f) { /* if this is a top face of the cone */ + luv->uv[0] = uv_center_x_top + uv_vco[0] * uv_scale_top; + luv->uv[1] = uv_center_y + uv_vco[1] * uv_scale_top; + } + else { + luv->uv[0] = uv_center_x_bottom + uv_vco[0] * uv_scale_bottom; + luv->uv[1] = uv_center_y + uv_vco[1] * uv_scale_bottom; + } + } + } + } +} + void bmo_create_cube_exec(BMesh *bm, BMOperator *op) { BMVert *verts[8]; float mat[4][4]; float off = BMO_slot_float_get(op->slots_in, "size") / 2.0f; + const bool calc_uvs = BMO_slot_bool_get(op->slots_in, "calc_uvs"); int i, x, y, z; const char faces[6][4] = { {1, 3, 2, 0}, @@ -693,6 +1069,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op) } for (i = 0; i < ARRAY_SIZE(faces); i++) { + BMFace *f; BMVert *quad[4] = { verts[faces[i][0]], verts[faces[i][1]], @@ -700,8 +1077,82 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op) verts[faces[i][3]], }; - BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true); + f = BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true); + if (calc_uvs) { + BMO_elem_flag_enable(bm, f, FACE_MARK); + } + } + + if (calc_uvs) { + BM_mesh_calc_uvs_cube(bm, FACE_MARK); } BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK); } + +/** + * Fills first available UVmap with cube-like UVs for all faces OpFlag-ged by given flag. + * + * \note Expects tagged faces to be six quads... + * + * \param bm The BMesh to operate on. + * \param oflag The flag to check faces with. + */ +void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag) +{ + BMFace *f; + BMLoop *l; + BMIter fiter, liter; + const float width = 0.25f; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + float x = 0.375f; + float y = 0.0f; + + int loop_index; + + BLI_assert(cd_loop_uv_offset != -1); /* the caller can ensure that we have UVs */ + + BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { + if (!BMO_elem_flag_test(bm, f, oflag)) { + continue; + } + + BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + luv->uv[0] = x; + luv->uv[1] = y; + + switch (loop_index) { + case 0: + x += width; + break; + case 1: + y += width; + break; + case 2: + x -= width; + break; + case 3: + y -= width; + break; + default: + break; + } + } + + if (y >= 0.75f && x > 0.125f) { + x = 0.125f; + y = 0.5f; + } + else if (x <= 0.125f) { + x = 0.625f; + y = 0.5f; + } + else { + y += 0.25f; + } + } +} diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 42373ad0ef0..5d9852d1c68 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -126,6 +126,21 @@ static void remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_targetmap continue; } + /* low level selection, not essential but means we can keep + * edge selection valid on auto-merge for example. */ + if ((BM_elem_flag_test(l->e, BM_ELEM_SELECT) == true) && + (BM_elem_flag_test(e_new, BM_ELEM_SELECT) == false)) + { + BM_elem_flag_disable(l->e, BM_ELEM_SELECT); + BM_elem_flag_merge_into(e_new, e_new, l->e); + BM_elem_flag_enable(e_new, BM_ELEM_SELECT); + /* bm->totedgesel remains valid */ + } + else { + BM_elem_flag_merge_into(e_new, e_new, l->e); + } + + STACK_PUSH(edges, e_new); STACK_PUSH(loops, l); } diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c index 624fbd93818..95ff3eb4858 100644 --- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c +++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c @@ -28,18 +28,15 @@ #include "MEM_guardedalloc.h" - #include "BLI_math.h" +#include "eigen_capi.h" + #include "bmesh.h" #include "intern/bmesh_operators_private.h" /* own include */ -#ifdef WITH_OPENNL - -#include "ONL_opennl.h" - // #define SMOOTH_LAPLACIAN_AREA_FACTOR 4.0f /* UNUSED */ // #define SMOOTH_LAPLACIAN_EDGE_FACTOR 2.0f /* UNUSED */ #define SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE 1.8f @@ -59,7 +56,7 @@ struct BLaplacianSystem { /* Pointers to data*/ BMesh *bm; BMOperator *op; - NLContext *context; + LinearSolver *context; /*Data*/ float min_area; @@ -92,7 +89,7 @@ static void delete_laplacian_system(LaplacianSystem *sys) delete_void_pointer(sys->vweights); delete_void_pointer(sys->zerola); if (sys->context) { - nlDeleteContext(sys->context); + EIG_linear_solver_delete(sys->context); } sys->bm = NULL; sys->op = NULL; @@ -333,9 +330,9 @@ static void fill_laplacian_matrix(LaplacianSystem *sys) w4 = w4 / 4.0f; if (!vert_is_boundary(vf[j]) && sys->zerola[idv1] == 0) { - nlMatrixAdd(sys->context, idv1, idv2, w2 * sys->vweights[idv1]); - nlMatrixAdd(sys->context, idv1, idv3, w3 * sys->vweights[idv1]); - nlMatrixAdd(sys->context, idv1, idv4, w4 * sys->vweights[idv1]); + EIG_linear_solver_matrix_add(sys->context, idv1, idv2, w2 * sys->vweights[idv1]); + EIG_linear_solver_matrix_add(sys->context, idv1, idv3, w3 * sys->vweights[idv1]); + EIG_linear_solver_matrix_add(sys->context, idv1, idv4, w4 * sys->vweights[idv1]); } } } @@ -346,16 +343,16 @@ static void fill_laplacian_matrix(LaplacianSystem *sys) /* Is ring if number of faces == number of edges around vertice*/ i = BM_elem_index_get(f); if (!vert_is_boundary(vf[0]) && sys->zerola[idv1] == 0) { - nlMatrixAdd(sys->context, idv1, idv2, sys->fweights[i][2] * sys->vweights[idv1]); - nlMatrixAdd(sys->context, idv1, idv3, sys->fweights[i][1] * sys->vweights[idv1]); + EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->fweights[i][2] * sys->vweights[idv1]); + EIG_linear_solver_matrix_add(sys->context, idv1, idv3, sys->fweights[i][1] * sys->vweights[idv1]); } if (!vert_is_boundary(vf[1]) && sys->zerola[idv2] == 0) { - nlMatrixAdd(sys->context, idv2, idv1, sys->fweights[i][2] * sys->vweights[idv2]); - nlMatrixAdd(sys->context, idv2, idv3, sys->fweights[i][0] * sys->vweights[idv2]); + EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->fweights[i][2] * sys->vweights[idv2]); + EIG_linear_solver_matrix_add(sys->context, idv2, idv3, sys->fweights[i][0] * sys->vweights[idv2]); } if (!vert_is_boundary(vf[2]) && sys->zerola[idv3] == 0) { - nlMatrixAdd(sys->context, idv3, idv1, sys->fweights[i][1] * sys->vweights[idv3]); - nlMatrixAdd(sys->context, idv3, idv2, sys->fweights[i][0] * sys->vweights[idv3]); + EIG_linear_solver_matrix_add(sys->context, idv3, idv1, sys->fweights[i][1] * sys->vweights[idv3]); + EIG_linear_solver_matrix_add(sys->context, idv3, idv2, sys->fweights[i][0] * sys->vweights[idv3]); } } } @@ -368,8 +365,8 @@ static void fill_laplacian_matrix(LaplacianSystem *sys) idv2 = BM_elem_index_get(e->v2); if (sys->zerola[idv1] == 0 && sys->zerola[idv2] == 0) { i = BM_elem_index_get(e); - nlMatrixAdd(sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]); - nlMatrixAdd(sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]); + EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]); + EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]); } } } @@ -434,12 +431,12 @@ static void validate_solution(LaplacianSystem *sys, int usex, int usey, int usez idv2 = BM_elem_index_get(e->v2); vi1 = e->v1->co; vi2 = e->v2->co; - ve1[0] = nlGetVariable(sys->context, 0, idv1); - ve1[1] = nlGetVariable(sys->context, 1, idv1); - ve1[2] = nlGetVariable(sys->context, 2, idv1); - ve2[0] = nlGetVariable(sys->context, 0, idv2); - ve2[1] = nlGetVariable(sys->context, 1, idv2); - ve2[2] = nlGetVariable(sys->context, 2, idv2); + ve1[0] = EIG_linear_solver_variable_get(sys->context, 0, idv1); + ve1[1] = EIG_linear_solver_variable_get(sys->context, 1, idv1); + ve1[2] = EIG_linear_solver_variable_get(sys->context, 2, idv1); + ve2[0] = EIG_linear_solver_variable_get(sys->context, 0, idv2); + ve2[1] = EIG_linear_solver_variable_get(sys->context, 1, idv2); + ve2[2] = EIG_linear_solver_variable_get(sys->context, 2, idv2); leni = len_v3v3(vi1, vi2); lene = len_v3v3(ve1, ve2); if (lene > leni * SMOOTH_LAPLACIAN_MAX_EDGE_PERCENTAGE || lene < leni * SMOOTH_LAPLACIAN_MIN_EDGE_PERCENTAGE) { @@ -455,13 +452,13 @@ static void validate_solution(LaplacianSystem *sys, int usex, int usey, int usez m_vertex_id = BM_elem_index_get(v); if (sys->zerola[m_vertex_id] == 0) { if (usex) { - v->co[0] = nlGetVariable(sys->context, 0, m_vertex_id); + v->co[0] = EIG_linear_solver_variable_get(sys->context, 0, m_vertex_id); } if (usey) { - v->co[1] = nlGetVariable(sys->context, 1, m_vertex_id); + v->co[1] = EIG_linear_solver_variable_get(sys->context, 1, m_vertex_id); } if (usez) { - v->co[2] = nlGetVariable(sys->context, 2, m_vertex_id); + v->co[2] = EIG_linear_solver_variable_get(sys->context, 2, m_vertex_id); } } } @@ -501,32 +498,24 @@ void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) preserve_volume = BMO_slot_bool_get(op->slots_in, "preserve_volume"); - sys->context = nlNewContext(); - - nlSolverParameteri(sys->context, NL_NB_VARIABLES, bm->totvert); - nlSolverParameteri(sys->context, NL_LEAST_SQUARES, NL_TRUE); - nlSolverParameteri(sys->context, NL_NB_ROWS, bm->totvert); - nlSolverParameteri(sys->context, NL_NB_RIGHT_HAND_SIDES, 3); + sys->context = EIG_linear_least_squares_solver_new(bm->totvert, bm->totvert, 3); - nlBegin(sys->context, NL_SYSTEM); for (i = 0; i < bm->totvert; i++) { - nlLockVariable(sys->context, i); + EIG_linear_solver_variable_lock(sys->context, i); } BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { m_vertex_id = BM_elem_index_get(v); - nlUnlockVariable(sys->context, m_vertex_id); - nlSetVariable(sys->context, 0, m_vertex_id, v->co[0]); - nlSetVariable(sys->context, 1, m_vertex_id, v->co[1]); - nlSetVariable(sys->context, 2, m_vertex_id, v->co[2]); + EIG_linear_solver_variable_set(sys->context, 0, m_vertex_id, v->co[0]); + EIG_linear_solver_variable_set(sys->context, 1, m_vertex_id, v->co[1]); + EIG_linear_solver_variable_set(sys->context, 2, m_vertex_id, v->co[2]); } - nlBegin(sys->context, NL_MATRIX); init_laplacian_matrix(sys); BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) { m_vertex_id = BM_elem_index_get(v); - nlRightHandSideAdd(sys->context, 0, m_vertex_id, v->co[0]); - nlRightHandSideAdd(sys->context, 1, m_vertex_id, v->co[1]); - nlRightHandSideAdd(sys->context, 2, m_vertex_id, v->co[2]); + EIG_linear_solver_right_hand_side_add(sys->context, 0, m_vertex_id, v->co[0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, m_vertex_id, v->co[1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, m_vertex_id, v->co[2]); i = m_vertex_id; if (sys->zerola[i] == 0) { w = sys->vweights[i] * sys->ring_areas[i]; @@ -535,34 +524,22 @@ void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) sys->vlengths[i] = (w == 0.0f) ? 0.0f : -lambda_border * 2.0f / w; if (!vert_is_boundary(v)) { - nlMatrixAdd(sys->context, i, i, 1.0f + lambda_factor / (4.0f * sys->ring_areas[i])); + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + lambda_factor / (4.0f * sys->ring_areas[i])); } else { - nlMatrixAdd(sys->context, i, i, 1.0f + lambda_border * 2.0f); + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + lambda_border * 2.0f); } } else { - nlMatrixAdd(sys->context, i, i, 1.0f); + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f); } } fill_laplacian_matrix(sys); - nlEnd(sys->context, NL_MATRIX); - nlEnd(sys->context, NL_SYSTEM); - - if (nlSolve(sys->context, NL_TRUE) ) { + if (EIG_linear_solver_solve(sys->context) ) { validate_solution(sys, usex, usey, usez, preserve_volume); } delete_laplacian_system(sys); } -#else /* WITH_OPENNL */ - -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - -void bmo_smooth_laplacian_vert_exec(BMesh *bm, BMOperator *op) {} - -#endif /* WITH_OPENNL */ diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index ddcbe34e8e1..0a5e5aba86b 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -242,6 +242,13 @@ static void bm_decim_build_edge_cost_single( BLI_heap_remove(eheap, eheap_table[BM_elem_index_get(e)]); } + if (UNLIKELY(vweights && + ((vweights[BM_elem_index_get(e->v1)] == 0.0f) || + (vweights[BM_elem_index_get(e->v2)] == 0.0f)))) + { + goto clear; + } + /* check we can collapse, some edges we better not touch */ if (BM_edge_is_boundary(e)) { if (e->l->f->len == 3) { diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 19cf2d29aff..80b1780758d 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -50,6 +50,7 @@ #endif #include "BLI_kdopbvh.h" +#include "BLI_buffer.h" #include "bmesh.h" #include "bmesh_intersect.h" /* own include */ @@ -70,12 +71,19 @@ #define USE_SEPARATE /* remove verts created by intersecting triangles */ #define USE_DISSOLVE +/* detect isolated holes and fill them */ +#define USE_NET_ISLAND_CONNECT /* strict asserts that may fail in practice (handy for debugging cases which should succeed) */ // #define USE_PARANOID /* use accelerated overlap check */ #define USE_BVH +// #define USE_BOOLEAN_RAYCAST_DRAW + +#ifdef USE_BOOLEAN_RAYCAST_DRAW +/* insert bl_debug_draw_quad_clear... here */ +#endif static void tri_v3_scale( float v1[3], float v2[3], float v3[3], @@ -147,21 +155,20 @@ static bool ghash_insert_link( GHash *gh, void *key, void *val, bool use_test, MemArena *mem_arena) { + void **ls_base_p; struct LinkBase *ls_base; LinkNode *ls; - ls_base = BLI_ghash_lookup(gh, key); - - if (ls_base) { - if (use_test && (BLI_linklist_index(ls_base->list, key) != -1)) { - return false; - } - } - else { - ls_base = BLI_memarena_alloc(mem_arena, sizeof(*ls_base)); + if (!BLI_ghash_ensure_p(gh, key, &ls_base_p)) { + ls_base = *ls_base_p = BLI_memarena_alloc(mem_arena, sizeof(*ls_base)); ls_base->list = NULL; ls_base->list_len = 0; - BLI_ghash_insert(gh, key, ls_base); + } + else { + ls_base = *ls_base_p; + if (use_test && (BLI_linklist_index(ls_base->list, val) != -1)) { + return false; + } } ls = BLI_memarena_alloc(mem_arena, sizeof(*ls)); @@ -231,12 +238,13 @@ static void face_edges_add( #ifdef USE_NET static void face_edges_split( - BMesh *bm, - BMFace *f, - struct LinkBase *e_ls_base) + BMesh *bm, BMFace *f, struct LinkBase *e_ls_base, + bool use_island_connect, + MemArena *mem_arena_edgenet) { unsigned int i; - BMEdge **edge_arr = BLI_array_alloca(edge_arr, e_ls_base->list_len); + unsigned int edge_arr_len = e_ls_base->list_len; + BMEdge **edge_arr = BLI_array_alloca(edge_arr, edge_arr_len); LinkNode *node; BLI_assert(f->head.htype == BM_FACE); @@ -249,7 +257,30 @@ static void face_edges_split( printf("# %s: %d %u\n", __func__, BM_elem_index_get(f), e_ls_base->list_len); #endif - BM_face_split_edgenet(bm, f, edge_arr, (int)e_ls_base->list_len, NULL, NULL); +#ifdef USE_NET_ISLAND_CONNECT + if (use_island_connect) { + unsigned int edge_arr_holes_len; + BMEdge **edge_arr_holes; + if (BM_face_split_edgenet_connect_islands( + bm, f, + edge_arr, edge_arr_len, + mem_arena_edgenet, + &edge_arr_holes, &edge_arr_holes_len)) + { + /* newly created wire edges need to be tagged */ + for (i = edge_arr_len; i < edge_arr_holes_len; i++) { + BM_elem_flag_enable(edge_arr_holes[i], BM_ELEM_TAG); + } + + edge_arr_len = edge_arr_holes_len; + edge_arr = edge_arr_holes; /* owned by the arena */ + } + } +#else + UNUSED_VARS(use_island_connect, mem_arena_edgenet); +#endif + + BM_face_split_edgenet(bm, f, edge_arr, (int)edge_arr_len, NULL, NULL); } #endif @@ -461,6 +492,35 @@ static BMVert *bm_isect_edge_tri( return NULL; } +struct LoopFilterWrap { + int (*test_fn)(BMFace *f, void *user_data); + void *user_data; +}; + +static bool bm_loop_filter_fn(const BMLoop *l, void *user_data) +{ + if (BM_elem_flag_test(l->e, BM_ELEM_TAG)) { + return false; + } + + if (l->radial_next != l) { + struct LoopFilterWrap *data = user_data; + BMLoop *l_iter = l->radial_next; + const int face_side = data->test_fn(l->f, data->user_data); + do { + const int face_side_other = data->test_fn(l_iter->f, data->user_data); + if (UNLIKELY(face_side_other == -1)) { + /* pass */ + } + else if (face_side_other != face_side) { + return false; + } + } while ((l_iter = l_iter->radial_next) != l); + return true; + } + return false; +} + /** * Return true if we have any intersections. */ @@ -774,23 +834,146 @@ static void bm_isect_tri_tri( } } +#ifdef USE_BVH + +struct RaycastData { + const float **looptris; + BLI_Buffer *z_buffer; +}; + +#ifdef USE_KDOPBVH_WATERTIGHT +static const struct IsectRayPrecalc isect_precalc_x = {1, 2, 0, 0, 0, 1}; +#endif + +static void raycast_callback(void *userdata, + int index, + const BVHTreeRay *ray, + BVHTreeRayHit *UNUSED(hit)) +{ + struct RaycastData *raycast_data = userdata; + const float **looptris = raycast_data->looptris; + const float *v0 = looptris[index * 3 + 0]; + const float *v1 = looptris[index * 3 + 1]; + const float *v2 = looptris[index * 3 + 2]; + float dist; + + if ( +#ifdef USE_KDOPBVH_WATERTIGHT + isect_ray_tri_watertight_v3(ray->origin, &isect_precalc_x, v0, v1, v2, &dist, NULL) +#else + isect_ray_tri_epsilon_v3(ray->origin, ray->direction, v0, v1, v2, &dist, NULL, FLT_EPSILON) +#endif + ) + { + if (dist >= 0.0f) { +#ifdef USE_DUMP + printf("%s:\n", __func__); + print_v3(" origin", ray->origin); + print_v3(" direction", ray->direction); + printf(" dist %f\n", dist); + print_v3(" v0", v0); + print_v3(" v1", v1); + print_v3(" v2", v2); +#endif + +#ifdef USE_DUMP + printf("%s: Adding depth %f\n", __func__, depth); +#endif + BLI_buffer_append(raycast_data->z_buffer, float, dist); + } + } +} + +static int isect_bvhtree_point_v3( + BVHTree *tree, + const float **looptris, + const float co[3]) +{ + BLI_buffer_declare_static(float, z_buffer, BLI_BUFFER_NOP, 64); + + struct RaycastData raycast_data = { + looptris, + &z_buffer, + }; + BVHTreeRayHit hit = {0}; + float dir[3] = {1.0f, 0.0f, 0.0f}; + + /* Need to initialize hit even tho it's not used. + * This is to make it so kdotree believes we didn't intersect anything and + * keeps calling the intersect callback. + */ + hit.index = -1; + hit.dist = FLT_MAX; + + BLI_bvhtree_ray_cast(tree, + co, dir, + 0.0f, + &hit, + raycast_callback, + &raycast_data); + +#ifdef USE_DUMP + printf("%s: Total intersections: %d\n", __func__, raycast_data.num_isect); +#endif + + int num_isect; + + if (z_buffer.count == 0) { + num_isect = 0; + } + else if (z_buffer.count == 1) { + num_isect = 1; + } + else { + /* 2 or more */ + const float eps = FLT_EPSILON * 10; + num_isect = 1; /* always count first */ + + qsort(z_buffer.data, z_buffer.count, sizeof(float), BLI_sortutil_cmp_float); + + const float *depth_arr = z_buffer.data; + float depth_last = depth_arr[0]; + + for (unsigned int i = 1; i < z_buffer.count; i++) { + if (depth_arr[i] - depth_last > eps) { + depth_last = depth_arr[i]; + num_isect++; + } + } + + BLI_buffer_free(&z_buffer); + } + + + // return (num_isect & 1) == 1; + return num_isect; +} + +#endif /* USE_BVH */ + /** * Intersect tessellated faces * leaving the resulting edges tagged. * * \param test_fn Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false) + * \param boolean_mode -1: no-boolean, 0: intersection... see #BMESH_ISECT_BOOLEAN_ISECT. + * \return true if the mesh is changed (intersections cut or faces removed from boolean). */ bool BM_mesh_intersect( BMesh *bm, struct BMLoop *(*looptris)[3], const int looptris_tot, int (*test_fn)(BMFace *f, void *user_data), void *user_data, - const bool use_self, const bool use_separate, + const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect, + const int boolean_mode, const float eps) { struct ISectState s; bool has_isect; const int totface_orig = bm->totface; + /* needed for boolean, since cutting up faces moves the loops within the face */ + const float **looptri_coords = NULL; + #ifdef USE_BVH BVHTree *tree_a, *tree_b; unsigned int tree_overlap_tot; @@ -799,6 +982,10 @@ bool BM_mesh_intersect( int i_a, i_b; #endif +#ifdef USE_BOOLEAN_RAYCAST_DRAW + bl_debug_draw_quad_clear(); +#endif + s.bm = bm; s.edgetri_cache = BLI_ghash_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__); @@ -840,13 +1027,31 @@ bool BM_mesh_intersect( 0); #ifdef USE_DISSOLVE - BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_VERT, BM_ELEM_TAG, false); + if (use_dissolve) { + BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_VERT, BM_ELEM_TAG, false); + } +#else + UNUSED_VARS(use_dissolve); #endif #ifdef USE_DUMP printf("data = [\n"); #endif + if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) { + /* keep original geometrty for raycast callbacks */ + float **cos; + int i, j; + + cos = MEM_mallocN((size_t)looptris_tot * sizeof(*looptri_coords) * 3, __func__); + for (i = 0, j = 0; i < looptris_tot; i++) { + cos[j++] = looptris[i][0]->v->co; + cos[j++] = looptris[i][1]->v->co; + cos[j++] = looptris[i][2]->v->co; + } + looptri_coords = (const float **)cos; + } + #ifdef USE_BVH { int i; @@ -908,9 +1113,13 @@ bool BM_mesh_intersect( } MEM_freeN(overlap); } - BLI_bvhtree_free(tree_a); - if (tree_a != tree_b) { - BLI_bvhtree_free(tree_b); + + if (boolean_mode == BMESH_ISECT_BOOLEAN_NONE) { + /* no booleans, just free immediate */ + BLI_bvhtree_free(tree_a); + if (tree_a != tree_b) { + BLI_bvhtree_free(tree_b); + } } #else @@ -979,7 +1188,7 @@ bool BM_mesh_intersect( } #ifdef USE_DUMP - printf("# SPLITTING EDGE: %d, %d\n", e_index, v_ls_base->list_len); + printf("# SPLITTING EDGE: %d, %d\n", BM_elem_index_get(e), v_ls_base->list_len); #endif /* intersect */ is_wire = BLI_gset_haskey(s.wire_edges, e); @@ -999,7 +1208,8 @@ bool BM_mesh_intersect( const float fac = line_point_factor_v3(vi->co, e->v1->co, e->v2->co); if (BM_vert_in_edge(e, v_prev)) { - v_prev = BM_edge_split(bm, e, v_prev, NULL, CLAMPIS(fac, 0.0f, 1.0f)); + BMEdge *e_split; + v_prev = BM_edge_split(bm, e, v_prev, &e_split, CLAMPIS(fac, 0.0f, 1.0f)); BLI_assert(BM_vert_in_edge(e, v_end)); if (!BM_edge_exists(v_prev, vi) && @@ -1013,7 +1223,7 @@ bool BM_mesh_intersect( } v_prev = vi; if (is_wire) { - BLI_gset_insert(s.wire_edges, e); + BLI_gset_insert(s.wire_edges, e_split); } } } @@ -1025,7 +1235,7 @@ bool BM_mesh_intersect( /* important to handle before edgenet */ #ifdef USE_DISSOLVE - { + if (use_dissolve && (boolean_mode == BMESH_ISECT_BOOLEAN_NONE)) { /* first pass */ BMVert *(*splice_ls)[2]; STACK_DECLARE(splice_ls); @@ -1249,6 +1459,8 @@ bool BM_mesh_intersect( GHashIterator gh_iter; BMFace **faces; + MemArena *mem_arena_edgenet = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + faces = bm->ftable; GHASH_ITER (gh_iter, s.face_edges) { @@ -1265,9 +1477,15 @@ bool BM_mesh_intersect( BLI_assert(BM_elem_index_get(f) == f_index); - face_edges_split(bm, f, e_ls_base); + face_edges_split(bm, f, e_ls_base, use_island_connect, mem_arena_edgenet); + + BLI_memarena_clear(mem_arena_edgenet); } + + BLI_memarena_free(mem_arena_edgenet); } +#else + UNUSED_VARS(use_island_connect); #endif /* USE_NET */ (void)totface_orig; @@ -1284,10 +1502,168 @@ bool BM_mesh_intersect( BM_mesh_edgesplit(bm, false, true, false); } + else if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) { + GSetIterator gs_iter; + + /* no need to clear for boolean */ + + GSET_ITER (gs_iter, s.wire_edges) { + BMEdge *e = BLI_gsetIterator_getKey(&gs_iter); + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + } #else (void)use_separate; #endif /* USE_SEPARATE */ + if ((boolean_mode != BMESH_ISECT_BOOLEAN_NONE)) { + BVHTree *tree_pair[2] = {tree_a, tree_b}; + + /* group vars */ + int *groups_array; + int (*group_index)[2]; + int group_tot; + int i; + BMFace **ftable; + + BM_mesh_elem_table_ensure(bm, BM_FACE); + ftable = bm->ftable; + + /* wrap the face-test callback to make it into an edge-loop delimiter */ + struct LoopFilterWrap user_data_wrap = { + .test_fn = test_fn, + .user_data = user_data, + }; + + groups_array = MEM_mallocN(sizeof(*groups_array) * (size_t)bm->totface, __func__); + group_tot = BM_mesh_calc_face_groups( + bm, groups_array, &group_index, + bm_loop_filter_fn, &user_data_wrap, + 0, BM_EDGE); + +#ifdef USE_DUMP + printf("%s: Total face-groups: %d\n", __func__, group_tot); +#endif + + /* Check if island is inside/outside */ + for (i = 0; i < group_tot; i++) { + int fg = group_index[i][0]; + int fg_end = group_index[i][1] + fg; + bool do_remove, do_flip; + + { + /* for now assyme this is an OK face to test with (not degenerate!) */ + BMFace *f = ftable[groups_array[fg]]; + float co[3]; + int hits; + int side = test_fn(f, user_data); + + if (side == -1) { + continue; + } + BLI_assert(ELEM(side, 0, 1)); + side = !side; + + // BM_face_calc_center_mean(f, co); + BM_face_calc_point_in_face(f, co); + + hits = isect_bvhtree_point_v3(tree_pair[side], looptri_coords, co); + + switch (boolean_mode) { + case BMESH_ISECT_BOOLEAN_ISECT: + do_remove = ((hits & 1) != 1); + do_flip = false; + break; + case BMESH_ISECT_BOOLEAN_UNION: + do_remove = ((hits & 1) == 1); + do_flip = false; + break; + case BMESH_ISECT_BOOLEAN_DIFFERENCE: + do_remove = ((hits & 1) == 1) == side; + do_flip = (side == 0); + break; + } + +#ifdef USE_BOOLEAN_RAYCAST_DRAW + { + unsigned int colors[4] = {0x00000000, 0xffffffff, 0xff000000, 0x0000ff}; + float co_other[3] = {UNPACK3(co)}; + co_other[0] += 1000.0f; + bl_debug_color_set(colors[(hits & 1) == 1]); + bl_debug_draw_edge_add(co, co_other); + } +#endif + + } + + if (do_remove) { + for (; fg != fg_end; fg++) { + /* postpone killing the face since we access below, mark instead */ + // BM_face_kill_loose(bm, ftable[groups_array[fg]]); + ftable[groups_array[fg]]->mat_nr = -1; + } + } + else if (do_flip) { + for (; fg != fg_end; fg++) { + BM_face_normal_flip(bm, ftable[groups_array[fg]]); + } + } + } + + MEM_freeN(groups_array); + MEM_freeN(group_index); + +#ifdef USE_DISSOLVE + /* We have dissolve code above, this is alternative logic, + * we need to do it after the boolean is executed. */ + if (use_dissolve) { + LinkNode *node; + for (node = s.vert_dissolve; node; node = node->next) { + BMVert *v = node->link; + if (BM_vert_is_edge_pair(v)) { + /* we wont create degenerate faces from this */ + bool ok = true; + + /* would we create a 2-sided-face? + * if so, don't dissolve this since we may */ + if (v->e->l) { + BMLoop *l_iter = v->e->l; + do { + if (l_iter->f->len == 3) { + ok = false; + break; + } + } while ((l_iter = l_iter->radial_next) != v->e->l); + } + + if (ok) { + BM_vert_collapse_edge(bm, v->e, v, true, false); + } + } + } + } +#endif + + { + int tot = bm->totface; + for (i = 0; i < tot; i++) { + if (ftable[i]->mat_nr == -1) { + BM_face_kill_loose(bm, ftable[i]); + } + } + } + } + + if (boolean_mode != BMESH_ISECT_BOOLEAN_NONE) { + MEM_freeN((void *)looptri_coords); + + /* no booleans, just free immediate */ + BLI_bvhtree_free(tree_a); + if (tree_a != tree_b) { + BLI_bvhtree_free(tree_b); + } + } + has_isect = (BLI_ghash_size(s.face_edges) != 0); /* cleanup */ @@ -1299,5 +1675,5 @@ bool BM_mesh_intersect( BLI_memarena_free(s.mem_arena); - return has_isect; + return has_isect || (totface_orig != bm->totface); } diff --git a/source/blender/bmesh/tools/bmesh_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h index af6e510a8f6..d0cc41654eb 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.h +++ b/source/blender/bmesh/tools/bmesh_intersect.h @@ -29,7 +29,16 @@ bool BM_mesh_intersect( BMesh *bm, struct BMLoop *(*looptris)[3], const int looptris_tot, int (*test_fn)(BMFace *f, void *user_data), void *user_data, - const bool use_self, const bool use_separate, + const bool use_self, const bool use_separate, const bool use_dissolve, const bool use_island_connect, + const int boolean_mode, const float eps); +enum { + BMESH_ISECT_BOOLEAN_NONE = -1, + /* aligned with BooleanModifierOp */ + BMESH_ISECT_BOOLEAN_ISECT = 0, + BMESH_ISECT_BOOLEAN_UNION = 1, + BMESH_ISECT_BOOLEAN_DIFFERENCE = 2, +}; + #endif /* __BMESH_INTERSECT_H__ */ diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c index 1c05b8ae5d4..bc9ab084467 100644 --- a/source/blender/bmesh/tools/bmesh_path.c +++ b/source/blender/bmesh/tools/bmesh_path.c @@ -316,10 +316,10 @@ static float facetag_cut_cost(BMFace *f_a, BMFace *f_b, BMEdge *e) float ix_e[3], ix_f[3], f; isect_line_line_v3(e->v1->co, e->v2->co, f_a_cent, f_b_cent, ix_e, ix_f); f = line_point_factor_v3(ix_e, e->v1->co, e->v2->co); - if (f < 0.0) { + if (f < 0.0f) { copy_v3_v3(e_cent, e->v1->co); } - else if (f > 1.0) { + else if (f > 1.0f) { copy_v3_v3(e_cent, e->v2->co); } else { diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index 7398126c97b..3ade7c3cb27 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -98,6 +98,7 @@ extern "C" #include "BKE_material.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "BKE_appdir.h" #include "ED_keyframing.h" #ifdef WITH_BUILDINFO @@ -153,6 +154,26 @@ char *bc_CustomData_get_active_layer_name(const CustomData *data, int type) DocumentExporter::DocumentExporter(const ExportSettings *export_settings) : export_settings(export_settings) { } +static COLLADABU::NativeString make_temp_filepath(const char *name, const char *extension) +{ + char tempfile[FILE_MAX]; + const char *tempdir = BKE_tempdir_session(); + + if (name == NULL){ + name = tmpnam(NULL); + } + + BLI_make_file_string(NULL, tempfile, tempdir, name); + + if (extension) { + BLI_ensure_extension(tempfile, FILE_MAX, extension); + } + + COLLADABU::NativeString native_filename = + COLLADABU::NativeString(tempfile, COLLADABU::NativeString::ENCODING_UTF8); + return native_filename; +} + // TODO: it would be better to instantiate animations rather than create a new one per object // COLLADA allows this through multiple <channel>s in <animation>. // For this to work, we need to know objects that use a certain action. @@ -163,18 +184,17 @@ void DocumentExporter::exportCurrentScene(Scene *sce) PropertyRNA *system; /* unused , *scale; */ clear_global_id_map(); - - COLLADABU::NativeString native_filename = - COLLADABU::NativeString(std::string(this->export_settings->filepath), COLLADABU::NativeString::ENCODING_UTF8); - COLLADASW::StreamWriter sw(native_filename); + + COLLADABU::NativeString native_filename = make_temp_filepath(NULL, ".dae"); + COLLADASW::StreamWriter *writer = new COLLADASW::StreamWriter(native_filename); fprintf(stdout, "Collada export: %s\n", this->export_settings->filepath); // open <collada> - sw.startDocument(); + writer->startDocument(); // <asset> - COLLADASW::Asset asset(&sw); + COLLADASW::Asset asset(writer); RNA_id_pointer_create(&(sce->id), &sceneptr); unit_settings = RNA_pointer_get(&sceneptr, "unit_settings"); @@ -241,41 +261,41 @@ void DocumentExporter::exportCurrentScene(Scene *sce) LinkNode *export_set = this->export_settings->export_set; // <library_cameras> if (bc_has_object_type(export_set, OB_CAMERA)) { - CamerasExporter ce(&sw, this->export_settings); + CamerasExporter ce(writer, this->export_settings); ce.exportCameras(sce); } // <library_lights> if (bc_has_object_type(export_set, OB_LAMP)) { - LightsExporter le(&sw, this->export_settings); + LightsExporter le(writer, this->export_settings); le.exportLights(sce); } // <library_images> - ImagesExporter ie(&sw, this->export_settings); + ImagesExporter ie(writer, this->export_settings); ie.exportImages(sce); // <library_effects> - EffectsExporter ee(&sw, this->export_settings); + EffectsExporter ee(writer, this->export_settings); ee.exportEffects(sce); // <library_materials> - MaterialsExporter me(&sw, this->export_settings); + MaterialsExporter me(writer, this->export_settings); me.exportMaterials(sce); // <library_geometries> if (bc_has_object_type(export_set, OB_MESH)) { - GeometryExporter ge(&sw, this->export_settings); + GeometryExporter ge(writer, this->export_settings); ge.exportGeom(sce); } // <library_animations> - AnimationExporter ae(&sw, this->export_settings); + AnimationExporter ae(writer, this->export_settings); bool has_animations = ae.exportAnimations(sce); // <library_controllers> - ArmatureExporter arm_exporter(&sw, this->export_settings); - ControllerExporter controller_exporter(&sw , this->export_settings); + ArmatureExporter arm_exporter(writer, this->export_settings); + ControllerExporter controller_exporter(writer, this->export_settings); if (bc_has_object_type(export_set, OB_ARMATURE) || this->export_settings->include_shapekeys) { controller_exporter.export_controllers(sce); @@ -283,7 +303,7 @@ void DocumentExporter::exportCurrentScene(Scene *sce) // <library_visual_scenes> - SceneExporter se(&sw, &arm_exporter, this->export_settings); + SceneExporter se(writer, &arm_exporter, this->export_settings); if (has_animations && this->export_settings->export_transformation_type == BC_TRANSFORMATION_TYPE_MATRIX) { // channels adressing <matrix> objects is not (yet) supported @@ -301,12 +321,16 @@ void DocumentExporter::exportCurrentScene(Scene *sce) // <scene> std::string scene_name(translate_id(id_name(sce))); - COLLADASW::Scene scene(&sw, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, + COLLADASW::Scene scene(writer, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, scene_name)); scene.add(); // close <Collada> - sw.endDocument(); + writer->endDocument(); + delete writer; + + // Finally move the created document into place + BLI_rename(native_filename.c_str(), this->export_settings->filepath); } diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp index 2e60c2d3e42..97ac09d4abb 100644 --- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp +++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp @@ -15,9 +15,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor: - * Jeroen Bakker - * Monique Dewanchand + * Contributor(s): Jeroen Bakker + * Monique Dewanchand + * Sergey Sharybin */ #include "COM_AntiAliasOperation.h" @@ -31,76 +31,122 @@ extern "C" { } +/* An implementation of the Scale3X edge-extrapolation algorithm. + * + * Code from GIMP plugin, based on code from Adam D. Moss (adam@gimp.org) + * licensed by the MIT license. + */ +static int extrapolate9(float *E0, float *E1, float *E2, + float *E3, float *E4, float *E5, + float *E6, float *E7, float *E8, + const float *A, const float *B, const float *C, + const float *D, const float *E, const float *F, + const float *G, const float *H, const float *I) +{ +#define PEQ(X, Y) (fabsf(*X - *Y) < 1e-3f) +#define PCPY(DST, SRC) do { *DST = *SRC; } while (0) + if ((!PEQ(B, H)) && (!PEQ(D, F))) { + if (PEQ(D, B)) PCPY(E0, D); else PCPY(E0, E); + if ((PEQ(D, B) && !PEQ(E, C)) || (PEQ(B, F) && !PEQ(E, A))) + PCPY(E1, B); else PCPY(E1, E); + if (PEQ(B, F)) PCPY(E2, F); else PCPY(E2, E); + if ((PEQ(D, B) && !PEQ(E, G)) || (PEQ(D, H) && !PEQ(E, A))) + PCPY(E3, D); else PCPY(E3, E); + PCPY(E4, E); + if ((PEQ(B, F) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, C))) + PCPY(E5, F); else PCPY(E5, E); + if (PEQ(D, H)) PCPY(E6, D); else PCPY(E6, E); + if ((PEQ(D, H) && !PEQ(E, I)) || (PEQ(H, F) && !PEQ(E, G))) + PCPY(E7, H); else PCPY(E7, E); + if (PEQ(H, F)) PCPY(E8, F); else PCPY(E8, E); + return 1; + } + else { + return 0; + } +#undef PEQ +#undef PCPY +} + AntiAliasOperation::AntiAliasOperation() : NodeOperation() { this->addInputSocket(COM_DT_VALUE); this->addOutputSocket(COM_DT_VALUE); this->m_valueReader = NULL; - this->m_buffer = NULL; this->setComplex(true); } + void AntiAliasOperation::initExecution() { this->m_valueReader = this->getInputSocketReader(0); - NodeOperation::initMutex(); } -void AntiAliasOperation::executePixel(float output[4], int x, int y, void * /*data*/) +void AntiAliasOperation::executePixel(float output[4], + int x, int y, + void *data) { - if (y < 0 || (unsigned int)y >= this->m_height || x < 0 || (unsigned int)x >= this->m_width) { + MemoryBuffer *input_buffer = (MemoryBuffer *)data; + const int buffer_width = input_buffer->getWidth(), + buffer_height = input_buffer->getHeight(); + if (y < 0 || y >= buffer_height || x < 0 || x >= buffer_width) { output[0] = 0.0f; } else { - int offset = y * this->m_width + x; - output[0] = this->m_buffer[offset] / 255.0f; + const float *buffer = input_buffer->getBuffer(); + const float *row_curr = &buffer[y * buffer_width]; + if (x == 0 || x == buffer_width - 1 || + y == 0 || y == buffer_height - 1) + { + output[0] = row_curr[x]; + return; + } + const float *row_prev = &buffer[(y - 1) * buffer_width], + *row_next = &buffer[(y + 1) * buffer_width]; + float ninepix[9]; + if (extrapolate9(&ninepix[0], &ninepix[1], &ninepix[2], + &ninepix[3], &ninepix[4], &ninepix[5], + &ninepix[6], &ninepix[7], &ninepix[8], + &row_prev[x - 1], &row_prev[x], &row_prev[x + 1], + &row_curr[x - 1], &row_curr[x], &row_curr[x + 1], + &row_next[x - 1], &row_next[x], &row_next[x + 1])) + { + /* Some rounding magic to so make weighting correct with the + * original coefficients. + */ + unsigned char result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] + + 5 * ninepix[3] + 6 * ninepix[4] + 5 * ninepix[5] + + 3 * ninepix[6] + 5 * ninepix[7] + 3 * ninepix[8]) * 255.0f + + 19.0f) / 38.0f; + output[0] = result / 255.0f; + } + else { + output[0] = row_curr[x]; + } } - } void AntiAliasOperation::deinitExecution() { this->m_valueReader = NULL; - if (this->m_buffer) { - MEM_freeN(this->m_buffer); - } - NodeOperation::deinitMutex(); } -bool AntiAliasOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output) +bool AntiAliasOperation::determineDependingAreaOfInterest( + rcti *input, + ReadBufferOperation *readOperation, + rcti *output) { rcti imageInput; - if (this->m_buffer) { - return false; - } - else { - NodeOperation *operation = getInputOperation(0); - imageInput.xmax = operation->getWidth(); - imageInput.xmin = 0; - imageInput.ymax = operation->getHeight(); - imageInput.ymin = 0; - if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output) ) { - return true; - } - } - return false; + NodeOperation *operation = getInputOperation(0); + imageInput.xmax = input->xmax + 1; + imageInput.xmin = input->xmin - 1; + imageInput.ymax = input->ymax + 1; + imageInput.ymin = input->ymin - 1; + return operation->determineDependingAreaOfInterest(&imageInput, + readOperation, + output); } void *AntiAliasOperation::initializeTileData(rcti *rect) { - if (this->m_buffer) { return this->m_buffer; } - lockMutex(); - if (this->m_buffer == NULL) { - MemoryBuffer *tile = (MemoryBuffer *)this->m_valueReader->initializeTileData(rect); - int size = tile->getHeight() * tile->getWidth(); - float *input = tile->getBuffer(); - char *valuebuffer = (char *)MEM_mallocN(sizeof(char) * size, __func__); - for (int i = 0; i < size; i++) { - float in = input[i]; - valuebuffer[i] = FTOCHAR(in); - } - antialias_tagbuf(tile->getWidth(), tile->getHeight(), valuebuffer); - this->m_buffer = valuebuffer; - } - unlockMutex(); - return this->m_buffer; + return getInputOperation(0)->initializeTileData(rect); } diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.h b/source/blender/compositor/operations/COM_AntiAliasOperation.h index 385d59fec3c..996c7c2fe41 100644 --- a/source/blender/compositor/operations/COM_AntiAliasOperation.h +++ b/source/blender/compositor/operations/COM_AntiAliasOperation.h @@ -36,7 +36,6 @@ protected: * @brief Cached reference to the reader */ SocketReader *m_valueReader; - char *m_buffer; public: AntiAliasOperation(); diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index 1ed70b3cd98..b213aca478f 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -28,6 +28,7 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + ../../../../intern/eigen ../../../../intern/glew-mx ) @@ -68,13 +69,6 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() -if(WITH_OPENNL) - add_definitions(-DWITH_OPENNL) - list(APPEND INC_SYS - ../../../../intern/opennl/extern - ) -endif() - add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_editor_armature "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript index 9c3959ecb5b..850834d2cd4 100644 --- a/source/blender/editors/armature/SConscript +++ b/source/blender/editors/armature/SConscript @@ -31,9 +31,9 @@ sources = env.Glob('*.c') incs = [ '#/intern/guardedalloc', + '#/intern/eigen', env['BF_GLEW_INC'], '#/intern/glew-mx', - '#/intern/opennl/extern', '../include', '../../blenkernel', '../../blenlib', diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 5a0e70dc5dd..94b7277ce8f 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -156,7 +156,7 @@ void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int cente mul_m4_v3(ob->imat, cent); } else { - if (around == V3D_CENTROID) { + if (around == V3D_AROUND_CENTER_MEAN) { int total = 0; zero_v3(cent); for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index ea1a94fbba6..c621d6f99c0 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -51,12 +51,10 @@ #include "ED_armature.h" #include "ED_mesh.h" +#include "eigen_capi.h" #include "armature_intern.h" - -#ifdef WITH_OPENNL -# include "meshlaplacian.h" -#endif +#include "meshlaplacian.h" #if 0 #include "reeb.h" @@ -401,12 +399,8 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, if (heat) { const char *error = NULL; -#ifdef WITH_OPENNL heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip, root, tip, selected, &error); -#else - error = "Built without OpenNL"; -#endif if (error) { BKE_report(reports, RPT_WARNING, error); } diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index 9319ccf3b13..87d75aa8fad 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -982,7 +982,7 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S mvalf[0] = dd->mval[0]; mvalf[1] = dd->mval[1]; - peelObjectsContext(C, &sketch->depth_peels, mvalf, SNAP_ALL); + peelObjectsContext(C, mvalf, SNAP_ALL, &sketch->depth_peels); if (stk->nb_points > 0 && stk->points[stk->nb_points - 1].type == PT_CONTINUOUS) { last_p = stk->points[stk->nb_points - 1].p; @@ -1086,7 +1086,9 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S mval[1] = dd->mval[1]; /* try to snap to closer object */ - found = snapObjectsContext(C, mval, &dist_px, vec, no, SNAP_NOT_SELECTED); + found = snapObjectsContext( + C, mval, SNAP_NOT_SELECTED, + vec, no, &dist_px); if (found == 1) { pt->type = dd->type; pt->mode = PT_SNAP; diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 3f27a58930d..ce87ffb3494 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -46,11 +46,9 @@ #include "ED_mesh.h" #include "ED_armature.h" -#include "meshlaplacian.h" - -#ifdef WITH_OPENNL +#include "eigen_capi.h" -#include "ONL_opennl.h" +#include "meshlaplacian.h" /* ************* XXX *************** */ static void waitcursor(int UNUSED(val)) {} @@ -64,7 +62,7 @@ static void error(const char *str) { printf("error: %s\n", str); } /************************** Laplacian System *****************************/ struct LaplacianSystem { - NLContext *context; /* opennl context */ + LinearSolver *context; /* linear solver */ int totvert, totface; @@ -76,7 +74,7 @@ struct LaplacianSystem { int areaweights; /* use area in cotangent weights? */ int storeweights; /* store cotangent weights in fweights */ - int nlbegun; /* nlBegin(NL_SYSTEM/NL_MATRIX) done */ + bool variablesdone; /* variables set in linear system */ EdgeHash *edgehash; /* edge hash for construction */ @@ -182,18 +180,18 @@ static void laplacian_triangle_weights(LaplacianSystem *sys, int f, int i1, int t2 = cotangent_tri_weight_v3(v2, v3, v1) / laplacian_edge_count(sys->edgehash, i3, i1); t3 = cotangent_tri_weight_v3(v3, v1, v2) / laplacian_edge_count(sys->edgehash, i1, i2); - nlMatrixAdd(sys->context, i1, i1, (t2 + t3) * varea[i1]); - nlMatrixAdd(sys->context, i2, i2, (t1 + t3) * varea[i2]); - nlMatrixAdd(sys->context, i3, i3, (t1 + t2) * varea[i3]); + EIG_linear_solver_matrix_add(sys->context, i1, i1, (t2 + t3) * varea[i1]); + EIG_linear_solver_matrix_add(sys->context, i2, i2, (t1 + t3) * varea[i2]); + EIG_linear_solver_matrix_add(sys->context, i3, i3, (t1 + t2) * varea[i3]); - nlMatrixAdd(sys->context, i1, i2, -t3 * varea[i1]); - nlMatrixAdd(sys->context, i2, i1, -t3 * varea[i2]); + EIG_linear_solver_matrix_add(sys->context, i1, i2, -t3 * varea[i1]); + EIG_linear_solver_matrix_add(sys->context, i2, i1, -t3 * varea[i2]); - nlMatrixAdd(sys->context, i2, i3, -t1 * varea[i2]); - nlMatrixAdd(sys->context, i3, i2, -t1 * varea[i3]); + EIG_linear_solver_matrix_add(sys->context, i2, i3, -t1 * varea[i2]); + EIG_linear_solver_matrix_add(sys->context, i3, i2, -t1 * varea[i3]); - nlMatrixAdd(sys->context, i3, i1, -t2 * varea[i3]); - nlMatrixAdd(sys->context, i1, i3, -t2 * varea[i1]); + EIG_linear_solver_matrix_add(sys->context, i3, i1, -t2 * varea[i3]); + EIG_linear_solver_matrix_add(sys->context, i1, i3, -t2 * varea[i1]); if (sys->storeweights) { sys->fweights[f][0] = t1 * varea[i1]; @@ -218,11 +216,11 @@ static LaplacianSystem *laplacian_system_construct_begin(int totvert, int totfac sys->areaweights = 1; sys->storeweights = 0; - /* create opennl context */ - sys->context = nlNewContext(); - nlSolverParameteri(sys->context, NL_NB_VARIABLES, totvert); + /* create linear solver */ if (lsq) - nlSolverParameteri(sys->context, NL_LEAST_SQUARES, NL_TRUE); + sys->context = EIG_linear_least_squares_solver_new(0, totvert, 1); + else + sys->context = EIG_linear_solver_new(0, totvert, 1); return sys; } @@ -272,7 +270,7 @@ static void laplacian_system_construct_end(LaplacianSystem *sys) /* for heat weighting */ if (sys->heat.H) - nlMatrixAdd(sys->context, a, a, sys->heat.H[a]); + EIG_linear_solver_matrix_add(sys->context, a, a, sys->heat.H[a]); } if (sys->storeweights) @@ -301,7 +299,7 @@ static void laplacian_system_delete(LaplacianSystem *sys) if (sys->faces) MEM_freeN(sys->faces); if (sys->fweights) MEM_freeN(sys->fweights); - nlDeleteContext(sys->context); + EIG_linear_solver_delete(sys->context); MEM_freeN(sys); } @@ -309,42 +307,37 @@ void laplacian_begin_solve(LaplacianSystem *sys, int index) { int a; - if (!sys->nlbegun) { - nlBegin(sys->context, NL_SYSTEM); - + if (!sys->variablesdone) { if (index >= 0) { for (a = 0; a < sys->totvert; a++) { if (sys->vpinned[a]) { - nlSetVariable(sys->context, 0, a, sys->verts[a][index]); - nlLockVariable(sys->context, a); + EIG_linear_solver_variable_set(sys->context, 0, a, sys->verts[a][index]); + EIG_linear_solver_variable_lock(sys->context, a); } } } - nlBegin(sys->context, NL_MATRIX); - sys->nlbegun = 1; + sys->variablesdone = true; } } void laplacian_add_right_hand_side(LaplacianSystem *sys, int v, float value) { - nlRightHandSideAdd(sys->context, 0, v, value); + EIG_linear_solver_right_hand_side_add(sys->context, 0, v, value); } int laplacian_system_solve(LaplacianSystem *sys) { - nlEnd(sys->context, NL_MATRIX); - nlEnd(sys->context, NL_SYSTEM); - sys->nlbegun = 0; + sys->variablesdone = false; - //nlPrintMatrix(sys->context, ); + //EIG_linear_solver_print_matrix(sys->context, ); - return nlSolve(sys->context, NL_TRUE); + return EIG_linear_solver_solve(sys->context); } float laplacian_system_get_solution(LaplacianSystem *sys, int v) { - return nlGetVariable(sys->context, 0, v); + return EIG_linear_solver_variable_get(sys->context, 0, v); } /************************* Heat Bone Weighting ******************************/ @@ -1284,7 +1277,7 @@ static float meshdeform_boundary_total_weight(MeshDeformBind *mdb, int x, int y, return totweight; } -static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, NLContext *context, int x, int y, int z) +static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z) { MDefBoundIsect *isect; float weight, totweight; @@ -1294,7 +1287,7 @@ static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, NLContext *context, if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR) return; - nlMatrixAdd(context, mdb->varidx[acenter], mdb->varidx[acenter], 1.0f); + EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[acenter], 1.0f); totweight = meshdeform_boundary_total_weight(mdb, x, y, z); for (i = 1; i <= 6; i++) { @@ -1305,12 +1298,12 @@ static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, NLContext *context, isect = mdb->boundisect[acenter][i - 1]; if (!isect) { weight = (1.0f / mdb->width[0]) / totweight; - nlMatrixAdd(context, mdb->varidx[acenter], mdb->varidx[a], -weight); + EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[a], -weight); } } } -static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, NLContext *context, int x, int y, int z, int cagevert) +static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z, int cagevert) { MDefBoundIsect *isect; float rhs, weight, totweight; @@ -1331,7 +1324,7 @@ static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, NLContext *context, i if (isect) { weight = (1.0f / isect->len) / totweight; rhs = weight * meshdeform_boundary_phi(mdb, isect, cagevert); - nlRightHandSideAdd(context, 0, mdb->varidx[acenter], rhs); + EIG_linear_solver_right_hand_side_add(context, 0, mdb->varidx[acenter], rhs); } } } @@ -1386,7 +1379,7 @@ static void meshdeform_matrix_add_exterior_phi(MeshDeformBind *mdb, int x, int y static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind *mdb) { - NLContext *context; + LinearSolver *context; float vec[3], gridvec[3]; int a, b, x, y, z, totvar; char message[256]; @@ -1403,15 +1396,8 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind progress_bar(0, "Starting mesh deform solve"); - /* setup opennl solver */ - context = nlNewContext(); - - nlSolverParameteri(context, NL_NB_VARIABLES, totvar); - nlSolverParameteri(context, NL_NB_ROWS, totvar); - nlSolverParameteri(context, NL_NB_RIGHT_HAND_SIDES, 1); - - nlBegin(context, NL_SYSTEM); - nlBegin(context, NL_MATRIX); + /* setup linear solver */ + context = EIG_linear_solver_new(totvar, totvar, 1); /* build matrix */ for (z = 0; z < mdb->size; z++) @@ -1421,21 +1407,13 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind /* solve for each cage vert */ for (a = 0; a < mdb->totcagevert; a++) { - if (a != 0) { - nlBegin(context, NL_SYSTEM); - nlBegin(context, NL_MATRIX); - } - /* fill in right hand side and solve */ for (z = 0; z < mdb->size; z++) for (y = 0; y < mdb->size; y++) for (x = 0; x < mdb->size; x++) meshdeform_matrix_add_rhs(mdb, context, x, y, z, a); - nlEnd(context, NL_MATRIX); - nlEnd(context, NL_SYSTEM); - - if (nlSolve(context, NL_TRUE)) { + if (EIG_linear_solver_solve(context)) { for (z = 0; z < mdb->size; z++) for (y = 0; y < mdb->size; y++) for (x = 0; x < mdb->size; x++) @@ -1448,7 +1426,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind for (b = 0; b < mdb->size3; b++) { if (mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR) - mdb->phi[b] = nlGetVariable(context, 0, mdb->varidx[b]); + mdb->phi[b] = EIG_linear_solver_variable_get(context, 0, mdb->varidx[b]); mdb->totalphi[b] += mdb->phi[b]; } @@ -1502,7 +1480,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind /* free */ MEM_freeN(mdb->varidx); - nlDeleteContext(context); + EIG_linear_solver_delete(context); } static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierData *mmd, MeshDeformBind *mdb) @@ -1655,7 +1633,9 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa free_bvhtree_from_mesh(&mdb->bvhdata); } -void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[4][4]) +void mesh_deform_bind( + Scene *scene, MeshDeformModifierData *mmd, DerivedMesh *cagedm, + float *vertexcos, int totvert, float cagemat[4][4]) { MeshDeformBind mdb; MVert *mvert; @@ -1670,7 +1650,7 @@ void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexco mdb.vertexcos = MEM_callocN(sizeof(float) * 3 * totvert, "MeshDeformCos"); mdb.totvert = totvert; - mdb.cagedm = mesh_create_derived_no_deform(scene, mmd->object, NULL, CD_MASK_BAREMESH); + mdb.cagedm = cagedm; mdb.totcagevert = mdb.cagedm->getNumVerts(mdb.cagedm); mdb.cagecos = MEM_callocN(sizeof(*mdb.cagecos) * mdb.totcagevert, "MeshDeformBindCos"); copy_m4_m4(mdb.cagemat, cagemat); @@ -1695,7 +1675,6 @@ void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexco mul_m4_v3(mmd->object->obmat, mmd->bindcagecos + a * 3); /* free */ - mdb.cagedm->release(mdb.cagedm); MEM_freeN(mdb.vertexcos); /* compact weights */ @@ -1704,14 +1683,3 @@ void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexco end_progress_bar(); waitcursor(0); } - -#else /* WITH_OPENNL */ - -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - -void mesh_deform_bind(Scene *scene, MeshDeformModifierData *mmd, float *vertexcos, int totvert, float cagemat[4][4]) {} -void *modifier_mdef_compact_influences_link_kludge = modifier_mdef_compact_influences; - -#endif /* WITH_OPENNL */ diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c index d53e5b857a0..a1c1f4f115e 100644 --- a/source/blender/editors/armature/reeb.c +++ b/source/blender/editors/armature/reeb.c @@ -2497,7 +2497,7 @@ int weightFromLoc(EditMesh *em, int axis) return 1; } -static void addTriangle(NLContext *context, EditVert *v1, EditVert *v2, EditVert *v3, int e1, int e2, int e3) +static void addTriangle(LinearSolver *context, EditVert *v1, EditVert *v2, EditVert *v3, int e1, int e2, int e3) { /* Angle opposite e1 */ float t1 = cotangent_tri_weight_v3(v1->co, v2->co, v3->co) / e2; @@ -2512,23 +2512,23 @@ static void addTriangle(NLContext *context, EditVert *v1, EditVert *v2, EditVert int i2 = indexData(v2); int i3 = indexData(v3); - nlMatrixAdd(context, i1, i1, t2 + t3); - nlMatrixAdd(context, i2, i2, t1 + t3); - nlMatrixAdd(context, i3, i3, t1 + t2); + EIG_linear_solver_matrix_add(context, i1, i1, t2 + t3); + EIG_linear_solver_matrix_add(context, i2, i2, t1 + t3); + EIG_linear_solver_matrix_add(context, i3, i3, t1 + t2); - nlMatrixAdd(context, i1, i2, -t3); - nlMatrixAdd(context, i2, i1, -t3); + EIG_linear_solver_matrix_add(context, i1, i2, -t3); + EIG_linear_solver_matrix_add(context, i2, i1, -t3); - nlMatrixAdd(context, i2, i3, -t1); - nlMatrixAdd(context, i3, i2, -t1); + EIG_linear_solver_matrix_add(context, i2, i3, -t1); + EIG_linear_solver_matrix_add(context, i3, i2, -t1); - nlMatrixAdd(context, i3, i1, -t2); - nlMatrixAdd(context, i1, i3, -t2); + EIG_linear_solver_matrix_add(context, i3, i1, -t2); + EIG_linear_solver_matrix_add(context, i1, i3, -t2); } int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges) { - NLContext *context; + LinearSolver *context; NLboolean success; EditVert *eve; EditEdge *eed; @@ -2542,14 +2542,10 @@ int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges) totvert++; } - /* Solve with openNL */ + /* Solve */ - context = nlNewContext(); + context = EIG_linear_solver_new(, 0, totvert, 1); - nlSolverParameteri(context, NL_NB_VARIABLES, totvert); - - nlBegin(context, NL_SYSTEM); - /* Find local extrema */ for (index = 0, eve = em->verts.first; eve; index++, eve = eve->next) { if (eve->h == 0) { @@ -2583,8 +2579,8 @@ int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges) if (maximum || minimum) { float w = weightData(eve); eve->f1 = 0; - nlSetVariable(context, 0, index, w); - nlLockVariable(context, index); + EIG_linear_solver_variable_set(context, 0, index, w); + EIG_linear_solver_variable_lock(context, index); } else { eve->f1 = 1; @@ -2592,8 +2588,6 @@ int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges) } } - nlBegin(context, NL_MATRIX); - /* Zero edge weight */ for (eed = em->edges.first; eed; eed = eed->next) { eed->tmp.l = 0; @@ -2625,23 +2619,19 @@ int weightToHarmonic(EditMesh *em, EdgeIndex *indexed_edges) } } - nlEnd(context, NL_MATRIX); - - nlEnd(context, NL_SYSTEM); - - success = nlSolve(context, NL_TRUE); + success = EIG_linear_solver_solve(context); if (success) { rval = 1; for (index = 0, eve = em->verts.first; eve; index++, eve = eve->next) { - weightSetData(eve, nlGetVariable(context, 0, index)); + weightSetData(eve, EIG_linear_solver_variable_get(context, 0, index)); } } else { rval = 0; } - nlDeleteContext(context); + EIG_linear_solver_delete(context); return rval; } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index e2cf0c1ec14..22cb479e77d 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1352,7 +1352,11 @@ static int curve_split_exec(bContext *C, wmOperator *op) adduplicateflagNurb(obedit, &newnurb, SELECT, true); if (BLI_listbase_is_empty(&newnurb) == false) { + Curve *cu = obedit->data; + const int len_orig = BLI_listbase_count(editnurb); + curve_delete_segments(obedit, true); + cu->actnu -= len_orig - BLI_listbase_count(editnurb); BLI_movelisttolist(editnurb, &newnurb); if (ED_curve_updateAnimPaths(obedit->data)) @@ -1919,18 +1923,30 @@ bool ed_editnurb_extrude_flag(EditNurb *editnurb, const short flag) return ok; } +static bool calc_duplicate_actvert( + const ListBase *editnurb, const ListBase *newnurb, Curve *cu, + int start, int end, int vert) +{ + if ((start <= cu->actvert) && (end > cu->actvert)) { + cu->actvert = vert; + cu->actnu = BLI_listbase_count(editnurb) + BLI_listbase_count(newnurb); + return true; + } + return false; +} + static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, const short flag, const bool split) { ListBase *editnurb = object_editcurve_get(obedit); - Nurb *nu = editnurb->last, *newnu; + Nurb *nu, *newnu; BezTriple *bezt, *bezt1; BPoint *bp, *bp1, *bp2, *bp3; Curve *cu = (Curve *)obedit->data; - int a, b, c, starta, enda, diffa, cyclicu, cyclicv, newu, newv; + int a, b, c, starta, enda, diffa, cyclicu, cyclicv, newu, newv, i; char *usel; - while (nu) { + for (i = 0, nu = editnurb->first; nu; i++, nu = nu->next) { cyclicu = cyclicv = 0; if (nu->type == CU_BEZIER) { for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) { @@ -1951,12 +1967,21 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, } else { if (enda == nu->pntsu - 1) newu += cyclicu; + if (i == cu->actnu) { + calc_duplicate_actvert( + editnurb, newnurb, cu, + starta, starta + diffa, cu->actvert - starta); + } newnu = BKE_nurb_copy(nu, newu, 1); - BLI_addtail(newnurb, newnu); memcpy(newnu->bezt, &nu->bezt[starta], diffa * sizeof(BezTriple)); if (newu != diffa) { memcpy(&newnu->bezt[diffa], nu->bezt, cyclicu * sizeof(BezTriple)); + if (i == cu->actnu) { + calc_duplicate_actvert( + editnurb, newnurb, cu, + 0, cyclicu, newu - cyclicu + cu->actvert); + } cyclicu = 0; } @@ -1965,19 +1990,28 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) { select_beztriple(bezt1, SELECT, flag, HIDDEN); } + + BLI_addtail(newnurb, newnu); } } } if (cyclicu != 0) { + if (i == cu->actnu) { + calc_duplicate_actvert( + editnurb, newnurb, cu, + 0, cyclicu, cu->actvert); + } + newnu = BKE_nurb_copy(nu, cyclicu, 1); - BLI_addtail(newnurb, newnu); memcpy(newnu->bezt, nu->bezt, cyclicu * sizeof(BezTriple)); newnu->flagu &= ~CU_NURB_CYCLIC; for (b = 0, bezt1 = newnu->bezt; b < newnu->pntsu; b++, bezt1++) { select_beztriple(bezt1, SELECT, flag, HIDDEN); } + + BLI_addtail(newnurb, newnu); } } else if (nu->pntsv == 1) { /* because UV Nurb has a different method for dupli */ @@ -1999,12 +2033,21 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, } else { if (enda == nu->pntsu - 1) newu += cyclicu; + if (i == cu->actnu) { + calc_duplicate_actvert( + editnurb, newnurb, cu, + starta, starta + diffa, cu->actvert - starta); + } newnu = BKE_nurb_copy(nu, newu, 1); - BLI_addtail(newnurb, newnu); memcpy(newnu->bp, &nu->bp[starta], diffa * sizeof(BPoint)); if (newu != diffa) { memcpy(&newnu->bp[diffa], nu->bp, cyclicu * sizeof(BPoint)); + if (i == cu->actnu) { + calc_duplicate_actvert( + editnurb, newnurb, cu, + 0, cyclicu, newu - cyclicu + cu->actvert); + } cyclicu = 0; } @@ -2013,19 +2056,28 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) { select_bpoint(bp1, SELECT, flag, HIDDEN); } + + BLI_addtail(newnurb, newnu); } } } if (cyclicu != 0) { + if (i == cu->actnu) { + calc_duplicate_actvert( + editnurb, newnurb, cu, + 0, cyclicu, cu->actvert); + } + newnu = BKE_nurb_copy(nu, cyclicu, 1); - BLI_addtail(newnurb, newnu); memcpy(newnu->bp, nu->bp, cyclicu * sizeof(BPoint)); newnu->flagu &= ~CU_NURB_CYCLIC; for (b = 0, bp1 = newnu->bp; b < newnu->pntsu; b++, bp1++) { select_bpoint(bp1, SELECT, flag, HIDDEN); } + + BLI_addtail(newnurb, newnu); } } else { @@ -2101,6 +2153,28 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, memcpy(&newnu->bp[b * newnu->pntsu], &nu->bp[b * nu->pntsu + a], newu * sizeof(BPoint)); memcpy(&newnu->bp[b * newnu->pntsu + newu], &nu->bp[b * nu->pntsu], cyclicu * sizeof(BPoint)); } + + if (cu->actnu == i) { + for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) { + starta = b * nu->pntsu + a; + if (calc_duplicate_actvert( + editnurb, newnurb, cu, + cu->actvert, starta, + cu->actvert % nu->pntsu + newu + b * newnu->pntsu)) + { + /* actvert in cyclicu selection */ + break; + } + else if (calc_duplicate_actvert( + editnurb, newnurb, cu, + starta, starta + newu, + cu->actvert - starta + b * newnu->pntsu)) + { + /* actvert in 'current' iteration selection */ + break; + } + } + } cyclicu = cyclicv = 0; } else if ((a / nu->pntsu) + newv == nu->pntsv && cyclicv != 0) { @@ -2108,6 +2182,14 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, newnu = BKE_nurb_copy(nu, newu, newv + cyclicv); memcpy(newnu->bp, &nu->bp[a], newu * newv * sizeof(BPoint)); memcpy(&newnu->bp[newu * newv], nu->bp, newu * cyclicv * sizeof(BPoint)); + + /* check for actvert in cylicv selection */ + if (cu->actnu == i) { + calc_duplicate_actvert( + editnurb, newnurb, cu, + cu->actvert, a, + (newu * newv) + cu->actvert); + } cyclicu = cyclicv = 0; } else { @@ -2116,6 +2198,20 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, memcpy(&newnu->bp[b * newu], &nu->bp[b * nu->pntsu + a], newu * sizeof(BPoint)); } } + + /* general case if not handled by cyclicu or cyclicv */ + if (cu->actnu == i) { + for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) { + starta = b * nu->pntsu + a; + if (calc_duplicate_actvert( + editnurb, newnurb, cu, + starta, starta + newu, + cu->actvert - (a / nu->pntsu * nu->pntsu + diffa + (starta % nu->pntsu)))) + { + break; + } + } + } BLI_addtail(newnurb, newnu); if (newu != nu->pntsu) newnu->flagu &= ~CU_NURB_CYCLIC; @@ -2132,6 +2228,20 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, for (b = 0; b < newv; b++) { memcpy(&newnu->bp[b * newu], &nu->bp[b * nu->pntsu], newu * sizeof(BPoint)); } + + /* check for actvert in the unused cyclicuv selection */ + if (cu->actnu == i) { + for (b = 0, diffa = 0; b < newv; b++, diffa += nu->pntsu - newu) { + starta = b * nu->pntsu; + if (calc_duplicate_actvert( + editnurb, newnurb, cu, + starta, starta + newu, + cu->actvert - (diffa + (starta % nu->pntsu)))) + { + break; + } + } + } BLI_addtail(newnurb, newnu); if (newu != nu->pntsu) newnu->flagu &= ~CU_NURB_CYCLIC; @@ -2145,12 +2255,9 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb, } } } - nu = nu->prev; } if (BLI_listbase_is_empty(newnurb) == false) { - cu->actnu = cu->actvert = CU_ACT_NONE; - for (nu = newnurb->first; nu; nu = nu->next) { if (nu->type == CU_BEZIER) { if (split) { @@ -4868,7 +4975,9 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) const float mval[2] = {UNPACK2(event->mval)}; float no_dummy[3]; float dist_px_dummy; - snapObjectsContext(C, mval, &dist_px_dummy, location, no_dummy, SNAP_NOT_OBEDIT); + snapObjectsContext( + C, mval, SNAP_NOT_OBEDIT, + location, no_dummy, &dist_px_dummy); } RNA_float_set_array(op->ptr, "location", location); diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index b904417cfcb..05b733d2564 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -90,12 +90,6 @@ void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments); /** - * Returns an integer value as obtained by glGetIntegerv. - * The param must cause only one value to be gotten from GL. - */ -int glaGetOneInteger(int param); - -/** * Returns a float value as obtained by glGetFloatv. * The param must cause only one value to be gotten from GL. */ diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 7d7ee33bde4..15c68378b9a 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -42,6 +42,7 @@ struct bPoseChannel; struct IDProperty; struct ListBase; struct MeshDeformModifierData; +struct DerivedMesh; struct Object; struct ReportList; struct Scene; @@ -208,6 +209,7 @@ int BDR_drawSketchNames(struct ViewContext *vc); /* meshlaplacian.c */ void mesh_deform_bind(struct Scene *scene, struct MeshDeformModifierData *mmd, + struct DerivedMesh *cagedm, float *vertexcos, int totvert, float cagemat[4][4]); #ifdef __cplusplus diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 8e19ec839d8..c509aeb4ac2 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -196,7 +196,7 @@ void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct BMEd /* editface.c */ -void paintface_flush_flags(struct Object *ob); +void paintface_flush_flags(struct Object *ob, short flag); bool paintface_mouse_select(struct bContext *C, struct Object *ob, const int mval[2], bool extend, bool deselect, bool toggle); int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, bool select, bool extend); void paintface_deselect_all_visible(struct Object *ob, int action, bool flush_flags); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 9fd7ec32279..c9b7875aef0 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -137,6 +137,7 @@ float ED_object_new_primitive_matrix( void ED_object_add_unit_props(struct wmOperatorType *ot); void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode); +void ED_object_add_mesh_props(struct wmOperatorType *ot); bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, const char view_align_axis, float loc[3], float rot[3], bool *enter_editmode, unsigned int *layer, bool *is_view_aligned); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index b0866a564e5..19bfb94e130 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -168,30 +168,53 @@ typedef struct DepthPeel { struct ListBase; -typedef enum SnapMode { +typedef enum SnapSelect { SNAP_ALL = 0, SNAP_NOT_SELECTED = 1, SNAP_NOT_OBEDIT = 2 -} SnapMode; +} SnapSelect; #define SNAP_MIN_DISTANCE 30 #define TRANSFORM_DIST_MAX_RAY (FLT_MAX / 2.0f) -bool peelObjectsTransForm(struct TransInfo *t, struct ListBase *depth_peels, const float mval[2], SnapMode mode); -bool peelObjectsContext(struct bContext *C, struct ListBase *depth_peels, const float mval[2], SnapMode mode); -bool snapObjectsTransform(struct TransInfo *t, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode); -bool snapObjectsContext(struct bContext *C, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode); +bool peelObjectsTransForm( + struct TransInfo *t, const float mval[2], SnapSelect snap_select, + /* return args */ + struct ListBase *r_depth_peels); +bool peelObjectsContext( + struct bContext *C, const float mval[2], SnapSelect snap_select, + /* return args */ + struct ListBase *r_depth_peels); +bool snapObjectsTransform( + struct TransInfo *t, const float mval[2], SnapSelect snap_select, + /* return args */ + float r_loc[3], float r_no[3], float *r_dist_px); +bool snapObjectsContext( + struct bContext *C, const float mval[2], SnapSelect snap_select, + /* return args */ + float r_loc[3], float r_no[3], float *r_dist_px); /* taks args for all settings */ -bool snapObjectsEx(struct Scene *scene, struct Base *base_act, struct View3D *v3d, struct ARegion *ar, struct Object *obedit, short snap_mode, - const float mval[2], float *r_dist_px, - float r_loc[3], float r_no[3], float *r_ray_dist, SnapMode mode); -bool snapObjectsRayEx(struct Scene *scene, struct Base *base_act, struct View3D *v3d, struct ARegion *ar, struct Object *obedit, short snap_mode, - struct Object **r_ob, float r_obmat[4][4], - const float ray_start[3], const float ray_normal[3], float *r_ray_dist, - const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode); - -bool snapNodesTransform(struct TransInfo *t, const int mval[2], float *r_dist_px, float r_loc[2], char *r_node_border, SnapMode mode); -bool snapNodesContext(struct bContext *C, const int mval[2], float *r_dist_px, float r_loc[2], char *r_node_border, SnapMode mode); - -#endif - +bool snapObjectsEx( + struct Scene *scene, struct View3D *v3d, struct ARegion *ar, struct Base *base_act, struct Object *obedit, + const float mval[2], SnapSelect snap_select, short snap_mode, + float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], float *r_dist_px); +bool snapObjectsRayEx( + struct Scene *scene, struct View3D *v3d, struct ARegion *ar, struct Base *base_act, struct Object *obedit, + const float mval[2], SnapSelect snap_select, short snap_mode, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], float *r_dist_px, int *r_index, + struct Object **r_ob, float r_obmat[4][4]); + +bool snapNodesTransform( + struct TransInfo *t, const int mval[2], SnapSelect snap_select, + /* return args */ + float r_loc[2], float *r_dist_px, char *r_node_border); +bool snapNodesContext( + struct bContext *C, const int mval[2], SnapSelect snap_select, + /* return args */ + float r_loc[2], float *r_dist_px, char *r_node_border); + +#endif /* __ED_TRANSFORM_H__ */ diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 496ce7f2c60..cb331554a8f 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -44,6 +44,8 @@ bool ED_editors_flush_edits(const struct bContext *C, bool for_render); void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id); +void ED_OT_flush_edits(struct wmOperatorType *ot); + /* ************** Undo ************************ */ /* undo.c */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 108fcdda613..d4b723b807f 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -39,9 +39,11 @@ /* Struct Declarations */ struct ID; +struct IDProperty; struct ListBase; struct ARegion; struct ScrArea; +struct bScreen; struct wmEvent; struct wmWindow; struct wmOperator; @@ -657,7 +659,7 @@ uiBut *uiDefKeyevtButS(uiBlock *block, int retval, const char *str, int x, int y uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, const char *str, int x, int y, short width, short height, short *keypoin, short *modkeypoin, const char *tip); uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, int x, int y, short width, short height, float a1, float a2, const char *tip); -uiBut *uiDefSearchButO_ptr(uiBlock *block, struct wmOperatorType *ot, IDProperty *properties, +uiBut *uiDefSearchButO_ptr(uiBlock *block, struct wmOperatorType *ot, struct IDProperty *properties, void *arg, int retval, int icon, int maxlen, int x, int y, short width, short height, float a1, float a2, const char *tip); @@ -964,7 +966,7 @@ void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname void uiItemFloatO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, float value); void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, const char *value); -PointerRNA uiItemFullO_ptr(uiLayout *layout, struct wmOperatorType *ot, const char *name, int icon, IDProperty *properties, int context, int flag); +PointerRNA uiItemFullO_ptr(uiLayout *layout, struct wmOperatorType *ot, const char *name, int icon, struct IDProperty *properties, int context, int flag); PointerRNA uiItemFullO(uiLayout *layout, const char *idname, const char *name, int icon, struct IDProperty *properties, int context, int flag); void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index cd68425cc33..dc843952229 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -200,8 +200,9 @@ enum { TH_SEQ_EFFECT, TH_SEQ_TRANSITION, TH_SEQ_META, + TH_SEQ_TEXT, TH_SEQ_PREVIEW, - + TH_EDGE_SHARP, TH_EDITMESH_ACTIVE, diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index e03273aa474..79a7f4fc57a 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1046,6 +1046,10 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, /* dopesheet filtering options... */ data_path = BLI_sprintfN("space_data.dopesheet.%s", RNA_property_identifier(but->rnaprop)); } + else if (RNA_struct_is_a(but->rnapoin.type, &RNA_FileSelectParams)) { + /* Filebrowser options... */ + data_path = BLI_sprintfN("space_data.params.%s", RNA_property_identifier(but->rnaprop)); + } } } else if (GS(id->name) == ID_SCE) { diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c index 89a44db5fa3..e9d601457b4 100644 --- a/source/blender/editors/interface/interface_align.c +++ b/source/blender/editors/interface/interface_align.c @@ -164,11 +164,16 @@ static void block_align_proximity_compute(ButAlign *butal, ButAlign *butal_other if (delta < max_delta) { /* We are only interested in neighbors that are at least as close as already found ones. */ if (delta <= butal->dists[side]) { - if (delta < butal->dists[side]) { - /* We found a closer neighbor. + { + /* We found an as close or closer neighbor. * If both buttons are alignable, we set them as each other neighbors. * Else, we have an unalignable one, we need to reset the others matching neighbor to NULL - * if its 'proximity distance' is really lower with current one. */ + * if its 'proximity distance' is really lower with current one. + * + * NOTE: We cannot only execute that piece of code in case we found a **closer** neighbor, + * due to the limited way we represent neighbors (buttons only know **one** neighbor + * on each side, when they can actually have several ones), it would prevent + * some buttons to be properly 'neighborly-initialized'. */ if (butal_can_align && butal_other_can_align) { butal->neighbors[side] = butal_other; butal_other->neighbors[side_opp] = butal; @@ -181,6 +186,7 @@ static void block_align_proximity_compute(ButAlign *butal, ButAlign *butal_other } butal->dists[side] = butal_other->dists[side_opp] = delta; } + if (butal_can_align && butal_other_can_align) { const int side_s1 = SIDE1(side); const int side_s2 = SIDE2(side); diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 84767eae350..ae2e6744160 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -55,6 +55,9 @@ #include "BLF_api.h" +#include "GPU_draw.h" +#include "GPU_basic_shader.h" + #include "UI_interface.h" /* own include */ @@ -1216,43 +1219,33 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect) { static GLuint displist = 0; - int a, old[8]; - GLfloat diff[4], diffn[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - float vec0[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - float dir[4], size; + float diffuse[3] = {1.0f, 1.0f, 1.0f}; + float size; - /* store stuff */ - glGetMaterialfv(GL_FRONT, GL_DIFFUSE, diff); - /* backdrop */ glColor3ubv((unsigned char *)wcol->inner); UI_draw_roundbox_corner_set(UI_CNR_ALL); UI_draw_roundbox_gl_mode(GL_POLYGON, rect->xmin, rect->ymin, rect->xmax, rect->ymax, 5.0f); /* sphere color */ - glMaterialfv(GL_FRONT, GL_DIFFUSE, diffn); glCullFace(GL_BACK); glEnable(GL_CULL_FACE); - /* disable blender light */ - for (a = 0; a < 8; a++) { - old[a] = glIsEnabled(GL_LIGHT0 + a); - glDisable(GL_LIGHT0 + a); - } - - /* own light */ - glEnable(GL_LIGHT7); - glEnable(GL_LIGHTING); - - ui_but_v3_get(but, dir); + /* setup lights */ + GPULightData light = {0}; + light.type = GPU_LIGHT_SUN; + copy_v3_v3(light.diffuse, diffuse); + zero_v3(light.specular); + ui_but_v3_get(but, light.direction); + + GPU_basic_shader_light_set(0, &light); + for (int a = 1; a < 8; a++) + GPU_basic_shader_light_set(a, NULL); + + /* setup shader */ + GPU_basic_shader_colors(diffuse, NULL, 0, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING); - dir[3] = 0.0f; /* glLightfv needs 4 args, 0.0 is sun */ - glLightfv(GL_LIGHT7, GL_POSITION, dir); - glLightfv(GL_LIGHT7, GL_DIFFUSE, diffn); - glLightfv(GL_LIGHT7, GL_SPECULAR, vec0); - glLightf(GL_LIGHT7, GL_CONSTANT_ATTENUATION, 1.0f); - glLightf(GL_LIGHT7, GL_LINEAR_ATTENUATION, 0.0f); - /* transform to button */ glPushMatrix(); glTranslatef(rect->xmin + 0.5f * BLI_rcti_size_x(rect), rect->ymin + 0.5f * BLI_rcti_size_y(rect), 0.0f); @@ -1283,10 +1276,9 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect) glCallList(displist); /* restore */ - glDisable(GL_LIGHTING); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + GPU_default_lights(); glDisable(GL_CULL_FACE); - glMaterialfv(GL_FRONT, GL_DIFFUSE, diff); - glDisable(GL_LIGHT7); /* AA circle */ glEnable(GL_BLEND); @@ -1298,12 +1290,6 @@ void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect) /* matrix after circle */ glPopMatrix(); - - /* enable blender light */ - for (a = 0; a < 8; a++) { - if (old[a]) - glEnable(GL_LIGHT0 + a); - } } static void ui_draw_but_curve_grid(const rcti *rect, float zoomx, float zoomy, float offsx, float offsy, float step) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 561a59b57ef..9a85f5b508d 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2186,6 +2186,32 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB /* ******************* copy and paste ******************** */ +static void ui_but_copy_data_path(uiBut *but, const bool full_path) +{ + char *id_path; + + if (but->rnapoin.id.data == NULL) { + return; + } + + if (full_path) { + if (but->rnaprop) { + id_path = RNA_path_full_property_py_ex(&but->rnapoin, but->rnaprop, but->rnaindex, true); + } + else { + id_path = RNA_path_full_struct_py(&but->rnapoin); + } + } + else { + id_path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop); + } + + if (id_path) { + WM_clipboard_text_set(id_path, false); + MEM_freeN(id_path); + } +} + /* c = copy, v = paste */ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode) { @@ -6375,10 +6401,10 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg) uiLayout *layout; uiStyle *style = UI_style_get_dpi(); IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; - int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km); - kmi = WM_keymap_item_find_id(km, kmi_id); - + kmi = WM_key_event_operator(C, but->optype->idname, but->opcontext, prop, true, &km); + BLI_assert(kmi != NULL); + RNA_pointer_create(&wm->id, &RNA_KeyMapItem, kmi, &ptr); block = UI_block_begin(C, ar, "_popup", UI_EMBOSS); @@ -6482,9 +6508,10 @@ static void remove_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) wmKeyMap *km; wmKeyMapItem *kmi; IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; - int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km); - - kmi = WM_keymap_item_find_id(km, kmi_id); + + kmi = WM_key_event_operator(C, but->optype->idname, but->opcontext, prop, true, &km); + BLI_assert(kmi != NULL); + WM_keymap_remove_item(km, kmi); but_shortcut_name_func(C, but, 0); @@ -6727,12 +6754,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) IDProperty *prop = (but->opptr) ? but->opptr->data : NULL; int w = uiLayoutGetWidth(layout); wmKeyMap *km; - wmKeyMapItem *kmi = NULL; /* We want to know if this op has a shortcut, be it hotkey or not. */ - int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, false, &km); - - if (kmi_id) - kmi = WM_keymap_item_find_id(km, kmi_id); + wmKeyMapItem *kmi = WM_key_event_operator(C, but->optype->idname, but->opcontext, prop, false, &km); /* We do have a shortcut, but only keyboard ones are editbale that way... */ if (kmi) { @@ -6840,6 +6863,12 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * } } + /* special case, copy-data-path */ + if ((event->type == CKEY) && event->shift) { + ui_but_copy_data_path(but, event->alt != 0); + return WM_UI_HANDLER_BREAK; + } + ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v'); return WM_UI_HANDLER_BREAK; } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 843b0d5f2dc..8e6558c74b8 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" #include "GPU_extensions.h" +#include "GPU_basic_shader.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -626,7 +627,7 @@ static void init_internal_icons(void) } /* we only use a texture for cards with non-power of two */ - if (GPU_non_power_of_two_support()) { + if (GPU_full_non_power_of_two_support()) { glGenTextures(1, &icongltex.id); if (icongltex.id) { @@ -639,12 +640,12 @@ static void init_internal_icons(void) glBindTexture(GL_TEXTURE_2D, icongltex.id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, b32buf->x, b32buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b32buf->rect); - glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, b32buf->x, b32buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b32buf->rect); + glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, b16buf->x, b16buf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, b16buf->rect); while (b16buf->x > 1) { ImBuf *nbuf = IMB_onehalf(b16buf); - glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, nbuf->x, nbuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nbuf->rect); + glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, nbuf->x, nbuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nbuf->rect); level++; IMB_freeImBuf(b16buf); b16buf = nbuf; @@ -1122,7 +1123,7 @@ static void icon_draw_texture( y1 = iy * icongltex.invh; y2 = (iy + ih) * icongltex.invh; - glEnable(GL_TEXTURE_2D); + GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); glBindTexture(GL_TEXTURE_2D, icongltex.id); /* sharper downscaling, has no effect when scale matches with a mip level */ @@ -1145,7 +1146,7 @@ static void icon_draw_texture( glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.0f); glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } /* Drawing size for preview images */ diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 5ee7556a042..8242d029b6a 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1648,7 +1648,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) /* Secondary theme colors */ unsigned char theme_col_tab_outline[3]; - unsigned char theme_col_tab_divider[3]; /* line that divides tabs from the main area */ + unsigned char theme_col_tab_divider[3]; /* line that divides tabs from the main region */ unsigned char theme_col_tab_highlight[3]; unsigned char theme_col_tab_highlight_inactive[3]; diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 3a24625c36c..5fe6fd119aa 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -534,33 +534,18 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) if (but->rnapoin.id.data) { /* this could get its own 'BUT_GET_...' type */ - PointerRNA *ptr = &but->rnapoin; - PropertyRNA *prop = but->rnaprop; - ID *id = ptr->id.data; - - char *id_path; - char *data_path = NULL; /* never fails */ - id_path = RNA_path_full_ID_py(id); - - if (ptr->data && prop) { - data_path = RNA_path_from_ID_to_property(ptr, prop); - } + char *id_path; - if (data_path) { - const char *data_delim = (data_path[0] == '[') ? "" : "."; - BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), - "%s%s%s", /* no need to translate */ - id_path, data_delim, data_path); - MEM_freeN(data_path); + if (but->rnaprop) { + id_path = RNA_path_full_property_py_ex(&but->rnapoin, but->rnaprop, but->rnaindex, true); } - else if (prop) { - /* can't find the path. be explicit in our ignorance "..." */ - BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), - "%s ... %s", /* no need to translate */ - id_path, rna_prop.strinfo ? rna_prop.strinfo : RNA_property_identifier(prop)); + else { + id_path = RNA_path_full_struct_py(&but->rnapoin); } + + BLI_strncat_utf8(data->lines[data->totline], id_path, sizeof(data->lines[0])); MEM_freeN(id_path); data->format[data->totline].style = UI_TIP_STYLE_MONO; diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 25a187c43ad..6ce29242cbb 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -410,6 +410,11 @@ void uiStyleInit(void) BLF_unload_id(font->blf_id); } + if (blf_mono_font != -1) { + BLF_unload_id(blf_mono_font); + blf_mono_font = -1; + } + font = U.uifonts.first; /* default builtin */ @@ -498,14 +503,17 @@ void uiStyleInit(void) } /* reload */ - BLF_unload("monospace"); - blf_mono_font = -1; blf_mono_font_render = -1; #endif /* XXX, this should be moved into a style, but for now best only load the monospaced font once. */ - if (blf_mono_font == -1) + BLI_assert(blf_mono_font == -1); + if (U.font_path_ui_mono[0]) { + blf_mono_font = BLF_load_unique(U.font_path_ui_mono); + } + if (blf_mono_font == -1) { blf_mono_font = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size); + } BLF_size(blf_mono_font, 12 * U.pixelsize, 72); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 294aa6ce2ac..5fb1afac34f 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -492,6 +492,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo cp = ts->transition; break; case TH_SEQ_META: cp = ts->meta; break; + case TH_SEQ_TEXT: + cp = ts->text_strip; break; case TH_SEQ_PREVIEW: cp = ts->preview_back; break; @@ -1062,6 +1064,7 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tseq.effect, 169, 84, 124, 255); rgba_char_args_set(btheme->tseq.transition, 162, 95, 111, 255); rgba_char_args_set(btheme->tseq.meta, 109, 145, 131, 255); + rgba_char_args_set(btheme->tseq.text_strip, 162, 151, 0, 255); rgba_char_args_set(btheme->tseq.preview_back, 0, 0, 0, 255); rgba_char_args_set(btheme->tseq.grid, 64, 64, 64, 255); @@ -2668,6 +2671,13 @@ void init_userdef_do_versions(void) } } + if (!USER_VERSION_ATLEAST(276, 3)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + rgba_char_args_set(btheme->tseq.text_strip, 162, 151, 0, 255); + } + } + if (U.pixelsize == 0.0f) U.pixelsize = 1.0f; diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 0017cd3c2ae..e5b4e661773 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -53,11 +53,13 @@ #include "WM_api.h" #include "WM_types.h" +#include "GPU_buffers.h" + /* own include */ /* copy the face flags, most importantly selection from the mesh to the final derived mesh, * use in object mode when selecting faces (while painting) */ -void paintface_flush_flags(Object *ob) +void paintface_flush_flags(Object *ob, short flag) { Mesh *me = BKE_mesh_from_object(ob); DerivedMesh *dm = ob->derivedFinal; @@ -66,6 +68,8 @@ void paintface_flush_flags(Object *ob) int totpoly; int i; + BLI_assert((flag & ~(SELECT | ME_HIDE)) == 0); + if (me == NULL) return; @@ -73,7 +77,9 @@ void paintface_flush_flags(Object *ob) /* we could call this directly in all areas that change selection, * since this could become slow for realtime updates (circle-select for eg) */ - BKE_mesh_flush_select_from_polys(me); + if (flag & SELECT) { + BKE_mesh_flush_select_from_polys(me); + } if (dm == NULL) return; @@ -90,9 +96,15 @@ void paintface_flush_flags(Object *ob) /* Copy flags onto the final derived poly from the original mesh poly */ mp_orig = me->mpoly + index_array[i]; polys[i].flag = mp_orig->flag; + } } } + + if (flag & ME_HIDE) { + /* draw-object caches hidden faces, force re-generation T46867 */ + GPU_drawobject_free(dm); + } } void paintface_hide(Object *ob, const bool unselected) @@ -122,7 +134,7 @@ void paintface_hide(Object *ob, const bool unselected) BKE_mesh_flush_hidden_from_polys(me); - paintface_flush_flags(ob); + paintface_flush_flags(ob, SELECT | ME_HIDE); } @@ -147,7 +159,7 @@ void paintface_reveal(Object *ob) BKE_mesh_flush_hidden_from_polys(me); - paintface_flush_flags(ob); + paintface_flush_flags(ob, SELECT | ME_HIDE); } /* Set tface seams based on edge data, uses hash table to find seam edges. */ @@ -241,7 +253,7 @@ void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const b select_linked_tfaces_with_seams(me, index, select); - paintface_flush_flags(ob); + paintface_flush_flags(ob, SELECT); } void paintface_deselect_all_visible(Object *ob, int action, bool flush_flags) @@ -287,7 +299,7 @@ void paintface_deselect_all_visible(Object *ob, int action, bool flush_flags) } if (flush_flags) { - paintface_flush_flags(ob); + paintface_flush_flags(ob, SELECT); } } @@ -376,7 +388,7 @@ bool paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], b /* image window redraw */ - paintface_flush_flags(ob); + paintface_flush_flags(ob, SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views return true; @@ -454,7 +466,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten glReadBuffer(GL_BACK); #endif - paintface_flush_flags(vc->obact); + paintface_flush_flags(vc->obact, SELECT); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index e073a255f73..2a9f9c830f4 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -29,6 +29,7 @@ * \ingroup edmesh */ +#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -49,6 +50,7 @@ #include "ED_mesh.h" #include "ED_screen.h" #include "ED_object.h" +#include "ED_uvedit.h" #include "mesh_intern.h" /* own include */ @@ -105,16 +107,21 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op) bool enter_editmode; bool was_editmode; unsigned int layer; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4", - 1, 1, RNA_float_get(op->ptr, "radius"), mat)) + "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", + 1, 1, RNA_float_get(op->ptr, "radius"), mat, calc_uvs)) { return OPERATOR_CANCELLED; } @@ -139,6 +146,7 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ED_object_add_unit_props(ot); + ED_object_add_mesh_props(ot); ED_object_add_generic_props(ot, true); } @@ -150,16 +158,21 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op) bool enter_editmode; bool was_editmode; unsigned int layer; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_cube matrix=%m4 size=%f", - mat, RNA_float_get(op->ptr, "radius") * 2.0f)) + "create_cube matrix=%m4 size=%f calc_uvs=%b", + mat, RNA_float_get(op->ptr, "radius") * 2.0f, calc_uvs)) { return OPERATOR_CANCELLED; } @@ -185,6 +198,7 @@ void MESH_OT_primitive_cube_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ED_object_add_unit_props(ot); + ED_object_add_mesh_props(ot); ED_object_add_generic_props(ot, true); } @@ -203,6 +217,7 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) int cap_end, cap_tri; unsigned int layer; bool was_editmode; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); cap_end = RNA_enum_get(op->ptr, "fill_type"); cap_tri = (cap_end == 2); @@ -212,11 +227,15 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op) obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_circle segments=%i diameter=%f cap_ends=%b cap_tris=%b matrix=%m4", + "create_circle segments=%i diameter=%f cap_ends=%b cap_tris=%b matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"), - cap_end, cap_tri, mat)) + cap_end, cap_tri, mat, calc_uvs)) { return OPERATOR_CANCELLED; } @@ -245,6 +264,7 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot) ED_object_add_unit_props(ot); RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", ""); + ED_object_add_mesh_props(ot); ED_object_add_generic_props(ot, true); } @@ -259,20 +279,25 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); const bool cap_end = (end_fill_type != 0); const bool cap_tri = (end_fill_type == 2); + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4", + "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"), RNA_float_get(op->ptr, "radius"), cap_end, cap_tri, - RNA_float_get(op->ptr, "depth"), mat)) + RNA_float_get(op->ptr, "depth"), mat, calc_uvs)) { return OPERATOR_CANCELLED; } @@ -284,8 +309,6 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Add Cylinder"; ot->description = "Construct a cylinder mesh"; @@ -301,10 +324,10 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) /* props */ RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500); ED_object_add_unit_props(ot); - prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00); - RNA_def_property_subtype(prop, PROP_DISTANCE); + RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00); RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", ""); + ED_object_add_mesh_props(ot); ED_object_add_generic_props(ot, true); } @@ -319,17 +342,22 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type"); const bool cap_end = (end_fill_type != 0); const bool cap_tri = (end_fill_type == 2); + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4", + "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"), - RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat)) + RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat, calc_uvs)) { return OPERATOR_CANCELLED; } @@ -341,8 +369,6 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op) void MESH_OT_primitive_cone_add(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Add Cone"; ot->description = "Construct a conic mesh"; @@ -357,14 +383,12 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot) /* props */ RNA_def_int(ot->srna, "vertices", 32, 3, MESH_ADD_VERTS_MAXI, "Vertices", "", 3, 500); - prop = RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00); - RNA_def_property_subtype(prop, PROP_DISTANCE); - prop = RNA_def_float(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.001, 100.00); - RNA_def_property_subtype(prop, PROP_DISTANCE); - prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00); - RNA_def_property_subtype(prop, PROP_DISTANCE); + RNA_def_float_distance(ot->srna, "radius1", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 1", "", 0.001, 100.00); + RNA_def_float_distance(ot->srna, "radius2", 0.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius 2", "", 0.001, 100.00); + RNA_def_float_distance(ot->srna, "depth", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Depth", "", 0.001, 100.00); RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", ""); + ED_object_add_mesh_props(ot); ED_object_add_generic_props(ot, true); } @@ -376,18 +400,23 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op) bool enter_editmode; bool was_editmode; unsigned int layer; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4", + "create_grid x_segments=%i y_segments=%i size=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "x_subdivisions"), RNA_int_get(op->ptr, "y_subdivisions"), - RNA_float_get(op->ptr, "radius"), mat)) + RNA_float_get(op->ptr, "radius"), mat, calc_uvs)) { return OPERATOR_CANCELLED; } @@ -418,6 +447,7 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot) RNA_def_int(ot->srna, "y_subdivisions", 10, 2, MESH_ADD_VERTS_MAXI, "Y Subdivisions", "", 2, 1000); ED_object_add_unit_props(ot); + ED_object_add_mesh_props(ot); ED_object_add_generic_props(ot, true); } @@ -479,17 +509,22 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) bool enter_editmode; bool was_editmode; unsigned int layer; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4", + "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "segments"), RNA_int_get(op->ptr, "ring_count"), - RNA_float_get(op->ptr, "size"), mat)) + RNA_float_get(op->ptr, "size"), mat, calc_uvs)) { return OPERATOR_CANCELLED; } @@ -501,8 +536,6 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Add UV Sphere"; ot->description = "Construct a UV sphere mesh"; @@ -518,9 +551,9 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) /* props */ RNA_def_int(ot->srna, "segments", 32, 3, MESH_ADD_VERTS_MAXI / 100, "Segments", "", 3, 500); RNA_def_int(ot->srna, "ring_count", 16, 3, MESH_ADD_VERTS_MAXI / 100, "Rings", "", 3, 500); - prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00); - RNA_def_property_subtype(prop, PROP_DISTANCE); + RNA_def_float_distance(ot->srna, "size", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00); + ED_object_add_mesh_props(ot); ED_object_add_generic_props(ot, true); } @@ -532,17 +565,22 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) bool enter_editmode; bool was_editmode; unsigned int layer; + const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs"); WM_operator_view3d_unit_defaults(C, op); ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL); obedit = make_prim_init(C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"), &dia, mat, &was_editmode, loc, rot, layer); em = BKE_editmesh_from_object(obedit); + if (calc_uvs) { + ED_mesh_uv_texture_ensure(obedit->data, NULL); + } + if (!EDBM_op_call_and_selectf( em, op, "verts.out", false, - "create_icosphere subdivisions=%i diameter=%f matrix=%m4", + "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b", RNA_int_get(op->ptr, "subdivisions"), - RNA_float_get(op->ptr, "size"), mat)) + RNA_float_get(op->ptr, "size"), mat, calc_uvs)) { return OPERATOR_CANCELLED; } @@ -554,8 +592,6 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot) { - PropertyRNA *prop; - /* identifiers */ ot->name = "Add Ico Sphere"; ot->description = "Construct an Icosphere mesh"; @@ -570,8 +606,8 @@ void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot) /* props */ RNA_def_int(ot->srna, "subdivisions", 2, 1, 10, "Subdivisions", "", 1, 8); - prop = RNA_def_float(ot->srna, "size", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001f, 100.00); - RNA_def_property_subtype(prop, PROP_DISTANCE); + RNA_def_float_distance(ot->srna, "size", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001f, 100.00); + ED_object_add_mesh_props(ot); ED_object_add_generic_props(ot, true); } diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index ce6856321d2..f001eadd9cd 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -259,7 +259,7 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event) opdata = op->customdata; /* initialize mouse values */ - if (!calculateTransformCenter(C, V3D_CENTROID, center_3d, opdata->mcenter)) { + if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEAN, center_3d, opdata->mcenter)) { /* in this case the tool will likely do nothing, * ideally this will never happen and should be checked for above */ opdata->mcenter[0] = opdata->mcenter[1] = 0; diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index a020fed0835..161159d0be0 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -326,7 +326,7 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* props */ - RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f); + RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f); RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180); } diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index c037b0c6b0f..937547c99ef 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -280,7 +280,7 @@ static int edbm_inset_invoke(bContext *C, wmOperator *op, const wmEvent *event) opdata = op->customdata; /* initialize mouse values */ - if (!calculateTransformCenter(C, V3D_CENTROID, center_3d, opdata->mcenter)) { + if (!calculateTransformCenter(C, V3D_AROUND_CENTER_MEAN, center_3d, opdata->mcenter)) { /* in this case the tool will likely do nothing, * ideally this will never happen and should be checked for above */ opdata->mcenter[0] = opdata->mcenter[1] = 0; @@ -507,10 +507,10 @@ void MESH_OT_inset(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry"); RNA_def_boolean(ot->srna, "use_edge_rail", false, "Edge Rail", "Inset the region along existing edges"); - prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f); + prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f); /* use 1 rather then 10 for max else dragging the button moves too far */ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4); - prop = RNA_def_float(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f); + prop = RNA_def_float_distance(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f); RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4); RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset"); diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index e2e4638254b..fcba1e5ec72 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -49,10 +49,6 @@ #include "tools/bmesh_intersect.h" - -/* -------------------------------------------------------------------- */ -/* Cut intersections into geometry */ - /** * Compare selected with its self. */ @@ -75,6 +71,23 @@ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data)) return -1; } else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + return 1; + } + else { + return 0; + } +} + +/** + * A flipped version of #bm_face_isect_pair + * use for boolean 'difference', which depends on order. + */ +static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data)) +{ + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + return -1; + } + else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { return 0; } else { @@ -82,19 +95,41 @@ static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data)) } } +/** + * Use for intersect and boolean. + */ +static void edbm_intersect_select(BMEditMesh *em) +{ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); + + if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { + BMIter iter; + BMEdge *e; + + BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + BM_edge_select_set(em->bm, e, true); + } + } + } + + EDBM_mesh_normals_update(em); + EDBM_update_generic(em, true, true); + +} + +/* -------------------------------------------------------------------- */ +/* Cut intersections into geometry */ + +/** \name Simple Intersect (self-intersect) + * \{ + */ + enum { ISECT_SEL = 0, ISECT_SEL_UNSEL = 1, }; -static EnumPropertyItem isect_mode_items[] = { - {ISECT_SEL, "SELECT", 0, "Self Intersect", - "Self intersect selected faces"}, - {ISECT_SEL_UNSEL, "SELECT_UNSELECT", 0, "Selected/Unselected", - "Intersect selected with unselected faces"}, - {0, NULL, 0, NULL, NULL} -}; - static int edbm_intersect_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); @@ -123,26 +158,13 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op) bm, em->looptris, em->tottri, test_fn, NULL, - use_self, use_separate, + use_self, use_separate, true, true, + -1, eps); if (has_isect) { - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false); - - if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { - BMIter iter; - BMEdge *e; - - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(e, BM_ELEM_TAG)) { - BM_edge_select_set(bm, e, true); - } - } - } - - EDBM_mesh_normals_update(em); - EDBM_update_generic(em, true, true); + edbm_intersect_select(em); } else { BKE_report(op->reports, RPT_WARNING, "No intersections found"); @@ -153,6 +175,14 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op) void MESH_OT_intersect(struct wmOperatorType *ot) { + static EnumPropertyItem isect_mode_items[] = { + {ISECT_SEL, "SELECT", 0, "Self Intersect", + "Self intersect selected faces"}, + {ISECT_SEL_UNSEL, "SELECT_UNSELECT", 0, "Selected/Unselected", + "Intersect selected with unselected faces"}, + {0, NULL, 0, NULL, NULL} + }; + /* identifiers */ ot->name = "Intersect"; ot->description = "Cut an intersection into faces"; @@ -165,16 +195,89 @@ void MESH_OT_intersect(struct wmOperatorType *ot) /* props */ RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", ""); RNA_def_boolean(ot->srna, "use_separate", true, "Separate", ""); - RNA_def_float(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); + RNA_def_float_distance(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + /* -------------------------------------------------------------------- */ -/* Face Split by Edges */ +/* Boolean (a kind of intersect) */ + +/** \name Boolean Intersect + * + * \note internally this is nearly exactly the same as 'MESH_OT_intersect', + * however from a user perspective they are quite different, so expose as different tools. + * + * \{ + */ + +static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + const int boolean_operation = RNA_enum_get(op->ptr, "operation"); + bool use_swap = RNA_boolean_get(op->ptr, "use_swap"); + const float eps = RNA_float_get(op->ptr, "threshold"); + int (*test_fn)(BMFace *, void *); + bool has_isect; + + test_fn = use_swap ? bm_face_isect_pair_swap : bm_face_isect_pair; + + has_isect = BM_mesh_intersect( + bm, + em->looptris, em->tottri, + test_fn, NULL, + false, false, true, true, + boolean_operation, + eps); + + + if (has_isect) { + edbm_intersect_select(em); + } + else { + BKE_report(op->reports, RPT_WARNING, "No intersections found"); + } + + return OPERATOR_FINISHED; +} + +void MESH_OT_intersect_boolean(struct wmOperatorType *ot) +{ + static EnumPropertyItem isect_boolean_operation_items[] = { + {BMESH_ISECT_BOOLEAN_ISECT, "INTERSECT", 0, "Intersect", ""}, + {BMESH_ISECT_BOOLEAN_UNION, "UNION", 0, "Union", ""}, + {BMESH_ISECT_BOOLEAN_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name = "Boolean Intersect"; + ot->description = "Cut solid geometry from selected to unselected"; + ot->idname = "MESH_OT_intersect_boolean"; + + /* api callbacks */ + ot->exec = edbm_intersect_boolean_exec; + ot->poll = ED_operator_editmesh; + + /* props */ + RNA_def_enum(ot->srna, "operation", isect_boolean_operation_items, BMESH_ISECT_BOOLEAN_DIFFERENCE, "Boolean", ""); + RNA_def_boolean(ot->srna, "use_swap", false, "Swap", "Use with difference intersection to swap which side is kept"); + RNA_def_float_distance(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001); + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ +/* -------------------------------------------------------------------- */ +/* Face Split by Edges */ /** \name Face/Edge Split * \{ */ diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index baf1fa8ed4d..818526ab772 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -3341,43 +3341,6 @@ void MESH_OT_knife_tool(wmOperatorType *ot) /* Knife tool as a utility function * that can be used for internal slicing operations */ -/** - * Return a point inside the face. - * - * tessellation here seems way overkill, - * but without this its very hard to know of a point is inside the face - */ -static void edbm_mesh_knife_face_point(BMFace *f, float r_cent[3]) -{ - const int tottri = f->len - 2; - BMLoop **loops = BLI_array_alloca(loops, f->len); - unsigned int (*index)[3] = BLI_array_alloca(index, tottri); - int j; - int j_best = 0; /* use as fallback when unset */ - float area_best = -1.0f; - - BM_face_calc_tessellation(f, loops, index); - - for (j = 0; j < tottri; j++) { - const float *p1 = loops[index[j][0]]->v->co; - const float *p2 = loops[index[j][1]]->v->co; - const float *p3 = loops[index[j][2]]->v->co; - float area; - - area = area_squared_tri_v3(p1, p2, p3); - if (area > area_best) { - j_best = j; - area_best = area; - } - } - - mid_v3_v3v3v3( - r_cent, - loops[index[j_best][0]]->v->co, - loops[index[j_best][1]]->v->co, - loops[index[j_best][2]]->v->co); -} - static bool edbm_mesh_knife_point_isect(LinkNode *polys, const float cent_ss[2]) { LinkNode *p = polys; @@ -3495,7 +3458,7 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug BMIter fiter; BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { float cent[3], cent_ss[2]; - edbm_mesh_knife_face_point(f, cent); + BM_face_calc_point_in_face(f, cent); knife_project_v2(kcd, cent, cent_ss); if (edbm_mesh_knife_point_isect(polys, cent_ss)) { BM_elem_flag_enable(f, BM_ELEM_TAG); @@ -3531,7 +3494,7 @@ void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag, bool cut_throug if (found) { float cent[3], cent_ss[2]; - edbm_mesh_knife_face_point(f, cent); + BM_face_calc_point_in_face(f, cent); knife_project_v2(kcd, cent, cent_ss); if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, &mats, (BMElem *)f)) && edbm_mesh_knife_point_isect(polys, cent_ss)) diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 23deffe5b0d..d6933aa88d8 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -1259,7 +1259,7 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) while ((f = *(faces++))) { BM_face_select_set(bm, f, true); } - MEM_freeN(faces); + MEM_freeN(link->data); MEM_freeN(link); changed = true; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 3cd3b7ec86e..b240836b153 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -306,7 +306,10 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) float mval[2], co_proj[3], no_dummy[3]; float dist_px_dummy; if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - if (snapObjectsContext(C, mval, &dist_px_dummy, co_proj, no_dummy, SNAP_NOT_OBEDIT)) { + if (snapObjectsContext( + C, mval, SNAP_NOT_OBEDIT, + co_proj, no_dummy, &dist_px_dummy)) + { mul_v3_m4v3(eve->co, obedit->imat, co_proj); } } @@ -2357,8 +2360,8 @@ void MESH_OT_remove_doubles(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_float(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance", - "Minimum distance between elements to merge", 1e-5f, 10.0f); + RNA_def_float_distance(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance", + "Minimum distance between elements to merge", 1e-5f, 10.0f); RNA_def_boolean(ot->srna, "use_unselected", false, "Unselected", "Merge selected to other unselected vertices"); } @@ -2608,7 +2611,7 @@ void MESH_OT_solidify(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - prop = RNA_def_float(ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f); + prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, -1e4f, 1e4f, "Thickness", "", -10.0f, 10.0f); RNA_def_property_ui_range(prop, -10.0, 10.0, 0.1, 4); } @@ -3783,7 +3786,6 @@ static int edbm_poke_face_exec(bContext *C, wmOperator *op) void MESH_OT_poke(wmOperatorType *ot) { - static EnumPropertyItem poke_center_modes[] = { {BMOP_POKE_MEAN_WEIGHTED, "MEAN_WEIGHTED", 0, "Weighted Mean", "Weighted Mean Face Center"}, {BMOP_POKE_MEAN, "MEAN", 0, "Mean", "Mean Face Center"}, @@ -3803,7 +3805,7 @@ void MESH_OT_poke(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_float(ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f); + RNA_def_float_distance(ot->srna, "offset", 0.0f, -1e3f, 1e3f, "Poke Offset", "Poke Offset", -1.0f, 1.0f); RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry"); RNA_def_enum(ot->srna, "center_mode", poke_center_modes, BMOP_POKE_MEAN_WEIGHTED, "Poke Center", "Poke Face Center Calculation"); @@ -4255,8 +4257,8 @@ void MESH_OT_dissolve_degenerate(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_float(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance", - "Minimum distance between elements to merge", 1e-5f, 10.0f); + RNA_def_float_distance(ot->srna, "threshold", 1e-4f, 1e-6f, 50.0f, "Merge Distance", + "Minimum distance between elements to merge", 1e-5f, 10.0f); } @@ -5252,10 +5254,10 @@ void MESH_OT_wireframe(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness"); RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry"); RNA_def_boolean(ot->srna, "use_replace", true, "Replace", "Remove original faces"); - prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f); + prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, 0.0f, 1e4f, "Thickness", "", 0.0f, 10.0f); /* use 1 rather then 10 for max else dragging the button moves too far */ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4); - RNA_def_float(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f); + RNA_def_float_distance(ot->srna, "offset", 0.01f, 0.0f, 1e4f, "Offset", "", 0.0f, 10.0f); RNA_def_boolean(ot->srna, "use_crease", false, "Crease", "Crease hub edges for improved subsurf"); prop = RNA_def_float(ot->srna, "crease_weight", 0.01f, 0.0f, 1e3f, "Crease weight", "", 0.0f, 1.0f); RNA_def_property_ui_range(prop, 0.0, 1.0, 0.1, 2); @@ -5587,7 +5589,7 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "direction", rna_enum_symmetrize_direction_items, BMO_SYMMETRIZE_NEGATIVE_X, "Direction", "Which sides to copy from and to"); - RNA_def_float(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", "", 1e-4f, 1.0f); + RNA_def_float_distance(ot->srna, "threshold", 0.05f, 0.0f, 10.0f, "Threshold", "", 1e-4f, 1.0f); RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0f, "Factor", "", 0.0f, 1.0f); RNA_def_boolean(ot->srna, "use_center", true, "Center", "Snap mid verts to the axis center"); } diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 148398fca5c..4a9be4978b1 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -382,7 +382,7 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob) /** * \warning This can invalidate the #DerivedMesh cache of other objects (for linked duplicates). - * Most callers should run #DAG_id_tag_update on \a ob, see: T46738. + * Most callers should run #DAG_id_tag_update on \a ob->data, see: T46738, T46913 */ void EDBM_mesh_load(Object *ob) { diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index c56465f570a..3b018eadb2d 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -109,6 +109,7 @@ void MESH_OT_inset(struct wmOperatorType *ot); /* *** editmesh_intersect.c *** */ void MESH_OT_intersect(struct wmOperatorType *ot); +void MESH_OT_intersect_boolean(struct wmOperatorType *ot); void MESH_OT_face_split_by_edges(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 9718e63f012..e24dfa3d123 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -179,6 +179,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_inset); WM_operatortype_append(MESH_OT_offset_edge_loops); WM_operatortype_append(MESH_OT_intersect); + WM_operatortype_append(MESH_OT_intersect_boolean); WM_operatortype_append(MESH_OT_face_split_by_edges); WM_operatortype_append(MESH_OT_poke); WM_operatortype_append(MESH_OT_wireframe); diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 31497f69d71..f05414fbfa6 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -665,6 +665,11 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese /* ************* undo for MetaBalls ************* */ +typedef struct UndoMBall { + ListBase editelems; + int lastelem_index; +} UndoMBall; + /* free all MetaElems from ListBase */ static void freeMetaElemlist(ListBase *lb) { @@ -678,58 +683,61 @@ static void freeMetaElemlist(ListBase *lb) } -static void undoMball_to_editMball(void *lbu, void *lbe, void *UNUSED(obe)) +static void undoMball_to_editMball(void *umb_v, void *mb_v, void *UNUSED(obdata)) { - ListBase *lb = lbu; - ListBase *editelems = lbe; - MetaElem *ml, *newml; - - freeMetaElemlist(editelems); + MetaBall *mb = mb_v; + UndoMBall *umb = umb_v; + + freeMetaElemlist(mb->editelems); + mb->lastelem = NULL; /* copy 'undo' MetaElems to 'edit' MetaElems */ - ml = lb->first; - while (ml) { - newml = MEM_dupallocN(ml); - BLI_addtail(editelems, newml); - ml = ml->next; + int index = 0; + for (MetaElem *ml_undo = umb->editelems.first; ml_undo; ml_undo = ml_undo->next, index += 1) { + MetaElem *ml_edit = MEM_dupallocN(ml_undo); + BLI_addtail(mb->editelems, ml_edit); + if (index == umb->lastelem_index) { + mb->lastelem = ml_edit; + } } } -static void *editMball_to_undoMball(void *lbe, void *UNUSED(obe)) +static void *editMball_to_undoMball(void *mb_v, void *UNUSED(obdata)) { - ListBase *editelems = lbe; - ListBase *lb; - MetaElem *ml, *newml; + MetaBall *mb = mb_v; + UndoMBall *umb; /* allocate memory for undo ListBase */ - lb = MEM_callocN(sizeof(ListBase), "listbase undo"); + umb = MEM_callocN(sizeof(UndoMBall), __func__); + umb->lastelem_index = -1; /* copy contents of current ListBase to the undo ListBase */ - ml = editelems->first; - while (ml) { - newml = MEM_dupallocN(ml); - BLI_addtail(lb, newml); - ml = ml->next; + int index = 0; + for (MetaElem *ml_edit = mb->editelems->first; ml_edit; ml_edit = ml_edit->next, index += 1) { + MetaElem *ml_undo = MEM_dupallocN(ml_edit); + BLI_addtail(&umb->editelems, ml_undo); + if (ml_edit == mb->lastelem) { + umb->lastelem_index = index; + } } - return lb; + return umb; } /* free undo ListBase of MetaElems */ -static void free_undoMball(void *lbv) +static void free_undoMball(void *umb_v) { - ListBase *lb = lbv; + UndoMBall *umb = umb_v; - freeMetaElemlist(lb); - MEM_freeN(lb); + freeMetaElemlist(&umb->editelems); + MEM_freeN(umb); } -static ListBase *metaball_get_editelems(Object *ob) +static MetaBall *metaball_get_obdata(Object *ob) { if (ob && ob->type == OB_MBALL) { - struct MetaBall *mb = (struct MetaBall *)ob->data; - return mb->editelems; + return ob->data; } return NULL; } @@ -738,7 +746,7 @@ static ListBase *metaball_get_editelems(Object *ob) static void *get_data(bContext *C) { Object *obedit = CTX_data_edit_object(C); - return metaball_get_editelems(obedit); + return metaball_get_obdata(obedit); } /* this is undo system for MetaBalls */ diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 7ef6638e753..7650be941d4 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -261,10 +261,7 @@ static void view_align_update(struct Main *UNUSED(main), struct Scene *UNUSED(sc void ED_object_add_unit_props(wmOperatorType *ot) { - PropertyRNA *prop; - - prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00); - RNA_def_property_subtype(prop, PROP_DISTANCE); + RNA_def_float_distance(ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00); } void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode) @@ -293,6 +290,11 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +void ED_object_add_mesh_props(wmOperatorType *ot) +{ + RNA_def_boolean(ot->srna, "calc_uvs", false, "Generate UVs", "Generate a default UV map"); +} + bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view_align_axis, float loc[3], float rot[3], bool *enter_editmode, unsigned int *layer, bool *is_view_aligned) diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 6a1220bbbaa..492b6724f93 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -318,7 +318,7 @@ static bool object_hook_index_array(Scene *scene, Object *obedit, EDBM_mesh_load(obedit); EDBM_mesh_make(scene->toolsettings, obedit); - DAG_id_tag_update(&obedit->id, 0); + DAG_id_tag_update(obedit->data, 0); em = me->edit_btmesh; diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index c638714a951..a1f59166c81 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -138,6 +138,8 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) EDBM_mesh_load(obedit); EDBM_mesh_make(scene->toolsettings, obedit); + DAG_id_tag_update(obedit->data, 0); + em = me->edit_btmesh; EDBM_mesh_normals_update(em); diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index ac1f13ee59c..8f00c0eb467 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -718,7 +718,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) mul_m4_v3(obedit->imat, cent); } else { - if (around == V3D_CENTROID) { + if (around == V3D_AROUND_CENTER_MEAN) { if (em->bm->totvert) { const float total_div = 1.0f / (float)em->bm->totvert; BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { @@ -825,9 +825,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) Mesh *me = ob->data; if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (centermode == ORIGIN_TO_CENTER_OF_MASS) { BKE_mesh_center_centroid(me, cent); } - else if (around == V3D_CENTROID) { BKE_mesh_center_median(me, cent); } - else { BKE_mesh_center_bounds(me, cent); } + else if (centermode == ORIGIN_TO_CENTER_OF_MASS) { BKE_mesh_center_centroid(me, cent); } + else if (around == V3D_AROUND_CENTER_MEAN) { BKE_mesh_center_median(me, cent); } + else { BKE_mesh_center_bounds(me, cent); } negate_v3_v3(cent_neg, cent); BKE_mesh_translate(me, cent_neg, 1); @@ -839,9 +839,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (around == V3D_CENTROID) { BKE_curve_center_median(cu, cent); } - else { BKE_curve_center_bounds(cu, cent); } + if (centermode == ORIGIN_TO_CURSOR) { /* done */ } + else if (around == V3D_AROUND_CENTER_MEAN) { BKE_curve_center_median(cu, cent); } + else { BKE_curve_center_bounds(cu, cent); } /* don't allow Z change if curve is 2D */ if ((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) @@ -921,9 +921,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (around == V3D_CENTROID) { BKE_mball_center_median(mb, cent); } - else { BKE_mball_center_bounds(mb, cent); } + if (centermode == ORIGIN_TO_CURSOR) { /* done */ } + else if (around == V3D_AROUND_CENTER_MEAN) { BKE_mball_center_median(mb, cent); } + else { BKE_mball_center_bounds(mb, cent); } negate_v3_v3(cent_neg, cent); BKE_mball_translate(mb, cent_neg); @@ -942,9 +942,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; - if (centermode == ORIGIN_TO_CURSOR) { /* done */ } - else if (around == V3D_CENTROID) { BKE_lattice_center_median(lt, cent); } - else { BKE_lattice_center_bounds(lt, cent); } + if (centermode == ORIGIN_TO_CURSOR) { /* done */ } + else if (around == V3D_AROUND_CENTER_MEAN) { BKE_lattice_center_median(lt, cent); } + else { BKE_lattice_center_bounds(lt, cent); } negate_v3_v3(cent_neg, cent); BKE_lattice_translate(lt, cent_neg, 1); @@ -1044,8 +1044,8 @@ void OBJECT_OT_origin_set(wmOperatorType *ot) }; static EnumPropertyItem prop_set_bounds_types[] = { - {V3D_CENTROID, "MEDIAN", 0, "Median Center", ""}, - {V3D_CENTER, "BOUNDS", 0, "Bounds Center", ""}, + {V3D_AROUND_CENTER_MEAN, "MEDIAN", 0, "Median Center", ""}, + {V3D_AROUND_CENTER_BOUNDS, "BOUNDS", 0, "Bounds Center", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1064,5 +1064,5 @@ void OBJECT_OT_origin_set(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; ot->prop = RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", ""); - RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_CENTROID, "Center", ""); + RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_AROUND_CENTER_MEAN, "Center", ""); } diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index f44374b1d7b..a7038ac53cc 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -311,7 +311,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); - BKE_image_backup_render(scene, ima); + BKE_image_backup_render(scene, ima, true); /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into @@ -956,7 +956,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* get a render result image, and make sure it is empty */ ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); - BKE_image_backup_render(rj->scene, ima); + BKE_image_backup_render(rj->scene, ima, true); rj->image = ima; /* setup new render */ diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 2e9ccc520d9..5268afae270 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -69,9 +69,9 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_compositing.h" +#include "GPU_framebuffer.h" #include "render_intern.h" @@ -559,7 +559,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* create image and image user */ oglrender->ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(oglrender->ima, NULL, IMA_SIGNAL_FREE); - BKE_image_backup_render(oglrender->scene, oglrender->ima); + BKE_image_backup_render(oglrender->scene, oglrender->ima, true); oglrender->iuser.scene = scene; oglrender->iuser.ok = 1; diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index fd65d81baad..91eea6f8248 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -45,10 +45,11 @@ #include "BIF_gl.h" #include "BIF_glutil.h" - #include "IMB_colormanagement.h" #include "IMB_imbuf_types.h" +#include "GPU_basic_shader.h" + #include "UI_interface.h" #ifndef GL_CLAMP_TO_EDGE @@ -136,7 +137,7 @@ const GLubyte stipple_diag_stripes_neg[128] = { const GLubyte stipple_checker_8px[128] = { 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, - 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, + 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, @@ -179,32 +180,20 @@ void fdrawbezier(float vec[4][3]) void fdrawline(float x1, float y1, float x2, float y2) { - float v[2]; - - glBegin(GL_LINE_STRIP); - v[0] = x1; v[1] = y1; - glVertex2fv(v); - v[0] = x2; v[1] = y2; - glVertex2fv(v); + glBegin(GL_LINES); + glVertex2f(x1, y1); + glVertex2f(x2, y2); glEnd(); } void fdrawbox(float x1, float y1, float x2, float y2) { - float v[2]; + glBegin(GL_LINE_LOOP); - glBegin(GL_LINE_STRIP); - - v[0] = x1; v[1] = y1; - glVertex2fv(v); - v[0] = x1; v[1] = y2; - glVertex2fv(v); - v[0] = x2; v[1] = y2; - glVertex2fv(v); - v[0] = x2; v[1] = y1; - glVertex2fv(v); - v[0] = x1; v[1] = y1; - glVertex2fv(v); + glVertex2f(x1, y1); + glVertex2f(x1, y2); + glVertex2f(x2, y2); + glVertex2f(x2, y1); glEnd(); } @@ -225,13 +214,9 @@ void fdrawcheckerboard(float x1, float y1, float x2, float y2) void sdrawline(int x1, int y1, int x2, int y2) { - int v[2]; - - glBegin(GL_LINE_STRIP); - v[0] = x1; v[1] = y1; - glVertex2iv(v); - v[0] = x2; v[1] = y2; - glVertex2iv(v); + glBegin(GL_LINES); + glVertex2i(x1, y1); + glVertex2i(x2, y2); glEnd(); } @@ -247,13 +232,9 @@ void sdrawline(int x1, int y1, int x2, int y2) static void sdrawtripoints(int x1, int y1, int x2, int y2) { - int v[2]; - v[0] = x1; v[1] = y1; - glVertex2iv(v); - v[0] = x1; v[1] = y2; - glVertex2iv(v); - v[0] = x2; v[1] = y1; - glVertex2iv(v); + glVertex2i(x1, y1); + glVertex2i(x1, y2); + glVertex2i(x2, y1); } void sdrawtri(int x1, int y1, int x2, int y2) @@ -273,20 +254,12 @@ void sdrawtrifill(int x1, int y1, int x2, int y2) void sdrawbox(int x1, int y1, int x2, int y2) { - int v[2]; - - glBegin(GL_LINE_STRIP); + glBegin(GL_LINE_LOOP); - v[0] = x1; v[1] = y1; - glVertex2iv(v); - v[0] = x1; v[1] = y2; - glVertex2iv(v); - v[0] = x2; v[1] = y2; - glVertex2iv(v); - v[0] = x2; v[1] = y1; - glVertex2iv(v); - v[0] = x1; v[1] = y1; - glVertex2iv(v); + glVertex2i(x1, y1); + glVertex2i(x1, y2); + glVertex2i(x2, y2); + glVertex2i(x2, y1); glEnd(); } @@ -436,13 +409,6 @@ void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments glEnd(); } -int glaGetOneInteger(int param) -{ - GLint i; - glGetIntegerv(param, &i); - return i; -} - float glaGetOneFloat(int param) { GLfloat v; @@ -474,7 +440,6 @@ static int get_cached_work_texture(int *r_w, int *r_h) static int tex_h = 256; if (texid == -1) { - GLint ltexid = glaGetOneInteger(GL_TEXTURE_2D); unsigned char *tbuf; glGenTextures(1, (GLuint *)&texid); @@ -488,7 +453,7 @@ static int get_cached_work_texture(int *r_w, int *r_h) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tbuf); MEM_freeN(tbuf); - glBindTexture(GL_TEXTURE_2D, ltexid); + glBindTexture(GL_TEXTURE_2D, 0); } *r_w = tex_w; @@ -501,8 +466,6 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, unsigned char *uc_rect = (unsigned char *) rect; const float *f_rect = (float *)rect; float xzoom = glaGetOneFloat(GL_ZOOM_X), yzoom = glaGetOneFloat(GL_ZOOM_Y); - int ltexid = glaGetOneInteger(GL_TEXTURE_2D); - int lrowlength = glaGetOneInteger(GL_UNPACK_ROW_LENGTH); int subpart_x, subpart_y, tex_w, tex_h; int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y; int texid = get_cached_work_texture(&tex_w, &tex_h); @@ -511,7 +474,6 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, /* Specify the color outside this function, and tex will modulate it. * This is useful for changing alpha without using glPixelTransferf() */ - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w); glBindTexture(GL_TEXTURE_2D, texid); @@ -520,9 +482,10 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter); -#ifdef __APPLE__ +#if defined(__APPLE__) && 0 + /* [merwin] disable this workaround and see if anyone is affected. If not scrap it! Also at end of this function */ /* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */ - glPixelZoom(1.f, 1.f); + glPixelZoom(1.0f, 1.0f); #endif /* setup seamless 2=on, 0=off */ @@ -600,7 +563,7 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]); } - glEnable(GL_TEXTURE_2D); + GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); glBegin(GL_QUADS); glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h); glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom); @@ -614,15 +577,14 @@ void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, int format, glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h); glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY); glEnd(); - glDisable(GL_TEXTURE_2D); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } } - glBindTexture(GL_TEXTURE_2D, ltexid); - glPixelStorei(GL_UNPACK_ROW_LENGTH, lrowlength); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBindTexture(GL_TEXTURE_2D, 0); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); -#ifdef __APPLE__ +#if defined(__APPLE__) && 0 /* workaround for os x 10.5/10.6 driver bug (above) */ glPixelZoom(xzoom, yzoom); #endif @@ -676,8 +638,6 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom)); if (draw_w > 0 && draw_h > 0) { - int old_row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH); - /* Don't use safe RasterPos (slower) if we can avoid it. */ if (rast_x >= 0 && rast_y >= 0) { glRasterPos2f(rast_x, rast_y); @@ -708,7 +668,7 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo } } - glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } } @@ -1096,7 +1056,6 @@ void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, } if (ok) { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1.0, 1.0, 1.0, 1.0); if (ibuf->rect_float) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index f8dda23bc9b..7806038b313 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -4231,6 +4231,8 @@ void ED_operatortypes_screen(void) WM_operatortype_append(ED_OT_undo_push); WM_operatortype_append(ED_OT_redo); WM_operatortype_append(ED_OT_undo_history); + + WM_operatortype_append(ED_OT_flush_edits); } @@ -4302,14 +4304,13 @@ void ED_keymap_screen(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "SCREEN_OT_area_options", RIGHTMOUSE, KM_PRESS, 0, 0); - - WM_keymap_add_item(keymap, "SCREEN_OT_header", F9KEY, KM_PRESS, KM_ALT, 0); - + /* Header Editing ------------------------------------------------ */ keymap = WM_keymap_find(keyconf, "Header", 0, 0); - + + WM_keymap_add_item(keymap, "SCREEN_OT_header", F9KEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "SCREEN_OT_header_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0); - + /* Screen General ------------------------------------------------ */ keymap = WM_keymap_find(keyconf, "Screen", 0, 0); diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 1a12ec3e6bc..f57255aff61 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -59,6 +59,8 @@ #include "ED_view3d.h" +#include "GPU_basic_shader.h" + #include "UI_resources.h" #include "paint_intern.h" @@ -149,7 +151,6 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima int size; int j; int refresh; - GLenum format = col ? GL_RGBA : GL_ALPHA; OverlayControlFlags invalid = (primary) ? (overlay_flags & PAINT_INVALID_OVERLAY_TEXTURE_PRIMARY) : (overlay_flags & PAINT_INVALID_OVERLAY_TEXTURE_SECONDARY); @@ -321,8 +322,11 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima glBindTexture(GL_TEXTURE_2D, target->overlay_texture); if (refresh) { + GLenum format = col ? GL_RGBA : GL_ALPHA; + GLenum internalformat = col ? GL_RGBA8 : GL_ALPHA8; + if (!init || (target->old_col != col)) { - glTexImage2D(GL_TEXTURE_2D, 0, format, size, size, 0, format, GL_UNSIGNED_BYTE, buffer); + glTexImage2D(GL_TEXTURE_2D, 0, internalformat, size, size, 0, format, GL_UNSIGNED_BYTE, buffer); } else { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, format, GL_UNSIGNED_BYTE, buffer); @@ -334,9 +338,8 @@ static int load_tex(Brush *br, ViewContext *vc, float zoom, bool col, bool prima target->old_col = col; } - glEnable(GL_TEXTURE_2D); + GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -448,7 +451,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom) if (refresh) { if (!init) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, size, size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, size, size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer); } else { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_ALPHA, GL_UNSIGNED_BYTE, buffer); @@ -458,9 +461,8 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom) MEM_freeN(buffer); } - glEnable(GL_TEXTURE_2D); + GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -534,8 +536,7 @@ static bool sculpt_get_brush_geometry( mouse[0] = x; mouse[1] = y; - if (vc->obact->sculpt && vc->obact->sculpt->pbvh) - { + if (vc->obact->sculpt && vc->obact->sculpt->pbvh) { if (!ups->stroke_active) { hit = sculpt_stroke_get_location(C, location, mouse); } @@ -796,6 +797,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush, } glPopAttrib(); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 5d0b34a2e0c..b6f4600ab88 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -83,7 +83,7 @@ static SpaceLink *action_new(const bContext *C) ar->alignment = RGN_ALIGN_BOTTOM; /* channel list region */ - ar = MEM_callocN(sizeof(ARegion), "channel area for action"); + ar = MEM_callocN(sizeof(ARegion), "channel region for action"); BLI_addtail(&saction->regionbase, ar); ar->regiontype = RGN_TYPE_CHANNELS; ar->alignment = RGN_ALIGN_LEFT; @@ -92,8 +92,8 @@ static SpaceLink *action_new(const bContext *C) ar->v2d.scroll = V2D_SCROLL_BOTTOM; ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for action"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for action"); BLI_addtail(&saction->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -149,7 +149,7 @@ static SpaceLink *action_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ -static void action_main_area_init(wmWindowManager *wm, ARegion *ar) +static void action_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -160,7 +160,7 @@ static void action_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void action_main_area_draw(const bContext *C, ARegion *ar) +static void action_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceAction *saction = CTX_wm_space_action(C); @@ -218,7 +218,7 @@ static void action_main_area_draw(const bContext *C, ARegion *ar) } /* add handlers, stuff you only do once or on area/region changes */ -static void action_channel_area_init(wmWindowManager *wm, ARegion *ar) +static void action_channel_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -232,7 +232,7 @@ static void action_channel_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void action_channel_area_draw(const bContext *C, ARegion *ar) +static void action_channel_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ bAnimContext ac; @@ -257,17 +257,17 @@ static void action_channel_area_draw(const bContext *C, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ -static void action_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void action_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void action_header_area_draw(const bContext *C, ARegion *ar) +static void action_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } -static void action_channel_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void action_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -306,7 +306,7 @@ static void action_channel_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa } } -static void action_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void action_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -457,7 +457,7 @@ static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) } } -static void action_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void action_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { // SpaceAction *saction = (SpaceAction *)sa->spacedata.first; @@ -543,9 +543,9 @@ void ED_spacetype_action(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); art->regionid = RGN_TYPE_WINDOW; - art->init = action_main_area_init; - art->draw = action_main_area_draw; - art->listener = action_main_area_listener; + art->init = action_main_region_init; + art->draw = action_main_region_draw; + art->listener = action_main_region_listener; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art); @@ -556,9 +556,9 @@ void ED_spacetype_action(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - art->init = action_header_area_init; - art->draw = action_header_area_draw; - art->listener = action_header_area_listener; + art->init = action_header_region_init; + art->draw = action_header_region_draw; + art->listener = action_header_region_listener; BLI_addhead(&st->regiontypes, art); @@ -568,9 +568,9 @@ void ED_spacetype_action(void) art->prefsizex = 200; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES; - art->init = action_channel_area_init; - art->draw = action_channel_area_draw; - art->listener = action_channel_area_listener; + art->init = action_channel_region_init; + art->draw = action_channel_region_draw; + art->listener = action_channel_region_listener; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index e28ad686d2a..126a27c36cb 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -66,15 +66,15 @@ static SpaceLink *buttons_new(const bContext *UNUSED(C)) ar->alignment = RGN_ALIGN_TOP; #if 0 - /* context area */ - ar = MEM_callocN(sizeof(ARegion), "context area for buts"); + /* context region */ + ar = MEM_callocN(sizeof(ARegion), "context region for buts"); BLI_addtail(&sbuts->regionbase, ar); ar->regiontype = RGN_TYPE_CHANNELS; ar->alignment = RGN_ALIGN_TOP; #endif - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for buts"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for buts"); BLI_addtail(&sbuts->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -123,7 +123,7 @@ static SpaceLink *buttons_duplicate(SpaceLink *sl) } /* add handlers, stuff you only do once or on area/region changes */ -static void buttons_main_area_init(wmWindowManager *wm, ARegion *ar) +static void buttons_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -133,7 +133,7 @@ static void buttons_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void buttons_main_area_draw(const bContext *C, ARegion *ar) +static void buttons_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceButs *sbuts = CTX_wm_space_buts(C); @@ -189,12 +189,12 @@ static void buttons_keymap(struct wmKeyConfig *keyconf) } /* add handlers, stuff you only do once or on area/region changes */ -static void buttons_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void buttons_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void buttons_header_area_draw(const bContext *C, ARegion *ar) +static void buttons_header_region_draw(const bContext *C, ARegion *ar) { SpaceButs *sbuts = CTX_wm_space_buts(C); @@ -410,8 +410,8 @@ void ED_spacetype_buttons(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region"); art->regionid = RGN_TYPE_WINDOW; - art->init = buttons_main_area_init; - art->draw = buttons_main_area_draw; + art->init = buttons_main_region_init; + art->draw = buttons_main_region_draw; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art); @@ -423,8 +423,8 @@ void ED_spacetype_buttons(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - art->init = buttons_header_area_init; - art->draw = buttons_header_area_draw; + art->init = buttons_header_region_init; + art->draw = buttons_header_region_draw; BLI_addhead(&st->regiontypes, art); BKE_spacetype_register(st); diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index ba5bf7449d2..e00ebc14ee0 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -58,6 +58,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_basic_shader.h" + #include "WM_types.h" #include "UI_interface.h" @@ -1063,7 +1065,7 @@ static void draw_plane_marker_image(Scene *scene, } if (display_buffer) { - GLuint texid, last_texid; + GLuint texid; float frame_corners[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, @@ -1083,11 +1085,9 @@ static void draw_plane_marker_image(Scene *scene, glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1.0, 1.0, 1.0, plane_track->image_opacity); - last_texid = glaGetOneInteger(GL_TEXTURE_2D); - glEnable(GL_TEXTURE_2D); + GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); glGenTextures(1, (GLuint *)&texid); glBindTexture(GL_TEXTURE_2D, texid); @@ -1110,8 +1110,8 @@ static void draw_plane_marker_image(Scene *scene, glPopMatrix(); - glBindTexture(GL_TEXTURE_2D, last_texid); - glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); if (transparent) { glDisable(GL_BLEND); diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index c1db31a26db..7a66599655f 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1534,7 +1534,7 @@ static int clip_set_2d_cursor_exec(bContext *C, wmOperator *op) bool show_cursor = false; show_cursor |= sclip->mode == SC_MODE_MASKEDIT; - show_cursor |= sclip->around == V3D_CURSOR; + show_cursor |= sclip->around == V3D_AROUND_CURSOR; if (!show_cursor) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index f119fe23c12..e1d4e4fabc5 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -250,7 +250,7 @@ static SpaceLink *clip_new(const bContext *C) sc->zoom = 1.0f; sc->path_length = 20; sc->scopes.track_preview_height = 120; - sc->around = V3D_LOCAL; + sc->around = V3D_AROUND_LOCAL_ORIGINS; /* header */ ar = MEM_callocN(sizeof(ARegion), "header for clip"); @@ -296,8 +296,8 @@ static SpaceLink *clip_new(const bContext *C) BLI_addtail(&sc->regionbase, ar); init_preview_region(C, ar); - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for clip"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for clip"); BLI_addtail(&sc->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -1132,7 +1132,7 @@ static void movieclip_main_area_set_view2d(const bContext *C, ARegion *ar) } /* add handlers, stuff you only do once or on area/region changes */ -static void clip_main_area_init(wmWindowManager *wm, ARegion *ar) +static void clip_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -1150,7 +1150,7 @@ static void clip_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void clip_main_area_draw(const bContext *C, ARegion *ar) +static void clip_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceClip *sc = CTX_wm_space_clip(C); @@ -1213,7 +1213,7 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar) } show_cursor |= sc->mode == SC_MODE_MASKEDIT; - show_cursor |= sc->around == V3D_CURSOR; + show_cursor |= sc->around == V3D_AROUND_CURSOR; if (show_cursor) { glPushMatrix(); @@ -1241,7 +1241,7 @@ static void clip_main_area_draw(const bContext *C, ARegion *ar) } } -static void clip_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void clip_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -1256,7 +1256,7 @@ static void clip_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AR /****************** preview region ******************/ -static void clip_preview_area_init(wmWindowManager *wm, ARegion *ar) +static void clip_preview_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -1273,7 +1273,7 @@ static void clip_preview_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void graph_area_draw(const bContext *C, ARegion *ar) +static void graph_region_draw(const bContext *C, ARegion *ar) { View2D *v2d = &ar->v2d; View2DScrollers *scrollers; @@ -1304,7 +1304,7 @@ static void graph_area_draw(const bContext *C, ARegion *ar) UI_view2d_scrollers_free(scrollers); } -static void dopesheet_area_draw(const bContext *C, ARegion *ar) +static void dopesheet_region_draw(const bContext *C, ARegion *ar) { Scene *scene = CTX_data_scene(C); SpaceClip *sc = CTX_wm_space_clip(C); @@ -1342,23 +1342,23 @@ static void dopesheet_area_draw(const bContext *C, ARegion *ar) UI_view2d_scrollers_free(scrollers); } -static void clip_preview_area_draw(const bContext *C, ARegion *ar) +static void clip_preview_region_draw(const bContext *C, ARegion *ar) { SpaceClip *sc = CTX_wm_space_clip(C); if (sc->view == SC_VIEW_GRAPH) - graph_area_draw(C, ar); + graph_region_draw(C, ar); else if (sc->view == SC_VIEW_DOPESHEET) - dopesheet_area_draw(C, ar); + dopesheet_region_draw(C, ar); } -static void clip_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn)) +static void clip_preview_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn)) { } /****************** channels region ******************/ -static void clip_channels_area_init(wmWindowManager *wm, ARegion *ar) +static void clip_channels_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -1371,7 +1371,7 @@ static void clip_channels_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void clip_channels_area_draw(const bContext *C, ARegion *ar) +static void clip_channels_region_draw(const bContext *C, ARegion *ar) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); @@ -1393,24 +1393,24 @@ static void clip_channels_area_draw(const bContext *C, ARegion *ar) UI_view2d_view_restore(C); } -static void clip_channels_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn)) +static void clip_channels_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn)) { } /****************** header region ******************/ /* add handlers, stuff you only do once or on area/region changes */ -static void clip_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void clip_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void clip_header_area_draw(const bContext *C, ARegion *ar) +static void clip_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } -static void clip_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void clip_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -1433,7 +1433,7 @@ static void clip_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), /****************** tools region ******************/ /* add handlers, stuff you only do once or on area/region changes */ -static void clip_tools_area_init(wmWindowManager *wm, ARegion *ar) +static void clip_tools_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -1443,14 +1443,14 @@ static void clip_tools_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void clip_tools_area_draw(const bContext *C, ARegion *ar) +static void clip_tools_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } /****************** tool properties region ******************/ -static void clip_props_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void clip_props_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -1476,7 +1476,7 @@ static void clip_props_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), A /****************** properties region ******************/ /* add handlers, stuff you only do once or on area/region changes */ -static void clip_properties_area_init(wmWindowManager *wm, ARegion *ar) +static void clip_properties_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -1486,7 +1486,7 @@ static void clip_properties_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void clip_properties_area_draw(const bContext *C, ARegion *ar) +static void clip_properties_region_draw(const bContext *C, ARegion *ar) { SpaceClip *sc = CTX_wm_space_clip(C); @@ -1495,7 +1495,7 @@ static void clip_properties_area_draw(const bContext *C, ARegion *ar) ED_region_panels(C, ar, NULL, -1, true); } -static void clip_properties_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -1535,9 +1535,9 @@ void ED_spacetype_clip(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype clip region"); art->regionid = RGN_TYPE_WINDOW; - art->init = clip_main_area_init; - art->draw = clip_main_area_draw; - art->listener = clip_main_area_listener; + art->init = clip_main_region_init; + art->draw = clip_main_region_draw; + art->listener = clip_main_region_listener; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI | ED_KEYMAP_GPENCIL; BLI_addhead(&st->regiontypes, art); @@ -1546,9 +1546,9 @@ void ED_spacetype_clip(void) art = MEM_callocN(sizeof(ARegionType), "spacetype clip region preview"); art->regionid = RGN_TYPE_PREVIEW; art->prefsizey = 240; - art->init = clip_preview_area_init; - art->draw = clip_preview_area_draw; - art->listener = clip_preview_area_listener; + art->init = clip_preview_region_init; + art->draw = clip_preview_region_draw; + art->listener = clip_preview_region_listener; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; BLI_addhead(&st->regiontypes, art); @@ -1558,9 +1558,9 @@ void ED_spacetype_clip(void) art->regionid = RGN_TYPE_UI; art->prefsizex = UI_COMPACT_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI; - art->init = clip_properties_area_init; - art->draw = clip_properties_area_draw; - art->listener = clip_properties_area_listener; + art->init = clip_properties_region_init; + art->draw = clip_properties_region_draw; + art->listener = clip_properties_region_listener; BLI_addhead(&st->regiontypes, art); ED_clip_buttons_register(art); @@ -1569,9 +1569,9 @@ void ED_spacetype_clip(void) art->regionid = RGN_TYPE_TOOLS; art->prefsizex = UI_COMPACT_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI; - art->listener = clip_props_area_listener; - art->init = clip_tools_area_init; - art->draw = clip_tools_area_draw; + art->listener = clip_props_region_listener; + art->init = clip_tools_region_init; + art->draw = clip_tools_region_draw; BLI_addhead(&st->regiontypes, art); @@ -1581,9 +1581,9 @@ void ED_spacetype_clip(void) art->prefsizex = 0; art->prefsizey = 120; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI; - art->listener = clip_props_area_listener; - art->init = clip_tools_area_init; - art->draw = clip_tools_area_draw; + art->listener = clip_props_region_listener; + art->init = clip_tools_region_init; + art->draw = clip_tools_region_draw; ED_clip_tool_props_register(art); BLI_addhead(&st->regiontypes, art); @@ -1594,9 +1594,9 @@ void ED_spacetype_clip(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; - art->init = clip_header_area_init; - art->draw = clip_header_area_draw; - art->listener = clip_header_area_listener; + art->init = clip_header_region_init; + art->draw = clip_header_region_draw; + art->listener = clip_header_region_listener; BLI_addhead(&st->regiontypes, art); @@ -1607,9 +1607,9 @@ void ED_spacetype_clip(void) art->regionid = RGN_TYPE_CHANNELS; art->prefsizex = UI_COMPACT_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_UI; - art->listener = clip_channels_area_listener; - art->init = clip_channels_area_init; - art->draw = clip_channels_area_draw; + art->listener = clip_channels_region_listener; + art->init = clip_channels_region_init; + art->draw = clip_channels_region_draw; BLI_addhead(&st->regiontypes, art); } diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index d206ce4699e..6396b390ca0 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -68,21 +68,6 @@ static void console_line_color(unsigned char fg[3], int type) } } -typedef struct ConsoleDrawContext { - int cwidth; - int lheight; - int console_width; - int ymin, ymax; -#if 0 /* used by textview, may use later */ - int winx; - int *xy; // [2] - int *sel; // [2] - int *pos_pick; /* bottom of view == 0, top of file == combine chars, end of line is lower then start. */ - int *mval; // [2] - int draw; -#endif -} ConsoleDrawContext; - void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_dummy) { /* fake the edit line being in the scroll buffer */ diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index a592f35f629..cf235d0fc02 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -74,8 +74,8 @@ static SpaceLink *console_new(const bContext *UNUSED(C)) ar->alignment = RGN_ALIGN_BOTTOM; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for text"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for text"); BLI_addtail(&sconsole->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -129,7 +129,7 @@ static SpaceLink *console_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ -static void console_main_area_init(wmWindowManager *wm, ARegion *ar) +static void console_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; ListBase *lb; @@ -219,7 +219,7 @@ static void console_dropboxes(void) /* ************* end drop *********** */ -static void console_main_area_draw(const bContext *C, ARegion *ar) +static void console_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceConsole *sc = CTX_wm_space_console(C); @@ -362,17 +362,17 @@ static void console_keymap(struct wmKeyConfig *keyconf) /****************** header region ******************/ /* add handlers, stuff you only do once or on area/region changes */ -static void console_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void console_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void console_header_area_draw(const bContext *C, ARegion *ar) +static void console_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } -static void console_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void console_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { // SpaceInfo *sinfo = sa->spacedata.first; @@ -408,10 +408,10 @@ void ED_spacetype_console(void) art->regionid = RGN_TYPE_WINDOW; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; - art->init = console_main_area_init; - art->draw = console_main_area_draw; + art->init = console_main_region_init; + art->draw = console_main_region_draw; art->cursor = console_cursor; - art->listener = console_main_area_listener; + art->listener = console_main_region_listener; @@ -423,8 +423,8 @@ void ED_spacetype_console(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; - art->init = console_header_area_init; - art->draw = console_header_area_draw; + art->init = console_header_region_init; + art->draw = console_header_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 7f405e8ad16..85d92d07222 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2444,6 +2444,7 @@ static void filelist_readjob_do( bool is_lib = do_lib; char *subdir; + char rel_subdir[FILE_MAX_LIBEXTRA]; int recursion_level; bool skip_currpar; @@ -2454,6 +2455,14 @@ static void filelist_readjob_do( BLI_stack_discard(todo_dirs); + /* ARRRG! We have to be very careful *not to use* common BLI_path_util helpers over entry->relpath itself + * (nor any path containing it), since it may actually be a datablock name inside .blend file, + * which can have slashes and backslashes! See T46827. + * Note that in the end, this means we 'cache' valid relative subdir once here, this is actually better. */ + BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir)); + BLI_cleanup_dir(root, rel_subdir); + BLI_path_rel(rel_subdir, root); + if (do_lib) { nbr_entries = filelist_readjob_list_lib(subdir, &entries, skip_currpar); } @@ -2463,8 +2472,7 @@ static void filelist_readjob_do( } for (entry = entries.first; entry; entry = entry->next) { - BLI_join_dirfile(dir, sizeof(dir), subdir, entry->relpath); - BLI_cleanup_file(root, dir); + BLI_join_dirfile(dir, sizeof(dir), rel_subdir, entry->relpath); /* Generate our entry uuid. Abusing uuid as an uint32, shall be more than enough here, * things would crash way before we overflow that counter! @@ -2473,10 +2481,9 @@ static void filelist_readjob_do( * remain consistent about threading! */ *((uint32_t *)entry->uuid) = atomic_add_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1); - BLI_path_rel(dir, root); /* Only thing we change in direntry here, so we need to free it first. */ MEM_freeN(entry->relpath); - entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' added by BLI_path_rel */ + entry->relpath = BLI_strdup(dir + 2); /* + 2 to remove '//' added by BLI_path_rel to rel_subdir */ entry->name = BLI_strdup(fileentry_uiname(root, entry->relpath, entry->typeflag, dir)); /* Here we decide whether current filedirentry is to be listed too, or not. */ diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 3202164edbd..e77f545fbc0 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -82,25 +82,25 @@ static SpaceLink *file_new(const bContext *UNUSED(C)) ar->alignment = RGN_ALIGN_TOP; /* Tools region */ - ar = MEM_callocN(sizeof(ARegion), "tools area for file"); + ar = MEM_callocN(sizeof(ARegion), "tools region for file"); BLI_addtail(&sfile->regionbase, ar); ar->regiontype = RGN_TYPE_TOOLS; ar->alignment = RGN_ALIGN_LEFT; /* Tool props (aka operator) region */ - ar = MEM_callocN(sizeof(ARegion), "tool props area for file"); + ar = MEM_callocN(sizeof(ARegion), "tool props region for file"); BLI_addtail(&sfile->regionbase, ar); ar->regiontype = RGN_TYPE_TOOL_PROPS; ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; /* ui list region */ - ar = MEM_callocN(sizeof(ARegion), "ui area for file"); + ar = MEM_callocN(sizeof(ARegion), "ui region for file"); BLI_addtail(&sfile->regionbase, ar); ar->regiontype = RGN_TYPE_UI; ar->alignment = RGN_ALIGN_TOP; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for file"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for file"); BLI_addtail(&sfile->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); @@ -281,7 +281,7 @@ static void file_refresh(const bContext *C, ScrArea *sa) sfile->layout->dirty = true; } - /* Might be called with NULL sa, see file_main_area_draw() below. */ + /* Might be called with NULL sa, see file_main_region_draw() below. */ if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) { /* Create TOOLS/TOOL_PROPS regions. */ file_tools_region(sa); @@ -319,7 +319,7 @@ static void file_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) } /* add handlers, stuff you only do once or on area/region changes */ -static void file_main_area_init(wmWindowManager *wm, ARegion *ar) +static void file_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -333,7 +333,7 @@ static void file_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void file_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void file_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -350,7 +350,7 @@ static void file_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AR } } -static void file_main_area_draw(const bContext *C, ARegion *ar) +static void file_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceFile *sfile = CTX_wm_space_file(C); @@ -435,7 +435,6 @@ static void file_operatortypes(void) WM_operatortype_append(FILE_OT_bookmark_cleanup); WM_operatortype_append(FILE_OT_bookmark_move); WM_operatortype_append(FILE_OT_reset_recent); - WM_operatortype_append(FILE_OT_hidedot); WM_operatortype_append(FILE_OT_filenum); WM_operatortype_append(FILE_OT_directory_new); WM_operatortype_append(FILE_OT_delete); @@ -448,24 +447,36 @@ static void file_operatortypes(void) static void file_keymap(struct wmKeyConfig *keyconf) { wmKeyMapItem *kmi; - /* keys for all areas */ + /* keys for all regions */ wmKeyMap *keymap = WM_keymap_find(keyconf, "File Browser", SPACE_FILE, 0); - WM_keymap_add_item(keymap, "FILE_OT_bookmark_toggle", TKEY, KM_PRESS, 0, 0); + + /* More common 'fliebrowser-like navigation' shortcuts. */ + WM_keymap_add_item(keymap, "FILE_OT_parent", UPARROWKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "FILE_OT_previous", LEFTARROWKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "FILE_OT_next", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "FILE_OT_refresh", RKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "FILE_OT_parent", PKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "FILE_OT_bookmark_add", BKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "FILE_OT_hidedot", HKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_previous", BACKSPACEKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_next", BACKSPACEKEY, KM_PRESS, KM_SHIFT, 0); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", HKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.params.show_hidden"); WM_keymap_add_item(keymap, "FILE_OT_directory_new", IKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_delete", XKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_delete", DELKEY, KM_PRESS, 0, 0); + WM_keymap_verify_item(keymap, "FILE_OT_smoothscroll", TIMER1, KM_ANY, KM_ANY, 0); - /* keys for main area */ + WM_keymap_add_item(keymap, "FILE_OT_bookmark_toggle", TKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "FILE_OT_bookmark_add", BKEY, KM_PRESS, KM_CTRL, 0); + + /* keys for main region */ keymap = WM_keymap_find(keyconf, "File Browser Main", SPACE_FILE, 0); kmi = WM_keymap_add_item(keymap, "FILE_OT_execute", LEFTMOUSE, KM_DBL_CLICK, 0, 0); RNA_boolean_set(kmi->ptr, "need_active", true); + WM_keymap_add_item(keymap, "FILE_OT_refresh", PADPERIOD, KM_PRESS, 0, 0); + /* left mouse selects and opens */ WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, 0, 0); kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0); @@ -533,7 +544,6 @@ static void file_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "FILE_OT_next", BUTTON5MOUSE, KM_CLICK, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "FILE_OT_refresh", PADPERIOD, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_select_border", BKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_select_border", EVT_TWEAK_L, KM_ANY, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); @@ -552,7 +562,7 @@ static void file_keymap(struct wmKeyConfig *keyconf) RNA_int_set(kmi->ptr, "increment", -100); - /* keys for button area (top) */ + /* keys for button region (top) */ keymap = WM_keymap_find(keyconf, "File Browser Buttons", SPACE_FILE, 0); kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, 0, 0); RNA_int_set(kmi->ptr, "increment", 1); @@ -569,7 +579,7 @@ static void file_keymap(struct wmKeyConfig *keyconf) } -static void file_tools_area_init(wmWindowManager *wm, ARegion *ar) +static void file_tools_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -581,12 +591,12 @@ static void file_tools_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void file_tools_area_draw(const bContext *C, ARegion *ar) +static void file_tools_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } -static void file_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn)) +static void file_tools_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn)) { #if 0 /* context changes */ @@ -597,7 +607,7 @@ static void file_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), A } /* add handlers, stuff you only do once or on area/region changes */ -static void file_header_area_init(wmWindowManager *wm, ARegion *ar) +static void file_header_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -607,13 +617,13 @@ static void file_header_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void file_header_area_draw(const bContext *C, ARegion *ar) +static void file_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } /* add handlers, stuff you only do once or on area/region changes */ -static void file_ui_area_init(wmWindowManager *wm, ARegion *ar) +static void file_ui_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -627,7 +637,7 @@ static void file_ui_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void file_ui_area_draw(const bContext *C, ARegion *ar) +static void file_ui_region_draw(const bContext *C, ARegion *ar) { float col[3]; /* clear */ @@ -648,7 +658,7 @@ static void file_ui_area_draw(const bContext *C, ARegion *ar) UI_view2d_view_restore(C); } -static void file_ui_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void file_ui_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -709,9 +719,9 @@ void ED_spacetype_file(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); art->regionid = RGN_TYPE_WINDOW; - art->init = file_main_area_init; - art->draw = file_main_area_draw; - art->listener = file_main_area_listener; + art->init = file_main_region_init; + art->draw = file_main_region_draw; + art->listener = file_main_region_listener; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; BLI_addhead(&st->regiontypes, art); @@ -720,9 +730,9 @@ void ED_spacetype_file(void) art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; - art->init = file_header_area_init; - art->draw = file_header_area_draw; - // art->listener = file_header_area_listener; + art->init = file_header_region_init; + art->draw = file_header_region_draw; + // art->listener = file_header_region_listener; BLI_addhead(&st->regiontypes, art); /* regions: ui */ @@ -730,9 +740,9 @@ void ED_spacetype_file(void) art->regionid = RGN_TYPE_UI; art->prefsizey = 60; art->keymapflag = ED_KEYMAP_UI; - art->listener = file_ui_area_listener; - art->init = file_ui_area_init; - art->draw = file_ui_area_draw; + art->listener = file_ui_region_listener; + art->init = file_ui_region_init; + art->draw = file_ui_region_draw; BLI_addhead(&st->regiontypes, art); /* regions: channels (directories) */ @@ -741,9 +751,9 @@ void ED_spacetype_file(void) art->prefsizex = 240; art->prefsizey = 60; art->keymapflag = ED_KEYMAP_UI; - art->listener = file_tools_area_listener; - art->init = file_tools_area_init; - art->draw = file_tools_area_draw; + art->listener = file_tools_region_listener; + art->init = file_tools_region_init; + art->draw = file_tools_region_draw; BLI_addhead(&st->regiontypes, art); /* regions: tool properties */ @@ -752,9 +762,9 @@ void ED_spacetype_file(void) art->prefsizex = 0; art->prefsizey = 360; art->keymapflag = ED_KEYMAP_UI; - art->listener = file_tools_area_listener; - art->init = file_tools_area_init; - art->draw = file_tools_area_draw; + art->listener = file_tools_region_listener; + art->init = file_tools_region_init; + art->draw = file_tools_region_draw; BLI_addhead(&st->regiontypes, art); file_panels_register(art); diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 91e11ac4b1e..51865ebcf90 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -964,7 +964,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar) glDisable(GL_BLEND); } -/* This is called twice from space_graph.c -> graph_main_area_draw() +/* This is called twice from space_graph.c -> graph_main_region_draw() * Unselected then selected F-Curves are drawn so that they do not occlude each other. */ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid *grid, short sel) diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 200523f591d..9f3bfe6b533 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -119,7 +119,7 @@ static SpaceLink *graph_new(const bContext *C) ar->alignment = RGN_ALIGN_BOTTOM; /* channels */ - ar = MEM_callocN(sizeof(ARegion), "channels area for graphedit"); + ar = MEM_callocN(sizeof(ARegion), "channels region for graphedit"); BLI_addtail(&sipo->regionbase, ar); ar->regiontype = RGN_TYPE_CHANNELS; @@ -128,15 +128,15 @@ static SpaceLink *graph_new(const bContext *C) ar->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); /* ui buttons */ - ar = MEM_callocN(sizeof(ARegion), "buttons area for graphedit"); + ar = MEM_callocN(sizeof(ARegion), "buttons region for graphedit"); BLI_addtail(&sipo->regionbase, ar); ar->regiontype = RGN_TYPE_UI; ar->alignment = RGN_ALIGN_RIGHT; ar->flag = RGN_FLAG_HIDDEN; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for graphedit"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for graphedit"); BLI_addtail(&sipo->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -208,7 +208,7 @@ static SpaceLink *graph_duplicate(SpaceLink *sl) } /* add handlers, stuff you only do once or on area/region changes */ -static void graph_main_area_init(wmWindowManager *wm, ARegion *ar) +static void graph_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -221,7 +221,7 @@ static void graph_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void graph_main_area_draw(const bContext *C, ARegion *ar) +static void graph_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceIpo *sipo = CTX_wm_space_graph(C); @@ -340,7 +340,7 @@ static void graph_main_area_draw(const bContext *C, ARegion *ar) UI_view2d_scrollers_free(scrollers); } -static void graph_channel_area_init(wmWindowManager *wm, ARegion *ar) +static void graph_channel_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -359,7 +359,7 @@ static void graph_channel_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void graph_channel_area_draw(const bContext *C, ARegion *ar) +static void graph_channel_region_draw(const bContext *C, ARegion *ar) { bAnimContext ac; View2D *v2d = &ar->v2d; @@ -388,18 +388,18 @@ static void graph_channel_area_draw(const bContext *C, ARegion *ar) } /* add handlers, stuff you only do once or on area/region changes */ -static void graph_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void graph_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void graph_header_area_draw(const bContext *C, ARegion *ar) +static void graph_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } /* add handlers, stuff you only do once or on area/region changes */ -static void graph_buttons_area_init(wmWindowManager *wm, ARegion *ar) +static void graph_buttons_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -409,7 +409,7 @@ static void graph_buttons_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void graph_buttons_area_draw(const bContext *C, ARegion *ar) +static void graph_buttons_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } @@ -659,8 +659,8 @@ void ED_spacetype_ipo(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"); art->regionid = RGN_TYPE_WINDOW; - art->init = graph_main_area_init; - art->draw = graph_main_area_draw; + art->init = graph_main_region_init; + art->draw = graph_main_region_draw; art->listener = graph_region_listener; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; @@ -672,8 +672,8 @@ void ED_spacetype_ipo(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; art->listener = graph_region_listener; - art->init = graph_header_area_init; - art->draw = graph_header_area_draw; + art->init = graph_header_region_init; + art->draw = graph_header_region_draw; BLI_addhead(&st->regiontypes, art); @@ -683,8 +683,8 @@ void ED_spacetype_ipo(void) art->prefsizex = 200 + V2D_SCROLL_WIDTH; /* 200 is the 'standard', but due to scrollers, we want a bit more to fit the lock icons in */ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES; art->listener = graph_region_listener; - art->init = graph_channel_area_init; - art->draw = graph_channel_area_draw; + art->init = graph_channel_region_init; + art->draw = graph_channel_region_draw; BLI_addhead(&st->regiontypes, art); @@ -694,8 +694,8 @@ void ED_spacetype_ipo(void) art->prefsizex = 200; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = graph_region_listener; - art->init = graph_buttons_area_init; - art->draw = graph_buttons_area_draw; + art->init = graph_buttons_region_init; + art->draw = graph_buttons_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 80d6858ea86..ffd801d2146 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -150,7 +150,7 @@ struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree) /* 0: disable preview * otherwise refresh preview * - * XXX if you put this back, also check XXX in image_main_area_draw() */ + * XXX if you put this back, also check XXX in image_main_region_draw() */ * / void image_preview_event(int event) { diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 35a53afa550..d36ab5e10e2 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -816,7 +816,7 @@ static void draw_image_paint_helpers(const bContext *C, ARegion *ar, Scene *scen } } -/* draw main image area */ +/* draw main image region */ void draw_image_main(const bContext *C, ARegion *ar) { diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h index 6eaad302180..3b57d17f9f3 100644 --- a/source/blender/editors/space_image/image_intern.h +++ b/source/blender/editors/space_image/image_intern.h @@ -54,7 +54,7 @@ void draw_image_grease_pencil(struct bContext *C, bool onlyv2d); void draw_image_sample_line(struct SpaceImage *sima); /* image_ops.c */ -int space_image_main_area_poll(struct bContext *C); +int space_image_main_region_poll(struct bContext *C); void IMAGE_OT_view_all(struct wmOperatorType *ot); void IMAGE_OT_view_pan(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 9a4a3b24e24..1d11e7c6287 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -230,7 +230,7 @@ static int space_image_poll(bContext *C) } #endif -int space_image_main_area_poll(bContext *C) +int space_image_main_region_poll(bContext *C) { SpaceImage *sima = CTX_wm_space_image(C); /* XXX ARegion *ar = CTX_wm_region(C); */ @@ -270,7 +270,7 @@ static int image_sample_poll(bContext *C) return false; } - return space_image_main_area_poll(C); + return space_image_main_region_poll(C); } else { return false; @@ -401,7 +401,7 @@ void IMAGE_OT_view_pan(wmOperatorType *ot) ot->invoke = image_view_pan_invoke; ot->modal = image_view_pan_modal; ot->cancel = image_view_pan_cancel; - ot->poll = space_image_main_area_poll; + ot->poll = space_image_main_region_poll; /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS; @@ -617,7 +617,7 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot) ot->invoke = image_view_zoom_invoke; ot->modal = image_view_zoom_modal; ot->cancel = image_view_zoom_cancel; - ot->poll = space_image_main_area_poll; + ot->poll = space_image_main_region_poll; /* flags */ ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_LOCK_BYPASS; @@ -672,7 +672,7 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot) /* api callbacks */ ot->invoke = image_view_ndof_invoke; - ot->poll = space_image_main_area_poll; + ot->poll = space_image_main_region_poll; /* flags */ ot->flag = OPTYPE_LOCK_BYPASS; @@ -744,7 +744,7 @@ void IMAGE_OT_view_all(wmOperatorType *ot) /* api callbacks */ ot->exec = image_view_all_exec; - ot->poll = space_image_main_area_poll; + ot->poll = space_image_main_region_poll; /* flags */ ot->flag = OPTYPE_LOCK_BYPASS; @@ -808,7 +808,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) static int image_view_selected_poll(bContext *C) { - return (space_image_main_area_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C))); + return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C))); } void IMAGE_OT_view_selected(wmOperatorType *ot) @@ -863,7 +863,7 @@ void IMAGE_OT_view_zoom_in(wmOperatorType *ot) /* api callbacks */ ot->invoke = image_view_zoom_in_invoke; ot->exec = image_view_zoom_in_exec; - ot->poll = space_image_main_area_poll; + ot->poll = space_image_main_region_poll; /* flags */ ot->flag = OPTYPE_LOCK_BYPASS; @@ -912,7 +912,7 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot) /* api callbacks */ ot->invoke = image_view_zoom_out_invoke; ot->exec = image_view_zoom_out_exec; - ot->poll = space_image_main_area_poll; + ot->poll = space_image_main_region_poll; /* flags */ ot->flag = OPTYPE_LOCK_BYPASS; @@ -959,7 +959,7 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot) /* api callbacks */ ot->exec = image_view_zoom_ratio_exec; - ot->poll = space_image_main_area_poll; + ot->poll = space_image_main_region_poll; /* flags */ ot->flag = OPTYPE_LOCK_BYPASS; @@ -3079,7 +3079,7 @@ void IMAGE_OT_sample_line(wmOperatorType *ot) ot->invoke = image_sample_line_invoke; ot->modal = WM_gesture_straightline_modal; ot->exec = image_sample_line_exec; - ot->poll = space_image_main_area_poll; + ot->poll = space_image_main_region_poll; ot->cancel = WM_gesture_straightline_cancel; /* flags */ @@ -3322,7 +3322,7 @@ static int change_frame_poll(bContext *C) if (G.is_rendering) return 0; - return space_image_main_area_poll(C); + return space_image_main_region_poll(C); } static void change_frame_apply(bContext *C, wmOperator *op) @@ -3455,7 +3455,7 @@ void IMAGE_OT_read_renderlayers(wmOperatorType *ot) ot->idname = "IMAGE_OT_read_renderlayers"; ot->description = "Read all the current scene's render layers from cache, as needed"; - ot->poll = space_image_main_area_poll; + ot->poll = space_image_main_region_poll; ot->exec = image_read_renderlayers_exec; /* flags */ diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 97e3390f142..93c446ab3cb 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -582,7 +582,7 @@ static int image_context(const bContext *C, const char *member, bContextDataResu /************************** main region ***************************/ /* sets up the fields of the View2D from zoom and offset */ -static void image_main_area_set_view2d(SpaceImage *sima, ARegion *ar) +static void image_main_region_set_view2d(SpaceImage *sima, ARegion *ar) { Image *ima = ED_space_image(sima); float x1, y1, w, h; @@ -635,7 +635,7 @@ static void image_main_area_set_view2d(SpaceImage *sima, ARegion *ar) } /* add handlers, stuff you only do once or on area/region changes */ -static void image_main_area_init(wmWindowManager *wm, ARegion *ar) +static void image_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -670,7 +670,7 @@ static void image_main_area_init(wmWindowManager *wm, ARegion *ar) } -static void image_main_area_draw(const bContext *C, ARegion *ar) +static void image_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceImage *sima = CTX_wm_space_image(C); @@ -704,7 +704,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) sima->iuser.scene = scene; /* we set view2d from own zoom and offset each time */ - image_main_area_set_view2d(sima, ar); + image_main_region_set_view2d(sima, ar); /* we draw image in pixelspace */ draw_image_main(C, ar); @@ -793,7 +793,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar) #endif } -static void image_main_area_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion *ar, wmNotifier *wmn) +static void image_main_region_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -821,7 +821,7 @@ static void image_main_area_listener(bScreen *UNUSED(sc), ScrArea *sa, ARegion * /* *********************** buttons region ************************ */ /* add handlers, stuff you only do once or on area/region changes */ -static void image_buttons_area_init(wmWindowManager *wm, ARegion *ar) +static void image_buttons_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -832,12 +832,12 @@ static void image_buttons_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void image_buttons_area_draw(const bContext *C, ARegion *ar) +static void image_buttons_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } -static void image_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void image_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -873,7 +873,7 @@ static void image_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa) /* *********************** scopes region ************************ */ /* add handlers, stuff you only do once or on area/region changes */ -static void image_tools_area_init(wmWindowManager *wm, ARegion *ar) +static void image_tools_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -884,7 +884,7 @@ static void image_tools_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void image_tools_area_draw(const bContext *C, ARegion *ar) +static void image_tools_region_draw(const bContext *C, ARegion *ar) { SpaceImage *sima = CTX_wm_space_image(C); Scene *scene = CTX_data_scene(C); @@ -910,7 +910,7 @@ static void image_tools_area_draw(const bContext *C, ARegion *ar) ED_region_panels(C, ar, NULL, -1, true); } -static void image_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void image_tools_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -946,17 +946,17 @@ static void image_tools_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), /************************* header region **************************/ /* add handlers, stuff you only do once or on area/region changes */ -static void image_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void image_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void image_header_area_draw(const bContext *C, ARegion *ar) +static void image_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } -static void image_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void image_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -1005,9 +1005,9 @@ void ED_spacetype_image(void) art = MEM_callocN(sizeof(ARegionType), "spacetype image region"); art->regionid = RGN_TYPE_WINDOW; art->keymapflag = ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL; - art->init = image_main_area_init; - art->draw = image_main_area_draw; - art->listener = image_main_area_listener; + art->init = image_main_region_init; + art->draw = image_main_region_draw; + art->listener = image_main_region_listener; BLI_addhead(&st->regiontypes, art); @@ -1016,9 +1016,9 @@ void ED_spacetype_image(void) art->regionid = RGN_TYPE_UI; art->prefsizex = 220; // XXX art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; - art->listener = image_buttons_area_listener; - art->init = image_buttons_area_init; - art->draw = image_buttons_area_draw; + art->listener = image_buttons_region_listener; + art->init = image_buttons_region_init; + art->draw = image_buttons_region_draw; BLI_addhead(&st->regiontypes, art); ED_uvedit_buttons_register(art); @@ -1029,9 +1029,9 @@ void ED_spacetype_image(void) art->regionid = RGN_TYPE_TOOLS; art->prefsizex = 220; // XXX art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; - art->listener = image_tools_area_listener; - art->init = image_tools_area_init; - art->draw = image_tools_area_draw; + art->listener = image_tools_region_listener; + art->init = image_tools_region_init; + art->draw = image_tools_region_draw; BLI_addhead(&st->regiontypes, art); /* regions: header */ @@ -1039,9 +1039,9 @@ void ED_spacetype_image(void) art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - art->listener = image_header_area_listener; - art->init = image_header_area_init; - art->draw = image_header_area_draw; + art->listener = image_header_region_listener; + art->init = image_header_region_init; + art->draw = image_header_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c index aeab87e6cb5..21777fd8afa 100644 --- a/source/blender/editors/space_info/space_info.c +++ b/source/blender/editors/space_info/space_info.c @@ -77,8 +77,8 @@ static SpaceLink *info_new(const bContext *UNUSED(C)) ar->regiontype = RGN_TYPE_HEADER; ar->alignment = RGN_ALIGN_BOTTOM; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for info"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for info"); BLI_addtail(&sinfo->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -123,7 +123,7 @@ static SpaceLink *info_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ -static void info_main_area_init(wmWindowManager *wm, ARegion *ar) +static void info_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -145,7 +145,7 @@ static void info_textview_update_rect(const bContext *C, ARegion *ar) UI_view2d_totRect_set(v2d, ar->winx - 1, info_textview_height(sinfo, ar, CTX_wm_reports(C))); } -static void info_main_area_draw(const bContext *C, ARegion *ar) +static void info_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceInfo *sinfo = CTX_wm_space_info(C); @@ -226,17 +226,17 @@ static void info_keymap(struct wmKeyConfig *keyconf) } /* add handlers, stuff you only do once or on area/region changes */ -static void info_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void info_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void info_header_area_draw(const bContext *C, ARegion *ar) +static void info_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } -static void info_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void info_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { // SpaceInfo *sinfo = sa->spacedata.first; @@ -329,9 +329,9 @@ void ED_spacetype_info(void) art->regionid = RGN_TYPE_WINDOW; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES; - art->init = info_main_area_init; - art->draw = info_main_area_draw; - art->listener = info_main_area_listener; + art->init = info_main_region_init; + art->draw = info_main_region_draw; + art->listener = info_main_region_listener; BLI_addhead(&st->regiontypes, art); @@ -342,8 +342,8 @@ void ED_spacetype_info(void) art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; art->listener = info_header_listener; - art->init = info_header_area_init; - art->draw = info_header_area_draw; + art->init = info_header_region_init; + art->draw = info_header_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index ebce13389c9..c801a736e31 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -45,13 +45,14 @@ #include "textview.h" -static void console_font_begin(TextViewContext *sc) +static void console_font_begin(const int font_id, const int lheight) { /* 0.875 is based on: 16 pixels lines get 14 pixel text */ - BLF_size(blf_mono_font, 0.875 * sc->lheight, 72); + BLF_size(font_id, 0.875 * lheight, 72); } typedef struct ConsoleDrawContext { + int font_id; int cwidth; int lheight; int lofs; /* text vertical offset */ @@ -123,7 +124,6 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str int tot_lines; /* total number of lines for wrapping */ int *offsets; /* offsets of line beginnings for wrapping */ int y_next; - const int mono = blf_mono_font; str_len = console_wrap_offsets(str, str_len, cdc->console_width, &tot_lines, &offsets); y_next = cdc->xy[1] + cdc->lheight * tot_lines; @@ -189,8 +189,8 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str glColor3ubv(fg); /* last part needs no clipping */ - BLF_position(mono, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); - BLF_draw_mono(mono, s, len, cdc->cwidth); + BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); + BLF_draw_mono(cdc->font_id, s, len, cdc->cwidth); if (cdc->sel[0] != cdc->sel[1]) { console_step_sel(cdc, -initial_offset); @@ -205,8 +205,8 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str len = offsets[i] - offsets[i - 1]; s = str + offsets[i - 1]; - BLF_position(mono, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); - BLF_draw_mono(mono, s, len, cdc->cwidth); + BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); + BLF_draw_mono(cdc->font_id, s, len, cdc->cwidth); if (cdc->sel[0] != cdc->sel[1]) { console_step_sel(cdc, len); @@ -236,8 +236,8 @@ static int console_draw_string(ConsoleDrawContext *cdc, const char *str, int str glColor3ubv(fg); - BLF_position(mono, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); - BLF_draw_mono(mono, str, str_len, cdc->cwidth); + BLF_position(cdc->font_id, cdc->xy[0], cdc->lofs + cdc->xy[1], 0); + BLF_draw_mono(cdc->font_id, str, str_len, cdc->cwidth); if (cdc->sel[0] != cdc->sel[1]) { int isel[2]; @@ -272,9 +272,9 @@ int textview_draw(TextViewContext *tvc, const int draw, int mval[2], void **mous int xy[2], y_prev; int sel[2] = {-1, -1}; /* defaults disabled */ unsigned char fg[3], bg[3]; - const int mono = blf_mono_font; + const int font_id = blf_mono_font; - console_font_begin(tvc); + console_font_begin(font_id, tvc->lheight); xy[0] = x_orig; xy[1] = y_orig; @@ -285,10 +285,11 @@ int textview_draw(TextViewContext *tvc, const int draw, int mval[2], void **mous *pos_pick = 0; /* constants for the sequencer context */ - cdc.cwidth = (int)BLF_fixed_width(mono); + cdc.font_id = font_id; + cdc.cwidth = (int)BLF_fixed_width(font_id); assert(cdc.cwidth > 0); cdc.lheight = tvc->lheight; - cdc.lofs = -BLF_descender(mono); + cdc.lofs = -BLF_descender(font_id); /* note, scroll bar must be already subtracted () */ cdc.console_width = (tvc->winx - (CONSOLE_DRAW_MARGIN * 2)) / cdc.cwidth; /* avoid divide by zero on small windows */ diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c index 34a5fee88eb..243a522011b 100644 --- a/source/blender/editors/space_logic/space_logic.c +++ b/source/blender/editors/space_logic/space_logic.c @@ -113,8 +113,8 @@ static SpaceLink *logic_new(const bContext *C) ar->regiontype= RGN_TYPE_UI; ar->alignment= RGN_ALIGN_RIGHT; - /* main area */ - ar= MEM_callocN(sizeof(ARegion), "main area for logic"); + /* main region */ + ar= MEM_callocN(sizeof(ARegion), "main region for logic"); BLI_addtail(&slogic->regionbase, ar); ar->regiontype= RGN_TYPE_WINDOW; @@ -230,7 +230,7 @@ static int logic_context(const bContext *UNUSED(C), const char *UNUSED(member), /* add handlers, stuff you only do once or on area/region changes */ -static void logic_main_area_init(wmWindowManager *wm, ARegion *ar) +static void logic_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -241,7 +241,7 @@ static void logic_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void logic_main_area_draw(const bContext *C, ARegion *ar) +static void logic_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ // SpaceLogic *slogic= CTX_wm_space_logic(C); @@ -270,7 +270,7 @@ static void logic_main_area_draw(const bContext *C, ARegion *ar) /* *********************** buttons region ************************ */ /* add handlers, stuff you only do once or on area/region changes */ -static void logic_buttons_area_init(wmWindowManager *wm, ARegion *ar) +static void logic_buttons_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -280,7 +280,7 @@ static void logic_buttons_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void logic_buttons_area_draw(const bContext *C, ARegion *ar) +static void logic_buttons_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } @@ -288,12 +288,12 @@ static void logic_buttons_area_draw(const bContext *C, ARegion *ar) /************************* header region **************************/ /* add handlers, stuff you only do once or on area/region changes */ -static void logic_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void logic_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void logic_header_area_draw(const bContext *C, ARegion *ar) +static void logic_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } @@ -322,8 +322,8 @@ void ED_spacetype_logic(void) art = MEM_callocN(sizeof(ARegionType), "spacetype logic region"); art->regionid = RGN_TYPE_WINDOW; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES | ED_KEYMAP_VIEW2D; - art->init = logic_main_area_init; - art->draw = logic_main_area_draw; + art->init = logic_main_region_init; + art->draw = logic_main_region_draw; art->listener = logic_listener; BLI_addhead(&st->regiontypes, art); @@ -334,8 +334,8 @@ void ED_spacetype_logic(void) art->prefsizex= 220; // XXX art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = logic_listener; - art->init = logic_buttons_area_init; - art->draw = logic_buttons_area_draw; + art->init = logic_buttons_region_init; + art->draw = logic_buttons_region_draw; BLI_addhead(&st->regiontypes, art); /* regions: header */ @@ -343,8 +343,8 @@ void ED_spacetype_logic(void) art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - art->init = logic_header_area_init; - art->draw = logic_header_area_draw; + art->init = logic_header_region_init; + art->draw = logic_header_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index a0ea12b8aa0..9e73e03a664 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -268,7 +268,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe { AnimData *adt = BKE_animdata_from_id(ale->id); - /* button area... */ + /* button region... */ if (x >= (v2d->cur.xmax - NLACHANNEL_BUTTON_WIDTH)) { if (nlaedit_is_tweakmode_on(ac) == 0) { /* 'push-down' action - only usable when not in TweakMode */ diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index 9fc7b5d6f8f..e2b36c5b5ae 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -125,15 +125,15 @@ static SpaceLink *nla_new(const bContext *C) ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL; /* ui buttons */ - ar = MEM_callocN(sizeof(ARegion), "buttons area for nla"); + ar = MEM_callocN(sizeof(ARegion), "buttons region for nla"); BLI_addtail(&snla->regionbase, ar); ar->regiontype = RGN_TYPE_UI; ar->alignment = RGN_ALIGN_RIGHT; ar->flag = RGN_FLAG_HIDDEN; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for nla"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for nla"); BLI_addtail(&snla->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -200,7 +200,7 @@ static SpaceLink *nla_duplicate(SpaceLink *sl) } /* add handlers, stuff you only do once or on area/region changes */ -static void nla_channel_area_init(wmWindowManager *wm, ARegion *ar) +static void nla_channel_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -222,7 +222,7 @@ static void nla_channel_area_init(wmWindowManager *wm, ARegion *ar) } /* draw entirely, view changes should be handled here */ -static void nla_channel_area_draw(const bContext *C, ARegion *ar) +static void nla_channel_region_draw(const bContext *C, ARegion *ar) { bAnimContext ac; View2D *v2d = &ar->v2d; @@ -250,7 +250,7 @@ static void nla_channel_area_draw(const bContext *C, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ -static void nla_main_area_init(wmWindowManager *wm, ARegion *ar) +static void nla_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -263,7 +263,7 @@ static void nla_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void nla_main_area_draw(const bContext *C, ARegion *ar) +static void nla_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceNla *snla = CTX_wm_space_nla(C); @@ -326,18 +326,18 @@ static void nla_main_area_draw(const bContext *C, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ -static void nla_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void nla_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void nla_header_area_draw(const bContext *C, ARegion *ar) +static void nla_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } /* add handlers, stuff you only do once or on area/region changes */ -static void nla_buttons_area_init(wmWindowManager *wm, ARegion *ar) +static void nla_buttons_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -347,7 +347,7 @@ static void nla_buttons_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void nla_buttons_area_draw(const bContext *C, ARegion *ar) +static void nla_buttons_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } @@ -385,7 +385,7 @@ static void nla_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegio } -static void nla_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void nla_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -430,7 +430,7 @@ static void nla_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARe } } -static void nla_channel_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void nla_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -521,9 +521,9 @@ void ED_spacetype_nla(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype nla region"); art->regionid = RGN_TYPE_WINDOW; - art->init = nla_main_area_init; - art->draw = nla_main_area_draw; - art->listener = nla_main_area_listener; + art->init = nla_main_region_init; + art->draw = nla_main_region_draw; + art->listener = nla_main_region_listener; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; BLI_addhead(&st->regiontypes, art); @@ -534,8 +534,8 @@ void ED_spacetype_nla(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - art->init = nla_header_area_init; - art->draw = nla_header_area_draw; + art->init = nla_header_region_init; + art->draw = nla_header_region_draw; BLI_addhead(&st->regiontypes, art); @@ -545,9 +545,9 @@ void ED_spacetype_nla(void) art->prefsizex = 200; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES; - art->init = nla_channel_area_init; - art->draw = nla_channel_area_draw; - art->listener = nla_channel_area_listener; + art->init = nla_channel_region_init; + art->draw = nla_channel_region_draw; + art->listener = nla_channel_region_listener; BLI_addhead(&st->regiontypes, art); @@ -557,8 +557,8 @@ void ED_spacetype_nla(void) art->prefsizex = 200; art->keymapflag = ED_KEYMAP_UI; art->listener = nla_region_listener; - art->init = nla_buttons_area_init; - art->draw = nla_buttons_area_draw; + art->init = nla_buttons_region_init; + art->draw = nla_buttons_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 413cdc208dd..a312888fc44 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -277,7 +277,7 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene G.is_break = false; #endif - BKE_image_backup_render(scene, BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result")); + BKE_image_backup_render(scene, BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"), false); wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene_owner, "Compositing", WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS, WM_JOB_TYPE_COMPOSITE); diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 96f0e69ca71..7788173a8ee 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -233,7 +233,7 @@ void node_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "NODE_OT_properties", NKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_toolbar", TKEY, KM_PRESS, 0, 0); - /* Main Area only ----------------- */ + /* Main Region only ----------------- */ keymap = WM_keymap_find(keyconf, "Node Editor", SPACE_NODE, 0); /* mouse select in nodes used to be both keys, but perhaps this should be reduced? diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 8a808b2ae9d..0852b6164d3 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -29,8 +29,6 @@ * \ingroup spnode */ -#include <ctype.h> - #include "MEM_guardedalloc.h" #include "DNA_node_types.h" @@ -420,7 +418,6 @@ static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag)) #undef HEADER_LENGTH } -/* update link_count fields to avoid repeated link counting */ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock) { bNodeLink *link; @@ -434,64 +431,13 @@ static int node_count_links(bNodeTree *ntree, bNodeSocket *sock) return count; } -/* test if two sockets are interchangeable - * XXX this could be made into a tree-type callback for flexibility - */ -static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b) -{ - /* tests if alphabetic prefix matches - * this allows for imperfect matches, such as numeric suffixes, - * like Color1/Color2 - */ - int prefix_len = 0; - char *ca = a->name, *cb = b->name; - for (; *ca != '\0' && *cb != '\0'; ++ca, ++cb) { - /* end of common prefix? */ - if (*ca != *cb) { - /* prefix delimited by non-alphabetic char */ - if (isalpha(*ca) || isalpha(*cb)) - return false; - break; - } - ++prefix_len; - } - return prefix_len > 0; -} - -/* find an eligible socket for linking */ -static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *cur, bool use_swap) -{ - int cur_link_count = node_count_links(ntree, cur); - if (cur_link_count <= cur->limit) { - /* current socket is fine, use it */ - return cur; - } - else if (use_swap) { - /* link swapping: try to find a free slot with a matching name */ - - bNodeSocket *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first; - bNodeSocket *sock; - - sock = cur->next ? cur->next : first; /* wrap around the list end */ - while (sock != cur) { - if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) { - int link_count = node_count_links(ntree, sock); - /* take +1 into account since we would add a new link */ - if (link_count + 1 <= sock->limit) - return sock; /* found a valid free socket we can swap to */ - } - - sock = sock->next ? sock->next : first; /* wrap around the list end */ - } - } - return NULL; -} - -static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link, bool use_swap) +static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link) { bNodeTree *ntree = snode->edittree; bNodeSocket *from = link->fromsock, *to = link->tosock; bNodeLink *tlink, *tlink_next; + int to_count = node_count_links(ntree, to); + int from_count = node_count_links(ntree, from); for (tlink = ntree->links.first; tlink; tlink = tlink_next) { tlink_next = tlink->next; @@ -499,28 +445,18 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link, bool use_ continue; if (tlink && tlink->fromsock == from) { - bNodeSocket *new_from = node_find_linkable_socket(ntree, tlink->fromnode, from, use_swap); - if (new_from && new_from != from) { - /* redirect existing link */ - tlink->fromsock = new_from; - } - else if (!new_from) { - /* no possible replacement, remove tlink */ + if (from_count > from->limit) { nodeRemLink(ntree, tlink); tlink = NULL; + --from_count; } } if (tlink && tlink->tosock == to) { - bNodeSocket *new_to = node_find_linkable_socket(ntree, tlink->tonode, to, use_swap); - if (new_to && new_to != to) { - /* redirect existing link */ - tlink->tosock = new_to; - } - else if (!new_to) { - /* no possible replacement, remove tlink */ + if (to_count > to->limit) { nodeRemLink(ntree, tlink); tlink = NULL; + --to_count; } } } @@ -533,10 +469,20 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) bNodeLinkDrag *nldrag = op->customdata; LinkData *linkdata; + /* avoid updates while applying links */ + ntree->is_updating = true; for (linkdata = nldrag->links.first; linkdata; linkdata = linkdata->next) { bNodeLink *link = linkdata->data; if (apply_links && link->tosock && link->fromsock) { + /* before actually adding the link, + * let nodes perform special link insertion handling + */ + if (link->fromnode->typeinfo->insert_link) + link->fromnode->typeinfo->insert_link(ntree, link->fromnode, link); + if (link->tonode->typeinfo->insert_link) + link->tonode->typeinfo->insert_link(ntree, link->tonode, link); + /* add link to the node tree */ BLI_addtail(&ntree->links, link); @@ -546,11 +492,12 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) link->tonode->update |= NODE_UPDATE; /* we might need to remove a link */ - node_remove_extra_links(snode, link, true); + node_remove_extra_links(snode, link); } else nodeRemLink(ntree, link); } + ntree->is_updating = false; ntreeUpdateTree(CTX_data_main(C), ntree); snode_notify(C, snode); @@ -1746,7 +1693,7 @@ void ED_node_link_insert(ScrArea *sa) link->tonode = select; link->tosock = best_input; - node_remove_extra_links(snode, link, false); + node_remove_extra_links(snode, link); link->flag &= ~NODE_LINKFLAG_HILITE; nodeAddLink(snode->edittree, select, best_output, node, sockto); diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index b9b925f1829..df484724fc5 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -333,8 +333,8 @@ static SpaceLink *node_new(const bContext *UNUSED(C)) ar->flag = RGN_FLAG_HIDDEN; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for node"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for node"); BLI_addtail(&snode->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -586,7 +586,7 @@ static SpaceLink *node_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ -static void node_buttons_area_init(wmWindowManager *wm, ARegion *ar) +static void node_buttons_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -596,13 +596,13 @@ static void node_buttons_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void node_buttons_area_draw(const bContext *C, ARegion *ar) +static void node_buttons_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } /* add handlers, stuff you only do once or on area/region changes */ -static void node_toolbar_area_init(wmWindowManager *wm, ARegion *ar) +static void node_toolbar_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -612,7 +612,7 @@ static void node_toolbar_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void node_toolbar_area_draw(const bContext *C, ARegion *ar) +static void node_toolbar_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } @@ -634,8 +634,8 @@ static void node_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) } -/* Initialize main area, setting handlers. */ -static void node_main_area_init(wmWindowManager *wm, ARegion *ar) +/* Initialize main region, setting handlers. */ +static void node_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; ListBase *lb; @@ -655,7 +655,7 @@ static void node_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_dropbox_handler(&ar->handlers, lb); } -static void node_main_area_draw(const bContext *C, ARegion *ar) +static void node_main_region_draw(const bContext *C, ARegion *ar) { drawnodespace(C, ar); } @@ -722,12 +722,12 @@ static void node_dropboxes(void) /* add handlers, stuff you only do once or on area/region changes */ -static void node_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void node_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void node_header_area_draw(const bContext *C, ARegion *ar) +static void node_header_region_draw(const bContext *C, ARegion *ar) { /* find and set the context */ snode_set_context(C); @@ -735,7 +735,7 @@ static void node_header_area_draw(const bContext *C, ARegion *ar) ED_region_header(C, ar); } -/* used for header + main area */ +/* used for header + main region */ static void node_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ @@ -844,8 +844,8 @@ void ED_spacetype_node(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_WINDOW; - art->init = node_main_area_init; - art->draw = node_main_area_draw; + art->init = node_main_region_init; + art->draw = node_main_region_draw; art->listener = node_region_listener; art->cursor = node_cursor; art->event_cursor = true; @@ -859,8 +859,8 @@ void ED_spacetype_node(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; art->listener = node_region_listener; - art->init = node_header_area_init; - art->draw = node_header_area_draw; + art->init = node_header_region_init; + art->draw = node_header_region_draw; BLI_addhead(&st->regiontypes, art); @@ -870,8 +870,8 @@ void ED_spacetype_node(void) art->prefsizex = 180; // XXX art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = node_region_listener; - art->init = node_buttons_area_init; - art->draw = node_buttons_area_draw; + art->init = node_buttons_region_init; + art->draw = node_buttons_region_draw; BLI_addhead(&st->regiontypes, art); node_buttons_register(art); @@ -883,8 +883,8 @@ void ED_spacetype_node(void) art->prefsizey = 50; /* XXX */ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; art->listener = node_region_listener; - art->init = node_toolbar_area_init; - art->draw = node_toolbar_area_draw; + art->init = node_toolbar_region_init; + art->draw = node_toolbar_region_draw; BLI_addhead(&st->regiontypes, art); node_toolbar_register(art); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index fd1eb129c51..14f397f61fe 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -434,6 +434,7 @@ static void restrictbutton_gr_restrict_view(bContext *C, void *poin, void *poin2 { restrictbutton_gr_restrict_flag(poin, poin2, OB_RESTRICT_VIEW); WM_event_add_notifier(C, NC_GROUP, NULL); + DAG_id_type_tag(CTX_data_main(C), ID_OB); } static void restrictbutton_gr_restrict_select(bContext *C, void *poin, void *poin2) { diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 6d420674f3e..46974a6e911 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -290,6 +290,103 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } +/* Library delete --------------------------------------------------- */ + +static void lib_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem, ReportList *reports) +{ + Library *lib = (Library *)tselem->id; + ListBase *lbarray[MAX_LIBARRAY]; + int a; + + BLI_assert(te->idcode == ID_LI && lib != NULL); + UNUSED_VARS_NDEBUG(te); + + /* We simply set all ID from given lib (including lib itself) to zero user count. + * It is not possible to do a proper cleanup without a save/reload in current master. */ + a = set_listbasepointers(CTX_data_main(C), lbarray); + while (a--) { + ListBase *lb = lbarray[a]; + ID *id; + + for (id = lb->first; id; id = id->next) { + if (id->lib == lib) { + id_fake_user_clear(id); + id->us = 0; + } + } + } + + BKE_reportf(reports, RPT_WARNING, + "Please save and reload .blend file to complete deletion of '%s' library", + ((Library *)tselem->id)->filepath); +} + +void lib_delete_cb( + bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem) +{ + lib_delete(C, te, tselem, CTX_wm_reports(C)); +} + +static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2]) +{ + if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); + + if (te->idcode == ID_LI && tselem->id) { + if (((Library *)tselem->id)->parent) { + BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, + "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath); + return OPERATOR_CANCELLED; + } + + lib_delete(C, te, tselem, reports); + return OPERATOR_FINISHED; + } + } + else { + for (te = te->subtree.first; te; te = te->next) { + int ret; + if ((ret = outliner_lib_delete_invoke_do(C, reports, te, mval))) { + return ret; + } + } + } + + return 0; +} + +static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; + + BLI_assert(ar && soops); + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + for (te = soops->tree.first; te; te = te->next) { + int ret; + + if ((ret = outliner_lib_delete_invoke_do(C, op->reports, te, fmval))) { + return ret; + } + } + + return OPERATOR_CANCELLED; +} + +void OUTLINER_OT_lib_delete(wmOperatorType *ot) +{ + ot->name = "Delete Library"; + ot->idname = "OUTLINER_OT_lib_delete"; + ot->description = "Delete the library under cursor (needs a save/reload)"; + + ot->invoke = outliner_lib_delete_invoke; + ot->poll = ED_operator_outliner_active; +} + /* ************************************************************** */ /* Setting Toggling Operators */ diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index f10e6be2fa9..262aa9b6209 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -176,6 +176,10 @@ void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, Tree void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem); +void lib_delete_cb( + struct bContext *C, struct Scene *scene, struct TreeElement *te, + struct TreeStoreElem *tsep, struct TreeStoreElem *tselem); + TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children); /* ...................................................... */ @@ -183,6 +187,8 @@ void OUTLINER_OT_item_activate(struct wmOperatorType *ot); void OUTLINER_OT_item_openclose(struct wmOperatorType *ot); void OUTLINER_OT_item_rename(struct wmOperatorType *ot); +void OUTLINER_OT_lib_delete(struct wmOperatorType *ot); + void OUTLINER_OT_show_one_level(struct wmOperatorType *ot); void OUTLINER_OT_show_active(struct wmOperatorType *ot); void OUTLINER_OT_show_hierarchy(struct wmOperatorType *ot); @@ -218,6 +224,7 @@ void OUTLINER_OT_operation(struct wmOperatorType *ot); void OUTLINER_OT_scene_operation(struct wmOperatorType *ot); void OUTLINER_OT_object_operation(struct wmOperatorType *ot); void OUTLINER_OT_group_operation(struct wmOperatorType *ot); +void OUTLINER_OT_lib_operation(struct wmOperatorType *ot); void OUTLINER_OT_id_operation(struct wmOperatorType *ot); void OUTLINER_OT_data_operation(struct wmOperatorType *ot); void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 839d44df25d..9710c3fc36b 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -47,10 +47,12 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_select_border); WM_operatortype_append(OUTLINER_OT_item_openclose); WM_operatortype_append(OUTLINER_OT_item_rename); + WM_operatortype_append(OUTLINER_OT_lib_delete); WM_operatortype_append(OUTLINER_OT_operation); WM_operatortype_append(OUTLINER_OT_scene_operation); WM_operatortype_append(OUTLINER_OT_object_operation); WM_operatortype_append(OUTLINER_OT_group_operation); + WM_operatortype_append(OUTLINER_OT_lib_operation); WM_operatortype_append(OUTLINER_OT_id_operation); WM_operatortype_append(OUTLINER_OT_data_operation); WM_operatortype_append(OUTLINER_OT_animdata_operation); diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 02511917b29..84f8c629c5d 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -315,7 +315,7 @@ static eOLDrawState tree_element_active_texture( /*tselem = TREESTORE(te);*/ /*UNUSED*/ - /* find buttons area (note, this is undefined really still, needs recode in blender) */ + /* find buttons region (note, this is undefined really still, needs recode in blender) */ /* XXX removed finding sbuts */ /* where is texture linked to? */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 313a75f373a..e4471acc2c8 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -119,6 +119,7 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, case ID_MA: case ID_TE: case ID_IP: case ID_IM: case ID_SO: case ID_KE: case ID_WO: case ID_AC: case ID_NLA: case ID_TXT: case ID_GR: case ID_LS: + case ID_LI: if (*idlevel == 0) *idlevel = idcode; else if (*idlevel != idcode) *idlevel = -1; break; @@ -846,7 +847,7 @@ enum { OL_OP_TOGVIS, OL_OP_TOGSEL, OL_OP_TOGREN, - OL_OP_RENAME + OL_OP_RENAME, }; static EnumPropertyItem prop_object_op_types[] = { @@ -1246,6 +1247,88 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot) /* **************************************** */ +typedef enum eOutlinerLibOpTypes { + OL_LIB_INVALID = 0, + + OL_LIB_RENAME, + OL_LIB_DELETE, +} eOutlinerLibOpTypes; + +static EnumPropertyItem outliner_lib_op_type_items[] = { + {OL_LIB_RENAME, "RENAME", 0, "Rename", ""}, + {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender (needs a save/reload)"}, + {0, NULL, 0, NULL, NULL} + +}; + +static int outliner_lib_operation_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutlinerIdOpTypes event; + + /* check for invalid states */ + if (soops == NULL) + return OPERATOR_CANCELLED; + + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + event = RNA_enum_get(op->ptr, "type"); + + switch (event) { + case OL_LIB_RENAME: + { + /* rename */ + outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb); + + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + ED_undo_push(C, "Rename"); + break; + } + case OL_LIB_DELETE: + { + /* delete */ + outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_delete_cb); + + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + /* Note: no undo possible here really, not 100% sure why... + * Probably because of library optimizations in undo/redo process? */ + /* ED_undo_push(C, "Rename"); */ + break; + } + default: + /* invalid - unhandled */ + break; + } + + /* wrong notifier still... */ + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + + /* XXX: this is just so that outliner is always up to date */ + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + return OPERATOR_FINISHED; +} + + +void OUTLINER_OT_lib_operation(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Outliner Library Operation"; + ot->idname = "OUTLINER_OT_lib_operation"; + ot->description = ""; + + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_lib_operation_exec; + ot->poll = ED_operator_outliner_active; + + ot->prop = RNA_def_enum(ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", ""); +} + +/* **************************************** */ + static void outliner_do_id_set_operation(SpaceOops *soops, int type, ListBase *lb, ID *newid, void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *)) { @@ -1703,10 +1786,17 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S BKE_report(reports, RPT_WARNING, "Mixed selection"); } else { - if (idlevel == ID_GR) - WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL); - else - WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL); + switch (idlevel) { + case ID_GR: + WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL); + break; + case ID_LI: + WM_operator_name_call(C, "OUTLINER_OT_lib_operation", WM_OP_INVOKE_REGION_WIN, NULL); + break; + default: + WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL); + break; + } } } else if (datalevel) { diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 7b1ec174a6b..1dd66366e5d 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -62,7 +62,7 @@ #include "outliner_intern.h" -static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar) +static void outliner_main_region_init(wmWindowManager *wm, ARegion *ar) { ListBase *lb; wmKeyMap *keymap; @@ -266,7 +266,7 @@ static void outliner_dropboxes(void) WM_dropbox_add(lb, "OUTLINER_OT_group_link", outliner_group_link_poll, outliner_group_link_copy); } -static void outliner_main_area_draw(const bContext *C, ARegion *ar) +static void outliner_main_region_draw(const bContext *C, ARegion *ar) { View2D *v2d = &ar->v2d; View2DScrollers *scrollers; @@ -287,12 +287,12 @@ static void outliner_main_area_draw(const bContext *C, ARegion *ar) } -static void outliner_main_area_free(ARegion *UNUSED(ar)) +static void outliner_main_region_free(ARegion *UNUSED(ar)) { } -static void outliner_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void outliner_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -399,21 +399,21 @@ static void outliner_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa) /* ************************ header outliner area region *********************** */ /* add handlers, stuff you only do once or on area/region changes */ -static void outliner_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void outliner_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void outliner_header_area_draw(const bContext *C, ARegion *ar) +static void outliner_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } -static void outliner_header_area_free(ARegion *UNUSED(ar)) +static void outliner_header_region_free(ARegion *UNUSED(ar)) { } -static void outliner_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void outliner_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -445,8 +445,8 @@ static SpaceLink *outliner_new(const bContext *UNUSED(C)) ar->regiontype = RGN_TYPE_HEADER; ar->alignment = RGN_ALIGN_BOTTOM; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for outliner"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for outliner"); BLI_addtail(&soutliner->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -508,10 +508,10 @@ void ED_spacetype_outliner(void) art->regionid = RGN_TYPE_WINDOW; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES; - art->init = outliner_main_area_init; - art->draw = outliner_main_area_draw; - art->free = outliner_main_area_free; - art->listener = outliner_main_area_listener; + art->init = outliner_main_region_init; + art->draw = outliner_main_region_draw; + art->free = outliner_main_region_free; + art->listener = outliner_main_region_listener; BLI_addhead(&st->regiontypes, art); /* regions: header */ @@ -520,10 +520,10 @@ void ED_spacetype_outliner(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - art->init = outliner_header_area_init; - art->draw = outliner_header_area_draw; - art->free = outliner_header_area_free; - art->listener = outliner_header_area_listener; + art->init = outliner_header_region_init; + art->draw = outliner_header_region_draw; + art->free = outliner_header_region_free; + art->listener = outliner_header_region_listener; BLI_addhead(&st->regiontypes, art); BKE_spacetype_register(st); diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c index 759dcd3d0a4..4228635ccd6 100644 --- a/source/blender/editors/space_script/space_script.c +++ b/source/blender/editors/space_script/space_script.c @@ -78,8 +78,8 @@ static SpaceLink *script_new(const bContext *UNUSED(C)) ar->regiontype = RGN_TYPE_HEADER; ar->alignment = RGN_ALIGN_BOTTOM; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for script"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for script"); BLI_addtail(&sscript->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -125,7 +125,7 @@ static SpaceLink *script_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ -static void script_main_area_init(wmWindowManager *wm, ARegion *ar) +static void script_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -136,7 +136,7 @@ static void script_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void script_main_area_draw(const bContext *C, ARegion *ar) +static void script_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceScript *sscript = (SpaceScript *)CTX_wm_space_data(C); @@ -166,17 +166,17 @@ static void script_main_area_draw(const bContext *C, ARegion *ar) } /* add handlers, stuff you only do once or on area/region changes */ -static void script_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void script_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void script_header_area_draw(const bContext *C, ARegion *ar) +static void script_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } -static void script_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn)) +static void script_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn)) { /* context changes */ // XXX - Todo, need the ScriptSpace accessible to get the python script to run. @@ -202,9 +202,9 @@ void ED_spacetype_script(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype script region"); art->regionid = RGN_TYPE_WINDOW; - art->init = script_main_area_init; - art->draw = script_main_area_draw; - art->listener = script_main_area_listener; + art->init = script_main_region_init; + art->draw = script_main_region_draw; + art->listener = script_main_region_listener; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_UI | ED_KEYMAP_FRAMES; // XXX need to further test this ED_KEYMAP_UI is needed for button interaction BLI_addhead(&st->regiontypes, art); @@ -215,8 +215,8 @@ void ED_spacetype_script(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; - art->init = script_header_area_init; - art->draw = script_header_area_draw; + art->init = script_header_region_init; + art->draw = script_header_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 2ae7cdd4f98..deb0a3f6d03 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -58,6 +58,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_basic_shader.h" + #include "ED_anim_api.h" #include "ED_gpencil.h" #include "ED_markers.h" @@ -177,7 +179,11 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3]) blendcol[0] = blendcol[1] = blendcol[2] = 128; if (seq->flag & SEQ_MUTE) UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.5, 20); break; - + + case SEQ_TYPE_TEXT: + UI_GetThemeColor3ubv(TH_SEQ_TEXT, col); + break; + default: col[0] = 10; col[1] = 255; col[2] = 40; break; @@ -301,6 +307,20 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, int chan_range = 0; float draw_range = y2 - y1; float draw_height; + ListBase *seqbase; + int offset; + + seqbase = BKE_sequence_seqbase_get(seqm, &offset); + if (!seqbase || BLI_listbase_is_empty(seqbase)) { + return; + } + + if (seqm->type == SEQ_TYPE_SCENE) { + offset = seqm->start - offset; + } + else { + offset = 0; + } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -308,7 +328,7 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, if (seqm->flag & SEQ_MUTE) drawmeta_stipple(1); - for (seq = seqm->seqbase.first; seq; seq = seq->next) { + for (seq = seqbase->first; seq; seq = seq->next) { chan_min = min_ii(chan_min, seq->machine); chan_max = max_ii(chan_max, seq->machine); } @@ -318,11 +338,14 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, col[3] = 196; /* alpha, used for all meta children */ - for (seq = seqm->seqbase.first; seq; seq = seq->next) { - if ((seq->startdisp > x2 || seq->enddisp < x1) == 0) { + for (seq = seqbase->first; seq; seq = seq->next) { + const int startdisp = seq->startdisp + offset; + const int enddisp = seq->enddisp + offset; + + if ((startdisp > x2 || enddisp < x1) == 0) { float y_chan = (seq->machine - chan_min) / (float)(chan_range) * draw_range; - float x1_chan = seq->startdisp; - float x2_chan = seq->enddisp; + float x1_chan = startdisp; + float x2_chan = enddisp; float y1_chan, y2_chan; if ((seqm->flag & SEQ_MUTE) == 0 && (seq->flag & SEQ_MUTE)) @@ -830,7 +853,9 @@ static void draw_seq_strip(const bContext *C, SpaceSeq *sseq, Scene *scene, AReg glDisable(GL_LINE_STIPPLE); } - if (seq->type == SEQ_TYPE_META) { + if ((seq->type == SEQ_TYPE_META) || + ((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS))) + { drawmeta_contents(scene, seq, x1, y1, x2, y2); } @@ -1074,7 +1099,6 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq float viewrect[2]; float col[3]; GLuint texid; - GLuint last_texid; void *display_buffer; void *cache_handle = NULL; const bool is_imbuf = ED_space_sequencer_check_show_imbuf(sseq); @@ -1270,11 +1294,9 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq } } - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f(1.0, 1.0, 1.0, 1.0); - last_texid = glaGetOneInteger(GL_TEXTURE_2D); - glEnable(GL_TEXTURE_2D); + GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); glGenTextures(1, (GLuint *)&texid); glBindTexture(GL_TEXTURE_2D, texid); @@ -1348,8 +1370,8 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq } glEnd(); - glBindTexture(GL_TEXTURE_2D, last_texid); - glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) glDisable(GL_BLEND); glDeleteTextures(1, &texid); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 70adaa2f3a6..fd8b1165719 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2517,7 +2517,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) #if 1 BKE_sequence_tx_set_final_left(ms->parseq, ms->disp_range[0]); BKE_sequence_tx_set_final_right(ms->parseq, ms->disp_range[1]); - BKE_sequence_single_fix(seq); + BKE_sequence_single_fix(ms->parseq); BKE_sequence_calc(scene, ms->parseq); #else if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq)) diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 5b3061bd513..fce40f8ca59 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -136,9 +136,9 @@ static SpaceLink *sequencer_new(const bContext *C) ar->alignment = RGN_ALIGN_RIGHT; ar->flag = RGN_FLAG_HIDDEN; - /* preview area */ + /* preview region */ /* NOTE: if you change values here, also change them in sequencer_init_preview_region */ - ar = MEM_callocN(sizeof(ARegion), "preview area for sequencer"); + ar = MEM_callocN(sizeof(ARegion), "preview region for sequencer"); BLI_addtail(&sseq->regionbase, ar); ar->regiontype = RGN_TYPE_PREVIEW; ar->alignment = RGN_ALIGN_TOP; @@ -160,8 +160,8 @@ static SpaceLink *sequencer_new(const bContext *C) ar->v2d.keeptot = V2D_KEEPTOT_FREE; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for sequencer"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for sequencer"); BLI_addtail(&sseq->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -283,7 +283,7 @@ static void sequencer_refresh(const bContext *C, ScrArea *sa) /* Get available height (without DPI correction). */ const float height = (sa->winy - ED_area_headersize()) / UI_DPI_FAC; - /* We reuse hidden area's size, allows to find same layout as before if we just switch + /* We reuse hidden region's size, allows to find same layout as before if we just switch * between one 'full window' view and the combined one. This gets lost if we switch to both * 'full window' views before, though... Better than nothing. */ if (ar_main->flag & RGN_FLAG_HIDDEN) { @@ -457,7 +457,7 @@ static int sequencer_context(const bContext *C, const char *member, bContextData /* *********************** sequencer (main) region ************************ */ /* add handlers, stuff you only do once or on area/region changes */ -static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar) +static void sequencer_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; ListBase *lb; @@ -482,13 +482,13 @@ static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_dropbox_handler(&ar->handlers, lb); } -static void sequencer_main_area_draw(const bContext *C, ARegion *ar) +static void sequencer_main_region_draw(const bContext *C, ARegion *ar) { /* NLE - strip editing timeline interface */ draw_timeline_seq(C, ar); } -static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void sequencer_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -528,18 +528,18 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa /* *********************** header region ************************ */ /* add handlers, stuff you only do once or on area/region changes */ -static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void sequencer_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void sequencer_header_area_draw(const bContext *C, ARegion *ar) +static void sequencer_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } /* *********************** preview region ************************ */ -static void sequencer_preview_area_init(wmWindowManager *wm, ARegion *ar) +static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -558,7 +558,7 @@ static void sequencer_preview_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void sequencer_preview_area_draw(const bContext *C, ARegion *ar) +static void sequencer_preview_region_draw(const bContext *C, ARegion *ar) { ScrArea *sa = CTX_wm_area(C); SpaceSeq *sseq = sa->spacedata.first; @@ -594,7 +594,7 @@ static void sequencer_preview_area_draw(const bContext *C, ARegion *ar) } } -static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void sequencer_preview_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -645,7 +645,7 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED /* *********************** buttons region ************************ */ /* add handlers, stuff you only do once or on area/region changes */ -static void sequencer_buttons_area_init(wmWindowManager *wm, ARegion *ar) +static void sequencer_buttons_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -655,12 +655,12 @@ static void sequencer_buttons_area_init(wmWindowManager *wm, ARegion *ar) ED_region_panels_init(wm, ar); } -static void sequencer_buttons_area_draw(const bContext *C, ARegion *ar) +static void sequencer_buttons_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } -static void sequencer_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -712,9 +712,9 @@ void ED_spacetype_sequencer(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); art->regionid = RGN_TYPE_WINDOW; - art->init = sequencer_main_area_init; - art->draw = sequencer_main_area_draw; - art->listener = sequencer_main_area_listener; + art->init = sequencer_main_region_init; + art->draw = sequencer_main_region_draw; + art->listener = sequencer_main_region_listener; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION; BLI_addhead(&st->regiontypes, art); @@ -722,9 +722,9 @@ void ED_spacetype_sequencer(void) /* preview */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); art->regionid = RGN_TYPE_PREVIEW; - art->init = sequencer_preview_area_init; - art->draw = sequencer_preview_area_draw; - art->listener = sequencer_preview_area_listener; + art->init = sequencer_preview_region_init; + art->draw = sequencer_preview_region_draw; + art->listener = sequencer_preview_region_listener; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL; BLI_addhead(&st->regiontypes, art); @@ -733,9 +733,9 @@ void ED_spacetype_sequencer(void) art->regionid = RGN_TYPE_UI; art->prefsizex = 220; // XXX art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; - art->listener = sequencer_buttons_area_listener; - art->init = sequencer_buttons_area_init; - art->draw = sequencer_buttons_area_draw; + art->listener = sequencer_buttons_region_listener; + art->init = sequencer_buttons_region_init; + art->draw = sequencer_buttons_region_draw; BLI_addhead(&st->regiontypes, art); sequencer_buttons_register(art); @@ -746,9 +746,9 @@ void ED_spacetype_sequencer(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - art->init = sequencer_header_area_init; - art->draw = sequencer_header_area_draw; - art->listener = sequencer_main_area_listener; + art->init = sequencer_header_region_init; + art->draw = sequencer_header_region_draw; + art->listener = sequencer_main_region_listener; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index ff53d306e69..87270bace9a 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -80,8 +80,8 @@ static SpaceLink *text_new(const bContext *UNUSED(C)) ar->regiontype = RGN_TYPE_HEADER; ar->alignment = RGN_ALIGN_BOTTOM; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for text"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for text"); BLI_addtail(&stext->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -404,7 +404,7 @@ static int text_context(const bContext *C, const char *member, bContextDataResul /********************* main region ********************/ /* add handlers, stuff you only do once or on area/region changes */ -static void text_main_area_init(wmWindowManager *wm, ARegion *ar) +static void text_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; ListBase *lb; @@ -423,7 +423,7 @@ static void text_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_dropbox_handler(&ar->handlers, lb); } -static void text_main_area_draw(const bContext *C, ARegion *ar) +static void text_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ SpaceText *st = CTX_wm_space_text(C); @@ -511,12 +511,12 @@ static void text_dropboxes(void) /****************** header region ******************/ /* add handlers, stuff you only do once or on area/region changes */ -static void text_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void text_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void text_header_area_draw(const bContext *C, ARegion *ar) +static void text_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } @@ -524,7 +524,7 @@ static void text_header_area_draw(const bContext *C, ARegion *ar) /****************** properties region ******************/ /* add handlers, stuff you only do once or on area/region changes */ -static void text_properties_area_init(wmWindowManager *wm, ARegion *ar) +static void text_properties_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -537,7 +537,7 @@ static void text_properties_area_init(wmWindowManager *wm, ARegion *ar) } -static void text_properties_area_draw(const bContext *C, ARegion *ar) +static void text_properties_region_draw(const bContext *C, ARegion *ar) { SpaceText *st = CTX_wm_space_text(C); @@ -578,8 +578,8 @@ void ED_spacetype_text(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype text region"); art->regionid = RGN_TYPE_WINDOW; - art->init = text_main_area_init; - art->draw = text_main_area_draw; + art->init = text_main_region_init; + art->draw = text_main_region_draw; art->cursor = text_cursor; art->event_cursor = true; @@ -591,8 +591,8 @@ void ED_spacetype_text(void) art->prefsizex = UI_COMPACT_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI; - art->init = text_properties_area_init; - art->draw = text_properties_area_draw; + art->init = text_properties_region_init; + art->draw = text_properties_region_draw; BLI_addhead(&st->regiontypes, art); /* regions: header */ @@ -601,8 +601,8 @@ void ED_spacetype_text(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; - art->init = text_header_area_init; - art->draw = text_header_area_draw; + art->init = text_header_region_init; + art->draw = text_header_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index 9bcaf04e520..16087921ab6 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -57,45 +57,56 @@ #include "text_format.h" /******************** text font drawing ******************/ -// XXX, fixme -#define mono blf_mono_font -static void text_font_begin(SpaceText *st) +typedef struct TextDrawContext { + int font_id; + int cwidth; + int lheight_dpi; +} TextDrawContext; + +static void text_draw_context_init(const SpaceText *st, TextDrawContext *tdc) +{ + tdc->font_id = blf_mono_font; + tdc->cwidth = 0; + tdc->lheight_dpi = st->lheight_dpi; +} + +static void text_font_begin(const TextDrawContext *tdc) { - BLF_size(mono, st->lheight_dpi, 72); + BLF_size(tdc->font_id, tdc->lheight_dpi, 72); } -static void text_font_end(SpaceText *UNUSED(st)) +static void text_font_end(const TextDrawContext *UNUSED(tdc)) { } -static int text_font_draw(SpaceText *st, int x, int y, const char *str) +static int text_font_draw(const TextDrawContext *tdc, int x, int y, const char *str) { int columns; - BLF_position(mono, x, y, 0); - columns = BLF_draw_mono(mono, str, BLF_DRAW_STR_DUMMY_MAX, st->cwidth); + BLF_position(tdc->font_id, x, y, 0); + columns = BLF_draw_mono(tdc->font_id, str, BLF_DRAW_STR_DUMMY_MAX, tdc->cwidth); - return st->cwidth * columns; + return tdc->cwidth * columns; } -static int text_font_draw_character(SpaceText *st, int x, int y, char c) +static int text_font_draw_character(const TextDrawContext *tdc, int x, int y, char c) { - BLF_position(mono, x, y, 0); - BLF_draw(mono, &c, 1); + BLF_position(tdc->font_id, x, y, 0); + BLF_draw(tdc->font_id, &c, 1); - return st->cwidth; + return tdc->cwidth; } -static int text_font_draw_character_utf8(SpaceText *st, int x, int y, const char *c) +static int text_font_draw_character_utf8(const TextDrawContext *tdc, int x, int y, const char *c) { int columns; const size_t len = BLI_str_utf8_size_safe(c); - BLF_position(mono, x, y, 0); - columns = BLF_draw_mono(mono, c, len, st->cwidth); + BLF_position(tdc->font_id, x, y, 0); + columns = BLF_draw_mono(tdc->font_id, c, len, tdc->cwidth); - return st->cwidth * columns; + return tdc->cwidth * columns; } #if 0 @@ -174,7 +185,7 @@ static void format_draw_color(char formatchar) * */ -int wrap_width(SpaceText *st, ARegion *ar) +int wrap_width(const SpaceText *st, ARegion *ar) { int winx = ar->winx - TXT_SCROLL_WIDTH; int x, max; @@ -185,7 +196,7 @@ int wrap_width(SpaceText *st, ARegion *ar) } /* Sets (offl, offc) for transforming (line, curs) to its wrapped position */ -void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc) +void wrap_offset(const SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc) { Text *text; TextLine *linep; @@ -280,7 +291,7 @@ void wrap_offset(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int * } /* cursin - mem, offc - view */ -void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc) +void wrap_offset_in_line(const SpaceText *st, ARegion *ar, TextLine *linein, int cursin, int *offl, int *offc) { int i, j, start, end, chars, max, chop; char ch; @@ -342,7 +353,7 @@ void wrap_offset_in_line(SpaceText *st, ARegion *ar, TextLine *linein, int cursi } } -int text_get_char_pos(SpaceText *st, const char *line, int cur) +int text_get_char_pos(const SpaceText *st, const char *line, int cur) { int a = 0, i; @@ -373,7 +384,9 @@ static const char *txt_utf8_forward_columns(const char *str, int columns, int *p return p; } -static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w, const char *format, int skip) +static int text_draw_wrapped( + const SpaceText *st, const TextDrawContext *tdc, + const char *str, int x, int y, int w, const char *format, int skip) { const bool use_syntax = (st->showsyntax && format); FlattenString fs; @@ -418,7 +431,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w if (use_syntax) { if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); } - x += text_font_draw_character_utf8(st, x, y, str + ma); + x += text_font_draw_character_utf8(tdc, x, y, str + ma); fpos++; } y -= st->lheight_dpi + TXT_LINE_SPACING; @@ -442,7 +455,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]); } - x += text_font_draw_character_utf8(st, x, y, str + ma); + x += text_font_draw_character_utf8(tdc, x, y, str + ma); } flatten_string_free(&fs); @@ -450,7 +463,9 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w return lines; } -static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x, int y, const char *format) +static void text_draw( + const SpaceText *st, const TextDrawContext *tdc, + char *str, int cshift, int maxwidth, int x, int y, const char *format) { const bool use_syntax = (st->showsyntax && format); FlattenString fs; @@ -483,7 +498,7 @@ static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x, return; /* String is shorter than shift or ends with a padding */ } - x += st->cwidth * padding; + x += tdc->cwidth * padding; if (use_syntax) { int a, str_shift = 0; @@ -491,12 +506,12 @@ static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x, for (a = 0; a < amount; a++) { if (format[a] != fmt_prev) format_draw_color(fmt_prev = format[a]); - x += text_font_draw_character_utf8(st, x, y, in + str_shift); + x += text_font_draw_character_utf8(tdc, x, y, in + str_shift); str_shift += BLI_str_utf8_size_safe(in + str_shift); } } else { - text_font_draw(st, x, y, in); + text_font_draw(tdc, x, y, in); } flatten_string_free(&fs); @@ -696,14 +711,14 @@ void text_free_caches(SpaceText *st) /************************ word-wrap utilities *****************************/ /* cache should be updated in caller */ -static int text_get_visible_lines_no(SpaceText *st, int lineno) +static int text_get_visible_lines_no(const SpaceText *st, int lineno) { - DrawCache *drawcache = (DrawCache *)st->drawcache; + const DrawCache *drawcache = st->drawcache; return drawcache->line_height[lineno]; } -int text_get_visible_lines(SpaceText *st, ARegion *ar, const char *str) +int text_get_visible_lines(const SpaceText *st, ARegion *ar, const char *str) { int i, j, start, end, max, lines, chars; char ch; @@ -742,7 +757,7 @@ int text_get_visible_lines(SpaceText *st, ARegion *ar, const char *str) return lines; } -int text_get_span_wrap(SpaceText *st, ARegion *ar, TextLine *from, TextLine *to) +int text_get_span_wrap(const SpaceText *st, ARegion *ar, TextLine *from, TextLine *to) { if (st->wordwrap) { int ret = 0; @@ -767,7 +782,7 @@ int text_get_total_lines(SpaceText *st, ARegion *ar) DrawCache *drawcache; text_update_drawcache(st, ar); - drawcache = (DrawCache *)st->drawcache; + drawcache = st->drawcache; return drawcache->total_lines; } @@ -785,7 +800,7 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back) pix_available = ar->winy - pix_top_margin - pix_bottom_margin; ltexth = text_get_total_lines(st, ar); blank_lines = st->viewlines / 2; - + /* nicer code: use scroll rect for entire bar */ back->xmin = ar->winx - (V2D_SCROLL_WIDTH + 1); back->xmax = ar->winx; @@ -887,7 +902,7 @@ static void calc_text_rcts(SpaceText *st, ARegion *ar, rcti *scroll, rcti *back) CLAMP(st->txtscroll.ymax, pix_bottom_margin, ar->winy - pix_top_margin); } -static void draw_textscroll(SpaceText *st, rcti *scroll, rcti *back) +static void draw_textscroll(const SpaceText *st, rcti *scroll, rcti *back) { bTheme *btheme = UI_GetTheme(); uiWidgetColors wcol = btheme->tui.wcol_scroll; @@ -911,8 +926,9 @@ static void draw_textscroll(SpaceText *st, rcti *scroll, rcti *back) /*********************** draw documentation *******************************/ -static void draw_documentation(SpaceText *st, ARegion *ar) +static void draw_documentation(const SpaceText *st, ARegion *ar) { + TextDrawContext tdc = {0}; TextLine *tmp; char *docs, buf[DOC_WIDTH + 1], *p; int i, br, lines; @@ -925,6 +941,8 @@ static void draw_documentation(SpaceText *st, ARegion *ar) if (!docs) return; + text_draw_context_init(st, &tdc); + /* Count the visible lines to the cursor */ for (tmp = st->text->curl, l = -st->top; tmp; tmp = tmp->prev, l++) ; if (l < 0) return; @@ -974,7 +992,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar) buf[i] = '\0'; if (lines >= 0) { y -= st->lheight_dpi; - text_draw(st, buf, 0, 0, x + 4, y - 3, NULL); + text_draw(st, &tdc, buf, 0, 0, x + 4, y - 3, NULL); } i = 0; br = DOC_WIDTH; lines++; } @@ -983,7 +1001,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar) buf[br] = '\0'; if (lines >= 0) { y -= st->lheight_dpi; - text_draw(st, buf, 0, 0, x + 4, y - 3, NULL); + text_draw(st, &tdc, buf, 0, 0, x + 4, y - 3, NULL); } p -= i - br - 1; /* Rewind pointer to last break */ i = 0; br = DOC_WIDTH; lines++; @@ -999,7 +1017,7 @@ static void draw_documentation(SpaceText *st, ARegion *ar) /*********************** draw suggestion list *******************************/ -static void draw_suggestion_list(SpaceText *st, ARegion *ar) +static void draw_suggestion_list(const SpaceText *st, const TextDrawContext *tdc, ARegion *ar) { SuggItem *item, *first, *last, *sel; char str[SUGG_LIST_WIDTH * BLI_UTF8_MAX + 1]; @@ -1064,7 +1082,7 @@ static void draw_suggestion_list(SpaceText *st, ARegion *ar) } format_draw_color(item->type); - text_draw(st, str, 0, 0, x + margin_x, y - 1, NULL); + text_draw(st, tdc, str, 0, 0, x + margin_x, y - 1, NULL); if (item == last) break; } @@ -1191,7 +1209,7 @@ static void draw_cursor(SpaceText *st, ARegion *ar) /******************* draw matching brackets *********************/ -static void draw_brackets(SpaceText *st, ARegion *ar) +static void draw_brackets(const SpaceText *st, const TextDrawContext *tdc, ARegion *ar) { TextLine *startl, *endl, *linep; Text *text = st->text; @@ -1299,8 +1317,8 @@ static void draw_brackets(SpaceText *st, ARegion *ar) if (viewc >= 0) { viewl = txt_get_span(text->lines.first, startl) - st->top + offl; - text_font_draw_character(st, x + viewc * st->cwidth, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); - text_font_draw_character(st, x + viewc * st->cwidth + 1, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); + text_font_draw_character(tdc, x + viewc * st->cwidth, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); + text_font_draw_character(tdc, x + viewc * st->cwidth + 1, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); } /* draw closing bracket */ @@ -1311,15 +1329,16 @@ static void draw_brackets(SpaceText *st, ARegion *ar) if (viewc >= 0) { viewl = txt_get_span(text->lines.first, endl) - st->top + offl; - text_font_draw_character(st, x + viewc * st->cwidth, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); - text_font_draw_character(st, x + viewc * st->cwidth + 1, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); + text_font_draw_character(tdc, x + viewc * st->cwidth, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); + text_font_draw_character(tdc, x + viewc * st->cwidth + 1, y - viewl * (st->lheight_dpi + TXT_LINE_SPACING), ch); } } -/*********************** main area drawing *************************/ +/*********************** main region drawing *************************/ void draw_text_main(SpaceText *st, ARegion *ar) { + TextDrawContext tdc = {0}; Text *text = st->text; TextFormatType *tft; TextLine *tmp; @@ -1328,8 +1347,6 @@ void draw_text_main(SpaceText *st, ARegion *ar) int i, x, y, winx, linecount = 0, lineno = 0; int wraplinecount = 0, wrap_skip = 0; int margin_column_x; - /* don't draw lines below this */ - const int clip_min_y = -(int)(st->lheight_dpi - 1); /* if no text, nothing to do */ if (!text) @@ -1337,8 +1354,14 @@ void draw_text_main(SpaceText *st, ARegion *ar) /* dpi controlled line height and font size */ st->lheight_dpi = (U.widget_unit * st->lheight) / 20; + + /* don't draw lines below this */ + const int clip_min_y = -(int)(st->lheight_dpi - 1); + st->viewlines = (st->lheight_dpi) ? (int)(ar->winy - clip_min_y) / (st->lheight_dpi + TXT_LINE_SPACING) : 0; + text_draw_context_init(st, &tdc); + text_update_drawcache(st, ar); /* make sure all the positional pointers exist */ @@ -1377,9 +1400,11 @@ void draw_text_main(SpaceText *st, ARegion *ar) lineno++; } - text_font_begin(st); - st->cwidth = BLF_fixed_width(mono); - st->cwidth = MAX2(st->cwidth, (char)1); + + text_font_begin(&tdc); + + tdc.cwidth = max_ii((int)BLF_fixed_width(tdc.font_id), 1); + st->cwidth = tdc.cwidth; /* draw line numbers background */ if (st->showlinenrs) { @@ -1414,19 +1439,19 @@ void draw_text_main(SpaceText *st, ARegion *ar) BLI_snprintf(linenr, sizeof(linenr), "%*d", st->linenrs_tot, i + linecount + 1); /* itoa(i + linecount + 1, linenr, 10); */ /* not ansi-c :/ */ - text_font_draw(st, TXT_OFFSET - 7, y, linenr); + text_font_draw(&tdc, TXT_OFFSET - 7, y, linenr); UI_ThemeColor(TH_TEXT); } if (st->wordwrap) { /* draw word wrapped text */ - int lines = text_draw_wrapped(st, tmp->line, x, y, winx - x, tmp->format, wrap_skip); + int lines = text_draw_wrapped(st, &tdc, tmp->line, x, y, winx - x, tmp->format, wrap_skip); y -= lines * (st->lheight_dpi + TXT_LINE_SPACING); } else { /* draw unwrapped text */ - text_draw(st, tmp->line, st->left, ar->winx / st->cwidth, x, y, tmp->format); + text_draw(st, &tdc, tmp->line, st->left, ar->winx / st->cwidth, x, y, tmp->format); y -= st->lheight_dpi + TXT_LINE_SPACING; } @@ -1450,22 +1475,26 @@ void draw_text_main(SpaceText *st, ARegion *ar) } /* draw other stuff */ - draw_brackets(st, ar); + draw_brackets(st, &tdc, ar); draw_textscroll(st, &scroll, &back); draw_documentation(st, ar); - draw_suggestion_list(st, ar); + draw_suggestion_list(st, &tdc, ar); - text_font_end(st); + text_font_end(&tdc); } /************************** update ***************************/ void text_update_character_width(SpaceText *st) { - text_font_begin(st); - st->cwidth = BLF_fixed_width(mono); + TextDrawContext tdc = {0}; + + text_draw_context_init(st, &tdc); + + text_font_begin(&tdc); + st->cwidth = BLF_fixed_width(tdc.font_id); st->cwidth = MAX2(st->cwidth, (char)1); - text_font_end(st); + text_font_end(&tdc); } /* Moves the view to the cursor location, diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c index b29c6420d60..0133122c5a3 100644 --- a/source/blender/editors/space_text/text_format.c +++ b/source/blender/editors/space_text/text_format.c @@ -73,7 +73,7 @@ static void flatten_string_append(FlattenString *fs, const char *c, int accum, i fs->pos += len; } -int flatten_string(SpaceText *st, FlattenString *fs, const char *in) +int flatten_string(const SpaceText *st, FlattenString *fs, const char *in) { int r, i, total = 0; diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h index daed3b3e447..b901ec83a9c 100644 --- a/source/blender/editors/space_text/text_format.h +++ b/source/blender/editors/space_text/text_format.h @@ -54,7 +54,7 @@ enum { #define FMT_CONT_ALL \ (FMT_CONT_QUOTESINGLE | FMT_CONT_QUOTEDOUBLE | FMT_CONT_TRIPLE | FMT_CONT_COMMENT_C) -int flatten_string(struct SpaceText *st, FlattenString *fs, const char *in); +int flatten_string(const struct SpaceText *st, FlattenString *fs, const char *in); void flatten_string_free(FlattenString *fs); int flatten_string_strlen(FlattenString *fs, const char *str); diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h index 7ae2617f375..3129c1bfc85 100644 --- a/source/blender/editors/space_text/text_intern.h +++ b/source/blender/editors/space_text/text_intern.h @@ -65,10 +65,10 @@ void text_update_cursor_moved(struct bContext *C); #define TOOL_SUGG_LIST 0x01 #define TOOL_DOCUMENT 0x02 -int wrap_width(struct SpaceText *st, struct ARegion *ar); -void wrap_offset(struct SpaceText *st, struct ARegion *ar, struct TextLine *linein, int cursin, int *offl, int *offc); -void wrap_offset_in_line(struct SpaceText *st, struct ARegion *ar, struct TextLine *linep, int cursin, int *offl, int *offc); -int text_get_char_pos(struct SpaceText *st, const char *line, int cur); +int wrap_width(const struct SpaceText *st, struct ARegion *ar); +void wrap_offset(const struct SpaceText *st, struct ARegion *ar, struct TextLine *linein, int cursin, int *offl, int *offc); +void wrap_offset_in_line(const struct SpaceText *st, struct ARegion *ar, struct TextLine *linep, int cursin, int *offl, int *offc); +int text_get_char_pos(const struct SpaceText *st, const char *line, int cur); void text_drawcache_tag_update(struct SpaceText *st, int full); void text_free_caches(struct SpaceText *st); @@ -76,8 +76,8 @@ void text_free_caches(struct SpaceText *st); int text_do_suggest_select(struct SpaceText *st, struct ARegion *ar); void text_pop_suggest_list(void); -int text_get_visible_lines(struct SpaceText *st, struct ARegion *ar, const char *str); -int text_get_span_wrap(struct SpaceText *st, struct ARegion *ar, struct TextLine *from, struct TextLine *to); +int text_get_visible_lines(const struct SpaceText *st, struct ARegion *ar, const char *str); +int text_get_span_wrap(const struct SpaceText *st, struct ARegion *ar, struct TextLine *from, struct TextLine *to); int text_get_total_lines(struct SpaceText *st, struct ARegion *ar); /* text_ops.c */ diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 003dbd55edd..4c64c52ba2b 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -487,7 +487,7 @@ static void time_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) /* ---------------- */ /* add handlers, stuff you only do once or on area/region changes */ -static void time_main_area_init(wmWindowManager *wm, ARegion *ar) +static void time_main_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -498,7 +498,7 @@ static void time_main_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } -static void time_main_area_draw(const bContext *C, ARegion *ar) +static void time_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ Scene *scene = CTX_data_scene(C); @@ -557,7 +557,7 @@ static void time_main_area_draw(const bContext *C, ARegion *ar) UI_view2d_scrollers_free(scrollers); } -static void time_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void time_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -588,17 +588,17 @@ static void time_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), AR /* ************************ header time area region *********************** */ /* add handlers, stuff you only do once or on area/region changes */ -static void time_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void time_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void time_header_area_draw(const bContext *C, ARegion *ar) +static void time_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } -static void time_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void time_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -651,8 +651,8 @@ static SpaceLink *time_new(const bContext *C) ar->regiontype = RGN_TYPE_HEADER; ar->alignment = RGN_ALIGN_BOTTOM; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for time"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for time"); BLI_addtail(&stime->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -739,9 +739,9 @@ void ED_spacetype_time(void) art->regionid = RGN_TYPE_WINDOW; art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_MARKERS | ED_KEYMAP_ANIMATION | ED_KEYMAP_FRAMES; - art->init = time_main_area_init; - art->draw = time_main_area_draw; - art->listener = time_main_area_listener; + art->init = time_main_region_init; + art->draw = time_main_region_draw; + art->listener = time_main_region_listener; art->keymap = time_keymap; BLI_addhead(&st->regiontypes, art); @@ -751,9 +751,9 @@ void ED_spacetype_time(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - art->init = time_header_area_init; - art->draw = time_header_area_draw; - art->listener = time_header_area_listener; + art->init = time_header_region_init; + art->draw = time_header_region_draw; + art->listener = time_header_region_listener; BLI_addhead(&st->regiontypes, art); BKE_spacetype_register(st); diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index b5a6821d147..aeba4a86f3e 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -66,8 +66,8 @@ static SpaceLink *userpref_new(const bContext *UNUSED(C)) ar->regiontype = RGN_TYPE_HEADER; ar->alignment = RGN_ALIGN_BOTTOM; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for userpref"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for userpref"); BLI_addtail(&spref->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -101,7 +101,7 @@ static SpaceLink *userpref_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ -static void userpref_main_area_init(wmWindowManager *wm, ARegion *ar) +static void userpref_main_region_init(wmWindowManager *wm, ARegion *ar) { /* do not use here, the properties changed in userprefs do a system-wide refresh, then scroller jumps back */ /* ar->v2d.flag &= ~V2D_IS_INITIALISED; */ @@ -111,7 +111,7 @@ static void userpref_main_area_init(wmWindowManager *wm, ARegion *ar) ED_region_panels_init(wm, ar); } -static void userpref_main_area_draw(const bContext *C, ARegion *ar) +static void userpref_main_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } @@ -126,17 +126,17 @@ static void userpref_keymap(struct wmKeyConfig *UNUSED(keyconf)) } /* add handlers, stuff you only do once or on area/region changes */ -static void userpref_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar) +static void userpref_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { ED_region_header_init(ar); } -static void userpref_header_area_draw(const bContext *C, ARegion *ar) +static void userpref_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } -static void userpref_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn)) +static void userpref_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *UNUSED(ar), wmNotifier *UNUSED(wmn)) { /* context changes */ } @@ -171,9 +171,9 @@ void ED_spacetype_userpref(void) /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region"); art->regionid = RGN_TYPE_WINDOW; - art->init = userpref_main_area_init; - art->draw = userpref_main_area_draw; - art->listener = userpref_main_area_listener; + art->init = userpref_main_region_init; + art->draw = userpref_main_region_draw; + art->listener = userpref_main_region_listener; art->keymapflag = ED_KEYMAP_UI; BLI_addhead(&st->regiontypes, art); @@ -184,8 +184,8 @@ void ED_spacetype_userpref(void) art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; art->listener = userpref_header_listener; - art->init = userpref_header_area_init; - art->draw = userpref_header_area_draw; + art->init = userpref_header_region_init; + art->draw = userpref_header_region_draw; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index f7698b0e9f3..2ff3dcdda29 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -61,6 +61,7 @@ #include "ED_armature.h" #include "ED_keyframes_draw.h" +#include "GPU_basic_shader.h" #include "UI_resources.h" @@ -884,8 +885,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co if (dt == OB_SOLID) { /* set up solid drawing */ - glEnable(GL_COLOR_MATERIAL); - glEnable(GL_LIGHTING); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); gluQuadricDrawStyle(qobj, GLU_FILL); glShadeModel(GL_SMOOTH); @@ -967,8 +967,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co /* restore */ if (dt == OB_SOLID) { glShadeModel(GL_FLAT); - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } glPopMatrix(); @@ -1166,8 +1165,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl /* set up solid drawing */ if (dt > OB_WIRE) { - glEnable(GL_COLOR_MATERIAL); - glEnable(GL_LIGHTING); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); if (armflag & ARM_POSEMODE) set_pchan_glColor(PCHAN_COLOR_SOLID, boneflag, constflag); @@ -1177,8 +1175,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth); /* disable solid drawing */ - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_LIGHTING); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } else { /* wire */ @@ -1297,8 +1294,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag /* set up solid drawing */ if (dt > OB_WIRE) { - glEnable(GL_COLOR_MATERIAL); - glEnable(GL_LIGHTING); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); UI_ThemeColor(TH_BONE_SOLID); } @@ -1352,8 +1348,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag /* disable solid drawing */ if (dt > OB_WIRE) { - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_LIGHTING); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } } @@ -2602,13 +2597,20 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, if (v3d->flag2 & V3D_RENDER_OVERRIDE) return true; - - if (dt > OB_WIRE && !ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { + + if (dt > OB_WIRE) { /* we use color for solid lighting */ - const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, white); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); /* only for lighting... */ + if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) { + const float diffuse[3] = {0.64f, 0.64f, 0.64f}; + const float specular[3] = {0.5f, 0.5f, 0.5f}; + GPU_basic_shader_colors(diffuse, specular, 35, 1.0f); + } + else { + const float diffuse[3] = {1.0f, 1.0f, 1.0f}; + const float specular[3] = {1.0f, 1.0f, 1.0f}; + GPU_basic_shader_colors(diffuse, specular, 35, 1.0f); + glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); /* only for lighting... */ + } } /* arm->flag is being used to detect mode... */ diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index 9fac4ca2265..5c8c1a42389 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -60,9 +60,10 @@ #include "UI_resources.h" -#include "GPU_extensions.h" #include "GPU_draw.h" #include "GPU_material.h" +#include "GPU_basic_shader.h" +#include "GPU_shader.h" #include "RE_engine.h" @@ -179,7 +180,6 @@ void draw_mesh_face_select(RegionView3D *rv3d, Mesh *me, DerivedMesh *dm, bool d data.edge_flags = get_tface_mesh_marked_edge_info(me, draw_select_edges); glEnable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); ED_view3d_polygon_offset(rv3d, 1.0); /* Draw (Hidden) Edges */ @@ -231,10 +231,11 @@ static struct TextureDrawState { int is_lit, is_tex; int color_profile; bool use_backface_culling; + bool two_sided_lighting; unsigned char obcol[4]; bool is_texpaint; bool texpaint_material; /* use material slots for texture painting */ -} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, {0, 0, 0, 0}, false, false}; +} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, false, {0, 0, 0, 0}, false, false}; static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material *ma, struct TextureDrawState gtexdraw) { @@ -370,24 +371,26 @@ static bool set_draw_settings_cached(int clearcache, MTexPoly *texface, Material if (c_badtex) lit = 0; if (lit != c_lit || ma != c_ma) { if (lit) { - float spec[4]; - if (!ma) ma = give_current_material_or_def(NULL, 0); /* default material */ - - spec[0] = ma->spec * ma->specr; - spec[1] = ma->spec * ma->specg; - spec[2] = ma->spec * ma->specb; - spec[3] = 1.0; - - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(ma->har, 0, 128)); - glEnable(GL_LIGHTING); - glEnable(GL_COLOR_MATERIAL); + int options = GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR; + + if (gtexdraw.two_sided_lighting) + options |= GPU_SHADER_TWO_SIDED; + if (c_textured && !c_badtex) + options |= GPU_SHADER_TEXTURE_2D; + + if (!ma) + ma = give_current_material_or_def(NULL, 0); /* default material */ + + float specular[3]; + mul_v3_v3fl(specular, &ma->specr, ma->spec); + + GPU_basic_shader_colors(NULL, specular, ma->har, 0.0f); + GPU_basic_shader_bind(options); } else { - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } + c_lit = lit; c_ma = ma; } @@ -488,12 +491,12 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O Gtexdraw.color_profile = BKE_scene_check_color_management_enabled(scene); Gtexdraw.use_game_mat = (RE_engines_find(scene->r.engine)->flag & RE_GAME) != 0; Gtexdraw.use_backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0; + Gtexdraw.two_sided_lighting = (me->flag & ME_TWOSIDED); memcpy(Gtexdraw.obcol, obcol, sizeof(obcol)); set_draw_settings_cached(1, NULL, NULL, Gtexdraw); glShadeModel(GL_SMOOTH); glCullFace(GL_BACK); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, (me->flag & ME_TWOSIDED) ? GL_TRUE : GL_FALSE); } static void draw_textured_end(void) @@ -526,7 +529,7 @@ static void draw_textured_end(void) glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); /* XXX, bad patch - GPU_default_lights() calls * glLightfv(GL_POSITION, ...) which @@ -815,7 +818,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl) /* TEXFACE */ if (glsl) { - GPU_enable_material(matnr + 1, &gattribs); + GPU_object_material_bind(matnr + 1, &gattribs); for (i = 0; i < gattribs.totlayer; i++) { if (gattribs.layer[i].type == CD_MTFACE) { @@ -967,7 +970,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d } else if (draw_flags & DRAW_FACE_SELECT) { if (ob->mode & OB_MODE_WEIGHT_PAINT) - dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions_facemask, GPU_enable_material, NULL, me, + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions_facemask, GPU_object_material_bind, NULL, me, DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN); else { drawTFace_userData userData; @@ -1016,6 +1019,8 @@ typedef struct TexMatCallback { Object *ob; Mesh *me; DerivedMesh *dm; + bool shadeless; + bool two_sided_lighting; } TexMatCallback; static void tex_mat_set_material_cb(void *UNUSED(userData), int mat_nr, void *attribs) @@ -1024,7 +1029,7 @@ static void tex_mat_set_material_cb(void *UNUSED(userData), int mat_nr, void *at * that the GLSL code will give different result depending on the drawtype, * in texture draw mode it will output the active texture node, in material * draw mode it will show the full material. */ - GPU_enable_material(mat_nr, attribs); + GPU_object_material_bind(mat_nr, attribs); } static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs) @@ -1035,31 +1040,21 @@ static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs) Image *ima; ImageUser *iuser; bNode *node; - int texture_set = 0; /* draw image texture if we find one */ if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node, NULL)) { /* get openl texture */ int mipmap = 1; int bindcode = (ima) ? GPU_verify_image(ima, iuser, 0, 0, mipmap, false) : 0; - float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; if (bindcode) { NodeTexBase *texbase = node->storage; /* disable existing material */ - GPU_disable_material(); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0); + GPU_object_material_unbind(); /* bind texture */ - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glEnable(GL_COLOR_MATERIAL); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, ima->bindcode); - glColor3f(1.0f, 1.0f, 1.0f); glMatrixMode(GL_TEXTURE); glLoadMatrixf(texbase->tex_mapping.mat); @@ -1073,21 +1068,36 @@ static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs) gattribs->layer[0].gltexco = 1; gattribs->totlayer = 1; - texture_set = 1; + /* bind material */ + float diffuse[3] = {1.0f, 1.0f, 1.0f}; + + int options = GPU_SHADER_TEXTURE_2D; + if (!data->shadeless) + options |= GPU_SHADER_LIGHTING; + if (data->two_sided_lighting) + options |= GPU_SHADER_TWO_SIDED; + + GPU_basic_shader_colors(diffuse, NULL, 0, 0.0f); + GPU_basic_shader_bind(options); + + return; } } - if (!texture_set) { + /* disable texture material */ + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + + if (data->shadeless) { + glColor3f(1.0f, 1.0f, 1.0f); + memset(gattribs, 0, sizeof(*gattribs)); + } + else { glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); - /* disable texture */ - glDisable(GL_TEXTURE_2D); - glDisable(GL_COLOR_MATERIAL); - - /* draw single color */ - GPU_enable_material(mat_nr, attribs); + /* enable solid material */ + GPU_object_material_bind(mat_nr, attribs); } } @@ -1138,61 +1148,50 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW); else glFrontFace(GL_CCW); - if ((v3d->flag2 & V3D_SHADELESS_TEX) && - ((v3d->drawtype == OB_TEXTURE) || (ob->mode & OB_MODE_TEXTURE_PAINT))) - { - glColor3f(1.0f, 1.0f, 1.0f); - } - else { - glEnable(GL_LIGHTING); - } - - { - Mesh *me = ob->data; - TexMatCallback data = {scene, ob, me, dm}; - bool (*set_face_cb)(void *, int); - bool glsl, picking = (G.f & G_PICKSEL) != 0; - - /* face hiding callback depending on mode */ - if (ob == scene->obedit) - set_face_cb = tex_mat_set_face_editmesh_cb; - else if (draw_flags & DRAW_FACE_SELECT) - set_face_cb = tex_mat_set_face_mesh_cb; - else - set_face_cb = NULL; - - /* test if we can use glsl */ - glsl = (v3d->drawtype == OB_MATERIAL) && GPU_glsl_support() && !picking; + Mesh *me = ob->data; - GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); + bool shadeless = ((v3d->flag2 & V3D_SHADELESS_TEX) && + ((v3d->drawtype == OB_TEXTURE) || (ob->mode & OB_MODE_TEXTURE_PAINT))); + bool two_sided_lighting = (me->flag & ME_TWOSIDED) != 0; - if (glsl || picking) { - /* draw glsl or solid */ - dm->drawMappedFacesMat(dm, - tex_mat_set_material_cb, - set_face_cb, &data); - } - else { - float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + TexMatCallback data = {scene, ob, me, dm, shadeless, two_sided_lighting}; + bool (*set_face_cb)(void *, int); + bool picking = (G.f & G_PICKSEL) != 0; + + /* face hiding callback depending on mode */ + if (ob == scene->obedit) + set_face_cb = tex_mat_set_face_editmesh_cb; + else if (draw_flags & DRAW_FACE_SELECT) + set_face_cb = tex_mat_set_face_mesh_cb; + else + set_face_cb = NULL; - /* draw textured */ - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, zero); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, zero); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0); + /* test if we can use glsl */ + bool glsl = (v3d->drawtype == OB_MATERIAL) && !picking; - dm->drawMappedFacesMat(dm, - tex_mat_set_texture_cb, - set_face_cb, &data); - } + GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); - GPU_end_object_materials(); + if (glsl || picking) { + /* draw glsl or solid */ + dm->drawMappedFacesMat(dm, + tex_mat_set_material_cb, + set_face_cb, &data); } + else { + /* draw textured */ + dm->drawMappedFacesMat(dm, + tex_mat_set_texture_cb, + set_face_cb, &data); + } + + GPU_end_object_materials(); /* reset opengl state */ - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_TEXTURE_2D); - glDisable(GL_LIGHTING); + GPU_end_object_materials(); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + glBindTexture(GL_TEXTURE_2D, 0); + glFrontFace(GL_CCW); glMatrixMode(GL_TEXTURE); @@ -1209,38 +1208,29 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, /* Vertex Paint and Weight Paint */ static void draw_mesh_paint_light_begin(void) { - const float spec[4] = {0.47f, 0.47f, 0.47f, 0.47f}; - - GPU_enable_material(0, NULL); - - /* but set default spec */ - glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec); - - /* diffuse */ - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glEnable(GL_LIGHTING); - glEnable(GL_COLOR_MATERIAL); + /* get material diffuse color from vertex colors but set default spec */ + const float specular[3] = {0.47f, 0.47f, 0.47f}; + GPU_basic_shader_colors(NULL, specular, 35, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); } + static void draw_mesh_paint_light_end(void) { - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_LIGHTING); - - GPU_disable_material(); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } void draw_mesh_paint_weight_faces(DerivedMesh *dm, const bool use_light, void *facemask_cb, void *user_data) { - DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_enable_material : NULL; + DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_object_material_bind : NULL; + int flags = DM_DRAW_USE_COLORS; if (use_light) { draw_mesh_paint_light_begin(); + flags |= DM_DRAW_NEED_NORMALS; } - dm->drawMappedFaces(dm, (DMSetDrawOptions)facemask_cb, setMaterial, NULL, user_data, - DM_DRAW_USE_COLORS); + dm->drawMappedFaces(dm, (DMSetDrawOptions)facemask_cb, setMaterial, NULL, user_data, flags); if (use_light) { draw_mesh_paint_light_end(); @@ -1251,18 +1241,21 @@ void draw_mesh_paint_vcolor_faces(DerivedMesh *dm, const bool use_light, void *facemask_cb, void *user_data, const Mesh *me) { - DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_enable_material : NULL; + DMSetMaterial setMaterial = GPU_object_materials_check() ? GPU_object_material_bind : NULL; + int flags = 0; if (use_light) { draw_mesh_paint_light_begin(); + flags |= DM_DRAW_NEED_NORMALS; } if (me->mloopcol) { - dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, DM_DRAW_USE_COLORS); + dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, + DM_DRAW_USE_COLORS | flags); } else { glColor3f(1.0f, 1.0f, 1.0f); - dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, 0); + dm->drawMappedFaces(dm, facemask_cb, setMaterial, NULL, user_data, flags); } if (use_light) { diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index c697b22d57b..e03f81742b7 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -87,8 +87,9 @@ #include "BIF_glutil.h" #include "GPU_draw.h" -#include "GPU_extensions.h" #include "GPU_select.h" +#include "GPU_basic_shader.h" +#include "GPU_shader.h" #include "ED_mesh.h" #include "ED_particle.h" @@ -289,8 +290,6 @@ static bool check_ob_drawface_dot(Scene *sce, View3D *vd, char dt) bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt) { - if (!GPU_glsl_support()) - return false; if (G.f & G_PICKSEL) return false; if (!check_object_draw_texture(scene, v3d, dt)) @@ -1694,8 +1693,6 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D v3d->bundle_size / 0.05f / camera_size[2]); if (v3d->drawtype == OB_WIRE) { - glDisable(GL_LIGHTING); - if ((dflag & DRAW_CONSTCOLOR) == 0) { if (selected && (track->flag & TRACK_CUSTOMCOLOR) == 0) { glColor3ubv(ob_wire_col); @@ -1706,8 +1703,6 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D } drawaxes(0.05f, v3d->bundle_drawtype); - - glEnable(GL_LIGHTING); } else if (v3d->drawtype > OB_WIRE) { if (v3d->bundle_drawtype == OB_EMPTY_SPHERE) { @@ -1718,13 +1713,11 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D } glLineWidth(2.0f); - glDisable(GL_LIGHTING); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); draw_bundle_sphere(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glEnable(GL_LIGHTING); glLineWidth(1.0f); } @@ -1736,8 +1729,6 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D draw_bundle_sphere(); } else { - glDisable(GL_LIGHTING); - if ((dflag & DRAW_CONSTCOLOR) == 0) { if (selected) { glColor3ubv(ob_wire_col); @@ -1749,8 +1740,6 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D } drawaxes(0.05f, v3d->bundle_drawtype); - - glEnable(GL_LIGHTING); } } @@ -1778,7 +1767,6 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D MovieReconstructedCamera *camera = reconstruction->cameras; int a = 0; - glDisable(GL_LIGHTING); UI_ThemeColor(TH_CAMERA_PATH); glLineWidth(2.0f); @@ -1789,7 +1777,6 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D glEnd(); glLineWidth(1.0f); - glEnable(GL_LIGHTING); } } } @@ -1813,9 +1800,9 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, if (v3d->flag2 & V3D_RENDER_OVERRIDE) return; - glEnable(GL_LIGHTING); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glEnable(GL_COLOR_MATERIAL); + GPU_basic_shader_colors(NULL, NULL, 0, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); + glShadeModel(GL_SMOOTH); tracking_object = tracking->objects.first; @@ -1828,8 +1815,7 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d, /* restore */ glShadeModel(GL_FLAT); - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_LIGHTING); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); if ((dflag & DRAW_CONSTCOLOR) == 0) { glColor3ubv(ob_wire_col); @@ -2137,7 +2123,6 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base BKE_camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale, asp, shift, &drawsize, vec); - glDisable(GL_LIGHTING); glDisable(GL_CULL_FACE); /* camera frame */ @@ -3799,16 +3784,16 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, /* use the cageDM since it always overlaps the editmesh faces */ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); cageDM->drawMappedFaces(cageDM, draw_em_fancy__setFaceOpts, - GPU_enable_material, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN); + GPU_object_material_bind, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN | DM_DRAW_NEED_NORMALS); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } else if (check_object_draw_texture(scene, v3d, dt)) { if (draw_glsl_material(scene, ob, v3d, dt)) { glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); - finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material, + finalDM->drawMappedFacesGLSL(finalDM, GPU_object_material_bind, draw_em_fancy__setGLSLFaceOpts, em); - GPU_disable_material(); + GPU_object_material_unbind(); glFrontFace(GL_CCW); } @@ -3817,17 +3802,12 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, } } else { - /* 3 floats for position, - * 3 for normal and times two because the faces may actually be quads instead of triangles */ - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, (me->flag & ME_TWOSIDED) ? GL_TRUE : GL_FALSE); - - glEnable(GL_LIGHTING); glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); - finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN); + finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_object_material_bind, NULL, me->edit_btmesh, DM_DRAW_SKIP_HIDDEN | DM_DRAW_NEED_NORMALS); glFrontFace(GL_CCW); - glDisable(GL_LIGHTING); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); + + GPU_object_material_unbind(); } /* Setup for drawing wire over, disable zbuffer @@ -3987,7 +3967,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, if (dt > OB_WIRE) { glDepthMask(1); ED_view3d_polygon_offset(rv3d, 0.0); - GPU_disable_material(); + GPU_object_material_unbind(); } #if 0 /* currently not needed */ else if (use_occlude_wire) { @@ -4006,13 +3986,13 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm) glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); glDepthMask(0); - /* if transparent, we cannot draw the edges for solid select... edges have no material info. - * drawFacesSolid() doesn't draw the transparent faces */ + /* if transparent, we cannot draw the edges for solid select... edges + * have no material info. GPU_object_material_visible will skip the + * transparent faces */ if (ob->dtx & OB_DRAWTRANSP) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material); + dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_visible); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - GPU_disable_material(); } else { dm->drawEdges(dm, 0, 1); @@ -4122,18 +4102,18 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D } } - GPU_enable_material(1, &gattribs); + GPU_object_material_bind(1, &gattribs); dm->drawFacesSolid(dm, fpl, fast, NULL); draw_loose = false; } else - dm->drawFacesGLSL(dm, GPU_enable_material); + dm->drawFacesGLSL(dm, GPU_object_material_bind); #if 0 /* XXX */ if (BKE_bproperty_object_get(ob, "Text")) draw_mesh_text(ob, 1); #endif - GPU_disable_material(); + GPU_object_material_unbind(); glFrontFace(GL_CCW); @@ -4157,10 +4137,11 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D if (draw_flags & DRAW_MODIFIERS_PREVIEW) { /* for object selection draws no shade */ if (dflag & (DRAW_PICKING | DRAW_CONSTCOLOR)) { - dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material); + dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); + GPU_object_material_unbind(); } else { - const float spec[4] = {0.47f, 0.47f, 0.47f, 0.47f}; + const float specular[3] = {0.47f, 0.47f, 0.47f}; /* draw outline */ if ((v3d->flag & V3D_SELECT_OUTLINE) && @@ -4175,21 +4156,13 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D /* materials arent compatible with vertex colors */ GPU_end_object_materials(); - GPU_enable_material(0, NULL); - - /* set default spec */ - glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec); - /* diffuse */ - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glEnable(GL_LIGHTING); - glEnable(GL_COLOR_MATERIAL); + /* set default specular */ + GPU_basic_shader_colors(NULL, specular, 35, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); - dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS); - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_LIGHTING); + dm->drawMappedFaces(dm, NULL, NULL, NULL, NULL, DM_DRAW_USE_COLORS | DM_DRAW_NEED_NORMALS); - GPU_disable_material(); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } } else { @@ -4204,9 +4177,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D draw_mesh_object_outline(v3d, ob, dm); } - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, (me->flag & ME_TWOSIDED) ? GL_TRUE : GL_FALSE); - - glEnable(GL_LIGHTING); glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); if (ob->sculpt && (p = BKE_paint_get_active(scene))) { @@ -4222,17 +4192,14 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D } } - dm->drawFacesSolid(dm, fpl, fast, GPU_enable_material); + dm->drawFacesSolid(dm, fpl, fast, GPU_object_material_bind); } else - dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material); - - GPU_disable_material(); + dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); glFrontFace(GL_CCW); - glDisable(GL_LIGHTING); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); + GPU_object_material_unbind(); if (!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { if ((dflag & DRAW_CONSTCOLOR) == 0) { @@ -4536,7 +4503,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, if (lb == NULL) return; - glEnable(GL_LIGHTING); glEnableClientState(GL_VERTEX_ARRAY); if (ob->type == OB_MBALL) { /* mball always smooth shaded */ @@ -4553,8 +4519,6 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, if (ob->type == OB_SURF) { int nr; - glDisable(GL_LIGHTING); - if ((dflag & DRAW_CONSTCOLOR) == 0) glColor3ubv(ob_wire_col); @@ -4565,16 +4529,12 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, for (nr = dl->nr; nr; nr--, data += 3) glVertex3fv(data); glEnd(); - - glEnable(GL_LIGHTING); } break; case DL_POLY: if (ob->type == OB_SURF) { int nr; - glDisable(GL_LIGHTING); - /* for some reason glDrawArrays crashes here in half of the platforms (not osx) */ //glVertexPointer(3, GL_FLOAT, 0, dl->verts); //glDrawArrays(GL_LINE_LOOP, 0, dl->nr); @@ -4583,14 +4543,12 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, for (nr = dl->nr; nr; nr--, data += 3) glVertex3fv(data); glEnd(); - - glEnable(GL_LIGHTING); } break; case DL_SURF: if (dl->index) { - GPU_enable_material(dl->col + 1, (use_glsl) ? &gattribs : NULL); + GPU_object_material_bind(dl->col + 1, (use_glsl) ? &gattribs : NULL); if (dl->rt & CU_SMOOTH) glShadeModel(GL_SMOOTH); else glShadeModel(GL_FLAT); @@ -4604,7 +4562,7 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, break; case DL_INDEX3: - GPU_enable_material(dl->col + 1, (use_glsl) ? &gattribs : NULL); + GPU_object_material_bind(dl->col + 1, (use_glsl) ? &gattribs : NULL); glVertexPointer(3, GL_FLOAT, 0, dl->verts); @@ -4624,7 +4582,7 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, break; case DL_INDEX4: - GPU_enable_material(dl->col + 1, (use_glsl) ? &gattribs : NULL); + GPU_object_material_bind(dl->col + 1, (use_glsl) ? &gattribs : NULL); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, 0, dl->verts); @@ -4639,8 +4597,9 @@ static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag, glDisableClientState(GL_VERTEX_ARRAY); glShadeModel(GL_FLAT); - glDisable(GL_LIGHTING); glFrontFace(GL_CCW); + + GPU_object_material_unbind(); } static void drawCurveDMWired(Object *ob) @@ -4667,13 +4626,10 @@ static bool drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, int glsl = draw_glsl_material(scene, ob, v3d, dt); GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); - if (!glsl) { - glEnable(GL_LIGHTING); - dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material); - glDisable(GL_LIGHTING); - } + if (!glsl) + dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); else - dm->drawFacesGLSL(dm, GPU_enable_material); + dm->drawFacesGLSL(dm, GPU_object_material_bind); GPU_end_object_materials(); } @@ -5505,19 +5461,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv glEnableClientState(GL_COLOR_ARRAY); } - glEnable(GL_LIGHTING); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glEnable(GL_COLOR_MATERIAL); - } -#if 0 - else { - glDisableClientState(GL_NORMAL_ARRAY); - - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_LIGHTING); - UI_ThemeColor(TH_WIRE); + // XXX test + GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); } -#endif if (totchild && (part->draw & PART_DRAW_PARENT) == 0) totpart = 0; @@ -5548,8 +5495,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if (part->draw & PART_DRAW_GUIDE_HAIRS) { DerivedMesh *hair_dm = psys->hair_out_dm; - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); @@ -5593,8 +5538,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv glEnd(); } - glEnable(GL_LIGHTING); - glEnable(GL_COLOR_MATERIAL); glEnableClientState(GL_NORMAL_ARRAY); if ((dflag & DRAW_CONSTCOLOR) == 0) if (part->draw_col == PART_DRAW_COL_MAT) @@ -5609,8 +5552,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv int *res = clmd->hair_grid_res; int i; - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); @@ -5665,8 +5606,6 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv glEnd(); glDisable(GL_BLEND); - glEnable(GL_LIGHTING); - glEnable(GL_COLOR_MATERIAL); glEnableClientState(GL_NORMAL_ARRAY); if ((dflag & DRAW_CONSTCOLOR) == 0) if (part->draw_col == PART_DRAW_COL_MAT) @@ -5697,7 +5636,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if (1) { //ob_dt > OB_WIRE) { if (part->draw_col == PART_DRAW_COL_MAT) glDisableClientState(GL_COLOR_ARRAY); - glDisable(GL_COLOR_MATERIAL); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } if (cdata2) { @@ -5758,11 +5697,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv if (pdd->ndata && ob_dt > OB_WIRE) { glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, 0, pdd->ndata); - glEnable(GL_LIGHTING); - } - else { - glDisableClientState(GL_NORMAL_ARRAY); - glDisable(GL_LIGHTING); + GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); } if ((dflag & DRAW_CONSTCOLOR) == 0) { @@ -5794,7 +5730,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv /* 7. */ - glDisable(GL_LIGHTING); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); @@ -5869,14 +5805,10 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glEnable(GL_COLOR_MATERIAL); glShadeModel(GL_SMOOTH); - if (pset->brushtype == PE_BRUSH_WEIGHT) { + if (pset->brushtype == PE_BRUSH_WEIGHT) glLineWidth(2.0f); - glDisable(GL_LIGHTING); - } cache = edit->pathcache; for (i = 0, point = edit->points; i < totpoint; i++, point++) { @@ -5989,8 +5921,6 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) } glDisable(GL_BLEND); - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); @@ -7939,11 +7869,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short draw_bounding_volume(ob, ob->boundtype); } else { - if (dt > OB_WIRE) - GPU_enable_material(0, NULL); /* we use default material */ empty_object = draw_armature(scene, v3d, ar, base, dt, dflag, ob_wire_col, false); - if (dt > OB_WIRE) - GPU_disable_material(); } } break; @@ -8113,13 +8039,13 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if (!sds->wt || !(sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { sds->tex = NULL; GPU_create_smoke(smd, 0); - draw_smoke_volume(sds, ob, p0, p1, sds->res, viewnormal); + draw_smoke_volume(sds, ob, p0, p1, viewnormal); GPU_free_smoke(smd); } else if (sds->wt && (sds->viewsettings & MOD_SMOKE_VIEW_SHOWBIG)) { sds->tex = NULL; GPU_create_smoke(smd, 1); - draw_smoke_volume(sds, ob, p0, p1, sds->res_wt, viewnormal); + draw_smoke_volume(sds, ob, p0, p1, viewnormal); GPU_free_smoke(smd); } @@ -8542,7 +8468,7 @@ static void bbs_mesh_solid_verts(Scene *scene, Object *ob) DM_update_materials(dm, ob); - dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_enable_material, NULL, me, DM_DRAW_SKIP_HIDDEN); + dm->drawMappedFaces(dm, bbs_mesh_solid_hide2__setDrawOpts, GPU_object_material_bind, NULL, me, DM_DRAW_SKIP_HIDDEN); bbs_obmode_mesh_verts(ob, dm, 1); bm_vertoffs = me->totvert + 1; @@ -8668,23 +8594,17 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r glsl = draw_glsl_material(scene, ob, v3d, dt); GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); } - else { - glEnable(GL_COLOR_MATERIAL); - UI_ThemeColor(TH_BONE_SOLID); - glDisable(GL_COLOR_MATERIAL); - } glFrontFace((ob->transflag & OB_NEG_SCALE) ? GL_CW : GL_CCW); - glEnable(GL_LIGHTING); if (dm) { - dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material); + dm->drawFacesSolid(dm, NULL, 0, GPU_object_material_bind); GPU_end_object_materials(); } else if (edm) - edm->drawMappedFaces(edm, NULL, GPU_enable_material, NULL, NULL, 0); - - glDisable(GL_LIGHTING); + edm->drawMappedFaces(edm, NULL, GPU_object_material_bind, NULL, NULL, DM_DRAW_NEED_NORMALS); + + GPU_object_material_unbind(); } if (edm) edm->release(edm); diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index 7f102bccff1..102bfc55a2c 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -46,7 +46,8 @@ #include "BIF_gl.h" -#include "GPU_extensions.h" +#include "GPU_shader.h" +#include "GPU_texture.h" #include "view3d_intern.h" // own include @@ -135,9 +136,9 @@ static GPUTexture *create_flame_spectrum_texture(void) void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, const float min[3], const float max[3], - const int res[3], const float viewnormal[3]) + const float viewnormal[3]) { - GPUTexture *tex_spec; + GPUTexture *tex_spec = NULL; GPUProgram *smoke_program; const int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED : GPU_PROGRAM_SMOKE; @@ -152,7 +153,6 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, float d /*, d0 */ /* UNUSED */, dd, ds; float (*points)[3] = NULL; int numpoints = 0; - float cor[3] = {1.0f, 1.0f, 1.0f}; int gl_depth = 0, gl_blend = 0; const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) != 0; @@ -171,6 +171,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, }; const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] }; + const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] }; /* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */ const float edges[12][2][3] = { @@ -257,16 +258,6 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, GPU_texture_bind(tex_spec, 3); } - if (!GPU_non_power_of_two_support()) { - cor[0] = (float)res[0] / (float)power_of_2_max_u(res[0]); - cor[1] = (float)res[1] / (float)power_of_2_max_u(res[1]); - cor[2] = (float)res[2] / (float)power_of_2_max_u(res[2]); - } - - cor[0] /= size[0]; - cor[1] /= size[1]; - cor[2] /= size[2]; - /* our slices are defined by the plane equation a*x + b*y +c*z + d = 0 * (a,b,c), the plane normal, are given by viewdir * d is the parameter along the view direction. the first d is given by @@ -318,9 +309,9 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); for (i = 0; i < numpoints; i++) { - glTexCoord3d((points[i][0] - min[0]) * cor[0], - (points[i][1] - min[1]) * cor[1], - (points[i][2] - min[2]) * cor[2]); + glTexCoord3d((points[i][0] - min[0]) * invsize[0], + (points[i][1] - min[1]) * invsize[1], + (points[i][2] - min[2]) * invsize[2]); glVertex3f(points[i][0] * ob_sizei[0], points[i][1] * ob_sizei[1], points[i][2] * ob_sizei[2]); @@ -334,9 +325,9 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0); glBegin(GL_POLYGON); for (i = 0; i < numpoints; i++) { - glTexCoord3d((points[i][0] - min[0]) * cor[0], - (points[i][1] - min[1]) * cor[1], - (points[i][2] - min[2]) * cor[2]); + glTexCoord3d((points[i][0] - min[0]) * invsize[0], + (points[i][1] - min[1]) * invsize[1], + (points[i][2] - min[2]) * invsize[2]); glVertex3f(points[i][0] * ob_sizei[0], points[i][1] * ob_sizei[1], points[i][2] * ob_sizei[2]); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index e276a46fd71..fa14ca96fe2 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -54,9 +54,9 @@ #include "ED_space_api.h" #include "ED_screen.h" -#include "GPU_extensions.h" -#include "GPU_material.h" #include "GPU_compositing.h" +#include "GPU_framebuffer.h" +#include "GPU_material.h" #include "BIF_gl.h" @@ -342,7 +342,7 @@ static SpaceLink *view3d_new(const bContext *C) v3d->twflag |= U.tw_flag & V3D_USE_MANIPULATOR; v3d->twtype = V3D_MANIP_TRANSLATE; - v3d->around = V3D_CENTROID; + v3d->around = V3D_AROUND_CENTER_MEAN; v3d->bundle_size = 0.2f; v3d->bundle_drawtype = OB_PLAINAXES; @@ -384,8 +384,8 @@ static SpaceLink *view3d_new(const bContext *C) ar->alignment = RGN_ALIGN_RIGHT; ar->flag = RGN_FLAG_HIDDEN; - /* main area */ - ar = MEM_callocN(sizeof(ARegion), "main area for view3d"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for view3d"); BLI_addtail(&v3d->regionbase, ar); ar->regiontype = RGN_TYPE_WINDOW; @@ -482,7 +482,7 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) } /* add handlers, stuff you only do once or on area/region changes */ -static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar) +static void view3d_main_region_init(wmWindowManager *wm, ARegion *ar) { ListBase *lb; wmKeyMap *keymap; @@ -567,7 +567,7 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar) } -static void view3d_main_area_exit(wmWindowManager *wm, ARegion *ar) +static void view3d_main_region_exit(wmWindowManager *wm, ARegion *ar) { RegionView3D *rv3d = ar->regiondata; @@ -715,7 +715,7 @@ static void view3d_dropboxes(void) /* type callback, not region itself */ -static void view3d_main_area_free(ARegion *ar) +static void view3d_main_region_free(ARegion *ar) { RegionView3D *rv3d = ar->regiondata; @@ -746,7 +746,7 @@ static void view3d_main_area_free(ARegion *ar) } /* copy regiondata */ -static void *view3d_main_area_duplicate(void *poin) +static void *view3d_main_region_duplicate(void *poin) { if (poin) { RegionView3D *rv3d = poin, *new; @@ -799,7 +799,7 @@ static void view3d_recalc_used_layers(ARegion *ar, wmNotifier *wmn, Scene *scene } } -static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *wmn) +static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *wmn) { Scene *scene = sc->scene; View3D *v3d = sa->spacedata.first; @@ -1025,7 +1025,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN } /* concept is to retrieve cursor type context-less */ -static void view3d_main_area_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar)) +static void view3d_main_region_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar)) { Scene *scene = win->screen->scene; @@ -1038,7 +1038,7 @@ static void view3d_main_area_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion } /* add handlers, stuff you only do once or on area/region changes */ -static void view3d_header_area_init(wmWindowManager *wm, ARegion *ar) +static void view3d_header_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap = WM_keymap_find(wm->defaultconf, "3D View Generic", SPACE_VIEW3D, 0); @@ -1047,12 +1047,12 @@ static void view3d_header_area_init(wmWindowManager *wm, ARegion *ar) ED_region_header_init(ar); } -static void view3d_header_area_draw(const bContext *C, ARegion *ar) +static void view3d_header_region_draw(const bContext *C, ARegion *ar) { ED_region_header(C, ar); } -static void view3d_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void view3d_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -1083,7 +1083,7 @@ static void view3d_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa) } /* add handlers, stuff you only do once or on area/region changes */ -static void view3d_buttons_area_init(wmWindowManager *wm, ARegion *ar) +static void view3d_buttons_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -1093,12 +1093,12 @@ static void view3d_buttons_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void view3d_buttons_area_draw(const bContext *C, ARegion *ar) +static void view3d_buttons_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, NULL, -1, true); } -static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void view3d_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -1189,7 +1189,7 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa } /* add handlers, stuff you only do once or on area/region changes */ -static void view3d_tools_area_init(wmWindowManager *wm, ARegion *ar) +static void view3d_tools_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; @@ -1199,12 +1199,12 @@ static void view3d_tools_area_init(wmWindowManager *wm, ARegion *ar) WM_event_add_keymap_handler(&ar->handlers, keymap); } -static void view3d_tools_area_draw(const bContext *C, ARegion *ar) +static void view3d_tools_region_draw(const bContext *C, ARegion *ar) { ED_region_panels(C, ar, CTX_data_mode_string(C), -1, true); } -static void view3d_props_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) +static void view3d_props_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn) { /* context changes */ switch (wmn->category) { @@ -1223,7 +1223,7 @@ static void view3d_props_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), } } -/*area (not region) level listener*/ +/* area (not region) level listener */ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNotifier *wmn) { View3D *v3d = sa->spacedata.first; @@ -1424,13 +1424,13 @@ void ED_spacetype_view3d(void) art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region"); art->regionid = RGN_TYPE_WINDOW; art->keymapflag = ED_KEYMAP_GPENCIL; - art->draw = view3d_main_area_draw; - art->init = view3d_main_area_init; - art->exit = view3d_main_area_exit; - art->free = view3d_main_area_free; - art->duplicate = view3d_main_area_duplicate; - art->listener = view3d_main_area_listener; - art->cursor = view3d_main_area_cursor; + art->draw = view3d_main_region_draw; + art->init = view3d_main_region_init; + art->exit = view3d_main_region_exit; + art->free = view3d_main_region_free; + art->duplicate = view3d_main_region_duplicate; + art->listener = view3d_main_region_listener; + art->cursor = view3d_main_region_cursor; art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */ BLI_addhead(&st->regiontypes, art); @@ -1439,9 +1439,9 @@ void ED_spacetype_view3d(void) art->regionid = RGN_TYPE_UI; art->prefsizex = 180; /* XXX */ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; - art->listener = view3d_buttons_area_listener; - art->init = view3d_buttons_area_init; - art->draw = view3d_buttons_area_draw; + art->listener = view3d_buttons_region_listener; + art->init = view3d_buttons_region_init; + art->draw = view3d_buttons_region_draw; BLI_addhead(&st->regiontypes, art); view3d_buttons_register(art); @@ -1452,9 +1452,9 @@ void ED_spacetype_view3d(void) art->prefsizex = 160; /* XXX */ art->prefsizey = 50; /* XXX */ art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; - art->listener = view3d_buttons_area_listener; - art->init = view3d_tools_area_init; - art->draw = view3d_tools_area_draw; + art->listener = view3d_buttons_region_listener; + art->init = view3d_tools_region_init; + art->draw = view3d_tools_region_draw; BLI_addhead(&st->regiontypes, art); #if 0 @@ -1468,9 +1468,9 @@ void ED_spacetype_view3d(void) art->prefsizex = 0; art->prefsizey = 120; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; - art->listener = view3d_props_area_listener; - art->init = view3d_tools_area_init; - art->draw = view3d_tools_area_draw; + art->listener = view3d_props_region_listener; + art->init = view3d_tools_region_init; + art->draw = view3d_tools_region_draw; BLI_addhead(&st->regiontypes, art); view3d_tool_props_register(art); @@ -1481,9 +1481,9 @@ void ED_spacetype_view3d(void) art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - art->listener = view3d_header_area_listener; - art->init = view3d_header_area_init; - art->draw = view3d_header_area_draw; + art->listener = view3d_header_region_listener; + art->init = view3d_header_region_init; + art->draw = view3d_header_region_draw; BLI_addhead(&st->regiontypes, art); BKE_spacetype_register(st); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index dc0047db962..e7223ddf065 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -96,8 +96,8 @@ #include "UI_resources.h" #include "GPU_draw.h" +#include "GPU_framebuffer.h" #include "GPU_material.h" -#include "GPU_extensions.h" #include "GPU_compositing.h" #include "view3d_intern.h" /* own include */ @@ -2225,7 +2225,7 @@ void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect) { int x, y, w, h; rcti r; - /* clamp rect by area */ + /* clamp rect by region */ r.xmin = 0; r.xmax = ar->winx - 1; @@ -2705,7 +2705,7 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view } /** - * Shared by #ED_view3d_draw_offscreen and #view3d_main_area_draw_objects + * Shared by #ED_view3d_draw_offscreen and #view3d_main_region_draw_objects * * \note \a C and \a grid_unit will be NULL when \a draw_offscreen is set. * \note Drawing lamps and opengl render uses this, so dont do grease pencil or view widgets here. @@ -2906,7 +2906,7 @@ static void view3d_draw_objects( } } -static void view3d_main_area_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) +static void view3d_main_region_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) { RegionView3D *rv3d = ar->regiondata; @@ -2970,20 +2970,19 @@ void ED_view3d_draw_offscreen_init(Scene *scene, View3D *v3d) /* * Function to clear the view */ -static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar) +static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) { if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) { - bool glsl = GPU_glsl_support() && BKE_scene_use_new_shading_nodes(scene) && scene->world->nodetree && scene->world->use_nodes; + bool glsl = BKE_scene_use_new_shading_nodes(scene) && scene->world->nodetree && scene->world->use_nodes; if (glsl) { RegionView3D *rv3d = ar->regiondata; GPUMaterial *gpumat = GPU_material_world(scene, scene->world); - bool material_not_bound; /* calculate full shader for background */ GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0)); - material_not_bound = !GPU_material_bound(gpumat); + bool material_not_bound = !GPU_material_bound(gpumat); if (material_not_bound) { glMatrixMode(GL_PROJECTION); @@ -3027,7 +3026,7 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar) #define VIEWGRAD_RES_Y 16 GLubyte grid_col[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][4]; - static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3]; + static float grid_pos[VIEWGRAD_RES_X][VIEWGRAD_RES_Y][3]; static GLushort indices[VIEWGRAD_RES_X - 1][VIEWGRAD_RES_X - 1][4]; static bool buf_calculated = false; @@ -3228,7 +3227,7 @@ void ED_view3d_draw_offscreen( if ((viewname != NULL && viewname[0] != '\0') && (viewmat == NULL) && rv3d->persp == RV3D_CAMOB && v3d->camera) view3d_stereo3d_setup_offscreen(scene, v3d, ar, winmat, viewname); else - view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat); + view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); /* framebuffer fx needed, we need to draw offscreen first */ if (v3d->fx_settings.fx_flag && fx) { @@ -3247,7 +3246,7 @@ void ED_view3d_draw_offscreen( /* clear opengl buffers */ if (do_sky) { - view3d_main_area_clear(scene, v3d, ar); + view3d_main_region_clear(scene, v3d, ar); } else { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -3314,9 +3313,6 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( float winmat[4][4]; if (own_ofs) { - /* state changes make normal drawing go weird otherwise */ - glPushAttrib(GL_LIGHTING_BIT); - /* bind */ ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out); if (ofs == NULL) { @@ -3581,7 +3577,7 @@ void ED_scene_draw_fps(Scene *scene, const rcti *rect) #endif } -static bool view3d_main_area_do_render_draw(Scene *scene) +static bool view3d_main_region_do_render_draw(Scene *scene) { RenderEngineType *type = RE_engines_find(scene->r.engine); @@ -3595,7 +3591,7 @@ bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti * bool use_border; /* test if there is a 3d view rendering */ - if (v3d->drawtype != OB_RENDER || !view3d_main_area_do_render_draw(scene)) + if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene)) return false; /* test if there is a border render */ @@ -3629,7 +3625,7 @@ bool ED_view3d_calc_render_border(Scene *scene, View3D *v3d, ARegion *ar, rcti * return true; } -static bool view3d_main_area_draw_engine(const bContext *C, Scene *scene, +static bool view3d_main_region_draw_engine(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, bool clip_border, const rcti *border_rect) { @@ -3657,7 +3653,7 @@ static bool view3d_main_area_draw_engine(const bContext *C, Scene *scene, } /* setup view matrices */ - view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL); + view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); /* background draw */ ED_region_pixelspace(ar); @@ -3697,7 +3693,7 @@ static bool view3d_main_area_draw_engine(const bContext *C, Scene *scene, return true; } -static void view3d_main_area_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border) +static void view3d_main_region_draw_engine_info(View3D *v3d, RegionView3D *rv3d, ARegion *ar, bool render_border) { float fill_color[4] = {0.0f, 0.0f, 0.0f, 0.25f}; @@ -3706,7 +3702,7 @@ static void view3d_main_area_draw_engine_info(View3D *v3d, RegionView3D *rv3d, A if (render_border) { /* draw darkened background color. no alpha because border render does - * partial redraw and will not redraw the area behind this info bar */ + * partial redraw and will not redraw the region behind this info bar */ float alpha = 1.0f - fill_color[3]; Camera *camera = ED_view3d_camera_data_get(v3d, rv3d); @@ -3753,7 +3749,7 @@ static bool view3d_stereo3d_active(const bContext *C, Scene *scene, View3D *v3d, * we have no winmatrix (i.e., projection matrix) defined at that time. * Since the camera and the camera shift are needed for the winmat calculation * we do a small hack to replace it temporarily so we don't need to change the - * view3d)main_area_setup_view() code to account for that. + * view3d)main_region_setup_view() code to account for that. */ static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar) { @@ -3781,7 +3777,7 @@ static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar) data->shiftx = BKE_camera_multiview_shift_x(&scene->r, v3d->camera, viewname); BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); - view3d_main_area_setup_view(scene, v3d, ar, viewmat, NULL); + view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL); data->shiftx = shiftx; BLI_unlock_thread(LOCK_VIEW3D); @@ -3795,7 +3791,7 @@ static void view3d_stereo3d_setup(Scene *scene, View3D *v3d, ARegion *ar) v3d->camera = camera; BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); - view3d_main_area_setup_view(scene, v3d, ar, viewmat, NULL); + view3d_main_region_setup_view(scene, v3d, ar, viewmat, NULL); v3d->camera = view_ob; BLI_unlock_thread(LOCK_VIEW3D); @@ -3811,14 +3807,14 @@ static void view3d_stereo3d_setup_offscreen(Scene *scene, View3D *v3d, ARegion * const bool is_left = STREQ(viewname, STEREO_LEFT_NAME); BKE_camera_multiview_view_matrix(&scene->r, v3d->camera, is_left, viewmat); - view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat); + view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); } else { /* SCE_VIEWS_FORMAT_MULTIVIEW */ float viewmat[4][4]; Object *camera = BKE_camera_multiview_render(scene, v3d->camera, viewname); BKE_camera_multiview_view_matrix(&scene->r, camera, false, viewmat); - view3d_main_area_setup_view(scene, v3d, ar, viewmat, winmat); + view3d_main_region_setup_view(scene, v3d, ar, viewmat, winmat); } } @@ -3836,7 +3832,7 @@ static void update_lods(Scene *scene, float camera_pos[3]) } #endif -static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3D *v3d, +static void view3d_main_region_draw_objects(const bContext *C, Scene *scene, View3D *v3d, ARegion *ar, const char **grid_unit) { RegionView3D *rv3d = ar->regiondata; @@ -3859,7 +3855,7 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3 if (view3d_stereo3d_active(C, scene, v3d, rv3d)) view3d_stereo3d_setup(scene, v3d, ar); else - view3d_main_area_setup_view(scene, v3d, ar, NULL, NULL); + view3d_main_region_setup_view(scene, v3d, ar, NULL, NULL); rv3d->rflag &= ~RV3D_IS_GAME_ENGINE; #ifdef WITH_GAMEENGINE @@ -3889,7 +3885,7 @@ static void view3d_main_area_draw_objects(const bContext *C, Scene *scene, View3 } /* clear the background */ - view3d_main_area_clear(scene, v3d, ar); + view3d_main_region_clear(scene, v3d, ar); /* enables anti-aliasing for 3D view drawing */ if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) { @@ -3956,7 +3952,7 @@ static bool is_cursor_visible(Scene *scene) return true; } -static void view3d_main_area_draw_info(const bContext *C, Scene *scene, +static void view3d_main_region_draw_info(const bContext *C, Scene *scene, ARegion *ar, View3D *v3d, const char *grid_unit, bool render_border) { @@ -4006,7 +4002,7 @@ static void view3d_main_area_draw_info(const bContext *C, Scene *scene, } if (rv3d->render_engine) { - view3d_main_area_draw_engine_info(v3d, rv3d, ar, render_border); + view3d_main_region_draw_engine_info(v3d, rv3d, ar, render_border); return; } @@ -4033,7 +4029,7 @@ static void view3d_main_area_draw_info(const bContext *C, Scene *scene, } } -void view3d_main_area_draw(const bContext *C, ARegion *ar) +void view3d_main_region_draw(const bContext *C, ARegion *ar) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); @@ -4047,8 +4043,8 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar) clip_border = (render_border && !BLI_rcti_compare(&ar->drawrct, &border_rect)); /* draw viewport using opengl */ - if (v3d->drawtype != OB_RENDER || !view3d_main_area_do_render_draw(scene) || clip_border) { - view3d_main_area_draw_objects(C, scene, v3d, ar, &grid_unit); + if (v3d->drawtype != OB_RENDER || !view3d_main_region_do_render_draw(scene) || clip_border) { + view3d_main_region_draw_objects(C, scene, v3d, ar, &grid_unit); #ifdef DEBUG_DRAW bl_debug_draw(); @@ -4061,9 +4057,9 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar) /* draw viewport using external renderer */ if (v3d->drawtype == OB_RENDER) - view3d_main_area_draw_engine(C, scene, ar, v3d, clip_border, &border_rect); + view3d_main_region_draw_engine(C, scene, ar, v3d, clip_border, &border_rect); - view3d_main_area_draw_info(C, scene, ar, v3d, grid_unit, render_border); + view3d_main_region_draw_info(C, scene, ar, v3d, grid_unit, render_border); v3d->flag |= V3D_INVALID_BACKBUF; } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 7458d819213..b09cbedb6fa 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -700,7 +700,7 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3]) } else { /* If there's no selection, lastofs is unmodified and last value since static */ - is_set = calculateTransformCenter(C, V3D_CENTROID, lastofs, NULL); + is_set = calculateTransformCenter(C, V3D_AROUND_CENTER_MEAN, lastofs, NULL); } copy_v3_v3(r_dyn_ofs, lastofs); @@ -3757,7 +3757,7 @@ static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar, float twmat[3][3]; /* same as transform manipulator when normal is set */ - ED_getTransformOrientationMatrix(C, twmat, V3D_ACTIVE); + ED_getTransformOrientationMatrix(C, twmat, V3D_AROUND_ACTIVE); mat3_to_quat(obact_quat, twmat); invert_qt_normalized(obact_quat); @@ -5168,10 +5168,11 @@ bool ED_view3d_snap_from_ray( /* try snap edge, then face if it fails */ ret = snapObjectsRayEx( - scene, NULL, NULL, NULL, obedit, SCE_SNAP_MODE_FACE, - NULL, NULL, + scene, NULL, NULL, NULL, obedit, + NULL, SNAP_ALL, SCE_SNAP_MODE_FACE, ray_start, ray_normal, &ray_dist, - NULL, NULL, r_co, r_no_dummy, SNAP_ALL); + r_co, r_no_dummy, NULL, NULL, + NULL, NULL); return ret; } @@ -5216,8 +5217,10 @@ bool ED_view3d_snap_from_region( ray_dist = TRANSFORM_DIST_MAX_RAY; } if (snapObjectsEx( - scene, NULL, v3d, ar, obedit, elem_type[i], - mval, &dist_px, r_co, r_no_ptr, &ray_dist, SNAP_ALL)) + scene, v3d, ar, NULL, obedit, + mval, SNAP_ALL, elem_type[i], + &ray_dist, + r_co, r_no_ptr, &dist_px)) { is_hit = true; } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 94c1db8aa5d..2c6d76240d9 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -180,7 +180,7 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d, void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar); /* view3d_draw.c */ -void view3d_main_area_draw(const struct bContext *C, struct ARegion *ar); +void view3d_main_region_draw(const struct bContext *C, struct ARegion *ar); void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride); void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d); void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag); @@ -274,7 +274,7 @@ extern const char *view3d_context_dir[]; /* doc access */ /* draw_volume.c */ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob, const float min[3], const float max[3], - const int res[3], const float viewnormal[3]); + const float viewnormal[3]); //#define SMOKE_DEBUG_VELOCITY //#define SMOKE_DEBUG_HEAT diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 3c0987221bd..0a465c751d2 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -784,7 +784,7 @@ static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], sh EDBM_backbuf_free(); - paintface_flush_flags(ob); + paintface_flush_flags(ob, SELECT); } #if 0 @@ -2462,7 +2462,7 @@ static void paint_facesel_circle_select(ViewContext *vc, const bool select, cons if (bbsel) { edbm_backbuf_check_and_select_tfaces(me, select); EDBM_backbuf_free(); - paintface_flush_flags(ob); + paintface_flush_flags(ob, SELECT); } } diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 8bb84d00c83..e8e7d3c62fb 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -223,7 +223,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) cursor_global = ED_view3d_cursor3d_get(scene, v3d); if (use_offset) { - if ((v3d && v3d->around == V3D_ACTIVE) && + if ((v3d && v3d->around == V3D_AROUND_ACTIVE) && snap_calc_active_center(C, true, center_global)) { /* pass */ @@ -543,7 +543,7 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) minmax_v3v3_v3(min, max, vec); } - if (v3d->around == V3D_CENTROID) { + if (v3d->around == V3D_AROUND_CENTER_MEAN) { mul_v3_fl(centroid, 1.0f / (float)tvs.transverts_tot); copy_v3_v3(cursor, centroid); } @@ -595,7 +595,7 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) return false; } - if (v3d->around == V3D_CENTROID) { + if (v3d->around == V3D_AROUND_CENTER_MEAN) { mul_v3_fl(centroid, 1.0f / (float)count); copy_v3_v3(cursor, centroid); } diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 4d36d703ae7..8b3ea2a1fee 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -403,7 +403,6 @@ static void walk_navigation_mode_set(bContext *C, wmOperator *op, WalkInfo *walk */ static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *walk, const float dvec[3], float *r_distance) { - float dummy_dist_px = 0; float ray_normal[3] = {0, 0, -1}; /* down */ float ray_start[3]; float r_location[3]; @@ -418,10 +417,12 @@ static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *w mul_v3_v3fl(dvec_tmp, dvec, walk->grid); add_v3_v3(ray_start, dvec_tmp); - ret = snapObjectsRayEx(CTX_data_scene(C), NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE, - NULL, NULL, - ray_start, ray_normal, r_distance, - NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL); + ret = snapObjectsRayEx( + CTX_data_scene(C), NULL, NULL, NULL, NULL, + NULL, SNAP_ALL, SCE_SNAP_MODE_FACE, + ray_start, ray_normal, r_distance, + r_location, r_normal, NULL, NULL, + NULL, NULL); /* artifically scale the distance to the scene size */ *r_distance /= walk->grid; @@ -435,7 +436,6 @@ static bool walk_floor_distance_get(bContext *C, RegionView3D *rv3d, WalkInfo *w */ static bool walk_ray_cast(bContext *C, RegionView3D *rv3d, WalkInfo *walk, float r_location[3], float r_normal[3], float *ray_distance) { - float dummy_dist_px = 0; float ray_normal[3] = {0, 0, 1}; /* forward */ float ray_start[3]; float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */ @@ -451,10 +451,12 @@ static bool walk_ray_cast(bContext *C, RegionView3D *rv3d, WalkInfo *walk, float mul_v3_fl(ray_normal, -1); normalize_v3(ray_normal); - ret = snapObjectsRayEx(CTX_data_scene(C), NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE, - NULL, NULL, - ray_start, ray_normal, ray_distance, - NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL); + ret = snapObjectsRayEx( + CTX_data_scene(C), NULL, NULL, NULL, NULL, + NULL, SNAP_ALL, SCE_SNAP_MODE_FACE, + ray_start, ray_normal, ray_distance, + r_location, r_normal, NULL, NULL, + NULL, NULL); /* dot is positive if both rays are facing the same direction */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 57688ca9f3c..7656a8a54c6 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -203,7 +203,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2]); static bool transdata_check_local_center(TransInfo *t, short around) { - return ((around == V3D_LOCAL) && ( + return ((around == V3D_AROUND_LOCAL_ORIGINS) && ( (t->flag & (T_OBJECT | T_POSE)) || (t->obedit && ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) || (t->spacetype == SPACE_IPO) || @@ -213,7 +213,7 @@ static bool transdata_check_local_center(TransInfo *t, short around) bool transdata_check_local_islands(TransInfo *t, short around) { - return ((around == V3D_LOCAL) && ( + return ((around == V3D_AROUND_LOCAL_ORIGINS) && ( (t->obedit && ELEM(t->obedit->type, OB_MESH)))); } @@ -1553,8 +1553,8 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa initTransInfo(C, t, NULL, NULL); - /* avoid doing connectivity lookups (when V3D_LOCAL is set) */ - t->around = V3D_CENTER; + /* avoid doing connectivity lookups (when V3D_AROUND_LOCAL_ORIGINS is set) */ + t->around = V3D_AROUND_CENTER_BOUNDS; createTransData(C, t); // make TransData structs from selection @@ -3018,7 +3018,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2])) /* rotation */ if ((t->flag & T_POINTS) == 0) { - ElementRotation(t, td, mat, V3D_LOCAL); + ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS); } /* location */ @@ -4345,14 +4345,14 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal); - ElementRotation(t, td, mat, V3D_LOCAL); + ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS); } else { float mat[3][3]; unit_m3(mat); - ElementRotation(t, td, mat, V3D_LOCAL); + ElementRotation(t, td, mat, V3D_AROUND_LOCAL_ORIGINS); } } @@ -8524,7 +8524,9 @@ bool checkUseAxisMatrix(TransInfo *t) { /* currently only checks for editmode */ if (t->flag & T_EDIT) { - if ((t->around == V3D_LOCAL) && (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) { + if ((t->around == V3D_AROUND_LOCAL_ORIGINS) && + (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) + { /* not all editmode supports axis-matrix */ return true; } diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 6360535a696..dc0b153d6e9 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -129,10 +129,10 @@ static void transform_around_single_fallback(TransInfo *t) { if ((t->total == 1) && - (ELEM(t->around, V3D_CENTER, V3D_CENTROID, V3D_ACTIVE)) && + (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEAN, V3D_AROUND_ACTIVE)) && (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) { - t->around = V3D_LOCAL; + t->around = V3D_AROUND_LOCAL_ORIGINS; } } @@ -681,7 +681,7 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb) } else if ((bone->flag & BONE_TRANSFORM) && (mode == TFM_ROTATION || mode == TFM_TRACKBALL) && - (around == V3D_LOCAL)) + (around == V3D_AROUND_LOCAL_ORIGINS)) { bone->flag |= BONE_TRANSFORM_CHILD; } @@ -1275,7 +1275,9 @@ static void createTransArmatureVerts(TransInfo *t) * causes problem with snapping (see T45974). * However, in rotation mode, we want to keep that 'rotate bone around root with * only its tip selected' behavior (see T46325). */ - if ((t->around == V3D_LOCAL) && ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL))) { + if ((t->around == V3D_AROUND_LOCAL_ORIGINS) && + ((t->mode == TFM_ROTATION) || (ebo->flag & BONE_ROOTSEL))) + { copy_v3_v3(td->center, ebo->head); } else { @@ -1551,7 +1553,7 @@ static void createTransCurveVerts(TransInfo *t) TransDataCurveHandleFlags *hdata = NULL; float axismtx[3][3]; - if (t->around == V3D_LOCAL) { + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { float normal[3], plane[3]; BKE_nurb_bezt_calc_normal(nu, bezt, normal); @@ -1574,7 +1576,7 @@ static void createTransCurveVerts(TransInfo *t) copy_v3_v3(td->iloc, bezt->vec[0]); td->loc = bezt->vec[0]; copy_v3_v3(td->center, bezt->vec[(hide_handles || - (t->around == V3D_LOCAL) || + (t->around == V3D_AROUND_LOCAL_ORIGINS) || (bezt->f2 & SELECT)) ? 1 : 0]); if (hide_handles) { if (bezt->f2 & SELECT) td->flag = TD_SELECTED; @@ -1591,7 +1593,7 @@ static void createTransCurveVerts(TransInfo *t) copy_m3_m3(td->smtx, smtx); copy_m3_m3(td->mtx, mtx); - if (t->around == V3D_LOCAL) { + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { copy_m3_m3(td->axismtx, axismtx); } @@ -1623,7 +1625,7 @@ static void createTransCurveVerts(TransInfo *t) copy_m3_m3(td->smtx, smtx); copy_m3_m3(td->mtx, mtx); - if (t->around == V3D_LOCAL) { + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { copy_m3_m3(td->axismtx, axismtx); } @@ -1644,7 +1646,7 @@ static void createTransCurveVerts(TransInfo *t) copy_v3_v3(td->iloc, bezt->vec[2]); td->loc = bezt->vec[2]; copy_v3_v3(td->center, bezt->vec[(hide_handles || - (t->around == V3D_LOCAL) || + (t->around == V3D_AROUND_LOCAL_ORIGINS) || (bezt->f2 & SELECT)) ? 1 : 2]); if (hide_handles) { if (bezt->f2 & SELECT) td->flag = TD_SELECTED; @@ -1663,7 +1665,7 @@ static void createTransCurveVerts(TransInfo *t) copy_m3_m3(td->smtx, smtx); copy_m3_m3(td->mtx, mtx); - if (t->around == V3D_LOCAL) { + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { copy_m3_m3(td->axismtx, axismtx); } @@ -2261,7 +2263,7 @@ static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx copy_v3_v3(td->center, v_island->co); copy_m3_m3(td->axismtx, v_island->axismtx); } - else if (t->around == V3D_LOCAL) { + else if (t->around == V3D_AROUND_LOCAL_ORIGINS) { copy_v3_v3(td->center, td->loc); createSpaceNormal(td->axismtx, no); } @@ -2392,7 +2394,7 @@ static void createTransEditVerts(TransInfo *t) editmesh_set_connectivity_distance(em->bm, mtx, dists); } - if (t->around == V3D_LOCAL) { + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { island_info = editmesh_islands_info_calc(em, &island_info_tot, &island_vert_map); } @@ -2760,7 +2762,7 @@ static void createTransUVs(bContext *C, TransInfo *t) int count = 0, countsel = 0, count_rejected = 0; const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0; const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0; - const bool is_island_center = (t->around == V3D_LOCAL); + const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS); const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); const int cd_poly_tex_offset = CustomData_get_offset(&em->bm->pdata, CD_MTEXPOLY); @@ -4019,7 +4021,8 @@ static bool graph_edit_is_translation_mode(TransInfo *t) static bool graph_edit_use_local_center(TransInfo *t) { - return (t->around == V3D_LOCAL) && !graph_edit_is_translation_mode(t); + return ((t->around == V3D_AROUND_LOCAL_ORIGINS) && + (graph_edit_is_translation_mode(t) == false)); } @@ -5436,7 +5439,9 @@ static void set_trans_object_base_flags(TransInfo *t) if (parsel) { /* rotation around local centers are allowed to propagate */ - if ((t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL) && t->around == V3D_LOCAL) { + if ((t->around == V3D_AROUND_LOCAL_ORIGINS) && + (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) + { base->flag |= BA_TRANSFORM_CHILD; } else { @@ -5486,7 +5491,9 @@ static int count_proportional_objects(TransInfo *t) Base *base; /* rotations around local centers are allowed to propagate, so we take all objects */ - if (!((t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL) && t->around == V3D_LOCAL)) { + if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) && + (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) + { /* mark all parents */ for (base = scene->base.first; base; base = base->next) { if (TESTBASELIB_BGMODE(v3d, scene, base)) { @@ -5607,22 +5614,22 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, do_loc = true; } else if (tmode == TFM_ROTATION) { - if (v3d->around == V3D_ACTIVE) { + if (v3d->around == V3D_AROUND_ACTIVE) { if (ob != OBACT) do_loc = true; } - else if (v3d->around == V3D_CURSOR) + else if (v3d->around == V3D_AROUND_CURSOR) do_loc = true; if ((v3d->flag & V3D_ALIGN) == 0) do_rot = true; } else if (tmode == TFM_RESIZE) { - if (v3d->around == V3D_ACTIVE) { + if (v3d->around == V3D_AROUND_ACTIVE) { if (ob != OBACT) do_loc = true; } - else if (v3d->around == V3D_CURSOR) + else if (v3d->around == V3D_AROUND_CURSOR) do_loc = true; if ((v3d->flag & V3D_ALIGN) == 0) @@ -5747,14 +5754,14 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o do_loc = true; } else if (tmode == TFM_ROTATION) { - if (ELEM(v3d->around, V3D_CURSOR, V3D_ACTIVE)) + if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE)) do_loc = true; if ((v3d->flag & V3D_ALIGN) == 0) do_rot = true; } else if (tmode == TFM_RESIZE) { - if (ELEM(v3d->around, V3D_CURSOR, V3D_ACTIVE)) + if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE)) do_loc = true; if ((v3d->flag & V3D_ALIGN) == 0) @@ -5935,6 +5942,10 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) } EDBM_automerge(t->scene, t->obedit, true, hflag); + + if ((em->selectmode & SCE_SELECT_VERTEX) == 0) { + EDBM_select_flush(em); + } } } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 77c34b888fb..84087ec8840 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1219,13 +1219,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve /* bend always uses the cursor */ if (t->mode == TFM_BEND) { - t->around = V3D_CURSOR; + t->around = V3D_AROUND_CURSOR; } t->current_orientation = v3d->twmode; /* exceptional case */ - if (t->around == V3D_LOCAL) { + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { const bool use_island = transdata_check_local_islands(t, t->around); @@ -1281,7 +1281,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve else if (t->spacetype == SPACE_NODE) { // XXX for now, get View2D from the active region t->view = &ar->v2d; - t->around = V3D_CENTER; + t->around = V3D_AROUND_CENTER_BOUNDS; } else if (t->spacetype == SPACE_IPO) { SpaceIpo *sipo = sa->spacedata.first; @@ -1307,7 +1307,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve else { t->view = NULL; } - t->around = V3D_CENTER; + t->around = V3D_AROUND_CENTER_BOUNDS; } if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) && @@ -1778,13 +1778,13 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3]) void calculateCenter(TransInfo *t) { switch (t->around) { - case V3D_CENTER: + case V3D_AROUND_CENTER_BOUNDS: calculateCenterBound(t, t->center); break; - case V3D_CENTROID: + case V3D_AROUND_CENTER_MEAN: calculateCenterMedian(t, t->center); break; - case V3D_CURSOR: + case V3D_AROUND_CURSOR: if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) calculateCenterCursor2D(t, t->center); else if (t->spacetype == SPACE_IPO) @@ -1792,11 +1792,11 @@ void calculateCenter(TransInfo *t) else calculateCenterCursor(t, t->center); break; - case V3D_LOCAL: + case V3D_AROUND_LOCAL_ORIGINS: /* Individual element center uses median center for helpline and such */ calculateCenterMedian(t, t->center); break; - case V3D_ACTIVE: + case V3D_AROUND_ACTIVE: { if (calculateCenterActive(t, false, t->center)) { /* pass */ diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index 44779fc1cf2..b4e907c4ffe 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -51,9 +51,9 @@ static void InputSpring(TransInfo *UNUSED(t), MouseInput *mi, const double mval[ double dx, dy; float ratio; - dx = (mi->center[0] - mval[0]); - dy = (mi->center[1] - mval[1]); - ratio = hypot(dx, dy) / mi->factor; + dx = ((double)mi->center[0] - mval[0]); + dy = ((double)mi->center[1] - mval[1]); + ratio = hypot(dx, dy) / (double)mi->factor; output[0] = ratio; } @@ -64,8 +64,8 @@ static void InputSpringFlip(TransInfo *t, MouseInput *mi, const double mval[2], /* flip scale */ /* values can become really big when zoomed in so use longs [#26598] */ - if ((long long int)(mi->center[0] - mval[0]) * (long long int)(mi->center[0] - mi->imval[0]) + - (long long int)(mi->center[1] - mval[1]) * (long long int)(mi->center[1] - mi->imval[1]) < 0) + if ((int64_t)((int)mi->center[0] - mval[0]) * (int64_t)((int)mi->center[0] - mi->imval[0]) + + (int64_t)((int)mi->center[1] - mval[1]) * (int64_t)((int)mi->center[1] - mi->imval[1]) < 0) { output[0] *= -1.0f; } @@ -88,7 +88,7 @@ static void InputTrackBall(TransInfo *UNUSED(t), MouseInput *mi, const double mv static void InputHorizontalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3]) { - const float pad = t->ar->winx / 10; + const double pad = t->ar->winx / 10; output[0] = (mval[0] - pad) / (t->ar->winx - 2 * pad); } @@ -105,7 +105,7 @@ static void InputHorizontalAbsolute(TransInfo *t, MouseInput *mi, const double m static void InputVerticalRatio(TransInfo *t, MouseInput *UNUSED(mi), const double mval[2], float output[3]) { - const float pad = t->ar->winy / 10; + const double pad = t->ar->winy / 10; output[0] = (mval[1] - pad) / (t->ar->winy - 2 * pad); } @@ -171,12 +171,12 @@ struct InputAngle_Data { static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], float output[3]) { struct InputAngle_Data *data = mi->data; - double dx2 = mval[0] - mi->center[0]; - double dy2 = mval[1] - mi->center[1]; + double dx2 = mval[0] - (double)mi->center[0]; + double dy2 = mval[1] - (double)mi->center[1]; double B = sqrt(dx2 * dx2 + dy2 * dy2); - double dx1 = data->mval_prev[0] - mi->center[0]; - double dy1 = data->mval_prev[1] - mi->center[1]; + double dx1 = data->mval_prev[0] - (double)mi->center[0]; + double dy1 = data->mval_prev[1] - (double)mi->center[1]; double A = sqrt(dx1 * dx1 + dy1 * dy1); double dx3 = mval[0] - data->mval_prev[0]; @@ -214,7 +214,7 @@ static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2 if ((dx1 * dy2 - dx2 * dy1) > 0.0) dphi = -dphi; } - data->angle += ((double)dphi) * (mi->precision ? mi->precision_factor : 1.0f); + data->angle += ((double)dphi) * (mi->precision ? (double)mi->precision_factor : 1.0); data->mval_prev[0] = mval[0]; data->mval_prev[1] = mval[1]; @@ -371,8 +371,8 @@ void applyMouseInput(TransInfo *t, MouseInput *mi, const int mval[2], float outp mi->virtual_mval.prev[1] += mval_delta[1]; if (mi->precision) { - mval_delta[0] *= mi->precision_factor; - mval_delta[1] *= mi->precision_factor; + mval_delta[0] *= (double)mi->precision_factor; + mval_delta[1] *= (double)mi->precision_factor; } mi->virtual_mval.accum[0] += mval_delta[0]; diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 8ddd7aebc54..0c3f74dbe9d 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -321,7 +321,7 @@ static int calc_manipulator_stats(const bContext *C) float vec[3] = {0, 0, 0}; /* USE LAST SELECTE WITH ACTIVE */ - if ((v3d->around == V3D_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) { + if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) { BM_editselection_center(&ese, vec); calc_tw_center(scene, vec); totsel = 1; @@ -346,7 +346,7 @@ static int calc_manipulator_stats(const bContext *C) bArmature *arm = obedit->data; EditBone *ebo; - if ((v3d->around == V3D_ACTIVE) && (ebo = arm->act_edbone)) { + if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) { /* doesn't check selection or visibility intentionally */ if (ebo->flag & BONE_TIPSEL) { calc_tw_center(scene, ebo->tail); @@ -382,7 +382,7 @@ static int calc_manipulator_stats(const bContext *C) Curve *cu = obedit->data; float center[3]; - if (v3d->around == V3D_ACTIVE && ED_curve_active_center(cu, center)) { + if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) { calc_tw_center(scene, center); totsel++; } @@ -414,11 +414,11 @@ static int calc_manipulator_stats(const bContext *C) } else { if (bezt->f1 & SELECT) { - calc_tw_center(scene, bezt->vec[(v3d->around == V3D_LOCAL) ? 1 : 0]); + calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]); totsel++; } if (bezt->f3 & SELECT) { - calc_tw_center(scene, bezt->vec[(v3d->around == V3D_LOCAL) ? 1 : 2]); + calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]); totsel++; } } @@ -444,7 +444,7 @@ static int calc_manipulator_stats(const bContext *C) MetaBall *mb = (MetaBall *)obedit->data; MetaElem *ml; - if ((v3d->around == V3D_ACTIVE) && (ml = mb->lastelem)) { + if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) { calc_tw_center(scene, &ml->x); totsel++; } @@ -461,7 +461,7 @@ static int calc_manipulator_stats(const bContext *C) Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt; BPoint *bp; - if ((v3d->around == V3D_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) { + if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) { calc_tw_center(scene, bp->vec); totsel++; } @@ -493,7 +493,7 @@ static int calc_manipulator_stats(const bContext *C) if ((ob->lay & v3d->lay) == 0) return 0; - if ((v3d->around == V3D_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) { + if ((v3d->around == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) { /* doesn't check selection or visibility intentionally */ Bone *bone = pchan->bone; if (bone) { @@ -1620,13 +1620,10 @@ void BIF_draw_manipulator(const bContext *C) /* now we can define center */ switch (v3d->around) { - case V3D_CENTER: - case V3D_ACTIVE: + case V3D_AROUND_CENTER_BOUNDS: + case V3D_AROUND_ACTIVE: { - bGPdata *gpd = CTX_data_gpencil_data(C); - Object *ob = OBACT; - - if (((v3d->around == V3D_ACTIVE) && (scene->obedit == NULL)) && + if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) && ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) && (!(ob->mode & OB_MODE_POSE))) { @@ -1637,11 +1634,11 @@ void BIF_draw_manipulator(const bContext *C) } break; } - case V3D_LOCAL: - case V3D_CENTROID: + case V3D_AROUND_LOCAL_ORIGINS: + case V3D_AROUND_CENTER_MEAN: copy_v3_v3(rv3d->twmat[3], scene->twcent); break; - case V3D_CURSOR: + case V3D_AROUND_CURSOR: copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)); break; } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index a1bb6f4e0f3..2ea18d509f0 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -591,7 +591,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 Base *base; Object *ob = OBACT; int result = ORIENTATION_NONE; - const bool activeOnly = (around == V3D_ACTIVE); + const bool activeOnly = (around == V3D_AROUND_ACTIVE); zero_v3(normal); zero_v3(plane); @@ -854,7 +854,7 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 /* exception */ if (flag) { float tvec[3]; - if ((around == V3D_LOCAL) || + if ((around == V3D_AROUND_LOCAL_ORIGINS) || ELEM(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3)) { BKE_nurb_bezt_calc_normal(nu, bezt, tvec); @@ -1044,8 +1044,8 @@ int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3 int getTransformOrientation(const bContext *C, float normal[3], float plane[3]) { - /* dummy value, not V3D_ACTIVE and not V3D_LOCAL */ - short around = V3D_CENTER; + /* dummy value, not V3D_AROUND_ACTIVE and not V3D_AROUND_LOCAL_ORIGINS */ + short around = V3D_AROUND_CENTER_BOUNDS; return getTransformOrientation_ex(C, normal, plane, around); } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 2251dedc268..359e191c90d 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -112,7 +112,7 @@ static float ResizeBetween(TransInfo *t, const float p1[3], const float p2[3]); /****************** IMPLEMENTATIONS *********************/ -static bool snapNodeTest(View2D *v2d, bNode *node, SnapMode mode); +static bool snapNodeTest(View2D *v2d, bNode *node, SnapSelect snap_select); static NodeBorder snapNodeBorder(int snap_node_mode); #if 0 @@ -330,7 +330,10 @@ void applyProject(TransInfo *t) } if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - if (snapObjectsTransform(t, mval_fl, &dist_px, loc, no, t->tsnap.modeSelect)) { + if (snapObjectsTransform( + t, mval_fl, t->tsnap.modeSelect, + loc, no, &dist_px)) + { // if (t->flag & (T_EDIT|T_POSE)) { // mul_m4_v3(imat, loc); // } @@ -933,7 +936,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) BLI_listbase_clear(&depth_peels); - peelObjectsTransForm(t, &depth_peels, mval, t->tsnap.modeSelect); + peelObjectsTransForm(t, mval, t->tsnap.modeSelect, &depth_peels); // if (LAST_SNAP_POINT_VALID) // { @@ -1008,7 +1011,9 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) } else { zero_v3(no); /* objects won't set this */ - found = snapObjectsTransform(t, mval, &dist_px, loc, no, t->tsnap.modeSelect); + found = snapObjectsTransform( + t, mval, t->tsnap.modeSelect, + loc, no, &dist_px); } if (found == true) { @@ -1052,7 +1057,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec)) float dist_px = SNAP_MIN_DISTANCE; // Use a user defined value here char node_border; - if (snapNodesTransform(t, t->mval, &dist_px, loc, &node_border, t->tsnap.modeSelect)) { + if (snapNodesTransform(t, t->mval, t->tsnap.modeSelect, loc, &dist_px, &node_border)) { copy_v2_v2(t->tsnap.snapPoint, loc); t->tsnap.snapNodeBorder = node_border; @@ -1242,9 +1247,11 @@ static void TargetSnapClosest(TransInfo *t) } } -static bool snapEdge(ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3], float obmat[4][4], float timat[3][3], - const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval_fl[2], - float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth) +static bool snapEdge( + ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3], + float obmat[4][4], float timat[3][3], const float mval_fl[2], + const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, + float r_loc[3], float r_no[3], float *r_dist_px) { float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3]; int result; @@ -1300,10 +1307,10 @@ static bool snapEdge(ARegion *ar, const float v1co[3], const short v1no[3], cons * this takes care of series of connected edges a bit slanted w.r.t the viewport * otherwise, it would stick to the verts of the closest edge and not slide along merrily * */ - if (new_dist <= *r_dist_px && new_depth < *r_depth * 1.001f) { + if (new_dist <= *r_dist_px && new_depth < *ray_depth * 1.001f) { float n1[3], n2[3]; - *r_depth = new_depth; + *ray_depth = new_depth; retval = true; sub_v3_v3v3(edge_loc, v1co, v2co); @@ -1329,9 +1336,11 @@ static bool snapEdge(ARegion *ar, const float v1co[3], const short v1no[3], cons return retval; } -static bool snapVertex(ARegion *ar, const float vco[3], const short vno[3], float obmat[4][4], float timat[3][3], - const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], const float mval_fl[2], - float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth) +static bool snapVertex( + ARegion *ar, const float vco[3], const short vno[3], + float obmat[4][4], float timat[3][3], const float mval_fl[2], + const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, + float r_loc[3], float r_no[3], float *r_dist_px) { bool retval = false; float dvec[3]; @@ -1358,8 +1367,8 @@ static bool snapVertex(ARegion *ar, const float vco[3], const short vno[3], floa } - if (new_dist <= *r_dist_px && new_depth < *r_depth) { - *r_depth = new_depth; + if (new_dist <= *r_dist_px && new_depth < *ray_depth) { + *ray_depth = new_depth; retval = true; copy_v3_v3(r_loc, location); @@ -1377,9 +1386,11 @@ static bool snapVertex(ARegion *ar, const float vco[3], const short vno[3], floa return retval; } -static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float mval[2], - float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth) +static bool snapArmature( + ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], + const float mval[2], const short snap_to, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + float r_loc[3], float *UNUSED(r_no), float *r_dist_px) { float imat[4][4]; float ray_start_local[3], ray_normal_local[3]; @@ -1397,13 +1408,13 @@ static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *ar if (eBone->layer & arm->layer) { /* skip hidden or moving (selected) bones */ if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) { - switch (snap_mode) { + switch (snap_to) { case SCE_SNAP_MODE_VERTEX: - retval |= snapVertex(ar, eBone->head, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); - retval |= snapVertex(ar, eBone->tail, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapVertex(ar, eBone->head, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); + retval |= snapVertex(ar, eBone->tail, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); break; case SCE_SNAP_MODE_EDGE: - retval |= snapEdge(ar, eBone->head, NULL, eBone->tail, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapEdge(ar, eBone->head, NULL, eBone->tail, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); break; } } @@ -1421,13 +1432,13 @@ static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *ar const float *head_vec = pchan->pose_head; const float *tail_vec = pchan->pose_tail; - switch (snap_mode) { + switch (snap_to) { case SCE_SNAP_MODE_VERTEX: - retval |= snapVertex(ar, head_vec, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); - retval |= snapVertex(ar, tail_vec, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapVertex(ar, head_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); + retval |= snapVertex(ar, tail_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); break; case SCE_SNAP_MODE_EDGE: - retval |= snapEdge(ar, head_vec, NULL, tail_vec, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapEdge(ar, head_vec, NULL, tail_vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); break; } } @@ -1437,9 +1448,11 @@ static bool snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *ar return retval; } -static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float mval[2], - float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth) +static bool snapCurve( + ARegion *ar, Object *ob, Curve *cu, float obmat[4][4], + const float mval[2], const short snap_to, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + float r_loc[3], float *UNUSED(r_no), float *r_dist_px) { float imat[4][4]; float ray_start_local[3], ray_normal_local[3]; @@ -1449,7 +1462,7 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float Nurb *nu; /* only vertex snapping mode (eg control points and handles) supported for now) */ - if (snap_mode != SCE_SNAP_MODE_VERTEX) { + if (snap_to != SCE_SNAP_MODE_VERTEX) { return retval; } @@ -1463,7 +1476,7 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { for (u = 0; u < nu->pntsu; u++) { - switch (snap_mode) { + switch (snap_to) { case SCE_SNAP_MODE_VERTEX: { if (ob->mode == OB_MODE_EDIT) { @@ -1472,13 +1485,13 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) { break; } - retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */ if (!(nu->bezt[u].f1 & SELECT) && !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) { - retval |= snapVertex(ar, nu->bezt[u].vec[0], NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapVertex(ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); } if (!(nu->bezt[u].f3 & SELECT) && !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) { - retval |= snapVertex(ar, nu->bezt[u].vec[2], NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapVertex(ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); } } else { @@ -1486,17 +1499,17 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) { break; } - retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); } } else { /* curve is not visible outside editmode if nurb length less than two */ if (nu->pntsu > 1) { if (nu->bezt) { - retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapVertex(ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); } else { - retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapVertex(ar, nu->bp[u].vec, NULL, obmat, NULL, mval, ray_start, ray_start_local, ray_normal_local, ray_depth, r_loc, NULL, r_dist_px); } } } @@ -1510,13 +1523,22 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float return retval; } -static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], - const float mval[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth, bool do_bb) +static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) +{ + const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX); + return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly; +} + +static bool snapDerivedMesh( + ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4], + const float mval[2], const short snap_to, bool do_bb, + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + float r_loc[3], float r_no[3], float *r_dist_px, int *r_index) { bool retval = false; - const bool do_ray_start_correction = (snap_mode == SCE_SNAP_MODE_FACE && ar && - !((RegionView3D *)ar->regiondata)->is_persp); + const bool do_ray_start_correction = ( + (snap_to == SCE_SNAP_MODE_FACE) && + (ar && !((RegionView3D *)ar->regiondata)->is_persp)); int totvert = dm->getNumVerts(dm); if (totvert > 0) { @@ -1548,7 +1570,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes /* Exact value here is arbitrary (ideally we would scale in pixel-space based on 'r_dist_px'), * scale up so we can snap against verts & edges on the boundbox, see T46816. */ - if (ELEM(snap_mode, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { + if (ELEM(snap_to, SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE)) { BKE_boundbox_scale(&bb_temp, bb, 1.0f + 1e-1f); bb = &bb_temp; } @@ -1582,7 +1604,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes free_bvhtree_from_mesh(&treeData); } - switch (snap_mode) { + switch (snap_to) { case SCE_SNAP_MODE_FACE: { BVHTreeRayHit hit; @@ -1614,7 +1636,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes bvhtree_from_mesh_looptri(&treeData, dm, 0.0f, 4, 6); hit.index = -1; - hit.dist = *r_depth; + hit.dist = *ray_depth; if (hit.dist != TRANSFORM_DIST_MAX_RAY) { hit.dist *= local_scale; hit.dist -= len_diff; @@ -1626,8 +1648,8 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes { hit.dist += len_diff; hit.dist /= local_scale; - if (hit.dist <= *r_depth) { - *r_depth = hit.dist; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); copy_v3_v3(r_no, hit.no); @@ -1637,6 +1659,10 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes normalize_v3(r_no); retval = true; + + if (r_index) { + *r_index = dm_looptri_to_poly_index(dm, &treeData.looptri[hit.index]); + } } } free_bvhtree_from_mesh(&treeData); @@ -1682,8 +1708,10 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes } if (test) { - retval |= snapVertex(ar, v->co, v->no, obmat, timat, ray_start, ray_start_local, - ray_normal_local, mval, r_loc, r_no, r_dist_px, r_depth); + retval |= snapVertex( + ar, v->co, v->no, obmat, timat, mval, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, r_no, r_dist_px); } } @@ -1731,9 +1759,10 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes } if (test) { - retval |= snapEdge(ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, - obmat, timat, ray_start, ray_start_local, ray_normal_local, mval, - r_loc, r_no, r_dist_px, r_depth); + retval |= snapEdge( + ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, obmat, timat, + mval, ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, r_no, r_dist_px); } } @@ -1746,9 +1775,11 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes } /* may extend later (for now just snaps to empty center) */ -static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float mval[2], - float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth) +static bool snapEmpty( + ARegion *ar, Object *ob, float obmat[4][4], + const float mval[2], const short snap_to, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + float r_loc[3], float *UNUSED(r_no), float *r_dist_px) { float imat[4][4]; float ray_start_local[3], ray_normal_local[3]; @@ -1758,7 +1789,7 @@ static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4 return retval; } /* for now only vertex supported */ - if (snap_mode != SCE_SNAP_MODE_VERTEX) { + if (snap_to != SCE_SNAP_MODE_VERTEX) { return retval; } @@ -1767,11 +1798,14 @@ static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4 mul_v3_m4v3(ray_start_local, imat, ray_start); mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); - switch (snap_mode) { + switch (snap_to) { case SCE_SNAP_MODE_VERTEX: { const float zero_co[3] = {0.0f}; - retval |= snapVertex(ar, zero_co, NULL, obmat, NULL, ray_start, ray_start_local, ray_normal_local, mval, r_loc, NULL, r_dist_px, r_depth); + retval |= snapVertex( + ar, zero_co, NULL, obmat, NULL, mval, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL, r_dist_px); break; } default: @@ -1781,9 +1815,11 @@ static bool snapEmpty(short snap_mode, ARegion *ar, Object *ob, float obmat[4][4 return retval; } -static bool snapCamera(short snap_mode, ARegion *ar, Scene *scene, Object *object, float obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float mval[2], - float r_loc[3], float *UNUSED(r_no), float *r_dist_px, float *r_depth) +static bool snapCamera( + ARegion *ar, Scene *scene, Object *object, float obmat[4][4], + const float mval[2], const short snap_to, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + float r_loc[3], float *UNUSED(r_no), float *r_dist_px) { float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4]; bool retval = false; @@ -1805,7 +1841,7 @@ static bool snapCamera(short snap_mode, ARegion *ar, Scene *scene, Object *objec invert_m4_m4(orig_camera_imat, orig_camera_mat); invert_m4_m4(imat, obmat); - switch (snap_mode) { + switch (snap_to) { case SCE_SNAP_MODE_VERTEX: { MovieTrackingObject *tracking_object; @@ -1850,9 +1886,10 @@ static bool snapCamera(short snap_mode, ARegion *ar, Scene *scene, Object *objec vertex_obmat = obmat; } - retval |= snapVertex(ar, bundle_pos, NULL, vertex_obmat, NULL, - ray_start, ray_start_local, ray_normal_local, mval, - r_loc, NULL, r_dist_px, r_depth); + retval |= snapVertex( + ar, bundle_pos, NULL, vertex_obmat, NULL, mval, + ray_start, ray_start_local, ray_normal_local, ray_depth, + r_loc, NULL, r_dist_px); } } @@ -1865,10 +1902,13 @@ static bool snapCamera(short snap_mode, ARegion *ar, Scene *scene, Object *objec return retval; } -static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, float obmat[4][4], bool use_obedit, - Object **r_ob, float r_obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], - const float mval[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth) +static bool snapObject( + Scene *scene, ARegion *ar, Object *ob, float obmat[4][4], bool use_obedit, + const float mval[2], const short snap_to, + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], float *r_dist_px, int *r_index, + Object **r_ob, float r_obmat[4][4]) { bool retval = false; @@ -1895,21 +1935,36 @@ static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, f em = NULL; } - retval = snapDerivedMesh(snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_depth, do_bb); + retval = snapDerivedMesh( + ar, ob, dm, em, obmat, mval, snap_to, do_bb, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_dist_px, r_index); dm->release(dm); } else if (ob->type == OB_ARMATURE) { - retval = snapArmature(snap_mode, ar, ob, ob->data, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth); + retval = snapArmature( + ar, ob, ob->data, obmat, mval, snap_to, + ray_start, ray_normal, ray_depth, + r_loc, r_no, r_dist_px); } else if (ob->type == OB_CURVE) { - retval = snapCurve(snap_mode, ar, ob, ob->data, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth); + retval = snapCurve( + ar, ob, ob->data, obmat, mval, snap_to, + ray_start, ray_normal, ray_depth, + r_loc, r_no, r_dist_px); } else if (ob->type == OB_EMPTY) { - retval = snapEmpty(snap_mode, ar, ob, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth); + retval = snapEmpty( + ar, ob, obmat, mval, snap_to, + ray_start, ray_normal, ray_depth, + r_loc, r_no, r_dist_px); } else if (ob->type == OB_CAMERA) { - retval = snapCamera(snap_mode, ar, scene, ob, obmat, ray_start, ray_normal, mval, r_loc, r_no, r_dist_px, r_depth); + retval = snapCamera( + ar, scene, ob, obmat, mval, snap_to, + ray_start, ray_normal, ray_depth, + r_loc, r_no, r_dist_px); } if (retval) { @@ -1922,21 +1977,25 @@ static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, f return retval; } -static bool snapObjectsRay(Scene *scene, short snap_mode, Base *base_act, View3D *v3d, ARegion *ar, Object *obedit, - Object **r_ob, float r_obmat[4][4], - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], - float *r_ray_dist, - const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode) +static bool snapObjectsRay( + Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit, + const float mval[2], SnapSelect snap_select, const short snap_to, + const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + /* return args */ + float r_loc[3], float r_no[3], float *r_dist_px, int *r_index, + Object **r_ob, float r_obmat[4][4]) { Base *base; bool retval = false; - if (mode == SNAP_ALL && obedit) { + if (snap_select == SNAP_ALL && obedit) { Object *ob = obedit; - retval |= snapObject(scene, snap_mode, ar, ob, ob->obmat, true, - r_ob, r_obmat, - ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_ray_dist); + retval |= snapObject( + scene, ar, ob, ob->obmat, true, + mval, snap_to, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat); } /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA @@ -1947,17 +2006,19 @@ static bool snapObjectsRay(Scene *scene, short snap_mode, Base *base_act, View3D base = base_act; if (base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT) { Object *ob = base->object; - retval |= snapObject(scene, snap_mode, ar, ob, ob->obmat, false, - r_ob, r_obmat, - ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_ray_dist); + retval |= snapObject( + scene, ar, ob, ob->obmat, false, + mval, snap_to, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat); } for (base = FIRSTBASE; base != NULL; base = base->next) { if ((BASE_VISIBLE_BGMODE(v3d, scene, base)) && (base->flag & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && - ((mode == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || - (ELEM(mode, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act))) + ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || + (ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT) && base != base_act))) { Object *ob = base->object; Object *ob_snap = ob; @@ -1977,25 +2038,31 @@ static bool snapObjectsRay(Scene *scene, short snap_mode, Base *base_act, View3D bool use_obedit_dupli = (obedit && dupli_ob->ob->data == obedit->data); Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob; - retval |= snapObject(scene, snap_mode, ar, dupli_snap, dupli_ob->mat, use_obedit_dupli, - r_ob, r_obmat, - ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_ray_dist); + retval |= snapObject( + scene, ar, dupli_snap, dupli_ob->mat, use_obedit_dupli, + mval, snap_to, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat); } free_object_duplilist(lb); } - retval |= snapObject(scene, snap_mode, ar, ob_snap, ob->obmat, use_obedit, - r_ob, r_obmat, - ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_ray_dist); + retval |= snapObject( + scene, ar, ob_snap, ob->obmat, use_obedit, + mval, snap_to, + ray_start, ray_normal, ray_origin, ray_depth, + r_loc, r_no, r_dist_px, r_index, r_ob, r_obmat); } } return retval; } -static bool snapObjects(Scene *scene, short snap_mode, Base *base_act, View3D *v3d, ARegion *ar, Object *obedit, - const float mval[2], float *r_dist_px, - float r_loc[3], float r_no[3], float *r_ray_dist, SnapMode mode) +static bool snapObjects( + Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit, + const float mval[2], SnapSelect snap_select, const short snap_to, + float *ray_depth, + float r_loc[3], float r_no[3], float *r_dist_px, int *r_index) { float ray_start[3], ray_normal[3], ray_orgigin[3]; @@ -2003,13 +2070,16 @@ static bool snapObjects(Scene *scene, short snap_mode, Base *base_act, View3D *v return false; } - return snapObjectsRay(scene, snap_mode, base_act, v3d, ar, obedit, - NULL, NULL, - ray_start, ray_normal, ray_orgigin, r_ray_dist, - mval, r_dist_px, r_loc, r_no, mode); + return snapObjectsRay( + scene, v3d, ar, base_act, obedit, + mval, snap_select, snap_to, + ray_start, ray_normal, ray_orgigin, ray_depth, + r_loc, r_no, r_dist_px, r_index, NULL, NULL); } -bool snapObjectsTransform(TransInfo *t, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode) +bool snapObjectsTransform( + TransInfo *t, const float mval[2], SnapSelect snap_select, + float r_loc[3], float r_no[3], float *r_dist_px) { float ray_dist = TRANSFORM_DIST_MAX_RAY; Object *obedit = NULL; @@ -2024,11 +2094,15 @@ bool snapObjectsTransform(TransInfo *t, const float mval[2], float *r_dist_px, f } return snapObjects( - t->scene, t->scene->toolsettings->snap_mode, base_act, t->view, t->ar, obedit, - mval, r_dist_px, r_loc, r_no, &ray_dist, mode); + t->scene, t->view, t->ar, base_act, obedit, + mval, snap_select, t->scene->toolsettings->snap_mode, + &ray_dist, + r_loc, r_no, r_dist_px, NULL); } -bool snapObjectsContext(bContext *C, const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode) +bool snapObjectsContext( + bContext *C, const float mval[2], SnapSelect snap_select, + float r_loc[3], float r_no[3], float *r_dist_px) { ScrArea *sa = CTX_wm_area(C); View3D *v3d = sa->spacedata.first; @@ -2037,27 +2111,38 @@ bool snapObjectsContext(bContext *C, const float mval[2], float *r_dist_px, floa Object *obedit = CTX_data_edit_object(C); float ray_dist = TRANSFORM_DIST_MAX_RAY; - return snapObjects(scene, scene->toolsettings->snap_mode, scene->basact, v3d, ar, obedit, - mval, r_dist_px, r_loc, r_no, &ray_dist, mode); + return snapObjects( + scene, v3d, ar, scene->basact, obedit, + mval, snap_select, scene->toolsettings->snap_mode, + &ray_dist, + r_loc, r_no, r_dist_px, NULL); } -bool snapObjectsEx(Scene *scene, Base *base_act, View3D *v3d, ARegion *ar, Object *obedit, short snap_mode, - const float mval[2], float *r_dist_px, - float r_loc[3], float r_no[3], float *r_ray_dist, SnapMode mode) +bool snapObjectsEx( + Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit, + const float mval[2], SnapSelect snap_select, const short snap_to, + float *ray_depth, + float r_loc[3], float r_no[3], float *r_dist_px) { - return snapObjects(scene, snap_mode, base_act, v3d, ar, obedit, - mval, r_dist_px, - r_loc, r_no, r_ray_dist, mode); + return snapObjects( + scene, v3d, ar, base_act, obedit, + mval, snap_select, snap_to, + ray_depth, + r_loc, r_no, r_dist_px, NULL); } -bool snapObjectsRayEx(Scene *scene, Base *base_act, View3D *v3d, ARegion *ar, Object *obedit, short snap_mode, - Object **r_ob, float r_obmat[4][4], - const float ray_start[3], const float ray_normal[3], float *r_ray_dist, - const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode) -{ - return snapObjectsRay(scene, snap_mode, base_act, v3d, ar, obedit, - r_ob, r_obmat, - ray_start, ray_normal, ray_start, r_ray_dist, - mval, r_dist_px, r_loc, r_no, mode); +bool snapObjectsRayEx( + Scene *scene, View3D *v3d, ARegion *ar, Base *base_act, Object *obedit, + const float mval[2], SnapSelect snap_select, const short snap_to, + const float ray_start[3], const float ray_normal[3], float *ray_depth, + float r_loc[3], float r_no[3], float *r_dist_px, int *r_index, + Object **r_ob, float r_obmat[4][4]) +{ + return snapObjectsRay( + scene, v3d, ar, base_act, obedit, + mval, snap_select, snap_to, + ray_start, ray_normal, ray_start, ray_depth, + r_loc, r_no, r_dist_px, r_index, + r_ob, r_obmat); } /******************** PEELING *********************************/ @@ -2220,8 +2305,10 @@ static bool peelDerivedMesh( return retval; } -static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, - ListBase *depth_peels, const float mval[2], SnapMode mode) +static bool peelObjects( + Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, + const float mval[2], SnapSelect snap_select, + ListBase *r_depth_peels) { Base *base; bool retval = false; @@ -2250,13 +2337,13 @@ static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, if (dob != obedit) { dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH); - val = peelDerivedMesh(dob, dm, NULL, dob->obmat, ray_start, ray_normal, mval, depth_peels); + val = peelDerivedMesh(dob, dm, NULL, dob->obmat, ray_start, ray_normal, mval, r_depth_peels); } else { em = BKE_editmesh_from_object(dob); dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); - val = peelDerivedMesh(dob, dm, em, dob->obmat, ray_start, ray_normal, mval, depth_peels); + val = peelDerivedMesh(dob, dm, em, dob->obmat, ray_start, ray_normal, mval, r_depth_peels); } retval = retval || val; @@ -2271,17 +2358,17 @@ static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, if (ob->type == OB_MESH) { bool val = false; - if (ob != obedit && ((mode == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(mode, SNAP_ALL, SNAP_NOT_OBEDIT))) { + if (ob != obedit && ((snap_select == SNAP_NOT_SELECTED && (base->flag & (SELECT | BA_WAS_SEL)) == 0) || ELEM(snap_select, SNAP_ALL, SNAP_NOT_OBEDIT))) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, depth_peels); + val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels); dm->release(dm); } - else if (ob == obedit && mode != SNAP_NOT_OBEDIT) { + else if (ob == obedit && snap_select != SNAP_NOT_OBEDIT) { BMEditMesh *em = BKE_editmesh_from_object(ob); DerivedMesh *dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); - val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, depth_peels); + val = peelDerivedMesh(ob, dm, NULL, ob->obmat, ray_start, ray_normal, mval, r_depth_peels); dm->release(dm); } @@ -2291,18 +2378,22 @@ static bool peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, } } - BLI_listbase_sort(depth_peels, cmpPeel); - removeDoublesPeel(depth_peels); + BLI_listbase_sort(r_depth_peels, cmpPeel); + removeDoublesPeel(r_depth_peels); return retval; } -bool peelObjectsTransForm(TransInfo *t, ListBase *depth_peels, const float mval[2], SnapMode mode) +bool peelObjectsTransForm( + TransInfo *t, const float mval[2], SnapSelect snap_select, + ListBase *r_depth_peels) { - return peelObjects(t->scene, t->view, t->ar, t->obedit, depth_peels, mval, mode); + return peelObjects(t->scene, t->view, t->ar, t->obedit, mval, snap_select, r_depth_peels); } -bool peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2], SnapMode mode) +bool peelObjectsContext( + bContext *C, const float mval[2], SnapSelect snap_select, + ListBase *r_depth_peels) { Scene *scene = CTX_data_scene(C); ScrArea *sa = CTX_wm_area(C); @@ -2310,16 +2401,16 @@ bool peelObjectsContext(bContext *C, ListBase *depth_peels, const float mval[2], ARegion *ar = CTX_wm_region(C); Object *obedit = CTX_data_edit_object(C); - return peelObjects(scene, v3d, ar, obedit, depth_peels, mval, mode); + return peelObjects(scene, v3d, ar, obedit, mval, snap_select, r_depth_peels); } /******************** NODES ***********************************/ -static bool snapNodeTest(View2D *v2d, bNode *node, SnapMode mode) +static bool snapNodeTest(View2D *v2d, bNode *node, SnapSelect snap_select) { /* node is use for snapping only if a) snap mode matches and b) node is inside the view */ - return ((mode == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) || - (mode == SNAP_ALL && !(node->flag & NODE_ACTIVE))) && + return ((snap_select == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) || + (snap_select == SNAP_ALL && !(node->flag & NODE_ACTIVE))) && (node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin && node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin); } @@ -2337,8 +2428,9 @@ static NodeBorder snapNodeBorder(int snap_node_mode) return 0; } -static bool snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNode *node, const int mval[2], - float r_loc[2], float *r_dist_px, char *r_node_border) +static bool snapNode( + ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bNode *node, const int mval[2], + float r_loc[2], float *r_dist_px, char *r_node_border) { View2D *v2d = &ar->v2d; NodeBorder border = snapNodeBorder(ts->snap_node_mode); @@ -2391,8 +2483,10 @@ static bool snapNode(ToolSettings *ts, SpaceNode *UNUSED(snode), ARegion *ar, bN return retval; } -static bool snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int mval[2], - float *r_dist_px, float r_loc[2], char *r_node_border, SnapMode mode) +static bool snapNodes( + ToolSettings *ts, SpaceNode *snode, ARegion *ar, + const int mval[2], SnapSelect snap_select, + float r_loc[2], float *r_dist_px, char *r_node_border) { bNodeTree *ntree = snode->edittree; bNode *node; @@ -2401,23 +2495,32 @@ static bool snapNodes(ToolSettings *ts, SpaceNode *snode, ARegion *ar, const int *r_node_border = 0; for (node = ntree->nodes.first; node; node = node->next) { - if (snapNodeTest(&ar->v2d, node, mode)) + if (snapNodeTest(&ar->v2d, node, snap_select)) { retval |= snapNode(ts, snode, ar, node, mval, r_loc, r_dist_px, r_node_border); + } } return retval; } -bool snapNodesTransform(TransInfo *t, const int mval[2], float *r_dist_px, float r_loc[2], char *r_node_border, SnapMode mode) +bool snapNodesTransform( + TransInfo *t, const int mval[2], SnapSelect snap_select, + float r_loc[2], float *r_dist_px, char *r_node_border) { - return snapNodes(t->settings, t->sa->spacedata.first, t->ar, mval, r_dist_px, r_loc, r_node_border, mode); + return snapNodes( + t->settings, t->sa->spacedata.first, t->ar, mval, snap_select, + r_loc, r_dist_px, r_node_border); } -bool snapNodesContext(bContext *C, const int mval[2], float *r_dist_px, float r_loc[2], char *r_node_border, SnapMode mode) +bool snapNodesContext( + bContext *C, const int mval[2], SnapSelect snap_select, + float r_loc[2], float *r_dist_px, char *r_node_border) { Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); - return snapNodes(scene->toolsettings, CTX_wm_space_node(C), ar, mval, r_dist_px, r_loc, r_node_border, mode); + return snapNodes( + scene->toolsettings, CTX_wm_space_node(C), ar, mval, snap_select, + r_loc, r_dist_px, r_node_border); } /*================================================================*/ diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index f727f48e993..0463980dacd 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -344,3 +344,23 @@ void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id) break; } } + +static int ed_flush_edits_exec(bContext *C, wmOperator *UNUSED(op)) +{ + ED_editors_flush_edits(C, false); + return OPERATOR_FINISHED; +} + +void ED_OT_flush_edits(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Flush Edits"; + ot->description = "Flush edit data from active editing modes"; + ot->idname = "ED_OT_flush_edits"; + + /* api callbacks */ + ot->exec = ed_flush_edits_exec; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; +} diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index a90763eed4e..543ef0e0663 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -29,6 +29,7 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + ../../../../intern/eigen ../../../../intern/glew-mx ) @@ -52,13 +53,6 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() -if(WITH_OPENNL) - add_definitions(-DWITH_OPENNL) - list(APPEND INC_SYS - ../../../../intern/opennl/extern - ) -endif() - add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_editor_uvedit "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/editors/uvedit/SConscript b/source/blender/editors/uvedit/SConscript index b5cccab4002..85ea7f45536 100644 --- a/source/blender/editors/uvedit/SConscript +++ b/source/blender/editors/uvedit/SConscript @@ -34,9 +34,9 @@ sources = env.Glob('*.c') incs = [ '#/intern/guardedalloc', + '#/intern/eigen', env['BF_GLEW_INC'], '#/intern/glew-mx', - '#/intern/opennl/extern', '../include', '../../blenkernel', '../../blenlib', diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 3fc0b654b82..1a106b40f32 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -727,7 +727,7 @@ static bool uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2 { bool changed = false; - if (mode == V3D_CENTER) { /* bounding box */ + if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */ float min[2], max[2]; if (ED_uvedit_minmax(scene, ima, obedit, min, max)) { mid_v2_v2v2(cent, min, max); diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index 311c152a239..e1495b617f8 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -44,9 +44,7 @@ #include "BLI_sys_types.h" /* for intptr_t support */ -#ifdef WITH_OPENNL - -#include "ONL_opennl.h" +#include "eigen_capi.h" /* Utils */ @@ -193,7 +191,7 @@ typedef struct PChart { union PChartUnion { struct PChartLscm { - NLContext *context; + LinearSolver *context; float *abf_alpha; PVert *pin1, *pin2; } lscm; @@ -2471,17 +2469,12 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) PEdge *e; int i, j, ninterior = sys->ninterior, nvar = 2 * sys->ninterior; PBool success; - NLContext *context; - - context = nlNewContext(); - nlSolverParameteri(context, NL_NB_VARIABLES, nvar); + LinearSolver *context; - nlBegin(context, NL_SYSTEM); - - nlBegin(context, NL_MATRIX); + context = EIG_linear_solver_new(0, nvar, 1); for (i = 0; i < nvar; i++) - nlRightHandSideAdd(context, 0, i, sys->bInterior[i]); + EIG_linear_solver_right_hand_side_add(context, 0, i, sys->bInterior[i]); for (f = chart->faces; f; f = f->nextlink) { float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3]; @@ -2527,8 +2520,8 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) sys->J2dt[e2->u.id][0] = j2[1][0] = p_abf_compute_sin_product(sys, v1, e2->u.id) * wi2; sys->J2dt[e3->u.id][0] = j2[2][0] = p_abf_compute_sin_product(sys, v1, e3->u.id) * wi3; - nlRightHandSideAdd(context, 0, v1->u.id, j2[0][0] * beta[0]); - nlRightHandSideAdd(context, 0, ninterior + v1->u.id, j2[1][0] * beta[1] + j2[2][0] * beta[2]); + EIG_linear_solver_right_hand_side_add(context, 0, v1->u.id, j2[0][0] * beta[0]); + EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v1->u.id, j2[1][0] * beta[1] + j2[2][0] * beta[2]); row1[0] = j2[0][0] * W[0][0]; row2[0] = j2[0][0] * W[1][0]; @@ -2547,8 +2540,8 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) sys->J2dt[e2->u.id][1] = j2[1][1] = 1.0f * wi2; sys->J2dt[e3->u.id][1] = j2[2][1] = p_abf_compute_sin_product(sys, v2, e3->u.id) * wi3; - nlRightHandSideAdd(context, 0, v2->u.id, j2[1][1] * beta[1]); - nlRightHandSideAdd(context, 0, ninterior + v2->u.id, j2[0][1] * beta[0] + j2[2][1] * beta[2]); + EIG_linear_solver_right_hand_side_add(context, 0, v2->u.id, j2[1][1] * beta[1]); + EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v2->u.id, j2[0][1] * beta[0] + j2[2][1] * beta[2]); row1[1] = j2[1][1] * W[0][1]; row2[1] = j2[1][1] * W[1][1]; @@ -2567,8 +2560,8 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) sys->J2dt[e2->u.id][2] = j2[1][2] = p_abf_compute_sin_product(sys, v3, e2->u.id) * wi2; sys->J2dt[e3->u.id][2] = j2[2][2] = 1.0f * wi3; - nlRightHandSideAdd(context, 0, v3->u.id, j2[2][2] * beta[2]); - nlRightHandSideAdd(context, 0, ninterior + v3->u.id, j2[0][2] * beta[0] + j2[1][2] * beta[1]); + EIG_linear_solver_right_hand_side_add(context, 0, v3->u.id, j2[2][2] * beta[2]); + EIG_linear_solver_right_hand_side_add(context, 0, ninterior + v3->u.id, j2[0][2] * beta[0] + j2[1][2] * beta[1]); row1[2] = j2[2][2] * W[0][2]; row2[2] = j2[2][2] * W[1][2]; @@ -2592,29 +2585,25 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) continue; if (i == 0) - nlMatrixAdd(context, r, c, j2[0][i] * row1[j]); + EIG_linear_solver_matrix_add(context, r, c, j2[0][i] * row1[j]); else - nlMatrixAdd(context, r + ninterior, c, j2[0][i] * row1[j]); + EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[0][i] * row1[j]); if (i == 1) - nlMatrixAdd(context, r, c, j2[1][i] * row2[j]); + EIG_linear_solver_matrix_add(context, r, c, j2[1][i] * row2[j]); else - nlMatrixAdd(context, r + ninterior, c, j2[1][i] * row2[j]); + EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[1][i] * row2[j]); if (i == 2) - nlMatrixAdd(context, r, c, j2[2][i] * row3[j]); + EIG_linear_solver_matrix_add(context, r, c, j2[2][i] * row3[j]); else - nlMatrixAdd(context, r + ninterior, c, j2[2][i] * row3[j]); + EIG_linear_solver_matrix_add(context, r + ninterior, c, j2[2][i] * row3[j]); } } } - nlEnd(context, NL_MATRIX); - - nlEnd(context, NL_SYSTEM); - - success = nlSolve(context, NL_FALSE); + success = EIG_linear_solver_solve(context); if (success) { for (f = chart->faces; f; f = f->nextlink) { @@ -2625,24 +2614,24 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) pre[0] = pre[1] = pre[2] = 0.0; if (v1->flag & PVERT_INTERIOR) { - float x = nlGetVariable(context, 0, v1->u.id); - float x2 = nlGetVariable(context, 0, ninterior + v1->u.id); + float x = EIG_linear_solver_variable_get(context, 0, v1->u.id); + float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v1->u.id); pre[0] += sys->J2dt[e1->u.id][0] * x; pre[1] += sys->J2dt[e2->u.id][0] * x2; pre[2] += sys->J2dt[e3->u.id][0] * x2; } if (v2->flag & PVERT_INTERIOR) { - float x = nlGetVariable(context, 0, v2->u.id); - float x2 = nlGetVariable(context, 0, ninterior + v2->u.id); + float x = EIG_linear_solver_variable_get(context, 0, v2->u.id); + float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v2->u.id); pre[0] += sys->J2dt[e1->u.id][1] * x2; pre[1] += sys->J2dt[e2->u.id][1] * x; pre[2] += sys->J2dt[e3->u.id][1] * x2; } if (v3->flag & PVERT_INTERIOR) { - float x = nlGetVariable(context, 0, v3->u.id); - float x2 = nlGetVariable(context, 0, ninterior + v3->u.id); + float x = EIG_linear_solver_variable_get(context, 0, v3->u.id); + float x2 = EIG_linear_solver_variable_get(context, 0, ninterior + v3->u.id); pre[0] += sys->J2dt[e1->u.id][2] * x2; pre[1] += sys->J2dt[e2->u.id][2] * x2; pre[2] += sys->J2dt[e3->u.id][2] * x; @@ -2673,12 +2662,12 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart) } for (i = 0; i < ninterior; i++) { - sys->lambdaPlanar[i] += (float)nlGetVariable(context, 0, i); - sys->lambdaLength[i] += (float)nlGetVariable(context, 0, ninterior + i); + sys->lambdaPlanar[i] += (float)EIG_linear_solver_variable_get(context, 0, i); + sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i); } } - nlDeleteContext(context); + EIG_linear_solver_delete(context); return success; } @@ -3004,12 +2993,12 @@ static void p_chart_extrema_verts(PChart *chart, PVert **pin1, PVert **pin2) static void p_chart_lscm_load_solution(PChart *chart) { - NLContext *context = chart->u.lscm.context; + LinearSolver *context = chart->u.lscm.context; PVert *v; for (v = chart->verts; v; v = v->nextlink) { - v->uv[0] = nlGetVariable(context, 0, 2 * v->u.id); - v->uv[1] = nlGetVariable(context, 0, 2 * v->u.id + 1); + v->uv[0] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id); + v->uv[1] = EIG_linear_solver_variable_get(context, 0, 2 * v->u.id + 1); } } @@ -3064,16 +3053,13 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) for (v = chart->verts; v; v = v->nextlink) v->u.id = id++; - chart->u.lscm.context = nlNewContext(); - nlSolverParameteri(chart->u.lscm.context, NL_NB_VARIABLES, 2 * chart->nverts); - nlSolverParameteri(chart->u.lscm.context, NL_NB_ROWS, 2 * chart->nfaces); - nlSolverParameteri(chart->u.lscm.context, NL_LEAST_SQUARES, NL_TRUE); + chart->u.lscm.context = EIG_linear_least_squares_solver_new(2 * chart->nfaces, 2 * chart->nverts, 1); } } static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) { - NLContext *context = chart->u.lscm.context; + LinearSolver *context = chart->u.lscm.context; PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2; PFace *f; float *alpha = chart->u.lscm.abf_alpha; @@ -3081,8 +3067,6 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) bool flip_faces; int row; - nlBegin(context, NL_SYSTEM); - #if 0 /* TODO: make loading pins work for simplify/complexify. */ #endif @@ -3092,25 +3076,25 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) p_vert_load_pin_select_uvs(handle, v); /* reload for live */ if (chart->u.lscm.pin1) { - nlLockVariable(context, 2 * pin1->u.id); - nlLockVariable(context, 2 * pin1->u.id + 1); - nlLockVariable(context, 2 * pin2->u.id); - nlLockVariable(context, 2 * pin2->u.id + 1); + EIG_linear_solver_variable_lock(context, 2 * pin1->u.id); + EIG_linear_solver_variable_lock(context, 2 * pin1->u.id + 1); + EIG_linear_solver_variable_lock(context, 2 * pin2->u.id); + EIG_linear_solver_variable_lock(context, 2 * pin2->u.id + 1); - nlSetVariable(context, 0, 2 * pin1->u.id, pin1->uv[0]); - nlSetVariable(context, 0, 2 * pin1->u.id + 1, pin1->uv[1]); - nlSetVariable(context, 0, 2 * pin2->u.id, pin2->uv[0]); - nlSetVariable(context, 0, 2 * pin2->u.id + 1, pin2->uv[1]); + EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id, pin1->uv[0]); + EIG_linear_solver_variable_set(context, 0, 2 * pin1->u.id + 1, pin1->uv[1]); + EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id, pin2->uv[0]); + EIG_linear_solver_variable_set(context, 0, 2 * pin2->u.id + 1, pin2->uv[1]); } else { /* set and lock the pins */ for (v = chart->verts; v; v = v->nextlink) { if (v->flag & PVERT_PIN) { - nlLockVariable(context, 2 * v->u.id); - nlLockVariable(context, 2 * v->u.id + 1); + EIG_linear_solver_variable_lock(context, 2 * v->u.id); + EIG_linear_solver_variable_lock(context, 2 * v->u.id + 1); - nlSetVariable(context, 0, 2 * v->u.id, v->uv[0]); - nlSetVariable(context, 0, 2 * v->u.id + 1, v->uv[1]); + EIG_linear_solver_variable_set(context, 0, 2 * v->u.id, v->uv[0]); + EIG_linear_solver_variable_set(context, 0, 2 * v->u.id + 1, v->uv[1]); } } } @@ -3137,8 +3121,6 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) /* construct matrix */ - nlBegin(context, NL_MATRIX); - row = 0; for (f = chart->faces; f; f = f->nextlink) { PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next; @@ -3185,26 +3167,22 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) cosine = cosf(a1) * ratio; sine = sina1 * ratio; - nlMatrixAdd(context, row, 2 * v1->u.id, cosine - 1.0f); - nlMatrixAdd(context, row, 2 * v1->u.id + 1, -sine); - nlMatrixAdd(context, row, 2 * v2->u.id, -cosine); - nlMatrixAdd(context, row, 2 * v2->u.id + 1, sine); - nlMatrixAdd(context, row, 2 * v3->u.id, 1.0); + EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, cosine - 1.0f); + EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, -sine); + EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -cosine); + EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, sine); + EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id, 1.0); row++; - nlMatrixAdd(context, row, 2 * v1->u.id, sine); - nlMatrixAdd(context, row, 2 * v1->u.id + 1, cosine - 1.0f); - nlMatrixAdd(context, row, 2 * v2->u.id, -sine); - nlMatrixAdd(context, row, 2 * v2->u.id + 1, -cosine); - nlMatrixAdd(context, row, 2 * v3->u.id + 1, 1.0); + EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id, sine); + EIG_linear_solver_matrix_add(context, row, 2 * v1->u.id + 1, cosine - 1.0f); + EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id, -sine); + EIG_linear_solver_matrix_add(context, row, 2 * v2->u.id + 1, -cosine); + EIG_linear_solver_matrix_add(context, row, 2 * v3->u.id + 1, 1.0); row++; } - nlEnd(context, NL_MATRIX); - - nlEnd(context, NL_SYSTEM); - - if (nlSolve(context, NL_TRUE)) { + if (EIG_linear_solver_solve(context)) { p_chart_lscm_load_solution(chart); return P_TRUE; } @@ -3221,7 +3199,7 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart) static void p_chart_lscm_end(PChart *chart) { if (chart->u.lscm.context) - nlDeleteContext(chart->u.lscm.context); + EIG_linear_solver_delete(chart->u.lscm.context); if (chart->u.lscm.abf_alpha) { MEM_freeN(chart->u.lscm.abf_alpha); @@ -4700,36 +4678,3 @@ void param_flush_restore(ParamHandle *handle) } } -#else /* WITH_OPENNL */ - -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - -/* stubs */ -void param_face_add(ParamHandle *handle, ParamKey key, int nverts, - ParamKey *vkeys, float **co, float **uv, - ParamBool *pin, ParamBool *select, float normal[3]) {} -void param_edge_set_seam(ParamHandle *handle, - ParamKey *vkeys) {} -void param_aspect_ratio(ParamHandle *handle, float aspx, float aspy) {} -ParamHandle *param_construct_begin(void) { return NULL; } -void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl) {} -void param_delete(ParamHandle *handle) {} - -void param_stretch_begin(ParamHandle *handle) {} -void param_stretch_blend(ParamHandle *handle, float blend) {} -void param_stretch_iter(ParamHandle *handle) {} -void param_stretch_end(ParamHandle *handle) {} - -void param_pack(ParamHandle *handle, float margin, bool do_rotate) {} -void param_average(ParamHandle *handle) {} - -void param_flush(ParamHandle *handle) {} -void param_flush_restore(ParamHandle *handle) {} - -void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf) {} -void param_lscm_solve(ParamHandle *handle) {} -void param_lscm_end(ParamHandle *handle) {} - -#endif /* WITH_OPENNL */ diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 3ff3e29f79d..3f218136751 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -859,12 +859,12 @@ void ED_uvedit_live_unwrap(Scene *scene, Object *obedit) static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, Object *ob, BMEditMesh *em) { - int around = (v3d) ? v3d->around : V3D_CENTER; + const int around = (v3d) ? v3d->around : V3D_AROUND_CENTER_BOUNDS; /* only operates on the edit object - this is all that's needed now */ switch (around) { - case V3D_CENTER: /* bounding box center */ + case V3D_AROUND_CENTER_BOUNDS: /* bounding box center */ { BMFace *efa; BMLoop *l; @@ -883,15 +883,15 @@ static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, mid_v3_v3v3(result, min, max); break; } - case V3D_CURSOR: /* cursor center */ + case V3D_AROUND_CURSOR: /* cursor center */ { const float *curs = ED_view3d_cursor3d_get(scene, v3d); /* shift to objects world */ sub_v3_v3v3(result, curs, ob->obmat[3]); break; } - case V3D_LOCAL: /* object center */ - case V3D_CENTROID: /* multiple objects centers, only one object here*/ + case V3D_AROUND_LOCAL_ORIGINS: /* object center */ + case V3D_AROUND_CENTER_MEAN: /* multiple objects centers, only one object here*/ default: zero_v3(result); break; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 328623f884f..6d3a5d37d66 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -46,16 +46,19 @@ set(INC_SYS ) set(SRC + intern/gpu_basic_shader.c intern/gpu_buffers.c intern/gpu_codegen.c + intern/gpu_compositing.c + intern/gpu_debug.c intern/gpu_draw.c intern/gpu_extensions.c + intern/gpu_framebuffer.c intern/gpu_init_exit.c intern/gpu_material.c - intern/gpu_simple_shader.c intern/gpu_select.c - intern/gpu_compositing.c - intern/gpu_debug.c + intern/gpu_shader.c + intern/gpu_texture.c shaders/gpu_program_smoke_frag.glsl shaders/gpu_program_smoke_color_frag.glsl @@ -71,23 +74,26 @@ set(SRC shaders/gpu_shader_material.glsl shaders/gpu_shader_sep_gaussian_blur_frag.glsl shaders/gpu_shader_sep_gaussian_blur_vert.glsl - shaders/gpu_shader_simple_frag.glsl - shaders/gpu_shader_simple_vert.glsl + shaders/gpu_shader_basic_frag.glsl + shaders/gpu_shader_basic_vert.glsl shaders/gpu_shader_vertex.glsl shaders/gpu_shader_vsm_store_frag.glsl shaders/gpu_shader_vsm_store_vert.glsl shaders/gpu_shader_fx_depth_resolve.glsl + GPU_basic_shader.h GPU_buffers.h - GPU_draw.h + GPU_compositing.h GPU_debug.h + GPU_draw.h GPU_extensions.h + GPU_framebuffer.h GPU_glew.h GPU_init_exit.h GPU_material.h - GPU_simple_shader.h GPU_select.h - GPU_compositing.h + GPU_shader.h + GPU_texture.h intern/gpu_codegen.h intern/gpu_private.h ) @@ -98,8 +104,8 @@ data_to_c_simple(shaders/gpu_program_smoke_color_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_material.glsl SRC) data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC) -data_to_c_simple(shaders/gpu_shader_simple_frag.glsl SRC) -data_to_c_simple(shaders/gpu_shader_simple_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_basic_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_basic_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC) data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC) data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC) diff --git a/source/blender/gpu/GPU_simple_shader.h b/source/blender/gpu/GPU_basic_shader.h index 239296209b4..3298f0f35b4 100644 --- a/source/blender/gpu/GPU_simple_shader.h +++ b/source/blender/gpu/GPU_basic_shader.h @@ -25,12 +25,12 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file GPU_simple_shader.h +/** \file GPU_basic_shader.h * \ingroup gpu */ -#ifndef __GPU_SIMPLE_SHADER_H__ -#define __GPU_SIMPLE_SHADER_H__ +#ifndef __GPU_BASIC_SHADER_H__ +#define __GPU_BASIC_SHADER_H__ #include "BLI_utildefines.h" @@ -40,8 +40,8 @@ extern "C" { /* Fixed Function Shader */ -typedef enum GPUSimpleShaderOption { - GPU_SHADER_OVERRIDE_DIFFUSE = (1<<0), /* replace diffuse with glcolor */ +typedef enum GPUBasicShaderOption { + GPU_SHADER_USE_COLOR = (1<<0), /* use glColor, for lighting it replaces diffuse */ GPU_SHADER_LIGHTING = (1<<1), /* use lighting */ GPU_SHADER_TWO_SIDED = (1<<2), /* flip normals towards viewer */ GPU_SHADER_TEXTURE_2D = (1<<3), /* use 2D texture to replace diffuse color */ @@ -49,37 +49,44 @@ typedef enum GPUSimpleShaderOption { GPU_SHADER_SOLID_LIGHTING = (1<<4), /* use faster lighting (set automatically) */ GPU_SHADER_OPTIONS_NUM = 5, GPU_SHADER_OPTION_COMBINATIONS = (1<<GPU_SHADER_OPTIONS_NUM) -} GPUSimpleShaderOption; +} GPUBasicShaderOption; -void GPU_simple_shaders_init(void); -void GPU_simple_shaders_exit(void); +void GPU_basic_shaders_init(void); +void GPU_basic_shaders_exit(void); -void GPU_simple_shader_bind(int options); -void GPU_simple_shader_unbind(void); +void GPU_basic_shader_bind(int options); +int GPU_basic_shader_bound_options(void); -void GPU_simple_shader_colors(const float diffuse[3], const float specular[3], +void GPU_basic_shader_colors(const float diffuse[3], const float specular[3], int shininess, float alpha); -bool GPU_simple_shader_need_normals(void); - /* Fixed Function Lighting */ +typedef enum GPULightType { + GPU_LIGHT_POINT, + GPU_LIGHT_SPOT, + GPU_LIGHT_SUN +} GPULightType; + typedef struct GPULightData { - float position[4]; - float diffuse[4]; - float specular[4]; + GPULightType type; + + float position[3]; + float direction[3]; + + float diffuse[3]; + float specular[3]; float constant_attenuation; float linear_attenuation; float quadratic_attenuation; - float spot_direction[3]; float spot_cutoff; float spot_exponent; } GPULightData; -void GPU_simple_shader_light_set(int light_num, GPULightData *light); -void GPU_simple_shader_light_set_viewer(bool local); +void GPU_basic_shader_light_set(int light_num, GPULightData *light); +void GPU_basic_shader_light_set_viewer(bool local); #ifdef __cplusplus } diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index 9c67f404a12..a8656c05224 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -229,7 +229,7 @@ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers( GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, unsigned int **grid_hidden, int gridsize, const struct CCGKey *key); -GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading); +GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading); /* update */ diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 0992f8e9d21..3e6c26f608c 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -63,7 +63,7 @@ void GPU_state_init(void); * - first the state is initialized by a particular object and * it's materials * - after this, materials can be quickly enabled by their number, - * GPU_enable_material returns 0 if drawing should be skipped + * GPU_object_material_bind returns 0 if drawing should be skipped * - after drawing, the material must be disabled again */ void GPU_begin_object_materials(struct View3D *v3d, struct RegionView3D *rv3d, @@ -71,8 +71,9 @@ void GPU_begin_object_materials(struct View3D *v3d, struct RegionView3D *rv3d, void GPU_end_object_materials(void); bool GPU_object_materials_check(void); -int GPU_enable_material(int nr, void *attribs); -void GPU_disable_material(void); +int GPU_object_material_bind(int nr, void *attribs); +void GPU_object_material_unbind(void); +int GPU_object_material_visible(int nr, void *attribs); void GPU_begin_dupli_object(struct DupliObject *dob); void GPU_end_dupli_object(void); @@ -128,7 +129,7 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap); /* Image updates and free * - these deal with images bound as opengl textures */ -void GPU_paint_update_image(struct Image *ima, ImageUser *iuser, int x, int y, int w, int h); +void GPU_paint_update_image(struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h); void GPU_update_images_framechange(void); int GPU_update_image_time(struct Image *ima, double time); int GPU_verify_image(struct Image *ima, struct ImageUser *iuser, int tftile, bool compare, bool mipmap, bool is_data); diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index e07f9025090..f3be52f324b 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -36,37 +36,22 @@ extern "C" { #endif -struct Image; -struct ImageUser; -struct PreviewImage; - -struct GPUTexture; -typedef struct GPUTexture GPUTexture; - -struct GPUFrameBuffer; -typedef struct GPUFrameBuffer GPUFrameBuffer; - -struct GPUOffScreen; -typedef struct GPUOffScreen GPUOffScreen; - -struct GPUShader; -typedef struct GPUShader GPUShader; - -struct GPUProgram; -typedef struct GPUProgram GPUProgram; - /* GPU extensions support */ void GPU_extensions_disable(void); +bool GPU_legacy_support(void); bool GPU_glsl_support(void); -bool GPU_non_power_of_two_support(void); +bool GPU_full_non_power_of_two_support(void); bool GPU_display_list_support(void); bool GPU_bicubic_bump_support(void); bool GPU_geometry_shader_support(void); +bool GPU_geometry_shader_support_via_extension(void); bool GPU_instanced_drawing_support(void); int GPU_max_texture_size(void); +int GPU_max_textures(void); +int GPU_max_color_texture_samples(void); int GPU_color_depth(void); void GPU_get_dfdy_factors(float fac[2]); @@ -102,173 +87,6 @@ typedef enum GPUDriverType { bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver); -/* GPU Texture - * - always returns unsigned char RGBA textures - * - if texture with non square dimensions is created, depending on the - * graphics card capabilities the texture may actually be stored in a - * larger texture with power of two dimensions. the actual dimensions - * may be queried with GPU_texture_opengl_width/height. GPU_texture_coord_2f - * calls glTexCoord2f with the coordinates adjusted for this. - * - can use reference counting: - * - reference counter after GPU_texture_create is 1 - * - GPU_texture_ref increases by one - * - GPU_texture_free decreases by one, and frees if 0 - * - if created with from_blender, will not free the texture - */ - -typedef enum GPUHDRType { - GPU_HDR_NONE = 0, - GPU_HDR_HALF_FLOAT = 1, - GPU_HDR_FULL_FLOAT = (1 << 1), -} GPUHDRType; - -GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]); -GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]); -GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels); -GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]); -GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]); -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]); -GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]); -GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]); -GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]); -GPUTexture *GPU_texture_from_blender(struct Image *ima, - struct ImageUser *iuser, bool is_data, double time, int mipmap); -GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap); -void GPU_invalid_tex_init(void); -void GPU_invalid_tex_bind(int mode); -void GPU_invalid_tex_free(void); - -void GPU_texture_free(GPUTexture *tex); - -void GPU_texture_ref(GPUTexture *tex); - -void GPU_texture_bind(GPUTexture *tex, int number); -void GPU_texture_unbind(GPUTexture *tex); - -void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter); - -GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex); - -int GPU_texture_target(const GPUTexture *tex); -int GPU_texture_opengl_width(const GPUTexture *tex); -int GPU_texture_opengl_height(const GPUTexture *tex); -int GPU_texture_opengl_bindcode(const GPUTexture *tex); - -/* GPU Framebuffer - * - this is a wrapper for an OpenGL framebuffer object (FBO). in practice - * multiple FBO's may be created, to get around limitations on the number - * of attached textures and the dimension requirements. - * - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must - * be called before rendering to the window framebuffer again */ - -void GPU_texture_bind_as_framebuffer(GPUTexture *tex); - -GPUFrameBuffer *GPU_framebuffer_create(void); -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]); -void GPU_framebuffer_texture_detach(GPUTexture *tex); -void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot); -void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex); -void GPU_framebuffer_free(GPUFrameBuffer *fb); -bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]); - -void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot); - -void GPU_framebuffer_restore(void); -void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex); - -/* GPU OffScreen - * - wrapper around framebuffer and texture for simple offscreen drawing - * - changes size if graphics card can't support it */ - -GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]); -void GPU_offscreen_free(GPUOffScreen *ofs); -void GPU_offscreen_bind(GPUOffScreen *ofs, bool save); -void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore); -void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels); -int GPU_offscreen_width(const GPUOffScreen *ofs); -int GPU_offscreen_height(const GPUOffScreen *ofs); -int GPU_offscreen_color_texture(const GPUOffScreen *ofs); - -/* Builtin/Non-generated shaders */ -typedef enum GPUProgramType { - GPU_PROGRAM_TYPE_FRAGMENT = 0 -} GPUProgramType; - -/* TODO: remove ARB program support (recode smoke shader in GLSL) */ -GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code); -void GPU_program_free(GPUProgram *program); -void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w); -void GPU_program_bind(GPUProgram *); -void GPU_program_unbind(GPUProgram *); - -/* GPU Shader - * - only for fragment shaders now - * - must call texture bind before setting a texture as uniform! */ - -GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number); -enum { - GPU_SHADER_FLAGS_NONE = 0, - GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0), -}; -GPUShader *GPU_shader_create_ex(const char *vertexcode, - const char *fragcode, - const char *geocode, - const char *libcode, - const char *defines, - int input, - int output, - int number, - const int flags); -void GPU_shader_free(GPUShader *shader); - -void GPU_shader_bind(GPUShader *shader); -void GPU_shader_unbind(void); - -int GPU_shader_get_uniform(GPUShader *shader, const char *name); -void GPU_shader_uniform_vector(GPUShader *shader, int location, int length, - int arraysize, const float *value); -void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length, - int arraysize, const int *value); - -void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex); -void GPU_shader_uniform_int(GPUShader *shader, int location, int value); -void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number); - -int GPU_shader_get_attribute(GPUShader *shader, const char *name); - -/* Builtin/Non-generated shaders */ -typedef enum GPUBuiltinShader { - GPU_SHADER_VSM_STORE = 0, - GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, -} GPUBuiltinShader; - -typedef enum GPUBuiltinProgram { - GPU_PROGRAM_SMOKE = 0, - GPU_PROGRAM_SMOKE_COLORED = 1, -} GPUBuiltinProgram; - -GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader); -GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program); -GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp); - -void GPU_shader_free_builtin_shaders(void); - -/* Vertex attributes for shaders */ - -#define GPU_MAX_ATTRIB 32 - -typedef struct GPUVertexAttribs { - struct { - int type; - int glindex; - int gltexco; - int attribid; - char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ - } layer[GPU_MAX_ATTRIB]; - - int totlayer; -} GPUVertexAttribs; - #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h new file mode 100644 index 00000000000..4a7b0454181 --- /dev/null +++ b/source/blender/gpu/GPU_framebuffer.h @@ -0,0 +1,84 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_framebuffer.h + * \ingroup gpu + */ + +#ifndef __GPU_FRAMEBUFFER_H__ +#define __GPU_FRAMEBUFFER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GPUFrameBuffer GPUFrameBuffer; +typedef struct GPUOffScreen GPUOffScreen; +typedef struct GPUTexture GPUTexture; + +/* GPU Framebuffer + * - this is a wrapper for an OpenGL framebuffer object (FBO). in practice + * multiple FBO's may be created, to get around limitations on the number + * of attached textures and the dimension requirements. + * - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must + * be called before rendering to the window framebuffer again */ + +void GPU_texture_bind_as_framebuffer(GPUTexture *tex); + +GPUFrameBuffer *GPU_framebuffer_create(void); +int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]); +void GPU_framebuffer_texture_detach(GPUTexture *tex); +void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot); +void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *tex); +void GPU_framebuffer_free(GPUFrameBuffer *fb); +bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]); + +void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot); + +bool GPU_framebuffer_bound(GPUFrameBuffer *fb); + +void GPU_framebuffer_restore(void); +void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex); + +/* GPU OffScreen + * - wrapper around framebuffer and texture for simple offscreen drawing + * - changes size if graphics card can't support it */ + +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]); +void GPU_offscreen_free(GPUOffScreen *ofs); +void GPU_offscreen_bind(GPUOffScreen *ofs, bool save); +void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore); +void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels); +int GPU_offscreen_width(const GPUOffScreen *ofs); +int GPU_offscreen_height(const GPUOffScreen *ofs); +int GPU_offscreen_color_texture(const GPUOffScreen *ofs); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPU_FRAMEBUFFER_H__ */ diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h new file mode 100644 index 00000000000..a7cfd4e262f --- /dev/null +++ b/source/blender/gpu/GPU_shader.h @@ -0,0 +1,127 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_shader.h + * \ingroup gpu + */ + +#ifndef __GPU_SHADER_H__ +#define __GPU_SHADER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GPUShader GPUShader; +typedef struct GPUProgram GPUProgram; +typedef struct GPUTexture GPUTexture; + +/* Builtin/Non-generated shaders */ +typedef enum GPUProgramType { + GPU_PROGRAM_TYPE_FRAGMENT = 0 +} GPUProgramType; + +/* TODO: remove ARB program support (recode smoke shader in GLSL) */ +GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code); +void GPU_program_free(GPUProgram *program); +void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w); +void GPU_program_bind(GPUProgram *); +void GPU_program_unbind(GPUProgram *); + +/* GPU Shader + * - only for fragment shaders now + * - must call texture bind before setting a texture as uniform! */ + +GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *geocode, const char *libcode, const char *defines, int input, int output, int number); +enum { + GPU_SHADER_FLAGS_NONE = 0, + GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0), +}; +GPUShader *GPU_shader_create_ex(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number, + const int flags); +void GPU_shader_free(GPUShader *shader); + +void GPU_shader_bind(GPUShader *shader); +void GPU_shader_unbind(void); + +int GPU_shader_get_uniform(GPUShader *shader, const char *name); +void GPU_shader_uniform_vector(GPUShader *shader, int location, int length, + int arraysize, const float *value); +void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length, + int arraysize, const int *value); + +void GPU_shader_uniform_texture(GPUShader *shader, int location, GPUTexture *tex); +void GPU_shader_uniform_int(GPUShader *shader, int location, int value); +void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number); + +int GPU_shader_get_attribute(GPUShader *shader, const char *name); + +/* Builtin/Non-generated shaders */ +typedef enum GPUBuiltinShader { + GPU_SHADER_VSM_STORE = 0, + GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, +} GPUBuiltinShader; + +typedef enum GPUBuiltinProgram { + GPU_PROGRAM_SMOKE = 0, + GPU_PROGRAM_SMOKE_COLORED = 1, +} GPUBuiltinProgram; + +GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader); +GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program); +GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp); + +void GPU_shader_free_builtin_shaders(void); + +/* Vertex attributes for shaders */ + +#define GPU_MAX_ATTRIB 32 + +typedef struct GPUVertexAttribs { + struct { + int type; + int glindex; + int gltexco; + int attribid; + char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ + } layer[GPU_MAX_ATTRIB]; + + int totlayer; +} GPUVertexAttribs; + +#ifdef __cplusplus +} +#endif + +#endif /* __GPU_SHADER_H__ */ diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h new file mode 100644 index 00000000000..a17da53b890 --- /dev/null +++ b/source/blender/gpu/GPU_texture.h @@ -0,0 +1,104 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file GPU_texture.h + * \ingroup gpu + */ + +#ifndef __GPU_TEXTURE_H__ +#define __GPU_TEXTURE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct Image; +struct ImageUser; +struct PreviewImage; + +typedef struct GPUFrameBuffer GPUFrameBuffer; +typedef struct GPUTexture GPUTexture; + +/* GPU Texture + * - always returns unsigned char RGBA textures + * - if texture with non square dimensions is created, depending on the + * graphics card capabilities the texture may actually be stored in a + * larger texture with power of two dimensions. + * - can use reference counting: + * - reference counter after GPU_texture_create is 1 + * - GPU_texture_ref increases by one + * - GPU_texture_free decreases by one, and frees if 0 + * - if created with from_blender, will not free the texture + */ + +typedef enum GPUHDRType { + GPU_HDR_NONE = 0, + GPU_HDR_HALF_FLOAT = 1, + GPU_HDR_FULL_FLOAT = (1 << 1), +} GPUHDRType; + +GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]); +GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels); +GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]); +GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]); +GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]); +GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]); +GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]); +GPUTexture *GPU_texture_from_blender(struct Image *ima, + struct ImageUser *iuser, bool is_data, double time, int mipmap); +GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap); +void GPU_invalid_tex_init(void); +void GPU_invalid_tex_bind(int mode); +void GPU_invalid_tex_free(void); + +void GPU_texture_free(GPUTexture *tex); + +void GPU_texture_ref(GPUTexture *tex); + +void GPU_texture_bind(GPUTexture *tex, int number); +void GPU_texture_unbind(GPUTexture *tex); +int GPU_texture_bound_number(GPUTexture *tex); + +void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter); + +GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex); +int GPU_texture_framebuffer_attachment(GPUTexture *tex); +void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment); + +int GPU_texture_target(const GPUTexture *tex); +int GPU_texture_width(const GPUTexture *tex); +int GPU_texture_height(const GPUTexture *tex); +int GPU_texture_depth(const GPUTexture *tex); +int GPU_texture_opengl_bindcode(const GPUTexture *tex); + +#ifdef __cplusplus +} +#endif + +#endif /* __GPU_TEXTURE_H__ */ diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript index d27d5b09b56..15898f5c203 100644 --- a/source/blender/gpu/SConscript +++ b/source/blender/gpu/SConscript @@ -70,8 +70,8 @@ sources.extend(( os.path.join(env['DATA_SOURCES'], "gpu_shader_geometry.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_program_smoke_color_frag.glsl.c"), - os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_frag.glsl.c"), - os.path.join(env['DATA_SOURCES'], "gpu_shader_simple_vert.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_basic_frag.glsl.c"), + os.path.join(env['DATA_SOURCES'], "gpu_shader_basic_vert.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_ssao_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_frag.glsl.c"), os.path.join(env['DATA_SOURCES'], "gpu_shader_fx_dof_hq_vert.glsl.c"), diff --git a/source/blender/gpu/intern/gpu_simple_shader.c b/source/blender/gpu/intern/gpu_basic_shader.c index 89d3c0f59df..6b01ee85170 100644 --- a/source/blender/gpu/intern/gpu_simple_shader.c +++ b/source/blender/gpu/intern/gpu_basic_shader.c @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/gpu/intern/gpu_simple_shader.c +/** \file blender/gpu/intern/gpu_basic_shader.c * \ingroup gpu * * GLSL shaders to replace fixed function OpenGL materials and lighting. These @@ -42,23 +42,22 @@ * - Optimize for case where no texture matrix is used. */ -#include "GPU_glew.h" - #include "BLI_math.h" #include "BLI_utildefines.h" -#include "GPU_extensions.h" -#include "GPU_simple_shader.h" +#include "GPU_basic_shader.h" +#include "GPU_glew.h" +#include "GPU_shader.h" /* State */ -// #define NUM_OPENGL_LIGHTS 8 +static const bool USE_GLSL = false; static struct { GPUShader *cached_shaders[GPU_SHADER_OPTION_COMBINATIONS]; bool failed_shaders[GPU_SHADER_OPTION_COMBINATIONS]; - bool need_normals; + int bound_options; int lights_enabled; int lights_directional; @@ -66,12 +65,12 @@ static struct { /* Init / exit */ -void GPU_simple_shaders_init(void) +void GPU_basic_shaders_init(void) { memset(&GPU_MATERIAL_STATE, 0, sizeof(GPU_MATERIAL_STATE)); } -void GPU_simple_shaders_exit(void) +void GPU_basic_shaders_exit(void) { int i; @@ -104,7 +103,7 @@ static int detect_options() if (glIsEnabled(GL_TEXTURE_2D)) options |= GPU_SHADER_TEXTURE_2D; if (glIsEnabled(GL_COLOR_MATERIAL)) - options |= GPU_SHADER_OVERRIDE_DIFFUSE; + options |= GPU_SHADER_USE_COLOR; if (glIsEnabled(GL_LIGHTING)) options |= GPU_SHADER_LIGHTING; @@ -117,11 +116,11 @@ static int detect_options() } #endif -static GPUShader *gpu_simple_shader(int options) +static GPUShader *gpu_basic_shader(int options) { /* glsl code */ - extern char datatoc_gpu_shader_simple_vert_glsl[]; - extern char datatoc_gpu_shader_simple_frag_glsl[]; + extern char datatoc_gpu_shader_basic_vert_glsl[]; + extern char datatoc_gpu_shader_basic_frag_glsl[]; GPUShader *shader; /* detect if we can do faster lighting for solid draw mode */ @@ -136,7 +135,7 @@ static GPUShader *gpu_simple_shader(int options) /* create shader if it doesn't exist yet */ char defines[64*GPU_SHADER_OPTIONS_NUM] = ""; - if (options & GPU_SHADER_OVERRIDE_DIFFUSE) + if (options & GPU_SHADER_USE_COLOR) strcat(defines, "#define USE_COLOR\n"); if (options & GPU_SHADER_TWO_SIDED) strcat(defines, "#define USE_TWO_SIDED\n"); @@ -149,8 +148,8 @@ static GPUShader *gpu_simple_shader(int options) strcat(defines, "#define USE_SCENE_LIGHTING\n"); shader = GPU_shader_create( - datatoc_gpu_shader_simple_vert_glsl, - datatoc_gpu_shader_simple_frag_glsl, + datatoc_gpu_shader_basic_vert_glsl, + datatoc_gpu_shader_basic_frag_glsl, NULL, NULL, defines, 0, 0, 0); @@ -171,60 +170,74 @@ static GPUShader *gpu_simple_shader(int options) /* Bind / unbind */ -void GPU_simple_shader_bind(int options) +void GPU_basic_shader_bind(int options) { - if (GPU_glsl_support()) { - GPUShader *shader = gpu_simple_shader(options); + if (USE_GLSL) { + if (options) { + GPUShader *shader = gpu_basic_shader(options); - if (shader) - GPU_shader_bind(shader); + if (shader) + GPU_shader_bind(shader); + } + else { + GPU_shader_unbind(); + } } else { - // XXX where does this fit, depends on ortho/persp? + int bound_options = GPU_MATERIAL_STATE.bound_options; - if (options & GPU_SHADER_LIGHTING) + if (options & GPU_SHADER_LIGHTING) { glEnable(GL_LIGHTING); - if (options & GPU_SHADER_TWO_SIDED) - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); + if (options & GPU_SHADER_USE_COLOR) + glEnable(GL_COLOR_MATERIAL); + else + glDisable(GL_COLOR_MATERIAL); - if (options & GPU_SHADER_OVERRIDE_DIFFUSE) { - glEnable(GL_COLOR_MATERIAL); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); + if (options & GPU_SHADER_TWO_SIDED) + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); + else + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); + } + else if (bound_options & GPU_SHADER_LIGHTING) { + glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); } if (options & GPU_SHADER_TEXTURE_2D) glEnable(GL_TEXTURE_2D); + else if (bound_options & GPU_SHADER_TEXTURE_2D) + glDisable(GL_TEXTURE_2D); } - /* temporary hack, should be solved outside of this file */ - GPU_MATERIAL_STATE.need_normals = (options & GPU_SHADER_LIGHTING); + GPU_MATERIAL_STATE.bound_options = options; } -void GPU_simple_shader_unbind(void) +int GPU_basic_shader_bound_options(void) { - if (GPU_glsl_support()) { - GPU_shader_unbind(); - } - else { - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - glDisable(GL_TEXTURE_2D); - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); - } + /* ideally this should disappear, anything that uses this is making fragile + * assumptions that the basic shader is bound and not another shader */ + return GPU_MATERIAL_STATE.bound_options; } /* Material Colors */ -void GPU_simple_shader_colors(const float diffuse[3], const float specular[3], +void GPU_basic_shader_colors(const float diffuse[3], const float specular[3], int shininess, float alpha) { float gl_diffuse[4], gl_specular[4]; - copy_v3_v3(gl_diffuse, diffuse); + if (diffuse) + copy_v3_v3(gl_diffuse, diffuse); + else + zero_v3(gl_diffuse); gl_diffuse[3] = alpha; - copy_v3_v3(gl_specular, specular); + if (specular) + copy_v3_v3(gl_specular, specular); + else + zero_v3(gl_specular); gl_specular[3] = 1.0f; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, gl_diffuse); @@ -232,49 +245,81 @@ void GPU_simple_shader_colors(const float diffuse[3], const float specular[3], glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, CLAMPIS(shininess, 1, 128)); } -bool GPU_simple_shader_need_normals(void) -{ - return GPU_MATERIAL_STATE.need_normals; -} - -void GPU_simple_shader_light_set(int light_num, GPULightData *light) +void GPU_basic_shader_light_set(int light_num, GPULightData *light) { int light_bit = (1 << light_num); + /* note that light position is affected by the current modelview matrix! */ + GPU_MATERIAL_STATE.lights_enabled &= ~light_bit; GPU_MATERIAL_STATE.lights_directional &= ~light_bit; if (light) { - glEnable(GL_LIGHT0+light_num); + float position[4], diffuse[4], specular[4]; - glLightfv(GL_LIGHT0+light_num, GL_POSITION, light->position); - glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, light->diffuse); - glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, light->specular); + glEnable(GL_LIGHT0+light_num); - glLightf(GL_LIGHT0+light_num, GL_CONSTANT_ATTENUATION, light->constant_attenuation); - glLightf(GL_LIGHT0+light_num, GL_LINEAR_ATTENUATION, light->linear_attenuation); - glLightf(GL_LIGHT0+light_num, GL_QUADRATIC_ATTENUATION, light->quadratic_attenuation); + /* position */ + if (light->type == GPU_LIGHT_SUN) { + copy_v3_v3(position, light->direction); + position[3] = 0.0f; + } + else { + copy_v3_v3(position, light->position); + position[3] = 1.0f; + } + glLightfv(GL_LIGHT0+light_num, GL_POSITION, position); + + /* energy */ + copy_v3_v3(diffuse, light->diffuse); + copy_v3_v3(specular, light->specular); + diffuse[3] = 1.0f; + specular[3] = 1.0f; + glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, diffuse); + glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, specular); + + /* attenuation */ + if (light->type == GPU_LIGHT_SUN) { + glLightf(GL_LIGHT0+light_num, GL_CONSTANT_ATTENUATION, 1.0f); + glLightf(GL_LIGHT0+light_num, GL_LINEAR_ATTENUATION, 0.0f); + glLightf(GL_LIGHT0+light_num, GL_QUADRATIC_ATTENUATION, 0.0f); + } + else { + glLightf(GL_LIGHT0+light_num, GL_CONSTANT_ATTENUATION, light->constant_attenuation); + glLightf(GL_LIGHT0+light_num, GL_LINEAR_ATTENUATION, light->linear_attenuation); + glLightf(GL_LIGHT0+light_num, GL_QUADRATIC_ATTENUATION, light->quadratic_attenuation); + } - glLightfv(GL_LIGHT0+light_num, GL_SPOT_DIRECTION, light->spot_direction); - glLightf(GL_LIGHT0+light_num, GL_SPOT_CUTOFF, light->spot_cutoff); - glLightf(GL_LIGHT0+light_num, GL_SPOT_EXPONENT, light->spot_exponent); + /* spot */ + glLightfv(GL_LIGHT0+light_num, GL_SPOT_DIRECTION, light->direction); + if (light->type == GPU_LIGHT_SPOT) { + glLightf(GL_LIGHT0+light_num, GL_SPOT_CUTOFF, light->spot_cutoff); + glLightf(GL_LIGHT0+light_num, GL_SPOT_EXPONENT, light->spot_exponent); + } + else { + glLightf(GL_LIGHT0+light_num, GL_SPOT_CUTOFF, 180.0f); + glLightf(GL_LIGHT0+light_num, GL_SPOT_EXPONENT, 0.0f); + } GPU_MATERIAL_STATE.lights_enabled |= light_bit; - if (light->position[3] == 0.0f) + if (position[3] == 0.0f) GPU_MATERIAL_STATE.lights_directional |= light_bit; } else { - const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + if (USE_GLSL) { + /* glsl shader needs these zero to skip them */ + const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - glLightfv(GL_LIGHT0+light_num, GL_POSITION, zero); - glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, zero); - glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, zero); + glLightfv(GL_LIGHT0+light_num, GL_POSITION, zero); + glLightfv(GL_LIGHT0+light_num, GL_DIFFUSE, zero); + glLightfv(GL_LIGHT0+light_num, GL_SPECULAR, zero); + } glDisable(GL_LIGHT0+light_num); } } -void GPU_simple_shader_light_set_viewer(bool local) +void GPU_basic_shader_light_set_viewer(bool local) { glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (local)? GL_TRUE: GL_FALSE); } diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 69aca31e21a..3c44811324c 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -28,8 +28,7 @@ /** \file blender/gpu/intern/gpu_buffers.c * \ingroup gpu * - * Mesh drawing using OpenGL VBO (Vertex Buffer Objects), - * with fall-back to vertex arrays. + * Mesh drawing using OpenGL VBO (Vertex Buffer Objects) */ #include <limits.h> @@ -58,6 +57,7 @@ #include "GPU_buffers.h" #include "GPU_draw.h" +#include "GPU_basic_shader.h" #include "bmesh.h" @@ -101,7 +101,6 @@ const GPUBufferTypeSettings gpu_buffer_type_settings[] = { #define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n)) -/* -1 - undefined, 0 - vertex arrays, 1 - VBOs */ static GPUBufferState GLStates = 0; static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } }; @@ -527,6 +526,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object, if (!(buffer && (varray = glMapBuffer(target, GL_WRITE_ONLY)))) { if (buffer) gpu_buffer_free_intern(buffer); + BLI_mutex_unlock(&buffer_mutex); return NULL; } } @@ -864,10 +864,9 @@ void GPU_buffers_unbind(void) } if (GLStates & GPU_BUFFER_COLOR_STATE) glDisableClientState(GL_COLOR_ARRAY); - if (GLStates & GPU_BUFFER_ELEMENT_STATE) { - /* not guaranteed we used VBOs but in that case it's just a no-op */ + if (GLStates & GPU_BUFFER_ELEMENT_STATE) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } + GLStates &= ~(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE | GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE); @@ -881,7 +880,6 @@ void GPU_buffers_unbind(void) } attribData[0].index = -1; - /* not guaranteed we used VBOs but in that case it's just a no-op */ glBindBuffer(GL_ARRAY_BUFFER, 0); } @@ -1004,41 +1002,21 @@ struct GPU_PBVH_Buffers { BLI_bitmap * const *grid_hidden; const int *grid_indices; int totgrid; - int has_hidden; + bool has_hidden; - int use_bmesh; + bool use_bmesh; unsigned int tot_tri, tot_quad; /* The PBVH ensures that either all faces in the node are * smooth-shaded or all faces are flat-shaded */ - int smooth; + bool smooth; bool show_diffuse_color; bool use_matcaps; float diffuse_color[4]; }; -typedef enum { - VBO_ENABLED, - VBO_DISABLED -} VBO_State; - -static void gpu_colors_enable(VBO_State vbo_state) -{ - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glEnable(GL_COLOR_MATERIAL); - if (vbo_state == VBO_ENABLED) - glEnableClientState(GL_COLOR_ARRAY); -} - -static void gpu_colors_disable(VBO_State vbo_state) -{ - glDisable(GL_COLOR_MATERIAL); - if (vbo_state == VBO_ENABLED) - glDisableClientState(GL_COLOR_ARRAY); -} - static float gpu_color_from_mask(float mask) { return 1.0f - mask * 0.75f; @@ -1290,10 +1268,10 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, buffers->show_diffuse_color = show_diffuse_color; buffers->use_matcaps = GPU_material_use_matcaps_get(); + buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; /* Build VBO */ if (buffers->vert_buf) { - int smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; const int has_mask = key->has_mask; float diffuse_color[4] = {0.8f, 0.8f, 0.8f, 1.0f}; @@ -1318,7 +1296,7 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, CCGElem *elem = CCG_grid_elem(key, grid, x, y); copy_v3_v3(vd->co, CCG_elem_co(key, elem)); - if (smooth) { + if (buffers->smooth) { normal_float_to_short_v3(vd->no, CCG_elem_no(key, elem)); if (has_mask) { @@ -1330,7 +1308,7 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, } } - if (!smooth) { + if (!buffers->smooth) { /* for flat shading, recalc normals and set the last vertex of * each triangle in the index buffer to have the flat normal as * that is what opengl will use */ @@ -1383,8 +1361,6 @@ void GPU_update_grid_pbvh_buffers(GPU_PBVH_Buffers *buffers, CCGElem **grids, buffers->grid_flag_mats = grid_flag_mats; buffers->gridkey = *key; - buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; - //printf("node updated %p\n", buffers); } @@ -1525,7 +1501,7 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, if (totquad == fully_visible_totquad) { buffers->index_buf = gpu_get_grid_buffer(gridsize, &buffers->index_type, &buffers->tot_quad); - buffers->has_hidden = 0; + buffers->has_hidden = false; } else { buffers->tot_quad = totquad; @@ -1539,7 +1515,7 @@ GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers(int *grid_indices, int totgrid, FILL_QUAD_BUFFER(unsigned int, totquad, buffers->index_buf); } - buffers->has_hidden = 1; + buffers->has_hidden = true; } /* Build coord/normal VBO */ @@ -1819,7 +1795,7 @@ void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, } } -GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(int smooth_shading) +GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading) { GPU_PBVH_Buffers *buffers; @@ -1861,10 +1837,15 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, if (buffers->vert_buf) { char *base = NULL; char *index_base = NULL; + int bound_options = 0; glEnableClientState(GL_VERTEX_ARRAY); if (!wireframe) { glEnableClientState(GL_NORMAL_ARRAY); - gpu_colors_enable(VBO_ENABLED); + glEnableClientState(GL_COLOR_ARRAY); + + /* weak inspection of bound options, should not be necessary ideally */ + bound_options = GPU_basic_shader_bound_options(); + GPU_basic_shader_bind(bound_options | GPU_SHADER_USE_COLOR); } GPU_buffer_bind(buffers->vert_buf, GPU_BINDING_ARRAY); @@ -1943,7 +1924,8 @@ void GPU_draw_pbvh_buffers(GPU_PBVH_Buffers *buffers, DMSetMaterial setMaterial, glDisableClientState(GL_VERTEX_ARRAY); if (!wireframe) { glDisableClientState(GL_NORMAL_ARRAY); - gpu_colors_disable(VBO_ENABLED); + glDisableClientState(GL_COLOR_ARRAY); + GPU_basic_shader_bind(bound_options); } } } @@ -2059,8 +2041,6 @@ void GPU_init_draw_pbvh_BB(void) glEnableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); glEnable(GL_BLEND); } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index d479415556e..1db44c5b3a9 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -42,9 +42,11 @@ #include "BLI_dynstr.h" #include "BLI_ghash.h" +#include "GPU_extensions.h" #include "GPU_glew.h" #include "GPU_material.h" -#include "GPU_extensions.h" +#include "GPU_shader.h" +#include "GPU_texture.h" #include "BLI_sys_types.h" /* for intptr_t support */ @@ -829,10 +831,11 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv) for (input = node->inputs.first; input; input = input->next) { if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { if (input->attribtype == CD_MTFACE) { - BLI_dynstr_appendf(ds, "%s %s var%d;\n", + BLI_dynstr_appendf(ds, "%s %s var%d%s;\n", GLEW_VERSION_3_0 ? "in" : "varying", GPU_DATATYPE_STR[input->type], - input->attribid); + input->attribid, + GLEW_VERSION_3_0 ? "[]" : ""); BLI_dynstr_appendf(ds, "uniform int fvar%d_offset;\n", input->attribid); } @@ -997,18 +1000,21 @@ void GPU_pass_bind(GPUPass *pass, double time, int mipmap) GPU_shader_bind(shader); - /* now bind the textures */ + /* create the textures */ for (input = inputs->first; input; input = input->next) { if (input->ima) input->tex = GPU_texture_from_blender(input->ima, input->iuser, input->image_isdata, time, mipmap); else if (input->prv) input->tex = GPU_texture_from_preview(input->prv, mipmap); + } + /* bind the textures, in second loop so texture binding during + * create doesn't overwrite already bound textures */ + for (input = inputs->first; input; input = input->next) { if (input->tex && input->bindtex) { GPU_texture_bind(input->tex, input->texid); GPU_shader_uniform_texture(shader, input->shaderloc, input->tex); } - } } diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 1ad35c1edae..05968bf1e4c 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -47,10 +47,12 @@ #include "DNA_camera_types.h" #include "DNA_gpu_types.h" -#include "GPU_extensions.h" #include "GPU_compositing.h" - +#include "GPU_extensions.h" +#include "GPU_framebuffer.h" #include "GPU_glew.h" +#include "GPU_shader.h" +#include "GPU_texture.h" #include "MEM_guardedalloc.h" @@ -304,7 +306,7 @@ bool GPU_fx_compositor_initialize_passes( fx->effects = 0; - if (!GPU_non_power_of_two_support() || !GLEW_EXT_framebuffer_object) + if (!GLEW_EXT_framebuffer_object) return false; if (!fx_settings) { @@ -1082,12 +1084,12 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str { int invrendertargetdim_uniform, color_uniform, depth_uniform, dof_uniform; int viewvecs_uniform; - float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer), - 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)}; + float invrendertargetdim[2] = {1.0f / GPU_texture_width(fx->dof_near_coc_blurred_buffer), + 1.0f / GPU_texture_height(fx->dof_near_coc_blurred_buffer)}; float tmp = invrendertargetdim[0]; invrendertargetdim[0] = 0.0f; - dof_params[2] = GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor); + dof_params[2] = GPU_texture_width(fx->dof_near_coc_blurred_buffer) / (scale_camera * fx_dof->sensor); dof_uniform = GPU_shader_get_uniform(dof_shader_pass2, "dof_params"); invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass2, "invrendertargetdim"); @@ -1174,8 +1176,8 @@ bool GPU_fx_do_composite_pass(GPUFX *fx, float projmat[4][4], bool is_persp, str { int near_coc_downsampled; int invrendertargetdim_uniform; - float invrendertargetdim[2] = {1.0f / GPU_texture_opengl_width(fx->dof_near_coc_blurred_buffer), - 1.0f / GPU_texture_opengl_height(fx->dof_near_coc_blurred_buffer)}; + float invrendertargetdim[2] = {1.0f / GPU_texture_width(fx->dof_near_coc_blurred_buffer), + 1.0f / GPU_texture_height(fx->dof_near_coc_blurred_buffer)}; near_coc_downsampled = GPU_shader_get_uniform(dof_shader_pass4, "colorbuffer"); invrendertargetdim_uniform = GPU_shader_get_uniform(dof_shader_pass4, "invrendertargetdim"); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index aaf4037197e..05d11549656 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -49,6 +49,7 @@ #include "DNA_lamp_types.h" #include "DNA_material_types.h" +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_node_types.h" @@ -74,10 +75,13 @@ #include "BKE_subsurf.h" #include "BKE_DerivedMesh.h" +#include "GPU_basic_shader.h" #include "GPU_buffers.h" #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_material.h" +#include "GPU_shader.h" +#include "GPU_texture.h" #include "PIL_time.h" @@ -728,7 +732,7 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int /* scale if not a power of two. this is not strictly necessary for newer * GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures * Then don't bother scaling for hardware that supports NPOT textures! */ - if ((!GPU_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) || + if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) || is_over_resolution_limit(rectw, recth)) { rectw = smaller_power_of_2_limit(rectw); recth = smaller_power_of_2_limit(recth); @@ -753,12 +757,12 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int if (use_high_bit_depth) { if (GLEW_ARB_texture_float) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect); } else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); @@ -784,12 +788,12 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int ImBuf *mip = ibuf->mipmap[i - 1]; if (use_high_bit_depth) { if (GLEW_ARB_texture_float) - glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float); + glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16F_ARB, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float); else glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA16, mip->x, mip->y, 0, GL_RGBA, GL_FLOAT, mip->rect_float); } else { - glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect); + glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA8, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect); } } } @@ -804,8 +808,6 @@ void GPU_create_gl_tex(unsigned int *bind, unsigned int *rect, float *frect, int if (GLEW_EXT_texture_filter_anisotropic) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - /* set to modulate with vertex color */ - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if (ibuf) IMB_freeImBuf(ibuf); @@ -847,8 +849,6 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1)); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - if (GLEW_EXT_texture_filter_anisotropic) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); @@ -1002,7 +1002,7 @@ void GPU_paint_set_mipmap(bool mipmap) /* check if image has been downscaled and do scaled partial update */ static bool GPU_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h) { - if ((!GPU_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) || + if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) || is_over_resolution_limit(ibuf->x, ibuf->y)) { int x_limit = smaller_power_of_2_limit(ibuf->x); @@ -1403,9 +1403,10 @@ void GPU_free_images_old(void) /* OpenGL state caching for materials */ typedef struct GPUMaterialFixed { - float diff[4]; - float spec[4]; + float diff[3]; + float spec[3]; int hard; + float alpha; } GPUMaterialFixed; static struct GPUMaterialState { @@ -1414,7 +1415,7 @@ static struct GPUMaterialState { int totmat; /* set when called inside GPU_begin_object_materials / GPU_end_object_materials - * otherwise calling GPU_enable_material returns zero */ + * otherwise calling GPU_object_material_bind returns zero */ bool is_enabled; Material **gmatbuf; @@ -1430,6 +1431,7 @@ static struct GPUMaterialState { float (*gviewcamtexcofac); bool backface_culling; + bool two_sided_lighting; GPUBlendMode *alphablend; GPUBlendMode alphablend_fixed[FIXEDMAT]; @@ -1447,20 +1449,18 @@ static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat, { if (bmat->mode & MA_SHLESS) { copy_v3_v3(smat->diff, &bmat->r); - smat->diff[3] = 1.0; if (gamma) linearrgb_to_srgb_v3_v3(smat->diff, smat->diff); - zero_v4(smat->spec); + zero_v3(smat->spec); + smat->alpha = 1.0f; smat->hard = 0; } else if (new_shading_nodes) { copy_v3_v3(smat->diff, &bmat->r); - smat->diff[3] = 1.0; - copy_v3_v3(smat->spec, &bmat->specr); - smat->spec[3] = 1.0; + smat->alpha = 1.0f; smat->hard = CLAMPIS(bmat->har, 0, 128); if (dimdown) { @@ -1475,14 +1475,13 @@ static void gpu_material_to_fixed(GPUMaterialFixed *smat, const Material *bmat, } else { mul_v3_v3fl(smat->diff, &bmat->r, bmat->ref + bmat->emit); - smat->diff[3] = 1.0; /* caller may set this to bmat->alpha */ if (bmat->shade_flag & MA_OBCOLOR) mul_v3_v3(smat->diff, ob->col); mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec); - smat->spec[3] = 1.0; /* always 1 */ - smat->hard= CLAMPIS(bmat->har, 0, 128); + smat->hard = CLAMPIS(bmat->har, 1, 128); + smat->alpha = 1.0f; if (gamma) { linearrgb_to_srgb_v3_v3(smat->diff, smat->diff); @@ -1570,6 +1569,10 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O GMS.backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0; + GMS.two_sided_lighting = false; + if (ob && ob->type == OB_MESH) + GMS.two_sided_lighting = (((Mesh*)ob->data)->flag & ME_TWOSIDED) != 0; + GMS.gob = ob; GMS.gscene = scene; GMS.is_opensubdiv = use_opensubdiv; @@ -1648,11 +1651,11 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O gpu_material_to_fixed(&GMS.matbuf[a], ma, gamma, ob, new_shading_nodes, false); if (GMS.use_alpha_pass && ((ma->mode & MA_TRANSP) || (new_shading_nodes && ma->alpha != 1.0f))) { - GMS.matbuf[a].diff[3] = ma->alpha; + GMS.matbuf[a].alpha = ma->alpha; alphablend = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA; } else { - GMS.matbuf[a].diff[3] = 1.0f; + GMS.matbuf[a].alpha = 1.0f; alphablend = GPU_BLEND_SOLID; } } @@ -1668,7 +1671,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O } /* let's start with a clean state */ - GPU_disable_material(); + GPU_object_material_unbind(); } static int GPU_get_particle_info(GPUParticleInfo *pi) @@ -1701,7 +1704,7 @@ static int GPU_get_particle_info(GPUParticleInfo *pi) return 0; } -int GPU_enable_material(int nr, void *attribs) +int GPU_object_material_bind(int nr, void *attribs) { GPUVertexAttribs *gattribs = attribs; GPUMaterial *gpumat; @@ -1709,19 +1712,17 @@ int GPU_enable_material(int nr, void *attribs) /* no GPU_begin_object_materials, use default material */ if (!GMS.matbuf) { - float diff[4], spec[4]; - memset(&GMS, 0, sizeof(GMS)); - mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit); - diff[3] = 1.0; - - mul_v3_v3fl(spec, &defmaterial.specr, defmaterial.spec); - spec[3] = 1.0; + float diffuse[3], specular[3]; + mul_v3_v3fl(diffuse, &defmaterial.r, defmaterial.ref + defmaterial.emit); + mul_v3_v3fl(specular, &defmaterial.specr, defmaterial.spec); + GPU_basic_shader_colors(diffuse, specular, 35, 1.0f); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diff); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 35); /* blender default */ + if (GMS.two_sided_lighting) + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED); + else + GPU_basic_shader_bind(GPU_SHADER_LIGHTING); return 0; } @@ -1798,9 +1799,13 @@ int GPU_enable_material(int nr, void *attribs) } else { /* or do fixed function opengl material */ - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, GMS.matbuf[nr].diff); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, GMS.matbuf[nr].spec); - glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, GMS.matbuf[nr].hard); + GPU_basic_shader_colors(GMS.matbuf[nr].diff, + GMS.matbuf[nr].spec, GMS.matbuf[nr].hard, GMS.matbuf[nr].alpha); + + if (GMS.two_sided_lighting) + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_TWO_SIDED); + else + GPU_basic_shader_bind(GPU_SHADER_LIGHTING); } /* set (alpha) blending mode */ @@ -1810,6 +1815,31 @@ int GPU_enable_material(int nr, void *attribs) return GMS.lastretval; } +int GPU_object_material_visible(int nr, void *attribs) +{ + GPUVertexAttribs *gattribs = attribs; + int visible; + + if (!GMS.matbuf) + return 0; + + if (gattribs) + memset(gattribs, 0, sizeof(*gattribs)); + + if (nr>=GMS.totmat) + nr = 0; + + if (GMS.use_alpha_pass) { + visible = ELEM(GMS.alphablend[nr], GPU_BLEND_SOLID, GPU_BLEND_CLIP); + if (GMS.is_alpha_pass) + visible = !visible; + } + else + visible = !GMS.is_alpha_pass; + + return visible; +} + void GPU_set_material_alpha_blend(int alphablend) { if (GMS.lastalphablend == alphablend) @@ -1824,7 +1854,7 @@ int GPU_get_material_alpha_blend(void) return GMS.lastalphablend; } -void GPU_disable_material(void) +void GPU_object_material_unbind(void) { GMS.lastmatnr = -1; GMS.lastretval = 1; @@ -1837,6 +1867,8 @@ void GPU_disable_material(void) GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv)); GMS.gboundmat = NULL; } + else + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); GPU_set_material_alpha_blend(GPU_BLEND_SOLID); } @@ -1852,7 +1884,8 @@ void GPU_material_diffuse_get(int nr, float diff[4]) mul_v3_v3fl(diff, &defmaterial.r, defmaterial.ref + defmaterial.emit); } else { - copy_v4_v4(diff, GMS.matbuf[nr].diff); + copy_v3_v3(diff, GMS.matbuf[nr].diff); + diff[3] = GMS.matbuf[nr].alpha; } } @@ -1868,7 +1901,7 @@ bool GPU_object_materials_check(void) void GPU_end_object_materials(void) { - GPU_disable_material(); + GPU_object_material_unbind(); GMS.is_enabled = false; @@ -1881,6 +1914,7 @@ void GPU_end_object_materials(void) GMS.matbuf = NULL; GMS.gmatbuf = NULL; GMS.alphablend = NULL; + GMS.two_sided_lighting = false; /* resetting the texture matrix after the scaling needed for tiled textures */ if (GTS.tilemode) { @@ -1894,7 +1928,6 @@ void GPU_end_object_materials(void) int GPU_default_lights(void) { - float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f}, position[4]; int a, count = 0; /* initialize */ @@ -1918,42 +1951,25 @@ int GPU_default_lights(void) U.light[2].spec[3] = 1.0; } - glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE); + GPU_basic_shader_light_set_viewer(false); for (a = 0; a < 8; a++) { - if (a < 3) { - if (U.light[a].flag) { - glEnable(GL_LIGHT0 + a); + if (a < 3 && U.light[a].flag) { + GPULightData light = {0}; - normalize_v3_v3(position, U.light[a].vec); - position[3] = 0.0f; - - glLightfv(GL_LIGHT0 + a, GL_POSITION, position); - glLightfv(GL_LIGHT0 + a, GL_DIFFUSE, U.light[a].col); - glLightfv(GL_LIGHT0 + a, GL_SPECULAR, U.light[a].spec); + light.type = GPU_LIGHT_SUN; - count++; - } - else { - glDisable(GL_LIGHT0 + a); + normalize_v3_v3(light.direction, U.light[a].vec); + copy_v3_v3(light.diffuse, U.light[a].col); + copy_v3_v3(light.specular, U.light[a].spec); - glLightfv(GL_LIGHT0 + a, GL_POSITION, zero); - glLightfv(GL_LIGHT0 + a, GL_DIFFUSE, zero); - glLightfv(GL_LIGHT0 + a, GL_SPECULAR, zero); - } + GPU_basic_shader_light_set(a, &light); - /* clear stuff from other opengl lamp usage */ - glLightf(GL_LIGHT0 + a, GL_SPOT_CUTOFF, 180.0); - glLightf(GL_LIGHT0 + a, GL_CONSTANT_ATTENUATION, 1.0); - glLightf(GL_LIGHT0 + a, GL_LINEAR_ATTENUATION, 0.0); + count++; } else - glDisable(GL_LIGHT0 + a); + GPU_basic_shader_light_set(a, NULL); } - - glDisable(GL_LIGHTING); - - glDisable(GL_COLOR_MATERIAL); return count; } @@ -1963,15 +1979,14 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ Base *base; Lamp *la; int count; - float position[4], direction[4], energy[4]; /* disable all lights */ for (count = 0; count < 8; count++) - glDisable(GL_LIGHT0 + count); + GPU_basic_shader_light_set(count, NULL); /* view direction for specular is not computed correct by default in * opengl, so we set the settings ourselfs */ - glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, ortho ? GL_FALSE : GL_TRUE); + GPU_basic_shader_light_set_viewer(!ortho); count = 0; @@ -1988,41 +2003,37 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][ glPushMatrix(); glLoadMatrixf((float *)viewmat); - if (la->type == LA_SUN) { - /* sun lamp */ - copy_v3_v3(direction, base->object->obmat[2]); - direction[3] = 0.0; + /* setup light */ + GPULightData light = {0}; - glLightfv(GL_LIGHT0+count, GL_POSITION, direction); + mul_v3_v3fl(light.diffuse, &la->r, la->energy); + mul_v3_v3fl(light.specular, &la->r, la->energy); + + if (la->type == LA_SUN) { + /* directional sun light */ + light.type = GPU_LIGHT_SUN; + normalize_v3_v3(light.direction, base->object->obmat[2]); } else { - /* other lamps with attenuation */ - copy_v3_v3(position, base->object->obmat[3]); - position[3] = 1.0f; - - glLightfv(GL_LIGHT0+count, GL_POSITION, position); - glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0); - glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1 / la->dist); - glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2 / (la->dist * la->dist)); + /* other lamps with position attenuation */ + copy_v3_v3(light.position, base->object->obmat[3]); + + light.constant_attenuation = 1.0f; + light.linear_attenuation = la->att1 / la->dist; + light.quadratic_attenuation = la->att2 / (la->dist * la->dist); if (la->type == LA_SPOT) { - /* spot lamp */ - negate_v3_v3(direction, base->object->obmat[2]); - glLightfv(GL_LIGHT0 + count, GL_SPOT_DIRECTION, direction); - glLightf(GL_LIGHT0 + count, GL_SPOT_CUTOFF, RAD2DEGF(la->spotsize * 0.5f)); - glLightf(GL_LIGHT0 + count, GL_SPOT_EXPONENT, 128.0f * la->spotblend); + light.type = GPU_LIGHT_SPOT; + negate_v3_v3(light.direction, base->object->obmat[2]); + normalize_v3(light.direction); + light.spot_cutoff = RAD2DEGF(la->spotsize * 0.5f); + light.spot_exponent = 128.0f * la->spotblend; } else - glLightf(GL_LIGHT0 + count, GL_SPOT_CUTOFF, 180.0); + light.type = GPU_LIGHT_POINT; } - /* setup energy */ - mul_v3_v3fl(energy, &la->r, la->energy); - energy[3] = 1.0; - - glLightfv(GL_LIGHT0 + count, GL_DIFFUSE, energy); - glLightfv(GL_LIGHT0 + count, GL_SPECULAR, energy); - glEnable(GL_LIGHT0 + count); + GPU_basic_shader_light_set(count, &light); glPopMatrix(); @@ -2063,11 +2074,15 @@ static void gpu_multisample(bool enable) #endif } -/* Default OpenGL State */ +/* Default OpenGL State + * + * This is called on startup, for opengl offscreen render and to restore state + * for the game engine. Generally we should always return to this state when + * temporarily modifying the state for drawing, though that are (undocumented) + * exceptions that we should try to get rid of. */ void GPU_state_init(void) { - /* also called when doing opengl rendering and in the game engine */ float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 }; float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 }; int a, x, y; @@ -2078,6 +2093,7 @@ void GPU_state_init(void) glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 35); + glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); GPU_default_lights(); @@ -2092,6 +2108,7 @@ void GPU_state_init(void) glDisable(GL_DEPTH_TEST); glDisable(GL_FOG); glDisable(GL_LIGHTING); + glDisable(GL_COLOR_MATERIAL); glDisable(GL_LOGIC_OP); glDisable(GL_STENCIL_TEST); glDisable(GL_TEXTURE_1D); @@ -2136,6 +2153,8 @@ void GPU_state_init(void) glDisable(GL_CULL_FACE); gpu_multisample(false); + + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } #ifdef WITH_OPENSUBDIV diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 3ff8ab5b4c8..c855c53ace4 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -32,9 +32,6 @@ * with checks for drivers and GPU support. */ - -#include "DNA_image_types.h" - #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" @@ -44,12 +41,11 @@ #include "BKE_global.h" -#include "GPU_glew.h" -#include "GPU_debug.h" +#include "GPU_basic_shader.h" #include "GPU_draw.h" #include "GPU_extensions.h" -#include "GPU_compositing.h" -#include "GPU_simple_shader.h" +#include "GPU_glew.h" +#include "GPU_texture.h" #include "intern/gpu_private.h" @@ -61,17 +57,14 @@ # include "BLI_winstuff.h" #endif -/* TODO(sergey): Find better default values for this constants. */ -#define MAX_DEFINE_LENGTH 1024 -#define MAX_EXT_DEFINE_LENGTH 1024 - /* Extensions support */ /* -- extension: version of GL that absorbs it * ARB_fragment_program: 2.0 * ARB_framebuffer object: 3.0 - * EXT_framebuffer_multisample: 3.0 + * EXT_framebuffer_object: 3.0 * EXT_framebuffer_blit: 3.0 + * EXT_framebuffer_multisample: 3.0 * EXT_framebuffer_multisample_blit_scaled: ??? * ARB_draw_instanced: 3.1 * ARB_texture_multisample: 3.2 @@ -79,64 +72,20 @@ * ARB_texture_query_lod: 4.0 */ -/* Non-generated shaders */ -extern char datatoc_gpu_program_smoke_frag_glsl[]; -extern char datatoc_gpu_program_smoke_color_frag_glsl[]; -extern char datatoc_gpu_shader_vsm_store_vert_glsl[]; -extern char datatoc_gpu_shader_vsm_store_frag_glsl[]; -extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[]; -extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[]; -extern char datatoc_gpu_shader_fx_vert_glsl[]; -extern char datatoc_gpu_shader_fx_ssao_frag_glsl[]; -extern char datatoc_gpu_shader_fx_dof_frag_glsl[]; -extern char datatoc_gpu_shader_fx_dof_vert_glsl[]; -extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[]; -extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[]; -extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[]; -extern char datatoc_gpu_shader_fx_depth_resolve_glsl[]; -extern char datatoc_gpu_shader_fx_lib_glsl[]; - -typedef struct GPUShaders { - GPUShader *vsm_store; - GPUShader *sep_gaussian_blur; - GPUProgram *smoke; - GPUProgram *smoke_colored; - /* cache for shader fx. Those can exist in combinations so store them here */ - GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; -} GPUShaders; - static struct GPUGlobal { GLint maxtexsize; GLint maxtextures; - GLuint currentfb; - int glslsupport; - int extdisabled; + bool extdisabled; int colordepth; int samples_color_texture_max; - int npotdisabled; /* ATI 3xx-5xx (and more) chipsets support NPoT partially (== not enough) */ - int dlistsdisabled; /* Legacy ATI driver does not support display lists well */ GPUDeviceType device; GPUOSType os; GPUDriverType driver; - GPUShaders shaders; - GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */ - GPUTexture *invalid_tex_2D; - GPUTexture *invalid_tex_3D; float dfdyfactors[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers calculate dfdy in shader differently when drawing to an offscreen buffer. First number is factor on screen and second is off-screen */ } GG = {1, 0}; -/* Number of maximum output slots. We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */ -#define GPU_FB_MAX_SLOTS 4 - -struct GPUFrameBuffer { - GLuint object; - GPUTexture *colortex[GPU_FB_MAX_SLOTS]; - GPUTexture *depthtex; -}; - - /* GPU Types */ bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver) @@ -148,7 +97,7 @@ bool GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver) void GPU_extensions_disable(void) { - GG.extdisabled = 1; + GG.extdisabled = true; } int GPU_max_texture_size(void) @@ -156,6 +105,16 @@ int GPU_max_texture_size(void) return GG.maxtexsize; } +int GPU_max_textures(void) +{ + return GG.maxtextures; +} + +int GPU_max_color_texture_samples(void) +{ + return GG.samples_color_texture_max; +} + void GPU_get_dfdy_factors(float fac[2]) { copy_v2_v2(fac, GG.dfdyfactors); @@ -163,9 +122,6 @@ void GPU_get_dfdy_factors(float fac[2]) void gpu_extensions_init(void) { - GLint r, g, b; - const char *vendor, *renderer, *version; - /* BLI_assert(GLEW_VERSION_2_1); */ /* ^-- maybe a bit extreme? */ @@ -173,8 +129,7 @@ void gpu_extensions_init(void) glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GG.maxtexsize); - GG.glslsupport = 1; - + GLint r, g, b; glGetIntegerv(GL_RED_BITS, &r); glGetIntegerv(GL_GREEN_BITS, &g); glGetIntegerv(GL_BLUE_BITS, &b); @@ -184,9 +139,9 @@ void gpu_extensions_init(void) glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES , &GG.samples_color_texture_max); } - vendor = (const char *)glGetString(GL_VENDOR); - renderer = (const char *)glGetString(GL_RENDERER); - version = (const char *)glGetString(GL_VERSION); + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + const char *version = (const char *)glGetString(GL_VERSION); if (strstr(vendor, "ATI")) { GG.device = GPU_DEVICE_ATI; @@ -263,2048 +218,85 @@ void gpu_extensions_init(void) GPU_invalid_tex_init(); - GPU_simple_shaders_init(); + GPU_basic_shaders_init(); } void gpu_extensions_exit(void) { - GPU_simple_shaders_exit(); + GPU_basic_shaders_exit(); GPU_invalid_tex_free(); } -bool GPU_glsl_support(void) -{ - return GG.glslsupport; -} - -bool GPU_non_power_of_two_support(void) -{ - /* still relevant for OpenGL ES */ - return !GG.npotdisabled; -} - -bool GPU_display_list_support(void) -{ - return !GG.dlistsdisabled; -} - -bool GPU_bicubic_bump_support(void) -{ - return GLEW_VERSION_4_0 || (GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0); -} - - -bool GPU_geometry_shader_support(void) -{ - /* in GL 3.2 geometry shaders are fully supported - * core profile clashes with our other shaders so accept compatibility only - * other GL versions can use EXT_geometry_shader4 if available - */ - return (GLEW_VERSION_3_2 && GLEW_ARB_compatibility) || GLEW_EXT_geometry_shader4; -} - -static bool GPU_geometry_shader_support_via_extension(void) -{ - return GLEW_EXT_geometry_shader4 && !(GLEW_VERSION_3_2 && GLEW_ARB_compatibility); -} - -bool GPU_instanced_drawing_support(void) -{ - return GLEW_VERSION_3_1 || GLEW_ARB_draw_instanced; -} - -int GPU_color_depth(void) -{ - return GG.colordepth; -} - -static void GPU_print_framebuffer_error(GLenum status, char err_out[256]) -{ - const char *err = "unknown"; - - switch (status) { - case GL_FRAMEBUFFER_COMPLETE_EXT: - break; - case GL_INVALID_OPERATION: - err = "Invalid operation"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - err = "Incomplete attachment"; - break; - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - err = "Unsupported framebuffer format"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - err = "Missing attachment"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - err = "Attached images must have same dimensions"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - err = "Attached images must have same format"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - err = "Missing draw buffer"; - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - err = "Missing read buffer"; - break; - } - - if (err_out) { - BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'", - (int)status, err); - } - else { - fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n", - (int)status, err); - } -} - -/* GPUTexture */ - -struct GPUTexture { - int w, h; /* width/height */ - int w_orig, h_orig; /* width/height (before power of 2 is applied) */ - int number; /* number for multitexture binding */ - int refcount; /* reference count */ - GLenum target; /* GL_TEXTURE_* */ - GLenum target_base; /* same as target, (but no multisample) */ - GLuint bindcode; /* opengl identifier for texture */ - int fromblender; /* we got the texture from Blender */ - - GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ - int fb_attachment; /* slot the texture is attached to */ - int depth; /* is a depth texture? if 3D how deep? */ - int depth_orig; /* depth (before power of 2 is applied) */ -}; - -static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels) -{ - unsigned char *pixels, *p; - const float *fp = fpixels; - const int len = 4 * length; - int a; - - p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels"); - - for (a = 0; a < len; a++, p++, fp++) - *p = FTOCHAR((*fp)); - - return pixels; -} - -static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h) -{ - void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels"); - - if (target == GL_TEXTURE_1D) - glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels); - else - glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels); - - MEM_freeN(pixels); -} - -static GPUTexture *GPU_texture_create_nD( - int w, int h, int n, const float *fpixels, int depth, - GPUHDRType hdr_type, int components, int samples, - char err_out[256]) -{ - GPUTexture *tex; - GLenum type, format, internalformat; - void *pixels = NULL; - - if (samples) { - CLAMP_MAX(samples, GG.samples_color_texture_max); - } - - tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->w = tex->w_orig = w; - tex->h = tex->h_orig = h; - tex->number = -1; - tex->refcount = 1; - tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); - tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D; - tex->depth = tex->depth_orig = depth; - tex->fb_attachment = -1; - - glGenTextures(1, &tex->bindcode); - - if (!tex->bindcode) { - if (err_out) { - BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d", - (int)glGetError()); - } - else { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); - } - GPU_texture_free(tex); - return NULL; - } - - if (!GPU_non_power_of_two_support()) { - tex->w = power_of_2_max_i(tex->w); - tex->h = power_of_2_max_i(tex->h); - } - - tex->number = 0; - glBindTexture(tex->target, tex->bindcode); - - if (depth) { - type = GL_UNSIGNED_BYTE; - format = GL_DEPTH_COMPONENT; - internalformat = GL_DEPTH_COMPONENT; - } - else { - type = GL_FLOAT; - - if (components == 4) { - format = GL_RGBA; - switch (hdr_type) { - case GPU_HDR_NONE: - internalformat = GL_RGBA8; - break; - case GPU_HDR_HALF_FLOAT: - internalformat = GL_RGBA16F; - break; - case GPU_HDR_FULL_FLOAT: - internalformat = GL_RGBA32F; - break; - default: - break; - } - } - else if (components == 2) { - format = GL_RG; - switch (hdr_type) { - case GPU_HDR_NONE: - internalformat = GL_RG8; - break; - case GPU_HDR_HALF_FLOAT: - internalformat = GL_RG16F; - break; - case GPU_HDR_FULL_FLOAT: - internalformat = GL_RG32F; - break; - default: - break; - } - } - - if (fpixels && hdr_type == GPU_HDR_NONE) { - type = GL_UNSIGNED_BYTE; - pixels = GPU_texture_convert_pixels(w*h, fpixels); - } - } - - if (tex->target == GL_TEXTURE_1D) { - glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL); - - if (fpixels) { - glTexSubImage1D(tex->target, 0, 0, w, format, type, - pixels ? pixels : fpixels); - - if (tex->w > w) - GPU_glTexSubImageEmpty(tex->target, format, w, 0, - tex->w-w, 1); - } - } - else { - if (samples) { - glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true); - } - else { - glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, - format, type, NULL); - } - - if (fpixels) { - glTexSubImage2D(tex->target, 0, 0, 0, w, h, - format, type, pixels ? pixels : fpixels); - - if (tex->w > w) - GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, tex->h); - if (tex->h > h) - GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h-h); - } - } - - if (pixels) - MEM_freeN(pixels); - - if (depth) { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); - } - else { - glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (tex->target_base != GL_TEXTURE_1D) { - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - else - glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - - return tex; -} - - -GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels) -{ - GPUTexture *tex; - GLenum type, format, internalformat; - void *pixels = NULL; - int r_width; - bool rescale = false; - - if (!GLEW_VERSION_1_2) - return NULL; - - tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->w = tex->w_orig = w; - tex->h = tex->h_orig = h; - tex->depth = tex->depth_orig = depth; - tex->number = -1; - tex->refcount = 1; - tex->target = GL_TEXTURE_3D; - tex->target_base = GL_TEXTURE_3D; - - glGenTextures(1, &tex->bindcode); - - if (!tex->bindcode) { - fprintf(stderr, "GPUTexture: texture create failed: %d\n", - (int)glGetError()); - GPU_texture_free(tex); - return NULL; - } - - if (!GPU_non_power_of_two_support()) { - tex->w = power_of_2_max_i(tex->w); - tex->h = power_of_2_max_i(tex->h); - tex->depth = power_of_2_max_i(tex->depth); - } - - tex->number = 0; - glBindTexture(tex->target, tex->bindcode); - - GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture"); - - type = GL_FLOAT; - if (channels == 4) { - format = GL_RGBA; - internalformat = GL_RGBA; - } - else { - format = GL_RED; - internalformat = GL_INTENSITY; - } - - /* 3D textures are quite heavy, test if it's possible to create them first */ - glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); - glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); - - while (r_width == 0) { - rescale = true; - tex->w /= 2; - tex->h /= 2; - tex->depth /= 2; - glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); - glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); - } - - /* really unlikely to happen but keep this just in case */ - tex->w = max_ii(tex->w, 1); - tex->h = max_ii(tex->h, 1); - tex->depth = max_ii(tex->depth, 1); - -#if 0 - if (fpixels) - pixels = GPU_texture_convert_pixels(w*h*depth, fpixels); -#endif - - GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D"); - - /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it - * for gooseberry */ - if (rescale && fpixels) { - unsigned int i, j, k; - unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth; - float *tex3d = MEM_mallocN(channels * sizeof(float)*tex->w*tex->h*tex->depth, "tex3d"); - - GPU_print_error_debug("You need to scale a 3D texture, feel the pain!"); - - for (k = 0; k < tex->depth; k++) { - for (j = 0; j < tex->h; j++) { - for (i = 0; i < tex->w; i++) { - /* obviously doing nearest filtering here, it's going to be slow in any case, let's not make it worse */ - float xb = i * xf; - float yb = j * yf; - float zb = k * zf; - unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j; - unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb); - - if (channels == 4) { - tex3d[offset * 4] = fpixels[offset_orig * 4]; - tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1]; - tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2]; - tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3]; - } - else - tex3d[offset] = fpixels[offset_orig]; - } - } - } - - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d); - - MEM_freeN(tex3d); - } - else { - if (fpixels) { - if (!GPU_non_power_of_two_support() && (w != tex->w || h != tex->h || depth != tex->depth)) { - /* clear first to avoid unitialized pixels */ - float *zero= MEM_callocN(sizeof(float)*tex->w*tex->h*tex->depth, "zero"); - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); - glTexSubImage3D(tex->target, 0, 0, 0, 0, tex->w, tex->h, tex->depth, GL_INTENSITY, GL_FLOAT, zero); - glTexSubImage3D(tex->target, 0, 0, 0, 0, w, h, depth, format, type, fpixels); - MEM_freeN(zero); - } - else { - glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels); - } - - GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D"); - } - } - - - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - - if (pixels) - MEM_freeN(pixels); - - GPU_texture_unbind(tex); - - return tex; -} - -GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data, double time, int mipmap) -{ - GPUTexture *tex; - GLint w, h, border, lastbindcode, bindcode; - - glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode); - - GPU_update_image_time(ima, time); - /* this binds a texture, so that's why to restore it with lastbindcode */ - bindcode = GPU_verify_image(ima, iuser, 0, 0, mipmap, is_data); - - if (ima->gputexture) { - ima->gputexture->bindcode = bindcode; - glBindTexture(GL_TEXTURE_2D, lastbindcode); - return ima->gputexture; - } - - tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->bindcode = bindcode; - tex->number = -1; - tex->refcount = 1; - tex->target = GL_TEXTURE_2D; - tex->target_base = GL_TEXTURE_2D; - tex->fromblender = 1; - - ima->gputexture= tex; - - if (!glIsTexture(tex->bindcode)) { - GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); - } - else { - glBindTexture(GL_TEXTURE_2D, tex->bindcode); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border); - - tex->w = tex->w_orig = w - border; - tex->h = tex->h_orig = h - border; - } - - glBindTexture(GL_TEXTURE_2D, lastbindcode); - - return tex; -} - -GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) -{ - GPUTexture *tex = prv->gputexture[0]; - GLint w, h, lastbindcode; - GLuint bindcode = 0; - - glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode); - - if (tex) - bindcode = tex->bindcode; - - /* this binds a texture, so that's why to restore it */ - if (bindcode == 0) { - GPU_create_gl_tex(&bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], mipmap, 0, NULL); - } - if (tex) { - tex->bindcode = bindcode; - glBindTexture(GL_TEXTURE_2D, lastbindcode); - return tex; - } - - tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); - tex->bindcode = bindcode; - tex->number = -1; - tex->refcount = 1; - tex->target = GL_TEXTURE_2D; - tex->target_base = GL_TEXTURE_2D; - - prv->gputexture[0] = tex; - - if (!glIsTexture(tex->bindcode)) { - GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); - } - else { - glBindTexture(GL_TEXTURE_2D, tex->bindcode); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); - - tex->w = tex->w_orig = w; - tex->h = tex->h_orig = h; - } - - glBindTexture(GL_TEXTURE_2D, lastbindcode); - - return tex; - -} - -GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; -} - -GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; -} -GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; -} - -GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; -} -GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out); - - if (tex) - GPU_texture_unbind(tex); - - return tex; -} - -/** - * A shadow map for VSM needs two components (depth and depth^2) - */ -GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out); - - if (tex) { - /* Now we tweak some of the settings */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - GPU_texture_unbind(tex); - } - - return tex; -} - -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); - - if (tex) { - /* Now we tweak some of the settings */ - if (repeat) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - GPU_texture_unbind(tex); - } - - return tex; -} - -GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]) -{ - GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); - - if (tex) { - /* Now we tweak some of the settings */ - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - GPU_texture_unbind(tex); - } - - return tex; -} - -void GPU_invalid_tex_init(void) -{ - const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f}; - GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL); - GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL); - GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color); -} - -void GPU_invalid_tex_bind(int mode) -{ - switch (mode) { - case GL_TEXTURE_1D: - glBindTexture(GL_TEXTURE_1D, GG.invalid_tex_1D->bindcode); - break; - case GL_TEXTURE_2D: - glBindTexture(GL_TEXTURE_2D, GG.invalid_tex_2D->bindcode); - break; - case GL_TEXTURE_3D: - glBindTexture(GL_TEXTURE_3D, GG.invalid_tex_3D->bindcode); - break; - } -} - -void GPU_invalid_tex_free(void) -{ - if (GG.invalid_tex_1D) - GPU_texture_free(GG.invalid_tex_1D); - if (GG.invalid_tex_2D) - GPU_texture_free(GG.invalid_tex_2D); - if (GG.invalid_tex_3D) - GPU_texture_free(GG.invalid_tex_3D); -} - - -void GPU_texture_bind(GPUTexture *tex, int number) +bool GPU_legacy_support(void) { - GLenum arbnumber; - - if (number >= GG.maxtextures) { - fprintf(stderr, "Not enough texture slots.\n"); - return; - } - - if ((G.debug & G_DEBUG)) { - if (tex->fb && tex->fb->object == GG.currentfb) { - fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n"); - } - } - - if (number < 0) - return; - - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind"); - - arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); - if (number != 0) glActiveTexture(arbnumber); - if (tex->bindcode != 0) { - glBindTexture(tex->target, tex->bindcode); - } - else - GPU_invalid_tex_bind(tex->target); - glEnable(tex->target); - if (number != 0) glActiveTexture(GL_TEXTURE0); - - tex->number = number; - - GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind"); -} + // return whether or not current GL context is compatible with legacy OpenGL -void GPU_texture_unbind(GPUTexture *tex) -{ - GLenum arbnumber; - - if (tex->number >= GG.maxtextures) { - fprintf(stderr, "Not enough texture slots.\n"); - return; - } - - if (tex->number == -1) - return; - - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); - - arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); - glBindTexture(tex->target, 0); - glDisable(tex->target_base); - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); - - tex->number = -1; - - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); -} - -void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) -{ - GLenum arbnumber; - - if (tex->number >= GG.maxtextures) { - fprintf(stderr, "Not enough texture slots.\n"); - return; - } - - if (tex->number == -1) - return; - - GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); - - arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - if (tex->number != 0) glActiveTexture(arbnumber); - - if (tex->depth) { - if (compare) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - - if (use_filter) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); - - GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); -} - -void GPU_texture_free(GPUTexture *tex) -{ - tex->refcount--; - - if (tex->refcount < 0) - fprintf(stderr, "GPUTexture: negative refcount\n"); - - if (tex->refcount == 0) { - if (tex->fb) - GPU_framebuffer_texture_detach(tex); - if (tex->bindcode && !tex->fromblender) - glDeleteTextures(1, &tex->bindcode); - - MEM_freeN(tex); - } -} - -void GPU_texture_ref(GPUTexture *tex) -{ - tex->refcount++; -} - -int GPU_texture_target(const GPUTexture *tex) -{ - return tex->target; -} - -int GPU_texture_opengl_width(const GPUTexture *tex) -{ - return tex->w; -} - -int GPU_texture_opengl_height(const GPUTexture *tex) -{ - return tex->h; -} - -int GPU_texture_opengl_bindcode(const GPUTexture *tex) -{ - return tex->bindcode; -} - -GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex) -{ - return tex->fb; -} - -/* GPUFrameBuffer */ - -GPUFrameBuffer *GPU_framebuffer_create(void) -{ - GPUFrameBuffer *fb; - - if (!GLEW_EXT_framebuffer_object) - return NULL; - - fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); - glGenFramebuffersEXT(1, &fb->object); - - if (!fb->object) { - fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n", - (int)glGetError()); - GPU_framebuffer_free(fb); - return NULL; - } - - /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - glReadBuffer(GL_NONE); - glDrawBuffer(GL_NONE); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - return fb; -} - -int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]) -{ - GLenum attachment; - GLenum error; - - if (slot >= GPU_FB_MAX_SLOTS) { - fprintf(stderr, - "Attaching to index %d framebuffer slot unsupported. " - "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); - return 0; - } + if (GLEW_VERSION_3_2) { + static GLint profile = 0; - if ((G.debug & G_DEBUG)) { - if (tex->number != -1) { - fprintf(stderr, - "Feedback loop warning!: " - "Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n"); + if (profile == 0) { + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile); } - } - - if (tex->depth) - attachment = GL_DEPTH_ATTACHMENT_EXT; - else - attachment = GL_COLOR_ATTACHMENT0_EXT + slot; - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - GG.currentfb = fb->object; - - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, - tex->target, tex->bindcode, 0); - error = glGetError(); - - if (error == GL_INVALID_OPERATION) { - GPU_framebuffer_restore(); - GPU_print_framebuffer_error(error, err_out); - return 0; + return profile & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT; } - - if (tex->depth) - fb->depthtex = tex; - else - fb->colortex[slot] = tex; - - tex->fb= fb; - tex->fb_attachment = slot; - - return 1; -} - -void GPU_framebuffer_texture_detach(GPUTexture *tex) -{ - GLenum attachment; - GPUFrameBuffer *fb; - - if (!tex->fb) - return; - - fb = tex->fb; - - if (GG.currentfb != fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - GG.currentfb = tex->fb->object; - } - - if (tex->depth) { - fb->depthtex = NULL; - attachment = GL_DEPTH_ATTACHMENT_EXT; - } - else { - BLI_assert(fb->colortex[tex->fb_attachment] == tex); - fb->colortex[tex->fb_attachment] = NULL; - attachment = GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment; - } - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, tex->target, 0, 0); - - tex->fb = NULL; - tex->fb_attachment = -1; -} - -void GPU_texture_bind_as_framebuffer(GPUTexture *tex) -{ - if (!tex->fb) { - fprintf(stderr, "Error, texture not bound to framebuffer!\n"); - return; - } - - /* push attributes */ - glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); - glDisable(GL_SCISSOR_TEST); - - /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, tex->fb->object); - - if (tex->depth) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); + else if (GLEW_VERSION_3_1) { + return GLEW_ARB_compatibility; } else { - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + tex->fb_attachment); - } - - if (tex->target == GL_TEXTURE_2D_MULTISAMPLE) { - glEnable(GL_MULTISAMPLE); - } - - /* push matrices and set default viewport and matrix */ - glViewport(0, 0, tex->w_orig, tex->h_orig); - GG.currentfb = tex->fb->object; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); -} - -void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) -{ - int numslots = 0, i; - GLenum attachments[4]; - - if (!fb->colortex[slot]) { - fprintf(stderr, "Error, framebuffer slot empty!\n"); - return; - } - - for (i = 0; i < 4; i++) { - if (fb->colortex[i]) { - attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i; - numslots++; - } + return true; } - - /* push attributes */ - glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); - glDisable(GL_SCISSOR_TEST); - - /* bind framebuffer */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffers(numslots, attachments); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); - - /* push matrices and set default viewport and matrix */ - glViewport(0, 0, fb->colortex[slot]->w_orig, fb->colortex[slot]->h_orig); - GG.currentfb = fb->object; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); } - -void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) -{ - /* restore matrix */ - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - /* restore attributes */ - glPopAttrib(); -} - -void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) -{ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); - - /* push matrices and set default viewport and matrix */ - glViewport(0, 0, fb->colortex[slot]->w_orig, fb->colortex[slot]->h_orig); - GG.currentfb = fb->object; - GG.currentfb = fb->object; -} - -bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) +bool GPU_glsl_support(void) { - GLenum status; - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - GG.currentfb = fb->object; - - /* Clean glError buffer. */ - while (glGetError() != GL_NO_ERROR) {} - - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - GPU_framebuffer_restore(); - GPU_print_framebuffer_error(status, err_out); - return false; - } - + /* always supported, still queried by game engine */ return true; } -void GPU_framebuffer_free(GPUFrameBuffer *fb) +bool GPU_full_non_power_of_two_support(void) { - int i; - if (fb->depthtex) - GPU_framebuffer_texture_detach(fb->depthtex); - - for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { - if (fb->colortex[i]) { - GPU_framebuffer_texture_detach(fb->colortex[i]); - } - } - - if (fb->object) { - glDeleteFramebuffersEXT(1, &fb->object); - - if (GG.currentfb == fb->object) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - GG.currentfb = 0; - } - } - - MEM_freeN(fb); -} - -void GPU_framebuffer_restore(void) -{ - if (GG.currentfb != 0) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - GG.currentfb = 0; - } -} - -void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex) -{ - const float scaleh[2] = {1.0f / blurtex->w_orig, 0.0f}; - const float scalev[2] = {0.0f, 1.0f / tex->h_orig}; - - GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); - int scale_uniform, texture_source_uniform; - - if (!blur_shader) - return; - - scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU"); - texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource"); - - /* Blurring horizontally */ - - /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid - * pushing unnecessary matrices onto the OpenGL stack. */ - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - - /* avoid warnings from texture binding */ - GG.currentfb = blurfb->object; - - GPU_shader_bind(blur_shader); - GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh); - GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex); - glViewport(0, 0, blurtex->w_orig, blurtex->h_orig); - - /* Peparing to draw quad */ - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - glDisable(GL_DEPTH_TEST); - - GPU_texture_bind(tex, 0); - - /* Drawing quad */ - glBegin(GL_QUADS); - glTexCoord2d(0, 0); glVertex2f(1, 1); - glTexCoord2d(1, 0); glVertex2f(-1, 1); - glTexCoord2d(1, 1); glVertex2f(-1, -1); - glTexCoord2d(0, 1); glVertex2f(1, -1); - glEnd(); - - /* Blurring vertically */ - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); - glDrawBuffer(GL_COLOR_ATTACHMENT0); - - GG.currentfb = fb->object; - - glViewport(0, 0, tex->w_orig, tex->h_orig); - GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev); - GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); - GPU_texture_bind(blurtex, 0); - - glBegin(GL_QUADS); - glTexCoord2d(0, 0); glVertex2f(1, 1); - glTexCoord2d(1, 0); glVertex2f(-1, 1); - glTexCoord2d(1, 1); glVertex2f(-1, -1); - glTexCoord2d(0, 1); glVertex2f(1, -1); - glEnd(); - - GPU_shader_unbind(); -} - -/* GPUOffScreen */ - -struct GPUOffScreen { - GPUFrameBuffer *fb; - GPUTexture *color; - GPUTexture *depth; -}; - -GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]) -{ - GPUOffScreen *ofs; - - ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen"); - - ofs->fb = GPU_framebuffer_create(); - if (!ofs->fb) { - GPU_offscreen_free(ofs); - return NULL; - } - - if (samples) { - if (!GLEW_EXT_framebuffer_multisample || - !GLEW_ARB_texture_multisample || - /* Only needed for GPU_offscreen_read_pixels. - * We could add an arg if we intend to use multi-sample - * offscreen buffers w/o reading their pixels */ - !GLEW_EXT_framebuffer_blit || - /* This is required when blitting from a multi-sampled buffers, - * even though we're not scaling. */ - !GLEW_EXT_framebuffer_multisample_blit_scaled) - { - samples = 0; - } - } - - ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out); - if (!ofs->depth) { - GPU_offscreen_free(ofs); - return NULL; - } - - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { - GPU_offscreen_free(ofs); - return NULL; - } - - ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out); - if (!ofs->color) { - GPU_offscreen_free(ofs); - return NULL; - } - - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { - GPU_offscreen_free(ofs); - return NULL; - } - - /* check validity at the very end! */ - if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) { - GPU_offscreen_free(ofs); - return NULL; - } - - GPU_framebuffer_restore(); - - return ofs; -} - -void GPU_offscreen_free(GPUOffScreen *ofs) -{ - if (ofs->fb) - GPU_framebuffer_free(ofs->fb); - if (ofs->color) - GPU_texture_free(ofs->color); - if (ofs->depth) - GPU_texture_free(ofs->depth); - - MEM_freeN(ofs); -} - -void GPU_offscreen_bind(GPUOffScreen *ofs, bool save) -{ - glDisable(GL_SCISSOR_TEST); - if (save) - GPU_texture_bind_as_framebuffer(ofs->color); - else { - GPU_framebuffer_bind_no_save(ofs->fb, 0); - } -} - -void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore) -{ - if (restore) - GPU_framebuffer_texture_unbind(ofs->fb, ofs->color); - GPU_framebuffer_restore(); - glEnable(GL_SCISSOR_TEST); -} - -void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) -{ - const int w = ofs->color->w_orig; - const int h = ofs->color->h_orig; - - if (ofs->color->target == GL_TEXTURE_2D_MULTISAMPLE) { - /* For a multi-sample texture, - * we need to create an intermediate buffer to blit to, - * before its copied using 'glReadPixels' */ - - /* not needed since 'ofs' needs to be bound to the framebuffer already */ -// #define USE_FBO_CTX_SWITCH - - GLuint fbo_blit = 0; - GLuint tex_blit = 0; - GLenum status; - - /* create texture for new 'fbo_blit' */ - glGenTextures(1, &tex_blit); - if (!tex_blit) { - goto finally; - } - - glBindTexture(GL_TEXTURE_2D, tex_blit); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, type, 0); - -#ifdef USE_FBO_CTX_SWITCH - /* read from multi-sample buffer */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER, ofs->color->fb->object); - glFramebufferTexture2DEXT( - GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment, - GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); - status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - goto finally; - } -#endif - - /* write into new single-sample buffer */ - glGenFramebuffersEXT(1, &fbo_blit); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); - glFramebufferTexture2DEXT( - GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, tex_blit, 0); - status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - goto finally; - } - - /* perform the copy */ - glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); - - /* read the results */ - glBindFramebufferEXT(GL_READ_FRAMEBUFFER, fbo_blit); - glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); - -#ifdef USE_FBO_CTX_SWITCH - /* restore the original frame-bufer */ - glBindFramebufferEXT(GL_FRAMEBUFFER, ofs->color->fb->object); -#undef USE_FBO_CTX_SWITCH -#endif - - -finally: - /* cleanup */ - if (tex_blit) { - glDeleteTextures(1, &tex_blit); - } - if (fbo_blit) { - glDeleteFramebuffersEXT(1, &fbo_blit); - } - - GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels"); - } - else { - glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); - } -} - -int GPU_offscreen_width(const GPUOffScreen *ofs) -{ - return ofs->color->w_orig; -} - -int GPU_offscreen_height(const GPUOffScreen *ofs) -{ - return ofs->color->h_orig; -} - -int GPU_offscreen_color_texture(const GPUOffScreen *ofs) -{ - return ofs->color->bindcode; -} - -/* GPUShader */ - -struct GPUShader { - GLuint program; /* handle for full program (links shader stages below) */ - - GLuint vertex; /* handle for vertex shader */ - GLuint geometry; /* handle for geometry shader */ - GLuint fragment; /* handle for fragment shader */ - - int totattrib; /* total number of attributes */ - int uniforms; /* required uniforms */ -}; - -struct GPUProgram { - GPUProgramType type; - GLuint prog; -}; - - -static void shader_print_errors(const char *task, const char *log, const char **code, int totcode) -{ - int i; - int line = 1; - - fprintf(stderr, "GPUShader: %s error:\n", task); - - for (i = 0; i < totcode; i++) { - const char *c, *pos, *end = code[i] + strlen(code[i]); - - if (G.debug & G_DEBUG) { - fprintf(stderr, "===== shader string %d ====\n", i + 1); - - c = code[i]; - while ((c < end) && (pos = strchr(c, '\n'))) { - fprintf(stderr, "%2d ", line); - fwrite(c, (pos + 1) - c, 1, stderr); - c = pos + 1; - line++; - } - - fprintf(stderr, "%s", c); - } - } - - fprintf(stderr, "%s\n", log); -} - -static const char *gpu_shader_version(void) -{ - if (GLEW_VERSION_3_2) { - if (GLEW_ARB_compatibility) { - return "#version 150 compatibility\n"; - /* highest version that is widely supported - * gives us native geometry shaders! - * use compatibility profile so we can continue using builtin shader input/output names - */ - } - else { - return "#version 130\n"; - /* latest version that is compatible with existing shaders */ - } - } - else if (GLEW_VERSION_3_1) { - if (GLEW_ARB_compatibility) { - return "#version 140\n"; - /* also need the ARB_compatibility extension, handled below */ - } - else { - return "#version 130\n"; - /* latest version that is compatible with existing shaders */ - } - } - else if (GLEW_VERSION_3_0) { - return "#version 130\n"; - /* GLSL 1.3 has modern syntax/keywords/datatypes so use if available - * older features are deprecated but still available without compatibility extension or profile - */ - } - else { - return "#version 120\n"; - /* minimum supported */ - } + /* always supported on full GL but still relevant for OpenGL ES 2.0 where + * NPOT textures can't use mipmaps or repeat wrap mode */ + return true; } - -static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_geometry_shader) +bool GPU_display_list_support(void) { - /* enable extensions for features that are not part of our base GLSL version - * don't use an extension for something already available! + /* deprecated in GL 3 + * supported on older GL and compatibility profile + * still queried by game engine */ - - if (GLEW_ARB_texture_query_lod) { - /* a #version 400 feature, but we use #version 150 maximum so use extension */ - strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); - } - - if (use_geometry_shader && GPU_geometry_shader_support_via_extension()) { - strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n"); - } - - if (GLEW_VERSION_3_1 && !GLEW_VERSION_3_2 && GLEW_ARB_compatibility) { - strcat(defines, "#extension GL_ARB_compatibility: enable\n"); - } - - if (!GLEW_VERSION_3_1) { - if (GLEW_ARB_draw_instanced) { - strcat(defines, "#extension GL_ARB_draw_instanced: enable\n"); - } - - if (!GLEW_VERSION_3_0 && GLEW_EXT_gpu_shader4) { - strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n"); - /* TODO: maybe require this? shaders become so much nicer */ - } - } -} - -static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], bool use_opensubdiv) -{ - /* some useful defines to detect GPU type */ - if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { - strcat(defines, "#define GPU_ATI\n"); - if (GLEW_VERSION_3_0) { - /* TODO(merwin): revisit this version check; GLEW_VERSION_3_0 means GL 3.0 or newer */ - strcat(defines, "#define CLIP_WORKAROUND\n"); - } - } - else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) - strcat(defines, "#define GPU_NVIDIA\n"); - else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) - strcat(defines, "#define GPU_INTEL\n"); - - if (GPU_bicubic_bump_support()) - strcat(defines, "#define BUMP_BICUBIC\n"); - -#ifdef WITH_OPENSUBDIV - /* TODO(sergey): Check whether we actually compiling shader for - * the OpenSubdiv mesh. - */ - if (use_opensubdiv) { - strcat(defines, "#define USE_OPENSUBDIV\n"); - - /* TODO(sergey): not strictly speaking a define, but this is - * a global typedef which we don't have better place to define - * in yet. - */ - strcat(defines, "struct VertexData {\n" - " vec4 position;\n" - " vec3 normal;\n" - " vec2 uv;" - "};\n"); - } -#else - UNUSED_VARS(use_opensubdiv); -#endif - - return; -} - -void GPU_program_bind(GPUProgram *program) -{ - glEnable(program->type); - glBindProgramARB(program->type, program->prog); -} - -void GPU_program_unbind(GPUProgram *program) -{ - glDisable(program->type); - glBindProgramARB(program->type, 0); -} - - -GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code) -{ - /* TODO(merwin): remove ARB program support (recode smoke shader in GLSL) */ - - GPUProgram *program; - GLint error_pos, is_native; - - if (!(GLEW_ARB_fragment_program && type == GPU_PROGRAM_TYPE_FRAGMENT)) - return NULL; - - program = MEM_callocN(sizeof(GPUProgram), "GPUProgram"); - - switch (type) { - case GPU_PROGRAM_TYPE_FRAGMENT: - program->type = GL_FRAGMENT_PROGRAM_ARB; - break; - } - - /* create the object and set its code string */ - glGenProgramsARB(1, &program->prog); - glBindProgramARB(program->type, program->prog); - - glProgramStringARB(program->type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), code); - - glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos); - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &is_native); - if ((error_pos == -1) && (is_native == 1)) { - return program; - } - else { - /* glGetError is set before that, clear it */ - while (glGetError() != GL_NO_ERROR) - ; - shader_print_errors("compile", (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB), &code, 1); - MEM_freeN(program); - } - - return NULL; -} - -void GPU_program_free(GPUProgram *program) -{ - glDeleteProgramsARB(1, &program->prog); - MEM_freeN(program); -} - -void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w) -{ - glProgramLocalParameter4fARB(program->type, location, x, y, z, w); + return true; } -GPUShader *GPU_shader_create(const char *vertexcode, - const char *fragcode, - const char *geocode, - const char *libcode, - const char *defines, - int input, - int output, - int number) +bool GPU_bicubic_bump_support(void) { - return GPU_shader_create_ex(vertexcode, - fragcode, - geocode, - libcode, - defines, - input, - output, - number, - GPU_SHADER_FLAGS_NONE); + return GLEW_VERSION_4_0 || (GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0); } -GPUShader *GPU_shader_create_ex(const char *vertexcode, - const char *fragcode, - const char *geocode, - const char *libcode, - const char *defines, - int input, - int output, - int number, - const int flags) +bool GPU_geometry_shader_support(void) { -#ifdef WITH_OPENSUBDIV - /* TODO(sergey): used to add #version 150 to the geometry shader. - * Could safely be renamed to "use_geometry_code" since it's very - * likely any of geometry code will want to use GLSL 1.5. + /* in GL 3.2 geometry shaders are fully supported + * core profile clashes with our other shaders so accept compatibility only + * other GL versions can use EXT_geometry_shader4 if available */ - bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0; -#else - UNUSED_VARS(flags); - bool use_opensubdiv = false; -#endif - GLint status; - GLchar log[5000]; - GLsizei length = 0; - GPUShader *shader; - char standard_defines[MAX_DEFINE_LENGTH] = ""; - char standard_extensions[MAX_EXT_DEFINE_LENGTH] = ""; - - if (geocode && !GPU_geometry_shader_support()) - return NULL; - - shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); - - if (vertexcode) - shader->vertex = glCreateShader(GL_VERTEX_SHADER); - if (fragcode) - shader->fragment = glCreateShader(GL_FRAGMENT_SHADER); - if (geocode) - shader->geometry = glCreateShader(GL_GEOMETRY_SHADER_EXT); - - shader->program = glCreateProgram(); - - if (!shader->program || - (vertexcode && !shader->vertex) || - (fragcode && !shader->fragment) || - (geocode && !shader->geometry)) - { - fprintf(stderr, "GPUShader, object creation failed.\n"); - GPU_shader_free(shader); - return NULL; - } - - gpu_shader_standard_defines(standard_defines, use_opensubdiv); - gpu_shader_standard_extensions(standard_extensions, geocode != NULL); - - if (vertexcode) { - const char *source[5]; - /* custom limit, may be too small, beware */ - int num_source = 0; - - source[num_source++] = gpu_shader_version(); - source[num_source++] = standard_extensions; - source[num_source++] = standard_defines; - - if (defines) source[num_source++] = defines; - source[num_source++] = vertexcode; - - glAttachShader(shader->program, shader->vertex); - glShaderSource(shader->vertex, num_source, source, NULL); - - glCompileShader(shader->vertex); - glGetShaderiv(shader->vertex, GL_COMPILE_STATUS, &status); - - if (!status) { - glGetShaderInfoLog(shader->vertex, sizeof(log), &length, log); - shader_print_errors("compile", log, source, num_source); - - GPU_shader_free(shader); - return NULL; - } - } - - if (fragcode) { - const char *source[7]; - int num_source = 0; - - source[num_source++] = gpu_shader_version(); - source[num_source++] = standard_extensions; - source[num_source++] = standard_defines; - -#ifdef WITH_OPENSUBDIV - /* TODO(sergey): Move to fragment shader source code generation. */ - if (use_opensubdiv) { - source[num_source++] = - "#ifdef USE_OPENSUBDIV\n" - "in block {\n" - " VertexData v;\n" - "} inpt;\n" - "#endif\n"; - } -#endif - - if (defines) source[num_source++] = defines; - if (libcode) source[num_source++] = libcode; - source[num_source++] = fragcode; - - glAttachShader(shader->program, shader->fragment); - glShaderSource(shader->fragment, num_source, source, NULL); - - glCompileShader(shader->fragment); - glGetShaderiv(shader->fragment, GL_COMPILE_STATUS, &status); - - if (!status) { - glGetShaderInfoLog(shader->fragment, sizeof(log), &length, log); - shader_print_errors("compile", log, source, num_source); - - GPU_shader_free(shader); - return NULL; - } - } - - if (geocode) { - const char *source[6]; - int num_source = 0; - - source[num_source++] = gpu_shader_version(); - source[num_source++] = standard_extensions; - source[num_source++] = standard_defines; - - if (defines) source[num_source++] = defines; - source[num_source++] = geocode; - - glAttachShader(shader->program, shader->geometry); - glShaderSource(shader->geometry, num_source, source, NULL); - - glCompileShader(shader->geometry); - glGetShaderiv(shader->geometry, GL_COMPILE_STATUS, &status); - - if (!status) { - glGetShaderInfoLog(shader->geometry, sizeof(log), &length, log); - shader_print_errors("compile", log, source, num_source); - - GPU_shader_free(shader); - return NULL; - } - - if (!use_opensubdiv) { - GPU_shader_geometry_stage_primitive_io(shader, input, output, number); - } - } - -#ifdef WITH_OPENSUBDIV - if (use_opensubdiv) { - glBindAttribLocation(shader->program, 0, "position"); - glBindAttribLocation(shader->program, 1, "normal"); - GPU_shader_geometry_stage_primitive_io(shader, - GL_LINES_ADJACENCY_EXT, - GL_TRIANGLE_STRIP, - 4); - } -#endif - - glLinkProgram(shader->program); - glGetProgramiv(shader->program, GL_LINK_STATUS, &status); - if (!status) { - glGetProgramInfoLog(shader->program, sizeof(log), &length, log); - /* print attached shaders in pipeline order */ - if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1); - if (geocode) shader_print_errors("linking", log, &geocode, 1); - if (libcode) shader_print_errors("linking", log, &libcode, 1); - if (fragcode) shader_print_errors("linking", log, &fragcode, 1); - - GPU_shader_free(shader); - return NULL; - } - -#ifdef WITH_OPENSUBDIV - /* TODO(sergey): Find a better place for this. */ - if (use_opensubdiv && GLEW_VERSION_4_1) { - glProgramUniform1i(shader->program, - glGetUniformLocation(shader->program, "FVarDataBuffer"), - 31); /* GL_TEXTURE31 */ - } -#endif - - return shader; -} - -void GPU_shader_bind(GPUShader *shader) -{ - GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind"); - glUseProgram(shader->program); - GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind"); -} - -void GPU_shader_unbind(void) -{ - GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind"); - glUseProgram(0); - GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind"); -} - -void GPU_shader_free(GPUShader *shader) -{ - if (shader->vertex) - glDeleteShader(shader->vertex); - if (shader->geometry) - glDeleteShader(shader->geometry); - if (shader->fragment) - glDeleteShader(shader->fragment); - if (shader->program) - glDeleteProgram(shader->program); - MEM_freeN(shader); -} - -int GPU_shader_get_uniform(GPUShader *shader, const char *name) -{ - return glGetUniformLocation(shader->program, name); -} - -void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value) -{ - if (location == -1 || value == NULL) - return; - - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); - - if (length == 1) glUniform1fv(location, arraysize, value); - else if (length == 2) glUniform2fv(location, arraysize, value); - else if (length == 3) glUniform3fv(location, arraysize, value); - else if (length == 4) glUniform4fv(location, arraysize, value); - else if (length == 9) glUniformMatrix3fv(location, arraysize, 0, value); - else if (length == 16) glUniformMatrix4fv(location, arraysize, 0, value); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); -} - -void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value) -{ - if (location == -1) - return; - - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); - - if (length == 1) glUniform1iv(location, arraysize, value); - else if (length == 2) glUniform2iv(location, arraysize, value); - else if (length == 3) glUniform3iv(location, arraysize, value); - else if (length == 4) glUniform4iv(location, arraysize, value); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); -} - -void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) -{ - if (location == -1) - return; - - GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value)); -} - -void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number) -{ - if (GPU_geometry_shader_support_via_extension()) { - /* geometry shaders must provide this info themselves for #version 150 and up */ - glProgramParameteriEXT(shader->program, GL_GEOMETRY_INPUT_TYPE_EXT, input); - glProgramParameteriEXT(shader->program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output); - glProgramParameteriEXT(shader->program, GL_GEOMETRY_VERTICES_OUT_EXT, number); - } -} - -void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) -{ - GLenum arbnumber; - - if (tex->number >= GG.maxtextures) { - fprintf(stderr, "Not enough texture slots.\n"); - return; - } - - if (tex->number == -1) - return; - - if (location == -1) - return; - - GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture"); - - arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); - - if (tex->number != 0) glActiveTexture(arbnumber); - if (tex->bindcode != 0) - glBindTexture(tex->target, tex->bindcode); - else - GPU_invalid_tex_bind(tex->target); - glUniform1i(location, tex->number); - glEnable(tex->target); - if (tex->number != 0) glActiveTexture(GL_TEXTURE0); - - GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture"); -} - -int GPU_shader_get_attribute(GPUShader *shader, const char *name) -{ - int index; - - GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocation(shader->program, name)); - - return index; -} - -GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) -{ - GPUShader *retval = NULL; - - switch (shader) { - case GPU_SHADER_VSM_STORE: - if (!GG.shaders.vsm_store) - GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.vsm_store; - break; - case GPU_SHADER_SEP_GAUSSIAN_BLUR: - if (!GG.shaders.sep_gaussian_blur) - GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL, NULL, NULL, 0, 0, 0); - retval = GG.shaders.sep_gaussian_blur; - break; - } - - if (retval == NULL) - printf("Unable to create a GPUShader for builtin shader: %u\n", shader); - - return retval; + return (GLEW_VERSION_3_2 && GPU_legacy_support()) || GLEW_EXT_geometry_shader4; } -GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program) +bool GPU_geometry_shader_support_via_extension(void) { - GPUProgram *retval = NULL; - - switch (program) { - case GPU_PROGRAM_SMOKE: - if (!GG.shaders.smoke) - GG.shaders.smoke = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_frag_glsl); - retval = GG.shaders.smoke; - break; - case GPU_PROGRAM_SMOKE_COLORED: - if (!GG.shaders.smoke_colored) - GG.shaders.smoke_colored = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_color_frag_glsl); - retval = GG.shaders.smoke_colored; - break; - } - - if (retval == NULL) - printf("Unable to create a GPUProgram for builtin program: %u\n", program); - - return retval; + return GLEW_EXT_geometry_shader4 && !(GLEW_VERSION_3_2 && GPU_legacy_support()); } -#define MAX_DEFINES 100 - -GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp) +bool GPU_instanced_drawing_support(void) { - int offset; - char defines[MAX_DEFINES] = ""; - /* avoid shaders out of range */ - if (effects >= MAX_FX_SHADERS) - return NULL; - - offset = 2 * effects; - - if (persp) { - offset += 1; - strcat(defines, "#define PERSP_MATRIX\n"); - } - - if (!GG.shaders.fx_shaders[offset]) { - GPUShader *shader; - - switch (effects) { - case GPU_SHADER_FX_SSAO: - GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE: - strcat(defines, "#define FIRST_PASS\n"); - GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO: - strcat(defines, "#define SECOND_PASS\n"); - GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE: - strcat(defines, "#define THIRD_PASS\n"); - GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR: - strcat(defines, "#define FOURTH_PASS\n"); - GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE: - strcat(defines, "#define FIFTH_PASS\n"); - GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE: - strcat(defines, "#define FIRST_PASS\n"); - GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO: - strcat(defines, "#define SECOND_PASS\n"); - shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl, - defines, GL_POINTS, GL_TRIANGLE_STRIP, 4); - GG.shaders.fx_shaders[offset] = shader; - break; - - case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE: - strcat(defines, "#define THIRD_PASS\n"); - GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); - break; - - case GPU_SHADER_FX_DEPTH_RESOLVE: - GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0); - } - } - - return GG.shaders.fx_shaders[offset]; + return GLEW_VERSION_3_1 || GLEW_ARB_draw_instanced; } - -void GPU_shader_free_builtin_shaders(void) +int GPU_color_depth(void) { - int i; - - if (GG.shaders.vsm_store) { - GPU_shader_free(GG.shaders.vsm_store); - GG.shaders.vsm_store = NULL; - } - - if (GG.shaders.sep_gaussian_blur) { - GPU_shader_free(GG.shaders.sep_gaussian_blur); - GG.shaders.sep_gaussian_blur = NULL; - } - - if (GG.shaders.smoke) { - GPU_program_free(GG.shaders.smoke); - GG.shaders.smoke = NULL; - } - - if (GG.shaders.smoke_colored) { - GPU_program_free(GG.shaders.smoke_colored); - GG.shaders.smoke_colored = NULL; - } - - for (i = 0; i < 2 * MAX_FX_SHADERS; i++) { - if (GG.shaders.fx_shaders[i]) { - GPU_shader_free(GG.shaders.fx_shaders[i]); - GG.shaders.fx_shaders[i] = NULL; - } - } + return GG.colordepth; } bool GPU_mem_stats_supported(void) @@ -2334,117 +326,3 @@ void GPU_mem_stats_get(int *totalmem, int *freemem) } } - -#if 0 /* unused */ - -/* GPUPixelBuffer */ - -typedef struct GPUPixelBuffer { - GLuint bindcode[2]; - GLuint current; - int datasize; - int numbuffers; - int halffloat; -} GPUPixelBuffer; - -void GPU_pixelbuffer_free(GPUPixelBuffer *pb) -{ - if (pb->bindcode[0]) - glDeleteBuffers(pb->numbuffers, pb->bindcode); - MEM_freeN(pb); -} - -GPUPixelBuffer *gpu_pixelbuffer_create(int x, int y, int halffloat, int numbuffers) -{ - GPUPixelBuffer *pb; - - pb = MEM_callocN(sizeof(GPUPixelBuffer), "GPUPBO"); - pb->datasize = x * y * 4 * (halffloat ? 16 : 8); - pb->numbuffers = numbuffers; - pb->halffloat = halffloat; - - glGenBuffers(pb->numbuffers, pb->bindcode); - - if (!pb->bindcode[0]) { - fprintf(stderr, "GPUPixelBuffer allocation failed\n"); - GPU_pixelbuffer_free(pb); - return NULL; - } - - return pb; -} - -void GPU_pixelbuffer_texture(GPUTexture *tex, GPUPixelBuffer *pb) -{ - void *pixels; - int i; - - glBindTexture(GL_TEXTURE_RECTANGLE, tex->bindcode); - - for (i = 0; i < pb->numbuffers; i++) { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pb->bindcode[pb->current]); - glBufferData(GL_PIXEL_UNPACK_BUFFER, pb->datasize, NULL, - GL_STREAM_DRAW); - - pixels = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); - -# if 0 - memcpy(pixels, _oImage.data(), pb->datasize); -# endif - - if (!glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) { - fprintf(stderr, "Could not unmap OpenGL PBO\n"); - break; - } - } - - glBindTexture(GL_TEXTURE_RECTANGLE, 0); -} - -static int pixelbuffer_map_into_gpu(GLuint bindcode) -{ - void *pixels; - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bindcode); - pixels = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); - - /* do stuff in pixels */ - - if (!glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) { - fprintf(stderr, "Could not unmap OpenGL PBO\n"); - return 0; - } - - return 1; -} - -static void pixelbuffer_copy_to_texture(GPUTexture *tex, GPUPixelBuffer *pb, GLuint bindcode) -{ - GLenum type = (pb->halffloat)? GL_HALF_FLOAT_NV: GL_UNSIGNED_BYTE; - glBindTexture(GL_TEXTURE_RECTANGLE, tex->bindcode); - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, bindcode); - - glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, 0, 0, tex->w, tex->h, GL_RGBA, type, NULL); - - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - glBindTexture(GL_TEXTURE_RECTANGLE, 0); -} - -void GPU_pixelbuffer_async_to_gpu(GPUTexture *tex, GPUPixelBuffer *pb) -{ - int newbuffer; - - if (pb->numbuffers == 1) { - pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[0]); - pixelbuffer_map_into_gpu(pb->bindcode[0]); - } - else { - pb->current = (pb->current + 1) % pb->numbuffers; - newbuffer = (pb->current + 1) % pb->numbuffers; - - pixelbuffer_map_into_gpu(pb->bindcode[newbuffer]); - pixelbuffer_copy_to_texture(tex, pb, pb->bindcode[pb->current]); - } -} -#endif /* unused */ - diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c new file mode 100644 index 00000000000..4ef7611a3f3 --- /dev/null +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -0,0 +1,633 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_base.h" +#include "BLI_math_vector.h" + +#include "BKE_global.h" + +#include "GPU_debug.h" +#include "GPU_glew.h" +#include "GPU_framebuffer.h" +#include "GPU_shader.h" +#include "GPU_texture.h" + +static struct GPUFrameBufferGlobal { + GLuint currentfb; +} GG = {0}; + +/* Number of maximum output slots. We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */ +#define GPU_FB_MAX_SLOTS 4 + +struct GPUFrameBuffer { + GLuint object; + GPUTexture *colortex[GPU_FB_MAX_SLOTS]; + GPUTexture *depthtex; +}; + +static void GPU_print_framebuffer_error(GLenum status, char err_out[256]) +{ + const char *err = "unknown"; + + switch (status) { + case GL_FRAMEBUFFER_COMPLETE_EXT: + break; + case GL_INVALID_OPERATION: + err = "Invalid operation"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: + err = "Incomplete attachment"; + break; + case GL_FRAMEBUFFER_UNSUPPORTED_EXT: + err = "Unsupported framebuffer format"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: + err = "Missing attachment"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: + err = "Attached images must have same dimensions"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: + err = "Attached images must have same format"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: + err = "Missing draw buffer"; + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: + err = "Missing read buffer"; + break; + } + + if (err_out) { + BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'", + (int)status, err); + } + else { + fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n", + (int)status, err); + } +} + +/* GPUFrameBuffer */ + +GPUFrameBuffer *GPU_framebuffer_create(void) +{ + GPUFrameBuffer *fb; + + if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object || (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit))) + return NULL; + + fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); + glGenFramebuffersEXT(1, &fb->object); + + if (!fb->object) { + fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n", + (int)glGetError()); + GPU_framebuffer_free(fb); + return NULL; + } + + /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glReadBuffer(GL_NONE); + glDrawBuffer(GL_NONE); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + return fb; +} + +int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]) +{ + GLenum attachment; + GLenum error; + + if (slot >= GPU_FB_MAX_SLOTS) { + fprintf(stderr, + "Attaching to index %d framebuffer slot unsupported. " + "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); + return 0; + } + + if ((G.debug & G_DEBUG)) { + if (GPU_texture_bound_number(tex) != -1) { + fprintf(stderr, + "Feedback loop warning!: " + "Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n"); + } + } + + if (GPU_texture_depth(tex)) + attachment = GL_DEPTH_ATTACHMENT_EXT; + else + attachment = GL_COLOR_ATTACHMENT0_EXT + slot; + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + GG.currentfb = fb->object; + + /* Clean glError buffer. */ + while (glGetError() != GL_NO_ERROR) {} + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, + GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0); + + error = glGetError(); + + if (error == GL_INVALID_OPERATION) { + GPU_framebuffer_restore(); + GPU_print_framebuffer_error(error, err_out); + return 0; + } + + if (GPU_texture_depth(tex)) + fb->depthtex = tex; + else + fb->colortex[slot] = tex; + + GPU_texture_framebuffer_set(tex, fb, slot); + + return 1; +} + +void GPU_framebuffer_texture_detach(GPUTexture *tex) +{ + GLenum attachment; + GPUFrameBuffer *fb = GPU_texture_framebuffer(tex); + int fb_attachment = GPU_texture_framebuffer_attachment(tex); + + if (!fb) + return; + + if (GG.currentfb != fb->object) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + GG.currentfb = fb->object; + } + + if (GPU_texture_depth(tex)) { + fb->depthtex = NULL; + attachment = GL_DEPTH_ATTACHMENT_EXT; + } + else { + BLI_assert(fb->colortex[fb_attachment] == tex); + fb->colortex[fb_attachment] = NULL; + attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment; + } + + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0); + + GPU_texture_framebuffer_set(tex, NULL, -1); +} + +void GPU_texture_bind_as_framebuffer(GPUTexture *tex) +{ + GPUFrameBuffer *fb = GPU_texture_framebuffer(tex); + int fb_attachment = GPU_texture_framebuffer_attachment(tex); + + if (!fb) { + fprintf(stderr, "Error, texture not bound to framebuffer!\n"); + return; + } + + /* push attributes */ + glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); + glDisable(GL_SCISSOR_TEST); + + /* bind framebuffer */ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + + if (GPU_texture_depth(tex)) { + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + } + else { + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment); + } + + if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { + glEnable(GL_MULTISAMPLE); + } + + /* push matrices and set default viewport and matrix */ + glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); + GG.currentfb = fb->object; + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); +} + +void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) +{ + int numslots = 0, i; + GLenum attachments[4]; + + if (!fb->colortex[slot]) { + fprintf(stderr, "Error, framebuffer slot empty!\n"); + return; + } + + for (i = 0; i < 4; i++) { + if (fb->colortex[i]) { + attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i; + numslots++; + } + } + + /* push attributes */ + glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT); + glDisable(GL_SCISSOR_TEST); + + /* bind framebuffer */ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffers(numslots, attachments); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + + /* push matrices and set default viewport and matrix */ + glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); + GG.currentfb = fb->object; + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); +} + + +void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) +{ + /* restore matrix */ + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + + /* restore attributes */ + glPopAttrib(); +} + +void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) +{ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot); + + /* push matrices and set default viewport and matrix */ + glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); + GG.currentfb = fb->object; + GG.currentfb = fb->object; +} + +bool GPU_framebuffer_bound(GPUFrameBuffer *fb) +{ + return fb->object == GG.currentfb; +} + +bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) +{ + GLenum status; + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + GG.currentfb = fb->object; + + /* Clean glError buffer. */ + while (glGetError() != GL_NO_ERROR) {} + + status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + GPU_framebuffer_restore(); + GPU_print_framebuffer_error(status, err_out); + return false; + } + + return true; +} + +void GPU_framebuffer_free(GPUFrameBuffer *fb) +{ + int i; + if (fb->depthtex) + GPU_framebuffer_texture_detach(fb->depthtex); + + for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { + if (fb->colortex[i]) { + GPU_framebuffer_texture_detach(fb->colortex[i]); + } + } + + if (fb->object) { + glDeleteFramebuffersEXT(1, &fb->object); + + if (GG.currentfb == fb->object) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + GG.currentfb = 0; + } + } + + MEM_freeN(fb); +} + +void GPU_framebuffer_restore(void) +{ + if (GG.currentfb != 0) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + GG.currentfb = 0; + } +} + +void GPU_framebuffer_blur(GPUFrameBuffer *fb, GPUTexture *tex, GPUFrameBuffer *blurfb, GPUTexture *blurtex) +{ + const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f}; + const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)}; + + GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); + int scale_uniform, texture_source_uniform; + + if (!blur_shader) + return; + + scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU"); + texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource"); + + /* Blurring horizontally */ + + /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid + * pushing unnecessary matrices onto the OpenGL stack. */ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + + /* avoid warnings from texture binding */ + GG.currentfb = blurfb->object; + + GPU_shader_bind(blur_shader); + GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh); + GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex); + glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex)); + + /* Peparing to draw quad */ + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glDisable(GL_DEPTH_TEST); + + GPU_texture_bind(tex, 0); + + /* Drawing quad */ + glBegin(GL_QUADS); + glTexCoord2d(0, 0); glVertex2f(1, 1); + glTexCoord2d(1, 0); glVertex2f(-1, 1); + glTexCoord2d(1, 1); glVertex2f(-1, -1); + glTexCoord2d(0, 1); glVertex2f(1, -1); + glEnd(); + + /* Blurring vertically */ + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + + GG.currentfb = fb->object; + + glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); + GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev); + GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); + GPU_texture_bind(blurtex, 0); + + glBegin(GL_QUADS); + glTexCoord2d(0, 0); glVertex2f(1, 1); + glTexCoord2d(1, 0); glVertex2f(-1, 1); + glTexCoord2d(1, 1); glVertex2f(-1, -1); + glTexCoord2d(0, 1); glVertex2f(1, -1); + glEnd(); + + GPU_shader_unbind(); +} + +/* GPUOffScreen */ + +struct GPUOffScreen { + GPUFrameBuffer *fb; + GPUTexture *color; + GPUTexture *depth; +}; + +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]) +{ + GPUOffScreen *ofs; + + ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen"); + + ofs->fb = GPU_framebuffer_create(); + if (!ofs->fb) { + GPU_offscreen_free(ofs); + return NULL; + } + + if (samples) { + if (!GLEW_EXT_framebuffer_multisample || + !GLEW_ARB_texture_multisample || + /* Only needed for GPU_offscreen_read_pixels. + * We could add an arg if we intend to use multi-sample + * offscreen buffers w/o reading their pixels */ + !GLEW_EXT_framebuffer_blit || + /* This is required when blitting from a multi-sampled buffers, + * even though we're not scaling. */ + !GLEW_EXT_framebuffer_multisample_blit_scaled) + { + samples = 0; + } + } + + ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out); + if (!ofs->depth) { + GPU_offscreen_free(ofs); + return NULL; + } + + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { + GPU_offscreen_free(ofs); + return NULL; + } + + ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out); + if (!ofs->color) { + GPU_offscreen_free(ofs); + return NULL; + } + + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { + GPU_offscreen_free(ofs); + return NULL; + } + + /* check validity at the very end! */ + if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) { + GPU_offscreen_free(ofs); + return NULL; + } + + GPU_framebuffer_restore(); + + return ofs; +} + +void GPU_offscreen_free(GPUOffScreen *ofs) +{ + if (ofs->fb) + GPU_framebuffer_free(ofs->fb); + if (ofs->color) + GPU_texture_free(ofs->color); + if (ofs->depth) + GPU_texture_free(ofs->depth); + + MEM_freeN(ofs); +} + +void GPU_offscreen_bind(GPUOffScreen *ofs, bool save) +{ + glDisable(GL_SCISSOR_TEST); + if (save) + GPU_texture_bind_as_framebuffer(ofs->color); + else { + GPU_framebuffer_bind_no_save(ofs->fb, 0); + } +} + +void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore) +{ + if (restore) + GPU_framebuffer_texture_unbind(ofs->fb, ofs->color); + GPU_framebuffer_restore(); + glEnable(GL_SCISSOR_TEST); +} + +void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) +{ + const int w = GPU_texture_width(ofs->color); + const int h = GPU_texture_height(ofs->color); + + if (GPU_texture_target(ofs->color) == GL_TEXTURE_2D_MULTISAMPLE) { + /* For a multi-sample texture, + * we need to create an intermediate buffer to blit to, + * before its copied using 'glReadPixels' */ + + /* not needed since 'ofs' needs to be bound to the framebuffer already */ +// #define USE_FBO_CTX_SWITCH + + GLuint fbo_blit = 0; + GLuint tex_blit = 0; + GLenum status; + + /* create texture for new 'fbo_blit' */ + glGenTextures(1, &tex_blit); + if (!tex_blit) { + goto finally; + } + + glBindTexture(GL_TEXTURE_2D, tex_blit); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, type, 0); + +#ifdef USE_FBO_CTX_SWITCH + /* read from multi-sample buffer */ + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ofs->color->fb->object); + glFramebufferTexture2DEXT( + GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment, + GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); + status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + goto finally; + } +#endif + + /* write into new single-sample buffer */ + glGenFramebuffersEXT(1, &fbo_blit); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit); + glFramebufferTexture2DEXT( + GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, tex_blit, 0); + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + goto finally; + } + + /* perform the copy */ + glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + /* read the results */ + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo_blit); + glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); + +#ifdef USE_FBO_CTX_SWITCH + /* restore the original frame-bufer */ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ofs->color->fb->object); +#undef USE_FBO_CTX_SWITCH +#endif + + +finally: + /* cleanup */ + if (tex_blit) { + glDeleteTextures(1, &tex_blit); + } + if (fbo_blit) { + glDeleteFramebuffersEXT(1, &fbo_blit); + } + + GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels"); + } + else { + glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); + } +} + +int GPU_offscreen_width(const GPUOffScreen *ofs) +{ + return GPU_texture_width(ofs->color); +} + +int GPU_offscreen_height(const GPUOffScreen *ofs) +{ + return GPU_texture_height(ofs->color); +} + +int GPU_offscreen_color_texture(const GPUOffScreen *ofs) +{ + return GPU_texture_opengl_bindcode(ofs->color); +} + diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 82902f8d69c..a176297de28 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -61,7 +61,10 @@ #include "IMB_imbuf_types.h" #include "GPU_extensions.h" +#include "GPU_framebuffer.h" #include "GPU_material.h" +#include "GPU_shader.h" +#include "GPU_texture.h" #include "gpu_codegen.h" @@ -2275,12 +2278,8 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) GPUMaterial *mat; GPUInputUniform *uniform; GPUInputAttribute *attribute; - GLint lastbindcode; int i, liblen, fraglen; - if (!GPU_glsl_support()) - return NULL; - /* TODO(sergey): How to detemine whether we need OSD or not here? */ mat = GPU_material_from_blender(scene, ma, false); pass = (mat)? mat->pass: NULL; @@ -2313,12 +2312,11 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) case GPU_TEX2D: if (GPU_texture_opengl_bindcode(input->tex)) { uniform->type = GPU_DYNAMIC_SAMPLER_2DBUFFER; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastbindcode); glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(input->tex)); - uniform->texsize = GPU_texture_opengl_width(input->tex) * GPU_texture_opengl_height(input->tex); + uniform->texsize = GPU_texture_width(input->tex) * GPU_texture_height(input->tex); uniform->texpixels = MEM_mallocN(uniform->texsize*4, "RGBApixels"); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, uniform->texpixels); - glBindTexture(GL_TEXTURE_2D, lastbindcode); + glBindTexture(GL_TEXTURE_2D, 0); } break; diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c new file mode 100644 index 00000000000..83413dfdcb1 --- /dev/null +++ b/source/blender/gpu/intern/gpu_shader.c @@ -0,0 +1,783 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_base.h" +#include "BLI_math_vector.h" + +#include "BKE_global.h" + +#include "GPU_compositing.h" +#include "GPU_debug.h" +#include "GPU_extensions.h" +#include "GPU_glew.h" +#include "GPU_shader.h" +#include "GPU_texture.h" + +/* TODO(sergey): Find better default values for this constants. */ +#define MAX_DEFINE_LENGTH 1024 +#define MAX_EXT_DEFINE_LENGTH 1024 + +/* Non-generated shaders */ +extern char datatoc_gpu_program_smoke_frag_glsl[]; +extern char datatoc_gpu_program_smoke_color_frag_glsl[]; +extern char datatoc_gpu_shader_vsm_store_vert_glsl[]; +extern char datatoc_gpu_shader_vsm_store_frag_glsl[]; +extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[]; +extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[]; +extern char datatoc_gpu_shader_fx_vert_glsl[]; +extern char datatoc_gpu_shader_fx_ssao_frag_glsl[]; +extern char datatoc_gpu_shader_fx_dof_frag_glsl[]; +extern char datatoc_gpu_shader_fx_dof_vert_glsl[]; +extern char datatoc_gpu_shader_fx_dof_hq_frag_glsl[]; +extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[]; +extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[]; +extern char datatoc_gpu_shader_fx_depth_resolve_glsl[]; +extern char datatoc_gpu_shader_fx_lib_glsl[]; + +static struct GPUShadersGlobal { + struct { + GPUShader *vsm_store; + GPUShader *sep_gaussian_blur; + GPUProgram *smoke; + GPUProgram *smoke_colored; + /* cache for shader fx. Those can exist in combinations so store them here */ + GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; + } shaders; +} GG = {{NULL}}; + +/* GPUShader */ + +struct GPUShader { + GLuint program; /* handle for full program (links shader stages below) */ + + GLuint vertex; /* handle for vertex shader */ + GLuint geometry; /* handle for geometry shader */ + GLuint fragment; /* handle for fragment shader */ + + int totattrib; /* total number of attributes */ + int uniforms; /* required uniforms */ +}; + +struct GPUProgram { + GPUProgramType type; + GLuint prog; +}; + +static void shader_print_errors(const char *task, const char *log, const char **code, int totcode) +{ + int i; + int line = 1; + + fprintf(stderr, "GPUShader: %s error:\n", task); + + for (i = 0; i < totcode; i++) { + const char *c, *pos, *end = code[i] + strlen(code[i]); + + if (G.debug & G_DEBUG) { + fprintf(stderr, "===== shader string %d ====\n", i + 1); + + c = code[i]; + while ((c < end) && (pos = strchr(c, '\n'))) { + fprintf(stderr, "%2d ", line); + fwrite(c, (pos + 1) - c, 1, stderr); + c = pos + 1; + line++; + } + + fprintf(stderr, "%s", c); + } + } + + fprintf(stderr, "%s\n", log); +} + +static const char *gpu_shader_version(void) +{ + if (GLEW_VERSION_3_2) { + if (GLEW_ARB_compatibility) { + return "#version 150 compatibility\n"; + /* highest version that is widely supported + * gives us native geometry shaders! + * use compatibility profile so we can continue using builtin shader input/output names + */ + } + else { + return "#version 130\n"; + /* latest version that is compatible with existing shaders */ + } + } + else if (GLEW_VERSION_3_1) { + if (GLEW_ARB_compatibility) { + return "#version 140\n"; + /* also need the ARB_compatibility extension, handled below */ + } + else { + return "#version 130\n"; + /* latest version that is compatible with existing shaders */ + } + } + else if (GLEW_VERSION_3_0) { + return "#version 130\n"; + /* GLSL 1.3 has modern syntax/keywords/datatypes so use if available + * older features are deprecated but still available without compatibility extension or profile + */ + } + else { + return "#version 120\n"; + /* minimum supported */ + } +} + + +static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], bool use_geometry_shader) +{ + /* enable extensions for features that are not part of our base GLSL version + * don't use an extension for something already available! + */ + + if (GLEW_ARB_texture_query_lod) { + /* a #version 400 feature, but we use #version 150 maximum so use extension */ + strcat(defines, "#extension GL_ARB_texture_query_lod: enable\n"); + } + + if (use_geometry_shader && GPU_geometry_shader_support_via_extension()) { + strcat(defines, "#extension GL_EXT_geometry_shader4: enable\n"); + } + + if (GLEW_VERSION_3_1 && !GLEW_VERSION_3_2 && GLEW_ARB_compatibility) { + strcat(defines, "#extension GL_ARB_compatibility: enable\n"); + } + + if (!GLEW_VERSION_3_1) { + if (GLEW_ARB_draw_instanced) { + strcat(defines, "#extension GL_ARB_draw_instanced: enable\n"); + } + + if (!GLEW_VERSION_3_0 && GLEW_EXT_gpu_shader4) { + strcat(defines, "#extension GL_EXT_gpu_shader4: enable\n"); + /* TODO: maybe require this? shaders become so much nicer */ + } + } +} + +static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], bool use_opensubdiv) +{ + /* some useful defines to detect GPU type */ + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) { + strcat(defines, "#define GPU_ATI\n"); + if (GLEW_VERSION_3_0) { + /* TODO(merwin): revisit this version check; GLEW_VERSION_3_0 means GL 3.0 or newer */ + strcat(defines, "#define CLIP_WORKAROUND\n"); + } + } + else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) + strcat(defines, "#define GPU_NVIDIA\n"); + else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) + strcat(defines, "#define GPU_INTEL\n"); + + if (GPU_bicubic_bump_support()) + strcat(defines, "#define BUMP_BICUBIC\n"); + +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): Check whether we actually compiling shader for + * the OpenSubdiv mesh. + */ + if (use_opensubdiv) { + strcat(defines, "#define USE_OPENSUBDIV\n"); + + /* TODO(sergey): not strictly speaking a define, but this is + * a global typedef which we don't have better place to define + * in yet. + */ + strcat(defines, "struct VertexData {\n" + " vec4 position;\n" + " vec3 normal;\n" + " vec2 uv;" + "};\n"); + } +#else + UNUSED_VARS(use_opensubdiv); +#endif + + return; +} + +void GPU_program_bind(GPUProgram *program) +{ + glEnable(program->type); + glBindProgramARB(program->type, program->prog); +} + +void GPU_program_unbind(GPUProgram *program) +{ + glDisable(program->type); + glBindProgramARB(program->type, 0); +} + + +GPUProgram *GPU_program_shader_create(GPUProgramType type, const char *code) +{ + /* TODO(merwin): remove ARB program support (recode smoke shader in GLSL) */ + + GPUProgram *program; + GLint error_pos, is_native; + + if (!(GLEW_ARB_fragment_program && type == GPU_PROGRAM_TYPE_FRAGMENT)) + return NULL; + + program = MEM_callocN(sizeof(GPUProgram), "GPUProgram"); + + switch (type) { + case GPU_PROGRAM_TYPE_FRAGMENT: + program->type = GL_FRAGMENT_PROGRAM_ARB; + break; + } + + /* create the object and set its code string */ + glGenProgramsARB(1, &program->prog); + glBindProgramARB(program->type, program->prog); + + glProgramStringARB(program->type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), code); + + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos); + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &is_native); + if ((error_pos == -1) && (is_native == 1)) { + return program; + } + else { + /* glGetError is set before that, clear it */ + while (glGetError() != GL_NO_ERROR) + ; + shader_print_errors("compile", (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB), &code, 1); + MEM_freeN(program); + } + + return NULL; +} + +void GPU_program_free(GPUProgram *program) +{ + glDeleteProgramsARB(1, &program->prog); + MEM_freeN(program); +} + +void GPU_program_parameter_4f(GPUProgram *program, unsigned int location, float x, float y, float z, float w) +{ + glProgramLocalParameter4fARB(program->type, location, x, y, z, w); +} + +GPUShader *GPU_shader_create(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number) +{ + return GPU_shader_create_ex(vertexcode, + fragcode, + geocode, + libcode, + defines, + input, + output, + number, + GPU_SHADER_FLAGS_NONE); +} + +GPUShader *GPU_shader_create_ex(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines, + int input, + int output, + int number, + const int flags) +{ +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): used to add #version 150 to the geometry shader. + * Could safely be renamed to "use_geometry_code" since it's very + * likely any of geometry code will want to use GLSL 1.5. + */ + bool use_opensubdiv = (flags & GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV) != 0; +#else + UNUSED_VARS(flags); + bool use_opensubdiv = false; +#endif + GLint status; + GLchar log[5000]; + GLsizei length = 0; + GPUShader *shader; + char standard_defines[MAX_DEFINE_LENGTH] = ""; + char standard_extensions[MAX_EXT_DEFINE_LENGTH] = ""; + + if (geocode && !GPU_geometry_shader_support()) + return NULL; + + shader = MEM_callocN(sizeof(GPUShader), "GPUShader"); + + if (vertexcode) + shader->vertex = glCreateShader(GL_VERTEX_SHADER); + if (fragcode) + shader->fragment = glCreateShader(GL_FRAGMENT_SHADER); + if (geocode) + shader->geometry = glCreateShader(GL_GEOMETRY_SHADER_EXT); + + shader->program = glCreateProgram(); + + if (!shader->program || + (vertexcode && !shader->vertex) || + (fragcode && !shader->fragment) || + (geocode && !shader->geometry)) + { + fprintf(stderr, "GPUShader, object creation failed.\n"); + GPU_shader_free(shader); + return NULL; + } + + gpu_shader_standard_defines(standard_defines, use_opensubdiv); + gpu_shader_standard_extensions(standard_extensions, geocode != NULL); + + if (vertexcode) { + const char *source[5]; + /* custom limit, may be too small, beware */ + int num_source = 0; + + source[num_source++] = gpu_shader_version(); + source[num_source++] = standard_extensions; + source[num_source++] = standard_defines; + + if (defines) source[num_source++] = defines; + source[num_source++] = vertexcode; + + glAttachShader(shader->program, shader->vertex); + glShaderSource(shader->vertex, num_source, source, NULL); + + glCompileShader(shader->vertex); + glGetShaderiv(shader->vertex, GL_COMPILE_STATUS, &status); + + if (!status) { + glGetShaderInfoLog(shader->vertex, sizeof(log), &length, log); + shader_print_errors("compile", log, source, num_source); + + GPU_shader_free(shader); + return NULL; + } + } + + if (fragcode) { + const char *source[7]; + int num_source = 0; + + source[num_source++] = gpu_shader_version(); + source[num_source++] = standard_extensions; + source[num_source++] = standard_defines; + +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): Move to fragment shader source code generation. */ + if (use_opensubdiv) { + source[num_source++] = + "#ifdef USE_OPENSUBDIV\n" + "in block {\n" + " VertexData v;\n" + "} inpt;\n" + "#endif\n"; + } +#endif + + if (defines) source[num_source++] = defines; + if (libcode) source[num_source++] = libcode; + source[num_source++] = fragcode; + + glAttachShader(shader->program, shader->fragment); + glShaderSource(shader->fragment, num_source, source, NULL); + + glCompileShader(shader->fragment); + glGetShaderiv(shader->fragment, GL_COMPILE_STATUS, &status); + + if (!status) { + glGetShaderInfoLog(shader->fragment, sizeof(log), &length, log); + shader_print_errors("compile", log, source, num_source); + + GPU_shader_free(shader); + return NULL; + } + } + + if (geocode) { + const char *source[6]; + int num_source = 0; + + source[num_source++] = gpu_shader_version(); + source[num_source++] = standard_extensions; + source[num_source++] = standard_defines; + + if (defines) source[num_source++] = defines; + source[num_source++] = geocode; + + glAttachShader(shader->program, shader->geometry); + glShaderSource(shader->geometry, num_source, source, NULL); + + glCompileShader(shader->geometry); + glGetShaderiv(shader->geometry, GL_COMPILE_STATUS, &status); + + if (!status) { + glGetShaderInfoLog(shader->geometry, sizeof(log), &length, log); + shader_print_errors("compile", log, source, num_source); + + GPU_shader_free(shader); + return NULL; + } + + if (!use_opensubdiv) { + GPU_shader_geometry_stage_primitive_io(shader, input, output, number); + } + } + +#ifdef WITH_OPENSUBDIV + if (use_opensubdiv) { + glBindAttribLocation(shader->program, 0, "position"); + glBindAttribLocation(shader->program, 1, "normal"); + GPU_shader_geometry_stage_primitive_io(shader, + GL_LINES_ADJACENCY_EXT, + GL_TRIANGLE_STRIP, + 4); + } +#endif + + glLinkProgram(shader->program); + glGetProgramiv(shader->program, GL_LINK_STATUS, &status); + if (!status) { + glGetProgramInfoLog(shader->program, sizeof(log), &length, log); + /* print attached shaders in pipeline order */ + if (vertexcode) shader_print_errors("linking", log, &vertexcode, 1); + if (geocode) shader_print_errors("linking", log, &geocode, 1); + if (libcode) shader_print_errors("linking", log, &libcode, 1); + if (fragcode) shader_print_errors("linking", log, &fragcode, 1); + + GPU_shader_free(shader); + return NULL; + } + +#ifdef WITH_OPENSUBDIV + /* TODO(sergey): Find a better place for this. */ + if (use_opensubdiv && GLEW_VERSION_4_1) { + glProgramUniform1i(shader->program, + glGetUniformLocation(shader->program, "FVarDataBuffer"), + 31); /* GL_TEXTURE31 */ + } +#endif + + return shader; +} + +void GPU_shader_bind(GPUShader *shader) +{ + GPU_ASSERT_NO_GL_ERRORS("Pre Shader Bind"); + glUseProgram(shader->program); + GPU_ASSERT_NO_GL_ERRORS("Post Shader Bind"); +} + +void GPU_shader_unbind(void) +{ + GPU_ASSERT_NO_GL_ERRORS("Pre Shader Unbind"); + glUseProgram(0); + GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind"); +} + +void GPU_shader_free(GPUShader *shader) +{ + if (shader->vertex) + glDeleteShader(shader->vertex); + if (shader->geometry) + glDeleteShader(shader->geometry); + if (shader->fragment) + glDeleteShader(shader->fragment); + if (shader->program) + glDeleteProgram(shader->program); + MEM_freeN(shader); +} + +int GPU_shader_get_uniform(GPUShader *shader, const char *name) +{ + return glGetUniformLocation(shader->program, name); +} + +void GPU_shader_uniform_vector(GPUShader *UNUSED(shader), int location, int length, int arraysize, const float *value) +{ + if (location == -1 || value == NULL) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); + + if (length == 1) glUniform1fv(location, arraysize, value); + else if (length == 2) glUniform2fv(location, arraysize, value); + else if (length == 3) glUniform3fv(location, arraysize, value); + else if (length == 4) glUniform4fv(location, arraysize, value); + else if (length == 9) glUniformMatrix3fv(location, arraysize, 0, value); + else if (length == 16) glUniformMatrix4fv(location, arraysize, 0, value); + + GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); +} + +void GPU_shader_uniform_vector_int(GPUShader *UNUSED(shader), int location, int length, int arraysize, const int *value) +{ + if (location == -1) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Vector"); + + if (length == 1) glUniform1iv(location, arraysize, value); + else if (length == 2) glUniform2iv(location, arraysize, value); + else if (length == 3) glUniform3iv(location, arraysize, value); + else if (length == 4) glUniform4iv(location, arraysize, value); + + GPU_ASSERT_NO_GL_ERRORS("Post Uniform Vector"); +} + +void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) +{ + if (location == -1) + return; + + GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value)); +} + +void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number) +{ + if (GPU_geometry_shader_support_via_extension()) { + /* geometry shaders must provide this info themselves for #version 150 and up */ + glProgramParameteriEXT(shader->program, GL_GEOMETRY_INPUT_TYPE_EXT, input); + glProgramParameteriEXT(shader->program, GL_GEOMETRY_OUTPUT_TYPE_EXT, output); + glProgramParameteriEXT(shader->program, GL_GEOMETRY_VERTICES_OUT_EXT, number); + } +} + +void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUTexture *tex) +{ + GLenum arbnumber; + int number = GPU_texture_bound_number(tex); + int bindcode = GPU_texture_opengl_bindcode(tex); + int target = GPU_texture_target(tex); + + if (number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if (number == -1) + return; + + if (location == -1) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Uniform Texture"); + + arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); + + if (number != 0) glActiveTexture(arbnumber); + if (bindcode != 0) + glBindTexture(target, bindcode); + else + GPU_invalid_tex_bind(target); + glUniform1i(location, number); + glEnable(target); + if (number != 0) glActiveTexture(GL_TEXTURE0); + + GPU_ASSERT_NO_GL_ERRORS("Post Uniform Texture"); +} + +int GPU_shader_get_attribute(GPUShader *shader, const char *name) +{ + int index; + + GPU_CHECK_ERRORS_AROUND(index = glGetAttribLocation(shader->program, name)); + + return index; +} + +GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) +{ + GPUShader *retval = NULL; + + switch (shader) { + case GPU_SHADER_VSM_STORE: + if (!GG.shaders.vsm_store) + GG.shaders.vsm_store = GPU_shader_create(datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.vsm_store; + break; + case GPU_SHADER_SEP_GAUSSIAN_BLUR: + if (!GG.shaders.sep_gaussian_blur) + GG.shaders.sep_gaussian_blur = GPU_shader_create(datatoc_gpu_shader_sep_gaussian_blur_vert_glsl, datatoc_gpu_shader_sep_gaussian_blur_frag_glsl, NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.sep_gaussian_blur; + break; + } + + if (retval == NULL) + printf("Unable to create a GPUShader for builtin shader: %u\n", shader); + + return retval; +} + +GPUProgram *GPU_shader_get_builtin_program(GPUBuiltinProgram program) +{ + GPUProgram *retval = NULL; + + switch (program) { + case GPU_PROGRAM_SMOKE: + if (!GG.shaders.smoke) + GG.shaders.smoke = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_frag_glsl); + retval = GG.shaders.smoke; + break; + case GPU_PROGRAM_SMOKE_COLORED: + if (!GG.shaders.smoke_colored) + GG.shaders.smoke_colored = GPU_program_shader_create(GPU_PROGRAM_TYPE_FRAGMENT, datatoc_gpu_program_smoke_color_frag_glsl); + retval = GG.shaders.smoke_colored; + break; + } + + if (retval == NULL) + printf("Unable to create a GPUProgram for builtin program: %u\n", program); + + return retval; +} + +#define MAX_DEFINES 100 + +GPUShader *GPU_shader_get_builtin_fx_shader(int effects, bool persp) +{ + int offset; + char defines[MAX_DEFINES] = ""; + /* avoid shaders out of range */ + if (effects >= MAX_FX_SHADERS) + return NULL; + + offset = 2 * effects; + + if (persp) { + offset += 1; + strcat(defines, "#define PERSP_MATRIX\n"); + } + + if (!GG.shaders.fx_shaders[offset]) { + GPUShader *shader; + + switch (effects) { + case GPU_SHADER_FX_SSAO: + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_ssao_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_ONE: + strcat(defines, "#define FIRST_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_TWO: + strcat(defines, "#define SECOND_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_THREE: + strcat(defines, "#define THIRD_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FOUR: + strcat(defines, "#define FOURTH_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_PASS_FIVE: + strcat(defines, "#define FIFTH_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_vert_glsl, datatoc_gpu_shader_fx_dof_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_ONE: + strcat(defines, "#define FIRST_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_TWO: + strcat(defines, "#define SECOND_PASS\n"); + shader = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, datatoc_gpu_shader_fx_dof_hq_geo_glsl, datatoc_gpu_shader_fx_lib_glsl, + defines, GL_POINTS, GL_TRIANGLE_STRIP, 4); + GG.shaders.fx_shaders[offset] = shader; + break; + + case GPU_SHADER_FX_DEPTH_OF_FIELD_HQ_PASS_THREE: + strcat(defines, "#define THIRD_PASS\n"); + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_dof_hq_vert_glsl, datatoc_gpu_shader_fx_dof_hq_frag_glsl, NULL, datatoc_gpu_shader_fx_lib_glsl, defines, 0, 0, 0); + break; + + case GPU_SHADER_FX_DEPTH_RESOLVE: + GG.shaders.fx_shaders[offset] = GPU_shader_create(datatoc_gpu_shader_fx_vert_glsl, datatoc_gpu_shader_fx_depth_resolve_glsl, NULL, NULL, defines, 0, 0, 0); + } + } + + return GG.shaders.fx_shaders[offset]; +} + + +void GPU_shader_free_builtin_shaders(void) +{ + int i; + + if (GG.shaders.vsm_store) { + GPU_shader_free(GG.shaders.vsm_store); + GG.shaders.vsm_store = NULL; + } + + if (GG.shaders.sep_gaussian_blur) { + GPU_shader_free(GG.shaders.sep_gaussian_blur); + GG.shaders.sep_gaussian_blur = NULL; + } + + if (GG.shaders.smoke) { + GPU_program_free(GG.shaders.smoke); + GG.shaders.smoke = NULL; + } + + if (GG.shaders.smoke_colored) { + GPU_program_free(GG.shaders.smoke_colored); + GG.shaders.smoke_colored = NULL; + } + + for (i = 0; i < 2 * MAX_FX_SHADERS; i++) { + if (GG.shaders.fx_shaders[i]) { + GPU_shader_free(GG.shaders.fx_shaders[i]); + GG.shaders.fx_shaders[i] = NULL; + } + } +} + + diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c new file mode 100644 index 00000000000..7803c0d0a87 --- /dev/null +++ b/source/blender/gpu/intern/gpu_texture.c @@ -0,0 +1,762 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_image_types.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_base.h" +#include "BLI_math_vector.h" + +#include "BKE_global.h" + +#include "GPU_debug.h" +#include "GPU_draw.h" +#include "GPU_extensions.h" +#include "GPU_framebuffer.h" +#include "GPU_glew.h" +#include "GPU_texture.h" + +static struct GPUTextureGlobal { + GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */ + GPUTexture *invalid_tex_2D; + GPUTexture *invalid_tex_3D; +} GG = {NULL, NULL, NULL}; + +/* GPUTexture */ + +struct GPUTexture { + int w, h; /* width/height */ + int number; /* number for multitexture binding */ + int refcount; /* reference count */ + GLenum target; /* GL_TEXTURE_* */ + GLenum target_base; /* same as target, (but no multisample) */ + GLuint bindcode; /* opengl identifier for texture */ + int fromblender; /* we got the texture from Blender */ + + GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ + int fb_attachment; /* slot the texture is attached to */ + int depth; /* is a depth texture? if 3D how deep? */ +}; + +static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels) +{ + unsigned char *pixels, *p; + const float *fp = fpixels; + const int len = 4 * length; + int a; + + p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels"); + + for (a = 0; a < len; a++, p++, fp++) + *p = FTOCHAR((*fp)); + + return pixels; +} + +static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h) +{ + void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels"); + + if (target == GL_TEXTURE_1D) + glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels); + else + glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels); + + MEM_freeN(pixels); +} + +static GPUTexture *GPU_texture_create_nD( + int w, int h, int n, const float *fpixels, int depth, + GPUHDRType hdr_type, int components, int samples, + char err_out[256]) +{ + GPUTexture *tex; + GLenum type, format, internalformat; + void *pixels = NULL; + + if (samples) { + CLAMP_MAX(samples, GPU_max_color_texture_samples()); + } + + tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); + tex->w = w; + tex->h = h; + tex->number = -1; + tex->refcount = 1; + tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); + tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D; + tex->depth = depth; + tex->fb_attachment = -1; + + glGenTextures(1, &tex->bindcode); + + if (!tex->bindcode) { + if (err_out) { + BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d", + (int)glGetError()); + } + else { + fprintf(stderr, "GPUTexture: texture create failed: %d\n", + (int)glGetError()); + } + GPU_texture_free(tex); + return NULL; + } + + if (!GPU_full_non_power_of_two_support()) { + tex->w = power_of_2_max_i(tex->w); + tex->h = power_of_2_max_i(tex->h); + } + + tex->number = 0; + glBindTexture(tex->target, tex->bindcode); + + if (depth) { + type = GL_UNSIGNED_BYTE; + format = GL_DEPTH_COMPONENT; + internalformat = GL_DEPTH_COMPONENT; + } + else { + type = GL_FLOAT; + + if (components == 4) { + format = GL_RGBA; + switch (hdr_type) { + case GPU_HDR_NONE: + internalformat = GL_RGBA8; + break; + /* the following formats rely on ARB_texture_float or OpenGL 3.0 */ + case GPU_HDR_HALF_FLOAT: + internalformat = GL_RGBA16F_ARB; + break; + case GPU_HDR_FULL_FLOAT: + internalformat = GL_RGBA32F_ARB; + break; + default: + break; + } + } + else if (components == 2) { + /* these formats rely on ARB_texture_rg or OpenGL 3.0 */ + format = GL_RG; + switch (hdr_type) { + case GPU_HDR_NONE: + internalformat = GL_RG8; + break; + case GPU_HDR_HALF_FLOAT: + internalformat = GL_RG16F; + break; + case GPU_HDR_FULL_FLOAT: + internalformat = GL_RG32F; + break; + default: + break; + } + } + + if (fpixels && hdr_type == GPU_HDR_NONE) { + type = GL_UNSIGNED_BYTE; + pixels = GPU_texture_convert_pixels(w*h, fpixels); + } + } + + if (tex->target == GL_TEXTURE_1D) { + glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL); + + if (fpixels) { + glTexSubImage1D(tex->target, 0, 0, w, format, type, + pixels ? pixels : fpixels); + + if (tex->w > w) + GPU_glTexSubImageEmpty(tex->target, format, w, 0, + tex->w-w, 1); + } + } + else { + if (samples) { + glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true); + } + else { + glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, + format, type, NULL); + } + + if (fpixels) { + glTexSubImage2D(tex->target, 0, 0, 0, w, h, + format, type, pixels ? pixels : fpixels); + + if (tex->w > w) + GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w-w, tex->h); + if (tex->h > h) + GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h-h); + } + } + + if (pixels) + MEM_freeN(pixels); + + if (depth) { + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); + } + else { + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + if (tex->target_base != GL_TEXTURE_1D) { + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + + return tex; +} + + +GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels) +{ + GPUTexture *tex; + GLenum type, format, internalformat; + void *pixels = NULL; + int r_width; + bool rescale = false; + + if (!GLEW_VERSION_1_2) + return NULL; + + tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); + tex->w = w; + tex->h = h; + tex->depth = depth; + tex->number = -1; + tex->refcount = 1; + tex->target = GL_TEXTURE_3D; + tex->target_base = GL_TEXTURE_3D; + + glGenTextures(1, &tex->bindcode); + + if (!tex->bindcode) { + fprintf(stderr, "GPUTexture: texture create failed: %d\n", + (int)glGetError()); + GPU_texture_free(tex); + return NULL; + } + + tex->number = 0; + glBindTexture(tex->target, tex->bindcode); + + GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture"); + + type = GL_FLOAT; + if (channels == 4) { + format = GL_RGBA; + internalformat = GL_RGBA8; + } + else { + format = GL_RED; + internalformat = GL_INTENSITY8; + } + + /* 3D textures are quite heavy, test if it's possible to create them first */ + glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + + while (r_width == 0) { + rescale = true; + tex->w /= 2; + tex->h /= 2; + tex->depth /= 2; + glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + } + + /* really unlikely to happen but keep this just in case */ + tex->w = max_ii(tex->w, 1); + tex->h = max_ii(tex->h, 1); + tex->depth = max_ii(tex->depth, 1); + +#if 0 + if (fpixels) + pixels = GPU_texture_convert_pixels(w*h*depth, fpixels); +#endif + + GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D"); + + /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it + * for gooseberry */ + if (rescale && fpixels) { + unsigned int i, j, k; + unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth; + float *tex3d = MEM_mallocN(channels * sizeof(float)*tex->w*tex->h*tex->depth, "tex3d"); + + GPU_print_error_debug("You need to scale a 3D texture, feel the pain!"); + + for (k = 0; k < tex->depth; k++) { + for (j = 0; j < tex->h; j++) { + for (i = 0; i < tex->w; i++) { + /* obviously doing nearest filtering here, it's going to be slow in any case, let's not make it worse */ + float xb = i * xf; + float yb = j * yf; + float zb = k * zf; + unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j; + unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb); + + if (channels == 4) { + tex3d[offset * 4] = fpixels[offset_orig * 4]; + tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1]; + tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2]; + tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3]; + } + else + tex3d[offset] = fpixels[offset_orig]; + } + } + } + + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d); + + MEM_freeN(tex3d); + } + else { + if (fpixels) { + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels); + GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D"); + } + } + + + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + if (pixels) + MEM_freeN(pixels); + + GPU_texture_unbind(tex); + + return tex; +} + +GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data, double time, int mipmap) +{ + GPUTexture *tex; + GLint w, h, border, bindcode; + + GPU_update_image_time(ima, time); + /* this binds a texture, so that's why to restore it to 0 */ + bindcode = GPU_verify_image(ima, iuser, 0, 0, mipmap, is_data); + + if (ima->gputexture) { + ima->gputexture->bindcode = bindcode; + glBindTexture(GL_TEXTURE_2D, 0); + return ima->gputexture; + } + + tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); + tex->bindcode = bindcode; + tex->number = -1; + tex->refcount = 1; + tex->target = GL_TEXTURE_2D; + tex->target_base = GL_TEXTURE_2D; + tex->fromblender = 1; + + ima->gputexture= tex; + + if (!glIsTexture(tex->bindcode)) { + GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + } + else { + glBindTexture(GL_TEXTURE_2D, tex->bindcode); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BORDER, &border); + + tex->w = w - border; + tex->h = h - border; + } + + glBindTexture(GL_TEXTURE_2D, 0); + + return tex; +} + +GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) +{ + GPUTexture *tex = prv->gputexture[0]; + GLint w, h; + GLuint bindcode = 0; + + if (tex) + bindcode = tex->bindcode; + + /* this binds a texture, so that's why we restore it to 0 */ + if (bindcode == 0) { + GPU_create_gl_tex(&bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], mipmap, 0, NULL); + } + if (tex) { + tex->bindcode = bindcode; + glBindTexture(GL_TEXTURE_2D, 0); + return tex; + } + + tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); + tex->bindcode = bindcode; + tex->number = -1; + tex->refcount = 1; + tex->target = GL_TEXTURE_2D; + tex->target_base = GL_TEXTURE_2D; + + prv->gputexture[0] = tex; + + if (!glIsTexture(tex->bindcode)) { + GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + } + else { + glBindTexture(GL_TEXTURE_2D, tex->bindcode); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); + + tex->w = w; + tex->h = h; + } + + glBindTexture(GL_TEXTURE_2D, 0); + + return tex; + +} + +GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} + +GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} +GPUTexture *GPU_texture_create_2D_multisample(int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} + +GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} +GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} + +/** + * A shadow map for VSM needs two components (depth and depth^2) + */ +GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out); + + if (tex) { + /* Now we tweak some of the settings */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + GPU_texture_unbind(tex); + } + + return tex; +} + +GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + + if (tex) { + /* Now we tweak some of the settings */ + if (repeat) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + GPU_texture_unbind(tex); + } + + return tex; +} + +GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + + if (tex) { + /* Now we tweak some of the settings */ + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + GPU_texture_unbind(tex); + } + + return tex; +} + +void GPU_invalid_tex_init(void) +{ + const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f}; + GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL); + GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL); + GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color); +} + +void GPU_invalid_tex_bind(int mode) +{ + switch (mode) { + case GL_TEXTURE_1D: + glBindTexture(GL_TEXTURE_1D, GG.invalid_tex_1D->bindcode); + break; + case GL_TEXTURE_2D: + glBindTexture(GL_TEXTURE_2D, GG.invalid_tex_2D->bindcode); + break; + case GL_TEXTURE_3D: + glBindTexture(GL_TEXTURE_3D, GG.invalid_tex_3D->bindcode); + break; + } +} + +void GPU_invalid_tex_free(void) +{ + if (GG.invalid_tex_1D) + GPU_texture_free(GG.invalid_tex_1D); + if (GG.invalid_tex_2D) + GPU_texture_free(GG.invalid_tex_2D); + if (GG.invalid_tex_3D) + GPU_texture_free(GG.invalid_tex_3D); +} + + +void GPU_texture_bind(GPUTexture *tex, int number) +{ + GLenum arbnumber; + + if (number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if ((G.debug & G_DEBUG)) { + if (tex->fb && GPU_framebuffer_bound(tex->fb)) { + fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n"); + } + } + + if (number < 0) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind"); + + arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); + if (number != 0) glActiveTexture(arbnumber); + if (tex->bindcode != 0) { + glBindTexture(tex->target, tex->bindcode); + } + else + GPU_invalid_tex_bind(tex->target); + glEnable(tex->target); + if (number != 0) glActiveTexture(GL_TEXTURE0); + + tex->number = number; + + GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind"); +} + +void GPU_texture_unbind(GPUTexture *tex) +{ + GLenum arbnumber; + + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if (tex->number == -1) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); + + arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); + if (tex->number != 0) glActiveTexture(arbnumber); + glBindTexture(tex->target, 0); + glDisable(tex->target_base); + if (tex->number != 0) glActiveTexture(GL_TEXTURE0); + + tex->number = -1; + + GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); +} + +int GPU_texture_bound_number(GPUTexture *tex) +{ + return tex->number; +} + +void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) +{ + GLenum arbnumber; + + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if (tex->number == -1) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); + + arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); + if (tex->number != 0) glActiveTexture(arbnumber); + + if (tex->depth) { + if (compare) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + if (use_filter) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + if (tex->number != 0) glActiveTexture(GL_TEXTURE0); + + GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); +} + +void GPU_texture_free(GPUTexture *tex) +{ + tex->refcount--; + + if (tex->refcount < 0) + fprintf(stderr, "GPUTexture: negative refcount\n"); + + if (tex->refcount == 0) { + if (tex->fb) + GPU_framebuffer_texture_detach(tex); + if (tex->bindcode && !tex->fromblender) + glDeleteTextures(1, &tex->bindcode); + + MEM_freeN(tex); + } +} + +void GPU_texture_ref(GPUTexture *tex) +{ + tex->refcount++; +} + +int GPU_texture_target(const GPUTexture *tex) +{ + return tex->target; +} + +int GPU_texture_width(const GPUTexture *tex) +{ + return tex->w; +} + +int GPU_texture_height(const GPUTexture *tex) +{ + return tex->h; +} + +int GPU_texture_depth(const GPUTexture *tex) +{ + return tex->depth; +} + +int GPU_texture_opengl_bindcode(const GPUTexture *tex) +{ + return tex->bindcode; +} + +GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex) +{ + return tex->fb; +} + +int GPU_texture_framebuffer_attachment(GPUTexture *tex) +{ + return tex->fb_attachment; +} + +void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment) +{ + tex->fb = fb; + tex->fb_attachment = attachment; +} + diff --git a/source/blender/gpu/shaders/gpu_shader_simple_frag.glsl b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl index 94c73d9e248..94c73d9e248 100644 --- a/source/blender/gpu/shaders/gpu_shader_simple_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_frag.glsl diff --git a/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl index 8ccd0feb5e2..8ccd0feb5e2 100644 --- a/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_basic_vert.glsl diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 6f07d18953e..7bd29137aeb 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -640,7 +640,9 @@ typedef struct BooleanModifierData { ModifierData modifier; struct Object *object; - int operation, pad; + char operation; + char bm_flag, pad[2]; + float threshold; } BooleanModifierData; typedef enum { @@ -649,6 +651,14 @@ typedef enum { eBooleanModifierOp_Difference = 2, } BooleanModifierOp; +/* temp bm_flag (debugging only) */ +enum { + eBooleanModifierBMeshFlag_Enabled = (1 << 0), + eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 1), + eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 2), + eBooleanModifierBMeshFlag_BMesh_NoConnectRegions = (1 << 3), +}; + typedef struct MDefInfluence { int vertex; float weight; @@ -688,7 +698,7 @@ typedef struct MeshDeformModifierData { float *bindcos; /* deprecated storage of cage coords */ /* runtime */ - void (*bindfunc)(struct Scene *scene, struct MeshDeformModifierData *mmd, + void (*bindfunc)(struct Scene *scene, struct MeshDeformModifierData *mmd, struct DerivedMesh *cagedm, float *vertexcos, int totvert, float cagemat[4][4]); } MeshDeformModifierData; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 6d282f4ece9..86713d7dcc8 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -807,6 +807,7 @@ typedef struct NodeShaderTexPointDensity { short interpolation; short color_source; short pad2; + PointDensity pd; } NodeShaderTexPointDensity; /* TEX_output */ diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 69e7fb43fb6..e5c102b1d2d 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -417,6 +417,9 @@ enum { SEQ_SCENE_NO_GPENCIL = (1 << 28), SEQ_USE_VIEWS = (1 << 29), + /* access scene strips directly (like a metastrip) */ + SEQ_SCENE_STRIPS = (1 << 30), + SEQ_INVALID_EFFECT = (1 << 31), }; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 4beeaa8bc3f..af1dfc62894 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -284,7 +284,7 @@ typedef struct ThemeSpace { char nodeclass_pattern[4], nodeclass_layout[4]; char movie[4], movieclip[4], mask[4], image[4], scene[4], audio[4]; /* for sequence editor */ - char effect[4], transition[4], meta[4]; + char effect[4], transition[4], meta[4], text_strip[4], pad[4]; char editmesh_active[4]; char handle_vertex[4]; @@ -545,6 +545,7 @@ typedef struct UserDef { char author[80]; /* author name for file formats supporting it */ char font_path_ui[1024]; + char font_path_ui_mono[1024]; int compute_device_type; int compute_device_id; diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 2384bb7347b..06c53547b77 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -315,11 +315,18 @@ typedef struct View3D { #define V3D_SHOW_WORLD (1 << 0) /* View3D->around */ -#define V3D_CENTER 0 -#define V3D_CENTROID 3 -#define V3D_CURSOR 1 -#define V3D_LOCAL 2 -#define V3D_ACTIVE 4 +enum { + /* center of the bounding box */ + V3D_AROUND_CENTER_BOUNDS = 0, + /* center from the sum of all points divided by the total */ + V3D_AROUND_CENTER_MEAN = 3, + /* pivot around the 2D/3D cursor */ + V3D_AROUND_CURSOR = 1, + /* pivot around each items own origin */ + V3D_AROUND_LOCAL_ORIGINS = 2, + /* pivot around the active items origin */ + V3D_AROUND_ACTIVE = 4, +}; /*View3D types (only used in tools, not actually saved)*/ #define V3D_VIEW_STEPLEFT 1 diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 826dd961010..8b785c8a65f 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -975,6 +975,7 @@ char *RNA_path_resolve_from_type_to_property( char *RNA_path_full_ID_py(struct ID *id); char *RNA_path_full_struct_py(struct PointerRNA *ptr); +char *RNA_path_full_property_py_ex(PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback); char *RNA_path_full_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index); char *RNA_path_struct_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index); char *RNA_path_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index); diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index cc876b4375e..bf8ea048fae 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -100,6 +100,8 @@ PropertyRNA *RNA_def_float_color(StructOrFunctionRNA *cont, const char *identifi PropertyRNA *RNA_def_float_matrix(StructOrFunctionRNA *cont, const char *identifier, int rows, int columns, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax); PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax); +PropertyRNA *RNA_def_float_distance(StructOrFunctionRNA *cont, const char *identifier, float default_value, + float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax); PropertyRNA *RNA_def_float_array(StructOrFunctionRNA *cont, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax); diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 887124fc486..ce977daf30a 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1900,9 +1900,13 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn if (!(flag & PROP_DYNAMIC) && dp->prop->arraydimension) fprintf(f, "%s %s[%u]", rna_parameter_type_cpp_name(dp->prop), rna_safe_id(dp->prop->identifier), dp->prop->totarraylength); - else - fprintf(f, "%s %s%s", rna_parameter_type_cpp_name(dp->prop), - ptrstr, rna_safe_id(dp->prop->identifier)); + else { + fprintf(f, "%s%s%s%s", + rna_parameter_type_cpp_name(dp->prop), + (dp->prop->type == PROP_POINTER && ptrstr[0] == '\0') ? "& " : " ", + ptrstr, + rna_safe_id(dp->prop->identifier)); + } } fprintf(f, ")"); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 5e4ea749b22..ede5073483b 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -4719,11 +4719,12 @@ char *RNA_path_full_struct_py(struct PointerRNA *ptr) * Get the ID.struct.property as a python representation, eg: * bpy.data.foo["bar"].some_struct.some_prop[10] */ -char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) +char *RNA_path_full_property_py_ex(PointerRNA *ptr, PropertyRNA *prop, int index, bool use_fallback) { char *id_path; const char *data_delim; - char *data_path; + const char *data_path; + bool data_path_free; char *ret; @@ -4735,8 +4736,23 @@ char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) id_path = RNA_path_full_ID_py(ptr->id.data); data_path = RNA_path_from_ID_to_property(ptr, prop); + if (data_path) { + data_delim = (data_path[0] == '[') ? "" : "."; + data_path_free = true; + } + else { + if (use_fallback) { + /* fuzzy fallback. be explicit in our ignoranc. */ + data_path = RNA_property_identifier(prop); + data_delim = " ... "; + } + else { + data_delim = "."; + + } + data_path_free = false; + } - data_delim = (data_path && data_path[0] == '[') ? "" : "."; if ((index == -1) || (RNA_property_array_check(prop) == false)) { ret = BLI_sprintfN("%s%s%s", @@ -4747,13 +4763,18 @@ char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) id_path, data_delim, data_path, index); } MEM_freeN(id_path); - if (data_path) { - MEM_freeN(data_path); + if (data_path_free) { + MEM_freeN((void *)data_path); } return ret; } +char *RNA_path_full_property_py(PointerRNA *ptr, PropertyRNA *prop, int index) +{ + return RNA_path_full_property_py_ex(ptr, prop, index, false); +} + /** * Get the struct.property as a python representation, eg: * some_struct.some_prop[10] diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 3b01305110c..f4b2c15b304 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -1315,7 +1315,7 @@ void RNA_def_property_ui_icon(PropertyRNA *prop, int icon, bool consecutive) * The values hare are a little confusing: * * \param step: Used as the value to increase/decrease when clicking on number buttons, - * \as well as scaling mouse input for click-dragging number buttons. + * as well as scaling mouse input for click-dragging number buttons. * For floats this is (step * UI_PRECISION_FLOAT_SCALE), why? - nobody knows. * For ints, whole values are used. * @@ -2875,6 +2875,18 @@ PropertyRNA *RNA_def_float_rotation(StructOrFunctionRNA *cont_, const char *iden return prop; } +PropertyRNA *RNA_def_float_distance(StructOrFunctionRNA *cont_, const char *identifier, + float default_value, float hardmin, float hardmax, const char *ui_name, + const char *ui_description, float softmin, float softmax) +{ + PropertyRNA *prop = RNA_def_float(cont_, identifier, default_value, + hardmin, hardmax, ui_name, ui_description, + softmin, softmax); + RNA_def_property_subtype(prop, PROP_DISTANCE); + + return prop; +} + PropertyRNA *RNA_def_float_array(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax) diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 18523f7c3e8..7280cc622dc 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -249,7 +249,6 @@ static int rna_Image_gl_load(Image *image, ReportList *reports, int frame, int f glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLint)filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLint)mag); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); error = glGetError(); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 4ca7493eb13..bf35752dcf6 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1883,6 +1883,34 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) RNA_def_property_enum_items(prop, prop_operation_items); RNA_def_property_ui_text(prop, "Operation", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + /* BMesh intersection options */ + prop = RNA_def_property(srna, "use_bmesh", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_Enabled); + RNA_def_property_ui_text(prop, "Use BMesh", "Use BMesh boolean calculation"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "use_bmesh_separate", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_Separate); + RNA_def_property_ui_text(prop, "Separate", "Keep edges separate"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "use_bmesh_dissolve", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoDissolve); + RNA_def_property_ui_text(prop, "Dissolve", "Dissolve verts created from tessellated intersection"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "use_bmesh_connect_regions", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoConnectRegions); + RNA_def_property_ui_text(prop, "Calculate Holes", "Connect regions (needed for hole filling)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "threshold"); + RNA_def_property_range(prop, 0, 1.0f); + RNA_def_property_ui_range(prop, 0, 1, 1, 7); + RNA_def_property_ui_text(prop, "Threshold", ""); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_array(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 2d412bf778b..c10fe52bb29 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1182,6 +1182,24 @@ static void rna_Node_update_reg(bNodeTree *ntree, bNode *node) RNA_parameter_list_free(&list); } +static void rna_Node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link) +{ + extern FunctionRNA rna_Node_insert_link_func; + + PointerRNA ptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create((ID *)ntree, node->typeinfo->ext.srna, node, &ptr); + func = &rna_Node_insert_link_func; + + RNA_parameter_list_create(&list, &ptr, func); + RNA_parameter_set_lookup(&list, "link", &link); + node->typeinfo->ext.call(NULL, &ptr, func, &list); + + RNA_parameter_list_free(&list); +} + static void rna_Node_init(const bContext *C, PointerRNA *ptr) { extern FunctionRNA rna_Node_init_func; @@ -1331,7 +1349,7 @@ static bNodeType *rna_Node_register_base(Main *bmain, ReportList *reports, Struc PointerRNA dummyptr; FunctionRNA *func; PropertyRNA *parm; - int have_function[9]; + int have_function[10]; /* setup dummy node & node type to store static properties in */ memset(&dummynt, 0, sizeof(bNodeType)); @@ -1384,12 +1402,13 @@ static bNodeType *rna_Node_register_base(Main *bmain, ReportList *reports, Struc nt->poll = (have_function[0]) ? rna_Node_poll : NULL; nt->poll_instance = (have_function[1]) ? rna_Node_poll_instance : rna_Node_poll_instance_default; nt->updatefunc = (have_function[2]) ? rna_Node_update_reg : NULL; - nt->initfunc_api = (have_function[3]) ? rna_Node_init : NULL; - nt->copyfunc_api = (have_function[4]) ? rna_Node_copy : NULL; - nt->freefunc_api = (have_function[5]) ? rna_Node_free : NULL; - nt->draw_buttons = (have_function[6]) ? rna_Node_draw_buttons : NULL; - nt->draw_buttons_ex = (have_function[7]) ? rna_Node_draw_buttons_ext : NULL; - nt->labelfunc = (have_function[8]) ? rna_Node_draw_label : NULL; + nt->insert_link = (have_function[3]) ? rna_Node_insert_link : NULL; + nt->initfunc_api = (have_function[4]) ? rna_Node_init : NULL; + nt->copyfunc_api = (have_function[5]) ? rna_Node_copy : NULL; + nt->freefunc_api = (have_function[6]) ? rna_Node_free : NULL; + nt->draw_buttons = (have_function[7]) ? rna_Node_draw_buttons : NULL; + nt->draw_buttons_ex = (have_function[8]) ? rna_Node_draw_buttons_ext : NULL; + nt->labelfunc = (have_function[9]) ? rna_Node_draw_label : NULL; /* sanitize size values in case not all have been registered */ if (nt->maxwidth < nt->minwidth) @@ -3016,6 +3035,39 @@ static int point_density_color_source_from_shader(NodeShaderTexPointDensity *sha } } +void rna_ShaderNodePointDensity_density_cache(bNode *self, + Scene *scene, + int settings) +{ + NodeShaderTexPointDensity *shader_point_density = self->storage; + PointDensity *pd = &shader_point_density->pd; + if (scene == NULL) { + return; + } + + /* Create PointDensity structure from node for sampling. */ + memset(pd, 0, sizeof(*pd)); + BKE_texture_pointdensity_init_data(pd); + pd->object = (Object *)self->id; + pd->radius = shader_point_density->radius; + if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) { + pd->source = TEX_PD_PSYS; + pd->psys = shader_point_density->particle_system; + pd->psys_cache_space = TEX_PD_OBJECTSPACE; + } + else { + BLI_assert(shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_OBJECT); + pd->source = TEX_PD_OBJECT; + pd->ob_cache_space = TEX_PD_OBJECTSPACE; + } + pd->color_source = point_density_color_source_from_shader(shader_point_density); + + /* Single-threaded sampling of the voxel domain. */ + RE_cache_point_density(scene, + pd, + settings == 1); +} + void rna_ShaderNodePointDensity_density_calc(bNode *self, Scene *scene, int settings, @@ -3023,7 +3075,7 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self, float **values) { NodeShaderTexPointDensity *shader_point_density = self->storage; - PointDensity pd; + PointDensity *pd = &shader_point_density->pd; if (scene == NULL) { *length = 0; @@ -3038,30 +3090,14 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self, *values = MEM_mallocN(sizeof(float) * (*length), "point density dynamic array"); } - /* Create PointDensity structure from node for sampling. */ - BKE_texture_pointdensity_init_data(&pd); - pd.object = (Object *)self->id; - pd.radius = shader_point_density->radius; - if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) { - pd.source = TEX_PD_PSYS; - pd.psys = shader_point_density->particle_system; - pd.psys_cache_space = TEX_PD_OBJECTSPACE; - } - else { - BLI_assert(shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_OBJECT); - pd.source = TEX_PD_OBJECT; - pd.ob_cache_space = TEX_PD_OBJECTSPACE; - } - pd.color_source = point_density_color_source_from_shader(shader_point_density); - /* Single-threaded sampling of the voxel domain. */ - RE_sample_point_density(scene, &pd, + RE_sample_point_density(scene, pd, shader_point_density->resolution, settings == 1, *values); /* We're done, time to clean up. */ - BKE_texture_pointdensity_free_data(&pd); + BKE_texture_pointdensity_free_data(pd); } #else @@ -3993,6 +4029,11 @@ static void def_sh_tex_pointdensity(StructRNA *srna) RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from"); RNA_def_property_update(prop, 0, "rna_Node_update"); + func = RNA_def_function(srna, "cache_point_density", "rna_ShaderNodePointDensity_density_cache"); + RNA_def_function_ui_description(func, "Cache point density data for later calculation"); + RNA_def_pointer(func, "scene", "Scene", "", ""); + RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering"); + func = RNA_def_function(srna, "calc_point_density", "rna_ShaderNodePointDensity_density_calc"); RNA_def_function_ui_description(func, "Calculate point density"); RNA_def_pointer(func, "scene", "Scene", "", ""); @@ -7684,6 +7725,13 @@ static void rna_def_node(BlenderRNA *brna) RNA_def_function_ui_description(func, "Update on editor changes"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); + /* insert_link */ + func = RNA_def_function(srna, "insert_link", NULL); + RNA_def_function_ui_description(func, "Handle creation of a link to or from the node"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); + parm = RNA_def_pointer(func, "link", "NodeLink", "Link", "Node link that will be inserted"); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + /* init */ func = RNA_def_function(srna, "init", NULL); RNA_def_function_ui_description(func, "Initialize a new instance of this node"); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 7409a9c9c23..81b1e4ac4be 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -276,6 +276,9 @@ static void rna_Object_active_shape_update(Main *bmain, Scene *scene, PointerRNA case OB_MESH: EDBM_mesh_load(ob); EDBM_mesh_make(scene->toolsettings, ob); + + DAG_id_tag_update(ob->data, 0); + EDBM_mesh_normals_update(((Mesh *)ob->data)->edit_btmesh); BKE_editmesh_tessface_calc(((Mesh *)ob->data)->edit_btmesh); break; diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 628dd98eaf7..5645f018cad 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -315,8 +315,10 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly; } -static void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start[3], float ray_end[3], - float r_location[3], float r_normal[3], int *index) +static void rna_Object_ray_cast( + Object *ob, ReportList *reports, + float origin[3], float direction[3], float distance, + int *r_success, float r_location[3], float r_normal[3], int *r_index) { BVHTreeFromMesh treeData = {NULL}; @@ -331,33 +333,41 @@ static void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start /* may fail if the mesh has no faces, in that case the ray-cast misses */ if (treeData.tree != NULL) { BVHTreeRayHit hit; - float ray_nor[3], dist; - sub_v3_v3v3(ray_nor, ray_end, ray_start); - dist = hit.dist = normalize_v3(ray_nor); hit.index = -1; + hit.dist = distance; - if (BLI_bvhtree_ray_cast(treeData.tree, ray_start, ray_nor, 0.0f, &hit, + normalize_v3(direction); + + + if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) { - if (hit.dist <= dist) { + if (hit.dist <= distance) { + *r_success = true; + copy_v3_v3(r_location, hit.co); copy_v3_v3(r_normal, hit.no); - *index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]); - free_bvhtree_from_mesh(&treeData); - return; + *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]); + + goto finally; } } } + *r_success = false; + zero_v3(r_location); zero_v3(r_normal); - *index = -1; + *r_index = -1; + +finally: free_bvhtree_from_mesh(&treeData); } -static void rna_Object_closest_point_on_mesh(Object *ob, ReportList *reports, float point_co[3], float max_dist, - float n_location[3], float n_normal[3], int *index) +static void rna_Object_closest_point_on_mesh( + Object *ob, ReportList *reports, float origin[3], float distance, + int *r_success, float r_location[3], float r_normal[3], int *r_index) { BVHTreeFromMesh treeData = {NULL}; @@ -379,20 +389,26 @@ static void rna_Object_closest_point_on_mesh(Object *ob, ReportList *reports, fl BVHTreeNearest nearest; nearest.index = -1; - nearest.dist_sq = max_dist * max_dist; + nearest.dist_sq = distance * distance; - if (BLI_bvhtree_find_nearest(treeData.tree, point_co, &nearest, treeData.nearest_callback, &treeData) != -1) { - copy_v3_v3(n_location, nearest.co); - copy_v3_v3(n_normal, nearest.no); - *index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[nearest.index]); - free_bvhtree_from_mesh(&treeData); - return; + if (BLI_bvhtree_find_nearest(treeData.tree, origin, &nearest, treeData.nearest_callback, &treeData) != -1) { + *r_success = true; + + copy_v3_v3(r_location, nearest.co); + copy_v3_v3(r_normal, nearest.no); + *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[nearest.index]); + + goto finally; } } - zero_v3(n_location); - zero_v3(n_normal); - *index = -1; + *r_success = false; + + zero_v3(r_location); + zero_v3(r_normal); + *r_index = -1; + +finally: free_bvhtree_from_mesh(&treeData); } @@ -593,12 +609,15 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_REPORTS); /* ray start and end */ - parm = RNA_def_float_vector(func, "start", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); + parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); RNA_def_property_flag(parm, PROP_REQUIRED); - parm = RNA_def_float_vector(func, "end", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); + parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_float(func, "distance", FLT_MAX, 0.0, FLT_MAX, "", "Maximum distance", 0.0, FLT_MAX); /* return location and normal */ + parm = RNA_def_boolean(func, "result", 0, "", ""); + RNA_def_function_output(func, parm); parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "The hit location of this ray cast", -1e4, 1e4); RNA_def_property_flag(parm, PROP_THICK_WRAP); @@ -607,8 +626,7 @@ void RNA_api_object(StructRNA *srna) "The face normal at the ray cast hit location", -1e4, 1e4); RNA_def_property_flag(parm, PROP_THICK_WRAP); RNA_def_function_output(func, parm); - - parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when no intersection is found", 0, 0); + parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0); RNA_def_function_output(func, parm); /* Nearest Point */ @@ -617,12 +635,14 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_REPORTS); /* location of point for test and max distance */ - parm = RNA_def_float_vector(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); + parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); RNA_def_property_flag(parm, PROP_REQUIRED); /* default is sqrt(FLT_MAX) */ - RNA_def_float(func, "max_dist", 1.844674352395373e+19, 0.0, FLT_MAX, "", "", 0.0, FLT_MAX); + RNA_def_float(func, "distance", 1.844674352395373e+19, 0.0, FLT_MAX, "", "Maximum distance", 0.0, FLT_MAX); /* return location and normal */ + parm = RNA_def_boolean(func, "result", 0, "", ""); + RNA_def_function_output(func, parm); parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "The location on the object closest to the point", -1e4, 1e4); RNA_def_property_flag(parm, PROP_THICK_WRAP); @@ -632,7 +652,7 @@ void RNA_api_object(StructRNA *srna) RNA_def_property_flag(parm, PROP_THICK_WRAP); RNA_def_function_output(func, parm); - parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when no closest point is found", 0, 0); + parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0); RNA_def_function_output(func, parm); /* View */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index ed7f9223b7c..2624e351c74 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -3828,12 +3828,9 @@ static void rna_def_scene_game_data(BlenderRNA *brna) static EnumPropertyItem storage_items[] = { {RAS_STORE_AUTO, "AUTO", 0, "Auto Select", "Choose the best supported mode"}, - {RAS_STORE_IMMEDIATE, "IMMEDIATE", 0, "Immediate Mode", "Slowest performance, requires OpenGL (any version)"}, - {RAS_STORE_VA, "VERTEX_ARRAY", 0, "Vertex Arrays", "Better performance, requires at least OpenGL 1.1"}, -#if 0 /* XXX VBOS are currently disabled since they cannot beat vertex array with display lists in performance. */ + {RAS_STORE_VA, "VERTEX_ARRAY", 0, "Vertex Arrays", "Usually the best choice (good performance with display lists)"}, {RAS_STORE_VBO, "VERTEX_BUFFER_OBJECT", 0, "Vertex Buffer Objects", - "Best performance, requires at least OpenGL 1.4"}, -#endif + "Typically slower than vertex arrays with display lists, requires at least OpenGL 1.4"}, {0, NULL, 0, NULL, NULL}}; srna = RNA_def_struct(brna, "SceneGameData", NULL); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 9d63dfe0f55..b31681f1b6e 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -137,30 +137,28 @@ static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, int previe } } -static void rna_Scene_ray_cast(Scene *scene, float ray_start[3], float ray_end[3], - int *r_success, Object **r_ob, float r_obmat[16], - float r_location[3], float r_normal[3]) +static void rna_Scene_ray_cast( + Scene *scene, float origin[3], float direction[3], float ray_dist, + int *r_success, float r_location[3], float r_normal[3], int *r_index, + Object **r_ob, float r_obmat[16]) { - float dummy_dist_px = 0; - float ray_nor[3]; - float ray_dist; - - sub_v3_v3v3(ray_nor, ray_end, ray_start); - ray_dist = normalize_v3(ray_nor); - - if (snapObjectsRayEx(scene, NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE, - r_ob, (float(*)[4])r_obmat, - ray_start, ray_nor, &ray_dist, - NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL)) + normalize_v3(direction); + + if (snapObjectsRayEx( + scene, NULL, NULL, NULL, NULL, + NULL, SNAP_ALL, SCE_SNAP_MODE_FACE, + origin, direction, &ray_dist, + r_location, r_normal, NULL, r_index, + r_ob, (float(*)[4])r_obmat)) { *r_success = true; } else { + *r_success = false; + unit_m4((float(*)[4])r_obmat); zero_v3(r_location); zero_v3(r_normal); - - *r_success = false; } } @@ -230,18 +228,15 @@ void RNA_api_scene(StructRNA *srna) RNA_def_function_ui_description(func, "Cast a ray onto in object space"); /* ray start and end */ - parm = RNA_def_float_vector(func, "start", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); + parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); RNA_def_property_flag(parm, PROP_REQUIRED); - parm = RNA_def_float_vector(func, "end", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); + parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_float(func, "distance", FLT_MAX, 0.0, FLT_MAX, "", "Maximum distance", 0.0, FLT_MAX); /* return location and normal */ parm = RNA_def_boolean(func, "result", 0, "", ""); RNA_def_function_output(func, parm); - parm = RNA_def_pointer(func, "object", "Object", "", "Ray cast object"); - RNA_def_function_output(func, parm); - parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); - RNA_def_function_output(func, parm); parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "The hit location of this ray cast", -1e4, 1e4); RNA_def_property_flag(parm, PROP_THICK_WRAP); @@ -250,6 +245,12 @@ void RNA_api_scene(StructRNA *srna) "The face normal at the ray cast hit location", -1e4, 1e4); RNA_def_property_flag(parm, PROP_THICK_WRAP); RNA_def_function_output(func, parm); + parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0); + RNA_def_function_output(func, parm); + parm = RNA_def_pointer(func, "object", "Object", "", "Ray cast object"); + RNA_def_function_output(func, parm); + parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); + RNA_def_function_output(func, parm); #ifdef WITH_COLLADA /* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */ diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index de138699e3a..1fb57fc1d11 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1901,7 +1901,12 @@ static void rna_def_scene(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_Camera_object_poll"); RNA_def_property_ui_text(prop, "Camera Override", "Override the scenes active camera"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); - + + prop = RNA_def_property(srna, "use_sequence", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SCENE_STRIPS); + RNA_def_property_ui_text(prop, "Use Sequence", "Use scenes sequence strips directly, instead of rendering"); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update"); + prop = RNA_def_property(srna, "use_grease_pencil", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SEQ_SCENE_NO_GPENCIL); RNA_def_property_ui_text(prop, "Use Grease Pencil", "Show Grease Pencil strokes in OpenGL previews"); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index f3f4f3c1c3d..ad26891c96a 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -124,14 +124,14 @@ static EnumPropertyItem stereo3d_eye_items[] = { #endif static EnumPropertyItem pivot_items_full[] = { - {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", + {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", "Pivot around bounding box center of selected object(s)"}, - {V3D_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Pivot around the 3D cursor"}, - {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, + {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Pivot around the 3D cursor"}, + {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, "Individual Origins", "Pivot around each object's own origin"}, - {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point", + {V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point", "Pivot around the median point of selected objects"}, - {V3D_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"}, + {V3D_AROUND_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"}, {0, NULL, 0, NULL, NULL} }; @@ -935,10 +935,10 @@ static EnumPropertyItem *rna_SpaceImageEditor_pivot_itemf(bContext *UNUSED(C), P PropertyRNA *UNUSED(prop), bool *UNUSED(r_free)) { static EnumPropertyItem pivot_items[] = { - {V3D_CENTER, "CENTER", ICON_ROTATE, "Bounding Box Center", ""}, - {V3D_CENTROID, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""}, - {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""}, - {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, + {V3D_AROUND_CENTER_BOUNDS, "CENTER", ICON_ROTATE, "Bounding Box Center", ""}, + {V3D_AROUND_CENTER_MEAN, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""}, + {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""}, + {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, "Individual Origins", "Pivot around each object's own origin"}, {0, NULL, 0, NULL, NULL} }; @@ -3426,11 +3426,11 @@ static void rna_def_space_graph(BlenderRNA *brna) /* this is basically the same as the one for the 3D-View, but with some entries omitted */ static EnumPropertyItem gpivot_items[] = { - {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", ""}, - {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""}, - {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, "Individual Centers", ""}, - /*{V3D_CENTROID, "MEDIAN_POINT", 0, "Median Point", ""}, */ - /*{V3D_ACTIVE, "ACTIVE_ELEMENT", 0, "Active Element", ""}, */ + {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", ""}, + {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""}, + {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, "Individual Centers", ""}, + /*{V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", 0, "Median Point", ""}, */ + /*{V3D_AROUND_ACTIVE, "ACTIVE_ELEMENT", 0, "Active Element", ""}, */ {0, NULL, 0, NULL, NULL} }; @@ -4457,12 +4457,12 @@ static void rna_def_space_clip(BlenderRNA *brna) }; static EnumPropertyItem pivot_items[] = { - {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", + {V3D_AROUND_CENTER_BOUNDS, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center", "Pivot around bounding box center of selected object(s)"}, - {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", "Pivot around the 2D cursor"}, - {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, + {V3D_AROUND_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", "Pivot around the 2D cursor"}, + {V3D_AROUND_LOCAL_ORIGINS, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION, "Individual Origins", "Pivot around each object's own origin"}, - {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point", + {V3D_AROUND_CENTER_MEAN, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point", "Pivot around the median point of selected objects"}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 90202a62d8b..39562d4d8a0 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -2548,6 +2548,11 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Meta Strip", ""); RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "text_strip", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Text Strip", ""); + RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "frame_current", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "cframe"); RNA_def_property_array(prop, 3); @@ -4000,6 +4005,11 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Interface Font", "Path to interface font"); RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update"); + prop = RNA_def_property(srna, "font_path_ui_mono", PROP_STRING, PROP_FILEPATH); + RNA_def_property_string_sdna(prop, NULL, "font_path_ui_mono"); + RNA_def_property_ui_text(prop, "Mono-space Font", "Path to interface mono-space Font"); + RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update"); + prop = RNA_def_property(srna, "scrollback", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "scrollback"); RNA_def_property_range(prop, 32, 32768); diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index ad230dede24..0de7676e8f8 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -37,6 +37,7 @@ set(INC ../render/extern/include ../../../intern/elbeem/extern ../../../intern/guardedalloc + ../../../intern/eigen ) set(INC_SYS @@ -144,13 +145,6 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() -if(WITH_OPENNL) - add_definitions(-DWITH_OPENNL) - list(APPEND INC_SYS - ../../../intern/opennl/extern - ) -endif() - if(WITH_OPENSUBDIV) add_definitions(-DWITH_OPENSUBDIV) endif() diff --git a/source/blender/modifiers/SConscript b/source/blender/modifiers/SConscript index 7be295aa1a0..30007118562 100644 --- a/source/blender/modifiers/SConscript +++ b/source/blender/modifiers/SConscript @@ -33,8 +33,8 @@ incs = [ '.', './intern', '#/intern/guardedalloc', + '#/intern/eigen', '#/intern/elbeem/extern', - '#/intern/opennl/extern', '../render/extern/include', '../bmesh', '../include', diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 3fd2c8a3502..57318e44eec 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -1,4 +1,3 @@ - /* * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -33,6 +32,12 @@ * \ingroup modifiers */ +// #ifdef DEBUG_TIME +#define USE_BMESH +#ifdef WITH_MOD_BOOLEAN +# define USE_CARVE WITH_MOD_BOOLEAN +#endif + #include <stdio.h> #include "DNA_object_types.h" @@ -48,6 +53,20 @@ #include "MOD_boolean_util.h" #include "MOD_util.h" +#ifdef USE_BMESH +#include "BLI_math_geom.h" +#include "MEM_guardedalloc.h" + +#include "bmesh.h" +#include "bmesh_tools.h" +#include "tools/bmesh_intersect.h" +#endif + +#ifdef DEBUG_TIME +#include "PIL_time.h" +#include "PIL_time_utildefines.h" +#endif + static void copyData(ModifierData *md, ModifierData *target) { #if 0 @@ -104,7 +123,8 @@ static void updateDepsgraph(ModifierData *md, DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Boolean Modifier"); } -#ifdef WITH_MOD_BOOLEAN +#if defined(USE_CARVE) || defined(USE_BMESH) + static DerivedMesh *get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh *dm, int operation) { DerivedMesh *result = NULL; @@ -129,10 +149,162 @@ static DerivedMesh *get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh return result; } +#endif /* defined(USE_CARVE) || defined(USE_BMESH) */ + + +/* -------------------------------------------------------------------- */ +/* BMESH */ + +#ifdef USE_BMESH + +/* has no meaning for faces, do this so we can tell which face is which */ +#define BM_FACE_TAG BM_ELEM_DRAW + +/** + * Compare selected/unselected. + */ +static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data)) +{ + return BM_elem_flag_test(f, BM_FACE_TAG) ? 1 : 0; +} -static DerivedMesh *applyModifier(ModifierData *md, Object *ob, - DerivedMesh *derivedData, - ModifierApplyFlag flag) +static DerivedMesh *applyModifier_bmesh( + ModifierData *md, Object *ob, + DerivedMesh *dm, + ModifierApplyFlag flag) +{ + BooleanModifierData *bmd = (BooleanModifierData *) md; + DerivedMesh *dm_other; + + if (!bmd->object) + return dm; + + dm_other = get_dm_for_modifier(bmd->object, flag); + + if (dm_other) { + DerivedMesh *result; + + /* when one of objects is empty (has got no faces) we could speed up + * calculation a bit returning one of objects' derived meshes (or empty one) + * Returning mesh is depended on modifiers operation (sergey) */ + result = get_quick_derivedMesh(dm, dm_other, bmd->operation); + + if (result == NULL) { + BMesh *bm; + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm, dm_other); + +#ifdef DEBUG_TIME + TIMEIT_START(boolean_bmesh); +#endif + bm = BM_mesh_create(&allocsize); + + DM_to_bmesh_ex(dm_other, bm, true); + DM_to_bmesh_ex(dm, bm, true); + + /* main bmesh intersection setup */ + { + /* create tessface & intersect */ + const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop); + int tottri; + BMLoop *(*looptris)[3]; + + looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__); + + BM_bmesh_calc_tessellation(bm, looptris, &tottri); + + /* postpone this until after tessellating + * so we can use the original normals before the vertex are moved */ + { + BMIter iter; + int i; + const int i_verts_end = dm_other->getNumVerts(dm_other); + const int i_faces_end = dm_other->getNumPolys(dm_other); + + float imat[4][4]; + float omat[4][4]; + + invert_m4_m4(imat, ob->obmat); + mul_m4_m4m4(omat, imat, bmd->object->obmat); + + + BMVert *eve; + i = 0; + BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { + mul_m4_v3(omat, eve->co); + if (++i == i_verts_end) { + break; + } + } + + /* we need face normals because of 'BM_face_split_edgenet' + * we could calculate on the fly too (before calling split). */ + float nmat[4][4]; + invert_m4_m4(nmat, omat); + + BMFace *efa; + i = 0; + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + mul_transposed_mat3_m4_v3(nmat, efa->no); + normalize_v3(efa->no); + BM_elem_flag_enable(efa, BM_FACE_TAG); /* temp tag to test which side split faces are from */ + if (++i == i_faces_end) { + break; + } + } + } + + /* not needed, but normals for 'dm' will be invalid, + * currently this is ok for 'BM_mesh_intersect' */ + // BM_mesh_normals_update(bm); + + BM_mesh_intersect( + bm, + looptris, tottri, + bm_face_isect_pair, NULL, + false, + (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0, + (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0, + (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0, + bmd->operation, + bmd->threshold); + + MEM_freeN(looptris); + } + + result = CDDM_from_bmesh(bm, true); + + BM_mesh_free(bm); + + result->dirty |= DM_DIRTY_NORMALS; + +#ifdef DEBUG_TIME + TIMEIT_END(boolean_bmesh); +#endif + + return result; + } + + /* if new mesh returned, return it; otherwise there was + * an error, so delete the modifier object */ + if (result) + return result; + else + modifier_setError(md, "Cannot execute boolean operation"); + } + + return dm; +} +#endif /* USE_BMESH */ + + +/* -------------------------------------------------------------------- */ +/* CARVE */ + +#ifdef USE_CARVE +static DerivedMesh *applyModifier_carve( + ModifierData *md, Object *ob, + DerivedMesh *derivedData, + ModifierApplyFlag flag) { BooleanModifierData *bmd = (BooleanModifierData *) md; DerivedMesh *dm; @@ -151,12 +323,15 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, result = get_quick_derivedMesh(derivedData, dm, bmd->operation); if (result == NULL) { - // TIMEIT_START(NewBooleanDerivedMesh) +#ifdef DEBUG_TIME + TIMEIT_START(boolean_carve); +#endif result = NewBooleanDerivedMesh(dm, bmd->object, derivedData, ob, 1 + bmd->operation); - - // TIMEIT_END(NewBooleanDerivedMesh) +#ifdef DEBUG_TIME + TIMEIT_END(boolean_carve); +#endif } /* if new mesh returned, return it; otherwise there was @@ -169,14 +344,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, return derivedData; } -#else // WITH_MOD_BOOLEAN -static DerivedMesh *applyModifier(ModifierData *UNUSED(md), Object *UNUSED(ob), - DerivedMesh *derivedData, - ModifierApplyFlag UNUSED(flag)) +#endif /* USE_CARVE */ + + +static DerivedMesh *applyModifier_nop( + ModifierData *UNUSED(md), Object *UNUSED(ob), + DerivedMesh *derivedData, + ModifierApplyFlag UNUSED(flag)) { return derivedData; } -#endif // WITH_MOD_BOOLEAN static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED(md)) { @@ -187,6 +364,28 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *UNUSED( return dataMask; } +static DerivedMesh *applyModifier( + ModifierData *md, Object *ob, + DerivedMesh *derivedData, + ModifierApplyFlag flag) +{ + BooleanModifierData *bmd = (BooleanModifierData *)md; + const int method = (bmd->bm_flag & eBooleanModifierBMeshFlag_Enabled) ? 1 : 0; + + switch (method) { +#ifdef USE_CARVE + case 0: + return applyModifier_carve(md, ob, derivedData, flag); +#endif +#ifdef USE_BMESH + case 1: + return applyModifier_bmesh(md, ob, derivedData, flag); +#endif + default: + return applyModifier_nop(md, ob, derivedData, flag); + } +} + ModifierTypeInfo modifierType_Boolean = { /* name */ "Boolean", diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c index fdaacc7cd9e..d4f02d923d3 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.c +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c @@ -42,6 +42,7 @@ #include "MOD_util.h" +#include "eigen_capi.h" enum { LAPDEFORM_SYSTEM_NOT_CHANGE = 0, @@ -54,10 +55,6 @@ enum { LAPDEFORM_SYSTEM_CHANGE_NOT_VALID_GROUP, }; -#ifdef WITH_OPENNL - -#include "ONL_opennl.h" - typedef struct LaplacianSystem { bool is_matrix_computed; bool has_solution; @@ -75,7 +72,7 @@ typedef struct LaplacianSystem { int *unit_verts; /* Unit vectors of projected edges onto the plane orthogonal to n */ int *ringf_indices; /* Indices of faces per vertex */ int *ringv_indices; /* Indices of neighbors(vertex) per vertex */ - NLContext *context; /* System for solve general implicit rotations */ + LinearSolver *context; /* System for solve general implicit rotations */ MeshElemMap *ringf_map; /* Map of faces per vertex */ MeshElemMap *ringv_map; /* Map of vertex per vertex */ } LaplacianSystem; @@ -134,7 +131,7 @@ static void deleteLaplacianSystem(LaplacianSystem *sys) MEM_SAFE_FREE(sys->ringv_map); if (sys->context) { - nlDeleteContext(sys->context); + EIG_linear_solver_delete(sys->context); } MEM_SAFE_FREE(sys); } @@ -283,9 +280,9 @@ static void initLaplacianMatrix(LaplacianSystem *sys) sys->delta[idv[0]][1] -= v3[1] * w3; sys->delta[idv[0]][2] -= v3[2] * w3; - nlMatrixAdd(sys->context, idv[0], idv[1], -w2); - nlMatrixAdd(sys->context, idv[0], idv[2], -w3); - nlMatrixAdd(sys->context, idv[0], idv[0], w2 + w3); + EIG_linear_solver_matrix_add(sys->context, idv[0], idv[1], -w2); + EIG_linear_solver_matrix_add(sys->context, idv[0], idv[2], -w3); + EIG_linear_solver_matrix_add(sys->context, idv[0], idv[0], w2 + w3); } } } @@ -338,9 +335,9 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys) beta = dot_v3v3(uij, di); gamma = dot_v3v3(e2, di); - pi[0] = nlGetVariable(sys->context, 0, i); - pi[1] = nlGetVariable(sys->context, 1, i); - pi[2] = nlGetVariable(sys->context, 2, i); + pi[0] = EIG_linear_solver_variable_get(sys->context, 0, i); + pi[1] = EIG_linear_solver_variable_get(sys->context, 1, i); + pi[2] = EIG_linear_solver_variable_get(sys->context, 2, i); zero_v3(ni); num_fni = 0; num_fni = sys->ringf_map[i].count; @@ -349,9 +346,9 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys) fidn = sys->ringf_map[i].indices; vin = sys->tris[fidn[fi]]; for (j = 0; j < 3; j++) { - vn[j][0] = nlGetVariable(sys->context, 0, vin[j]); - vn[j][1] = nlGetVariable(sys->context, 1, vin[j]); - vn[j][2] = nlGetVariable(sys->context, 2, vin[j]); + vn[j][0] = EIG_linear_solver_variable_get(sys->context, 0, vin[j]); + vn[j][1] = EIG_linear_solver_variable_get(sys->context, 1, vin[j]); + vn[j][2] = EIG_linear_solver_variable_get(sys->context, 2, vin[j]); if (vin[j] == sys->unit_verts[i]) { copy_v3_v3(pj, vn[j]); } @@ -372,14 +369,14 @@ static void rotateDifferentialCoordinates(LaplacianSystem *sys) fni[2] = alpha * ni[2] + beta * uij[2] + gamma * e2[2]; if (len_squared_v3(fni) > FLT_EPSILON) { - nlRightHandSideSet(sys->context, 0, i, fni[0]); - nlRightHandSideSet(sys->context, 1, i, fni[1]); - nlRightHandSideSet(sys->context, 2, i, fni[2]); + EIG_linear_solver_right_hand_side_add(sys->context, 0, i, fni[0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, i, fni[1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, i, fni[2]); } else { - nlRightHandSideSet(sys->context, 0, i, sys->delta[i][0]); - nlRightHandSideSet(sys->context, 1, i, sys->delta[i][1]); - nlRightHandSideSet(sys->context, 2, i, sys->delta[i][2]); + EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]); } } } @@ -390,75 +387,59 @@ static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3]) n = sys->total_verts; na = sys->total_anchors; -#ifdef OPENNL_THREADING_HACK - modifier_opennl_lock(); -#endif - if (!sys->is_matrix_computed) { - sys->context = nlNewContext(); + sys->context = EIG_linear_least_squares_solver_new(n + na, n, 3); - nlSolverParameteri(sys->context, NL_NB_VARIABLES, n); - nlSolverParameteri(sys->context, NL_LEAST_SQUARES, NL_TRUE); - nlSolverParameteri(sys->context, NL_NB_ROWS, n + na); - nlSolverParameteri(sys->context, NL_NB_RIGHT_HAND_SIDES, 3); - nlBegin(sys->context, NL_SYSTEM); for (i = 0; i < n; i++) { - nlSetVariable(sys->context, 0, i, sys->co[i][0]); - nlSetVariable(sys->context, 1, i, sys->co[i][1]); - nlSetVariable(sys->context, 2, i, sys->co[i][2]); + EIG_linear_solver_variable_set(sys->context, 0, i, sys->co[i][0]); + EIG_linear_solver_variable_set(sys->context, 1, i, sys->co[i][1]); + EIG_linear_solver_variable_set(sys->context, 2, i, sys->co[i][2]); } for (i = 0; i < na; i++) { vid = sys->index_anchors[i]; - nlSetVariable(sys->context, 0, vid, vertexCos[vid][0]); - nlSetVariable(sys->context, 1, vid, vertexCos[vid][1]); - nlSetVariable(sys->context, 2, vid, vertexCos[vid][2]); + EIG_linear_solver_variable_set(sys->context, 0, vid, vertexCos[vid][0]); + EIG_linear_solver_variable_set(sys->context, 1, vid, vertexCos[vid][1]); + EIG_linear_solver_variable_set(sys->context, 2, vid, vertexCos[vid][2]); } - nlBegin(sys->context, NL_MATRIX); initLaplacianMatrix(sys); computeImplictRotations(sys); for (i = 0; i < n; i++) { - nlRightHandSideSet(sys->context, 0, i, sys->delta[i][0]); - nlRightHandSideSet(sys->context, 1, i, sys->delta[i][1]); - nlRightHandSideSet(sys->context, 2, i, sys->delta[i][2]); + EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]); } for (i = 0; i < na; i++) { vid = sys->index_anchors[i]; - nlRightHandSideSet(sys->context, 0, n + i, vertexCos[vid][0]); - nlRightHandSideSet(sys->context, 1, n + i, vertexCos[vid][1]); - nlRightHandSideSet(sys->context, 2, n + i, vertexCos[vid][2]); - nlMatrixAdd(sys->context, n + i, vid, 1.0f); + EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); + EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f); } - nlEnd(sys->context, NL_MATRIX); - nlEnd(sys->context, NL_SYSTEM); - if (nlSolve(sys->context, NL_TRUE)) { + if (EIG_linear_solver_solve(sys->context)) { sys->has_solution = true; for (j = 1; j <= sys->repeat; j++) { - nlBegin(sys->context, NL_SYSTEM); - nlBegin(sys->context, NL_MATRIX); rotateDifferentialCoordinates(sys); for (i = 0; i < na; i++) { vid = sys->index_anchors[i]; - nlRightHandSideSet(sys->context, 0, n + i, vertexCos[vid][0]); - nlRightHandSideSet(sys->context, 1, n + i, vertexCos[vid][1]); - nlRightHandSideSet(sys->context, 2, n + i, vertexCos[vid][2]); + EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); } - nlEnd(sys->context, NL_MATRIX); - nlEnd(sys->context, NL_SYSTEM); - if (!nlSolve(sys->context, NL_FALSE)) { + if (!EIG_linear_solver_solve(sys->context)) { sys->has_solution = false; break; } } if (sys->has_solution) { for (vid = 0; vid < sys->total_verts; vid++) { - vertexCos[vid][0] = nlGetVariable(sys->context, 0, vid); - vertexCos[vid][1] = nlGetVariable(sys->context, 1, vid); - vertexCos[vid][2] = nlGetVariable(sys->context, 2, vid); + vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid); + vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid); + vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid); } } else { @@ -473,49 +454,40 @@ static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3]) } else if (sys->has_solution) { - nlBegin(sys->context, NL_SYSTEM); - nlBegin(sys->context, NL_MATRIX); - for (i = 0; i < n; i++) { - nlRightHandSideSet(sys->context, 0, i, sys->delta[i][0]); - nlRightHandSideSet(sys->context, 1, i, sys->delta[i][1]); - nlRightHandSideSet(sys->context, 2, i, sys->delta[i][2]); + EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]); } for (i = 0; i < na; i++) { vid = sys->index_anchors[i]; - nlRightHandSideSet(sys->context, 0, n + i, vertexCos[vid][0]); - nlRightHandSideSet(sys->context, 1, n + i, vertexCos[vid][1]); - nlRightHandSideSet(sys->context, 2, n + i, vertexCos[vid][2]); - nlMatrixAdd(sys->context, n + i, vid, 1.0f); + EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); + EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f); } - nlEnd(sys->context, NL_MATRIX); - nlEnd(sys->context, NL_SYSTEM); - if (nlSolve(sys->context, NL_FALSE)) { + if (EIG_linear_solver_solve(sys->context)) { sys->has_solution = true; for (j = 1; j <= sys->repeat; j++) { - nlBegin(sys->context, NL_SYSTEM); - nlBegin(sys->context, NL_MATRIX); rotateDifferentialCoordinates(sys); for (i = 0; i < na; i++) { vid = sys->index_anchors[i]; - nlRightHandSideSet(sys->context, 0, n + i, vertexCos[vid][0]); - nlRightHandSideSet(sys->context, 1, n + i, vertexCos[vid][1]); - nlRightHandSideSet(sys->context, 2, n + i, vertexCos[vid][2]); + EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]); } - nlEnd(sys->context, NL_MATRIX); - nlEnd(sys->context, NL_SYSTEM); - if (!nlSolve(sys->context, NL_FALSE)) { + if (!EIG_linear_solver_solve(sys->context)) { sys->has_solution = false; break; } } if (sys->has_solution) { for (vid = 0; vid < sys->total_verts; vid++) { - vertexCos[vid][0] = nlGetVariable(sys->context, 0, vid); - vertexCos[vid][1] = nlGetVariable(sys->context, 1, vid); - vertexCos[vid][2] = nlGetVariable(sys->context, 2, vid); + vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid); + vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid); + vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid); } } else { @@ -526,10 +498,6 @@ static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3]) sys->has_solution = false; } } - -#ifdef OPENNL_THREADING_HACK - modifier_opennl_unlock(); -#endif } static bool isValidVertexGroup(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm) @@ -720,15 +688,6 @@ static void LaplacianDeformModifier_do( } } -#else /* WITH_OPENNL */ -static void LaplacianDeformModifier_do( - LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts) -{ - UNUSED_VARS(lmd, ob, dm, vertexCos, numVerts); -} -#endif /* WITH_OPENNL */ - static void initData(ModifierData *md) { LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; @@ -792,12 +751,10 @@ static void deformVertsEM( static void freeData(ModifierData *md) { LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; -#ifdef WITH_OPENNL LaplacianSystem *sys = (LaplacianSystem *)lmd->cache_system; if (sys) { deleteLaplacianSystem(sys); } -#endif MEM_SAFE_FREE(lmd->vertexco); lmd->total_verts = 0; } diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c index 189ceb11d08..f1216ff462a 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c @@ -43,9 +43,7 @@ #include "MOD_util.h" -#ifdef WITH_OPENNL - -#include "ONL_opennl.h" +#include "eigen_capi.h" #if 0 #define MOD_LAPLACIANSMOOTH_MAX_EDGE_PERCENTAGE 1.8f @@ -71,7 +69,7 @@ struct BLaplacianSystem { const MPoly *mpoly; const MLoop *mloop; const MEdge *medges; - NLContext *context; + LinearSolver *context; /*Data*/ float min_area; @@ -104,7 +102,7 @@ static void delete_laplacian_system(LaplacianSystem *sys) MEM_SAFE_FREE(sys->zerola); if (sys->context) { - nlDeleteContext(sys->context); + EIG_linear_solver_delete(sys->context); } sys->vertexCos = NULL; sys->mpoly = NULL; @@ -300,16 +298,16 @@ static void fill_laplacian_matrix(LaplacianSystem *sys) /* Is ring if number of faces == number of edges around vertice*/ if (sys->numNeEd[l_curr->v] == sys->numNeFa[l_curr->v] && sys->zerola[l_curr->v] == 0) { - nlMatrixAdd(sys->context, l_curr->v, l_next->v, sys->fweights[l_curr_index][2] * sys->vweights[l_curr->v]); - nlMatrixAdd(sys->context, l_curr->v, l_prev->v, sys->fweights[l_curr_index][1] * sys->vweights[l_curr->v]); + EIG_linear_solver_matrix_add(sys->context, l_curr->v, l_next->v, sys->fweights[l_curr_index][2] * sys->vweights[l_curr->v]); + EIG_linear_solver_matrix_add(sys->context, l_curr->v, l_prev->v, sys->fweights[l_curr_index][1] * sys->vweights[l_curr->v]); } if (sys->numNeEd[l_next->v] == sys->numNeFa[l_next->v] && sys->zerola[l_next->v] == 0) { - nlMatrixAdd(sys->context, l_next->v, l_curr->v, sys->fweights[l_curr_index][2] * sys->vweights[l_next->v]); - nlMatrixAdd(sys->context, l_next->v, l_prev->v, sys->fweights[l_curr_index][0] * sys->vweights[l_next->v]); + EIG_linear_solver_matrix_add(sys->context, l_next->v, l_curr->v, sys->fweights[l_curr_index][2] * sys->vweights[l_next->v]); + EIG_linear_solver_matrix_add(sys->context, l_next->v, l_prev->v, sys->fweights[l_curr_index][0] * sys->vweights[l_next->v]); } if (sys->numNeEd[l_prev->v] == sys->numNeFa[l_prev->v] && sys->zerola[l_prev->v] == 0) { - nlMatrixAdd(sys->context, l_prev->v, l_curr->v, sys->fweights[l_curr_index][1] * sys->vweights[l_prev->v]); - nlMatrixAdd(sys->context, l_prev->v, l_next->v, sys->fweights[l_curr_index][0] * sys->vweights[l_prev->v]); + EIG_linear_solver_matrix_add(sys->context, l_prev->v, l_curr->v, sys->fweights[l_curr_index][1] * sys->vweights[l_prev->v]); + EIG_linear_solver_matrix_add(sys->context, l_prev->v, l_next->v, sys->fweights[l_curr_index][0] * sys->vweights[l_prev->v]); } } } @@ -323,8 +321,8 @@ static void fill_laplacian_matrix(LaplacianSystem *sys) sys->zerola[idv1] == 0 && sys->zerola[idv2] == 0) { - nlMatrixAdd(sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]); - nlMatrixAdd(sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]); + EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]); + EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]); } } } @@ -342,13 +340,13 @@ static void validate_solution(LaplacianSystem *sys, short flag, float lambda, fl if (sys->zerola[i] == 0) { lam = sys->numNeEd[i] == sys->numNeFa[i] ? (lambda >= 0.0f ? 1.0f : -1.0f) : (lambda_border >= 0.0f ? 1.0f : -1.0f); if (flag & MOD_LAPLACIANSMOOTH_X) { - sys->vertexCos[i][0] += lam * ((float)nlGetVariable(sys->context, 0, i) - sys->vertexCos[i][0]); + sys->vertexCos[i][0] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 0, i) - sys->vertexCos[i][0]); } if (flag & MOD_LAPLACIANSMOOTH_Y) { - sys->vertexCos[i][1] += lam * ((float)nlGetVariable(sys->context, 1, i) - sys->vertexCos[i][1]); + sys->vertexCos[i][1] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 1, i) - sys->vertexCos[i][1]); } if (flag & MOD_LAPLACIANSMOOTH_Z) { - sys->vertexCos[i][2] += lam * ((float)nlGetVariable(sys->context, 2, i) - sys->vertexCos[i][2]); + sys->vertexCos[i][2] += lam * ((float)EIG_linear_solver_variable_get(sys->context, 2, i) - sys->vertexCos[i][2]); } } } @@ -386,24 +384,15 @@ static void laplaciansmoothModifier_do( sys->vert_centroid[2] = 0.0f; memset_laplacian_system(sys, 0); -#ifdef OPENNL_THREADING_HACK - modifier_opennl_lock(); -#endif - - sys->context = nlNewContext(); - nlSolverParameteri(sys->context, NL_NB_VARIABLES, numVerts); - nlSolverParameteri(sys->context, NL_LEAST_SQUARES, NL_TRUE); - nlSolverParameteri(sys->context, NL_NB_ROWS, numVerts); - nlSolverParameteri(sys->context, NL_NB_RIGHT_HAND_SIDES, 3); + sys->context = EIG_linear_least_squares_solver_new(numVerts, numVerts, 3); init_laplacian_matrix(sys); for (iter = 0; iter < smd->repeat; iter++) { - nlBegin(sys->context, NL_SYSTEM); for (i = 0; i < numVerts; i++) { - nlSetVariable(sys->context, 0, i, vertexCos[i][0]); - nlSetVariable(sys->context, 1, i, vertexCos[i][1]); - nlSetVariable(sys->context, 2, i, vertexCos[i][2]); + EIG_linear_solver_variable_set(sys->context, 0, i, vertexCos[i][0]); + EIG_linear_solver_variable_set(sys->context, 1, i, vertexCos[i][1]); + EIG_linear_solver_variable_set(sys->context, 2, i, vertexCos[i][2]); if (iter == 0) { add_v3_v3(sys->vert_centroid, vertexCos[i]); } @@ -412,12 +401,11 @@ static void laplaciansmoothModifier_do( mul_v3_fl(sys->vert_centroid, 1.0f / (float)numVerts); } - nlBegin(sys->context, NL_MATRIX); dv = dvert; for (i = 0; i < numVerts; i++) { - nlRightHandSideSet(sys->context, 0, i, vertexCos[i][0]); - nlRightHandSideSet(sys->context, 1, i, vertexCos[i][1]); - nlRightHandSideSet(sys->context, 2, i, vertexCos[i][2]); + EIG_linear_solver_right_hand_side_add(sys->context, 0, i, vertexCos[i][0]); + EIG_linear_solver_right_hand_side_add(sys->context, 1, i, vertexCos[i][1]); + EIG_linear_solver_right_hand_side_add(sys->context, 2, i, vertexCos[i][2]); if (iter == 0) { if (dv) { wpaint = defvert_find_weight(dv, defgrp_index); @@ -434,10 +422,10 @@ static void laplaciansmoothModifier_do( w = sys->vlengths[i]; sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; if (sys->numNeEd[i] == sys->numNeFa[i]) { - nlMatrixAdd(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint); + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint); } else { - nlMatrixAdd(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); } } else { @@ -447,15 +435,15 @@ static void laplaciansmoothModifier_do( sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w; if (sys->numNeEd[i] == sys->numNeFa[i]) { - nlMatrixAdd(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i])); + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i])); } else { - nlMatrixAdd(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f); } } } else { - nlMatrixAdd(sys->context, i, i, 1.0f); + EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f); } } } @@ -464,32 +452,16 @@ static void laplaciansmoothModifier_do( fill_laplacian_matrix(sys); } - nlEnd(sys->context, NL_MATRIX); - nlEnd(sys->context, NL_SYSTEM); - - if (nlSolve(sys->context, NL_TRUE)) { + if (EIG_linear_solver_solve(sys->context)) { validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border); } } - nlDeleteContext(sys->context); + EIG_linear_solver_delete(sys->context); sys->context = NULL; -#ifdef OPENNL_THREADING_HACK - modifier_opennl_unlock(); -#endif - delete_laplacian_system(sys); } -#else /* WITH_OPENNL */ -static void laplaciansmoothModifier_do( - LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm, - float (*vertexCos)[3], int numVerts) -{ - UNUSED_VARS(smd, ob, dm, vertexCos, numVerts); -} -#endif /* WITH_OPENNL */ - static void init_data(ModifierData *md) { LaplacianSmoothModifierData *smd = (LaplacianSmoothModifierData *) md; diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index 8aa5f281f56..5f2f51df528 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -234,7 +234,7 @@ typedef struct MeshdeformUserdata { float (*icagemat)[3]; } MeshdeformUserdata; -static void meshdeform_vert_task(void * userdata, int iter) +static void meshdeform_vert_task(void *userdata, void *UNUSED(userdata_chunck), int iter) { MeshdeformUserdata *data = userdata; /*const*/ MeshDeformModifierData *mmd = data->mmd; @@ -352,7 +352,7 @@ static void meshdeformModifier_do( /* progress bar redraw can make this recursive .. */ if (!recursive) { recursive = 1; - mmd->bindfunc(md->scene, mmd, (float *)vertexCos, numVerts, cagemat); + mmd->bindfunc(md->scene, mmd, cagedm, (float *)vertexCos, numVerts, cagemat); recursive = 0; } } diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 54a7278be72..b82725a08e7 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -37,6 +37,7 @@ #include "BLI_math.h" #include "BLI_math_inline.h" +#include "BLI_task.h" #include "BLI_utildefines.h" #include "BKE_cdderivedmesh.h" @@ -265,125 +266,142 @@ static void dm_get_bounds(DerivedMesh *dm, float *sx, float *sy, float *ox, floa #ifdef WITH_OCEANSIM -#ifdef _OPENMP -#define OMP_MIN_RES 18 -#endif - -static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd) -{ - DerivedMesh *result; - +typedef struct GenerateOceanGeometryData { MVert *mverts; MPoly *mpolys; MLoop *mloops; int *origindex; + MLoopUV *mloopuvs; - int cdlayer; + int res_x, res_y; + int rx, ry; + float ox, oy; + float sx, sy; + float ix, iy; +} GenerateOceanGeometryData; - const int rx = omd->resolution * omd->resolution; - const int ry = omd->resolution * omd->resolution; - const int res_x = rx * omd->repeat_x; - const int res_y = ry * omd->repeat_y; +static void generate_ocean_geometry_vertices(void *userdata, void *UNUSED(userdata_chunk), int y) +{ + GenerateOceanGeometryData *gogd = userdata; + int x; + + for (x = 0; x <= gogd->res_x; x++) { + const int i = y * (gogd->res_x + 1) + x; + float *co = gogd->mverts[i].co; + co[0] = gogd->ox + (x * gogd->sx); + co[1] = gogd->oy + (y * gogd->sy); + co[2] = 0.0f; + } +} - const int num_verts = (res_x + 1) * (res_y + 1); - /* const int num_edges = (res_x * res_y * 2) + res_x + res_y; */ /* UNUSED BMESH */ - const int num_faces = res_x * res_y; +static void generate_ocean_geometry_polygons(void *userdata, void *UNUSED(userdata_chunk), int y) +{ + GenerateOceanGeometryData *gogd = userdata; + int x; + + for (x = 0; x < gogd->res_x; x++) { + const int fi = y * gogd->res_x + x; + const int vi = y * (gogd->res_x + 1) + x; + MPoly *mp = &gogd->mpolys[fi]; + MLoop *ml = &gogd->mloops[fi * 4]; + + ml->v = vi; + ml++; + ml->v = vi + 1; + ml++; + ml->v = vi + 1 + gogd->res_x + 1; + ml++; + ml->v = vi + gogd->res_x + 1; + ml++; + + mp->loopstart = fi * 4; + mp->totloop = 4; + + mp->flag |= ME_SMOOTH; + + /* generated geometry does not map to original faces */ + gogd->origindex[fi] = ORIGINDEX_NONE; + } +} - float sx = omd->size * omd->spatial_size; - float sy = omd->size * omd->spatial_size; - const float ox = -sx / 2.0f; - const float oy = -sy / 2.0f; +static void generate_ocean_geometry_uvs(void *userdata, void *UNUSED(userdata_chunk), int y) +{ + GenerateOceanGeometryData *gogd = userdata; + int x; - float ix, iy; + for (x = 0; x < gogd->res_x; x++) { + const int i = y * gogd->res_x + x; + MLoopUV *luv = &gogd->mloopuvs[i * 4]; + + luv->uv[0] = x * gogd->ix; + luv->uv[1] = y * gogd->iy; + luv++; + + luv->uv[0] = (x + 1) * gogd->ix; + luv->uv[1] = y * gogd->iy; + luv++; + + luv->uv[0] = (x + 1) * gogd->ix; + luv->uv[1] = (y + 1) * gogd->iy; + luv++; + + luv->uv[0] = x * gogd->ix; + luv->uv[1] = (y + 1) * gogd->iy; + luv++; + } +} + +static DerivedMesh *generate_ocean_geometry(OceanModifierData *omd) +{ + DerivedMesh *result; + + GenerateOceanGeometryData gogd; + + int num_verts; + int num_polys; + + gogd.rx = omd->resolution * omd->resolution; + gogd.ry = omd->resolution * omd->resolution; + gogd.res_x = gogd.rx * omd->repeat_x; + gogd.res_y = gogd.ry * omd->repeat_y; - int x, y; + num_verts = (gogd.res_x + 1) * (gogd.res_y + 1); + num_polys = gogd.res_x * gogd.res_y; - sx /= rx; - sy /= ry; + gogd.sx = omd->size * omd->spatial_size; + gogd.sy = omd->size * omd->spatial_size; + gogd.ox = -gogd.sx / 2.0f; + gogd.oy = -gogd.sy / 2.0f; - result = CDDM_new(num_verts, 0, 0, num_faces * 4, num_faces); + gogd.sx /= gogd.rx; + gogd.sy /= gogd.ry; - mverts = CDDM_get_verts(result); - mpolys = CDDM_get_polys(result); - mloops = CDDM_get_loops(result); + result = CDDM_new(num_verts, 0, 0, num_polys * 4, num_polys); - origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX); + gogd.mverts = CDDM_get_verts(result); + gogd.mpolys = CDDM_get_polys(result); + gogd.mloops = CDDM_get_loops(result); + + gogd.origindex = CustomData_get_layer(&result->polyData, CD_ORIGINDEX); /* create vertices */ -#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES) - for (y = 0; y <= res_y; y++) { - for (x = 0; x <= res_x; x++) { - const int i = y * (res_x + 1) + x; - float *co = mverts[i].co; - co[0] = ox + (x * sx); - co[1] = oy + (y * sy); - co[2] = 0; - } - } + BLI_task_parallel_range(0, gogd.res_y + 1, &gogd, generate_ocean_geometry_vertices); /* create faces */ -#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES) - for (y = 0; y < res_y; y++) { - for (x = 0; x < res_x; x++) { - const int fi = y * res_x + x; - const int vi = y * (res_x + 1) + x; - MPoly *mp = &mpolys[fi]; - MLoop *ml = &mloops[fi * 4]; - - ml->v = vi; - ml++; - ml->v = vi + 1; - ml++; - ml->v = vi + 1 + res_x + 1; - ml++; - ml->v = vi + res_x + 1; - ml++; - - mp->loopstart = fi * 4; - mp->totloop = 4; - - mp->flag |= ME_SMOOTH; - - /* generated geometry does not map to original faces */ - origindex[fi] = ORIGINDEX_NONE; - } - } + BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_polygons); CDDM_calc_edges(result); /* add uvs */ - cdlayer = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV); - if (cdlayer < MAX_MTFACE) { - MLoopUV *mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_faces * 4); - CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_faces); - - if (mloopuvs) { /* unlikely to fail */ - ix = 1.0 / rx; - iy = 1.0 / ry; -#pragma omp parallel for private(x, y) if (rx > OMP_MIN_RES) - for (y = 0; y < res_y; y++) { - for (x = 0; x < res_x; x++) { - const int i = y * res_x + x; - MLoopUV *luv = &mloopuvs[i * 4]; - - luv->uv[0] = x * ix; - luv->uv[1] = y * iy; - luv++; - - luv->uv[0] = (x + 1) * ix; - luv->uv[1] = y * iy; - luv++; - - luv->uv[0] = (x + 1) * ix; - luv->uv[1] = (y + 1) * iy; - luv++; - - luv->uv[0] = x * ix; - luv->uv[1] = (y + 1) * iy; - luv++; + if (CustomData_number_of_layers(&result->loopData, CD_MLOOPUV) < MAX_MTFACE) { + gogd.mloopuvs = CustomData_add_layer(&result->loopData, CD_MLOOPUV, CD_CALLOC, NULL, num_polys * 4); + CustomData_add_layer(&result->polyData, CD_MTEXPOLY, CD_CALLOC, NULL, num_polys); - } - } + if (gogd.mloopuvs) { /* unlikely to fail */ + gogd.ix = 1.0 / gogd.rx; + gogd.iy = 1.0 / gogd.ry; + + BLI_task_parallel_range(0, gogd.res_y, &gogd, generate_ocean_geometry_uvs); } } @@ -401,15 +419,10 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob, DerivedMesh *dm = NULL; OceanResult ocr; - MVert *mverts, *mv; - MLoop *mloops; - - int i, j; - - int num_verts; - int num_faces; + MVert *mverts; int cfra; + int i, j; /* use cached & inverted value for speed * expanded this would read... @@ -425,18 +438,22 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob, } /* update modifier */ - if (omd->refresh & MOD_OCEAN_REFRESH_ADD) + if (omd->refresh & MOD_OCEAN_REFRESH_ADD) { omd->ocean = BKE_ocean_add(); - if (omd->refresh & MOD_OCEAN_REFRESH_RESET) + } + if (omd->refresh & MOD_OCEAN_REFRESH_RESET) { init_ocean_modifier(omd); - if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) + } + if (omd->refresh & MOD_OCEAN_REFRESH_CLEAR_CACHE) { clear_cache_data(omd); - + } omd->refresh = 0; /* do ocean simulation */ if (omd->cached == true) { - if (!omd->oceancache) init_cache_data(ob, omd); + if (!omd->oceancache) { + init_cache_data(ob, omd); + } BKE_ocean_simulate_cache(omd->oceancache, md->scene->r.cfra); } else { @@ -455,38 +472,31 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob, CLAMP(cfra, omd->bakestart, omd->bakeend); cfra -= omd->bakestart; /* shift to 0 based */ - num_verts = dm->getNumVerts(dm); - num_faces = dm->getNumPolys(dm); - mverts = dm->getVertArray(dm); - mloops = dm->getLoopArray(dm); /* add vcols before displacement - allows lookup based on position */ if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { - int cdlayer = CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL); - - if (cdlayer < MAX_MCOL) { - MLoopCol *mloopcols = CustomData_add_layer_named(&dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, - num_faces * 4, omd->foamlayername); + if (CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL) < MAX_MCOL) { + const int num_polys = dm->getNumPolys(dm); + const int num_loops = dm->getNumLoops(dm); + MLoop *mloops = dm->getLoopArray(dm); + MLoopCol *mloopcols = CustomData_add_layer_named( + &dm->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, num_loops, omd->foamlayername); if (mloopcols) { /* unlikely to fail */ - MLoopCol *mlcol; MPoly *mpolys = dm->getPolyArray(dm); MPoly *mp; - float foam; - - for (i = 0, mp = mpolys; i < num_faces; i++, mp++) { - j = mp->totloop - 1; + for (i = 0, mp = mpolys; i < num_polys; i++, mp++) { + MLoop *ml = &mloops[mp->loopstart]; + MLoopCol *mlcol = &mloopcols[mp->loopstart]; - /* highly unlikely */ - if (j <= 0) continue; - - do { - const float *co = mverts[mloops[mp->loopstart + j].v].co; - const float u = OCEAN_CO(size_co_inv, co[0]); - const float v = OCEAN_CO(size_co_inv, co[1]); + for (j = mp->totloop; j--; ml++, mlcol++) { + const float *vco = mverts[ml->v].co; + const float u = OCEAN_CO(size_co_inv, vco[0]); + const float v = OCEAN_CO(size_co_inv, vco[1]); + float foam; if (omd->oceancache && omd->cached == true) { BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); @@ -498,11 +508,10 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob, foam = BKE_ocean_jminus_to_foam(ocr.Jminus, omd->foam_coverage); } - mlcol = &mloopcols[mp->loopstart + j]; mlcol->r = mlcol->g = mlcol->b = (char)(foam * 255); /* This needs to be set (render engine uses) */ mlcol->a = 255; - } while (j--); + } } } } @@ -511,21 +520,29 @@ static DerivedMesh *doOcean(ModifierData *md, Object *ob, /* displace the geometry */ - /* #pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES) */ - for (i = 0, mv = mverts; i < num_verts; i++, mv++) { - const float u = OCEAN_CO(size_co_inv, mv->co[0]); - const float v = OCEAN_CO(size_co_inv, mv->co[1]); + /* Note: tried to parallelized that one and previous foam loop, but gives 20% slower results... odd. */ + { + const int num_verts = dm->getNumVerts(dm); - if (omd->oceancache && omd->cached == true) - BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); - else - BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); + /* #pragma omp parallel for private(i, ocr) if (omd->resolution > OMP_MIN_RES) */ + for (i = 0; i < num_verts; i++) { + float *vco = mverts[i].co; + const float u = OCEAN_CO(size_co_inv, vco[0]); + const float v = OCEAN_CO(size_co_inv, vco[1]); - mv->co[2] += ocr.disp[1]; + if (omd->oceancache && omd->cached == true) { + BKE_ocean_cache_eval_uv(omd->oceancache, &ocr, cfra, u, v); + } + else { + BKE_ocean_eval_uv(omd->ocean, &ocr, u, v); + } + + vco[2] += ocr.disp[1]; - if (omd->chop_amount > 0.0f) { - mv->co[0] += ocr.disp[0]; - mv->co[1] += ocr.disp[2]; + if (omd->chop_amount > 0.0f) { + vco[0] += ocr.disp[0]; + vco[1] += ocr.disp[2]; + } } } diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index be6f7af7791..f9291fb077f 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -55,10 +55,6 @@ #include "MEM_guardedalloc.h" -#ifdef OPENNL_THREADING_HACK -#include "BLI_threads.h" -#endif - void modifier_init_texture(const Scene *scene, Tex *tex) { if (!tex) @@ -234,23 +230,6 @@ void modifier_get_vgroup(Object *ob, DerivedMesh *dm, const char *name, MDeformV } -#ifdef OPENNL_THREADING_HACK - -static ThreadMutex opennl_context_mutex = BLI_MUTEX_INITIALIZER; - -void modifier_opennl_lock(void) -{ - BLI_mutex_lock(&opennl_context_mutex); -} - -void modifier_opennl_unlock(void) -{ - BLI_mutex_unlock(&opennl_context_mutex); -} - -#endif - - /* only called by BKE_modifier.h/modifier.c */ void modifier_type_init(ModifierTypeInfo *types[]) { diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h index b74ff9c2a25..095d7c278df 100644 --- a/source/blender/modifiers/intern/MOD_util.h +++ b/source/blender/modifiers/intern/MOD_util.h @@ -52,21 +52,4 @@ struct DerivedMesh *get_dm_for_modifier(struct Object *ob, ModifierApplyFlag fla void modifier_get_vgroup(struct Object *ob, struct DerivedMesh *dm, const char *name, struct MDeformVert **dvert, int *defgrp_index); -/* XXX workaround for non-threadsafe context in OpenNL (T38403) - * OpenNL uses global pointer for "current context", which causes - * conflict when multiple modifiers get evaluated in threaded depgraph. - * This is just a stupid hack to prevent assert failure / crash, - * otherwise we'd have to modify OpenNL on a large scale. - * OpenNL should be replaced eventually, there are other options (eigen, ceres). - * - lukas_t - */ -#ifdef WITH_OPENNL -#define OPENNL_THREADING_HACK -#endif - -#ifdef OPENNL_THREADING_HACK -void modifier_opennl_lock(void); -void modifier_opennl_unlock(void); -#endif - #endif /* __MOD_UTIL_H__ */ diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 51c6f5cab3c..0a73a187161 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -33,6 +33,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rand.h" +#include "BLI_task.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -52,7 +53,7 @@ #include "MEM_guardedalloc.h" #include "MOD_weightvg_util.h" -// #define USE_TIMEIT +//#define USE_TIMEIT #ifdef USE_TIMEIT # include "PIL_time.h" @@ -66,6 +67,67 @@ /* Util macro. */ #define OUT_OF_MEMORY() ((void)printf("WeightVGProximity: Out of memory.\n")) +typedef struct Vert2GeomData { + /* Read-only data */ + float (*v_cos)[3]; + + const SpaceTransform *loc2trgt; + + BVHTreeFromMesh *treeData[3]; + + /* Write data, but not needing locking (two different threads will never write same index). */ + float *dist[3]; +} Vert2GeomData; + +/* Data which is localized to each computed chunk (i.e. thread-safe, and with continous subset of index range). */ +typedef struct Vert2GeomDataChunk { + /* Read-only data */ + float last_hit_co[3][3]; + bool is_init[3]; +} Vert2GeomDataChunk; + +/** + * Callback used by BLI_task 'for loop' helper. + */ +static void vert2geom_task_cb(void *userdata, void *userdata_chunk, int iter) +{ + Vert2GeomData *data = userdata; + Vert2GeomDataChunk *data_chunk = userdata_chunk; + + float tmp_co[3]; + int i; + + /* Convert the vertex to tree coordinates. */ + copy_v3_v3(tmp_co, data->v_cos[iter]); + BLI_space_transform_apply(data->loc2trgt, tmp_co); + + for (i = 0; i < ARRAY_SIZE(data->dist); i++) { + if (data->dist[i]) { + BVHTreeNearest nearest = {0}; + + /* Note that we use local proximity heuristics (to reduce the nearest search). + * + * If we already had an hit before in same chunk of tasks (i.e. previous vertex by index), + * we assume this vertex is going to have a close hit to that other vertex, so we can initiate + * the "nearest.dist" with the expected value to that last hit. + * This will lead in pruning of the search tree. + */ + nearest.dist_sq = data_chunk->is_init[i] ? len_squared_v3v3(tmp_co, data_chunk->last_hit_co[i]) : FLT_MAX; + nearest.index = -1; + + /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */ + BLI_bvhtree_find_nearest(data->treeData[i]->tree, tmp_co, &nearest, + data->treeData[i]->nearest_callback, data->treeData[i]); + data->dist[i][iter] = sqrtf(nearest.dist_sq); + + if (nearest.index != -1) { + copy_v3_v3(data_chunk->last_hit_co[i], nearest.co); + data_chunk->is_init[i] = true; + } + } + } +} + /** * Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c). */ @@ -73,13 +135,12 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], float *dist_v, float *dist_e, float *dist_f, DerivedMesh *target, const SpaceTransform *loc2trgt) { - int i; + Vert2GeomData data = {0}; + Vert2GeomDataChunk data_chunk = {{{0}}}; + BVHTreeFromMesh treeData_v = {NULL}; BVHTreeFromMesh treeData_e = {NULL}; BVHTreeFromMesh treeData_f = {NULL}; - BVHTreeNearest nearest_v = {0}; - BVHTreeNearest nearest_e = {0}; - BVHTreeNearest nearest_f = {0}; if (dist_v) { /* Create a bvh-tree of the given target's verts. */ @@ -106,45 +167,16 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3], } } - /* Setup nearest. */ - nearest_v.index = nearest_e.index = nearest_f.index = -1; - /*nearest_v.dist = nearest_e.dist = nearest_f.dist = FLT_MAX;*/ - /* Find the nearest vert/edge/face. */ -#pragma omp parallel for default(shared) private(i) firstprivate(nearest_v, nearest_e, nearest_f) \ - schedule(static) if (numVerts > 10000) - for (i = 0; i < numVerts; i++) { - float tmp_co[3]; - - /* Convert the vertex to tree coordinates. */ - copy_v3_v3(tmp_co, v_cos[i]); - BLI_space_transform_apply(loc2trgt, tmp_co); - - /* Use local proximity heuristics (to reduce the nearest search). - * - * If we already had an hit before, we assume this vertex is going to have a close hit to - * that other vertex, so we can initiate the "nearest.dist" with the expected value to that - * last hit. - * This will lead in pruning of the search tree. - */ - if (dist_v) { - nearest_v.dist_sq = nearest_v.index != -1 ? len_squared_v3v3(tmp_co, nearest_v.co) : FLT_MAX; - /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */ - BLI_bvhtree_find_nearest(treeData_v.tree, tmp_co, &nearest_v, treeData_v.nearest_callback, &treeData_v); - dist_v[i] = sqrtf(nearest_v.dist_sq); - } - if (dist_e) { - nearest_e.dist_sq = nearest_e.index != -1 ? len_squared_v3v3(tmp_co, nearest_e.co) : FLT_MAX; - /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */ - BLI_bvhtree_find_nearest(treeData_e.tree, tmp_co, &nearest_e, treeData_e.nearest_callback, &treeData_e); - dist_e[i] = sqrtf(nearest_e.dist_sq); - } - if (dist_f) { - nearest_f.dist_sq = nearest_f.index != -1 ? len_squared_v3v3(tmp_co, nearest_f.co) : FLT_MAX; - /* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */ - BLI_bvhtree_find_nearest(treeData_f.tree, tmp_co, &nearest_f, treeData_f.nearest_callback, &treeData_f); - dist_f[i] = sqrtf(nearest_f.dist_sq); - } - } + data.v_cos = v_cos; + data.loc2trgt = loc2trgt; + data.treeData[0] = &treeData_v; + data.treeData[1] = &treeData_e; + data.treeData[2] = &treeData_f; + data.dist[0] = dist_v; + data.dist[1] = dist_e; + data.dist[2] = dist_f; + + BLI_task_parallel_range_ex(0, numVerts, &data, &data_chunk, sizeof(data_chunk), vert2geom_task_cb, 10000, false); if (dist_v) free_bvhtree_from_mesh(&treeData_v); diff --git a/source/blender/nodes/composite/node_composite_util.c b/source/blender/nodes/composite/node_composite_util.c index bbfb07a316d..c6b1d37f8b4 100644 --- a/source/blender/nodes/composite/node_composite_util.c +++ b/source/blender/nodes/composite/node_composite_util.c @@ -55,5 +55,6 @@ void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short ncla ntype->poll = cmp_node_poll_default; ntype->updatefunc = cmp_node_update_default; + ntype->insert_link = node_insert_link_default; ntype->update_internal_links = node_update_internal_links_default; } diff --git a/source/blender/nodes/composite/nodes/node_composite_common.c b/source/blender/nodes/composite/nodes/node_composite_common.c index 75e7fa8fbac..0fbbb54ee7a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_common.c +++ b/source/blender/nodes/composite/nodes/node_composite_common.c @@ -51,6 +51,7 @@ void register_node_type_cmp_group(void) ntype.type = NODE_GROUP; ntype.poll = cmp_node_poll_default; ntype.poll_instance = node_group_poll_instance; + ntype.insert_link = node_insert_link_default; ntype.update_internal_links = node_update_internal_links_default; ntype.ext.srna = RNA_struct_find("CompositorNodeGroup"); BLI_assert(ntype.ext.srna != NULL); diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index 3a301f55487..dd5715891d5 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -29,6 +29,7 @@ * \ingroup nodes */ +#include <ctype.h> #include <limits.h> #include <string.h> @@ -112,6 +113,95 @@ void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int m } +/*** Link Insertion ***/ + +/* test if two sockets are interchangeable */ +static bool node_link_socket_match(bNodeSocket *a, bNodeSocket *b) +{ + /* tests if alphabetic prefix matches + * this allows for imperfect matches, such as numeric suffixes, + * like Color1/Color2 + */ + int prefix_len = 0; + char *ca = a->name, *cb = b->name; + for (; *ca != '\0' && *cb != '\0'; ++ca, ++cb) { + /* end of common prefix? */ + if (*ca != *cb) { + /* prefix delimited by non-alphabetic char */ + if (isalpha(*ca) || isalpha(*cb)) + return false; + break; + } + ++prefix_len; + } + return prefix_len > 0; +} + +static int node_count_links(bNodeTree *ntree, bNodeSocket *sock) +{ + bNodeLink *link; + int count = 0; + for (link = ntree->links.first; link; link = link->next) { + if (link->fromsock == sock) + ++count; + if (link->tosock == sock) + ++count; + } + return count; +} + +/* find an eligible socket for linking */ +static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNodeSocket *cur) +{ + /* link swapping: try to find a free slot with a matching name */ + + bNodeSocket *first = cur->in_out == SOCK_IN ? node->inputs.first : node->outputs.first; + bNodeSocket *sock; + + sock = cur->next ? cur->next : first; /* wrap around the list end */ + while (sock != cur) { + if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) { + int link_count = node_count_links(ntree, sock); + /* take +1 into account since we would add a new link */ + if (link_count + 1 <= sock->limit) + return sock; /* found a valid free socket we can swap to */ + } + + sock = sock->next ? sock->next : first; /* wrap around the list end */ + } + return NULL; +} + +void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link) +{ + bNodeSocket *sock = link->tosock; + bNodeLink *tlink, *tlink_next; + + /* inputs can have one link only, outputs can have unlimited links */ + if (node != link->tonode) + return; + + for (tlink = ntree->links.first; tlink; tlink = tlink_next) { + bNodeSocket *new_sock; + tlink_next = tlink->next; + + if (sock != tlink->tosock) + continue; + + new_sock = node_find_linkable_socket(ntree, node, sock); + if (new_sock && new_sock != sock) { + /* redirect existing link */ + tlink->tosock = new_sock; + } + else if (!new_sock) { + /* no possible replacement, remove tlink */ + nodeRemLink(ntree, tlink); + tlink = NULL; + } + } +} + + /**** Internal Links (mute and disconnect) ****/ /* common datatype priorities, works for compositor, shader and texture nodes alike diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index 64b2028874b..2e20a8e79d4 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -76,6 +76,9 @@ void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, i void node_vect_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); + +/*** Link Handling */ +void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); void node_update_internal_links_default(struct bNodeTree *ntree, struct bNode *node); float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index 92b244bae55..9bd43f331fb 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -47,6 +47,7 @@ void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, shor node_type_base(ntype, type, name, nclass, flag); ntype->poll = sh_node_poll_default; + ntype->insert_link = node_insert_link_default; ntype->update_internal_links = node_update_internal_links_default; } diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c index 7ff60ac716a..796193a564e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_common.c +++ b/source/blender/nodes/shader/nodes/node_shader_common.c @@ -236,6 +236,7 @@ void register_node_type_sh_group(void) ntype.type = NODE_GROUP; ntype.poll = sh_node_poll_default; ntype.poll_instance = node_group_poll_instance; + ntype.insert_link = node_insert_link_default; ntype.update_internal_links = node_update_internal_links_default; ntype.ext.srna = RNA_struct_find("ShaderNodeGroup"); BLI_assert(ntype.ext.srna != NULL); diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c index 42c684b8247..32720364f73 100644 --- a/source/blender/nodes/texture/node_texture_util.c +++ b/source/blender/nodes/texture/node_texture_util.c @@ -60,6 +60,7 @@ void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, sho node_type_base(ntype, type, name, nclass, flag); ntype->poll = tex_node_poll_default; + ntype->insert_link = node_insert_link_default; ntype->update_internal_links = node_update_internal_links_default; } diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c index 914f1ef5110..79a4c4e3a6b 100644 --- a/source/blender/nodes/texture/nodes/node_texture_common.c +++ b/source/blender/nodes/texture/nodes/node_texture_common.c @@ -166,6 +166,7 @@ void register_node_type_tex_group(void) ntype.type = NODE_GROUP; ntype.poll = tex_node_poll_default; ntype.poll_instance = node_group_poll_instance; + ntype.insert_link = node_insert_link_default; ntype.update_internal_links = node_update_internal_links_default; ntype.ext.srna = RNA_struct_find("TextureNodeGroup"); BLI_assert(ntype.ext.srna != NULL); diff --git a/source/blender/physics/CMakeLists.txt b/source/blender/physics/CMakeLists.txt index 08ff1faca49..0a4ff3fe0f0 100644 --- a/source/blender/physics/CMakeLists.txt +++ b/source/blender/physics/CMakeLists.txt @@ -31,11 +31,10 @@ set(INC ../imbuf ../makesdna ../../../intern/guardedalloc - ../../../extern/Eigen3 ) set(INC_SYS - + ${EIGEN3_INCLUDE_DIRS} ) set(SRC diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index e833dba04c8..89c3ed2460e 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -38,8 +38,10 @@ #include "python_utildefines.h" +#ifndef MATH_STANDALONE /* only for BLI_strncpy_wchar_from_utf8, should replace with py funcs but too late in release now */ #include "BLI_string_utf8.h" +#endif #ifdef _WIN32 #include "BLI_path_util.h" /* BLI_setenv() */ @@ -199,6 +201,27 @@ void PyC_List_Fill(PyObject *list, PyObject *value) } } +/** + * Use with PyArg_ParseTuple's "O&" formatting. + */ +int PyC_ParseBool(PyObject *o, void *p) +{ + bool *bool_p = p; + long value; + if (((value = PyLong_AsLong(o)) == -1) || !ELEM(value, 0, 1)) { + PyErr_Format(PyExc_ValueError, + "expected a bool or int (0/1), got %s", + Py_TYPE(o)->tp_name); + return 0; + } + + *bool_p = value ? true : false; + return 1; +} + + +#ifndef MATH_STANDALONE + /* for debugging */ void PyC_ObSpit(const char *name, PyObject *var) { @@ -533,15 +556,6 @@ const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce) if (PyBytes_Check(py_str)) { return PyBytes_AS_STRING(py_str); } -#ifdef WIN32 - /* bug [#31856] oddly enough, Python3.2 --> 3.3 on Windows will throw an - * exception here this needs to be fixed in python: - * see: bugs.python.org/issue15859 */ - else if (!PyUnicode_Check(py_str)) { - PyErr_BadArgument(); - return NULL; - } -#endif else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) { return PyBytes_AS_STRING(*coerce); } @@ -710,7 +724,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...) } if (ret == NULL) { - printf("PyC_InlineRun error, line:%d\n", __LINE__); + printf("%s error, line:%d\n", __func__, __LINE__); PyErr_Print(); PyErr_Clear(); @@ -784,7 +798,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...) Py_DECREF(ret); } else { - printf("PyC_InlineRun error on arg '%d', line:%d\n", i, __LINE__); + printf("%s error on arg '%d', line:%d\n", __func__, i, __LINE__); PyC_ObSpit("failed converting:", item_new); PyErr_Print(); PyErr_Clear(); @@ -795,11 +809,11 @@ void PyC_RunQuicky(const char *filepath, int n, ...) va_end(vargs); } else { - printf("PyC_InlineRun error, 'values' not a list, line:%d\n", __LINE__); + printf("%s error, 'values' not a list, line:%d\n", __func__, __LINE__); } } else { - printf("PyC_InlineRun error line:%d\n", __LINE__); + printf("%s error line:%d\n", __func__, __LINE__); PyErr_Print(); PyErr_Clear(); } @@ -1025,20 +1039,4 @@ int PyC_RunString_AsNumber(const char *expr, double *value, const char *filename return error_ret; } -/** - * Use with PyArg_ParseTuple's "O&" formatting. - */ -int PyC_ParseBool(PyObject *o, void *p) -{ - bool *bool_p = p; - long value; - if (((value = PyLong_AsLong(o)) == -1) || !ELEM(value, 0, 1)) { - PyErr_Format(PyExc_ValueError, - "expected a bool or int (0/1), got %s", - Py_TYPE(o)->tp_name); - return 0; - } - - *bool_p = value ? true : false; - return 1; -} +#endif /* #ifndef MATH_STANDALONE */ diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index fa2ad3a4803..bdae2a7cb17 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -320,9 +320,6 @@ void BPy_init_modules(void) /* needs to be first so bpy_types can run */ PyModule_AddObject(mod, "types", BPY_rna_types()); - /* metaclass for idprop types, bpy_types.py needs access */ - PyModule_AddObject(mod, "StructMetaPropGroup", (PyObject *)&pyrna_struct_meta_idprop_Type); - /* needs to be first so bpy_types can run */ BPY_library_module(mod); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 220ec5b6e8c..47d89cd43ae 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -6678,6 +6678,21 @@ PyObject *BPY_rna_types(void) /* add __name__ since help() expects its */ PyDict_SetItem(pyrna_basetype_Type.tp_dict, bpy_intern_str___name__, bpy_intern_str_bpy_types); + /* internal base types we have no other accessors for */ + { + PyTypeObject *pyrna_types[] = { + &pyrna_struct_meta_idprop_Type, + &pyrna_struct_Type, + &pyrna_prop_Type, + &pyrna_prop_array_Type, + &pyrna_prop_collection_Type, + &pyrna_func_Type, + }; + + for (int i = 0; i < ARRAY_SIZE(pyrna_types); i += 1) { + PyDict_SetItemString(pyrna_basetype_Type.tp_dict, pyrna_types[i]->tp_name, (PyObject *)pyrna_types[i]); + } + } self = (BPy_BaseTypeRNA *)PyObject_NEW(BPy_BaseTypeRNA, &pyrna_basetype_Type); diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h index 1ae00a7fb02..63cb7920bd1 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_util.h @@ -27,8 +27,8 @@ #ifndef __BPY_UTIL_H__ #define __BPY_UTIL_H__ -#if PY_VERSION_HEX < 0x03040000 -# error "Python 3.4 or greater is required, you'll need to update your python." +#if PY_VERSION_HEX < 0x03050000 +# error "Python 3.5 or greater is required, you'll need to update your python." #endif struct EnumPropertyItem; diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c index ed31ac052c6..c4863b2a92f 100644 --- a/source/blender/python/intern/gpu_offscreen.c +++ b/source/blender/python/intern/gpu_offscreen.c @@ -37,8 +37,8 @@ #include "ED_screen.h" -#include "GPU_extensions.h" #include "GPU_compositing.h" +#include "GPU_framebuffer.h" #include "../mathutils/mathutils.h" diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index 9deb57d6760..b3b9d4a86dc 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -328,7 +328,7 @@ static void py_bvhtree_nearest_point_cb(void *userdata, int index, const float c } PyDoc_STRVAR(py_bvhtree_ray_cast_doc, -".. method:: ray_cast(co, direction, distance=sys.float_info.max)\n" +".. method:: ray_cast(origin, direction, distance=sys.float_info.max)\n" "\n" " Cast a ray onto the mesh.\n" "\n" @@ -383,7 +383,7 @@ static PyObject *py_bvhtree_ray_cast(PyBVHTree *self, PyObject *args) } PyDoc_STRVAR(py_bvhtree_find_nearest_doc, -".. method:: find_nearest(co, distance=" PYBVH_MAX_DIST_STR ")\n" +".. method:: find_nearest(origin, distance=" PYBVH_MAX_DIST_STR ")\n" "\n" " Find the nearest element to a point.\n" "\n" diff --git a/source/blender/python/mathutils/mathutils_kdtree.c b/source/blender/python/mathutils/mathutils_kdtree.c index 199c2e02da4..ca66c1906b4 100644 --- a/source/blender/python/mathutils/mathutils_kdtree.c +++ b/source/blender/python/mathutils/mathutils_kdtree.c @@ -104,7 +104,10 @@ static int PyKDTree__tp_init(PyKDTree *self, PyObject *args, PyObject *kwargs) unsigned int maxsize; const char *keywords[] = {"size", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "I:KDTree", (char **)keywords, &maxsize)) { + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "I:KDTree", (char **)keywords, + &maxsize)) + { return -1; } @@ -144,8 +147,9 @@ static PyObject *py_kdtree_insert(PyKDTree *self, PyObject *args, PyObject *kwar int index; const char *keywords[] = {"co", "index", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "Oi:insert", (char **)keywords, - &py_co, &index)) + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, (char *) "Oi:insert", (char **)keywords, + &py_co, &index)) { return NULL; } @@ -185,25 +189,57 @@ static PyObject *py_kdtree_balance(PyKDTree *self) Py_RETURN_NONE; } +struct PyKDTree_NearestData { + PyObject *py_filter; + bool is_error; +}; + +static int py_find_nearest_cb(void *user_data, int index, const float co[3], float dist_sq) +{ + UNUSED_VARS(co, dist_sq); + + struct PyKDTree_NearestData *data = user_data; + + PyObject *py_args = PyTuple_New(1); + PyTuple_SET_ITEM(py_args, 0, PyLong_FromLong(index)); + PyObject *result = PyObject_CallObject(data->py_filter, py_args); + Py_DECREF(py_args); + + if (result) { + bool use_node; + int ok = PyC_ParseBool(result, &use_node); + Py_DECREF(result); + if (ok) { + return (int)use_node; + } + } + + data->is_error = true; + return -1; +} + PyDoc_STRVAR(py_kdtree_find_doc, -".. method:: find(co)\n" +".. method:: find(co, filter=None)\n" "\n" " Find nearest point to ``co``.\n" "\n" " :arg co: 3d coordinates.\n" " :type co: float triplet\n" +" :arg filter: function which takes an index and returns True for indices to include in the search.\n" +" :type filter: callable\n" " :return: Returns (:class:`Vector`, index, distance).\n" " :rtype: :class:`tuple`\n" ); static PyObject *py_kdtree_find(PyKDTree *self, PyObject *args, PyObject *kwargs) { - PyObject *py_co; + PyObject *py_co, *py_filter = NULL; float co[3]; KDTreeNearest nearest; - const char *keywords[] = {"co", NULL}; + const char *keywords[] = {"co", "filter", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "O:find", (char **)keywords, - &py_co)) + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, (char *) "O|O:find", (char **)keywords, + &py_co, &py_filter)) { return NULL; } @@ -216,10 +252,26 @@ static PyObject *py_kdtree_find(PyKDTree *self, PyObject *args, PyObject *kwargs return NULL; } - nearest.index = -1; - BLI_kdtree_find_nearest(self->obj, co, &nearest); + if (py_filter == NULL) { + BLI_kdtree_find_nearest(self->obj, co, &nearest); + } + else { + struct PyKDTree_NearestData data = {0}; + + data.py_filter = py_filter; + data.is_error = false; + + BLI_kdtree_find_nearest_cb( + self->obj, co, + py_find_nearest_cb, &data, + &nearest); + + if (data.is_error) { + return NULL; + } + } return kdtree_nearest_to_py_and_check(&nearest); } @@ -246,8 +298,9 @@ static PyObject *py_kdtree_find_n(PyKDTree *self, PyObject *args, PyObject *kwar int i, found; const char *keywords[] = {"co", "n", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "OI:find_n", (char **)keywords, - &py_co, &n)) + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, (char *) "OI:find_n", (char **)keywords, + &py_co, &n)) { return NULL; } @@ -303,8 +356,9 @@ static PyObject *py_kdtree_find_range(PyKDTree *self, PyObject *args, PyObject * const char *keywords[] = {"co", "radius", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "Of:find_range", (char **)keywords, - &py_co, &radius)) + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, (char *) "Of:find_range", (char **)keywords, + &py_co, &radius)) { return NULL; } diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h index 85a9dc9fccd..81d1a00702d 100644 --- a/source/blender/render/extern/include/RE_render_ext.h +++ b/source/blender/render/extern/include/RE_render_ext.h @@ -63,6 +63,10 @@ void RE_sample_material_color( struct PointDensity; +void RE_cache_point_density(struct Scene *scene, + struct PointDensity *pd, + const bool use_render_params); + void RE_sample_point_density(struct Scene *scene, struct PointDensity *pd, const int resolution, diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 3ae93649ee2..64866509a0c 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -2832,6 +2832,8 @@ static bool check_valid_camera_multiview(Scene *scene, Object *camera, ReportLis static int check_valid_camera(Scene *scene, Object *camera_override, ReportList *reports) { + const char *err_msg = "No camera found in scene \"%s\""; + if (camera_override == NULL && scene->camera == NULL) scene->camera = BKE_scene_camera_find(scene); @@ -2843,14 +2845,17 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList Sequence *seq = scene->ed->seqbase.first; while (seq) { - if (seq->type == SEQ_TYPE_SCENE && seq->scene) { + if ((seq->type == SEQ_TYPE_SCENE) && + ((seq->flag & SEQ_SCENE_STRIPS) == 0) && + (seq->scene != NULL)) + { if (!seq->scene_camera) { if (!seq->scene->camera && !BKE_scene_camera_find(seq->scene)) { /* camera could be unneeded due to composite nodes */ Object *override = (seq->scene == scene) ? camera_override : NULL; if (!check_valid_compositing_camera(seq->scene, override)) { - BKE_reportf(reports, RPT_ERROR, "No camera found in scene \"%s\"", seq->scene->id.name+2); + BKE_reportf(reports, RPT_ERROR, err_msg, seq->scene->id.name + 2); return false; } } @@ -2864,7 +2869,7 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList } } else if (!check_valid_compositing_camera(scene, camera_override)) { - BKE_report(reports, RPT_ERROR, "No camera found in scene"); + BKE_reportf(reports, RPT_ERROR, err_msg, scene->id.name + 2); return false; } @@ -3353,7 +3358,6 @@ bool RE_WriteRenderViewsMovie( if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) { int view_id; for (view_id = 0; view_id < totvideos; view_id++) { - bool do_free = false; const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id); ImBuf *ibuf = render_result_rect_to_ibuf(rr, &scene->r, view_id); @@ -3363,12 +3367,6 @@ bool RE_WriteRenderViewsMovie( ok &= mh->append_movie(movie_ctx_arr[view_id], rd, preview ? scene->r.psfra : scene->r.sfra, scene->r.cfra, (int *) ibuf->rect, ibuf->x, ibuf->y, suffix, reports); - if (do_free) { - MEM_freeN(ibuf->rect); - ibuf->rect = NULL; - ibuf->mall &= ~IB_rect; - } - /* imbuf knows which rects are not part of ibuf */ IMB_freeImBuf(ibuf); } @@ -3377,7 +3375,6 @@ bool RE_WriteRenderViewsMovie( else { /* R_IMF_VIEWS_STEREO_3D */ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME}; ImBuf *ibuf_arr[3] = {NULL}; - bool do_free[2] = {false, false}; int i; BLI_assert((totvideos == 1) && (scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D)); @@ -3396,12 +3393,6 @@ bool RE_WriteRenderViewsMovie( ibuf_arr[2]->x, ibuf_arr[2]->y, "", reports); for (i = 0; i < 2; i++) { - if (do_free[i]) { - MEM_freeN(ibuf_arr[i]->rect); - ibuf_arr[i]->rect = NULL; - ibuf_arr[i]->mall &= ~IB_rect; - } - /* imbuf knows which rects are not part of ibuf */ IMB_freeImBuf(ibuf_arr[i]); } diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 9b58bde730a..4028d80fd86 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -715,6 +715,21 @@ static void particle_system_minmax(Scene *scene, } } +void RE_cache_point_density(Scene *scene, + PointDensity *pd, + const bool use_render_params) +{ + float mat[4][4]; + /* Same matricies/resolution as dupli_render_particle_set(). */ + unit_m4(mat); + BLI_mutex_lock(&sample_mutex); + cache_pointdensity_ex(scene, pd, mat, mat, 1, 1, use_render_params); + BLI_mutex_unlock(&sample_mutex); +} + +/* NOTE 1: Requires RE_cache_point_density() to be called first. + * NOTE 2: Frees point density structure after sampling. + */ void RE_sample_point_density(Scene *scene, PointDensity *pd, const int resolution, @@ -724,7 +739,11 @@ void RE_sample_point_density(Scene *scene, const size_t resolution2 = resolution * resolution; Object *object = pd->object; size_t x, y, z; - float min[3], max[3], dim[3], mat[4][4]; + float min[3], max[3], dim[3]; + + /* TODO(sergey): Implement some sort of assert() that point density + * was cached already. + */ if (object == NULL) { sample_dummy_point_density(resolution, values); @@ -766,11 +785,7 @@ void RE_sample_point_density(Scene *scene, return; } - /* Same matricies/resolution as dupli_render_particle_set(). */ - unit_m4(mat); - BLI_mutex_lock(&sample_mutex); - cache_pointdensity_ex(scene, pd, mat, mat, 1, 1, use_render_params); for (z = 0; z < resolution; ++z) { for (y = 0; y < resolution; ++y) { for (x = 0; x < resolution; ++x) { diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index 28a8340cd92..079ade0fbe3 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -110,7 +110,7 @@ const char *WM_key_event_string(const short type, const bool compact); int WM_keymap_item_raw_to_string( const short shift, const short ctrl, const short alt, const short oskey, const short keymodifier, const short val, const short type, const bool compact, const int len, char *r_str); -int WM_key_event_operator_id( +wmKeyMapItem *WM_key_event_operator( const struct bContext *C, const char *opname, int opcontext, struct IDProperty *properties, const bool is_hotkey, struct wmKeyMap **r_keymap); diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 6ad0405c56f..8ace4ee19fb 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -355,67 +355,15 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) } } -#if 0 -/******************** draw damage ************************/ -/* - not implemented */ - -static void wm_method_draw_damage(bContext *C, wmWindow *win) -{ - wm_method_draw_all(C, win); -} -#endif - /****************** draw triple buffer ********************/ /* - area regions are written into a texture, without any */ /* of the overlapping menus, brushes, gestures. these */ /* are redrawn each time. */ -/* */ -/* - if non-power of two textures are supported, that is */ -/* used. if not, multiple smaller ones are used, with */ -/* worst case wasted space being 23.4% for 3x3 textures */ - -static void split_width(int x, int n, int *splitx, int *nx) -{ - int a, newnx, waste; - - /* if already power of two just use it */ - if (is_power_of_2_i(x)) { - splitx[0] = x; - (*nx)++; - return; - } - - if (n == 1) { - /* last part, we have to go larger */ - splitx[0] = power_of_2_max_i(x); - (*nx)++; - } - else { - /* two or more parts to go, use smaller part */ - splitx[0] = power_of_2_min_i(x); - newnx = ++(*nx); - split_width(x - splitx[0], n - 1, splitx + 1, &newnx); - - for (waste = 0, a = 0; a < n; a++) - waste += splitx[a]; - - /* if we waste more space or use the same amount, - * revert deeper splits and just use larger */ - if (waste >= power_of_2_max_i(x)) { - splitx[0] = power_of_2_max_i(x); - memset(splitx + 1, 0, sizeof(int) * (n - 1)); - } - else - *nx = newnx; - } -} static void wm_draw_triple_free(wmDrawTriple *triple) { if (triple) { - - glDeleteTextures(triple->nx * triple->ny, triple->bind); - + glDeleteTextures(1, &triple->bind); MEM_freeN(triple); } } @@ -434,68 +382,49 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple) const int winsize_y = WM_window_pixels_y(win); GLint maxsize; - int x, y; /* compute texture sizes */ if (GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) { triple->target = GL_TEXTURE_RECTANGLE_ARB; - triple->nx = 1; - triple->ny = 1; - triple->x[0] = winsize_x; - triple->y[0] = winsize_y; - } - else if (GPU_non_power_of_two_support()) { - triple->target = GL_TEXTURE_2D; - triple->nx = 1; - triple->ny = 1; - triple->x[0] = winsize_x; - triple->y[0] = winsize_y; } else { triple->target = GL_TEXTURE_2D; - triple->nx = 0; - triple->ny = 0; - split_width(winsize_x, MAX_N_TEX, triple->x, &triple->nx); - split_width(winsize_y, MAX_N_TEX, triple->y, &triple->ny); } + triple->x = winsize_x; + triple->y = winsize_y; + /* generate texture names */ - glGenTextures(triple->nx * triple->ny, triple->bind); + glGenTextures(1, &triple->bind); - if (!triple->bind[0]) { + if (!triple->bind) { /* not the typical failure case but we handle it anyway */ printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n"); return 0; } - for (y = 0; y < triple->ny; y++) { - for (x = 0; x < triple->nx; x++) { - /* proxy texture is only guaranteed to test for the cases that - * there is only one texture in use, which may not be the case */ - maxsize = GPU_max_texture_size(); - - if (triple->x[x] > maxsize || triple->y[y] > maxsize) { - glBindTexture(triple->target, 0); - printf("WM: failed to allocate texture for triple buffer drawing " - "(texture too large for graphics card).\n"); - return 0; - } + /* proxy texture is only guaranteed to test for the cases that + * there is only one texture in use, which may not be the case */ + maxsize = GPU_max_texture_size(); - /* setup actual texture */ - glBindTexture(triple->target, triple->bind[x + y * triple->nx]); - glTexImage2D(triple->target, 0, GL_RGB8, triple->x[x], triple->y[y], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - /* The current color is ignored if the GL_REPLACE texture environment is used. */ - // glTexEnvi(triple->target, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glBindTexture(triple->target, 0); - - /* not sure if this works everywhere .. */ - if (glGetError() == GL_OUT_OF_MEMORY) { - printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n"); - return 0; - } - } + if (triple->x > maxsize || triple->y > maxsize) { + glBindTexture(triple->target, 0); + printf("WM: failed to allocate texture for triple buffer drawing " + "(texture too large for graphics card).\n"); + return 0; + } + + /* setup actual texture */ + glBindTexture(triple->target, triple->bind); + glTexImage2D(triple->target, 0, GL_RGB8, triple->x, triple->y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glBindTexture(triple->target, 0); + + /* not sure if this works everywhere .. */ + if (glGetError() == GL_OUT_OF_MEMORY) { + printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n"); + return 0; } return 1; @@ -503,51 +432,43 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple) void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) { - const int winsize_x = WM_window_pixels_x(win); - const int winsize_y = WM_window_pixels_y(win); + const int sizex = WM_window_pixels_x(win); + const int sizey = WM_window_pixels_y(win); float halfx, halfy, ratiox, ratioy; - int x, y, sizex, sizey, offx, offy; glEnable(triple->target); - for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) { - for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) { - sizex = (x == triple->nx - 1) ? winsize_x - offx : triple->x[x]; - sizey = (y == triple->ny - 1) ? winsize_y - offy : triple->y[y]; - - /* wmOrtho for the screen has this same offset */ - ratiox = sizex; - ratioy = sizey; - halfx = GLA_PIXEL_OFS; - halfy = GLA_PIXEL_OFS; - - /* texture rectangle has unnormalized coordinates */ - if (triple->target == GL_TEXTURE_2D) { - ratiox /= triple->x[x]; - ratioy /= triple->y[y]; - halfx /= triple->x[x]; - halfy /= triple->y[y]; - } + /* wmOrtho for the screen has this same offset */ + ratiox = sizex; + ratioy = sizey; + halfx = GLA_PIXEL_OFS; + halfy = GLA_PIXEL_OFS; + + /* texture rectangle has unnormalized coordinates */ + if (triple->target == GL_TEXTURE_2D) { + ratiox /= triple->x; + ratioy /= triple->y; + halfx /= triple->x; + halfy /= triple->y; + } - glBindTexture(triple->target, triple->bind[x + y * triple->nx]); + glBindTexture(triple->target, triple->bind); - glColor4f(1.0f, 1.0f, 1.0f, alpha); - glBegin(GL_QUADS); - glTexCoord2f(halfx, halfy); - glVertex2f(offx, offy); + glColor4f(1.0f, 1.0f, 1.0f, alpha); + glBegin(GL_QUADS); + glTexCoord2f(halfx, halfy); + glVertex2f(0, 0); - glTexCoord2f(ratiox + halfx, halfy); - glVertex2f(offx + sizex, offy); + glTexCoord2f(ratiox + halfx, halfy); + glVertex2f(sizex, 0); - glTexCoord2f(ratiox + halfx, ratioy + halfy); - glVertex2f(offx + sizex, offy + sizey); + glTexCoord2f(ratiox + halfx, ratioy + halfy); + glVertex2f(sizex, sizey); - glTexCoord2f(halfx, ratioy + halfy); - glVertex2f(offx, offy + sizey); - glEnd(); - } - } + glTexCoord2f(halfx, ratioy + halfy); + glVertex2f(0, sizey); + glEnd(); glBindTexture(triple->target, 0); glDisable(triple->target); @@ -555,20 +476,11 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple) { - const int winsize_x = WM_window_pixels_x(win); - const int winsize_y = WM_window_pixels_y(win); - - int x, y, sizex, sizey, offx, offy; - - for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) { - for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) { - sizex = (x == triple->nx - 1) ? winsize_x - offx : triple->x[x]; - sizey = (y == triple->ny - 1) ? winsize_y - offy : triple->y[y]; + const int sizex = WM_window_pixels_x(win); + const int sizey = WM_window_pixels_y(win); - glBindTexture(triple->target, triple->bind[x + y * triple->nx]); - glCopyTexSubImage2D(triple->target, 0, 0, 0, offx, offy, sizex, sizey); - } - } + glBindTexture(triple->target, triple->bind); + glCopyTexSubImage2D(triple->target, 0, 0, 0, 0, 0, sizex, sizey); glBindTexture(triple->target, 0); } diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index a643e1c632a..72b26cc6207 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1301,17 +1301,12 @@ char *WM_key_event_operator_string( return NULL; } -int WM_key_event_operator_id( +wmKeyMapItem *WM_key_event_operator( const bContext *C, const char *opname, int opcontext, IDProperty *properties, const bool is_hotkey, wmKeyMap **r_keymap) { - wmKeyMapItem *kmi = wm_keymap_item_find(C, opname, opcontext, properties, is_hotkey, true, r_keymap); - - if (kmi) - return kmi->id; - else - return 0; + return wm_keymap_item_find(C, opname, opcontext, properties, is_hotkey, true, r_keymap); } int WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2) @@ -1867,7 +1862,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) km = WM_keymap_find_all(C, "NLA Editor", sl->spacetype, 0); break; case SPACE_IMAGE: - km = WM_keymap_find_all(C, "UV Editor", sl->spacetype, 0); + km = WM_keymap_find_all(C, "UV Editor", 0, 0); break; case SPACE_NODE: km = WM_keymap_find_all(C, "Node Editor", sl->spacetype, 0); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 3734b5ab530..a4a56345798 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -105,6 +105,7 @@ #include "ED_util.h" #include "ED_view3d.h" +#include "GPU_basic_shader.h" #include "GPU_material.h" #include "RNA_access.h" @@ -4144,7 +4145,7 @@ static void radial_control_set_tex(RadialControl *rc) if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data, rc->use_secondary_tex))) { glGenTextures(1, &rc->gltex); glBindTexture(GL_TEXTURE_2D, rc->gltex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, ibuf->x, ibuf->y, 0, + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, ibuf->x, ibuf->y, 0, GL_ALPHA, GL_FLOAT, ibuf->rect_float); MEM_freeN(ibuf->rect_float); MEM_freeN(ibuf); @@ -4179,7 +4180,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph } /* draw textured quad */ - glEnable(GL_TEXTURE_2D); + GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(-radius, -radius); @@ -4190,7 +4191,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph glTexCoord2f(0, 1); glVertex2f(-radius, radius); glEnd(); - glDisable(GL_TEXTURE_2D); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); /* undo rotation */ if (rc->rot_prop) diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c index 98c45bfb6ea..21fc7f2b5b2 100644 --- a/source/blender/windowmanager/intern/wm_stereo.c +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -195,7 +195,6 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win) wmDrawData *drawdata; wmDrawTriple *triple; float halfx, halfy, ratiox, ratioy; - int x, y, offx, offy; float alpha = 1.0f; int view; int soffx; @@ -217,44 +216,40 @@ static void wm_method_draw_stereo3d_sidebyside(wmWindow *win) glEnable(triple->target); - for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) { - for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) { - const int sizex = triple->x[x]; - const int sizey = triple->y[y]; - - /* wmOrtho for the screen has this same offset */ - ratiox = sizex; - ratioy = sizey; - halfx = GLA_PIXEL_OFS; - halfy = GLA_PIXEL_OFS; - - /* texture rectangle has unnormalized coordinates */ - if (triple->target == GL_TEXTURE_2D) { - ratiox /= triple->x[x]; - ratioy /= triple->y[y]; - halfx /= triple->x[x]; - halfy /= triple->y[y]; - } - - glBindTexture(triple->target, triple->bind[x + y * triple->nx]); - - glColor4f(1.0f, 1.0f, 1.0f, alpha); - glBegin(GL_QUADS); - glTexCoord2f(halfx, halfy); - glVertex2f(soffx + (offx * 0.5f), offy); - - glTexCoord2f(ratiox + halfx, halfy); - glVertex2f(soffx + ((offx + sizex) * 0.5f), offy); - - glTexCoord2f(ratiox + halfx, ratioy + halfy); - glVertex2f(soffx + ((offx + sizex) * 0.5f), offy + sizey); - - glTexCoord2f(halfx, ratioy + halfy); - glVertex2f(soffx + (offx * 0.5f), offy + sizey); - glEnd(); - } + const int sizex = triple->x; + const int sizey = triple->y; + + /* wmOrtho for the screen has this same offset */ + ratiox = sizex; + ratioy = sizey; + halfx = GLA_PIXEL_OFS; + halfy = GLA_PIXEL_OFS; + + /* texture rectangle has unnormalized coordinates */ + if (triple->target == GL_TEXTURE_2D) { + ratiox /= triple->x; + ratioy /= triple->y; + halfx /= triple->x; + halfy /= triple->y; } + glBindTexture(triple->target, triple->bind); + + glColor4f(1.0f, 1.0f, 1.0f, alpha); + glBegin(GL_QUADS); + glTexCoord2f(halfx, halfy); + glVertex2f(soffx, 0); + + glTexCoord2f(ratiox + halfx, halfy); + glVertex2f(soffx + (sizex * 0.5f), 0); + + glTexCoord2f(ratiox + halfx, ratioy + halfy); + glVertex2f(soffx + (sizex * 0.5f), sizey); + + glTexCoord2f(halfx, ratioy + halfy); + glVertex2f(soffx, sizey); + glEnd(); + glBindTexture(triple->target, 0); glDisable(triple->target); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -266,7 +261,6 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win) wmDrawData *drawdata; wmDrawTriple *triple; float halfx, halfy, ratiox, ratioy; - int x, y, offx, offy; float alpha = 1.0f; int view; int soffy; @@ -284,44 +278,40 @@ static void wm_method_draw_stereo3d_topbottom(wmWindow *win) glEnable(triple->target); - for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) { - for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) { - const int sizex = triple->x[x]; - const int sizey = triple->y[y]; - - /* wmOrtho for the screen has this same offset */ - ratiox = sizex; - ratioy = sizey; - halfx = GLA_PIXEL_OFS; - halfy = GLA_PIXEL_OFS; - - /* texture rectangle has unnormalized coordinates */ - if (triple->target == GL_TEXTURE_2D) { - ratiox /= triple->x[x]; - ratioy /= triple->y[y]; - halfx /= triple->x[x]; - halfy /= triple->y[y]; - } - - glBindTexture(triple->target, triple->bind[x + y * triple->nx]); - - glColor4f(1.0f, 1.0f, 1.0f, alpha); - glBegin(GL_QUADS); - glTexCoord2f(halfx, halfy); - glVertex2f(offx, soffy + (offy * 0.5f)); - - glTexCoord2f(ratiox + halfx, halfy); - glVertex2f(offx + sizex, soffy + (offy * 0.5f)); - - glTexCoord2f(ratiox + halfx, ratioy + halfy); - glVertex2f(offx + sizex, soffy + ((offy + sizey) * 0.5f)); - - glTexCoord2f(halfx, ratioy + halfy); - glVertex2f(offx, soffy + ((offy + sizey) * 0.5f)); - glEnd(); - } + const int sizex = triple->x; + const int sizey = triple->y; + + /* wmOrtho for the screen has this same offset */ + ratiox = sizex; + ratioy = sizey; + halfx = GLA_PIXEL_OFS; + halfy = GLA_PIXEL_OFS; + + /* texture rectangle has unnormalized coordinates */ + if (triple->target == GL_TEXTURE_2D) { + ratiox /= triple->x; + ratioy /= triple->y; + halfx /= triple->x; + halfy /= triple->y; } + glBindTexture(triple->target, triple->bind); + + glColor4f(1.0f, 1.0f, 1.0f, alpha); + glBegin(GL_QUADS); + glTexCoord2f(halfx, halfy); + glVertex2f(0, soffy); + + glTexCoord2f(ratiox + halfx, halfy); + glVertex2f(sizex, soffy); + + glTexCoord2f(ratiox + halfx, ratioy + halfy); + glVertex2f(sizex, soffy + (sizey * 0.5f)); + + glTexCoord2f(halfx, ratioy + halfy); + glVertex2f(0, soffy + (sizey * 0.5f)); + glEnd(); + glBindTexture(triple->target, 0); glDisable(triple->target); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h index 5dc52b2e4fb..0f125309045 100644 --- a/source/blender/windowmanager/wm_draw.h +++ b/source/blender/windowmanager/wm_draw.h @@ -34,13 +34,9 @@ #include "GPU_glew.h" - -#define MAX_N_TEX 3 - typedef struct wmDrawTriple { - GLuint bind[MAX_N_TEX * MAX_N_TEX]; - int x[MAX_N_TEX], y[MAX_N_TEX]; - int nx, ny; + GLuint bind; + int x, y; GLenum target; } wmDrawTriple; diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index af367467e00..deb702f005c 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -79,6 +79,11 @@ else() TARGETS blenderplayer DESTINATION bin ) + else() + install( + TARGETS blenderplayer + DESTINATION "." + ) endif() endif() @@ -164,14 +169,13 @@ endif() extern_recastnavigation bf_intern_raskter bf_intern_opencolorio - bf_intern_opennl bf_intern_glew_mx + bf_intern_eigen extern_rangetree extern_wcwidth extern_libmv extern_glog extern_sdlew - extern_eigen3 ) if(WITH_MOD_CLOTH_ELTOPO) @@ -190,8 +194,6 @@ endif() list(APPEND BLENDER_SORTED_LIBS extern_ceres) endif() - list(APPEND BLENDER_SORTED_LIBS extern_colamd) - if(WITH_MOD_BOOLEAN) list(APPEND BLENDER_SORTED_LIBS extern_carve) endif() diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index d28f3a21341..458d883666e 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -137,6 +137,7 @@ struct wmWindowManager; #if 1 #if defined(__GNUC__) # pragma GCC diagnostic error "-Wmissing-prototypes" +# pragma GCC diagnostic ignored "-Wunused-parameter" #endif #include "../../intern/cycles/blender/CCL_api.h" @@ -283,6 +284,7 @@ struct Render *RE_NewRender(const char *name) RET_NULL void RE_SwapResult(struct Render *re, struct RenderResult **rr) RET_NONE void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene, struct SceneRenderLayer *srl, struct Object *camera_override, unsigned int lay_override, int frame, const bool write_still) RET_NONE bool RE_WriteEnvmapResult(struct ReportList *reports, struct Scene *scene, struct EnvMap *env, const char *relpath, const char imtype, float layout[12]) RET_ZERO +void RE_cache_point_density(struct Scene *scene, struct PointDensity *pd, const bool use_render_params) RET_NONE /* rna */ float *ED_view3d_cursor3d_get(struct Scene *scene, struct View3D *v3d) RET_NULL @@ -511,10 +513,12 @@ bool ED_texture_context_check_others(const struct bContext *C) RET_ZERO bool ED_text_region_location_from_cursor(SpaceText *st, ARegion *ar, const int cursor_co[2], int r_pixel_co[2]) RET_ZERO -bool snapObjectsRayEx(struct Scene *scene, struct Base *base_act, struct View3D *v3d, struct ARegion *ar, struct Object *obedit, short snap_mode, - struct Object **r_ob, float r_obmat[4][4], - const float ray_start[3], const float ray_normal[3], float *r_ray_dist, - const float mval[2], float *r_dist_px, float r_loc[3], float r_no[3], SnapMode mode) RET_ZERO +bool snapObjectsRayEx( + struct Scene *scene, struct View3D *v3d, struct ARegion *ar, struct Base *base_act, struct Object *obedit, + const float mval[2], SnapSelect snap_select, short snap_mode, + const float ray_start[3], const float ray_normal[3], float *ray_dist, + float r_loc[3], float r_no[3], float *r_dist_px, int *r_index, + struct Object **r_ob, float r_obmat[4][4]) RET_ZERO void ED_lattice_editlatt_make(struct Object *obedit) RET_NONE void ED_lattice_editlatt_load(struct Object *obedit) RET_NONE diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 08390b585ac..49fb4fe82eb 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -250,8 +250,10 @@ endif() set(BLENDER_TEXT_FILES ${CMAKE_SOURCE_DIR}/release/text/GPL-license.txt + ${CMAKE_SOURCE_DIR}/release/text/GPL3-license.txt ${CMAKE_SOURCE_DIR}/release/text/Python-license.txt ${CMAKE_SOURCE_DIR}/release/text/copyright.txt + ${CMAKE_SOURCE_DIR}/release/text/jemalloc-license.txt # generate this file # ${CMAKE_SOURCE_DIR}/release/text/readme.html ${CMAKE_SOURCE_DIR}/release/datafiles/LICENSE-bfont.ttf.txt diff --git a/source/creator/blender.map b/source/creator/blender.map index 359cbe0415f..9c900a62705 100644 --- a/source/creator/blender.map +++ b/source/creator/blender.map @@ -9,6 +9,7 @@ global: *; *_boost*; local: + *default_error_condition*; *llvm*; *LLVM*; decodeInstruction; diff --git a/source/creator/creator.c b/source/creator/creator.c index c6203b6fd40..f7dd0aaf736 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -1505,7 +1505,7 @@ static int load_file(int UNUSED(argc), const char **argv, void *data) } } else { - /* failed to load file, stop processing arguments */ + /* failed to load file, stop processing arguments if running in background mode */ if (G.background) { /* Set is_break if running in the background mode so * blender will return non-zero exit code which then @@ -1513,8 +1513,14 @@ static int load_file(int UNUSED(argc), const char **argv, void *data) * good or bad things are. */ G.is_break = true; + return -1; } - return -1; + + /* Just pretend a file was loaded, so the user can press Save and it'll save at the filename from the CLI. */ + BLI_strncpy(G.main->name, filename, FILE_MAX); + G.relbase_valid = true; + G.save_over = true; + printf("... opened default scene instead; saving will write to %s\n", filename); } G.file_loaded = 1; diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 6832b4191f5..c5fc55a8e68 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -54,7 +54,6 @@ #include "KX_PyConstraintBinding.h" #include "KX_PythonMain.h" -#include "RAS_GLExtensionManager.h" #include "RAS_OpenGLRasterizer.h" #include "RAS_ListRasterizer.h" @@ -250,8 +249,6 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c PyObject *pyGlobalDict = PyDict_New(); /* python utility storage, spans blend file loading */ #endif - - bgl::InitExtensions(true); // Globals to be carried on over blender files GlobalSettings gs; @@ -302,12 +299,20 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c canvas->SetSwapInterval((startscene->gm.vsync == VSYNC_ON) ? 1 : 0); RAS_IRasterizer* rasterizer = NULL; + RAS_STORAGE_TYPE raster_storage = RAS_AUTO_STORAGE; + + if (startscene->gm.raster_storage == RAS_STORE_VBO) { + raster_storage = RAS_VBO; + } + else if (startscene->gm.raster_storage == RAS_STORE_VA) { + raster_storage = RAS_VA; + } //Don't use displaylists with VBOs //If auto starts using VBOs, make sure to check for that here - if (displaylists && startscene->gm.raster_storage != RAS_STORE_VBO) - rasterizer = new RAS_ListRasterizer(canvas, true, startscene->gm.raster_storage); + if (displaylists && raster_storage != RAS_VBO) + rasterizer = new RAS_ListRasterizer(canvas, true, raster_storage); else - rasterizer = new RAS_OpenGLRasterizer(canvas, startscene->gm.raster_storage); + rasterizer = new RAS_OpenGLRasterizer(canvas, raster_storage); RAS_IRasterizer::MipmapOption mipmapval = rasterizer->GetMipmapping(); @@ -677,6 +682,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c BLI_strncpy(G.main->name, oldsce, sizeof(G.main->name)); #ifdef WITH_PYTHON + PyDict_Clear(pyGlobalDict); Py_DECREF(pyGlobalDict); // Release Python's GIL diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index 2b357f43031..f0a7bd47ca3 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -78,7 +78,6 @@ extern "C" #include "RAS_MeshObject.h" #include "RAS_OpenGLRasterizer.h" #include "RAS_ListRasterizer.h" -#include "RAS_GLExtensionManager.h" #include "KX_PythonInit.h" #include "KX_PyConstraintBinding.h" #include "BL_Material.h" // MAXTEX @@ -563,7 +562,6 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) if (!m_engineInitialized) { GPU_init(); - bgl::InitExtensions(true); // get and set the preferences SYS_SystemHandle syshandle = SYS_GetSystem(); @@ -607,12 +605,20 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) if (gm->flag & GAME_SHOW_MOUSE) m_canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); + RAS_STORAGE_TYPE raster_storage = RAS_AUTO_STORAGE; + + if (gm->raster_storage == RAS_STORE_VBO) { + raster_storage = RAS_VBO; + } + else if (gm->raster_storage == RAS_STORE_VA) { + raster_storage = RAS_VA; + } //Don't use displaylists with VBOs //If auto starts using VBOs, make sure to check for that here - if (useLists && gm->raster_storage != RAS_STORE_VBO) - m_rasterizer = new RAS_ListRasterizer(m_canvas, false, gm->raster_storage); + if (useLists && raster_storage != RAS_VBO) + m_rasterizer = new RAS_ListRasterizer(m_canvas, true, raster_storage); else - m_rasterizer = new RAS_OpenGLRasterizer(m_canvas, gm->raster_storage); + m_rasterizer = new RAS_OpenGLRasterizer(m_canvas, raster_storage); /* Stereo parameters - Eye Separation from the UI - stereomode from the command-line/UI */ m_rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) stereoMode); diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp index b5151615f3b..0f71f8d3bac 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.cpp +++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp @@ -35,8 +35,8 @@ #include "BL_BlenderShader.h" #include "BL_Material.h" -#include "GPU_extensions.h" #include "GPU_material.h" +#include "GPU_shader.h" #include "RAS_BucketManager.h" #include "RAS_MeshObject.h" diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp index 4b229f53d77..6613780a0f8 100644 --- a/source/gameengine/Ketsji/BL_Shader.cpp +++ b/source/gameengine/Ketsji/BL_Shader.cpp @@ -34,7 +34,6 @@ #include "KX_PyMath.h" #include "MEM_guardedalloc.h" -#include "RAS_GLExtensionManager.h" #include "RAS_MeshObject.h" #include "RAS_IRasterizer.h" diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp index 8f717c05c0f..d14b9cc57b8 100644 --- a/source/gameengine/Ketsji/BL_Texture.cpp +++ b/source/gameengine/Ketsji/BL_Texture.cpp @@ -38,7 +38,6 @@ #include "BKE_image.h" #include "BLI_blenlib.h" -#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h" #include "RAS_ICanvas.h" #include "RAS_Rect.h" @@ -196,7 +195,7 @@ bool BL_Texture::InitFromImage(int unit, Image *img, bool mipmap) void BL_Texture::InitGLTex(unsigned int *pix,int x,int y,bool mipmap) { - if (!GPU_non_power_of_two_support() && (!is_power_of_2_i(x) || !is_power_of_2_i(y)) ) { + if (!GPU_full_non_power_of_two_support() && (!is_power_of_2_i(x) || !is_power_of_2_i(y)) ) { InitNonPow2Tex(pix, x,y,mipmap); return; } diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index d85d33d9834..a10bdf4ac98 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -39,7 +39,6 @@ #include "RAS_BucketManager.h" #include "RAS_MeshObject.h" #include "RAS_IRasterizer.h" -#include "RAS_OpenGLRasterizer/RAS_GLExtensionManager.h" #include "GPU_draw.h" diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 5e66250bd80..412a112df6b 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -3736,8 +3736,9 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, RayCastData rayData(propName, false, (1 << OB_MAX_COL_MASKS) - 1); KX_RayCast::Callback<KX_GameObject, RayCastData> callback(this, spc, &rayData); - if (KX_RayCast::RayTest(pe, fromPoint, toPoint, callback)) + if (KX_RayCast::RayTest(pe, fromPoint, toPoint, callback) && rayData.m_hitObject) { return rayData.m_hitObject->GetProxy(); + } Py_RETURN_NONE; } @@ -3883,8 +3884,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, RayCastData rayData(propName, xray, mask); KX_RayCast::Callback<KX_GameObject, RayCastData> callback(this, spc, &rayData, face, (poly == 2)); - if (KX_RayCast::RayTest(pe, fromPoint, toPoint, callback)) - { + if (KX_RayCast::RayTest(pe, fromPoint, toPoint, callback) && rayData.m_hitObject) { PyObject *returnValue = (poly == 2) ? PyTuple_New(5) : (poly) ? PyTuple_New(4) : PyTuple_New(3); if (returnValue) { // unlikely this would ever fail, if it does python sets an error PyTuple_SET_ITEM(returnValue, 0, rayData.m_hitObject->GetProxy()); diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 5f36a980a53..fa924f74290 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -128,6 +128,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_bInitialized(false), m_activecam(0), m_bFixedTime(false), + m_useExternalClock(false), m_firstframe(true), @@ -135,6 +136,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) m_clockTime(0.f), m_previousClockTime(0.f), m_previousAnimTime(0.f), + m_timescale(1.0f), + m_previousRealTime(0.0f), m_exitcode(KX_EXIT_REQUEST_NO_REQUEST), @@ -411,6 +414,7 @@ void KX_KetsjiEngine::StartEngine(bool clearIpo) m_clockTime = m_kxsystem->GetTimeInSeconds(); m_frameTime = m_kxsystem->GetTimeInSeconds(); m_previousClockTime = m_kxsystem->GetTimeInSeconds(); + m_previousRealTime = m_kxsystem->GetTimeInSeconds(); m_firstframe = true; m_bInitialized = true; @@ -554,7 +558,7 @@ void KX_KetsjiEngine::EndFrame() bool KX_KetsjiEngine::NextFrame() { - double timestep = 1.0/m_ticrate; + double timestep = m_timescale / m_ticrate; double framestep = timestep; // static hidden::Clock sClock; @@ -563,12 +567,43 @@ bool KX_KetsjiEngine::NextFrame() //float dt = sClock.getTimeMicroseconds() * 0.000001f; //sClock.reset(); - if (m_bFixedTime) { - m_clockTime += timestep; - } - else { - // m_clockTime += dt; - m_clockTime = m_kxsystem->GetTimeInSeconds(); + /* + * Clock advancement. There is basically three case: + * - m_useExternalClock is true, the user is responsible to advance the time + * manually using setClockTime, so here, we do not do anything. + * - m_useExternalClock is false, m_bFixedTime is true, we advance for one + * timestep, which already handle the time scaling parameter + * - m_useExternalClock is false, m_bFixedTime is false, we consider how much + * time has elapsed since last call and we scale this time by the time + * scaling parameter. If m_timescale is 1.0 (default value), the clock + * corresponds to the computer clock. + * + * Once clockTime has been computed, we will compute how many logic frames + * will be executed before the next rendering phase (which will occur at "clockTime"). + * The game time elapsing between two logic frames (called framestep) + * depends on several variables: + * - ticrate + * - max_physic_frame + * - max_logic_frame + * XXX The logic over computation framestep is definitively not clear (and + * I'm not even sure it is correct). If needed frame is strictly greater + * than max_physics_frame, we are doing a jump in game time, but keeping + * framestep = 1 / ticrate, while if frames is greater than + * max_logic_frame, we increase framestep. + * + * XXX render.fps is not considred anywhere. + */ + if (!m_useExternalClock) { + if (m_bFixedTime) { + m_clockTime += timestep; + } + else { + double current_time = m_kxsystem->GetTimeInSeconds(); + double dt = current_time - m_previousRealTime; + m_previousRealTime = current_time; + // m_clockTime += dt; + m_clockTime += dt * m_timescale; + } } double deltatime = m_clockTime - m_frameTime; @@ -579,16 +614,14 @@ bool KX_KetsjiEngine::NextFrame() return false; } - // Compute the number of logic frames to do each update (fixed tic bricks) - int frames =int(deltatime*m_ticrate+1e-6); + int frames = int(deltatime * m_ticrate / m_timescale + 1e-6); // if (frames>1) // printf("****************************************"); // printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames); // if (!frames) // PIL_sleep_ms(1); - KX_SceneList::iterator sceneit; if (frames>m_maxPhysicsFrame) @@ -1756,6 +1789,10 @@ void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime) m_bFixedTime = bUseFixedTime; } +void KX_KetsjiEngine::SetUseExternalClock(bool useExternalClock) +{ + m_useExternalClock = useExternalClock; +} void KX_KetsjiEngine::SetAnimRecordMode(bool animation_record, int startFrame) { @@ -1783,6 +1820,11 @@ bool KX_KetsjiEngine::GetUseFixedTime(void) const return m_bFixedTime; } +bool KX_KetsjiEngine::GetUseExternalClock(void) const +{ + return m_useExternalClock; +} + double KX_KetsjiEngine::GetSuspendedDelta() { return m_suspendeddelta; @@ -1798,6 +1840,16 @@ void KX_KetsjiEngine::SetTicRate(double ticrate) m_ticrate = ticrate; } +double KX_KetsjiEngine::GetTimeScale() const +{ + return m_timescale; +} + +void KX_KetsjiEngine::SetTimeScale(double timescale) +{ + m_timescale = timescale; +} + int KX_KetsjiEngine::GetMaxLogicFrame() { return m_maxLogicFrame; @@ -1838,6 +1890,11 @@ double KX_KetsjiEngine::GetClockTime(void) const return m_clockTime; } +void KX_KetsjiEngine::SetClockTime(double externalClockTime) +{ + m_clockTime = externalClockTime; +} + double KX_KetsjiEngine::GetFrameTime(void) const { return m_frameTime; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index ec855be3212..3b8cec2ac82 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -103,16 +103,19 @@ private: bool m_bInitialized; int m_activecam; bool m_bFixedTime; + bool m_useExternalClock; bool m_firstframe; int m_currentFrame; - double m_frameTime;//discrete timestamp of the 'game logic frame' - double m_clockTime;//current time - double m_previousClockTime;//previous clock time - double m_previousAnimTime; //the last time animations were updated + double m_frameTime; // current logic game time + double m_clockTime; // game time for the next rendering step + double m_previousClockTime; // game time of the previous rendering step + double m_previousAnimTime; //game time when the animations were last updated double m_remainingTime; + double m_timescale; // time scaling parameter. if > 1.0, time goes faster than real-time. If < 1.0, times goes slower than real-time. + double m_previousRealTime; static int m_maxLogicFrame; /* maximum number of consecutive logic frame */ static int m_maxPhysicsFrame; /* maximum number of consecutive physics frame */ @@ -297,15 +300,37 @@ public: bool GetUseFixedTime(void) const; /** - * Returns current render frame clock time + * Sets if the BGE relies on a external clock or its own internal clock + */ + void SetUseExternalClock(bool bUseExternalClock); + + /** + * Returns if we rely on an external clock + * \return Current setting + */ + bool GetUseExternalClock(void) const; + + /** + * Returns next render frame game time */ double GetClockTime(void) const; + + /** + * Set the next render frame game time. It will impact also frame time, as + * this one is derived from clocktime + */ + void SetClockTime(double externalClockTime); + /** - * Returns current logic frame clock time + * Returns current logic frame game time */ double GetFrameTime(void) const; + /** + * Returns the real (system) time + */ double GetRealTime(void) const; + /** * Returns the difference between the local time of the scene (when it * was running and not suspended) and the "curtime" @@ -361,6 +386,16 @@ public: */ static double GetAverageFrameRate(); + /** + * Gets the time scale multiplier + */ + double GetTimeScale() const; + + /** + * Sets the time scale multiplier + */ + void SetTimeScale(double scale); + static void SetExitKey(short key); static short GetExitKey(); diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 26c6fcaa928..8a010726bba 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -548,6 +548,64 @@ static PyObject *gPyGetAverageFrameRate(PyObject *) return PyFloat_FromDouble(KX_KetsjiEngine::GetAverageFrameRate()); } +static PyObject *gPyGetUseExternalClock(PyObject *) +{ + return PyBool_FromLong(gp_KetsjiEngine->GetUseExternalClock()); +} + +static PyObject *gPySetUseExternalClock(PyObject *, PyObject *args) +{ + bool bUseExternalClock; + + if (!PyArg_ParseTuple(args, "p:setUseExternalClock", &bUseExternalClock)) + return NULL; + + gp_KetsjiEngine->SetUseExternalClock(bUseExternalClock); + Py_RETURN_NONE; +} + +static PyObject *gPyGetClockTime(PyObject *) +{ + return PyFloat_FromDouble(gp_KetsjiEngine->GetClockTime()); +} + +static PyObject *gPySetClockTime(PyObject *, PyObject *args) +{ + double externalClockTime; + + if (!PyArg_ParseTuple(args, "d:setClockTime", &externalClockTime)) + return NULL; + + gp_KetsjiEngine->SetClockTime(externalClockTime); + Py_RETURN_NONE; +} + +static PyObject *gPyGetFrameTime(PyObject *) +{ + return PyFloat_FromDouble(gp_KetsjiEngine->GetFrameTime()); +} + +static PyObject *gPyGetRealTime(PyObject *) +{ + return PyFloat_FromDouble(gp_KetsjiEngine->GetRealTime()); +} + +static PyObject *gPyGetTimeScale(PyObject *) +{ + return PyFloat_FromDouble(gp_KetsjiEngine->GetTimeScale()); +} + +static PyObject *gPySetTimeScale(PyObject *, PyObject *args) +{ + double time_scale; + + if (!PyArg_ParseTuple(args, "d:setTimeScale", &time_scale)) + return NULL; + + gp_KetsjiEngine->SetTimeScale(time_scale); + Py_RETURN_NONE; +} + static PyObject *gPyGetBlendFileList(PyObject *, PyObject *args) { char cpath[sizeof(gp_GamePythonPath)]; @@ -647,71 +705,10 @@ static PyObject *pyPrintStats(PyObject *,PyObject *,PyObject *) static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) { -#define pprint(x) std::cout << x << std::endl; - bool count=0; - bool support=0; - pprint("Supported Extensions..."); - pprint(" GL_ARB_shader_objects supported? "<< (GLEW_ARB_shader_objects?"yes.":"no.")); - count = 1; - - support= GLEW_ARB_vertex_shader; - pprint(" GL_ARB_vertex_shader supported? "<< (support?"yes.":"no.")); - count = 1; - if (support) { - pprint(" ----------Details----------"); - int max=0; - glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, (GLint*)&max); - pprint(" Max uniform components." << max); - - glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, (GLint*)&max); - pprint(" Max varying floats." << max); - - glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max); - pprint(" Max vertex texture units." << max); - - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max); - pprint(" Max combined texture units." << max); - pprint(""); - } - - support=GLEW_ARB_fragment_shader; - pprint(" GL_ARB_fragment_shader supported? "<< (support?"yes.":"no.")); - count = 1; - if (support) { - pprint(" ----------Details----------"); - int max=0; - glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, (GLint*)&max); - pprint(" Max uniform components." << max); - pprint(""); - } - - support = GLEW_ARB_texture_cube_map; - pprint(" GL_ARB_texture_cube_map supported? "<< (support?"yes.":"no.")); - count = 1; - if (support) { - pprint(" ----------Details----------"); - int size=0; - glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, (GLint*)&size); - pprint(" Max cubemap size." << size); - pprint(""); - } - - support = GLEW_ARB_multitexture; - count = 1; - pprint(" GL_ARB_multitexture supported? "<< (support?"yes.":"no.")); - if (support) { - pprint(" ----------Details----------"); - int units=0; - glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&units); - pprint(" Max texture units available. " << units); - pprint(""); - } - - pprint(" GL_ARB_texture_env_combine supported? "<< (GLEW_ARB_texture_env_combine?"yes.":"no.")); - count = 1; - - if (!count) - pprint("No extenstions are used in this build"); + if (gp_Rasterizer) + gp_Rasterizer->PrintHardwareInfo(); + else + printf("Warning: no rasterizer detected for PrintGLInfo!\n"); Py_RETURN_NONE; } @@ -908,7 +905,19 @@ static struct PyMethodDef game_methods[] = { {"setAnimRecordFrame", (PyCFunction) gPySetAnimRecordFrame, METH_VARARGS, (const char *)"Sets the current frame number used for animation recording"}, {"getExitKey", (PyCFunction) gPyGetExitKey, METH_NOARGS, (const char *)"Gets the key used to exit the game engine"}, {"setExitKey", (PyCFunction) gPySetExitKey, METH_VARARGS, (const char *)"Sets the key used to exit the game engine"}, + {"getUseExternalClock", (PyCFunction) gPyGetUseExternalClock, METH_NOARGS, (const char *)"Get if we use the time provided by an external clock"}, + {"setUseExternalClock", (PyCFunction) gPySetUseExternalClock, METH_VARARGS, (const char *)"Set if we use the time provided by an external clock"}, + {"getClockTime", (PyCFunction) gPyGetClockTime, METH_NOARGS, (const char *)"Get the last BGE render time. " + "The BGE render time is the simulated time corresponding to the next scene that will be renderered"}, + {"setClockTime", (PyCFunction) gPySetClockTime, METH_VARARGS, (const char *)"Set the BGE render time. " + "The BGE render time is the simulated time corresponding to the next scene that will be rendered"}, + {"getFrameTime", (PyCFunction) gPyGetFrameTime, METH_NOARGS, (const char *)"Get the BGE last frametime. " + "The BGE frame time is the simulated time corresponding to the last call of the logic system"}, + {"getRealTime", (PyCFunction) gPyGetRealTime, METH_NOARGS, (const char *)"Get the real system time. " + "The real-time corresponds to the system time" }, {"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (const char *)"Gets the estimated average frame rate"}, + {"getTimeScale", (PyCFunction) gPyGetTimeScale, METH_NOARGS, (const char *)"Get the time multiplier"}, + {"setTimeScale", (PyCFunction) gPySetTimeScale, METH_VARARGS, (const char *)"Set the time multiplier"}, {"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, (const char *)"Gets a list of blend files in the same directory as the current blend file"}, {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (const char *)"Prints GL Extension Info"}, {"PrintMemInfo", (PyCFunction)pyPrintStats, METH_NOARGS, (const char *)"Print engine statistics"}, diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h index 7fbaf076d25..e960131c1fb 100644 --- a/source/gameengine/Rasterizer/RAS_IRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h @@ -267,7 +267,6 @@ public: * IndexPrimitives: Renders primitives from mesh slot. */ virtual void IndexPrimitives(class RAS_MeshSlot &ms) = 0; - virtual void IndexPrimitivesMulti(class RAS_MeshSlot &ms) = 0; /** * IndexPrimitives_3DText will render text into the polygons. @@ -480,6 +479,11 @@ public: virtual void SetAuxilaryClientInfo(void *inf) = 0; + /** + * Prints information about what the hardware supports. + */ + virtual void PrintHardwareInfo() = 0; + #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_IRasterizer") #endif diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp index 2078fc99f2e..13d49c53423 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp @@ -649,15 +649,13 @@ void RAS_MaterialBucket::RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRa else ms.m_bDisplayList = true; - // for text drawing using faces - if (m_material->GetDrawingMode() & RAS_IRasterizer::RAS_RENDER_3DPOLYGON_TEXT) + if (m_material->GetDrawingMode() & RAS_IRasterizer::RAS_RENDER_3DPOLYGON_TEXT) { + // for text drawing using faces rasty->IndexPrimitives_3DText(ms, m_material); - // for multitexturing - else if ((m_material->GetFlag() & (RAS_MULTITEX|RAS_BLENDERGLSL))) - rasty->IndexPrimitivesMulti(ms); - // use normal IndexPrimitives - else + } + else { rasty->IndexPrimitives(ms); + } rasty->PopMatrix(); } diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt index 888a7114f50..9f95e2c82af 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt @@ -49,20 +49,16 @@ set(INC_SYS ) set(SRC - RAS_GLExtensionManager.cpp RAS_ListRasterizer.cpp RAS_OpenGLLight.cpp RAS_OpenGLRasterizer.cpp - RAS_StorageIM.cpp RAS_StorageVA.cpp RAS_StorageVBO.cpp - RAS_GLExtensionManager.h RAS_IStorage.h RAS_ListRasterizer.h RAS_OpenGLLight.h RAS_OpenGLRasterizer.h - RAS_StorageIM.h RAS_StorageVA.h RAS_StorageVBO.h ) diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp deleted file mode 100644 index bc22d68e218..00000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp - * \ingroup bgerastogl - */ - - -#include <iostream> - -#include "glew-mx.h" - -#include "RAS_GLExtensionManager.h" - -namespace bgl -{ - void InitExtensions(bool debug) - { - static bool firsttime = true; - - if (firsttime) { - firsttime = false; - - if (debug) { - if (GLEW_ATI_pn_triangles) - std::cout << "Enabled GL_ATI_pn_triangles" << std::endl; - if (GLEW_ARB_texture_env_combine) - std::cout << "Detected GL_ARB_texture_env_combine" << std::endl; - if (GLEW_ARB_texture_cube_map) - std::cout << "Detected GL_ARB_texture_cube_map" << std::endl; - if (GLEW_ARB_multitexture) - std::cout << "Detected GL_ARB_multitexture" << std::endl; - if (GLEW_ARB_shader_objects) - std::cout << "Detected GL_ARB_shader_objects" << std::endl; - if (GLEW_ARB_vertex_shader) - std::cout << "Detected GL_ARB_vertex_shader" << std::endl; - if (GLEW_ARB_fragment_shader) - std::cout << "Detected GL_ARB_fragment_shader" << std::endl; - if (GLEW_ARB_vertex_program) - std::cout << "Detected GL_ARB_vertex_program" << std::endl; - if (GLEW_ARB_depth_texture) - std::cout << "Detected GL_ARB_depth_texture" << std::endl; - if (GLEW_EXT_separate_specular_color) - std::cout << "Detected GL_EXT_separate_specular_color" << std::endl; - } - } - } -} // namespace bgl - diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h index bfa6e1a6cb7..ae0cdcd84af 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h @@ -44,7 +44,6 @@ public: virtual void Exit()=0; virtual void IndexPrimitives(RAS_MeshSlot& ms)=0; - virtual void IndexPrimitivesMulti(RAS_MeshSlot& ms)=0; virtual void SetDrawingMode(int drawingmode)=0; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp index 34184f73953..b2d580161ca 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp @@ -122,7 +122,7 @@ bool RAS_ListSlot::End() -RAS_ListRasterizer::RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock, int storage) +RAS_ListRasterizer::RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock, RAS_STORAGE_TYPE storage) : RAS_OpenGLRasterizer(canvas, storage) { } @@ -243,30 +243,6 @@ void RAS_ListRasterizer::IndexPrimitives(RAS_MeshSlot& ms) if (ms.m_bDisplayList) { localSlot = FindOrAdd(ms); localSlot->DrawList(); - if (localSlot->End()) { - // save slot here too, needed for replicas and object using same mesh - // => they have the same vertexarray but different mesh slot - ms.m_DisplayList = localSlot; - return; - } - } - - RAS_OpenGLRasterizer::IndexPrimitives(ms); - - if (ms.m_bDisplayList) { - localSlot->EndList(); - ms.m_DisplayList = localSlot; - } -} - - -void RAS_ListRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms) -{ - RAS_ListSlot* localSlot =0; - - if (ms.m_bDisplayList) { - localSlot = FindOrAdd(ms); - localSlot->DrawList(); if (localSlot->End()) { // save slot here too, needed for replicas and object using same mesh @@ -276,7 +252,7 @@ void RAS_ListRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms) } } - RAS_OpenGLRasterizer::IndexPrimitivesMulti(ms); + RAS_OpenGLRasterizer::IndexPrimitives(ms); if (ms.m_bDisplayList) { localSlot->EndList(); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h index 5e1c662bc17..e3e6931311b 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h @@ -56,11 +56,10 @@ class RAS_ListRasterizer : public RAS_OpenGLRasterizer public: void RemoveListSlot(RAS_ListSlot* list); - RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock=false, int storage=RAS_AUTO_STORAGE); + RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock, RAS_STORAGE_TYPE storage); virtual ~RAS_ListRasterizer(); virtual void IndexPrimitives(class RAS_MeshSlot& ms); - virtual void IndexPrimitivesMulti(class RAS_MeshSlot& ms); virtual bool Init(); virtual void Exit(); diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index 28545576f05..bbdf17b5bc4 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -47,15 +47,17 @@ #include "RAS_OpenGLLight.h" -#include "RAS_StorageIM.h" #include "RAS_StorageVA.h" #include "RAS_StorageVBO.h" #include "GPU_draw.h" +#include "GPU_extensions.h" #include "GPU_material.h" +#include "GPU_shader.h" extern "C"{ #include "BLF_api.h" + #include "BKE_DerivedMesh.h" } @@ -83,7 +85,7 @@ static GLuint right_eye_vinterlace_mask[32]; */ static GLuint hinterlace_mask[33]; -RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, int storage) +RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, RAS_STORAGE_TYPE storage) :RAS_IRasterizer(canvas), m_2DCanvas(canvas), m_fogenabled(false), @@ -122,27 +124,22 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, int storage) m_prevafvalue = GPU_get_anisotropic(); - if (m_storage_type == RAS_VBO /*|| m_storage_type == RAS_AUTO_STORAGE && GLEW_ARB_vertex_buffer_object*/) - { + if (m_storage_type == RAS_VBO /*|| m_storage_type == RAS_AUTO_STORAGE && GLEW_ARB_vertex_buffer_object*/) { m_storage = new RAS_StorageVBO(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer); - m_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer); - m_storage_type = RAS_VBO; } - else if ((m_storage_type == RAS_VA) || (m_storage_type == RAS_AUTO_STORAGE && GLEW_VERSION_1_1)) - { + else if ((m_storage_type == RAS_VA) || (m_storage_type == RAS_AUTO_STORAGE)) { m_storage = new RAS_StorageVA(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer); - m_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer); - m_storage_type = RAS_VA; } - else - { - m_storage = m_failsafe_storage = new RAS_StorageIM(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer); - m_storage_type = RAS_IMMEDIATE; + else { + printf("Unknown rasterizer storage type, falling back to vertex arrays\n"); + m_storage = new RAS_StorageVA(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer); } glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &m_numgllights); if (m_numgllights < 8) m_numgllights = 8; + + PrintHardwareInfo(); } @@ -151,8 +148,6 @@ RAS_OpenGLRasterizer::~RAS_OpenGLRasterizer() { // Restore the previous AF value GPU_set_anisotropic(m_prevafvalue); - if (m_failsafe_storage && m_failsafe_storage != m_storage) - delete m_failsafe_storage; if (m_storage) delete m_storage; @@ -321,9 +316,6 @@ void RAS_OpenGLRasterizer::SetDrawingMode(int drawingmode) glDisable(GL_CULL_FACE); m_storage->SetDrawingMode(drawingmode); - if (m_failsafe_storage && m_failsafe_storage != m_storage) { - m_failsafe_storage->SetDrawingMode(drawingmode); - } } int RAS_OpenGLRasterizer::GetDrawingMode() @@ -735,17 +727,97 @@ void RAS_OpenGLRasterizer::SetAttrib(TexCoGen coords, int unit, int layer) void RAS_OpenGLRasterizer::IndexPrimitives(RAS_MeshSlot& ms) { if (ms.m_pDerivedMesh) - m_failsafe_storage->IndexPrimitives(ms); + DrawDerivedMesh(ms); else m_storage->IndexPrimitives(ms); } -void RAS_OpenGLRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms) +// Code for hooking into Blender's mesh drawing for derived meshes. +// If/when we use more of Blender's drawing code, we may be able to +// clean this up +static bool current_wireframe; +static RAS_MaterialBucket *current_bucket; +static RAS_IPolyMaterial *current_polymat; +static RAS_MeshSlot *current_ms; +static RAS_MeshObject *current_mesh; +static int current_blmat_nr; +static GPUVertexAttribs current_gpu_attribs; +static Image *current_image; +static int CheckMaterialDM(int matnr, void *attribs) +{ + // only draw the current material + if (matnr != current_blmat_nr) + return 0; + GPUVertexAttribs *gattribs = (GPUVertexAttribs *)attribs; + if (gattribs) + memcpy(gattribs, ¤t_gpu_attribs, sizeof(GPUVertexAttribs)); + return 1; +} + +static DMDrawOption CheckTexDM(MTexPoly *mtexpoly, const bool has_mcol, int matnr) +{ + + // index is the original face index, retrieve the polygon + if (matnr == current_blmat_nr && + (mtexpoly == NULL || mtexpoly->tpage == current_image)) { + // must handle color. + if (current_wireframe) + return DM_DRAW_OPTION_NO_MCOL; + if (current_ms->m_bObjectColor) { + MT_Vector4& rgba = current_ms->m_RGBAcolor; + glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); + // don't use mcol + return DM_DRAW_OPTION_NO_MCOL; + } + if (!has_mcol) { + // we have to set the color from the material + unsigned char rgba[4]; + current_polymat->GetMaterialRGBAColor(rgba); + glColor4ubv((const GLubyte *)rgba); + return DM_DRAW_OPTION_NO_MCOL; + } + return DM_DRAW_OPTION_NORMAL; + } + return DM_DRAW_OPTION_SKIP; +} + +void RAS_OpenGLRasterizer::DrawDerivedMesh(class RAS_MeshSlot &ms) { - if (ms.m_pDerivedMesh) - m_failsafe_storage->IndexPrimitivesMulti(ms); + // mesh data is in derived mesh, + current_bucket = ms.m_bucket; + current_polymat = current_bucket->GetPolyMaterial(); + current_ms = &ms; + current_mesh = ms.m_mesh; + current_wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME; + // MCol *mcol = (MCol*)ms.m_pDerivedMesh->getFaceDataArray(ms.m_pDerivedMesh, CD_MCOL); /* UNUSED */ + + // handle two-side + if (current_polymat->GetDrawingMode() & RAS_IRasterizer::KX_BACKCULL) + this->SetCullFace(true); else - m_storage->IndexPrimitivesMulti(ms); + this->SetCullFace(false); + + if (current_polymat->GetFlag() & RAS_BLENDERGLSL) { + // GetMaterialIndex return the original mface material index, + // increment by 1 to match what derived mesh is doing + current_blmat_nr = current_polymat->GetMaterialIndex()+1; + // For GLSL we need to retrieve the GPU material attribute + Material* blmat = current_polymat->GetBlenderMaterial(); + Scene* blscene = current_polymat->GetBlenderScene(); + if (!current_wireframe && blscene && blmat) + GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat, false), ¤t_gpu_attribs); + else + memset(¤t_gpu_attribs, 0, sizeof(current_gpu_attribs)); + // DM draw can mess up blending mode, restore at the end + int current_blend_mode = GPU_get_material_alpha_blend(); + ms.m_pDerivedMesh->drawFacesGLSL(ms.m_pDerivedMesh, CheckMaterialDM); + GPU_set_material_alpha_blend(current_blend_mode); + } else { + //ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol); + current_blmat_nr = current_polymat->GetMaterialIndex(); + current_image = current_polymat->GetBlenderImage(); + ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV); + } } void RAS_OpenGLRasterizer::SetProjectionMatrix(MT_CmMatrix4x4 &mat) @@ -1547,3 +1619,68 @@ void RAS_OpenGLRasterizer::SetAuxilaryClientInfo(void* inf) m_auxilaryClientInfo = inf; } +void RAS_OpenGLRasterizer::PrintHardwareInfo() +{ + #define pprint(x) std::cout << x << std::endl; + + pprint("GL_VENDOR: " << glGetString(GL_VENDOR)); + pprint("GL_RENDERER: " << glGetString(GL_RENDERER)); + pprint("GL_VERSION: " << glGetString(GL_VERSION)); + bool support=0; + pprint("Supported Extensions..."); + pprint(" GL_ARB_shader_objects supported? "<< (GLEW_ARB_shader_objects?"yes.":"no.")); + + support= GLEW_ARB_vertex_shader; + pprint(" GL_ARB_vertex_shader supported? "<< (support?"yes.":"no.")); + if (support) { + pprint(" ----------Details----------"); + int max=0; + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, (GLint*)&max); + pprint(" Max uniform components." << max); + + glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, (GLint*)&max); + pprint(" Max varying floats." << max); + + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max); + pprint(" Max vertex texture units." << max); + + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max); + pprint(" Max combined texture units." << max); + pprint(""); + } + + support=GLEW_ARB_fragment_shader; + pprint(" GL_ARB_fragment_shader supported? "<< (support?"yes.":"no.")); + if (support) { + pprint(" ----------Details----------"); + int max=0; + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, (GLint*)&max); + pprint(" Max uniform components." << max); + pprint(""); + } + + support = GLEW_ARB_texture_cube_map; + pprint(" GL_ARB_texture_cube_map supported? "<< (support?"yes.":"no.")); + if (support) { + pprint(" ----------Details----------"); + int size=0; + glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, (GLint*)&size); + pprint(" Max cubemap size." << size); + pprint(""); + } + + support = GLEW_ARB_multitexture; + pprint(" GL_ARB_multitexture supported? "<< (support?"yes.":"no.")); + if (support) { + pprint(" ----------Details----------"); + int units=0; + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&units); + pprint(" Max texture units available. " << units); + pprint(""); + } + + pprint(" GL_ARB_texture_env_combine supported? "<< (GLEW_ARB_texture_env_combine?"yes.":"no.")); + + pprint(" GL_ARB_texture_non_power_of_two supported " << (GPU_full_non_power_of_two_support()?"yes.":"no.")); +} + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h index 67a11f64726..1b012a61355 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h @@ -56,7 +56,6 @@ class RAS_OpenGLLight; enum RAS_STORAGE_TYPE { RAS_AUTO_STORAGE, - RAS_IMMEDIATE, RAS_VA, RAS_VBO, }; @@ -139,11 +138,10 @@ protected: * Examples of concrete strategies: Vertex Arrays, VBOs, Immediate Mode*/ int m_storage_type; RAS_IStorage *m_storage; - RAS_IStorage *m_failsafe_storage; /* So derived mesh can use immediate mode */ public: double GetTime(); - RAS_OpenGLRasterizer(RAS_ICanvas *canv, int storage=RAS_AUTO_STORAGE); + RAS_OpenGLRasterizer(RAS_ICanvas *canv, RAS_STORAGE_TYPE storage); virtual ~RAS_OpenGLRasterizer(); /*enum DrawType @@ -186,8 +184,8 @@ public: virtual void SwapBuffers(); virtual void IndexPrimitives(class RAS_MeshSlot &ms); - virtual void IndexPrimitivesMulti(class RAS_MeshSlot &ms); virtual void IndexPrimitives_3DText(class RAS_MeshSlot &ms, class RAS_IPolyMaterial *polymat); + virtual void DrawDerivedMesh(class RAS_MeshSlot &ms); virtual void SetProjectionMatrix(MT_CmMatrix4x4 &mat); virtual void SetProjectionMatrix(const MT_Matrix4x4 &mat); @@ -325,6 +323,10 @@ public: void SetAuxilaryClientInfo(void *inf); + /** + * Prints information about what the hardware supports. + */ + virtual void PrintHardwareInfo(); #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_OpenGLRasterizer") diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp deleted file mode 100644 index 2cf6088629a..00000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "RAS_StorageIM.h" -#include "RAS_MaterialBucket.h" -#include "RAS_IPolygonMaterial.h" - -#include "glew-mx.h" -#include "GPU_draw.h" -#include "GPU_extensions.h" -#include "GPU_material.h" - -extern "C"{ - #include "BKE_DerivedMesh.h" -} - -RAS_StorageIM::RAS_StorageIM(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer) : - m_drawingmode(RAS_IRasterizer::KX_TEXTURED), - m_texco_num(texco_num), - m_attrib_num(attrib_num), - m_texco(texco), - m_attrib(attrib), - m_attrib_layer(attrib_layer) -{ -} -RAS_StorageIM::~RAS_StorageIM() -{ -} - -bool RAS_StorageIM::Init() -{ - return true; -} -void RAS_StorageIM::Exit() -{ -} - -void RAS_StorageIM::IndexPrimitives(RAS_MeshSlot& ms) -{ - IndexPrimitivesInternal(ms, false); -} - -void RAS_StorageIM::IndexPrimitivesMulti(class RAS_MeshSlot& ms) -{ - IndexPrimitivesInternal(ms, true); -} - -void RAS_StorageIM::TexCoord(const RAS_TexVert &tv) -{ - int unit; - - if (GLEW_ARB_multitexture) { - for (unit = 0; unit < *m_texco_num; unit++) { - switch (m_texco[unit]) { - case RAS_IRasterizer::RAS_TEXCO_ORCO: - case RAS_IRasterizer::RAS_TEXCO_GLOB: - glMultiTexCoord3fvARB(GL_TEXTURE0_ARB + unit, tv.getXYZ()); - break; - case RAS_IRasterizer::RAS_TEXCO_UV: - glMultiTexCoord2fvARB(GL_TEXTURE0_ARB + unit, tv.getUV(unit)); - break; - case RAS_IRasterizer::RAS_TEXCO_NORM: - glMultiTexCoord3fvARB(GL_TEXTURE0_ARB + unit, tv.getNormal()); - break; - case RAS_IRasterizer::RAS_TEXTANGENT: - glMultiTexCoord4fvARB(GL_TEXTURE0_ARB + unit, tv.getTangent()); - break; - default: - break; - } - } - } - - if (GLEW_ARB_vertex_program) { - for (unit = 0; unit < *m_attrib_num; unit++) { - switch (m_attrib[unit]) { - case RAS_IRasterizer::RAS_TEXCO_ORCO: - case RAS_IRasterizer::RAS_TEXCO_GLOB: - glVertexAttrib3fvARB(unit, tv.getXYZ()); - break; - case RAS_IRasterizer::RAS_TEXCO_UV: - glVertexAttrib2fvARB(unit, tv.getUV(m_attrib_layer[unit])); - break; - case RAS_IRasterizer::RAS_TEXCO_NORM: - glVertexAttrib3fvARB(unit, tv.getNormal()); - break; - case RAS_IRasterizer::RAS_TEXTANGENT: - glVertexAttrib4fvARB(unit, tv.getTangent()); - break; - case RAS_IRasterizer::RAS_TEXCO_VCOL: - glVertexAttrib4ubvARB(unit, tv.getRGBA()); - break; - default: - break; - } - } - } - -} - -void RAS_StorageIM::SetCullFace(bool enable) -{ - if (enable) - glEnable(GL_CULL_FACE); - else - glDisable(GL_CULL_FACE); -} - -static bool current_wireframe; -static RAS_MaterialBucket *current_bucket; -static RAS_IPolyMaterial *current_polymat; -static RAS_MeshSlot *current_ms; -static RAS_MeshObject *current_mesh; -static int current_blmat_nr; -static GPUVertexAttribs current_gpu_attribs; -static Image *current_image; -static int CheckMaterialDM(int matnr, void *attribs) -{ - // only draw the current material - if (matnr != current_blmat_nr) - return 0; - GPUVertexAttribs *gattribs = (GPUVertexAttribs *)attribs; - if (gattribs) - memcpy(gattribs, ¤t_gpu_attribs, sizeof(GPUVertexAttribs)); - return 1; -} - -/* -static int CheckTexfaceDM(void *mcol, int index) -{ - - // index is the original face index, retrieve the polygon - RAS_Polygon* polygon = (index >= 0 && index < current_mesh->NumPolygons()) ? - current_mesh->GetPolygon(index) : NULL; - if (polygon && polygon->GetMaterial() == current_bucket) { - // must handle color. - if (current_wireframe) - return 2; - if (current_ms->m_bObjectColor) { - MT_Vector4& rgba = current_ms->m_RGBAcolor; - glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); - // don't use mcol - return 2; - } - if (!mcol) { - // we have to set the color from the material - unsigned char rgba[4]; - current_polymat->GetMaterialRGBAColor(rgba); - glColor4ubv((const GLubyte *)rgba); - return 2; - } - return 1; - } - return 0; -} -*/ - -static DMDrawOption CheckTexDM(MTexPoly *mtexpoly, const bool has_mcol, int matnr) -{ - - // index is the original face index, retrieve the polygon - if (matnr == current_blmat_nr && - (mtexpoly == NULL || mtexpoly->tpage == current_image)) { - // must handle color. - if (current_wireframe) - return DM_DRAW_OPTION_NO_MCOL; - if (current_ms->m_bObjectColor) { - MT_Vector4& rgba = current_ms->m_RGBAcolor; - glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); - // don't use mcol - return DM_DRAW_OPTION_NO_MCOL; - } - if (!has_mcol) { - // we have to set the color from the material - unsigned char rgba[4]; - current_polymat->GetMaterialRGBAColor(rgba); - glColor4ubv((const GLubyte *)rgba); - return DM_DRAW_OPTION_NO_MCOL; - } - return DM_DRAW_OPTION_NORMAL; - } - return DM_DRAW_OPTION_SKIP; -} - -void RAS_StorageIM::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi) -{ - bool obcolor = ms.m_bObjectColor; - bool wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME; - MT_Vector4& rgba = ms.m_RGBAcolor; - RAS_MeshSlot::iterator it; - - if (ms.m_pDerivedMesh) { - // mesh data is in derived mesh, - current_bucket = ms.m_bucket; - current_polymat = current_bucket->GetPolyMaterial(); - current_ms = &ms; - current_mesh = ms.m_mesh; - current_wireframe = wireframe; - // MCol *mcol = (MCol*)ms.m_pDerivedMesh->getFaceDataArray(ms.m_pDerivedMesh, CD_MCOL); /* UNUSED */ - - // handle two-side - if (current_polymat->GetDrawingMode() & RAS_IRasterizer::KX_BACKCULL) - this->SetCullFace(true); - else - this->SetCullFace(false); - - if (current_polymat->GetFlag() & RAS_BLENDERGLSL) { - // GetMaterialIndex return the original mface material index, - // increment by 1 to match what derived mesh is doing - current_blmat_nr = current_polymat->GetMaterialIndex()+1; - // For GLSL we need to retrieve the GPU material attribute - Material* blmat = current_polymat->GetBlenderMaterial(); - Scene* blscene = current_polymat->GetBlenderScene(); - if (!wireframe && blscene && blmat) - GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat, false), ¤t_gpu_attribs); - else - memset(¤t_gpu_attribs, 0, sizeof(current_gpu_attribs)); - // DM draw can mess up blending mode, restore at the end - int current_blend_mode = GPU_get_material_alpha_blend(); - ms.m_pDerivedMesh->drawFacesGLSL(ms.m_pDerivedMesh, CheckMaterialDM); - GPU_set_material_alpha_blend(current_blend_mode); - } else { - //ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol); - current_blmat_nr = current_polymat->GetMaterialIndex(); - current_image = current_polymat->GetBlenderImage(); - ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV); - } - return; - } - // iterate over display arrays, each containing an index + vertex array - for (ms.begin(it); !ms.end(it); ms.next(it)) { - RAS_TexVert *vertex; - size_t i, j, numvert; - - numvert = it.array->m_type; - - if (it.array->m_type == RAS_DisplayArray::LINE) { - // line drawing - glBegin(GL_LINES); - - for (i = 0; i < it.totindex; i += 2) - { - vertex = &it.vertex[it.index[i]]; - glVertex3fv(vertex->getXYZ()); - - vertex = &it.vertex[it.index[i+1]]; - glVertex3fv(vertex->getXYZ()); - } - - glEnd(); - } - else { - // triangle and quad drawing - if (it.array->m_type == RAS_DisplayArray::TRIANGLE) - glBegin(GL_TRIANGLES); - else - glBegin(GL_QUADS); - - for (i = 0; i < it.totindex; i += numvert) - { - if (obcolor) - glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); - - for (j = 0; j < numvert; j++) { - vertex = &it.vertex[it.index[i+j]]; - - if (!wireframe) { - if (!obcolor) - glColor4ubv((const GLubyte *)(vertex->getRGBA())); - - glNormal3fv(vertex->getNormal()); - - if (multi) - TexCoord(*vertex); - else - glTexCoord2fv(vertex->getUV(0)); - } - - glVertex3fv(vertex->getXYZ()); - } - } - - glEnd(); - } - } -} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h deleted file mode 100644 index 54ba2a57b61..00000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __KX_IMMEDIATEMODESTORAGE -#define __KX_IMMEDIATEMODESTORAGE - -#include "RAS_IStorage.h" -#include "RAS_IRasterizer.h" - -class RAS_StorageIM : public RAS_IStorage -{ -public: - RAS_StorageIM(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer); - virtual ~RAS_StorageIM(); - - virtual bool Init(); - virtual void Exit(); - - virtual void IndexPrimitives(RAS_MeshSlot& ms); - virtual void IndexPrimitivesMulti(class RAS_MeshSlot& ms); - - virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;}; - -protected: - int m_drawingmode; - int* m_texco_num; - int* m_attrib_num; - RAS_IRasterizer::TexCoGen* m_texco; - RAS_IRasterizer::TexCoGen* m_attrib; - int* m_attrib_layer; - - void TexCoord(const RAS_TexVert &tv); - void SetCullFace(bool enable); - - void IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi); - - -#ifdef WITH_CXX_GUARDEDALLOC -public: - void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_StorageIM"); } - void operator delete( void *mem ) { MEM_freeN(mem); } -#endif -}; - -#endif //__KX_IMMEDIATEMODESTORAGE diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp index c2980a6c15f..cf77ebfbeb9 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp @@ -56,68 +56,7 @@ void RAS_StorageVA::Exit() { } -void RAS_StorageVA::IndexPrimitives(RAS_MeshSlot& ms) -{ - static const GLsizei stride = sizeof(RAS_TexVert); - bool wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME; - RAS_MeshSlot::iterator it; - GLenum drawmode; - - if (!wireframe) - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - // use glDrawElements to draw each vertexarray - for (ms.begin(it); !ms.end(it); ms.next(it)) { - if (it.totindex == 0) - continue; - - // drawing mode - if (it.array->m_type == RAS_DisplayArray::TRIANGLE) - drawmode = GL_TRIANGLES; - else if (it.array->m_type == RAS_DisplayArray::QUAD) - drawmode = GL_QUADS; - else - drawmode = GL_LINES; - - // colors - if (drawmode != GL_LINES && !wireframe) { - if (ms.m_bObjectColor) { - const MT_Vector4& rgba = ms.m_RGBAcolor; - - glDisableClientState(GL_COLOR_ARRAY); - glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); - } - else { - glColor4f(0.0f, 0.0f, 0.0f, 1.0f); - glEnableClientState(GL_COLOR_ARRAY); - } - } - else - glColor4f(0.0f, 0.0f, 0.0f, 1.0f); - - glVertexPointer(3, GL_FLOAT, stride, it.vertex->getXYZ()); - glNormalPointer(GL_FLOAT, stride, it.vertex->getNormal()); - if (!wireframe) { - glTexCoordPointer(2, GL_FLOAT, stride, it.vertex->getUV(0)); - if (glIsEnabled(GL_COLOR_ARRAY)) - glColorPointer(4, GL_UNSIGNED_BYTE, stride, it.vertex->getRGBA()); - } - - // here the actual drawing takes places - glDrawElements(drawmode, it.totindex, GL_UNSIGNED_SHORT, it.index); - } - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - if (!wireframe) { - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - } -} - -void RAS_StorageVA::IndexPrimitivesMulti(class RAS_MeshSlot& ms) +void RAS_StorageVA::IndexPrimitives(class RAS_MeshSlot& ms) { static const GLsizei stride = sizeof(RAS_TexVert); bool wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME, use_color_array = true; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h index e4d00310a11..34fdca23ee6 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h @@ -44,7 +44,6 @@ public: virtual void Exit(); virtual void IndexPrimitives(RAS_MeshSlot& ms); - virtual void IndexPrimitivesMulti(class RAS_MeshSlot& ms); virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;}; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp index 58f3d4c05da..08d27cbc3fc 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp @@ -80,7 +80,7 @@ void VBO::UpdateIndices() &data->m_index[0], GL_STATIC_DRAW); } -void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer, bool multi) +void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer) { int unit; @@ -100,41 +100,32 @@ void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_UNSIGNED_BYTE, this->stride, this->color_offset); - if (multi) + for (unit = 0; unit < texco_num; ++unit) { - for (unit = 0; unit < texco_num; ++unit) - { - glClientActiveTexture(GL_TEXTURE0_ARB + unit); - switch (texco[unit]) { - case RAS_IRasterizer::RAS_TEXCO_ORCO: - case RAS_IRasterizer::RAS_TEXCO_GLOB: - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(3, GL_FLOAT, this->stride, this->vertex_offset); - break; - case RAS_IRasterizer::RAS_TEXCO_UV: - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, this->stride, (void*)((intptr_t)this->uv_offset+(sizeof(GLfloat)*2*unit))); - break; - case RAS_IRasterizer::RAS_TEXCO_NORM: - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(3, GL_FLOAT, this->stride, this->normal_offset); - break; - case RAS_IRasterizer::RAS_TEXTANGENT: - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(4, GL_FLOAT, this->stride, this->tangent_offset); - break; - default: - break; - } + glClientActiveTexture(GL_TEXTURE0_ARB + unit); + switch (texco[unit]) { + case RAS_IRasterizer::RAS_TEXCO_ORCO: + case RAS_IRasterizer::RAS_TEXCO_GLOB: + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(3, GL_FLOAT, this->stride, this->vertex_offset); + break; + case RAS_IRasterizer::RAS_TEXCO_UV: + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, this->stride, (void*)((intptr_t)this->uv_offset+(sizeof(GLfloat)*2*unit))); + break; + case RAS_IRasterizer::RAS_TEXCO_NORM: + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(3, GL_FLOAT, this->stride, this->normal_offset); + break; + case RAS_IRasterizer::RAS_TEXTANGENT: + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(4, GL_FLOAT, this->stride, this->tangent_offset); + break; + default: + break; } - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - else //TexFace - { - glClientActiveTextureARB(GL_TEXTURE0_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, this->stride, this->uv_offset); } + glClientActiveTextureARB(GL_TEXTURE0_ARB); if (GLEW_ARB_vertex_program) { @@ -163,7 +154,7 @@ void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, } } } - + glDrawElements(this->mode, this->indices, GL_UNSIGNED_SHORT, 0); glDisableClientState(GL_VERTEX_ARRAY); @@ -207,16 +198,6 @@ void RAS_StorageVBO::Exit() void RAS_StorageVBO::IndexPrimitives(RAS_MeshSlot& ms) { - IndexPrimitivesInternal(ms, false); -} - -void RAS_StorageVBO::IndexPrimitivesMulti(RAS_MeshSlot& ms) -{ - IndexPrimitivesInternal(ms, true); -} - -void RAS_StorageVBO::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi) -{ RAS_MeshSlot::iterator it; VBO *vbo; @@ -233,6 +214,6 @@ void RAS_StorageVBO::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi) vbo->UpdateData(); } - vbo->Draw(*m_texco_num, m_texco, *m_attrib_num, m_attrib, m_attrib_layer, multi); + vbo->Draw(*m_texco_num, m_texco, *m_attrib_num, m_attrib, m_attrib_layer); } } diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h index f156722247c..f78faa97b16 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h @@ -42,7 +42,7 @@ public: VBO(RAS_DisplayArray *data, unsigned int indices); ~VBO(); - void Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer, bool multi); + void Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer); void UpdateData(); void UpdateIndices(); @@ -73,7 +73,6 @@ public: virtual void Exit(); virtual void IndexPrimitives(RAS_MeshSlot& ms); - virtual void IndexPrimitivesMulti(RAS_MeshSlot& ms); virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;}; @@ -89,8 +88,6 @@ protected: std::map<RAS_DisplayArray*, class VBO*> m_vbo_lookup; - virtual void IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi); - #ifdef WITH_CXX_GUARDEDALLOC public: void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_StorageVA"); } diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp index 9585d8b0138..3bf11fbdfd6 100644 --- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp +++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp @@ -1024,11 +1024,11 @@ AVFrame *VideoFFmpeg::grabFrame(long position) AVFrame *input = m_frame; short counter = 0; - /* While the data is not read properly (png, tiffs, etc formats may need several pass)*/ - while ((input->data[0] == 0 && input->data[1] == 0 && input->data[2] == 0 && input->data[3] == 0) && counter < 10) { + /* If m_isImage, while the data is not read properly (png, tiffs, etc formats may need several pass), else don't need while loop*/ + do { avcodec_decode_video2(m_codecCtx, m_frame, &frameFinished, &packet); counter++; - } + } while ((input->data[0] == 0 && input->data[1] == 0 && input->data[2] == 0 && input->data[3] == 0) && counter < 10 && m_isImage); // remember dts to compute exact frame number dts = packet.dts; diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp index 30a8107b558..a62ffee3137 100644 --- a/source/gameengine/VideoTexture/blendVideoTex.cpp +++ b/source/gameengine/VideoTexture/blendVideoTex.cpp @@ -32,8 +32,6 @@ #include "KX_PythonInit.h" -#include <RAS_GLExtensionManager.h> - #include <RAS_IPolygonMaterial.h> //Old API diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt index e10d6b13b59..443d9b0e84b 100644 --- a/tests/gtests/blenlib/CMakeLists.txt +++ b/tests/gtests/blenlib/CMakeLists.txt @@ -37,11 +37,11 @@ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LIN BLENDER_TEST(BLI_stack "bf_blenlib") BLENDER_TEST(BLI_math_color "bf_blenlib") -BLENDER_TEST(BLI_math_geom "bf_blenlib;extern_eigen3") +BLENDER_TEST(BLI_math_geom "bf_blenlib;bf_intern_eigen") BLENDER_TEST(BLI_math_base "bf_blenlib") BLENDER_TEST(BLI_string "bf_blenlib") BLENDER_TEST(BLI_path_util "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}") -BLENDER_TEST(BLI_polyfill2d "bf_blenlib;extern_eigen3") +BLENDER_TEST(BLI_polyfill2d "bf_blenlib;bf_intern_eigen") BLENDER_TEST(BLI_listbase "bf_blenlib") BLENDER_TEST(BLI_hash_mm2a "bf_blenlib") BLENDER_TEST(BLI_ghash "bf_blenlib") diff --git a/tests/python/bl_pyapi_mathutils.py b/tests/python/bl_pyapi_mathutils.py index b7f61df0e40..7761b6cb7b1 100644 --- a/tests/python/bl_pyapi_mathutils.py +++ b/tests/python/bl_pyapi_mathutils.py @@ -240,17 +240,23 @@ class QuaternionTesting(unittest.TestCase): class KDTreeTesting(unittest.TestCase): - @staticmethod - def kdtree_create_grid_3d(tot): - k = kdtree.KDTree(tot * tot * tot) + def kdtree_create_grid_3d_data(tot): index = 0 mul = 1.0 / (tot - 1) for x in range(tot): for y in range(tot): for z in range(tot): - k.insert((x * mul, y * mul, z * mul), index) + yield (x * mul, y * mul, z * mul), index index += 1 + + @staticmethod + def kdtree_create_grid_3d(tot, *, filter_fn=None): + k = kdtree.KDTree(tot * tot * tot) + for co, index in KDTreeTesting.kdtree_create_grid_3d_data(tot): + if (filter_fn is not None) and (not filter_fn(co, index)): + continue + k.insert(co, index) k.balance() return k @@ -327,6 +333,49 @@ class KDTreeTesting(unittest.TestCase): ret = k.find_n((1.0,) * 3, tot) self.assertEqual(len(ret), tot) + def test_kdtree_grid_filter_simple(self): + size = 10 + k = self.kdtree_create_grid_3d(size) + + # filter exact index + ret_regular = k.find((1.0,) * 3) + ret_filter = k.find((1.0,) * 3, filter=lambda i: i == ret_regular[1]) + self.assertEqual(ret_regular, ret_filter) + ret_filter = k.find((-1.0,) * 3, filter=lambda i: i == ret_regular[1]) + self.assertEqual(ret_regular[:2], ret_filter[:2]) # ignore distance + + def test_kdtree_grid_filter_pairs(self): + size = 10 + k_all = self.kdtree_create_grid_3d(size) + k_odd = self.kdtree_create_grid_3d(size, filter_fn=lambda co, i: (i % 2) == 1) + k_evn = self.kdtree_create_grid_3d(size, filter_fn=lambda co, i: (i % 2) == 0) + + samples = 5 + mul = 1 / (samples - 1) + for x in range(samples): + for y in range(samples): + for z in range(samples): + co = (x * mul, y * mul, z * mul) + + ret_regular = k_odd.find(co) + self.assertEqual(ret_regular[1] % 2, 1) + ret_filter = k_all.find(co, lambda i: (i % 2) == 1) + self.assertEqual(ret_regular, ret_filter) + + ret_regular = k_evn.find(co) + self.assertEqual(ret_regular[1] % 2, 0) + ret_filter = k_all.find(co, lambda i: (i % 2) == 0) + self.assertEqual(ret_regular, ret_filter) + + + # filter out all values (search odd tree for even values and the reverse) + co = (0,) * 3 + ret_filter = k_odd.find(co, lambda i: (i % 2) == 0) + self.assertEqual(ret_filter[1], None) + + ret_filter = k_evn.find(co, lambda i: (i % 2) == 1) + self.assertEqual(ret_filter[1], None) + def test_kdtree_invalid_size(self): with self.assertRaises(ValueError): kdtree.KDTree(-1) @@ -342,6 +391,21 @@ class KDTreeTesting(unittest.TestCase): with self.assertRaises(RuntimeError): k.find(co) + def test_kdtree_invalid_filter(self): + k = kdtree.KDTree(1) + k.insert((0,) * 3, 0) + k.balance() + # not callable + with self.assertRaises(TypeError): + k.find((0,) * 3, filter=None) + # no args + with self.assertRaises(TypeError): + k.find((0,) * 3, filter=lambda: None) + # bad return value + with self.assertRaises(ValueError): + k.find((0,) * 3, filter=lambda i: None) + + if __name__ == '__main__': import sys sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) |