diff options
574 files changed, 13892 insertions, 8989 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 24201ae6869..ddfce0a48d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -901,6 +901,18 @@ if(NOT CMAKE_BUILD_TYPE MATCHES "Release") endif() endif() +# Test SIMD support, before platform includes to determine if sse2neon is needed. +if(WITH_CPU_SIMD) + set(COMPILER_SSE_FLAG) + set(COMPILER_SSE2_FLAG) + + # Test Neon first since macOS Arm can compile and run x86-64 SSE binaries. + TEST_NEON_SUPPORT() + if(NOT SUPPORT_NEON_BUILD) + TEST_SSE_SUPPORT(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG) + endif() +endif() + # ---------------------------------------------------------------------------- # Main Platform Checks # @@ -956,16 +968,11 @@ if(WITH_INTERNATIONAL) endif() endif() -# See TEST_SSE_SUPPORT() and TEST_NEON_SUPPORT() for how these are defined. +# Enable SIMD support if detected by TEST_SSE_SUPPORT() or TEST_NEON_SUPPORT(). # # This is done globally, so that all modules can use it if available, and # because these are used in headers used by many modules. if(WITH_CPU_SIMD) - set(COMPILER_SSE_FLAG) - set(COMPILER_SSE2_FLAG) - - # Test Neon first since macOS Arm can compile and run x86-64 SSE binaries. - TEST_NEON_SUPPORT() if(SUPPORT_NEON_BUILD) # Neon if(SSE2NEON_FOUND) @@ -974,7 +981,6 @@ if(WITH_CPU_SIMD) endif() else() # SSE - TEST_SSE_SUPPORT(COMPILER_SSE_FLAG COMPILER_SSE2_FLAG) if(SUPPORT_SSE_BUILD) string(PREPEND PLATFORM_CFLAGS "${COMPILER_SSE_FLAG} ") add_definitions(-D__SSE__ -D__MMX__) diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt index aa6b1cbe539..09dcc91ce08 100644 --- a/build_files/build_environment/CMakeLists.txt +++ b/build_files/build_environment/CMakeLists.txt @@ -31,6 +31,7 @@ # # MAC OS X USAGE: # Install with homebrew: brew install autoconf automake bison cmake libtool pkg-config yasm +# Additional requirements for macOS arm64: brew install flex # Run "make deps" from main Blender directory # # LINUX USAGE: diff --git a/build_files/build_environment/cmake/python.cmake b/build_files/build_environment/cmake/python.cmake index fa1498dda82..7e718d22805 100644 --- a/build_files/build_environment/cmake/python.cmake +++ b/build_files/build_environment/cmake/python.cmake @@ -81,8 +81,8 @@ else() # Link against zlib statically (Unix). Avoid rpath issues (macOS). set(PYTHON_PATCH ${PATCH_CMD} --verbose -p1 -d ${BUILD_DIR}/python/src/external_python < ${PATCH_DIR}/python_unix.diff) set(PYTHON_CONFIGURE_EXTRA_ARGS "--with-openssl=${LIBDIR}/ssl") - set(PYTHON_CFLAGS "-I${LIBDIR}/sqlite/include -I${LIBDIR}/bzip2/include -I${LIBDIR}/lzma/include -I${LIBDIR}/zlib/include") - set(PYTHON_LDFLAGS "-L${LIBDIR}/ffi/lib -L${LIBDIR}/sqlite/lib -L${LIBDIR}/bzip2/lib -L${LIBDIR}/lzma/lib -L${LIBDIR}/zlib/lib") + set(PYTHON_CFLAGS "-I${LIBDIR}/sqlite/include -I${LIBDIR}/bzip2/include -I${LIBDIR}/lzma/include -I${LIBDIR}/zlib/include ${PLATFORM_CFLAGS}") + set(PYTHON_LDFLAGS "-L${LIBDIR}/ffi/lib -L${LIBDIR}/sqlite/lib -L${LIBDIR}/bzip2/lib -L${LIBDIR}/lzma/lib -L${LIBDIR}/zlib/lib ${PLATFORM_LDFLAGS}") set(PYTHON_CONFIGURE_EXTRA_ENV export CFLAGS=${PYTHON_CFLAGS} && export CPPFLAGS=${PYTHON_CFLAGS} && diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index b8f92a10761..cad1d86b75a 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -682,11 +682,13 @@ macro(TEST_SSE_SUPPORT endmacro() macro(TEST_NEON_SUPPORT) - include(CheckCXXSourceCompiles) - check_cxx_source_compiles( - "#include <arm_neon.h> - int main() {return vaddvq_s32(vdupq_n_s32(1));}" - SUPPORT_NEON_BUILD) + if(NOT DEFINED SUPPORT_NEON_BUILD) + include(CheckCXXSourceCompiles) + check_cxx_source_compiles( + "#include <arm_neon.h> + int main() {return vaddvq_s32(vdupq_n_s32(1));}" + SUPPORT_NEON_BUILD) + endif() endmacro() # Only print message if running CMake first time diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 12a7a6c504f..be9261798f4 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -324,7 +324,7 @@ if(WITH_NANOVDB) find_package(NanoVDB) endif() -if(WITH_CPU_SIMD) +if(WITH_CPU_SIMD AND SUPPORT_NEON_BUILD) find_package(sse2neon) endif() diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index ef73ef40ac3..47c788c7eb6 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -285,7 +285,7 @@ if(WITH_NANOVDB) endif() endif() -if(WITH_CPU_SIMD) +if(WITH_CPU_SIMD AND SUPPORT_NEON_BUILD) find_package_wrapper(sse2neon) endif() diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 2b659de1cf8..5c6cf24a178 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -253,6 +253,7 @@ else: "gpu.select", "gpu.shader", "gpu.state", + "gpu.texture", "gpu_extras", "idprop.types", "mathutils", @@ -1981,10 +1982,11 @@ def write_rst_importable_modules(basepath): "imbuf.types": "Image Buffer Types", "gpu": "GPU Shader Module", "gpu.types": "GPU Types", - "gpu.matrix": "GPU Matrix", - "gpu.select": "GPU Select", - "gpu.shader": "GPU Shader", - "gpu.state": "GPU State", + "gpu.matrix": "GPU Matrix Utilities", + "gpu.select": "GPU Select Utilities", + "gpu.shader": "GPU Shader Utilities", + "gpu.state": "GPU State Utilities", + "gpu.texture": "GPU Texture Utilities", "bmesh": "BMesh Module", "bmesh.ops": "BMesh Operators", "bmesh.types": "BMesh Types", diff --git a/intern/clog/clog.c b/intern/clog/clog.c index 2bc3985c71f..a26ac10a61f 100644 --- a/intern/clog/clog.c +++ b/intern/clog/clog.c @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -38,8 +38,13 @@ #endif #if defined(_MSC_VER) +# include <Windows.h> + +# include <VersionHelpers.h> /* This needs to be included after Windows.h. */ # include <io.h> -# include <windows.h> +# if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) +# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +# endif #endif /* For printing timestamp. */ @@ -228,6 +233,9 @@ enum eCLogColor { #define COLOR_LEN (COLOR_RESET + 1) static const char *clg_color_table[COLOR_LEN] = {NULL}; +#ifdef _WIN32 +static DWORD clg_previous_console_mode = 0; +#endif static void clg_color_table_init(bool use_color) { @@ -548,13 +556,22 @@ static void CLG_ctx_output_set(CLogContext *ctx, void *file_handle) #if defined(__unix__) || defined(__APPLE__) ctx->use_color = isatty(ctx->output); #elif defined(WIN32) - /* Windows Terminal supports color like the Linux terminals do while the standard console does - * not, the way to tell the two apart is to look at the `WT_SESSION` environment variable which - * will only be defined for Windows Terminal. */ - - /* #getenv is used here rather than #BLI_getenv since it would be a bad level call - * and there are no benefits for using it in this context. */ - ctx->use_color = isatty(ctx->output) && getenv("WT_SESSION"); + /* As of Windows 10 build 18298 all the standard consoles supports color + * like the Linux Terminal do, but it needs to be turned on. + * To turn on colors we need to enable virtual terminal processing by passing the flag + * ENABLE_VIRTUAL_TERMINAL_PROCESSING into SetConsoleMode. + * If the system doesn't support virtual terminal processing it will fail silently and the flag + * will not be set. */ + + GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &clg_previous_console_mode); + + ctx->use_color = 0; + if (IsWindows10OrGreater() && isatty(ctx->output)) { + DWORD mode = clg_previous_console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if (SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), mode)) { + ctx->use_color = 1; + } + } #endif } @@ -638,6 +655,9 @@ static CLogContext *CLG_ctx_init(void) static void CLG_ctx_free(CLogContext *ctx) { +#if defined(WIN32) + SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), clg_previous_console_mode); +#endif while (ctx->types != NULL) { CLG_LogType *item = ctx->types; ctx->types = item->next; diff --git a/intern/cycles/bvh/bvh_binning.cpp b/intern/cycles/bvh/bvh_binning.cpp index d51143c578e..1cc38275d11 100644 --- a/intern/cycles/bvh/bvh_binning.cpp +++ b/intern/cycles/bvh/bvh_binning.cpp @@ -107,9 +107,9 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange &job, /* map geometry to bins, unrolled once */ { - ssize_t i; + int64_t i; - for (i = 0; i < ssize_t(size()) - 1; i += 2) { + for (i = 0; i < int64_t(size()) - 1; i += 2) { prefetch_L2(&prims[start() + i + 8]); /* map even and odd primitive to bin */ @@ -146,7 +146,7 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange &job, } /* for uneven number of primitives */ - if (i < ssize_t(size())) { + if (i < int64_t(size())) { /* map primitive to bin */ const BVHReference &prim0 = prims[start() + i]; BoundBox bounds0 = get_prim_bounds(prim0); @@ -237,7 +237,7 @@ void BVHObjectBinning::split(BVHReference *prims, BoundBox lcent_bounds = BoundBox::empty; BoundBox rcent_bounds = BoundBox::empty; - ssize_t l = 0, r = N - 1; + int64_t l = 0, r = N - 1; while (l <= r) { prefetch_L2(&prims[start() + l + 8]); diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h index ea3b78b7cef..da74d6aafac 100644 --- a/intern/cycles/kernel/kernel_compat_cuda.h +++ b/intern/cycles/kernel/kernel_compat_cuda.h @@ -41,6 +41,18 @@ typedef unsigned long long uint64_t; typedef unsigned short half; typedef unsigned long long CUtexObject; +//XXX fix compiler error on windows +#ifdef __CUDA_ARCH__ +static __device__ float myfloor(float f) { + float f2 = (float)((int)f); + f2 += (float)(f < 0.0f); + + return f2; +} + +#define floor myfloor +#endif + #ifdef CYCLES_CUBIN_CC # define FLT_MIN 1.175494350822287507969e-38f # define FLT_MAX 340282346638528859811704183484516925440.0f diff --git a/intern/cycles/util/util_logging.cpp b/intern/cycles/util/util_logging.cpp index e41250ab1b9..3782187d78c 100644 --- a/intern/cycles/util/util_logging.cpp +++ b/intern/cycles/util/util_logging.cpp @@ -46,17 +46,13 @@ void util_logging_init(const char *argv0) #ifdef WITH_CYCLES_LOGGING using CYCLES_GFLAGS_NAMESPACE::SetCommandLineOption; - /* Make it so ERROR messages are always print into console. */ - char severity_fatal[32]; - snprintf(severity_fatal, sizeof(severity_fatal), "%d", google::GLOG_ERROR); - google::InitGoogleLogging(argv0); SetCommandLineOption("logtostderr", "1"); if (!is_verbosity_set()) { SetCommandLineOption("v", "0"); } - SetCommandLineOption("stderrthreshold", severity_fatal); - SetCommandLineOption("minloglevel", severity_fatal); + SetCommandLineOption("stderrthreshold", "0"); + SetCommandLineOption("minloglevel", "0"); #else (void)argv0; #endif @@ -70,7 +66,7 @@ void util_logging_start() if (!is_verbosity_set()) { SetCommandLineOption("v", "2"); } - SetCommandLineOption("stderrthreshold", "1"); + SetCommandLineOption("stderrthreshold", "0"); SetCommandLineOption("minloglevel", "0"); #endif } diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm index ab76b78e6df..687173ded09 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.mm +++ b/intern/ghost/intern/GHOST_ContextCGL.mm @@ -278,7 +278,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() #ifdef GHOST_WAIT_FOR_VSYNC { GLint swapInt = 1; - /* wait for vsync, to avoid tearing artifacts */ + /* Wait for vertical-sync, to avoid tearing artifacts. */ [m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; } #endif diff --git a/intern/ghost/intern/GHOST_ImeWin32.h b/intern/ghost/intern/GHOST_ImeWin32.h index cd13ee1a8ae..0c851e067e8 100644 --- a/intern/ghost/intern/GHOST_ImeWin32.h +++ b/intern/ghost/intern/GHOST_ImeWin32.h @@ -296,7 +296,7 @@ class GHOST_ImeWin32 { * Disable the IME attached to the given window, i.e. prohibits any user-input * events from being dispatched to the IME. * In Chrome, this function is used when: - * * a rendeder process sets its input focus to a password input. + * * a renderer process sets its input focus to a password input. * Parameters * * window_handle [in] (HWND) * Represents the window handle of the caller. diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index f42d4af109a..4a23b30e078 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -80,7 +80,7 @@ static GHOST_TButtonMask convertButton(int button) } /** - * Converts Mac rawkey codes (same for Cocoa & Carbon) + * Converts Mac raw-key codes (same for Cocoa & Carbon) * into GHOST key codes * \param rawCode: The raw physical key code * \param recvChar: the character ignoring modifiers (except for shift) @@ -646,6 +646,11 @@ GHOST_TSuccess GHOST_SystemCocoa::init() [NSApp setDelegate:appDelegate]; } + // AppKit provides automatic window tabbing. Blender is a single-tabbed application without a + // macOS tab bar, and should explicitly opt-out of this. This is also controlled by the macOS + // user default #NSWindowTabbingEnabled. + NSWindow.allowsAutomaticWindowTabbing = NO; + [NSApp finishLaunching]; [pool drain]; diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index a7e325bc9e1..ed5e945f69e 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -34,9 +34,9 @@ #ifdef WITH_X11_XINPUT # include <X11/extensions/XInput.h> -/* Disable xinput warp, currently not implemented by Xorg for multi-head display. - * (see comment in xserver "Xi/xiwarppointer.c" -> "FIXME: panoramix stuff is missing" ~ v1.13.4) - * If this is supported we can add back xinput for warping (fixing T48901). +/* Disable XINPUT warp, currently not implemented by Xorg for multi-head display. + * (see comment in XSERVER `Xi/xiwarppointer.c` -> `FIXME: panoramix stuff is missing` ~ v1.13.4) + * If this is supported we can add back XINPUT for warping (fixing T48901). * For now disable (see T50383). */ // # define USE_X11_XINPUT_WARP #endif diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 73927317b24..add7962d924 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -336,11 +336,6 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa, backing:NSBackingStoreBuffered defer:NO]; - if (m_window == nil) { - [pool drain]; - return; - } - [m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; // Forbid to resize the window below the blender defined minimum one diff --git a/intern/ghost/intern/GHOST_WindowViewCocoa.h b/intern/ghost/intern/GHOST_WindowViewCocoa.h index 14c70382916..f47e02704b2 100644 --- a/intern/ghost/intern/GHOST_WindowViewCocoa.h +++ b/intern/ghost/intern/GHOST_WindowViewCocoa.h @@ -253,7 +253,7 @@ - (NSAttributedString *)attributedSubstringFromRange:(NSRange)range { - return [NSAttributedString new]; // XXX does this leak? + return [[[NSAttributedString alloc] init] autorelease]; } - (NSRange)markedRange @@ -284,7 +284,7 @@ - (NSArray *)validAttributesForMarkedText { - return [NSArray array]; // XXX does this leak? + return [NSArray array]; } @end diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 32672461873..eaa708f52b9 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -124,16 +124,11 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, { wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0); RECT win_rect = {left, top, (long)(left + width), (long)(top + height)}; - RECT parent_rect = {0, 0, 0, 0}; // Initialize tablet variables memset(&m_wintab, 0, sizeof(m_wintab)); m_tabletData = GHOST_TABLET_DATA_NONE; - if (parentwindow) { - GetWindowRect(m_parentWindowHwnd, &parent_rect); - } - DWORD style = parentwindow ? WS_POPUPWINDOW | WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX : WS_OVERLAPPEDWINDOW; @@ -156,9 +151,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, MONITORINFOEX monitor; monitor.cbSize = sizeof(MONITORINFOEX); monitor.dwFlags = 0; - GetMonitorInfo( - MonitorFromRect(parentwindow ? &parent_rect : &win_rect, MONITOR_DEFAULTTONEAREST), - &monitor); + GetMonitorInfo(MonitorFromRect(&win_rect, MONITOR_DEFAULTTONEAREST), &monitor); /* Adjust our requested size to allow for caption and borders and constrain to monitor. */ AdjustWindowRectEx(&win_rect, WS_CAPTION, FALSE, 0); @@ -1232,7 +1225,7 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap GHOST_TUns32 fullBitRow, fullMaskRow; int x, y, cols; - cols = sizeX / 8; /* Number of whole bytes per row (width of bm/mask). */ + cols = sizeX / 8; /* Number of whole bytes per row (width of bitmap/mask). */ if (sizeX % 8) cols++; diff --git a/intern/libmv/.clang-format b/intern/libmv/.clang-format index 9d159247d51..fae0530c572 100644 --- a/intern/libmv/.clang-format +++ b/intern/libmv/.clang-format @@ -1,2 +1,34 @@ -DisableFormat: true -SortIncludes: false +BasedOnStyle: Google + +ColumnLimit: 80 + +Standard: Cpp11 + +# Indent nested preprocessor. +# #ifdef Foo +# # include <nested> +# #endif +IndentPPDirectives: AfterHash + +# For the cases when namespace is closing with a wrong comment +FixNamespaceComments: true + +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortBlocksOnASingleLine: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true + +# No bin packing, every argument is on its own line. +BinPackArguments: false +BinPackParameters: false + +# Ensure pointer alignment. +# ObjectType* object; +PointerAlignment: Left +DerivePointerAlignment: false + +AlignEscapedNewlines: Right + +IncludeBlocks: Preserve +SortIncludes: true diff --git a/intern/libmv/intern/autotrack.cc b/intern/libmv/intern/autotrack.cc index 7000a422de8..b7110957b15 100644 --- a/intern/libmv/intern/autotrack.cc +++ b/intern/libmv/intern/autotrack.cc @@ -22,15 +22,15 @@ #include "intern/utildefines.h" #include "libmv/autotrack/autotrack.h" +using libmv::TrackRegionOptions; +using libmv::TrackRegionResult; using mv::AutoTrack; using mv::FrameAccessor; using mv::Marker; -using libmv::TrackRegionOptions; -using libmv::TrackRegionResult; -libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor *frame_accessor) { - return (libmv_AutoTrack*) LIBMV_OBJECT_NEW(AutoTrack, - (FrameAccessor*) frame_accessor); +libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* frame_accessor) { + return (libmv_AutoTrack*)LIBMV_OBJECT_NEW(AutoTrack, + (FrameAccessor*)frame_accessor); } void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack) { @@ -39,7 +39,7 @@ void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack) { void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack, const libmv_AutoTrackOptions* options) { - AutoTrack *autotrack = ((AutoTrack*) libmv_autotrack); + AutoTrack* autotrack = ((AutoTrack*)libmv_autotrack); libmv_configureTrackRegionOptions(options->track_region, &autotrack->options.track_region); @@ -51,18 +51,15 @@ void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack, int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack, const libmv_TrackRegionOptions* libmv_options, - libmv_Marker *libmv_tracked_marker, + libmv_Marker* libmv_tracked_marker, libmv_TrackRegionResult* libmv_result) { - Marker tracked_marker; TrackRegionOptions options; TrackRegionResult result; libmv_apiMarkerToMarker(*libmv_tracked_marker, &tracked_marker); - libmv_configureTrackRegionOptions(*libmv_options, - &options); - bool ok = (((AutoTrack*) libmv_autotrack)->TrackMarker(&tracked_marker, - &result, - &options)); + libmv_configureTrackRegionOptions(*libmv_options, &options); + bool ok = (((AutoTrack*)libmv_autotrack) + ->TrackMarker(&tracked_marker, &result, &options)); libmv_markerToApiMarker(tracked_marker, libmv_tracked_marker); libmv_regionTrackergetResult(result, libmv_result); return ok && result.is_usable(); @@ -72,7 +69,7 @@ void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack, const libmv_Marker* libmv_marker) { Marker marker; libmv_apiMarkerToMarker(*libmv_marker, &marker); - ((AutoTrack*) libmv_autotrack)->AddMarker(marker); + ((AutoTrack*)libmv_autotrack)->AddMarker(marker); } void libmv_autoTrackSetMarkers(libmv_AutoTrack* libmv_autotrack, @@ -87,19 +84,17 @@ void libmv_autoTrackSetMarkers(libmv_AutoTrack* libmv_autotrack, for (size_t i = 0; i < num_markers; ++i) { libmv_apiMarkerToMarker(libmv_marker[i], &markers[i]); } - ((AutoTrack*) libmv_autotrack)->SetMarkers(&markers); + ((AutoTrack*)libmv_autotrack)->SetMarkers(&markers); } int libmv_autoTrackGetMarker(libmv_AutoTrack* libmv_autotrack, int clip, int frame, int track, - libmv_Marker *libmv_marker) { + libmv_Marker* libmv_marker) { Marker marker; - int ok = ((AutoTrack*) libmv_autotrack)->GetMarker(clip, - frame, - track, - &marker); + int ok = + ((AutoTrack*)libmv_autotrack)->GetMarker(clip, frame, track, &marker); if (ok) { libmv_markerToApiMarker(marker, libmv_marker); } diff --git a/intern/libmv/intern/autotrack.h b/intern/libmv/intern/autotrack.h index 6b49a6908e1..3887983814b 100644 --- a/intern/libmv/intern/autotrack.h +++ b/intern/libmv/intern/autotrack.h @@ -21,9 +21,9 @@ #define LIBMV_C_API_AUTOTRACK_H_ #include "intern/frame_accessor.h" -#include "intern/tracksN.h" -#include "intern/track_region.h" #include "intern/region.h" +#include "intern/track_region.h" +#include "intern/tracksN.h" #ifdef __cplusplus extern "C" { @@ -36,7 +36,7 @@ typedef struct libmv_AutoTrackOptions { libmv_Region search_region; } libmv_AutoTrackOptions; -libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor *frame_accessor); +libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* frame_accessor); void libmv_autoTrackDestroy(libmv_AutoTrack* libmv_autotrack); @@ -45,7 +45,7 @@ void libmv_autoTrackSetOptions(libmv_AutoTrack* libmv_autotrack, int libmv_autoTrackMarker(libmv_AutoTrack* libmv_autotrack, const libmv_TrackRegionOptions* libmv_options, - libmv_Marker *libmv_tracker_marker, + libmv_Marker* libmv_tracker_marker, libmv_TrackRegionResult* libmv_result); void libmv_autoTrackAddMarker(libmv_AutoTrack* libmv_autotrack, @@ -59,7 +59,7 @@ int libmv_autoTrackGetMarker(libmv_AutoTrack* libmv_autotrack, int clip, int frame, int track, - libmv_Marker *libmv_marker); + libmv_Marker* libmv_marker); #ifdef __cplusplus } diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc index 628637e12cc..243b26d9fb3 100644 --- a/intern/libmv/intern/camera_intrinsics.cc +++ b/intern/libmv/intern/camera_intrinsics.cc @@ -21,62 +21,56 @@ #include "intern/utildefines.h" #include "libmv/simple_pipeline/camera_intrinsics.h" +using libmv::BrownCameraIntrinsics; using libmv::CameraIntrinsics; using libmv::DivisionCameraIntrinsics; -using libmv::PolynomialCameraIntrinsics; using libmv::NukeCameraIntrinsics; -using libmv::BrownCameraIntrinsics; +using libmv::PolynomialCameraIntrinsics; -libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( +libmv_CameraIntrinsics* libmv_cameraIntrinsicsNew( const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options) { - CameraIntrinsics *camera_intrinsics = - libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); - return (libmv_CameraIntrinsics *) camera_intrinsics; + CameraIntrinsics* camera_intrinsics = + libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); + return (libmv_CameraIntrinsics*)camera_intrinsics; } -libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( +libmv_CameraIntrinsics* libmv_cameraIntrinsicsCopy( const libmv_CameraIntrinsics* libmv_intrinsics) { - const CameraIntrinsics *orig_intrinsics = - (const CameraIntrinsics *) libmv_intrinsics; + const CameraIntrinsics* orig_intrinsics = + (const CameraIntrinsics*)libmv_intrinsics; - CameraIntrinsics *new_intrinsics = NULL; + CameraIntrinsics* new_intrinsics = NULL; switch (orig_intrinsics->GetDistortionModelType()) { - case libmv::DISTORTION_MODEL_POLYNOMIAL: - { - const PolynomialCameraIntrinsics *polynomial_intrinsics = + case libmv::DISTORTION_MODEL_POLYNOMIAL: { + const PolynomialCameraIntrinsics* polynomial_intrinsics = static_cast<const PolynomialCameraIntrinsics*>(orig_intrinsics); - new_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics, - *polynomial_intrinsics); - break; - } - case libmv::DISTORTION_MODEL_DIVISION: - { - const DivisionCameraIntrinsics *division_intrinsics = + new_intrinsics = + LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics, *polynomial_intrinsics); + break; + } + case libmv::DISTORTION_MODEL_DIVISION: { + const DivisionCameraIntrinsics* division_intrinsics = static_cast<const DivisionCameraIntrinsics*>(orig_intrinsics); - new_intrinsics = LIBMV_OBJECT_NEW(DivisionCameraIntrinsics, - *division_intrinsics); - break; - } - case libmv::DISTORTION_MODEL_NUKE: - { - const NukeCameraIntrinsics *nuke_intrinsics = + new_intrinsics = + LIBMV_OBJECT_NEW(DivisionCameraIntrinsics, *division_intrinsics); + break; + } + case libmv::DISTORTION_MODEL_NUKE: { + const NukeCameraIntrinsics* nuke_intrinsics = static_cast<const NukeCameraIntrinsics*>(orig_intrinsics); - new_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics, - *nuke_intrinsics); - break; - } - case libmv::DISTORTION_MODEL_BROWN: - { - const BrownCameraIntrinsics *brown_intrinsics = + new_intrinsics = LIBMV_OBJECT_NEW(NukeCameraIntrinsics, *nuke_intrinsics); + break; + } + case libmv::DISTORTION_MODEL_BROWN: { + const BrownCameraIntrinsics* brown_intrinsics = static_cast<const BrownCameraIntrinsics*>(orig_intrinsics); - new_intrinsics = LIBMV_OBJECT_NEW(BrownCameraIntrinsics, - *brown_intrinsics); - break; - } - default: - assert(!"Unknown distortion model"); + new_intrinsics = + LIBMV_OBJECT_NEW(BrownCameraIntrinsics, *brown_intrinsics); + break; + } + default: assert(!"Unknown distortion model"); } - return (libmv_CameraIntrinsics *) new_intrinsics; + return (libmv_CameraIntrinsics*)new_intrinsics; } void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics) { @@ -86,7 +80,7 @@ void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics) { void libmv_cameraIntrinsicsUpdate( const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, libmv_CameraIntrinsics* libmv_intrinsics) { - CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; + CameraIntrinsics* camera_intrinsics = (CameraIntrinsics*)libmv_intrinsics; double focal_length = libmv_camera_intrinsics_options->focal_length; double principal_x = libmv_camera_intrinsics_options->principal_point_x; @@ -115,191 +109,173 @@ void libmv_cameraIntrinsicsUpdate( } switch (libmv_camera_intrinsics_options->distortion_model) { - case LIBMV_DISTORTION_MODEL_POLYNOMIAL: - { - assert(camera_intrinsics->GetDistortionModelType() == - libmv::DISTORTION_MODEL_POLYNOMIAL); - - PolynomialCameraIntrinsics *polynomial_intrinsics = - (PolynomialCameraIntrinsics *) camera_intrinsics; - - double k1 = libmv_camera_intrinsics_options->polynomial_k1; - double k2 = libmv_camera_intrinsics_options->polynomial_k2; - double k3 = libmv_camera_intrinsics_options->polynomial_k3; - - if (polynomial_intrinsics->k1() != k1 || - polynomial_intrinsics->k2() != k2 || - polynomial_intrinsics->k3() != k3) { - polynomial_intrinsics->SetRadialDistortion(k1, k2, k3); - } - break; + case LIBMV_DISTORTION_MODEL_POLYNOMIAL: { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_POLYNOMIAL); + + PolynomialCameraIntrinsics* polynomial_intrinsics = + (PolynomialCameraIntrinsics*)camera_intrinsics; + + double k1 = libmv_camera_intrinsics_options->polynomial_k1; + double k2 = libmv_camera_intrinsics_options->polynomial_k2; + double k3 = libmv_camera_intrinsics_options->polynomial_k3; + + if (polynomial_intrinsics->k1() != k1 || + polynomial_intrinsics->k2() != k2 || + polynomial_intrinsics->k3() != k3) { + polynomial_intrinsics->SetRadialDistortion(k1, k2, k3); } + break; + } - case LIBMV_DISTORTION_MODEL_DIVISION: - { - assert(camera_intrinsics->GetDistortionModelType() == - libmv::DISTORTION_MODEL_DIVISION); + case LIBMV_DISTORTION_MODEL_DIVISION: { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_DIVISION); - DivisionCameraIntrinsics *division_intrinsics = - (DivisionCameraIntrinsics *) camera_intrinsics; + DivisionCameraIntrinsics* division_intrinsics = + (DivisionCameraIntrinsics*)camera_intrinsics; - double k1 = libmv_camera_intrinsics_options->division_k1; - double k2 = libmv_camera_intrinsics_options->division_k2; + double k1 = libmv_camera_intrinsics_options->division_k1; + double k2 = libmv_camera_intrinsics_options->division_k2; - if (division_intrinsics->k1() != k1 || - division_intrinsics->k2() != k2) { - division_intrinsics->SetDistortion(k1, k2); - } + if (division_intrinsics->k1() != k1 || division_intrinsics->k2() != k2) { + division_intrinsics->SetDistortion(k1, k2); + } - break; + break; + } + + case LIBMV_DISTORTION_MODEL_NUKE: { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_NUKE); + + NukeCameraIntrinsics* nuke_intrinsics = + (NukeCameraIntrinsics*)camera_intrinsics; + + double k1 = libmv_camera_intrinsics_options->nuke_k1; + double k2 = libmv_camera_intrinsics_options->nuke_k2; + + if (nuke_intrinsics->k1() != k1 || nuke_intrinsics->k2() != k2) { + nuke_intrinsics->SetDistortion(k1, k2); } - case LIBMV_DISTORTION_MODEL_NUKE: - { - assert(camera_intrinsics->GetDistortionModelType() == - libmv::DISTORTION_MODEL_NUKE); + break; + } - NukeCameraIntrinsics *nuke_intrinsics = - (NukeCameraIntrinsics *) camera_intrinsics; + case LIBMV_DISTORTION_MODEL_BROWN: { + assert(camera_intrinsics->GetDistortionModelType() == + libmv::DISTORTION_MODEL_BROWN); - double k1 = libmv_camera_intrinsics_options->nuke_k1; - double k2 = libmv_camera_intrinsics_options->nuke_k2; + BrownCameraIntrinsics* brown_intrinsics = + (BrownCameraIntrinsics*)camera_intrinsics; - if (nuke_intrinsics->k1() != k1 || - nuke_intrinsics->k2() != k2) { - nuke_intrinsics->SetDistortion(k1, k2); - } + double k1 = libmv_camera_intrinsics_options->brown_k1; + double k2 = libmv_camera_intrinsics_options->brown_k2; + double k3 = libmv_camera_intrinsics_options->brown_k3; + double k4 = libmv_camera_intrinsics_options->brown_k4; - break; + if (brown_intrinsics->k1() != k1 || brown_intrinsics->k2() != k2 || + brown_intrinsics->k3() != k3 || brown_intrinsics->k4() != k4) { + brown_intrinsics->SetRadialDistortion(k1, k2, k3, k4); } - case LIBMV_DISTORTION_MODEL_BROWN: - { - assert(camera_intrinsics->GetDistortionModelType() == - libmv::DISTORTION_MODEL_BROWN); - - BrownCameraIntrinsics *brown_intrinsics = - (BrownCameraIntrinsics *) camera_intrinsics; - - double k1 = libmv_camera_intrinsics_options->brown_k1; - double k2 = libmv_camera_intrinsics_options->brown_k2; - double k3 = libmv_camera_intrinsics_options->brown_k3; - double k4 = libmv_camera_intrinsics_options->brown_k4; - - if (brown_intrinsics->k1() != k1 || - brown_intrinsics->k2() != k2 || - brown_intrinsics->k3() != k3 || - brown_intrinsics->k4() != k4) { - brown_intrinsics->SetRadialDistortion(k1, k2, k3, k4); - } - - double p1 = libmv_camera_intrinsics_options->brown_p1; - double p2 = libmv_camera_intrinsics_options->brown_p2; - - if (brown_intrinsics->p1() != p1 || brown_intrinsics->p2() != p2) { - brown_intrinsics->SetTangentialDistortion(p1, p2); - } - break; + double p1 = libmv_camera_intrinsics_options->brown_p1; + double p2 = libmv_camera_intrinsics_options->brown_p2; + + if (brown_intrinsics->p1() != p1 || brown_intrinsics->p2() != p2) { + brown_intrinsics->SetTangentialDistortion(p1, p2); } + break; + } - default: - assert(!"Unknown distortion model"); + default: assert(!"Unknown distortion model"); } } void libmv_cameraIntrinsicsSetThreads(libmv_CameraIntrinsics* libmv_intrinsics, int threads) { - CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; + CameraIntrinsics* camera_intrinsics = (CameraIntrinsics*)libmv_intrinsics; camera_intrinsics->SetThreads(threads); } void libmv_cameraIntrinsicsExtractOptions( const libmv_CameraIntrinsics* libmv_intrinsics, libmv_CameraIntrinsicsOptions* camera_intrinsics_options) { - const CameraIntrinsics *camera_intrinsics = - (const CameraIntrinsics *) libmv_intrinsics; + const CameraIntrinsics* camera_intrinsics = + (const CameraIntrinsics*)libmv_intrinsics; // Fill in options which are common for all distortion models. camera_intrinsics_options->focal_length = camera_intrinsics->focal_length(); camera_intrinsics_options->principal_point_x = - camera_intrinsics->principal_point_x(); + camera_intrinsics->principal_point_x(); camera_intrinsics_options->principal_point_y = - camera_intrinsics->principal_point_y(); + camera_intrinsics->principal_point_y(); camera_intrinsics_options->image_width = camera_intrinsics->image_width(); camera_intrinsics_options->image_height = camera_intrinsics->image_height(); switch (camera_intrinsics->GetDistortionModelType()) { - case libmv::DISTORTION_MODEL_POLYNOMIAL: - { - const PolynomialCameraIntrinsics *polynomial_intrinsics = - static_cast<const PolynomialCameraIntrinsics *>(camera_intrinsics); - camera_intrinsics_options->distortion_model = + case libmv::DISTORTION_MODEL_POLYNOMIAL: { + const PolynomialCameraIntrinsics* polynomial_intrinsics = + static_cast<const PolynomialCameraIntrinsics*>(camera_intrinsics); + camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_POLYNOMIAL; - camera_intrinsics_options->polynomial_k1 = polynomial_intrinsics->k1(); - camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2(); - camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3(); - camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1(); - camera_intrinsics_options->polynomial_p2 = polynomial_intrinsics->p2(); - break; - } + camera_intrinsics_options->polynomial_k1 = polynomial_intrinsics->k1(); + camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2(); + camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3(); + camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1(); + camera_intrinsics_options->polynomial_p2 = polynomial_intrinsics->p2(); + break; + } - case libmv::DISTORTION_MODEL_DIVISION: - { - const DivisionCameraIntrinsics *division_intrinsics = - static_cast<const DivisionCameraIntrinsics *>(camera_intrinsics); - camera_intrinsics_options->distortion_model = + case libmv::DISTORTION_MODEL_DIVISION: { + const DivisionCameraIntrinsics* division_intrinsics = + static_cast<const DivisionCameraIntrinsics*>(camera_intrinsics); + camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_DIVISION; - camera_intrinsics_options->division_k1 = division_intrinsics->k1(); - camera_intrinsics_options->division_k2 = division_intrinsics->k2(); - break; - } - - case libmv::DISTORTION_MODEL_NUKE: - { - const NukeCameraIntrinsics *nuke_intrinsics = - static_cast<const NukeCameraIntrinsics *>(camera_intrinsics); - camera_intrinsics_options->distortion_model = - LIBMV_DISTORTION_MODEL_NUKE; - camera_intrinsics_options->nuke_k1 = nuke_intrinsics->k1(); - camera_intrinsics_options->nuke_k2 = nuke_intrinsics->k2(); - break; - } + camera_intrinsics_options->division_k1 = division_intrinsics->k1(); + camera_intrinsics_options->division_k2 = division_intrinsics->k2(); + break; + } + + case libmv::DISTORTION_MODEL_NUKE: { + const NukeCameraIntrinsics* nuke_intrinsics = + static_cast<const NukeCameraIntrinsics*>(camera_intrinsics); + camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_NUKE; + camera_intrinsics_options->nuke_k1 = nuke_intrinsics->k1(); + camera_intrinsics_options->nuke_k2 = nuke_intrinsics->k2(); + break; + } - case libmv::DISTORTION_MODEL_BROWN: - { - const BrownCameraIntrinsics *brown_intrinsics = - static_cast<const BrownCameraIntrinsics *>(camera_intrinsics); - camera_intrinsics_options->distortion_model = + case libmv::DISTORTION_MODEL_BROWN: { + const BrownCameraIntrinsics* brown_intrinsics = + static_cast<const BrownCameraIntrinsics*>(camera_intrinsics); + camera_intrinsics_options->distortion_model = LIBMV_DISTORTION_MODEL_BROWN; - camera_intrinsics_options->brown_k1 = brown_intrinsics->k1(); - camera_intrinsics_options->brown_k2 = brown_intrinsics->k2(); - camera_intrinsics_options->brown_k3 = brown_intrinsics->k3(); - camera_intrinsics_options->brown_k4 = brown_intrinsics->k4(); - camera_intrinsics_options->brown_p1 = brown_intrinsics->p1(); - camera_intrinsics_options->brown_p2 = brown_intrinsics->p2(); - break; - } + camera_intrinsics_options->brown_k1 = brown_intrinsics->k1(); + camera_intrinsics_options->brown_k2 = brown_intrinsics->k2(); + camera_intrinsics_options->brown_k3 = brown_intrinsics->k3(); + camera_intrinsics_options->brown_k4 = brown_intrinsics->k4(); + camera_intrinsics_options->brown_p1 = brown_intrinsics->p1(); + camera_intrinsics_options->brown_p2 = brown_intrinsics->p2(); + break; + } - default: - assert(!"Unknown distortion model"); + default: assert(!"Unknown distortion model"); } } void libmv_cameraIntrinsicsUndistortByte( const libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, + const unsigned char* source_image, int width, int height, float overscan, int channels, unsigned char* destination_image) { - CameraIntrinsics *camera_intrinsics = (CameraIntrinsics *) libmv_intrinsics; - camera_intrinsics->UndistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); + CameraIntrinsics* camera_intrinsics = (CameraIntrinsics*)libmv_intrinsics; + camera_intrinsics->UndistortBuffer( + source_image, width, height, overscan, channels, destination_image); } void libmv_cameraIntrinsicsUndistortFloat( @@ -310,28 +286,22 @@ void libmv_cameraIntrinsicsUndistortFloat( float overscan, int channels, float* destination_image) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; - intrinsics->UndistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); + CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics; + intrinsics->UndistortBuffer( + source_image, width, height, overscan, channels, destination_image); } void libmv_cameraIntrinsicsDistortByte( const struct libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, + const unsigned char* source_image, int width, int height, float overscan, int channels, - unsigned char *destination_image) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; - intrinsics->DistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); + unsigned char* destination_image) { + CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics; + intrinsics->DistortBuffer( + source_image, width, height, overscan, channels, destination_image); } void libmv_cameraIntrinsicsDistortFloat( @@ -342,12 +312,9 @@ void libmv_cameraIntrinsicsDistortFloat( float overscan, int channels, float* destination_image) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; - intrinsics->DistortBuffer(source_image, - width, height, - overscan, - channels, - destination_image); + CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics; + intrinsics->DistortBuffer( + source_image, width, height, overscan, channels, destination_image); } void libmv_cameraIntrinsicsApply( @@ -356,7 +323,7 @@ void libmv_cameraIntrinsicsApply( double y, double* x1, double* y1) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; + CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics; intrinsics->ApplyIntrinsics(x, y, x1, y1); } @@ -366,7 +333,7 @@ void libmv_cameraIntrinsicsInvert( double y, double* x1, double* y1) { - CameraIntrinsics *intrinsics = (CameraIntrinsics *) libmv_intrinsics; + CameraIntrinsics* intrinsics = (CameraIntrinsics*)libmv_intrinsics; intrinsics->InvertIntrinsics(x, y, x1, y1); } @@ -381,69 +348,63 @@ static void libmv_cameraIntrinsicsFillFromOptions( camera_intrinsics_options->principal_point_y); camera_intrinsics->SetImageSize(camera_intrinsics_options->image_width, - camera_intrinsics_options->image_height); + camera_intrinsics_options->image_height); switch (camera_intrinsics_options->distortion_model) { - case LIBMV_DISTORTION_MODEL_POLYNOMIAL: - { - PolynomialCameraIntrinsics *polynomial_intrinsics = + case LIBMV_DISTORTION_MODEL_POLYNOMIAL: { + PolynomialCameraIntrinsics* polynomial_intrinsics = static_cast<PolynomialCameraIntrinsics*>(camera_intrinsics); - polynomial_intrinsics->SetRadialDistortion( - camera_intrinsics_options->polynomial_k1, - camera_intrinsics_options->polynomial_k2, - camera_intrinsics_options->polynomial_k3); + polynomial_intrinsics->SetRadialDistortion( + camera_intrinsics_options->polynomial_k1, + camera_intrinsics_options->polynomial_k2, + camera_intrinsics_options->polynomial_k3); - break; - } + break; + } - case LIBMV_DISTORTION_MODEL_DIVISION: - { - DivisionCameraIntrinsics *division_intrinsics = + case LIBMV_DISTORTION_MODEL_DIVISION: { + DivisionCameraIntrinsics* division_intrinsics = static_cast<DivisionCameraIntrinsics*>(camera_intrinsics); - division_intrinsics->SetDistortion( - camera_intrinsics_options->division_k1, - camera_intrinsics_options->division_k2); - break; - } + division_intrinsics->SetDistortion( + camera_intrinsics_options->division_k1, + camera_intrinsics_options->division_k2); + break; + } - case LIBMV_DISTORTION_MODEL_NUKE: - { - NukeCameraIntrinsics *nuke_intrinsics = + case LIBMV_DISTORTION_MODEL_NUKE: { + NukeCameraIntrinsics* nuke_intrinsics = static_cast<NukeCameraIntrinsics*>(camera_intrinsics); - nuke_intrinsics->SetDistortion( - camera_intrinsics_options->nuke_k1, - camera_intrinsics_options->nuke_k2); - break; - } + nuke_intrinsics->SetDistortion(camera_intrinsics_options->nuke_k1, + camera_intrinsics_options->nuke_k2); + break; + } - case LIBMV_DISTORTION_MODEL_BROWN: - { - BrownCameraIntrinsics *brown_intrinsics = + case LIBMV_DISTORTION_MODEL_BROWN: { + BrownCameraIntrinsics* brown_intrinsics = static_cast<BrownCameraIntrinsics*>(camera_intrinsics); - brown_intrinsics->SetRadialDistortion( - camera_intrinsics_options->brown_k1, - camera_intrinsics_options->brown_k2, - camera_intrinsics_options->brown_k3, - camera_intrinsics_options->brown_k4); - brown_intrinsics->SetTangentialDistortion( + brown_intrinsics->SetRadialDistortion( + camera_intrinsics_options->brown_k1, + camera_intrinsics_options->brown_k2, + camera_intrinsics_options->brown_k3, + camera_intrinsics_options->brown_k4); + brown_intrinsics->SetTangentialDistortion( camera_intrinsics_options->brown_p1, camera_intrinsics_options->brown_p2); - break; - } + break; + } - default: - assert(!"Unknown distortion model"); + default: assert(!"Unknown distortion model"); } } CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( const libmv_CameraIntrinsicsOptions* camera_intrinsics_options) { - CameraIntrinsics *camera_intrinsics = NULL; + CameraIntrinsics* camera_intrinsics = NULL; switch (camera_intrinsics_options->distortion_model) { case LIBMV_DISTORTION_MODEL_POLYNOMIAL: camera_intrinsics = LIBMV_OBJECT_NEW(PolynomialCameraIntrinsics); @@ -457,8 +418,7 @@ CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( case LIBMV_DISTORTION_MODEL_BROWN: camera_intrinsics = LIBMV_OBJECT_NEW(BrownCameraIntrinsics); break; - default: - assert(!"Unknown distortion model"); + default: assert(!"Unknown distortion model"); } libmv_cameraIntrinsicsFillFromOptions(camera_intrinsics_options, camera_intrinsics); diff --git a/intern/libmv/intern/camera_intrinsics.h b/intern/libmv/intern/camera_intrinsics.h index eb6176770ec..8a65c93e6a4 100644 --- a/intern/libmv/intern/camera_intrinsics.h +++ b/intern/libmv/intern/camera_intrinsics.h @@ -56,10 +56,10 @@ typedef struct libmv_CameraIntrinsicsOptions { double brown_p1, brown_p2; } libmv_CameraIntrinsicsOptions; -libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( +libmv_CameraIntrinsics* libmv_cameraIntrinsicsNew( const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options); -libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( +libmv_CameraIntrinsics* libmv_cameraIntrinsicsCopy( const libmv_CameraIntrinsics* libmv_intrinsics); void libmv_cameraIntrinsicsDestroy(libmv_CameraIntrinsics* libmv_intrinsics); @@ -76,7 +76,7 @@ void libmv_cameraIntrinsicsExtractOptions( void libmv_cameraIntrinsicsUndistortByte( const libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, + const unsigned char* source_image, int width, int height, float overscan, @@ -94,12 +94,12 @@ void libmv_cameraIntrinsicsUndistortFloat( void libmv_cameraIntrinsicsDistortByte( const struct libmv_CameraIntrinsics* libmv_intrinsics, - const unsigned char *source_image, + const unsigned char* source_image, int width, int height, float overscan, int channels, - unsigned char *destination_image); + unsigned char* destination_image); void libmv_cameraIntrinsicsDistortFloat( const libmv_CameraIntrinsics* libmv_intrinsics, @@ -131,7 +131,7 @@ void libmv_cameraIntrinsicsInvert( #ifdef __cplusplus namespace libmv { - class CameraIntrinsics; +class CameraIntrinsics; } libmv::CameraIntrinsics* libmv_cameraIntrinsicsCreateFromOptions( diff --git a/intern/libmv/intern/detector.cc b/intern/libmv/intern/detector.cc index 455e431f6f4..21f5b46595c 100644 --- a/intern/libmv/intern/detector.cc +++ b/intern/libmv/intern/detector.cc @@ -34,7 +34,7 @@ struct libmv_Features { namespace { -libmv_Features *libmv_featuresFromVector( +libmv_Features* libmv_featuresFromVector( const libmv::vector<Feature>& features) { libmv_Features* libmv_features = LIBMV_STRUCT_NEW(libmv_Features, 1); int count = features.size(); @@ -50,12 +50,12 @@ libmv_Features *libmv_featuresFromVector( return libmv_features; } -void libmv_convertDetectorOptions(libmv_DetectOptions *options, - DetectOptions *detector_options) { +void libmv_convertDetectorOptions(libmv_DetectOptions* options, + DetectOptions* detector_options) { switch (options->detector) { -#define LIBMV_CONVERT(the_detector) \ - case LIBMV_DETECTOR_ ## the_detector: \ - detector_options->type = DetectOptions::the_detector; \ +#define LIBMV_CONVERT(the_detector) \ + case LIBMV_DETECTOR_##the_detector: \ + detector_options->type = DetectOptions::the_detector; \ break; LIBMV_CONVERT(FAST) LIBMV_CONVERT(MORAVEC) @@ -72,7 +72,7 @@ void libmv_convertDetectorOptions(libmv_DetectOptions *options, } // namespace -libmv_Features *libmv_detectFeaturesByte(const unsigned char* image_buffer, +libmv_Features* libmv_detectFeaturesByte(const unsigned char* image_buffer, int width, int height, int channels, @@ -133,7 +133,7 @@ void libmv_getFeature(const libmv_Features* libmv_features, double* y, double* score, double* size) { - Feature &feature = libmv_features->features[number]; + Feature& feature = libmv_features->features[number]; *x = feature.x; *y = feature.y; *score = feature.score; diff --git a/intern/libmv/intern/detector.h b/intern/libmv/intern/detector.h index b36935fc67f..f21e78d7f2b 100644 --- a/intern/libmv/intern/detector.h +++ b/intern/libmv/intern/detector.h @@ -38,7 +38,7 @@ typedef struct libmv_DetectOptions { int min_distance; int fast_min_trackness; int moravec_max_count; - unsigned char *moravec_pattern; + unsigned char* moravec_pattern; double harris_threshold; } libmv_DetectOptions; diff --git a/intern/libmv/intern/frame_accessor.cc b/intern/libmv/intern/frame_accessor.cc index 9fde73f0d71..3a6c753cc8d 100644 --- a/intern/libmv/intern/frame_accessor.cc +++ b/intern/libmv/intern/frame_accessor.cc @@ -36,20 +36,18 @@ struct LibmvFrameAccessor : public FrameAccessor { libmv_ReleaseImageCallback release_image_callback, libmv_GetMaskForTrackCallback get_mask_for_track_callback, libmv_ReleaseMaskCallback release_mask_callback) - : user_data_(user_data), - get_image_callback_(get_image_callback), - release_image_callback_(release_image_callback), - get_mask_for_track_callback_(get_mask_for_track_callback), - release_mask_callback_(release_mask_callback) { } + : user_data_(user_data), + get_image_callback_(get_image_callback), + release_image_callback_(release_image_callback), + get_mask_for_track_callback_(get_mask_for_track_callback), + release_mask_callback_(release_mask_callback) {} - virtual ~LibmvFrameAccessor() { - } + virtual ~LibmvFrameAccessor() {} libmv_InputMode get_libmv_input_mode(InputMode input_mode) { switch (input_mode) { -#define CHECK_INPUT_MODE(mode) \ - case mode: \ - return LIBMV_IMAGE_MODE_ ## mode; +#define CHECK_INPUT_MODE(mode) \ + case mode: return LIBMV_IMAGE_MODE_##mode; CHECK_INPUT_MODE(MONO) CHECK_INPUT_MODE(RGBA) #undef CHECK_INPUT_MODE @@ -59,8 +57,7 @@ struct LibmvFrameAccessor : public FrameAccessor { return LIBMV_IMAGE_MODE_MONO; } - void get_libmv_region(const Region& region, - libmv_Region* libmv_region) { + void get_libmv_region(const Region& region, libmv_Region* libmv_region) { libmv_region->min[0] = region.min(0); libmv_region->min[1] = region.min(1); libmv_region->max[0] = region.max(0); @@ -74,7 +71,7 @@ struct LibmvFrameAccessor : public FrameAccessor { const Region* region, const Transform* transform, FloatImage* destination) { - float *float_buffer; + float* float_buffer; int width, height, channels; libmv_Region libmv_region; if (region) { @@ -86,46 +83,41 @@ struct LibmvFrameAccessor : public FrameAccessor { get_libmv_input_mode(input_mode), downscale, region != NULL ? &libmv_region : NULL, - (libmv_FrameTransform*) transform, + (libmv_FrameTransform*)transform, &float_buffer, &width, &height, &channels); // TODO(sergey): Dumb code for until we can set data directly. - FloatImage temp_image(float_buffer, - height, - width, - channels); + FloatImage temp_image(float_buffer, height, width, channels); destination->CopyFrom(temp_image); return cache_key; } - void ReleaseImage(Key cache_key) { - release_image_callback_(cache_key); - } + void ReleaseImage(Key cache_key) { release_image_callback_(cache_key); } Key GetMaskForTrack(int clip, int frame, int track, const Region* region, FloatImage* destination) { - float *float_buffer; + float* float_buffer; int width, height; libmv_Region libmv_region; if (region) { get_libmv_region(*region, &libmv_region); } - Key cache_key = get_mask_for_track_callback_( - user_data_, - clip, - frame, - track, - region != NULL ? &libmv_region : NULL, - &float_buffer, - &width, - &height); + Key cache_key = + get_mask_for_track_callback_(user_data_, + clip, + frame, + track, + region != NULL ? &libmv_region : NULL, + &float_buffer, + &width, + &height); if (cache_key == NULL) { // No mask for the given track. @@ -133,30 +125,21 @@ struct LibmvFrameAccessor : public FrameAccessor { } // TODO(sergey): Dumb code for until we can set data directly. - FloatImage temp_image(float_buffer, - height, - width, - 1); + FloatImage temp_image(float_buffer, height, width, 1); destination->CopyFrom(temp_image); return cache_key; } - void ReleaseMask(Key key) { - release_mask_callback_(key); - } + void ReleaseMask(Key key) { release_mask_callback_(key); } - bool GetClipDimensions(int /*clip*/, int * /*width*/, int * /*height*/) { + bool GetClipDimensions(int /*clip*/, int* /*width*/, int* /*height*/) { return false; } - int NumClips() { - return 1; - } + int NumClips() { return 1; } - int NumFrames(int /*clip*/) { - return 0; - } + int NumFrames(int /*clip*/) { return 0; } libmv_FrameAccessorUserData* user_data_; libmv_GetImageCallback get_image_callback_; @@ -173,35 +156,35 @@ libmv_FrameAccessor* libmv_FrameAccessorNew( libmv_ReleaseImageCallback release_image_callback, libmv_GetMaskForTrackCallback get_mask_for_track_callback, libmv_ReleaseMaskCallback release_mask_callback) { - return (libmv_FrameAccessor*) LIBMV_OBJECT_NEW(LibmvFrameAccessor, - user_data, - get_image_callback, - release_image_callback, - get_mask_for_track_callback, - release_mask_callback); + return (libmv_FrameAccessor*)LIBMV_OBJECT_NEW(LibmvFrameAccessor, + user_data, + get_image_callback, + release_image_callback, + get_mask_for_track_callback, + release_mask_callback); } void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor) { LIBMV_OBJECT_DELETE(frame_accessor, LibmvFrameAccessor); } -int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform) { - return ((FrameAccessor::Transform*) transform)->key(); +int64_t libmv_frameAccessorgetTransformKey( + const libmv_FrameTransform* transform) { + return ((FrameAccessor::Transform*)transform)->key(); } -void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform, - const libmv_FloatImage *input_image, - libmv_FloatImage *output_image) { +void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* transform, + const libmv_FloatImage* input_image, + libmv_FloatImage* output_image) { const FloatImage input(input_image->buffer, input_image->height, input_image->width, input_image->channels); FloatImage output; - ((FrameAccessor::Transform*) transform)->run(input, - &output); + ((FrameAccessor::Transform*)transform)->run(input, &output); - int num_pixels = output.Width() *output.Height() * output.Depth(); + int num_pixels = output.Width() * output.Height() * output.Depth(); output_image->buffer = new float[num_pixels]; memcpy(output_image->buffer, output.Data(), num_pixels * sizeof(float)); output_image->width = output.Width(); diff --git a/intern/libmv/intern/frame_accessor.h b/intern/libmv/intern/frame_accessor.h index 6bccb305282..39a3bc5eb1d 100644 --- a/intern/libmv/intern/frame_accessor.h +++ b/intern/libmv/intern/frame_accessor.h @@ -32,14 +32,14 @@ extern "C" { typedef struct libmv_FrameAccessor libmv_FrameAccessor; typedef struct libmv_FrameTransform libmv_FrameTransform; typedef struct libmv_FrameAccessorUserData libmv_FrameAccessorUserData; -typedef void *libmv_CacheKey; +typedef void* libmv_CacheKey; typedef enum { LIBMV_IMAGE_MODE_MONO, LIBMV_IMAGE_MODE_RGBA, } libmv_InputMode; -typedef libmv_CacheKey (*libmv_GetImageCallback) ( +typedef libmv_CacheKey (*libmv_GetImageCallback)( libmv_FrameAccessorUserData* user_data, int clip, int frame, @@ -52,9 +52,9 @@ typedef libmv_CacheKey (*libmv_GetImageCallback) ( int* height, int* channels); -typedef void (*libmv_ReleaseImageCallback) (libmv_CacheKey cache_key); +typedef void (*libmv_ReleaseImageCallback)(libmv_CacheKey cache_key); -typedef libmv_CacheKey (*libmv_GetMaskForTrackCallback) ( +typedef libmv_CacheKey (*libmv_GetMaskForTrackCallback)( libmv_FrameAccessorUserData* user_data, int clip, int frame, @@ -63,7 +63,7 @@ typedef libmv_CacheKey (*libmv_GetMaskForTrackCallback) ( float** destination, int* width, int* height); -typedef void (*libmv_ReleaseMaskCallback) (libmv_CacheKey cache_key); +typedef void (*libmv_ReleaseMaskCallback)(libmv_CacheKey cache_key); libmv_FrameAccessor* libmv_FrameAccessorNew( libmv_FrameAccessorUserData* user_data, @@ -73,11 +73,12 @@ libmv_FrameAccessor* libmv_FrameAccessorNew( libmv_ReleaseMaskCallback release_mask_callback); void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor); -int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform); +int64_t libmv_frameAccessorgetTransformKey( + const libmv_FrameTransform* transform); -void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform *transform, - const libmv_FloatImage *input_image, - libmv_FloatImage *output_image); +void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* transform, + const libmv_FloatImage* input_image, + libmv_FloatImage* output_image); #ifdef __cplusplus } #endif diff --git a/intern/libmv/intern/homography.cc b/intern/libmv/intern/homography.cc index 179aeaa08aa..dc1009b5636 100644 --- a/intern/libmv/intern/homography.cc +++ b/intern/libmv/intern/homography.cc @@ -41,10 +41,8 @@ void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*x1)[2], LG << "x2: " << x2_mat; libmv::EstimateHomographyOptions options; - libmv::EstimateHomography2DFromCorrespondences(x1_mat, - x2_mat, - options, - &H_mat); + libmv::EstimateHomography2DFromCorrespondences( + x1_mat, x2_mat, options, &H_mat); LG << "H: " << H_mat; diff --git a/intern/libmv/intern/image.cc b/intern/libmv/intern/image.cc index a6e09277680..564e4762448 100644 --- a/intern/libmv/intern/image.cc +++ b/intern/libmv/intern/image.cc @@ -21,14 +21,14 @@ #include "intern/utildefines.h" #include "libmv/tracking/track_region.h" -#include <cassert> #include <png.h> +#include <cassert> using libmv::FloatImage; using libmv::SamplePlanarPatch; -void libmv_floatImageDestroy(libmv_FloatImage *image) { - delete [] image->buffer; +void libmv_floatImageDestroy(libmv_FloatImage* image) { + delete[] image->buffer; } /* Image <-> buffers conversion */ @@ -63,8 +63,7 @@ void libmv_floatBufferToFloatImage(const float* buffer, } } -void libmv_floatImageToFloatBuffer(const FloatImage &image, - float* buffer) { +void libmv_floatImageToFloatBuffer(const FloatImage& image, float* buffer) { for (int y = 0, a = 0; y < image.Height(); y++) { for (int x = 0; x < image.Width(); x++) { for (int k = 0; k < image.Depth(); k++) { @@ -74,9 +73,9 @@ void libmv_floatImageToFloatBuffer(const FloatImage &image, } } -void libmv_floatImageToByteBuffer(const libmv::FloatImage &image, +void libmv_floatImageToByteBuffer(const libmv::FloatImage& image, unsigned char* buffer) { - for (int y = 0, a= 0; y < image.Height(); y++) { + for (int y = 0, a = 0; y < image.Height(); y++) { for (int x = 0; x < image.Width(); x++) { for (int k = 0; k < image.Depth(); k++) { buffer[a++] = image(y, x, k) * 255.0f; @@ -93,7 +92,7 @@ static bool savePNGImage(png_bytep* row_pointers, const char* file_name) { png_infop info_ptr; png_structp png_ptr; - FILE *fp = fopen(file_name, "wb"); + FILE* fp = fopen(file_name, "wb"); if (fp == NULL) { return false; @@ -153,7 +152,7 @@ bool libmv_saveImage(const FloatImage& image, int x0, int y0) { int x, y; - png_bytep *row_pointers; + png_bytep* row_pointers; assert(image.Depth() == 1); @@ -180,9 +179,8 @@ bool libmv_saveImage(const FloatImage& image, static int image_counter = 0; char file_name[128]; - snprintf(file_name, sizeof(file_name), - "%s_%02d.png", - prefix, ++image_counter); + snprintf( + file_name, sizeof(file_name), "%s_%02d.png", prefix, ++image_counter); bool result = savePNGImage(row_pointers, image.Width(), image.Height(), @@ -191,9 +189,9 @@ bool libmv_saveImage(const FloatImage& image, file_name); for (y = 0; y < image.Height(); y++) { - delete [] row_pointers[y]; + delete[] row_pointers[y]; } - delete [] row_pointers; + delete[] row_pointers; return result; } @@ -211,7 +209,7 @@ void libmv_samplePlanarPatchFloat(const float* image, double* warped_position_x, double* warped_position_y) { FloatImage libmv_image, libmv_patch, libmv_mask; - FloatImage *libmv_mask_for_sample = NULL; + FloatImage* libmv_mask_for_sample = NULL; libmv_floatBufferToFloatImage(image, width, height, channels, &libmv_image); @@ -221,8 +219,10 @@ void libmv_samplePlanarPatchFloat(const float* image, } SamplePlanarPatch(libmv_image, - xs, ys, - num_samples_x, num_samples_y, + xs, + ys, + num_samples_x, + num_samples_y, libmv_mask_for_sample, &libmv_patch, warped_position_x, @@ -232,19 +232,19 @@ void libmv_samplePlanarPatchFloat(const float* image, } void libmv_samplePlanarPatchByte(const unsigned char* image, - int width, - int height, - int channels, - const double* xs, - const double* ys, - int num_samples_x, - int num_samples_y, - const float* mask, - unsigned char* patch, - double* warped_position_x, - double* warped_position_y) { + int width, + int height, + int channels, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + const float* mask, + unsigned char* patch, + double* warped_position_x, + double* warped_position_y) { libmv::FloatImage libmv_image, libmv_patch, libmv_mask; - libmv::FloatImage *libmv_mask_for_sample = NULL; + libmv::FloatImage* libmv_mask_for_sample = NULL; libmv_byteBufferToFloatImage(image, width, height, channels, &libmv_image); @@ -254,8 +254,10 @@ void libmv_samplePlanarPatchByte(const unsigned char* image, } libmv::SamplePlanarPatch(libmv_image, - xs, ys, - num_samples_x, num_samples_y, + xs, + ys, + num_samples_x, + num_samples_y, libmv_mask_for_sample, &libmv_patch, warped_position_x, diff --git a/intern/libmv/intern/image.h b/intern/libmv/intern/image.h index a1381a4c216..02cef86a127 100644 --- a/intern/libmv/intern/image.h +++ b/intern/libmv/intern/image.h @@ -35,7 +35,7 @@ void libmv_floatBufferToFloatImage(const float* buffer, libmv::FloatImage* image); void libmv_floatImageToFloatBuffer(const libmv::FloatImage& image, - float *buffer); + float* buffer); void libmv_floatImageToByteBuffer(const libmv::FloatImage& image, unsigned char* buffer); @@ -51,13 +51,13 @@ extern "C" { #endif typedef struct libmv_FloatImage { - float *buffer; + float* buffer; int width; int height; int channels; } libmv_FloatImage; -void libmv_floatImageDestroy(libmv_FloatImage *image); +void libmv_floatImageDestroy(libmv_FloatImage* image); void libmv_samplePlanarPatchFloat(const float* image, int width, @@ -72,18 +72,18 @@ void libmv_samplePlanarPatchFloat(const float* image, double* warped_position_x, double* warped_position_y); - void libmv_samplePlanarPatchByte(const unsigned char* image, - int width, - int height, - int channels, - const double* xs, - const double* ys, - int num_samples_x, - int num_samples_y, - const float* mask, - unsigned char* patch, - double* warped_position_x, - double* warped_position_y); +void libmv_samplePlanarPatchByte(const unsigned char* image, + int width, + int height, + int channels, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + const float* mask, + unsigned char* patch, + double* warped_position_x, + double* warped_position_y); #ifdef __cplusplus } diff --git a/intern/libmv/intern/logging.cc b/intern/libmv/intern/logging.cc index 350be29d4db..a8c7e93880d 100644 --- a/intern/libmv/intern/logging.cc +++ b/intern/libmv/intern/logging.cc @@ -35,16 +35,13 @@ static bool is_verbosity_set() { void libmv_initLogging(const char* argv0) { using LIBMV_GFLAGS_NAMESPACE::SetCommandLineOption; - // Make it so ERROR messages are always print into console. - char severity_fatal[32]; - snprintf(severity_fatal, sizeof(severity_fatal), "%d", - google::GLOG_ERROR); google::InitGoogleLogging(argv0); + SetCommandLineOption("logtostderr", "1"); if (!is_verbosity_set()) { SetCommandLineOption("v", "0"); } - SetCommandLineOption("stderrthreshold", severity_fatal); - SetCommandLineOption("minloglevel", severity_fatal); + SetCommandLineOption("stderrthreshold", "0"); + SetCommandLineOption("minloglevel", "0"); } void libmv_startDebugLogging(void) { @@ -53,7 +50,7 @@ void libmv_startDebugLogging(void) { if (!is_verbosity_set()) { SetCommandLineOption("v", "2"); } - SetCommandLineOption("stderrthreshold", "1"); + SetCommandLineOption("stderrthreshold", "0"); SetCommandLineOption("minloglevel", "0"); } diff --git a/intern/libmv/intern/reconstruction.cc b/intern/libmv/intern/reconstruction.cc index 0f4e890d4ca..430607461da 100644 --- a/intern/libmv/intern/reconstruction.cc +++ b/intern/libmv/intern/reconstruction.cc @@ -24,8 +24,8 @@ #include "libmv/logging/logging.h" #include "libmv/simple_pipeline/bundle.h" -#include "libmv/simple_pipeline/keyframe_selection.h" #include "libmv/simple_pipeline/initialize_reconstruction.h" +#include "libmv/simple_pipeline/keyframe_selection.h" #include "libmv/simple_pipeline/modal_solver.h" #include "libmv/simple_pipeline/pipeline.h" #include "libmv/simple_pipeline/reconstruction_scale.h" @@ -39,19 +39,19 @@ using libmv::EuclideanScaleToUnity; using libmv::Marker; using libmv::ProgressUpdateCallback; -using libmv::PolynomialCameraIntrinsics; -using libmv::Tracks; using libmv::EuclideanBundle; using libmv::EuclideanCompleteReconstruction; using libmv::EuclideanReconstructTwoFrames; using libmv::EuclideanReprojectionError; +using libmv::PolynomialCameraIntrinsics; +using libmv::Tracks; struct libmv_Reconstruction { EuclideanReconstruction reconstruction; /* Used for per-track average error calculation after reconstruction */ Tracks tracks; - CameraIntrinsics *intrinsics; + CameraIntrinsics* intrinsics; double error; bool is_valid; @@ -63,7 +63,7 @@ class ReconstructUpdateCallback : public ProgressUpdateCallback { public: ReconstructUpdateCallback( reconstruct_progress_update_cb progress_update_callback, - void *callback_customdata) { + void* callback_customdata) { progress_update_callback_ = progress_update_callback; callback_customdata_ = callback_customdata; } @@ -73,13 +73,14 @@ class ReconstructUpdateCallback : public ProgressUpdateCallback { progress_update_callback_(callback_customdata_, progress, message); } } + protected: reconstruct_progress_update_cb progress_update_callback_; void* callback_customdata_; }; void libmv_solveRefineIntrinsics( - const Tracks &tracks, + const Tracks& tracks, const int refine_intrinsics, const int bundle_constraints, reconstruct_progress_update_cb progress_update_callback, @@ -96,11 +97,11 @@ void libmv_solveRefineIntrinsics( bundle_intrinsics |= libmv::BUNDLE_PRINCIPAL_POINT; } -#define SET_DISTORTION_FLAG_CHECKED(type, coefficient) \ - do { \ - if (refine_intrinsics & LIBMV_REFINE_ ## type ##_DISTORTION_ ## coefficient) { \ - bundle_intrinsics |= libmv::BUNDLE_ ## type ## _ ## coefficient; \ - } \ +#define SET_DISTORTION_FLAG_CHECKED(type, coefficient) \ + do { \ + if (refine_intrinsics & LIBMV_REFINE_##type##_DISTORTION_##coefficient) { \ + bundle_intrinsics |= libmv::BUNDLE_##type##_##coefficient; \ + } \ } while (0) SET_DISTORTION_FLAG_CHECKED(RADIAL, K1); @@ -123,20 +124,19 @@ void libmv_solveRefineIntrinsics( } void finishReconstruction( - const Tracks &tracks, - const CameraIntrinsics &camera_intrinsics, - libmv_Reconstruction *libmv_reconstruction, + const Tracks& tracks, + const CameraIntrinsics& camera_intrinsics, + libmv_Reconstruction* libmv_reconstruction, reconstruct_progress_update_cb progress_update_callback, - void *callback_customdata) { - EuclideanReconstruction &reconstruction = - libmv_reconstruction->reconstruction; + void* callback_customdata) { + EuclideanReconstruction& reconstruction = + libmv_reconstruction->reconstruction; /* Reprojection error calculation. */ progress_update_callback(callback_customdata, 1.0, "Finishing solution"); libmv_reconstruction->tracks = tracks; - libmv_reconstruction->error = EuclideanReprojectionError(tracks, - reconstruction, - camera_intrinsics); + libmv_reconstruction->error = + EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics); } bool selectTwoKeyframesBasedOnGRICAndVariance( @@ -148,9 +148,8 @@ bool selectTwoKeyframesBasedOnGRICAndVariance( libmv::vector<int> keyframes; /* Get list of all keyframe candidates first. */ - SelectKeyframesBasedOnGRICAndVariance(normalized_tracks, - camera_intrinsics, - keyframes); + SelectKeyframesBasedOnGRICAndVariance( + normalized_tracks, camera_intrinsics, keyframes); if (keyframes.size() < 2) { LG << "Not enough keyframes detected by GRIC"; @@ -175,24 +174,20 @@ bool selectTwoKeyframesBasedOnGRICAndVariance( EuclideanReconstruction reconstruction; int current_keyframe = keyframes[i]; libmv::vector<Marker> keyframe_markers = - normalized_tracks.MarkersForTracksInBothImages(previous_keyframe, - current_keyframe); + normalized_tracks.MarkersForTracksInBothImages(previous_keyframe, + current_keyframe); Tracks keyframe_tracks(keyframe_markers); /* get a solution from two keyframes only */ EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction); EuclideanBundle(keyframe_tracks, &reconstruction); - EuclideanCompleteReconstruction(keyframe_tracks, - &reconstruction, - NULL); + EuclideanCompleteReconstruction(keyframe_tracks, &reconstruction, NULL); - double current_error = EuclideanReprojectionError(tracks, - reconstruction, - camera_intrinsics); + double current_error = + EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics); - LG << "Error between " << previous_keyframe - << " and " << current_keyframe + LG << "Error between " << previous_keyframe << " and " << current_keyframe << ": " << current_error; if (current_error < best_error) { @@ -214,53 +209,49 @@ Marker libmv_projectMarker(const EuclideanPoint& point, projected /= projected(2); libmv::Marker reprojected_marker; - intrinsics.ApplyIntrinsics(projected(0), projected(1), - &reprojected_marker.x, - &reprojected_marker.y); + intrinsics.ApplyIntrinsics( + projected(0), projected(1), &reprojected_marker.x, &reprojected_marker.y); reprojected_marker.image = camera.image; reprojected_marker.track = point.track; return reprojected_marker; } -void libmv_getNormalizedTracks(const Tracks &tracks, - const CameraIntrinsics &camera_intrinsics, - Tracks *normalized_tracks) { +void libmv_getNormalizedTracks(const Tracks& tracks, + const CameraIntrinsics& camera_intrinsics, + Tracks* normalized_tracks) { libmv::vector<Marker> markers = tracks.AllMarkers(); for (int i = 0; i < markers.size(); ++i) { - Marker &marker = markers[i]; - camera_intrinsics.InvertIntrinsics(marker.x, marker.y, - &marker.x, &marker.y); - normalized_tracks->Insert(marker.image, - marker.track, - marker.x, marker.y, - marker.weight); + Marker& marker = markers[i]; + camera_intrinsics.InvertIntrinsics( + marker.x, marker.y, &marker.x, &marker.y); + normalized_tracks->Insert( + marker.image, marker.track, marker.x, marker.y, marker.weight); } } } // namespace -libmv_Reconstruction *libmv_solveReconstruction( +libmv_Reconstruction* libmv_solveReconstruction( const libmv_Tracks* libmv_tracks, const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, libmv_ReconstructionOptions* libmv_reconstruction_options, reconstruct_progress_update_cb progress_update_callback, void* callback_customdata) { - libmv_Reconstruction *libmv_reconstruction = - LIBMV_OBJECT_NEW(libmv_Reconstruction); + libmv_Reconstruction* libmv_reconstruction = + LIBMV_OBJECT_NEW(libmv_Reconstruction); - Tracks &tracks = *((Tracks *) libmv_tracks); - EuclideanReconstruction &reconstruction = - libmv_reconstruction->reconstruction; + Tracks& tracks = *((Tracks*)libmv_tracks); + EuclideanReconstruction& reconstruction = + libmv_reconstruction->reconstruction; ReconstructUpdateCallback update_callback = - ReconstructUpdateCallback(progress_update_callback, - callback_customdata); + ReconstructUpdateCallback(progress_update_callback, callback_customdata); /* Retrieve reconstruction options from C-API to libmv API. */ - CameraIntrinsics *camera_intrinsics; + CameraIntrinsics* camera_intrinsics; camera_intrinsics = libmv_reconstruction->intrinsics = - libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); + libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); /* Invert the camera intrinsics/ */ Tracks normalized_tracks; @@ -276,10 +267,10 @@ libmv_Reconstruction *libmv_solveReconstruction( update_callback.invoke(0, "Selecting keyframes"); if (selectTwoKeyframesBasedOnGRICAndVariance(tracks, - normalized_tracks, - *camera_intrinsics, - keyframe1, - keyframe2)) { + normalized_tracks, + *camera_intrinsics, + keyframe1, + keyframe2)) { /* so keyframes in the interface would be updated */ libmv_reconstruction_options->keyframe1 = keyframe1; libmv_reconstruction_options->keyframe2 = keyframe2; @@ -290,7 +281,7 @@ libmv_Reconstruction *libmv_solveReconstruction( LG << "frames to init from: " << keyframe1 << " " << keyframe2; libmv::vector<Marker> keyframe_markers = - normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2); + normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2); LG << "number of markers for init: " << keyframe_markers.size(); @@ -309,14 +300,12 @@ libmv_Reconstruction *libmv_solveReconstruction( } EuclideanBundle(normalized_tracks, &reconstruction); - EuclideanCompleteReconstruction(normalized_tracks, - &reconstruction, - &update_callback); + EuclideanCompleteReconstruction( + normalized_tracks, &reconstruction, &update_callback); /* Refinement. */ if (libmv_reconstruction_options->refine_intrinsics) { - libmv_solveRefineIntrinsics( - tracks, + libmv_solveRefineIntrinsics(tracks, libmv_reconstruction_options->refine_intrinsics, libmv::BUNDLE_NO_CONSTRAINTS, progress_update_callback, @@ -336,31 +325,29 @@ libmv_Reconstruction *libmv_solveReconstruction( callback_customdata); libmv_reconstruction->is_valid = true; - return (libmv_Reconstruction *) libmv_reconstruction; + return (libmv_Reconstruction*)libmv_reconstruction; } -libmv_Reconstruction *libmv_solveModal( - const libmv_Tracks *libmv_tracks, - const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options, - const libmv_ReconstructionOptions *libmv_reconstruction_options, +libmv_Reconstruction* libmv_solveModal( + const libmv_Tracks* libmv_tracks, + const libmv_CameraIntrinsicsOptions* libmv_camera_intrinsics_options, + const libmv_ReconstructionOptions* libmv_reconstruction_options, reconstruct_progress_update_cb progress_update_callback, - void *callback_customdata) { - libmv_Reconstruction *libmv_reconstruction = - LIBMV_OBJECT_NEW(libmv_Reconstruction); + void* callback_customdata) { + libmv_Reconstruction* libmv_reconstruction = + LIBMV_OBJECT_NEW(libmv_Reconstruction); - Tracks &tracks = *((Tracks *) libmv_tracks); - EuclideanReconstruction &reconstruction = - libmv_reconstruction->reconstruction; + Tracks& tracks = *((Tracks*)libmv_tracks); + EuclideanReconstruction& reconstruction = + libmv_reconstruction->reconstruction; ReconstructUpdateCallback update_callback = - ReconstructUpdateCallback(progress_update_callback, - callback_customdata); + ReconstructUpdateCallback(progress_update_callback, callback_customdata); /* Retrieve reconstruction options from C-API to libmv API. */ - CameraIntrinsics *camera_intrinsics; + CameraIntrinsics* camera_intrinsics; camera_intrinsics = libmv_reconstruction->intrinsics = - libmv_cameraIntrinsicsCreateFromOptions( - libmv_camera_intrinsics_options); + libmv_cameraIntrinsicsCreateFromOptions(libmv_camera_intrinsics_options); /* Invert the camera intrinsics. */ Tracks normalized_tracks; @@ -378,11 +365,11 @@ libmv_Reconstruction *libmv_solveModal( /* Refinement. */ if (libmv_reconstruction_options->refine_intrinsics) { - libmv_solveRefineIntrinsics( - tracks, + libmv_solveRefineIntrinsics(tracks, libmv_reconstruction_options->refine_intrinsics, libmv::BUNDLE_NO_TRANSLATION, - progress_update_callback, callback_customdata, + progress_update_callback, + callback_customdata, &reconstruction, camera_intrinsics); } @@ -395,26 +382,25 @@ libmv_Reconstruction *libmv_solveModal( callback_customdata); libmv_reconstruction->is_valid = true; - return (libmv_Reconstruction *) libmv_reconstruction; + return (libmv_Reconstruction*)libmv_reconstruction; } -int libmv_reconstructionIsValid(libmv_Reconstruction *libmv_reconstruction) { +int libmv_reconstructionIsValid(libmv_Reconstruction* libmv_reconstruction) { return libmv_reconstruction->is_valid; } -void libmv_reconstructionDestroy(libmv_Reconstruction *libmv_reconstruction) { +void libmv_reconstructionDestroy(libmv_Reconstruction* libmv_reconstruction) { LIBMV_OBJECT_DELETE(libmv_reconstruction->intrinsics, CameraIntrinsics); LIBMV_OBJECT_DELETE(libmv_reconstruction, libmv_Reconstruction); } int libmv_reprojectionPointForTrack( - const libmv_Reconstruction *libmv_reconstruction, + const libmv_Reconstruction* libmv_reconstruction, int track, double pos[3]) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const EuclideanPoint *point = - reconstruction->PointForTrack(track); + const EuclideanReconstruction* reconstruction = + &libmv_reconstruction->reconstruction; + const EuclideanPoint* point = reconstruction->PointForTrack(track); if (point) { pos[0] = point->X[0]; pos[1] = point->X[2]; @@ -425,23 +411,22 @@ int libmv_reprojectionPointForTrack( } double libmv_reprojectionErrorForTrack( - const libmv_Reconstruction *libmv_reconstruction, - int track) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const CameraIntrinsics *intrinsics = libmv_reconstruction->intrinsics; + const libmv_Reconstruction* libmv_reconstruction, int track) { + const EuclideanReconstruction* reconstruction = + &libmv_reconstruction->reconstruction; + const CameraIntrinsics* intrinsics = libmv_reconstruction->intrinsics; libmv::vector<Marker> markers = - libmv_reconstruction->tracks.MarkersForTrack(track); + libmv_reconstruction->tracks.MarkersForTrack(track); int num_reprojected = 0; double total_error = 0.0; for (int i = 0; i < markers.size(); ++i) { double weight = markers[i].weight; - const EuclideanCamera *camera = - reconstruction->CameraForImage(markers[i].image); - const EuclideanPoint *point = - reconstruction->PointForTrack(markers[i].track); + const EuclideanCamera* camera = + reconstruction->CameraForImage(markers[i].image); + const EuclideanPoint* point = + reconstruction->PointForTrack(markers[i].track); if (!camera || !point || weight == 0.0) { continue; @@ -450,7 +435,7 @@ double libmv_reprojectionErrorForTrack( num_reprojected++; Marker reprojected_marker = - libmv_projectMarker(*point, *camera, *intrinsics); + libmv_projectMarker(*point, *camera, *intrinsics); double ex = (reprojected_marker.x - markers[i].x) * weight; double ey = (reprojected_marker.y - markers[i].y) * weight; @@ -461,14 +446,13 @@ double libmv_reprojectionErrorForTrack( } double libmv_reprojectionErrorForImage( - const libmv_Reconstruction *libmv_reconstruction, - int image) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const CameraIntrinsics *intrinsics = libmv_reconstruction->intrinsics; + const libmv_Reconstruction* libmv_reconstruction, int image) { + const EuclideanReconstruction* reconstruction = + &libmv_reconstruction->reconstruction; + const CameraIntrinsics* intrinsics = libmv_reconstruction->intrinsics; libmv::vector<Marker> markers = - libmv_reconstruction->tracks.MarkersInImage(image); - const EuclideanCamera *camera = reconstruction->CameraForImage(image); + libmv_reconstruction->tracks.MarkersInImage(image); + const EuclideanCamera* camera = reconstruction->CameraForImage(image); int num_reprojected = 0; double total_error = 0.0; @@ -477,8 +461,8 @@ double libmv_reprojectionErrorForImage( } for (int i = 0; i < markers.size(); ++i) { - const EuclideanPoint *point = - reconstruction->PointForTrack(markers[i].track); + const EuclideanPoint* point = + reconstruction->PointForTrack(markers[i].track); if (!point) { continue; @@ -487,7 +471,7 @@ double libmv_reprojectionErrorForImage( num_reprojected++; Marker reprojected_marker = - libmv_projectMarker(*point, *camera, *intrinsics); + libmv_projectMarker(*point, *camera, *intrinsics); double ex = (reprojected_marker.x - markers[i].x) * markers[i].weight; double ey = (reprojected_marker.y - markers[i].y) * markers[i].weight; @@ -498,13 +482,12 @@ double libmv_reprojectionErrorForImage( } int libmv_reprojectionCameraForImage( - const libmv_Reconstruction *libmv_reconstruction, + const libmv_Reconstruction* libmv_reconstruction, int image, double mat[4][4]) { - const EuclideanReconstruction *reconstruction = - &libmv_reconstruction->reconstruction; - const EuclideanCamera *camera = - reconstruction->CameraForImage(image); + const EuclideanReconstruction* reconstruction = + &libmv_reconstruction->reconstruction; + const EuclideanCamera* camera = reconstruction->CameraForImage(image); if (camera) { for (int j = 0; j < 3; ++j) { @@ -541,11 +524,11 @@ int libmv_reprojectionCameraForImage( } double libmv_reprojectionError( - const libmv_Reconstruction *libmv_reconstruction) { + const libmv_Reconstruction* libmv_reconstruction) { return libmv_reconstruction->error; } -libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics( - libmv_Reconstruction *libmv_reconstruction) { - return (libmv_CameraIntrinsics *) libmv_reconstruction->intrinsics; +libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics( + libmv_Reconstruction* libmv_reconstruction) { + return (libmv_CameraIntrinsics*)libmv_reconstruction->intrinsics; } diff --git a/intern/libmv/intern/reconstruction.h b/intern/libmv/intern/reconstruction.h index 408ac884684..600bc92ccfc 100644 --- a/intern/libmv/intern/reconstruction.h +++ b/intern/libmv/intern/reconstruction.h @@ -31,17 +31,16 @@ struct libmv_CameraIntrinsicsOptions; typedef struct libmv_Reconstruction libmv_Reconstruction; enum { - LIBMV_REFINE_FOCAL_LENGTH = (1 << 0), - LIBMV_REFINE_PRINCIPAL_POINT = (1 << 1), - - LIBMV_REFINE_RADIAL_DISTORTION_K1 = (1 << 2), - LIBMV_REFINE_RADIAL_DISTORTION_K2 = (1 << 3), - LIBMV_REFINE_RADIAL_DISTORTION_K3 = (1 << 4), - LIBMV_REFINE_RADIAL_DISTORTION_K4 = (1 << 5), - LIBMV_REFINE_RADIAL_DISTORTION = (LIBMV_REFINE_RADIAL_DISTORTION_K1 | - LIBMV_REFINE_RADIAL_DISTORTION_K2 | - LIBMV_REFINE_RADIAL_DISTORTION_K3 | - LIBMV_REFINE_RADIAL_DISTORTION_K4), + LIBMV_REFINE_FOCAL_LENGTH = (1 << 0), + LIBMV_REFINE_PRINCIPAL_POINT = (1 << 1), + + LIBMV_REFINE_RADIAL_DISTORTION_K1 = (1 << 2), + LIBMV_REFINE_RADIAL_DISTORTION_K2 = (1 << 3), + LIBMV_REFINE_RADIAL_DISTORTION_K3 = (1 << 4), + LIBMV_REFINE_RADIAL_DISTORTION_K4 = (1 << 5), + LIBMV_REFINE_RADIAL_DISTORTION = + (LIBMV_REFINE_RADIAL_DISTORTION_K1 | LIBMV_REFINE_RADIAL_DISTORTION_K2 | + LIBMV_REFINE_RADIAL_DISTORTION_K3 | LIBMV_REFINE_RADIAL_DISTORTION_K4), LIBMV_REFINE_TANGENTIAL_DISTORTION_P1 = (1 << 6), LIBMV_REFINE_TANGENTIAL_DISTORTION_P2 = (1 << 7), @@ -55,9 +54,9 @@ typedef struct libmv_ReconstructionOptions { int refine_intrinsics; } libmv_ReconstructionOptions; -typedef void (*reconstruct_progress_update_cb) (void* customdata, - double progress, - const char* message); +typedef void (*reconstruct_progress_update_cb)(void* customdata, + double progress, + const char* message); libmv_Reconstruction* libmv_solveReconstruction( const struct libmv_Tracks* libmv_tracks, @@ -73,35 +72,32 @@ libmv_Reconstruction* libmv_solveModal( reconstruct_progress_update_cb progress_update_callback, void* callback_customdata); -int libmv_reconstructionIsValid(libmv_Reconstruction *libmv_reconstruction); +int libmv_reconstructionIsValid(libmv_Reconstruction* libmv_reconstruction); void libmv_reconstructionDestroy(libmv_Reconstruction* libmv_reconstruction); int libmv_reprojectionPointForTrack( - const libmv_Reconstruction* libmv_reconstruction, - int track, - double pos[3]); + const libmv_Reconstruction* libmv_reconstruction, int track, double pos[3]); double libmv_reprojectionErrorForTrack( - const libmv_Reconstruction* libmv_reconstruction, - int track); + const libmv_Reconstruction* libmv_reconstruction, int track); double libmv_reprojectionErrorForImage( - const libmv_Reconstruction* libmv_reconstruction, - int image); + const libmv_Reconstruction* libmv_reconstruction, int image); int libmv_reprojectionCameraForImage( const libmv_Reconstruction* libmv_reconstruction, int image, double mat[4][4]); -double libmv_reprojectionError(const libmv_Reconstruction* libmv_reconstruction); +double libmv_reprojectionError( + const libmv_Reconstruction* libmv_reconstruction); struct libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics( - libmv_Reconstruction *libmv_Reconstruction); + libmv_Reconstruction* libmv_Reconstruction); #ifdef __cplusplus } #endif -#endif // LIBMV_C_API_RECONSTRUCTION_H_ +#endif // LIBMV_C_API_RECONSTRUCTION_H_ diff --git a/intern/libmv/intern/stub.cc b/intern/libmv/intern/stub.cc index 47e1896b4cf..1920042b4ec 100644 --- a/intern/libmv/intern/stub.cc +++ b/intern/libmv/intern/stub.cc @@ -24,7 +24,7 @@ /* ************ Logging ************ */ -void libmv_initLogging(const char * /*argv0*/) { +void libmv_initLogging(const char* /*argv0*/) { } void libmv_startDebugLogging(void) { @@ -36,18 +36,18 @@ void libmv_setLoggingVerbosity(int /*verbosity*/) { /* ************ Planar tracker ************ */ /* TrackRegion (new planar tracker) */ -int libmv_trackRegion(const libmv_TrackRegionOptions * /*options*/, - const float * /*image1*/, +int libmv_trackRegion(const libmv_TrackRegionOptions* /*options*/, + const float* /*image1*/, int /*image1_width*/, int /*image1_height*/, - const float * /*image2*/, + const float* /*image2*/, int /*image2_width*/, int /*image2_height*/, - const double *x1, - const double *y1, - libmv_TrackRegionResult *result, - double *x2, - double *y2) { + const double* x1, + const double* y1, + libmv_TrackRegionResult* result, + double* x2, + double* y2) { /* Convert to doubles for the libmv api. The four corners and the center. */ for (int i = 0; i < 5; ++i) { x2[i] = x1[i]; @@ -61,46 +61,46 @@ int libmv_trackRegion(const libmv_TrackRegionOptions * /*options*/, return false; } -void libmv_samplePlanarPatchFloat(const float * /*image*/, +void libmv_samplePlanarPatchFloat(const float* /*image*/, int /*width*/, int /*height*/, int /*channels*/, - const double * /*xs*/, - const double * /*ys*/, + const double* /*xs*/, + const double* /*ys*/, int /*num_samples_x*/, int /*num_samples_y*/, - const float * /*mask*/, - float * /*patch*/, - double * /*warped_position_x*/, - double * /*warped_position_y*/) { + const float* /*mask*/, + float* /*patch*/, + double* /*warped_position_x*/, + double* /*warped_position_y*/) { /* TODO(sergey): implement */ } -void libmv_samplePlanarPatchByte(const unsigned char * /*image*/, +void libmv_samplePlanarPatchByte(const unsigned char* /*image*/, int /*width*/, int /*height*/, int /*channels*/, - const double * /*xs*/, - const double * /*ys*/, - int /*num_samples_x*/, int /*num_samples_y*/, - const float * /*mask*/, - unsigned char * /*patch*/, - double * /*warped_position_x*/, - double * /*warped_position_y*/) { + const double* /*xs*/, + const double* /*ys*/, + int /*num_samples_x*/, + int /*num_samples_y*/, + const float* /*mask*/, + unsigned char* /*patch*/, + double* /*warped_position_x*/, + double* /*warped_position_y*/) { /* TODO(sergey): implement */ } -void libmv_floatImageDestroy(libmv_FloatImage* /*image*/) -{ +void libmv_floatImageDestroy(libmv_FloatImage* /*image*/) { } /* ************ Tracks ************ */ -libmv_Tracks *libmv_tracksNew(void) { +libmv_Tracks* libmv_tracksNew(void) { return NULL; } -void libmv_tracksInsert(libmv_Tracks * /*libmv_tracks*/, +void libmv_tracksInsert(libmv_Tracks* /*libmv_tracks*/, int /*image*/, int /*track*/, double /*x*/, @@ -108,152 +108,152 @@ void libmv_tracksInsert(libmv_Tracks * /*libmv_tracks*/, double /*weight*/) { } -void libmv_tracksDestroy(libmv_Tracks * /*libmv_tracks*/) { +void libmv_tracksDestroy(libmv_Tracks* /*libmv_tracks*/) { } /* ************ Reconstruction solver ************ */ -libmv_Reconstruction *libmv_solveReconstruction( - const libmv_Tracks * /*libmv_tracks*/, - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, - libmv_ReconstructionOptions * /*libmv_reconstruction_options*/, +libmv_Reconstruction* libmv_solveReconstruction( + const libmv_Tracks* /*libmv_tracks*/, + const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/, + libmv_ReconstructionOptions* /*libmv_reconstruction_options*/, reconstruct_progress_update_cb /*progress_update_callback*/, - void * /*callback_customdata*/) { + void* /*callback_customdata*/) { return NULL; } -libmv_Reconstruction *libmv_solveModal( - const libmv_Tracks * /*libmv_tracks*/, - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, - const libmv_ReconstructionOptions * /*libmv_reconstruction_options*/, +libmv_Reconstruction* libmv_solveModal( + const libmv_Tracks* /*libmv_tracks*/, + const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/, + const libmv_ReconstructionOptions* /*libmv_reconstruction_options*/, reconstruct_progress_update_cb /*progress_update_callback*/, - void * /*callback_customdata*/) { + void* /*callback_customdata*/) { return NULL; } -int libmv_reconstructionIsValid(libmv_Reconstruction * /*libmv_reconstruction*/) { +int libmv_reconstructionIsValid( + libmv_Reconstruction* /*libmv_reconstruction*/) { return 0; } int libmv_reprojectionPointForTrack( - const libmv_Reconstruction * /*libmv_reconstruction*/, + const libmv_Reconstruction* /*libmv_reconstruction*/, int /*track*/, double /*pos*/[3]) { return 0; } double libmv_reprojectionErrorForTrack( - const libmv_Reconstruction * /*libmv_reconstruction*/, - int /*track*/) { + const libmv_Reconstruction* /*libmv_reconstruction*/, int /*track*/) { return 0.0; } double libmv_reprojectionErrorForImage( - const libmv_Reconstruction * /*libmv_reconstruction*/, - int /*image*/) { + const libmv_Reconstruction* /*libmv_reconstruction*/, int /*image*/) { return 0.0; } int libmv_reprojectionCameraForImage( - const libmv_Reconstruction * /*libmv_reconstruction*/, + const libmv_Reconstruction* /*libmv_reconstruction*/, int /*image*/, double /*mat*/[4][4]) { return 0; } double libmv_reprojectionError( - const libmv_Reconstruction * /*libmv_reconstruction*/) { + const libmv_Reconstruction* /*libmv_reconstruction*/) { return 0.0; } void libmv_reconstructionDestroy( - struct libmv_Reconstruction * /*libmv_reconstruction*/) { + struct libmv_Reconstruction* /*libmv_reconstruction*/) { } /* ************ Feature detector ************ */ -libmv_Features *libmv_detectFeaturesByte(const unsigned char * /*image_buffer*/, +libmv_Features* libmv_detectFeaturesByte(const unsigned char* /*image_buffer*/, int /*width*/, int /*height*/, int /*channels*/, - libmv_DetectOptions * /*options*/) { + libmv_DetectOptions* /*options*/) { return NULL; } -struct libmv_Features *libmv_detectFeaturesFloat( - const float * /*image_buffer*/, +struct libmv_Features* libmv_detectFeaturesFloat( + const float* /*image_buffer*/, int /*width*/, int /*height*/, int /*channels*/, - libmv_DetectOptions * /*options*/) { + libmv_DetectOptions* /*options*/) { return NULL; } -int libmv_countFeatures(const libmv_Features * /*libmv_features*/) { +int libmv_countFeatures(const libmv_Features* /*libmv_features*/) { return 0; } -void libmv_getFeature(const libmv_Features * /*libmv_features*/, +void libmv_getFeature(const libmv_Features* /*libmv_features*/, int /*number*/, - double *x, - double *y, - double *score, - double *size) { + double* x, + double* y, + double* score, + double* size) { *x = 0.0; *y = 0.0; *score = 0.0; *size = 0.0; } -void libmv_featuresDestroy(struct libmv_Features * /*libmv_features*/) { +void libmv_featuresDestroy(struct libmv_Features* /*libmv_features*/) { } /* ************ Camera intrinsics ************ */ -libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics( - libmv_Reconstruction * /*libmv_reconstruction*/) { +libmv_CameraIntrinsics* libmv_reconstructionExtractIntrinsics( + libmv_Reconstruction* /*libmv_reconstruction*/) { return NULL; } -libmv_CameraIntrinsics *libmv_cameraIntrinsicsNew( - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/) { +libmv_CameraIntrinsics* libmv_cameraIntrinsicsNew( + const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/) { return NULL; } -libmv_CameraIntrinsics *libmv_cameraIntrinsicsCopy( - const libmv_CameraIntrinsics * /*libmvIntrinsics*/) { +libmv_CameraIntrinsics* libmv_cameraIntrinsicsCopy( + const libmv_CameraIntrinsics* /*libmvIntrinsics*/) { return NULL; } void libmv_cameraIntrinsicsDestroy( - libmv_CameraIntrinsics * /*libmvIntrinsics*/) { + libmv_CameraIntrinsics* /*libmvIntrinsics*/) { } void libmv_cameraIntrinsicsUpdate( - const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/, - libmv_CameraIntrinsics * /*libmv_intrinsics*/) { + const libmv_CameraIntrinsicsOptions* /*libmv_camera_intrinsics_options*/, + libmv_CameraIntrinsics* /*libmv_intrinsics*/) { } void libmv_cameraIntrinsicsSetThreads( - libmv_CameraIntrinsics * /*libmv_intrinsics*/, - int /*threads*/) { + libmv_CameraIntrinsics* /*libmv_intrinsics*/, int /*threads*/) { } void libmv_cameraIntrinsicsExtractOptions( - const libmv_CameraIntrinsics * /*libmv_intrinsics*/, - libmv_CameraIntrinsicsOptions *camera_intrinsics_options) { + const libmv_CameraIntrinsics* /*libmv_intrinsics*/, + libmv_CameraIntrinsicsOptions* camera_intrinsics_options) { memset(camera_intrinsics_options, 0, sizeof(libmv_CameraIntrinsicsOptions)); camera_intrinsics_options->focal_length = 1.0; } void libmv_cameraIntrinsicsUndistortByte( - const libmv_CameraIntrinsics * /*libmv_intrinsics*/, - const unsigned char *source_image, - int width, int height, + const libmv_CameraIntrinsics* /*libmv_intrinsics*/, + const unsigned char* source_image, + int width, + int height, float /*overscan*/, int channels, - unsigned char *destination_image) { - memcpy(destination_image, source_image, + unsigned char* destination_image) { + memcpy(destination_image, + source_image, channels * width * height * sizeof(unsigned char)); } @@ -265,19 +265,21 @@ void libmv_cameraIntrinsicsUndistortFloat( float /*overscan*/, int channels, float* destination_image) { - memcpy(destination_image, source_image, + memcpy(destination_image, + source_image, channels * width * height * sizeof(float)); } void libmv_cameraIntrinsicsDistortByte( const struct libmv_CameraIntrinsics* /*libmv_intrinsics*/, - const unsigned char *source_image, + const unsigned char* source_image, int width, int height, float /*overscan*/, int channels, - unsigned char *destination_image) { - memcpy(destination_image, source_image, + unsigned char* destination_image) { + memcpy(destination_image, + source_image, channels * width * height * sizeof(unsigned char)); } @@ -289,7 +291,8 @@ void libmv_cameraIntrinsicsDistortFloat( float /*overscan*/, int channels, float* destination_image) { - memcpy(destination_image, source_image, + memcpy(destination_image, + source_image, channels * width * height * sizeof(float)); } @@ -315,8 +318,8 @@ void libmv_cameraIntrinsicsInvert( *y1 = 0.0; } -void libmv_homography2DFromCorrespondencesEuc(/* const */ double (* /*x1*/)[2], - /* const */ double (* /*x2*/)[2], +void libmv_homography2DFromCorrespondencesEuc(/* const */ double (*/*x1*/)[2], + /* const */ double (*/*x2*/)[2], int /*num_points*/, double H[3][3]) { memset(H, 0, sizeof(double[3][3])); @@ -327,45 +330,38 @@ void libmv_homography2DFromCorrespondencesEuc(/* const */ double (* /*x1*/)[2], /* ************ autotrack ************ */ -libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* /*frame_accessor*/) -{ +libmv_AutoTrack* libmv_autoTrackNew(libmv_FrameAccessor* /*frame_accessor*/) { return NULL; } -void libmv_autoTrackDestroy(libmv_AutoTrack* /*libmv_autotrack*/) -{ +void libmv_autoTrackDestroy(libmv_AutoTrack* /*libmv_autotrack*/) { } void libmv_autoTrackSetOptions(libmv_AutoTrack* /*libmv_autotrack*/, - const libmv_AutoTrackOptions* /*options*/) -{ + const libmv_AutoTrackOptions* /*options*/) { } int libmv_autoTrackMarker(libmv_AutoTrack* /*libmv_autotrack*/, const libmv_TrackRegionOptions* /*libmv_options*/, - libmv_Marker * /*libmv_tracker_marker*/, - libmv_TrackRegionResult* /*libmv_result*/) -{ + libmv_Marker* /*libmv_tracker_marker*/, + libmv_TrackRegionResult* /*libmv_result*/) { return 0; } void libmv_autoTrackAddMarker(libmv_AutoTrack* /*libmv_autotrack*/, - const libmv_Marker* /*libmv_marker*/) -{ + const libmv_Marker* /*libmv_marker*/) { } void libmv_autoTrackSetMarkers(libmv_AutoTrack* /*libmv_autotrack*/, const libmv_Marker* /*libmv_marker-*/, - size_t /*num_markers*/) -{ + size_t /*num_markers*/) { } int libmv_autoTrackGetMarker(libmv_AutoTrack* /*libmv_autotrack*/, int /*clip*/, int /*frame*/, int /*track*/, - libmv_Marker* /*libmv_marker*/) -{ + libmv_Marker* /*libmv_marker*/) { return 0; } @@ -376,24 +372,20 @@ libmv_FrameAccessor* libmv_FrameAccessorNew( libmv_GetImageCallback /*get_image_callback*/, libmv_ReleaseImageCallback /*release_image_callback*/, libmv_GetMaskForTrackCallback /*get_mask_for_track_callback*/, - libmv_ReleaseMaskCallback /*release_mask_callback*/) -{ + libmv_ReleaseMaskCallback /*release_mask_callback*/) { return NULL; } -void libmv_FrameAccessorDestroy(libmv_FrameAccessor* /*frame_accessor*/) -{ +void libmv_FrameAccessorDestroy(libmv_FrameAccessor* /*frame_accessor*/) { } int64_t libmv_frameAccessorgetTransformKey( - const libmv_FrameTransform * /*transform*/) -{ + const libmv_FrameTransform* /*transform*/) { return 0; } -void libmv_frameAccessorgetTransformRun(const libmv_FrameTransform* /*transform*/, - const libmv_FloatImage* /*input_image*/, - libmv_FloatImage* /*output_image*/) -{ +void libmv_frameAccessorgetTransformRun( + const libmv_FrameTransform* /*transform*/, + const libmv_FloatImage* /*input_image*/, + libmv_FloatImage* /*output_image*/) { } - diff --git a/intern/libmv/intern/track_region.cc b/intern/libmv/intern/track_region.cc index 2a3909c0ced..af88afd7ac2 100644 --- a/intern/libmv/intern/track_region.cc +++ b/intern/libmv/intern/track_region.cc @@ -32,17 +32,17 @@ #undef DUMP_ALWAYS using libmv::FloatImage; +using libmv::TrackRegion; using libmv::TrackRegionOptions; using libmv::TrackRegionResult; -using libmv::TrackRegion; void libmv_configureTrackRegionOptions( const libmv_TrackRegionOptions& options, TrackRegionOptions* track_region_options) { switch (options.motion_model) { -#define LIBMV_CONVERT(the_model) \ - case TrackRegionOptions::the_model: \ - track_region_options->mode = TrackRegionOptions::the_model; \ +#define LIBMV_CONVERT(the_model) \ + case TrackRegionOptions::the_model: \ + track_region_options->mode = TrackRegionOptions::the_model; \ break; LIBMV_CONVERT(TRANSLATION) LIBMV_CONVERT(TRANSLATION_ROTATION) @@ -66,7 +66,8 @@ void libmv_configureTrackRegionOptions( * so disabling for now for until proper prediction model is landed. * * The thing is, currently blender sends input coordinates as the guess to - * region tracker and in case of fast motion such an early out ruins the track. + * region tracker and in case of fast motion such an early out ruins the + * track. */ track_region_options->attempt_refine_before_brute = false; track_region_options->use_normalized_intensities = options.use_normalization; @@ -74,7 +75,7 @@ void libmv_configureTrackRegionOptions( void libmv_regionTrackergetResult(const TrackRegionResult& track_region_result, libmv_TrackRegionResult* result) { - result->termination = (int) track_region_result.termination; + result->termination = (int)track_region_result.termination; result->termination_reason = ""; result->correlation = track_region_result.correlation; } @@ -108,33 +109,27 @@ int libmv_trackRegion(const libmv_TrackRegionOptions* options, libmv_configureTrackRegionOptions(*options, &track_region_options); if (options->image1_mask) { - libmv_floatBufferToFloatImage(options->image1_mask, - image1_width, - image1_height, - 1, - &image1_mask); + libmv_floatBufferToFloatImage( + options->image1_mask, image1_width, image1_height, 1, &image1_mask); track_region_options.image1_mask = &image1_mask; } // Convert from raw float buffers to libmv's FloatImage. FloatImage old_patch, new_patch; - libmv_floatBufferToFloatImage(image1, - image1_width, - image1_height, - 1, - &old_patch); - libmv_floatBufferToFloatImage(image2, - image2_width, - image2_height, - 1, - &new_patch); + libmv_floatBufferToFloatImage( + image1, image1_width, image1_height, 1, &old_patch); + libmv_floatBufferToFloatImage( + image2, image2_width, image2_height, 1, &new_patch); TrackRegionResult track_region_result; - TrackRegion(old_patch, new_patch, - xx1, yy1, + TrackRegion(old_patch, + new_patch, + xx1, + yy1, track_region_options, - xx2, yy2, + xx2, + yy2, &track_region_result); // Convert to floats for the blender api. diff --git a/intern/libmv/intern/track_region.h b/intern/libmv/intern/track_region.h index 48ae97a1c1a..4566fe9bf0f 100644 --- a/intern/libmv/intern/track_region.h +++ b/intern/libmv/intern/track_region.h @@ -31,7 +31,7 @@ typedef struct libmv_TrackRegionOptions { int use_normalization; double minimum_correlation; double sigma; - float *image1_mask; + float* image1_mask; } libmv_TrackRegionOptions; typedef struct libmv_TrackRegionResult { @@ -42,9 +42,9 @@ typedef struct libmv_TrackRegionResult { #ifdef __cplusplus namespace libmv { - struct TrackRegionOptions; - struct TrackRegionResult; -} +struct TrackRegionOptions; +struct TrackRegionResult; +} // namespace libmv void libmv_configureTrackRegionOptions( const libmv_TrackRegionOptions& options, libmv::TrackRegionOptions* track_region_options); diff --git a/intern/libmv/intern/tracks.cc b/intern/libmv/intern/tracks.cc index 0ca5a31796b..146908d6db5 100644 --- a/intern/libmv/intern/tracks.cc +++ b/intern/libmv/intern/tracks.cc @@ -28,18 +28,18 @@ using libmv::Tracks; libmv_Tracks* libmv_tracksNew(void) { Tracks* tracks = LIBMV_OBJECT_NEW(Tracks); - return (libmv_Tracks*) tracks; + return (libmv_Tracks*)tracks; } void libmv_tracksDestroy(libmv_Tracks* libmv_tracks) { LIBMV_OBJECT_DELETE(libmv_tracks, Tracks); } -void libmv_tracksInsert(libmv_Tracks *libmv_tracks, +void libmv_tracksInsert(libmv_Tracks* libmv_tracks, int image, int track, double x, double y, double weight) { - ((Tracks *) libmv_tracks)->Insert(image, track, x, y, weight); + ((Tracks*)libmv_tracks)->Insert(image, track, x, y, weight); } diff --git a/intern/libmv/intern/tracksN.cc b/intern/libmv/intern/tracksN.cc index 1441d8a2066..c7ffb13a386 100644 --- a/intern/libmv/intern/tracksN.cc +++ b/intern/libmv/intern/tracksN.cc @@ -25,8 +25,7 @@ using mv::Marker; using mv::Tracks; -void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, - Marker *marker) { +void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, Marker* marker) { marker->clip = libmv_marker.clip; marker->frame = libmv_marker.frame; marker->track = libmv_marker.track; @@ -41,17 +40,16 @@ void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, marker->search_region.max(0) = libmv_marker.search_region_max[0]; marker->search_region.max(1) = libmv_marker.search_region_max[1]; marker->weight = libmv_marker.weight; - marker->source = (Marker::Source) libmv_marker.source; - marker->status = (Marker::Status) libmv_marker.status; + marker->source = (Marker::Source)libmv_marker.source; + marker->status = (Marker::Status)libmv_marker.status; marker->reference_clip = libmv_marker.reference_clip; marker->reference_frame = libmv_marker.reference_frame; - marker->model_type = (Marker::ModelType) libmv_marker.model_type; + marker->model_type = (Marker::ModelType)libmv_marker.model_type; marker->model_id = libmv_marker.model_id; marker->disabled_channels = libmv_marker.disabled_channels; } -void libmv_markerToApiMarker(const Marker& marker, - libmv_Marker *libmv_marker) { +void libmv_markerToApiMarker(const Marker& marker, libmv_Marker* libmv_marker) { libmv_marker->clip = marker.clip; libmv_marker->frame = marker.frame; libmv_marker->track = marker.track; @@ -66,11 +64,11 @@ void libmv_markerToApiMarker(const Marker& marker, libmv_marker->search_region_max[0] = marker.search_region.max(0); libmv_marker->search_region_max[1] = marker.search_region.max(1); libmv_marker->weight = marker.weight; - libmv_marker->source = (libmv_MarkerSource) marker.source; - libmv_marker->status = (libmv_MarkerStatus) marker.status; + libmv_marker->source = (libmv_MarkerSource)marker.source; + libmv_marker->status = (libmv_MarkerStatus)marker.status; libmv_marker->reference_clip = marker.reference_clip; libmv_marker->reference_frame = marker.reference_frame; - libmv_marker->model_type = (libmv_MarkerModelType) marker.model_type; + libmv_marker->model_type = (libmv_MarkerModelType)marker.model_type; libmv_marker->model_id = marker.model_id; libmv_marker->disabled_channels = marker.disabled_channels; } @@ -78,7 +76,7 @@ void libmv_markerToApiMarker(const Marker& marker, libmv_TracksN* libmv_tracksNewN(void) { Tracks* tracks = LIBMV_OBJECT_NEW(Tracks); - return (libmv_TracksN*) tracks; + return (libmv_TracksN*)tracks; } void libmv_tracksDestroyN(libmv_TracksN* libmv_tracks) { @@ -89,7 +87,7 @@ void libmv_tracksAddMarkerN(libmv_TracksN* libmv_tracks, const libmv_Marker* libmv_marker) { Marker marker; libmv_apiMarkerToMarker(*libmv_marker, &marker); - ((Tracks*) libmv_tracks)->AddMarker(marker); + ((Tracks*)libmv_tracks)->AddMarker(marker); } void libmv_tracksGetMarkerN(libmv_TracksN* libmv_tracks, @@ -98,7 +96,7 @@ void libmv_tracksGetMarkerN(libmv_TracksN* libmv_tracks, int track, libmv_Marker* libmv_marker) { Marker marker; - ((Tracks*) libmv_tracks)->GetMarker(clip, frame, track, &marker); + ((Tracks*)libmv_tracks)->GetMarker(clip, frame, track, &marker); libmv_markerToApiMarker(marker, libmv_marker); } @@ -106,26 +104,25 @@ void libmv_tracksRemoveMarkerN(libmv_TracksN* libmv_tracks, int clip, int frame, int track) { - ((Tracks *) libmv_tracks)->RemoveMarker(clip, frame, track); + ((Tracks*)libmv_tracks)->RemoveMarker(clip, frame, track); } -void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, - int track) { - ((Tracks *) libmv_tracks)->RemoveMarkersForTrack(track); +void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, int track) { + ((Tracks*)libmv_tracks)->RemoveMarkersForTrack(track); } int libmv_tracksMaxClipN(libmv_TracksN* libmv_tracks) { - return ((Tracks*) libmv_tracks)->MaxClip(); + return ((Tracks*)libmv_tracks)->MaxClip(); } int libmv_tracksMaxFrameN(libmv_TracksN* libmv_tracks, int clip) { - return ((Tracks*) libmv_tracks)->MaxFrame(clip); + return ((Tracks*)libmv_tracks)->MaxFrame(clip); } int libmv_tracksMaxTrackN(libmv_TracksN* libmv_tracks) { - return ((Tracks*) libmv_tracks)->MaxTrack(); + return ((Tracks*)libmv_tracks)->MaxTrack(); } int libmv_tracksNumMarkersN(libmv_TracksN* libmv_tracks) { - return ((Tracks*) libmv_tracks)->NumMarkers(); + return ((Tracks*)libmv_tracks)->NumMarkers(); } diff --git a/intern/libmv/intern/tracksN.h b/intern/libmv/intern/tracksN.h index 9363d34bed7..b5d1f9753e0 100644 --- a/intern/libmv/intern/tracksN.h +++ b/intern/libmv/intern/tracksN.h @@ -79,20 +79,19 @@ typedef struct libmv_Marker { #ifdef __cplusplus namespace mv { - struct Marker; +struct Marker; } void libmv_apiMarkerToMarker(const libmv_Marker& libmv_marker, - mv::Marker *marker); + mv::Marker* marker); void libmv_markerToApiMarker(const mv::Marker& marker, - libmv_Marker *libmv_marker); + libmv_Marker* libmv_marker); #endif libmv_TracksN* libmv_tracksNewN(void); void libmv_tracksDestroyN(libmv_TracksN* libmv_tracks); - void libmv_tracksAddMarkerN(libmv_TracksN* libmv_tracks, const libmv_Marker* libmv_marker); @@ -107,8 +106,7 @@ void libmv_tracksRemoveMarkerN(libmv_TracksN* libmv_tracks, int frame, int track); -void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, - int track); +void libmv_tracksRemoveMarkersForTrack(libmv_TracksN* libmv_tracks, int track); int libmv_tracksMaxClipN(libmv_TracksN* libmv_tracks); int libmv_tracksMaxFrameN(libmv_TracksN* libmv_tracks, int clip); diff --git a/intern/libmv/intern/utildefines.h b/intern/libmv/intern/utildefines.h index d76d32f9c4d..052052a1d76 100644 --- a/intern/libmv/intern/utildefines.h +++ b/intern/libmv/intern/utildefines.h @@ -30,27 +30,33 @@ # define LIBMV_OBJECT_NEW OBJECT_GUARDED_NEW # define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE # define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE -# define LIBMV_STRUCT_NEW(type, count) \ - (type*)MEM_mallocN(sizeof(type) * count, __func__) +# define LIBMV_STRUCT_NEW(type, count) \ + (type*)MEM_mallocN(sizeof(type) * count, __func__) # define LIBMV_STRUCT_DELETE(what) MEM_freeN(what) #else // Need this to keep libmv-capi potentially standalone. # if defined __GNUC__ || defined __sun -# define LIBMV_OBJECT_NEW(type, args ...) \ - new(malloc(sizeof(type))) type(args) +# define LIBMV_OBJECT_NEW(type, args...) \ + new (malloc(sizeof(type))) type(args) # else -# define LIBMV_OBJECT_NEW(type, ...) \ - new(malloc(sizeof(type))) type(__VA_ARGS__) -#endif -# define LIBMV_OBJECT_DELETE(what, type) \ - { \ - if (what) { \ - ((type*)(what))->~type(); \ - free(what); \ - } \ - } (void)0 +# define LIBMV_OBJECT_NEW(type, ...) \ + new (malloc(sizeof(type))) type(__VA_ARGS__) +# endif +# define LIBMV_OBJECT_DELETE(what, type) \ + { \ + if (what) { \ + ((type*)(what))->~type(); \ + free(what); \ + } \ + } \ + (void)0 # define LIBMV_STRUCT_NEW(type, count) (type*)malloc(sizeof(type) * count) -# define LIBMV_STRUCT_DELETE(what) { if (what) free(what); } (void)0 +# define LIBMV_STRUCT_DELETE(what) \ + { \ + if (what) \ + free(what); \ + } \ + (void)0 #endif #endif // LIBMV_C_API_UTILDEFINES_H_ diff --git a/intern/libmv/libmv/autotrack/autotrack.cc b/intern/libmv/libmv/autotrack/autotrack.cc index 3b0a762178a..c18567a5f28 100644 --- a/intern/libmv/libmv/autotrack/autotrack.cc +++ b/intern/libmv/libmv/autotrack/autotrack.cc @@ -21,9 +21,9 @@ // Author: mierle@gmail.com (Keir Mierle) #include "libmv/autotrack/autotrack.h" -#include "libmv/autotrack/quad.h" #include "libmv/autotrack/frame_accessor.h" #include "libmv/autotrack/predict_tracks.h" +#include "libmv/autotrack/quad.h" #include "libmv/base/scoped_ptr.h" #include "libmv/logging/logging.h" #include "libmv/numeric/numeric.h" @@ -35,34 +35,30 @@ namespace { class DisableChannelsTransform : public FrameAccessor::Transform { public: DisableChannelsTransform(int disabled_channels) - : disabled_channels_(disabled_channels) { } + : disabled_channels_(disabled_channels) {} - int64_t key() const { - return disabled_channels_; - } + int64_t key() const { return disabled_channels_; } void run(const FloatImage& input, FloatImage* output) const { - bool disable_red = (disabled_channels_ & Marker::CHANNEL_R) != 0, + bool disable_red = (disabled_channels_ & Marker::CHANNEL_R) != 0, disable_green = (disabled_channels_ & Marker::CHANNEL_G) != 0, - disable_blue = (disabled_channels_ & Marker::CHANNEL_B) != 0; + disable_blue = (disabled_channels_ & Marker::CHANNEL_B) != 0; - LG << "Disabling channels: " - << (disable_red ? "R " : "") - << (disable_green ? "G " : "") - << (disable_blue ? "B" : ""); + LG << "Disabling channels: " << (disable_red ? "R " : "") + << (disable_green ? "G " : "") << (disable_blue ? "B" : ""); // It's important to rescale the resultappropriately so that e.g. if only // blue is selected, it's not zeroed out. - float scale = (disable_red ? 0.0f : 0.2126f) + + float scale = (disable_red ? 0.0f : 0.2126f) + (disable_green ? 0.0f : 0.7152f) + - (disable_blue ? 0.0f : 0.0722f); + (disable_blue ? 0.0f : 0.0722f); output->Resize(input.Height(), input.Width(), 1); for (int y = 0; y < input.Height(); y++) { for (int x = 0; x < input.Width(); x++) { - float r = disable_red ? 0.0f : input(y, x, 0); + float r = disable_red ? 0.0f : input(y, x, 0); float g = disable_green ? 0.0f : input(y, x, 1); - float b = disable_blue ? 0.0f : input(y, x, 2); + float b = disable_blue ? 0.0f : input(y, x, 2); (*output)(y, x, 0) = (0.2126f * r + 0.7152f * g + 0.0722f * b) / scale; } } @@ -73,7 +69,7 @@ class DisableChannelsTransform : public FrameAccessor::Transform { int disabled_channels_; }; -template<typename QuadT, typename ArrayT> +template <typename QuadT, typename ArrayT> void QuadToArrays(const QuadT& quad, ArrayT* x, ArrayT* y) { for (int i = 0; i < 4; ++i) { x[i] = quad.coordinates(i, 0); @@ -115,11 +111,8 @@ FrameAccessor::Key GetMaskForMarker(const Marker& marker, FrameAccessor* frame_accessor, FloatImage* mask) { Region region = marker.search_region.Rounded(); - return frame_accessor->GetMaskForTrack(marker.clip, - marker.frame, - marker.track, - ®ion, - mask); + return frame_accessor->GetMaskForTrack( + marker.clip, marker.frame, marker.track, ®ion, mask); } } // namespace @@ -152,23 +145,20 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker, // TODO(keir): Technically this could take a smaller slice from the source // image instead of taking one the size of the search window. FloatImage reference_image; - FrameAccessor::Key reference_key = GetImageForMarker(reference_marker, - frame_accessor_, - &reference_image); + FrameAccessor::Key reference_key = + GetImageForMarker(reference_marker, frame_accessor_, &reference_image); if (!reference_key) { LG << "Couldn't get frame for reference marker: " << reference_marker; return false; } FloatImage reference_mask; - FrameAccessor::Key reference_mask_key = GetMaskForMarker(reference_marker, - frame_accessor_, - &reference_mask); + FrameAccessor::Key reference_mask_key = + GetMaskForMarker(reference_marker, frame_accessor_, &reference_mask); FloatImage tracked_image; - FrameAccessor::Key tracked_key = GetImageForMarker(*tracked_marker, - frame_accessor_, - &tracked_image); + FrameAccessor::Key tracked_key = + GetImageForMarker(*tracked_marker, frame_accessor_, &tracked_image); if (!tracked_key) { frame_accessor_->ReleaseImage(reference_key); LG << "Couldn't get frame for tracked marker: " << tracked_marker; @@ -191,9 +181,11 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker, local_track_region_options.attempt_refine_before_brute = predicted_position; TrackRegion(reference_image, tracked_image, - x1, y1, + x1, + y1, local_track_region_options, - x2, y2, + x2, + y2, result); // Copy results over the tracked marker. @@ -208,7 +200,7 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker, tracked_marker->search_region.Offset(delta); tracked_marker->source = Marker::TRACKED; tracked_marker->status = Marker::UNKNOWN; - tracked_marker->reference_clip = reference_marker.clip; + tracked_marker->reference_clip = reference_marker.clip; tracked_marker->reference_frame = reference_marker.frame; // Release the images and masks from the accessor cache. @@ -230,7 +222,9 @@ void AutoTrack::SetMarkers(vector<Marker>* markers) { tracks_.SetMarkers(markers); } -bool AutoTrack::GetMarker(int clip, int frame, int track, +bool AutoTrack::GetMarker(int clip, + int frame, + int track, Marker* markers) const { return tracks_.GetMarker(clip, frame, track, markers); } @@ -242,7 +236,8 @@ void AutoTrack::DetectAndTrack(const DetectAndTrackOptions& options) { vector<Marker> previous_frame_markers; // Q: How to decide track #s when detecting? // Q: How to match markers from previous frame? set of prev frame tracks? - // Q: How to decide what markers should get tracked and which ones should not? + // Q: How to decide what markers should get tracked and which ones should + // not? for (int frame = 0; frame < num_frames; ++frame) { if (Cancelled()) { LG << "Got cancel message while detecting and tracking..."; @@ -271,8 +266,7 @@ void AutoTrack::DetectAndTrack(const DetectAndTrackOptions& options) { for (int i = 0; i < this_frame_markers.size(); ++i) { tracks_in_this_frame.push_back(this_frame_markers[i].track); } - std::sort(tracks_in_this_frame.begin(), - tracks_in_this_frame.end()); + std::sort(tracks_in_this_frame.begin(), tracks_in_this_frame.end()); // Find tracks in the previous frame that are not in this one. vector<Marker*> previous_frame_markers_to_track; diff --git a/intern/libmv/libmv/autotrack/autotrack.h b/intern/libmv/libmv/autotrack/autotrack.h index 1d7422f54e7..281766f600f 100644 --- a/intern/libmv/libmv/autotrack/autotrack.h +++ b/intern/libmv/libmv/autotrack/autotrack.h @@ -23,8 +23,8 @@ #ifndef LIBMV_AUTOTRACK_AUTOTRACK_H_ #define LIBMV_AUTOTRACK_AUTOTRACK_H_ -#include "libmv/autotrack/tracks.h" #include "libmv/autotrack/region.h" +#include "libmv/autotrack/tracks.h" #include "libmv/tracking/track_region.h" namespace libmv { @@ -74,15 +74,14 @@ class AutoTrack { Region search_region; }; - AutoTrack(FrameAccessor* frame_accessor) - : frame_accessor_(frame_accessor) {} + AutoTrack(FrameAccessor* frame_accessor) : frame_accessor_(frame_accessor) {} // Marker manipulation. // Clip manipulation. // Set the number of clips. These clips will get accessed from the frame // accessor, matches between frames found, and a reconstruction created. - //void SetNumFrames(int clip, int num_frames); + // void SetNumFrames(int clip, int num_frames); // Tracking & Matching @@ -90,7 +89,7 @@ class AutoTrack { // Caller maintains ownership of *result and *tracked_marker. bool TrackMarker(Marker* tracked_marker, TrackRegionResult* result, - const TrackRegionOptions* track_options=NULL); + const TrackRegionOptions* track_options = NULL); // Wrapper around Tracks API; however these may add additional processing. void AddMarker(const Marker& tracked_marker); @@ -99,36 +98,36 @@ class AutoTrack { // TODO(keir): Implement frame matching! This could be very cool for loop // closing and connecting across clips. - //void MatchFrames(int clip1, int frame1, int clip2, int frame2) {} + // void MatchFrames(int clip1, int frame1, int clip2, int frame2) {} // Wrapper around the Reconstruction API. // Returns the new ID. int AddCameraIntrinsics(CameraIntrinsics* intrinsics) { - (void) intrinsics; + (void)intrinsics; return 0; } // XXX int SetClipIntrinsics(int clip, int intrinsics) { - (void) clip; - (void) intrinsics; + (void)clip; + (void)intrinsics; return 0; - } // XXX + } // XXX enum Motion { GENERAL_CAMERA_MOTION, TRIPOD_CAMERA_MOTION, }; int SetClipMotion(int clip, Motion motion) { - (void) clip; - (void) motion; + (void)clip; + (void)motion; return 0; - } // XXX + } // XXX // Decide what to refine for the given intrinsics. bundle_options is from // bundle.h (e.g. BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL_K1). void SetIntrinsicsRefine(int intrinsics, int bundle_options) { - (void) intrinsics; - (void) bundle_options; - } // XXX + (void)intrinsics; + (void)bundle_options; + } // XXX // Keyframe read/write. struct ClipFrame { @@ -150,20 +149,19 @@ class AutoTrack { }; void DetectAndTrack(const DetectAndTrackOptions& options); - struct DetectFeaturesInFrameOptions { - }; - void DetectFeaturesInFrame(int clip, int frame, - const DetectFeaturesInFrameOptions* options=NULL) { - (void) clip; - (void) frame; - (void) options; - } // XXX + struct DetectFeaturesInFrameOptions {}; + void DetectFeaturesInFrame( + int clip, int frame, const DetectFeaturesInFrameOptions* options = NULL) { + (void)clip; + (void)frame; + (void)options; + } // XXX // Does not take ownership of the given listener, but keeps a reference to it. - void AddListener(OperationListener* listener) {(void) listener;} // XXX + void AddListener(OperationListener* listener) { (void)listener; } // XXX // Create the initial reconstruction, - //void FindInitialReconstruction(); + // void FindInitialReconstruction(); // State machine // @@ -202,17 +200,17 @@ class AutoTrack { bool Cancelled() { return false; } Tracks tracks_; // May be normalized camera coordinates or raw pixels. - //Reconstruction reconstruction_; + // Reconstruction reconstruction_; // TODO(keir): Add the motion models here. - //vector<MotionModel> motion_models_; + // vector<MotionModel> motion_models_; // TODO(keir): Should num_clips and num_frames get moved to FrameAccessor? // TODO(keir): What about masking for clips and frames to prevent various // things like reconstruction or tracking from happening on certain frames? FrameAccessor* frame_accessor_; - //int num_clips_; - //vector<int> num_frames_; // Indexed by clip. + // int num_clips_; + // vector<int> num_frames_; // Indexed by clip. // The intrinsics for each clip, assuming each clip has fixed intrinsics. // TODO(keir): Decide what the semantics should be for varying focal length. diff --git a/intern/libmv/libmv/autotrack/frame_accessor.h b/intern/libmv/libmv/autotrack/frame_accessor.h index cfad9ca71ff..e9308dc400a 100644 --- a/intern/libmv/libmv/autotrack/frame_accessor.h +++ b/intern/libmv/libmv/autotrack/frame_accessor.h @@ -41,7 +41,7 @@ using libmv::FloatImage; // implementations to cache filtered image pieces). struct FrameAccessor { struct Transform { - virtual ~Transform() { } + virtual ~Transform() {} // The key should depend on the transform arguments. Must be non-zero. virtual int64_t key() const = 0; @@ -50,10 +50,7 @@ struct FrameAccessor { virtual void run(const FloatImage& input, FloatImage* output) const = 0; }; - enum InputMode { - MONO, - RGBA - }; + enum InputMode { MONO, RGBA }; typedef void* Key; @@ -100,6 +97,6 @@ struct FrameAccessor { virtual int NumFrames(int clip) = 0; }; -} // namespace libmv +} // namespace mv #endif // LIBMV_AUTOTRACK_FRAME_ACCESSOR_H_ diff --git a/intern/libmv/libmv/autotrack/marker.h b/intern/libmv/libmv/autotrack/marker.h index bb803313af8..29e163c0446 100644 --- a/intern/libmv/libmv/autotrack/marker.h +++ b/intern/libmv/libmv/autotrack/marker.h @@ -57,23 +57,19 @@ struct Marker { float weight; enum Source { - MANUAL, // The user placed this marker manually. - DETECTED, // A keypoint detector found this point. - TRACKED, // The tracking algorithm placed this marker. - MATCHED, // A matching algorithm (e.g. SIFT or SURF or ORB) found this. - PREDICTED, // A motion model predicted this marker. This is needed for - // handling occlusions in some cases where an imaginary marker - // is placed to keep camera motion smooth. + MANUAL, // The user placed this marker manually. + DETECTED, // A keypoint detector found this point. + TRACKED, // The tracking algorithm placed this marker. + MATCHED, // A matching algorithm (e.g. SIFT or SURF or ORB) found this. + PREDICTED, // A motion model predicted this marker. This is needed for + // handling occlusions in some cases where an imaginary marker + // is placed to keep camera motion smooth. }; Source source; // Markers may be inliers or outliers if the tracking fails; this allows // visualizing the markers in the image. - enum Status { - UNKNOWN, - INLIER, - OUTLIER - }; + enum Status { UNKNOWN, INLIER, OUTLIER }; Status status; // When doing correlation tracking, where to search in the current frame for @@ -90,12 +86,7 @@ struct Marker { // another primitive (a rectangular prisim). This captures the information // needed to say that for example a collection of markers belongs to model #2 // (and model #2 is a plane). - enum ModelType { - POINT, - PLANE, - LINE, - CUBE - }; + enum ModelType { POINT, PLANE, LINE, CUBE }; ModelType model_type; // The model ID this track (e.g. the second model, which is a plane). @@ -114,7 +105,7 @@ struct Marker { int disabled_channels; // Offset everything (center, patch, search) by the given delta. - template<typename T> + template <typename T> void Offset(const T& offset) { center += offset.template cast<float>(); patch.coordinates.rowwise() += offset.template cast<int>(); @@ -122,19 +113,15 @@ struct Marker { } // Shift the center to the given new position (and patch, search). - template<typename T> + template <typename T> void SetPosition(const T& new_center) { Offset(new_center - center); } }; inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { - out << "{" - << marker.clip << ", " - << marker.frame << ", " - << marker.track << ", (" - << marker.center.x() << ", " - << marker.center.y() << ")" + out << "{" << marker.clip << ", " << marker.frame << ", " << marker.track + << ", (" << marker.center.x() << ", " << marker.center.y() << ")" << "}"; return out; } diff --git a/intern/libmv/libmv/autotrack/model.h b/intern/libmv/libmv/autotrack/model.h index 1165281cdac..e79d38b742b 100644 --- a/intern/libmv/libmv/autotrack/model.h +++ b/intern/libmv/libmv/autotrack/model.h @@ -23,18 +23,13 @@ #ifndef LIBMV_AUTOTRACK_MODEL_H_ #define LIBMV_AUTOTRACK_MODEL_H_ -#include "libmv/numeric/numeric.h" #include "libmv/autotrack/quad.h" +#include "libmv/numeric/numeric.h" namespace mv { struct Model { - enum ModelType { - POINT, - PLANE, - LINE, - CUBE - }; + enum ModelType { POINT, PLANE, LINE, CUBE }; // ??? }; diff --git a/intern/libmv/libmv/autotrack/predict_tracks.cc b/intern/libmv/libmv/autotrack/predict_tracks.cc index 3786c1b9a3b..d78b5b340f9 100644 --- a/intern/libmv/libmv/autotrack/predict_tracks.cc +++ b/intern/libmv/libmv/autotrack/predict_tracks.cc @@ -20,8 +20,8 @@ // // Author: mierle@gmail.com (Keir Mierle) -#include "libmv/autotrack/marker.h" #include "libmv/autotrack/predict_tracks.h" +#include "libmv/autotrack/marker.h" #include "libmv/autotrack/tracks.h" #include "libmv/base/vector.h" #include "libmv/logging/logging.h" @@ -31,8 +31,8 @@ namespace mv { namespace { -using libmv::vector; using libmv::Vec2; +using libmv::vector; // Implied time delta between steps. Set empirically by tweaking and seeing // what numbers did best at prediction. @@ -57,6 +57,8 @@ const double dt = 3.8; // For a typical system having constant velocity. This gives smooth-appearing // predictions, but they are not always as accurate. +// +// clang-format off const double velocity_state_transition_data[] = { 1, dt, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, @@ -65,10 +67,13 @@ const double velocity_state_transition_data[] = { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; +// clang-format on #if 0 // This 3rd-order system also models acceleration. This makes for "jerky" // predictions, but that tend to be more accurate. +// +// clang-format off const double acceleration_state_transition_data[] = { 1, dt, dt*dt/2, 0, 0, 0, 0, 1, dt, 0, 0, 0, @@ -77,9 +82,12 @@ const double acceleration_state_transition_data[] = { 0, 0, 0, 0, 1, dt, 0, 0, 0, 0, 0, 1 }; +// clang-format on // This system (attempts) to add an angular velocity component. However, it's // total junk. +// +// clang-format off const double angular_state_transition_data[] = { 1, dt, -dt, 0, 0, 0, // Position x 0, 1, 0, 0, 0, 0, // Velocity x @@ -88,17 +96,22 @@ const double angular_state_transition_data[] = { 0, 0, 0, 0, 1, 0, // Velocity y 0, 0, 0, 0, 0, 1 // Ignored }; +// clang-format on #endif const double* state_transition_data = velocity_state_transition_data; // Observation matrix. +// clang-format off const double observation_data[] = { 1., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0. }; +// clang-format on // Process covariance. +// +// clang-format off const double process_covariance_data[] = { 35, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, @@ -107,14 +120,19 @@ const double process_covariance_data[] = { 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 5 }; +// clang-format on // Process covariance. const double measurement_covariance_data[] = { - 0.01, 0.00, - 0.00, 0.01, + 0.01, + 0.00, + 0.00, + 0.01, }; // Initial covariance. +// +// clang-format off const double initial_covariance_data[] = { 10, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, @@ -123,6 +141,7 @@ const double initial_covariance_data[] = { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 }; +// clang-format on typedef mv::KalmanFilter<double, 6, 2> TrackerKalman; @@ -138,7 +157,7 @@ bool OrderByFrameLessThan(const Marker* a, const Marker* b) { } return a->clip < b->clip; } - return a->frame < b-> frame; + return a->frame < b->frame; } // Predicted must be after the previous markers (in the frame numbering sense). @@ -146,9 +165,9 @@ void RunPrediction(const vector<Marker*> previous_markers, Marker* predicted_marker) { TrackerKalman::State state; state.mean << previous_markers[0]->center.x(), 0, 0, - previous_markers[0]->center.y(), 0, 0; - state.covariance = Eigen::Matrix<double, 6, 6, Eigen::RowMajor>( - initial_covariance_data); + previous_markers[0]->center.y(), 0, 0; + state.covariance = + Eigen::Matrix<double, 6, 6, Eigen::RowMajor>(initial_covariance_data); int current_frame = previous_markers[0]->frame; int target_frame = predicted_marker->frame; @@ -159,19 +178,18 @@ void RunPrediction(const vector<Marker*> previous_markers, for (int i = 1; i < previous_markers.size(); ++i) { // Step forward predicting the state until it is on the current marker. int predictions = 0; - for (; - current_frame != previous_markers[i]->frame; + for (; current_frame != previous_markers[i]->frame; current_frame += frame_delta) { filter.Step(&state); predictions++; - LG << "Predicted point (frame " << current_frame << "): " - << state.mean(0) << ", " << state.mean(3); + LG << "Predicted point (frame " << current_frame << "): " << state.mean(0) + << ", " << state.mean(3); } // Log the error -- not actually used, but interesting. Vec2 error = previous_markers[i]->center.cast<double>() - Vec2(state.mean(0), state.mean(3)); - LG << "Prediction error for " << predictions << " steps: (" - << error.x() << ", " << error.y() << "); norm: " << error.norm(); + LG << "Prediction error for " << predictions << " steps: (" << error.x() + << ", " << error.y() << "); norm: " << error.norm(); // Now that the state is predicted in the current frame, update the state // based on the measurement from the current frame. filter.Update(previous_markers[i]->center.cast<double>(), @@ -184,8 +202,8 @@ void RunPrediction(const vector<Marker*> previous_markers, // predict until the target frame. for (; current_frame != target_frame; current_frame += frame_delta) { filter.Step(&state); - LG << "Final predicted point (frame " << current_frame << "): " - << state.mean(0) << ", " << state.mean(3); + LG << "Final predicted point (frame " << current_frame + << "): " << state.mean(0) << ", " << state.mean(3); } // The x and y positions are at 0 and 3; ignore acceleration and velocity. @@ -253,13 +271,13 @@ bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) { } else if (insert_at != -1) { // Found existing marker; scan before and after it. forward_scan_begin = insert_at + 1; - forward_scan_end = markers.size() - 1;; + forward_scan_end = markers.size() - 1; backward_scan_begin = insert_at - 1; backward_scan_end = 0; } else { // Didn't find existing marker but found an insertion point. forward_scan_begin = insert_before; - forward_scan_end = markers.size() - 1;; + forward_scan_end = markers.size() - 1; backward_scan_begin = insert_before - 1; backward_scan_end = 0; } @@ -301,9 +319,8 @@ bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) { return false; } LG << "Predicting backward"; - int predict_begin = - std::min(forward_scan_begin + max_frames_to_predict_from, - forward_scan_end); + int predict_begin = std::min( + forward_scan_begin + max_frames_to_predict_from, forward_scan_end); int predict_end = forward_scan_begin; vector<Marker*> previous_markers; for (int i = predict_begin; i >= predict_end; --i) { @@ -312,7 +329,6 @@ bool PredictMarkerPosition(const Tracks& tracks, Marker* marker) { RunPrediction(previous_markers, marker); return false; } - } } // namespace mv diff --git a/intern/libmv/libmv/autotrack/predict_tracks_test.cc b/intern/libmv/libmv/autotrack/predict_tracks_test.cc index f7c2c68d750..fea93b91bce 100644 --- a/intern/libmv/libmv/autotrack/predict_tracks_test.cc +++ b/intern/libmv/libmv/autotrack/predict_tracks_test.cc @@ -35,17 +35,15 @@ static void AddMarker(int frame, float x, float y, Tracks* tracks) { marker.frame = frame; marker.center.x() = x; marker.center.y() = y; - marker.patch.coordinates << x - 1, y - 1, - x + 1, y - 1, - x + 1, y + 1, - x - 1, y + 1; + marker.patch.coordinates << x - 1, y - 1, x + 1, y - 1, x + 1, y + 1, x - 1, + y + 1; tracks->AddMarker(marker); } TEST(PredictMarkerPosition, EasyLinearMotion) { Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); + AddMarker(0, 1.0, 0.0, &tracks); + AddMarker(1, 2.0, 5.0, &tracks); AddMarker(2, 3.0, 10.0, &tracks); AddMarker(3, 4.0, 15.0, &tracks); AddMarker(4, 5.0, 20.0, &tracks); @@ -66,10 +64,8 @@ TEST(PredictMarkerPosition, EasyLinearMotion) { // Check the patch coordinates as well. double x = 9, y = 40.0; Quad2Df expected_patch; - expected_patch.coordinates << x - 1, y - 1, - x + 1, y - 1, - x + 1, y + 1, - x - 1, y + 1; + expected_patch.coordinates << x - 1, y - 1, x + 1, y - 1, x + 1, y + 1, x - 1, + y + 1; error = (expected_patch.coordinates - predicted.patch.coordinates).norm(); LG << "Patch error: " << error; @@ -78,8 +74,8 @@ TEST(PredictMarkerPosition, EasyLinearMotion) { TEST(PredictMarkerPosition, EasyBackwardLinearMotion) { Tracks tracks; - AddMarker(8, 1.0, 0.0, &tracks); - AddMarker(7, 2.0, 5.0, &tracks); + AddMarker(8, 1.0, 0.0, &tracks); + AddMarker(7, 2.0, 5.0, &tracks); AddMarker(6, 3.0, 10.0, &tracks); AddMarker(5, 4.0, 15.0, &tracks); AddMarker(4, 5.0, 20.0, &tracks); @@ -101,10 +97,8 @@ TEST(PredictMarkerPosition, EasyBackwardLinearMotion) { // Check the patch coordinates as well. double x = 9.0, y = 40.0; Quad2Df expected_patch; - expected_patch.coordinates << x - 1, y - 1, - x + 1, y - 1, - x + 1, y + 1, - x - 1, y + 1; + expected_patch.coordinates << x - 1, y - 1, x + 1, y - 1, x + 1, y + 1, x - 1, + y + 1; error = (expected_patch.coordinates - predicted.patch.coordinates).norm(); LG << "Patch error: " << error; @@ -113,8 +107,8 @@ TEST(PredictMarkerPosition, EasyBackwardLinearMotion) { TEST(PredictMarkerPosition, TwoFrameGap) { Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); + AddMarker(0, 1.0, 0.0, &tracks); + AddMarker(1, 2.0, 5.0, &tracks); AddMarker(2, 3.0, 10.0, &tracks); AddMarker(3, 4.0, 15.0, &tracks); AddMarker(4, 5.0, 20.0, &tracks); @@ -135,8 +129,8 @@ TEST(PredictMarkerPosition, TwoFrameGap) { TEST(PredictMarkerPosition, FourFrameGap) { Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); + AddMarker(0, 1.0, 0.0, &tracks); + AddMarker(1, 2.0, 5.0, &tracks); AddMarker(2, 3.0, 10.0, &tracks); AddMarker(3, 4.0, 15.0, &tracks); // Missing frames 4, 5, 6, 7. @@ -154,13 +148,13 @@ TEST(PredictMarkerPosition, FourFrameGap) { TEST(PredictMarkerPosition, MultipleGaps) { Tracks tracks; - AddMarker(0, 1.0, 0.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); + AddMarker(0, 1.0, 0.0, &tracks); + AddMarker(1, 2.0, 5.0, &tracks); AddMarker(2, 3.0, 10.0, &tracks); // AddMarker(3, 4.0, 15.0, &tracks); // Note the 3-frame gap. // AddMarker(4, 5.0, 20.0, &tracks); // AddMarker(5, 6.0, 25.0, &tracks); - AddMarker(6, 7.0, 30.0, &tracks); // Intermediate measurement. + AddMarker(6, 7.0, 30.0, &tracks); // Intermediate measurement. // AddMarker(7, 8.0, 35.0, &tracks); Marker predicted; @@ -178,14 +172,14 @@ TEST(PredictMarkerPosition, MarkersInRandomOrder) { Tracks tracks; // This is the same as the easy, except that the tracks are randomly ordered. - AddMarker(0, 1.0, 0.0, &tracks); + AddMarker(0, 1.0, 0.0, &tracks); AddMarker(2, 3.0, 10.0, &tracks); AddMarker(7, 8.0, 35.0, &tracks); AddMarker(5, 6.0, 25.0, &tracks); AddMarker(4, 5.0, 20.0, &tracks); AddMarker(3, 4.0, 15.0, &tracks); AddMarker(6, 7.0, 30.0, &tracks); - AddMarker(1, 2.0, 5.0, &tracks); + AddMarker(1, 2.0, 5.0, &tracks); Marker predicted; predicted.clip = 0; diff --git a/intern/libmv/libmv/autotrack/quad.h b/intern/libmv/libmv/autotrack/quad.h index 0c70f9882da..4aeb66f20f7 100644 --- a/intern/libmv/libmv/autotrack/quad.h +++ b/intern/libmv/libmv/autotrack/quad.h @@ -27,7 +27,7 @@ namespace mv { -template<typename T, int D> +template <typename T, int D> struct Quad { // A quad is 4 points; generally in 2D or 3D. // @@ -35,7 +35,7 @@ struct Quad { // |\. // | \. // | z (z goes into screen) - // | + // | // | r0----->r1 // | ^ | // | | . | @@ -44,7 +44,7 @@ struct Quad { // | \. // | \. // v normal goes away (right handed). - // y + // y // // Each row is one of the corners coordinates; either (x, y) or (x, y, z). Eigen::Matrix<T, 4, D> coordinates; diff --git a/intern/libmv/libmv/autotrack/reconstruction.h b/intern/libmv/libmv/autotrack/reconstruction.h index 732e74063f1..f993b39f79e 100644 --- a/intern/libmv/libmv/autotrack/reconstruction.h +++ b/intern/libmv/libmv/autotrack/reconstruction.h @@ -57,17 +57,17 @@ class Reconstruction { public: // All methods copy their input reference or take ownership of the pointer. void AddCameraPose(const CameraPose& pose); - int AddCameraIntrinsics(CameraIntrinsics* intrinsics); - int AddPoint(const Point& point); - int AddModel(Model* model); + int AddCameraIntrinsics(CameraIntrinsics* intrinsics); + int AddPoint(const Point& point); + int AddModel(Model* model); // Returns the corresponding pose or point or NULL if missing. - CameraPose* CameraPoseForFrame(int clip, int frame); + CameraPose* CameraPoseForFrame(int clip, int frame); const CameraPose* CameraPoseForFrame(int clip, int frame) const; - Point* PointForTrack(int track); + Point* PointForTrack(int track); const Point* PointForTrack(int track) const; - const vector<vector<CameraPose> >& camera_poses() const { + const vector<vector<CameraPose>>& camera_poses() const { return camera_poses_; } diff --git a/intern/libmv/libmv/autotrack/region.h b/intern/libmv/libmv/autotrack/region.h index b35d99eb60d..687a217ab2a 100644 --- a/intern/libmv/libmv/autotrack/region.h +++ b/intern/libmv/libmv/autotrack/region.h @@ -46,7 +46,7 @@ struct Region { Vec2f min; Vec2f max; - template<typename T> + template <typename T> void Offset(const T& offset) { min += offset.template cast<float>(); max += offset.template cast<float>(); diff --git a/intern/libmv/libmv/autotrack/tracks.cc b/intern/libmv/libmv/autotrack/tracks.cc index 174f264f3f2..8044bb28bb4 100644 --- a/intern/libmv/libmv/autotrack/tracks.cc +++ b/intern/libmv/libmv/autotrack/tracks.cc @@ -23,8 +23,8 @@ #include "libmv/autotrack/tracks.h" #include <algorithm> -#include <vector> #include <iterator> +#include <vector> #include "libmv/numeric/numeric.h" @@ -34,12 +34,12 @@ Tracks::Tracks(const Tracks& other) { markers_ = other.markers_; } -Tracks::Tracks(const vector<Marker>& markers) : markers_(markers) {} +Tracks::Tracks(const vector<Marker>& markers) : markers_(markers) { +} bool Tracks::GetMarker(int clip, int frame, int track, Marker* marker) const { for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == clip && - markers_[i].frame == frame && + if (markers_[i].clip == clip && markers_[i].frame == frame && markers_[i].track == track) { *marker = markers_[i]; return true; @@ -60,8 +60,7 @@ void Tracks::GetMarkersForTrackInClip(int clip, int track, vector<Marker>* markers) const { for (int i = 0; i < markers_.size(); ++i) { - if (clip == markers_[i].clip && - track == markers_[i].track) { + if (clip == markers_[i].clip && track == markers_[i].track) { markers->push_back(markers_[i]); } } @@ -71,15 +70,16 @@ void Tracks::GetMarkersInFrame(int clip, int frame, vector<Marker>* markers) const { for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == clip && - markers_[i].frame == frame) { + if (markers_[i].clip == clip && markers_[i].frame == frame) { markers->push_back(markers_[i]); } } } -void Tracks::GetMarkersForTracksInBothImages(int clip1, int frame1, - int clip2, int frame2, +void Tracks::GetMarkersForTracksInBothImages(int clip1, + int frame1, + int clip2, + int frame2, vector<Marker>* markers) const { std::vector<int> image1_tracks; std::vector<int> image2_tracks; @@ -99,20 +99,19 @@ void Tracks::GetMarkersForTracksInBothImages(int clip1, int frame1, std::sort(image1_tracks.begin(), image1_tracks.end()); std::sort(image2_tracks.begin(), image2_tracks.end()); std::vector<int> intersection; - std::set_intersection(image1_tracks.begin(), image1_tracks.end(), - image2_tracks.begin(), image2_tracks.end(), + std::set_intersection(image1_tracks.begin(), + image1_tracks.end(), + image2_tracks.begin(), + image2_tracks.end(), std::back_inserter(intersection)); // Scan through and get the relevant tracks from the two images. for (int i = 0; i < markers_.size(); ++i) { // Save markers that are in either frame and are in our candidate set. - if (((markers_[i].clip == clip1 && - markers_[i].frame == frame1) || - (markers_[i].clip == clip2 && - markers_[i].frame == frame2)) && - std::binary_search(intersection.begin(), - intersection.end(), - markers_[i].track)) { + if (((markers_[i].clip == clip1 && markers_[i].frame == frame1) || + (markers_[i].clip == clip2 && markers_[i].frame == frame2)) && + std::binary_search( + intersection.begin(), intersection.end(), markers_[i].track)) { markers->push_back(markers_[i]); } } @@ -122,8 +121,7 @@ void Tracks::AddMarker(const Marker& marker) { // TODO(keir): This is quadratic for repeated insertions. Fix this by adding // a smarter data structure like a set<>. for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == marker.clip && - markers_[i].frame == marker.frame && + if (markers_[i].clip == marker.clip && markers_[i].frame == marker.frame && markers_[i].track == marker.track) { markers_[i] = marker; return; @@ -139,8 +137,7 @@ void Tracks::SetMarkers(vector<Marker>* markers) { bool Tracks::RemoveMarker(int clip, int frame, int track) { int size = markers_.size(); for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].clip == clip && - markers_[i].frame == frame && + if (markers_[i].clip == clip && markers_[i].frame == frame && markers_[i].track == track) { markers_[i] = markers_[size - 1]; markers_.resize(size - 1); diff --git a/intern/libmv/libmv/autotrack/tracks.h b/intern/libmv/libmv/autotrack/tracks.h index 0b7de91d211..dd11a2d6fbd 100644 --- a/intern/libmv/libmv/autotrack/tracks.h +++ b/intern/libmv/libmv/autotrack/tracks.h @@ -23,8 +23,8 @@ #ifndef LIBMV_AUTOTRACK_TRACKS_H_ #define LIBMV_AUTOTRACK_TRACKS_H_ -#include "libmv/base/vector.h" #include "libmv/autotrack/marker.h" +#include "libmv/base/vector.h" namespace mv { @@ -33,8 +33,8 @@ using libmv::vector; // The Tracks container stores correspondences between frames. class Tracks { public: - Tracks() { } - Tracks(const Tracks &other); + Tracks() {} + Tracks(const Tracks& other); // Create a tracks object with markers already initialized. Copies markers. explicit Tracks(const vector<Marker>& markers); @@ -51,8 +51,10 @@ class Tracks { // // This is not the same as the union of the markers in frame1 and // frame2; each marker is for a track that appears in both images. - void GetMarkersForTracksInBothImages(int clip1, int frame1, - int clip2, int frame2, + void GetMarkersForTracksInBothImages(int clip1, + int frame1, + int clip2, + int frame2, vector<Marker>* markers) const; void AddMarker(const Marker& marker); diff --git a/intern/libmv/libmv/autotrack/tracks_test.cc b/intern/libmv/libmv/autotrack/tracks_test.cc index 028b4a10913..eeefd3714b0 100644 --- a/intern/libmv/libmv/autotrack/tracks_test.cc +++ b/intern/libmv/libmv/autotrack/tracks_test.cc @@ -22,8 +22,8 @@ #include "libmv/autotrack/tracks.h" -#include "testing/testing.h" #include "libmv/logging/logging.h" +#include "testing/testing.h" namespace mv { diff --git a/intern/libmv/libmv/base/aligned_malloc.cc b/intern/libmv/libmv/base/aligned_malloc.cc index 5d3e05e9df9..6e327acf928 100644 --- a/intern/libmv/libmv/base/aligned_malloc.cc +++ b/intern/libmv/libmv/base/aligned_malloc.cc @@ -41,11 +41,11 @@ namespace libmv { -void *aligned_malloc(int size, int alignment) { +void* aligned_malloc(int size, int alignment) { #ifdef _WIN32 return _aligned_malloc(size, alignment); #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) - void *result; + void* result; if (posix_memalign(&result, alignment, size)) { // non-zero means allocation error @@ -58,7 +58,7 @@ void *aligned_malloc(int size, int alignment) { #endif } -void aligned_free(void *ptr) { +void aligned_free(void* ptr) { #ifdef _WIN32 _aligned_free(ptr); #else diff --git a/intern/libmv/libmv/base/aligned_malloc.h b/intern/libmv/libmv/base/aligned_malloc.h index 096ff6e2d7c..25583bb6be4 100644 --- a/intern/libmv/libmv/base/aligned_malloc.h +++ b/intern/libmv/libmv/base/aligned_malloc.h @@ -24,10 +24,10 @@ namespace libmv { // Allocate block of size bytes at least aligned to a given value. -void *aligned_malloc(int size, int alignment); +void* aligned_malloc(int size, int alignment); // Free memory allocated by aligned_malloc. -void aligned_free(void *ptr); +void aligned_free(void* ptr); } // namespace libmv diff --git a/intern/libmv/libmv/base/id_generator.h b/intern/libmv/libmv/base/id_generator.h index bf1eafd218e..535c9bd7b38 100644 --- a/intern/libmv/libmv/base/id_generator.h +++ b/intern/libmv/libmv/base/id_generator.h @@ -28,6 +28,7 @@ class IdGenerator { public: IdGenerator() : next_(0) {} ID Generate() { return next_++; } + private: ID next_; }; diff --git a/intern/libmv/libmv/base/map.h b/intern/libmv/libmv/base/map.h index 88b720f17fe..a91e3561791 100644 --- a/intern/libmv/libmv/base/map.h +++ b/intern/libmv/libmv/base/map.h @@ -26,8 +26,8 @@ namespace libmv { -using std::map; using std::make_pair; +using std::map; } // namespace libmv diff --git a/intern/libmv/libmv/base/scoped_ptr.h b/intern/libmv/libmv/base/scoped_ptr.h index b9cd4854213..9bfcfe1d615 100644 --- a/intern/libmv/libmv/base/scoped_ptr.h +++ b/intern/libmv/libmv/base/scoped_ptr.h @@ -30,44 +30,44 @@ namespace libmv { * A handle for a heap-allocated resource that should be freed when it goes out * of scope. This looks similar to the one found in TR1. */ -template<typename T> +template <typename T> class scoped_ptr { public: - scoped_ptr(T *resource) : resource_(resource) {} + scoped_ptr(T* resource) : resource_(resource) {} ~scoped_ptr() { reset(0); } - T *get() const { return resource_; } - T *operator->() const { return resource_; } - T &operator*() const { return *resource_; } + T* get() const { return resource_; } + T* operator->() const { return resource_; } + T& operator*() const { return *resource_; } - void reset(T *new_resource) { + void reset(T* new_resource) { if (sizeof(T)) { delete resource_; } resource_ = new_resource; } - T *release() { - T *released_resource = resource_; + T* release() { + T* released_resource = resource_; resource_ = 0; return released_resource; } private: // No copying allowed. - T *resource_; + T* resource_; }; // Same as scoped_ptr but caller must allocate the data // with new[] and the destructor will free the memory // using delete[]. -template<typename T> +template <typename T> class scoped_array { public: - scoped_array(T *array) : array_(array) {} + scoped_array(T* array) : array_(array) {} ~scoped_array() { reset(NULL); } - T *get() const { return array_; } + T* get() const { return array_; } T& operator[](std::ptrdiff_t i) const { assert(i >= 0); @@ -75,25 +75,27 @@ class scoped_array { return array_[i]; } - void reset(T *new_array) { + void reset(T* new_array) { if (sizeof(T)) { delete array_; } array_ = new_array; } - T *release() { - T *released_array = array_; + T* release() { + T* released_array = array_; array_ = NULL; return released_array; } private: - T *array_; + T* array_; // Forbid comparison of different scoped_array types. - template <typename T2> bool operator==(scoped_array<T2> const& p2) const; - template <typename T2> bool operator!=(scoped_array<T2> const& p2) const; + template <typename T2> + bool operator==(scoped_array<T2> const& p2) const; + template <typename T2> + bool operator!=(scoped_array<T2> const& p2) const; // Disallow evil constructors scoped_array(const scoped_array&); diff --git a/intern/libmv/libmv/base/scoped_ptr_test.cc b/intern/libmv/libmv/base/scoped_ptr_test.cc index ce1d56b500a..e86af6d4516 100644 --- a/intern/libmv/libmv/base/scoped_ptr_test.cc +++ b/intern/libmv/libmv/base/scoped_ptr_test.cc @@ -25,9 +25,9 @@ namespace libmv { namespace { struct FreeMe { - FreeMe(int *freed) : freed(freed) {} + FreeMe(int* freed) : freed(freed) {} ~FreeMe() { (*freed)++; } - int *freed; + int* freed; }; TEST(ScopedPtr, NullDoesNothing) { @@ -61,8 +61,8 @@ TEST(ScopedPtr, Reset) { TEST(ScopedPtr, ReleaseAndGet) { int frees = 0; - FreeMe *allocated = new FreeMe(&frees); - FreeMe *released = NULL; + FreeMe* allocated = new FreeMe(&frees); + FreeMe* released = NULL; { scoped_ptr<FreeMe> scoped(allocated); EXPECT_EQ(0, frees); diff --git a/intern/libmv/libmv/base/vector_test.cc b/intern/libmv/libmv/base/vector_test.cc index f171e3a18b5..d31bee751cd 100644 --- a/intern/libmv/libmv/base/vector_test.cc +++ b/intern/libmv/libmv/base/vector_test.cc @@ -19,9 +19,9 @@ // IN THE SOFTWARE. #include "libmv/base/vector.h" +#include <algorithm> #include "libmv/numeric/numeric.h" #include "testing/testing.h" -#include <algorithm> namespace { using namespace libmv; @@ -62,7 +62,7 @@ int foo_destruct_calls = 0; struct Foo { public: Foo() : value(5) { foo_construct_calls++; } - ~Foo() { foo_destruct_calls++; } + ~Foo() { foo_destruct_calls++; } int value; }; @@ -150,7 +150,7 @@ TEST_F(VectorTest, CopyConstructor) { a.push_back(3); vector<int> b(a); - EXPECT_EQ(a.size(), b.size()); + EXPECT_EQ(a.size(), b.size()); for (int i = 0; i < a.size(); ++i) { EXPECT_EQ(a[i], b[i]); } @@ -164,7 +164,7 @@ TEST_F(VectorTest, OperatorEquals) { b = a; - EXPECT_EQ(a.size(), b.size()); + EXPECT_EQ(a.size(), b.size()); for (int i = 0; i < a.size(); ++i) { EXPECT_EQ(a[i], b[i]); } diff --git a/intern/libmv/libmv/base/vector_utils.h b/intern/libmv/libmv/base/vector_utils.h index c71e1bea951..5f69c03d937 100644 --- a/intern/libmv/libmv/base/vector_utils.h +++ b/intern/libmv/libmv/base/vector_utils.h @@ -18,14 +18,13 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. - #ifndef LIBMV_BASE_VECTOR_UTILS_H_ #define LIBMV_BASE_VECTOR_UTILS_H_ /// Delete the contents of a container. template <class Array> -void DeleteElements(Array *array) { - for (int i = 0; i < array->size(); ++i) { +void DeleteElements(Array* array) { + for (int i = 0; i < array->size(); ++i) { delete (*array)[i]; } array->clear(); diff --git a/intern/libmv/libmv/image/array_nd.cc b/intern/libmv/libmv/image/array_nd.cc index 469a19aabf1..07feda33e66 100644 --- a/intern/libmv/libmv/image/array_nd.cc +++ b/intern/libmv/libmv/image/array_nd.cc @@ -18,18 +18,17 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "libmv/image/image.h" -#include <iostream> #include <cmath> +#include <iostream> +#include "libmv/image/image.h" namespace libmv { -void FloatArrayToScaledByteArray(const Array3Df &float_array, - Array3Du *byte_array, - bool automatic_range_detection - ) { +void FloatArrayToScaledByteArray(const Array3Df& float_array, + Array3Du* byte_array, + bool automatic_range_detection) { byte_array->ResizeLike(float_array); - float minval = HUGE_VAL; + float minval = HUGE_VAL; float maxval = -HUGE_VAL; if (automatic_range_detection) { for (int i = 0; i < float_array.Height(); ++i) { @@ -54,8 +53,8 @@ void FloatArrayToScaledByteArray(const Array3Df &float_array, } } -void ByteArrayToScaledFloatArray(const Array3Du &byte_array, - Array3Df *float_array) { +void ByteArrayToScaledFloatArray(const Array3Du& byte_array, + Array3Df* float_array) { float_array->ResizeLike(byte_array); for (int i = 0; i < byte_array.Height(); ++i) { for (int j = 0; j < byte_array.Width(); ++j) { @@ -66,10 +65,10 @@ void ByteArrayToScaledFloatArray(const Array3Du &byte_array, } } -void SplitChannels(const Array3Df &input, - Array3Df *channel0, - Array3Df *channel1, - Array3Df *channel2) { +void SplitChannels(const Array3Df& input, + Array3Df* channel0, + Array3Df* channel1, + Array3Df* channel2) { assert(input.Depth() >= 3); channel0->Resize(input.Height(), input.Width()); channel1->Resize(input.Height(), input.Width()); @@ -83,7 +82,7 @@ void SplitChannels(const Array3Df &input, } } -void PrintArray(const Array3Df &array) { +void PrintArray(const Array3Df& array) { using namespace std; printf("[\n"); diff --git a/intern/libmv/libmv/image/array_nd.h b/intern/libmv/libmv/image/array_nd.h index e95e66aa2b3..1a3c39d0461 100644 --- a/intern/libmv/libmv/image/array_nd.h +++ b/intern/libmv/libmv/image/array_nd.h @@ -44,13 +44,13 @@ class ArrayND : public BaseArray { ArrayND() : data_(NULL), own_data_(true) { Resize(Index(0)); } /// Create an array with the specified shape. - ArrayND(const Index &shape) : data_(NULL), own_data_(true) { Resize(shape); } + ArrayND(const Index& shape) : data_(NULL), own_data_(true) { Resize(shape); } /// Create an array with the specified shape. - ArrayND(int *shape) : data_(NULL), own_data_(true) { Resize(shape); } + ArrayND(int* shape) : data_(NULL), own_data_(true) { Resize(shape); } /// Copy constructor. - ArrayND(const ArrayND<T, N> &b) : data_(NULL), own_data_(true) { + ArrayND(const ArrayND<T, N>& b) : data_(NULL), own_data_(true) { ResizeLike(b); std::memcpy(Data(), b.Data(), sizeof(T) * Size()); } @@ -58,7 +58,7 @@ class ArrayND : public BaseArray { ArrayND(int s0) : data_(NULL), own_data_(true) { Resize(s0); } ArrayND(int s0, int s1) : data_(NULL), own_data_(true) { Resize(s0, s1); } ArrayND(int s0, int s1, int s2) : data_(NULL), own_data_(true) { - Resize(s0, s1, s2); + Resize(s0, s1, s2); } ArrayND(T* data, int s0, int s1, int s2) @@ -69,28 +69,24 @@ class ArrayND : public BaseArray { /// Destructor deletes pixel data. ~ArrayND() { if (own_data_) { - delete [] data_; + delete[] data_; } } /// Assignation copies pixel data. - ArrayND &operator=(const ArrayND<T, N> &b) { + ArrayND& operator=(const ArrayND<T, N>& b) { assert(this != &b); ResizeLike(b); std::memcpy(Data(), b.Data(), sizeof(T) * Size()); return *this; } - const Index &Shapes() const { - return shape_; - } + const Index& Shapes() const { return shape_; } - const Index &Strides() const { - return strides_; - } + const Index& Strides() const { return strides_; } /// Create an array of shape s. - void Resize(const Index &new_shape) { + void Resize(const Index& new_shape) { if (data_ != NULL && shape_ == new_shape) { // Don't bother realloacting if the shapes match. return; @@ -101,7 +97,7 @@ class ArrayND : public BaseArray { strides_(i - 1) = strides_(i) * shape_(i); } if (own_data_) { - delete [] data_; + delete[] data_; data_ = NULL; if (Size() > 0) { data_ = new T[Size()]; @@ -109,15 +105,13 @@ class ArrayND : public BaseArray { } } - template<typename D> - void ResizeLike(const ArrayND<D, N> &other) { + template <typename D> + void ResizeLike(const ArrayND<D, N>& other) { Resize(other.Shape()); } /// Resizes the array to shape s. All data is lost. - void Resize(const int *new_shape_array) { - Resize(Index(new_shape_array)); - } + void Resize(const int* new_shape_array) { Resize(Index(new_shape_array)); } /// Resize a 1D array to length s0. void Resize(int s0) { @@ -136,9 +130,7 @@ class ArrayND : public BaseArray { } // Match Eigen2's API. - void resize(int rows, int cols) { - Resize(rows, cols); - } + void resize(int rows, int cols) { Resize(rows, cols); } /// Resize a 3D array to shape (s0,s1,s2). void Resize(int s0, int s1, int s2) { @@ -147,11 +139,11 @@ class ArrayND : public BaseArray { Resize(shape); } - template<typename D> - void CopyFrom(const ArrayND<D, N> &other) { + template <typename D> + void CopyFrom(const ArrayND<D, N>& other) { ResizeLike(other); - T *data = Data(); - const D *other_data = other.Data(); + T* data = Data(); + const D* other_data = other.Data(); for (int i = 0; i < Size(); ++i) { data[i] = T(other_data[i]); } @@ -171,19 +163,13 @@ class ArrayND : public BaseArray { } /// Return a tuple containing the length of each axis. - const Index &Shape() const { - return shape_; - } + const Index& Shape() const { return shape_; } /// Return the length of an axis. - int Shape(int axis) const { - return shape_(axis); - } + int Shape(int axis) const { return shape_(axis); } /// Return the distance between neighboring elements along axis. - int Stride(int axis) const { - return strides_(axis); - } + int Stride(int axis) const { return strides_(axis); } /// Return the number of elements of the array. int Size() const { @@ -194,18 +180,16 @@ class ArrayND : public BaseArray { } /// Return the total amount of memory used by the array. - int MemorySizeInBytes() const { - return sizeof(*this) + Size() * sizeof(T); - } + int MemorySizeInBytes() const { return sizeof(*this) + Size() * sizeof(T); } /// Pointer to the first element of the array. - T *Data() { return data_; } + T* Data() { return data_; } /// Constant pointer to the first element of the array. - const T *Data() const { return data_; } + const T* Data() const { return data_; } /// Distance between the first element and the element at position index. - int Offset(const Index &index) const { + int Offset(const Index& index) const { int offset = 0; for (int i = 0; i < N; ++i) offset += index(i) * Stride(i); @@ -231,25 +215,23 @@ class ArrayND : public BaseArray { } /// Return a reference to the element at position index. - T &operator()(const Index &index) { + T& operator()(const Index& index) { // TODO(pau) Boundary checking in debug mode. - return *( Data() + Offset(index) ); + return *(Data() + Offset(index)); } /// 1D specialization. - T &operator()(int i0) { - return *( Data() + Offset(i0) ); - } + T& operator()(int i0) { return *(Data() + Offset(i0)); } /// 2D specialization. - T &operator()(int i0, int i1) { + T& operator()(int i0, int i1) { assert(0 <= i0 && i0 < Shape(0)); assert(0 <= i1 && i1 < Shape(1)); return *(Data() + Offset(i0, i1)); } /// 3D specialization. - T &operator()(int i0, int i1, int i2) { + T& operator()(int i0, int i1, int i2) { assert(0 <= i0 && i0 < Shape(0)); assert(0 <= i1 && i1 < Shape(1)); assert(0 <= i2 && i2 < Shape(2)); @@ -257,29 +239,27 @@ class ArrayND : public BaseArray { } /// Return a constant reference to the element at position index. - const T &operator()(const Index &index) const { + const T& operator()(const Index& index) const { return *(Data() + Offset(index)); } /// 1D specialization. - const T &operator()(int i0) const { - return *(Data() + Offset(i0)); - } + const T& operator()(int i0) const { return *(Data() + Offset(i0)); } /// 2D specialization. - const T &operator()(int i0, int i1) const { + const T& operator()(int i0, int i1) const { assert(0 <= i0 && i0 < Shape(0)); assert(0 <= i1 && i1 < Shape(1)); return *(Data() + Offset(i0, i1)); } /// 3D specialization. - const T &operator()(int i0, int i1, int i2) const { + const T& operator()(int i0, int i1, int i2) const { return *(Data() + Offset(i0, i1, i2)); } /// True if index is inside array. - bool Contains(const Index &index) const { + bool Contains(const Index& index) const { for (int i = 0; i < N; ++i) if (index(i) < 0 || index(i) >= Shape(i)) return false; @@ -287,26 +267,24 @@ class ArrayND : public BaseArray { } /// 1D specialization. - bool Contains(int i0) const { - return 0 <= i0 && i0 < Shape(0); - } + bool Contains(int i0) const { return 0 <= i0 && i0 < Shape(0); } /// 2D specialization. bool Contains(int i0, int i1) const { - return 0 <= i0 && i0 < Shape(0) - && 0 <= i1 && i1 < Shape(1); + return 0 <= i0 && i0 < Shape(0) && 0 <= i1 && i1 < Shape(1); } /// 3D specialization. bool Contains(int i0, int i1, int i2) const { - return 0 <= i0 && i0 < Shape(0) - && 0 <= i1 && i1 < Shape(1) - && 0 <= i2 && i2 < Shape(2); + return 0 <= i0 && i0 < Shape(0) && 0 <= i1 && i1 < Shape(1) && 0 <= i2 && + i2 < Shape(2); } - bool operator==(const ArrayND<T, N> &other) const { - if (shape_ != other.shape_) return false; - if (strides_ != other.strides_) return false; + bool operator==(const ArrayND<T, N>& other) const { + if (shape_ != other.shape_) + return false; + if (strides_ != other.strides_) + return false; for (int i = 0; i < Size(); ++i) { if (this->Data()[i] != other.Data()[i]) return false; @@ -314,11 +292,11 @@ class ArrayND : public BaseArray { return true; } - bool operator!=(const ArrayND<T, N> &other) const { + bool operator!=(const ArrayND<T, N>& other) const { return !(*this == other); } - ArrayND<T, N> operator*(const ArrayND<T, N> &other) const { + ArrayND<T, N> operator*(const ArrayND<T, N>& other) const { assert(Shape() = other.Shape()); ArrayND<T, N> res; res.ResizeLike(*this); @@ -336,7 +314,7 @@ class ArrayND : public BaseArray { Index strides_; /// Pointer to the first element of the array. - T *data_; + T* data_; /// Flag if this Array either own or reference the data bool own_data_; @@ -346,30 +324,20 @@ class ArrayND : public BaseArray { template <typename T> class Array3D : public ArrayND<T, 3> { typedef ArrayND<T, 3> Base; + public: - Array3D() - : Base() { - } - Array3D(int height, int width, int depth = 1) - : Base(height, width, depth) { - } + Array3D() : Base() {} + Array3D(int height, int width, int depth = 1) : Base(height, width, depth) {} Array3D(T* data, int height, int width, int depth = 1) - : Base(data, height, width, depth) { - } + : Base(data, height, width, depth) {} void Resize(int height, int width, int depth = 1) { Base::Resize(height, width, depth); } - int Height() const { - return Base::Shape(0); - } - int Width() const { - return Base::Shape(1); - } - int Depth() const { - return Base::Shape(2); - } + int Height() const { return Base::Shape(0); } + int Width() const { return Base::Shape(1); } + int Depth() const { return Base::Shape(2); } // Match Eigen2's API so that Array3D's and Mat*'s can work together via // template magic. @@ -377,15 +345,15 @@ class Array3D : public ArrayND<T, 3> { int cols() const { return Width(); } int depth() const { return Depth(); } - int Get_Step() const { return Width()*Depth(); } + int Get_Step() const { return Width() * Depth(); } /// Enable accessing with 2 indices for grayscale images. - T &operator()(int i0, int i1, int i2 = 0) { + T& operator()(int i0, int i1, int i2 = 0) { assert(0 <= i0 && i0 < Height()); assert(0 <= i1 && i1 < Width()); return Base::operator()(i0, i1, i2); } - const T &operator()(int i0, int i1, int i2 = 0) const { + const T& operator()(int i0, int i1, int i2 = 0) const { assert(0 <= i0 && i0 < Height()); assert(0 <= i1 && i1 < Width()); return Base::operator()(i0, i1, i2); @@ -398,31 +366,29 @@ typedef Array3D<int> Array3Di; typedef Array3D<float> Array3Df; typedef Array3D<short> Array3Ds; -void SplitChannels(const Array3Df &input, - Array3Df *channel0, - Array3Df *channel1, - Array3Df *channel2); +void SplitChannels(const Array3Df& input, + Array3Df* channel0, + Array3Df* channel1, + Array3Df* channel2); -void PrintArray(const Array3Df &array); +void PrintArray(const Array3Df& array); /** Convert a float array into a byte array by scaling values by 255* (max-min). - * where max and min are automatically detected + * where max and min are automatically detected * (if automatic_range_detection = true) * \note and TODO this automatic detection only works when the image contains * at least one pixel of both bounds. **/ -void FloatArrayToScaledByteArray(const Array3Df &float_array, - Array3Du *byte_array, +void FloatArrayToScaledByteArray(const Array3Df& float_array, + Array3Du* byte_array, bool automatic_range_detection = false); //! Convert a byte array into a float array by dividing values by 255. -void ByteArrayToScaledFloatArray(const Array3Du &byte_array, - Array3Df *float_array); +void ByteArrayToScaledFloatArray(const Array3Du& byte_array, + Array3Df* float_array); template <typename AArrayType, typename BArrayType, typename CArrayType> -void MultiplyElements(const AArrayType &a, - const BArrayType &b, - CArrayType *c) { +void MultiplyElements(const AArrayType& a, const BArrayType& b, CArrayType* c) { // This function does an element-wise multiply between // the two Arrays A and B, and stores the result in C. // A and B must have the same dimensions. @@ -435,7 +401,7 @@ void MultiplyElements(const AArrayType &a, // The index starts at the maximum value for each dimension const typename CArrayType::Index& cShape = c->Shape(); - for ( int i = 0; i < CArrayType::Index::SIZE; ++i ) + for (int i = 0; i < CArrayType::Index::SIZE; ++i) index(i) = cShape(i) - 1; // After each multiplication, the highest-dimensional index is reduced. @@ -443,12 +409,12 @@ void MultiplyElements(const AArrayType &a, // and decrements the index of the next lower dimension. // This ripple-action continues until the entire new array has been // calculated, indicated by dimension zero having a negative index. - while ( index(0) >= 0 ) { + while (index(0) >= 0) { (*c)(index) = a(index) * b(index); int dimension = CArrayType::Index::SIZE - 1; index(dimension) = index(dimension) - 1; - while ( dimension > 0 && index(dimension) < 0 ) { + while (dimension > 0 && index(dimension) < 0) { index(dimension) = cShape(dimension) - 1; index(dimension - 1) = index(dimension - 1) - 1; --dimension; @@ -457,9 +423,9 @@ void MultiplyElements(const AArrayType &a, } template <typename TA, typename TB, typename TC> -void MultiplyElements(const ArrayND<TA, 3> &a, - const ArrayND<TB, 3> &b, - ArrayND<TC, 3> *c) { +void MultiplyElements(const ArrayND<TA, 3>& a, + const ArrayND<TB, 3>& b, + ArrayND<TC, 3>* c) { // Specialization for N==3 c->ResizeLike(a); assert(a.Shape(0) == b.Shape(0)); @@ -475,9 +441,9 @@ void MultiplyElements(const ArrayND<TA, 3> &a, } template <typename TA, typename TB, typename TC> -void MultiplyElements(const Array3D<TA> &a, - const Array3D<TB> &b, - Array3D<TC> *c) { +void MultiplyElements(const Array3D<TA>& a, + const Array3D<TB>& b, + Array3D<TC>* c) { // Specialization for N==3 c->ResizeLike(a); assert(a.Shape(0) == b.Shape(0)); diff --git a/intern/libmv/libmv/image/array_nd_test.cc b/intern/libmv/libmv/image/array_nd_test.cc index dc7cfacf90d..67838d34051 100644 --- a/intern/libmv/libmv/image/array_nd_test.cc +++ b/intern/libmv/libmv/image/array_nd_test.cc @@ -21,9 +21,9 @@ #include "libmv/image/array_nd.h" #include "testing/testing.h" -using libmv::ArrayND; using libmv::Array3D; using libmv::Array3Df; +using libmv::ArrayND; namespace { @@ -100,7 +100,7 @@ TEST(ArrayND, Size) { int l[] = {0, 1, 2}; ArrayND<int, 3>::Index last(l); - EXPECT_EQ(a.Size(), a.Offset(last)+1); + EXPECT_EQ(a.Size(), a.Offset(last) + 1); EXPECT_TRUE(a.Contains(last)); EXPECT_FALSE(a.Contains(shape)); } @@ -120,8 +120,8 @@ TEST(ArrayND, Parenthesis) { int s[] = {3, 3}; ArrayND<int, 2> a(s); - *(a.Data()+0) = 0; - *(a.Data()+5) = 5; + *(a.Data() + 0) = 0; + *(a.Data() + 5) = 5; int i1[] = {0, 0}; EXPECT_EQ(0, a(Index(i1))); @@ -210,7 +210,7 @@ TEST(ArrayND, MultiplyElements) { b(1, 1, 0) = 3; ArrayND<int, 3> c; MultiplyElements(a, b, &c); - EXPECT_FLOAT_EQ(6, c(0, 0, 0)); + EXPECT_FLOAT_EQ(6, c(0, 0, 0)); EXPECT_FLOAT_EQ(10, c(0, 1, 0)); EXPECT_FLOAT_EQ(12, c(1, 0, 0)); EXPECT_FLOAT_EQ(12, c(1, 1, 0)); diff --git a/intern/libmv/libmv/image/convolve.cc b/intern/libmv/libmv/image/convolve.cc index 464043581d2..478e320377d 100644 --- a/intern/libmv/libmv/image/convolve.cc +++ b/intern/libmv/libmv/image/convolve.cc @@ -29,7 +29,7 @@ namespace libmv { // Compute a Gaussian kernel and derivative, such that you can take the // derivative of an image by convolving with the kernel horizontally then the // derivative vertically to get (eg) the y derivative. -void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) { +void ComputeGaussianKernel(double sigma, Vec* kernel, Vec* derivative) { assert(sigma >= 0.0); // 0.004 implies a 3 pixel kernel with 1 pixel sigma. @@ -37,7 +37,7 @@ void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) { // Calculate the kernel size based on sigma such that it is odd. float precisehalfwidth = GaussianInversePositive(truncation_factor, sigma); - int width = lround(2*precisehalfwidth); + int width = lround(2 * precisehalfwidth); if (width % 2 == 0) { width++; } @@ -47,7 +47,7 @@ void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) { kernel->setZero(); derivative->setZero(); int halfwidth = width / 2; - for (int i = -halfwidth; i <= halfwidth; ++i) { + for (int i = -halfwidth; i <= halfwidth; ++i) { (*kernel)(i + halfwidth) = Gaussian(i, sigma); (*derivative)(i + halfwidth) = GaussianDerivative(i, sigma); } @@ -57,16 +57,21 @@ void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative) { // Normalize the derivative differently. See // www.cs.duke.edu/courses/spring03/cps296.1/handouts/Image%20Processing.pdf double factor = 0.; - for (int i = -halfwidth; i <= halfwidth; ++i) { - factor -= i*(*derivative)(i+halfwidth); + for (int i = -halfwidth; i <= halfwidth; ++i) { + factor -= i * (*derivative)(i + halfwidth); } *derivative /= factor; } template <int size, bool vertical> -void FastConvolve(const Vec &kernel, int width, int height, - const float* src, int src_stride, int src_line_stride, - float* dst, int dst_stride) { +void FastConvolve(const Vec& kernel, + int width, + int height, + const float* src, + int src_stride, + int src_line_stride, + float* dst, + int dst_stride) { double coefficients[2 * size + 1]; for (int k = 0; k < 2 * size + 1; ++k) { coefficients[k] = kernel(2 * size - k); @@ -93,14 +98,14 @@ void FastConvolve(const Vec &kernel, int width, int height, } } -template<bool vertical> -void Convolve(const Array3Df &in, - const Vec &kernel, - Array3Df *out_pointer, +template <bool vertical> +void Convolve(const Array3Df& in, + const Vec& kernel, + Array3Df* out_pointer, int plane) { int width = in.Width(); int height = in.Height(); - Array3Df &out = *out_pointer; + Array3Df& out = *out_pointer; if (plane == -1) { out.ResizeLike(in); plane = 0; @@ -119,61 +124,62 @@ void Convolve(const Array3Df &in, // fast path. int half_width = kernel.size() / 2; switch (half_width) { -#define static_convolution(size) case size: \ - FastConvolve<size, vertical>(kernel, width, height, src, src_stride, \ - src_line_stride, dst, dst_stride); break; - static_convolution(1) - static_convolution(2) - static_convolution(3) - static_convolution(4) - static_convolution(5) - static_convolution(6) - static_convolution(7) +#define static_convolution(size) \ + case size: \ + FastConvolve<size, vertical>(kernel, \ + width, \ + height, \ + src, \ + src_stride, \ + src_line_stride, \ + dst, \ + dst_stride); \ + break; + static_convolution(1) static_convolution(2) static_convolution(3) + static_convolution(4) static_convolution(5) static_convolution(6) + static_convolution(7) #undef static_convolution - default: - int dynamic_size = kernel.size() / 2; - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - double sum = 0; - // Slow path: this loop cannot be unrolled. - for (int k = -dynamic_size; k <= dynamic_size; ++k) { - if (vertical) { - if (y + k >= 0 && y + k < height) { - sum += src[k * src_line_stride] * - kernel(2 * dynamic_size - (k + dynamic_size)); - } - } else { - if (x + k >= 0 && x + k < width) { - sum += src[k * src_stride] * - kernel(2 * dynamic_size - (k + dynamic_size)); - } + default : int dynamic_size = kernel.size() / 2; + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + double sum = 0; + // Slow path: this loop cannot be unrolled. + for (int k = -dynamic_size; k <= dynamic_size; ++k) { + if (vertical) { + if (y + k >= 0 && y + k < height) { + sum += src[k * src_line_stride] * + kernel(2 * dynamic_size - (k + dynamic_size)); + } + } else { + if (x + k >= 0 && x + k < width) { + sum += src[k * src_stride] * + kernel(2 * dynamic_size - (k + dynamic_size)); } } - dst[0] = static_cast<float>(sum); - src += src_stride; - dst += dst_stride; } + dst[0] = static_cast<float>(sum); + src += src_stride; + dst += dst_stride; } + } } } -void ConvolveHorizontal(const Array3Df &in, - const Vec &kernel, - Array3Df *out_pointer, +void ConvolveHorizontal(const Array3Df& in, + const Vec& kernel, + Array3Df* out_pointer, int plane) { Convolve<false>(in, kernel, out_pointer, plane); } -void ConvolveVertical(const Array3Df &in, - const Vec &kernel, - Array3Df *out_pointer, +void ConvolveVertical(const Array3Df& in, + const Vec& kernel, + Array3Df* out_pointer, int plane) { Convolve<true>(in, kernel, out_pointer, plane); } -void ConvolveGaussian(const Array3Df &in, - double sigma, - Array3Df *out_pointer) { +void ConvolveGaussian(const Array3Df& in, double sigma, Array3Df* out_pointer) { Vec kernel, derivative; ComputeGaussianKernel(sigma, &kernel, &derivative); @@ -182,10 +188,10 @@ void ConvolveGaussian(const Array3Df &in, ConvolveHorizontal(tmp, kernel, out_pointer); } -void ImageDerivatives(const Array3Df &in, +void ImageDerivatives(const Array3Df& in, double sigma, - Array3Df *gradient_x, - Array3Df *gradient_y) { + Array3Df* gradient_x, + Array3Df* gradient_y) { Vec kernel, derivative; ComputeGaussianKernel(sigma, &kernel, &derivative); Array3Df tmp; @@ -199,11 +205,11 @@ void ImageDerivatives(const Array3Df &in, ConvolveVertical(tmp, derivative, gradient_y); } -void BlurredImageAndDerivatives(const Array3Df &in, +void BlurredImageAndDerivatives(const Array3Df& in, double sigma, - Array3Df *blurred_image, - Array3Df *gradient_x, - Array3Df *gradient_y) { + Array3Df* blurred_image, + Array3Df* gradient_x, + Array3Df* gradient_y) { Vec kernel, derivative; ComputeGaussianKernel(sigma, &kernel, &derivative); Array3Df tmp; @@ -224,9 +230,9 @@ void BlurredImageAndDerivatives(const Array3Df &in, // image, and store the results in three channels. Since the blurred value and // gradients are closer in memory, this leads to better performance if all // three values are needed at the same time. -void BlurredImageAndDerivativesChannels(const Array3Df &in, +void BlurredImageAndDerivativesChannels(const Array3Df& in, double sigma, - Array3Df *blurred_and_gradxy) { + Array3Df* blurred_and_gradxy) { assert(in.Depth() == 1); Vec kernel, derivative; @@ -246,10 +252,10 @@ void BlurredImageAndDerivativesChannels(const Array3Df &in, ConvolveVertical(tmp, derivative, blurred_and_gradxy, 2); } -void BoxFilterHorizontal(const Array3Df &in, +void BoxFilterHorizontal(const Array3Df& in, int window_size, - Array3Df *out_pointer) { - Array3Df &out = *out_pointer; + Array3Df* out_pointer) { + Array3Df& out = *out_pointer; out.ResizeLike(in); int half_width = (window_size - 1) / 2; @@ -266,7 +272,7 @@ void BoxFilterHorizontal(const Array3Df &in, out(i, j, k) = sum; } // Fill interior. - for (int j = half_width + 1; j < in.Width()-half_width; ++j) { + for (int j = half_width + 1; j < in.Width() - half_width; ++j) { sum -= in(i, j - half_width - 1, k); sum += in(i, j + half_width, k); out(i, j, k) = sum; @@ -280,10 +286,10 @@ void BoxFilterHorizontal(const Array3Df &in, } } -void BoxFilterVertical(const Array3Df &in, +void BoxFilterVertical(const Array3Df& in, int window_size, - Array3Df *out_pointer) { - Array3Df &out = *out_pointer; + Array3Df* out_pointer) { + Array3Df& out = *out_pointer; out.ResizeLike(in); int half_width = (window_size - 1) / 2; @@ -300,7 +306,7 @@ void BoxFilterVertical(const Array3Df &in, out(i, j, k) = sum; } // Fill interior. - for (int i = half_width + 1; i < in.Height()-half_width; ++i) { + for (int i = half_width + 1; i < in.Height() - half_width; ++i) { sum -= in(i - half_width - 1, j, k); sum += in(i + half_width, j, k); out(i, j, k) = sum; @@ -314,9 +320,7 @@ void BoxFilterVertical(const Array3Df &in, } } -void BoxFilter(const Array3Df &in, - int box_width, - Array3Df *out) { +void BoxFilter(const Array3Df& in, int box_width, Array3Df* out) { Array3Df tmp; BoxFilterHorizontal(in, box_width, &tmp); BoxFilterVertical(tmp, box_width, out); @@ -327,17 +331,17 @@ void LaplaceFilter(unsigned char* src, int width, int height, int strength) { - for (int y = 1; y < height-1; y++) - for (int x = 1; x < width-1; x++) { - const unsigned char* s = &src[y*width+x]; - int l = 128 + - s[-width-1] + s[-width] + s[-width+1] + - s[1] - 8*s[0] + s[1] + - s[ width-1] + s[ width] + s[ width+1]; - int d = ((256-strength)*s[0] + strength*l) / 256; - if (d < 0) d=0; - if (d > 255) d=255; - dst[y*width+x] = d; + for (int y = 1; y < height - 1; y++) + for (int x = 1; x < width - 1; x++) { + const unsigned char* s = &src[y * width + x]; + int l = 128 + s[-width - 1] + s[-width] + s[-width + 1] + s[1] - + 8 * s[0] + s[1] + s[width - 1] + s[width] + s[width + 1]; + int d = ((256 - strength) * s[0] + strength * l) / 256; + if (d < 0) + d = 0; + if (d > 255) + d = 255; + dst[y * width + x] = d; } } diff --git a/intern/libmv/libmv/image/convolve.h b/intern/libmv/libmv/image/convolve.h index d3b6da9794b..3794550eb73 100644 --- a/intern/libmv/libmv/image/convolve.h +++ b/intern/libmv/libmv/image/convolve.h @@ -30,70 +30,71 @@ namespace libmv { // Zero mean Gaussian. inline double Gaussian(double x, double sigma) { - return 1/sqrt(2*M_PI*sigma*sigma) * exp(-(x*x/2/sigma/sigma)); + return 1 / sqrt(2 * M_PI * sigma * sigma) * exp(-(x * x / 2 / sigma / sigma)); } // 2D gaussian (zero mean) // (9) in http://mathworld.wolfram.com/GaussianFunction.html inline double Gaussian2D(double x, double y, double sigma) { - return 1.0/(2.0*M_PI*sigma*sigma) * exp( -(x*x+y*y)/(2.0*sigma*sigma)); + return 1.0 / (2.0 * M_PI * sigma * sigma) * + exp(-(x * x + y * y) / (2.0 * sigma * sigma)); } inline double GaussianDerivative(double x, double sigma) { return -x / sigma / sigma * Gaussian(x, sigma); } // Solve the inverse of the Gaussian for positive x. inline double GaussianInversePositive(double y, double sigma) { - return sqrt(-2 * sigma * sigma * log(y * sigma * sqrt(2*M_PI))); + return sqrt(-2 * sigma * sigma * log(y * sigma * sqrt(2 * M_PI))); } -void ComputeGaussianKernel(double sigma, Vec *kernel, Vec *derivative); -void ConvolveHorizontal(const FloatImage &in, - const Vec &kernel, - FloatImage *out_pointer, +void ComputeGaussianKernel(double sigma, Vec* kernel, Vec* derivative); +void ConvolveHorizontal(const FloatImage& in, + const Vec& kernel, + FloatImage* out_pointer, int plane = -1); -void ConvolveVertical(const FloatImage &in, - const Vec &kernel, - FloatImage *out_pointer, +void ConvolveVertical(const FloatImage& in, + const Vec& kernel, + FloatImage* out_pointer, int plane = -1); -void ConvolveGaussian(const FloatImage &in, +void ConvolveGaussian(const FloatImage& in, double sigma, - FloatImage *out_pointer); + FloatImage* out_pointer); -void ImageDerivatives(const FloatImage &in, +void ImageDerivatives(const FloatImage& in, double sigma, - FloatImage *gradient_x, - FloatImage *gradient_y); + FloatImage* gradient_x, + FloatImage* gradient_y); -void BlurredImageAndDerivatives(const FloatImage &in, +void BlurredImageAndDerivatives(const FloatImage& in, double sigma, - FloatImage *blurred_image, - FloatImage *gradient_x, - FloatImage *gradient_y); + FloatImage* blurred_image, + FloatImage* gradient_x, + FloatImage* gradient_y); // Blur and take the gradients of an image, storing the results inside the // three channels of blurred_and_gradxy. -void BlurredImageAndDerivativesChannels(const FloatImage &in, +void BlurredImageAndDerivativesChannels(const FloatImage& in, double sigma, - FloatImage *blurred_and_gradxy); + FloatImage* blurred_and_gradxy); -void BoxFilterHorizontal(const FloatImage &in, +void BoxFilterHorizontal(const FloatImage& in, int window_size, - FloatImage *out_pointer); + FloatImage* out_pointer); -void BoxFilterVertical(const FloatImage &in, +void BoxFilterVertical(const FloatImage& in, int window_size, - FloatImage *out_pointer); + FloatImage* out_pointer); -void BoxFilter(const FloatImage &in, - int box_width, - FloatImage *out); +void BoxFilter(const FloatImage& in, int box_width, FloatImage* out); /*! Convolve \a src into \a dst with the discrete laplacian operator. \a src and \a dst should be \a width x \a height images. - \a strength is an interpolation coefficient (0-256) between original image and the laplacian. + \a strength is an interpolation coefficient (0-256) between original image + and the laplacian. - \note Make sure the search region is filtered with the same strength as the pattern. + \note Make sure the search region is filtered with the same strength as the + pattern. */ void LaplaceFilter(unsigned char* src, unsigned char* dst, @@ -104,4 +105,3 @@ void LaplaceFilter(unsigned char* src, } // namespace libmv #endif // LIBMV_IMAGE_CONVOLVE_H_ - diff --git a/intern/libmv/libmv/image/convolve_test.cc b/intern/libmv/libmv/image/convolve_test.cc index 0cdef8e1e72..1ad4cb9a40e 100644 --- a/intern/libmv/libmv/image/convolve_test.cc +++ b/intern/libmv/libmv/image/convolve_test.cc @@ -85,26 +85,26 @@ TEST(Convolve, BlurredImageAndDerivativesChannelsHorizontalSlope) { FloatImage image(10, 10), blurred_and_derivatives; for (int j = 0; j < 10; ++j) { for (int i = 0; i < 10; ++i) { - image(j, i) = 2*i; + image(j, i) = 2 * i; } } BlurredImageAndDerivativesChannels(image, 0.9, &blurred_and_derivatives); EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 10.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 2.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 0.0, 1e-7); + EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 2.0, 1e-7); + EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 0.0, 1e-7); } TEST(Convolve, BlurredImageAndDerivativesChannelsVerticalSlope) { FloatImage image(10, 10), blurred_and_derivatives; for (int j = 0; j < 10; ++j) { for (int i = 0; i < 10; ++i) { - image(j, i) = 2*j; + image(j, i) = 2 * j; } } BlurredImageAndDerivativesChannels(image, 0.9, &blurred_and_derivatives); EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 10.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 0.0, 1e-7); - EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 2.0, 1e-7); + EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 0.0, 1e-7); + EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 2.0, 1e-7); } } // namespace diff --git a/intern/libmv/libmv/image/correlation.h b/intern/libmv/libmv/image/correlation.h index c354f7e891e..25123efe8d0 100644 --- a/intern/libmv/libmv/image/correlation.h +++ b/intern/libmv/libmv/image/correlation.h @@ -21,14 +21,14 @@ #ifndef LIBMV_IMAGE_CORRELATION_H #define LIBMV_IMAGE_CORRELATION_H -#include "libmv/logging/logging.h" #include "libmv/image/image.h" +#include "libmv/logging/logging.h" namespace libmv { inline double PearsonProductMomentCorrelation( - const FloatImage &image_and_gradient1_sampled, - const FloatImage &image_and_gradient2_sampled) { + const FloatImage& image_and_gradient1_sampled, + const FloatImage& image_and_gradient2_sampled) { assert(image_and_gradient1_sampled.Width() == image_and_gradient2_sampled.Width()); assert(image_and_gradient1_sampled.Height() == @@ -63,9 +63,8 @@ inline double PearsonProductMomentCorrelation( double covariance_xy = sXY - sX * sY; double correlation = covariance_xy / sqrt(var_x * var_y); - LG << "Covariance xy: " << covariance_xy - << ", var 1: " << var_x << ", var 2: " << var_y - << ", correlation: " << correlation; + LG << "Covariance xy: " << covariance_xy << ", var 1: " << var_x + << ", var 2: " << var_y << ", correlation: " << correlation; return correlation; } diff --git a/intern/libmv/libmv/image/image.h b/intern/libmv/libmv/image/image.h index e0f200a4c93..40d6aa6f70a 100644 --- a/intern/libmv/libmv/image/image.h +++ b/intern/libmv/libmv/image/image.h @@ -39,14 +39,11 @@ typedef Array3Ds ShortImage; // is the best solution after all. class Image { public: - // Create an image from an array. The image takes ownership of the array. - Image(Array3Du *array) : array_type_(BYTE), array_(array) {} - Image(Array3Df *array) : array_type_(FLOAT), array_(array) {} + Image(Array3Du* array) : array_type_(BYTE), array_(array) {} + Image(Array3Df* array) : array_type_(FLOAT), array_(array) {} - Image(const Image &img): array_type_(NONE), array_(NULL) { - *this = img; - } + Image(const Image& img) : array_type_(NONE), array_(NULL) { *this = img; } // Underlying data type. enum DataType { @@ -62,20 +59,18 @@ class Image { int size; switch (array_type_) { case BYTE: - size = reinterpret_cast<Array3Du *>(array_)->MemorySizeInBytes(); - break; + size = reinterpret_cast<Array3Du*>(array_)->MemorySizeInBytes(); + break; case FLOAT: - size = reinterpret_cast<Array3Df *>(array_)->MemorySizeInBytes(); - break; + size = reinterpret_cast<Array3Df*>(array_)->MemorySizeInBytes(); + break; case INT: - size = reinterpret_cast<Array3Di *>(array_)->MemorySizeInBytes(); - break; + size = reinterpret_cast<Array3Di*>(array_)->MemorySizeInBytes(); + break; case SHORT: - size = reinterpret_cast<Array3Ds *>(array_)->MemorySizeInBytes(); - break; - default : - size = 0; - assert(0); + size = reinterpret_cast<Array3Ds*>(array_)->MemorySizeInBytes(); + break; + default: size = 0; assert(0); } size += sizeof(*this); return size; @@ -83,71 +78,57 @@ class Image { ~Image() { switch (array_type_) { - case BYTE: - delete reinterpret_cast<Array3Du *>(array_); - - break; - case FLOAT: - delete reinterpret_cast<Array3Df *>(array_); - - break; - case INT: - delete reinterpret_cast<Array3Di *>(array_); - - break; - case SHORT: - delete reinterpret_cast<Array3Ds *>(array_); - - break; - default: - assert(0); - } + case BYTE: delete reinterpret_cast<Array3Du*>(array_); break; + case FLOAT: delete reinterpret_cast<Array3Df*>(array_); break; + case INT: delete reinterpret_cast<Array3Di*>(array_); break; + case SHORT: delete reinterpret_cast<Array3Ds*>(array_); break; + default: assert(0); + } } - Image& operator= (const Image& f) { + Image& operator=(const Image& f) { if (this != &f) { array_type_ = f.array_type_; switch (array_type_) { case BYTE: - delete reinterpret_cast<Array3Du *>(array_); - array_ = new Array3Du(*(Array3Du *)f.array_); - break; + delete reinterpret_cast<Array3Du*>(array_); + array_ = new Array3Du(*(Array3Du*)f.array_); + break; case FLOAT: - delete reinterpret_cast<Array3Df *>(array_); - array_ = new Array3Df(*(Array3Df *)f.array_); - break; + delete reinterpret_cast<Array3Df*>(array_); + array_ = new Array3Df(*(Array3Df*)f.array_); + break; case INT: - delete reinterpret_cast<Array3Di *>(array_); - array_ = new Array3Di(*(Array3Di *)f.array_); - break; + delete reinterpret_cast<Array3Di*>(array_); + array_ = new Array3Di(*(Array3Di*)f.array_); + break; case SHORT: - delete reinterpret_cast<Array3Ds *>(array_); - array_ = new Array3Ds(*(Array3Ds *)f.array_); - break; - default: - assert(0); + delete reinterpret_cast<Array3Ds*>(array_); + array_ = new Array3Ds(*(Array3Ds*)f.array_); + break; + default: assert(0); } } return *this; } - Array3Du *AsArray3Du() const { + Array3Du* AsArray3Du() const { if (array_type_ == BYTE) { - return reinterpret_cast<Array3Du *>(array_); + return reinterpret_cast<Array3Du*>(array_); } return NULL; } - Array3Df *AsArray3Df() const { + Array3Df* AsArray3Df() const { if (array_type_ == FLOAT) { - return reinterpret_cast<Array3Df *>(array_); + return reinterpret_cast<Array3Df*>(array_); } return NULL; } private: DataType array_type_; - BaseArray *array_; + BaseArray* array_; }; } // namespace libmv diff --git a/intern/libmv/libmv/image/image_converter.h b/intern/libmv/libmv/image/image_converter.h index b3a3fa2bf8c..41d53be6722 100644 --- a/intern/libmv/libmv/image/image_converter.h +++ b/intern/libmv/libmv/image/image_converter.h @@ -28,7 +28,7 @@ namespace libmv { // The factor comes from http://www.easyrgb.com/ // RGB to XYZ : Y is the luminance channel // var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722 -template<typename T> +template <typename T> inline T RGB2GRAY(const T r, const T g, const T b) { return static_cast<T>(r * 0.2126 + g * 0.7152 + b * 0.0722); } @@ -42,8 +42,8 @@ inline unsigned char RGB2GRAY<unsigned char>(const unsigned char r, return (unsigned char)(r * 0.2126 + g * 0.7152 + b * 0.0722 +0.5); }*/ -template<class ImageIn, class ImageOut> -void Rgb2Gray(const ImageIn &imaIn, ImageOut *imaOut) { +template <class ImageIn, class ImageOut> +void Rgb2Gray(const ImageIn& imaIn, ImageOut* imaOut) { // It is all fine to cnvert RGBA image here as well, // all the additional channels will be nicely ignored. assert(imaIn.Depth() >= 3); @@ -52,21 +52,22 @@ void Rgb2Gray(const ImageIn &imaIn, ImageOut *imaOut) { // Convert each RGB pixel into Gray value (luminance) for (int j = 0; j < imaIn.Height(); ++j) { - for (int i = 0; i < imaIn.Width(); ++i) { - (*imaOut)(j, i) = RGB2GRAY(imaIn(j, i, 0) , imaIn(j, i, 1), imaIn(j, i, 2)); + for (int i = 0; i < imaIn.Width(); ++i) { + (*imaOut)(j, i) = + RGB2GRAY(imaIn(j, i, 0), imaIn(j, i, 1), imaIn(j, i, 2)); } } } // Convert given float image to an unsigned char array of pixels. -template<class Image> -unsigned char *FloatImageToUCharArray(const Image &image) { - unsigned char *buffer = +template <class Image> +unsigned char* FloatImageToUCharArray(const Image& image) { + unsigned char* buffer = new unsigned char[image.Width() * image.Height() * image.Depth()]; for (int y = 0; y < image.Height(); y++) { - for (int x = 0; x < image.Width(); x++) { - for (int d = 0; d < image.Depth(); d++) { + for (int x = 0; x < image.Width(); x++) { + for (int d = 0; d < image.Depth(); d++) { int index = (y * image.Width() + x) * image.Depth() + d; buffer[index] = 255.0 * image(y, x, d); } diff --git a/intern/libmv/libmv/image/image_drawing.h b/intern/libmv/libmv/image/image_drawing.h index f50e48b75a3..dd6a94dd7d4 100644 --- a/intern/libmv/libmv/image/image_drawing.h +++ b/intern/libmv/libmv/image/image_drawing.h @@ -34,9 +34,9 @@ namespace libmv { /// Put the pixel in the image to the given color only if the point (xc,yc) /// is inside the image. template <class Image, class Color> -inline void safePutPixel(int yc, int xc, const Color & col, Image *pim) { +inline void safePutPixel(int yc, int xc, const Color& col, Image* pim) { if (!pim) - return; + return; if (pim->Contains(yc, xc)) { (*pim)(yc, xc) = col; } @@ -45,9 +45,9 @@ inline void safePutPixel(int yc, int xc, const Color & col, Image *pim) { /// is inside the image. This function support multi-channel color /// \note The color pointer col must have size as the image depth template <class Image, class Color> -inline void safePutPixel(int yc, int xc, const Color *col, Image *pim) { +inline void safePutPixel(int yc, int xc, const Color* col, Image* pim) { if (!pim) - return; + return; if (pim->Contains(yc, xc)) { for (int i = 0; i < pim->Depth(); ++i) (*pim)(yc, xc, i) = *(col + i); @@ -59,19 +59,23 @@ inline void safePutPixel(int yc, int xc, const Color *col, Image *pim) { // Add the rotation of the ellipse. // As the algo. use symmetry we must use 4 rotations. template <class Image, class Color> -void DrawEllipse(int xc, int yc, int radiusA, int radiusB, - const Color &col, Image *pim, double angle = 0.0) { +void DrawEllipse(int xc, + int yc, + int radiusA, + int radiusB, + const Color& col, + Image* pim, + double angle = 0.0) { int a = radiusA; int b = radiusB; // Counter Clockwise rotation matrix. - double matXY[4] = { cos(angle), sin(angle), - -sin(angle), cos(angle)}; + double matXY[4] = {cos(angle), sin(angle), -sin(angle), cos(angle)}; int x, y; double d1, d2; x = 0; y = b; - d1 = b*b - a*a*b + a*a/4; + d1 = b * b - a * a * b + a * a / 4; float rotX = (matXY[0] * x + matXY[1] * y); float rotY = (matXY[2] * x + matXY[3] * y); @@ -86,12 +90,12 @@ void DrawEllipse(int xc, int yc, int radiusA, int radiusB, rotY = (-matXY[2] * x + matXY[3] * y); safePutPixel(yc + rotY, xc + rotX, col, pim); - while (a*a*(y-.5) > b*b*(x+1)) { + while (a * a * (y - .5) > b * b * (x + 1)) { if (d1 < 0) { - d1 += b*b*(2*x+3); + d1 += b * b * (2 * x + 3); ++x; } else { - d1 += b*b*(2*x+3) + a*a*(-2*y+2); + d1 += b * b * (2 * x + 3) + a * a * (-2 * y + 2); ++x; --y; } @@ -108,14 +112,14 @@ void DrawEllipse(int xc, int yc, int radiusA, int radiusB, rotY = (-matXY[2] * x + matXY[3] * y); safePutPixel(yc + rotY, xc + rotX, col, pim); } - d2 = b*b*(x+.5)*(x+.5) + a*a*(y-1)*(y-1) - a*a*b*b; + d2 = b * b * (x + .5) * (x + .5) + a * a * (y - 1) * (y - 1) - a * a * b * b; while (y > 0) { if (d2 < 0) { - d2 += b*b*(2*x+2) + a*a*(-2*y+3); + d2 += b * b * (2 * x + 2) + a * a * (-2 * y + 3); --y; ++x; } else { - d2 += a*a*(-2*y+3); + d2 += a * a * (-2 * y + 3); --y; } rotX = (matXY[0] * x + matXY[1] * y); @@ -137,23 +141,23 @@ void DrawEllipse(int xc, int yc, int radiusA, int radiusB, // So it's better the use the Andres method. // http://fr.wikipedia.org/wiki/Algorithme_de_tracé_de_cercle_d'Andres. template <class Image, class Color> -void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) { - Image &im = *pim; - if ( im.Contains(y + radius, x + radius) - || im.Contains(y + radius, x - radius) - || im.Contains(y - radius, x + radius) - || im.Contains(y - radius, x - radius)) { +void DrawCircle(int x, int y, int radius, const Color& col, Image* pim) { + Image& im = *pim; + if (im.Contains(y + radius, x + radius) || + im.Contains(y + radius, x - radius) || + im.Contains(y - radius, x + radius) || + im.Contains(y - radius, x - radius)) { int x1 = 0; int y1 = radius; int d = radius - 1; while (y1 >= x1) { // Draw the point for each octant. - safePutPixel( y1 + y, x1 + x, col, pim); - safePutPixel( x1 + y, y1 + x, col, pim); - safePutPixel( y1 + y, -x1 + x, col, pim); - safePutPixel( x1 + y, -y1 + x, col, pim); - safePutPixel(-y1 + y, x1 + x, col, pim); - safePutPixel(-x1 + y, y1 + x, col, pim); + safePutPixel(y1 + y, x1 + x, col, pim); + safePutPixel(x1 + y, y1 + x, col, pim); + safePutPixel(y1 + y, -x1 + x, col, pim); + safePutPixel(x1 + y, -y1 + x, col, pim); + safePutPixel(-y1 + y, x1 + x, col, pim); + safePutPixel(-x1 + y, y1 + x, col, pim); safePutPixel(-y1 + y, -x1 + x, col, pim); safePutPixel(-x1 + y, -y1 + x, col, pim); if (d >= 2 * x1) { @@ -163,7 +167,7 @@ void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) { if (d <= 2 * (radius - y1)) { d = d + 2 * y1 - 1; y1 -= 1; - } else { + } else { d = d + 2 * (y1 - x1 - 1); y1 -= 1; x1 += 1; @@ -175,8 +179,8 @@ void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) { // Bresenham algorithm template <class Image, class Color> -void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { - Image &im = *pim; +void DrawLine(int xa, int ya, int xb, int yb, const Color& col, Image* pim) { + Image& im = *pim; // If one point is outside the image // Replace the outside point by the intersection of the line and @@ -185,35 +189,37 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { int width = pim->Width(); int height = pim->Height(); const bool xdir = xa < xb, ydir = ya < yb; - float nx0 = xa, nx1 = xb, ny0 = ya, ny1 = yb, - &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, - &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0, - &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, - &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0; + float nx0 = xa, nx1 = xb, ny0 = ya, ny1 = yb, &xleft = xdir ? nx0 : nx1, + &yleft = xdir ? ny0 : ny1, &xright = xdir ? nx1 : nx0, + &yright = xdir ? ny1 : ny0, &xup = ydir ? nx0 : nx1, + &yup = ydir ? ny0 : ny1, &xdown = ydir ? nx1 : nx0, + &ydown = ydir ? ny1 : ny0; - if (xright < 0 || xleft >= width) return; + if (xright < 0 || xleft >= width) + return; if (xleft < 0) { - yleft -= xleft*(yright - yleft)/(xright - xleft); - xleft = 0; + yleft -= xleft * (yright - yleft) / (xright - xleft); + xleft = 0; } if (xright >= width) { - yright -= (xright - width)*(yright - yleft)/(xright - xleft); - xright = width - 1; + yright -= (xright - width) * (yright - yleft) / (xright - xleft); + xright = width - 1; } - if (ydown < 0 || yup >= height) return; + if (ydown < 0 || yup >= height) + return; if (yup < 0) { - xup -= yup*(xdown - xup)/(ydown - yup); - yup = 0; + xup -= yup * (xdown - xup) / (ydown - yup); + yup = 0; } if (ydown >= height) { - xdown -= (ydown - height)*(xdown - xup)/(ydown - yup); - ydown = height - 1; + xdown -= (ydown - height) * (xdown - xup) / (ydown - yup); + ydown = height - 1; } - xa = (int) xleft; - xb = (int) xright; - ya = (int) yleft; - yb = (int) yright; + xa = (int)xleft; + xb = (int)xright; + ya = (int)yleft; + yb = (int)yright; } int xbas, xhaut, ybas, yhaut; @@ -241,7 +247,7 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { } if (dy > 0) { // Positive slope will increment X. incrmY = 1; - } else { // Negative slope. + } else { // Negative slope. incrmY = -1; } if (dx >= dy) { @@ -255,9 +261,9 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { x += incrmX; if (dp <= 0) { // Go in direction of the South Pixel. dp += S; - } else { // Go to the North. + } else { // Go to the North. dp += N; - y+=incrmY; + y += incrmY; } } } else { @@ -271,7 +277,7 @@ void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) { y += incrmY; if (dp <= 0) { // Go in direction of the South Pixel. dp += S; - } else { // Go to the North. + } else { // Go to the North. dp += N; x += incrmX; } diff --git a/intern/libmv/libmv/image/image_test.cc b/intern/libmv/libmv/image/image_test.cc index 241f49f2244..a1730a9a55e 100644 --- a/intern/libmv/libmv/image/image_test.cc +++ b/intern/libmv/libmv/image/image_test.cc @@ -23,20 +23,20 @@ #include "libmv/image/image.h" #include "testing/testing.h" -using libmv::Image; using libmv::Array3Df; +using libmv::Image; namespace { TEST(Image, SimpleImageAccessors) { - Array3Df *array = new Array3Df(2, 3); + Array3Df* array = new Array3Df(2, 3); Image image(array); EXPECT_EQ(array, image.AsArray3Df()); EXPECT_TRUE(NULL == image.AsArray3Du()); } TEST(Image, MemorySizeInBytes) { - Array3Df *array = new Array3Df(2, 3); + Array3Df* array = new Array3Df(2, 3); Image image(array); int size = sizeof(image) + array->MemorySizeInBytes(); EXPECT_EQ(size, image.MemorySizeInBytes()); diff --git a/intern/libmv/libmv/image/sample.h b/intern/libmv/libmv/image/sample.h index 24eb9ccd57d..2b57baf27b9 100644 --- a/intern/libmv/libmv/image/sample.h +++ b/intern/libmv/libmv/image/sample.h @@ -26,17 +26,14 @@ namespace libmv { /// Nearest neighbor interpolation. -template<typename T> -inline T SampleNearest(const Array3D<T> &image, - float y, float x, int v = 0) { +template <typename T> +inline T SampleNearest(const Array3D<T>& image, float y, float x, int v = 0) { const int i = int(round(y)); const int j = int(round(x)); return image(i, j, v); } -inline void LinearInitAxis(float x, int size, - int *x1, int *x2, - float *dx) { +inline void LinearInitAxis(float x, int size, int* x1, int* x2, float* dx) { const int ix = static_cast<int>(x); if (ix < 0) { *x1 = 0; @@ -54,32 +51,32 @@ inline void LinearInitAxis(float x, int size, } /// Linear interpolation. -template<typename T> -inline T SampleLinear(const Array3D<T> &image, float y, float x, int v = 0) { +template <typename T> +inline T SampleLinear(const Array3D<T>& image, float y, float x, int v = 0) { int x1, y1, x2, y2; float dx, dy; LinearInitAxis(y, image.Height(), &y1, &y2, &dy); - LinearInitAxis(x, image.Width(), &x1, &x2, &dx); + LinearInitAxis(x, image.Width(), &x1, &x2, &dx); const T im11 = image(y1, x1, v); const T im12 = image(y1, x2, v); const T im21 = image(y2, x1, v); const T im22 = image(y2, x2, v); - return T( dy * (dx * im11 + (1.0 - dx) * im12) + + return T(dy * (dx * im11 + (1.0 - dx) * im12) + (1 - dy) * (dx * im21 + (1.0 - dx) * im22)); } /// Linear interpolation, of all channels. The sample is assumed to have the /// same size as the number of channels in image. -template<typename T> -inline void SampleLinear(const Array3D<T> &image, float y, float x, T *sample) { +template <typename T> +inline void SampleLinear(const Array3D<T>& image, float y, float x, T* sample) { int x1, y1, x2, y2; float dx, dy; LinearInitAxis(y, image.Height(), &y1, &y2, &dy); - LinearInitAxis(x, image.Width(), &x1, &x2, &dx); + LinearInitAxis(x, image.Width(), &x1, &x2, &dx); for (int i = 0; i < image.Depth(); ++i) { const T im11 = image(y1, x1, i); @@ -87,7 +84,7 @@ inline void SampleLinear(const Array3D<T> &image, float y, float x, T *sample) { const T im21 = image(y2, x1, i); const T im22 = image(y2, x2, i); - sample[i] = T( dy * (dx * im11 + (1.0 - dx) * im12) + + sample[i] = T(dy * (dx * im11 + (1.0 - dx) * im12) + (1 - dy) * (dx * im21 + (1.0 - dx) * im22)); } } @@ -95,7 +92,7 @@ inline void SampleLinear(const Array3D<T> &image, float y, float x, T *sample) { // Downsample all channels by 2. If the image has odd width or height, the last // row or column is ignored. // FIXME(MatthiasF): this implementation shouldn't be in an interface file -inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) { +inline void DownsampleChannelsBy2(const Array3Df& in, Array3Df* out) { int height = in.Height() / 2; int width = in.Width() / 2; int depth = in.Depth(); @@ -106,10 +103,12 @@ inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) { for (int r = 0; r < height; ++r) { for (int c = 0; c < width; ++c) { for (int k = 0; k < depth; ++k) { + // clang-format off (*out)(r, c, k) = (in(2 * r, 2 * c, k) + in(2 * r + 1, 2 * c, k) + in(2 * r, 2 * c + 1, k) + in(2 * r + 1, 2 * c + 1, k)) / 4.0f; + // clang-format on } } } @@ -117,11 +116,12 @@ inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) { // Sample a region centered at x,y in image with size extending by half_width // from x,y. Channels specifies the number of channels to sample from. -inline void SamplePattern(const FloatImage &image, - double x, double y, - int half_width, - int channels, - FloatImage *sampled) { +inline void SamplePattern(const FloatImage& image, + double x, + double y, + int half_width, + int channels, + FloatImage* sampled) { sampled->Resize(2 * half_width + 1, 2 * half_width + 1, channels); for (int r = -half_width; r <= half_width; ++r) { for (int c = -half_width; c <= half_width; ++c) { diff --git a/intern/libmv/libmv/image/sample_test.cc b/intern/libmv/libmv/image/sample_test.cc index c8a0ce470c2..f1fb4c42c67 100644 --- a/intern/libmv/libmv/image/sample_test.cc +++ b/intern/libmv/libmv/image/sample_test.cc @@ -32,9 +32,9 @@ TEST(Image, Nearest) { image(1, 0) = 2; image(1, 1) = 3; EXPECT_EQ(0, SampleNearest(image, -0.4f, -0.4f)); - EXPECT_EQ(0, SampleNearest(image, 0.4f, 0.4f)); - EXPECT_EQ(3, SampleNearest(image, 0.6f, 0.6f)); - EXPECT_EQ(3, SampleNearest(image, 1.4f, 1.4f)); + EXPECT_EQ(0, SampleNearest(image, 0.4f, 0.4f)); + EXPECT_EQ(3, SampleNearest(image, 0.6f, 0.6f)); + EXPECT_EQ(3, SampleNearest(image, 1.4f, 1.4f)); } TEST(Image, Linear) { @@ -57,7 +57,7 @@ TEST(Image, DownsampleBy2) { ASSERT_EQ(1, resampled_image.Height()); ASSERT_EQ(1, resampled_image.Width()); ASSERT_EQ(1, resampled_image.Depth()); - EXPECT_FLOAT_EQ(6./4., resampled_image(0, 0)); + EXPECT_FLOAT_EQ(6. / 4., resampled_image(0, 0)); } TEST(Image, DownsampleBy2MultiChannel) { @@ -82,8 +82,8 @@ TEST(Image, DownsampleBy2MultiChannel) { ASSERT_EQ(1, resampled_image.Height()); ASSERT_EQ(1, resampled_image.Width()); ASSERT_EQ(3, resampled_image.Depth()); - EXPECT_FLOAT_EQ((0+1+2+3)/4., resampled_image(0, 0, 0)); - EXPECT_FLOAT_EQ((5+6+7+8)/4., resampled_image(0, 0, 1)); - EXPECT_FLOAT_EQ((9+10+11+12)/4., resampled_image(0, 0, 2)); + EXPECT_FLOAT_EQ((0 + 1 + 2 + 3) / 4., resampled_image(0, 0, 0)); + EXPECT_FLOAT_EQ((5 + 6 + 7 + 8) / 4., resampled_image(0, 0, 1)); + EXPECT_FLOAT_EQ((9 + 10 + 11 + 12) / 4., resampled_image(0, 0, 2)); } } // namespace diff --git a/intern/libmv/libmv/image/tuple.h b/intern/libmv/libmv/image/tuple.h index c8dc36f2e18..447bf0cc81c 100644 --- a/intern/libmv/libmv/image/tuple.h +++ b/intern/libmv/libmv/image/tuple.h @@ -34,10 +34,14 @@ class Tuple { Tuple(T initial_value) { Reset(initial_value); } template <typename D> - Tuple(D *values) { Reset(values); } + Tuple(D* values) { + Reset(values); + } template <typename D> - Tuple(const Tuple<D, N> &b) { Reset(b); } + Tuple(const Tuple<D, N>& b) { + Reset(b); + } template <typename D> Tuple& operator=(const Tuple<D, N>& b) { @@ -46,30 +50,32 @@ class Tuple { } template <typename D> - void Reset(const Tuple<D, N>& b) { Reset(b.Data()); } + void Reset(const Tuple<D, N>& b) { + Reset(b.Data()); + } template <typename D> - void Reset(D *values) { - for (int i = 0;i < N; i++) { + void Reset(D* values) { + for (int i = 0; i < N; i++) { data_[i] = T(values[i]); } } // Set all tuple values to the same thing. void Reset(T value) { - for (int i = 0;i < N; i++) { + for (int i = 0; i < N; i++) { data_[i] = value; } } // Pointer to the first element. - T *Data() { return &data_[0]; } - const T *Data() const { return &data_[0]; } + T* Data() { return &data_[0]; } + const T* Data() const { return &data_[0]; } - T &operator()(int i) { return data_[i]; } - const T &operator()(int i) const { return data_[i]; } + T& operator()(int i) { return data_[i]; } + const T& operator()(int i) const { return data_[i]; } - bool operator==(const Tuple<T, N> &other) const { + bool operator==(const Tuple<T, N>& other) const { for (int i = 0; i < N; ++i) { if ((*this)(i) != other(i)) { return false; @@ -77,9 +83,7 @@ class Tuple { } return true; } - bool operator!=(const Tuple<T, N> &other) const { - return !(*this == other); - } + bool operator!=(const Tuple<T, N>& other) const { return !(*this == other); } private: T data_[N]; diff --git a/intern/libmv/libmv/multiview/conditioning.cc b/intern/libmv/libmv/multiview/conditioning.cc index 0afbf119ea3..2f4bf653ca0 100644 --- a/intern/libmv/libmv/multiview/conditioning.cc +++ b/intern/libmv/libmv/multiview/conditioning.cc @@ -24,7 +24,7 @@ namespace libmv { // HZ 4.4.4 pag.109: Point conditioning (non isotropic) -void PreconditionerFromPoints(const Mat &points, Mat3 *T) { +void PreconditionerFromPoints(const Mat& points, Mat3* T) { Vec mean, variance; MeanAndVarianceAlongRows(points, &mean, &variance); @@ -38,12 +38,14 @@ void PreconditionerFromPoints(const Mat &points, Mat3 *T) { if (variance(1) < 1e-8) yfactor = mean(1) = 1.0; + // clang-format off *T << xfactor, 0, -xfactor * mean(0), 0, yfactor, -yfactor * mean(1), 0, 0, 1; + // clang-format on } // HZ 4.4.4 pag.107: Point conditioning (isotropic) -void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T) { +void IsotropicPreconditionerFromPoints(const Mat& points, Mat3* T) { Vec mean, variance; MeanAndVarianceAlongRows(points, &mean, &variance); @@ -57,14 +59,16 @@ void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T) { mean.setOnes(); } + // clang-format off *T << factor, 0, -factor * mean(0), 0, factor, -factor * mean(1), 0, 0, 1; + // clang-format on } -void ApplyTransformationToPoints(const Mat &points, - const Mat3 &T, - Mat *transformed_points) { +void ApplyTransformationToPoints(const Mat& points, + const Mat3& T, + Mat* transformed_points) { int n = points.cols(); transformed_points->resize(2, n); Mat3X p(3, n); @@ -73,26 +77,24 @@ void ApplyTransformationToPoints(const Mat &points, HomogeneousToEuclidean(p, transformed_points); } -void NormalizePoints(const Mat &points, - Mat *normalized_points, - Mat3 *T) { +void NormalizePoints(const Mat& points, Mat* normalized_points, Mat3* T) { PreconditionerFromPoints(points, T); ApplyTransformationToPoints(points, *T, normalized_points); } -void NormalizeIsotropicPoints(const Mat &points, - Mat *normalized_points, - Mat3 *T) { +void NormalizeIsotropicPoints(const Mat& points, + Mat* normalized_points, + Mat3* T) { IsotropicPreconditionerFromPoints(points, T); ApplyTransformationToPoints(points, *T, normalized_points); } // Denormalize the results. See HZ page 109. -void UnnormalizerT::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H) { +void UnnormalizerT::Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H) { *H = T2.transpose() * (*H) * T1; } -void UnnormalizerI::Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H) { +void UnnormalizerI::Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H) { *H = T2.inverse() * (*H) * T1; } diff --git a/intern/libmv/libmv/multiview/conditioning.h b/intern/libmv/libmv/multiview/conditioning.h index 8f3e3a76070..876c5af48e6 100644 --- a/intern/libmv/libmv/multiview/conditioning.h +++ b/intern/libmv/libmv/multiview/conditioning.h @@ -26,32 +26,30 @@ namespace libmv { // Point conditioning (non isotropic) -void PreconditionerFromPoints(const Mat &points, Mat3 *T); +void PreconditionerFromPoints(const Mat& points, Mat3* T); // Point conditioning (isotropic) -void IsotropicPreconditionerFromPoints(const Mat &points, Mat3 *T); +void IsotropicPreconditionerFromPoints(const Mat& points, Mat3* T); -void ApplyTransformationToPoints(const Mat &points, - const Mat3 &T, - Mat *transformed_points); +void ApplyTransformationToPoints(const Mat& points, + const Mat3& T, + Mat* transformed_points); -void NormalizePoints(const Mat &points, - Mat *normalized_points, - Mat3 *T); +void NormalizePoints(const Mat& points, Mat* normalized_points, Mat3* T); -void NormalizeIsotropicPoints(const Mat &points, - Mat *normalized_points, - Mat3 *T); +void NormalizeIsotropicPoints(const Mat& points, + Mat* normalized_points, + Mat3* T); /// Use inverse for unnormalize struct UnnormalizerI { // Denormalize the results. See HZ page 109. - static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H); + static void Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H); }; /// Use transpose for unnormalize struct UnnormalizerT { // Denormalize the results. See HZ page 109. - static void Unnormalize(const Mat3 &T1, const Mat3 &T2, Mat3 *H); + static void Unnormalize(const Mat3& T1, const Mat3& T2, Mat3* H); }; } // namespace libmv diff --git a/intern/libmv/libmv/multiview/euclidean_resection.cc b/intern/libmv/libmv/multiview/euclidean_resection.cc index 245b027fb7c..249d7ebef3d 100644 --- a/intern/libmv/libmv/multiview/euclidean_resection.cc +++ b/intern/libmv/libmv/multiview/euclidean_resection.cc @@ -23,8 +23,8 @@ #include <cmath> #include <limits> -#include <Eigen/SVD> #include <Eigen/Geometry> +#include <Eigen/SVD> #include "libmv/base/vector.h" #include "libmv/logging/logging.h" @@ -35,9 +35,10 @@ namespace euclidean_resection { typedef unsigned int uint; -bool EuclideanResection(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t, +bool EuclideanResection(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t, ResectionMethod method) { switch (method) { case RESECTION_ANSAR_DANIILIDIS: @@ -49,20 +50,20 @@ bool EuclideanResection(const Mat2X &x_camera, case RESECTION_PPNP: return EuclideanResectionPPnP(x_camera, X_world, R, t); break; - default: - LOG(FATAL) << "Unknown resection method."; + default: LOG(FATAL) << "Unknown resection method."; } return false; } -bool EuclideanResection(const Mat &x_image, - const Mat3X &X_world, - const Mat3 &K, - Mat3 *R, Vec3 *t, +bool EuclideanResection(const Mat& x_image, + const Mat3X& X_world, + const Mat3& K, + Mat3* R, + Vec3* t, ResectionMethod method) { CHECK(x_image.rows() == 2 || x_image.rows() == 3) - << "Invalid size for x_image: " - << x_image.rows() << "x" << x_image.cols(); + << "Invalid size for x_image: " << x_image.rows() << "x" + << x_image.cols(); Mat2X x_camera; if (x_image.rows() == 2) { @@ -73,18 +74,15 @@ bool EuclideanResection(const Mat &x_image, return EuclideanResection(x_camera, X_world, R, t, method); } -void AbsoluteOrientation(const Mat3X &X, - const Mat3X &Xp, - Mat3 *R, - Vec3 *t) { +void AbsoluteOrientation(const Mat3X& X, const Mat3X& Xp, Mat3* R, Vec3* t) { int num_points = X.cols(); - Vec3 C = X.rowwise().sum() / num_points; // Centroid of X. + Vec3 C = X.rowwise().sum() / num_points; // Centroid of X. Vec3 Cp = Xp.rowwise().sum() / num_points; // Centroid of Xp. // Normalize the two point sets. Mat3X Xn(3, num_points), Xpn(3, num_points); for (int i = 0; i < num_points; ++i) { - Xn.col(i) = X.col(i) - C; + Xn.col(i) = X.col(i) - C; Xpn.col(i) = Xp.col(i) - Cp; } @@ -100,10 +98,12 @@ void AbsoluteOrientation(const Mat3X &X, double Szy = Xn.row(2).dot(Xpn.row(1)); Mat4 N; + // clang-format off N << Sxx + Syy + Szz, Syz - Szy, Szx - Sxz, Sxy - Syx, Syz - Szy, Sxx - Syy - Szz, Sxy + Syx, Szx + Sxz, Szx - Sxz, Sxy + Syx, -Sxx + Syy - Szz, Syz + Szy, Sxy - Syx, Szx + Sxz, Syz + Szy, -Sxx - Syy + Szz; + // clang-format on // Find the unit quaternion q that maximizes qNq. It is the eigenvector // corresponding to the lagest eigenvalue. @@ -118,6 +118,7 @@ void AbsoluteOrientation(const Mat3X &X, double q1q3 = q(1) * q(3); double q2q3 = q(2) * q(3); + // clang-format off (*R) << qq(0) + qq(1) - qq(2) - qq(3), 2 * (q1q2 - q0q3), 2 * (q1q3 + q0q2), @@ -127,6 +128,7 @@ void AbsoluteOrientation(const Mat3X &X, 2 * (q1q3 - q0q2), 2 * (q2q3 + q0q1), qq(0) - qq(1) - qq(2) + qq(3); + // clang-format on // Fix the handedness of the R matrix. if (R->determinant() < 0) { @@ -176,9 +178,7 @@ static int Sign(double value) { // Lambda to create the constraints in equation (5) in "Linear Pose Estimation // from Points or Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no. // 5. -static Vec MatrixToConstraint(const Mat &A, - int num_k_columns, - int num_lambda) { +static Vec MatrixToConstraint(const Mat& A, int num_k_columns, int num_lambda) { Vec C(num_k_columns); C.setZero(); int idx = 0; @@ -195,17 +195,17 @@ static Vec MatrixToConstraint(const Mat &A, } // Normalizes the columns of vectors. -static void NormalizeColumnVectors(Mat3X *vectors) { +static void NormalizeColumnVectors(Mat3X* vectors) { int num_columns = vectors->cols(); for (int i = 0; i < num_columns; ++i) { vectors->col(i).normalize(); } } -void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, - Vec3 *t) { +void EuclideanResectionAnsarDaniilidis(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t) { CHECK(x_camera.cols() == X_world.cols()); CHECK(x_camera.cols() > 3); @@ -229,14 +229,14 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, // them into the M matrix (8). Also store the initial (i, j) indices. int row = 0; for (int i = 0; i < num_points; ++i) { - for (int j = i+1; j < num_points; ++j) { + for (int j = i + 1; j < num_points; ++j) { M(row, row) = -2 * x_camera_unit.col(i).dot(x_camera_unit.col(j)); M(row, num_m_rows + i) = x_camera_unit.col(i).dot(x_camera_unit.col(i)); M(row, num_m_rows + j) = x_camera_unit.col(j).dot(x_camera_unit.col(j)); Vec3 Xdiff = X_world.col(i) - X_world.col(j); double center_to_point_distance = Xdiff.norm(); M(row, num_m_columns - 1) = - - center_to_point_distance * center_to_point_distance; + -center_to_point_distance * center_to_point_distance; ij_index(row, 0) = i; ij_index(row, 1) = j; ++row; @@ -246,17 +246,17 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, } int num_lambda = num_points + 1; // Dimension of the null space of M. - Mat V = M.jacobiSvd(Eigen::ComputeFullV).matrixV().block(0, - num_m_rows, - num_m_columns, - num_lambda); + Mat V = M.jacobiSvd(Eigen::ComputeFullV) + .matrixV() + .block(0, num_m_rows, num_m_columns, num_lambda); // TODO(vess): The number of constraint equations in K (num_k_rows) must be // (num_points + 1) * (num_points + 2)/2. This creates a performance issue // for more than 4 points. It is fine for 4 points at the moment with 18 // instead of 15 equations. - int num_k_rows = num_m_rows + num_points * - (num_points*(num_points-1)/2 - num_points+1); + int num_k_rows = + num_m_rows + + num_points * (num_points * (num_points - 1) / 2 - num_points + 1); int num_k_columns = num_lambda * (num_lambda + 1) / 2; Mat K(num_k_rows, num_k_columns); K.setZero(); @@ -275,8 +275,8 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, int idx4 = IJToPointIndex(i, k, num_points); K.row(counter_k_row) = - MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)- - V.row(idx3).transpose() * V.row(idx4), + MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2) - + V.row(idx3).transpose() * V.row(idx4), num_k_columns, num_lambda); ++counter_k_row; @@ -296,8 +296,8 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, int idx4 = IJToPointIndex(i, k, num_points); K.row(counter_k_row) = - MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2)- - V.row(idx3).transpose() * V.row(idx4), + MatrixToConstraint(V.row(idx1).transpose() * V.row(idx2) - + V.row(idx3).transpose() * V.row(idx4), num_k_columns, num_lambda); ++counter_k_row; @@ -317,14 +317,12 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, } } // Ensure positiveness of the largest value corresponding to lambda_ii. - L_sq = L_sq * Sign(L_sq(IJToIndex(max_L_sq_index, - max_L_sq_index, - num_lambda))); + L_sq = + L_sq * Sign(L_sq(IJToIndex(max_L_sq_index, max_L_sq_index, num_lambda))); Vec L(num_lambda); - L(max_L_sq_index) = sqrt(L_sq(IJToIndex(max_L_sq_index, - max_L_sq_index, - num_lambda))); + L(max_L_sq_index) = + sqrt(L_sq(IJToIndex(max_L_sq_index, max_L_sq_index, num_lambda))); for (int i = 0; i < num_lambda; ++i) { if (i != max_L_sq_index) { @@ -353,9 +351,9 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, } // Selects 4 virtual control points using mean and PCA. -static void SelectControlPoints(const Mat3X &X_world, - Mat *X_centered, - Mat34 *X_control_points) { +static void SelectControlPoints(const Mat3X& X_world, + Mat* X_centered, + Mat34* X_control_points) { size_t num_points = X_world.cols(); // The first virtual control point, C0, is the centroid. @@ -379,13 +377,13 @@ static void SelectControlPoints(const Mat3X &X_world, } // Computes the barycentric coordinates for all real points -static void ComputeBarycentricCoordinates(const Mat3X &X_world_centered, - const Mat34 &X_control_points, - Mat4X *alphas) { +static void ComputeBarycentricCoordinates(const Mat3X& X_world_centered, + const Mat34& X_control_points, + Mat4X* alphas) { size_t num_points = X_world_centered.cols(); Mat3 C2; for (size_t c = 1; c < 4; c++) { - C2.col(c-1) = X_control_points.col(c) - X_control_points.col(0); + C2.col(c - 1) = X_control_points.col(c) - X_control_points.col(0); } Mat3 C2inv = C2.inverse(); @@ -401,14 +399,15 @@ static void ComputeBarycentricCoordinates(const Mat3X &X_world_centered, // Estimates the coordinates of all real points in the camera coordinate frame static void ComputePointsCoordinatesInCameraFrame( - const Mat4X &alphas, - const Vec4 &betas, - const Eigen::Matrix<double, 12, 12> &U, - Mat3X *X_camera) { + const Mat4X& alphas, + const Vec4& betas, + const Eigen::Matrix<double, 12, 12>& U, + Mat3X* X_camera) { size_t num_points = alphas.cols(); // Estimates the control points in the camera reference frame. - Mat34 C2b; C2b.setZero(); + Mat34 C2b; + C2b.setZero(); for (size_t cu = 0; cu < 4; cu++) { for (size_t c = 0; c < 4; c++) { C2b.col(c) += betas(cu) * U.block(11 - cu, c * 3, 1, 3).transpose(); @@ -436,9 +435,10 @@ static void ComputePointsCoordinatesInCameraFrame( } } -bool EuclideanResectionEPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t) { +bool EuclideanResectionEPnP(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t) { CHECK(x_camera.cols() == X_world.cols()); CHECK(x_camera.cols() > 3); size_t num_points = X_world.cols(); @@ -462,6 +462,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, double a3 = alphas(3, c); double ui = x_camera(0, c); double vi = x_camera(1, c); + // clang-format off M.block(2*c, 0, 2, 12) << a0, 0, a0*(-ui), a1, 0, a1*(-ui), a2, 0, @@ -471,10 +472,11 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, a1, a1*(-vi), 0, a2, a2*(-vi), 0, a3, a3*(-vi); + // clang-format on } // TODO(julien): Avoid the transpose by rewriting the u2.block() calls. - Eigen::JacobiSVD<Mat> MtMsvd(M.transpose()*M, Eigen::ComputeFullU); + Eigen::JacobiSVD<Mat> MtMsvd(M.transpose() * M, Eigen::ComputeFullU); Eigen::Matrix<double, 12, 12> u2 = MtMsvd.matrixU().transpose(); // Estimate the L matrix. @@ -495,21 +497,22 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, dv2.row(3) = u2.block(10, 3, 1, 3) - u2.block(10, 6, 1, 3); dv2.row(4) = u2.block(10, 3, 1, 3) - u2.block(10, 9, 1, 3); dv2.row(5) = u2.block(10, 6, 1, 3) - u2.block(10, 9, 1, 3); - dv3.row(0) = u2.block(9, 0, 1, 3) - u2.block(9, 3, 1, 3); - dv3.row(1) = u2.block(9, 0, 1, 3) - u2.block(9, 6, 1, 3); - dv3.row(2) = u2.block(9, 0, 1, 3) - u2.block(9, 9, 1, 3); - dv3.row(3) = u2.block(9, 3, 1, 3) - u2.block(9, 6, 1, 3); - dv3.row(4) = u2.block(9, 3, 1, 3) - u2.block(9, 9, 1, 3); - dv3.row(5) = u2.block(9, 6, 1, 3) - u2.block(9, 9, 1, 3); - dv4.row(0) = u2.block(8, 0, 1, 3) - u2.block(8, 3, 1, 3); - dv4.row(1) = u2.block(8, 0, 1, 3) - u2.block(8, 6, 1, 3); - dv4.row(2) = u2.block(8, 0, 1, 3) - u2.block(8, 9, 1, 3); - dv4.row(3) = u2.block(8, 3, 1, 3) - u2.block(8, 6, 1, 3); - dv4.row(4) = u2.block(8, 3, 1, 3) - u2.block(8, 9, 1, 3); - dv4.row(5) = u2.block(8, 6, 1, 3) - u2.block(8, 9, 1, 3); + dv3.row(0) = u2.block(9, 0, 1, 3) - u2.block(9, 3, 1, 3); + dv3.row(1) = u2.block(9, 0, 1, 3) - u2.block(9, 6, 1, 3); + dv3.row(2) = u2.block(9, 0, 1, 3) - u2.block(9, 9, 1, 3); + dv3.row(3) = u2.block(9, 3, 1, 3) - u2.block(9, 6, 1, 3); + dv3.row(4) = u2.block(9, 3, 1, 3) - u2.block(9, 9, 1, 3); + dv3.row(5) = u2.block(9, 6, 1, 3) - u2.block(9, 9, 1, 3); + dv4.row(0) = u2.block(8, 0, 1, 3) - u2.block(8, 3, 1, 3); + dv4.row(1) = u2.block(8, 0, 1, 3) - u2.block(8, 6, 1, 3); + dv4.row(2) = u2.block(8, 0, 1, 3) - u2.block(8, 9, 1, 3); + dv4.row(3) = u2.block(8, 3, 1, 3) - u2.block(8, 6, 1, 3); + dv4.row(4) = u2.block(8, 3, 1, 3) - u2.block(8, 9, 1, 3); + dv4.row(5) = u2.block(8, 6, 1, 3) - u2.block(8, 9, 1, 3); Eigen::Matrix<double, 6, 10> L; for (size_t r = 0; r < 6; r++) { + // clang-format off L.row(r) << dv1.row(r).dot(dv1.row(r)), 2.0 * dv1.row(r).dot(dv2.row(r)), dv2.row(r).dot(dv2.row(r)), @@ -520,19 +523,23 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, 2.0 * dv2.row(r).dot(dv4.row(r)), 2.0 * dv3.row(r).dot(dv4.row(r)), dv4.row(r).dot(dv4.row(r)); + // clang-format on } Vec6 rho; + // clang-format off rho << (X_control_points.col(0) - X_control_points.col(1)).squaredNorm(), (X_control_points.col(0) - X_control_points.col(2)).squaredNorm(), (X_control_points.col(0) - X_control_points.col(3)).squaredNorm(), (X_control_points.col(1) - X_control_points.col(2)).squaredNorm(), (X_control_points.col(1) - X_control_points.col(3)).squaredNorm(), (X_control_points.col(2) - X_control_points.col(3)).squaredNorm(); + // clang-format on // There are three possible solutions based on the three approximations of L // (betas). Below, each one is solved for then the best one is chosen. Mat3X X_camera; - Mat3 K; K.setIdentity(); + Mat3 K; + K.setIdentity(); vector<Mat3> Rs(3); vector<Vec3> ts(3); Vec rmse(3); @@ -546,7 +553,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, // // TODO(keir): Decide if setting this to infinity, effectively disabling the // check, is the right approach. So far this seems the case. - double kSuccessThreshold = std::numeric_limits<double>::max(); + double kSuccessThreshold = std::numeric_limits<double>::max(); // Find the first possible solution for R, t corresponding to: // Betas = [b00 b01 b11 b02 b12 b22 b03 b13 b23 b33] @@ -563,7 +570,7 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, if (b4(0) < 0) { b4 = -b4; } - b4(0) = std::sqrt(b4(0)); + b4(0) = std::sqrt(b4(0)); betas << b4(0), b4(1) / b4(0), b4(2) / b4(0), b4(3) / b4(0); ComputePointsCoordinatesInCameraFrame(alphas, betas, u2, &X_camera); AbsoluteOrientation(X_world, X_camera, &Rs[0], &ts[0]); @@ -669,12 +676,12 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, // TODO(julien): Improve the solutions with non-linear refinement. return true; } - + /* - + Straight from the paper: http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf - + function [R T] = ppnp(P,S,tol) % input % P : matrix (nx3) image coordinates in camera reference [u v 1] @@ -708,33 +715,34 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, end T = -R*c; end - + */ // TODO(keir): Re-do all the variable names and add comments matching the paper. // This implementation has too much of the terseness of the original. On the // other hand, it did work on the first try. -bool EuclideanResectionPPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t) { +bool EuclideanResectionPPnP(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t) { int n = x_camera.cols(); Mat Z = Mat::Zero(n, n); Vec e = Vec::Ones(n); Mat A = Mat::Identity(n, n) - (e * e.transpose() / n); Vec II = e / n; - + Mat P(n, 3); P.col(0) = x_camera.row(0); P.col(1) = x_camera.row(1); P.col(2).setConstant(1.0); - + Mat S = X_world.transpose(); - + double error = std::numeric_limits<double>::infinity(); Mat E_old = 1000 * Mat::Ones(n, 3); - + Vec3 c; Mat E(n, 3); - + int iteration = 0; double tolerance = 1e-5; // TODO(keir): The limit of 100 can probably be reduced, but this will require @@ -748,20 +756,21 @@ bool EuclideanResectionPPnP(const Mat2X &x_camera, s << 1, 1, (U * VT).determinant(); *R = U * s.asDiagonal() * VT; Mat PR = P * *R; // n x 3 - c = (S - Z*PR).transpose() * II; - Mat Y = S - e*c.transpose(); // n x 3 - Vec Zmindiag = (PR * Y.transpose()).diagonal() - .cwiseQuotient(P.rowwise().squaredNorm()); + c = (S - Z * PR).transpose() * II; + Mat Y = S - e * c.transpose(); // n x 3 + Vec Zmindiag = (PR * Y.transpose()) + .diagonal() + .cwiseQuotient(P.rowwise().squaredNorm()); for (int i = 0; i < n; ++i) { Zmindiag[i] = std::max(Zmindiag[i], 0.0); } Z = Zmindiag.asDiagonal(); - E = Y - Z*PR; + E = Y - Z * PR; error = (E - E_old).norm(); - LOG(INFO) << "PPnP error(" << (iteration++) << "): " << error; + LG << "PPnP error(" << (iteration++) << "): " << error; E_old = E; } - *t = -*R*c; + *t = -*R * c; // TODO(keir): Figure out what the failure cases are. Is it too many // iterations? Spend some time going through the math figuring out if there @@ -769,6 +778,5 @@ bool EuclideanResectionPPnP(const Mat2X &x_camera, return true; } - -} // namespace resection +} // namespace euclidean_resection } // namespace libmv diff --git a/intern/libmv/libmv/multiview/euclidean_resection.h b/intern/libmv/libmv/multiview/euclidean_resection.h index 28eae92611c..3c4c3979ff6 100644 --- a/intern/libmv/libmv/multiview/euclidean_resection.h +++ b/intern/libmv/libmv/multiview/euclidean_resection.h @@ -21,8 +21,8 @@ #ifndef LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ #define LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ -#include "libmv/numeric/numeric.h" #include "libmv/multiview/projection.h" +#include "libmv/numeric/numeric.h" namespace libmv { namespace euclidean_resection { @@ -33,7 +33,7 @@ enum ResectionMethod { // The "EPnP" algorithm by Lepetit et al. // http://cvlab.epfl.ch/~lepetit/papers/lepetit_ijcv08.pdf RESECTION_EPNP, - + // The Procrustes PNP algorithm ("PPnP") // http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf RESECTION_PPNP @@ -50,9 +50,10 @@ enum ResectionMethod { * \param t Solution for the camera translation vector * \param method The resection method to use. */ -bool EuclideanResection(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t, +bool EuclideanResection(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t, ResectionMethod method = RESECTION_EPNP); /** @@ -68,10 +69,11 @@ bool EuclideanResection(const Mat2X &x_camera, * \param t Solution for the camera translation vector * \param method Resection method */ -bool EuclideanResection(const Mat &x_image, - const Mat3X &X_world, - const Mat3 &K, - Mat3 *R, Vec3 *t, +bool EuclideanResection(const Mat& x_image, + const Mat3X& X_world, + const Mat3& K, + Mat3* R, + Vec3* t, ResectionMethod method = RESECTION_EPNP); /** @@ -84,10 +86,7 @@ bool EuclideanResection(const Mat &x_image, * Horn, Hilden, "Closed-form solution of absolute orientation using * orthonormal matrices" */ -void AbsoluteOrientation(const Mat3X &X, - const Mat3X &Xp, - Mat3 *R, - Vec3 *t); +void AbsoluteOrientation(const Mat3X& X, const Mat3X& Xp, Mat3* R, Vec3* t); /** * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or @@ -102,9 +101,10 @@ void AbsoluteOrientation(const Mat3X &X, * This is the algorithm described in: "Linear Pose Estimation from Points or * Lines", by Ansar, A. and Daniilidis, PAMI 2003. vol. 25, no. 5. */ -void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t); +void EuclideanResectionAnsarDaniilidis(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t); /** * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or * more 3D points and their images. @@ -120,9 +120,10 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X &x_camera, * and F. Moreno-Noguer and P. Fua, IJCV 2009. vol. 81, no. 2 * \note: the non-linear optimization is not implemented here. */ -bool EuclideanResectionEPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t); +bool EuclideanResectionEPnP(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t); /** * Computes the extrinsic parameters, R and t for a calibrated camera from 4 or @@ -137,12 +138,12 @@ bool EuclideanResectionEPnP(const Mat2X &x_camera, * Straight from the paper: * http://www.diegm.uniud.it/fusiello/papers/3dimpvt12-b.pdf */ -bool EuclideanResectionPPnP(const Mat2X &x_camera, - const Mat3X &X_world, - Mat3 *R, Vec3 *t); +bool EuclideanResectionPPnP(const Mat2X& x_camera, + const Mat3X& X_world, + Mat3* R, + Vec3* t); } // namespace euclidean_resection } // namespace libmv - #endif /* LIBMV_MULTIVIEW_EUCLIDEAN_RESECTION_H_ */ diff --git a/intern/libmv/libmv/multiview/euclidean_resection_test.cc b/intern/libmv/libmv/multiview/euclidean_resection_test.cc index 378837d3d2d..3bb8e6e1710 100644 --- a/intern/libmv/libmv/multiview/euclidean_resection_test.cc +++ b/intern/libmv/libmv/multiview/euclidean_resection_test.cc @@ -19,9 +19,9 @@ // IN THE SOFTWARE. #include "libmv/multiview/euclidean_resection.h" -#include "libmv/numeric/numeric.h" #include "libmv/logging/logging.h" #include "libmv/multiview/projection.h" +#include "libmv/numeric/numeric.h" #include "testing/testing.h" using namespace libmv::euclidean_resection; @@ -33,10 +33,10 @@ static void CreateCameraSystem(const Mat3& KK, const Vec& X_distances, const Mat3& R_input, const Vec3& T_input, - Mat2X *x_camera, - Mat3X *X_world, - Mat3 *R_expected, - Vec3 *T_expected) { + Mat2X* x_camera, + Mat3X* X_world, + Mat3* R_expected, + Vec3* T_expected) { int num_points = x_image.cols(); Mat3X x_unit_cam(3, num_points); @@ -76,9 +76,9 @@ TEST(AbsoluteOrientation, QuaternionSolution) { // Create a random translation and rotation. Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); + R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); Vec3 t_input; t_input.setRandom(); @@ -109,26 +109,29 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { image_dimensions << 1600, 1200; Mat3 KK; + // clang-format off KK << 2796, 0, 804, 0 , 2796, 641, 0, 0, 1; + // clang-format on // The real image points. int num_points = 4; Mat3X x_image(3, num_points); + // clang-format off x_image << 1164.06, 734.948, 749.599, 430.727, 681.386, 844.59, 496.315, 580.775, 1, 1, 1, 1; - + // clang-format on // A vector of the 4 distances to the 3D points. Vec X_distances = 100 * Vec::Random(num_points).array().abs(); // Create the random camera motion R and t that resection should recover. Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); + R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); Vec3 T_input; T_input.setRandom(); @@ -140,15 +143,21 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { Vec3 T_expected; Mat3X X_world; Mat2X x_camera; - CreateCameraSystem(KK, x_image, X_distances, R_input, T_input, - &x_camera, &X_world, &R_expected, &T_expected); + CreateCameraSystem(KK, + x_image, + X_distances, + R_input, + T_input, + &x_camera, + &X_world, + &R_expected, + &T_expected); // Finally, run the code under test. Mat3 R_output; Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_ANSAR_DANIILIDIS); + EuclideanResection( + x_camera, X_world, &R_output, &T_output, RESECTION_ANSAR_DANIILIDIS); EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); @@ -173,9 +182,11 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { // TODO(jmichot): Reduce the code duplication here with the code above. TEST(EuclideanResection, Points6AllRandomInput) { Mat3 KK; + // clang-format off KK << 2796, 0, 804, 0 , 2796, 641, 0, 0, 1; + // clang-format on // Create random image points for a 1600x1200 image. int w = 1600; @@ -192,9 +203,9 @@ TEST(EuclideanResection, Points6AllRandomInput) { // Create the random camera motion R and t that resection should recover. Mat3 R_input; - R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) - * Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); + R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY()) * + Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ()); Vec3 T_input; T_input.setRandom(); @@ -204,33 +215,36 @@ TEST(EuclideanResection, Points6AllRandomInput) { Mat3 R_expected; Vec3 T_expected; Mat3X X_world; - CreateCameraSystem(KK, x_image, X_distances, R_input, T_input, - &x_camera, &X_world, &R_expected, &T_expected); + CreateCameraSystem(KK, + x_image, + X_distances, + R_input, + T_input, + &x_camera, + &X_world, + &R_expected, + &T_expected); // Test each of the resection methods. { Mat3 R_output; Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_ANSAR_DANIILIDIS); + EuclideanResection( + x_camera, X_world, &R_output, &T_output, RESECTION_ANSAR_DANIILIDIS); EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); } { Mat3 R_output; Vec3 T_output; - EuclideanResection(x_camera, X_world, - &R_output, &T_output, - RESECTION_EPNP); + EuclideanResection(x_camera, X_world, &R_output, &T_output, RESECTION_EPNP); EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); } { Mat3 R_output; Vec3 T_output; - EuclideanResection(x_image, X_world, KK, - &R_output, &T_output); + EuclideanResection(x_image, X_world, KK, &R_output, &T_output); EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7); } diff --git a/intern/libmv/libmv/multiview/fundamental.cc b/intern/libmv/libmv/multiview/fundamental.cc index ea8594c8cc0..c8c94ecd7bb 100644 --- a/intern/libmv/libmv/multiview/fundamental.cc +++ b/intern/libmv/libmv/multiview/fundamental.cc @@ -22,15 +22,15 @@ #include "ceres/ceres.h" #include "libmv/logging/logging.h" -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/poly.h" #include "libmv/multiview/conditioning.h" #include "libmv/multiview/projection.h" #include "libmv/multiview/triangulation.h" +#include "libmv/numeric/numeric.h" +#include "libmv/numeric/poly.h" namespace libmv { -static void EliminateRow(const Mat34 &P, int row, Mat *X) { +static void EliminateRow(const Mat34& P, int row, Mat* X) { X->resize(2, 4); int first_row = (row + 1) % 3; @@ -42,7 +42,7 @@ static void EliminateRow(const Mat34 &P, int row, Mat *X) { } } -void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2) { +void ProjectionsFromFundamental(const Mat3& F, Mat34* P1, Mat34* P2) { *P1 << Mat3::Identity(), Vec3::Zero(); Vec3 e2; Mat3 Ft = F.transpose(); @@ -51,7 +51,7 @@ void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2) { } // Addapted from vgg_F_from_P. -void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F) { +void FundamentalFromProjections(const Mat34& P1, const Mat34& P2, Mat3* F) { Mat X[3]; Mat Y[3]; Mat XY; @@ -71,7 +71,7 @@ void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F) { // HZ 11.1 pag.279 (x1 = x, x2 = x') // http://www.cs.unc.edu/~marc/tutorial/node54.html -static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) { +static double EightPointSolver(const Mat& x1, const Mat& x2, Mat3* F) { DCHECK_EQ(x1.rows(), 2); DCHECK_GE(x1.cols(), 8); DCHECK_EQ(x1.rows(), x2.rows()); @@ -98,7 +98,7 @@ static double EightPointSolver(const Mat &x1, const Mat &x2, Mat3 *F) { } // HZ 11.1.1 pag.280 -void EnforceFundamentalRank2Constraint(Mat3 *F) { +void EnforceFundamentalRank2Constraint(Mat3* F) { Eigen::JacobiSVD<Mat3> USV(*F, Eigen::ComputeFullU | Eigen::ComputeFullV); Vec3 d = USV.singularValues(); d(2) = 0.0; @@ -106,9 +106,7 @@ void EnforceFundamentalRank2Constraint(Mat3 *F) { } // HZ 11.2 pag.281 (x1 = x, x2 = x') -double NormalizedEightPointSolver(const Mat &x1, - const Mat &x2, - Mat3 *F) { +double NormalizedEightPointSolver(const Mat& x1, const Mat& x2, Mat3* F) { DCHECK_EQ(x1.rows(), 2); DCHECK_GE(x1.cols(), 8); DCHECK_EQ(x1.rows(), x2.rows()); @@ -135,9 +133,9 @@ double NormalizedEightPointSolver(const Mat &x1, // Seven-point algorithm. // http://www.cs.unc.edu/~marc/tutorial/node55.html -double FundamentalFrom7CorrespondencesLinear(const Mat &x1, - const Mat &x2, - std::vector<Mat3> *F) { +double FundamentalFrom7CorrespondencesLinear(const Mat& x1, + const Mat& x2, + std::vector<Mat3>* F) { DCHECK_EQ(x1.rows(), 2); DCHECK_EQ(x1.cols(), 7); DCHECK_EQ(x1.rows(), x2.rows()); @@ -169,25 +167,29 @@ double FundamentalFrom7CorrespondencesLinear(const Mat &x1, // Then, use the condition det(F) = 0 to determine F. In other words, solve // det(F1 + a*F2) = 0 for a. - double a = F1(0, 0), j = F2(0, 0), - b = F1(0, 1), k = F2(0, 1), - c = F1(0, 2), l = F2(0, 2), - d = F1(1, 0), m = F2(1, 0), - e = F1(1, 1), n = F2(1, 1), - f = F1(1, 2), o = F2(1, 2), - g = F1(2, 0), p = F2(2, 0), - h = F1(2, 1), q = F2(2, 1), - i = F1(2, 2), r = F2(2, 2); + double a = F1(0, 0), j = F2(0, 0); + double b = F1(0, 1), k = F2(0, 1); + double c = F1(0, 2), l = F2(0, 2); + double d = F1(1, 0), m = F2(1, 0); + double e = F1(1, 1), n = F2(1, 1); + double f = F1(1, 2), o = F2(1, 2); + double g = F1(2, 0), p = F2(2, 0); + double h = F1(2, 1), q = F2(2, 1); + double i = F1(2, 2), r = F2(2, 2); // Run fundamental_7point_coeffs.py to get the below coefficients. // The coefficients are in ascending powers of alpha, i.e. P[N]*x^N. double P[4] = { - a*e*i + b*f*g + c*d*h - a*f*h - b*d*i - c*e*g, - a*e*r + a*i*n + b*f*p + b*g*o + c*d*q + c*h*m + d*h*l + e*i*j + f*g*k - - a*f*q - a*h*o - b*d*r - b*i*m - c*e*p - c*g*n - d*i*k - e*g*l - f*h*j, - a*n*r + b*o*p + c*m*q + d*l*q + e*j*r + f*k*p + g*k*o + h*l*m + i*j*n - - a*o*q - b*m*r - c*n*p - d*k*r - e*l*p - f*j*q - g*l*n - h*j*o - i*k*m, - j*n*r + k*o*p + l*m*q - j*o*q - k*m*r - l*n*p, + a * e * i + b * f * g + c * d * h - a * f * h - b * d * i - c * e * g, + a * e * r + a * i * n + b * f * p + b * g * o + c * d * q + c * h * m + + d * h * l + e * i * j + f * g * k - a * f * q - a * h * o - + b * d * r - b * i * m - c * e * p - c * g * n - d * i * k - + e * g * l - f * h * j, + a * n * r + b * o * p + c * m * q + d * l * q + e * j * r + f * k * p + + g * k * o + h * l * m + i * j * n - a * o * q - b * m * r - + c * n * p - d * k * r - e * l * p - f * j * q - g * l * n - + h * j * o - i * k * m, + j * n * r + k * o * p + l * m * q - j * o * q - k * m * r - l * n * p, }; // Solve for the roots of P[3]*x^3 + P[2]*x^2 + P[1]*x + P[0] = 0. @@ -195,15 +197,15 @@ double FundamentalFrom7CorrespondencesLinear(const Mat &x1, int num_roots = SolveCubicPolynomial(P, roots); // Build the fundamental matrix for each solution. - for (int kk = 0; kk < num_roots; ++kk) { + for (int kk = 0; kk < num_roots; ++kk) { F->push_back(F1 + roots[kk] * F2); } return s; } -double FundamentalFromCorrespondences7Point(const Mat &x1, - const Mat &x2, - std::vector<Mat3> *F) { +double FundamentalFromCorrespondences7Point(const Mat& x1, + const Mat& x2, + std::vector<Mat3>* F) { DCHECK_EQ(x1.rows(), 2); DCHECK_GE(x1.cols(), 7); DCHECK_EQ(x1.rows(), x2.rows()); @@ -218,25 +220,25 @@ double FundamentalFromCorrespondences7Point(const Mat &x1, ApplyTransformationToPoints(x2, T2, &x2_normalized); // Estimate the fundamental matrix. - double smaller_singular_value = - FundamentalFrom7CorrespondencesLinear(x1_normalized, x2_normalized, &(*F)); + double smaller_singular_value = FundamentalFrom7CorrespondencesLinear( + x1_normalized, x2_normalized, &(*F)); for (int k = 0; k < F->size(); ++k) { - Mat3 & Fmat = (*F)[k]; + Mat3& Fmat = (*F)[k]; // Denormalize the fundamental matrix. Fmat = T2.transpose() * Fmat * T1; } return smaller_singular_value; } -void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized) { +void NormalizeFundamental(const Mat3& F, Mat3* F_normalized) { *F_normalized = F / FrobeniusNorm(F); if ((*F_normalized)(2, 2) < 0) { *F_normalized *= -1; } } -double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { +double SampsonDistance(const Mat& F, const Vec2& x1, const Vec2& x2) { Vec3 x(x1(0), x1(1), 1.0); Vec3 y(x2(0), x2(1), 1.0); @@ -244,11 +246,11 @@ double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { Vec3 Ft_y = F.transpose() * y; double y_F_x = y.dot(F_x); - return Square(y_F_x) / ( F_x.head<2>().squaredNorm() - + Ft_y.head<2>().squaredNorm()); + return Square(y_F_x) / + (F_x.head<2>().squaredNorm() + Ft_y.head<2>().squaredNorm()); } -double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { +double SymmetricEpipolarDistance(const Mat& F, const Vec2& x1, const Vec2& x2) { Vec3 x(x1(0), x1(1), 1.0); Vec3 y(x2(0), x2(1), 1.0); @@ -256,43 +258,40 @@ double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2) { Vec3 Ft_y = F.transpose() * y; double y_F_x = y.dot(F_x); - return Square(y_F_x) * ( 1 / F_x.head<2>().squaredNorm() - + 1 / Ft_y.head<2>().squaredNorm()); + return Square(y_F_x) * + (1 / F_x.head<2>().squaredNorm() + 1 / Ft_y.head<2>().squaredNorm()); } // HZ 9.6 pag 257 (formula 9.12) -void EssentialFromFundamental(const Mat3 &F, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *E) { +void EssentialFromFundamental(const Mat3& F, + const Mat3& K1, + const Mat3& K2, + Mat3* E) { *E = K2.transpose() * F * K1; } // HZ 9.6 pag 257 (formula 9.12) // Or http://ai.stanford.edu/~birch/projective/node20.html -void FundamentalFromEssential(const Mat3 &E, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *F) { +void FundamentalFromEssential(const Mat3& E, + const Mat3& K1, + const Mat3& K2, + Mat3* F) { *F = K2.inverse().transpose() * E * K1.inverse(); } -void RelativeCameraMotion(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *R, - Vec3 *t) { +void RelativeCameraMotion(const Mat3& R1, + const Vec3& t1, + const Mat3& R2, + const Vec3& t2, + Mat3* R, + Vec3* t) { *R = R2 * R1.transpose(); *t = t2 - (*R) * t1; } // HZ 9.6 pag 257 -void EssentialFromRt(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *E) { +void EssentialFromRt( + const Mat3& R1, const Vec3& t1, const Mat3& R2, const Vec3& t2, Mat3* E) { Mat3 R; Vec3 t; RelativeCameraMotion(R1, t1, R2, t2, &R, &t); @@ -301,11 +300,11 @@ void EssentialFromRt(const Mat3 &R1, } // HZ 9.6 pag 259 (Result 9.19) -void MotionFromEssential(const Mat3 &E, - std::vector<Mat3> *Rs, - std::vector<Vec3> *ts) { +void MotionFromEssential(const Mat3& E, + std::vector<Mat3>* Rs, + std::vector<Vec3>* ts) { Eigen::JacobiSVD<Mat3> USV(E, Eigen::ComputeFullU | Eigen::ComputeFullV); - Mat3 U = USV.matrixU(); + Mat3 U = USV.matrixU(); Mat3 Vt = USV.matrixV().transpose(); // Last column of U is undetermined since d = (a a 0). @@ -318,9 +317,11 @@ void MotionFromEssential(const Mat3 &E, } Mat3 W; + // clang-format off W << 0, -1, 0, 1, 0, 0, 0, 0, 1; + // clang-format on Mat3 U_W_Vt = U * W * Vt; Mat3 U_Wt_Vt = U * W.transpose() * Vt; @@ -332,18 +333,18 @@ void MotionFromEssential(const Mat3 &E, (*Rs)[3] = U_Wt_Vt; ts->resize(4); - (*ts)[0] = U.col(2); + (*ts)[0] = U.col(2); (*ts)[1] = -U.col(2); - (*ts)[2] = U.col(2); + (*ts)[2] = U.col(2); (*ts)[3] = -U.col(2); } -int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs, - const std::vector<Vec3> &ts, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2) { +int MotionFromEssentialChooseSolution(const std::vector<Mat3>& Rs, + const std::vector<Vec3>& ts, + const Mat3& K1, + const Vec2& x1, + const Mat3& K2, + const Vec2& x2) { DCHECK_EQ(4, Rs.size()); DCHECK_EQ(4, ts.size()); @@ -354,8 +355,8 @@ int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs, t1.setZero(); P_From_KRt(K1, R1, t1, &P1); for (int i = 0; i < 4; ++i) { - const Mat3 &R2 = Rs[i]; - const Vec3 &t2 = ts[i]; + const Mat3& R2 = Rs[i]; + const Vec3& t2 = ts[i]; P_From_KRt(K2, R2, t2, &P2); Vec3 X; TriangulateDLT(P1, x1, P2, x2, &X); @@ -369,13 +370,13 @@ int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs, return -1; } -bool MotionFromEssentialAndCorrespondence(const Mat3 &E, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2, - Mat3 *R, - Vec3 *t) { +bool MotionFromEssentialAndCorrespondence(const Mat3& E, + const Mat3& K1, + const Vec2& x1, + const Mat3& K2, + const Vec2& x2, + Mat3* R, + Vec3* t) { std::vector<Mat3> Rs; std::vector<Vec3> ts; MotionFromEssential(E, &Rs, &ts); @@ -389,7 +390,7 @@ bool MotionFromEssentialAndCorrespondence(const Mat3 &E, } } -void FundamentalToEssential(const Mat3 &F, Mat3 *E) { +void FundamentalToEssential(const Mat3& F, Mat3* E) { Eigen::JacobiSVD<Mat3> svd(F, Eigen::ComputeFullU | Eigen::ComputeFullV); // See Hartley & Zisserman page 294, result 11.1, which shows how to get the @@ -399,8 +400,8 @@ void FundamentalToEssential(const Mat3 &F, Mat3 *E) { double s = (a + b) / 2.0; LG << "Initial reconstruction's rotation is non-euclidean by " - << (((a - b) / std::max(a, b)) * 100) << "%; singular values:" - << svd.singularValues().transpose(); + << (((a - b) / std::max(a, b)) * 100) + << "%; singular values:" << svd.singularValues().transpose(); Vec3 diag; diag << s, s, 0; @@ -410,9 +411,8 @@ void FundamentalToEssential(const Mat3 &F, Mat3 *E) { // Default settings for fundamental estimation which should be suitable // for a wide range of use cases. -EstimateFundamentalOptions::EstimateFundamentalOptions(void) : - max_num_iterations(50), - expected_average_symmetric_distance(1e-16) { +EstimateFundamentalOptions::EstimateFundamentalOptions(void) + : max_num_iterations(50), expected_average_symmetric_distance(1e-16) { } namespace { @@ -420,12 +420,11 @@ namespace { // used for fundamental matrix refinement. class FundamentalSymmetricEpipolarCostFunctor { public: - FundamentalSymmetricEpipolarCostFunctor(const Vec2 &x, - const Vec2 &y) - : x_(x), y_(y) {} + FundamentalSymmetricEpipolarCostFunctor(const Vec2& x, const Vec2& y) + : x_(x), y_(y) {} - template<typename T> - bool operator()(const T *fundamental_parameters, T *residuals) const { + template <typename T> + bool operator()(const T* fundamental_parameters, T* residuals) const { typedef Eigen::Matrix<T, 3, 3> Mat3; typedef Eigen::Matrix<T, 3, 1> Vec3; @@ -454,9 +453,10 @@ class FundamentalSymmetricEpipolarCostFunctor { // average value. class TerminationCheckingCallback : public ceres::IterationCallback { public: - TerminationCheckingCallback(const Mat &x1, const Mat &x2, - const EstimateFundamentalOptions &options, - Mat3 *F) + TerminationCheckingCallback(const Mat& x1, + const Mat& x2, + const EstimateFundamentalOptions& options, + Mat3* F) : options_(options), x1_(x1), x2_(x2), F_(F) {} virtual ceres::CallbackReturnType operator()( @@ -469,9 +469,7 @@ class TerminationCheckingCallback : public ceres::IterationCallback { // Calculate average of symmetric epipolar distance. double average_distance = 0.0; for (int i = 0; i < x1_.cols(); i++) { - average_distance = SymmetricEpipolarDistance(*F_, - x1_.col(i), - x2_.col(i)); + average_distance = SymmetricEpipolarDistance(*F_, x1_.col(i), x2_.col(i)); } average_distance /= x1_.cols(); @@ -483,19 +481,19 @@ class TerminationCheckingCallback : public ceres::IterationCallback { } private: - const EstimateFundamentalOptions &options_; - const Mat &x1_; - const Mat &x2_; - Mat3 *F_; + const EstimateFundamentalOptions& options_; + const Mat& x1_; + const Mat& x2_; + Mat3* F_; }; } // namespace /* Fundamental transformation estimation. */ bool EstimateFundamentalFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateFundamentalOptions &options, - Mat3 *F) { + const Mat& x1, + const Mat& x2, + const EstimateFundamentalOptions& options, + Mat3* F) { // Step 1: Algebraic fundamental estimation. // Assume algebraic estiation always succeeds, @@ -506,16 +504,15 @@ bool EstimateFundamentalFromCorrespondences( // Step 2: Refine matrix using Ceres minimizer. ceres::Problem problem; for (int i = 0; i < x1.cols(); i++) { - FundamentalSymmetricEpipolarCostFunctor - *fundamental_symmetric_epipolar_cost_function = - new FundamentalSymmetricEpipolarCostFunctor(x1.col(i), - x2.col(i)); + FundamentalSymmetricEpipolarCostFunctor* + fundamental_symmetric_epipolar_cost_function = + new FundamentalSymmetricEpipolarCostFunctor(x1.col(i), x2.col(i)); problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - FundamentalSymmetricEpipolarCostFunctor, - 2, // num_residuals - 9>(fundamental_symmetric_epipolar_cost_function), + new ceres::AutoDiffCostFunction<FundamentalSymmetricEpipolarCostFunctor, + 2, // num_residuals + 9>( + fundamental_symmetric_epipolar_cost_function), NULL, F->data()); } diff --git a/intern/libmv/libmv/multiview/fundamental.h b/intern/libmv/libmv/multiview/fundamental.h index a6c7a6802fe..6d25691c4a3 100644 --- a/intern/libmv/libmv/multiview/fundamental.h +++ b/intern/libmv/libmv/multiview/fundamental.h @@ -27,36 +27,34 @@ namespace libmv { -void ProjectionsFromFundamental(const Mat3 &F, Mat34 *P1, Mat34 *P2); -void FundamentalFromProjections(const Mat34 &P1, const Mat34 &P2, Mat3 *F); +void ProjectionsFromFundamental(const Mat3& F, Mat34* P1, Mat34* P2); +void FundamentalFromProjections(const Mat34& P1, const Mat34& P2, Mat3* F); /** * 7 points (minimal case, points coordinates must be normalized before): */ -double FundamentalFrom7CorrespondencesLinear(const Mat &x1, - const Mat &x2, - std::vector<Mat3> *F); +double FundamentalFrom7CorrespondencesLinear(const Mat& x1, + const Mat& x2, + std::vector<Mat3>* F); /** * 7 points (points coordinates must be in image space): */ -double FundamentalFromCorrespondences7Point(const Mat &x1, - const Mat &x2, - std::vector<Mat3> *F); +double FundamentalFromCorrespondences7Point(const Mat& x1, + const Mat& x2, + std::vector<Mat3>* F); /** * 8 points (points coordinates must be in image space): */ -double NormalizedEightPointSolver(const Mat &x1, - const Mat &x2, - Mat3 *F); +double NormalizedEightPointSolver(const Mat& x1, const Mat& x2, Mat3* F); /** * Fundamental matrix utility function: */ -void EnforceFundamentalRank2Constraint(Mat3 *F); +void EnforceFundamentalRank2Constraint(Mat3* F); -void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized); +void NormalizeFundamental(const Mat3& F, Mat3* F_normalized); /** * Approximate squared reprojection errror. @@ -64,14 +62,14 @@ void NormalizeFundamental(const Mat3 &F, Mat3 *F_normalized); * See page 287 of HZ equation 11.9. This avoids triangulating the point, * relying only on the entries in F. */ -double SampsonDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2); +double SampsonDistance(const Mat& F, const Vec2& x1, const Vec2& x2); /** * Calculates the sum of the distances from the points to the epipolar lines. * * See page 288 of HZ equation 11.10. */ -double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2); +double SymmetricEpipolarDistance(const Mat& F, const Vec2& x1, const Vec2& x2); /** * Compute the relative camera motion between two cameras. @@ -81,32 +79,29 @@ double SymmetricEpipolarDistance(const Mat &F, const Vec2 &x1, const Vec2 &x2); * If T1 and T2 are the camera motions, the computed relative motion is * T = T2 T1^{-1} */ -void RelativeCameraMotion(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *R, - Vec3 *t); - -void EssentialFromFundamental(const Mat3 &F, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *E); - -void FundamentalFromEssential(const Mat3 &E, - const Mat3 &K1, - const Mat3 &K2, - Mat3 *F); - -void EssentialFromRt(const Mat3 &R1, - const Vec3 &t1, - const Mat3 &R2, - const Vec3 &t2, - Mat3 *E); - -void MotionFromEssential(const Mat3 &E, - std::vector<Mat3> *Rs, - std::vector<Vec3> *ts); +void RelativeCameraMotion(const Mat3& R1, + const Vec3& t1, + const Mat3& R2, + const Vec3& t2, + Mat3* R, + Vec3* t); + +void EssentialFromFundamental(const Mat3& F, + const Mat3& K1, + const Mat3& K2, + Mat3* E); + +void FundamentalFromEssential(const Mat3& E, + const Mat3& K1, + const Mat3& K2, + Mat3* F); + +void EssentialFromRt( + const Mat3& R1, const Vec3& t1, const Mat3& R2, const Vec3& t2, Mat3* E); + +void MotionFromEssential(const Mat3& E, + std::vector<Mat3>* Rs, + std::vector<Vec3>* ts); /** * Choose one of the four possible motion solutions from an essential matrix. @@ -117,25 +112,25 @@ void MotionFromEssential(const Mat3 &E, * * \return index of the right solution or -1 if no solution. */ -int MotionFromEssentialChooseSolution(const std::vector<Mat3> &Rs, - const std::vector<Vec3> &ts, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2); - -bool MotionFromEssentialAndCorrespondence(const Mat3 &E, - const Mat3 &K1, - const Vec2 &x1, - const Mat3 &K2, - const Vec2 &x2, - Mat3 *R, - Vec3 *t); +int MotionFromEssentialChooseSolution(const std::vector<Mat3>& Rs, + const std::vector<Vec3>& ts, + const Mat3& K1, + const Vec2& x1, + const Mat3& K2, + const Vec2& x2); + +bool MotionFromEssentialAndCorrespondence(const Mat3& E, + const Mat3& K1, + const Vec2& x1, + const Mat3& K2, + const Vec2& x2, + Mat3* R, + Vec3* t); /** * Find closest essential matrix E to fundamental F */ -void FundamentalToEssential(const Mat3 &F, Mat3 *E); +void FundamentalToEssential(const Mat3& F, Mat3* E); /** * This structure contains options that controls how the fundamental @@ -170,10 +165,10 @@ struct EstimateFundamentalOptions { * refinement. */ bool EstimateFundamentalFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateFundamentalOptions &options, - Mat3 *F); + const Mat& x1, + const Mat& x2, + const EstimateFundamentalOptions& options, + Mat3* F); } // namespace libmv diff --git a/intern/libmv/libmv/multiview/fundamental_test.cc b/intern/libmv/libmv/multiview/fundamental_test.cc index da0eb449b8f..0ec91ca8d19 100644 --- a/intern/libmv/libmv/multiview/fundamental_test.cc +++ b/intern/libmv/libmv/multiview/fundamental_test.cc @@ -34,12 +34,14 @@ using namespace libmv; TEST(Fundamental, FundamentalFromProjections) { Mat34 P1_gt, P2_gt; + // clang-format off P1_gt << 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0; P2_gt << 1, 1, 1, 3, 0, 2, 0, 3, 0, 1, 1, 0; + // clang-format on Mat3 F_gt; FundamentalFromProjections(P1_gt, P2_gt, &F_gt); @@ -55,8 +57,10 @@ TEST(Fundamental, FundamentalFromProjections) { TEST(Fundamental, PreconditionerFromPoints) { int n = 4; Mat points(2, n); + // clang-format off points << 0, 0, 1, 1, 0, 2, 1, 3; + // clang-format on Mat3 T; PreconditionerFromPoints(points, &T); @@ -152,8 +156,8 @@ TEST(Fundamental, MotionFromEssentialAndCorrespondence) { Mat3 R_estimated; Vec3 t_estimated; - MotionFromEssentialAndCorrespondence(E, d.K1, x1, d.K2, x2, - &R_estimated, &t_estimated); + MotionFromEssentialAndCorrespondence( + E, d.K1, x1, d.K2, x2, &R_estimated, &t_estimated); EXPECT_LE(FrobeniusDistance(R_estimated, R), 1e-8); EXPECT_LE(DistanceL2(t_estimated, t), 1e-8); diff --git a/intern/libmv/libmv/multiview/homography.cc b/intern/libmv/libmv/multiview/homography.cc index 69177743f94..2db2c0cd3d5 100644 --- a/intern/libmv/libmv/multiview/homography.cc +++ b/intern/libmv/libmv/multiview/homography.cc @@ -26,7 +26,7 @@ #include "libmv/multiview/homography_parameterization.h" namespace libmv { -/** 2D Homography transformation estimation in the case that points are in +/** 2D Homography transformation estimation in the case that points are in * euclidean coordinates. * * x = H y @@ -44,10 +44,7 @@ namespace libmv { * (-x2*a+x1*d)*y1 + (-x2*b+x1*e)*y2 + -x2*c+x1*f |0| */ static bool Homography2DFromCorrespondencesLinearEuc( - const Mat &x1, - const Mat &x2, - Mat3 *H, - double expected_precision) { + const Mat& x1, const Mat& x2, Mat3* H, double expected_precision) { assert(2 == x1.rows()); assert(4 <= x1.cols()); assert(x1.rows() == x2.rows()); @@ -58,27 +55,27 @@ static bool Homography2DFromCorrespondencesLinearEuc( Mat b = Mat::Zero(n * 3, 1); for (int i = 0; i < n; ++i) { int j = 3 * i; - L(j, 0) = x1(0, i); // a - L(j, 1) = x1(1, i); // b - L(j, 2) = 1.0; // c + L(j, 0) = x1(0, i); // a + L(j, 1) = x1(1, i); // b + L(j, 2) = 1.0; // c L(j, 6) = -x2(0, i) * x1(0, i); // g L(j, 7) = -x2(0, i) * x1(1, i); // h - b(j, 0) = x2(0, i); // i + b(j, 0) = x2(0, i); // i ++j; - L(j, 3) = x1(0, i); // d - L(j, 4) = x1(1, i); // e - L(j, 5) = 1.0; // f + L(j, 3) = x1(0, i); // d + L(j, 4) = x1(1, i); // e + L(j, 5) = 1.0; // f L(j, 6) = -x2(1, i) * x1(0, i); // g L(j, 7) = -x2(1, i) * x1(1, i); // h - b(j, 0) = x2(1, i); // i + b(j, 0) = x2(1, i); // i // This ensures better stability // TODO(julien) make a lite version without this 3rd set ++j; - L(j, 0) = x2(1, i) * x1(0, i); // a - L(j, 1) = x2(1, i) * x1(1, i); // b - L(j, 2) = x2(1, i); // c + L(j, 0) = x2(1, i) * x1(0, i); // a + L(j, 1) = x2(1, i) * x1(1, i); // b + L(j, 2) = x2(1, i); // c L(j, 3) = -x2(0, i) * x1(0, i); // d L(j, 4) = -x2(0, i) * x1(1, i); // e L(j, 5) = -x2(0, i); // f @@ -86,14 +83,15 @@ static bool Homography2DFromCorrespondencesLinearEuc( // Solve Lx=B Vec h = L.fullPivLu().solve(b); Homography2DNormalizedParameterization<double>::To(h, H); - if ((L * h).isApprox(b, expected_precision)) { + if ((L * h).isApprox(b, expected_precision)) { return true; } else { return false; } } -/** 2D Homography transformation estimation in the case that points are in +// clang-format off +/** 2D Homography transformation estimation in the case that points are in * homogeneous coordinates. * * | 0 -x3 x2| |a b c| |y1| -x3*d+x2*g -x3*e+x2*h -x3*f+x2*1 |y1| (-x3*d+x2*g)*y1 (-x3*e+x2*h)*y2 (-x3*f+x2*1)*y3 |0| @@ -101,13 +99,14 @@ static bool Homography2DFromCorrespondencesLinearEuc( * |-x2 x1 0| |g h 1| |y3| -x2*a+x1*d -x2*b+x1*e -x2*c+x1*f |y3| (-x2*a+x1*d)*y1 (-x2*b+x1*e)*y2 (-x2*c+x1*f)*y3 |0| * X = |a b c d e f g h|^t */ -bool Homography2DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat3 *H, +// clang-format on +bool Homography2DFromCorrespondencesLinear(const Mat& x1, + const Mat& x2, + Mat3* H, double expected_precision) { if (x1.rows() == 2) { - return Homography2DFromCorrespondencesLinearEuc(x1, x2, H, - expected_precision); + return Homography2DFromCorrespondencesLinearEuc( + x1, x2, H, expected_precision); } assert(3 == x1.rows()); assert(4 <= x1.cols()); @@ -122,33 +121,33 @@ bool Homography2DFromCorrespondencesLinear(const Mat &x1, Mat b = Mat::Zero(n * 3, 1); for (int i = 0; i < n; ++i) { int j = 3 * i; - L(j, 0) = x2(w, i) * x1(x, i); // a - L(j, 1) = x2(w, i) * x1(y, i); // b - L(j, 2) = x2(w, i) * x1(w, i); // c + L(j, 0) = x2(w, i) * x1(x, i); // a + L(j, 1) = x2(w, i) * x1(y, i); // b + L(j, 2) = x2(w, i) * x1(w, i); // c L(j, 6) = -x2(x, i) * x1(x, i); // g L(j, 7) = -x2(x, i) * x1(y, i); // h - b(j, 0) = x2(x, i) * x1(w, i); + b(j, 0) = x2(x, i) * x1(w, i); ++j; - L(j, 3) = x2(w, i) * x1(x, i); // d - L(j, 4) = x2(w, i) * x1(y, i); // e - L(j, 5) = x2(w, i) * x1(w, i); // f + L(j, 3) = x2(w, i) * x1(x, i); // d + L(j, 4) = x2(w, i) * x1(y, i); // e + L(j, 5) = x2(w, i) * x1(w, i); // f L(j, 6) = -x2(y, i) * x1(x, i); // g L(j, 7) = -x2(y, i) * x1(y, i); // h - b(j, 0) = x2(y, i) * x1(w, i); + b(j, 0) = x2(y, i) * x1(w, i); // This ensures better stability ++j; - L(j, 0) = x2(y, i) * x1(x, i); // a - L(j, 1) = x2(y, i) * x1(y, i); // b - L(j, 2) = x2(y, i) * x1(w, i); // c + L(j, 0) = x2(y, i) * x1(x, i); // a + L(j, 1) = x2(y, i) * x1(y, i); // b + L(j, 2) = x2(y, i) * x1(w, i); // c L(j, 3) = -x2(x, i) * x1(x, i); // d L(j, 4) = -x2(x, i) * x1(y, i); // e L(j, 5) = -x2(x, i) * x1(w, i); // f } // Solve Lx=B Vec h = L.fullPivLu().solve(b); - if ((L * h).isApprox(b, expected_precision)) { + if ((L * h).isApprox(b, expected_precision)) { Homography2DNormalizedParameterization<double>::To(h, H); return true; } else { @@ -158,32 +157,30 @@ bool Homography2DFromCorrespondencesLinear(const Mat &x1, // Default settings for homography estimation which should be suitable // for a wide range of use cases. -EstimateHomographyOptions::EstimateHomographyOptions(void) : - use_normalization(true), - max_num_iterations(50), - expected_average_symmetric_distance(1e-16) { +EstimateHomographyOptions::EstimateHomographyOptions(void) + : use_normalization(true), + max_num_iterations(50), + expected_average_symmetric_distance(1e-16) { } namespace { -void GetNormalizedPoints(const Mat &original_points, - Mat *normalized_points, - Mat3 *normalization_matrix) { +void GetNormalizedPoints(const Mat& original_points, + Mat* normalized_points, + Mat3* normalization_matrix) { IsotropicPreconditionerFromPoints(original_points, normalization_matrix); - ApplyTransformationToPoints(original_points, - *normalization_matrix, - normalized_points); + ApplyTransformationToPoints( + original_points, *normalization_matrix, normalized_points); } // Cost functor which computes symmetric geometric distance // used for homography matrix refinement. class HomographySymmetricGeometricCostFunctor { public: - HomographySymmetricGeometricCostFunctor(const Vec2 &x, - const Vec2 &y) - : x_(x), y_(y) { } + HomographySymmetricGeometricCostFunctor(const Vec2& x, const Vec2& y) + : x_(x), y_(y) {} - template<typename T> - bool operator()(const T *homography_parameters, T *residuals) const { + template <typename T> + bool operator()(const T* homography_parameters, T* residuals) const { typedef Eigen::Matrix<T, 3, 3> Mat3; typedef Eigen::Matrix<T, 3, 1> Vec3; @@ -221,9 +218,10 @@ class HomographySymmetricGeometricCostFunctor { // average value. class TerminationCheckingCallback : public ceres::IterationCallback { public: - TerminationCheckingCallback(const Mat &x1, const Mat &x2, - const EstimateHomographyOptions &options, - Mat3 *H) + TerminationCheckingCallback(const Mat& x1, + const Mat& x2, + const EstimateHomographyOptions& options, + Mat3* H) : options_(options), x1_(x1), x2_(x2), H_(H) {} virtual ceres::CallbackReturnType operator()( @@ -236,9 +234,8 @@ class TerminationCheckingCallback : public ceres::IterationCallback { // Calculate average of symmetric geometric distance. double average_distance = 0.0; for (int i = 0; i < x1_.cols(); i++) { - average_distance = SymmetricGeometricDistance(*H_, - x1_.col(i), - x2_.col(i)); + average_distance = + SymmetricGeometricDistance(*H_, x1_.col(i), x2_.col(i)); } average_distance /= x1_.cols(); @@ -250,10 +247,10 @@ class TerminationCheckingCallback : public ceres::IterationCallback { } private: - const EstimateHomographyOptions &options_; - const Mat &x1_; - const Mat &x2_; - Mat3 *H_; + const EstimateHomographyOptions& options_; + const Mat& x1_; + const Mat& x2_; + Mat3* H_; }; } // namespace @@ -261,10 +258,10 @@ class TerminationCheckingCallback : public ceres::IterationCallback { * euclidean coordinates. */ bool EstimateHomography2DFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateHomographyOptions &options, - Mat3 *H) { + const Mat& x1, + const Mat& x2, + const EstimateHomographyOptions& options, + Mat3* H) { // TODO(sergey): Support homogenous coordinates, not just euclidean. assert(2 == x1.rows()); @@ -272,8 +269,7 @@ bool EstimateHomography2DFromCorrespondences( assert(x1.rows() == x2.rows()); assert(x1.cols() == x2.cols()); - Mat3 T1 = Mat3::Identity(), - T2 = Mat3::Identity(); + Mat3 T1 = Mat3::Identity(), T2 = Mat3::Identity(); // Step 1: Algebraic homography estimation. Mat x1_normalized, x2_normalized; @@ -300,16 +296,15 @@ bool EstimateHomography2DFromCorrespondences( // Step 2: Refine matrix using Ceres minimizer. ceres::Problem problem; for (int i = 0; i < x1.cols(); i++) { - HomographySymmetricGeometricCostFunctor - *homography_symmetric_geometric_cost_function = - new HomographySymmetricGeometricCostFunctor(x1.col(i), - x2.col(i)); + HomographySymmetricGeometricCostFunctor* + homography_symmetric_geometric_cost_function = + new HomographySymmetricGeometricCostFunctor(x1.col(i), x2.col(i)); problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - HomographySymmetricGeometricCostFunctor, - 4, // num_residuals - 9>(homography_symmetric_geometric_cost_function), + new ceres::AutoDiffCostFunction<HomographySymmetricGeometricCostFunctor, + 4, // num_residuals + 9>( + homography_symmetric_geometric_cost_function), NULL, H->data()); } @@ -335,15 +330,16 @@ bool EstimateHomography2DFromCorrespondences( return summary.IsSolutionUsable(); } +// clang-format off /** * x2 ~ A * x1 * x2^t * Hi * A *x1 = 0 - * H1 = H2 = H3 = + * H1 = H2 = H3 = * | 0 0 0 1| |-x2w| |0 0 0 0| | 0 | | 0 0 1 0| |-x2z| * | 0 0 0 0| -> | 0 | |0 0 1 0| -> |-x2z| | 0 0 0 0| -> | 0 | * | 0 0 0 0| | 0 | |0-1 0 0| | x2y| |-1 0 0 0| | x2x| * |-1 0 0 0| | x2x| |0 0 0 0| | 0 | | 0 0 0 0| | 0 | - * H4 = H5 = H6 = + * H4 = H5 = H6 = * |0 0 0 0| | 0 | | 0 1 0 0| |-x2y| |0 0 0 0| | 0 | * |0 0 0 1| -> |-x2w| |-1 0 0 0| -> | x2x| |0 0 0 0| -> | 0 | * |0 0 0 0| | 0 | | 0 0 0 0| | 0 | |0 0 0 1| |-x2w| @@ -361,10 +357,11 @@ bool EstimateHomography2DFromCorrespondences( * x2^t * H6 * A *x1 = (-x2w*i +x2z*m )*x1x + (-x2w*j +x2z*n )*x1y + (-x2w*k +x2z*o )*x1z + (-x2w*l +x2z*1 )*x1w = 0 * * X = |a b c d e f g h i j k l m n o|^t -*/ -bool Homography3DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat4 *H, + */ +// clang-format on +bool Homography3DFromCorrespondencesLinear(const Mat& x1, + const Mat& x2, + Mat4* H, double expected_precision) { assert(4 == x1.rows()); assert(5 <= x1.cols()); @@ -379,68 +376,68 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1, Mat b = Mat::Zero(n * 6, 1); for (int i = 0; i < n; ++i) { int j = 6 * i; - L(j, 0) = -x2(w, i) * x1(x, i); // a - L(j, 1) = -x2(w, i) * x1(y, i); // b - L(j, 2) = -x2(w, i) * x1(z, i); // c - L(j, 3) = -x2(w, i) * x1(w, i); // d - L(j, 12) = x2(x, i) * x1(x, i); // m - L(j, 13) = x2(x, i) * x1(y, i); // n - L(j, 14) = x2(x, i) * x1(z, i); // o - b(j, 0) = -x2(x, i) * x1(w, i); + L(j, 0) = -x2(w, i) * x1(x, i); // a + L(j, 1) = -x2(w, i) * x1(y, i); // b + L(j, 2) = -x2(w, i) * x1(z, i); // c + L(j, 3) = -x2(w, i) * x1(w, i); // d + L(j, 12) = x2(x, i) * x1(x, i); // m + L(j, 13) = x2(x, i) * x1(y, i); // n + L(j, 14) = x2(x, i) * x1(z, i); // o + b(j, 0) = -x2(x, i) * x1(w, i); ++j; - L(j, 4) = -x2(z, i) * x1(x, i); // e - L(j, 5) = -x2(z, i) * x1(y, i); // f - L(j, 6) = -x2(z, i) * x1(z, i); // g - L(j, 7) = -x2(z, i) * x1(w, i); // h - L(j, 8) = x2(y, i) * x1(x, i); // i - L(j, 9) = x2(y, i) * x1(y, i); // j - L(j, 10) = x2(y, i) * x1(z, i); // k - L(j, 11) = x2(y, i) * x1(w, i); // l + L(j, 4) = -x2(z, i) * x1(x, i); // e + L(j, 5) = -x2(z, i) * x1(y, i); // f + L(j, 6) = -x2(z, i) * x1(z, i); // g + L(j, 7) = -x2(z, i) * x1(w, i); // h + L(j, 8) = x2(y, i) * x1(x, i); // i + L(j, 9) = x2(y, i) * x1(y, i); // j + L(j, 10) = x2(y, i) * x1(z, i); // k + L(j, 11) = x2(y, i) * x1(w, i); // l ++j; - L(j, 0) = -x2(z, i) * x1(x, i); // a - L(j, 1) = -x2(z, i) * x1(y, i); // b - L(j, 2) = -x2(z, i) * x1(z, i); // c - L(j, 3) = -x2(z, i) * x1(w, i); // d - L(j, 8) = x2(x, i) * x1(x, i); // i - L(j, 9) = x2(x, i) * x1(y, i); // j - L(j, 10) = x2(x, i) * x1(z, i); // k - L(j, 11) = x2(x, i) * x1(w, i); // l + L(j, 0) = -x2(z, i) * x1(x, i); // a + L(j, 1) = -x2(z, i) * x1(y, i); // b + L(j, 2) = -x2(z, i) * x1(z, i); // c + L(j, 3) = -x2(z, i) * x1(w, i); // d + L(j, 8) = x2(x, i) * x1(x, i); // i + L(j, 9) = x2(x, i) * x1(y, i); // j + L(j, 10) = x2(x, i) * x1(z, i); // k + L(j, 11) = x2(x, i) * x1(w, i); // l ++j; - L(j, 4) = -x2(w, i) * x1(x, i); // e - L(j, 5) = -x2(w, i) * x1(y, i); // f - L(j, 6) = -x2(w, i) * x1(z, i); // g - L(j, 7) = -x2(w, i) * x1(w, i); // h - L(j, 12) = x2(y, i) * x1(x, i); // m - L(j, 13) = x2(y, i) * x1(y, i); // n - L(j, 14) = x2(y, i) * x1(z, i); // o - b(j, 0) = -x2(y, i) * x1(w, i); + L(j, 4) = -x2(w, i) * x1(x, i); // e + L(j, 5) = -x2(w, i) * x1(y, i); // f + L(j, 6) = -x2(w, i) * x1(z, i); // g + L(j, 7) = -x2(w, i) * x1(w, i); // h + L(j, 12) = x2(y, i) * x1(x, i); // m + L(j, 13) = x2(y, i) * x1(y, i); // n + L(j, 14) = x2(y, i) * x1(z, i); // o + b(j, 0) = -x2(y, i) * x1(w, i); ++j; L(j, 0) = -x2(y, i) * x1(x, i); // a L(j, 1) = -x2(y, i) * x1(y, i); // b L(j, 2) = -x2(y, i) * x1(z, i); // c L(j, 3) = -x2(y, i) * x1(w, i); // d - L(j, 4) = x2(x, i) * x1(x, i); // e - L(j, 5) = x2(x, i) * x1(y, i); // f - L(j, 6) = x2(x, i) * x1(z, i); // g - L(j, 7) = x2(x, i) * x1(w, i); // h + L(j, 4) = x2(x, i) * x1(x, i); // e + L(j, 5) = x2(x, i) * x1(y, i); // f + L(j, 6) = x2(x, i) * x1(z, i); // g + L(j, 7) = x2(x, i) * x1(w, i); // h ++j; - L(j, 8) = -x2(w, i) * x1(x, i); // i - L(j, 9) = -x2(w, i) * x1(y, i); // j + L(j, 8) = -x2(w, i) * x1(x, i); // i + L(j, 9) = -x2(w, i) * x1(y, i); // j L(j, 10) = -x2(w, i) * x1(z, i); // k L(j, 11) = -x2(w, i) * x1(w, i); // l - L(j, 12) = x2(z, i) * x1(x, i); // m - L(j, 13) = x2(z, i) * x1(y, i); // n - L(j, 14) = x2(z, i) * x1(z, i); // o - b(j, 0) = -x2(z, i) * x1(w, i); + L(j, 12) = x2(z, i) * x1(x, i); // m + L(j, 13) = x2(z, i) * x1(y, i); // n + L(j, 14) = x2(z, i) * x1(z, i); // o + b(j, 0) = -x2(z, i) * x1(w, i); } // Solve Lx=B Vec h = L.fullPivLu().solve(b); - if ((L * h).isApprox(b, expected_precision)) { + if ((L * h).isApprox(b, expected_precision)) { Homography3DNormalizedParameterization<double>::To(h, H); return true; } else { @@ -448,9 +445,9 @@ bool Homography3DFromCorrespondencesLinear(const Mat &x1, } } -double SymmetricGeometricDistance(const Mat3 &H, - const Vec2 &x1, - const Vec2 &x2) { +double SymmetricGeometricDistance(const Mat3& H, + const Vec2& x1, + const Vec2& x2) { Vec3 x(x1(0), x1(1), 1.0); Vec3 y(x2(0), x2(1), 1.0); diff --git a/intern/libmv/libmv/multiview/homography.h b/intern/libmv/libmv/multiview/homography.h index a76aa9405a5..0742c6f7c70 100644 --- a/intern/libmv/libmv/multiview/homography.h +++ b/intern/libmv/libmv/multiview/homography.h @@ -49,11 +49,11 @@ namespace libmv { * \return True if the transformation estimation has succeeded. * \note There must be at least 4 non-colinear points. */ -bool Homography2DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat3 *H, - double expected_precision = - EigenDouble::dummy_precision()); +bool Homography2DFromCorrespondencesLinear( + const Mat& x1, + const Mat& x2, + Mat3* H, + double expected_precision = EigenDouble::dummy_precision()); /** * This structure contains options that controls how the homography @@ -101,10 +101,10 @@ struct EstimateHomographyOptions { * refinement. */ bool EstimateHomography2DFromCorrespondences( - const Mat &x1, - const Mat &x2, - const EstimateHomographyOptions &options, - Mat3 *H); + const Mat& x1, + const Mat& x2, + const EstimateHomographyOptions& options, + Mat3* H); /** * 3D Homography transformation estimation. @@ -129,20 +129,20 @@ bool EstimateHomography2DFromCorrespondences( * \note Need at least 5 non coplanar points * \note Points coordinates must be in homogeneous coordinates */ -bool Homography3DFromCorrespondencesLinear(const Mat &x1, - const Mat &x2, - Mat4 *H, - double expected_precision = - EigenDouble::dummy_precision()); +bool Homography3DFromCorrespondencesLinear( + const Mat& x1, + const Mat& x2, + Mat4* H, + double expected_precision = EigenDouble::dummy_precision()); /** * Calculate symmetric geometric cost: * * D(H * x1, x2)^2 + D(H^-1 * x2, x1) */ -double SymmetricGeometricDistance(const Mat3 &H, - const Vec2 &x1, - const Vec2 &x2); +double SymmetricGeometricDistance(const Mat3& H, + const Vec2& x1, + const Vec2& x2); } // namespace libmv diff --git a/intern/libmv/libmv/multiview/homography_error.h b/intern/libmv/libmv/multiview/homography_error.h index f8b9d45e73c..786ca245ea6 100644 --- a/intern/libmv/libmv/multiview/homography_error.h +++ b/intern/libmv/libmv/multiview/homography_error.h @@ -27,18 +27,18 @@ namespace libmv { namespace homography { namespace homography2D { - /** - * Structure for estimating the asymmetric error between a vector x2 and the - * transformed x1 such that - * Error = ||x2 - Psi(H * x1)||^2 - * where Psi is the function that transforms homogeneous to euclidean coords. - * \note It should be distributed as Chi-squared with k = 2. - */ +/** + * Structure for estimating the asymmetric error between a vector x2 and the + * transformed x1 such that + * Error = ||x2 - Psi(H * x1)||^2 + * where Psi is the function that transforms homogeneous to euclidean coords. + * \note It should be distributed as Chi-squared with k = 2. + */ struct AsymmetricError { /** - * Computes the asymmetric residuals between a set of 2D points x2 and the + * Computes the asymmetric residuals between a set of 2D points x2 and the * transformed 2D point set x1 such that - * Residuals_i = x2_i - Psi(H * x1_i) + * Residuals_i = x2_i - Psi(H * x1_i) * where Psi is the function that transforms homogeneous to euclidean coords. * * \param[in] H The 3x3 homography matrix. @@ -47,8 +47,7 @@ struct AsymmetricError { * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). * \param[out] dx A 2xN matrix of column vectors of residuals errors */ - static void Residuals(const Mat &H, const Mat &x1, - const Mat &x2, Mat2X *dx) { + static void Residuals(const Mat& H, const Mat& x1, const Mat& x2, Mat2X* dx) { dx->resize(2, x1.cols()); Mat3X x2h_est; if (x1.rows() == 2) @@ -63,19 +62,18 @@ struct AsymmetricError { *dx = HomogeneousToEuclidean(static_cast<Mat3X>(x2)) - *dx; } /** - * Computes the asymmetric residuals between a 2D point x2 and the transformed + * Computes the asymmetric residuals between a 2D point x2 and the transformed * 2D point x1 such that - * Residuals = x2 - Psi(H * x1) + * Residuals = x2 - Psi(H * x1) * where Psi is the function that transforms homogeneous to euclidean coords. * * \param[in] H The 3x3 homography matrix. * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) * \param[out] dx A vector of size 2 of the residual error */ - static void Residuals(const Mat &H, const Vec &x1, - const Vec &x2, Vec2 *dx) { + static void Residuals(const Mat& H, const Vec& x1, const Vec& x2, Vec2* dx) { Vec3 x2h_est; if (x1.rows() == 2) x2h_est = H * EuclideanToHomogeneous(static_cast<Vec2>(x1)); @@ -85,10 +83,10 @@ struct AsymmetricError { *dx = x2 - x2h_est.head<2>() / x2h_est[2]; else *dx = HomogeneousToEuclidean(static_cast<Vec3>(x2)) - - x2h_est.head<2>() / x2h_est[2]; + x2h_est.head<2>() / x2h_est[2]; } /** - * Computes the squared norm of the residuals between a set of 2D points x2 + * Computes the squared norm of the residuals between a set of 2D points x2 * and the transformed 2D point set x1 such that * Error = || x2 - Psi(H * x1) ||^2 * where Psi is the function that transforms homogeneous to euclidean coords. @@ -99,70 +97,70 @@ struct AsymmetricError { * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). * \return The squared norm of the asymmetric residuals errors */ - static double Error(const Mat &H, const Mat &x1, const Mat &x2) { + static double Error(const Mat& H, const Mat& x1, const Mat& x2) { Mat2X dx; Residuals(H, x1, x2, &dx); return dx.squaredNorm(); } /** - * Computes the squared norm of the residuals between a 2D point x2 and the - * transformed 2D point x1 such that rms = || x2 - Psi(H * x1) ||^2 + * Computes the squared norm of the residuals between a 2D point x2 and the + * transformed 2D point x1 such that rms = || x2 - Psi(H * x1) ||^2 * where Psi is the function that transforms homogeneous to euclidean coords. * * \param[in] H The 3x3 homography matrix. * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) * \return The squared norm of the asymmetric residual error */ - static double Error(const Mat &H, const Vec &x1, const Vec &x2) { + static double Error(const Mat& H, const Vec& x1, const Vec& x2) { Vec2 dx; Residuals(H, x1, x2, &dx); return dx.squaredNorm(); } }; - /** - * Structure for estimating the symmetric error - * between a vector x2 and the transformed x1 such that - * Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2 - * where Psi is the function that transforms homogeneous to euclidean coords. - * \note It should be distributed as Chi-squared with k = 4. - */ +/** + * Structure for estimating the symmetric error + * between a vector x2 and the transformed x1 such that + * Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2 + * where Psi is the function that transforms homogeneous to euclidean coords. + * \note It should be distributed as Chi-squared with k = 4. + */ struct SymmetricError { /** - * Computes the squared norm of the residuals between x2 and the - * transformed x1 such that + * Computes the squared norm of the residuals between x2 and the + * transformed x1 such that * Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2 * where Psi is the function that transforms homogeneous to euclidean coords. * * \param[in] H The 3x3 homography matrix. * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) * \return The squared norm of the symmetric residuals errors */ - static double Error(const Mat &H, const Vec &x1, const Vec &x2) { + static double Error(const Mat& H, const Vec& x1, const Vec& x2) { // TODO(keir): This is awesomely inefficient because it does a 3x3 // inversion for each evaluation. Mat3 Hinv = H.inverse(); - return AsymmetricError::Error(H, x1, x2) + + return AsymmetricError::Error(H, x1, x2) + AsymmetricError::Error(Hinv, x2, x1); } // TODO(julien) Add residuals function \see AsymmetricError }; - /** - * Structure for estimating the algebraic error (cross product) - * between a vector x2 and the transformed x1 such that - * Error = ||[x2] * H * x1||^^2 - * where [x2] is the skew matrix of x2. - */ +/** + * Structure for estimating the algebraic error (cross product) + * between a vector x2 and the transformed x1 such that + * Error = ||[x2] * H * x1||^^2 + * where [x2] is the skew matrix of x2. + */ struct AlgebraicError { // TODO(julien) Make an AlgebraicError2Rows and AlgebraicError3Rows /** - * Computes the algebraic residuals (cross product) between a set of 2D - * points x2 and the transformed 2D point set x1 such that + * Computes the algebraic residuals (cross product) between a set of 2D + * points x2 and the transformed 2D point set x1 such that * [x2] * H * x1 where [x2] is the skew matrix of x2. * * \param[in] H The 3x3 homography matrix. @@ -171,8 +169,7 @@ struct AlgebraicError { * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). * \param[out] dx A 3xN matrix of column vectors of residuals errors */ - static void Residuals(const Mat &H, const Mat &x1, - const Mat &x2, Mat3X *dx) { + static void Residuals(const Mat& H, const Mat& x1, const Mat& x2, Mat3X* dx) { dx->resize(3, x1.cols()); Vec3 col; for (int i = 0; i < x1.cols(); ++i) { @@ -181,18 +178,17 @@ struct AlgebraicError { } } /** - * Computes the algebraic residuals (cross product) between a 2D point x2 - * and the transformed 2D point x1 such that + * Computes the algebraic residuals (cross product) between a 2D point x2 + * and the transformed 2D point x1 such that * [x2] * H * x1 where [x2] is the skew matrix of x2. * * \param[in] H The 3x3 homography matrix. * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) * \param[out] dx A vector of size 3 of the residual error */ - static void Residuals(const Mat &H, const Vec &x1, - const Vec &x2, Vec3 *dx) { + static void Residuals(const Mat& H, const Vec& x1, const Vec& x2, Vec3* dx) { Vec3 x2h_est; if (x1.rows() == 2) x2h_est = H * EuclideanToHomogeneous(static_cast<Vec2>(x1)); @@ -206,8 +202,8 @@ struct AlgebraicError { // identical 3x3 skew matrix for each evaluation. } /** - * Computes the squared norm of the algebraic residuals between a set of 2D - * points x2 and the transformed 2D point set x1 such that + * Computes the squared norm of the algebraic residuals between a set of 2D + * points x2 and the transformed 2D point set x1 such that * [x2] * H * x1 where [x2] is the skew matrix of x2. * * \param[in] H The 3x3 homography matrix. @@ -216,23 +212,23 @@ struct AlgebraicError { * \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors). * \return The squared norm of the asymmetric residuals errors */ - static double Error(const Mat &H, const Mat &x1, const Mat &x2) { + static double Error(const Mat& H, const Mat& x1, const Mat& x2) { Mat3X dx; Residuals(H, x1, x2, &dx); return dx.squaredNorm(); } /** - * Computes the squared norm of the algebraic residuals between a 2D point x2 - * and the transformed 2D point x1 such that + * Computes the squared norm of the algebraic residuals between a 2D point x2 + * and the transformed 2D point x1 such that * [x2] * H * x1 where [x2] is the skew matrix of x2. * * \param[in] H The 3x3 homography matrix. * The estimated homography should approximatelly hold the condition y = H x. - * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) - * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) + * \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous)) * \return The squared norm of the asymmetric residual error */ - static double Error(const Mat &H, const Vec &x1, const Vec &x2) { + static double Error(const Mat& H, const Vec& x1, const Vec& x2) { Vec3 dx; Residuals(H, x1, x2, &dx); return dx.squaredNorm(); diff --git a/intern/libmv/libmv/multiview/homography_parameterization.h b/intern/libmv/libmv/multiview/homography_parameterization.h index ca8fbd8066e..ae2d74da9ff 100644 --- a/intern/libmv/libmv/multiview/homography_parameterization.h +++ b/intern/libmv/libmv/multiview/homography_parameterization.h @@ -25,64 +25,72 @@ namespace libmv { -/** A parameterization of the 2D homography matrix that uses 8 parameters so +/** A parameterization of the 2D homography matrix that uses 8 parameters so * that the matrix is normalized (H(2,2) == 1). * The homography matrix H is built from a list of 8 parameters (a, b,...g, h) * as follows - * |a b c| + * |a b c| * H = |d e f| - * |g h 1| + * |g h 1| */ -template<typename T = double> +template <typename T = double> class Homography2DNormalizedParameterization { public: typedef Eigen::Matrix<T, 8, 1> Parameters; // a, b, ... g, h typedef Eigen::Matrix<T, 3, 3> Parameterized; // H /// Convert from the 8 parameters to a H matrix. - static void To(const Parameters &p, Parameterized *h) { + static void To(const Parameters& p, Parameterized* h) { + // clang-format off *h << p(0), p(1), p(2), p(3), p(4), p(5), p(6), p(7), 1.0; + // clang-format on } /// Convert from a H matrix to the 8 parameters. - static void From(const Parameterized &h, Parameters *p) { + static void From(const Parameterized& h, Parameters* p) { + // clang-format off *p << h(0, 0), h(0, 1), h(0, 2), h(1, 0), h(1, 1), h(1, 2), h(2, 0), h(2, 1); + // clang-format on } }; -/** A parameterization of the 2D homography matrix that uses 15 parameters so +/** A parameterization of the 2D homography matrix that uses 15 parameters so * that the matrix is normalized (H(3,3) == 1). * The homography matrix H is built from a list of 15 parameters (a, b,...n, o) * as follows - * |a b c d| + * |a b c d| * H = |e f g h| * |i j k l| - * |m n o 1| + * |m n o 1| */ -template<typename T = double> +template <typename T = double> class Homography3DNormalizedParameterization { public: - typedef Eigen::Matrix<T, 15, 1> Parameters; // a, b, ... n, o - typedef Eigen::Matrix<T, 4, 4> Parameterized; // H + typedef Eigen::Matrix<T, 15, 1> Parameters; // a, b, ... n, o + typedef Eigen::Matrix<T, 4, 4> Parameterized; // H /// Convert from the 15 parameters to a H matrix. - static void To(const Parameters &p, Parameterized *h) { + static void To(const Parameters& p, Parameterized* h) { + // clang-format off *h << p(0), p(1), p(2), p(3), p(4), p(5), p(6), p(7), p(8), p(9), p(10), p(11), p(12), p(13), p(14), 1.0; + // clang-format on } /// Convert from a H matrix to the 15 parameters. - static void From(const Parameterized &h, Parameters *p) { + static void From(const Parameterized& h, Parameters* p) { + // clang-format off *p << h(0, 0), h(0, 1), h(0, 2), h(0, 3), h(1, 0), h(1, 1), h(1, 2), h(1, 3), h(2, 0), h(2, 1), h(2, 2), h(2, 3), h(3, 0), h(3, 1), h(3, 2); + // clang-format on } }; diff --git a/intern/libmv/libmv/multiview/homography_test.cc b/intern/libmv/libmv/multiview/homography_test.cc index 8d7266e3d11..87d1c85028d 100644 --- a/intern/libmv/libmv/multiview/homography_test.cc +++ b/intern/libmv/libmv/multiview/homography_test.cc @@ -18,10 +18,10 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "testing/testing.h" +#include "libmv/multiview/homography.h" #include "libmv/logging/logging.h" #include "libmv/multiview/projection.h" -#include "libmv/multiview/homography.h" +#include "testing/testing.h" namespace { using namespace libmv; @@ -34,9 +34,7 @@ namespace { // TODO(sergey): Consider using this in all tests since possible homography // matrix is not fixed to a single value and different-looking matrices // might actually crrespond to the same exact transform. -void CheckHomography2DTransform(const Mat3 &H, - const Mat &x1, - const Mat &x2) { +void CheckHomography2DTransform(const Mat3& H, const Mat& x1, const Mat& x2) { for (int i = 0; i < x2.cols(); ++i) { Vec3 x2_expected = x2.col(i); Vec3 x2_observed = H * x1.col(i); @@ -49,15 +47,19 @@ void CheckHomography2DTransform(const Mat3 &H, TEST(Homography2DTest, Rotation45AndTranslationXY) { Mat x1(3, 4); + // clang-format off x1 << 0, 1, 0, 5, 0, 0, 2, 3, 1, 1, 1, 1; + // clang-format on double angle = 45.0; Mat3 m; + // clang-format off m << cos(angle), -sin(angle), -2, sin(angle), cos(angle), 5, 0, 0, 1; + // clang-format on Mat x2 = x1; // Transform point from ground truth matrix @@ -76,13 +78,17 @@ TEST(Homography2DTest, Rotation45AndTranslationXY) { TEST(Homography2DTest, AffineGeneral4) { // TODO(julien) find why it doesn't work with 4 points!!! Mat x1(3, 4); + // clang-format off x1 << 0, 1, 0, 2, 0, 0, 1, 2, 1, 1, 1, 1; + // clang-format on Mat3 m; + // clang-format off m << 3, -1, 4, 6, -2, -3, 0, 0, 1; + // clang-format on Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) { @@ -109,13 +115,17 @@ TEST(Homography2DTest, AffineGeneral4) { TEST(Homography2DTest, AffineGeneral5) { Mat x1(3, 5); + // clang-format off x1 << 0, 1, 0, 2, 5, 0, 0, 1, 2, 2, 1, 1, 1, 1, 1; + // clang-format on Mat3 m; + // clang-format off m << 3, -1, 4, 6, -2, -3, 0, 0, 1; + // clang-format on Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) @@ -142,13 +152,17 @@ TEST(Homography2DTest, AffineGeneral5) { TEST(Homography2DTest, HomographyGeneral) { Mat x1(3, 4); + // clang-format off x1 << 0, 1, 0, 5, 0, 0, 2, 3, 1, 1, 1, 1; + // clang-format on Mat3 m; + // clang-format off m << 3, -1, 4, 6, -2, -3, 1, -3, 1; + // clang-format on Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) @@ -164,10 +178,12 @@ TEST(Homography2DTest, HomographyGeneral) { TEST(Homography3DTest, RotationAndTranslationXYZ) { Mat x1(4, 5); + // clang-format off x1 << 0, 0, 1, 5, 2, 0, 1, 2, 3, 5, 0, 2, 0, 1, 5, 1, 1, 1, 1, 1; + // clang-format on Mat4 M; M.setIdentity(); /* @@ -178,24 +194,30 @@ TEST(Homography3DTest, RotationAndTranslationXYZ) { // Rotation on x + translation double angle = 45.0; Mat4 rot; + // clang-format off rot << 1, 0, 0, 1, 0, cos(angle), -sin(angle), 3, 0, sin(angle), cos(angle), -2, 0, 0, 0, 1; + // clang-format on M *= rot; // Rotation on y angle = 25.0; + // clang-format off rot << cos(angle), 0, sin(angle), 0, 0, 1, 0, 0, -sin(angle), 0, cos(angle), 0, 0, 0, 0, 1; + // clang-format on M *= rot; // Rotation on z angle = 5.0; + // clang-format off rot << cos(angle), -sin(angle), 0, 0, sin(angle), cos(angle), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1; + // clang-format on M *= rot; Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) { @@ -212,15 +234,19 @@ TEST(Homography3DTest, RotationAndTranslationXYZ) { TEST(Homography3DTest, AffineGeneral) { Mat x1(4, 5); + // clang-format off x1 << 0, 0, 1, 5, 2, 0, 1, 2, 3, 5, 0, 2, 0, 1, 5, 1, 1, 1, 1, 1; + // clang-format on Mat4 m; + // clang-format off m << 3, -1, 4, 1, 6, -2, -3, -6, 1, 0, 1, 2, 0, 0, 0, 1; + // clang-format on Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) { @@ -236,15 +262,19 @@ TEST(Homography3DTest, AffineGeneral) { TEST(Homography3DTest, HomographyGeneral) { Mat x1(4, 5); + // clang-format off x1 << 0, 0, 1, 5, 2, 0, 1, 2, 3, 5, 0, 2, 0, 1, 5, 1, 1, 1, 1, 1; + // clang-format on Mat4 m; + // clang-format off m << 3, -1, 4, 1, 6, -2, -3, -6, 1, 0, 1, 2, -3, 1, 0, 1; + // clang-format on Mat x2 = x1; for (int i = 0; i < x2.cols(); ++i) { diff --git a/intern/libmv/libmv/multiview/nviewtriangulation.h b/intern/libmv/libmv/multiview/nviewtriangulation.h index f4614ab1a5c..b2a320953a7 100644 --- a/intern/libmv/libmv/multiview/nviewtriangulation.h +++ b/intern/libmv/libmv/multiview/nviewtriangulation.h @@ -34,22 +34,22 @@ namespace libmv { // x's are 2D coordinates (x,y,1) in each image; Ps are projective cameras. The // output, X, is a homogeneous four vectors. -template<typename T> -void NViewTriangulate(const Matrix<T, 2, Dynamic> &x, - const vector<Matrix<T, 3, 4> > &Ps, - Matrix<T, 4, 1> *X) { +template <typename T> +void NViewTriangulate(const Matrix<T, 2, Dynamic>& x, + const vector<Matrix<T, 3, 4>>& Ps, + Matrix<T, 4, 1>* X) { int nviews = x.cols(); assert(nviews == Ps.size()); - Matrix<T, Dynamic, Dynamic> design(3*nviews, 4 + nviews); + Matrix<T, Dynamic, Dynamic> design(3 * nviews, 4 + nviews); design.setConstant(0.0); for (int i = 0; i < nviews; i++) { - design.template block<3, 4>(3*i, 0) = -Ps[i]; - design(3*i + 0, 4 + i) = x(0, i); - design(3*i + 1, 4 + i) = x(1, i); - design(3*i + 2, 4 + i) = 1.0; + design.template block<3, 4>(3 * i, 0) = -Ps[i]; + design(3 * i + 0, 4 + i) = x(0, i); + design(3 * i + 1, 4 + i) = x(1, i); + design(3 * i + 2, 4 + i) = 1.0; } - Matrix<T, Dynamic, 1> X_and_alphas; + Matrix<T, Dynamic, 1> X_and_alphas; Nullspace(&design, &X_and_alphas); X->resize(4); *X = X_and_alphas.head(4); @@ -60,16 +60,16 @@ void NViewTriangulate(const Matrix<T, 2, Dynamic> &x, // This method uses the algebraic distance approximation. // Note that this method works better when the 2D points are normalized // with an isotopic normalization. -template<typename T> -void NViewTriangulateAlgebraic(const Matrix<T, 2, Dynamic> &x, - const vector<Matrix<T, 3, 4> > &Ps, - Matrix<T, 4, 1> *X) { +template <typename T> +void NViewTriangulateAlgebraic(const Matrix<T, 2, Dynamic>& x, + const vector<Matrix<T, 3, 4>>& Ps, + Matrix<T, 4, 1>* X) { int nviews = x.cols(); assert(nviews == Ps.size()); - Matrix<T, Dynamic, 4> design(2*nviews, 4); + Matrix<T, Dynamic, 4> design(2 * nviews, 4); for (int i = 0; i < nviews; i++) { - design.template block<2, 4>(2*i, 0) = SkewMatMinimal(x.col(i)) * Ps[i]; + design.template block<2, 4>(2 * i, 0) = SkewMatMinimal(x.col(i)) * Ps[i]; } X->resize(4); Nullspace(&design, X); diff --git a/intern/libmv/libmv/multiview/nviewtriangulation_test.cc b/intern/libmv/libmv/multiview/nviewtriangulation_test.cc index 5a4d8499753..dba5fd07d5c 100644 --- a/intern/libmv/libmv/multiview/nviewtriangulation_test.cc +++ b/intern/libmv/libmv/multiview/nviewtriangulation_test.cc @@ -54,7 +54,7 @@ TEST(NViewTriangulate, FiveViews) { // Check reprojection error. Should be nearly zero. for (int j = 0; j < nviews; ++j) { - Vec3 x_reprojected = Ps[j]*X; + Vec3 x_reprojected = Ps[j] * X; x_reprojected /= x_reprojected(2); double error = (x_reprojected.head(2) - xs.col(j)).norm(); EXPECT_NEAR(error, 0.0, 1e-9); @@ -84,7 +84,7 @@ TEST(NViewTriangulateAlgebraic, FiveViews) { // Check reprojection error. Should be nearly zero. for (int j = 0; j < nviews; ++j) { - Vec3 x_reprojected = Ps[j]*X; + Vec3 x_reprojected = Ps[j] * X; x_reprojected /= x_reprojected(2); double error = (x_reprojected.head<2>() - xs.col(j)).norm(); EXPECT_NEAR(error, 0.0, 1e-9); diff --git a/intern/libmv/libmv/multiview/panography.cc b/intern/libmv/libmv/multiview/panography.cc index b62802948c4..42b1c19d65e 100644 --- a/intern/libmv/libmv/multiview/panography.cc +++ b/intern/libmv/libmv/multiview/panography.cc @@ -24,8 +24,9 @@ namespace libmv { static bool Build_Minimal2Point_PolynomialFactor( - const Mat & x1, const Mat & x2, - double * P) { // P must be a double[4] + const Mat& x1, + const Mat& x2, + double* P) { // P must be a double[4] assert(2 == x1.rows()); assert(2 == x1.cols()); assert(x1.rows() == x2.rows()); @@ -40,11 +41,11 @@ static bool Build_Minimal2Point_PolynomialFactor( Vec yx2 = (x2.col(1)).transpose(); double b12 = xx2.dot(yx2); - double a1 = xx1.squaredNorm(); - double a2 = yx1.squaredNorm(); + double a1 = xx1.squaredNorm(); + double a2 = yx1.squaredNorm(); - double b1 = xx2.squaredNorm(); - double b2 = yx2.squaredNorm(); + double b1 = xx2.squaredNorm(); + double b2 = yx2.squaredNorm(); // Build the 3rd degre polynomial in F^2. // @@ -52,10 +53,12 @@ static bool Build_Minimal2Point_PolynomialFactor( // // Coefficients in ascending powers of alpha, i.e. P[N]*x^N. // Run panography_coeffs.py to get the below coefficients. - P[0] = b1*b2*a12*a12-a1*a2*b12*b12; - P[1] = -2*a1*a2*b12+2*a12*b1*b2+b1*a12*a12+b2*a12*a12-a1*b12*b12-a2*b12*b12; - P[2] = b1*b2-a1*a2-2*a1*b12-2*a2*b12+2*a12*b1+2*a12*b2+a12*a12-b12*b12; - P[3] = b1+b2-2*b12-a1-a2+2*a12; + P[0] = b1 * b2 * a12 * a12 - a1 * a2 * b12 * b12; + P[1] = -2 * a1 * a2 * b12 + 2 * a12 * b1 * b2 + b1 * a12 * a12 + + b2 * a12 * a12 - a1 * b12 * b12 - a2 * b12 * b12; + P[2] = b1 * b2 - a1 * a2 - 2 * a1 * b12 - 2 * a2 * b12 + 2 * a12 * b1 + + 2 * a12 * b2 + a12 * a12 - b12 * b12; + P[3] = b1 + b2 - 2 * b12 - a1 - a2 + 2 * a12; // If P[3] equal to 0 we get ill conditionned data return (P[3] != 0.0); @@ -67,8 +70,9 @@ static bool Build_Minimal2Point_PolynomialFactor( // // [1] M. Brown and R. Hartley and D. Nister. Minimal Solutions for Panoramic // Stitching. CVPR07. -void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, - vector<double> *fs) { +void F_FromCorrespondance_2points(const Mat& x1, + const Mat& x2, + vector<double>* fs) { // Build Polynomial factor to get squared focal value. double P[4]; Build_Minimal2Point_PolynomialFactor(x1, x2, &P[0]); @@ -79,8 +83,8 @@ void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, // double roots[3]; int num_roots = SolveCubicPolynomial(P, roots); - for (int i = 0; i < num_roots; ++i) { - if (roots[i] > 0.0) { + for (int i = 0; i < num_roots; ++i) { + if (roots[i] > 0.0) { fs->push_back(sqrt(roots[i])); } } @@ -92,17 +96,18 @@ void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, // K. Arun,T. Huand and D. Blostein. Least-squares fitting of 2 3-D point // sets. IEEE Transactions on Pattern Analysis and Machine Intelligence, // 9:698-700, 1987. -void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2, +void GetR_FixedCameraCenter(const Mat& x1, + const Mat& x2, const double focal, - Mat3 *R) { + Mat3* R) { assert(3 == x1.rows()); assert(2 <= x1.cols()); assert(x1.rows() == x2.rows()); assert(x1.cols() == x2.cols()); // Build simplified K matrix - Mat3 K(Mat3::Identity() * 1.0/focal); - K(2, 2)= 1.0; + Mat3 K(Mat3::Identity() * 1.0 / focal); + K(2, 2) = 1.0; // Build the correlation matrix; equation (22) in [1]. Mat3 C = Mat3::Zero(); @@ -115,9 +120,9 @@ void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2, // Solve for rotation. Equations (24) and (25) in [1]. Eigen::JacobiSVD<Mat> svd(C, Eigen::ComputeThinU | Eigen::ComputeThinV); Mat3 scale = Mat3::Identity(); - scale(2, 2) = ((svd.matrixU() * svd.matrixV().transpose()).determinant() > 0.0) - ? 1.0 - : -1.0; + scale(2, 2) = + ((svd.matrixU() * svd.matrixV().transpose()).determinant() > 0.0) ? 1.0 + : -1.0; (*R) = svd.matrixU() * scale * svd.matrixV().transpose(); } diff --git a/intern/libmv/libmv/multiview/panography.h b/intern/libmv/libmv/multiview/panography.h index 6e87bd71304..5860a34d1fd 100644 --- a/intern/libmv/libmv/multiview/panography.h +++ b/intern/libmv/libmv/multiview/panography.h @@ -22,9 +22,9 @@ #ifndef LIBMV_MULTIVIEW_PANOGRAPHY_H #define LIBMV_MULTIVIEW_PANOGRAPHY_H +#include "libmv/base/vector.h" #include "libmv/numeric/numeric.h" #include "libmv/numeric/poly.h" -#include "libmv/base/vector.h" namespace libmv { @@ -53,8 +53,9 @@ namespace libmv { // K = [0 f 0] // [0 0 1] // -void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, - vector<double> *fs); +void F_FromCorrespondance_2points(const Mat& x1, + const Mat& x2, + vector<double>* fs); // Compute the 3x3 rotation matrix that fits two 3D point clouds in the least // square sense. The method is from: @@ -90,9 +91,10 @@ void F_FromCorrespondance_2points(const Mat &x1, const Mat &x2, // // R = arg min || X2 - R * x1 || // -void GetR_FixedCameraCenter(const Mat &x1, const Mat &x2, +void GetR_FixedCameraCenter(const Mat& x1, + const Mat& x2, const double focal, - Mat3 *R); + Mat3* R); } // namespace libmv diff --git a/intern/libmv/libmv/multiview/panography_kernel.cc b/intern/libmv/libmv/multiview/panography_kernel.cc index 8fdc9e79aed..e8ba648e352 100644 --- a/intern/libmv/libmv/multiview/panography_kernel.cc +++ b/intern/libmv/libmv/multiview/panography_kernel.cc @@ -25,7 +25,7 @@ namespace libmv { namespace panography { namespace kernel { -void TwoPointSolver::Solve(const Mat &x1, const Mat &x2, vector<Mat3> *Hs) { +void TwoPointSolver::Solve(const Mat& x1, const Mat& x2, vector<Mat3>* Hs) { // Solve for the focal lengths. vector<double> fs; F_FromCorrespondance_2points(x1, x2, &fs); @@ -34,7 +34,7 @@ void TwoPointSolver::Solve(const Mat &x1, const Mat &x2, vector<Mat3> *Hs) { Mat x1h, x2h; EuclideanToHomogeneous(x1, &x1h); EuclideanToHomogeneous(x2, &x2h); - for (int i = 0; i < fs.size(); ++i) { + for (int i = 0; i < fs.size(); ++i) { Mat3 K1 = Mat3::Identity() * fs[i]; K1(2, 2) = 1.0; diff --git a/intern/libmv/libmv/multiview/panography_kernel.h b/intern/libmv/libmv/multiview/panography_kernel.h index a6adbd54b20..d50d3ea0789 100644 --- a/intern/libmv/libmv/multiview/panography_kernel.h +++ b/intern/libmv/libmv/multiview/panography_kernel.h @@ -23,9 +23,9 @@ #include "libmv/base/vector.h" #include "libmv/multiview/conditioning.h" +#include "libmv/multiview/homography_error.h" #include "libmv/multiview/projection.h" #include "libmv/multiview/two_view_kernel.h" -#include "libmv/multiview/homography_error.h" #include "libmv/numeric/numeric.h" namespace libmv { @@ -34,18 +34,18 @@ namespace kernel { struct TwoPointSolver { enum { MINIMUM_SAMPLES = 2 }; - static void Solve(const Mat &x1, const Mat &x2, vector<Mat3> *Hs); + static void Solve(const Mat& x1, const Mat& x2, vector<Mat3>* Hs); }; -typedef two_view::kernel::Kernel< - TwoPointSolver, homography::homography2D::AsymmetricError, Mat3> - UnnormalizedKernel; +typedef two_view::kernel:: + Kernel<TwoPointSolver, homography::homography2D::AsymmetricError, Mat3> + UnnormalizedKernel; typedef two_view::kernel::Kernel< - two_view::kernel::NormalizedSolver<TwoPointSolver, UnnormalizerI>, - homography::homography2D::AsymmetricError, - Mat3> - Kernel; + two_view::kernel::NormalizedSolver<TwoPointSolver, UnnormalizerI>, + homography::homography2D::AsymmetricError, + Mat3> + Kernel; } // namespace kernel } // namespace panography diff --git a/intern/libmv/libmv/multiview/panography_test.cc b/intern/libmv/libmv/multiview/panography_test.cc index 96d52acfc3c..a7cbd371d40 100644 --- a/intern/libmv/libmv/multiview/panography_test.cc +++ b/intern/libmv/libmv/multiview/panography_test.cc @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "libmv/logging/logging.h" #include "libmv/multiview/panography.h" +#include "libmv/logging/logging.h" #include "libmv/multiview/panography_kernel.h" #include "libmv/multiview/projection.h" #include "libmv/numeric/numeric.h" @@ -30,18 +30,16 @@ namespace { TEST(Panography, PrintSomeSharedFocalEstimationValues) { Mat x1(2, 2), x2(2, 2); - x1<< 158, 78, - 124, 113; - x2<< 300, 214, - 125, 114; + x1 << 158, 78, 124, 113; + x2 << 300, 214, 125, 114; // Normalize data (set principal point 0,0 and image border to 1.0). x1.block<1, 2>(0, 0) /= 320; x1.block<1, 2>(1, 0) /= 240; x2.block<1, 2>(0, 0) /= 320; x2.block<1, 2>(1, 0) /= 240; - x1+=Mat2::Constant(0.5); - x2+=Mat2::Constant(0.5); + x1 += Mat2::Constant(0.5); + x2 += Mat2::Constant(0.5); vector<double> fs; F_FromCorrespondance_2points(x1, x2, &fs); @@ -53,9 +51,11 @@ TEST(Panography, PrintSomeSharedFocalEstimationValues) { TEST(Panography, GetR_FixedCameraCenterWithIdentity) { Mat x1(3, 3); + // clang-format off x1 << 0.5, 0.6, 0.7, 0.5, 0.5, 0.4, 10.0, 10.0, 10.0; + // clang-format on Mat3 R; GetR_FixedCameraCenter(x1, x1, 1.0, &R); @@ -68,16 +68,20 @@ TEST(Panography, Homography_GetR_Test_PitchY30) { int n = 3; Mat x1(3, n); + // clang-format off x1 << 0.5, 0.6, 0.7, 0.5, 0.5, 0.4, 10, 10, 10; + // clang-format on Mat x2 = x1; const double alpha = 30.0 * M_PI / 180.0; Mat3 rotY; + // clang-format off rotY << cos(alpha), 0, -sin(alpha), 0, 1, 0, sin(alpha), 0, cos(alpha); + // clang-format on for (int i = 0; i < n; ++i) { x2.block<3, 1>(0, i) = rotY * x1.col(i); @@ -101,17 +105,23 @@ TEST(Panography, Homography_GetR_Test_PitchY30) { TEST(MinimalPanoramic, Real_Case_Kernel) { const int n = 2; Mat x1(2, n); // From image 0.jpg + // clang-format off x1<< 158, 78, 124, 113; + // clang-format on Mat x2(2, n); // From image 3.jpg + // clang-format off x2<< 300, 214, 125, 114; + // clang-format on Mat3 Ground_TruthHomography; + // clang-format off Ground_TruthHomography<< 1, 0.02, 129.83, -0.02, 1.012, 0.07823, 0, 0, 1; + // clang-format on vector<Mat3> Hs; @@ -130,7 +140,7 @@ TEST(MinimalPanoramic, Real_Case_Kernel) { // Assert that residuals are small enough for (int i = 0; i < n; ++i) { Vec x1p = H * x1h.col(i); - Vec residuals = x1p/x1p(2) - x2h.col(i); + Vec residuals = x1p / x1p(2) - x2h.col(i); EXPECT_MATRIX_NEAR_ZERO(residuals, 1e-5); } } diff --git a/intern/libmv/libmv/multiview/projection.cc b/intern/libmv/libmv/multiview/projection.cc index f8bece3de68..001da89e127 100644 --- a/intern/libmv/libmv/multiview/projection.cc +++ b/intern/libmv/libmv/multiview/projection.cc @@ -23,13 +23,13 @@ namespace libmv { -void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P) { +void P_From_KRt(const Mat3& K, const Mat3& R, const Vec3& t, Mat34* P) { P->block<3, 3>(0, 0) = R; P->col(3) = t; (*P) = K * (*P); } -void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { +void KRt_From_P(const Mat34& P, Mat3* Kp, Mat3* Rp, Vec3* tp) { // Decompose using the RQ decomposition HZ A4.1.1 pag.579. Mat3 K = P.block(0, 0, 3, 3); @@ -44,9 +44,11 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { c /= l; s /= l; Mat3 Qx; + // clang-format off Qx << 1, 0, 0, 0, c, -s, 0, s, c; + // clang-format on K = K * Qx; Q = Qx.transpose() * Q; } @@ -58,9 +60,11 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { c /= l; s /= l; Mat3 Qy; + // clang-format off Qy << c, 0, s, 0, 1, 0, -s, 0, c; + // clang-format on K = K * Qy; Q = Qy.transpose() * Q; } @@ -72,9 +76,11 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { c /= l; s /= l; Mat3 Qz; + // clang-format off Qz << c, -s, 0, s, c, 0, 0, 0, 1; + // clang-format on K = K * Qz; Q = Qz.transpose() * Q; } @@ -92,17 +98,21 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { } if (K(1, 1) < 0) { Mat3 S; + // clang-format off S << 1, 0, 0, 0, -1, 0, 0, 0, 1; + // clang-format on K = K * S; R = S * R; } if (K(0, 0) < 0) { Mat3 S; + // clang-format off S << -1, 0, 0, 0, 1, 0, 0, 0, 1; + // clang-format on K = K * S; R = S * R; } @@ -122,26 +132,30 @@ void KRt_From_P(const Mat34 &P, Mat3 *Kp, Mat3 *Rp, Vec3 *tp) { *tp = t; } -void ProjectionShiftPrincipalPoint(const Mat34 &P, - const Vec2 &principal_point, - const Vec2 &principal_point_new, - Mat34 *P_new) { +void ProjectionShiftPrincipalPoint(const Mat34& P, + const Vec2& principal_point, + const Vec2& principal_point_new, + Mat34* P_new) { Mat3 T; + // clang-format off T << 1, 0, principal_point_new(0) - principal_point(0), 0, 1, principal_point_new(1) - principal_point(1), 0, 0, 1; + // clang-format on *P_new = T * P; } -void ProjectionChangeAspectRatio(const Mat34 &P, - const Vec2 &principal_point, +void ProjectionChangeAspectRatio(const Mat34& P, + const Vec2& principal_point, double aspect_ratio, double aspect_ratio_new, - Mat34 *P_new) { + Mat34* P_new) { Mat3 T; + // clang-format off T << 1, 0, 0, 0, aspect_ratio_new / aspect_ratio, 0, 0, 0, 1; + // clang-format on Mat34 P_temp; ProjectionShiftPrincipalPoint(P, principal_point, Vec2(0, 0), &P_temp); @@ -149,7 +163,7 @@ void ProjectionChangeAspectRatio(const Mat34 &P, ProjectionShiftPrincipalPoint(P_temp, Vec2(0, 0), principal_point, P_new); } -void HomogeneousToEuclidean(const Mat &H, Mat *X) { +void HomogeneousToEuclidean(const Mat& H, Mat* X) { int d = H.rows() - 1; int n = H.cols(); X->resize(d, n); @@ -161,29 +175,29 @@ void HomogeneousToEuclidean(const Mat &H, Mat *X) { } } -void HomogeneousToEuclidean(const Mat3X &h, Mat2X *e) { +void HomogeneousToEuclidean(const Mat3X& h, Mat2X* e) { e->resize(2, h.cols()); e->row(0) = h.row(0).array() / h.row(2).array(); e->row(1) = h.row(1).array() / h.row(2).array(); } -void HomogeneousToEuclidean(const Mat4X &h, Mat3X *e) { +void HomogeneousToEuclidean(const Mat4X& h, Mat3X* e) { e->resize(3, h.cols()); e->row(0) = h.row(0).array() / h.row(3).array(); e->row(1) = h.row(1).array() / h.row(3).array(); e->row(2) = h.row(2).array() / h.row(3).array(); } -void HomogeneousToEuclidean(const Vec3 &H, Vec2 *X) { +void HomogeneousToEuclidean(const Vec3& H, Vec2* X) { double w = H(2); *X << H(0) / w, H(1) / w; } -void HomogeneousToEuclidean(const Vec4 &H, Vec3 *X) { +void HomogeneousToEuclidean(const Vec4& H, Vec3* X) { double w = H(3); *X << H(0) / w, H(1) / w, H(2) / w; } -void EuclideanToHomogeneous(const Mat &X, Mat *H) { +void EuclideanToHomogeneous(const Mat& X, Mat* H) { int d = X.rows(); int n = X.cols(); H->resize(d + 1, n); @@ -191,32 +205,32 @@ void EuclideanToHomogeneous(const Mat &X, Mat *H) { H->row(d).setOnes(); } -void EuclideanToHomogeneous(const Vec2 &X, Vec3 *H) { +void EuclideanToHomogeneous(const Vec2& X, Vec3* H) { *H << X(0), X(1), 1; } -void EuclideanToHomogeneous(const Vec3 &X, Vec4 *H) { +void EuclideanToHomogeneous(const Vec3& X, Vec4* H) { *H << X(0), X(1), X(2), 1; } // TODO(julien) Call conditioning.h/ApplyTransformationToPoints ? -void EuclideanToNormalizedCamera(const Mat2X &x, const Mat3 &K, Mat2X *n) { +void EuclideanToNormalizedCamera(const Mat2X& x, const Mat3& K, Mat2X* n) { Mat3X x_image_h; EuclideanToHomogeneous(x, &x_image_h); Mat3X x_camera_h = K.inverse() * x_image_h; HomogeneousToEuclidean(x_camera_h, n); } -void HomogeneousToNormalizedCamera(const Mat3X &x, const Mat3 &K, Mat2X *n) { +void HomogeneousToNormalizedCamera(const Mat3X& x, const Mat3& K, Mat2X* n) { Mat3X x_camera_h = K.inverse() * x; HomogeneousToEuclidean(x_camera_h, n); } -double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X) { - return (R*X)(2) + t(2); +double Depth(const Mat3& R, const Vec3& t, const Vec3& X) { + return (R * X)(2) + t(2); } -double Depth(const Mat3 &R, const Vec3 &t, const Vec4 &X) { +double Depth(const Mat3& R, const Vec3& t, const Vec4& X) { Vec3 Xe = X.head<3>() / X(3); return Depth(R, t, Xe); } diff --git a/intern/libmv/libmv/multiview/projection.h b/intern/libmv/libmv/multiview/projection.h index 8f304f31ec6..ba8fc5d8303 100644 --- a/intern/libmv/libmv/multiview/projection.h +++ b/intern/libmv/libmv/multiview/projection.h @@ -25,108 +25,108 @@ namespace libmv { -void P_From_KRt(const Mat3 &K, const Mat3 &R, const Vec3 &t, Mat34 *P); -void KRt_From_P(const Mat34 &P, Mat3 *K, Mat3 *R, Vec3 *t); +void P_From_KRt(const Mat3& K, const Mat3& R, const Vec3& t, Mat34* P); +void KRt_From_P(const Mat34& P, Mat3* K, Mat3* R, Vec3* t); // Applies a change of basis to the image coordinates of the projection matrix // so that the principal point becomes principal_point_new. -void ProjectionShiftPrincipalPoint(const Mat34 &P, - const Vec2 &principal_point, - const Vec2 &principal_point_new, - Mat34 *P_new); +void ProjectionShiftPrincipalPoint(const Mat34& P, + const Vec2& principal_point, + const Vec2& principal_point_new, + Mat34* P_new); // Applies a change of basis to the image coordinates of the projection matrix // so that the aspect ratio becomes aspect_ratio_new. This is done by // stretching the y axis. The aspect ratio is defined as the quotient between // the focal length of the y and the x axis. -void ProjectionChangeAspectRatio(const Mat34 &P, - const Vec2 &principal_point, +void ProjectionChangeAspectRatio(const Mat34& P, + const Vec2& principal_point, double aspect_ratio, double aspect_ratio_new, - Mat34 *P_new); - -void HomogeneousToEuclidean(const Mat &H, Mat *X); -void HomogeneousToEuclidean(const Mat3X &h, Mat2X *e); -void HomogeneousToEuclidean(const Mat4X &h, Mat3X *e); -void HomogeneousToEuclidean(const Vec3 &H, Vec2 *X); -void HomogeneousToEuclidean(const Vec4 &H, Vec3 *X); -inline Vec2 HomogeneousToEuclidean(const Vec3 &h) { + Mat34* P_new); + +void HomogeneousToEuclidean(const Mat& H, Mat* X); +void HomogeneousToEuclidean(const Mat3X& h, Mat2X* e); +void HomogeneousToEuclidean(const Mat4X& h, Mat3X* e); +void HomogeneousToEuclidean(const Vec3& H, Vec2* X); +void HomogeneousToEuclidean(const Vec4& H, Vec3* X); +inline Vec2 HomogeneousToEuclidean(const Vec3& h) { return h.head<2>() / h(2); } -inline Vec3 HomogeneousToEuclidean(const Vec4 &h) { +inline Vec3 HomogeneousToEuclidean(const Vec4& h) { return h.head<3>() / h(3); } -inline Mat2X HomogeneousToEuclidean(const Mat3X &h) { +inline Mat2X HomogeneousToEuclidean(const Mat3X& h) { Mat2X e(2, h.cols()); e.row(0) = h.row(0).array() / h.row(2).array(); e.row(1) = h.row(1).array() / h.row(2).array(); return e; } -void EuclideanToHomogeneous(const Mat &X, Mat *H); -inline Mat3X EuclideanToHomogeneous(const Mat2X &x) { +void EuclideanToHomogeneous(const Mat& X, Mat* H); +inline Mat3X EuclideanToHomogeneous(const Mat2X& x) { Mat3X h(3, x.cols()); h.block(0, 0, 2, x.cols()) = x; h.row(2).setOnes(); return h; } -inline void EuclideanToHomogeneous(const Mat2X &x, Mat3X *h) { +inline void EuclideanToHomogeneous(const Mat2X& x, Mat3X* h) { h->resize(3, x.cols()); h->block(0, 0, 2, x.cols()) = x; h->row(2).setOnes(); } -inline Mat4X EuclideanToHomogeneous(const Mat3X &x) { +inline Mat4X EuclideanToHomogeneous(const Mat3X& x) { Mat4X h(4, x.cols()); h.block(0, 0, 3, x.cols()) = x; h.row(3).setOnes(); return h; } -inline void EuclideanToHomogeneous(const Mat3X &x, Mat4X *h) { +inline void EuclideanToHomogeneous(const Mat3X& x, Mat4X* h) { h->resize(4, x.cols()); h->block(0, 0, 3, x.cols()) = x; h->row(3).setOnes(); } -void EuclideanToHomogeneous(const Vec2 &X, Vec3 *H); -void EuclideanToHomogeneous(const Vec3 &X, Vec4 *H); -inline Vec3 EuclideanToHomogeneous(const Vec2 &x) { +void EuclideanToHomogeneous(const Vec2& X, Vec3* H); +void EuclideanToHomogeneous(const Vec3& X, Vec4* H); +inline Vec3 EuclideanToHomogeneous(const Vec2& x) { return Vec3(x(0), x(1), 1); } -inline Vec4 EuclideanToHomogeneous(const Vec3 &x) { +inline Vec4 EuclideanToHomogeneous(const Vec3& x) { return Vec4(x(0), x(1), x(2), 1); } // Conversion from image coordinates to normalized camera coordinates -void EuclideanToNormalizedCamera(const Mat2X &x, const Mat3 &K, Mat2X *n); -void HomogeneousToNormalizedCamera(const Mat3X &x, const Mat3 &K, Mat2X *n); +void EuclideanToNormalizedCamera(const Mat2X& x, const Mat3& K, Mat2X* n); +void HomogeneousToNormalizedCamera(const Mat3X& x, const Mat3& K, Mat2X* n); -inline Vec2 Project(const Mat34 &P, const Vec3 &X) { +inline Vec2 Project(const Mat34& P, const Vec3& X) { Vec4 HX; HX << X, 1.0; Vec3 hx = P * HX; return hx.head<2>() / hx(2); } -inline void Project(const Mat34 &P, const Vec4 &X, Vec3 *x) { +inline void Project(const Mat34& P, const Vec4& X, Vec3* x) { *x = P * X; } -inline void Project(const Mat34 &P, const Vec4 &X, Vec2 *x) { +inline void Project(const Mat34& P, const Vec4& X, Vec2* x) { Vec3 hx = P * X; *x = hx.head<2>() / hx(2); } -inline void Project(const Mat34 &P, const Vec3 &X, Vec3 *x) { +inline void Project(const Mat34& P, const Vec3& X, Vec3* x) { Vec4 HX; HX << X, 1.0; Project(P, HX, x); } -inline void Project(const Mat34 &P, const Vec3 &X, Vec2 *x) { +inline void Project(const Mat34& P, const Vec3& X, Vec2* x) { Vec3 hx; Project(P, X, &hx); *x = hx.head<2>() / hx(2); } -inline void Project(const Mat34 &P, const Mat4X &X, Mat2X *x) { +inline void Project(const Mat34& P, const Mat4X& X, Mat2X* x) { x->resize(2, X.cols()); for (int c = 0; c < X.cols(); ++c) { Vec3 hx = P * X.col(c); @@ -134,13 +134,13 @@ inline void Project(const Mat34 &P, const Mat4X &X, Mat2X *x) { } } -inline Mat2X Project(const Mat34 &P, const Mat4X &X) { +inline Mat2X Project(const Mat34& P, const Mat4X& X) { Mat2X x; Project(P, X, &x); return x; } -inline void Project(const Mat34 &P, const Mat3X &X, Mat2X *x) { +inline void Project(const Mat34& P, const Mat3X& X, Mat2X* x) { x->resize(2, X.cols()); for (int c = 0; c < X.cols(); ++c) { Vec4 HX; @@ -150,7 +150,7 @@ inline void Project(const Mat34 &P, const Mat3X &X, Mat2X *x) { } } -inline void Project(const Mat34 &P, const Mat3X &X, const Vecu &ids, Mat2X *x) { +inline void Project(const Mat34& P, const Mat3X& X, const Vecu& ids, Mat2X* x) { x->resize(2, ids.size()); Vec4 HX; Vec3 hx; @@ -161,26 +161,26 @@ inline void Project(const Mat34 &P, const Mat3X &X, const Vecu &ids, Mat2X *x) { } } -inline Mat2X Project(const Mat34 &P, const Mat3X &X) { +inline Mat2X Project(const Mat34& P, const Mat3X& X) { Mat2X x(2, X.cols()); Project(P, X, &x); return x; } -inline Mat2X Project(const Mat34 &P, const Mat3X &X, const Vecu &ids) { +inline Mat2X Project(const Mat34& P, const Mat3X& X, const Vecu& ids) { Mat2X x(2, ids.size()); Project(P, X, ids, &x); return x; } -double Depth(const Mat3 &R, const Vec3 &t, const Vec3 &X); -double Depth(const Mat3 &R, const Vec3 &t, const Vec4 &X); +double Depth(const Mat3& R, const Vec3& t, const Vec3& X); +double Depth(const Mat3& R, const Vec3& t, const Vec4& X); /** -* Returns true if the homogenious 3D point X is in front of -* the camera P. -*/ -inline bool isInFrontOfCamera(const Mat34 &P, const Vec4 &X) { + * Returns true if the homogenious 3D point X is in front of + * the camera P. + */ +inline bool isInFrontOfCamera(const Mat34& P, const Vec4& X) { double condition_1 = P.row(2).dot(X) * X[3]; double condition_2 = X[2] * X[3]; if (condition_1 > 0 && condition_2 > 0) @@ -189,37 +189,37 @@ inline bool isInFrontOfCamera(const Mat34 &P, const Vec4 &X) { return false; } -inline bool isInFrontOfCamera(const Mat34 &P, const Vec3 &X) { +inline bool isInFrontOfCamera(const Mat34& P, const Vec3& X) { Vec4 X_homo; X_homo.segment<3>(0) = X; X_homo(3) = 1; - return isInFrontOfCamera( P, X_homo); + return isInFrontOfCamera(P, X_homo); } /** -* Transforms a 2D point from pixel image coordinates to a 2D point in -* normalized image coordinates. -*/ -inline Vec2 ImageToNormImageCoordinates(Mat3 &Kinverse, Vec2 &x) { - Vec3 x_h = Kinverse*EuclideanToHomogeneous(x); - return HomogeneousToEuclidean( x_h ); + * Transforms a 2D point from pixel image coordinates to a 2D point in + * normalized image coordinates. + */ +inline Vec2 ImageToNormImageCoordinates(Mat3& Kinverse, Vec2& x) { + Vec3 x_h = Kinverse * EuclideanToHomogeneous(x); + return HomogeneousToEuclidean(x_h); } /// Estimates the root mean square error (2D) -inline double RootMeanSquareError(const Mat2X &x_image, - const Mat4X &X_world, - const Mat34 &P) { +inline double RootMeanSquareError(const Mat2X& x_image, + const Mat4X& X_world, + const Mat34& P) { size_t num_points = x_image.cols(); Mat2X dx = Project(P, X_world) - x_image; return dx.norm() / num_points; } /// Estimates the root mean square error (2D) -inline double RootMeanSquareError(const Mat2X &x_image, - const Mat3X &X_world, - const Mat3 &K, - const Mat3 &R, - const Vec3 &t) { +inline double RootMeanSquareError(const Mat2X& x_image, + const Mat3X& X_world, + const Mat3& K, + const Mat3& R, + const Vec3& t) { Mat34 P; P_From_KRt(K, R, t, &P); size_t num_points = x_image.cols(); diff --git a/intern/libmv/libmv/multiview/projection_test.cc b/intern/libmv/libmv/multiview/projection_test.cc index 40e766bfae7..683edefa99c 100644 --- a/intern/libmv/libmv/multiview/projection_test.cc +++ b/intern/libmv/libmv/multiview/projection_test.cc @@ -29,14 +29,18 @@ using namespace libmv; TEST(Projection, P_From_KRt) { Mat3 K, Kp; + // clang-format off K << 10, 1, 30, 0, 20, 40, 0, 0, 1; + // clang-format on Mat3 R, Rp; + // clang-format off R << 1, 0, 0, 0, 1, 0, 0, 0, 1; + // clang-format on Vec3 t, tp; t << 1, 2, 3; @@ -62,16 +66,18 @@ Vec4 GetRandomPoint() { TEST(Projection, isInFrontOfCamera) { Mat34 P; + // clang-format off P << 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0; + // clang-format on Vec4 X_front = GetRandomPoint(); Vec4 X_back = GetRandomPoint(); - X_front(2) = 10; /* Any point in the positive Z direction - * where Z > 1 is in front of the camera. */ - X_back(2) = -10; /* Any point in the negative Z direction - * is behind the camera. */ + X_front(2) = 10; /* Any point in the positive Z direction + * where Z > 1 is in front of the camera. */ + X_back(2) = -10; /* Any point in the negative Z direction + * is behind the camera. */ bool res_front = isInFrontOfCamera(P, X_front); bool res_back = isInFrontOfCamera(P, X_back); @@ -82,12 +88,14 @@ TEST(Projection, isInFrontOfCamera) { TEST(AutoCalibration, ProjectionShiftPrincipalPoint) { Mat34 P1, P2; + // clang-format off P1 << 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0; P2 << 1, 0, 3, 0, 0, 1, 4, 0, 0, 0, 1, 0; + // clang-format on Mat34 P1_computed, P2_computed; ProjectionShiftPrincipalPoint(P1, Vec2(0, 0), Vec2(3, 4), &P2_computed); ProjectionShiftPrincipalPoint(P2, Vec2(3, 4), Vec2(0, 0), &P1_computed); @@ -98,12 +106,14 @@ TEST(AutoCalibration, ProjectionShiftPrincipalPoint) { TEST(AutoCalibration, ProjectionChangeAspectRatio) { Mat34 P1, P2; + // clang-format off P1 << 1, 0, 3, 0, 0, 1, 4, 0, 0, 0, 1, 0; P2 << 1, 0, 3, 0, 0, 2, 4, 0, 0, 0, 1, 0; + // clang-format on Mat34 P1_computed, P2_computed; ProjectionChangeAspectRatio(P1, Vec2(3, 4), 1, 2, &P2_computed); ProjectionChangeAspectRatio(P2, Vec2(3, 4), 2, 1, &P1_computed); diff --git a/intern/libmv/libmv/multiview/resection.h b/intern/libmv/libmv/multiview/resection.h index c142d6deeb2..e543827c932 100644 --- a/intern/libmv/libmv/multiview/resection.h +++ b/intern/libmv/libmv/multiview/resection.h @@ -33,23 +33,23 @@ namespace libmv { namespace resection { // x's are 2D image coordinates, (x,y,1), and X's are homogeneous four vectors. -template<typename T> -void Resection(const Matrix<T, 2, Dynamic> &x, - const Matrix<T, 4, Dynamic> &X, - Matrix<T, 3, 4> *P) { +template <typename T> +void Resection(const Matrix<T, 2, Dynamic>& x, + const Matrix<T, 4, Dynamic>& X, + Matrix<T, 3, 4>* P) { int N = x.cols(); assert(X.cols() == N); - Matrix<T, Dynamic, 12> design(2*N, 12); + Matrix<T, Dynamic, 12> design(2 * N, 12); design.setZero(); for (int i = 0; i < N; i++) { T xi = x(0, i); T yi = x(1, i); // See equation (7.2) on page 179 of H&Z. - design.template block<1, 4>(2*i, 4) = -X.col(i).transpose(); - design.template block<1, 4>(2*i, 8) = yi*X.col(i).transpose(); - design.template block<1, 4>(2*i + 1, 0) = X.col(i).transpose(); - design.template block<1, 4>(2*i + 1, 8) = -xi*X.col(i).transpose(); + design.template block<1, 4>(2 * i, 4) = -X.col(i).transpose(); + design.template block<1, 4>(2 * i, 8) = yi * X.col(i).transpose(); + design.template block<1, 4>(2 * i + 1, 0) = X.col(i).transpose(); + design.template block<1, 4>(2 * i + 1, 8) = -xi * X.col(i).transpose(); } Matrix<T, 12, 1> p; Nullspace(&design, &p); diff --git a/intern/libmv/libmv/multiview/resection_test.cc b/intern/libmv/libmv/multiview/resection_test.cc index 368e2281cfa..fb075d02d69 100644 --- a/intern/libmv/libmv/multiview/resection_test.cc +++ b/intern/libmv/libmv/multiview/resection_test.cc @@ -20,12 +20,12 @@ #include <iostream> +#include "libmv/logging/logging.h" #include "libmv/multiview/projection.h" #include "libmv/multiview/resection.h" #include "libmv/multiview/test_data_sets.h" #include "libmv/numeric/numeric.h" #include "testing/testing.h" -#include "libmv/logging/logging.h" namespace { @@ -40,15 +40,15 @@ TEST(Resection, ThreeViews) { Mat4X X(4, npoints); X.block(0, 0, 3, npoints) = d.X; X.row(3).setOnes(); - const Mat2X &x = d.x[i]; + const Mat2X& x = d.x[i]; Mat34 P; Resection(x, X, &P); Mat34 P_expected = d.P(i); // Because the P matrices are homogeneous, it is necessary to be tricky // about the scale factor to make them match. - P_expected *= 1/P_expected.array().abs().sum(); - P *= 1/P.array().abs().sum(); + P_expected *= 1 / P_expected.array().abs().sum(); + P *= 1 / P.array().abs().sum(); if (!((P(0, 0) > 0 && P_expected(0, 0) > 0) || (P(0, 0) < 0 && P_expected(0, 0) < 0))) { P *= -1; diff --git a/intern/libmv/libmv/multiview/test_data_sets.cc b/intern/libmv/libmv/multiview/test_data_sets.cc index 110bde6f762..a927c166d19 100644 --- a/intern/libmv/libmv/multiview/test_data_sets.cc +++ b/intern/libmv/libmv/multiview/test_data_sets.cc @@ -22,24 +22,28 @@ #include <cmath> -#include "libmv/numeric/numeric.h" -#include "libmv/multiview/projection.h" #include "libmv/multiview/fundamental.h" +#include "libmv/multiview/projection.h" +#include "libmv/numeric/numeric.h" namespace libmv { TwoViewDataSet TwoRealisticCameras(bool same_K) { TwoViewDataSet d; + // clang-format off d.K1 << 320, 0, 160, 0, 320, 120, 0, 0, 1; + // clang-format on if (same_K) { d.K2 = d.K1; } else { + // clang-format off d.K2 << 360, 0, 170, 0, 360, 110, 0, 0, 1; + // clang-format on } d.R1 = RotationAroundZ(-0.1); d.R2 = RotationAroundX(-0.1); @@ -59,10 +63,8 @@ TwoViewDataSet TwoRealisticCameras(bool same_K) { return d; } -nViewDatasetConfigator::nViewDatasetConfigator(int fx , int fy, - int cx, int cy, - double distance, - double jitter_amount) { +nViewDatasetConfigator::nViewDatasetConfigator( + int fx, int fy, int cx, int cy, double distance, double jitter_amount) { _fx = fx; _fy = fy; _cx = cx; @@ -71,7 +73,8 @@ nViewDatasetConfigator::nViewDatasetConfigator(int fx , int fy, _jitter_amount = jitter_amount; } -NViewDataSet NRealisticCamerasFull(int nviews, int npoints, +NViewDataSet NRealisticCamerasFull(int nviews, + int npoints, const nViewDatasetConfigator config) { NViewDataSet d; d.n = nviews; @@ -102,9 +105,11 @@ NViewDataSet NRealisticCamerasFull(int nviews, int npoints, jitter *= config._jitter_amount / camera_center.norm(); lookdir = -camera_center + jitter; + // clang-format off d.K[i] << config._fx, 0, config._cx, 0, config._fy, config._cy, 0, 0, 1; + // clang-format on d.R[i] = LookAt(lookdir); d.t[i] = -d.R[i] * camera_center; d.x[i] = Project(d.P(i), d.X); @@ -113,9 +118,10 @@ NViewDataSet NRealisticCamerasFull(int nviews, int npoints, return d; } - -NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, - float view_ratio, unsigned min_projections, +NViewDataSet NRealisticCamerasSparse(int nviews, + int npoints, + float view_ratio, + unsigned min_projections, const nViewDatasetConfigator config) { assert(view_ratio <= 1.0); assert(view_ratio > 0.0); @@ -137,7 +143,7 @@ NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, visibility.setZero(); Mat randoms(nviews, npoints); randoms.setRandom(); - randoms = (randoms.array() + 1)/2.0; + randoms = (randoms.array() + 1) / 2.0; unsigned num_visibles = 0; for (size_t i = 0; i < nviews; ++i) { num_visibles = 0; @@ -174,15 +180,17 @@ NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, jitter *= config._jitter_amount / camera_center.norm(); lookdir = -camera_center + jitter; + // clang-format off d.K[i] << config._fx, 0, config._cx, 0, config._fy, config._cy, 0, 0, 1; + // clang-format on d.R[i] = LookAt(lookdir); d.t[i] = -d.R[i] * camera_center; j_visible = 0; for (size_t j = 0; j < npoints; j++) { if (visibility(i, j)) { - X = d.X.col(j); + X = d.X.col(j); d.x[i].col(j_visible) = Project(d.P(i), X); d.x_ids[i][j_visible] = j; j_visible++; @@ -192,5 +200,4 @@ NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, return d; } - } // namespace libmv diff --git a/intern/libmv/libmv/multiview/test_data_sets.h b/intern/libmv/libmv/multiview/test_data_sets.h index cf01663ca02..0c8785728bd 100644 --- a/intern/libmv/libmv/multiview/test_data_sets.h +++ b/intern/libmv/libmv/multiview/test_data_sets.h @@ -34,8 +34,8 @@ struct TwoViewDataSet { Vec3 t1, t2; // Translation. Mat34 P1, P2; // Projection matrix, P = K(R|t) Mat3 F; // Fundamental matrix. - Mat3X X; // 3D points. - Mat2X x1, x2; // Projected points. + Mat3X X; // 3D points. + Mat2X x1, x2; // Projected points. }; // Two cameras at (-1,-1,-10) and (2,1,-10) looking approximately towards z+. @@ -45,13 +45,13 @@ TwoViewDataSet TwoRealisticCameras(bool same_K = false); // and the other reconstruction data types is that all points are seen by all // cameras. struct NViewDataSet { - vector<Mat3> K; // Internal parameters (fx, fy, etc). - vector<Mat3> R; // Rotation. - vector<Vec3> t; // Translation. - vector<Vec3> C; // Camera centers. - Mat3X X; // 3D points. - vector<Mat2X> x; // Projected points; may have noise added. - vector<Vecu> x_ids; // Indexes of points corresponding to the projections + vector<Mat3> K; // Internal parameters (fx, fy, etc). + vector<Mat3> R; // Rotation. + vector<Vec3> t; // Translation. + vector<Vec3> C; // Camera centers. + Mat3X X; // 3D points. + vector<Mat2X> x; // Projected points; may have noise added. + vector<Vecu> x_ids; // Indexes of points corresponding to the projections int n; // Actual number of cameras. @@ -83,22 +83,26 @@ struct nViewDatasetConfigator { double _dist; double _jitter_amount; - nViewDatasetConfigator(int fx = 1000, int fy = 1000, - int cx = 500, int cy = 500, + nViewDatasetConfigator(int fx = 1000, + int fy = 1000, + int cx = 500, + int cy = 500, double distance = 1.5, double jitter_amount = 0.01); }; -NViewDataSet NRealisticCamerasFull(int nviews, int npoints, - const nViewDatasetConfigator - config = nViewDatasetConfigator()); +NViewDataSet NRealisticCamerasFull( + int nviews, + int npoints, + const nViewDatasetConfigator config = nViewDatasetConfigator()); // Generates sparse projections (not all points are projected) -NViewDataSet NRealisticCamerasSparse(int nviews, int npoints, - float view_ratio = 0.6, - unsigned min_projections = 3, - const nViewDatasetConfigator - config = nViewDatasetConfigator()); +NViewDataSet NRealisticCamerasSparse( + int nviews, + int npoints, + float view_ratio = 0.6, + unsigned min_projections = 3, + const nViewDatasetConfigator config = nViewDatasetConfigator()); } // namespace libmv diff --git a/intern/libmv/libmv/multiview/triangulation.cc b/intern/libmv/libmv/multiview/triangulation.cc index 4d146c8f21b..568625de19d 100644 --- a/intern/libmv/libmv/multiview/triangulation.cc +++ b/intern/libmv/libmv/multiview/triangulation.cc @@ -20,15 +20,17 @@ #include "libmv/multiview/triangulation.h" -#include "libmv/numeric/numeric.h" #include "libmv/multiview/projection.h" +#include "libmv/numeric/numeric.h" namespace libmv { // HZ 12.2 pag.312 -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec4 *X_homogeneous) { +void TriangulateDLT(const Mat34& P1, + const Vec2& x1, + const Mat34& P2, + const Vec2& x2, + Vec4* X_homogeneous) { Mat4 design; for (int i = 0; i < 4; ++i) { design(0, i) = x1(0) * P1(2, i) - P1(0, i); @@ -39,9 +41,11 @@ void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, Nullspace(&design, X_homogeneous); } -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec3 *X_euclidean) { +void TriangulateDLT(const Mat34& P1, + const Vec2& x1, + const Mat34& P2, + const Vec2& x2, + Vec3* X_euclidean) { Vec4 X_homogeneous; TriangulateDLT(P1, x1, P2, x2, &X_homogeneous); HomogeneousToEuclidean(X_homogeneous, X_euclidean); diff --git a/intern/libmv/libmv/multiview/triangulation.h b/intern/libmv/libmv/multiview/triangulation.h index be878890242..c538433eb8b 100644 --- a/intern/libmv/libmv/multiview/triangulation.h +++ b/intern/libmv/libmv/multiview/triangulation.h @@ -25,13 +25,17 @@ namespace libmv { -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec4 *X_homogeneous); +void TriangulateDLT(const Mat34& P1, + const Vec2& x1, + const Mat34& P2, + const Vec2& x2, + Vec4* X_homogeneous); -void TriangulateDLT(const Mat34 &P1, const Vec2 &x1, - const Mat34 &P2, const Vec2 &x2, - Vec3 *X_euclidean); +void TriangulateDLT(const Mat34& P1, + const Vec2& x1, + const Mat34& P2, + const Vec2& x2, + Vec3* X_euclidean); } // namespace libmv diff --git a/intern/libmv/libmv/multiview/triangulation_test.cc b/intern/libmv/libmv/multiview/triangulation_test.cc index 66d1ee25a62..54d20f4ee17 100644 --- a/intern/libmv/libmv/multiview/triangulation_test.cc +++ b/intern/libmv/libmv/multiview/triangulation_test.cc @@ -20,10 +20,10 @@ #include <iostream> -#include "libmv/multiview/triangulation.h" #include "libmv/multiview/fundamental.h" #include "libmv/multiview/projection.h" #include "libmv/multiview/test_data_sets.h" +#include "libmv/multiview/triangulation.h" #include "libmv/numeric/numeric.h" #include "testing/testing.h" diff --git a/intern/libmv/libmv/multiview/two_view_kernel.h b/intern/libmv/libmv/multiview/two_view_kernel.h index 7af0ed5ddab..4df99183ee0 100644 --- a/intern/libmv/libmv/multiview/two_view_kernel.h +++ b/intern/libmv/libmv/multiview/two_view_kernel.h @@ -30,10 +30,10 @@ namespace libmv { namespace two_view { namespace kernel { -template<typename Solver, typename Unnormalizer> +template <typename Solver, typename Unnormalizer> struct NormalizedSolver { enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES }; - static void Solve(const Mat &x1, const Mat &x2, vector<Mat3> *models) { + static void Solve(const Mat& x1, const Mat& x2, vector<Mat3>* models) { assert(2 == x1.rows()); assert(MINIMUM_SAMPLES <= x1.cols()); assert(x1.rows() == x2.rows()); @@ -53,10 +53,10 @@ struct NormalizedSolver { } }; -template<typename Solver, typename Unnormalizer> +template <typename Solver, typename Unnormalizer> struct IsotropicNormalizedSolver { enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES }; - static void Solve(const Mat &x1, const Mat &x2, vector<Mat3> *models) { + static void Solve(const Mat& x1, const Mat& x2, vector<Mat3>* models) { assert(2 == x1.rows()); assert(MINIMUM_SAMPLES <= x1.cols()); assert(x1.rows() == x2.rows()); @@ -99,35 +99,32 @@ struct IsotropicNormalizedSolver { // // The fit routine must not clear existing entries in the vector of models; it // should append new solutions to the end. -template<typename SolverArg, - typename ErrorArg, - typename ModelArg = Mat3> +template <typename SolverArg, typename ErrorArg, typename ModelArg = Mat3> class Kernel { public: - Kernel(const Mat &x1, const Mat &x2) : x1_(x1), x2_(x2) {} + Kernel(const Mat& x1, const Mat& x2) : x1_(x1), x2_(x2) {} typedef SolverArg Solver; - typedef ModelArg Model; + typedef ModelArg Model; enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES }; - void Fit(const vector<int> &samples, vector<Model> *models) const { + void Fit(const vector<int>& samples, vector<Model>* models) const { Mat x1 = ExtractColumns(x1_, samples); Mat x2 = ExtractColumns(x2_, samples); Solver::Solve(x1, x2, models); } - double Error(int sample, const Model &model) const { + double Error(int sample, const Model& model) const { return ErrorArg::Error(model, static_cast<Vec>(x1_.col(sample)), static_cast<Vec>(x2_.col(sample))); } - int NumSamples() const { - return x1_.cols(); - } - static void Solve(const Mat &x1, const Mat &x2, vector<Model> *models) { + int NumSamples() const { return x1_.cols(); } + static void Solve(const Mat& x1, const Mat& x2, vector<Model>* models) { // By offering this, Kernel types can be passed to templates. Solver::Solve(x1, x2, models); } + protected: - const Mat &x1_; - const Mat &x2_; + const Mat& x1_; + const Mat& x2_; }; } // namespace kernel diff --git a/intern/libmv/libmv/numeric/dogleg.h b/intern/libmv/libmv/numeric/dogleg.h index bf6f996ddaf..62abfbdcd4b 100644 --- a/intern/libmv/libmv/numeric/dogleg.h +++ b/intern/libmv/libmv/numeric/dogleg.h @@ -32,18 +32,18 @@ #include <cmath> #include <cstdio> -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/function_derivative.h" #include "libmv/logging/logging.h" +#include "libmv/numeric/function_derivative.h" +#include "libmv/numeric/numeric.h" namespace libmv { -template<typename Function, - typename Jacobian = NumericJacobian<Function>, - typename Solver = Eigen::PartialPivLU< - Matrix<typename Function::FMatrixType::RealScalar, - Function::XMatrixType::RowsAtCompileTime, - Function::XMatrixType::RowsAtCompileTime> > > +template <typename Function, + typename Jacobian = NumericJacobian<Function>, + typename Solver = Eigen::PartialPivLU< + Matrix<typename Function::FMatrixType::RealScalar, + Function::XMatrixType::RowsAtCompileTime, + Function::XMatrixType::RowsAtCompileTime>>> class Dogleg { public: typedef typename Function::XMatrixType::RealScalar Scalar; @@ -51,10 +51,12 @@ class Dogleg { typedef typename Function::XMatrixType Parameters; typedef Matrix<typename Function::FMatrixType::RealScalar, Function::FMatrixType::RowsAtCompileTime, - Function::XMatrixType::RowsAtCompileTime> JMatrixType; + Function::XMatrixType::RowsAtCompileTime> + JMatrixType; typedef Matrix<typename JMatrixType::RealScalar, JMatrixType::ColsAtCompileTime, - JMatrixType::ColsAtCompileTime> AMatrixType; + JMatrixType::ColsAtCompileTime> + AMatrixType; enum Status { RUNNING, @@ -71,34 +73,38 @@ class Dogleg { STEEPEST_DESCENT, }; - Dogleg(const Function &f) - : f_(f), df_(f) {} + Dogleg(const Function& f) : f_(f), df_(f) {} struct SolverParameters { SolverParameters() - : gradient_threshold(1e-16), - relative_step_threshold(1e-16), - error_threshold(1e-16), - initial_trust_radius(1e0), - max_iterations(500) {} + : gradient_threshold(1e-16), + relative_step_threshold(1e-16), + error_threshold(1e-16), + initial_trust_radius(1e0), + max_iterations(500) {} Scalar gradient_threshold; // eps > max(J'*f(x)) Scalar relative_step_threshold; // eps > ||dx|| / ||x|| Scalar error_threshold; // eps > ||f(x)|| Scalar initial_trust_radius; // Initial u for solving normal equations. - int max_iterations; // Maximum number of solver iterations. + int max_iterations; // Maximum number of solver iterations. }; struct Results { Scalar error_magnitude; // ||f(x)|| Scalar gradient_magnitude; // ||J'f(x)|| - int iterations; + int iterations; Status status; }; - Status Update(const Parameters &x, const SolverParameters ¶ms, - JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) { + Status Update(const Parameters& x, + const SolverParameters& params, + JMatrixType* J, + AMatrixType* A, + FVec* error, + Parameters* g) { *J = df_(x); - // TODO(keir): In the case of m = n, avoid computing A and just do J^-1 directly. + // TODO(keir): In the case of m = n, avoid computing A and just do J^-1 + // directly. *A = (*J).transpose() * (*J); *error = f_(x); *g = (*J).transpose() * *error; @@ -110,12 +116,12 @@ class Dogleg { return RUNNING; } - Step SolveDoglegDirection(const Parameters &dx_sd, - const Parameters &dx_gn, + Step SolveDoglegDirection(const Parameters& dx_sd, + const Parameters& dx_gn, Scalar radius, Scalar alpha, - Parameters *dx_dl, - Scalar *beta) { + Parameters* dx_dl, + Scalar* beta) { Parameters a, b_minus_a; // Solve for Dogleg step dx_dl. if (dx_gn.norm() < radius) { @@ -128,30 +134,29 @@ class Dogleg { } else { Parameters a = alpha * dx_sd; - const Parameters &b = dx_gn; + const Parameters& b = dx_gn; b_minus_a = a - b; Scalar Mbma2 = b_minus_a.squaredNorm(); Scalar Ma2 = a.squaredNorm(); Scalar c = a.dot(b_minus_a); - Scalar radius2 = radius*radius; + Scalar radius2 = radius * radius; if (c <= 0) { - *beta = (-c + sqrt(c*c + Mbma2*(radius2 - Ma2)))/(Mbma2); + *beta = (-c + sqrt(c * c + Mbma2 * (radius2 - Ma2))) / (Mbma2); } else { - *beta = (radius2 - Ma2) / - (c + sqrt(c*c + Mbma2*(radius2 - Ma2))); + *beta = (radius2 - Ma2) / (c + sqrt(c * c + Mbma2 * (radius2 - Ma2))); } - *dx_dl = alpha * dx_sd + (*beta) * (dx_gn - alpha*dx_sd); + *dx_dl = alpha * dx_sd + (*beta) * (dx_gn - alpha * dx_sd); return DOGLEG; } } - Results minimize(Parameters *x_and_min) { + Results minimize(Parameters* x_and_min) { SolverParameters params; return minimize(params, x_and_min); } - Results minimize(const SolverParameters ¶ms, Parameters *x_and_min) { - Parameters &x = *x_and_min; + Results minimize(const SolverParameters& params, Parameters* x_and_min) { + Parameters& x = *x_and_min; JMatrixType J; AMatrixType A; FVec error; @@ -167,18 +172,21 @@ class Dogleg { Parameters dx_sd; // Steepest descent step. Parameters dx_dl; // Dogleg step. Parameters dx_gn; // Gauss-Newton step. - printf("iteration ||f(x)|| max(g) radius\n"); + printf("iteration ||f(x)|| max(g) radius\n"); int i = 0; for (; results.status == RUNNING && i < params.max_iterations; ++i) { printf("%9d %12g %12g %12g", - i, f_(x).norm(), g.array().abs().maxCoeff(), radius); + i, + f_(x).norm(), + g.array().abs().maxCoeff(), + radius); - //LG << "iteration: " << i; - //LG << "||f(x)||: " << f_(x).norm(); - //LG << "max(g): " << g.cwise().abs().maxCoeff(); - //LG << "radius: " << radius; + // LG << "iteration: " << i; + // LG << "||f(x)||: " << f_(x).norm(); + // LG << "max(g): " << g.cwise().abs().maxCoeff(); + // LG << "radius: " << radius; // Eqn 3.19 from [1] - Scalar alpha = g.squaredNorm() / (J*g).squaredNorm(); + Scalar alpha = g.squaredNorm() / (J * g).squaredNorm(); // Solve for steepest descent direction dx_sd. dx_sd = -g; @@ -199,11 +207,11 @@ class Dogleg { // Solve for dogleg direction dx_dl. Scalar beta = 0; - Step step = SolveDoglegDirection(dx_sd, dx_gn, radius, alpha, - &dx_dl, &beta); + Step step = + SolveDoglegDirection(dx_sd, dx_gn, radius, alpha, &dx_dl, &beta); Scalar e3 = params.relative_step_threshold; - if (dx_dl.norm() < e3*(x.norm() + e3)) { + if (dx_dl.norm() < e3 * (x.norm() + e3)) { results.status = RELATIVE_STEP_SIZE_TOO_SMALL; break; } @@ -214,16 +222,19 @@ class Dogleg { if (step == GAUSS_NEWTON) { predicted = f_(x).squaredNorm(); } else if (step == STEEPEST_DESCENT) { - predicted = radius * (2*alpha*g.norm() - radius) / 2 / alpha; + predicted = radius * (2 * alpha * g.norm() - radius) / 2 / alpha; } else if (step == DOGLEG) { - predicted = 0.5 * alpha * (1-beta)*(1-beta)*g.squaredNorm() + - beta*(2-beta)*f_(x).squaredNorm(); + predicted = 0.5 * alpha * (1 - beta) * (1 - beta) * g.squaredNorm() + + beta * (2 - beta) * f_(x).squaredNorm(); } Scalar rho = actual / predicted; - if (step == GAUSS_NEWTON) printf(" GAUSS"); - if (step == STEEPEST_DESCENT) printf(" STEE"); - if (step == DOGLEG) printf(" DOGL"); + if (step == GAUSS_NEWTON) + printf(" GAUSS"); + if (step == STEEPEST_DESCENT) + printf(" STEE"); + if (step == DOGLEG) + printf(" DOGL"); printf(" %12g %12g %12g\n", rho, actual, predicted); @@ -234,7 +245,7 @@ class Dogleg { x_updated = true; } if (rho > 0.75) { - radius = std::max(radius, 3*dx_dl.norm()); + radius = std::max(radius, 3 * dx_dl.norm()); } else if (rho < 0.25) { radius /= 2; if (radius < e3 * (x.norm() + e3)) { @@ -252,10 +263,10 @@ class Dogleg { } private: - const Function &f_; + const Function& f_; Jacobian df_; }; -} // namespace mv +} // namespace libmv #endif // LIBMV_NUMERIC_DOGLEG_H diff --git a/intern/libmv/libmv/numeric/dogleg_test.cc b/intern/libmv/libmv/numeric/dogleg_test.cc index 90c46c31672..a5ab1957632 100644 --- a/intern/libmv/libmv/numeric/dogleg_test.cc +++ b/intern/libmv/libmv/numeric/dogleg_test.cc @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "testing/testing.h" #include "libmv/numeric/dogleg.h" +#include "testing/testing.h" using namespace libmv; @@ -29,26 +29,26 @@ class F { public: typedef Vec4 FMatrixType; typedef Vec3 XMatrixType; - Vec4 operator()(const Vec3 &x) const { + Vec4 operator()(const Vec3& x) const { double x1 = x.x() - 2; double y1 = x.y() - 5; double z1 = x.z(); - Vec4 fx; fx << x1*x1 + z1*z1, - y1*y1 + z1*z1, - z1*z1, - x1*x1; + Vec4 fx; + fx << x1 * x1 + z1 * z1, y1 * y1 + z1 * z1, z1 * z1, x1 * x1; return fx; } }; TEST(Dogleg, SimpleCase) { - Vec3 x; x << 0.76026643, -30.01799744, 0.55192142; + Vec3 x; + x << 0.76026643, -30.01799744, 0.55192142; F f; Dogleg<F>::SolverParameters params; Dogleg<F> lm(f); /* TODO(sergey): Better error handling. */ /* Dogleg<F>::Results results = */ lm.minimize(params, &x); - Vec3 expected_min_x; expected_min_x << 2, 5, 0; + Vec3 expected_min_x; + expected_min_x << 2, 5, 0; EXPECT_MATRIX_NEAR(expected_min_x, x, 1e-5); } @@ -59,20 +59,21 @@ class F32 { public: typedef Vec2 FMatrixType; typedef Vec2 XMatrixType; - Vec2 operator()(const Vec2 &x) const { + Vec2 operator()(const Vec2& x) const { double x1 = x(0); - double x2 = 10*x(0)/(x(0) + 0.1) + 2*x(1)*x(1); - Vec2 fx; fx << x1, x2; + double x2 = 10 * x(0) / (x(0) + 0.1) + 2 * x(1) * x(1); + Vec2 fx; + fx << x1, x2; return fx; } }; class JF32 { public: - JF32(const F32 &f) { (void) f; } - Mat2 operator()(const Vec2 &x) { - Mat2 J; J << 1, 0, - 1./pow(x(0) + 0.1, 2), 4*x(1)*x(1); + JF32(const F32& f) { (void)f; } + Mat2 operator()(const Vec2& x) { + Mat2 J; + J << 1, 0, 1. / pow(x(0) + 0.1, 2), 4 * x(1) * x(1); return J; } }; diff --git a/intern/libmv/libmv/numeric/function_derivative.h b/intern/libmv/libmv/numeric/function_derivative.h index 9820885f04e..30d7c4d34e9 100644 --- a/intern/libmv/libmv/numeric/function_derivative.h +++ b/intern/libmv/libmv/numeric/function_derivative.h @@ -23,8 +23,8 @@ #include <cmath> -#include "libmv/numeric/numeric.h" #include "libmv/logging/logging.h" +#include "libmv/numeric/numeric.h" namespace libmv { @@ -36,7 +36,7 @@ enum NumericJacobianMode { FORWARD, }; -template<typename Function, NumericJacobianMode mode = CENTRAL> +template <typename Function, NumericJacobianMode mode = CENTRAL> class NumericJacobian { public: typedef typename Function::XMatrixType Parameters; @@ -45,12 +45,12 @@ class NumericJacobian { typedef Matrix<typename Function::FMatrixType::RealScalar, Function::FMatrixType::RowsAtCompileTime, Function::XMatrixType::RowsAtCompileTime> - JMatrixType; + JMatrixType; - NumericJacobian(const Function &f) : f_(f) {} + NumericJacobian(const Function& f) : f_(f) {} // TODO(keir): Perhaps passing the jacobian back by value is not a good idea. - JMatrixType operator()(const Parameters &x) { + JMatrixType operator()(const Parameters& x) { // Empirically determined constant. Parameters eps = x.array().abs() * XScalar(1e-5); // To handle cases where a paremeter is exactly zero, instead use the mean @@ -87,12 +87,13 @@ class NumericJacobian { } return jacobian; } + private: - const Function &f_; + const Function& f_; }; -template<typename Function, typename Jacobian> -bool CheckJacobian(const Function &f, const typename Function::XMatrixType &x) { +template <typename Function, typename Jacobian> +bool CheckJacobian(const Function& f, const typename Function::XMatrixType& x) { Jacobian j_analytic(f); NumericJacobian<Function> j_numeric(f); diff --git a/intern/libmv/libmv/numeric/function_derivative_test.cc b/intern/libmv/libmv/numeric/function_derivative_test.cc index 8d976d3e9a0..defeedaa8a4 100644 --- a/intern/libmv/libmv/numeric/function_derivative_test.cc +++ b/intern/libmv/libmv/numeric/function_derivative_test.cc @@ -18,9 +18,9 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "testing/testing.h" -#include "libmv/numeric/numeric.h" #include "libmv/numeric/function_derivative.h" +#include "libmv/numeric/numeric.h" +#include "testing/testing.h" using namespace libmv; @@ -30,22 +30,22 @@ class F { public: typedef Vec2 FMatrixType; typedef Vec3 XMatrixType; - Vec2 operator()(const Vec3 &x) const { + Vec2 operator()(const Vec3& x) const { Vec2 fx; - fx << 0.19*x(0) + 0.19*x(1)*x(1) + x(2), - 3*sin(x(0)) + 2*cos(x(1)); + fx << 0.19 * x(0) + 0.19 * x(1) * x(1) + x(2), + 3 * sin(x(0)) + 2 * cos(x(1)); return fx; } - Mat23 J(const Vec3 &x) const { + Mat23 J(const Vec3& x) const { Mat23 jacobian; - jacobian << 0.19, 2*0.19*x(1), 1.0, - 3*cos(x(0)), -2*sin(x(1)), 0; + jacobian << 0.19, 2 * 0.19 * x(1), 1.0, 3 * cos(x(0)), -2 * sin(x(1)), 0; return jacobian; } }; TEST(FunctionDerivative, SimpleCase) { - Vec3 x; x << 0.76026643, 0.01799744, 0.55192142; + Vec3 x; + x << 0.76026643, 0.01799744, 0.55192142; F f; NumericJacobian<F, CENTRAL> J(f); EXPECT_MATRIX_NEAR(f.J(x), J(x), 1e-8); diff --git a/intern/libmv/libmv/numeric/levenberg_marquardt.h b/intern/libmv/libmv/numeric/levenberg_marquardt.h index 2af9a62cf7b..30c04a5ad5c 100644 --- a/intern/libmv/libmv/numeric/levenberg_marquardt.h +++ b/intern/libmv/libmv/numeric/levenberg_marquardt.h @@ -31,18 +31,18 @@ #include <cmath> -#include "libmv/numeric/numeric.h" -#include "libmv/numeric/function_derivative.h" #include "libmv/logging/logging.h" +#include "libmv/numeric/function_derivative.h" +#include "libmv/numeric/numeric.h" namespace libmv { -template<typename Function, - typename Jacobian = NumericJacobian<Function>, - typename Solver = Eigen::PartialPivLU< - Matrix<typename Function::FMatrixType::RealScalar, - Function::XMatrixType::RowsAtCompileTime, - Function::XMatrixType::RowsAtCompileTime> > > +template <typename Function, + typename Jacobian = NumericJacobian<Function>, + typename Solver = Eigen::PartialPivLU< + Matrix<typename Function::FMatrixType::RealScalar, + Function::XMatrixType::RowsAtCompileTime, + Function::XMatrixType::RowsAtCompileTime>>> class LevenbergMarquardt { public: typedef typename Function::XMatrixType::RealScalar Scalar; @@ -50,10 +50,12 @@ class LevenbergMarquardt { typedef typename Function::XMatrixType Parameters; typedef Matrix<typename Function::FMatrixType::RealScalar, Function::FMatrixType::RowsAtCompileTime, - Function::XMatrixType::RowsAtCompileTime> JMatrixType; + Function::XMatrixType::RowsAtCompileTime> + JMatrixType; typedef Matrix<typename JMatrixType::RealScalar, JMatrixType::ColsAtCompileTime, - JMatrixType::ColsAtCompileTime> AMatrixType; + JMatrixType::ColsAtCompileTime> + AMatrixType; // TODO(keir): Some of these knobs can be derived from each other and // removed, instead of requiring the user to set them. @@ -65,32 +67,35 @@ class LevenbergMarquardt { HIT_MAX_ITERATIONS, }; - LevenbergMarquardt(const Function &f) - : f_(f), df_(f) {} + LevenbergMarquardt(const Function& f) : f_(f), df_(f) {} struct SolverParameters { SolverParameters() - : gradient_threshold(1e-16), - relative_step_threshold(1e-16), - error_threshold(1e-16), - initial_scale_factor(1e-3), - max_iterations(100) {} + : gradient_threshold(1e-16), + relative_step_threshold(1e-16), + error_threshold(1e-16), + initial_scale_factor(1e-3), + max_iterations(100) {} Scalar gradient_threshold; // eps > max(J'*f(x)) Scalar relative_step_threshold; // eps > ||dx|| / ||x|| Scalar error_threshold; // eps > ||f(x)|| Scalar initial_scale_factor; // Initial u for solving normal equations. - int max_iterations; // Maximum number of solver iterations. + int max_iterations; // Maximum number of solver iterations. }; struct Results { Scalar error_magnitude; // ||f(x)|| Scalar gradient_magnitude; // ||J'f(x)|| - int iterations; + int iterations; Status status; }; - Status Update(const Parameters &x, const SolverParameters ¶ms, - JMatrixType *J, AMatrixType *A, FVec *error, Parameters *g) { + Status Update(const Parameters& x, + const SolverParameters& params, + JMatrixType* J, + AMatrixType* A, + FVec* error, + Parameters* g) { *J = df_(x); *A = (*J).transpose() * (*J); *error = -f_(x); @@ -103,13 +108,13 @@ class LevenbergMarquardt { return RUNNING; } - Results minimize(Parameters *x_and_min) { + Results minimize(Parameters* x_and_min) { SolverParameters params; minimize(params, x_and_min); } - Results minimize(const SolverParameters ¶ms, Parameters *x_and_min) { - Parameters &x = *x_and_min; + Results minimize(const SolverParameters& params, Parameters* x_and_min) { + Parameters& x = *x_and_min; JMatrixType J; AMatrixType A; FVec error; @@ -118,7 +123,7 @@ class LevenbergMarquardt { Results results; results.status = Update(x, params, &J, &A, &error, &g); - Scalar u = Scalar(params.initial_scale_factor*A.diagonal().maxCoeff()); + Scalar u = Scalar(params.initial_scale_factor * A.diagonal().maxCoeff()); Scalar v = 2; Parameters dx, x_new; @@ -130,7 +135,8 @@ class LevenbergMarquardt { VLOG(3) << "u: " << u; VLOG(3) << "v: " << v; - AMatrixType A_augmented = A + u*AMatrixType::Identity(J.cols(), J.cols()); + AMatrixType A_augmented = + A + u * AMatrixType::Identity(J.cols(), J.cols()); Solver solver(A_augmented); dx = solver.solve(g); bool solved = (A_augmented * dx).isApprox(g); @@ -146,14 +152,14 @@ class LevenbergMarquardt { // Rho is the ratio of the actual reduction in error to the reduction // in error that would be obtained if the problem was linear. // See [1] for details. - Scalar rho((error.squaredNorm() - f_(x_new).squaredNorm()) - / dx.dot(u*dx + g)); + Scalar rho((error.squaredNorm() - f_(x_new).squaredNorm()) / + dx.dot(u * dx + g)); if (rho > 0) { // Accept the Gauss-Newton step because the linear model fits well. x = x_new; results.status = Update(x, params, &J, &A, &error, &g); - Scalar tmp = Scalar(2*rho-1); - u = u*std::max(1/3., 1 - (tmp*tmp*tmp)); + Scalar tmp = Scalar(2 * rho - 1); + u = u * std::max(1 / 3., 1 - (tmp * tmp * tmp)); v = 2; continue; } @@ -174,10 +180,10 @@ class LevenbergMarquardt { } private: - const Function &f_; + const Function& f_; Jacobian df_; }; -} // namespace mv +} // namespace libmv #endif // LIBMV_NUMERIC_LEVENBERG_MARQUARDT_H diff --git a/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc b/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc index fc3f9ebbb29..805aac275b4 100644 --- a/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc +++ b/intern/libmv/libmv/numeric/levenberg_marquardt_test.cc @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "testing/testing.h" #include "libmv/numeric/levenberg_marquardt.h" +#include "testing/testing.h" using namespace libmv; @@ -29,14 +29,12 @@ class F { public: typedef Vec4 FMatrixType; typedef Vec3 XMatrixType; - Vec4 operator()(const Vec3 &x) const { + Vec4 operator()(const Vec3& x) const { double x1 = x.x() - 2; double y1 = x.y() - 5; double z1 = x.z(); - Vec4 fx; fx << x1*x1 + z1*z1, - y1*y1 + z1*z1, - z1*z1, - x1*x1; + Vec4 fx; + fx << x1 * x1 + z1 * z1, y1 * y1 + z1 * z1, z1 * z1, x1 * x1; return fx; } }; diff --git a/intern/libmv/libmv/numeric/numeric.cc b/intern/libmv/libmv/numeric/numeric.cc index 3fc1e3b2bfd..b7660950c2a 100644 --- a/intern/libmv/libmv/numeric/numeric.cc +++ b/intern/libmv/libmv/numeric/numeric.cc @@ -18,7 +18,6 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. - #include "libmv/numeric/numeric.h" namespace libmv { @@ -27,9 +26,11 @@ Mat3 RotationAroundX(double angle) { double c, s; sincos(angle, &s, &c); Mat3 R; + // clang-format off R << 1, 0, 0, 0, c, -s, 0, s, c; + // clang-format on return R; } @@ -37,9 +38,11 @@ Mat3 RotationAroundY(double angle) { double c, s; sincos(angle, &s, &c); Mat3 R; + // clang-format off R << c, 0, s, 0, 1, 0, -s, 0, c; + // clang-format on return R; } @@ -47,14 +50,15 @@ Mat3 RotationAroundZ(double angle) { double c, s; sincos(angle, &s, &c); Mat3 R; + // clang-format off R << c, -s, 0, s, c, 0, 0, 0, 1; + // clang-format on return R; } - -Mat3 RotationRodrigues(const Vec3 &axis) { +Mat3 RotationRodrigues(const Vec3& axis) { double theta = axis.norm(); Vec3 w = axis / theta; Mat3 W = CrossProductMatrix(w); @@ -62,7 +66,6 @@ Mat3 RotationRodrigues(const Vec3 &axis) { return Mat3::Identity() + sin(theta) * W + (1 - cos(theta)) * W * W; } - Mat3 LookAt(Vec3 center) { Vec3 zc = center.normalized(); Vec3 xc = Vec3::UnitY().cross(zc).normalized(); @@ -74,19 +77,21 @@ Mat3 LookAt(Vec3 center) { return R; } -Mat3 CrossProductMatrix(const Vec3 &x) { +Mat3 CrossProductMatrix(const Vec3& x) { Mat3 X; + // clang-format off X << 0, -x(2), x(1), x(2), 0, -x(0), -x(1), x(0), 0; + // clang-format on return X; } -void MeanAndVarianceAlongRows(const Mat &A, - Vec *mean_pointer, - Vec *variance_pointer) { - Vec &mean = *mean_pointer; - Vec &variance = *variance_pointer; +void MeanAndVarianceAlongRows(const Mat& A, + Vec* mean_pointer, + Vec* variance_pointer) { + Vec& mean = *mean_pointer; + Vec& variance = *variance_pointer; int n = A.rows(); int m = A.cols(); mean.resize(n); @@ -108,29 +113,28 @@ void MeanAndVarianceAlongRows(const Mat &A, } } -void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked) { +void HorizontalStack(const Mat& left, const Mat& right, Mat* stacked) { assert(left.rows() == right.rows()); int n = left.rows(); int m1 = left.cols(); int m2 = right.cols(); stacked->resize(n, m1 + m2); - stacked->block(0, 0, n, m1) = left; + stacked->block(0, 0, n, m1) = left; stacked->block(0, m1, n, m2) = right; } -void MatrixColumn(const Mat &A, int i, Vec2 *v) { +void MatrixColumn(const Mat& A, int i, Vec2* v) { assert(A.rows() == 2); *v << A(0, i), A(1, i); } -void MatrixColumn(const Mat &A, int i, Vec3 *v) { +void MatrixColumn(const Mat& A, int i, Vec3* v) { assert(A.rows() == 3); *v << A(0, i), A(1, i), A(2, i); } -void MatrixColumn(const Mat &A, int i, Vec4 *v) { +void MatrixColumn(const Mat& A, int i, Vec4* v) { assert(A.rows() == 4); *v << A(0, i), A(1, i), A(2, i), A(3, i); } } // namespace libmv - diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h index f5478bee6ab..e3d44226338 100644 --- a/intern/libmv/libmv/numeric/numeric.h +++ b/intern/libmv/libmv/numeric/numeric.h @@ -34,10 +34,9 @@ #include <Eigen/SVD> #if !defined(__MINGW64__) -# if defined(_WIN32) || defined(__APPLE__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__HAIKU__) -inline void sincos(double x, double *sinx, double *cosx) { +# if defined(_WIN32) || defined(__APPLE__) || defined(__FreeBSD__) || \ + defined(__NetBSD__) || defined(__HAIKU__) +inline void sincos(double x, double* sinx, double* cosx) { *sinx = sin(x); *cosx = cos(x); } @@ -46,11 +45,11 @@ inline void sincos(double x, double *sinx, double *cosx) { #if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__) inline long lround(double d) { - return (long)(d>0 ? d+0.5 : ceil(d-0.5)); + return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5)); } # if _MSC_VER < 1800 inline int round(double d) { - return (d>0) ? int(d+0.5) : int(d-0.5); + return (d > 0) ? int(d + 0.5) : int(d - 0.5); } # endif // _MSC_VER < 1800 typedef unsigned int uint; @@ -92,25 +91,25 @@ typedef Eigen::Matrix<double, 4, 4, Eigen::RowMajor> RMat4; typedef Eigen::Matrix<double, 2, Eigen::Dynamic> Mat2X; typedef Eigen::Matrix<double, 3, Eigen::Dynamic> Mat3X; typedef Eigen::Matrix<double, 4, Eigen::Dynamic> Mat4X; -typedef Eigen::Matrix<double, Eigen::Dynamic, 2> MatX2; -typedef Eigen::Matrix<double, Eigen::Dynamic, 3> MatX3; -typedef Eigen::Matrix<double, Eigen::Dynamic, 4> MatX4; -typedef Eigen::Matrix<double, Eigen::Dynamic, 5> MatX5; -typedef Eigen::Matrix<double, Eigen::Dynamic, 6> MatX6; -typedef Eigen::Matrix<double, Eigen::Dynamic, 7> MatX7; -typedef Eigen::Matrix<double, Eigen::Dynamic, 8> MatX8; -typedef Eigen::Matrix<double, Eigen::Dynamic, 9> MatX9; +typedef Eigen::Matrix<double, Eigen::Dynamic, 2> MatX2; +typedef Eigen::Matrix<double, Eigen::Dynamic, 3> MatX3; +typedef Eigen::Matrix<double, Eigen::Dynamic, 4> MatX4; +typedef Eigen::Matrix<double, Eigen::Dynamic, 5> MatX5; +typedef Eigen::Matrix<double, Eigen::Dynamic, 6> MatX6; +typedef Eigen::Matrix<double, Eigen::Dynamic, 7> MatX7; +typedef Eigen::Matrix<double, Eigen::Dynamic, 8> MatX8; +typedef Eigen::Matrix<double, Eigen::Dynamic, 9> MatX9; typedef Eigen::Matrix<double, Eigen::Dynamic, 15> MatX15; typedef Eigen::Matrix<double, Eigen::Dynamic, 16> MatX16; typedef Eigen::Vector2d Vec2; typedef Eigen::Vector3d Vec3; typedef Eigen::Vector4d Vec4; -typedef Eigen::Matrix<double, 5, 1> Vec5; -typedef Eigen::Matrix<double, 6, 1> Vec6; -typedef Eigen::Matrix<double, 7, 1> Vec7; -typedef Eigen::Matrix<double, 8, 1> Vec8; -typedef Eigen::Matrix<double, 9, 1> Vec9; +typedef Eigen::Matrix<double, 5, 1> Vec5; +typedef Eigen::Matrix<double, 6, 1> Vec6; +typedef Eigen::Matrix<double, 7, 1> Vec7; +typedef Eigen::Matrix<double, 8, 1> Vec8; +typedef Eigen::Matrix<double, 9, 1> Vec9; typedef Eigen::Matrix<double, 10, 1> Vec10; typedef Eigen::Matrix<double, 11, 1> Vec11; typedef Eigen::Matrix<double, 12, 1> Vec12; @@ -133,15 +132,13 @@ typedef Eigen::Vector2i Vec2i; typedef Eigen::Vector3i Vec3i; typedef Eigen::Vector4i Vec4i; -typedef Eigen::Matrix<float, - Eigen::Dynamic, - Eigen::Dynamic, - Eigen::RowMajor> RMatf; +typedef Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> + RMatf; typedef Eigen::NumTraits<double> EigenDouble; -using Eigen::Map; using Eigen::Dynamic; +using Eigen::Map; using Eigen::Matrix; // Find U, s, and VT such that @@ -149,7 +146,7 @@ using Eigen::Matrix; // A = U * diag(s) * VT // template <typename TMat, typename TVec> -inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) { +inline void SVD(TMat* /*A*/, Vec* /*s*/, Mat* /*U*/, Mat* /*VT*/) { assert(0); } @@ -158,11 +155,11 @@ inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) { // Destroys A and resizes x if necessary. // TODO(maclean): Take the SVD of the transpose instead of this zero padding. template <typename TMat, typename TVec> -double Nullspace(TMat *A, TVec *nullspace) { +double Nullspace(TMat* A, TVec* nullspace) { Eigen::JacobiSVD<TMat> svd(*A, Eigen::ComputeFullV); - (*nullspace) = svd.matrixV().col(A->cols()-1); + (*nullspace) = svd.matrixV().col(A->cols() - 1); if (A->rows() >= A->cols()) - return svd.singularValues()(A->cols()-1); + return svd.singularValues()(A->cols() - 1); else return 0.0; } @@ -173,55 +170,55 @@ double Nullspace(TMat *A, TVec *nullspace) { // the singluar value corresponding to the solution x1. Destroys A and resizes // x if necessary. template <typename TMat, typename TVec1, typename TVec2> -double Nullspace2(TMat *A, TVec1 *x1, TVec2 *x2) { +double Nullspace2(TMat* A, TVec1* x1, TVec2* x2) { Eigen::JacobiSVD<TMat> svd(*A, Eigen::ComputeFullV); *x1 = svd.matrixV().col(A->cols() - 1); *x2 = svd.matrixV().col(A->cols() - 2); if (A->rows() >= A->cols()) - return svd.singularValues()(A->cols()-1); + return svd.singularValues()(A->cols() - 1); else return 0.0; } // In place transpose for square matrices. -template<class TA> -inline void TransposeInPlace(TA *A) { +template <class TA> +inline void TransposeInPlace(TA* A) { *A = A->transpose().eval(); } -template<typename TVec> -inline double NormL1(const TVec &x) { +template <typename TVec> +inline double NormL1(const TVec& x) { return x.array().abs().sum(); } -template<typename TVec> -inline double NormL2(const TVec &x) { +template <typename TVec> +inline double NormL2(const TVec& x) { return x.norm(); } -template<typename TVec> -inline double NormLInfinity(const TVec &x) { +template <typename TVec> +inline double NormLInfinity(const TVec& x) { return x.array().abs().maxCoeff(); } -template<typename TVec> -inline double DistanceL1(const TVec &x, const TVec &y) { +template <typename TVec> +inline double DistanceL1(const TVec& x, const TVec& y) { return (x - y).array().abs().sum(); } -template<typename TVec> -inline double DistanceL2(const TVec &x, const TVec &y) { +template <typename TVec> +inline double DistanceL2(const TVec& x, const TVec& y) { return (x - y).norm(); } -template<typename TVec> -inline double DistanceLInfinity(const TVec &x, const TVec &y) { +template <typename TVec> +inline double DistanceLInfinity(const TVec& x, const TVec& y) { return (x - y).array().abs().maxCoeff(); } // Normalize a vector with the L1 norm, and return the norm before it was // normalized. -template<typename TVec> -inline double NormalizeL1(TVec *x) { +template <typename TVec> +inline double NormalizeL1(TVec* x) { double norm = NormL1(*x); *x /= norm; return norm; @@ -229,8 +226,8 @@ inline double NormalizeL1(TVec *x) { // Normalize a vector with the L2 norm, and return the norm before it was // normalized. -template<typename TVec> -inline double NormalizeL2(TVec *x) { +template <typename TVec> +inline double NormalizeL2(TVec* x) { double norm = NormL2(*x); *x /= norm; return norm; @@ -238,15 +235,15 @@ inline double NormalizeL2(TVec *x) { // Normalize a vector with the L^Infinity norm, and return the norm before it // was normalized. -template<typename TVec> -inline double NormalizeLInfinity(TVec *x) { +template <typename TVec> +inline double NormalizeLInfinity(TVec* x) { double norm = NormLInfinity(*x); *x /= norm; return norm; } // Return the square of a number. -template<typename T> +template <typename T> inline T Square(T x) { return x * x; } @@ -258,7 +255,7 @@ Mat3 RotationAroundZ(double angle); // Returns the rotation matrix of a rotation of angle |axis| around axis. // This is computed using the Rodrigues formula, see: // http://mathworld.wolfram.com/RodriguesRotationFormula.html -Mat3 RotationRodrigues(const Vec3 &axis); +Mat3 RotationRodrigues(const Vec3& axis); // Make a rotation matrix such that center becomes the direction of the // positive z-axis, and y is oriented close to up. @@ -266,177 +263,173 @@ Mat3 LookAt(Vec3 center); // Return a diagonal matrix from a vector containg the diagonal values. template <typename TVec> -inline Mat Diag(const TVec &x) { +inline Mat Diag(const TVec& x) { return x.asDiagonal(); } -template<typename TMat> -inline double FrobeniusNorm(const TMat &A) { +template <typename TMat> +inline double FrobeniusNorm(const TMat& A) { return sqrt(A.array().abs2().sum()); } -template<typename TMat> -inline double FrobeniusDistance(const TMat &A, const TMat &B) { +template <typename TMat> +inline double FrobeniusDistance(const TMat& A, const TMat& B) { return FrobeniusNorm(A - B); } -inline Vec3 CrossProduct(const Vec3 &x, const Vec3 &y) { +inline Vec3 CrossProduct(const Vec3& x, const Vec3& y) { return x.cross(y); } -Mat3 CrossProductMatrix(const Vec3 &x); +Mat3 CrossProductMatrix(const Vec3& x); -void MeanAndVarianceAlongRows(const Mat &A, - Vec *mean_pointer, - Vec *variance_pointer); +void MeanAndVarianceAlongRows(const Mat& A, + Vec* mean_pointer, + Vec* variance_pointer); #if defined(_WIN32) - // TODO(bomboze): un-#if this for both platforms once tested under Windows - /* This solution was extensively discussed here - http://forum.kde.org/viewtopic.php?f=74&t=61940 */ - #define SUM_OR_DYNAMIC(x, y) (x == Eigen::Dynamic || y == Eigen::Dynamic) ? Eigen::Dynamic : (x+y) - - template<typename Derived1, typename Derived2> - struct hstack_return { - typedef typename Derived1::Scalar Scalar; - enum { - RowsAtCompileTime = Derived1::RowsAtCompileTime, - ColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::ColsAtCompileTime, - Derived2::ColsAtCompileTime), - Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0, - MaxRowsAtCompileTime = Derived1::MaxRowsAtCompileTime, - MaxColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxColsAtCompileTime, - Derived2::MaxColsAtCompileTime) - }; - typedef Eigen::Matrix<Scalar, - RowsAtCompileTime, - ColsAtCompileTime, - Options, - MaxRowsAtCompileTime, - MaxColsAtCompileTime> type; +// TODO(bomboze): un-#if this for both platforms once tested under Windows +/* This solution was extensively discussed here + http://forum.kde.org/viewtopic.php?f=74&t=61940 */ +# define SUM_OR_DYNAMIC(x, y) \ + (x == Eigen::Dynamic || y == Eigen::Dynamic) ? Eigen::Dynamic : (x + y) + +template <typename Derived1, typename Derived2> +struct hstack_return { + typedef typename Derived1::Scalar Scalar; + enum { + RowsAtCompileTime = Derived1::RowsAtCompileTime, + ColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::ColsAtCompileTime, + Derived2::ColsAtCompileTime), + Options = Derived1::Flags & Eigen::RowMajorBit ? Eigen::RowMajor : 0, + MaxRowsAtCompileTime = Derived1::MaxRowsAtCompileTime, + MaxColsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxColsAtCompileTime, + Derived2::MaxColsAtCompileTime) }; - - template<typename Derived1, typename Derived2> - typename hstack_return<Derived1, Derived2>::type - HStack(const Eigen::MatrixBase<Derived1>& lhs, - const Eigen::MatrixBase<Derived2>& rhs) { - typename hstack_return<Derived1, Derived2>::type res; - res.resize(lhs.rows(), lhs.cols()+rhs.cols()); - res << lhs, rhs; - return res; - }; - - - template<typename Derived1, typename Derived2> - struct vstack_return { - typedef typename Derived1::Scalar Scalar; - enum { - RowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::RowsAtCompileTime, - Derived2::RowsAtCompileTime), - ColsAtCompileTime = Derived1::ColsAtCompileTime, - Options = Derived1::Flags&Eigen::RowMajorBit ? Eigen::RowMajor : 0, - MaxRowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxRowsAtCompileTime, - Derived2::MaxRowsAtCompileTime), - MaxColsAtCompileTime = Derived1::MaxColsAtCompileTime - }; - typedef Eigen::Matrix<Scalar, - RowsAtCompileTime, - ColsAtCompileTime, - Options, - MaxRowsAtCompileTime, - MaxColsAtCompileTime> type; + typedef Eigen::Matrix<Scalar, + RowsAtCompileTime, + ColsAtCompileTime, + Options, + MaxRowsAtCompileTime, + MaxColsAtCompileTime> + type; +}; + +template <typename Derived1, typename Derived2> +typename hstack_return<Derived1, Derived2>::type HStack( + const Eigen::MatrixBase<Derived1>& lhs, + const Eigen::MatrixBase<Derived2>& rhs) { + typename hstack_return<Derived1, Derived2>::type res; + res.resize(lhs.rows(), lhs.cols() + rhs.cols()); + res << lhs, rhs; + return res; +}; + +template <typename Derived1, typename Derived2> +struct vstack_return { + typedef typename Derived1::Scalar Scalar; + enum { + RowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::RowsAtCompileTime, + Derived2::RowsAtCompileTime), + ColsAtCompileTime = Derived1::ColsAtCompileTime, + Options = Derived1::Flags & Eigen::RowMajorBit ? Eigen::RowMajor : 0, + MaxRowsAtCompileTime = SUM_OR_DYNAMIC(Derived1::MaxRowsAtCompileTime, + Derived2::MaxRowsAtCompileTime), + MaxColsAtCompileTime = Derived1::MaxColsAtCompileTime }; - - template<typename Derived1, typename Derived2> - typename vstack_return<Derived1, Derived2>::type - VStack(const Eigen::MatrixBase<Derived1>& lhs, - const Eigen::MatrixBase<Derived2>& rhs) { - typename vstack_return<Derived1, Derived2>::type res; - res.resize(lhs.rows()+rhs.rows(), lhs.cols()); - res << lhs, rhs; - return res; - }; - + typedef Eigen::Matrix<Scalar, + RowsAtCompileTime, + ColsAtCompileTime, + Options, + MaxRowsAtCompileTime, + MaxColsAtCompileTime> + type; +}; + +template <typename Derived1, typename Derived2> +typename vstack_return<Derived1, Derived2>::type VStack( + const Eigen::MatrixBase<Derived1>& lhs, + const Eigen::MatrixBase<Derived2>& rhs) { + typename vstack_return<Derived1, Derived2>::type res; + res.resize(lhs.rows() + rhs.rows(), lhs.cols()); + res << lhs, rhs; + return res; +}; #else // _WIN32 - // Since it is not possible to typedef privately here, use a macro. - // Always take dynamic columns if either side is dynamic. - #define COLS \ - ((ColsLeft == Eigen::Dynamic || ColsRight == Eigen::Dynamic) \ - ? Eigen::Dynamic : (ColsLeft + ColsRight)) - - // Same as above, except that prefer fixed size if either is fixed. - #define ROWS \ - ((RowsLeft == Eigen::Dynamic && RowsRight == Eigen::Dynamic) \ - ? Eigen::Dynamic \ - : ((RowsLeft == Eigen::Dynamic) \ - ? RowsRight \ - : RowsLeft \ - ) \ - ) - - // TODO(keir): Add a static assert if both rows are at compiletime. - template<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight> - Eigen::Matrix<T, ROWS, COLS> - HStack(const Eigen::Matrix<T, RowsLeft, ColsLeft> &left, - const Eigen::Matrix<T, RowsRight, ColsRight> &right) { - assert(left.rows() == right.rows()); - int n = left.rows(); - int m1 = left.cols(); - int m2 = right.cols(); - - Eigen::Matrix<T, ROWS, COLS> stacked(n, m1 + m2); - stacked.block(0, 0, n, m1) = left; - stacked.block(0, m1, n, m2) = right; - return stacked; - } - - // Reuse the above macros by swapping the order of Rows and Cols. Nasty, but - // the duplication is worse. - // TODO(keir): Add a static assert if both rows are at compiletime. - // TODO(keir): Mail eigen list about making this work for general expressions - // rather than only matrix types. - template<typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight> - Eigen::Matrix<T, COLS, ROWS> - VStack(const Eigen::Matrix<T, ColsLeft, RowsLeft> &top, - const Eigen::Matrix<T, ColsRight, RowsRight> &bottom) { - assert(top.cols() == bottom.cols()); - int n1 = top.rows(); - int n2 = bottom.rows(); - int m = top.cols(); - - Eigen::Matrix<T, COLS, ROWS> stacked(n1 + n2, m); - stacked.block(0, 0, n1, m) = top; - stacked.block(n1, 0, n2, m) = bottom; - return stacked; - } - #undef COLS - #undef ROWS -#endif // _WIN32 +// Since it is not possible to typedef privately here, use a macro. +// Always take dynamic columns if either side is dynamic. +# define COLS \ + ((ColsLeft == Eigen::Dynamic || ColsRight == Eigen::Dynamic) \ + ? Eigen::Dynamic \ + : (ColsLeft + ColsRight)) + +// Same as above, except that prefer fixed size if either is fixed. +# define ROWS \ + ((RowsLeft == Eigen::Dynamic && RowsRight == Eigen::Dynamic) \ + ? Eigen::Dynamic \ + : ((RowsLeft == Eigen::Dynamic) ? RowsRight : RowsLeft)) + +// TODO(keir): Add a static assert if both rows are at compiletime. +template <typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight> +Eigen::Matrix<T, ROWS, COLS> HStack( + const Eigen::Matrix<T, RowsLeft, ColsLeft>& left, + const Eigen::Matrix<T, RowsRight, ColsRight>& right) { + assert(left.rows() == right.rows()); + int n = left.rows(); + int m1 = left.cols(); + int m2 = right.cols(); + + Eigen::Matrix<T, ROWS, COLS> stacked(n, m1 + m2); + stacked.block(0, 0, n, m1) = left; + stacked.block(0, m1, n, m2) = right; + return stacked; +} +// Reuse the above macros by swapping the order of Rows and Cols. Nasty, but +// the duplication is worse. +// TODO(keir): Add a static assert if both rows are at compiletime. +// TODO(keir): Mail eigen list about making this work for general expressions +// rather than only matrix types. +template <typename T, int RowsLeft, int RowsRight, int ColsLeft, int ColsRight> +Eigen::Matrix<T, COLS, ROWS> VStack( + const Eigen::Matrix<T, ColsLeft, RowsLeft>& top, + const Eigen::Matrix<T, ColsRight, RowsRight>& bottom) { + assert(top.cols() == bottom.cols()); + int n1 = top.rows(); + int n2 = bottom.rows(); + int m = top.cols(); + Eigen::Matrix<T, COLS, ROWS> stacked(n1 + n2, m); + stacked.block(0, 0, n1, m) = top; + stacked.block(n1, 0, n2, m) = bottom; + return stacked; +} +# undef COLS +# undef ROWS +#endif // _WIN32 -void HorizontalStack(const Mat &left, const Mat &right, Mat *stacked); +void HorizontalStack(const Mat& left, const Mat& right, Mat* stacked); -template<typename TTop, typename TBot, typename TStacked> -void VerticalStack(const TTop &top, const TBot &bottom, TStacked *stacked) { +template <typename TTop, typename TBot, typename TStacked> +void VerticalStack(const TTop& top, const TBot& bottom, TStacked* stacked) { assert(top.cols() == bottom.cols()); int n1 = top.rows(); int n2 = bottom.rows(); int m = top.cols(); stacked->resize(n1 + n2, m); - stacked->block(0, 0, n1, m) = top; + stacked->block(0, 0, n1, m) = top; stacked->block(n1, 0, n2, m) = bottom; } -void MatrixColumn(const Mat &A, int i, Vec2 *v); -void MatrixColumn(const Mat &A, int i, Vec3 *v); -void MatrixColumn(const Mat &A, int i, Vec4 *v); +void MatrixColumn(const Mat& A, int i, Vec2* v); +void MatrixColumn(const Mat& A, int i, Vec3* v); +void MatrixColumn(const Mat& A, int i, Vec4* v); template <typename TMat, typename TCols> -TMat ExtractColumns(const TMat &A, const TCols &columns) { +TMat ExtractColumns(const TMat& A, const TCols& columns) { TMat compressed(A.rows(), columns.size()); for (int i = 0; i < columns.size(); ++i) { compressed.col(i) = A.col(columns[i]); @@ -445,12 +438,12 @@ TMat ExtractColumns(const TMat &A, const TCols &columns) { } template <typename TMat, typename TDest> -void reshape(const TMat &a, int rows, int cols, TDest *b) { - assert(a.rows()*a.cols() == rows*cols); +void reshape(const TMat& a, int rows, int cols, TDest* b) { + assert(a.rows() * a.cols() == rows * cols); b->resize(rows, cols); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { - (*b)(i, j) = a[cols*i + j]; + (*b)(i, j) = a[cols * i + j]; } } } @@ -467,24 +460,21 @@ inline bool isnan(double i) { /// and negative values template <typename FloatType> FloatType ceil0(const FloatType& value) { - FloatType result = std::ceil(std::fabs(value)); - return (value < 0.0) ? -result : result; + FloatType result = std::ceil(std::fabs(value)); + return (value < 0.0) ? -result : result; } /// Returns the skew anti-symmetric matrix of a vector -inline Mat3 SkewMat(const Vec3 &x) { +inline Mat3 SkewMat(const Vec3& x) { Mat3 skew; - skew << 0 , -x(2), x(1), - x(2), 0 , -x(0), - -x(1), x(0), 0; + skew << 0, -x(2), x(1), x(2), 0, -x(0), -x(1), x(0), 0; return skew; } /// Returns the skew anti-symmetric matrix of a vector with only /// the first two (independent) lines -inline Mat23 SkewMatMinimal(const Vec2 &x) { +inline Mat23 SkewMatMinimal(const Vec2& x) { Mat23 skew; - skew << 0, -1, x(1), - 1, 0, -x(0); + skew << 0, -1, x(1), 1, 0, -x(0); return skew; } @@ -496,7 +486,8 @@ inline Mat3 RotationFromEulerVector(Vec3 euler_vector) { } Vec3 w = euler_vector / theta; Mat3 w_hat = CrossProductMatrix(w); - return Mat3::Identity() + w_hat*sin(theta) + w_hat*w_hat*(1 - cos(theta)); + return Mat3::Identity() + w_hat * sin(theta) + + w_hat * w_hat * (1 - cos(theta)); } } // namespace libmv diff --git a/intern/libmv/libmv/numeric/numeric_test.cc b/intern/libmv/libmv/numeric/numeric_test.cc index 0cdfaf33ab2..b2650a04658 100644 --- a/intern/libmv/libmv/numeric/numeric_test.cc +++ b/intern/libmv/libmv/numeric/numeric_test.cc @@ -27,9 +27,11 @@ namespace { TEST(Numeric, DynamicSizedNullspace) { Mat A(3, 4); + // clang-format off A << 0.76026643, 0.01799744, 0.55192142, 0.8699745, 0.42016166, 0.97863392, 0.33711682, 0.14479271, 0.51016811, 0.66528302, 0.54395496, 0.57794893; + // clang-format on Vec x; double s = Nullspace(&A, &x); EXPECT_NEAR(0.0, s, 1e-15); @@ -39,9 +41,11 @@ TEST(Numeric, DynamicSizedNullspace) { TEST(Numeric, FixedSizeMatrixNullspace) { Mat34 A; + // clang-format off A << 0.76026643, 0.01799744, 0.55192142, 0.8699745, 0.42016166, 0.97863392, 0.33711682, 0.14479271, 0.51016811, 0.66528302, 0.54395496, 0.57794893; + // clang-format on Vec x; double s = Nullspace(&A, &x); EXPECT_NEAR(0.0, s, 1e-15); @@ -51,10 +55,12 @@ TEST(Numeric, FixedSizeMatrixNullspace) { TEST(Numeric, NullspaceMatchesLapackSVD) { Mat43 A; + // clang-format off A << 0.76026643, 0.01799744, 0.55192142, 0.8699745, 0.42016166, 0.97863392, 0.33711682, 0.14479271, 0.51016811, 0.66528302, 0.54395496, 0.57794893; + // clang-format on Vec x; double s = Nullspace(&A, &x); EXPECT_NEAR(1.0, x.norm(), 1e-15); @@ -68,10 +74,12 @@ TEST(Numeric, NullspaceMatchesLapackSVD) { TEST(Numeric, Nullspace2) { Mat43 A; + // clang-format off A << 0.76026643, 0.01799744, 0.55192142, 0.8699745, 0.42016166, 0.97863392, 0.33711682, 0.14479271, 0.51016811, 0.66528302, 0.54395496, 0.57794893; + // clang-format on Vec3 x1, x2; double s = Nullspace2(&A, &x1, &x2); EXPECT_NEAR(1.0, x1.norm(), 1e-15); @@ -80,14 +88,14 @@ TEST(Numeric, Nullspace2) { EXPECT_NEAR(-0.64999717, x1(0), 1e-8); EXPECT_NEAR(-0.18452646, x1(1), 1e-8); - EXPECT_NEAR( 0.7371931, x1(2), 1e-8); + EXPECT_NEAR(0.7371931, x1(2), 1e-8); if (x2(0) < 0) { x2 *= -1; } - EXPECT_NEAR( 0.34679618, x2(0), 1e-8); + EXPECT_NEAR(0.34679618, x2(0), 1e-8); EXPECT_NEAR(-0.93519689, x2(1), 1e-8); - EXPECT_NEAR( 0.07168809, x2(2), 1e-8); + EXPECT_NEAR(0.07168809, x2(2), 1e-8); } TEST(Numeric, TinyMatrixSquareTranspose) { @@ -105,8 +113,8 @@ TEST(Numeric, NormalizeL1) { x << 1, 2; double l1 = NormalizeL1(&x); EXPECT_DOUBLE_EQ(3., l1); - EXPECT_DOUBLE_EQ(1./3., x(0)); - EXPECT_DOUBLE_EQ(2./3., x(1)); + EXPECT_DOUBLE_EQ(1. / 3., x(0)); + EXPECT_DOUBLE_EQ(2. / 3., x(1)); } TEST(Numeric, NormalizeL2) { @@ -114,8 +122,8 @@ TEST(Numeric, NormalizeL2) { x << 1, 2; double l2 = NormalizeL2(&x); EXPECT_DOUBLE_EQ(sqrt(5.0), l2); - EXPECT_DOUBLE_EQ(1./sqrt(5.), x(0)); - EXPECT_DOUBLE_EQ(2./sqrt(5.), x(1)); + EXPECT_DOUBLE_EQ(1. / sqrt(5.), x(0)); + EXPECT_DOUBLE_EQ(2. / sqrt(5.), x(1)); } TEST(Numeric, Diag) { @@ -130,31 +138,32 @@ TEST(Numeric, Diag) { TEST(Numeric, Determinant) { Mat A(2, 2); - A << 1, 2, - -1, 3; + A << 1, 2, -1, 3; double detA = A.determinant(); EXPECT_NEAR(5, detA, 1e-8); Mat B(4, 4); + // clang-format off B << 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15; + // clang-format on double detB = B.determinant(); EXPECT_NEAR(0, detB, 1e-8); Mat3 C; - C << 0, 1, 2, - 3, 4, 5, - 6, 7, 1; + C << 0, 1, 2, 3, 4, 5, 6, 7, 1; double detC = C.determinant(); EXPECT_NEAR(21, detC, 1e-8); } TEST(Numeric, Inverse) { Mat A(2, 2), A1; + // clang-format off A << 1, 2, -1, 3; + // clang-format on Mat I = A * A.inverse(); EXPECT_NEAR(1, I(0, 0), 1e-8); @@ -163,10 +172,12 @@ TEST(Numeric, Inverse) { EXPECT_NEAR(1, I(1, 1), 1e-8); Mat B(4, 4), B1; + // clang-format off B << 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 2, 11, 12, 13, 14, 4; + // clang-format on Mat I2 = B * B.inverse(); EXPECT_NEAR(1, I2(0, 0), 1e-8); EXPECT_NEAR(0, I2(0, 1), 1e-8); @@ -182,8 +193,10 @@ TEST(Numeric, Inverse) { TEST(Numeric, MeanAndVarianceAlongRows) { int n = 4; Mat points(2, n); + // clang-format off points << 0, 0, 1, 1, 0, 2, 1, 3; + // clang-format on Vec mean, variance; MeanAndVarianceAlongRows(points, &mean, &variance); @@ -213,15 +226,17 @@ TEST(Numeric, HStack) { Mat x(2, 1), y(2, 1), z(2, 2); x << 1, 2; y << 3, 4; + // clang-format off z << 1, 3, 2, 4; + // clang-format on Vec2 xC = x, yC = y; - Mat2 xy = HStack(x, y); + Mat2 xy = HStack(x, y); EXPECT_MATRIX_EQ(z, xy); - EXPECT_MATRIX_EQ(z, HStack(x, y)); - EXPECT_MATRIX_EQ(z, HStack(x, yC)); + EXPECT_MATRIX_EQ(z, HStack(x, y)); + EXPECT_MATRIX_EQ(z, HStack(x, yC)); EXPECT_MATRIX_EQ(z, HStack(xC, y)); EXPECT_MATRIX_EQ(z, HStack(xC, yC)); } @@ -230,6 +245,7 @@ TEST(Numeric, HStack) { // resulting stacked matrices properly propagate the fixed dimensions. TEST(Numeric, VStack) { Mat x(2, 2), y(2, 2), z(4, 2); + // clang-format off x << 1, 2, 3, 4; y << 10, 20, @@ -238,13 +254,14 @@ TEST(Numeric, VStack) { 3, 4, 10, 20, 30, 40; + // clang-format on Mat2 xC = x, yC = y; - Mat xy = VStack(x, y); + Mat xy = VStack(x, y); EXPECT_MATRIX_EQ(z, xy); - EXPECT_MATRIX_EQ(z, VStack(x, y)); - EXPECT_MATRIX_EQ(z, VStack(x, yC)); + EXPECT_MATRIX_EQ(z, VStack(x, y)); + EXPECT_MATRIX_EQ(z, VStack(x, yC)); EXPECT_MATRIX_EQ(z, VStack(xC, y)); EXPECT_MATRIX_EQ(z, VStack(xC, yC)); } @@ -293,17 +310,21 @@ TEST(Numeric, CrossProductMatrix) { TEST(Numeric, MatrixColumn) { Mat A2(2, 3); Vec2 v2; + // clang-format off A2 << 1, 2, 3, 4, 5, 6; + // clang-format on MatrixColumn(A2, 1, &v2); EXPECT_EQ(2, v2(0)); EXPECT_EQ(5, v2(1)); Mat A3(3, 3); Vec3 v3; + // clang-format off A3 << 1, 2, 3, 4, 5, 6, 7, 8, 9; + // clang-format on MatrixColumn(A3, 1, &v3); EXPECT_EQ(2, v3(0)); EXPECT_EQ(5, v3(1)); @@ -311,14 +332,16 @@ TEST(Numeric, MatrixColumn) { Mat A4(4, 3); Vec4 v4; + // clang-format off A4 << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12; + // clang-format on MatrixColumn(A4, 1, &v4); - EXPECT_EQ( 2, v4(0)); - EXPECT_EQ( 5, v4(1)); - EXPECT_EQ( 8, v4(2)); + EXPECT_EQ(2, v4(0)); + EXPECT_EQ(5, v4(1)); + EXPECT_EQ(8, v4(2)); EXPECT_EQ(11, v4(3)); } @@ -337,7 +360,8 @@ TEST(Numeric, Mat3MatProduct) { // This gives a compile error. TEST(Numeric, Vec3Negative) { - Vec3 y; y << 1, 2, 3; + Vec3 y; + y << 1, 2, 3; Vec3 x = -y; EXPECT_EQ(-1, x(0)); EXPECT_EQ(-2, x(1)); @@ -357,19 +381,23 @@ TEST(Numeric, Vec3VecInteroperability) { // This segfaults inside lapack. TEST(Numeric, DeterminantLU7) { Mat A(5, 5); + // clang-format off A << 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1; + // clang-format on EXPECT_NEAR(1, A.determinant(), 1e-8); } // This segfaults inside lapack. TEST(Numeric, DeterminantLU) { Mat A(2, 2); + // clang-format off A << 1, 2, -1, 3; + // clang-format on EXPECT_NEAR(5, A.determinant(), 1e-8); } @@ -377,19 +405,24 @@ TEST(Numeric, DeterminantLU) { // Keir: Not with eigen2! TEST(Numeric, InplaceProduct) { Mat2 K, S; + // clang-format off K << 1, 0, 0, 1; S << 1, 0, 0, 1; K = K * S; + // clang-format on EXPECT_MATRIX_NEAR(Mat2::Identity(), K, 1e-8); } TEST(Numeric, ExtractColumns) { Mat2X A(2, 5); + // clang-format off A << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; - Vec2i columns; columns << 0, 2; + // clang-format on + Vec2i columns; + columns << 0, 2; Mat2X extracted = ExtractColumns(A, columns); EXPECT_NEAR(1, extracted(0, 0), 1e-15); EXPECT_NEAR(3, extracted(0, 1), 1e-15); @@ -418,21 +451,22 @@ TEST(Numeric, RotationRodrigues) { TEST(Numeric, LookAt) { // Simple orthogonality check. - Vec3 e; e << 1, 2, 3; + Vec3 e; + e << 1, 2, 3; Mat3 R = LookAt(e), I = Mat3::Identity(); - Mat3 RRT = R*R.transpose(); - Mat3 RTR = R.transpose()*R; + Mat3 RRT = R * R.transpose(); + Mat3 RTR = R.transpose() * R; EXPECT_MATRIX_NEAR(I, RRT, 1e-15); EXPECT_MATRIX_NEAR(I, RTR, 1e-15); } TEST(Numeric, Reshape) { - Vec4 x; x << 1, 2, 3, 4; + Vec4 x; + x << 1, 2, 3, 4; Mat2 M, M_expected; reshape(x, 2, 2, &M); - M_expected << 1, 2, - 3, 4; + M_expected << 1, 2, 3, 4; EXPECT_MATRIX_NEAR(M_expected, M, 1e-15); } diff --git a/intern/libmv/libmv/numeric/poly.h b/intern/libmv/libmv/numeric/poly.h index 76ba062d475..a3d3801a399 100644 --- a/intern/libmv/libmv/numeric/poly.h +++ b/intern/libmv/libmv/numeric/poly.h @@ -21,8 +21,8 @@ #ifndef LIBMV_NUMERIC_POLY_H_ #define LIBMV_NUMERIC_POLY_H_ -#include <cmath> #include <stdio.h> +#include <cmath> namespace libmv { @@ -35,9 +35,8 @@ namespace libmv { // if there are 2 roots, only x0 and x1 are set. // // The GSL cubic solver was used as a reference for this routine. -template<typename Real> -int SolveCubicPolynomial(Real a, Real b, Real c, - Real *x0, Real *x1, Real *x2) { +template <typename Real> +int SolveCubicPolynomial(Real a, Real b, Real c, Real* x0, Real* x1, Real* x2) { Real q = a * a - 3 * b; Real r = 2 * a * a * a - 9 * a * b + 27 * c; @@ -65,12 +64,12 @@ int SolveCubicPolynomial(Real a, Real b, Real c, Real sqrtQ = sqrt(Q); if (R > 0) { *x0 = -2 * sqrtQ - a / 3; - *x1 = sqrtQ - a / 3; - *x2 = sqrtQ - a / 3; + *x1 = sqrtQ - a / 3; + *x2 = sqrtQ - a / 3; } else { - *x0 = -sqrtQ - a / 3; - *x1 = -sqrtQ - a / 3; - *x2 = 2 * sqrtQ - a / 3; + *x0 = -sqrtQ - a / 3; + *x1 = -sqrtQ - a / 3; + *x2 = 2 * sqrtQ - a / 3; } return 3; @@ -97,15 +96,15 @@ int SolveCubicPolynomial(Real a, Real b, Real c, return 3; } Real sgnR = (R >= 0 ? 1 : -1); - Real A = -sgnR * pow(fabs(R) + sqrt(R2 - Q3), 1.0/3.0); + Real A = -sgnR * pow(fabs(R) + sqrt(R2 - Q3), 1.0 / 3.0); Real B = Q / A; *x0 = A + B - a / 3; return 1; } // The coefficients are in ascending powers, i.e. coeffs[N]*x^N. -template<typename Real> -int SolveCubicPolynomial(const Real *coeffs, Real *solutions) { +template <typename Real> +int SolveCubicPolynomial(const Real* coeffs, Real* solutions) { if (coeffs[0] == 0.0) { // TODO(keir): This is a quadratic not a cubic. Implement a quadratic // solver! @@ -114,10 +113,8 @@ int SolveCubicPolynomial(const Real *coeffs, Real *solutions) { Real a = coeffs[2] / coeffs[3]; Real b = coeffs[1] / coeffs[3]; Real c = coeffs[0] / coeffs[3]; - return SolveCubicPolynomial(a, b, c, - solutions + 0, - solutions + 1, - solutions + 2); + return SolveCubicPolynomial( + a, b, c, solutions + 0, solutions + 1, solutions + 2); } } // namespace libmv #endif // LIBMV_NUMERIC_POLY_H_ diff --git a/intern/libmv/libmv/numeric/poly_test.cc b/intern/libmv/libmv/numeric/poly_test.cc index 69f887b416c..cb85c068468 100644 --- a/intern/libmv/libmv/numeric/poly_test.cc +++ b/intern/libmv/libmv/numeric/poly_test.cc @@ -18,8 +18,8 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. -#include "libmv/numeric/numeric.h" #include "libmv/numeric/poly.h" +#include "libmv/numeric/numeric.h" #include "testing/testing.h" using namespace libmv; @@ -34,8 +34,8 @@ namespace { // // x^3 - (c+b+a) * x^2 + (a*b+(b+a)*c) * x - a*b*c = 0. // = p = q = r -void CoeffsForCubicZeros(double a, double b, double c, - double *p, double *q, double *r) { +void CoeffsForCubicZeros( + double a, double b, double c, double* p, double* q, double* r) { *p = -(c + b + a); *q = (a * b + (b + a) * c); *r = -a * b * c; @@ -45,35 +45,45 @@ TEST(Poly, SolveCubicPolynomial) { double a, b, c, aa, bb, cc; double p, q, r; - a = 1; b = 2; c = 3; + a = 1; + b = 2; + c = 3; CoeffsForCubicZeros(a, b, c, &p, &q, &r); ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); EXPECT_NEAR(a, aa, 1e-10); EXPECT_NEAR(b, bb, 1e-10); EXPECT_NEAR(c, cc, 1e-10); - a = 0; b = 1; c = 3; + a = 0; + b = 1; + c = 3; CoeffsForCubicZeros(a, b, c, &p, &q, &r); ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); EXPECT_NEAR(a, aa, 1e-10); EXPECT_NEAR(b, bb, 1e-10); EXPECT_NEAR(c, cc, 1e-10); - a = -10; b = 0; c = 1; + a = -10; + b = 0; + c = 1; CoeffsForCubicZeros(a, b, c, &p, &q, &r); ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); EXPECT_NEAR(a, aa, 1e-10); EXPECT_NEAR(b, bb, 1e-10); EXPECT_NEAR(c, cc, 1e-10); - a = -8; b = 1; c = 3; + a = -8; + b = 1; + c = 3; CoeffsForCubicZeros(a, b, c, &p, &q, &r); ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); EXPECT_NEAR(a, aa, 1e-10); EXPECT_NEAR(b, bb, 1e-10); EXPECT_NEAR(c, cc, 1e-10); - a = 28; b = 28; c = 105; + a = 28; + b = 28; + c = 105; CoeffsForCubicZeros(a, b, c, &p, &q, &r); ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc)); EXPECT_NEAR(a, aa, 1e-10); diff --git a/intern/libmv/libmv/simple_pipeline/bundle.cc b/intern/libmv/libmv/simple_pipeline/bundle.cc index d62f0ebe94f..e86c3bca57f 100644 --- a/intern/libmv/libmv/simple_pipeline/bundle.cc +++ b/intern/libmv/libmv/simple_pipeline/bundle.cc @@ -32,16 +32,16 @@ #include "libmv/multiview/projection.h" #include "libmv/numeric/numeric.h" #include "libmv/simple_pipeline/camera_intrinsics.h" -#include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/distortion_models.h" #include "libmv/simple_pipeline/packed_intrinsics.h" +#include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { namespace { -bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics *intrinsics) { +bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics* intrinsics) { const DistortionModelType distortion_model = intrinsics->GetDistortionModelType(); return (distortion_model == DISTORTION_MODEL_NUKE); @@ -59,12 +59,14 @@ bool NeedUseInvertIntrinsicsPipeline(const CameraIntrinsics *intrinsics) { // The invariant_intrinsics are used to access intrinsics which are never // packed into parameter block: for example, distortion model type and image // dimension. -template<typename T> +template <typename T> void ApplyDistortionModelUsingIntrinsicsBlock( - const CameraIntrinsics *invariant_intrinsics, + const CameraIntrinsics* invariant_intrinsics, const T* const intrinsics_block, - const T& normalized_x, const T& normalized_y, - T* distorted_x, T* distorted_y) { + const T& normalized_x, + const T& normalized_y, + T* distorted_x, + T* distorted_y) { // Unpack the intrinsics. const T& focal_length = intrinsics_block[PackedIntrinsics::OFFSET_FOCAL_LENGTH]; @@ -76,65 +78,75 @@ void ApplyDistortionModelUsingIntrinsicsBlock( // TODO(keir): Do early bailouts for zero distortion; these are expensive // jet operations. switch (invariant_intrinsics->GetDistortionModelType()) { - case DISTORTION_MODEL_POLYNOMIAL: - { - const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; - const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; - const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3]; - const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1]; - const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2]; - - ApplyPolynomialDistortionModel(focal_length, - focal_length, - principal_point_x, - principal_point_y, - k1, k2, k3, - p1, p2, - normalized_x, normalized_y, - distorted_x, distorted_y); - return; - } - - case DISTORTION_MODEL_DIVISION: - { - const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; - const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; - - ApplyDivisionDistortionModel(focal_length, + case DISTORTION_MODEL_POLYNOMIAL: { + const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; + const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; + const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3]; + const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1]; + const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2]; + + ApplyPolynomialDistortionModel(focal_length, focal_length, principal_point_x, principal_point_y, - k1, k2, - normalized_x, normalized_y, - distorted_x, distorted_y); - return; - } + k1, + k2, + k3, + p1, + p2, + normalized_x, + normalized_y, + distorted_x, + distorted_y); + return; + } - case DISTORTION_MODEL_NUKE: - { - LOG(FATAL) << "Unsupported distortion model."; - return; - } + case DISTORTION_MODEL_DIVISION: { + const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; + const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; + + ApplyDivisionDistortionModel(focal_length, + focal_length, + principal_point_x, + principal_point_y, + k1, + k2, + normalized_x, + normalized_y, + distorted_x, + distorted_y); + return; + } - case DISTORTION_MODEL_BROWN: - { - const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; - const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; - const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3]; - const T& k4 = intrinsics_block[PackedIntrinsics::OFFSET_K4]; - const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1]; - const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2]; - - ApplyBrownDistortionModel(focal_length, - focal_length, - principal_point_x, - principal_point_y, - k1, k2, k3, k4, - p1, p2, - normalized_x, normalized_y, - distorted_x, distorted_y); - return; - } + case DISTORTION_MODEL_NUKE: { + LOG(FATAL) << "Unsupported distortion model."; + return; + } + + case DISTORTION_MODEL_BROWN: { + const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; + const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; + const T& k3 = intrinsics_block[PackedIntrinsics::OFFSET_K3]; + const T& k4 = intrinsics_block[PackedIntrinsics::OFFSET_K4]; + const T& p1 = intrinsics_block[PackedIntrinsics::OFFSET_P1]; + const T& p2 = intrinsics_block[PackedIntrinsics::OFFSET_P2]; + + ApplyBrownDistortionModel(focal_length, + focal_length, + principal_point_x, + principal_point_y, + k1, + k2, + k3, + k4, + p1, + p2, + normalized_x, + normalized_y, + distorted_x, + distorted_y); + return; + } } LOG(FATAL) << "Unknown distortion model."; @@ -152,12 +164,14 @@ void ApplyDistortionModelUsingIntrinsicsBlock( // The invariant_intrinsics are used to access intrinsics which are never // packed into parameter block: for example, distortion model type and image // dimension. -template<typename T> +template <typename T> void InvertDistortionModelUsingIntrinsicsBlock( - const CameraIntrinsics *invariant_intrinsics, + const CameraIntrinsics* invariant_intrinsics, const T* const intrinsics_block, - const T& image_x, const T& image_y, - T* normalized_x, T* normalized_y) { + const T& image_x, + const T& image_y, + T* normalized_x, + T* normalized_y) { // Unpack the intrinsics. const T& focal_length = intrinsics_block[PackedIntrinsics::OFFSET_FOCAL_LENGTH]; @@ -175,31 +189,35 @@ void InvertDistortionModelUsingIntrinsicsBlock( LOG(FATAL) << "Unsupported distortion model."; return; - case DISTORTION_MODEL_NUKE: - { - const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; - const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; - - InvertNukeDistortionModel(focal_length, - focal_length, - principal_point_x, - principal_point_y, - invariant_intrinsics->image_width(), - invariant_intrinsics->image_height(), - k1, k2, - image_x, image_y, - normalized_x, normalized_y); - return; - } + case DISTORTION_MODEL_NUKE: { + const T& k1 = intrinsics_block[PackedIntrinsics::OFFSET_K1]; + const T& k2 = intrinsics_block[PackedIntrinsics::OFFSET_K2]; + + InvertNukeDistortionModel(focal_length, + focal_length, + principal_point_x, + principal_point_y, + invariant_intrinsics->image_width(), + invariant_intrinsics->image_height(), + k1, + k2, + image_x, + image_y, + normalized_x, + normalized_y); + return; + } } LOG(FATAL) << "Unknown distortion model."; } -template<typename T> +template <typename T> void NormalizedToImageSpace(const T* const intrinsics_block, - const T& normalized_x, const T& normalized_y, - T* image_x, T* image_y) { + const T& normalized_x, + const T& normalized_y, + T* image_x, + T* image_y) { // Unpack the intrinsics. const T& focal_length = intrinsics_block[PackedIntrinsics::OFFSET_FOCAL_LENGTH]; @@ -219,11 +237,10 @@ void NormalizedToImageSpace(const T* const intrinsics_block, // This functor can only be used for distortion models which have analytically // defined Apply() function. struct ReprojectionErrorApplyIntrinsics { - ReprojectionErrorApplyIntrinsics( - const CameraIntrinsics *invariant_intrinsics, - const double observed_distorted_x, - const double observed_distorted_y, - const double weight) + ReprojectionErrorApplyIntrinsics(const CameraIntrinsics* invariant_intrinsics, + const double observed_distorted_x, + const double observed_distorted_y, + const double weight) : invariant_intrinsics_(invariant_intrinsics), observed_distorted_x_(observed_distorted_x), observed_distorted_y_(observed_distorted_y), @@ -253,11 +270,12 @@ struct ReprojectionErrorApplyIntrinsics { T yn = x[1] / x[2]; T predicted_distorted_x, predicted_distorted_y; - ApplyDistortionModelUsingIntrinsicsBlock( - invariant_intrinsics_, - intrinsics, - xn, yn, - &predicted_distorted_x, &predicted_distorted_y); + ApplyDistortionModelUsingIntrinsicsBlock(invariant_intrinsics_, + intrinsics, + xn, + yn, + &predicted_distorted_x, + &predicted_distorted_y); // The error is the difference between the predicted and observed position. residuals[0] = (predicted_distorted_x - T(observed_distorted_x_)) * weight_; @@ -265,7 +283,7 @@ struct ReprojectionErrorApplyIntrinsics { return true; } - const CameraIntrinsics *invariant_intrinsics_; + const CameraIntrinsics* invariant_intrinsics_; const double observed_distorted_x_; const double observed_distorted_y_; const double weight_; @@ -279,7 +297,7 @@ struct ReprojectionErrorApplyIntrinsics { // defined Invert() function. struct ReprojectionErrorInvertIntrinsics { ReprojectionErrorInvertIntrinsics( - const CameraIntrinsics *invariant_intrinsics, + const CameraIntrinsics* invariant_intrinsics, const double observed_distorted_x, const double observed_distorted_y, const double weight) @@ -295,8 +313,7 @@ struct ReprojectionErrorInvertIntrinsics { const T* const X, // Point coordinates 3x1. T* residuals) const { // Unpack the intrinsics. - const T& focal_length = - intrinsics[PackedIntrinsics::OFFSET_FOCAL_LENGTH]; + const T& focal_length = intrinsics[PackedIntrinsics::OFFSET_FOCAL_LENGTH]; const T& principal_point_x = intrinsics[PackedIntrinsics::OFFSET_PRINCIPAL_POINT_X]; const T& principal_point_y = @@ -327,14 +344,17 @@ struct ReprojectionErrorInvertIntrinsics { InvertDistortionModelUsingIntrinsicsBlock( invariant_intrinsics_, intrinsics, - T(observed_distorted_x_), T(observed_distorted_y_), - &observed_undistorted_normalized_x, &observed_undistorted_normalized_y); + T(observed_distorted_x_), + T(observed_distorted_y_), + &observed_undistorted_normalized_x, + &observed_undistorted_normalized_y); T observed_undistorted_image_x, observed_undistorted_image_y; - NormalizedToImageSpace( - intrinsics, - observed_undistorted_normalized_x, observed_undistorted_normalized_y, - &observed_undistorted_image_x, &observed_undistorted_image_y); + NormalizedToImageSpace(intrinsics, + observed_undistorted_normalized_x, + observed_undistorted_normalized_y, + &observed_undistorted_image_x, + &observed_undistorted_image_y); // The error is the difference between the predicted and observed position. residuals[0] = (predicted_x - observed_undistorted_image_x) * weight_; @@ -343,7 +363,7 @@ struct ReprojectionErrorInvertIntrinsics { return true; } - const CameraIntrinsics *invariant_intrinsics_; + const CameraIntrinsics* invariant_intrinsics_; const double observed_distorted_x_; const double observed_distorted_y_; const double weight_; @@ -352,28 +372,29 @@ struct ReprojectionErrorInvertIntrinsics { // Print a message to the log which camera intrinsics are gonna to be optimized. void BundleIntrinsicsLogMessage(const int bundle_intrinsics) { if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) { - LOG(INFO) << "Bundling only camera positions."; + LG << "Bundling only camera positions."; } else { std::string bundling_message = ""; -#define APPEND_BUNDLING_INTRINSICS(name, flag) \ - if (bundle_intrinsics & flag) { \ - if (!bundling_message.empty()) { \ - bundling_message += ", "; \ - } \ - bundling_message += name; \ - } (void)0 +#define APPEND_BUNDLING_INTRINSICS(name, flag) \ + if (bundle_intrinsics & flag) { \ + if (!bundling_message.empty()) { \ + bundling_message += ", "; \ + } \ + bundling_message += name; \ + } \ + (void)0 - APPEND_BUNDLING_INTRINSICS("f", BUNDLE_FOCAL_LENGTH); + APPEND_BUNDLING_INTRINSICS("f", BUNDLE_FOCAL_LENGTH); APPEND_BUNDLING_INTRINSICS("px, py", BUNDLE_PRINCIPAL_POINT); - APPEND_BUNDLING_INTRINSICS("k1", BUNDLE_RADIAL_K1); - APPEND_BUNDLING_INTRINSICS("k2", BUNDLE_RADIAL_K2); - APPEND_BUNDLING_INTRINSICS("k3", BUNDLE_RADIAL_K3); - APPEND_BUNDLING_INTRINSICS("k4", BUNDLE_RADIAL_K4); - APPEND_BUNDLING_INTRINSICS("p1", BUNDLE_TANGENTIAL_P1); - APPEND_BUNDLING_INTRINSICS("p2", BUNDLE_TANGENTIAL_P2); - - LOG(INFO) << "Bundling " << bundling_message << "."; + APPEND_BUNDLING_INTRINSICS("k1", BUNDLE_RADIAL_K1); + APPEND_BUNDLING_INTRINSICS("k2", BUNDLE_RADIAL_K2); + APPEND_BUNDLING_INTRINSICS("k3", BUNDLE_RADIAL_K3); + APPEND_BUNDLING_INTRINSICS("k4", BUNDLE_RADIAL_K4); + APPEND_BUNDLING_INTRINSICS("p1", BUNDLE_TANGENTIAL_P1); + APPEND_BUNDLING_INTRINSICS("p2", BUNDLE_TANGENTIAL_P2); + + LG << "Bundling " << bundling_message << "."; } } @@ -383,7 +404,7 @@ void BundleIntrinsicsLogMessage(const int bundle_intrinsics) { // Element with key i matches to a rotation+translation for // camera at image i. map<int, Vec6> PackCamerasRotationAndTranslation( - const EuclideanReconstruction &reconstruction) { + const EuclideanReconstruction& reconstruction) { map<int, Vec6> all_cameras_R_t; vector<EuclideanCamera> all_cameras = reconstruction.AllCameras(); @@ -399,14 +420,13 @@ map<int, Vec6> PackCamerasRotationAndTranslation( // Convert cameras rotations fro mangle axis back to rotation matrix. void UnpackCamerasRotationAndTranslation( - const map<int, Vec6> &all_cameras_R_t, - EuclideanReconstruction *reconstruction) { - + const map<int, Vec6>& all_cameras_R_t, + EuclideanReconstruction* reconstruction) { for (map<int, Vec6>::value_type image_and_camera_R_T : all_cameras_R_t) { const int image = image_and_camera_R_T.first; const Vec6& camera_R_t = image_and_camera_R_T.second; - EuclideanCamera *camera = reconstruction->CameraForImage(image); + EuclideanCamera* camera = reconstruction->CameraForImage(image); if (!camera) { continue; } @@ -421,8 +441,8 @@ void UnpackCamerasRotationAndTranslation( // // TODO(sergey): currently uses dense Eigen matrices, best would // be to use sparse Eigen matrices -void CRSMatrixToEigenMatrix(const ceres::CRSMatrix &crs_matrix, - Mat *eigen_matrix) { +void CRSMatrixToEigenMatrix(const ceres::CRSMatrix& crs_matrix, + Mat* eigen_matrix) { eigen_matrix->resize(crs_matrix.num_rows, crs_matrix.num_cols); eigen_matrix->setZero(); @@ -439,11 +459,11 @@ void CRSMatrixToEigenMatrix(const ceres::CRSMatrix &crs_matrix, } } -void EuclideanBundlerPerformEvaluation(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - map<int, Vec6> *all_cameras_R_t, - ceres::Problem *problem, - BundleEvaluation *evaluation) { +void EuclideanBundlerPerformEvaluation(const Tracks& tracks, + EuclideanReconstruction* reconstruction, + map<int, Vec6>* all_cameras_R_t, + ceres::Problem* problem, + BundleEvaluation* evaluation) { int max_track = tracks.MaxTrack(); // Number of camera rotations equals to number of translation, int num_cameras = all_cameras_R_t->size(); @@ -451,7 +471,7 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks, vector<EuclideanPoint*> minimized_points; for (int i = 0; i <= max_track; i++) { - EuclideanPoint *point = reconstruction->PointForTrack(i); + EuclideanPoint* point = reconstruction->PointForTrack(i); if (point) { // We need to know whether the track is a constant zero weight. // If it is so it wouldn't have a parameter block in the problem. @@ -477,16 +497,16 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks, evaluation->num_cameras = num_cameras; evaluation->num_points = num_points; - if (evaluation->evaluate_jacobian) { // Evaluate jacobian matrix. + if (evaluation->evaluate_jacobian) { // Evaluate jacobian matrix. ceres::CRSMatrix evaluated_jacobian; ceres::Problem::EvaluateOptions eval_options; // Cameras goes first in the ordering. int max_image = tracks.MaxImage(); for (int i = 0; i <= max_image; i++) { - const EuclideanCamera *camera = reconstruction->CameraForImage(i); + const EuclideanCamera* camera = reconstruction->CameraForImage(i); if (camera) { - double *current_camera_R_t = &(*all_cameras_R_t)[i](0); + double* current_camera_R_t = &(*all_cameras_R_t)[i](0); // All cameras are variable now. problem->SetParameterBlockVariable(current_camera_R_t); @@ -497,63 +517,65 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks, // Points goes at the end of ordering, for (int i = 0; i < minimized_points.size(); i++) { - EuclideanPoint *point = minimized_points.at(i); + EuclideanPoint* point = minimized_points.at(i); eval_options.parameter_blocks.push_back(&point->X(0)); } - problem->Evaluate(eval_options, - NULL, NULL, NULL, - &evaluated_jacobian); + problem->Evaluate(eval_options, NULL, NULL, NULL, &evaluated_jacobian); CRSMatrixToEigenMatrix(evaluated_jacobian, &evaluation->jacobian); } } -template<typename CostFunction> -void AddResidualBlockToProblemImpl(const CameraIntrinsics *invariant_intrinsics, - double observed_x, double observed_y, +template <typename CostFunction> +void AddResidualBlockToProblemImpl(const CameraIntrinsics* invariant_intrinsics, + double observed_x, + double observed_y, double weight, - double *intrinsics_block, - double *camera_R_t, - EuclideanPoint *point, + double* intrinsics_block, + double* camera_R_t, + EuclideanPoint* point, ceres::Problem* problem) { - problem->AddResidualBlock(new ceres::AutoDiffCostFunction< - CostFunction, 2, PackedIntrinsics::NUM_PARAMETERS, 6, 3>( - new CostFunction( - invariant_intrinsics, - observed_x, observed_y, - weight)), + problem->AddResidualBlock( + new ceres::AutoDiffCostFunction<CostFunction, + 2, + PackedIntrinsics::NUM_PARAMETERS, + 6, + 3>(new CostFunction( + invariant_intrinsics, observed_x, observed_y, weight)), NULL, intrinsics_block, camera_R_t, &point->X(0)); } -void AddResidualBlockToProblem(const CameraIntrinsics *invariant_intrinsics, - const Marker &marker, +void AddResidualBlockToProblem(const CameraIntrinsics* invariant_intrinsics, + const Marker& marker, double marker_weight, double* intrinsics_block, - double *camera_R_t, - EuclideanPoint *point, + double* camera_R_t, + EuclideanPoint* point, ceres::Problem* problem) { if (NeedUseInvertIntrinsicsPipeline(invariant_intrinsics)) { AddResidualBlockToProblemImpl<ReprojectionErrorInvertIntrinsics>( - invariant_intrinsics, - marker.x, marker.y, - marker_weight, - intrinsics_block, - camera_R_t, - point, - problem); + invariant_intrinsics, + marker.x, + marker.y, + marker_weight, + intrinsics_block, + camera_R_t, + point, + problem); } else { AddResidualBlockToProblemImpl<ReprojectionErrorApplyIntrinsics>( - invariant_intrinsics, - marker.x, marker.y, - marker_weight, - intrinsics_block, - camera_R_t, - point, - problem); + invariant_intrinsics, + marker.x, + marker.y, + marker_weight, + intrinsics_block, + camera_R_t, + point, + problem); } } @@ -566,25 +588,25 @@ void AddResidualBlockToProblem(const CameraIntrinsics *invariant_intrinsics, // // At this point we only need to bundle points positions, cameras // are to be totally still here. -void EuclideanBundlePointsOnly(const CameraIntrinsics *invariant_intrinsics, - const vector<Marker> &markers, - map<int, Vec6> &all_cameras_R_t, +void EuclideanBundlePointsOnly(const CameraIntrinsics* invariant_intrinsics, + const vector<Marker>& markers, + map<int, Vec6>& all_cameras_R_t, double* intrinsics_block, - EuclideanReconstruction *reconstruction) { + EuclideanReconstruction* reconstruction) { ceres::Problem::Options problem_options; ceres::Problem problem(problem_options); int num_residuals = 0; for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; - EuclideanCamera *camera = reconstruction->CameraForImage(marker.image); - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + const Marker& marker = markers[i]; + EuclideanCamera* camera = reconstruction->CameraForImage(marker.image); + EuclideanPoint* point = reconstruction->PointForTrack(marker.track); if (camera == NULL || point == NULL) { continue; } // Rotation of camera denoted in angle axis followed with // camera translation. - double *current_camera_R_t = &all_cameras_R_t[camera->image](0); + double* current_camera_R_t = &all_cameras_R_t[camera->image](0); AddResidualBlockToProblem(invariant_intrinsics, marker, @@ -625,8 +647,8 @@ void EuclideanBundlePointsOnly(const CameraIntrinsics *invariant_intrinsics, } // namespace -void EuclideanBundle(const Tracks &tracks, - EuclideanReconstruction *reconstruction) { +void EuclideanBundle(const Tracks& tracks, + EuclideanReconstruction* reconstruction) { PolynomialCameraIntrinsics empty_intrinsics; EuclideanBundleCommonIntrinsics(tracks, BUNDLE_NO_INTRINSICS, @@ -636,13 +658,12 @@ void EuclideanBundle(const Tracks &tracks, NULL); } -void EuclideanBundleCommonIntrinsics( - const Tracks &tracks, - const int bundle_intrinsics, - const int bundle_constraints, - EuclideanReconstruction *reconstruction, - CameraIntrinsics *intrinsics, - BundleEvaluation *evaluation) { +void EuclideanBundleCommonIntrinsics(const Tracks& tracks, + const int bundle_intrinsics, + const int bundle_constraints, + EuclideanReconstruction* reconstruction, + CameraIntrinsics* intrinsics, + BundleEvaluation* evaluation) { LG << "Original intrinsics: " << *intrinsics; vector<Marker> markers = tracks.AllMarkers(); @@ -661,19 +682,19 @@ void EuclideanBundleCommonIntrinsics( // Block for minimization has got the following structure: // <3 elements for angle-axis> <3 elements for translation> map<int, Vec6> all_cameras_R_t = - PackCamerasRotationAndTranslation(*reconstruction); + PackCamerasRotationAndTranslation(*reconstruction); // Parameterization used to restrict camera motion for modal solvers. - ceres::SubsetParameterization *constant_translation_parameterization = NULL; + ceres::SubsetParameterization* constant_translation_parameterization = NULL; if (bundle_constraints & BUNDLE_NO_TRANSLATION) { - std::vector<int> constant_translation; + std::vector<int> constant_translation; - // First three elements are rotation, ast three are translation. - constant_translation.push_back(3); - constant_translation.push_back(4); - constant_translation.push_back(5); + // First three elements are rotation, ast three are translation. + constant_translation.push_back(3); + constant_translation.push_back(4); + constant_translation.push_back(5); - constant_translation_parameterization = + constant_translation_parameterization = new ceres::SubsetParameterization(6, constant_translation); } @@ -683,16 +704,16 @@ void EuclideanBundleCommonIntrinsics( int num_residuals = 0; bool have_locked_camera = false; for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; - EuclideanCamera *camera = reconstruction->CameraForImage(marker.image); - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + const Marker& marker = markers[i]; + EuclideanCamera* camera = reconstruction->CameraForImage(marker.image); + EuclideanPoint* point = reconstruction->PointForTrack(marker.track); if (camera == NULL || point == NULL) { continue; } // Rotation of camera denoted in angle axis followed with // camera translation. - double *current_camera_R_t = &all_cameras_R_t[camera->image](0); + double* current_camera_R_t = &all_cameras_R_t[camera->image](0); // Skip residual block for markers which does have absolutely // no affect on the final solution. @@ -706,7 +727,8 @@ void EuclideanBundleCommonIntrinsics( point, &problem); - // We lock the first camera to better deal with scene orientation ambiguity. + // We lock the first camera to better deal with scene orientation + // ambiguity. if (!have_locked_camera) { problem.SetParameterBlockConstant(current_camera_R_t); have_locked_camera = true; @@ -729,7 +751,7 @@ void EuclideanBundleCommonIntrinsics( } if (intrinsics->GetDistortionModelType() == DISTORTION_MODEL_DIVISION && - (bundle_intrinsics & BUNDLE_TANGENTIAL) != 0) { + (bundle_intrinsics & BUNDLE_TANGENTIAL) != 0) { LOG(FATAL) << "Division model doesn't support bundling " "of tangential distortion"; } @@ -745,29 +767,29 @@ void EuclideanBundleCommonIntrinsics( // constant using some macro trickery. std::vector<int> constant_intrinsics; -#define MAYBE_SET_CONSTANT(bundle_enum, offset) \ - if (!(bundle_intrinsics & bundle_enum) || \ - !packed_intrinsics.IsParameterDefined(offset)) { \ - constant_intrinsics.push_back(offset); \ - } +#define MAYBE_SET_CONSTANT(bundle_enum, offset) \ + if (!(bundle_intrinsics & bundle_enum) || \ + !packed_intrinsics.IsParameterDefined(offset)) { \ + constant_intrinsics.push_back(offset); \ + } MAYBE_SET_CONSTANT(BUNDLE_FOCAL_LENGTH, PackedIntrinsics::OFFSET_FOCAL_LENGTH); MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, PackedIntrinsics::OFFSET_PRINCIPAL_POINT_X); MAYBE_SET_CONSTANT(BUNDLE_PRINCIPAL_POINT, PackedIntrinsics::OFFSET_PRINCIPAL_POINT_Y); - MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, PackedIntrinsics::OFFSET_K1); - MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, PackedIntrinsics::OFFSET_K2); - MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K3, PackedIntrinsics::OFFSET_K3); - MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K4, PackedIntrinsics::OFFSET_K4); - MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, PackedIntrinsics::OFFSET_P1); - MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, PackedIntrinsics::OFFSET_P2); + MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K1, PackedIntrinsics::OFFSET_K1); + MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K2, PackedIntrinsics::OFFSET_K2); + MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K3, PackedIntrinsics::OFFSET_K3); + MAYBE_SET_CONSTANT(BUNDLE_RADIAL_K4, PackedIntrinsics::OFFSET_K4); + MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P1, PackedIntrinsics::OFFSET_P1); + MAYBE_SET_CONSTANT(BUNDLE_TANGENTIAL_P2, PackedIntrinsics::OFFSET_P2); #undef MAYBE_SET_CONSTANT if (!constant_intrinsics.empty()) { - ceres::SubsetParameterization *subset_parameterization = - new ceres::SubsetParameterization(PackedIntrinsics::NUM_PARAMETERS, - constant_intrinsics); + ceres::SubsetParameterization* subset_parameterization = + new ceres::SubsetParameterization(PackedIntrinsics::NUM_PARAMETERS, + constant_intrinsics); problem.SetParameterization(intrinsics_block, subset_parameterization); } @@ -800,8 +822,8 @@ void EuclideanBundleCommonIntrinsics( LG << "Final intrinsics: " << *intrinsics; if (evaluation) { - EuclideanBundlerPerformEvaluation(tracks, reconstruction, &all_cameras_R_t, - &problem, evaluation); + EuclideanBundlerPerformEvaluation( + tracks, reconstruction, &all_cameras_R_t, &problem, evaluation); } // Separate step to adjust positions of tracks which are @@ -828,8 +850,8 @@ void EuclideanBundleCommonIntrinsics( } } -void ProjectiveBundle(const Tracks & /*tracks*/, - ProjectiveReconstruction * /*reconstruction*/) { +void ProjectiveBundle(const Tracks& /*tracks*/, + ProjectiveReconstruction* /*reconstruction*/) { // TODO(keir): Implement this! This can't work until we have a better bundler // than SSBA, since SSBA has no support for projective bundling. } diff --git a/intern/libmv/libmv/simple_pipeline/bundle.h b/intern/libmv/libmv/simple_pipeline/bundle.h index 5f420da0045..662313b396a 100644 --- a/intern/libmv/libmv/simple_pipeline/bundle.h +++ b/intern/libmv/libmv/simple_pipeline/bundle.h @@ -31,11 +31,8 @@ class ProjectiveReconstruction; class Tracks; struct BundleEvaluation { - BundleEvaluation() : - num_cameras(0), - num_points(0), - evaluate_jacobian(false) { - } + BundleEvaluation() + : num_cameras(0), num_points(0), evaluate_jacobian(false) {} // Number of cameras appeared in bundle adjustment problem int num_cameras; @@ -72,8 +69,8 @@ struct BundleEvaluation { \sa EuclideanResect, EuclideanIntersect, EuclideanReconstructTwoFrames */ -void EuclideanBundle(const Tracks &tracks, - EuclideanReconstruction *reconstruction); +void EuclideanBundle(const Tracks& tracks, + EuclideanReconstruction* reconstruction); /*! Refine camera poses and 3D coordinates using bundle adjustment. @@ -109,9 +106,7 @@ enum BundleIntrinsics { BUNDLE_RADIAL_K2 = (1 << 3), BUNDLE_RADIAL_K3 = (1 << 4), BUNDLE_RADIAL_K4 = (1 << 5), - BUNDLE_RADIAL = (BUNDLE_RADIAL_K1 | - BUNDLE_RADIAL_K2 | - BUNDLE_RADIAL_K3 | + BUNDLE_RADIAL = (BUNDLE_RADIAL_K1 | BUNDLE_RADIAL_K2 | BUNDLE_RADIAL_K3 | BUNDLE_RADIAL_K4), BUNDLE_TANGENTIAL_P1 = (1 << 6), @@ -122,13 +117,12 @@ enum BundleConstraints { BUNDLE_NO_CONSTRAINTS = 0, BUNDLE_NO_TRANSLATION = 1, }; -void EuclideanBundleCommonIntrinsics( - const Tracks &tracks, - const int bundle_intrinsics, - const int bundle_constraints, - EuclideanReconstruction *reconstruction, - CameraIntrinsics *intrinsics, - BundleEvaluation *evaluation = NULL); +void EuclideanBundleCommonIntrinsics(const Tracks& tracks, + const int bundle_intrinsics, + const int bundle_constraints, + EuclideanReconstruction* reconstruction, + CameraIntrinsics* intrinsics, + BundleEvaluation* evaluation = NULL); /*! Refine camera poses and 3D coordinates using bundle adjustment. @@ -147,10 +141,9 @@ void EuclideanBundleCommonIntrinsics( \sa ProjectiveResect, ProjectiveIntersect, ProjectiveReconstructTwoFrames */ -void ProjectiveBundle(const Tracks &tracks, - ProjectiveReconstruction *reconstruction); +void ProjectiveBundle(const Tracks& tracks, + ProjectiveReconstruction* reconstruction); } // namespace libmv -#endif // LIBMV_SIMPLE_PIPELINE_BUNDLE_H - +#endif // LIBMV_SIMPLE_PIPELINE_BUNDLE_H diff --git a/intern/libmv/libmv/simple_pipeline/callbacks.h b/intern/libmv/libmv/simple_pipeline/callbacks.h index 58f7b0d3cc9..a6855a9e5e7 100644 --- a/intern/libmv/libmv/simple_pipeline/callbacks.h +++ b/intern/libmv/libmv/simple_pipeline/callbacks.h @@ -26,7 +26,7 @@ namespace libmv { class ProgressUpdateCallback { public: virtual ~ProgressUpdateCallback() {} - virtual void invoke(double progress, const char *message) = 0; + virtual void invoke(double progress, const char* message) = 0; }; } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc index ccb6e3d34c8..b86e316b139 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.cc @@ -29,13 +29,10 @@ namespace libmv { namespace internal { LookupWarpGrid::LookupWarpGrid() - : offset_(NULL), - width_(0), - height_(0), - overscan_(0.0), - threads_(1) {} + : offset_(NULL), width_(0), height_(0), overscan_(0.0), threads_(1) { +} -LookupWarpGrid::LookupWarpGrid(const LookupWarpGrid &from) +LookupWarpGrid::LookupWarpGrid(const LookupWarpGrid& from) : offset_(NULL), width_(from.width_), height_(from.height_), @@ -48,11 +45,11 @@ LookupWarpGrid::LookupWarpGrid(const LookupWarpGrid &from) } LookupWarpGrid::~LookupWarpGrid() { - delete [] offset_; + delete[] offset_; } void LookupWarpGrid::Reset() { - delete [] offset_; + delete[] offset_; offset_ = NULL; } @@ -64,16 +61,16 @@ void LookupWarpGrid::SetThreads(int threads) { } // namespace internal CameraIntrinsics::CameraIntrinsics() - : image_width_(0), - image_height_(0), - K_(Mat3::Identity()) {} + : image_width_(0), image_height_(0), K_(Mat3::Identity()) { +} -CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics &from) +CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics& from) : image_width_(from.image_width_), image_height_(from.image_height_), K_(from.K_), distort_(from.distort_), - undistort_(from.undistort_) {} + undistort_(from.undistort_) { +} // Set the image size in pixels. void CameraIntrinsics::SetImageSize(int width, int height) { @@ -89,16 +86,14 @@ void CameraIntrinsics::SetK(const Mat3 new_k) { } // Set both x and y focal length in pixels. -void CameraIntrinsics::SetFocalLength(double focal_x, - double focal_y) { +void CameraIntrinsics::SetFocalLength(double focal_x, double focal_y) { K_(0, 0) = focal_x; K_(1, 1) = focal_y; ResetLookupGrids(); } // Set principal point in pixels. -void CameraIntrinsics::SetPrincipalPoint(double cx, - double cy) { +void CameraIntrinsics::SetPrincipalPoint(double cx, double cy) { K_(0, 2) = cx; K_(1, 2) = cy; ResetLookupGrids(); @@ -112,16 +107,16 @@ void CameraIntrinsics::SetThreads(int threads) { void CameraIntrinsics::ImageSpaceToNormalized(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const { + double* normalized_x, + double* normalized_y) const { *normalized_x = (image_x - principal_point_x()) / focal_length_x(); *normalized_y = (image_y - principal_point_y()) / focal_length_y(); } void CameraIntrinsics::NormalizedToImageSpace(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const { + double* image_x, + double* image_y) const { *image_x = normalized_x * focal_length_x() + principal_point_x(); *image_y = normalized_y * focal_length_y() + principal_point_y(); } @@ -148,14 +143,13 @@ void CameraIntrinsics::Unpack(const PackedIntrinsics& packed_intrinsics) { // Polynomial model. -PolynomialCameraIntrinsics::PolynomialCameraIntrinsics() - : CameraIntrinsics() { +PolynomialCameraIntrinsics::PolynomialCameraIntrinsics() : CameraIntrinsics() { SetRadialDistortion(0.0, 0.0, 0.0); SetTangentialDistortion(0.0, 0.0); } PolynomialCameraIntrinsics::PolynomialCameraIntrinsics( - const PolynomialCameraIntrinsics &from) + const PolynomialCameraIntrinsics& from) : CameraIntrinsics(from) { SetRadialDistortion(from.k1(), from.k2(), from.k3()); SetTangentialDistortion(from.p1(), from.p2()); @@ -170,8 +164,7 @@ void PolynomialCameraIntrinsics::SetRadialDistortion(double k1, ResetLookupGrids(); } -void PolynomialCameraIntrinsics::SetTangentialDistortion(double p1, - double p2) { +void PolynomialCameraIntrinsics::SetTangentialDistortion(double p1, double p2) { parameters_[OFFSET_P1] = p1; parameters_[OFFSET_P2] = p2; ResetLookupGrids(); @@ -179,31 +172,36 @@ void PolynomialCameraIntrinsics::SetTangentialDistortion(double p1, void PolynomialCameraIntrinsics::ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const { + double* image_x, + double* image_y) const { ApplyPolynomialDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), k3(), - p1(), p2(), + k1(), + k2(), + k3(), + p1(), + p2(), normalized_x, normalized_y, image_x, image_y); } -void PolynomialCameraIntrinsics::InvertIntrinsics( - double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const { +void PolynomialCameraIntrinsics::InvertIntrinsics(double image_x, + double image_y, + double* normalized_x, + double* normalized_y) const { InvertPolynomialDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), k3(), - p1(), p2(), + k1(), + k2(), + k3(), + p1(), + p2(), image_x, image_y, normalized_x, @@ -230,25 +228,22 @@ void PolynomialCameraIntrinsics::Unpack( packed_intrinsics.GetK2(), packed_intrinsics.GetK3()); - SetTangentialDistortion(packed_intrinsics.GetP1(), - packed_intrinsics.GetP2()); + SetTangentialDistortion(packed_intrinsics.GetP1(), packed_intrinsics.GetP2()); } // Division model. -DivisionCameraIntrinsics::DivisionCameraIntrinsics() - : CameraIntrinsics() { +DivisionCameraIntrinsics::DivisionCameraIntrinsics() : CameraIntrinsics() { SetDistortion(0.0, 0.0); } DivisionCameraIntrinsics::DivisionCameraIntrinsics( - const DivisionCameraIntrinsics &from) + const DivisionCameraIntrinsics& from) : CameraIntrinsics(from) { SetDistortion(from.k1(), from.k1()); } -void DivisionCameraIntrinsics::SetDistortion(double k1, - double k2) { +void DivisionCameraIntrinsics::SetDistortion(double k1, double k2) { parameters_[OFFSET_K1] = k1; parameters_[OFFSET_K2] = k2; ResetLookupGrids(); @@ -256,13 +251,14 @@ void DivisionCameraIntrinsics::SetDistortion(double k1, void DivisionCameraIntrinsics::ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const { + double* image_x, + double* image_y) const { ApplyDivisionDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), + k1(), + k2(), normalized_x, normalized_y, image_x, @@ -271,21 +267,21 @@ void DivisionCameraIntrinsics::ApplyIntrinsics(double normalized_x, void DivisionCameraIntrinsics::InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const { + double* normalized_x, + double* normalized_y) const { InvertDivisionDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), + k1(), + k2(), image_x, image_y, normalized_x, normalized_y); } -void DivisionCameraIntrinsics::Pack( - PackedIntrinsics* packed_intrinsics) const { +void DivisionCameraIntrinsics::Pack(PackedIntrinsics* packed_intrinsics) const { CameraIntrinsics::Pack(packed_intrinsics); packed_intrinsics->SetK1(k1()); @@ -301,13 +297,11 @@ void DivisionCameraIntrinsics::Unpack( // Nuke model. -NukeCameraIntrinsics::NukeCameraIntrinsics() - : CameraIntrinsics() { +NukeCameraIntrinsics::NukeCameraIntrinsics() : CameraIntrinsics() { SetDistortion(0.0, 0.0); } -NukeCameraIntrinsics::NukeCameraIntrinsics( - const NukeCameraIntrinsics &from) +NukeCameraIntrinsics::NukeCameraIntrinsics(const NukeCameraIntrinsics& from) : CameraIntrinsics(from) { SetDistortion(from.k1(), from.k2()); } @@ -320,14 +314,16 @@ void NukeCameraIntrinsics::SetDistortion(double k1, double k2) { void NukeCameraIntrinsics::ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const { + double* image_x, + double* image_y) const { ApplyNukeDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - image_width(), image_height(), - k1(), k2(), + image_width(), + image_height(), + k1(), + k2(), normalized_x, normalized_y, image_x, @@ -335,31 +331,31 @@ void NukeCameraIntrinsics::ApplyIntrinsics(double normalized_x, } void NukeCameraIntrinsics::InvertIntrinsics(double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const { + double image_y, + double* normalized_x, + double* normalized_y) const { InvertNukeDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - image_width(), image_height(), - k1(), k2(), + image_width(), + image_height(), + k1(), + k2(), image_x, image_y, normalized_x, normalized_y); } -void NukeCameraIntrinsics::Pack( - PackedIntrinsics* packed_intrinsics) const { +void NukeCameraIntrinsics::Pack(PackedIntrinsics* packed_intrinsics) const { CameraIntrinsics::Pack(packed_intrinsics); packed_intrinsics->SetK1(k1()); packed_intrinsics->SetK2(k2()); } -void NukeCameraIntrinsics::Unpack( - const PackedIntrinsics& packed_intrinsics) { +void NukeCameraIntrinsics::Unpack(const PackedIntrinsics& packed_intrinsics) { CameraIntrinsics::Unpack(packed_intrinsics); SetDistortion(packed_intrinsics.GetK1(), packed_intrinsics.GetK2()); @@ -367,14 +363,12 @@ void NukeCameraIntrinsics::Unpack( // Brown model. -BrownCameraIntrinsics::BrownCameraIntrinsics() - : CameraIntrinsics() { +BrownCameraIntrinsics::BrownCameraIntrinsics() : CameraIntrinsics() { SetRadialDistortion(0.0, 0.0, 0.0, 0.0); SetTangentialDistortion(0.0, 0.0); } -BrownCameraIntrinsics::BrownCameraIntrinsics( - const BrownCameraIntrinsics &from) +BrownCameraIntrinsics::BrownCameraIntrinsics(const BrownCameraIntrinsics& from) : CameraIntrinsics(from) { SetRadialDistortion(from.k1(), from.k2(), from.k3(), from.k4()); SetTangentialDistortion(from.p1(), from.p2()); @@ -391,8 +385,7 @@ void BrownCameraIntrinsics::SetRadialDistortion(double k1, ResetLookupGrids(); } -void BrownCameraIntrinsics::SetTangentialDistortion(double p1, - double p2) { +void BrownCameraIntrinsics::SetTangentialDistortion(double p1, double p2) { parameters_[OFFSET_P1] = p1; parameters_[OFFSET_P2] = p2; ResetLookupGrids(); @@ -400,39 +393,45 @@ void BrownCameraIntrinsics::SetTangentialDistortion(double p1, void BrownCameraIntrinsics::ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const { + double* image_x, + double* image_y) const { ApplyBrownDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), k3(), k4(), - p1(), p2(), + k1(), + k2(), + k3(), + k4(), + p1(), + p2(), normalized_x, normalized_y, image_x, image_y); } -void BrownCameraIntrinsics::InvertIntrinsics( - double image_x, - double image_y, - double *normalized_x, - double *normalized_y) const { +void BrownCameraIntrinsics::InvertIntrinsics(double image_x, + double image_y, + double* normalized_x, + double* normalized_y) const { InvertBrownDistortionModel(focal_length_x(), focal_length_y(), principal_point_x(), principal_point_y(), - k1(), k2(), k3(), k4(), - p1(), p2(), + k1(), + k2(), + k3(), + k4(), + p1(), + p2(), image_x, image_y, normalized_x, normalized_y); } -void BrownCameraIntrinsics::Pack( - PackedIntrinsics* packed_intrinsics) const { +void BrownCameraIntrinsics::Pack(PackedIntrinsics* packed_intrinsics) const { CameraIntrinsics::Pack(packed_intrinsics); packed_intrinsics->SetK1(k1()); @@ -444,8 +443,7 @@ void BrownCameraIntrinsics::Pack( packed_intrinsics->SetP2(p2()); } -void BrownCameraIntrinsics::Unpack( - const PackedIntrinsics& packed_intrinsics) { +void BrownCameraIntrinsics::Unpack(const PackedIntrinsics& packed_intrinsics) { CameraIntrinsics::Unpack(packed_intrinsics); SetRadialDistortion(packed_intrinsics.GetK1(), @@ -453,72 +451,65 @@ void BrownCameraIntrinsics::Unpack( packed_intrinsics.GetK3(), packed_intrinsics.GetK4()); - SetTangentialDistortion(packed_intrinsics.GetP1(), - packed_intrinsics.GetP2()); + SetTangentialDistortion(packed_intrinsics.GetP1(), packed_intrinsics.GetP2()); } -std::ostream& operator <<(std::ostream &os, - const CameraIntrinsics &intrinsics) { +std::ostream& operator<<(std::ostream& os, const CameraIntrinsics& intrinsics) { if (intrinsics.focal_length_x() == intrinsics.focal_length_x()) { os << "f=" << intrinsics.focal_length(); } else { - os << "fx=" << intrinsics.focal_length_x() + os << "fx=" << intrinsics.focal_length_x() << " fy=" << intrinsics.focal_length_y(); } os << " cx=" << intrinsics.principal_point_x() << " cy=" << intrinsics.principal_point_y() - << " w=" << intrinsics.image_width() - << " h=" << intrinsics.image_height(); + << " w=" << intrinsics.image_width() << " h=" << intrinsics.image_height(); -#define PRINT_NONZERO_COEFFICIENT(intrinsics, coeff) \ - { \ - if (intrinsics->coeff() != 0.0) { \ - os << " " #coeff "=" << intrinsics->coeff(); \ - } \ - } (void) 0 +#define PRINT_NONZERO_COEFFICIENT(intrinsics, coeff) \ + { \ + if (intrinsics->coeff() != 0.0) { \ + os << " " #coeff "=" << intrinsics->coeff(); \ + } \ + } \ + (void)0 switch (intrinsics.GetDistortionModelType()) { - case DISTORTION_MODEL_POLYNOMIAL: - { - const PolynomialCameraIntrinsics *polynomial_intrinsics = - static_cast<const PolynomialCameraIntrinsics *>(&intrinsics); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k1); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k2); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k3); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p1); - PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p2); - break; - } - case DISTORTION_MODEL_DIVISION: - { - const DivisionCameraIntrinsics *division_intrinsics = - static_cast<const DivisionCameraIntrinsics *>(&intrinsics); - PRINT_NONZERO_COEFFICIENT(division_intrinsics, k1); - PRINT_NONZERO_COEFFICIENT(division_intrinsics, k2); - break; - } - case DISTORTION_MODEL_NUKE: - { - const NukeCameraIntrinsics *nuke_intrinsics = - static_cast<const NukeCameraIntrinsics *>(&intrinsics); - PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k1); - PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k2); - break; - } - case DISTORTION_MODEL_BROWN: - { - const BrownCameraIntrinsics *brown_intrinsics = - static_cast<const BrownCameraIntrinsics *>(&intrinsics); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k1); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k2); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k3); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k4); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p1); - PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p2); - break; - } - default: - LOG(FATAL) << "Unknown distortion model."; + case DISTORTION_MODEL_POLYNOMIAL: { + const PolynomialCameraIntrinsics* polynomial_intrinsics = + static_cast<const PolynomialCameraIntrinsics*>(&intrinsics); + PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k1); + PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k2); + PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, k3); + PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p1); + PRINT_NONZERO_COEFFICIENT(polynomial_intrinsics, p2); + break; + } + case DISTORTION_MODEL_DIVISION: { + const DivisionCameraIntrinsics* division_intrinsics = + static_cast<const DivisionCameraIntrinsics*>(&intrinsics); + PRINT_NONZERO_COEFFICIENT(division_intrinsics, k1); + PRINT_NONZERO_COEFFICIENT(division_intrinsics, k2); + break; + } + case DISTORTION_MODEL_NUKE: { + const NukeCameraIntrinsics* nuke_intrinsics = + static_cast<const NukeCameraIntrinsics*>(&intrinsics); + PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k1); + PRINT_NONZERO_COEFFICIENT(nuke_intrinsics, k2); + break; + } + case DISTORTION_MODEL_BROWN: { + const BrownCameraIntrinsics* brown_intrinsics = + static_cast<const BrownCameraIntrinsics*>(&intrinsics); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k1); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k2); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k3); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, k4); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p1); + PRINT_NONZERO_COEFFICIENT(brown_intrinsics, p2); + break; + } + default: LOG(FATAL) << "Unknown distortion model."; } #undef PRINT_NONZERO_COEFFICIENT diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h index ba67ec468dc..efe0735bd93 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics.h @@ -43,11 +43,11 @@ namespace internal { class LookupWarpGrid { public: LookupWarpGrid(); - LookupWarpGrid(const LookupWarpGrid &from); + LookupWarpGrid(const LookupWarpGrid& from); ~LookupWarpGrid(); // Width and height og the image, measured in pixels. - int width() const { return width_; } + int width() const { return width_; } int height() const { return height_; } // Overscan factor of the image, so that @@ -61,8 +61,8 @@ class LookupWarpGrid { // // See comment for CameraIntrinsics::DistortBuffer to get more // details about what overscan is. - template<typename WarpFunction> - void Update(const CameraIntrinsics &intrinsics, + template <typename WarpFunction> + void Update(const CameraIntrinsics& intrinsics, int width, int height, double overscan); @@ -71,12 +71,12 @@ class LookupWarpGrid { // // See comment for CameraIntrinsics::DistortBuffer to get more // details about template type. - template<typename PixelType> - void Apply(const PixelType *input_buffer, + template <typename PixelType> + void Apply(const PixelType* input_buffer, int width, int height, int channels, - PixelType *output_buffer); + PixelType* output_buffer); // Reset lookup grids. // This will tag the grid for update without re-computing it. @@ -105,15 +105,15 @@ class LookupWarpGrid { // // width and height corresponds to a size of buffer which will // be warped later. - template<typename WarpFunction> - void Compute(const CameraIntrinsics &intrinsics, + template <typename WarpFunction> + void Compute(const CameraIntrinsics& intrinsics, int width, int height, double overscan); // This is a buffer which contains per-pixel offset of the // pixels from input buffer to correspond the warping function. - Offset *offset_; + Offset* offset_; // Dimensions of the image this lookup grid processes. int width_, height_; @@ -130,19 +130,19 @@ class LookupWarpGrid { class CameraIntrinsics { public: CameraIntrinsics(); - CameraIntrinsics(const CameraIntrinsics &from); + CameraIntrinsics(const CameraIntrinsics& from); virtual ~CameraIntrinsics() {} virtual DistortionModelType GetDistortionModelType() const = 0; - int image_width() const { return image_width_; } + int image_width() const { return image_width_; } int image_height() const { return image_height_; } - const Mat3 &K() const { return K_; } + const Mat3& K() const { return K_; } - double focal_length() const { return K_(0, 0); } - double focal_length_x() const { return K_(0, 0); } - double focal_length_y() const { return K_(1, 1); } + double focal_length() const { return K_(0, 0); } + double focal_length_x() const { return K_(0, 0); } + double focal_length_y() const { return K_(1, 1); } double principal_point_x() const { return K_(0, 2); } double principal_point_y() const { return K_(1, 2); } @@ -166,14 +166,14 @@ class CameraIntrinsics { // Convert image space coordinates to normalized. void ImageSpaceToNormalized(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const; + double* normalized_x, + double* normalized_y) const; // Convert normalized coordinates to image space. void NormalizedToImageSpace(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const; + double* image_x, + double* image_y) const; // Apply camera intrinsics to the normalized point to get image coordinates. // @@ -182,8 +182,8 @@ class CameraIntrinsics { // coordinates in pixels. virtual void ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const = 0; + double* image_x, + double* image_y) const = 0; // Invert camera intrinsics on the image point to get normalized coordinates. // @@ -191,8 +191,8 @@ class CameraIntrinsics { // coordinates to get normalized camera coordinates. virtual void InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const = 0; + double* normalized_x, + double* normalized_y) const = 0; virtual void Pack(PackedIntrinsics* packed_intrinsics) const; virtual void Unpack(const PackedIntrinsics& packed_intrinsics); @@ -218,13 +218,13 @@ class CameraIntrinsics { // But in fact PixelType might be any type for which multiplication by // a scalar and addition are implemented. For example PixelType might be // Vec3 as well. - template<typename PixelType> - void DistortBuffer(const PixelType *input_buffer, + template <typename PixelType> + void DistortBuffer(const PixelType* input_buffer, int width, int height, double overscan, int channels, - PixelType *output_buffer); + PixelType* output_buffer); // Undistort an image using the current camera instrinsics // @@ -247,13 +247,13 @@ class CameraIntrinsics { // But in fact PixelType might be any type for which multiplication by // a scalar and addition are implemented. For example PixelType might be // Vec3 as well. - template<typename PixelType> - void UndistortBuffer(const PixelType *input_buffer, + template <typename PixelType> + void UndistortBuffer(const PixelType* input_buffer, int width, int height, double overscan, int channels, - PixelType *output_buffer); + PixelType* output_buffer); private: // This is the size of the image. This is necessary to, for example, handle @@ -290,7 +290,7 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics { }; PolynomialCameraIntrinsics(); - PolynomialCameraIntrinsics(const PolynomialCameraIntrinsics &from); + PolynomialCameraIntrinsics(const PolynomialCameraIntrinsics& from); DistortionModelType GetDistortionModelType() const override { return DISTORTION_MODEL_POLYNOMIAL; @@ -315,8 +315,8 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics { // coordinates in pixels. void ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const override; + double* image_x, + double* image_y) const override; // Invert camera intrinsics on the image point to get normalized coordinates. // @@ -324,8 +324,8 @@ class PolynomialCameraIntrinsics : public CameraIntrinsics { // coordinates to get normalized camera coordinates. void InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const override; + double* normalized_x, + double* normalized_y) const override; virtual void Pack(PackedIntrinsics* packed_intrinsics) const override; virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override; @@ -352,7 +352,7 @@ class DivisionCameraIntrinsics : public CameraIntrinsics { }; DivisionCameraIntrinsics(); - DivisionCameraIntrinsics(const DivisionCameraIntrinsics &from); + DivisionCameraIntrinsics(const DivisionCameraIntrinsics& from); DistortionModelType GetDistortionModelType() const override { return DISTORTION_MODEL_DIVISION; @@ -371,8 +371,8 @@ class DivisionCameraIntrinsics : public CameraIntrinsics { // coordinates in pixels. void ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const override; + double* image_x, + double* image_y) const override; // Invert camera intrinsics on the image point to get normalized coordinates. // @@ -380,8 +380,8 @@ class DivisionCameraIntrinsics : public CameraIntrinsics { // coordinates to get normalized camera coordinates. void InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const override; + double* normalized_x, + double* normalized_y) const override; virtual void Pack(PackedIntrinsics* packed_intrinsics) const override; virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override; @@ -405,7 +405,7 @@ class NukeCameraIntrinsics : public CameraIntrinsics { }; NukeCameraIntrinsics(); - NukeCameraIntrinsics(const NukeCameraIntrinsics &from); + NukeCameraIntrinsics(const NukeCameraIntrinsics& from); DistortionModelType GetDistortionModelType() const override { return DISTORTION_MODEL_NUKE; @@ -424,8 +424,8 @@ class NukeCameraIntrinsics : public CameraIntrinsics { // coordinates in pixels. void ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const override; + double* image_x, + double* image_y) const override; // Invert camera intrinsics on the image point to get normalized coordinates. // @@ -433,8 +433,8 @@ class NukeCameraIntrinsics : public CameraIntrinsics { // coordinates to get normalized camera coordinates. void InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const override; + double* normalized_x, + double* normalized_y) const override; virtual void Pack(PackedIntrinsics* packed_intrinsics) const override; virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override; @@ -462,7 +462,7 @@ class BrownCameraIntrinsics : public CameraIntrinsics { }; BrownCameraIntrinsics(); - BrownCameraIntrinsics(const BrownCameraIntrinsics &from); + BrownCameraIntrinsics(const BrownCameraIntrinsics& from); DistortionModelType GetDistortionModelType() const override { return DISTORTION_MODEL_BROWN; @@ -488,8 +488,8 @@ class BrownCameraIntrinsics : public CameraIntrinsics { // coordinates in pixels. void ApplyIntrinsics(double normalized_x, double normalized_y, - double *image_x, - double *image_y) const override; + double* image_x, + double* image_y) const override; // Invert camera intrinsics on the image point to get normalized coordinates. // @@ -497,8 +497,8 @@ class BrownCameraIntrinsics : public CameraIntrinsics { // coordinates to get normalized camera coordinates. void InvertIntrinsics(double image_x, double image_y, - double *normalized_x, - double *normalized_y) const override; + double* normalized_x, + double* normalized_y) const override; virtual void Pack(PackedIntrinsics* packed_intrinsics) const override; virtual void Unpack(const PackedIntrinsics& packed_intrinsics) override; @@ -507,10 +507,8 @@ class BrownCameraIntrinsics : public CameraIntrinsics { double parameters_[NUM_PARAMETERS]; }; - /// A human-readable representation of the camera intrinsic parameters. -std::ostream& operator <<(std::ostream &os, - const CameraIntrinsics &intrinsics); +std::ostream& operator<<(std::ostream& os, const CameraIntrinsics& intrinsics); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h index e1b53992dfd..c8c4700f5c6 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_impl.h @@ -25,11 +25,11 @@ namespace { // FIXME: C++ templates limitations makes thing complicated, // but maybe there is a simpler method. struct ApplyIntrinsicsFunction { - ApplyIntrinsicsFunction(const CameraIntrinsics &intrinsics, + ApplyIntrinsicsFunction(const CameraIntrinsics& intrinsics, double x, double y, - double *warp_x, - double *warp_y) { + double* warp_x, + double* warp_y) { double normalized_x, normalized_y; intrinsics.ImageSpaceToNormalized(x, y, &normalized_x, &normalized_y); intrinsics.ApplyIntrinsics(normalized_x, normalized_y, warp_x, warp_y); @@ -37,14 +37,15 @@ struct ApplyIntrinsicsFunction { }; struct InvertIntrinsicsFunction { - InvertIntrinsicsFunction(const CameraIntrinsics &intrinsics, + InvertIntrinsicsFunction(const CameraIntrinsics& intrinsics, double x, double y, - double *warp_x, - double *warp_y) { + double* warp_x, + double* warp_y) { double normalized_x, normalized_y; intrinsics.InvertIntrinsics(x, y, &normalized_x, &normalized_y); - intrinsics.NormalizedToImageSpace(normalized_x, normalized_y, warp_x, warp_y); + intrinsics.NormalizedToImageSpace( + normalized_x, normalized_y, warp_x, warp_y); } }; @@ -53,18 +54,18 @@ struct InvertIntrinsicsFunction { namespace internal { // TODO(MatthiasF): downsample lookup -template<typename WarpFunction> -void LookupWarpGrid::Compute(const CameraIntrinsics &intrinsics, +template <typename WarpFunction> +void LookupWarpGrid::Compute(const CameraIntrinsics& intrinsics, int width, int height, double overscan) { - double w = (double) width / (1.0 + overscan); - double h = (double) height / (1.0 + overscan); - double aspx = (double) w / intrinsics.image_width(); - double aspy = (double) h / intrinsics.image_height(); + double w = (double)width / (1.0 + overscan); + double h = (double)height / (1.0 + overscan); + double aspx = (double)w / intrinsics.image_width(); + double aspy = (double)h / intrinsics.image_height(); #if defined(_OPENMP) -# pragma omp parallel for schedule(static) num_threads(threads_) \ - if (threads_ > 1 && height > 100) +# pragma omp parallel for schedule(static) \ + num_threads(threads_) if (threads_ > 1 && height > 100) #endif for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { @@ -76,40 +77,47 @@ void LookupWarpGrid::Compute(const CameraIntrinsics &intrinsics, warp_y = warp_y * aspy + 0.5 * overscan * h; int ix = int(warp_x), iy = int(warp_y); int fx = round((warp_x - ix) * 256), fy = round((warp_y - iy) * 256); - if (fx == 256) { fx = 0; ix++; } // NOLINT - if (fy == 256) { fy = 0; iy++; } // NOLINT + if (fx == 256) { + fx = 0; + ix++; + } // NOLINT + if (fy == 256) { + fy = 0; + iy++; + } // NOLINT // Use nearest border pixel - if (ix < 0) { ix = 0, fx = 0; } // NOLINT - if (iy < 0) { iy = 0, fy = 0; } // NOLINT - if (ix >= width - 2) ix = width - 2; - if (iy >= height - 2) iy = height - 2; - - Offset offset = { (short) (ix - x), - (short) (iy - y), - (unsigned char) fx, - (unsigned char) fy }; + if (ix < 0) { + ix = 0, fx = 0; + } // NOLINT + if (iy < 0) { + iy = 0, fy = 0; + } // NOLINT + if (ix >= width - 2) + ix = width - 2; + if (iy >= height - 2) + iy = height - 2; + + Offset offset = {(short)(ix - x), + (short)(iy - y), + (unsigned char)fx, + (unsigned char)fy}; offset_[y * width + x] = offset; } } } -template<typename WarpFunction> -void LookupWarpGrid::Update(const CameraIntrinsics &intrinsics, +template <typename WarpFunction> +void LookupWarpGrid::Update(const CameraIntrinsics& intrinsics, int width, int height, double overscan) { - if (width_ != width || - height_ != height || - overscan_ != overscan) { + if (width_ != width || height_ != height || overscan_ != overscan) { Reset(); } if (offset_ == NULL) { offset_ = new Offset[width * height]; - Compute<WarpFunction>(intrinsics, - width, - height, - overscan); + Compute<WarpFunction>(intrinsics, width, height, overscan); } width_ = width; @@ -118,29 +126,30 @@ void LookupWarpGrid::Update(const CameraIntrinsics &intrinsics, } // TODO(MatthiasF): cubic B-Spline image sampling, bilinear lookup -template<typename PixelType> -void LookupWarpGrid::Apply(const PixelType *input_buffer, +template <typename PixelType> +void LookupWarpGrid::Apply(const PixelType* input_buffer, int width, int height, int channels, - PixelType *output_buffer) { + PixelType* output_buffer) { #if defined(_OPENMP) -# pragma omp parallel for schedule(static) num_threads(threads_) \ - if (threads_ > 1 && height > 100) +# pragma omp parallel for schedule(static) \ + num_threads(threads_) if (threads_ > 1 && height > 100) #endif for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Offset offset = offset_[y * width + x]; - const int pixel_index = ((y + offset.iy) * width + - (x + offset.ix)) * channels; - const PixelType *s = &input_buffer[pixel_index]; + const int pixel_index = + ((y + offset.iy) * width + (x + offset.ix)) * channels; + const PixelType* s = &input_buffer[pixel_index]; for (int i = 0; i < channels; i++) { output_buffer[(y * width + x) * channels + i] = - ((s[i] * (256 - offset.fx) + - s[channels + i] * offset.fx) * (256 - offset.fy) + - (s[width * channels + i] * (256 - offset.fx) + - s[width * channels + channels + i] * offset.fx) * offset.fy) - / (256 * 256); + ((s[i] * (256 - offset.fx) + s[channels + i] * offset.fx) * + (256 - offset.fy) + + (s[width * channels + i] * (256 - offset.fx) + + s[width * channels + channels + i] * offset.fx) * + offset.fy) / + (256 * 256); } } } @@ -148,45 +157,33 @@ void LookupWarpGrid::Apply(const PixelType *input_buffer, } // namespace internal -template<typename PixelType> -void CameraIntrinsics::DistortBuffer(const PixelType *input_buffer, +template <typename PixelType> +void CameraIntrinsics::DistortBuffer(const PixelType* input_buffer, int width, int height, double overscan, int channels, - PixelType *output_buffer) { + PixelType* output_buffer) { assert(channels >= 1); assert(channels <= 4); - distort_.Update<InvertIntrinsicsFunction>(*this, - width, - height, - overscan); - distort_.Apply<PixelType>(input_buffer, - width, - height, - channels, - output_buffer); + distort_.Update<InvertIntrinsicsFunction>(*this, width, height, overscan); + distort_.Apply<PixelType>( + input_buffer, width, height, channels, output_buffer); } -template<typename PixelType> -void CameraIntrinsics::UndistortBuffer(const PixelType *input_buffer, +template <typename PixelType> +void CameraIntrinsics::UndistortBuffer(const PixelType* input_buffer, int width, int height, double overscan, int channels, - PixelType *output_buffer) { + PixelType* output_buffer) { assert(channels >= 1); assert(channels <= 4); - undistort_.Update<ApplyIntrinsicsFunction>(*this, - width, - height, - overscan); - - undistort_.Apply<PixelType>(input_buffer, - width, - height, - channels, - output_buffer); + undistort_.Update<ApplyIntrinsicsFunction>(*this, width, height, overscan); + + undistort_.Apply<PixelType>( + input_buffer, width, height, channels, output_buffer); } } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc index 96d35a29ef8..cfcc2d16682 100644 --- a/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc +++ b/intern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc @@ -22,10 +22,10 @@ #include <iostream> -#include "testing/testing.h" #include "libmv/image/image.h" #include "libmv/image/image_drawing.h" #include "libmv/logging/logging.h" +#include "testing/testing.h" namespace libmv { @@ -59,26 +59,36 @@ TEST(PolynomialCameraIntrinsics, ApplyIntrinsics) { const int N = 5; double expected[N][N][2] = { - { {75.312500, -24.687500}, {338.982239, -62.035522}, - {640.000000, -72.929688}, {941.017761, -62.035522}, - {1204.687500, -24.687500}}, - - { {37.964478, 238.982239}, {323.664551, 223.664551}, - {640.000000, 219.193420}, {956.335449, 223.664551}, - {1242.035522, 238.982239}}, - - { {27.070312, 540.000000}, {319.193420, 540.000000}, - {640.000000, 540.000000}, {960.806580, 540.000000}, - {1252.929688, 540.000000}}, - - { {37.964478, 841.017761}, {323.664551, 856.335449}, - {640.000000, 860.806580}, {956.335449, 856.335449}, - {1242.035522, 841.017761}}, - - { {75.312500, 1104.687500}, {338.982239, 1142.035522}, - {640.000000, 1152.929688}, {941.017761, 1142.035522}, - {1204.687500, 1104.687500}} - }; + {{75.312500, -24.687500}, + {338.982239, -62.035522}, + {640.000000, -72.929688}, + {941.017761, -62.035522}, + {1204.687500, -24.687500}}, + + {{37.964478, 238.982239}, + {323.664551, 223.664551}, + {640.000000, 219.193420}, + {956.335449, 223.664551}, + {1242.035522, 238.982239}}, + + {{27.070312, 540.000000}, + {319.193420, 540.000000}, + {640.000000, 540.000000}, + {960.806580, 540.000000}, + {1252.929688, 540.000000}}, + + {{37.964478, 841.017761}, + {323.664551, 856.335449}, + {640.000000, 860.806580}, + {956.335449, 856.335449}, + {1242.035522, 841.017761}}, + + {{75.312500, 1104.687500}, + {338.982239, 1142.035522}, + {640.000000, 1152.929688}, + {941.017761, 1142.035522}, + {1204.687500, 1104.687500}}, + }; PolynomialCameraIntrinsics intrinsics; intrinsics.SetFocalLength(1300.0, 1300.0); @@ -89,12 +99,11 @@ TEST(PolynomialCameraIntrinsics, ApplyIntrinsics) { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { - double normalized_x = j * step - 0.5, - normalized_y = i * step - 0.5; + double normalized_x = j * step - 0.5, normalized_y = i * step - 0.5; double distorted_x, distorted_y; - intrinsics.ApplyIntrinsics(normalized_x, normalized_y, - &distorted_x, &distorted_y); + intrinsics.ApplyIntrinsics( + normalized_x, normalized_y, &distorted_x, &distorted_y); EXPECT_NEAR(expected[i][j][0], distorted_x, 1e-6); EXPECT_NEAR(expected[i][j][1], distorted_y, 1e-6); @@ -106,43 +115,51 @@ TEST(PolynomialCameraIntrinsics, InvertIntrinsics) { const int N = 5; double expected[N][N][2] = { - { {-0.524482, -0.437069}, {-0.226237, -0.403994}, - { 0.031876, -0.398446}, { 0.293917, -0.408218}, - { 0.632438, -0.465028}}, - - { {-0.493496, -0.189173}, {-0.219052, -0.179936}, - { 0.030975, -0.178107}, { 0.283742, -0.181280}, - { 0.574557, -0.194335}}, - - { {-0.488013, 0.032534}, {-0.217537, 0.031077}, - { 0.030781, 0.030781}, { 0.281635, 0.031293}, - { 0.566344, 0.033314}}, - - { {-0.498696, 0.257660}, {-0.220424, 0.244041}, - { 0.031150, 0.241409}, { 0.285660, 0.245985}, - { 0.582670, 0.265629}}, - - { {-0.550617, 0.532263}, {-0.230399, 0.477255}, - { 0.032380, 0.469510}, { 0.299986, 0.483311}, - { 0.684740, 0.584043}} - }; + {{-0.524482, -0.437069}, + {-0.226237, -0.403994}, + {0.031876, -0.398446}, + {0.293917, -0.408218}, + {0.632438, -0.465028}}, + + {{-0.493496, -0.189173}, + {-0.219052, -0.179936}, + {0.030975, -0.178107}, + {0.283742, -0.181280}, + {0.574557, -0.194335}}, + + {{-0.488013, 0.032534}, + {-0.217537, 0.031077}, + {0.030781, 0.030781}, + {0.281635, 0.031293}, + {0.566344, 0.033314}}, + + {{-0.498696, 0.257660}, + {-0.220424, 0.244041}, + {0.031150, 0.241409}, + {0.285660, 0.245985}, + {0.582670, 0.265629}}, + + {{-0.550617, 0.532263}, + {-0.230399, 0.477255}, + {0.032380, 0.469510}, + {0.299986, 0.483311}, + {0.684740, 0.584043}}, + }; PolynomialCameraIntrinsics intrinsics; intrinsics.SetFocalLength(1300.0, 1300.0); intrinsics.SetPrincipalPoint(600.0, 500.0); intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05); - double step_x = 1280.0 / (N - 1), - step_y = 1080.0 / (N - 1); + double step_x = 1280.0 / (N - 1), step_y = 1080.0 / (N - 1); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { - double distorted_x = j * step_x, - distorted_y = i * step_y; + double distorted_x = j * step_x, distorted_y = i * step_y; double normalized_x, normalized_y; - intrinsics.InvertIntrinsics(distorted_x, distorted_y, - &normalized_x, &normalized_y); + intrinsics.InvertIntrinsics( + distorted_x, distorted_y, &normalized_x, &normalized_y); EXPECT_NEAR(expected[i][j][0], normalized_x, 1e-6); EXPECT_NEAR(expected[i][j][1], normalized_y, 1e-6); @@ -190,10 +207,11 @@ TEST(PolynomialCameraIntrinsics, IdentityDistortBuffer) { FloatImage distorted_image(h, w); intrinsics.SetImageSize(w, h); intrinsics.SetFocalLength(10.0, 10.0); - intrinsics.SetPrincipalPoint((double) w / 2.0, (double) h / 2.0); + intrinsics.SetPrincipalPoint((double)w / 2.0, (double)h / 2.0); intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); intrinsics.DistortBuffer(image.Data(), - image.Width(), image.Height(), + image.Width(), + image.Height(), 0.0, image.Depth(), distorted_image.Data()); @@ -221,10 +239,11 @@ TEST(PolynomialCameraIntrinsics, IdentityUndistortBuffer) { FloatImage distorted_image(h, w); intrinsics.SetImageSize(w, h); intrinsics.SetFocalLength(10.0, 10.0); - intrinsics.SetPrincipalPoint((double) w / 2.0, (double) h / 2.0); + intrinsics.SetPrincipalPoint((double)w / 2.0, (double)h / 2.0); intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); intrinsics.UndistortBuffer(image.Data(), - image.Width(), image.Height(), + image.Width(), + image.Height(), 0.0, image.Depth(), distorted_image.Data()); diff --git a/intern/libmv/libmv/simple_pipeline/detect.cc b/intern/libmv/libmv/simple_pipeline/detect.cc index 46599a4c49e..0897c5598c6 100644 --- a/intern/libmv/libmv/simple_pipeline/detect.cc +++ b/intern/libmv/libmv/simple_pipeline/detect.cc @@ -22,14 +22,14 @@ ** ****************************************************************************/ -#include <stdlib.h> #include <memory.h> +#include <stdlib.h> #include <queue> #include "libmv/base/scoped_ptr.h" #include "libmv/image/array_nd.h" -#include "libmv/image/image_converter.h" #include "libmv/image/convolve.h" +#include "libmv/image/image_converter.h" #include "libmv/logging/logging.h" #include "libmv/simple_pipeline/detect.h" @@ -55,7 +55,7 @@ double kDefaultHarrisThreshold = 1e-5; class FeatureComparison { public: - bool operator() (const Feature &left, const Feature &right) const { + bool operator()(const Feature& left, const Feature& right) const { return right.score > left.score; } }; @@ -63,18 +63,17 @@ class FeatureComparison { // Filter the features so there are no features closer than // minimal distance to each other. // This is a naive implementation with O(n^2) asymptotic. -void FilterFeaturesByDistance(const vector<Feature> &all_features, +void FilterFeaturesByDistance(const vector<Feature>& all_features, int min_distance, - vector<Feature> *detected_features) { + vector<Feature>* detected_features) { const int min_distance_squared = min_distance * min_distance; // Use priority queue to sort the features by their score. // // Do this on copy of the input features to prevent possible // distortion in callee function behavior. - std::priority_queue<Feature, - std::vector<Feature>, - FeatureComparison> priority_features; + std::priority_queue<Feature, std::vector<Feature>, FeatureComparison> + priority_features; for (int i = 0; i < all_features.size(); i++) { priority_features.push(all_features.at(i)); @@ -85,7 +84,7 @@ void FilterFeaturesByDistance(const vector<Feature> &all_features, Feature a = priority_features.top(); for (int i = 0; i < detected_features->size(); i++) { - Feature &b = detected_features->at(i); + Feature& b = detected_features->at(i); if (Square(a.x - b.x) + Square(a.y - b.y) < min_distance_squared) { ok = false; break; @@ -100,9 +99,9 @@ void FilterFeaturesByDistance(const vector<Feature> &all_features, } } -void DetectFAST(const FloatImage &grayscale_image, - const DetectOptions &options, - vector<Feature> *detected_features) { +void DetectFAST(const FloatImage& grayscale_image, + const DetectOptions& options, + vector<Feature>* detected_features) { #ifndef LIBMV_NO_FAST_DETECTOR const int min_distance = options.min_distance; const int min_trackness = options.fast_min_trackness; @@ -111,12 +110,14 @@ void DetectFAST(const FloatImage &grayscale_image, const int height = grayscale_image.Width() - 2 * margin; const int stride = grayscale_image.Width(); - scoped_array<unsigned char> byte_image(FloatImageToUCharArray(grayscale_image)); + scoped_array<unsigned char> byte_image( + FloatImageToUCharArray(grayscale_image)); const int byte_image_offset = margin * stride + margin; - // TODO(MatthiasF): Support targetting a feature count (binary search trackness) + // TODO(MatthiasF): Support targetting a feature count (binary search + // trackness) int num_features; - xy *all = fast9_detect(byte_image.get() + byte_image_offset, + xy* all = fast9_detect(byte_image.get() + byte_image_offset, width, height, stride, @@ -126,13 +127,13 @@ void DetectFAST(const FloatImage &grayscale_image, free(all); return; } - int *scores = fast9_score(byte_image.get() + byte_image_offset, + int* scores = fast9_score(byte_image.get() + byte_image_offset, stride, all, num_features, min_trackness); // TODO(MatthiasF): merge with close feature suppression - xy *nonmax = nonmax_suppression(all, scores, num_features, &num_features); + xy* nonmax = nonmax_suppression(all, scores, num_features, &num_features); free(all); // Remove too close features // TODO(MatthiasF): A resolution independent parameter would be better than @@ -152,89 +153,104 @@ void DetectFAST(const FloatImage &grayscale_image, free(scores); free(nonmax); #else - (void) grayscale_image; // Ignored. - (void) options; // Ignored. - (void) detected_features; // Ignored. + (void)grayscale_image; // Ignored. + (void)options; // Ignored. + (void)detected_features; // Ignored. LOG(FATAL) << "FAST detector is disabled in this build."; #endif } #ifdef __SSE2__ -static unsigned int SAD(const ubyte* imageA, const ubyte* imageB, - int strideA, int strideB) { +static unsigned int SAD(const ubyte* imageA, + const ubyte* imageB, + int strideA, + int strideB) { __m128i a = _mm_setzero_si128(); for (int i = 0; i < 16; i++) { - a = _mm_adds_epu16(a, - _mm_sad_epu8(_mm_loadu_si128((__m128i*)(imageA+i*strideA)), - _mm_loadu_si128((__m128i*)(imageB+i*strideB)))); + a = _mm_adds_epu16( + a, + _mm_sad_epu8(_mm_loadu_si128((__m128i*)(imageA + i * strideA)), + _mm_loadu_si128((__m128i*)(imageB + i * strideB)))); } return _mm_extract_epi16(a, 0) + _mm_extract_epi16(a, 4); } #else -static unsigned int SAD(const ubyte* imageA, const ubyte* imageB, - int strideA, int strideB) { +static unsigned int SAD(const ubyte* imageA, + const ubyte* imageB, + int strideA, + int strideB) { unsigned int sad = 0; for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { - sad += abs((int)imageA[i*strideA+j] - imageB[i*strideB+j]); + sad += abs((int)imageA[i * strideA + j] - imageB[i * strideB + j]); } } return sad; } #endif -void DetectMORAVEC(const FloatImage &grayscale_image, - const DetectOptions &options, - vector<Feature> *detected_features) { +void DetectMORAVEC(const FloatImage& grayscale_image, + const DetectOptions& options, + vector<Feature>* detected_features) { const int distance = options.min_distance; const int margin = options.margin; - const unsigned char *pattern = options.moravec_pattern; + const unsigned char* pattern = options.moravec_pattern; const int count = options.moravec_max_count; const int width = grayscale_image.Width() - 2 * margin; const int height = grayscale_image.Width() - 2 * margin; const int stride = grayscale_image.Width(); - scoped_array<unsigned char> byte_image(FloatImageToUCharArray(grayscale_image)); + scoped_array<unsigned char> byte_image( + FloatImageToUCharArray(grayscale_image)); unsigned short histogram[256]; memset(histogram, 0, sizeof(histogram)); - scoped_array<ubyte> scores(new ubyte[width*height]); - memset(scores.get(), 0, width*height); + scoped_array<ubyte> scores(new ubyte[width * height]); + memset(scores.get(), 0, width * height); const int r = 1; // radius for self similarity comparison - for (int y = distance; y < height-distance; y++) { - for (int x = distance; x < width-distance; x++) { - const ubyte* s = &byte_image[y*stride+x]; - int score = // low self-similarity with overlapping patterns - // OPTI: load pattern once + for (int y = distance; y < height - distance; y++) { + for (int x = distance; x < width - distance; x++) { + const ubyte* s = &byte_image[y * stride + x]; + // low self-similarity with overlapping patterns + // OPTI: load pattern once + // clang-format off + int score = SAD(s, s-r*stride-r, stride, stride)+SAD(s, s-r*stride, stride, stride)+SAD(s, s-r*stride+r, stride, stride)+ SAD(s, s -r, stride, stride)+ SAD(s, s +r, stride, stride)+ SAD(s, s+r*stride-r, stride, stride)+SAD(s, s+r*stride, stride, stride)+SAD(s, s+r*stride+r, stride, stride); + // clang-format on + score /= 256; // normalize - if (pattern) // find only features similar to pattern + if (pattern) // find only features similar to pattern score -= SAD(s, pattern, stride, 16); - if (score <= 16) continue; // filter very self-similar features + if (score <= 16) + continue; // filter very self-similar features score -= 16; // translate to score/histogram values - if (score>255) score=255; // clip - ubyte* c = &scores[y*width+x]; + if (score > 255) + score = 255; // clip + ubyte* c = &scores[y * width + x]; for (int i = -distance; i < 0; i++) { for (int j = -distance; j < distance; j++) { - int s = c[i*width+j]; - if (s == 0) continue; - if (s >= score) goto nonmax; - c[i*width+j] = 0; + int s = c[i * width + j]; + if (s == 0) + continue; + if (s >= score) + goto nonmax; + c[i * width + j] = 0; histogram[s]--; } } for (int i = 0, j = -distance; j < 0; j++) { - int s = c[i*width+j]; - if (s == 0) continue; - if (s >= score) goto nonmax; - c[i*width+j] = 0; + int s = c[i * width + j]; + if (s == 0) + continue; + if (s >= score) + goto nonmax; + c[i * width + j] = 0; histogram[s]--; } c[0] = score, histogram[score]++; - nonmax: - { } // Do nothing. + nonmax : {} // Do nothing. } } int min = 255, total = 0; @@ -254,18 +270,16 @@ void DetectMORAVEC(const FloatImage &grayscale_image, // Score calculation above uses top left corner of the // patch as the origin, here we need to convert this value // to a pattrn center by adding 8 pixels. - detected_features->push_back(Feature((float) x + 8.0f, - (float) y + 8.0f, - (float) s, - 16.0f)); + detected_features->push_back( + Feature((float)x + 8.0f, (float)y + 8.0f, (float)s, 16.0f)); } } } } -void DetectHarris(const FloatImage &grayscale_image, - const DetectOptions &options, - vector<Feature> *detected_features) { +void DetectHarris(const FloatImage& grayscale_image, + const DetectOptions& options, + vector<Feature>* detected_features) { const double alpha = 0.06; const double sigma = 0.9; @@ -281,9 +295,7 @@ void DetectHarris(const FloatImage &grayscale_image, MultiplyElements(gradient_y, gradient_y, &gradient_yy); MultiplyElements(gradient_x, gradient_y, &gradient_xy); - FloatImage gradient_xx_blurred, - gradient_yy_blurred, - gradient_xy_blurred; + FloatImage gradient_xx_blurred, gradient_yy_blurred, gradient_xy_blurred; ConvolveGaussian(gradient_xx, sigma, &gradient_xx_blurred); ConvolveGaussian(gradient_yy, sigma, &gradient_yy_blurred); ConvolveGaussian(gradient_xy, sigma, &gradient_xy_blurred); @@ -304,10 +316,8 @@ void DetectHarris(const FloatImage &grayscale_image, double traceA = A.trace(); double harris_function = detA - alpha * traceA * traceA; if (harris_function > threshold) { - all_features.push_back(Feature((float) x, - (float) y, - (float) harris_function, - 5.0f)); + all_features.push_back( + Feature((float)x, (float)y, (float)harris_function, 5.0f)); } } } @@ -318,17 +328,18 @@ void DetectHarris(const FloatImage &grayscale_image, } // namespace DetectOptions::DetectOptions() - : type(DetectOptions::HARRIS), - margin(0), - min_distance(120), - fast_min_trackness(kDefaultFastMinTrackness), - moravec_max_count(0), - moravec_pattern(NULL), - harris_threshold(kDefaultHarrisThreshold) {} - -void Detect(const FloatImage &image, - const DetectOptions &options, - vector<Feature> *detected_features) { + : type(DetectOptions::HARRIS), + margin(0), + min_distance(120), + fast_min_trackness(kDefaultFastMinTrackness), + moravec_max_count(0), + moravec_pattern(NULL), + harris_threshold(kDefaultHarrisThreshold) { +} + +void Detect(const FloatImage& image, + const DetectOptions& options, + vector<Feature>* detected_features) { // Currently all the detectors requires image to be grayscale. // Do it here to avoid code duplication. FloatImage grayscale_image; @@ -350,8 +361,7 @@ void Detect(const FloatImage &image, } } -std::ostream& operator <<(std::ostream &os, - const Feature &feature) { +std::ostream& operator<<(std::ostream& os, const Feature& feature) { os << "x: " << feature.x << ", y: " << feature.y; os << ", score: " << feature.score; os << ", size: " << feature.size; diff --git a/intern/libmv/libmv/simple_pipeline/detect.h b/intern/libmv/libmv/simple_pipeline/detect.h index 1035287bcf2..8ddf0025e4b 100644 --- a/intern/libmv/libmv/simple_pipeline/detect.h +++ b/intern/libmv/libmv/simple_pipeline/detect.h @@ -39,7 +39,7 @@ typedef unsigned char ubyte; struct Feature { Feature(float x, float y) : x(x), y(y) {} Feature(float x, float y, float score, float size) - : x(x), y(y), score(score), size(size) {} + : x(x), y(y), score(score), size(size) {} // Position of the feature in pixels from top-left corner. // Note: Libmv detector might eventually support subpixel precision. @@ -88,9 +88,9 @@ struct DetectOptions { // Find only features similar to this pattern. Only used by MORAVEC detector. // - // This is an image patch denoted in byte array with dimensions of 16px by 16px - // used to filter features by similarity to this patch. - unsigned char *moravec_pattern; + // This is an image patch denoted in byte array with dimensions of 16px by + // 16px used to filter features by similarity to this patch. + unsigned char* moravec_pattern; // Threshold value of the Harris function to add new featrue // to the result. @@ -101,12 +101,11 @@ struct DetectOptions { // // Image could have 1-4 channels, it'll be converted to a grayscale // by the detector function if needed. -void Detect(const FloatImage &image, - const DetectOptions &options, - vector<Feature> *detected_features); +void Detect(const FloatImage& image, + const DetectOptions& options, + vector<Feature>* detected_features); -std::ostream& operator <<(std::ostream &os, - const Feature &feature); +std::ostream& operator<<(std::ostream& os, const Feature& feature); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/detect_test.cc b/intern/libmv/libmv/simple_pipeline/detect_test.cc index b226ad96595..718598d04e1 100644 --- a/intern/libmv/libmv/simple_pipeline/detect_test.cc +++ b/intern/libmv/libmv/simple_pipeline/detect_test.cc @@ -20,14 +20,14 @@ #include "libmv/simple_pipeline/detect.h" -#include "testing/testing.h" #include "libmv/logging/logging.h" +#include "testing/testing.h" namespace libmv { namespace { -void PreformSinglePointTest(const DetectOptions &options) { +void PreformSinglePointTest(const DetectOptions& options) { // Prepare the image. FloatImage image(15, 15); image.fill(1.0); @@ -40,7 +40,7 @@ void PreformSinglePointTest(const DetectOptions &options) { // Check detected features matches our expectations. EXPECT_EQ(1, detected_features.size()); if (detected_features.size() == 1) { - Feature &feature = detected_features[0]; + Feature& feature = detected_features[0]; EXPECT_EQ(7, feature.x); EXPECT_EQ(7, feature.y); } @@ -83,8 +83,8 @@ void PreformCheckerBoardTest(const DetectOptions &options) { } #endif -void CheckExpectedFeatures(const vector<Feature> &detected_features, - const vector<Feature> &expected_features) { +void CheckExpectedFeatures(const vector<Feature>& detected_features, + const vector<Feature>& expected_features) { EXPECT_EQ(expected_features.size(), detected_features.size()); // That's unsafe to iterate over vectors when their lengths @@ -95,10 +95,10 @@ void CheckExpectedFeatures(const vector<Feature> &detected_features, } for (int i = 0; i < expected_features.size(); ++i) { - const Feature &extected_feature = expected_features[i]; + const Feature& extected_feature = expected_features[i]; bool found = false; for (int j = 0; j < detected_features.size(); ++j) { - const Feature &detected_feature = detected_features[j]; + const Feature& detected_feature = detected_features[j]; if (extected_feature.x == detected_feature.x && extected_feature.y == detected_feature.y) { found = true; @@ -109,15 +109,14 @@ void CheckExpectedFeatures(const vector<Feature> &detected_features, } } -void PreformSingleTriangleTest(const DetectOptions &options) { +void PreformSingleTriangleTest(const DetectOptions& options) { // Prepare the image. FloatImage image(15, 21); image.fill(1.0); int vertex_x = 10, vertex_y = 5; for (int i = 0; i < 6; ++i) { - int current_x = vertex_x - i, - current_y = vertex_y + i; + int current_x = vertex_x - i, current_y = vertex_y + i; for (int j = 0; j < i * 2 + 1; ++j, ++current_x) { image(current_y, current_x) = 0.0; } diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.cc b/intern/libmv/libmv/simple_pipeline/distortion_models.cc index f602234b630..4556e3ceaf9 100644 --- a/intern/libmv/libmv/simple_pipeline/distortion_models.cc +++ b/intern/libmv/libmv/simple_pipeline/distortion_models.cc @@ -41,25 +41,34 @@ struct InvertPolynomialIntrinsicsCostFunction { const double p2, const double image_x, const double image_y) - : focal_length_x_(focal_length_x), - focal_length_y_(focal_length_y), - principal_point_x_(principal_point_x), - principal_point_y_(principal_point_y), - k1_(k1), k2_(k2), k3_(k3), - p1_(p1), p2_(p2), - x_(image_x), y_(image_y) {} - - Vec2 operator()(const Vec2 &u) const { + : focal_length_x_(focal_length_x), + focal_length_y_(focal_length_y), + principal_point_x_(principal_point_x), + principal_point_y_(principal_point_y), + k1_(k1), + k2_(k2), + k3_(k3), + p1_(p1), + p2_(p2), + x_(image_x), + y_(image_y) {} + + Vec2 operator()(const Vec2& u) const { double xx, yy; ApplyPolynomialDistortionModel(focal_length_x_, focal_length_y_, principal_point_x_, principal_point_y_, - k1_, k2_, k3_, - p1_, p2_, - u(0), u(1), - &xx, &yy); + k1_, + k2_, + k3_, + p1_, + p2_, + u(0), + u(1), + &xx, + &yy); Vec2 fx; fx << (xx - x_), (yy - y_); @@ -87,23 +96,28 @@ struct InvertDivisionIntrinsicsCostFunction { const double k2, const double image_x, const double image_y) - : focal_length_x_(focal_length_x), - focal_length_y_(focal_length_y), - principal_point_x_(principal_point_x), - principal_point_y_(principal_point_y), - k1_(k1), k2_(k2), - x_(image_x), y_(image_y) {} - - Vec2 operator()(const Vec2 &u) const { + : focal_length_x_(focal_length_x), + focal_length_y_(focal_length_y), + principal_point_x_(principal_point_x), + principal_point_y_(principal_point_y), + k1_(k1), + k2_(k2), + x_(image_x), + y_(image_y) {} + + Vec2 operator()(const Vec2& u) const { double xx, yy; ApplyDivisionDistortionModel(focal_length_x_, focal_length_y_, principal_point_x_, principal_point_y_, - k1_, k2_, - u(0), u(1), - &xx, &yy); + k1_, + k2_, + u(0), + u(1), + &xx, + &yy); Vec2 fx; fx << (xx - x_), (yy - y_); @@ -134,25 +148,36 @@ struct InvertBrownIntrinsicsCostFunction { const double p2, const double image_x, const double image_y) - : focal_length_x_(focal_length_x), - focal_length_y_(focal_length_y), - principal_point_x_(principal_point_x), - principal_point_y_(principal_point_y), - k1_(k1), k2_(k2), k3_(k3), k4_(k4), - p1_(p1), p2_(p2), - x_(image_x), y_(image_y) {} - - Vec2 operator()(const Vec2 &u) const { + : focal_length_x_(focal_length_x), + focal_length_y_(focal_length_y), + principal_point_x_(principal_point_x), + principal_point_y_(principal_point_y), + k1_(k1), + k2_(k2), + k3_(k3), + k4_(k4), + p1_(p1), + p2_(p2), + x_(image_x), + y_(image_y) {} + + Vec2 operator()(const Vec2& u) const { double xx, yy; ApplyBrownDistortionModel(focal_length_x_, focal_length_y_, principal_point_x_, principal_point_y_, - k1_, k2_, k3_, k4_, - p1_, p2_, - u(0), u(1), - &xx, &yy); + k1_, + k2_, + k3_, + k4_, + p1_, + p2_, + u(0), + u(1), + &xx, + &yy); Vec2 fx; fx << (xx - x_), (yy - y_); @@ -180,8 +205,8 @@ void InvertPolynomialDistortionModel(const double focal_length_x, const double p2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y) { + double* normalized_x, + double* normalized_y) { // Compute the initial guess. For a camera with no distortion, this will also // be the final answer; the LM iteration will terminate immediately. Vec2 normalized; @@ -194,13 +219,17 @@ void InvertPolynomialDistortionModel(const double focal_length_x, focal_length_y, principal_point_x, principal_point_y, - k1, k2, k3, - p1, p2, - image_x, image_y); + k1, + k2, + k3, + p1, + p2, + image_x, + image_y); Solver::SolverParameters params; Solver solver(intrinsics_cost); - /*Solver::Results results =*/ solver.minimize(params, &normalized); + /*Solver::Results results =*/solver.minimize(params, &normalized); // TODO(keir): Better error handling. @@ -216,8 +245,8 @@ void InvertDivisionDistortionModel(const double focal_length_x, const double k2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y) { + double* normalized_x, + double* normalized_y) { // Compute the initial guess. For a camera with no distortion, this will also // be the final answer; the LM iteration will terminate immediately. Vec2 normalized; @@ -231,12 +260,14 @@ void InvertDivisionDistortionModel(const double focal_length_x, focal_length_y, principal_point_x, principal_point_y, - k1, k2, - image_x, image_y); + k1, + k2, + image_x, + image_y); Solver::SolverParameters params; Solver solver(intrinsics_cost); - /*Solver::Results results =*/ solver.minimize(params, &normalized); + /*Solver::Results results =*/solver.minimize(params, &normalized); // TODO(keir): Better error handling. @@ -256,8 +287,8 @@ void InvertBrownDistortionModel(const double focal_length_x, const double p2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y) { + double* normalized_x, + double* normalized_y) { // Compute the initial guess. For a camera with no distortion, this will also // be the final answer; the LM iteration will terminate immediately. Vec2 normalized; @@ -270,13 +301,18 @@ void InvertBrownDistortionModel(const double focal_length_x, focal_length_y, principal_point_x, principal_point_y, - k1, k2, k3, k4, - p1, p2, - image_x, image_y); + k1, + k2, + k3, + k4, + p1, + p2, + image_x, + image_y); Solver::SolverParameters params; Solver solver(intrinsics_cost); - /*Solver::Results results =*/ solver.minimize(params, &normalized); + /*Solver::Results results =*/solver.minimize(params, &normalized); // TODO(keir): Better error handling. @@ -299,31 +335,36 @@ struct ApplyNukeIntrinsicsCostFunction { const double k2, const double expected_normalized_x, const double expected_normalized_y) - : focal_length_x_(focal_length_x), - focal_length_y_(focal_length_y), - principal_point_x_(principal_point_x), - principal_point_y_(principal_point_y), - image_width_(image_width), - image_height_(image_height), - k1_(k1), k2_(k2), - expected_normalized_x_(expected_normalized_x), - expected_normalized_y_(expected_normalized_y) {} - - Vec2 operator()(const Vec2 &image_coordinate) const { + : focal_length_x_(focal_length_x), + focal_length_y_(focal_length_y), + principal_point_x_(principal_point_x), + principal_point_y_(principal_point_y), + image_width_(image_width), + image_height_(image_height), + k1_(k1), + k2_(k2), + expected_normalized_x_(expected_normalized_x), + expected_normalized_y_(expected_normalized_y) {} + + Vec2 operator()(const Vec2& image_coordinate) const { double actual_normalized_x, actual_normalized_y; InvertNukeDistortionModel(focal_length_x_, focal_length_y_, principal_point_x_, principal_point_y_, - image_width_, image_height_, - k1_, k2_, - image_coordinate(0), image_coordinate(1), - &actual_normalized_x, &actual_normalized_y); + image_width_, + image_height_, + k1_, + k2_, + image_coordinate(0), + image_coordinate(1), + &actual_normalized_x, + &actual_normalized_y); Vec2 fx; fx << (actual_normalized_x - expected_normalized_x_), - (actual_normalized_y - expected_normalized_y_); + (actual_normalized_y - expected_normalized_y_); return fx; } double focal_length_x_; @@ -346,8 +387,8 @@ void ApplyNukeDistortionModel(const double focal_length_x, const double k2, const double normalized_x, const double normalized_y, - double *image_x, - double *image_y) { + double* image_x, + double* image_y) { // Compute the initial guess. For a camera with no distortion, this will also // be the final answer; the LM iteration will terminate immediately. Vec2 image; @@ -363,12 +404,14 @@ void ApplyNukeDistortionModel(const double focal_length_x, principal_point_y, image_width, image_height, - k1, k2, - normalized_x, normalized_y); + k1, + k2, + normalized_x, + normalized_y); Solver::SolverParameters params; Solver solver(intrinsics_cost); - /*Solver::Results results =*/ solver.minimize(params, &image); + /*Solver::Results results =*/solver.minimize(params, &image); // TODO(keir): Better error handling. diff --git a/intern/libmv/libmv/simple_pipeline/distortion_models.h b/intern/libmv/libmv/simple_pipeline/distortion_models.h index 51300477956..5fe9fee8d54 100644 --- a/intern/libmv/libmv/simple_pipeline/distortion_models.h +++ b/intern/libmv/libmv/simple_pipeline/distortion_models.h @@ -46,37 +46,37 @@ void InvertPolynomialDistortionModel(const double focal_length_x, const double p2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y); + double* normalized_x, + double* normalized_y); // Apply camera intrinsics to the normalized point to get image coordinates. // This applies the radial lens distortion to a point which is in normalized // camera coordinates (i.e. the principal point is at (0, 0)) to get image // coordinates in pixels. Templated for use with autodifferentiation. template <typename T> -inline void ApplyPolynomialDistortionModel(const T &focal_length_x, - const T &focal_length_y, - const T &principal_point_x, - const T &principal_point_y, - const T &k1, - const T &k2, - const T &k3, - const T &p1, - const T &p2, - const T &normalized_x, - const T &normalized_y, - T *image_x, - T *image_y) { +inline void ApplyPolynomialDistortionModel(const T& focal_length_x, + const T& focal_length_y, + const T& principal_point_x, + const T& principal_point_y, + const T& k1, + const T& k2, + const T& k3, + const T& p1, + const T& p2, + const T& normalized_x, + const T& normalized_y, + T* image_x, + T* image_y) { T x = normalized_x; T y = normalized_y; // Apply distortion to the normalized points to get (xd, yd). - T r2 = x*x + y*y; + T r2 = x * x + y * y; T r4 = r2 * r2; T r6 = r4 * r2; - T r_coeff = (T(1) + k1*r2 + k2*r4 + k3*r6); - T xd = x * r_coeff + T(2)*p1*x*y + p2*(r2 + T(2)*x*x); - T yd = y * r_coeff + T(2)*p2*x*y + p1*(r2 + T(2)*y*y); + T r_coeff = (T(1) + k1 * r2 + k2 * r4 + k3 * r6); + T xd = x * r_coeff + T(2) * p1 * x * y + p2 * (r2 + T(2) * x * x); + T yd = y * r_coeff + T(2) * p2 * x * y + p1 * (r2 + T(2) * y * y); // Apply focal length and principal point to get the final image coordinates. *image_x = focal_length_x * xd + principal_point_x; @@ -96,8 +96,8 @@ void InvertDivisionDistortionModel(const double focal_length_x, const double k2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y); + double* normalized_x, + double* normalized_y); // Apply camera intrinsics to the normalized point to get image coordinates. // This applies the radial lens distortion to a point which is in normalized @@ -106,20 +106,19 @@ void InvertDivisionDistortionModel(const double focal_length_x, // // Uses division distortion model. template <typename T> -inline void ApplyDivisionDistortionModel(const T &focal_length_x, - const T &focal_length_y, - const T &principal_point_x, - const T &principal_point_y, - const T &k1, - const T &k2, - const T &normalized_x, - const T &normalized_y, - T *image_x, - T *image_y) { - +inline void ApplyDivisionDistortionModel(const T& focal_length_x, + const T& focal_length_y, + const T& principal_point_x, + const T& principal_point_y, + const T& k1, + const T& k2, + const T& normalized_x, + const T& normalized_y, + T* image_x, + T* image_y) { T x = normalized_x; T y = normalized_y; - T r2 = x*x + y*y; + T r2 = x * x + y * y; T r4 = r2 * r2; T xd = x / (T(1) + k1 * r2 + k2 * r4); @@ -136,18 +135,18 @@ inline void ApplyDivisionDistortionModel(const T &focal_length_x, // // Uses Nuke distortion model. template <typename T> -void InvertNukeDistortionModel(const T &focal_length_x, - const T &focal_length_y, - const T &principal_point_x, - const T &principal_point_y, +void InvertNukeDistortionModel(const T& focal_length_x, + const T& focal_length_y, + const T& principal_point_x, + const T& principal_point_y, const int image_width, const int image_height, - const T &k1, - const T &k2, - const T &image_x, - const T &image_y, - T *normalized_x, - T *normalized_y) { + const T& k1, + const T& k2, + const T& image_x, + const T& image_y, + T* normalized_x, + T* normalized_y) { // According to the documentation: // // xu = xd / (1 + k0 * rd^2 + k1 * rd^4) @@ -174,9 +173,9 @@ void InvertNukeDistortionModel(const T &focal_length_x, const T xd = (image_x - principal_point_x) / max_half_image_size; const T yd = (image_y - principal_point_y) / max_half_image_size; - T rd2 = xd*xd + yd*yd; + T rd2 = xd * xd + yd * yd; T rd4 = rd2 * rd2; - T r_coeff = T(1) / (T(1) + k1*rd2 + k2*rd4); + T r_coeff = T(1) / (T(1) + k1 * rd2 + k2 * rd4); T xu = xd * r_coeff; T yu = yd * r_coeff; @@ -200,8 +199,8 @@ void ApplyNukeDistortionModel(const double focal_length_x, const double k2, const double normalized_x, const double normalized_y, - double *image_x, - double *image_y); + double* image_x, + double* image_y); // Invert camera intrinsics on the image point to get normalized coordinates. // This inverts the radial lens distortion to a point which is in image pixel @@ -218,24 +217,24 @@ void InvertBrownDistortionModel(const double focal_length_x, const double p2, const double image_x, const double image_y, - double *normalized_x, - double *normalized_y); + double* normalized_x, + double* normalized_y); template <typename T> -inline void ApplyBrownDistortionModel(const T &focal_length_x, - const T &focal_length_y, - const T &principal_point_x, - const T &principal_point_y, - const T &k1, - const T &k2, - const T &k3, - const T &k4, - const T &p1, - const T &p2, - const T &normalized_x, - const T &normalized_y, - T *image_x, - T *image_y) { +inline void ApplyBrownDistortionModel(const T& focal_length_x, + const T& focal_length_y, + const T& principal_point_x, + const T& principal_point_y, + const T& k1, + const T& k2, + const T& k3, + const T& k4, + const T& p1, + const T& p2, + const T& normalized_x, + const T& normalized_y, + T* image_x, + T* image_y) { T x = normalized_x; T y = normalized_y; @@ -253,8 +252,8 @@ inline void ApplyBrownDistortionModel(const T &focal_length_x, // Apply focal length and principal point to get the final image coordinates. *image_x = focal_length_x * xd + principal_point_x; *image_y = focal_length_y * yd + principal_point_y; -} // namespace libmv +} // namespace libmv -} +} // namespace libmv #endif // LIBMV_SIMPLE_PIPELINE_DISTORTION_MODELS_H_ diff --git a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc index 7a086c375d5..10ad0929007 100644 --- a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc +++ b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.cc @@ -32,8 +32,9 @@ namespace libmv { namespace { -void GetImagesInMarkers(const vector<Marker> &markers, - int *image1, int *image2) { +void GetImagesInMarkers(const vector<Marker>& markers, + int* image1, + int* image2) { if (markers.size() < 2) { return; } @@ -50,10 +51,11 @@ void GetImagesInMarkers(const vector<Marker> &markers, } // namespace -bool EuclideanReconstructTwoFrames(const vector<Marker> &markers, - EuclideanReconstruction *reconstruction) { +bool EuclideanReconstructTwoFrames(const vector<Marker>& markers, + EuclideanReconstruction* reconstruction) { if (markers.size() < 16) { - LG << "Not enough markers to initialize from two frames: " << markers.size(); + LG << "Not enough markers to initialize from two frames: " + << markers.size(); return false; } @@ -76,10 +78,8 @@ bool EuclideanReconstructTwoFrames(const vector<Marker> &markers, Mat3 R; Vec3 t; Mat3 K = Mat3::Identity(); - if (!MotionFromEssentialAndCorrespondence(E, - K, x1.col(0), - K, x2.col(0), - &R, &t)) { + if (!MotionFromEssentialAndCorrespondence( + E, K, x1.col(0), K, x2.col(0), &R, &t)) { LG << "Failed to compute R and t from E and K."; return false; } @@ -88,14 +88,14 @@ bool EuclideanReconstructTwoFrames(const vector<Marker> &markers, reconstruction->InsertCamera(image1, Mat3::Identity(), Vec3::Zero()); reconstruction->InsertCamera(image2, R, t); - LG << "From two frame reconstruction got:\nR:\n" << R - << "\nt:" << t.transpose(); + LG << "From two frame reconstruction got:\nR:\n" + << R << "\nt:" << t.transpose(); return true; } namespace { -Mat3 DecodeF(const Vec9 &encoded_F) { +Mat3 DecodeF(const Vec9& encoded_F) { // Decode F and force it to be rank 2. Map<const Mat3> full_rank_F(encoded_F.data(), 3, 3); Eigen::JacobiSVD<Mat3> svd(full_rank_F, @@ -110,22 +110,22 @@ Mat3 DecodeF(const Vec9 &encoded_F) { // doing a full SVD of F at each iteration. This uses sampson error. struct FundamentalSampsonCostFunction { public: - typedef Vec FMatrixType; + typedef Vec FMatrixType; typedef Vec9 XMatrixType; // Assumes markers are ordered by track. - explicit FundamentalSampsonCostFunction(const vector<Marker> &markers) - : markers(markers) {} + explicit FundamentalSampsonCostFunction(const vector<Marker>& markers) + : markers(markers) {} - Vec operator()(const Vec9 &encoded_F) const { + Vec operator()(const Vec9& encoded_F) const { // Decode F and force it to be rank 2. Mat3 F = DecodeF(encoded_F); Vec residuals(markers.size() / 2); residuals.setZero(); for (int i = 0; i < markers.size() / 2; ++i) { - const Marker &marker1 = markers[2*i + 0]; - const Marker &marker2 = markers[2*i + 1]; + const Marker& marker1 = markers[2 * i + 0]; + const Marker& marker2 = markers[2 * i + 1]; CHECK_EQ(marker1.track, marker2.track); Vec2 x1(marker1.x, marker1.y); Vec2 x2(marker2.x, marker2.y); @@ -134,13 +134,13 @@ struct FundamentalSampsonCostFunction { } return residuals; } - const vector<Marker> &markers; + const vector<Marker>& markers; }; } // namespace -bool ProjectiveReconstructTwoFrames(const vector<Marker> &markers, - ProjectiveReconstruction *reconstruction) { +bool ProjectiveReconstructTwoFrames(const vector<Marker>& markers, + ProjectiveReconstruction* reconstruction) { if (markers.size() < 16) { return false; } diff --git a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h index 32cd4285190..354db14971f 100644 --- a/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h +++ b/intern/libmv/libmv/simple_pipeline/initialize_reconstruction.h @@ -37,18 +37,19 @@ class ProjectiveReconstruction; tracks visible in both frames. The pose estimation of the camera for these frames will be inserted into \a *reconstruction. - \note The two frames need to have both enough parallax and enough common tracks - for accurate reconstruction. At least 8 tracks are suggested. - \note The origin of the coordinate system is defined to be the camera of - the first keyframe. - \note This assumes a calibrated reconstruction, e.g. the markers are - already corrected for camera intrinsics and radial distortion. + \note The two frames need to have both enough parallax and enough common + tracks for accurate reconstruction. At least 8 tracks are suggested. + \note The origin of the coordinate system is defined to be the camera of the + first keyframe. + \note This assumes a calibrated reconstruction, e.g. the + markers are already corrected for camera intrinsics and radial + distortion. \note This assumes an outlier-free set of markers. \sa EuclideanResect, EuclideanIntersect, EuclideanBundle */ -bool EuclideanReconstructTwoFrames(const vector<Marker> &markers, - EuclideanReconstruction *reconstruction); +bool EuclideanReconstructTwoFrames(const vector<Marker>& markers, + EuclideanReconstruction* reconstruction); /*! Initialize the \link ProjectiveReconstruction reconstruction \endlink using @@ -58,17 +59,17 @@ bool EuclideanReconstructTwoFrames(const vector<Marker> &markers, tracks visible in both frames. An estimate of the projection matrices for the two frames will get added to the reconstruction. - \note The two frames need to have both enough parallax and enough common tracks - for accurate reconstruction. At least 8 tracks are suggested. - \note The origin of the coordinate system is defined to be the camera of - the first keyframe. + \note The two frames need to have both enough parallax and enough common + tracks for accurate reconstruction. At least 8 tracks are suggested. + \note The origin of the coordinate system is defined to be the camera of the + first keyframe. \note This assumes the markers are already corrected for radial distortion. \note This assumes an outlier-free set of markers. \sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle */ -bool ProjectiveReconstructTwoFrames(const vector<Marker> &markers, - ProjectiveReconstruction *reconstruction); +bool ProjectiveReconstructTwoFrames(const vector<Marker>& markers, + ProjectiveReconstruction* reconstruction); } // namespace libmv #endif // LIBMV_SIMPLE_PIPELINE_INITIALIZE_RECONSTRUCTION_H diff --git a/intern/libmv/libmv/simple_pipeline/intersect.cc b/intern/libmv/libmv/simple_pipeline/intersect.cc index ddb713684a4..86efd26f778 100644 --- a/intern/libmv/libmv/simple_pipeline/intersect.cc +++ b/intern/libmv/libmv/simple_pipeline/intersect.cc @@ -22,11 +22,11 @@ #include "libmv/base/vector.h" #include "libmv/logging/logging.h" +#include "libmv/multiview/nviewtriangulation.h" #include "libmv/multiview/projection.h" #include "libmv/multiview/triangulation.h" -#include "libmv/multiview/nviewtriangulation.h" -#include "libmv/numeric/numeric.h" #include "libmv/numeric/levenberg_marquardt.h" +#include "libmv/numeric/numeric.h" #include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/tracks.h" @@ -38,12 +38,12 @@ namespace { class EuclideanIntersectCostFunctor { public: - EuclideanIntersectCostFunctor(const Marker &marker, - const EuclideanCamera &camera) + EuclideanIntersectCostFunctor(const Marker& marker, + const EuclideanCamera& camera) : marker_(marker), camera_(camera) {} - template<typename T> - bool operator()(const T *X, T *residuals) const { + template <typename T> + bool operator()(const T* X, T* residuals) const { typedef Eigen::Matrix<T, 3, 3> Mat3; typedef Eigen::Matrix<T, 3, 1> Vec3; @@ -60,14 +60,14 @@ class EuclideanIntersectCostFunctor { return true; } - const Marker &marker_; - const EuclideanCamera &camera_; + const Marker& marker_; + const EuclideanCamera& camera_; }; } // namespace -bool EuclideanIntersect(const vector<Marker> &markers, - EuclideanReconstruction *reconstruction) { +bool EuclideanIntersect(const vector<Marker>& markers, + EuclideanReconstruction* reconstruction) { if (markers.size() < 2) { return false; } @@ -78,7 +78,7 @@ bool EuclideanIntersect(const vector<Marker> &markers, vector<Mat34> cameras; Mat34 P; for (int i = 0; i < markers.size(); ++i) { - EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image); + EuclideanCamera* camera = reconstruction->CameraForImage(markers[i].image); P_From_KRt(K, camera->R, camera->t, &P); cameras.push_back(P); } @@ -103,19 +103,19 @@ bool EuclideanIntersect(const vector<Marker> &markers, // Add residual blocks to the problem. int num_residuals = 0; for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; + const Marker& marker = markers[i]; if (marker.weight != 0.0) { - const EuclideanCamera &camera = + const EuclideanCamera& camera = *reconstruction->CameraForImage(marker.image); problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - EuclideanIntersectCostFunctor, - 2, /* num_residuals */ - 3>(new EuclideanIntersectCostFunctor(marker, camera)), + new ceres::AutoDiffCostFunction<EuclideanIntersectCostFunctor, + 2, /* num_residuals */ + 3>( + new EuclideanIntersectCostFunctor(marker, camera)), NULL, &X(0)); - num_residuals++; + num_residuals++; } } @@ -126,9 +126,9 @@ bool EuclideanIntersect(const vector<Marker> &markers, if (!num_residuals) { LG << "Skipping running minimizer with zero residuals"; - // We still add 3D point for the track regardless it was - // optimized or not. If track is a constant zero it'll use - // algebraic intersection result as a 3D coordinate. + // We still add 3D point for the track regardless it was + // optimized or not. If track is a constant zero it'll use + // algebraic intersection result as a 3D coordinate. Vec3 point = X.head<3>(); reconstruction->InsertPoint(markers[0].track, point); @@ -152,12 +152,12 @@ bool EuclideanIntersect(const vector<Marker> &markers, // Try projecting the point; make sure it's in front of everyone. for (int i = 0; i < cameras.size(); ++i) { - const EuclideanCamera &camera = + const EuclideanCamera& camera = *reconstruction->CameraForImage(markers[i].image); Vec3 x = camera.R * X + camera.t; if (x(2) < 0) { - LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image - << ": " << x.transpose(); + LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image << ": " + << x.transpose(); return false; } } @@ -173,35 +173,35 @@ namespace { struct ProjectiveIntersectCostFunction { public: - typedef Vec FMatrixType; + typedef Vec FMatrixType; typedef Vec4 XMatrixType; ProjectiveIntersectCostFunction( - const vector<Marker> &markers, - const ProjectiveReconstruction &reconstruction) - : markers(markers), reconstruction(reconstruction) {} + const vector<Marker>& markers, + const ProjectiveReconstruction& reconstruction) + : markers(markers), reconstruction(reconstruction) {} - Vec operator()(const Vec4 &X) const { + Vec operator()(const Vec4& X) const { Vec residuals(2 * markers.size()); residuals.setZero(); for (int i = 0; i < markers.size(); ++i) { - const ProjectiveCamera &camera = + const ProjectiveCamera& camera = *reconstruction.CameraForImage(markers[i].image); Vec3 projected = camera.P * X; projected /= projected(2); - residuals[2*i + 0] = projected(0) - markers[i].x; - residuals[2*i + 1] = projected(1) - markers[i].y; + residuals[2 * i + 0] = projected(0) - markers[i].x; + residuals[2 * i + 1] = projected(1) - markers[i].y; } return residuals; } - const vector<Marker> &markers; - const ProjectiveReconstruction &reconstruction; + const vector<Marker>& markers; + const ProjectiveReconstruction& reconstruction; }; } // namespace -bool ProjectiveIntersect(const vector<Marker> &markers, - ProjectiveReconstruction *reconstruction) { +bool ProjectiveIntersect(const vector<Marker>& markers, + ProjectiveReconstruction* reconstruction) { if (markers.size() < 2) { return false; } @@ -209,7 +209,7 @@ bool ProjectiveIntersect(const vector<Marker> &markers, // Get the cameras to use for the intersection. vector<Mat34> cameras; for (int i = 0; i < markers.size(); ++i) { - ProjectiveCamera *camera = reconstruction->CameraForImage(markers[i].image); + ProjectiveCamera* camera = reconstruction->CameraForImage(markers[i].image); cameras.push_back(camera->P); } @@ -232,16 +232,16 @@ bool ProjectiveIntersect(const vector<Marker> &markers, Solver solver(triangulate_cost); Solver::Results results = solver.minimize(params, &X); - (void) results; // TODO(keir): Ensure results are good. + (void)results; // TODO(keir): Ensure results are good. // Try projecting the point; make sure it's in front of everyone. for (int i = 0; i < cameras.size(); ++i) { - const ProjectiveCamera &camera = + const ProjectiveCamera& camera = *reconstruction->CameraForImage(markers[i].image); Vec3 x = camera.P * X; if (x(2) < 0) { - LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image - << ": " << x.transpose(); + LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image << ": " + << x.transpose(); } } diff --git a/intern/libmv/libmv/simple_pipeline/intersect.h b/intern/libmv/libmv/simple_pipeline/intersect.h index 15d6f998557..aff3ffe66e2 100644 --- a/intern/libmv/libmv/simple_pipeline/intersect.h +++ b/intern/libmv/libmv/simple_pipeline/intersect.h @@ -22,8 +22,8 @@ #define LIBMV_SIMPLE_PIPELINE_INTERSECT_H #include "libmv/base/vector.h" -#include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { @@ -38,7 +38,8 @@ namespace libmv { \a markers should contain all \link Marker markers \endlink belonging to tracks visible in all frames. \a reconstruction should contain the cameras for all frames. - The new \link Point points \endlink will be inserted in \a reconstruction. + The new \link Point points \endlink will be inserted in \a + reconstruction. \note This assumes a calibrated reconstruction, e.g. the markers are already corrected for camera intrinsics and radial distortion. @@ -46,8 +47,8 @@ namespace libmv { \sa EuclideanResect */ -bool EuclideanIntersect(const vector<Marker> &markers, - EuclideanReconstruction *reconstruction); +bool EuclideanIntersect(const vector<Marker>& markers, + EuclideanReconstruction* reconstruction); /*! Estimate the homogeneous coordinates of a track by intersecting rays. @@ -60,7 +61,8 @@ bool EuclideanIntersect(const vector<Marker> &markers, \a markers should contain all \link Marker markers \endlink belonging to tracks visible in all frames. \a reconstruction should contain the cameras for all frames. - The new \link Point points \endlink will be inserted in \a reconstruction. + The new \link Point points \endlink will be inserted in \a + reconstruction. \note This assumes that radial distortion is already corrected for, but does not assume that e.g. focal length and principal point are @@ -69,8 +71,8 @@ bool EuclideanIntersect(const vector<Marker> &markers, \sa Resect */ -bool ProjectiveIntersect(const vector<Marker> &markers, - ProjectiveReconstruction *reconstruction); +bool ProjectiveIntersect(const vector<Marker>& markers, + ProjectiveReconstruction* reconstruction); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/intersect_test.cc b/intern/libmv/libmv/simple_pipeline/intersect_test.cc index dd4fdc789af..447cc095cb0 100644 --- a/intern/libmv/libmv/simple_pipeline/intersect_test.cc +++ b/intern/libmv/libmv/simple_pipeline/intersect_test.cc @@ -22,10 +22,10 @@ #include <iostream> -#include "testing/testing.h" +#include "libmv/logging/logging.h" #include "libmv/multiview/projection.h" #include "libmv/numeric/numeric.h" -#include "libmv/logging/logging.h" +#include "testing/testing.h" namespace libmv { @@ -40,13 +40,15 @@ TEST(Intersect, EuclideanIntersect) { // 0, 0, 1; Mat3 R1 = RotationAroundZ(-0.1); Mat3 R2 = RotationAroundX(-0.1); - Vec3 t1; t1 << 1, 1, 10; - Vec3 t2; t2 << -2, -1, 10; + Vec3 t1; + t1 << 1, 1, 10; + Vec3 t2; + t2 << -2, -1, 10; Mat34 P1, P2; P_From_KRt(K1, R1, t1, &P1); P_From_KRt(K2, R2, t2, &P2); - //Mat3 F; FundamentalFromProjections(P1, P2, &F); + // Mat3 F; FundamentalFromProjections(P1, P2, &F); Mat3X X; X.resize(3, 30); @@ -68,9 +70,9 @@ TEST(Intersect, EuclideanIntersect) { reconstruction.InsertCamera(2, R2, t2); vector<Marker> markers; - Marker a = { 1, 0, x1.x(), x1.y(), 1.0 }; + Marker a = {1, 0, x1.x(), x1.y(), 1.0}; markers.push_back(a); - Marker b = { 2, 0, x2.x(), x2.y(), 1.0 }; + Marker b = {2, 0, x2.x(), x2.y(), 1.0}; markers.push_back(b); EuclideanIntersect(markers, &reconstruction); @@ -78,4 +80,4 @@ TEST(Intersect, EuclideanIntersect) { EXPECT_NEAR(0, DistanceLInfinity(estimated, expected), 1e-8); } } -} // namespace +} // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc b/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc index 241b5600505..5526d730651 100644 --- a/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc +++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection.cc @@ -20,20 +20,20 @@ #include "libmv/simple_pipeline/keyframe_selection.h" -#include "libmv/numeric/numeric.h" #include "ceres/ceres.h" #include "libmv/logging/logging.h" -#include "libmv/multiview/homography.h" #include "libmv/multiview/fundamental.h" -#include "libmv/simple_pipeline/intersect.h" +#include "libmv/multiview/homography.h" +#include "libmv/numeric/numeric.h" #include "libmv/simple_pipeline/bundle.h" +#include "libmv/simple_pipeline/intersect.h" #include <Eigen/Eigenvalues> namespace libmv { namespace { -Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics &intrinsics) { +Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics& intrinsics) { Mat3 T = Mat3::Identity(), S = Mat3::Identity(); T(0, 2) = -intrinsics.principal_point_x(); @@ -56,7 +56,7 @@ Mat3 IntrinsicsNormalizationMatrix(const CameraIntrinsics &intrinsics) { // (k = 7 for a fundamental matrix or 8 for a homography) // r is the dimension of the data // (r = 4 for 2D correspondences between two frames) -double GRIC(const Vec &e, int d, int k, int r) { +double GRIC(const Vec& e, int d, int k, int r) { int n = e.rows(); double lambda1 = log(static_cast<double>(r)); double lambda2 = log(static_cast<double>(r * n)); @@ -89,7 +89,7 @@ double GRIC(const Vec &e, int d, int k, int r) { // // TODO(keir): Consider moving this into the numeric code, since this is not // related to keyframe selection. -Mat PseudoInverseWithClampedEigenvalues(const Mat &matrix, +Mat PseudoInverseWithClampedEigenvalues(const Mat& matrix, int num_eigenvalues_to_clamp) { Eigen::EigenSolver<Mat> eigen_solver(matrix); Mat D = eigen_solver.pseudoEigenvalueMatrix(); @@ -112,27 +112,24 @@ Mat PseudoInverseWithClampedEigenvalues(const Mat &matrix, return V * D * V.inverse(); } -void FilterZeroWeightMarkersFromTracks(const Tracks &tracks, - Tracks *filtered_tracks) { +void FilterZeroWeightMarkersFromTracks(const Tracks& tracks, + Tracks* filtered_tracks) { vector<Marker> all_markers = tracks.AllMarkers(); for (int i = 0; i < all_markers.size(); ++i) { - Marker &marker = all_markers[i]; + Marker& marker = all_markers[i]; if (marker.weight != 0.0) { - filtered_tracks->Insert(marker.image, - marker.track, - marker.x, - marker.y, - marker.weight); + filtered_tracks->Insert( + marker.image, marker.track, marker.x, marker.y, marker.weight); } } } } // namespace -void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, - const CameraIntrinsics &intrinsics, - vector<int> &keyframes) { +void SelectKeyframesBasedOnGRICAndVariance(const Tracks& _tracks, + const CameraIntrinsics& intrinsics, + vector<int>& keyframes) { // Mirza Tahir Ahmed, Matthew N. Dailey // Robust key frame extraction for 3D reconstruction from video streams // @@ -172,23 +169,21 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, candidate_image <= max_image; candidate_image++) { // Conjunction of all markers from both keyframes - vector<Marker> all_markers = - filtered_tracks.MarkersInBothImages(current_keyframe, - candidate_image); + vector<Marker> all_markers = filtered_tracks.MarkersInBothImages( + current_keyframe, candidate_image); // Match keypoints between frames current_keyframe and candidate_image vector<Marker> tracked_markers = - filtered_tracks.MarkersForTracksInBothImages(current_keyframe, - candidate_image); + filtered_tracks.MarkersForTracksInBothImages(current_keyframe, + candidate_image); // Correspondences in normalized space Mat x1, x2; CoordinatesForMarkersInImage(tracked_markers, current_keyframe, &x1); CoordinatesForMarkersInImage(tracked_markers, candidate_image, &x2); - LG << "Found " << x1.cols() - << " correspondences between " << current_keyframe - << " and " << candidate_image; + LG << "Found " << x1.cols() << " correspondences between " + << current_keyframe << " and " << candidate_image; // Not enough points to construct fundamental matrix if (x1.cols() < 8 || x2.cols() < 8) @@ -199,9 +194,8 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, int Tf = all_markers.size(); double Rc = static_cast<double>(Tc) / Tf; - LG << "Correspondence between " << current_keyframe - << " and " << candidate_image - << ": " << Rc; + LG << "Correspondence between " << current_keyframe << " and " + << candidate_image << ": " << Rc; if (Rc < Tmin || Rc > Tmax) continue; @@ -210,19 +204,15 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, // Estimate homography using default options. EstimateHomographyOptions estimate_homography_options; - EstimateHomography2DFromCorrespondences(x1, - x2, - estimate_homography_options, - &H); + EstimateHomography2DFromCorrespondences( + x1, x2, estimate_homography_options, &H); // Convert homography to original pixel space. H = N_inverse * H * N; EstimateFundamentalOptions estimate_fundamental_options; - EstimateFundamentalFromCorrespondences(x1, - x2, - estimate_fundamental_options, - &F); + EstimateFundamentalFromCorrespondences( + x1, x2, estimate_fundamental_options, &F); // Convert fundamental to original pixel space. F = N_inverse * F * N; @@ -238,11 +228,11 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, for (int i = 0; i < x1.cols(); i++) { Vec2 current_x1, current_x2; - intrinsics.NormalizedToImageSpace(x1(0, i), x1(1, i), - ¤t_x1(0), ¤t_x1(1)); + intrinsics.NormalizedToImageSpace( + x1(0, i), x1(1, i), ¤t_x1(0), ¤t_x1(1)); - intrinsics.NormalizedToImageSpace(x2(0, i), x2(1, i), - ¤t_x2(0), ¤t_x2(1)); + intrinsics.NormalizedToImageSpace( + x2(0, i), x2(1, i), ¤t_x2(0), ¤t_x2(1)); H_e(i) = SymmetricGeometricDistance(H, current_x1, current_x2); F_e(i) = SymmetricEpipolarDistance(F, current_x1, current_x2); @@ -255,10 +245,8 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, double GRIC_H = GRIC(H_e, 2, 8, 4); double GRIC_F = GRIC(F_e, 3, 7, 4); - LG << "GRIC values for frames " << current_keyframe - << " and " << candidate_image - << ", H-GRIC: " << GRIC_H - << ", F-GRIC: " << GRIC_F; + LG << "GRIC values for frames " << current_keyframe << " and " + << candidate_image << ", H-GRIC: " << GRIC_H << ", F-GRIC: " << GRIC_F; if (GRIC_H <= GRIC_F) continue; @@ -295,23 +283,19 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, Vec3 t; Mat3 K = Mat3::Identity(); - if (!MotionFromEssentialAndCorrespondence(E, - K, x1.col(0), - K, x2.col(0), - &R, &t)) { + if (!MotionFromEssentialAndCorrespondence( + E, K, x1.col(0), K, x2.col(0), &R, &t)) { LG << "Failed to compute R and t from E and K"; continue; } - LG << "Camera transform between frames " << current_keyframe - << " and " << candidate_image - << ":\nR:\n" << R - << "\nt:" << t.transpose(); + LG << "Camera transform between frames " << current_keyframe << " and " + << candidate_image << ":\nR:\n" + << R << "\nt:" << t.transpose(); // First camera is identity, second one is relative to it - reconstruction.InsertCamera(current_keyframe, - Mat3::Identity(), - Vec3::Zero()); + reconstruction.InsertCamera( + current_keyframe, Mat3::Identity(), Vec3::Zero()); reconstruction.InsertCamera(candidate_image, R, t); // Reconstruct 3D points @@ -349,7 +333,7 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, } double success_intersects_factor = - (double) intersects_success / intersects_total; + (double)intersects_success / intersects_total; if (success_intersects_factor < success_intersects_factor_best) { LG << "Skip keyframe candidate because of " @@ -372,7 +356,7 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, &empty_intrinsics, &evaluation); - Mat &jacobian = evaluation.jacobian; + Mat& jacobian = evaluation.jacobian; Mat JT_J = jacobian.transpose() * jacobian; // There are 7 degrees of freedom, so clamp them out. @@ -380,10 +364,10 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, Mat temp_derived = JT_J * JT_J_inv * JT_J; bool is_inversed = (temp_derived - JT_J).cwiseAbs2().sum() < - 1e-4 * std::min(temp_derived.cwiseAbs2().sum(), - JT_J.cwiseAbs2().sum()); + 1e-4 * std::min(temp_derived.cwiseAbs2().sum(), + JT_J.cwiseAbs2().sum()); - LG << "Check on inversed: " << (is_inversed ? "true" : "false" ) + LG << "Check on inversed: " << (is_inversed ? "true" : "false") << ", det(JT_J): " << JT_J.determinant(); if (!is_inversed) { @@ -400,8 +384,7 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &_tracks, double Sc = static_cast<double>(I + A) / Square(3 * I) * Sigma_P.trace(); - LG << "Expected estimation error between " - << current_keyframe << " and " + LG << "Expected estimation error between " << current_keyframe << " and " << candidate_image << ": " << Sc; // Pairing with a lower Sc indicates a better choice diff --git a/intern/libmv/libmv/simple_pipeline/keyframe_selection.h b/intern/libmv/libmv/simple_pipeline/keyframe_selection.h index 25253af32fe..a1b3910abd4 100644 --- a/intern/libmv/libmv/simple_pipeline/keyframe_selection.h +++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection.h @@ -22,8 +22,8 @@ #define LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_ #include "libmv/base/vector.h" -#include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/camera_intrinsics.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { @@ -43,10 +43,9 @@ namespace libmv { // \param intrinsics: is camera intrinsics. // \param keyframes: will contain all images number which are considered // good to be used for reconstruction. -void SelectKeyframesBasedOnGRICAndVariance( - const Tracks &tracks, - const CameraIntrinsics &intrinsics, - vector<int> &keyframes); +void SelectKeyframesBasedOnGRICAndVariance(const Tracks& tracks, + const CameraIntrinsics& intrinsics, + vector<int>& keyframes); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc b/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc index 9d88362cc88..983349c0c5a 100644 --- a/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc +++ b/intern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc @@ -1,15 +1,15 @@ // Copyright (c) 2011 libmv authors. -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -20,9 +20,9 @@ #include "libmv/simple_pipeline/keyframe_selection.h" -#include "testing/testing.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" #include "libmv/logging/logging.h" +#include "libmv/simple_pipeline/camera_intrinsics.h" +#include "testing/testing.h" namespace libmv { @@ -30,7 +30,7 @@ namespace libmv { // Should not be keyframe TEST(KeyframeSelection, SyntheticNeighborFrame) { PolynomialCameraIntrinsics intrinsics; - intrinsics.SetFocalLength(900.0,900.0); + intrinsics.SetFocalLength(900.0, 900.0); intrinsics.SetPrincipalPoint(640.0, 540.0); intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); @@ -66,25 +66,56 @@ TEST(KeyframeSelection, FabrikEingangNeighborFrames) { intrinsics.SetPrincipalPoint(960.000, 544.000); intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); - Marker markers[] = { - {1, 0, 737.599983, 646.397594, 1.0}, {2, 0, 737.906628, 648.113327, 1.0}, {1, 1, 863.045425, 646.081905, 1.0}, - {2, 1, 863.339767, 647.650040, 1.0}, {1, 2, 736.959972, 574.080151, 1.0}, {2, 2, 737.217350, 575.604900, 1.0}, - {1, 3, 864.097424, 573.374908, 1.0}, {2, 3, 864.383469, 574.900307, 1.0}, {1, 4, 789.429073, 631.677521, 1.0}, - {2, 4, 789.893131, 633.124451, 1.0}, {1, 5, 791.051960, 573.442028, 1.0}, {2, 5, 791.336575, 575.088890, 1.0}, - {1, 6, 738.973961, 485.130308, 1.0}, {2, 6, 739.435501, 486.734207, 1.0}, {1, 7, 862.403240, 514.866074, 1.0}, - {2, 7, 862.660618, 516.413261, 1.0}, {1, 8, 802.240162, 485.759838, 1.0}, {2, 8, 802.602253, 487.432899, 1.0}, - {1, 9, 754.340630, 500.624559, 1.0}, {2, 9, 754.559956, 502.079920, 1.0}, {1, 10, 849.398689, 484.480545, 1.0}, - {2, 10, 849.599934, 486.079937, 1.0}, {1, 11, 788.803768, 515.924391, 1.0}, {2, 11, 789.119911, 517.439932, 1.0}, - {1, 12, 838.733940, 558.212688, 1.0}, {2, 12, 839.039898, 559.679916, 1.0}, {1, 13, 760.014782, 575.194466, 1.0}, - {2, 13, 760.319881, 576.639904, 1.0}, {1, 14, 765.321636, 616.015957, 1.0}, {2, 14, 765.759945, 617.599915, 1.0}, - {1, 15, 800.963230, 660.032082, 1.0}, {2, 15, 801.279945, 661.759876, 1.0}, {1, 16, 846.321087, 602.313053, 1.0}, - {2, 16, 846.719913, 603.839878, 1.0}, {1, 17, 864.288311, 616.790524, 1.0}, {2, 17, 864.639931, 618.239918, 1.0}, - {1, 18, 800.006790, 602.573425, 1.0}, {2, 18, 800.319958, 604.159912, 1.0}, {1, 19, 739.026890, 617.944138, 1.0}, - {2, 19, 739.199924, 619.519924, 1.0}, {1, 20, 801.987419, 544.134888, 1.0}, {2, 20, 802.239933, 545.599911, 1.0}, - {1, 21, 753.619823, 542.961300, 1.0}, {2, 21, 753.919945, 544.639874, 1.0}, {1, 22, 787.921257, 499.910206, 1.0}, - {2, 22, 788.159924, 501.439917, 1.0}, {1, 23, 839.095459, 529.287903, 1.0}, {2, 23, 839.359932, 530.879934, 1.0}, - {1, 24, 811.760330, 630.732269, 1.0}, {2, 24, 812.159901, 632.319859, 1.0} - }; + Marker markers[] = {{1, 0, 737.599983, 646.397594, 1.0}, + {2, 0, 737.906628, 648.113327, 1.0}, + {1, 1, 863.045425, 646.081905, 1.0}, + {2, 1, 863.339767, 647.650040, 1.0}, + {1, 2, 736.959972, 574.080151, 1.0}, + {2, 2, 737.217350, 575.604900, 1.0}, + {1, 3, 864.097424, 573.374908, 1.0}, + {2, 3, 864.383469, 574.900307, 1.0}, + {1, 4, 789.429073, 631.677521, 1.0}, + {2, 4, 789.893131, 633.124451, 1.0}, + {1, 5, 791.051960, 573.442028, 1.0}, + {2, 5, 791.336575, 575.088890, 1.0}, + {1, 6, 738.973961, 485.130308, 1.0}, + {2, 6, 739.435501, 486.734207, 1.0}, + {1, 7, 862.403240, 514.866074, 1.0}, + {2, 7, 862.660618, 516.413261, 1.0}, + {1, 8, 802.240162, 485.759838, 1.0}, + {2, 8, 802.602253, 487.432899, 1.0}, + {1, 9, 754.340630, 500.624559, 1.0}, + {2, 9, 754.559956, 502.079920, 1.0}, + {1, 10, 849.398689, 484.480545, 1.0}, + {2, 10, 849.599934, 486.079937, 1.0}, + {1, 11, 788.803768, 515.924391, 1.0}, + {2, 11, 789.119911, 517.439932, 1.0}, + {1, 12, 838.733940, 558.212688, 1.0}, + {2, 12, 839.039898, 559.679916, 1.0}, + {1, 13, 760.014782, 575.194466, 1.0}, + {2, 13, 760.319881, 576.639904, 1.0}, + {1, 14, 765.321636, 616.015957, 1.0}, + {2, 14, 765.759945, 617.599915, 1.0}, + {1, 15, 800.963230, 660.032082, 1.0}, + {2, 15, 801.279945, 661.759876, 1.0}, + {1, 16, 846.321087, 602.313053, 1.0}, + {2, 16, 846.719913, 603.839878, 1.0}, + {1, 17, 864.288311, 616.790524, 1.0}, + {2, 17, 864.639931, 618.239918, 1.0}, + {1, 18, 800.006790, 602.573425, 1.0}, + {2, 18, 800.319958, 604.159912, 1.0}, + {1, 19, 739.026890, 617.944138, 1.0}, + {2, 19, 739.199924, 619.519924, 1.0}, + {1, 20, 801.987419, 544.134888, 1.0}, + {2, 20, 802.239933, 545.599911, 1.0}, + {1, 21, 753.619823, 542.961300, 1.0}, + {2, 21, 753.919945, 544.639874, 1.0}, + {1, 22, 787.921257, 499.910206, 1.0}, + {2, 22, 788.159924, 501.439917, 1.0}, + {1, 23, 839.095459, 529.287903, 1.0}, + {2, 23, 839.359932, 530.879934, 1.0}, + {1, 24, 811.760330, 630.732269, 1.0}, + {2, 24, 812.159901, 632.319859, 1.0}}; int num_markers = sizeof(markers) / sizeof(Marker); Tracks tracks; @@ -108,18 +139,34 @@ TEST(KeyframeSelection, FabrikEingangFarFrames) { intrinsics.SetPrincipalPoint(960.000, 544.000); intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); - Marker markers[] = { - {1, 0, 369.459200, 619.315258, 1.0}, {2, 0, 279.677496, 722.086842, 1.0}, {1, 1, 376.831970, 370.278397, 1.0}, - {2, 1, 221.695247, 460.065418, 1.0}, {1, 2, 1209.139023, 567.705605, 1.0}, {2, 2, 1080.760117, 659.230083, 1.0}, - {1, 3, 1643.495750, 903.620453, 1.0}, {2, 3, 1618.405037, 1015.374908, 1.0}, {1, 4, 1494.849815, 425.302460, 1.0}, - {2, 4, 1457.467575, 514.727587, 1.0}, {1, 5, 1794.637299, 328.728609, 1.0}, {2, 5, 1742.161446, 408.988636, 1.0}, - {1, 6, 1672.822723, 102.240358, 1.0}, {2, 6, 1539.287224, 153.536892, 1.0}, {1, 7, 1550.843925, 53.424943, 1.0}, - {2, 7, 1385.579109, 96.450085, 1.0}, {1, 8, 852.953281, 465.399578, 1.0}, {2, 8, 779.404564, 560.091843, 1.0}, - {1, 9, 906.853752, 299.827040, 1.0}, {2, 9, 786.923218, 385.570770, 1.0}, {1, 10, 406.322966, 87.556041, 1.0}, - {2, 10, 140.339413, 150.877481, 1.0}, {1, 11, 254.811573, 851.296478, 1.0}, {2, 11, 94.478302, 969.350189, 1.0}, - {1, 12, 729.087868, 806.092758, 1.0}, {2, 12, 606.212139, 919.876560, 1.0}, {1, 13, 1525.719452, 920.398083, 1.0}, - {2, 13, 1495.579720, 1031.971218, 1.0} - }; + Marker markers[] = {{1, 0, 369.459200, 619.315258, 1.0}, + {2, 0, 279.677496, 722.086842, 1.0}, + {1, 1, 376.831970, 370.278397, 1.0}, + {2, 1, 221.695247, 460.065418, 1.0}, + {1, 2, 1209.139023, 567.705605, 1.0}, + {2, 2, 1080.760117, 659.230083, 1.0}, + {1, 3, 1643.495750, 903.620453, 1.0}, + {2, 3, 1618.405037, 1015.374908, 1.0}, + {1, 4, 1494.849815, 425.302460, 1.0}, + {2, 4, 1457.467575, 514.727587, 1.0}, + {1, 5, 1794.637299, 328.728609, 1.0}, + {2, 5, 1742.161446, 408.988636, 1.0}, + {1, 6, 1672.822723, 102.240358, 1.0}, + {2, 6, 1539.287224, 153.536892, 1.0}, + {1, 7, 1550.843925, 53.424943, 1.0}, + {2, 7, 1385.579109, 96.450085, 1.0}, + {1, 8, 852.953281, 465.399578, 1.0}, + {2, 8, 779.404564, 560.091843, 1.0}, + {1, 9, 906.853752, 299.827040, 1.0}, + {2, 9, 786.923218, 385.570770, 1.0}, + {1, 10, 406.322966, 87.556041, 1.0}, + {2, 10, 140.339413, 150.877481, 1.0}, + {1, 11, 254.811573, 851.296478, 1.0}, + {2, 11, 94.478302, 969.350189, 1.0}, + {1, 12, 729.087868, 806.092758, 1.0}, + {2, 12, 606.212139, 919.876560, 1.0}, + {1, 13, 1525.719452, 920.398083, 1.0}, + {2, 13, 1495.579720, 1031.971218, 1.0}}; int num_markers = sizeof(markers) / sizeof(Marker); Tracks tracks; @@ -144,17 +191,35 @@ TEST(KeyframeSelection, CopterManualKeyFrames) { intrinsics.SetRadialDistortion(-0.08590, 0.0, 0.0); Marker markers[] = { - {1, 0, 645.792694, 403.115931, 1.0}, {2, 0, 630.641174, 307.996409, 1.0}, {1, 1, 783.469086, 403.904328, 1.0}, - {2, 1, 766.001129, 308.998225, 1.0}, {1, 2, 650.000000, 160.000001, 1.0}, {1, 3, 785.225906, 158.619039, 1.0}, - {2, 3, 767.526474, 70.449695, 1.0}, {1, 4, 290.640526, 382.335634, 1.0}, {2, 4, 273.001728, 86.993319, 1.0}, - {1, 5, 291.162739, 410.602684, 1.0}, {2, 5, 273.287849, 111.937487, 1.0}, {1, 6, 136.919317, 349.895797, 1.0}, - {1, 7, 490.844345, 47.572222, 1.0}, {1, 8, 454.406433, 488.935761, 1.0}, {1, 9, 378.655815, 618.522248, 1.0}, - {2, 9, 357.061806, 372.265077, 1.0}, {1, 10, 496.011391, 372.668824, 1.0}, {2, 10, 477.979164, 222.986112, 1.0}, - {1, 11, 680.060272, 256.103625, 1.0}, {2, 11, 670.587540, 204.830453, 1.0}, {1, 12, 1070.817108, 218.775322, 1.0}, - {2, 12, 1046.129913, 128.969783, 1.0}, {1, 14, 242.516403, 596.048512, 1.0}, {2, 14, 224.182606, 248.272154, 1.0}, - {1, 15, 613.936272, 287.519073, 1.0}, {2, 15, 600.467644, 196.085722, 1.0}, {1, 31, 844.637451, 256.354315, 1.0}, + {1, 0, 645.792694, 403.115931, 1.0}, + {2, 0, 630.641174, 307.996409, 1.0}, + {1, 1, 783.469086, 403.904328, 1.0}, + {2, 1, 766.001129, 308.998225, 1.0}, + {1, 2, 650.000000, 160.000001, 1.0}, + {1, 3, 785.225906, 158.619039, 1.0}, + {2, 3, 767.526474, 70.449695, 1.0}, + {1, 4, 290.640526, 382.335634, 1.0}, + {2, 4, 273.001728, 86.993319, 1.0}, + {1, 5, 291.162739, 410.602684, 1.0}, + {2, 5, 273.287849, 111.937487, 1.0}, + {1, 6, 136.919317, 349.895797, 1.0}, + {1, 7, 490.844345, 47.572222, 1.0}, + {1, 8, 454.406433, 488.935761, 1.0}, + {1, 9, 378.655815, 618.522248, 1.0}, + {2, 9, 357.061806, 372.265077, 1.0}, + {1, 10, 496.011391, 372.668824, 1.0}, + {2, 10, 477.979164, 222.986112, 1.0}, + {1, 11, 680.060272, 256.103625, 1.0}, + {2, 11, 670.587540, 204.830453, 1.0}, + {1, 12, 1070.817108, 218.775322, 1.0}, + {2, 12, 1046.129913, 128.969783, 1.0}, + {1, 14, 242.516403, 596.048512, 1.0}, + {2, 14, 224.182606, 248.272154, 1.0}, + {1, 15, 613.936272, 287.519073, 1.0}, + {2, 15, 600.467644, 196.085722, 1.0}, + {1, 31, 844.637451, 256.354315, 1.0}, {2, 31, 823.200150, 165.714952, 1.0}, - }; + }; int num_markers = sizeof(markers) / sizeof(Marker); Tracks tracks; @@ -180,52 +245,140 @@ TEST(KeyframeSelection, ElevatorManualKeyframesFrames) { intrinsics.SetRadialDistortion(-0.034, 0.0, 0.0); Marker markers[] = { - {1, 2, 1139.861412, 1034.634984, 1.0}, {2, 2, 1143.512192, 1065.355718, 1.0}, {1, 3, 1760.821953, 644.658036, 1.0}, - {2, 3, 1770.901108, 697.899928, 1.0}, {1, 4, 858.071823, 1068.520746, 1.0}, {1, 6, 1633.952408, 797.050145, 1.0}, - {2, 6, 1642.508469, 849.157140, 1.0}, {1, 8, 1716.695824, 451.805491, 1.0}, {2, 8, 1726.513939, 502.095687, 1.0}, - {1, 9, 269.577627, 724.986935, 1.0}, {2, 9, 269.424820, 764.154246, 1.0}, {1, 10, 1891.321907, 706.948843, 1.0}, - {2, 10, 1903.338547, 766.068377, 1.0}, {1, 12, 1806.227074, 956.089604, 1.0}, {2, 12, 1816.619568, 1013.767376, 1.0}, - {1, 14, 269.544153, 1002.333570, 1.0}, {2, 14, 269.367542, 1043.509254, 1.0}, {1, 15, 1402.772141, 281.392962, 1.0}, - {2, 15, 1409.089165, 318.731629, 1.0}, {1, 16, 195.877233, 919.454341, 1.0}, {2, 16, 192.531109, 997.367899, 1.0}, - {1, 17, 1789.584045, 120.036661, 1.0}, {2, 17, 1800.391846, 167.822964, 1.0}, {1, 18, 999.363213, 765.004807, 1.0}, - {2, 18, 1002.345772, 790.560122, 1.0}, {1, 19, 647.342491, 1044.805727, 1.0}, {2, 19, 649.328041, 1058.682940, 1.0}, - {1, 20, 1365.486832, 440.901829, 1.0}, {2, 20, 1371.413040, 477.888730, 1.0}, {1, 21, 1787.125282, 301.431606, 1.0}, - {2, 21, 1798.527260, 355.224531, 1.0}, {1, 22, 1257.805824, 932.797258, 1.0}, {2, 22, 1263.017578, 969.376774, 1.0}, - {1, 23, 961.969528, 843.148112, 1.0}, {2, 23, 964.869461, 868.587620, 1.0}, {1, 24, 158.076110, 1052.643592, 1.0}, - {1, 25, 1072.884521, 1005.296981, 1.0}, {2, 25, 1076.091156, 1032.776856, 1.0}, {1, 26, 1107.656937, 526.577228, 1.0}, - {2, 26, 1111.618423, 555.524454, 1.0}, {1, 27, 1416.410751, 529.857581, 1.0}, {2, 27, 1422.663574, 570.025957, 1.0}, - {1, 28, 1498.673630, 1005.453086, 1.0}, {2, 28, 1505.381813, 1051.827149, 1.0}, {1, 29, 1428.647804, 652.473629, 1.0}, - {2, 29, 1434.898224, 692.715390, 1.0}, {1, 30, 1332.318764, 503.673599, 1.0}, {2, 30, 1338.000069, 540.507967, 1.0}, - {1, 32, 1358.642693, 709.837904, 1.0}, {2, 32, 1364.231529, 748.678265, 1.0}, {1, 33, 1850.911560, 460.475668, 1.0}, - {2, 33, 1862.221413, 512.797347, 1.0}, {1, 34, 1226.117821, 607.053959, 1.0}, {2, 34, 1230.736084, 641.091449, 1.0}, - {1, 35, 619.598236, 523.341744, 1.0}, {2, 35, 621.601124, 554.453287, 1.0}, {1, 36, 956.591492, 958.223183, 1.0}, - {2, 36, 959.289265, 983.289263, 1.0}, {1, 37, 1249.922218, 419.095856, 1.0}, {2, 37, 1255.005913, 452.556177, 1.0}, - {1, 39, 1300.528450, 386.251166, 1.0}, {2, 39, 1305.957413, 420.185595, 1.0}, {1, 40, 1128.689919, 972.558346, 1.0}, - {2, 40, 1132.413712, 1003.984737, 1.0}, {1, 41, 503.304749, 1053.504388, 1.0}, {2, 41, 505.019703, 1069.175613, 1.0}, - {1, 42, 1197.352982, 472.681564, 1.0}, {2, 42, 1201.910706, 503.459880, 1.0}, {1, 43, 1794.391022, 383.911400, 1.0}, - {2, 43, 1805.324135, 436.116468, 1.0}, {1, 44, 789.641418, 1058.045647, 1.0}, {1, 45, 1376.575241, 928.714979, 1.0}, - {2, 45, 1381.995850, 969.511957, 1.0}, {1, 46, 1598.023567, 93.975592, 1.0}, {2, 46, 1606.937141, 136.827035, 1.0}, - {1, 47, 1455.550232, 762.128685, 1.0}, {2, 47, 1462.014313, 805.164878, 1.0}, {1, 48, 1357.123489, 354.460326, 1.0}, - {2, 48, 1363.071899, 390.363121, 1.0}, {1, 49, 939.792652, 781.549895, 1.0}, {2, 49, 942.802620, 806.164012, 1.0}, - {1, 50, 1380.251083, 805.948620, 1.0}, {2, 50, 1385.637932, 845.592098, 1.0}, {1, 51, 1021.769943, 1049.802361, 1.0}, - {1, 52, 1065.634918, 608.099055, 1.0}, {2, 52, 1069.142189, 635.361736, 1.0}, {1, 53, 624.324188, 463.202863, 1.0}, - {2, 53, 626.395454, 494.994088, 1.0}, {1, 54, 1451.459885, 881.557624, 1.0}, {2, 54, 1457.679634, 924.345531, 1.0}, - {1, 55, 1201.885986, 1057.079022, 1.0}, {1, 56, 581.157532, 947.661438, 1.0}, {2, 56, 583.242359, 960.831449, 1.0}, - {1, 58, 513.593102, 954.175858, 1.0}, {2, 58, 515.470047, 971.309574, 1.0}, {1, 59, 928.069038, 901.774421, 1.0}, - {2, 59, 930.847950, 925.613744, 1.0}, {1, 60, 1065.860023, 740.395389, 1.0}, {2, 60, 1069.484253, 768.971086, 1.0}, - {1, 61, 990.479393, 906.264632, 1.0}, {2, 61, 993.217506, 933.088803, 1.0}, {1, 62, 1776.196747, 776.278453, 1.0}, - {2, 62, 1786.292496, 831.136880, 1.0}, {1, 63, 834.454365, 1012.449725, 1.0}, {2, 63, 836.868324, 1033.451807, 1.0}, - {1, 64, 1355.190697, 869.184809, 1.0}, {2, 64, 1360.736618, 909.773347, 1.0}, {1, 65, 702.072487, 897.519686, 1.0}, - {2, 65, 704.203377, 911.931131, 1.0}, {1, 66, 1214.022903, 856.199934, 1.0}, {2, 66, 1218.109016, 890.753052, 1.0}, - {1, 67, 327.676048, 236.814036, 1.0}, {2, 67, 328.335285, 277.251878, 1.0}, {1, 68, 289.064083, 454.793912, 1.0}, - {2, 68, 288.651924, 498.882444, 1.0}, {1, 69, 1626.240692, 278.374350, 1.0}, {2, 69, 1634.131508, 315.853672, 1.0}, - {1, 70, 1245.375710, 734.862142, 1.0}, {2, 70, 1250.047417, 769.670885, 1.0}, {1, 71, 497.015305, 510.718904, 1.0}, - {2, 71, 498.682308, 541.070201, 1.0}, {1, 72, 1280.542030, 153.939185, 1.0}, {2, 72, 1286.993637, 198.436196, 1.0}, - {1, 73, 1534.748840, 138.601043, 1.0}, {2, 73, 1542.961349, 180.170819, 1.0}, {1, 74, 1477.412682, 200.608061, 1.0}, - {2, 74, 1484.683914, 240.413260, 1.0}, {1, 76, 450.637321, 407.279642, 1.0}, {2, 76, 451.695642, 441.666291, 1.0}, - {1, 78, 246.981239, 220.786298, 1.0}, {2, 78, 244.524879, 290.016564, 1.0}, {1, 79, 36.696489, 420.023407, 1.0}, + {1, 2, 1139.861412, 1034.634984, 1.0}, + {2, 2, 1143.512192, 1065.355718, 1.0}, + {1, 3, 1760.821953, 644.658036, 1.0}, + {2, 3, 1770.901108, 697.899928, 1.0}, + {1, 4, 858.071823, 1068.520746, 1.0}, + {1, 6, 1633.952408, 797.050145, 1.0}, + {2, 6, 1642.508469, 849.157140, 1.0}, + {1, 8, 1716.695824, 451.805491, 1.0}, + {2, 8, 1726.513939, 502.095687, 1.0}, + {1, 9, 269.577627, 724.986935, 1.0}, + {2, 9, 269.424820, 764.154246, 1.0}, + {1, 10, 1891.321907, 706.948843, 1.0}, + {2, 10, 1903.338547, 766.068377, 1.0}, + {1, 12, 1806.227074, 956.089604, 1.0}, + {2, 12, 1816.619568, 1013.767376, 1.0}, + {1, 14, 269.544153, 1002.333570, 1.0}, + {2, 14, 269.367542, 1043.509254, 1.0}, + {1, 15, 1402.772141, 281.392962, 1.0}, + {2, 15, 1409.089165, 318.731629, 1.0}, + {1, 16, 195.877233, 919.454341, 1.0}, + {2, 16, 192.531109, 997.367899, 1.0}, + {1, 17, 1789.584045, 120.036661, 1.0}, + {2, 17, 1800.391846, 167.822964, 1.0}, + {1, 18, 999.363213, 765.004807, 1.0}, + {2, 18, 1002.345772, 790.560122, 1.0}, + {1, 19, 647.342491, 1044.805727, 1.0}, + {2, 19, 649.328041, 1058.682940, 1.0}, + {1, 20, 1365.486832, 440.901829, 1.0}, + {2, 20, 1371.413040, 477.888730, 1.0}, + {1, 21, 1787.125282, 301.431606, 1.0}, + {2, 21, 1798.527260, 355.224531, 1.0}, + {1, 22, 1257.805824, 932.797258, 1.0}, + {2, 22, 1263.017578, 969.376774, 1.0}, + {1, 23, 961.969528, 843.148112, 1.0}, + {2, 23, 964.869461, 868.587620, 1.0}, + {1, 24, 158.076110, 1052.643592, 1.0}, + {1, 25, 1072.884521, 1005.296981, 1.0}, + {2, 25, 1076.091156, 1032.776856, 1.0}, + {1, 26, 1107.656937, 526.577228, 1.0}, + {2, 26, 1111.618423, 555.524454, 1.0}, + {1, 27, 1416.410751, 529.857581, 1.0}, + {2, 27, 1422.663574, 570.025957, 1.0}, + {1, 28, 1498.673630, 1005.453086, 1.0}, + {2, 28, 1505.381813, 1051.827149, 1.0}, + {1, 29, 1428.647804, 652.473629, 1.0}, + {2, 29, 1434.898224, 692.715390, 1.0}, + {1, 30, 1332.318764, 503.673599, 1.0}, + {2, 30, 1338.000069, 540.507967, 1.0}, + {1, 32, 1358.642693, 709.837904, 1.0}, + {2, 32, 1364.231529, 748.678265, 1.0}, + {1, 33, 1850.911560, 460.475668, 1.0}, + {2, 33, 1862.221413, 512.797347, 1.0}, + {1, 34, 1226.117821, 607.053959, 1.0}, + {2, 34, 1230.736084, 641.091449, 1.0}, + {1, 35, 619.598236, 523.341744, 1.0}, + {2, 35, 621.601124, 554.453287, 1.0}, + {1, 36, 956.591492, 958.223183, 1.0}, + {2, 36, 959.289265, 983.289263, 1.0}, + {1, 37, 1249.922218, 419.095856, 1.0}, + {2, 37, 1255.005913, 452.556177, 1.0}, + {1, 39, 1300.528450, 386.251166, 1.0}, + {2, 39, 1305.957413, 420.185595, 1.0}, + {1, 40, 1128.689919, 972.558346, 1.0}, + {2, 40, 1132.413712, 1003.984737, 1.0}, + {1, 41, 503.304749, 1053.504388, 1.0}, + {2, 41, 505.019703, 1069.175613, 1.0}, + {1, 42, 1197.352982, 472.681564, 1.0}, + {2, 42, 1201.910706, 503.459880, 1.0}, + {1, 43, 1794.391022, 383.911400, 1.0}, + {2, 43, 1805.324135, 436.116468, 1.0}, + {1, 44, 789.641418, 1058.045647, 1.0}, + {1, 45, 1376.575241, 928.714979, 1.0}, + {2, 45, 1381.995850, 969.511957, 1.0}, + {1, 46, 1598.023567, 93.975592, 1.0}, + {2, 46, 1606.937141, 136.827035, 1.0}, + {1, 47, 1455.550232, 762.128685, 1.0}, + {2, 47, 1462.014313, 805.164878, 1.0}, + {1, 48, 1357.123489, 354.460326, 1.0}, + {2, 48, 1363.071899, 390.363121, 1.0}, + {1, 49, 939.792652, 781.549895, 1.0}, + {2, 49, 942.802620, 806.164012, 1.0}, + {1, 50, 1380.251083, 805.948620, 1.0}, + {2, 50, 1385.637932, 845.592098, 1.0}, + {1, 51, 1021.769943, 1049.802361, 1.0}, + {1, 52, 1065.634918, 608.099055, 1.0}, + {2, 52, 1069.142189, 635.361736, 1.0}, + {1, 53, 624.324188, 463.202863, 1.0}, + {2, 53, 626.395454, 494.994088, 1.0}, + {1, 54, 1451.459885, 881.557624, 1.0}, + {2, 54, 1457.679634, 924.345531, 1.0}, + {1, 55, 1201.885986, 1057.079022, 1.0}, + {1, 56, 581.157532, 947.661438, 1.0}, + {2, 56, 583.242359, 960.831449, 1.0}, + {1, 58, 513.593102, 954.175858, 1.0}, + {2, 58, 515.470047, 971.309574, 1.0}, + {1, 59, 928.069038, 901.774421, 1.0}, + {2, 59, 930.847950, 925.613744, 1.0}, + {1, 60, 1065.860023, 740.395389, 1.0}, + {2, 60, 1069.484253, 768.971086, 1.0}, + {1, 61, 990.479393, 906.264632, 1.0}, + {2, 61, 993.217506, 933.088803, 1.0}, + {1, 62, 1776.196747, 776.278453, 1.0}, + {2, 62, 1786.292496, 831.136880, 1.0}, + {1, 63, 834.454365, 1012.449725, 1.0}, + {2, 63, 836.868324, 1033.451807, 1.0}, + {1, 64, 1355.190697, 869.184809, 1.0}, + {2, 64, 1360.736618, 909.773347, 1.0}, + {1, 65, 702.072487, 897.519686, 1.0}, + {2, 65, 704.203377, 911.931131, 1.0}, + {1, 66, 1214.022903, 856.199934, 1.0}, + {2, 66, 1218.109016, 890.753052, 1.0}, + {1, 67, 327.676048, 236.814036, 1.0}, + {2, 67, 328.335285, 277.251878, 1.0}, + {1, 68, 289.064083, 454.793912, 1.0}, + {2, 68, 288.651924, 498.882444, 1.0}, + {1, 69, 1626.240692, 278.374350, 1.0}, + {2, 69, 1634.131508, 315.853672, 1.0}, + {1, 70, 1245.375710, 734.862142, 1.0}, + {2, 70, 1250.047417, 769.670885, 1.0}, + {1, 71, 497.015305, 510.718904, 1.0}, + {2, 71, 498.682308, 541.070201, 1.0}, + {1, 72, 1280.542030, 153.939185, 1.0}, + {2, 72, 1286.993637, 198.436196, 1.0}, + {1, 73, 1534.748840, 138.601043, 1.0}, + {2, 73, 1542.961349, 180.170819, 1.0}, + {1, 74, 1477.412682, 200.608061, 1.0}, + {2, 74, 1484.683914, 240.413260, 1.0}, + {1, 76, 450.637321, 407.279642, 1.0}, + {2, 76, 451.695642, 441.666291, 1.0}, + {1, 78, 246.981239, 220.786298, 1.0}, + {2, 78, 244.524879, 290.016564, 1.0}, + {1, 79, 36.696489, 420.023407, 1.0}, {2, 79, 21.364746, 591.245492, 1.0}, - }; + }; int num_markers = sizeof(markers) / sizeof(Marker); Tracks tracks; @@ -249,41 +402,110 @@ TEST(KeyframeSelection, ElevatorReconstructionVarianceTest) { intrinsics.SetRadialDistortion(-0.034, 0.0, 0.0); Marker markers[] = { - {1, 0, 182.999997, 1047.000010, 1.0}, {2, 0, 181.475730, 1052.091079, 1.0}, {3, 0, 181.741562, 1057.893341, 1.0}, - {4, 0, 183.190498, 1068.310440, 1.0}, {1, 1, 271.000013, 666.000009, 1.0}, {2, 1, 270.596180, 668.665760, 1.0}, - {3, 1, 270.523510, 671.559069, 1.0}, {4, 1, 271.856518, 676.818151, 1.0}, {5, 1, 268.989000, 727.051570, 1.0}, - {1, 2, 264.999990, 1018.000031, 1.0}, {2, 2, 264.020061, 1021.157591, 1.0}, {3, 2, 264.606056, 1024.823506, 1.0}, - {4, 2, 266.200933, 1031.168690, 1.0}, {1, 3, 270.000000, 938.000014, 1.0}, {2, 3, 269.022617, 941.153390, 1.0}, - {3, 3, 269.605579, 944.454954, 1.0}, {4, 3, 271.281366, 949.452167, 1.0}, {5, 3, 268.963480, 1004.417453, 1.0}, - {1, 4, 200.999994, 799.000003, 1.0}, {2, 4, 199.841366, 803.891838, 1.0}, {3, 4, 200.262208, 809.323246, 1.0}, - {4, 4, 201.456513, 819.271195, 1.0}, {5, 4, 195.026493, 924.363234, 1.0}, {1, 5, 1775.000038, 49.999998, 1.0}, - {2, 5, 1775.255127, 53.718264, 1.0}, {3, 5, 1776.449890, 55.951670, 1.0}, {4, 5, 1778.815727, 61.923309, 1.0}, - {5, 5, 1790.274124, 123.074923, 1.0}, {1, 6, 164.000001, 927.999988, 1.0}, {2, 6, 162.665462, 933.169527, 1.0}, - {3, 6, 163.067923, 938.577182, 1.0}, {4, 6, 164.370360, 948.840945, 1.0}, {5, 6, 157.199407, 1057.762341, 1.0}, - {1, 7, 618.000011, 477.999998, 1.0}, {2, 7, 617.583504, 480.124243, 1.0}, {3, 7, 618.356495, 482.441897, 1.0}, - {4, 7, 619.792500, 486.428132, 1.0}, {5, 7, 619.546051, 525.222627, 1.0}, {1, 8, 499.999981, 1036.999984, 1.0}, - {2, 8, 499.080162, 1038.720160, 1.0}, {3, 8, 499.949398, 1039.014344, 1.0}, {4, 8, 501.828003, 1041.286647, 1.0}, - {5, 8, 502.777576, 1055.196369, 1.0}, {1, 9, 1587.000046, 31.999999, 1.0}, {2, 9, 1586.988373, 34.635853, 1.0}, - {3, 9, 1588.155899, 37.444186, 1.0}, {4, 9, 1589.973106, 42.492081, 1.0}, {5, 9, 1598.683205, 96.526332, 1.0}, - {1, 10, 622.999992, 416.999999, 1.0}, {2, 10, 622.449017, 419.233485, 1.0}, {3, 10, 623.283234, 421.500703, 1.0}, - {4, 10, 624.620132, 425.537406, 1.0}, {5, 10, 624.290829, 465.078338, 1.0}, {1, 11, 577.999992, 931.999998, 1.0}, - {2, 11, 577.042294, 932.872703, 1.0}, {3, 11, 577.832451, 934.045451, 1.0}, {4, 11, 579.729137, 935.735435, 1.0}, - {5, 11, 580.691242, 948.396256, 1.0}, {1, 12, 510.999985, 931.999998, 1.0}, {2, 12, 510.111237, 933.152146, 1.0}, - {3, 12, 510.797081, 934.454219, 1.0}, {4, 12, 512.647362, 936.595910, 1.0}, {5, 12, 513.247204, 955.144157, 1.0}, - {1, 13, 330.459995, 177.059993, 1.0}, {2, 13, 329.876347, 179.615586, 1.0}, {3, 13, 330.681696, 182.757810, 1.0}, - {4, 13, 331.345053, 187.903853, 1.0}, {5, 13, 327.824135, 239.611639, 1.0}, {1, 14, 291.813097, 388.516195, 1.0}, - {2, 14, 290.984058, 391.382725, 1.0}, {3, 14, 291.526737, 394.778595, 1.0}, {4, 14, 292.763815, 400.310973, 1.0}, - {5, 14, 288.714552, 457.548015, 1.0}, {1, 15, 496.491680, 466.534005, 1.0}, {2, 15, 495.909519, 468.518561, 1.0}, - {3, 15, 496.588383, 470.853596, 1.0}, {4, 15, 497.976780, 474.731458, 1.0}, {5, 15, 496.998882, 512.568694, 1.0}, - {1, 16, 1273.000031, 89.000000, 1.0}, {2, 16, 1272.951965, 92.003637, 1.0}, {3, 16, 1273.934784, 94.972191, 1.0}, - {4, 16, 1275.493584, 100.139952, 1.0}, {5, 16, 1281.003571, 156.880163, 1.0}, {1, 17, 1524.713173, 78.852922, 1.0}, - {2, 17, 1524.782066, 81.427142, 1.0}, {3, 17, 1525.759048, 84.057939, 1.0}, {4, 17, 1527.579689, 88.966550, 1.0}, - {5, 17, 1535.262451, 141.186054, 1.0}, {1, 18, 1509.425011, 94.371824, 1.0}, {1, 19, 451.000013, 357.000003, 1.0}, - {2, 19, 450.354881, 359.312410, 1.0}, {3, 19, 451.107473, 361.837088, 1.0}, {4, 19, 452.186537, 366.318061, 1.0}, - {5, 19, 450.507660, 409.257599, 1.0}, {1, 20, 254.004936, 114.784185, 1.0}, {2, 20, 253.291512, 119.288486, 1.0}, - {3, 20, 253.745584, 124.114957, 1.0}, {4, 20, 254.453287, 132.795120, 1.0}, {5, 20, 246.772242, 225.165337, 1.0}, - {1, 21, 65.262880, 147.889409, 1.0}, {2, 21, 63.634465, 157.656807, 1.0}, {3, 21, 63.306799, 169.067053, 1.0}, - {4, 21, 62.462311, 189.724241, 1.0}, {5, 21, 35.396615, 430.308380, 1.0}, + {1, 0, 182.999997, 1047.000010, 1.0}, + {2, 0, 181.475730, 1052.091079, 1.0}, + {3, 0, 181.741562, 1057.893341, 1.0}, + {4, 0, 183.190498, 1068.310440, 1.0}, + {1, 1, 271.000013, 666.000009, 1.0}, + {2, 1, 270.596180, 668.665760, 1.0}, + {3, 1, 270.523510, 671.559069, 1.0}, + {4, 1, 271.856518, 676.818151, 1.0}, + {5, 1, 268.989000, 727.051570, 1.0}, + {1, 2, 264.999990, 1018.000031, 1.0}, + {2, 2, 264.020061, 1021.157591, 1.0}, + {3, 2, 264.606056, 1024.823506, 1.0}, + {4, 2, 266.200933, 1031.168690, 1.0}, + {1, 3, 270.000000, 938.000014, 1.0}, + {2, 3, 269.022617, 941.153390, 1.0}, + {3, 3, 269.605579, 944.454954, 1.0}, + {4, 3, 271.281366, 949.452167, 1.0}, + {5, 3, 268.963480, 1004.417453, 1.0}, + {1, 4, 200.999994, 799.000003, 1.0}, + {2, 4, 199.841366, 803.891838, 1.0}, + {3, 4, 200.262208, 809.323246, 1.0}, + {4, 4, 201.456513, 819.271195, 1.0}, + {5, 4, 195.026493, 924.363234, 1.0}, + {1, 5, 1775.000038, 49.999998, 1.0}, + {2, 5, 1775.255127, 53.718264, 1.0}, + {3, 5, 1776.449890, 55.951670, 1.0}, + {4, 5, 1778.815727, 61.923309, 1.0}, + {5, 5, 1790.274124, 123.074923, 1.0}, + {1, 6, 164.000001, 927.999988, 1.0}, + {2, 6, 162.665462, 933.169527, 1.0}, + {3, 6, 163.067923, 938.577182, 1.0}, + {4, 6, 164.370360, 948.840945, 1.0}, + {5, 6, 157.199407, 1057.762341, 1.0}, + {1, 7, 618.000011, 477.999998, 1.0}, + {2, 7, 617.583504, 480.124243, 1.0}, + {3, 7, 618.356495, 482.441897, 1.0}, + {4, 7, 619.792500, 486.428132, 1.0}, + {5, 7, 619.546051, 525.222627, 1.0}, + {1, 8, 499.999981, 1036.999984, 1.0}, + {2, 8, 499.080162, 1038.720160, 1.0}, + {3, 8, 499.949398, 1039.014344, 1.0}, + {4, 8, 501.828003, 1041.286647, 1.0}, + {5, 8, 502.777576, 1055.196369, 1.0}, + {1, 9, 1587.000046, 31.999999, 1.0}, + {2, 9, 1586.988373, 34.635853, 1.0}, + {3, 9, 1588.155899, 37.444186, 1.0}, + {4, 9, 1589.973106, 42.492081, 1.0}, + {5, 9, 1598.683205, 96.526332, 1.0}, + {1, 10, 622.999992, 416.999999, 1.0}, + {2, 10, 622.449017, 419.233485, 1.0}, + {3, 10, 623.283234, 421.500703, 1.0}, + {4, 10, 624.620132, 425.537406, 1.0}, + {5, 10, 624.290829, 465.078338, 1.0}, + {1, 11, 577.999992, 931.999998, 1.0}, + {2, 11, 577.042294, 932.872703, 1.0}, + {3, 11, 577.832451, 934.045451, 1.0}, + {4, 11, 579.729137, 935.735435, 1.0}, + {5, 11, 580.691242, 948.396256, 1.0}, + {1, 12, 510.999985, 931.999998, 1.0}, + {2, 12, 510.111237, 933.152146, 1.0}, + {3, 12, 510.797081, 934.454219, 1.0}, + {4, 12, 512.647362, 936.595910, 1.0}, + {5, 12, 513.247204, 955.144157, 1.0}, + {1, 13, 330.459995, 177.059993, 1.0}, + {2, 13, 329.876347, 179.615586, 1.0}, + {3, 13, 330.681696, 182.757810, 1.0}, + {4, 13, 331.345053, 187.903853, 1.0}, + {5, 13, 327.824135, 239.611639, 1.0}, + {1, 14, 291.813097, 388.516195, 1.0}, + {2, 14, 290.984058, 391.382725, 1.0}, + {3, 14, 291.526737, 394.778595, 1.0}, + {4, 14, 292.763815, 400.310973, 1.0}, + {5, 14, 288.714552, 457.548015, 1.0}, + {1, 15, 496.491680, 466.534005, 1.0}, + {2, 15, 495.909519, 468.518561, 1.0}, + {3, 15, 496.588383, 470.853596, 1.0}, + {4, 15, 497.976780, 474.731458, 1.0}, + {5, 15, 496.998882, 512.568694, 1.0}, + {1, 16, 1273.000031, 89.000000, 1.0}, + {2, 16, 1272.951965, 92.003637, 1.0}, + {3, 16, 1273.934784, 94.972191, 1.0}, + {4, 16, 1275.493584, 100.139952, 1.0}, + {5, 16, 1281.003571, 156.880163, 1.0}, + {1, 17, 1524.713173, 78.852922, 1.0}, + {2, 17, 1524.782066, 81.427142, 1.0}, + {3, 17, 1525.759048, 84.057939, 1.0}, + {4, 17, 1527.579689, 88.966550, 1.0}, + {5, 17, 1535.262451, 141.186054, 1.0}, + {1, 18, 1509.425011, 94.371824, 1.0}, + {1, 19, 451.000013, 357.000003, 1.0}, + {2, 19, 450.354881, 359.312410, 1.0}, + {3, 19, 451.107473, 361.837088, 1.0}, + {4, 19, 452.186537, 366.318061, 1.0}, + {5, 19, 450.507660, 409.257599, 1.0}, + {1, 20, 254.004936, 114.784185, 1.0}, + {2, 20, 253.291512, 119.288486, 1.0}, + {3, 20, 253.745584, 124.114957, 1.0}, + {4, 20, 254.453287, 132.795120, 1.0}, + {5, 20, 246.772242, 225.165337, 1.0}, + {1, 21, 65.262880, 147.889409, 1.0}, + {2, 21, 63.634465, 157.656807, 1.0}, + {3, 21, 63.306799, 169.067053, 1.0}, + {4, 21, 62.462311, 189.724241, 1.0}, + {5, 21, 35.396615, 430.308380, 1.0}, }; int num_markers = sizeof(markers) / sizeof(Marker); @@ -304,4 +526,4 @@ TEST(KeyframeSelection, ElevatorReconstructionVarianceTest) { } } -} // namespace libmv +} // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver.cc b/intern/libmv/libmv/simple_pipeline/modal_solver.cc index 687c328b004..845b299e31e 100644 --- a/intern/libmv/libmv/simple_pipeline/modal_solver.cc +++ b/intern/libmv/libmv/simple_pipeline/modal_solver.cc @@ -34,7 +34,7 @@ namespace libmv { namespace { -void ProjectMarkerOnSphere(const Marker &marker, Vec3 &X) { +void ProjectMarkerOnSphere(const Marker& marker, Vec3& X) { X(0) = marker.x; X(1) = marker.y; X(2) = 1.0; @@ -42,12 +42,14 @@ void ProjectMarkerOnSphere(const Marker &marker, Vec3 &X) { X *= 5.0 / X.norm(); } -void ModalSolverLogProgress(ProgressUpdateCallback *update_callback, - double progress) { +void ModalSolverLogProgress(ProgressUpdateCallback* update_callback, + double progress) { if (update_callback) { char message[256]; - snprintf(message, sizeof(message), "Solving progress %d%%", + snprintf(message, + sizeof(message), + "Solving progress %d%%", (int)(progress * 100)); update_callback->invoke(progress, message); @@ -58,25 +60,27 @@ struct ModalReprojectionError { ModalReprojectionError(double observed_x, double observed_y, const double weight, - const Vec3 &bundle) - : observed_x_(observed_x), observed_y_(observed_y), - weight_(weight), bundle_(bundle) { } + const Vec3& bundle) + : observed_x_(observed_x), + observed_y_(observed_y), + weight_(weight), + bundle_(bundle) {} // TODO(keir): This should support bundling focal length as well. template <typename T> bool operator()(const T* quaternion, T* residuals) const { // Convert bundle position from double to T. - T X[3] = { T(bundle_(0)), T(bundle_(1)), T(bundle_(2)) }; + T X[3] = {T(bundle_(0)), T(bundle_(1)), T(bundle_(2))}; // Compute the point position in camera coordinates: x = RX. T x[3]; // This flips the sense of the quaternion, to adhere to Blender conventions. T quaternion_inverse[4] = { - quaternion[0], - -quaternion[1], - -quaternion[2], - -quaternion[3], + quaternion[0], + -quaternion[1], + -quaternion[2], + -quaternion[3], }; ceres::QuaternionRotatePoint(quaternion_inverse, X, x); @@ -99,9 +103,9 @@ struct ModalReprojectionError { }; } // namespace -void ModalSolver(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback) { +void ModalSolver(const Tracks& tracks, + EuclideanReconstruction* reconstruction, + ProgressUpdateCallback* update_callback) { int max_image = tracks.MaxImage(); int max_track = tracks.MaxTrack(); @@ -116,7 +120,7 @@ void ModalSolver(const Tracks &tracks, for (int image = 0; image <= max_image; ++image) { vector<Marker> all_markers = tracks.MarkersInImage(image); - ModalSolverLogProgress(update_callback, (float) image / max_image); + ModalSolverLogProgress(update_callback, (float)image / max_image); // Skip empty images without doing anything. if (all_markers.size() == 0) { @@ -133,8 +137,8 @@ void ModalSolver(const Tracks &tracks, // 3D positions. Mat x1, x2; for (int i = 0; i < all_markers.size(); ++i) { - Marker &marker = all_markers[i]; - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + Marker& marker = all_markers[i]; + EuclideanPoint* point = reconstruction->PointForTrack(marker.track); if (point) { Vec3 X; ProjectMarkerOnSphere(marker, X); @@ -168,8 +172,7 @@ void ModalSolver(const Tracks &tracks, ceres::AngleAxisToQuaternion(&angle_axis(0), &quaternion(0)); - LG << "Analytically computed quaternion " - << quaternion.transpose(); + LG << "Analytically computed quaternion " << quaternion.transpose(); } // STEP 2: Refine rotation with Ceres. @@ -181,17 +184,15 @@ void ModalSolver(const Tracks &tracks, int num_residuals = 0; for (int i = 0; i < all_markers.size(); ++i) { - Marker &marker = all_markers[i]; - EuclideanPoint *point = reconstruction->PointForTrack(marker.track); + Marker& marker = all_markers[i]; + EuclideanPoint* point = reconstruction->PointForTrack(marker.track); if (point && marker.weight != 0.0) { - problem.AddResidualBlock(new ceres::AutoDiffCostFunction< - ModalReprojectionError, - 2, /* num_residuals */ - 4>(new ModalReprojectionError(marker.x, - marker.y, - marker.weight, - point->X)), + problem.AddResidualBlock( + new ceres::AutoDiffCostFunction<ModalReprojectionError, + 2, /* num_residuals */ + 4>(new ModalReprojectionError( + marker.x, marker.y, marker.weight, point->X)), NULL, &quaternion(0)); num_residuals++; diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver.h b/intern/libmv/libmv/simple_pipeline/modal_solver.h index 9801fd21d81..f7ce394b4b2 100644 --- a/intern/libmv/libmv/simple_pipeline/modal_solver.h +++ b/intern/libmv/libmv/simple_pipeline/modal_solver.h @@ -21,9 +21,9 @@ #ifndef LIBMV_SIMPLE_PIPELINE_MODAL_SOLVER_H_ #define LIBMV_SIMPLE_PIPELINE_MODAL_SOLVER_H_ -#include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/callbacks.h" +#include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { @@ -39,9 +39,9 @@ namespace libmv { Reconstructed cameras and projected bundles would be added to reconstruction object. */ -void ModalSolver(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback = NULL); +void ModalSolver(const Tracks& tracks, + EuclideanReconstruction* reconstruction, + ProgressUpdateCallback* update_callback = NULL); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc b/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc index b4cae8defb2..0acf978e6f5 100644 --- a/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc +++ b/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc @@ -20,10 +20,10 @@ #include "libmv/simple_pipeline/modal_solver.h" -#include "testing/testing.h" #include "libmv/logging/logging.h" #include "libmv/simple_pipeline/bundle.h" #include "libmv/simple_pipeline/camera_intrinsics.h" +#include "testing/testing.h" #include <stdio.h> @@ -38,14 +38,21 @@ TEST(ModalSolver, SyntheticCubeSceneMotion) { intrinsics.SetRadialDistortion(0.0, 0.0, 0.0); Marker markers[] = { - {1, 0, 212.172775, 354.713538, 1.0}, {2, 0, 773.468399, 358.735306, 1.0}, - {1, 1, 62.415197, 287.905354, 1.0}, {2, 1, 619.103336, 324.402537, 1.0}, - {1, 2, 206.847939, 237.567925, 1.0}, {2, 2, 737.496986, 247.881383, 1.0}, - {1, 3, 351.743889, 316.415906, 1.0}, {2, 3, 908.779621, 290.703617, 1.0}, - {1, 4, 232.941413, 54.265443, 1.0}, {2, 4, 719.444847, 63.062531, 1.0}, - {1, 5, 96.391611, 119.283537, 1.0}, {2, 5, 611.413136, 160.890715, 1.0}, - {1, 6, 363.444958, 150.838144, 1.0}, {2, 6, 876.374531, 114.916206, 1.0}, - }; + {1, 0, 212.172775, 354.713538, 1.0}, + {2, 0, 773.468399, 358.735306, 1.0}, + {1, 1, 62.415197, 287.905354, 1.0}, + {2, 1, 619.103336, 324.402537, 1.0}, + {1, 2, 206.847939, 237.567925, 1.0}, + {2, 2, 737.496986, 247.881383, 1.0}, + {1, 3, 351.743889, 316.415906, 1.0}, + {2, 3, 908.779621, 290.703617, 1.0}, + {1, 4, 232.941413, 54.265443, 1.0}, + {2, 4, 719.444847, 63.062531, 1.0}, + {1, 5, 96.391611, 119.283537, 1.0}, + {2, 5, 611.413136, 160.890715, 1.0}, + {1, 6, 363.444958, 150.838144, 1.0}, + {2, 6, 876.374531, 114.916206, 1.0}, + }; int num_markers = sizeof(markers) / sizeof(Marker); Tracks tracks; @@ -65,12 +72,14 @@ TEST(ModalSolver, SyntheticCubeSceneMotion) { NULL); Mat3 expected_rotation; + // clang-format off expected_rotation << 0.98215101743472, 0.17798354937546, 0.06083777694542, -0.16875283983360, 0.97665300495333, -0.13293376908719, -0.08307742172243, 0.12029448893171, 0.98925597189636; + // clang-format on - Mat3 &first_camera_R = reconstruction.CameraForImage(1)->R; - Mat3 &second_camera_R = reconstruction.CameraForImage(2)->R; + Mat3& first_camera_R = reconstruction.CameraForImage(1)->R; + Mat3& second_camera_R = reconstruction.CameraForImage(2)->R; EXPECT_TRUE(Mat3::Identity().isApprox(first_camera_R, kTolerance)); EXPECT_TRUE(expected_rotation.isApprox(second_camera_R, kTolerance)); diff --git a/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h b/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h index cbea599fccd..79fa3ab8379 100644 --- a/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h +++ b/intern/libmv/libmv/simple_pipeline/packed_intrinsics.h @@ -40,7 +40,7 @@ class PackedIntrinsics { OFFSET_FOCAL_LENGTH, OFFSET_PRINCIPAL_POINT_X, OFFSET_PRINCIPAL_POINT_Y, - + // Distortion model coefficients. OFFSET_K1, OFFSET_K2, @@ -48,7 +48,7 @@ class PackedIntrinsics { OFFSET_K4, OFFSET_P1, OFFSET_P2, - + // Number of parameters which are to be stored in the block. NUM_PARAMETERS, }; @@ -66,12 +66,12 @@ class PackedIntrinsics { // point. #define DEFINE_PARAMETER(parameter_name) \ - void Set ## parameter_name(double value) { \ - SetParameter(OFFSET_ ## parameter_name, value); \ - } \ - double Get ## parameter_name() const { \ - return GetParameter(OFFSET_ ## parameter_name); \ + void Set##parameter_name(double value) { \ + SetParameter(OFFSET_##parameter_name, value); \ } \ + double Get##parameter_name() const { \ + return GetParameter(OFFSET_##parameter_name); \ + } DEFINE_PARAMETER(K1) DEFINE_PARAMETER(K2) @@ -94,11 +94,11 @@ class PackedIntrinsics { // All intrinsics parameters packed into a single block. // Use OFFSET_FOO indexes to access corresponding values. - array<double, NUM_PARAMETERS> parameters_; + array<double, NUM_PARAMETERS> parameters_; // Indexed by parameter offset, set to truth if the value of the parameter is // explicitly specified. - array<bool, NUM_PARAMETERS> known_parameters_; + array<bool, NUM_PARAMETERS> known_parameters_; }; } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/pipeline.cc b/intern/libmv/libmv/simple_pipeline/pipeline.cc index 728601f3732..5d52aeb7406 100644 --- a/intern/libmv/libmv/simple_pipeline/pipeline.cc +++ b/intern/libmv/libmv/simple_pipeline/pipeline.cc @@ -24,11 +24,11 @@ #include "libmv/logging/logging.h" #include "libmv/simple_pipeline/bundle.h" +#include "libmv/simple_pipeline/camera_intrinsics.h" #include "libmv/simple_pipeline/intersect.h" -#include "libmv/simple_pipeline/resect.h" #include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/resect.h" #include "libmv/simple_pipeline/tracks.h" -#include "libmv/simple_pipeline/camera_intrinsics.h" #ifdef _MSC_VER # define snprintf _snprintf @@ -46,24 +46,25 @@ struct EuclideanPipelineRoutines { typedef EuclideanCamera Camera; typedef EuclideanPoint Point; - static void Bundle(const Tracks &tracks, - EuclideanReconstruction *reconstruction) { + static void Bundle(const Tracks& tracks, + EuclideanReconstruction* reconstruction) { EuclideanBundle(tracks, reconstruction); } - static bool Resect(const vector<Marker> &markers, - EuclideanReconstruction *reconstruction, bool final_pass) { + static bool Resect(const vector<Marker>& markers, + EuclideanReconstruction* reconstruction, + bool final_pass) { return EuclideanResect(markers, reconstruction, final_pass); } - static bool Intersect(const vector<Marker> &markers, - EuclideanReconstruction *reconstruction) { + static bool Intersect(const vector<Marker>& markers, + EuclideanReconstruction* reconstruction) { return EuclideanIntersect(markers, reconstruction); } - static Marker ProjectMarker(const EuclideanPoint &point, - const EuclideanCamera &camera, - const CameraIntrinsics &intrinsics) { + static Marker ProjectMarker(const EuclideanPoint& point, + const EuclideanCamera& camera, + const CameraIntrinsics& intrinsics) { Vec3 projected = camera.R * point.X + camera.t; projected /= projected(2); @@ -84,26 +85,27 @@ struct ProjectivePipelineRoutines { typedef ProjectiveCamera Camera; typedef ProjectivePoint Point; - static void Bundle(const Tracks &tracks, - ProjectiveReconstruction *reconstruction) { + static void Bundle(const Tracks& tracks, + ProjectiveReconstruction* reconstruction) { ProjectiveBundle(tracks, reconstruction); } - static bool Resect(const vector<Marker> &markers, - ProjectiveReconstruction *reconstruction, bool final_pass) { - (void) final_pass; // Ignored. + static bool Resect(const vector<Marker>& markers, + ProjectiveReconstruction* reconstruction, + bool final_pass) { + (void)final_pass; // Ignored. return ProjectiveResect(markers, reconstruction); } - static bool Intersect(const vector<Marker> &markers, - ProjectiveReconstruction *reconstruction) { + static bool Intersect(const vector<Marker>& markers, + ProjectiveReconstruction* reconstruction) { return ProjectiveIntersect(markers, reconstruction); } - static Marker ProjectMarker(const ProjectivePoint &point, - const ProjectiveCamera &camera, - const CameraIntrinsics &intrinsics) { + static Marker ProjectMarker(const ProjectivePoint& point, + const ProjectiveCamera& camera, + const CameraIntrinsics& intrinsics) { Vec3 projected = camera.P * point.X; projected /= projected(2); @@ -122,28 +124,33 @@ struct ProjectivePipelineRoutines { } // namespace static void CompleteReconstructionLogProgress( - ProgressUpdateCallback *update_callback, + ProgressUpdateCallback* update_callback, double progress, - const char *step = NULL) { + const char* step = NULL) { if (update_callback) { char message[256]; if (step) - snprintf(message, sizeof(message), "Completing solution %d%% | %s", - (int)(progress*100), step); + snprintf(message, + sizeof(message), + "Completing solution %d%% | %s", + (int)(progress * 100), + step); else - snprintf(message, sizeof(message), "Completing solution %d%%", - (int)(progress*100)); + snprintf(message, + sizeof(message), + "Completing solution %d%%", + (int)(progress * 100)); update_callback->invoke(progress, message); } } -template<typename PipelineRoutines> +template <typename PipelineRoutines> void InternalCompleteReconstruction( - const Tracks &tracks, - typename PipelineRoutines::Reconstruction *reconstruction, - ProgressUpdateCallback *update_callback = NULL) { + const Tracks& tracks, + typename PipelineRoutines::Reconstruction* reconstruction, + ProgressUpdateCallback* update_callback = NULL) { int max_track = tracks.MaxTrack(); int max_image = tracks.MaxImage(); int num_resects = -1; @@ -173,7 +180,7 @@ void InternalCompleteReconstruction( << " reconstructed markers for track " << track; if (reconstructed_markers.size() >= 2) { CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image)); + (double)tot_resects / (max_image)); if (PipelineRoutines::Intersect(reconstructed_markers, reconstruction)) { num_intersects++; @@ -184,9 +191,8 @@ void InternalCompleteReconstruction( } } if (num_intersects) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image), - "Bundling..."); + CompleteReconstructionLogProgress( + update_callback, (double)tot_resects / (max_image), "Bundling..."); PipelineRoutines::Bundle(tracks, reconstruction); LG << "Ran Bundle() after intersections."; } @@ -212,9 +218,9 @@ void InternalCompleteReconstruction( << " reconstructed markers for image " << image; if (reconstructed_markers.size() >= 5) { CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image)); - if (PipelineRoutines::Resect(reconstructed_markers, - reconstruction, false)) { + (double)tot_resects / (max_image)); + if (PipelineRoutines::Resect( + reconstructed_markers, reconstruction, false)) { num_resects++; tot_resects++; LG << "Ran Resect() for image " << image; @@ -224,9 +230,8 @@ void InternalCompleteReconstruction( } } if (num_resects) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image), - "Bundling..."); + CompleteReconstructionLogProgress( + update_callback, (double)tot_resects / (max_image), "Bundling..."); PipelineRoutines::Bundle(tracks, reconstruction); } LG << "Did " << num_resects << " resects."; @@ -249,9 +254,9 @@ void InternalCompleteReconstruction( } if (reconstructed_markers.size() >= 5) { CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image)); - if (PipelineRoutines::Resect(reconstructed_markers, - reconstruction, true)) { + (double)tot_resects / (max_image)); + if (PipelineRoutines::Resect( + reconstructed_markers, reconstruction, true)) { num_resects++; LG << "Ran final Resect() for image " << image; } else { @@ -260,27 +265,26 @@ void InternalCompleteReconstruction( } } if (num_resects) { - CompleteReconstructionLogProgress(update_callback, - (double)tot_resects/(max_image), - "Bundling..."); + CompleteReconstructionLogProgress( + update_callback, (double)tot_resects / (max_image), "Bundling..."); PipelineRoutines::Bundle(tracks, reconstruction); } } -template<typename PipelineRoutines> +template <typename PipelineRoutines> double InternalReprojectionError( - const Tracks &image_tracks, - const typename PipelineRoutines::Reconstruction &reconstruction, - const CameraIntrinsics &intrinsics) { + const Tracks& image_tracks, + const typename PipelineRoutines::Reconstruction& reconstruction, + const CameraIntrinsics& intrinsics) { int num_skipped = 0; int num_reprojected = 0; double total_error = 0.0; vector<Marker> markers = image_tracks.AllMarkers(); for (int i = 0; i < markers.size(); ++i) { double weight = markers[i].weight; - const typename PipelineRoutines::Camera *camera = + const typename PipelineRoutines::Camera* camera = reconstruction.CameraForImage(markers[i].image); - const typename PipelineRoutines::Point *point = + const typename PipelineRoutines::Point* point = reconstruction.PointForTrack(markers[i].track); if (!camera || !point || weight == 0.0) { num_skipped++; @@ -295,24 +299,25 @@ double InternalReprojectionError( const int N = 100; char line[N]; - snprintf(line, N, - "image %-3d track %-3d " - "x %7.1f y %7.1f " - "rx %7.1f ry %7.1f " - "ex %7.1f ey %7.1f" - " e %7.1f", - markers[i].image, - markers[i].track, - markers[i].x, - markers[i].y, - reprojected_marker.x, - reprojected_marker.y, - ex, - ey, - sqrt(ex*ex + ey*ey)); + snprintf(line, + N, + "image %-3d track %-3d " + "x %7.1f y %7.1f " + "rx %7.1f ry %7.1f " + "ex %7.1f ey %7.1f" + " e %7.1f", + markers[i].image, + markers[i].track, + markers[i].x, + markers[i].y, + reprojected_marker.x, + reprojected_marker.y, + ex, + ey, + sqrt(ex * ex + ey * ey)); VLOG(1) << line; - total_error += sqrt(ex*ex + ey*ey); + total_error += sqrt(ex * ex + ey * ey); } LG << "Skipped " << num_skipped << " markers."; LG << "Reprojected " << num_reprojected << " markers."; @@ -321,46 +326,41 @@ double InternalReprojectionError( return total_error / num_reprojected; } -double EuclideanReprojectionError(const Tracks &image_tracks, - const EuclideanReconstruction &reconstruction, - const CameraIntrinsics &intrinsics) { - return InternalReprojectionError<EuclideanPipelineRoutines>(image_tracks, - reconstruction, - intrinsics); +double EuclideanReprojectionError(const Tracks& image_tracks, + const EuclideanReconstruction& reconstruction, + const CameraIntrinsics& intrinsics) { + return InternalReprojectionError<EuclideanPipelineRoutines>( + image_tracks, reconstruction, intrinsics); } double ProjectiveReprojectionError( - const Tracks &image_tracks, - const ProjectiveReconstruction &reconstruction, - const CameraIntrinsics &intrinsics) { - return InternalReprojectionError<ProjectivePipelineRoutines>(image_tracks, - reconstruction, - intrinsics); + const Tracks& image_tracks, + const ProjectiveReconstruction& reconstruction, + const CameraIntrinsics& intrinsics) { + return InternalReprojectionError<ProjectivePipelineRoutines>( + image_tracks, reconstruction, intrinsics); } -void EuclideanCompleteReconstruction(const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback) { - InternalCompleteReconstruction<EuclideanPipelineRoutines>(tracks, - reconstruction, - update_callback); +void EuclideanCompleteReconstruction(const Tracks& tracks, + EuclideanReconstruction* reconstruction, + ProgressUpdateCallback* update_callback) { + InternalCompleteReconstruction<EuclideanPipelineRoutines>( + tracks, reconstruction, update_callback); } -void ProjectiveCompleteReconstruction(const Tracks &tracks, - ProjectiveReconstruction *reconstruction) { +void ProjectiveCompleteReconstruction( + const Tracks& tracks, ProjectiveReconstruction* reconstruction) { InternalCompleteReconstruction<ProjectivePipelineRoutines>(tracks, reconstruction); } -void InvertIntrinsicsForTracks(const Tracks &raw_tracks, - const CameraIntrinsics &camera_intrinsics, - Tracks *calibrated_tracks) { +void InvertIntrinsicsForTracks(const Tracks& raw_tracks, + const CameraIntrinsics& camera_intrinsics, + Tracks* calibrated_tracks) { vector<Marker> markers = raw_tracks.AllMarkers(); for (int i = 0; i < markers.size(); ++i) { - camera_intrinsics.InvertIntrinsics(markers[i].x, - markers[i].y, - &(markers[i].x), - &(markers[i].y)); + camera_intrinsics.InvertIntrinsics( + markers[i].x, markers[i].y, &(markers[i].x), &(markers[i].y)); } *calibrated_tracks = Tracks(markers); } diff --git a/intern/libmv/libmv/simple_pipeline/pipeline.h b/intern/libmv/libmv/simple_pipeline/pipeline.h index 4d1bd00c51f..d6b43536d46 100644 --- a/intern/libmv/libmv/simple_pipeline/pipeline.h +++ b/intern/libmv/libmv/simple_pipeline/pipeline.h @@ -22,8 +22,8 @@ #define LIBMV_SIMPLE_PIPELINE_PIPELINE_H_ #include "libmv/simple_pipeline/callbacks.h" -#include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { @@ -47,9 +47,9 @@ namespace libmv { \sa EuclideanResect, EuclideanIntersect, EuclideanBundle */ void EuclideanCompleteReconstruction( - const Tracks &tracks, - EuclideanReconstruction *reconstruction, - ProgressUpdateCallback *update_callback = NULL); + const Tracks& tracks, + EuclideanReconstruction* reconstruction, + ProgressUpdateCallback* update_callback = NULL); /*! Estimate camera matrices and homogeneous 3D coordinates for all frames and @@ -71,27 +71,26 @@ void EuclideanCompleteReconstruction( \sa ProjectiveResect, ProjectiveIntersect, ProjectiveBundle */ -void ProjectiveCompleteReconstruction(const Tracks &tracks, - ProjectiveReconstruction *reconstruction); - +void ProjectiveCompleteReconstruction(const Tracks& tracks, + ProjectiveReconstruction* reconstruction); class CameraIntrinsics; // TODO(keir): Decide if we want these in the public API, and if so, what the // appropriate include file is. -double EuclideanReprojectionError(const Tracks &image_tracks, - const EuclideanReconstruction &reconstruction, - const CameraIntrinsics &intrinsics); +double EuclideanReprojectionError(const Tracks& image_tracks, + const EuclideanReconstruction& reconstruction, + const CameraIntrinsics& intrinsics); double ProjectiveReprojectionError( - const Tracks &image_tracks, - const ProjectiveReconstruction &reconstruction, - const CameraIntrinsics &intrinsics); + const Tracks& image_tracks, + const ProjectiveReconstruction& reconstruction, + const CameraIntrinsics& intrinsics); -void InvertIntrinsicsForTracks(const Tracks &raw_tracks, - const CameraIntrinsics &camera_intrinsics, - Tracks *calibrated_tracks); +void InvertIntrinsicsForTracks(const Tracks& raw_tracks, + const CameraIntrinsics& camera_intrinsics, + Tracks* calibrated_tracks); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction.cc b/intern/libmv/libmv/simple_pipeline/reconstruction.cc index 851eedb5bb1..584f7440caf 100644 --- a/intern/libmv/libmv/simple_pipeline/reconstruction.cc +++ b/intern/libmv/libmv/simple_pipeline/reconstruction.cc @@ -19,20 +19,21 @@ // IN THE SOFTWARE. #include "libmv/simple_pipeline/reconstruction.h" -#include "libmv/numeric/numeric.h" #include "libmv/logging/logging.h" +#include "libmv/numeric/numeric.h" namespace libmv { -EuclideanReconstruction::EuclideanReconstruction() {} +EuclideanReconstruction::EuclideanReconstruction() { +} EuclideanReconstruction::EuclideanReconstruction( - const EuclideanReconstruction &other) { + const EuclideanReconstruction& other) { image_to_cameras_map_ = other.image_to_cameras_map_; points_ = other.points_; } -EuclideanReconstruction &EuclideanReconstruction::operator=( - const EuclideanReconstruction &other) { +EuclideanReconstruction& EuclideanReconstruction::operator=( + const EuclideanReconstruction& other) { if (&other != this) { image_to_cameras_map_ = other.image_to_cameras_map_; points_ = other.points_; @@ -41,9 +42,9 @@ EuclideanReconstruction &EuclideanReconstruction::operator=( } void EuclideanReconstruction::InsertCamera(int image, - const Mat3 &R, - const Vec3 &t) { - LG << "InsertCamera " << image << ":\nR:\n"<< R << "\nt:\n" << t; + const Mat3& R, + const Vec3& t) { + LG << "InsertCamera " << image << ":\nR:\n" << R << "\nt:\n" << t; EuclideanCamera camera; camera.image = image; @@ -53,7 +54,7 @@ void EuclideanReconstruction::InsertCamera(int image, image_to_cameras_map_.insert(make_pair(image, camera)); } -void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) { +void EuclideanReconstruction::InsertPoint(int track, const Vec3& X) { LG << "InsertPoint " << track << ":\n" << X; if (track >= points_.size()) { points_.resize(track + 1); @@ -62,13 +63,12 @@ void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) { points_[track].X = X; } -EuclideanCamera *EuclideanReconstruction::CameraForImage(int image) { - return const_cast<EuclideanCamera *>( - static_cast<const EuclideanReconstruction *>( - this)->CameraForImage(image)); +EuclideanCamera* EuclideanReconstruction::CameraForImage(int image) { + return const_cast<EuclideanCamera*>( + static_cast<const EuclideanReconstruction*>(this)->CameraForImage(image)); } -const EuclideanCamera *EuclideanReconstruction::CameraForImage( +const EuclideanCamera* EuclideanReconstruction::CameraForImage( int image) const { ImageToCameraMap::const_iterator it = image_to_cameras_map_.find(image); if (it == image_to_cameras_map_.end()) { @@ -86,16 +86,16 @@ vector<EuclideanCamera> EuclideanReconstruction::AllCameras() const { return cameras; } -EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) { - return const_cast<EuclideanPoint *>( - static_cast<const EuclideanReconstruction *>(this)->PointForTrack(track)); +EuclideanPoint* EuclideanReconstruction::PointForTrack(int track) { + return const_cast<EuclideanPoint*>( + static_cast<const EuclideanReconstruction*>(this)->PointForTrack(track)); } -const EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) const { +const EuclideanPoint* EuclideanReconstruction::PointForTrack(int track) const { if (track < 0 || track >= points_.size()) { return NULL; } - const EuclideanPoint *point = &points_[track]; + const EuclideanPoint* point = &points_[track]; if (point->track == -1) { return NULL; } @@ -112,8 +112,8 @@ vector<EuclideanPoint> EuclideanReconstruction::AllPoints() const { return points; } -void ProjectiveReconstruction::InsertCamera(int image, const Mat34 &P) { - LG << "InsertCamera " << image << ":\nP:\n"<< P; +void ProjectiveReconstruction::InsertCamera(int image, const Mat34& P) { + LG << "InsertCamera " << image << ":\nP:\n" << P; ProjectiveCamera camera; camera.image = image; @@ -122,7 +122,7 @@ void ProjectiveReconstruction::InsertCamera(int image, const Mat34 &P) { image_to_cameras_map_.insert(make_pair(image, camera)); } -void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) { +void ProjectiveReconstruction::InsertPoint(int track, const Vec4& X) { LG << "InsertPoint " << track << ":\n" << X; if (track >= points_.size()) { points_.resize(track + 1); @@ -131,17 +131,17 @@ void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) { points_[track].X = X; } -ProjectiveCamera *ProjectiveReconstruction::CameraForImage(int image) { - return const_cast<ProjectiveCamera *>( - static_cast<const ProjectiveReconstruction *>( - this)->CameraForImage(image)); +ProjectiveCamera* ProjectiveReconstruction::CameraForImage(int image) { + return const_cast<ProjectiveCamera*>( + static_cast<const ProjectiveReconstruction*>(this)->CameraForImage( + image)); } -const ProjectiveCamera *ProjectiveReconstruction::CameraForImage( +const ProjectiveCamera* ProjectiveReconstruction::CameraForImage( int image) const { ImageToCameraMap::const_iterator it = image_to_cameras_map_.find(image); if (it == image_to_cameras_map_.end()) { - return NULL; + return NULL; } return &it->second; } @@ -155,16 +155,17 @@ vector<ProjectiveCamera> ProjectiveReconstruction::AllCameras() const { return cameras; } -ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) { - return const_cast<ProjectivePoint *>( - static_cast<const ProjectiveReconstruction *>(this)->PointForTrack(track)); +ProjectivePoint* ProjectiveReconstruction::PointForTrack(int track) { + return const_cast<ProjectivePoint*>( + static_cast<const ProjectiveReconstruction*>(this)->PointForTrack(track)); } -const ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) const { +const ProjectivePoint* ProjectiveReconstruction::PointForTrack( + int track) const { if (track < 0 || track >= points_.size()) { return NULL; } - const ProjectivePoint *point = &points_[track]; + const ProjectivePoint* point = &points_[track]; if (point->track == -1) { return NULL; } diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction.h b/intern/libmv/libmv/simple_pipeline/reconstruction.h index 544aeac042e..56b2ba34c91 100644 --- a/intern/libmv/libmv/simple_pipeline/reconstruction.h +++ b/intern/libmv/libmv/simple_pipeline/reconstruction.h @@ -21,14 +21,15 @@ #ifndef LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_ #define LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_ -#include "libmv/base/vector.h" #include "libmv/base/map.h" +#include "libmv/base/vector.h" #include "libmv/numeric/numeric.h" namespace libmv { /*! - A EuclideanCamera is the location and rotation of the camera viewing \a image. + A EuclideanCamera is the location and rotation of the camera viewing \a + image. \a image identify which image from \link Tracks this camera represents. \a R is a 3x3 matrix representing the rotation of the camera. @@ -38,7 +39,7 @@ namespace libmv { */ struct EuclideanCamera { EuclideanCamera() : image(-1) {} - EuclideanCamera(const EuclideanCamera &c) : image(c.image), R(c.R), t(c.t) {} + EuclideanCamera(const EuclideanCamera& c) : image(c.image), R(c.R), t(c.t) {} int image; Mat3 R; @@ -55,7 +56,7 @@ struct EuclideanCamera { */ struct EuclideanPoint { EuclideanPoint() : track(-1) {} - EuclideanPoint(const EuclideanPoint &p) : track(p.track), X(p.X) {} + EuclideanPoint(const EuclideanPoint& p) : track(p.track), X(p.X) {} int track; Vec3 X; }; @@ -78,9 +79,9 @@ class EuclideanReconstruction { EuclideanReconstruction(); /// Copy constructor. - EuclideanReconstruction(const EuclideanReconstruction &other); + EuclideanReconstruction(const EuclideanReconstruction& other); - EuclideanReconstruction &operator=(const EuclideanReconstruction &other); + EuclideanReconstruction& operator=(const EuclideanReconstruction& other); /*! Insert a camera into the set. If there is already a camera for the given @@ -92,7 +93,7 @@ class EuclideanReconstruction { \note You should use the same \a image identifier as in \link Tracks. */ - void InsertCamera(int image, const Mat3 &R, const Vec3 &t); + void InsertCamera(int image, const Mat3& R, const Vec3& t); /*! Insert a point into the reconstruction. If there is already a point for @@ -104,18 +105,18 @@ class EuclideanReconstruction { \note You should use the same \a track identifier as in \link Tracks. */ - void InsertPoint(int track, const Vec3 &X); + void InsertPoint(int track, const Vec3& X); /// Returns a pointer to the camera corresponding to \a image. - EuclideanCamera *CameraForImage(int image); - const EuclideanCamera *CameraForImage(int image) const; + EuclideanCamera* CameraForImage(int image); + const EuclideanCamera* CameraForImage(int image) const; /// Returns all cameras. vector<EuclideanCamera> AllCameras() const; /// Returns a pointer to the point corresponding to \a track. - EuclideanPoint *PointForTrack(int track); - const EuclideanPoint *PointForTrack(int track) const; + EuclideanPoint* PointForTrack(int track); + const EuclideanPoint* PointForTrack(int track) const; /// Returns all points. vector<EuclideanPoint> AllPoints() const; @@ -139,7 +140,7 @@ class EuclideanReconstruction { */ struct ProjectiveCamera { ProjectiveCamera() : image(-1) {} - ProjectiveCamera(const ProjectiveCamera &c) : image(c.image), P(c.P) {} + ProjectiveCamera(const ProjectiveCamera& c) : image(c.image), P(c.P) {} int image; Mat34 P; @@ -155,7 +156,7 @@ struct ProjectiveCamera { */ struct ProjectivePoint { ProjectivePoint() : track(-1) {} - ProjectivePoint(const ProjectivePoint &p) : track(p.track), X(p.X) {} + ProjectivePoint(const ProjectivePoint& p) : track(p.track), X(p.X) {} int track; Vec4 X; }; @@ -184,7 +185,7 @@ class ProjectiveReconstruction { \note You should use the same \a image identifier as in \link Tracks. */ - void InsertCamera(int image, const Mat34 &P); + void InsertCamera(int image, const Mat34& P); /*! Insert a point into the reconstruction. If there is already a point for @@ -196,18 +197,18 @@ class ProjectiveReconstruction { \note You should use the same \a track identifier as in \link Tracks. */ - void InsertPoint(int track, const Vec4 &X); + void InsertPoint(int track, const Vec4& X); /// Returns a pointer to the camera corresponding to \a image. - ProjectiveCamera *CameraForImage(int image); - const ProjectiveCamera *CameraForImage(int image) const; + ProjectiveCamera* CameraForImage(int image); + const ProjectiveCamera* CameraForImage(int image) const; /// Returns all cameras. vector<ProjectiveCamera> AllCameras() const; /// Returns a pointer to the point corresponding to \a track. - ProjectivePoint *PointForTrack(int track); - const ProjectivePoint *PointForTrack(int track) const; + ProjectivePoint* PointForTrack(int track); + const ProjectivePoint* PointForTrack(int track) const; /// Returns all points. vector<ProjectivePoint> AllPoints() const; diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc index 40ac23be7a2..04fbb536d31 100644 --- a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc +++ b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.cc @@ -23,7 +23,7 @@ namespace libmv { -void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction) { +void EuclideanScaleToUnity(EuclideanReconstruction* reconstruction) { vector<EuclideanCamera> all_cameras = reconstruction->AllCameras(); vector<EuclideanPoint> all_points = reconstruction->AllPoints(); @@ -53,14 +53,14 @@ void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction) { // Rescale cameras positions. for (int i = 0; i < all_cameras.size(); ++i) { int image = all_cameras[i].image; - EuclideanCamera *camera = reconstruction->CameraForImage(image); + EuclideanCamera* camera = reconstruction->CameraForImage(image); camera->t = camera->t * scale_factor; } // Rescale points positions. for (int i = 0; i < all_points.size(); ++i) { int track = all_points[i].track; - EuclideanPoint *point = reconstruction->PointForTrack(track); + EuclideanPoint* point = reconstruction->PointForTrack(track); point->X = point->X * scale_factor; } } diff --git a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h index f2349ff5146..c164878ee25 100644 --- a/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h +++ b/intern/libmv/libmv/simple_pipeline/reconstruction_scale.h @@ -29,7 +29,7 @@ namespace libmv { Scale euclidean reconstruction in a way variance of camera centers equals to one. */ -void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction); +void EuclideanScaleToUnity(EuclideanReconstruction* reconstruction); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/resect.cc b/intern/libmv/libmv/simple_pipeline/resect.cc index e73fc44df2a..b5736767edd 100644 --- a/intern/libmv/libmv/simple_pipeline/resect.cc +++ b/intern/libmv/libmv/simple_pipeline/resect.cc @@ -25,17 +25,17 @@ #include "libmv/base/vector.h" #include "libmv/logging/logging.h" #include "libmv/multiview/euclidean_resection.h" -#include "libmv/multiview/resection.h" #include "libmv/multiview/projection.h" -#include "libmv/numeric/numeric.h" +#include "libmv/multiview/resection.h" #include "libmv/numeric/levenberg_marquardt.h" +#include "libmv/numeric/numeric.h" #include "libmv/simple_pipeline/reconstruction.h" #include "libmv/simple_pipeline/tracks.h" namespace libmv { namespace { -Mat2X PointMatrixFromMarkers(const vector<Marker> &markers) { +Mat2X PointMatrixFromMarkers(const vector<Marker>& markers) { Mat2X points(2, markers.size()); for (int i = 0; i < markers.size(); ++i) { points(0, i) = markers[i].x; @@ -53,19 +53,19 @@ Mat2X PointMatrixFromMarkers(const vector<Marker> &markers) { // axis to rotate around and the magnitude is the amount of the rotation. struct EuclideanResectCostFunction { public: - typedef Vec FMatrixType; + typedef Vec FMatrixType; typedef Vec6 XMatrixType; - EuclideanResectCostFunction(const vector<Marker> &markers, - const EuclideanReconstruction &reconstruction, - const Mat3 &initial_R) - : markers(markers), - reconstruction(reconstruction), - initial_R(initial_R) {} + EuclideanResectCostFunction(const vector<Marker>& markers, + const EuclideanReconstruction& reconstruction, + const Mat3& initial_R) + : markers(markers), + reconstruction(reconstruction), + initial_R(initial_R) {} // dRt has dR (delta R) encoded as a euler vector in the first 3 parameters, // followed by t in the next 3 parameters. - Vec operator()(const Vec6 &dRt) const { + Vec operator()(const Vec6& dRt) const { // Unpack R, t from dRt. Mat3 R = RotationFromEulerVector(dRt.head<3>()) * initial_R; Vec3 t = dRt.tail<3>(); @@ -74,25 +74,26 @@ struct EuclideanResectCostFunction { Vec residuals(2 * markers.size()); residuals.setZero(); for (int i = 0; i < markers.size(); ++i) { - const EuclideanPoint &point = + const EuclideanPoint& point = *reconstruction.PointForTrack(markers[i].track); Vec3 projected = R * point.X + t; projected /= projected(2); - residuals[2*i + 0] = projected(0) - markers[i].x; - residuals[2*i + 1] = projected(1) - markers[i].y; + residuals[2 * i + 0] = projected(0) - markers[i].x; + residuals[2 * i + 1] = projected(1) - markers[i].y; } return residuals; } - const vector<Marker> &markers; - const EuclideanReconstruction &reconstruction; - const Mat3 &initial_R; + const vector<Marker>& markers; + const EuclideanReconstruction& reconstruction; + const Mat3& initial_R; }; } // namespace -bool EuclideanResect(const vector<Marker> &markers, - EuclideanReconstruction *reconstruction, bool final_pass) { +bool EuclideanResect(const vector<Marker>& markers, + EuclideanReconstruction* reconstruction, + bool final_pass) { if (markers.size() < 5) { return false; } @@ -106,9 +107,9 @@ bool EuclideanResect(const vector<Marker> &markers, Mat3 R; Vec3 t; - if (0 || !euclidean_resection::EuclideanResection( - points_2d, points_3d, &R, &t, - euclidean_resection::RESECTION_EPNP)) { + if (0 || + !euclidean_resection::EuclideanResection( + points_2d, points_3d, &R, &t, euclidean_resection::RESECTION_EPNP)) { // printf("Resection for image %d failed\n", markers[0].image); LG << "Resection for image " << markers[0].image << " failed;" << " trying fallback projective resection."; @@ -116,7 +117,8 @@ bool EuclideanResect(const vector<Marker> &markers, LG << "No fallback; failing resection for " << markers[0].image; return false; - if (!final_pass) return false; + if (!final_pass) + return false; // Euclidean resection failed. Fall back to projective resection, which is // less reliable but better conditioned when there are many points. Mat34 P; @@ -173,7 +175,9 @@ bool EuclideanResect(const vector<Marker> &markers, t = dRt.tail<3>(); LG << "Resection for image " << markers[0].image << " got:\n" - << "R:\n" << R << "\nt:\n" << t; + << "R:\n" + << R << "\nt:\n" + << t; reconstruction->InsertCamera(markers[0].image, R, t); return true; } @@ -186,15 +190,14 @@ namespace { // freedom drift. struct ProjectiveResectCostFunction { public: - typedef Vec FMatrixType; + typedef Vec FMatrixType; typedef Vec12 XMatrixType; - ProjectiveResectCostFunction(const vector<Marker> &markers, - const ProjectiveReconstruction &reconstruction) - : markers(markers), - reconstruction(reconstruction) {} + ProjectiveResectCostFunction(const vector<Marker>& markers, + const ProjectiveReconstruction& reconstruction) + : markers(markers), reconstruction(reconstruction) {} - Vec operator()(const Vec12 &vector_P) const { + Vec operator()(const Vec12& vector_P) const { // Unpack P from vector_P. Map<const Mat34> P(vector_P.data(), 3, 4); @@ -202,24 +205,24 @@ struct ProjectiveResectCostFunction { Vec residuals(2 * markers.size()); residuals.setZero(); for (int i = 0; i < markers.size(); ++i) { - const ProjectivePoint &point = + const ProjectivePoint& point = *reconstruction.PointForTrack(markers[i].track); Vec3 projected = P * point.X; projected /= projected(2); - residuals[2*i + 0] = projected(0) - markers[i].x; - residuals[2*i + 1] = projected(1) - markers[i].y; + residuals[2 * i + 0] = projected(0) - markers[i].x; + residuals[2 * i + 1] = projected(1) - markers[i].y; } return residuals; } - const vector<Marker> &markers; - const ProjectiveReconstruction &reconstruction; + const vector<Marker>& markers; + const ProjectiveReconstruction& reconstruction; }; } // namespace -bool ProjectiveResect(const vector<Marker> &markers, - ProjectiveReconstruction *reconstruction) { +bool ProjectiveResect(const vector<Marker>& markers, + ProjectiveReconstruction* reconstruction) { if (markers.size() < 5) { return false; } @@ -263,7 +266,8 @@ bool ProjectiveResect(const vector<Marker> &markers, P = Map<Mat34>(vector_P.data(), 3, 4); LG << "Resection for image " << markers[0].image << " got:\n" - << "P:\n" << P; + << "P:\n" + << P; reconstruction->InsertCamera(markers[0].image, P); return true; } diff --git a/intern/libmv/libmv/simple_pipeline/resect.h b/intern/libmv/libmv/simple_pipeline/resect.h index f13d2e2d425..13c3d66bd37 100644 --- a/intern/libmv/libmv/simple_pipeline/resect.h +++ b/intern/libmv/libmv/simple_pipeline/resect.h @@ -22,8 +22,8 @@ #define LIBMV_SIMPLE_PIPELINE_RESECT_H #include "libmv/base/vector.h" -#include "libmv/simple_pipeline/tracks.h" #include "libmv/simple_pipeline/reconstruction.h" +#include "libmv/simple_pipeline/tracks.h" namespace libmv { @@ -51,8 +51,9 @@ namespace libmv { \sa EuclideanIntersect, EuclideanReconstructTwoFrames */ -bool EuclideanResect(const vector<Marker> &markers, - EuclideanReconstruction *reconstruction, bool final_pass); +bool EuclideanResect(const vector<Marker>& markers, + EuclideanReconstruction* reconstruction, + bool final_pass); /*! Estimate the projective pose of a camera from 2D to 3D correspondences. @@ -78,8 +79,8 @@ bool EuclideanResect(const vector<Marker> &markers, \sa ProjectiveIntersect, ProjectiveReconstructTwoFrames */ -bool ProjectiveResect(const vector<Marker> &markers, - ProjectiveReconstruction *reconstruction); +bool ProjectiveResect(const vector<Marker>& markers, + ProjectiveReconstruction* reconstruction); } // namespace libmv diff --git a/intern/libmv/libmv/simple_pipeline/resect_test.cc b/intern/libmv/libmv/simple_pipeline/resect_test.cc index 811edd282d8..ecf3f9b673d 100644 --- a/intern/libmv/libmv/simple_pipeline/resect_test.cc +++ b/intern/libmv/libmv/simple_pipeline/resect_test.cc @@ -153,7 +153,7 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { // not precise enough with only 4 points. // // TODO(jmichot): Reenable this test when there is nonlinear refinement. -#if 0 +# if 0 R_output.setIdentity(); T_output.setZero(); @@ -163,7 +163,7 @@ TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) { EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5); EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);*/ -#endif +# endif } // TODO(jmichot): Reduce the code duplication here with the code above. diff --git a/intern/libmv/libmv/simple_pipeline/tracks.cc b/intern/libmv/libmv/simple_pipeline/tracks.cc index d5d009708ba..66243807a4b 100644 --- a/intern/libmv/libmv/simple_pipeline/tracks.cc +++ b/intern/libmv/libmv/simple_pipeline/tracks.cc @@ -21,31 +21,31 @@ #include "libmv/simple_pipeline/tracks.h" #include <algorithm> -#include <vector> #include <iterator> +#include <vector> #include "libmv/numeric/numeric.h" namespace libmv { -Tracks::Tracks(const Tracks &other) { +Tracks::Tracks(const Tracks& other) { markers_ = other.markers_; } -Tracks::Tracks(const vector<Marker> &markers) : markers_(markers) {} +Tracks::Tracks(const vector<Marker>& markers) : markers_(markers) { +} void Tracks::Insert(int image, int track, double x, double y, double weight) { // TODO(keir): Wow, this is quadratic for repeated insertions. Fix this by // adding a smarter data structure like a set<>. for (int i = 0; i < markers_.size(); ++i) { - if (markers_[i].image == image && - markers_[i].track == track) { + if (markers_[i].image == image && markers_[i].track == track) { markers_[i].x = x; markers_[i].y = y; return; } } - Marker marker = { image, track, x, y, weight }; + Marker marker = {image, track, x, y, weight}; markers_.push_back(marker); } @@ -101,15 +101,17 @@ vector<Marker> Tracks::MarkersForTracksInBothImages(int image1, std::sort(image2_tracks.begin(), image2_tracks.end()); std::vector<int> intersection; - std::set_intersection(image1_tracks.begin(), image1_tracks.end(), - image2_tracks.begin(), image2_tracks.end(), + std::set_intersection(image1_tracks.begin(), + image1_tracks.end(), + image2_tracks.begin(), + image2_tracks.end(), std::back_inserter(intersection)); vector<Marker> markers; for (int i = 0; i < markers_.size(); ++i) { if ((markers_[i].image == image1 || markers_[i].image == image2) && - std::binary_search(intersection.begin(), intersection.end(), - markers_[i].track)) { + std::binary_search( + intersection.begin(), intersection.end(), markers_[i].track)) { markers.push_back(markers_[i]); } } @@ -122,7 +124,7 @@ Marker Tracks::MarkerInImageForTrack(int image, int track) const { return markers_[i]; } } - Marker null = { -1, -1, -1, -1, 0.0 }; + Marker null = {-1, -1, -1, -1, 0.0}; return null; } @@ -168,12 +170,12 @@ int Tracks::NumMarkers() const { return markers_.size(); } -void CoordinatesForMarkersInImage(const vector<Marker> &markers, +void CoordinatesForMarkersInImage(const vector<Marker>& markers, int image, - Mat *coordinates) { + Mat* coordinates) { vector<Vec2> coords; for (int i = 0; i < markers.size(); ++i) { - const Marker &marker = markers[i]; + const Marker& marker = markers[i]; if (markers[i].image == image) { coords.push_back(Vec2(marker.x, marker.y)); } diff --git a/intern/libmv/libmv/simple_pipeline/tracks.h b/intern/libmv/libmv/simple_pipeline/tracks.h index 752d2790a1c..c3df3a223d8 100644 --- a/intern/libmv/libmv/simple_pipeline/tracks.h +++ b/intern/libmv/libmv/simple_pipeline/tracks.h @@ -36,7 +36,8 @@ namespace libmv { \a weight is used by bundle adjustment and weight means how much the track affects on a final solution. - \note Markers are typically aggregated with the help of the \link Tracks class. + \note Markers are typically aggregated with the help of the \link Tracks + class. \sa Tracks */ @@ -56,19 +57,20 @@ struct Marker { images, which must get created before any 3D reconstruction can take place. The container has several fast lookups for queries typically needed for - structure from motion algorithms, such as \link MarkersForTracksInBothImages(). + structure from motion algorithms, such as \link + MarkersForTracksInBothImages(). \sa Marker */ class Tracks { public: - Tracks() { } + Tracks() {} // Copy constructor for a tracks object. - Tracks(const Tracks &other); + Tracks(const Tracks& other); /// Construct a new tracks object using the given markers to start. - explicit Tracks(const vector<Marker> &markers); + explicit Tracks(const vector<Marker>& markers); /*! Inserts a marker into the set. If there is already a marker for the given @@ -129,9 +131,9 @@ class Tracks { vector<Marker> markers_; }; -void CoordinatesForMarkersInImage(const vector<Marker> &markers, +void CoordinatesForMarkersInImage(const vector<Marker>& markers, int image, - Mat *coordinates); + Mat* coordinates); } // namespace libmv diff --git a/intern/libmv/libmv/threading/threading.h b/intern/libmv/libmv/threading/threading.h index f23bf6f172c..da625e02424 100644 --- a/intern/libmv/libmv/threading/threading.h +++ b/intern/libmv/libmv/threading/threading.h @@ -31,7 +31,7 @@ namespace libmv { #if COMPILER_SUPPORTS_CXX11 -using mutex = std::mutex; +using mutex = std::mutex; using scoped_lock = std::unique_lock<std::mutex>; using condition_variable = std::condition_variable; #else diff --git a/intern/libmv/libmv/tracking/brute_region_tracker.cc b/intern/libmv/libmv/tracking/brute_region_tracker.cc index 85aecb7f633..7007fb9440b 100644 --- a/intern/libmv/libmv/tracking/brute_region_tracker.cc +++ b/intern/libmv/libmv/tracking/brute_region_tracker.cc @@ -25,31 +25,30 @@ #endif #include "libmv/base/aligned_malloc.h" -#include "libmv/image/image.h" #include "libmv/image/convolve.h" #include "libmv/image/correlation.h" +#include "libmv/image/image.h" #include "libmv/image/sample.h" #include "libmv/logging/logging.h" namespace libmv { namespace { -bool RegionIsInBounds(const FloatImage &image1, - double x, double y, +bool RegionIsInBounds(const FloatImage& image1, + double x, + double y, int half_window_size) { // Check the minimum coordinates. int min_x = floor(x) - half_window_size - 1; int min_y = floor(y) - half_window_size - 1; - if (min_x < 0.0 || - min_y < 0.0) { + if (min_x < 0.0 || min_y < 0.0) { return false; } // Check the maximum coordinates. int max_x = ceil(x) + half_window_size + 1; int max_y = ceil(y) + half_window_size + 1; - if (max_x > image1.cols() || - max_y > image1.rows()) { + if (max_x > image1.cols() || max_y > image1.rows()) { return false; } @@ -69,14 +68,15 @@ bool RegionIsInBounds(const FloatImage &image1, // and "b", since the SSE load instructionst will pull in memory past the end // of the arrays if their size is not a multiple of 16. inline static __m128i SumOfAbsoluteDifferencesContiguousSSE( - const unsigned char *a, // aligned - const unsigned char *b, // not aligned + const unsigned char* a, // aligned + const unsigned char* b, // not aligned unsigned int size, __m128i sad) { // Do the bulk of the work as 16-way integer operations. for (unsigned int j = 0; j < size / 16; j++) { - sad = _mm_add_epi32(sad, _mm_sad_epu8( _mm_load_si128 ((__m128i*)(a + 16 * j)), - _mm_loadu_si128((__m128i*)(b + 16 * j)))); + sad = _mm_add_epi32(sad, + _mm_sad_epu8(_mm_load_si128((__m128i*)(a + 16 * j)), + _mm_loadu_si128((__m128i*)(b + 16 * j)))); } // Handle the trailing end. // TODO(keir): Benchmark to verify that the below SSE is a win compared to a @@ -90,32 +90,63 @@ inline static __m128i SumOfAbsoluteDifferencesContiguousSSE( unsigned int remainder = size % 16u; if (remainder) { unsigned int j = size / 16; - __m128i a_trail = _mm_load_si128 ((__m128i*)(a + 16 * j)); + __m128i a_trail = _mm_load_si128((__m128i*)(a + 16 * j)); __m128i b_trail = _mm_loadu_si128((__m128i*)(b + 16 * j)); __m128i mask; switch (remainder) { -#define X 0xff - case 1: mask = _mm_setr_epi8(X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 2: mask = _mm_setr_epi8(X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 3: mask = _mm_setr_epi8(X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 4: mask = _mm_setr_epi8(X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 5: mask = _mm_setr_epi8(X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 6: mask = _mm_setr_epi8(X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 7: mask = _mm_setr_epi8(X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 8: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0); break; - case 9: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0); break; - case 10: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0); break; - case 11: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0); break; - case 12: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0); break; - case 13: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0); break; - case 14: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0); break; - case 15: mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0); break; +# define X 0xff + case 1: + mask = _mm_setr_epi8(X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 2: + mask = _mm_setr_epi8(X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 3: + mask = _mm_setr_epi8(X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 4: + mask = _mm_setr_epi8(X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 5: + mask = _mm_setr_epi8(X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 6: + mask = _mm_setr_epi8(X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 7: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 8: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0); + break; + case 9: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0, 0); + break; + case 10: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0, 0); + break; + case 11: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0, 0); + break; + case 12: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0, 0); + break; + case 13: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0, 0); + break; + case 14: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0, 0); + break; + case 15: + mask = _mm_setr_epi8(X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, 0); + break; // To silence compiler warning. default: mask = _mm_setzero_si128(); break; -#undef X +# undef X } - sad = _mm_add_epi32(sad, _mm_sad_epu8(_mm_and_si128(mask, a_trail), - _mm_and_si128(mask, b_trail))); + sad = _mm_add_epi32(sad, + _mm_sad_epu8(_mm_and_si128(mask, a_trail), + _mm_and_si128(mask, b_trail))); } return sad; } @@ -124,13 +155,12 @@ inline static __m128i SumOfAbsoluteDifferencesContiguousSSE( // Computes the sum of absolute differences between pattern and image. Pattern // must be 16-byte aligned, and the stride must be a multiple of 16. The image // does pointer does not have to be aligned. -int SumOfAbsoluteDifferencesContiguousImage( - const unsigned char *pattern, - unsigned int pattern_width, - unsigned int pattern_height, - unsigned int pattern_stride, - const unsigned char *image, - unsigned int image_stride) { +int SumOfAbsoluteDifferencesContiguousImage(const unsigned char* pattern, + unsigned int pattern_width, + unsigned int pattern_height, + unsigned int pattern_stride, + const unsigned char* image, + unsigned int image_stride) { #ifdef __SSE2__ // TODO(keir): Add interleaved accumulation, where accumulation is done into // two or more SSE registers that then get combined at the end. This reduces @@ -145,8 +175,7 @@ int SumOfAbsoluteDifferencesContiguousImage( sad); } return _mm_cvtsi128_si32( - _mm_add_epi32(sad, - _mm_shuffle_epi32(sad, _MM_SHUFFLE(3, 0, 1, 2)))); + _mm_add_epi32(sad, _mm_shuffle_epi32(sad, _MM_SHUFFLE(3, 0, 1, 2)))); #else int sad = 0; for (int r = 0; r < pattern_height; ++r) { @@ -161,12 +190,13 @@ int SumOfAbsoluteDifferencesContiguousImage( // Sample a region of size width, height centered at x,y in image, converting // from float to byte in the process. Samples from the first channel. Puts // result into *pattern. -void SampleRectangularPattern(const FloatImage &image, - double x, double y, +void SampleRectangularPattern(const FloatImage& image, + double x, + double y, int width, int height, int pattern_stride, - unsigned char *pattern) { + unsigned char* pattern) { // There are two cases for width and height: even or odd. If it's odd, then // the bounds [-width / 2, width / 2] works as expected. However, for even, // this results in one extra access past the end. So use < instead of <= in @@ -175,7 +205,7 @@ void SampleRectangularPattern(const FloatImage &image, int end_height = (height / 2) + (height % 2); for (int r = -height / 2; r < end_height; ++r) { for (int c = -width / 2; c < end_width; ++c) { - pattern[pattern_stride * (r + height / 2) + c + width / 2] = + pattern[pattern_stride * (r + height / 2) + c + width / 2] = SampleLinear(image, y + r, x + c, 0) * 255.0; } } @@ -195,30 +225,30 @@ inline int PadToAlignment(int x, int alignment) { // is returned in *pattern_stride. // // NOTE: Caller must free *pattern with aligned_malloc() from above. -void SampleSquarePattern(const FloatImage &image, - double x, double y, +void SampleSquarePattern(const FloatImage& image, + double x, + double y, int half_width, - unsigned char **pattern, - int *pattern_stride) { + unsigned char** pattern, + int* pattern_stride) { int width = 2 * half_width + 1; // Allocate an aligned block with padding on the end so each row of the // pattern starts on a 16-byte boundary. *pattern_stride = PadToAlignment(width, 16); int pattern_size_bytes = *pattern_stride * width; - *pattern = static_cast<unsigned char *>( - aligned_malloc(pattern_size_bytes, 16)); - SampleRectangularPattern(image, x, y, width, width, - *pattern_stride, - *pattern); + *pattern = + static_cast<unsigned char*>(aligned_malloc(pattern_size_bytes, 16)); + SampleRectangularPattern( + image, x, y, width, width, *pattern_stride, *pattern); } // NOTE: Caller must free *image with aligned_malloc() from above. -void FloatArrayToByteArrayWithPadding(const FloatImage &float_image, - unsigned char **image, - int *image_stride) { +void FloatArrayToByteArrayWithPadding(const FloatImage& float_image, + unsigned char** image, + int* image_stride) { // Allocate enough so that accessing 16 elements past the end is fine. *image_stride = float_image.Width() + 16; - *image = static_cast<unsigned char *>( + *image = static_cast<unsigned char*>( aligned_malloc(*image_stride * float_image.Height(), 16)); for (int i = 0; i < float_image.Height(); ++i) { for (int j = 0; j < float_image.Width(); ++j) { @@ -235,10 +265,12 @@ void FloatArrayToByteArrayWithPadding(const FloatImage &float_image, // values for every hypothesis looks like. // // TODO(keir): Priority queue for multiple hypothesis. -bool BruteRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool BruteRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { if (!RegionIsInBounds(image1, x1, y1, half_window_size)) { LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1 << ", hw=" << half_window_size << "."; @@ -252,28 +284,28 @@ bool BruteRegionTracker::Track(const FloatImage &image1, BlurredImageAndDerivativesChannels(image2, 0.9, &image_and_gradient2); // Sample the pattern to get it aligned to an image grid. - unsigned char *pattern; + unsigned char* pattern; int pattern_stride; - SampleSquarePattern(image_and_gradient1, x1, y1, half_window_size, - &pattern, - &pattern_stride); + SampleSquarePattern( + image_and_gradient1, x1, y1, half_window_size, &pattern, &pattern_stride); // Convert the search area directly to bytes without sampling. - unsigned char *search_area; + unsigned char* search_area; int search_area_stride; - FloatArrayToByteArrayWithPadding(image_and_gradient2, &search_area, - &search_area_stride); + FloatArrayToByteArrayWithPadding( + image_and_gradient2, &search_area, &search_area_stride); // Try all possible locations inside the search area. Yes, everywhere. int best_i = -1, best_j = -1, best_sad = INT_MAX; for (int i = 0; i < image2.Height() - pattern_width; ++i) { for (int j = 0; j < image2.Width() - pattern_width; ++j) { - int sad = SumOfAbsoluteDifferencesContiguousImage(pattern, - pattern_width, - pattern_width, - pattern_stride, - search_area + search_area_stride * i + j, - search_area_stride); + int sad = SumOfAbsoluteDifferencesContiguousImage( + pattern, + pattern_width, + pattern_width, + pattern_stride, + search_area + search_area_stride * i + j, + search_area_stride); if (sad < best_sad) { best_i = i; best_j = j; @@ -309,16 +341,23 @@ bool BruteRegionTracker::Track(const FloatImage &image1, } Array3Df image_and_gradient1_sampled, image_and_gradient2_sampled; - SamplePattern(image_and_gradient1, x1, y1, half_window_size, 3, + SamplePattern(image_and_gradient1, + x1, + y1, + half_window_size, + 3, &image_and_gradient1_sampled); - SamplePattern(image_and_gradient2, *x2, *y2, half_window_size, 3, + SamplePattern(image_and_gradient2, + *x2, + *y2, + half_window_size, + 3, &image_and_gradient2_sampled); // Compute the Pearson product-moment correlation coefficient to check // for sanity. double correlation = PearsonProductMomentCorrelation( - image_and_gradient1_sampled, - image_and_gradient2_sampled); + image_and_gradient1_sampled, image_and_gradient2_sampled); LG << "Final correlation: " << correlation; diff --git a/intern/libmv/libmv/tracking/brute_region_tracker.h b/intern/libmv/libmv/tracking/brute_region_tracker.h index a699c42ee92..183dc6df07b 100644 --- a/intern/libmv/libmv/tracking/brute_region_tracker.h +++ b/intern/libmv/libmv/tracking/brute_region_tracker.h @@ -27,17 +27,17 @@ namespace libmv { struct BruteRegionTracker : public RegionTracker { - BruteRegionTracker() - : half_window_size(4), - minimum_correlation(0.78) {} + BruteRegionTracker() : half_window_size(4), minimum_correlation(0.78) {} virtual ~BruteRegionTracker() {} // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; // No point in creating getters or setters. int half_window_size; diff --git a/intern/libmv/libmv/tracking/hybrid_region_tracker.cc b/intern/libmv/libmv/tracking/hybrid_region_tracker.cc index ea3b0f5bfc0..f0392643a6c 100644 --- a/intern/libmv/libmv/tracking/hybrid_region_tracker.cc +++ b/intern/libmv/libmv/tracking/hybrid_region_tracker.cc @@ -20,17 +20,19 @@ #include "libmv/tracking/hybrid_region_tracker.h" -#include "libmv/image/image.h" #include "libmv/image/convolve.h" +#include "libmv/image/image.h" #include "libmv/image/sample.h" #include "libmv/logging/logging.h" namespace libmv { -bool HybridRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool HybridRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { double x2_coarse = *x2; double y2_coarse = *y2; if (!coarse_tracker_->Track(image1, image2, x1, y1, &x2_coarse, &y2_coarse)) { diff --git a/intern/libmv/libmv/tracking/hybrid_region_tracker.h b/intern/libmv/libmv/tracking/hybrid_region_tracker.h index 967d2afd1e5..2730d2dbbf2 100644 --- a/intern/libmv/libmv/tracking/hybrid_region_tracker.h +++ b/intern/libmv/libmv/tracking/hybrid_region_tracker.h @@ -21,8 +21,8 @@ #ifndef LIBMV_REGION_TRACKING_HYBRID_REGION_TRACKER_H_ #define LIBMV_REGION_TRACKING_HYBRID_REGION_TRACKER_H_ -#include "libmv/image/image.h" #include "libmv/base/scoped_ptr.h" +#include "libmv/image/image.h" #include "libmv/tracking/region_tracker.h" namespace libmv { @@ -30,18 +30,19 @@ namespace libmv { // TODO(keir): Documentation! class HybridRegionTracker : public RegionTracker { public: - HybridRegionTracker(RegionTracker *coarse_tracker, - RegionTracker *fine_tracker) - : coarse_tracker_(coarse_tracker), - fine_tracker_(fine_tracker) {} + HybridRegionTracker(RegionTracker* coarse_tracker, + RegionTracker* fine_tracker) + : coarse_tracker_(coarse_tracker), fine_tracker_(fine_tracker) {} virtual ~HybridRegionTracker() {} // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; scoped_ptr<RegionTracker> coarse_tracker_; scoped_ptr<RegionTracker> fine_tracker_; diff --git a/intern/libmv/libmv/tracking/kalman_filter.h b/intern/libmv/libmv/tracking/kalman_filter.h index 9841f0e912c..b1312d0e027 100644 --- a/intern/libmv/libmv/tracking/kalman_filter.h +++ b/intern/libmv/libmv/tracking/kalman_filter.h @@ -19,13 +19,14 @@ // IN THE SOFTWARE. #ifndef LIBMV_TRACKING_KALMAN_FILTER_H_ +#define LIBMV_TRACKING_KALMAN_FILTER_H_ #include "libmv/numeric/numeric.h" namespace mv { // A Kalman filter with order N and observation size K. -template<typename T, int N, int K> +template <typename T, int N, int K> class KalmanFilter { public: struct State { @@ -38,54 +39,47 @@ class KalmanFilter { const T* observation_data, const T* process_covariance_data, const T* default_measurement_covariance_data) - : state_transition_matrix_( - Eigen::Matrix<T, N, N, Eigen::RowMajor>(state_transition_data)), - observation_matrix_( - Eigen::Matrix<T, K, N, Eigen::RowMajor>(observation_data)), - process_covariance_( - Eigen::Matrix<T, N, N, Eigen::RowMajor>(process_covariance_data)), - default_measurement_covariance_( - Eigen::Matrix<T, K, K, Eigen::RowMajor>( - default_measurement_covariance_data)) { - } + : state_transition_matrix_( + Eigen::Matrix<T, N, N, Eigen::RowMajor>(state_transition_data)), + observation_matrix_( + Eigen::Matrix<T, K, N, Eigen::RowMajor>(observation_data)), + process_covariance_( + Eigen::Matrix<T, N, N, Eigen::RowMajor>(process_covariance_data)), + default_measurement_covariance_(Eigen::Matrix<T, K, K, Eigen::RowMajor>( + default_measurement_covariance_data)) {} - KalmanFilter( - const Eigen::Matrix<T, N, N> &state_transition_matrix, - const Eigen::Matrix<T, K, N> &observation_matrix, - const Eigen::Matrix<T, N, N> &process_covariance, - const Eigen::Matrix<T, K, K> &default_measurement_covariance) - : state_transition_matrix_(state_transition_matrix), - observation_matrix_(observation_matrix), - process_covariance_(process_covariance), - default_measurement_covariance_(default_measurement_covariance) { - } + KalmanFilter(const Eigen::Matrix<T, N, N>& state_transition_matrix, + const Eigen::Matrix<T, K, N>& observation_matrix, + const Eigen::Matrix<T, N, N>& process_covariance, + const Eigen::Matrix<T, K, K>& default_measurement_covariance) + : state_transition_matrix_(state_transition_matrix), + observation_matrix_(observation_matrix), + process_covariance_(process_covariance), + default_measurement_covariance_(default_measurement_covariance) {} // Advances the system according to the current state estimate. - void Step(State *state) const { + void Step(State* state) const { state->mean = state_transition_matrix_ * state->mean; - state->covariance = state_transition_matrix_ * - state->covariance * - state_transition_matrix_.transpose() + + state->covariance = state_transition_matrix_ * state->covariance * + state_transition_matrix_.transpose() + process_covariance_; } // Updates a state with a new measurement. - void Update(const Eigen::Matrix<T, K, 1> &measurement_mean, - const Eigen::Matrix<T, K, K> &measurement_covariance, - State *state) const { + void Update(const Eigen::Matrix<T, K, 1>& measurement_mean, + const Eigen::Matrix<T, K, K>& measurement_covariance, + State* state) const { // Calculate the innovation, which is a distribution over prediction error. - Eigen::Matrix<T, K, 1> innovation_mean = measurement_mean - - observation_matrix_ * - state->mean; + Eigen::Matrix<T, K, 1> innovation_mean = + measurement_mean - observation_matrix_ * state->mean; Eigen::Matrix<T, K, K> innovation_covariance = - observation_matrix_ * - state->covariance * - observation_matrix_.transpose() + + observation_matrix_ * state->covariance * + observation_matrix_.transpose() + measurement_covariance; // Calculate the Kalman gain. Eigen::Matrix<T, 6, 2> kalman_gain = state->covariance * - observation_matrix_.transpose() * + observation_matrix_.transpose() * innovation_covariance.inverse(); // Update the state mean and covariance. @@ -95,8 +89,8 @@ class KalmanFilter { state->covariance; } - void Update(State *state, - const Eigen::Matrix<T, K, 1> &measurement_mean) const { + void Update(State* state, + const Eigen::Matrix<T, K, 1>& measurement_mean) const { Update(state, measurement_mean, default_measurement_covariance_); } diff --git a/intern/libmv/libmv/tracking/klt_region_tracker.cc b/intern/libmv/libmv/tracking/klt_region_tracker.cc index dbbf9f0b996..df1ded65489 100644 --- a/intern/libmv/libmv/tracking/klt_region_tracker.cc +++ b/intern/libmv/libmv/tracking/klt_region_tracker.cc @@ -20,10 +20,10 @@ #include "libmv/tracking/klt_region_tracker.h" -#include "libmv/logging/logging.h" -#include "libmv/image/image.h" #include "libmv/image/convolve.h" +#include "libmv/image/image.h" #include "libmv/image/sample.h" +#include "libmv/logging/logging.h" namespace libmv { @@ -33,16 +33,18 @@ namespace libmv { // TODO(keir): The calls to SampleLinear() do boundary checking that should // instead happen outside the loop. Since this is the innermost loop, the extra // bounds checking hurts performance. -static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, - const Array3Df &image_and_gradient2, - double x1, double y1, - double x2, double y2, +static void ComputeTrackingEquation(const Array3Df& image_and_gradient1, + const Array3Df& image_and_gradient2, + double x1, + double y1, + double x2, + double y2, int half_width, - float *gxx, - float *gxy, - float *gyy, - float *ex, - float *ey) { + float* gxx, + float* gxy, + float* gyy, + float* ex, + float* ey) { *gxx = *gxy = *gyy = 0; *ex = *ey = 0; for (int r = -half_width; r <= half_width; ++r) { @@ -51,8 +53,8 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, float yy1 = y1 + r; float xx2 = x2 + c; float yy2 = y2 + r; - float I = SampleLinear(image_and_gradient1, yy1, xx1, 0); - float J = SampleLinear(image_and_gradient2, yy2, xx2, 0); + float I = SampleLinear(image_and_gradient1, yy1, xx1, 0); + float J = SampleLinear(image_and_gradient2, yy2, xx2, 0); float gx = SampleLinear(image_and_gradient2, yy2, xx2, 1); float gy = SampleLinear(image_and_gradient2, yy2, xx2, 2); *gxx += gx * gx; @@ -64,22 +66,21 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, } } -static bool RegionIsInBounds(const FloatImage &image1, - double x, double y, - int half_window_size) { +static bool RegionIsInBounds(const FloatImage& image1, + double x, + double y, + int half_window_size) { // Check the minimum coordinates. int min_x = floor(x) - half_window_size - 1; int min_y = floor(y) - half_window_size - 1; - if (min_x < 0.0 || - min_y < 0.0) { + if (min_x < 0.0 || min_y < 0.0) { return false; } // Check the maximum coordinates. int max_x = ceil(x) + half_window_size + 1; int max_y = ceil(y) + half_window_size + 1; - if (max_x > image1.cols() || - max_y > image1.rows()) { + if (max_x > image1.cols() || max_y > image1.rows()) { return false; } @@ -87,10 +88,12 @@ static bool RegionIsInBounds(const FloatImage &image1, return true; } -bool KltRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool KltRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { if (!RegionIsInBounds(image1, x1, y1, half_window_size)) { LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1 << ", hw=" << half_window_size << "."; @@ -116,10 +119,16 @@ bool KltRegionTracker::Track(const FloatImage &image1, float gxx, gxy, gyy, ex, ey; ComputeTrackingEquation(image_and_gradient1, image_and_gradient2, - x1, y1, - *x2, *y2, + x1, + y1, + *x2, + *y2, half_window_size, - &gxx, &gxy, &gyy, &ex, &ey); + &gxx, + &gxy, + &gyy, + &ex, + &ey); // Solve the tracking equation // diff --git a/intern/libmv/libmv/tracking/klt_region_tracker.h b/intern/libmv/libmv/tracking/klt_region_tracker.h index 43977757084..07ed1b7155c 100644 --- a/intern/libmv/libmv/tracking/klt_region_tracker.h +++ b/intern/libmv/libmv/tracking/klt_region_tracker.h @@ -37,10 +37,12 @@ struct KltRegionTracker : public RegionTracker { virtual ~KltRegionTracker() {} // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; // No point in creating getters or setters. int half_window_size; diff --git a/intern/libmv/libmv/tracking/pyramid_region_tracker.cc b/intern/libmv/libmv/tracking/pyramid_region_tracker.cc index 4db501050f3..52764a535e0 100644 --- a/intern/libmv/libmv/tracking/pyramid_region_tracker.cc +++ b/intern/libmv/libmv/tracking/pyramid_region_tracker.cc @@ -29,8 +29,9 @@ namespace libmv { -static void MakePyramid(const FloatImage &image, int num_levels, - std::vector<FloatImage> *pyramid) { +static void MakePyramid(const FloatImage& image, + int num_levels, + std::vector<FloatImage>* pyramid) { pyramid->resize(num_levels); (*pyramid)[0] = image; for (int i = 1; i < num_levels; ++i) { @@ -38,10 +39,12 @@ static void MakePyramid(const FloatImage &image, int num_levels, } } -bool PyramidRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool PyramidRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { // Shrink the guessed x and y location to match the coarsest level + 1 (which // when gets corrected in the loop). *x2 /= pow(2., num_levels_); @@ -71,8 +74,8 @@ bool PyramidRegionTracker::Track(const FloatImage &image1, // Track the point on this level with the base tracker. LG << "Tracking on level " << i; - bool succeeded = tracker_->Track(pyramid1[i], pyramid2[i], xx, yy, - &x2_new, &y2_new); + bool succeeded = + tracker_->Track(pyramid1[i], pyramid2[i], xx, yy, &x2_new, &y2_new); if (!succeeded) { if (i == 0) { diff --git a/intern/libmv/libmv/tracking/pyramid_region_tracker.h b/intern/libmv/libmv/tracking/pyramid_region_tracker.h index 1f9675469f4..5fe21c95904 100644 --- a/intern/libmv/libmv/tracking/pyramid_region_tracker.h +++ b/intern/libmv/libmv/tracking/pyramid_region_tracker.h @@ -21,21 +21,24 @@ #ifndef LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_ #define LIBMV_CORRESPONDENCE_PYRAMID_TRACKER_H_ -#include "libmv/image/image.h" #include "libmv/base/scoped_ptr.h" +#include "libmv/image/image.h" #include "libmv/tracking/region_tracker.h" namespace libmv { class PyramidRegionTracker : public RegionTracker { public: - PyramidRegionTracker(RegionTracker *tracker, int num_levels) + PyramidRegionTracker(RegionTracker* tracker, int num_levels) : tracker_(tracker), num_levels_(num_levels) {} - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; + private: scoped_ptr<RegionTracker> tracker_; int num_levels_; diff --git a/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc b/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc index d90a1012237..2fcf292e404 100644 --- a/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc +++ b/intern/libmv/libmv/tracking/pyramid_region_tracker_test.cc @@ -19,8 +19,8 @@ // IN THE SOFTWARE. #include "libmv/tracking/pyramid_region_tracker.h" -#include "libmv/tracking/klt_region_tracker.h" #include "libmv/image/image.h" +#include "libmv/tracking/klt_region_tracker.h" #include "testing/testing.h" namespace libmv { @@ -55,8 +55,7 @@ TEST(PyramidKltRegionTracker, Track) { KltRegionTracker tracker; tracker.half_window_size = half_window_size; - EXPECT_FALSE(tracker.Track(image1, image2, x1, y1, - &x2_actual, &y2_actual)); + EXPECT_FALSE(tracker.Track(image1, image2, x1, y1, &x2_actual, &y2_actual)); } // Verify that it works with the pyramid tracker. @@ -64,12 +63,11 @@ TEST(PyramidKltRegionTracker, Track) { double x2_actual = x1; double y2_actual = y1; - KltRegionTracker *klt_tracker = new KltRegionTracker; + KltRegionTracker* klt_tracker = new KltRegionTracker; klt_tracker->half_window_size = half_window_size; PyramidRegionTracker tracker(klt_tracker, 3); - EXPECT_TRUE(tracker.Track(image1, image2, x1, y1, - &x2_actual, &y2_actual)); + EXPECT_TRUE(tracker.Track(image1, image2, x1, y1, &x2_actual, &y2_actual)); EXPECT_NEAR(x2_actual, x2, 0.001); EXPECT_NEAR(y2_actual, y2, 0.001); diff --git a/intern/libmv/libmv/tracking/region_tracker.h b/intern/libmv/libmv/tracking/region_tracker.h index 4f7574df1a3..e753ac8be6c 100644 --- a/intern/libmv/libmv/tracking/region_tracker.h +++ b/intern/libmv/libmv/tracking/region_tracker.h @@ -37,10 +37,12 @@ class RegionTracker { image2. If no guess is available, (\a x1, \a y1) is a good start. Returns true on success, false otherwise */ - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const = 0; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const = 0; }; } // namespace libmv diff --git a/intern/libmv/libmv/tracking/retrack_region_tracker.cc b/intern/libmv/libmv/tracking/retrack_region_tracker.cc index 4d230086d28..9152078053c 100644 --- a/intern/libmv/libmv/tracking/retrack_region_tracker.cc +++ b/intern/libmv/libmv/tracking/retrack_region_tracker.cc @@ -25,10 +25,12 @@ namespace libmv { -bool RetrackRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool RetrackRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { // Track forward, getting x2 and y2. if (!tracker_->Track(image1, image2, x1, y1, x2, y2)) { return false; diff --git a/intern/libmv/libmv/tracking/retrack_region_tracker.h b/intern/libmv/libmv/tracking/retrack_region_tracker.h index ab05f320834..504cf697349 100644 --- a/intern/libmv/libmv/tracking/retrack_region_tracker.h +++ b/intern/libmv/libmv/tracking/retrack_region_tracker.h @@ -21,8 +21,8 @@ #ifndef LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_ #define LIBMV_TRACKING_RETRACK_REGION_TRACKER_H_ -#include "libmv/image/image.h" #include "libmv/base/scoped_ptr.h" +#include "libmv/image/image.h" #include "libmv/tracking/region_tracker.h" namespace libmv { @@ -31,13 +31,16 @@ namespace libmv { // track that doesn't track backwards to the starting point. class RetrackRegionTracker : public RegionTracker { public: - RetrackRegionTracker(RegionTracker *tracker, double tolerance) + RetrackRegionTracker(RegionTracker* tracker, double tolerance) : tracker_(tracker), tolerance_(tolerance) {} - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; + private: scoped_ptr<RegionTracker> tracker_; double tolerance_; diff --git a/intern/libmv/libmv/tracking/track_region.cc b/intern/libmv/libmv/tracking/track_region.cc index 895c9a1e23d..403b4088174 100644 --- a/intern/libmv/libmv/tracking/track_region.cc +++ b/intern/libmv/libmv/tracking/track_region.cc @@ -27,14 +27,14 @@ #include "libmv/tracking/track_region.h" -#include <Eigen/SVD> #include <Eigen/QR> +#include <Eigen/SVD> #include <iostream> #include "ceres/ceres.h" -#include "libmv/logging/logging.h" +#include "libmv/image/convolve.h" #include "libmv/image/image.h" #include "libmv/image/sample.h" -#include "libmv/image/convolve.h" +#include "libmv/logging/logging.h" #include "libmv/multiview/homography.h" #include "libmv/numeric/numeric.h" @@ -44,57 +44,45 @@ namespace ceres { // A jet traits class to make it easier to work with mixed auto / numeric diff. -template<typename T> +template <typename T> struct JetOps { - static bool IsScalar() { - return true; - } - static T GetScalar(const T& t) { - return t; - } - static void SetScalar(const T& scalar, T* t) { - *t = scalar; - } - static void ScaleDerivative(double scale_by, T *value) { + static bool IsScalar() { return true; } + static T GetScalar(const T& t) { return t; } + static void SetScalar(const T& scalar, T* t) { *t = scalar; } + static void ScaleDerivative(double scale_by, T* value) { // For double, there is no derivative to scale. - (void) scale_by; // Ignored. - (void) value; // Ignored. + (void)scale_by; // Ignored. + (void)value; // Ignored. } }; -template<typename T, int N> -struct JetOps<Jet<T, N> > { - static bool IsScalar() { - return false; - } - static T GetScalar(const Jet<T, N>& t) { - return t.a; - } - static void SetScalar(const T& scalar, Jet<T, N>* t) { - t->a = scalar; - } - static void ScaleDerivative(double scale_by, Jet<T, N> *value) { +template <typename T, int N> +struct JetOps<Jet<T, N>> { + static bool IsScalar() { return false; } + static T GetScalar(const Jet<T, N>& t) { return t.a; } + static void SetScalar(const T& scalar, Jet<T, N>* t) { t->a = scalar; } + static void ScaleDerivative(double scale_by, Jet<T, N>* value) { value->v *= scale_by; } }; -template<typename FunctionType, int kNumArgs, typename ArgumentType> +template <typename FunctionType, int kNumArgs, typename ArgumentType> struct Chain { - static ArgumentType Rule(const FunctionType &f, + static ArgumentType Rule(const FunctionType& f, const FunctionType dfdx[kNumArgs], const ArgumentType x[kNumArgs]) { // In the default case of scalars, there's nothing to do since there are no // derivatives to propagate. - (void) dfdx; // Ignored. - (void) x; // Ignored. + (void)dfdx; // Ignored. + (void)x; // Ignored. return f; } }; // XXX Add documentation here! -template<typename FunctionType, int kNumArgs, typename T, int N> -struct Chain<FunctionType, kNumArgs, Jet<T, N> > { - static Jet<T, N> Rule(const FunctionType &f, +template <typename FunctionType, int kNumArgs, typename T, int N> +struct Chain<FunctionType, kNumArgs, Jet<T, N>> { + static Jet<T, N> Rule(const FunctionType& f, const FunctionType dfdx[kNumArgs], const Jet<T, N> x[kNumArgs]) { // x is itself a function of another variable ("z"); what this function @@ -107,8 +95,8 @@ struct Chain<FunctionType, kNumArgs, Jet<T, N> > { } // Map the input gradient dfdx into an Eigen row vector. - Eigen::Map<const Eigen::Matrix<FunctionType, 1, kNumArgs> > - vector_dfdx(dfdx, 1, kNumArgs); + Eigen::Map<const Eigen::Matrix<FunctionType, 1, kNumArgs>> vector_dfdx( + dfdx, 1, kNumArgs); // Now apply the chain rule to obtain df/dz. Combine the derivative with // the scalar part to obtain f with full derivative information. @@ -123,9 +111,9 @@ struct Chain<FunctionType, kNumArgs, Jet<T, N> > { namespace libmv { +using ceres::Chain; using ceres::Jet; using ceres::JetOps; -using ceres::Chain; TrackRegionOptions::TrackRegionOptions() : mode(TRANSLATION), @@ -144,17 +132,12 @@ TrackRegionOptions::TrackRegionOptions() namespace { // TODO(keir): Consider adding padding. -template<typename T> -bool InBounds(const FloatImage &image, - const T &x, - const T &y) { - return 0.0 <= x && x < image.Width() && - 0.0 <= y && y < image.Height(); +template <typename T> +bool InBounds(const FloatImage& image, const T& x, const T& y) { + return 0.0 <= x && x < image.Width() && 0.0 <= y && y < image.Height(); } -bool AllInBounds(const FloatImage &image, - const double *x, - const double *y) { +bool AllInBounds(const FloatImage& image, const double* x, const double* y) { for (int i = 0; i < 4; ++i) { if (!InBounds(image, x[i], y[i])) { return false; @@ -166,10 +149,10 @@ bool AllInBounds(const FloatImage &image, // Sample the image at position (x, y) but use the gradient, if present, to // propagate derivatives from x and y. This is needed to integrate the numeric // image gradients with Ceres's autodiff framework. -template<typename T> -static T SampleWithDerivative(const FloatImage &image_and_gradient, - const T &x, - const T &y) { +template <typename T> +static T SampleWithDerivative(const FloatImage& image_and_gradient, + const T& x, + const T& y) { float scalar_x = JetOps<T>::GetScalar(x); float scalar_y = JetOps<T>::GetScalar(y); @@ -184,18 +167,23 @@ static T SampleWithDerivative(const FloatImage &image_and_gradient, // For the derivative case, sample the gradient as well. SampleLinear(image_and_gradient, scalar_y, scalar_x, sample); } - T xy[2] = { x, y }; + T xy[2] = {x, y}; return Chain<float, 2, T>::Rule(sample[0], sample + 1, xy); } -template<typename Warp> +template <typename Warp> class TerminationCheckingCallback : public ceres::IterationCallback { public: - TerminationCheckingCallback(const TrackRegionOptions &options, + TerminationCheckingCallback(const TrackRegionOptions& options, const FloatImage& image2, - const Warp &warp, - const double *x1, const double *y1) - : options_(options), image2_(image2), warp_(warp), x1_(x1), y1_(y1), + const Warp& warp, + const double* x1, + const double* y1) + : options_(options), + image2_(image2), + warp_(warp), + x1_(x1), + y1_(y1), have_last_successful_step_(false) {} virtual ceres::CallbackReturnType operator()( @@ -229,7 +217,7 @@ class TerminationCheckingCallback : public ceres::IterationCallback { for (int i = 0; i < 4; ++i) { double dx = x2[i] - x2_last_successful_[i]; double dy = y2[i] - y2_last_successful_[i]; - double change_pixels = dx*dx + dy*dy; + double change_pixels = dx * dx + dy * dy; if (change_pixels > max_change_pixels) { max_change_pixels = change_pixels; } @@ -255,27 +243,27 @@ class TerminationCheckingCallback : public ceres::IterationCallback { } private: - const TrackRegionOptions &options_; - const FloatImage &image2_; - const Warp &warp_; - const double *x1_; - const double *y1_; + const TrackRegionOptions& options_; + const FloatImage& image2_; + const Warp& warp_; + const double* x1_; + const double* y1_; bool have_last_successful_step_; double x2_last_successful_[4]; double y2_last_successful_[4]; }; -template<typename Warp> +template <typename Warp> class PixelDifferenceCostFunctor { public: - PixelDifferenceCostFunctor(const TrackRegionOptions &options, - const FloatImage &image_and_gradient1, - const FloatImage &image_and_gradient2, - const Mat3 &canonical_to_image1, + PixelDifferenceCostFunctor(const TrackRegionOptions& options, + const FloatImage& image_and_gradient1, + const FloatImage& image_and_gradient2, + const Mat3& canonical_to_image1, int num_samples_x, int num_samples_y, - const Warp &warp) + const Warp& warp) : options_(options), image_and_gradient1_(image_and_gradient1), image_and_gradient2_(image_and_gradient2), @@ -322,8 +310,8 @@ class PixelDifferenceCostFunctor { src_mean_ /= num_samples; } - template<typename T> - bool operator()(const T *warp_parameters, T *residuals) const { + template <typename T> + bool operator()(const T* warp_parameters, T* residuals) const { if (options_.image1_mask != NULL) { VLOG(2) << "Using a mask."; } @@ -333,8 +321,7 @@ class PixelDifferenceCostFunctor { T dst_mean = T(1.0); if (options_.use_normalized_intensities) { - ComputeNormalizingCoefficient(warp_parameters, - &dst_mean); + ComputeNormalizingCoefficient(warp_parameters, &dst_mean); } int cursor = 0; @@ -374,9 +361,8 @@ class PixelDifferenceCostFunctor { &image2_position[1]); // Sample the destination, propagating derivatives. - T dst_sample = SampleWithDerivative(image_and_gradient2_, - image2_position[0], - image2_position[1]); + T dst_sample = SampleWithDerivative( + image_and_gradient2_, image2_position[0], image2_position[1]); // Sample the source. This is made complicated by ESM mode. T src_sample; @@ -386,8 +372,8 @@ class PixelDifferenceCostFunctor { // better convergence. Copy the derivative of the warp parameters // onto the jets for the image1 position. This is the ESM hack. T image1_position_jet[2] = { - image2_position[0], // Order is x, y. This matches the - image2_position[1] // derivative order in the patch. + image2_position[0], // Order is x, y. This matches the + image2_position[1] // derivative order in the patch. }; JetOps<T>::SetScalar(image1_position[0], image1_position_jet + 0); JetOps<T>::SetScalar(image1_position[1], image1_position_jet + 1); @@ -433,9 +419,9 @@ class PixelDifferenceCostFunctor { } // For normalized matching, the average and - template<typename T> - void ComputeNormalizingCoefficient(const T *warp_parameters, - T *dst_mean) const { + template <typename T> + void ComputeNormalizingCoefficient(const T* warp_parameters, + T* dst_mean) const { *dst_mean = T(0.0); double num_samples = 0.0; for (int r = 0; r < num_samples_y_; ++r) { @@ -462,14 +448,12 @@ class PixelDifferenceCostFunctor { &image2_position[0], &image2_position[1]); - // Sample the destination, propagating derivatives. // TODO(keir): This accumulation can, surprisingly, be done as a // pre-pass by using integral images. This is complicated by the need // to store the jets in the integral image, but it is possible. - T dst_sample = SampleWithDerivative(image_and_gradient2_, - image2_position[0], - image2_position[1]); + T dst_sample = SampleWithDerivative( + image_and_gradient2_, image2_position[0], image2_position[1]); // Weight the sample by the mask, if one is present. if (options_.image1_mask != NULL) { @@ -486,10 +470,10 @@ class PixelDifferenceCostFunctor { // TODO(keir): Consider also computing the cost here. double PearsonProductMomentCorrelationCoefficient( - const double *warp_parameters) const { + const double* warp_parameters) const { for (int i = 0; i < Warp::NUM_PARAMETERS; ++i) { - VLOG(2) << "Correlation warp_parameters[" << i << "]: " - << warp_parameters[i]; + VLOG(2) << "Correlation warp_parameters[" << i + << "]: " << warp_parameters[i]; } // The single-pass PMCC computation is somewhat numerically unstable, but @@ -537,9 +521,9 @@ class PixelDifferenceCostFunctor { } sX += x; sY += y; - sXX += x*x; - sYY += y*y; - sXY += x*y; + sXX += x * x; + sYY += y * y; + sXY += x * y; } } // Normalize. @@ -549,25 +533,24 @@ class PixelDifferenceCostFunctor { sYY /= num_samples; sXY /= num_samples; - double var_x = sXX - sX*sX; - double var_y = sYY - sY*sY; - double covariance_xy = sXY - sX*sY; + double var_x = sXX - sX * sX; + double var_y = sYY - sY * sY; + double covariance_xy = sXY - sX * sY; double correlation = covariance_xy / sqrt(var_x * var_y); - LG << "Covariance xy: " << covariance_xy - << ", var 1: " << var_x << ", var 2: " << var_y - << ", correlation: " << correlation; + LG << "Covariance xy: " << covariance_xy << ", var 1: " << var_x + << ", var 2: " << var_y << ", correlation: " << correlation; return correlation; } private: - const TrackRegionOptions &options_; - const FloatImage &image_and_gradient1_; - const FloatImage &image_and_gradient2_; - const Mat3 &canonical_to_image1_; + const TrackRegionOptions& options_; + const FloatImage& image_and_gradient1_; + const FloatImage& image_and_gradient2_; + const Mat3& canonical_to_image1_; int num_samples_x_; int num_samples_y_; - const Warp &warp_; + const Warp& warp_; double src_mean_; FloatImage pattern_and_gradient_; @@ -579,15 +562,15 @@ class PixelDifferenceCostFunctor { FloatImage pattern_mask_; }; -template<typename Warp> +template <typename Warp> class WarpRegularizingCostFunctor { public: - WarpRegularizingCostFunctor(const TrackRegionOptions &options, - const double *x1, - const double *y1, - const double *x2_original, - const double *y2_original, - const Warp &warp) + WarpRegularizingCostFunctor(const TrackRegionOptions& options, + const double* x1, + const double* y1, + const double* x2_original, + const double* y2_original, + const Warp& warp) : options_(options), x1_(x1), y1_(y1), @@ -606,11 +589,11 @@ class WarpRegularizingCostFunctor { original_centroid_[1] /= 4; } - template<typename T> - bool operator()(const T *warp_parameters, T *residuals) const { - T dst_centroid[2] = { T(0.0), T(0.0) }; + template <typename T> + bool operator()(const T* warp_parameters, T* residuals) const { + T dst_centroid[2] = {T(0.0), T(0.0)}; for (int i = 0; i < 4; ++i) { - T image1_position[2] = { T(x1_[i]), T(y1_[i]) }; + T image1_position[2] = {T(x1_[i]), T(y1_[i])}; T image2_position[2]; warp_.Forward(warp_parameters, T(x1_[i]), @@ -643,28 +626,30 @@ class WarpRegularizingCostFunctor { return true; } - const TrackRegionOptions &options_; - const double *x1_; - const double *y1_; - const double *x2_original_; - const double *y2_original_; + const TrackRegionOptions& options_; + const double* x1_; + const double* y1_; + const double* x2_original_; + const double* y2_original_; double original_centroid_[2]; - const Warp &warp_; + const Warp& warp_; }; // Compute the warp from rectangular coordinates, where one corner is the // origin, and the opposite corner is at (num_samples_x, num_samples_y). -Mat3 ComputeCanonicalHomography(const double *x1, - const double *y1, +Mat3 ComputeCanonicalHomography(const double* x1, + const double* y1, int num_samples_x, int num_samples_y) { Mat canonical(2, 4); - canonical << 0, num_samples_x, num_samples_x, 0, - 0, 0, num_samples_y, num_samples_y; + canonical << 0, num_samples_x, num_samples_x, 0, 0, 0, num_samples_y, + num_samples_y; Mat xy1(2, 4); + // clang-format off xy1 << x1[0], x1[1], x1[2], x1[3], y1[0], y1[1], y1[2], y1[3]; + // clang-format om Mat3 H; if (!Homography2DFromCorrespondencesLinear(canonical, xy1, &H, 1e-12)) { @@ -675,7 +660,7 @@ Mat3 ComputeCanonicalHomography(const double *x1, class Quad { public: - Quad(const double *x, const double *y) : x_(x), y_(y) { + Quad(const double* x, const double* y) : x_(x), y_(y) { // Compute the centroid and store it. centroid_ = Vec2(0.0, 0.0); for (int i = 0; i < 4; ++i) { @@ -685,9 +670,7 @@ class Quad { } // The centroid of the four points representing the quad. - const Vec2& Centroid() const { - return centroid_; - } + const Vec2& Centroid() const { return centroid_; } // The average magnitude of the four points relative to the centroid. double Scale() const { @@ -703,22 +686,24 @@ class Quad { } private: - const double *x_; - const double *y_; + const double* x_; + const double* y_; Vec2 centroid_; }; struct TranslationWarp { - TranslationWarp(const double *x1, const double *y1, - const double *x2, const double *y2) { + TranslationWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) { Vec2 t = Quad(x2, y2).Centroid() - Quad(x1, y1).Centroid(); parameters[0] = t[0]; parameters[1] = t[1]; } - template<typename T> - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { + template <typename T> + void Forward( + const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const { *x2 = x1 + warp_parameters[0]; *y2 = y1 + warp_parameters[1]; } @@ -729,8 +714,10 @@ struct TranslationWarp { }; struct TranslationScaleWarp { - TranslationScaleWarp(const double *x1, const double *y1, - const double *x2, const double *y2) + TranslationScaleWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) : q1(x1, y1) { Quad q2(x2, y2); @@ -746,9 +733,9 @@ struct TranslationScaleWarp { // The strange way of parameterizing the translation and scaling is to make // the knobs that the optimizer sees easy to adjust. This is less important // for the scaling case than the rotation case. - template<typename T> - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { + template <typename T> + void Forward( + const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const { // Make the centroid of Q1 the origin. const T x1_origin = x1 - q1.Centroid()(0); const T y1_origin = y1 - q1.Centroid()(1); @@ -775,15 +762,17 @@ struct TranslationScaleWarp { }; // Assumes the given points are already zero-centroid and the same size. -Mat2 OrthogonalProcrustes(const Mat2 &correlation_matrix) { +Mat2 OrthogonalProcrustes(const Mat2& correlation_matrix) { Eigen::JacobiSVD<Mat2> svd(correlation_matrix, Eigen::ComputeFullU | Eigen::ComputeFullV); return svd.matrixV() * svd.matrixU().transpose(); } struct TranslationRotationWarp { - TranslationRotationWarp(const double *x1, const double *y1, - const double *x2, const double *y2) + TranslationRotationWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) : q1(x1, y1) { Quad q2(x2, y2); @@ -816,9 +805,9 @@ struct TranslationRotationWarp { // // Instead, use the parameterization below that offers a parameterization // that exposes the degrees of freedom in a way amenable to optimization. - template<typename T> - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { + template <typename T> + void Forward( + const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const { // Make the centroid of Q1 the origin. const T x1_origin = x1 - q1.Centroid()(0); const T y1_origin = y1 - q1.Centroid()(1); @@ -847,8 +836,10 @@ struct TranslationRotationWarp { }; struct TranslationRotationScaleWarp { - TranslationRotationScaleWarp(const double *x1, const double *y1, - const double *x2, const double *y2) + TranslationRotationScaleWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) : q1(x1, y1) { Quad q2(x2, y2); @@ -884,9 +875,9 @@ struct TranslationRotationScaleWarp { // // Instead, use the parameterization below that offers a parameterization // that exposes the degrees of freedom in a way amenable to optimization. - template<typename T> - void Forward(const T *warp_parameters, - const T &x1, const T& y1, T *x2, T* y2) const { + template <typename T> + void Forward( + const T* warp_parameters, const T& x1, const T& y1, T* x2, T* y2) const { // Make the centroid of Q1 the origin. const T x1_origin = x1 - q1.Centroid()(0); const T y1_origin = y1 - q1.Centroid()(1); @@ -921,8 +912,10 @@ struct TranslationRotationScaleWarp { }; struct AffineWarp { - AffineWarp(const double *x1, const double *y1, - const double *x2, const double *y2) + AffineWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) : q1(x1, y1) { Quad q2(x2, y2); @@ -938,8 +931,8 @@ struct AffineWarp { Vec2 v1 = q1.CornerRelativeToCentroid(i); Vec2 v2 = q2.CornerRelativeToCentroid(i); - Q1.row(2 * i + 0) << v1[0], v1[1], 0, 0; - Q1.row(2 * i + 1) << 0, 0, v1[0], v1[1]; + Q1.row(2 * i + 0) << v1[0], v1[1], 0, 0; + Q1.row(2 * i + 1) << 0, 0, v1[0], v1[1]; Q2(2 * i + 0) = v2[0]; Q2(2 * i + 1) = v2[1]; @@ -957,8 +950,8 @@ struct AffineWarp { } // See comments in other parameterizations about why the centroid is used. - template<typename T> - void Forward(const T *p, const T &x1, const T& y1, T *x2, T* y2) const { + template <typename T> + void Forward(const T* p, const T& x1, const T& y1, T* x2, T* y2) const { // Make the centroid of Q1 the origin. const T x1_origin = x1 - q1.Centroid()(0); const T y1_origin = y1 - q1.Centroid()(1); @@ -985,15 +978,21 @@ struct AffineWarp { }; struct HomographyWarp { - HomographyWarp(const double *x1, const double *y1, - const double *x2, const double *y2) { + HomographyWarp(const double* x1, + const double* y1, + const double* x2, + const double* y2) { Mat quad1(2, 4); + // clang-format off quad1 << x1[0], x1[1], x1[2], x1[3], y1[0], y1[1], y1[2], y1[3]; + // clang-format on Mat quad2(2, 4); + // clang-format off quad2 << x2[0], x2[1], x2[2], x2[3], y2[0], y2[1], y2[2], y2[3]; + // clang-format on Mat3 H; if (!Homography2DFromCorrespondencesLinear(quad1, quad2, &H, 1e-12)) { @@ -1014,13 +1013,12 @@ struct HomographyWarp { } } - template<typename T> - static void Forward(const T *p, - const T &x1, const T& y1, T *x2, T* y2) { + template <typename T> + static void Forward(const T* p, const T& x1, const T& y1, T* x2, T* y2) { // Homography warp with manual 3x3 matrix multiply. - const T xx2 = (1.0 + p[0]) * x1 + p[1] * y1 + p[2]; - const T yy2 = p[3] * x1 + (1.0 + p[4]) * y1 + p[5]; - const T zz2 = p[6] * x1 + p[7] * y1 + 1.0; + const T xx2 = (1.0 + p[0]) * x1 + p[1] * y1 + p[2]; + const T yy2 = p[3] * x1 + (1.0 + p[4]) * y1 + p[5]; + const T zz2 = p[6] * x1 + p[7] * y1 + 1.0; *x2 = xx2 / zz2; *y2 = yy2 / zz2; } @@ -1036,11 +1034,14 @@ struct HomographyWarp { // // The idea is to take the maximum x or y distance. This may be oversampling. // TODO(keir): Investigate the various choices; perhaps average is better? -void PickSampling(const double *x1, const double *y1, - const double *x2, const double *y2, - int *num_samples_x, int *num_samples_y) { - (void) x2; // Ignored. - (void) y2; // Ignored. +void PickSampling(const double* x1, + const double* y1, + const double* x2, + const double* y2, + int* num_samples_x, + int* num_samples_y) { + (void)x2; // Ignored. + (void)y2; // Ignored. Vec2 a0(x1[0], y1[0]); Vec2 a1(x1[1], y1[1]); @@ -1053,18 +1054,10 @@ void PickSampling(const double *x1, const double *y1, Vec2 b3(x1[3], y1[3]); double x_dimensions[4] = { - (a1 - a0).norm(), - (a3 - a2).norm(), - (b1 - b0).norm(), - (b3 - b2).norm() - }; + (a1 - a0).norm(), (a3 - a2).norm(), (b1 - b0).norm(), (b3 - b2).norm()}; double y_dimensions[4] = { - (a3 - a0).norm(), - (a1 - a2).norm(), - (b3 - b0).norm(), - (b1 - b2).norm() - }; + (a3 - a0).norm(), (a1 - a2).norm(), (b3 - b0).norm(), (b1 - b2).norm()}; const double kScaleFactor = 1.0; *num_samples_x = static_cast<int>( kScaleFactor * *std::max_element(x_dimensions, x_dimensions + 4)); @@ -1074,17 +1067,18 @@ void PickSampling(const double *x1, const double *y1, << ", num_samples_y: " << *num_samples_y; } -bool SearchAreaTooBigForDescent(const FloatImage &image2, - const double *x2, const double *y2) { +bool SearchAreaTooBigForDescent(const FloatImage& image2, + const double* x2, + const double* y2) { // TODO(keir): Check the bounds and enable only when it makes sense. - (void) image2; // Ignored. - (void) x2; // Ignored. - (void) y2; // Ignored. + (void)image2; // Ignored. + (void)x2; // Ignored. + (void)y2; // Ignored. return true; } -bool PointOnRightHalfPlane(const Vec2 &a, const Vec2 &b, double x, double y) { +bool PointOnRightHalfPlane(const Vec2& a, const Vec2& b, double x, double y) { Vec2 ba = b - a; return ((Vec2(x, y) - b).transpose() * Vec2(-ba.y(), ba.x())) > 0; } @@ -1102,7 +1096,7 @@ bool PointOnRightHalfPlane(const Vec2 &a, const Vec2 &b, double x, double y) { // y // // The implementation does up to four half-plane comparisons. -bool PointInQuad(const double *xs, const double *ys, double x, double y) { +bool PointInQuad(const double* xs, const double* ys, double x, double y) { Vec2 a0(xs[0], ys[0]); Vec2 a1(xs[1], ys[1]); Vec2 a2(xs[2], ys[2]); @@ -1116,24 +1110,27 @@ bool PointInQuad(const double *xs, const double *ys, double x, double y) { // This makes it possible to map between Eigen float arrays and FloatImage // without using comparisons. -typedef Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> FloatArray; +typedef Eigen::Array<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> + FloatArray; // This creates a pattern in the frame of image2, from the pixel is image1, // based on the initial guess represented by the two quads x1, y1, and x2, y2. -template<typename Warp> -void CreateBrutePattern(const double *x1, const double *y1, - const double *x2, const double *y2, - const FloatImage &image1, - const FloatImage *image1_mask, - FloatArray *pattern, - FloatArray *mask, - int *origin_x, - int *origin_y) { +template <typename Warp> +void CreateBrutePattern(const double* x1, + const double* y1, + const double* x2, + const double* y2, + const FloatImage& image1, + const FloatImage* image1_mask, + FloatArray* pattern, + FloatArray* mask, + int* origin_x, + int* origin_y) { // Get integer bounding box of quad2 in image2. int min_x = static_cast<int>(floor(*std::min_element(x2, x2 + 4))); int min_y = static_cast<int>(floor(*std::min_element(y2, y2 + 4))); - int max_x = static_cast<int>(ceil (*std::max_element(x2, x2 + 4))); - int max_y = static_cast<int>(ceil (*std::max_element(y2, y2 + 4))); + int max_x = static_cast<int>(ceil(*std::max_element(x2, x2 + 4))); + int max_y = static_cast<int>(ceil(*std::max_element(y2, y2 + 4))); int w = max_x - min_x; int h = max_y - min_y; @@ -1154,9 +1151,8 @@ void CreateBrutePattern(const double *x1, const double *y1, double dst_y = r; double src_x; double src_y; - inverse_warp.Forward(inverse_warp.parameters, - dst_x, dst_y, - &src_x, &src_y); + inverse_warp.Forward( + inverse_warp.parameters, dst_x, dst_y, &src_x, &src_y); if (PointInQuad(x1, y1, src_x, src_y)) { (*pattern)(i, j) = SampleLinear(image1, src_y, src_x); @@ -1191,24 +1187,32 @@ void CreateBrutePattern(const double *x1, const double *y1, // pattern, when doing brute initialization. Unfortunately that implies a // totally different warping interface, since access to more than a the source // and current destination frame is necessary. -template<typename Warp> -bool BruteTranslationOnlyInitialize(const FloatImage &image1, - const FloatImage *image1_mask, - const FloatImage &image2, +template <typename Warp> +bool BruteTranslationOnlyInitialize(const FloatImage& image1, + const FloatImage* image1_mask, + const FloatImage& image2, const int num_extra_points, const bool use_normalized_intensities, - const double *x1, const double *y1, - double *x2, double *y2) { + const double* x1, + const double* y1, + double* x2, + double* y2) { // Create the pattern to match in the space of image2, assuming our inital // guess isn't too far from the template in image1. If there is no image1 // mask, then the resulting mask is binary. FloatArray pattern; FloatArray mask; int origin_x = -1, origin_y = -1; - CreateBrutePattern<Warp>(x1, y1, x2, y2, - image1, image1_mask, - &pattern, &mask, - &origin_x, &origin_y); + CreateBrutePattern<Warp>(x1, + y1, + x2, + y2, + image1, + image1_mask, + &pattern, + &mask, + &origin_x, + &origin_y); // For normalization, premultiply the pattern by the inverse pattern mean. double mask_sum = 1.0; @@ -1251,8 +1255,10 @@ bool BruteTranslationOnlyInitialize(const FloatImage &image1, // instead, reducing the mean calculation to an O(1) operation. double inverse_search_mean = mask_sum / ((mask * search.block(r, c, h, w)).sum()); - sad = (mask * (pattern - (search.block(r, c, h, w) * - inverse_search_mean))).abs().sum(); + sad = (mask * + (pattern - (search.block(r, c, h, w) * inverse_search_mean))) + .abs() + .sum(); } else { sad = (mask * (pattern - search.block(r, c, h, w))).abs().sum(); } @@ -1274,9 +1280,8 @@ bool BruteTranslationOnlyInitialize(const FloatImage &image1, << "best_c: " << best_c << ", best_r: " << best_r << ", " << "origin_x: " << origin_x << ", origin_y: " << origin_y << ", " << "dc: " << (best_c - origin_x) << ", " - << "dr: " << (best_r - origin_y) - << ", tried " << ((image2.Height() - h) * (image2.Width() - w)) - << " shifts."; + << "dr: " << (best_r - origin_y) << ", tried " + << ((image2.Height() - h) * (image2.Width() - w)) << " shifts."; // Apply the shift. for (int i = 0; i < 4 + num_extra_points; ++i) { @@ -1286,8 +1291,10 @@ bool BruteTranslationOnlyInitialize(const FloatImage &image1, return true; } -void CopyQuad(double *src_x, double *src_y, - double *dst_x, double *dst_y, +void CopyQuad(double* src_x, + double* src_y, + double* dst_x, + double* dst_y, int num_extra_points) { for (int i = 0; i < 4 + num_extra_points; ++i) { dst_x[i] = src_x[i]; @@ -1297,16 +1304,18 @@ void CopyQuad(double *src_x, double *src_y, } // namespace -template<typename Warp> -void TemplatedTrackRegion(const FloatImage &image1, - const FloatImage &image2, - const double *x1, const double *y1, - const TrackRegionOptions &options, - double *x2, double *y2, - TrackRegionResult *result) { +template <typename Warp> +void TemplatedTrackRegion(const FloatImage& image1, + const FloatImage& image2, + const double* x1, + const double* y1, + const TrackRegionOptions& options, + double* x2, + double* y2, + TrackRegionResult* result) { for (int i = 0; i < 4 + options.num_extra_points; ++i) { - LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); guess (" - << x2[i] << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", " + LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); guess (" << x2[i] + << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", " << (y2[i] - y1[i]) << ")."; } @@ -1322,9 +1331,14 @@ void TemplatedTrackRegion(const FloatImage &image1, double y2_first_try[5]; CopyQuad(x2, y2, x2_first_try, y2_first_try, options.num_extra_points); - TemplatedTrackRegion<Warp>(image1, image2, - x1, y1, modified_options, - x2_first_try, y2_first_try, result); + TemplatedTrackRegion<Warp>(image1, + image2, + x1, + y1, + modified_options, + x2_first_try, + y2_first_try, + result); // Of the things that can happen in the first pass, don't try the brute // pass (and second attempt) if the error is one of the terminations below. @@ -1368,22 +1382,25 @@ void TemplatedTrackRegion(const FloatImage &image1, // Prepare the image and gradient. Array3Df image_and_gradient1; Array3Df image_and_gradient2; - BlurredImageAndDerivativesChannels(image1, options.sigma, - &image_and_gradient1); - BlurredImageAndDerivativesChannels(image2, options.sigma, - &image_and_gradient2); + BlurredImageAndDerivativesChannels( + image1, options.sigma, &image_and_gradient1); + BlurredImageAndDerivativesChannels( + image2, options.sigma, &image_and_gradient2); // Possibly do a brute-force translation-only initialization. if (SearchAreaTooBigForDescent(image2, x2, y2) && options.use_brute_initialization) { LG << "Running brute initialization..."; - bool found_any_alignment = BruteTranslationOnlyInitialize<Warp>( - image_and_gradient1, - options.image1_mask, - image2, - options.num_extra_points, - options.use_normalized_intensities, - x1, y1, x2, y2); + bool found_any_alignment = + BruteTranslationOnlyInitialize<Warp>(image_and_gradient1, + options.image1_mask, + image2, + options.num_extra_points, + options.use_normalized_intensities, + x1, + y1, + x2, + y2); if (!found_any_alignment) { LG << "Brute failed to find an alignment; pattern too small. " << "Failing entire track operation."; @@ -1391,9 +1408,9 @@ void TemplatedTrackRegion(const FloatImage &image1, return; } for (int i = 0; i < 4; ++i) { - LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); brute (" - << x2[i] << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) - << ", " << (y2[i] - y1[i]) << ")."; + LG << "P" << i << ": (" << x1[i] << ", " << y1[i] << "); brute (" << x2[i] + << ", " << y2[i] << "); (dx, dy): (" << (x2[i] - x1[i]) << ", " + << (y2[i] - y1[i]) << ")."; } } @@ -1408,14 +1425,13 @@ void TemplatedTrackRegion(const FloatImage &image1, PickSampling(x1, y1, x2, y2, &num_samples_x, &num_samples_y); // Compute the warp from rectangular coordinates. - Mat3 canonical_homography = ComputeCanonicalHomography(x1, y1, - num_samples_x, - num_samples_y); + Mat3 canonical_homography = + ComputeCanonicalHomography(x1, y1, num_samples_x, num_samples_y); ceres::Problem problem; // Construct the warp cost function. AutoDiffCostFunction takes ownership. - PixelDifferenceCostFunctor<Warp> *pixel_difference_cost_function = + PixelDifferenceCostFunctor<Warp>* pixel_difference_cost_function = new PixelDifferenceCostFunctor<Warp>(options, image_and_gradient1, image_and_gradient2, @@ -1424,28 +1440,24 @@ void TemplatedTrackRegion(const FloatImage &image1, num_samples_y, warp); problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - PixelDifferenceCostFunctor<Warp>, - ceres::DYNAMIC, - Warp::NUM_PARAMETERS>(pixel_difference_cost_function, - num_samples_x * num_samples_y), - NULL, - warp.parameters); + new ceres::AutoDiffCostFunction<PixelDifferenceCostFunctor<Warp>, + ceres::DYNAMIC, + Warp::NUM_PARAMETERS>( + pixel_difference_cost_function, num_samples_x * num_samples_y), + NULL, + warp.parameters); // Construct the regularizing cost function if (options.regularization_coefficient != 0.0) { - WarpRegularizingCostFunctor<Warp> *regularizing_warp_cost_function = - new WarpRegularizingCostFunctor<Warp>(options, - x1, y2, - x2_original, - y2_original, - warp); + WarpRegularizingCostFunctor<Warp>* regularizing_warp_cost_function = + new WarpRegularizingCostFunctor<Warp>( + options, x1, y2, x2_original, y2_original, warp); problem.AddResidualBlock( - new ceres::AutoDiffCostFunction< - WarpRegularizingCostFunctor<Warp>, - 8 /* num_residuals */, - Warp::NUM_PARAMETERS>(regularizing_warp_cost_function), + new ceres::AutoDiffCostFunction<WarpRegularizingCostFunctor<Warp>, + 8 /* num_residuals */, + Warp::NUM_PARAMETERS>( + regularizing_warp_cost_function), NULL, warp.parameters); } @@ -1488,10 +1500,10 @@ void TemplatedTrackRegion(const FloatImage &image1, return; } -#define HANDLE_TERMINATION(termination_enum) \ - if (summary.termination_type == ceres::termination_enum) { \ - result->termination = TrackRegionResult::termination_enum; \ - return; \ +#define HANDLE_TERMINATION(termination_enum) \ + if (summary.termination_type == ceres::termination_enum) { \ + result->termination = TrackRegionResult::termination_enum; \ + return; \ } // Avoid computing correlation for tracking failures. @@ -1499,8 +1511,9 @@ void TemplatedTrackRegion(const FloatImage &image1, // Otherwise, run a final correlation check. if (options.minimum_correlation > 0.0) { - result->correlation = pixel_difference_cost_function-> - PearsonProductMomentCorrelationCoefficient(warp.parameters); + result->correlation = + pixel_difference_cost_function + ->PearsonProductMomentCorrelationCoefficient(warp.parameters); if (result->correlation < options.minimum_correlation) { LG << "Failing with insufficient correlation."; result->termination = TrackRegionResult::INSUFFICIENT_CORRELATION; @@ -1523,36 +1536,39 @@ void TemplatedTrackRegion(const FloatImage &image1, #undef HANDLE_TERMINATION }; -void TrackRegion(const FloatImage &image1, - const FloatImage &image2, - const double *x1, const double *y1, - const TrackRegionOptions &options, - double *x2, double *y2, - TrackRegionResult *result) { +void TrackRegion(const FloatImage& image1, + const FloatImage& image2, + const double* x1, + const double* y1, + const TrackRegionOptions& options, + double* x2, + double* y2, + TrackRegionResult* result) { // Enum is necessary due to templated nature of autodiff. -#define HANDLE_MODE(mode_enum, mode_type) \ - if (options.mode == TrackRegionOptions::mode_enum) { \ - TemplatedTrackRegion<mode_type>(image1, image2, \ - x1, y1, \ - options, \ - x2, y2, \ - result); \ - return; \ +#define HANDLE_MODE(mode_enum, mode_type) \ + if (options.mode == TrackRegionOptions::mode_enum) { \ + TemplatedTrackRegion<mode_type>( \ + image1, image2, x1, y1, options, x2, y2, result); \ + return; \ } - HANDLE_MODE(TRANSLATION, TranslationWarp); - HANDLE_MODE(TRANSLATION_SCALE, TranslationScaleWarp); - HANDLE_MODE(TRANSLATION_ROTATION, TranslationRotationWarp); + HANDLE_MODE(TRANSLATION, TranslationWarp); + HANDLE_MODE(TRANSLATION_SCALE, TranslationScaleWarp); + HANDLE_MODE(TRANSLATION_ROTATION, TranslationRotationWarp); HANDLE_MODE(TRANSLATION_ROTATION_SCALE, TranslationRotationScaleWarp); - HANDLE_MODE(AFFINE, AffineWarp); - HANDLE_MODE(HOMOGRAPHY, HomographyWarp); + HANDLE_MODE(AFFINE, AffineWarp); + HANDLE_MODE(HOMOGRAPHY, HomographyWarp); #undef HANDLE_MODE } -bool SamplePlanarPatch(const FloatImage &image, - const double *xs, const double *ys, - int num_samples_x, int num_samples_y, - FloatImage *mask, FloatImage *patch, - double *warped_position_x, double *warped_position_y) { +bool SamplePlanarPatch(const FloatImage& image, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + FloatImage* mask, + FloatImage* patch, + double* warped_position_x, + double* warped_position_y) { // Bail early if the points are outside the image. if (!AllInBounds(image, xs, ys)) { LG << "Can't sample patch: out of bounds."; @@ -1563,9 +1579,8 @@ bool SamplePlanarPatch(const FloatImage &image, patch->Resize(num_samples_y, num_samples_x, image.Depth()); // Compute the warp from rectangular coordinates. - Mat3 canonical_homography = ComputeCanonicalHomography(xs, ys, - num_samples_x, - num_samples_y); + Mat3 canonical_homography = + ComputeCanonicalHomography(xs, ys, num_samples_x, num_samples_y); // Walk over the coordinates in the canonical space, sampling from the image // in the original space and copying the result into the patch. @@ -1573,12 +1588,11 @@ bool SamplePlanarPatch(const FloatImage &image, for (int c = 0; c < num_samples_x; ++c) { Vec3 image_position = canonical_homography * Vec3(c, r, 1); image_position /= image_position(2); - SampleLinear(image, image_position(1), - image_position(0), - &(*patch)(r, c, 0)); + SampleLinear( + image, image_position(1), image_position(0), &(*patch)(r, c, 0)); if (mask) { - float mask_value = SampleLinear(*mask, image_position(1), - image_position(0), 0); + float mask_value = + SampleLinear(*mask, image_position(1), image_position(0), 0); for (int d = 0; d < image.Depth(); d++) (*patch)(r, c, d) *= mask_value; diff --git a/intern/libmv/libmv/tracking/track_region.h b/intern/libmv/libmv/tracking/track_region.h index 61dce22bcb8..7868e3b8b77 100644 --- a/intern/libmv/libmv/tracking/track_region.h +++ b/intern/libmv/libmv/tracking/track_region.h @@ -19,6 +19,7 @@ // IN THE SOFTWARE. #ifndef LIBMV_TRACKING_TRACK_REGION_H_ +#define LIBMV_TRACKING_TRACK_REGION_H_ #include "libmv/image/image.h" #include "libmv/image/sample.h" @@ -107,7 +108,7 @@ struct TrackRegionOptions { // If non-null, this is used as the pattern mask. It should match the size of // image1, even though only values inside the image1 quad are examined. The // values must be in the range 0.0 to 0.1. - FloatImage *image1_mask; + FloatImage* image1_mask; }; struct TrackRegionResult { @@ -128,8 +129,7 @@ struct TrackRegionResult { Termination termination; bool is_usable() { - return termination == CONVERGENCE || - termination == NO_CONVERGENCE; + return termination == CONVERGENCE || termination == NO_CONVERGENCE; } int num_iterations; @@ -140,12 +140,14 @@ struct TrackRegionResult { }; // Always needs 4 correspondences. -void TrackRegion(const FloatImage &image1, - const FloatImage &image2, - const double *x1, const double *y1, - const TrackRegionOptions &options, - double *x2, double *y2, - TrackRegionResult *result); +void TrackRegion(const FloatImage& image1, + const FloatImage& image2, + const double* x1, + const double* y1, + const TrackRegionOptions& options, + double* x2, + double* y2, + TrackRegionResult* result); // Sample a "canonical" version of the passed planar patch, using bilinear // sampling. The passed corners must be within the image, and have at least two @@ -156,11 +158,15 @@ void TrackRegion(const FloatImage &image1, // the size of image. // Warped coordinates of marker's position would be returned in // warped_position_x and warped_position_y -bool SamplePlanarPatch(const FloatImage &image, - const double *xs, const double *ys, - int num_samples_x, int num_samples_y, - FloatImage *mask, FloatImage *patch, - double *warped_position_x, double *warped_position_y); +bool SamplePlanarPatch(const FloatImage& image, + const double* xs, + const double* ys, + int num_samples_x, + int num_samples_y, + FloatImage* mask, + FloatImage* patch, + double* warped_position_x, + double* warped_position_y); } // namespace libmv diff --git a/intern/libmv/libmv/tracking/trklt_region_tracker.cc b/intern/libmv/libmv/tracking/trklt_region_tracker.cc index 05ef3d1d272..7ffa7555467 100644 --- a/intern/libmv/libmv/tracking/trklt_region_tracker.cc +++ b/intern/libmv/libmv/tracking/trklt_region_tracker.cc @@ -20,27 +20,29 @@ #include "libmv/tracking/trklt_region_tracker.h" -#include "libmv/logging/logging.h" -#include "libmv/numeric/numeric.h" -#include "libmv/image/image.h" #include "libmv/image/convolve.h" +#include "libmv/image/image.h" #include "libmv/image/sample.h" +#include "libmv/logging/logging.h" +#include "libmv/numeric/numeric.h" namespace libmv { // TODO(keir): Switch this to use the smarter LM loop like in ESM. // Computes U and e from the Ud = e equation (number 14) from the paper. -static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, - const Array3Df &image_and_gradient2, - double x1, double y1, - double x2, double y2, +static void ComputeTrackingEquation(const Array3Df& image_and_gradient1, + const Array3Df& image_and_gradient2, + double x1, + double y1, + double x2, + double y2, int half_width, double lambda, - Mat2f *U, - Vec2f *e) { + Mat2f* U, + Vec2f* e) { Mat2f A, B, C, D; - A = B = C = D = Mat2f::Zero(); + A = B = C = D = Mat2f::Zero(); Vec2f R, S, V, W; R = S = V = W = Vec2f::Zero(); @@ -57,9 +59,9 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, Vec2f gI, gJ; gI << SampleLinear(image_and_gradient1, yy1, xx1, 1), - SampleLinear(image_and_gradient1, yy1, xx1, 2); + SampleLinear(image_and_gradient1, yy1, xx1, 2); gJ << SampleLinear(image_and_gradient2, yy2, xx2, 1), - SampleLinear(image_and_gradient2, yy2, xx2, 2); + SampleLinear(image_and_gradient2, yy2, xx2, 2); // Equation 15 from the paper. A += gI * gI.transpose(); @@ -77,26 +79,25 @@ static void ComputeTrackingEquation(const Array3Df &image_and_gradient1, Mat2f Di = B.transpose().inverse(); // Equation 14 from the paper. - *U = A*Di*C + lambda*Di*C - 0.5*B; - *e = (A + lambda*Mat2f::Identity())*Di*(V - W) + 0.5*(S - R); + *U = A * Di * C + lambda * Di * C - 0.5 * B; + *e = (A + lambda * Mat2f::Identity()) * Di * (V - W) + 0.5 * (S - R); } -static bool RegionIsInBounds(const FloatImage &image1, - double x, double y, - int half_window_size) { +static bool RegionIsInBounds(const FloatImage& image1, + double x, + double y, + int half_window_size) { // Check the minimum coordinates. int min_x = floor(x) - half_window_size - 1; int min_y = floor(y) - half_window_size - 1; - if (min_x < 0.0 || - min_y < 0.0) { + if (min_x < 0.0 || min_y < 0.0) { return false; } // Check the maximum coordinates. int max_x = ceil(x) + half_window_size + 1; int max_y = ceil(y) + half_window_size + 1; - if (max_x > image1.cols() || - max_y > image1.rows()) { + if (max_x > image1.cols() || max_y > image1.rows()) { return false; } @@ -104,10 +105,12 @@ static bool RegionIsInBounds(const FloatImage &image1, return true; } -bool TrkltRegionTracker::Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const { +bool TrkltRegionTracker::Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const { if (!RegionIsInBounds(image1, x1, y1, half_window_size)) { LG << "Fell out of image1's window with x1=" << x1 << ", y1=" << y1 << ", hw=" << half_window_size << "."; @@ -134,11 +137,14 @@ bool TrkltRegionTracker::Track(const FloatImage &image1, Vec2f e; ComputeTrackingEquation(image_and_gradient1, image_and_gradient2, - x1, y1, - *x2, *y2, + x1, + y1, + *x2, + *y2, half_window_size, lambda, - &U, &e); + &U, + &e); // Solve the linear system for the best update to x2 and y2. d = U.lu().solve(e); @@ -161,7 +167,6 @@ bool TrkltRegionTracker::Track(const FloatImage &image1, LG << "x=" << *x2 << ", y=" << *y2 << ", dx=" << d[0] << ", dy=" << d[1] << ", det=" << determinant; - // If the update is small, then we probably found the target. if (d.squaredNorm() < min_update_squared_distance) { LG << "Successful track in " << i << " iterations."; diff --git a/intern/libmv/libmv/tracking/trklt_region_tracker.h b/intern/libmv/libmv/tracking/trklt_region_tracker.h index 26d0621aa02..a9cf5580f61 100644 --- a/intern/libmv/libmv/tracking/trklt_region_tracker.h +++ b/intern/libmv/libmv/tracking/trklt_region_tracker.h @@ -46,10 +46,12 @@ struct TrkltRegionTracker : public RegionTracker { virtual ~TrkltRegionTracker() {} // Tracker interface. - virtual bool Track(const FloatImage &image1, - const FloatImage &image2, - double x1, double y1, - double *x2, double *y2) const; + virtual bool Track(const FloatImage& image1, + const FloatImage& image2, + double x1, + double y1, + double* x2, + double* y2) const; // No point in creating getters or setters. int half_window_size; diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 180f9f0a01c..3355e9075a0 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -22,8 +22,6 @@ # XXX: This script is meant to be used from inside Blender! # You should not directly use this script, rather use update_msg.py! -import collections -import copy import datetime import os import re diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py index fd4488ecd73..b17c9eeebc5 100644 --- a/release/scripts/modules/bl_i18n_utils/utils.py +++ b/release/scripts/modules/bl_i18n_utils/utils.py @@ -21,12 +21,9 @@ # Some misc utilities... import collections -import copy -import hashlib import os import re import struct -import sys import tempfile #import time diff --git a/release/scripts/modules/bl_i18n_utils/utils_rtl.py b/release/scripts/modules/bl_i18n_utils/utils_rtl.py index 2b6a56c5deb..8da1417c468 100755 --- a/release/scripts/modules/bl_i18n_utils/utils_rtl.py +++ b/release/scripts/modules/bl_i18n_utils/utils_rtl.py @@ -32,7 +32,6 @@ # \", %s, %x12, %.4f, etc.), protecting them from ugly (evil) fribidi, # which seems completely unaware of such things (as unicode is...). -import sys import ctypes import re @@ -89,7 +88,7 @@ def protect_format_seq(msg): PDF = "\u202C" LRO = "\u202D" RLO = "\u202E" - uctrl = {LRE, RLE, PDF, LRO, RLO} + # uctrl = {LRE, RLE, PDF, LRO, RLO} # Most likely incomplete, but seems to cover current needs. format_codes = set("tslfd") digits = set(".0123456789") diff --git a/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py b/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py index b5127784c1e..0784a91d174 100644 --- a/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py +++ b/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py @@ -114,6 +114,7 @@ _km_hierarchy = [ ('Custom Normals Modal Map', 'EMPTY', 'WINDOW', []), ('Bevel Modal Map', 'EMPTY', 'WINDOW', []), ('Paint Stroke Modal', 'EMPTY', 'WINDOW', []), + ('Sculpt Expand Modal', 'EMPTY', 'WINDOW', []), ('Paint Curve', 'EMPTY', 'WINDOW', []), ('Object Non-modal', 'EMPTY', 'WINDOW', []), # mode change diff --git a/release/scripts/modules/bl_previews_utils/bl_previews_render.py b/release/scripts/modules/bl_previews_utils/bl_previews_render.py index 6e3d04e7fa2..979b47f7a14 100644 --- a/release/scripts/modules/bl_previews_utils/bl_previews_render.py +++ b/release/scripts/modules/bl_previews_utils/bl_previews_render.py @@ -283,7 +283,8 @@ def do_previews(do_objects, do_collections, do_scenes, do_data_intern): return cos def preview_render_do(render_context, item_container, item_name, objects, offset_matrix=None): - scene = bpy.data.scenes[render_context.scene, None] + # Unused. + # scene = bpy.data.scenes[render_context.scene, None] if objects is not None: camera = bpy.data.objects[render_context.camera, None] light = bpy.data.objects[render_context.light, None] if render_context.light is not None else None diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 8afb09882fd..ddfd3d66e90 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -32,7 +32,6 @@ __all__ = ( import bpy from bpy.props import ( - BoolProperty, FloatVectorProperty, EnumProperty, ) @@ -50,7 +49,7 @@ def add_object_align_init(context, operator): :rtype: :class:`mathutils.Matrix` """ - from mathutils import Matrix, Vector, Euler + from mathutils import Matrix, Vector properties = operator.properties if operator is not None else None space_data = context.space_data @@ -113,7 +112,6 @@ def object_data_add(context, obdata, operator=None, name=None): :return: the newly created object in the scene. :rtype: :class:`bpy.types.Object` """ - scene = context.scene layer = context.view_layer layer_collection = context.layer_collection or layer.active_layer_collection scene_collection = layer_collection.collection diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 5d89763f34b..ee9115b6643 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -19,7 +19,6 @@ # <pep8-80 compliant> from _bpy import types as bpy_types -import _bpy StructRNA = bpy_types.bpy_struct StructMetaPropGroup = bpy_types.bpy_struct_meta_idprop @@ -900,6 +899,7 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): layout = self.layout import os + import re import bpy.utils layout = self.layout @@ -920,7 +920,11 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): (filter_path(f))) ]) - files.sort() + # Perform a "natural sort", so 20 comes after 3 (for example). + files.sort( + key=lambda file_path: + tuple(int(t) if t.isdigit() else t for t in re.split("(\d+)", file_path[0].lower())), + ) col = layout.column(align=True) diff --git a/release/scripts/modules/console/complete_calltip.py b/release/scripts/modules/console/complete_calltip.py index 611be00b633..4271003ae13 100644 --- a/release/scripts/modules/console/complete_calltip.py +++ b/release/scripts/modules/console/complete_calltip.py @@ -107,11 +107,7 @@ def get_argspec(func, strip_self=True, doc=None, source=None): try: func = func.__func__ except AttributeError: - try: - # py 2.X - func = func.im_func - except AttributeError: - pass + pass # is callable? if not hasattr(func, '__call__'): return '' @@ -141,14 +137,10 @@ def get_argspec(func, strip_self=True, doc=None, source=None): argspec = inspect.formatargspec(*inspect.getfullargspec(func)) except: try: - # py 2.X - argspec = inspect.formatargspec(*inspect.getargspec(func)) + argspec = inspect.formatargvalues( + *inspect.getargvalues(func)) except: - try: - argspec = inspect.formatargvalues( - *inspect.getargvalues(func)) - except: - argspec = '' + argspec = '' if strip_self: argspec = argspec.replace('self, ', '') return argspec diff --git a/release/scripts/modules/console_python.py b/release/scripts/modules/console_python.py index 5106010b555..9e1b921774d 100644 --- a/release/scripts/modules/console_python.py +++ b/release/scripts/modules/console_python.py @@ -229,8 +229,6 @@ execute.hooks = [] def autocomplete(context): - _readline_bypass() - from console import intellisense sc = context.space_data @@ -358,14 +356,3 @@ def banner(context): sc.prompt = PROMPT return {'FINISHED'} - - -# workaround for readline crashing, see: T43491 -def _readline_bypass(): - if "rlcompleter" in sys.modules or "readline" in sys.modules: - return - - # prevent 'rlcompleter' from loading the real 'readline' module. - sys.modules["readline"] = None - import rlcompleter - del sys.modules["readline"] diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py index 964eff0e572..3bcc709ab72 100644 --- a/release/scripts/modules/rna_info.py +++ b/release/scripts/modules/rna_info.py @@ -622,8 +622,8 @@ def BuildRNAInfo(): yield (rna_sub_type_name, rna_sub_struct) i += 1 - for (rna_type_name, rna_struct) in _bpy_types_iterator(): - # if not rna_type_name.startswith('__'): + for (_rna_type_name, rna_struct) in _bpy_types_iterator(): + # if not _rna_type_name.startswith('__'): identifier = rna_struct.identifier diff --git a/release/scripts/presets/framerate/120.py b/release/scripts/presets/framerate/120.py new file mode 100644 index 00000000000..53328907d2b --- /dev/null +++ b/release/scripts/presets/framerate/120.py @@ -0,0 +1,3 @@ +import bpy +bpy.context.scene.render.fps = 120 +bpy.context.scene.render.fps_base = 1 diff --git a/release/scripts/presets/framerate/240.py b/release/scripts/presets/framerate/240.py new file mode 100644 index 00000000000..096af4e38ec --- /dev/null +++ b/release/scripts/presets/framerate/240.py @@ -0,0 +1,3 @@ +import bpy +bpy.context.scene.render.fps = 240 +bpy.context.scene.render.fps_base = 1 diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 69582849308..949cfcae2b1 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -4470,6 +4470,15 @@ def km_sculpt(params): {"properties": [("mode", 'INVERT')]}), ("sculpt.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True}, {"properties": [("mode", 'SMOOTH')]}), + # Expand + ("sculpt.expand", {"type": 'A', "value": 'PRESS', "shift": True}, + {"properties": [("target", "MASK"), ("falloff_type", "GEODESIC"), ("invert", True)]}), + ("sculpt.expand", {"type": 'A', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": [("target", "MASK"), ("falloff_type", "NORMALS"), ("invert", False)]}), + ("sculpt.expand", {"type": 'W', "value": 'PRESS', "shift": True}, + {"properties": [("target", "FACE_SETS"), ("falloff_type", "GEODESIC"), ("invert", False), ("use_modify_active", False)]}), + ("sculpt.expand", {"type": 'W', "value": 'PRESS', "shift": True, "alt": True}, + {"properties": [("target", "FACE_SETS"), ("falloff_type", "BOUNDARY_FACE_SET"),("invert", False), ("use_modify_active", True)]}), # Partial Visibility Show/hide ("sculpt.face_set_change_visibility", {"type": 'H', "value": 'PRESS'}, {"properties": [("mode", 'TOGGLE')]}), @@ -4477,8 +4486,6 @@ def km_sculpt(params): {"properties": [("mode", 'HIDE_ACTIVE')]}), ("sculpt.face_set_change_visibility", {"type": 'H', "value": 'PRESS', "alt": True}, {"properties": [("mode", 'SHOW_ALL')]}), - ("sculpt.mask_expand", {"type": 'W', "value": 'PRESS', "shift": True}, - {"properties": [("use_normals", False), ("keep_previous_mask", False), ("invert", False), ("smooth_iterations", 0), ("create_face_set", True)]}), ("sculpt.face_set_edit", {"type": 'W', "value": 'PRESS', "ctrl": True}, {"properties": [("mode", 'GROW')]}), ("sculpt.face_set_edit", {"type": 'W', "value": 'PRESS', "ctrl": True, "alt": True}, @@ -4499,10 +4506,6 @@ def km_sculpt(params): ("paint.mask_lasso_gesture", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None), ("wm.context_toggle", {"type": 'M', "value": 'PRESS', "ctrl": True}, {"properties": [("data_path", 'scene.tool_settings.sculpt.show_mask')]}), - ("sculpt.mask_expand", {"type": 'A', "value": 'PRESS', "shift": True}, - {"properties": [("use_normals", False), ("keep_previous_mask", False), ("invert", True), ("smooth_iterations", 2), ("create_face_set", False)]}), - ("sculpt.mask_expand", {"type": 'A', "value": 'PRESS', "shift": True, 'alt': True}, - {"properties": [("use_normals", True), ("keep_previous_mask", True), ("invert", False), ("smooth_iterations", 0), ("create_face_set", False)]}), # Dynamic topology ("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None), ("sculpt.dyntopo_detail_size_edit", {"type": 'D', "value": 'PRESS', "shift": True}, None), @@ -5571,6 +5574,39 @@ def km_paint_stroke_modal(_params): return keymap +def km_sculpt_expand_modal(_params): + items = [] + keymap = ( + "Sculpt Expand Modal", + {"space_type": 'EMPTY', "region_type": 'WINDOW', "modal": True}, + {"items": items}, + ) + + items.extend([ + ("CANCEL", {"type": 'ESC', "value": 'PRESS', "any": True}, None), + ("CANCEL", {"type": 'RIGHTMOUSE', "value": 'PRESS', "any": True}, None), + ("CONFIRM", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ("INVERT", {"type": 'F', "value": 'PRESS', "any": True, "repeat" : False}, None), + ("PRESERVE", {"type": 'E', "value": 'PRESS', "any": True, "repeat" : False}, None), + ("GRADIENT", {"type": 'G', "value": 'PRESS', "any": True, "repeat" : False}, None), + ("RECURSION_STEP_GEODESIC", {"type": 'R', "value": 'PRESS', "repeat" : False}, None), + ("RECURSION_STEP_TOPOLOGY", {"type": 'R', "value": 'PRESS', "alt" : True ,"any": True, "repeat" : False}, None), + ("MOVE_TOGGLE", {"type": 'SPACE', "value": 'ANY', "any": True, "repeat" : False}, None), + ("FALLOFF_GEODESICS", {"type": 'ONE', "value": 'PRESS', "any": True, "repeat" : False}, None), + ("FALLOFF_TOPOLOGY", {"type": 'TWO', "value": 'PRESS', "any": True, "repeat" : False}, None), + ("FALLOFF_TOPOLOGY_DIAGONALS", {"type": 'THREE', "value": 'PRESS', "any": True, "repeat" : False}, None), + ("FALLOFF_SPHERICAL", {"type": 'FOUR', "value": 'PRESS', "any": True, "repeat" : False}, None), + ("SNAP_TOGGLE", {"type": 'LEFT_CTRL', "value": 'ANY', "repeat" : False}, None), + ("LOOP_COUNT_INCREASE", {"type": 'W', "value": 'PRESS', "any": True, "repeat" : True}, None), + ("LOOP_COUNT_DECREASE", {"type": 'Q', "value": 'PRESS', "any": True, "repeat" : True}, None), + ("BRUSH_GRADIENT_TOGGLE", {"type": 'B', "value": 'PRESS', "any": True, "repeat" : False}, None), + ("TEXTURE_DISTORTION_INCREASE", {"type": 'Y', "value": 'PRESS', "any": False, "repeat" : True}, None), + ("TEXTURE_DISTORTION_DECREASE", {"type": 'T', "value": 'PRESS', "any": False, "repeat" : True}, None), + ]) + return keymap + + + # Fallback for gizmos that don't have custom a custom key-map. def km_generic_gizmo(_params): @@ -7085,6 +7121,7 @@ def generate_keymaps(params=None): km_view3d_zoom_modal(params), km_view3d_dolly_modal(params), km_paint_stroke_modal(params), + km_sculpt_expand_modal(params), # Gizmos. km_generic_gizmo(params), diff --git a/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py b/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py index 9b0a260dc95..192ba2cf5b5 100644 --- a/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py +++ b/release/scripts/startup/bl_app_templates_system/2D_Animation/__init__.py @@ -58,6 +58,7 @@ def load_handler(dummy): # Grease pencil object scene = bpy.data.scenes[0] if scene: + scene.tool_settings.use_keyframe_insert_auto = True for ob in scene.objects: if ob.type == 'GPENCIL': gpd = ob.data diff --git a/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py b/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py index bfad66ec6cd..c97c3466085 100644 --- a/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py +++ b/release/scripts/startup/bl_app_templates_system/Video_Editing/__init__.py @@ -22,7 +22,6 @@ from bpy.app.handlers import persistent @persistent def load_handler(dummy): - import os from bpy import context screen = context.screen for area in screen.areas: diff --git a/release/scripts/startup/bl_operators/console.py b/release/scripts/startup/bl_operators/console.py index 231dade820d..cd6728d56b2 100644 --- a/release/scripts/startup/bl_operators/console.py +++ b/release/scripts/startup/bl_operators/console.py @@ -37,6 +37,7 @@ class ConsoleExec(Operator): """Execute the current console line as a python expression""" bl_idname = "console.execute" bl_label = "Console Execute" + bl_options = {'UNDO_GROUPED'} interactive: BoolProperty( options={'SKIP_SAVE'}, diff --git a/release/scripts/startup/bl_operators/geometry_nodes.py b/release/scripts/startup/bl_operators/geometry_nodes.py index 9652f23aadb..c66f0ada955 100644 --- a/release/scripts/startup/bl_operators/geometry_nodes.py +++ b/release/scripts/startup/bl_operators/geometry_nodes.py @@ -19,7 +19,7 @@ import bpy -def geometry_node_group_empty_new(context): +def geometry_node_group_empty_new(): group = bpy.data.node_groups.new("Geometry Nodes", 'GeometryNodeTree') group.inputs.new('NodeSocketGeometry', "Geometry") group.outputs.new('NodeSocketGeometry', "Geometry") @@ -85,7 +85,7 @@ class NewGeometryNodeTreeAssign(bpy.types.Operator): if not modifier: return {'CANCELLED'} - group = geometry_node_group_empty_new(context) + group = geometry_node_group_empty_new() modifier.node_group = group return {'FINISHED'} diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 70b80f7198f..4a7700b03bb 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -19,7 +19,6 @@ # <pep8-80 compliant> -import bpy from bpy.types import Operator from mathutils import Vector diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index 48312f958ef..a34ed019148 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -25,7 +25,6 @@ from bpy.props import ( BoolProperty, EnumProperty, FloatProperty, - FloatVectorProperty, IntProperty, ) diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py index 4343717f264..1b801f77e07 100644 --- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py +++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py @@ -18,7 +18,6 @@ # <pep8 compliant> -import bpy from bpy.types import Operator from bpy.props import ( diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py index 3442e189d14..ff5bcdb034f 100644 --- a/release/scripts/startup/bl_operators/view3d.py +++ b/release/scripts/startup/bl_operators/view3d.py @@ -169,7 +169,7 @@ class VIEW3D_OT_edit_mesh_extrude_manifold_normal(Operator): obj = context.active_object return (obj is not None and obj.mode == 'EDIT') - def execute(self, context): + def execute(self, _context): bpy.ops.mesh.extrude_manifold( 'INVOKE_REGION_WIN', MESH_OT_extrude_region={ diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index e8c62368239..e835e577953 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -42,7 +42,7 @@ class OBJECT_PT_constraints(ObjectConstraintPanel, Panel): bl_label = "Object Constraints" bl_options = {'HIDE_HEADER'} - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator_menu_enum("object.constraint_add", "type", text="Add Object Constraint") @@ -56,7 +56,7 @@ class BONE_PT_constraints(BoneConstraintPanel, Panel): bl_label = "Bone Constraints" bl_options = {'HIDE_HEADER'} - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator_menu_enum("pose.constraint_add", "type", text="Add Bone Constraint") @@ -122,7 +122,7 @@ class ConstraintButtonsPanel: elif con.target.type in {'MESH', 'LATTICE'}: col.prop_search(con, "subtarget", con.target, "vertex_groups", text="Vertex Group") - def get_constraint(self, context): + def get_constraint(self, _context): con = self.custom_data self.layout.context_pointer_set("constraint", con) return con @@ -844,7 +844,7 @@ class ConstraintButtonsPanel: self.draw_influence(layout, con) - def draw_python_constraint(self, context): + def draw_python_constraint(self, _context): layout = self.layout layout.label(text="Blender 2.6 doesn't support python constraints yet") @@ -976,7 +976,7 @@ class ConstraintButtonsSubPanel: bl_label = "" bl_options = {'DRAW_BOX'} - def get_constraint(self, context): + def get_constraint(self, _context): con = self.custom_data self.layout.context_pointer_set("constraint", con) return con diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py index 170d7910339..f3e116ca321 100644 --- a/release/scripts/startup/bl_ui/properties_data_bone.py +++ b/release/scripts/startup/bl_ui/properties_data_bone.py @@ -255,17 +255,11 @@ class BONE_PT_display(BoneButtonsPanel, Panel): layout = self.layout layout.use_property_split = True - ob = context.object bone = context.bone - pchan = None - - if ob and bone: - pchan = ob.pose.bones[bone.name] - elif bone is None: + if bone is None: bone = context.edit_bone if bone: - col = layout.column() col.prop(bone, "hide", text="Hide", toggle=False) diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py index 9db6eedb04c..69720a6c54b 100644 --- a/release/scripts/startup/bl_ui/properties_data_gpencil.py +++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py @@ -392,7 +392,6 @@ class DATA_PT_gpencil_display(DataButtonsPanel, Panel): layout.use_property_decorate = False gpd = context.gpencil - gpl = gpd.layers.active layout.prop(gpd, "edit_line_color", text="Edit Line Color") diff --git a/release/scripts/startup/bl_ui/properties_data_hair.py b/release/scripts/startup/bl_ui/properties_data_hair.py index 4964316ad0f..7f95fad9a9e 100644 --- a/release/scripts/startup/bl_ui/properties_data_hair.py +++ b/release/scripts/startup/bl_ui/properties_data_hair.py @@ -81,7 +81,7 @@ class HAIR_MT_add_attribute(Menu): class HAIR_UL_attributes(UIList): - def draw_item(self, context, layout, data, attribute, icon, active_data, active_propname, index): + def draw_item(self, _context, layout, _data, attribute, _icon, _active_data, _active_propname, _index): data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type] domain = attribute.bl_rna.properties['domain'].enum_items[attribute.domain] diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index d464a3ffc6b..39250559741 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -17,9 +17,7 @@ # ##### END GPL LICENSE BLOCK ##### # <pep8 compliant> -import bpy from bpy.types import Panel -from bpy.app.translations import pgettext_iface as iface_ class ModifierButtonsPanel: @@ -37,7 +35,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): ob = context.object return ob and ob.type != 'GPENCIL' - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator_menu_enum("object.modifier_add", "type") layout.template_modifiers() @@ -51,7 +49,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): ob = context.object return ob and ob.type == 'GPENCIL' - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator_menu_enum("object.gpencil_modifier_add", "type") layout.template_grease_pencil_modifiers() diff --git a/release/scripts/startup/bl_ui/properties_data_pointcloud.py b/release/scripts/startup/bl_ui/properties_data_pointcloud.py index eca59ea4aaf..f0584c81c0c 100644 --- a/release/scripts/startup/bl_ui/properties_data_pointcloud.py +++ b/release/scripts/startup/bl_ui/properties_data_pointcloud.py @@ -83,7 +83,7 @@ class POINTCLOUD_MT_add_attribute(Menu): class POINTCLOUD_UL_attributes(UIList): - def draw_item(self, context, layout, data, attribute, icon, active_data, active_propname, index): + def draw_item(self, _context, layout, _data, attribute, _icon, _active_data, _active_propname, _index): data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type] split = layout.split(factor=0.75) diff --git a/release/scripts/startup/bl_ui/properties_data_shaderfx.py b/release/scripts/startup/bl_ui/properties_data_shaderfx.py index a96fef018c7..576910697ad 100644 --- a/release/scripts/startup/bl_ui/properties_data_shaderfx.py +++ b/release/scripts/startup/bl_ui/properties_data_shaderfx.py @@ -37,7 +37,7 @@ class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel): # ob = context.object # return ob and ob.type == 'GPENCIL' - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator_menu_enum("object.shaderfx_add", "type") layout.template_shaderfx() diff --git a/release/scripts/startup/bl_ui/properties_data_volume.py b/release/scripts/startup/bl_ui/properties_data_volume.py index e7bf9adb876..70056b1d27c 100644 --- a/release/scripts/startup/bl_ui/properties_data_volume.py +++ b/release/scripts/startup/bl_ui/properties_data_volume.py @@ -84,7 +84,7 @@ class DATA_PT_volume_file(DataButtonsPanel, Panel): class VOLUME_UL_grids(UIList): - def draw_item(self, context, layout, data, grid, icon, active_data, active_propname, index): + def draw_item(self, _context, layout, _data, grid, _icon, _active_data, _active_propname, _index): name = grid.name data_type = grid.bl_rna.properties['data_type'].enum_items[grid.data_type] diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 0eb5d60457c..c23cc838e51 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -37,8 +37,6 @@ class AnnotationDrawingToolsPanel: tool_settings = context.tool_settings - is_clip_editor = context.space_data.type == 'CLIP_EDITOR' - col = layout.column(align=True) col.label(text="Draw:") @@ -337,7 +335,6 @@ class GPENCIL_MT_material_active(Menu): layout = self.layout layout.operator_context = 'INVOKE_REGION_WIN' ob = context.active_object - mat_active = ob.active_material for slot in ob.material_slots: mat = slot.material diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py index 4d25b8ca309..09a1f40d3a9 100644 --- a/release/scripts/startup/bl_ui/properties_mask_common.py +++ b/release/scripts/startup/bl_ui/properties_mask_common.py @@ -26,7 +26,7 @@ from bpy.app.translations import contexts as i18n_contexts # Use by both image & clip context menus. -def draw_mask_context_menu(layout, context): +def draw_mask_context_menu(layout, _context): layout.operator_menu_enum("mask.handle_type_set", "type") layout.operator("mask.switch_direction") layout.operator("mask.cyclic_toggle") diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py index 69c557d336f..75c1f69f84f 100644 --- a/release/scripts/startup/bl_ui/properties_output.py +++ b/release/scripts/startup/bl_ui/properties_output.py @@ -80,7 +80,7 @@ class RENDER_PT_dimensions(RenderOutputButtonsPanel, Panel): fps_rate = round(fps / fps_base, 2) # TODO: Change the following to iterate over existing presets - custom_framerate = (fps_rate not in {23.98, 24, 25, 29.97, 30, 50, 59.94, 60}) + custom_framerate = (fps_rate not in {23.98, 24, 25, 29.97, 30, 50, 59.94, 60, 120, 240}) if custom_framerate is True: fps_label_text = tip_("Custom (%.4g fps)") % fps_rate diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 91c58ba49cb..b248a70208f 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -617,7 +617,6 @@ def brush_settings(layout, context, brush, popover=False): # use_persistent, set_persistent_base if capabilities.has_persistence: - ob = context.sculpt_object layout.separator() layout.prop(brush, "use_persistent") layout.operator("sculpt.set_persistent_base") @@ -1293,7 +1292,7 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False) layout.template_curve_mapping(settings, "thickness_primitive_curve", brush=True) -def brush_basic_gpencil_sculpt_settings(layout, context, brush, *, compact=False): +def brush_basic_gpencil_sculpt_settings(layout, _context, brush, *, compact=False): gp_settings = brush.gpencil_settings tool = brush.gpencil_sculpt_tool @@ -1328,7 +1327,6 @@ def brush_basic_gpencil_sculpt_settings(layout, context, brush, *, compact=False def brush_basic_gpencil_weight_settings(layout, _context, brush, *, compact=False): - gp_settings = brush.gpencil_settings layout.prop(brush, "size", slider=True) row = layout.row(align=True) diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py index 5d3417fad0f..d168d9ab6dd 100644 --- a/release/scripts/startup/bl_ui/properties_physics_fluid.py +++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py @@ -19,7 +19,7 @@ # <pep8 compliant> import bpy -from bpy.types import Menu, Panel +from bpy.types import Panel from bl_ui.utils import PresetPanel from .properties_physics_common import ( effector_weights_ui, diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py index 8c39684583f..ad7d6008238 100644 --- a/release/scripts/startup/bl_ui/properties_view_layer.py +++ b/release/scripts/startup/bl_ui/properties_view_layer.py @@ -21,7 +21,7 @@ from bpy.types import Panel, UIList class VIEWLAYER_UL_aov(UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname): row = layout.row() split = row.split(factor=0.65) icon = 'NONE' if item.is_valid else 'ERROR' @@ -77,8 +77,6 @@ class VIEWLAYER_PT_eevee_layer_passes_data(ViewLayerButtonsPanel, Panel): layout.use_property_split = True layout.use_property_decorate = False - scene = context.scene - rd = scene.render view_layer = context.view_layer col = layout.column() @@ -101,8 +99,6 @@ class VIEWLAYER_PT_eevee_layer_passes_light(ViewLayerButtonsPanel, Panel): view_layer = context.view_layer view_layer_eevee = view_layer.eevee - scene = context.scene - scene_eevee = scene.eevee col = layout.column(heading="Diffuse", align=True) col.prop(view_layer, "use_pass_diffuse_direct", text="Light") diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 73cc674858c..9b5942cbaa9 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -375,7 +375,7 @@ class IMAGE_MT_uvs_split(Menu): class IMAGE_MT_uvs_unwrap(Menu): bl_label = "Unwrap" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator("uv.unwrap") diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 43a5e17e50e..5c5a78f3942 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -19,10 +19,6 @@ # <pep8 compliant> import bpy from bpy.types import Header, Menu, Panel -from bpy.app.translations import ( - contexts as i18n_contexts, - pgettext_iface as iface_, -) class OUTLINER_HT_header(Header): @@ -257,7 +253,7 @@ class OUTLINER_MT_collection_new(Menu): bl_label = "Collection" @staticmethod - def draw_without_context_menu(context, layout): + def draw_without_context_menu(_context, layout): layout.operator("outliner.collection_new", text="New Collection").nested = True layout.operator("outliner.id_paste", text="Paste Data-Blocks", icon='PASTEDOWN') @@ -278,7 +274,6 @@ class OUTLINER_MT_object(Menu): layout = self.layout space = context.space_data - obj = context.active_object layout.operator("outliner.id_copy", text="Copy", icon='COPYDOWN') layout.operator("outliner.id_paste", text="Paste", icon='PASTEDOWN') diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index e10f3383bc8..fa7082e139a 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -113,6 +113,10 @@ class SEQUENCER_HT_tool_header(Header): # TODO: options popover. def draw_tool_settings(self, context): + pass + + # Currently unused. + ''' layout = self.layout # Active Tool @@ -120,6 +124,7 @@ class SEQUENCER_HT_tool_header(Header): from bl_ui.space_toolsystem_common import ToolSelectPanelHelper tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout) tool_mode = context.mode if tool is None else tool.mode + ''' class SEQUENCER_HT_header(Header): @@ -129,8 +134,6 @@ class SEQUENCER_HT_header(Header): layout = self.layout st = context.space_data - scene = context.scene - sequencer_tool_settings = context.tool_settings.sequencer_tool_settings show_region_tool_header = st.show_region_tool_header @@ -336,8 +339,6 @@ class SEQUENCER_MT_view(Menu): st = context.space_data is_preview = st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'} is_sequencer_view = st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'} - scene = context.scene - ed = scene.sequence_editor if st.view_type == 'PREVIEW': # Specifying the REGION_PREVIEW context is needed in preview-only @@ -1904,7 +1905,6 @@ class SEQUENCER_PT_strip_proxy(SequencerButtonsPanel, Panel): if strip.proxy: proxy = strip.proxy - flow = layout.column_flow() if ed.proxy_storage == 'PER_STRIP': col = layout.column(heading="Custom Proxy") col.prop(proxy, "use_proxy_custom_directory", text="Directory") diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py index 12ec863327c..25f2a740f7c 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_common.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -1022,7 +1022,7 @@ def activate_by_id(context, space_type, idname, *, as_fallback=False): return True -def activate_by_id_or_cycle(context, space_type, idname, *, offset=1, as_fallback=False): +def activate_by_id_or_cycle(context, space_type, idname, *, offset=1, _as_fallback=False): # Only cycle when the active tool is activated again. cls = ToolSelectPanelHelper._tool_class_from_space_type(space_type) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 8e99c3af4c3..1e52142c85c 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1096,7 +1096,7 @@ class _defs_edit_curve: @ToolDef.from_fn def draw(): - def draw_settings(context, layout, tool, *, extra=False): + def draw_settings(context, layout, _tool, *, extra=False): # Tool settings initialize operator options. tool_settings = context.tool_settings cps = tool_settings.curve_paint_settings @@ -1589,7 +1589,7 @@ class _defs_weight_paint: @ToolDef.from_fn def sample_weight(): - def draw_settings(context, layout, tool): + def draw_settings(context, layout, _tool): if context.tool_settings.unified_paint_settings.use_unified_weight: weight = context.tool_settings.unified_paint_settings.weight elif context.tool_settings.weight_paint.brush: @@ -1869,7 +1869,7 @@ class _defs_image_uv_sculpt: class _defs_gpencil_paint: @staticmethod - def gpencil_primitive_toolbar(context, layout, tool, props): + def gpencil_primitive_toolbar(context, layout, _tool, props): paint = context.tool_settings.gpencil_paint brush = paint.brush @@ -1907,7 +1907,7 @@ class _defs_gpencil_paint: @ToolDef.from_fn def cutter(): - def draw_settings(context, layout, tool): + def draw_settings(_context, layout, tool): props = tool.operator_properties("gpencil.stroke_cutter") row = layout.row() row.use_property_split = False @@ -2020,7 +2020,7 @@ class _defs_gpencil_paint: @ToolDef.from_fn def eyedropper(): - def draw_settings(context, layout, tool): + def draw_settings(_context, layout, tool): props = tool.operator_properties("ui.eyedropper_gpencil_color") row = layout.row() row.use_property_split = False @@ -2037,7 +2037,7 @@ class _defs_gpencil_paint: @ToolDef.from_fn def interpolate(): - def draw_settings(context, layout, tool): + def draw_settings(_context, layout, tool): props = tool.operator_properties("gpencil.interpolate") layout.prop(props, "layers") layout.prop(props, "flip") @@ -2201,7 +2201,7 @@ class _defs_gpencil_edit: @ToolDef.from_fn def transform_fill(): - def draw_settings(context, layout, tool): + def draw_settings(_context, layout, tool): props = tool.operator_properties("gpencil.transform_fill") row = layout.row() row.use_property_split = False @@ -2219,7 +2219,7 @@ class _defs_gpencil_edit: @ToolDef.from_fn def interpolate(): - def draw_settings(context, layout, tool): + def draw_settings(_context, layout, tool): props = tool.operator_properties("gpencil.interpolate") layout.prop(props, "layers") layout.prop(props, "interpolate_selected_only") @@ -2411,8 +2411,6 @@ class _defs_sequencer_generic: @ToolDef.from_fn def sample(): - def draw_settings(_context, layout, tool): - props = tool.operator_properties("sequencer.sample") return dict( idname="builtin.sample", label="Sample", @@ -2421,7 +2419,6 @@ class _defs_sequencer_generic: ), icon="ops.paint.weight_sample", # XXX, needs own icon. keymap="Sequencer Tool: Sample", - draw_settings=draw_settings, ) diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 45460a1a5de..7219922c379 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -244,7 +244,7 @@ class TOPBAR_MT_app(Menu): class TOPBAR_MT_file_cleanup(Menu): bl_label = "Clean Up" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.separator() @@ -475,7 +475,7 @@ class TOPBAR_MT_file_export(Menu): bl_label = "Export" bl_owner_use_filter = False - def draw(self, context): + def draw(self, _context): if bpy.app.build_options.collada: self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)") diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 94a1e2bec4d..b214dc0c245 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -96,7 +96,7 @@ class USERPREF_MT_editor_menus(Menu): class USERPREF_MT_view(Menu): bl_label = "View" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.menu("INFO_MT_area") @@ -241,7 +241,7 @@ class USERPREF_PT_interface_translation(InterfacePanel, CenterAlignMixIn, Panel) bl_translation_context = i18n_contexts.id_windowmanager @classmethod - def poll(cls, context): + def poll(cls, _context): return bpy.app.build_options.international def draw_centered(self, context, layout): @@ -581,7 +581,7 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel): bl_label = "Cycles Render Devices" @classmethod - def poll(cls, context): + def poll(cls, _context): # No GPU rendering on macOS currently. import sys return bpy.app.build_options.cycles and sys.platform != "darwin" @@ -642,7 +642,7 @@ class USERPREF_PT_system_video_sequencer(SystemPanel, CenterAlignMixIn, Panel): def draw_centered(self, context, layout): prefs = context.preferences system = prefs.system - edit = prefs.edit + # edit = prefs.edit layout.prop(system, "memory_cache_limit") @@ -2185,7 +2185,7 @@ class ExperimentalPanel: url_prefix = "https://developer.blender.org/" @classmethod - def poll(cls, context): + def poll(cls, _context): return bpy.app.version_cycle == 'alpha' def _draw_items(self, context, items): @@ -2260,7 +2260,7 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel): bl_label = "Debugging" @classmethod - def poll(cls, context): + def poll(cls, _context): # Unlike the other experimental panels, the debugging one is always visible # even in beta or release. return True diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 41a1831f46a..26e0c128f7c 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1068,7 +1068,7 @@ class VIEW3D_MT_snap(Menu): class VIEW3D_MT_uv_map(Menu): bl_label = "UV Mapping" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator("uv.unwrap") @@ -1822,7 +1822,7 @@ class VIEW3D_MT_select_edit_armature(Menu): class VIEW3D_MT_paint_gpencil(Menu): bl_label = "Paint" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator("gpencil.vertex_color_set", text="Set Vertex Colors") @@ -2238,7 +2238,7 @@ class VIEW3D_MT_object(Menu): bl_context = "objectmode" bl_label = "Object" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.menu("VIEW3D_MT_transform_object") @@ -2717,7 +2717,7 @@ class VIEW3D_MT_object_constraints(Menu): class VIEW3D_MT_object_quick_effects(Menu): bl_label = "Quick Effects" - def draw(self, context): + def draw(self, _context): layout = self.layout layout.operator("object.quick_fur") @@ -7009,10 +7009,9 @@ class VIEW3D_PT_gpencil_curve_edit(Panel): bl_label = "Curve Editing" def draw(self, context): - gpd = context.gpencil_data - settings = context.tool_settings.gpencil_sculpt - layout = self.layout + + gpd = context.gpencil_data col = layout.column(align=True) col.prop(gpd, "edit_curve_resolution") col.prop(gpd, "curve_edit_threshold") diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index ecf46ac2592..10010ab0b15 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -199,8 +199,6 @@ class VIEW3D_PT_tools_meshedit_options(View3DPanel, Panel): ob = context.active_object mesh = ob.data - split = layout.split() - row = layout.row(align=True, heading="Transform") row.prop(tool_settings, "use_transform_correct_face_attributes") @@ -1353,8 +1351,6 @@ class VIEW3D_PT_tools_grease_pencil_brush_select(Panel, View3DPanel, GreasePenci if context.mode == 'PAINT_GPENCIL': brush = tool_settings.gpencil_paint.brush if brush is not None: - gp_settings = brush.gpencil_settings - col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="") if brush.use_custom_icon: @@ -1493,8 +1489,9 @@ class VIEW3D_PT_tools_grease_pencil_brush_stroke(Panel, View3DPanel): brush = context.tool_settings.gpencil_paint.brush return brush is not None and brush.gpencil_tool == 'DRAW' - def draw(self, context): - layout = self.layout + def draw(self, _context): + # layout = self.layout + pass class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(Panel, View3DPanel): diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 2fce4bfc5b8..8666291cec8 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -235,12 +235,12 @@ typedef enum eAnimData_Recalc { ADT_RECALC_ALL = (ADT_RECALC_DRIVERS | ADT_RECALC_ANIM), } eAnimData_Recalc; -bool BKE_animsys_store_rna_setting(struct PointerRNA *ptr, - const char *rna_path, - const int array_index, - struct PathResolvedRNA *r_result); -bool BKE_animsys_read_rna_setting(struct PathResolvedRNA *anim_rna, float *r_value); -bool BKE_animsys_write_rna_setting(struct PathResolvedRNA *anim_rna, const float value); +bool BKE_animsys_rna_path_resolve(struct PointerRNA *ptr, + const char *rna_path, + const int array_index, + struct PathResolvedRNA *r_result); +bool BKE_animsys_read_from_rna_path(struct PathResolvedRNA *anim_rna, float *r_value); +bool BKE_animsys_write_to_rna_path(struct PathResolvedRNA *anim_rna, const float value); /* Evaluation loop for evaluating animation data */ void BKE_animsys_evaluate_animdata(struct ID *id, diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index db44a771095..f5face2120e 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -27,6 +27,8 @@ extern "C" { #endif +struct AnimationEvalContext; +struct bAction; struct BMEditMesh; struct Bone; struct Depsgraph; @@ -193,6 +195,12 @@ void BKE_pose_where_is_bone(struct Depsgraph *depsgraph, bool do_extra); void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan); +/* Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that + * relate to those bones are evaluated. */ +void BKE_pose_apply_action(struct Object *ob, + struct bAction *action, + struct AnimationEvalContext *anim_eval_context); + /* get_objectspace_bone_matrix has to be removed still */ void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 17eb6e19292..66bfe620df7 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 9 +#define BLENDER_FILE_SUBVERSION 10 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h index 3631feb5071..ec2262d4f60 100644 --- a/source/blender/blenkernel/BKE_colortools.h +++ b/source/blender/blenkernel/BKE_colortools.h @@ -59,6 +59,7 @@ enum { CURVEMAP_SLOPE_POS_NEG = 2, }; +void BKE_curvemapping_reset_view(struct CurveMapping *cumap); void BKE_curvemap_reset(struct CurveMap *cuma, const struct rctf *clipr, int preset, int slope); void BKE_curvemap_remove(struct CurveMap *cuma, const short flag); bool BKE_curvemap_remove_point(struct CurveMap *cuma, struct CurveMapPoint *cmp); diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h index 1b1c4deeb8a..7d295929e77 100644 --- a/source/blender/blenkernel/BKE_cryptomatte.h +++ b/source/blender/blenkernel/BKE_cryptomatte.h @@ -31,21 +31,25 @@ extern "C" { #endif struct CryptomatteSession; -struct ID; -struct Main; struct Material; struct Object; struct RenderResult; struct CryptomatteSession *BKE_cryptomatte_init(void); +struct CryptomatteSession *BKE_cryptomatte_init_from_render_result( + const struct RenderResult *render_result); void BKE_cryptomatte_free(struct CryptomatteSession *session); +void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name); uint32_t BKE_cryptomatte_hash(const char *name, int name_len); uint32_t BKE_cryptomatte_object_hash(struct CryptomatteSession *session, + const char *layer_name, const struct Object *object); uint32_t BKE_cryptomatte_material_hash(struct CryptomatteSession *session, + const char *layer_name, const struct Material *material); uint32_t BKE_cryptomatte_asset_hash(struct CryptomatteSession *session, + const char *layer_name, const struct Object *object); float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash); @@ -53,11 +57,9 @@ char *BKE_cryptomatte_entries_to_matte_id(struct NodeCryptomatte *node_storage); void BKE_cryptomatte_matte_id_to_entries(struct NodeCryptomatte *node_storage, const char *matte_id); -void BKE_cryptomatte_store_metadata(struct CryptomatteSession *session, +void BKE_cryptomatte_store_metadata(const struct CryptomatteSession *session, struct RenderResult *render_result, - const ViewLayer *view_layer, - eViewLayerCryptomatteFlags cryptomatte_layer, - const char *cryptomatte_layer_name); + const ViewLayer *view_layer); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh index c1da0339359..f10b4c1f7c4 100644 --- a/source/blender/blenkernel/BKE_cryptomatte.hh +++ b/source/blender/blenkernel/BKE_cryptomatte.hh @@ -81,9 +81,26 @@ struct CryptomatteLayer { static std::unique_ptr<CryptomatteLayer> read_from_manifest(blender::StringRefNull manifest); uint32_t add_ID(const struct ID &id); void add_hash(blender::StringRef name, CryptomatteHash cryptomatte_hash); - std::string manifest(); + std::string manifest() const; std::optional<std::string> operator[](float encoded_hash) const; }; +struct CryptomatteStampDataCallbackData { + struct CryptomatteSession *session; + blender::Map<std::string, std::string> hash_to_layer_name; + + /** + * Extract the hash from a stamp data key. + * + * Cryptomatte keys are formatted as "cryptomatte/{layer_hash}/{attribute}". + */ + static blender::StringRef extract_layer_hash(blender::StringRefNull key); + + /* C type callback function (StampCallback). */ + static void extract_layer_names(void *_data, const char *propname, char *propvalue, int len); + /* C type callback function (StampCallback). */ + static void extract_layer_manifest(void *_data, const char *propname, char *propvalue, int len); +}; + } // namespace blender::bke::cryptomatte diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index b6116b32ca5..2c6e5ed3873 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -223,7 +223,7 @@ struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset); #define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb) \ { \ - ListBase *_lbarray[MAX_LIBARRAY]; \ + ListBase *_lbarray[INDEX_ID_MAX]; \ int _i = set_listbasepointers((_bmain), _lbarray); \ while (_i--) { \ (_lb) = _lbarray[_i]; @@ -234,9 +234,13 @@ struct GSet *BKE_main_gset_create(struct Main *bmain, struct GSet *gset); ((void)0) /** - * DO NOT use break statement with that macro, - * use #FOREACH_MAIN_LISTBASE and #FOREACH_MAIN_LISTBASE_ID instead - * if you need that kind of control flow. */ + * Top level `foreach`-like macro allowing to loop over all IDs in a given #Main data-base. + * + * NOTE: Order tries to go from 'user IDs' to 'used IDs' (e.g. collections will be processed + * before objects, which will be processed before obdata types, etc.). + * + * WARNING: DO NOT use break statement with that macro, use #FOREACH_MAIN_LISTBASE and + * #FOREACH_MAIN_LISTBASE_ID instead if you need that kind of control flow. */ #define FOREACH_MAIN_ID_BEGIN(_bmain, _id) \ { \ ListBase *_lb; \ @@ -259,8 +263,8 @@ const char *BKE_main_blendfile_path_from_global(void); struct ListBase *which_libbase(struct Main *bmain, short type); -#define MAX_LIBARRAY 41 -int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]); +//#define INDEX_ID_MAX 41 +int set_listbasepointers(struct Main *main, struct ListBase *lb[]); #define MAIN_VERSION_ATLEAST(main, ver, subver) \ ((main)->versionfile > (ver) || \ diff --git a/source/blender/blenkernel/BKE_mesh_mirror.h b/source/blender/blenkernel/BKE_mesh_mirror.h index 2f792049a41..b5d0fec6bc1 100644 --- a/source/blender/blenkernel/BKE_mesh_mirror.h +++ b/source/blender/blenkernel/BKE_mesh_mirror.h @@ -46,7 +46,7 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain, struct Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(struct MirrorModifierData *mmd, struct Object *ob, const struct Mesh *mesh, - int axis); + const int axis); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index d675df6d868..655c53455cc 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -301,11 +301,11 @@ typedef struct bNodeType { void (*free_self)(struct bNodeType *ntype); /* **** execution callbacks **** */ - NodeInitExecFunction initexecfunc; - NodeFreeExecFunction freeexecfunc; - NodeExecFunction execfunc; + NodeInitExecFunction init_exec_fn; + NodeFreeExecFunction free_exec_fn; + NodeExecFunction exec_fn; /* gpu */ - NodeGPUExecFunction gpufunc; + NodeGPUExecFunction gpu_fn; /* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */ NodeExpandInMFNetworkFunction expand_in_mf_network; @@ -829,10 +829,10 @@ void node_type_group_update(struct bNodeType *ntype, struct bNode *node)); void node_type_exec(struct bNodeType *ntype, - NodeInitExecFunction initexecfunc, - NodeFreeExecFunction freeexecfunc, - NodeExecFunction execfunc); -void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc); + NodeInitExecFunction init_exec_fn, + NodeFreeExecFunction free_exec_fn, + NodeExecFunction exec_fn); +void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn); void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *)); diff --git a/source/blender/blenkernel/BKE_node_ui_storage.hh b/source/blender/blenkernel/BKE_node_ui_storage.hh index 231eb11d473..a49ff988272 100644 --- a/source/blender/blenkernel/BKE_node_ui_storage.hh +++ b/source/blender/blenkernel/BKE_node_ui_storage.hh @@ -16,6 +16,8 @@ #pragma once +#include <mutex> + #include "BLI_hash.hh" #include "BLI_map.hh" #include "BLI_session_uuid.h" @@ -82,6 +84,7 @@ struct NodeUIStorage { struct NodeTreeUIStorage { blender::Map<NodeTreeEvaluationContext, blender::Map<std::string, NodeUIStorage>> context_map; + std::mutex context_map_mutex; }; const NodeUIStorage *BKE_node_tree_ui_storage_get_from_context(const bContext *C, diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index bca23f93b5c..3e5bf2570a6 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -473,10 +473,19 @@ typedef struct SculptSession { struct MPropCol *vcol; float *vmask; - /* Mesh connectivity */ + /* Mesh connectivity maps. */ + /* Vertices to adjacent polys. */ struct MeshElemMap *pmap; int *pmap_mem; + /* Edges to adjacent polys. */ + struct MeshElemMap *epmap; + int *epmap_mem; + + /* Vertices to adjacent edges. */ + struct MeshElemMap *vemap; + int *vemap_mem; + /* Mesh Face Sets */ /* Total number of polys of the base mesh. */ int totfaces; @@ -515,6 +524,7 @@ typedef struct SculptSession { struct StrokeCache *cache; struct FilterCache *filter_cache; + struct ExpandCache *expand_cache; /* Cursor data and active vertex for tools */ SculptVertRef active_vertex_index; diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh index 1ec8a8e84cd..1f6e89636c4 100644 --- a/source/blender/blenkernel/BKE_volume_to_mesh.hh +++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh @@ -21,7 +21,6 @@ #endif struct Mesh; -struct VolumeGrid; namespace blender::bke { diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 1e7986eedd9..c954d0670f0 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -77,6 +77,7 @@ set(SRC intern/appdir.c intern/armature.c intern/armature_deform.c + intern/armature_pose.cc intern/armature_update.c intern/asset.cc intern/attribute.c diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 06b8bd5f0f2..f9c2a4e53ad 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -2002,7 +2002,7 @@ void BKE_pose_blend_read_lib(BlendLibReader *reader, Object *ob, bPose *pose) IDP_BlendReadLib(reader, pchan->prop); - BLO_read_id_address(reader, arm->id.lib, &pchan->custom); + BLO_read_id_address(reader, ob->id.lib, &pchan->custom); if (UNLIKELY(pchan->bone == NULL)) { rebuild = true; } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 4d490f8f76a..9a890fd02be 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -376,59 +376,56 @@ static bool is_fcurve_evaluatable(FCurve *fcu) return true; } -bool BKE_animsys_store_rna_setting(PointerRNA *ptr, - /* typically 'fcu->rna_path', 'fcu->array_index' */ - const char *rna_path, - const int array_index, - PathResolvedRNA *r_result) +bool BKE_animsys_rna_path_resolve(PointerRNA *ptr, + /* typically 'fcu->rna_path', 'fcu->array_index' */ + const char *rna_path, + const int array_index, + PathResolvedRNA *r_result) { - bool success = false; - const char *path = rna_path; + if (rna_path == NULL) { + return false; + } - /* write value to setting */ - if (path) { - /* get property to write to */ - if (RNA_path_resolve_property(ptr, path, &r_result->ptr, &r_result->prop)) { - if ((ptr->owner_id == NULL) || RNA_property_animateable(&r_result->ptr, r_result->prop)) { - int array_len = RNA_property_array_length(&r_result->ptr, r_result->prop); - - if (array_len && array_index >= array_len) { - if (G.debug & G_DEBUG) { - CLOG_WARN(&LOG, - "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d", - (ptr->owner_id) ? (ptr->owner_id->name + 2) : "<No ID>", - path, - array_index, - array_len - 1); - } - } - else { - r_result->prop_index = array_len ? array_index : -1; - success = true; - } - } + const char *path = rna_path; + if (!RNA_path_resolve_property(ptr, path, &r_result->ptr, &r_result->prop)) { + /* failed to get path */ + /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint) + * where some channels will not exist, but shouldn't lock up Action */ + if (G.debug & G_DEBUG) { + CLOG_WARN(&LOG, + "Animato: Invalid path. ID = '%s', '%s[%d]'", + (ptr->owner_id) ? (ptr->owner_id->name + 2) : "<No ID>", + path, + array_index); } - else { - /* failed to get path */ - /* XXX don't tag as failed yet though, as there are some legit situations (Action Constraint) - * where some channels will not exist, but shouldn't lock up Action */ - if (G.debug & G_DEBUG) { - CLOG_WARN(&LOG, - "Animato: Invalid path. ID = '%s', '%s[%d]'", - (ptr->owner_id) ? (ptr->owner_id->name + 2) : "<No ID>", - path, - array_index); - } + return false; + } + + if (ptr->owner_id != NULL && !RNA_property_animateable(&r_result->ptr, r_result->prop)) { + return false; + } + + int array_len = RNA_property_array_length(&r_result->ptr, r_result->prop); + if (array_len && array_index >= array_len) { + if (G.debug & G_DEBUG) { + CLOG_WARN(&LOG, + "Animato: Invalid array index. ID = '%s', '%s[%d]', array length is %d", + (ptr->owner_id) ? (ptr->owner_id->name + 2) : "<No ID>", + path, + array_index, + array_len - 1); } + return false; } - return success; + r_result->prop_index = array_len ? array_index : -1; + return true; } /* less than 1.0 evaluates to false, use epsilon to avoid float error */ #define ANIMSYS_FLOAT_AS_BOOL(value) ((value) > ((1.0f - FLT_EPSILON))) -bool BKE_animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value) +bool BKE_animsys_read_from_rna_path(PathResolvedRNA *anim_rna, float *r_value) { PropertyRNA *prop = anim_rna->prop; PointerRNA *ptr = &anim_rna->ptr; @@ -491,7 +488,7 @@ bool BKE_animsys_read_rna_setting(PathResolvedRNA *anim_rna, float *r_value) } /* Write the given value to a setting using RNA, and return success */ -bool BKE_animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value) +bool BKE_animsys_write_to_rna_path(PathResolvedRNA *anim_rna, const float value) { PropertyRNA *prop = anim_rna->prop; PointerRNA *ptr = &anim_rna->ptr; @@ -502,7 +499,7 @@ bool BKE_animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float value) /* Check whether value is new. Otherwise we skip all the updates. */ float old_value; - if (!BKE_animsys_read_rna_setting(anim_rna, &old_value)) { + if (!BKE_animsys_read_from_rna_path(anim_rna, &old_value)) { return false; } if (old_value == value) { @@ -591,8 +588,8 @@ static void animsys_write_orig_anim_rna(PointerRNA *ptr, } PathResolvedRNA orig_anim_rna; /* TODO(sergey): Should be possible to cache resolved path in dependency graph somehow. */ - if (BKE_animsys_store_rna_setting(&ptr_orig, rna_path, array_index, &orig_anim_rna)) { - BKE_animsys_write_rna_setting(&orig_anim_rna, value); + if (BKE_animsys_rna_path_resolve(&ptr_orig, rna_path, array_index, &orig_anim_rna)) { + BKE_animsys_write_to_rna_path(&orig_anim_rna, value); } } @@ -614,9 +611,9 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr, } PathResolvedRNA anim_rna; - if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_rna_path_resolve(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, anim_eval_context); - BKE_animsys_write_rna_setting(&anim_rna, curval); + BKE_animsys_write_to_rna_path(&anim_rna, curval); if (flush_to_original) { animsys_write_orig_anim_rna(ptr, fcu->rna_path, fcu->array_index, curval); } @@ -666,9 +663,9 @@ static void animsys_evaluate_drivers(PointerRNA *ptr, * NOTE: for 'layering' option later on, we should check if we should remove old value * before adding new to only be done when drivers only changed. */ PathResolvedRNA anim_rna; - if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_rna_path_resolve(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, anim_eval_context); - ok = BKE_animsys_write_rna_setting(&anim_rna, curval); + ok = BKE_animsys_write_to_rna_path(&anim_rna, curval); } /* set error-flag if evaluation failed */ @@ -747,19 +744,19 @@ void animsys_evaluate_action_group(PointerRNA *ptr, /* check if this curve should be skipped */ if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) == 0 && !BKE_fcurve_is_empty(fcu)) { PathResolvedRNA anim_rna; - if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_rna_path_resolve(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { const float curval = calculate_fcurve(&anim_rna, fcu, anim_eval_context); - BKE_animsys_write_rna_setting(&anim_rna, curval); + BKE_animsys_write_to_rna_path(&anim_rna, curval); } } } } /* Evaluate Action (F-Curve Bag) */ -static void animsys_evaluate_action_ex(PointerRNA *ptr, - bAction *act, - const AnimationEvalContext *anim_eval_context, - const bool flush_to_original) +void animsys_evaluate_action(PointerRNA *ptr, + bAction *act, + const AnimationEvalContext *anim_eval_context, + const bool flush_to_original) { /* check if mapper is appropriate for use here (we set to NULL if it's inappropriate) */ if (act == NULL) { @@ -772,14 +769,6 @@ static void animsys_evaluate_action_ex(PointerRNA *ptr, animsys_evaluate_fcurves(ptr, &act->curves, anim_eval_context, flush_to_original); } -void animsys_evaluate_action(PointerRNA *ptr, - bAction *act, - const AnimationEvalContext *anim_eval_context, - const bool flush_to_original) -{ - animsys_evaluate_action_ex(ptr, act, anim_eval_context, flush_to_original); -} - /* ***************************************** */ /* NLA System - Evaluation */ @@ -2008,7 +1997,7 @@ void nladata_flush_channels(PointerRNA *ptr, if (nec->is_array) { rna.prop_index = i; } - BKE_animsys_write_rna_setting(&rna, value); + BKE_animsys_write_to_rna_path(&rna, value); if (flush_to_original) { animsys_write_orig_anim_rna(ptr, nec->rna_path, rna.prop_index, value); } @@ -2769,8 +2758,8 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt) /* for each override, simply execute... */ for (aor = adt->overrides.first; aor; aor = aor->next) { PathResolvedRNA anim_rna; - if (BKE_animsys_store_rna_setting(ptr, aor->rna_path, aor->array_index, &anim_rna)) { - BKE_animsys_write_rna_setting(&anim_rna, aor->value); + if (BKE_animsys_rna_path_resolve(ptr, aor->rna_path, aor->array_index, &anim_rna)) { + BKE_animsys_write_to_rna_path(&anim_rna, aor->value); } } } @@ -2850,7 +2839,7 @@ void BKE_animsys_evaluate_animdata(ID *id, } /* evaluate Active Action only */ else if (adt->action) { - animsys_evaluate_action_ex(&id_ptr, adt->action, anim_eval_context, flush_to_original); + animsys_evaluate_action(&id_ptr, adt->action, anim_eval_context, flush_to_original); } } @@ -3100,13 +3089,13 @@ void BKE_animsys_eval_driver(Depsgraph *depsgraph, ID *id, int driver_index, FCu // printf("\told val = %f\n", fcu->curval); PathResolvedRNA anim_rna; - if (BKE_animsys_store_rna_setting(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { + if (BKE_animsys_rna_path_resolve(&id_ptr, fcu->rna_path, fcu->array_index, &anim_rna)) { /* Evaluate driver, and write results to COW-domain destination */ const float ctime = DEG_get_ctime(depsgraph); const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct( depsgraph, ctime); const float curval = calculate_fcurve(&anim_rna, fcu, &anim_eval_context); - ok = BKE_animsys_write_rna_setting(&anim_rna, curval); + ok = BKE_animsys_write_to_rna_path(&anim_rna, curval); /* Flush results & status codes to original data for UI (T59984) */ if (ok && DEG_is_active(depsgraph)) { diff --git a/source/blender/blenkernel/intern/armature_pose.cc b/source/blender/blenkernel/intern/armature_pose.cc new file mode 100644 index 00000000000..bb371b16c42 --- /dev/null +++ b/source/blender/blenkernel/intern/armature_pose.cc @@ -0,0 +1,133 @@ +/* + * 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) 2015 Blender Foundation. + * All rights reserved. + * + * Defines and code for core node types + */ + +/** \file + * \ingroup bke + */ + +#include "BKE_animsys.h" +#include "BKE_armature.h" + +#include "BLI_set.hh" + +#include "DNA_action_types.h" +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_object_types.h" + +#include "RNA_access.h" + +namespace { +using BoneNameSet = blender::Set<std::string>; + +// Forward declarations. +BoneNameSet pose_apply_find_selected_bones(const bPose *pose); +void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, + const BoneNameSet &selected_bone_names); +void pose_apply_restore_fcurves(bAction *action); +} // namespace + +void BKE_pose_apply_action(struct Object *ob, + struct bAction *action, + struct AnimationEvalContext *anim_eval_context) +{ + bPose *pose = ob->pose; + if (pose == nullptr) { + return; + } + + const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(pose); + const bool limit_to_selected_bones = !selected_bone_names.is_empty(); + + if (limit_to_selected_bones) { + /* Mute all FCurves that are not associated with selected bones. This separates the concept of + * bone selection from the FCurve evaluation code. */ + pose_apply_disable_fcurves_for_unselected_bones(action, selected_bone_names); + } + + /* Apply the Action. */ + PointerRNA pose_owner_ptr; + RNA_id_pointer_create(&ob->id, &pose_owner_ptr); + animsys_evaluate_action(&pose_owner_ptr, action, anim_eval_context, false); + + if (limit_to_selected_bones) { + pose_apply_restore_fcurves(action); + } +} + +namespace { +BoneNameSet pose_apply_find_selected_bones(const bPose *pose) +{ + BoneNameSet selected_bone_names; + bool all_bones_selected = true; + bool no_bones_selected = true; + + LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { + const bool is_selected = (pchan->bone->flag & BONE_SELECTED) != 0 && + (pchan->bone->flag & BONE_HIDDEN_P) == 0; + all_bones_selected &= is_selected; + no_bones_selected &= !is_selected; + + if (is_selected) { + /* Bone names are unique, so no need to check for duplicates. */ + selected_bone_names.add_new(pchan->name); + } + } + + /* If no bones are selected, act as if all are. */ + if (all_bones_selected || no_bones_selected) { + return BoneNameSet(); /* An empty set means "ignore bone selection". */ + } + return selected_bone_names; +} + +void pose_apply_restore_fcurves(bAction *action) +{ + /* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */ + LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { + fcu->flag &= ~FCURVE_DISABLED; + } +} + +void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, + const BoneNameSet &selected_bone_names) +{ + LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { + if (!fcu->rna_path || !strstr(fcu->rna_path, "pose.bones[")) { + continue; + } + + /* Get bone name, and check if this bone is selected. */ + char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + if (!bone_name) { + continue; + } + const bool is_selected = selected_bone_names.contains(bone_name); + MEM_freeN(bone_name); + if (is_selected) { + continue; + } + + fcu->flag |= FCURVE_DISABLED; + } +} + +} // namespace diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 8974190d0e3..61dc0903cc8 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -31,6 +31,7 @@ #include "BLI_color.hh" #include "BLI_float2.hh" #include "BLI_span.hh" +#include "BLI_threads.h" #include "CLG_log.h" @@ -712,11 +713,13 @@ struct CustomDataAccessInfo { class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); + using UpdateOnRead = void (*)(const GeometryComponent &component); using UpdateOnWrite = void (*)(GeometryComponent &component); const CustomDataType stored_type_; const CustomDataAccessInfo custom_data_access_; const AsReadAttribute as_read_attribute_; const AsWriteAttribute as_write_attribute_; + const UpdateOnRead update_on_read_; const UpdateOnWrite update_on_write_; public: @@ -730,6 +733,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { const CustomDataAccessInfo custom_data_access, const AsReadAttribute as_read_attribute, const AsWriteAttribute as_write_attribute, + const UpdateOnRead update_on_read, const UpdateOnWrite update_on_write) : BuiltinAttributeProvider( std::move(attribute_name), domain, attribute_type, creatable, writable, deletable), @@ -737,6 +741,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { custom_data_access_(custom_data_access), as_read_attribute_(as_read_attribute), as_write_attribute_(as_write_attribute), + update_on_read_(update_on_read), update_on_write_(update_on_write) { } @@ -747,6 +752,11 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { if (custom_data == nullptr) { return {}; } + + if (update_on_read_ != nullptr) { + update_on_read_(component); + } + const int domain_size = component.attribute_domain_size(domain_); const void *data = CustomData_get_layer(custom_data, stored_type_); if (data == nullptr) { @@ -1350,6 +1360,43 @@ static WriteAttributePtr make_material_index_write_attribute(void *data, const i ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size)); } +static float3 get_vertex_normal(const MVert &vert) +{ + float3 result; + normal_short_to_float_v3(result, vert.no); + return result; +} + +static ReadAttributePtr make_vertex_normal_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_normal>>( + ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size)); +} + +static void update_vertex_normals_when_dirty(const GeometryComponent &component) +{ + const Mesh *mesh = get_mesh_from_component_for_read(component); + if (mesh == nullptr) { + return; + } + + /* Since normals are derived data, `const` write access to them is okay. However, ensure that + * two threads don't use write normals to a mesh at the same time. Note that this relies on + * the idempotence of the operation; calculating the normals just fills the #MVert struct + * rather than allocating new memory. */ + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex; + BLI_mutex_lock(mesh_eval_mutex); + + /* Check again to avoid a second thread needlessly recalculating the same normals. */ + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + BKE_mesh_calc_normals(const_cast<Mesh *>(mesh)); + } + + BLI_mutex_unlock(mesh_eval_mutex); + } +} + static float2 get_loop_uv(const MLoopUV &uv) { return float2(uv.uv); @@ -1459,6 +1506,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() point_access, make_vertex_position_read_attribute, make_vertex_position_write_attribute, + nullptr, tag_normals_dirty_when_writing_position); static BuiltinCustomDataLayerProvider material_index("material_index", @@ -1471,8 +1519,22 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() polygon_access, make_material_index_read_attribute, make_material_index_write_attribute, + nullptr, nullptr); + static BuiltinCustomDataLayerProvider vertex_normal("vertex_normal", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_MVERT, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Readonly, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_vertex_normal_read_attribute, + nullptr, + update_vertex_normals_when_dirty, + nullptr); + static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, CD_MLOOPUV, @@ -1493,7 +1555,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); - return ComponentAttributeProviders({&position, &material_index}, + return ComponentAttributeProviders({&position, &material_index, &vertex_normal}, {&uvs, &vertex_colors, &corner_custom_data, @@ -1541,6 +1603,7 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud() point_access, make_array_read_attribute<float3, ATTR_DOMAIN_POINT>, make_array_write_attribute<float3, ATTR_DOMAIN_POINT>, + nullptr, nullptr); static BuiltinCustomDataLayerProvider radius( "radius", @@ -1553,6 +1616,7 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud() point_access, make_array_read_attribute<float, ATTR_DOMAIN_POINT>, make_array_write_attribute<float, ATTR_DOMAIN_POINT>, + nullptr, nullptr); static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); return ComponentAttributeProviders({&position, &radius}, {&point_custom_data}); @@ -1886,7 +1950,7 @@ OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringR if (!attribute) { this->attribute_try_create(attribute_name, domain, data_type); attribute = this->attribute_try_get_for_write(attribute_name); - if (default_value != nullptr) { + if (attribute && default_value != nullptr) { void *data = attribute->get_span_for_write_only().data(); cpp_type->fill_initialized(default_value, data, attribute->size()); attribute->apply_span(); diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 32710c4fa60..101f4b7caf6 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -865,7 +865,7 @@ bool BKE_blendfile_write_partial(Main *bmain_src, ReportList *reports) { Main *bmain_dst = MEM_callocN(sizeof(Main), "copybuffer"); - ListBase *lbarray_dst[MAX_LIBARRAY], *lbarray_src[MAX_LIBARRAY]; + ListBase *lbarray_dst[INDEX_ID_MAX], *lbarray_src[INDEX_ID_MAX]; int a, retval; void *path_list_backup = NULL; diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 2ad0ac950d0..47427beccba 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -783,7 +783,7 @@ void BKE_bpath_traverse_main(Main *bmain, const int flag, void *bpath_user_data) { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int a = set_listbasepointers(bmain, lbarray); while (a--) { BKE_bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data); diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 3eb9fb6161d..44d9bd6b2d2 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -965,6 +965,12 @@ void BKE_curvemapping_changed_all(CurveMapping *cumap) cumap->cur = cur; } +/* Reset the view for current curve. */ +void BKE_curvemapping_reset_view(CurveMapping *cumap) +{ + cumap->curr = cumap->clipr; +} + /* table should be verified */ float BKE_curvemap_evaluateF(const CurveMapping *cumap, const CurveMap *cuma, float value) { diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc index 42158dced96..9d9cace3a35 100644 --- a/source/blender/blenkernel/intern/cryptomatte.cc +++ b/source/blender/blenkernel/intern/cryptomatte.cc @@ -37,6 +37,8 @@ #include "BLI_listbase.h" #include "BLI_string.h" +#include "RE_pipeline.h" + #include "MEM_guardedalloc.h" #include <cctype> @@ -47,13 +49,13 @@ #include <string_view> struct CryptomatteSession { - blender::bke::cryptomatte::CryptomatteLayer objects; - blender::bke::cryptomatte::CryptomatteLayer assets; - blender::bke::cryptomatte::CryptomatteLayer materials; + blender::Map<std::string, blender::bke::cryptomatte::CryptomatteLayer> layers; CryptomatteSession(); CryptomatteSession(const Main *bmain); + CryptomatteSession(StampData *stamp_data); + blender::bke::cryptomatte::CryptomatteLayer &add_layer(std::string layer_name); std::optional<std::string> operator[](float encoded_hash) const; #ifdef WITH_CXX_GUARDEDALLOC @@ -67,21 +69,50 @@ CryptomatteSession::CryptomatteSession() CryptomatteSession::CryptomatteSession(const Main *bmain) { - LISTBASE_FOREACH (ID *, id, &bmain->objects) { - objects.add_ID(*id); + if (!BLI_listbase_is_empty(&bmain->objects)) { + blender::bke::cryptomatte::CryptomatteLayer &objects = add_layer("CryptoObject"); + LISTBASE_FOREACH (ID *, id, &bmain->objects) { + objects.add_ID(*id); + } } - LISTBASE_FOREACH (ID *, id, &bmain->materials) { - materials.add_ID(*id); + if (!BLI_listbase_is_empty(&bmain->materials)) { + blender::bke::cryptomatte::CryptomatteLayer &materials = add_layer("CryptoMaterial"); + LISTBASE_FOREACH (ID *, id, &bmain->materials) { + materials.add_ID(*id); + } } } +CryptomatteSession::CryptomatteSession(StampData *stamp_data) +{ + blender::bke::cryptomatte::CryptomatteStampDataCallbackData callback_data; + callback_data.session = this; + BKE_stamp_info_callback( + &callback_data, + stamp_data, + blender::bke::cryptomatte::CryptomatteStampDataCallbackData::extract_layer_names, + false); + BKE_stamp_info_callback( + &callback_data, + stamp_data, + blender::bke::cryptomatte::CryptomatteStampDataCallbackData::extract_layer_manifest, + false); +} + +blender::bke::cryptomatte::CryptomatteLayer &CryptomatteSession::add_layer(std::string layer_name) +{ + return layers.lookup_or_add_default(layer_name); +} + std::optional<std::string> CryptomatteSession::operator[](float encoded_hash) const { - std::optional<std::string> result = objects[encoded_hash]; - if (result) { - return result; + for (const blender::bke::cryptomatte::CryptomatteLayer &layer : layers.values()) { + std::optional<std::string> result = layer[encoded_hash]; + if (result) { + return result; + } } - return materials[encoded_hash]; + return std::nullopt; } CryptomatteSession *BKE_cryptomatte_init(void) @@ -90,6 +121,18 @@ CryptomatteSession *BKE_cryptomatte_init(void) return session; } +struct CryptomatteSession *BKE_cryptomatte_init_from_render_result( + const struct RenderResult *render_result) +{ + CryptomatteSession *session = new CryptomatteSession(render_result->stamp_data); + return session; +} + +void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name) +{ + session->add_layer(layer_name); +} + void BKE_cryptomatte_free(CryptomatteSession *session) { BLI_assert(session != nullptr); @@ -102,26 +145,36 @@ uint32_t BKE_cryptomatte_hash(const char *name, const int name_len) return hash.hash; } -uint32_t BKE_cryptomatte_object_hash(CryptomatteSession *session, const Object *object) +uint32_t BKE_cryptomatte_object_hash(CryptomatteSession *session, + const char *layer_name, + const Object *object) { - return session->objects.add_ID(object->id); + blender::bke::cryptomatte::CryptomatteLayer *layer = session->layers.lookup_ptr(layer_name); + BLI_assert(layer); + return layer->add_ID(object->id); } -uint32_t BKE_cryptomatte_material_hash(CryptomatteSession *session, const Material *material) +uint32_t BKE_cryptomatte_material_hash(CryptomatteSession *session, + const char *layer_name, + const Material *material) { if (material == nullptr) { return 0.0f; } - return session->materials.add_ID(material->id); + blender::bke::cryptomatte::CryptomatteLayer *layer = session->layers.lookup_ptr(layer_name); + BLI_assert(layer); + return layer->add_ID(material->id); } -uint32_t BKE_cryptomatte_asset_hash(CryptomatteSession *session, const Object *object) +uint32_t BKE_cryptomatte_asset_hash(CryptomatteSession *session, + const char *layer_name, + const Object *object) { const Object *asset_object = object; while (asset_object->parent != nullptr) { asset_object = asset_object->parent; } - return session->assets.add_ID(asset_object->id); + return BKE_cryptomatte_object_hash(session, layer_name, asset_object); } float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash) @@ -131,22 +184,30 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash) char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage) { - DynStr *matte_id = BLI_dynstr_new(); + std::stringstream ss; + ss.precision(9); + bool first = true; LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) { if (!first) { - BLI_dynstr_append(matte_id, ","); + ss << ','; } - if (BLI_strnlen(entry->name, sizeof(entry->name)) != 0) { - BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name)); + blender::StringRef entry_name(entry->name, BLI_strnlen(entry->name, sizeof(entry->name))); + if (!entry_name.is_empty()) { + ss << entry_name; } else { - BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash); + ss << '<' << std::scientific << entry->encoded_hash << '>'; } first = false; } - char *result = BLI_dynstr_get_cstring(matte_id); - BLI_dynstr_free(matte_id); + + /* Convert result to C string. */ + const std::string result_string = ss.str(); + const char *c_str = result_string.c_str(); + size_t result_len = result_string.size() + 1; + char *result = static_cast<char *>(MEM_mallocN(sizeof(char) * result_len, __func__)); + memcpy(result, c_str, result_len); return result; } @@ -213,37 +274,23 @@ static void add_render_result_meta_data(RenderResult *render_result, value.data()); } -void BKE_cryptomatte_store_metadata(struct CryptomatteSession *session, +void BKE_cryptomatte_store_metadata(const struct CryptomatteSession *session, RenderResult *render_result, - const ViewLayer *view_layer, - eViewLayerCryptomatteFlags cryptomatte_layer, - const char *cryptomatte_layer_name) -{ - /* Create Manifest. */ - blender::bke::cryptomatte::CryptomatteLayer *layer = nullptr; - switch (cryptomatte_layer) { - case VIEW_LAYER_CRYPTOMATTE_OBJECT: - layer = &session->objects; - break; - case VIEW_LAYER_CRYPTOMATTE_MATERIAL: - layer = &session->materials; - break; - case VIEW_LAYER_CRYPTOMATTE_ASSET: - layer = &session->assets; - break; - default: - BLI_assert(!"Incorrect cryptomatte layer"); - break; - } + const ViewLayer *view_layer) +{ + for (const blender::Map<std::string, blender::bke::cryptomatte::CryptomatteLayer>::Item item : + session->layers.items()) { + const blender::StringRefNull layer_name(item.key); + const blender::bke::cryptomatte::CryptomatteLayer &layer = item.value; - const std::string manifest = layer->manifest(); - const std::string name = cryptomatte_determine_name(view_layer, cryptomatte_layer_name); + const std::string manifest = layer.manifest(); + const std::string name = cryptomatte_determine_name(view_layer, layer_name); - /* Store the meta data into the render result. */ - add_render_result_meta_data(render_result, name, "name", name); - add_render_result_meta_data(render_result, name, "hash", "MurmurHash3_32"); - add_render_result_meta_data(render_result, name, "conversion", "uint32_to_float32"); - add_render_result_meta_data(render_result, name, "manifest", manifest); + add_render_result_meta_data(render_result, name, "name", name); + add_render_result_meta_data(render_result, name, "hash", "MurmurHash3_32"); + add_render_result_meta_data(render_result, name, "conversion", "uint32_to_float32"); + add_render_result_meta_data(render_result, name, "manifest", manifest); + } } namespace blender::bke::cryptomatte { @@ -253,6 +300,9 @@ constexpr StringRef WHITESPACES = " \t\n\v\f\r"; static constexpr blender::StringRef skip_whitespaces_(blender::StringRef ref) { size_t skip = ref.find_first_not_of(WHITESPACES); + if (skip == blender::StringRef::not_found) { + return ref; + } return ref.drop_prefix(skip); } @@ -450,7 +500,7 @@ std::unique_ptr<CryptomatteLayer> CryptomatteLayer::read_from_manifest( blender::StringRefNull manifest) { std::unique_ptr<CryptomatteLayer> layer = std::make_unique<CryptomatteLayer>(); - blender::bke::cryptomatte::manifest::from_manifest(*layer.get(), manifest); + blender::bke::cryptomatte::manifest::from_manifest(*layer, manifest); return layer; } @@ -481,9 +531,70 @@ std::optional<std::string> CryptomatteLayer::operator[](float encoded_hash) cons return std::nullopt; } -std::string CryptomatteLayer::manifest() +std::string CryptomatteLayer::manifest() const { return blender::bke::cryptomatte::manifest::to_manifest(this); } +blender::StringRef CryptomatteStampDataCallbackData::extract_layer_hash(blender::StringRefNull key) +{ + BLI_assert(key.startswith("cryptomatte/")); + + size_t start_index = key.find_first_of('/'); + size_t end_index = key.find_last_of('/'); + if (start_index == blender::StringRef::not_found) { + return ""; + } + if (end_index == blender::StringRef::not_found) { + return ""; + } + if (end_index <= start_index) { + return ""; + } + return key.substr(start_index + 1, end_index - start_index - 1); +} + +void CryptomatteStampDataCallbackData::extract_layer_names(void *_data, + const char *propname, + char *propvalue, + int UNUSED(len)) +{ + CryptomatteStampDataCallbackData *data = static_cast<CryptomatteStampDataCallbackData *>(_data); + + blender::StringRefNull key(propname); + if (!key.startswith("cryptomatte/")) { + return; + } + if (!key.endswith("/name")) { + return; + } + blender::StringRef layer_hash = extract_layer_hash(key); + data->hash_to_layer_name.add(layer_hash, propvalue); +} + +/* C type callback function (StampCallback). */ +void CryptomatteStampDataCallbackData::extract_layer_manifest(void *_data, + const char *propname, + char *propvalue, + int UNUSED(len)) +{ + CryptomatteStampDataCallbackData *data = static_cast<CryptomatteStampDataCallbackData *>(_data); + + blender::StringRefNull key(propname); + if (!key.startswith("cryptomatte/")) { + return; + } + if (!key.endswith("/manifest")) { + return; + } + blender::StringRef layer_hash = extract_layer_hash(key); + if (!data->hash_to_layer_name.contains(layer_hash)) { + return; + } + + blender::StringRef layer_name = data->hash_to_layer_name.lookup(layer_hash); + blender::bke::cryptomatte::CryptomatteLayer &layer = data->session->add_layer(layer_name); + blender::bke::cryptomatte::manifest::from_manifest(layer, propvalue); +} + } // namespace blender::bke::cryptomatte diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc index 4a25f5f7d87..5481b97913c 100644 --- a/source/blender/blenkernel/intern/cryptomatte_test.cc +++ b/source/blender/blenkernel/intern/cryptomatte_test.cc @@ -17,7 +17,15 @@ */ #include "testing/testing.h" +#include "BKE_cryptomatte.h" #include "BKE_cryptomatte.hh" +#include "BKE_image.h" + +#include "DNA_node_types.h" + +#include "RE_pipeline.h" + +#include "MEM_guardedalloc.h" namespace blender::bke::cryptomatte::tests { @@ -41,7 +49,7 @@ TEST(cryptomatte, extract_layer_name) ASSERT_EQ("", BKE_cryptomatte_extract_layer_name("")); } -TEST(cryptomatte, cryptomatte_layer) +TEST(cryptomatte, layer) { blender::bke::cryptomatte::CryptomatteLayer layer; ASSERT_EQ("{}", layer.manifest()); @@ -53,7 +61,7 @@ TEST(cryptomatte, cryptomatte_layer) ASSERT_EQ("{\"Object\":\"0000007b\",\"Object2\":\"0758946e\"}", layer.manifest()); } -TEST(cryptomatte, cryptomatte_layer_quoted) +TEST(cryptomatte, layer_quoted) { blender::bke::cryptomatte::CryptomatteLayer layer; layer.add_hash("\"Object\"", 123); @@ -66,7 +74,7 @@ static void test_cryptomatte_manifest(std::string expected, std::string manifest blender::bke::cryptomatte::CryptomatteLayer::read_from_manifest(manifest)->manifest()); } -TEST(cryptomatte, cryptomatte_layer_from_manifest) +TEST(cryptomatte, layer_from_manifest) { test_cryptomatte_manifest("{}", "{}"); test_cryptomatte_manifest("{\"Object\":\"12345678\"}", "{\"Object\": \"12345678\"}"); @@ -82,4 +90,103 @@ TEST(cryptomatte, cryptomatte_layer_from_manifest) "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\", \"Object2\":\"87654321\"}"); } +TEST(cryptomatte, extract_layer_hash_from_metadata_key) +{ + EXPECT_EQ("eb4c67b", + blender::bke::cryptomatte::CryptomatteStampDataCallbackData::extract_layer_hash( + "cryptomatte/eb4c67b/conversion")); + EXPECT_EQ("qwerty", + blender::bke::cryptomatte::CryptomatteStampDataCallbackData::extract_layer_hash( + "cryptomatte/qwerty/name")); + /* Check if undefined behaviors are handled. */ + EXPECT_EQ("", + blender::bke::cryptomatte::CryptomatteStampDataCallbackData::extract_layer_hash( + "cryptomatte/name")); + EXPECT_EQ("", + blender::bke::cryptomatte::CryptomatteStampDataCallbackData::extract_layer_hash( + "cryptomatte/")); +} + +static void validate_cryptomatte_session_from_stamp_data(void *UNUSED(data), + const char *propname, + char *propvalue, + int UNUSED(len)) +{ + blender::StringRefNull prop_name(propname); + if (!prop_name.startswith("cryptomatte/")) { + return; + } + + if (prop_name == "cryptomatte/87f095e/name") { + EXPECT_STREQ("viewlayername.layer1", propvalue); + } + else if (prop_name == "cryptomatte/87f095e/hash") { + EXPECT_STREQ("MurmurHash3_32", propvalue); + } + else if (prop_name == "cryptomatte/87f095e/conversion") { + EXPECT_STREQ("uint32_to_float32", propvalue); + } + else if (prop_name == "cryptomatte/87f095e/manifest") { + EXPECT_STREQ("{\"Object\":\"12345678\"}", propvalue); + } + + else if (prop_name == "cryptomatte/c42daa7/name") { + EXPECT_STREQ("viewlayername.layer2", propvalue); + } + else if (prop_name == "cryptomatte/c42daa7/hash") { + EXPECT_STREQ("MurmurHash3_32", propvalue); + } + else if (prop_name == "cryptomatte/c42daa7/conversion") { + EXPECT_STREQ("uint32_to_float32", propvalue); + } + else if (prop_name == "cryptomatte/c42daa7/manifest") { + EXPECT_STREQ("{\"Object2\":\"87654321\"}", propvalue); + } + + else { + EXPECT_EQ("Unhandled", std::string(propname) + ": " + propvalue); + } +} + +TEST(cryptomatte, session_from_stamp_data) +{ + /* Create CryptomatteSession from stamp data. */ + RenderResult *render_result = static_cast<RenderResult *>( + MEM_callocN(sizeof(RenderResult), __func__)); + BKE_render_result_stamp_data(render_result, "cryptomatte/qwerty/name", "layer1"); + BKE_render_result_stamp_data( + render_result, "cryptomatte/qwerty/manifest", "{\"Object\":\"12345678\"}"); + BKE_render_result_stamp_data(render_result, "cryptomatte/uiop/name", "layer2"); + BKE_render_result_stamp_data( + render_result, "cryptomatte/uiop/manifest", "{\"Object2\":\"87654321\"}"); + CryptomatteSession *session = BKE_cryptomatte_init_from_render_result(render_result); + EXPECT_NE(session, nullptr); + RE_FreeRenderResult(render_result); + + /* Create StampData from CryptomatteSession. */ + ViewLayer view_layer; + BLI_strncpy(view_layer.name, "viewlayername", sizeof(view_layer.name)); + RenderResult *render_result2 = static_cast<RenderResult *>( + MEM_callocN(sizeof(RenderResult), __func__)); + BKE_cryptomatte_store_metadata(session, render_result2, &view_layer); + + /* Validate StampData. */ + BKE_stamp_info_callback( + nullptr, render_result2->stamp_data, validate_cryptomatte_session_from_stamp_data, false); + + RE_FreeRenderResult(render_result2); + BKE_cryptomatte_free(session); +} + +TEST(cryptomatte, T86026) +{ + NodeCryptomatte storage = {{0.0f}}; + CryptomatteEntry entry = {nullptr}; + BLI_addtail(&storage.entries, &entry); + entry.encoded_hash = 4.76190593e-07; + char *matte_id = BKE_cryptomatte_entries_to_matte_id(&storage); + EXPECT_STREQ("<4.761905927e-07>", matte_id); + MEM_freeN(matte_id); +} + } // namespace blender::bke::cryptomatte::tests diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 1a260c5d48e..6c4c3231667 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -378,7 +378,8 @@ static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups, /* Don't copy attributes that are stored directly in the mesh data structs. */ Map<std::string, AttributeKind> attributes; - gather_attribute_info(attributes, component_types, set_groups, {"position", "material_index"}); + gather_attribute_info( + attributes, component_types, set_groups, {"position", "material_index", "vertex_normal"}); join_attributes( set_groups, component_types, attributes, static_cast<GeometryComponent &>(dst_component)); } diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c index 1889d1c4eb0..fee70922570 100644 --- a/source/blender/blenkernel/intern/idtype.c +++ b/source/blender/blenkernel/intern/idtype.c @@ -63,7 +63,7 @@ bool BKE_idtype_cache_key_cmp(const void *key_a_v, const void *key_b_v) (key_a->offset_in_ID != key_b->offset_in_ID) || (key_a->cache_v != key_b->cache_v); } -static IDTypeInfo *id_types[MAX_LIBARRAY] = {NULL}; +static IDTypeInfo *id_types[INDEX_ID_MAX] = {NULL}; static void id_type_init(void) { diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 54c2f5f5565..a511c1f9c4c 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -916,7 +916,7 @@ void BKE_main_id_tag_idcode(struct Main *mainvar, */ void BKE_main_id_tag_all(struct Main *mainvar, const int tag, const bool value) { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int a; a = set_listbasepointers(mainvar, lbarray); @@ -949,7 +949,7 @@ void BKE_main_id_flag_listbase(ListBase *lb, const int flag, const bool value) */ void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value) { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int a; a = set_listbasepointers(bmain, lbarray); while (a--) { @@ -1870,7 +1870,7 @@ void BKE_library_make_local(Main *bmain, const bool untagged_only, const bool set_fake) { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; LinkNode *todo_ids = NULL; LinkNode *copied_ids = NULL; diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index 7c5032c97f4..1d7f89e1e8d 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -240,7 +240,7 @@ void BKE_id_free_us(Main *bmain, void *idv) /* test users */ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) { const int tag = LIB_TAG_DOIT; - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; Link dummy_link = {0}; int base_count, i; diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index eaf1e2d46e6..acd0c10040c 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -46,7 +46,7 @@ enum { typedef struct LibraryForeachIDData { Main *bmain; /** - * 'Real' ID, the one that might be in bmain, only differs from self_id when the later is a + * 'Real' ID, the one that might be in `bmain`, only differs from self_id when the later is a * private one. */ ID *owner_id; @@ -137,7 +137,7 @@ void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) { - /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */ + /* Needed e.g. for callbacks handling relationships. This call shall be absolutely read-only. */ ID *id = *id_pp; const int flag = data->flag; @@ -215,7 +215,7 @@ static void library_foreach_ID_link(Main *bmain, data.self_id; /* inherit_data is non-NULL when this function is called for some sub-data ID - * (like root nodetree of a material). + * (like root node-tree of a material). * In that case, we do not want to generate those 'generic flags' from our current sub-data ID * (the node tree), but re-use those generated for the 'owner' ID (the material). */ if (inherit_data == NULL) { @@ -440,7 +440,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) typedef struct IDUsersIter { ID *id; - ListBase *lb_array[MAX_LIBARRAY]; + ListBase *lb_array[INDEX_ID_MAX]; int lb_idx; ID *curr_id; @@ -514,7 +514,7 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used) static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked) { IDUsersIter iter; - ListBase *lb_array[MAX_LIBARRAY]; + ListBase *lb_array[INDEX_ID_MAX]; ID *id = idv; int i = set_listbasepointers(bmain, lb_array); bool is_defined = false; @@ -567,7 +567,7 @@ bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv) void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked) { IDUsersIter iter; - ListBase *lb_array[MAX_LIBARRAY]; + ListBase *lb_array[INDEX_ID_MAX]; ID *id = idv; int i = set_listbasepointers(bmain, lb_array); bool is_defined = false; @@ -632,7 +632,7 @@ static void lib_query_unused_ids_tag_recurse(Main *bmain, if (ELEM(GS(id->name), ID_WM, ID_WS, ID_SCE, ID_SCR, ID_LI)) { /* Some 'root' ID types are never unused (even though they may not have actual users), unless - * their actual usercount is set to 0. */ + * their actual user-count is set to 0. */ return; } @@ -683,7 +683,7 @@ static void lib_query_unused_ids_tag_recurse(Main *bmain, * * By default only tag IDs with `0` user count. * If `do_tag_recursive` is set, it will check dependencies to detect all IDs that are not actually - * used in current file, including 'archipelagoes` (i.e. set of IDs referencing each other in + * used in current file, including 'archipelagos` (i.e. set of IDs referencing each other in * loops, but without any 'external' valid usages. * * Valid usages here are defined as ref-counting usages, which are not towards embedded or @@ -700,7 +700,7 @@ void BKE_lib_query_unused_ids_tag(Main *bmain, const bool do_tag_recursive, int *r_num_tagged) { - /* First loop, to only check for immediatly unused IDs (those with 0 user count). + /* First loop, to only check for immediately unused IDs (those with 0 user count). * NOTE: It also takes care of clearing given tag for used IDs. */ ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { @@ -805,7 +805,7 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag) */ void BKE_library_indirectly_used_data_tag_clear(Main *bmain) { - ListBase *lb_array[MAX_LIBARRAY]; + ListBase *lb_array[INDEX_ID_MAX]; bool do_loop = true; while (do_loop) { diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c index 6f94b3355fa..d1f34ad8ce9 100644 --- a/source/blender/blenkernel/intern/main.c +++ b/source/blender/blenkernel/intern/main.c @@ -53,7 +53,7 @@ Main *BKE_main_new(void) void BKE_main_free(Main *mainvar) { /* also call when reading a file, erase all, etc */ - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int a; /* Since we are removing whole main, no need to bother 'properly' @@ -532,18 +532,17 @@ ListBase *which_libbase(Main *bmain, short type) } /** - * puts into array *lb pointers to all the #ListBase structs in main, - * and returns the number of them as the function result. This is useful for - * generic traversal of all the blocks in a Main (by traversing all the - * lists in turn), without worrying about block types. + * Put the pointers to all the #ListBase structs in given `bmain` into the `*lb[INDEX_ID_MAX]` + * array, and return the number of those for convenience. * - * \note #MAX_LIBARRAY define should match this code */ -int set_listbasepointers(Main *bmain, ListBase **lb) + * This is useful for generic traversal of all the blocks in a #Main (by traversing all the lists + * in turn), without worrying about block types. + * + * \note The order of each ID type #ListBase in the array is determined by the `INDEX_ID_<IDTYPE>` + * enum definitions in `DNA_ID.h`. See also the #FOREACH_MAIN_ID_BEGIN macro in `BKE_main.h` + */ +int set_listbasepointers(Main *bmain, ListBase *lb[INDEX_ID_MAX]) { - /* BACKWARDS! also watch order of free-ing! (mesh<->mat), first items freed last. - * This is important because freeing data decreases user-counts of other data-blocks, - * if this data is its self freed it can crash. */ - /* Libraries may be accessed from pretty much any other ID. */ lb[INDEX_ID_LI] = &(bmain->libraries); @@ -606,5 +605,5 @@ int set_listbasepointers(Main *bmain, ListBase **lb) lb[INDEX_ID_NULL] = NULL; - return (MAX_LIBARRAY - 1); + return (INDEX_ID_MAX - 1); } diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c index 21f5e9c6fb2..1d362db4432 100644 --- a/source/blender/blenkernel/intern/main_idmap.c +++ b/source/blender/blenkernel/intern/main_idmap.c @@ -66,7 +66,7 @@ struct IDNameLib_TypeMap { * Opaque structure, external API users only see this. */ struct IDNameLib_Map { - struct IDNameLib_TypeMap type_maps[MAX_LIBARRAY]; + struct IDNameLib_TypeMap type_maps[INDEX_ID_MAX]; struct GHash *uuid_map; struct Main *bmain; struct GSet *valid_id_pointers; @@ -77,7 +77,7 @@ static struct IDNameLib_TypeMap *main_idmap_from_idcode(struct IDNameLib_Map *id short id_type) { if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) { - for (int i = 0; i < MAX_LIBARRAY; i++) { + for (int i = 0; i < INDEX_ID_MAX; i++) { if (id_map->type_maps[i].id_type == id_type) { return &id_map->type_maps[i]; } @@ -108,13 +108,13 @@ struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain, id_map->idmap_types = idmap_types; int index = 0; - while (index < MAX_LIBARRAY) { + while (index < INDEX_ID_MAX) { struct IDNameLib_TypeMap *type_map = &id_map->type_maps[index]; type_map->map = NULL; type_map->id_type = BKE_idtype_idcode_iter_step(&index); BLI_assert(type_map->id_type != 0); } - BLI_assert(index == MAX_LIBARRAY); + BLI_assert(index == INDEX_ID_MAX); if (idmap_types & MAIN_IDMAP_TYPE_UUID) { ID *id; @@ -231,7 +231,7 @@ void BKE_main_idmap_destroy(struct IDNameLib_Map *id_map) { if (id_map->idmap_types & MAIN_IDMAP_TYPE_NAME) { struct IDNameLib_TypeMap *type_map = id_map->type_maps; - for (int i = 0; i < MAX_LIBARRAY; i++, type_map++) { + for (int i = 0; i < INDEX_ID_MAX; i++, type_map++) { if (type_map->map) { BLI_ghash_free(type_map->map, NULL, NULL); type_map->map = NULL; diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index 299b1ff1c71..a179d39a9d2 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -32,6 +32,7 @@ #include "BLI_alloca.h" #include "BLI_float2.hh" +#include "BLI_float4x4.hh" #include "BLI_math.h" #include "BLI_mesh_boolean.hh" #include "BLI_mesh_intersect.hh" @@ -50,12 +51,12 @@ constexpr int estimated_max_facelen = 100; /* Used for initial size of some Vect * so this is a hack to clean up such matrices. * Would be better to change the transformation code itself. */ -static void clean_obmat(float cleaned[4][4], const float mat[4][4]) +static void clean_obmat(float4x4 &cleaned, const float4x4 &mat) { const float fuzz = 1e-6f; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - float f = mat[i][j]; + float f = mat.values[i][j]; if (fabsf(f) <= fuzz) { f = 0.0f; } @@ -65,17 +66,11 @@ static void clean_obmat(float cleaned[4][4], const float mat[4][4]) else if (fabsf(f + 1.0f) <= fuzz) { f = -1.0f; } - cleaned[i][j] = f; + cleaned.values[i][j] = f; } } } -/* Need to wrap this in a class to use it in an Array. */ -class TransMat { - public: - float mat[4][4]; -}; - /* `MeshesToIMeshInfo` keeps track of information used when combining a number * of `Mesh`es into a single `IMesh` for doing boolean on. * Mostly this means keeping track of the index offsets for various mesh elements. */ @@ -97,7 +92,7 @@ class MeshesToIMeshInfo { Array<Face *> mesh_to_imesh_face; /* Transformation matrix to transform a coordinate in the corresponding * Mesh to the local space of the first Mesh. */ - Array<TransMat> to_obj0; + Array<float4x4> to_obj0; /* Total number of input mesh vertices. */ int tot_meshes_verts; /* Total number of input mesh edges. */ @@ -242,7 +237,7 @@ const MEdge *MeshesToIMeshInfo::input_medge_for_orig_index(int orig_index, * All allocation of memory for the IMesh comes from `arena`. */ static IMesh meshes_to_imesh(Span<const Mesh *> meshes, - const float (*obmats[])[4][4], + Span<const float4x4 *> obmats, IMeshArena &arena, MeshesToIMeshInfo *r_info) { @@ -271,7 +266,7 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes, r_info->mesh_vert_offset = Array<int>(nmeshes); r_info->mesh_edge_offset = Array<int>(nmeshes); r_info->mesh_poly_offset = Array<int>(nmeshes); - r_info->to_obj0 = Array<TransMat>(nmeshes); + r_info->to_obj0 = Array<float4x4>(nmeshes); int v = 0; int e = 0; int f = 0; @@ -286,15 +281,15 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes, * of object 0, we multiply each object's `obmat` by the inverse of * object 0's `obmat`. Exact Boolean works better if these matrices * are 'cleaned' -- see the comment for the `clean_obmat` function, above. */ - float obj0_mat[4][4]; - float inv_obj0_mat[4][4]; + float4x4 obj0_mat; + float4x4 inv_obj0_mat; if (obmats[0] == nullptr) { - unit_m4(obj0_mat); - unit_m4(inv_obj0_mat); + unit_m4(obj0_mat.values); + unit_m4(inv_obj0_mat.values); } else { clean_obmat(obj0_mat, *obmats[0]); - invert_m4_m4(inv_obj0_mat, obj0_mat); + invert_m4_m4(inv_obj0_mat.values, obj0_mat.values); } /* For each input `Mesh`, make `Vert`s and `Face`s for the corresponding @@ -303,13 +298,13 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes, * When making `Face`s, we also put in the original indices for `MEdge`s that * make up the `MPoly`s using the same scheme. */ for (int mi : meshes.index_range()) { - float objn_to_obj0_mat[4][4]; + float4x4 objn_to_obj0_mat; const Mesh *me = meshes[mi]; if (mi == 0) { r_info->mesh_vert_offset[mi] = 0; r_info->mesh_edge_offset[mi] = 0; r_info->mesh_poly_offset[mi] = 0; - unit_m4(r_info->to_obj0[0].mat); + unit_m4(r_info->to_obj0[0].values); } else { r_info->mesh_vert_offset[mi] = v; @@ -317,23 +312,22 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes, r_info->mesh_poly_offset[mi] = f; /* Get matrix that transforms a coordinate in objects[mi]'s local space * to object[0]'s local space.*/ - float objn_mat[4][4]; + float4x4 objn_mat; if (obmats[mi] == nullptr) { - unit_m4(objn_mat); + unit_m4(objn_mat.values); } else { clean_obmat(objn_mat, *obmats[mi]); } - mul_m4_m4m4(objn_to_obj0_mat, inv_obj0_mat, objn_mat); - copy_m4_m4(r_info->to_obj0[mi].mat, objn_to_obj0_mat); + objn_to_obj0_mat = inv_obj0_mat * objn_mat; + r_info->to_obj0[mi] = objn_to_obj0_mat; } for (int vi = 0; vi < me->totvert; ++vi) { - float co[3]; - copy_v3_v3(co, me->mvert[vi].co); + float3 co = me->mvert[vi].co; if (mi > 0) { - mul_m4_v3(objn_to_obj0_mat, co); + co = objn_to_obj0_mat * co; } - r_info->mesh_to_imesh_vert[v] = arena.add_or_find_vert(mpq3(co[0], co[1], co[2]), v); + r_info->mesh_to_imesh_vert[v] = arena.add_or_find_vert(mpq3(co.x, co.y, co.z), v); ++v; } for (const MPoly &poly : Span(me->mpoly, me->totpoly)) { @@ -534,7 +528,7 @@ static int fill_orig_loops(const Face *f, static void get_poly2d_cos(const Mesh *me, const MPoly *mp, float (*cos_2d)[2], - const TransMat &trans_mat, + const float4x4 &trans_mat, float r_axis_mat[3][3]) { int n = mp->totloop; @@ -546,9 +540,8 @@ static void get_poly2d_cos(const Mesh *me, MLoop *ml = &me->mloop[mp->loopstart]; const MVert *mverts = me->mvert; for (int i = 0; i < n; ++i) { - float co[3]; - copy_v3_v3(co, mverts[ml->v].co); - mul_m4_v3(trans_mat.mat, co); + float3 co = mverts[ml->v].co; + co = trans_mat * co; mul_v2_m3v3(cos_2d[i], r_axis_mat, co); ++ml; } @@ -618,6 +611,9 @@ static void copy_or_interp_loop_attributes(Mesh *dest_mesh, * A non bmesh version could have the benefit of not copying data into src_blocks_ofs - * using the contiguous data instead. TODO: add to the custom data API. */ int target_layer_type_index = CustomData_get_named_layer(target_cd, ty, name); + if (!CustomData_layer_has_interp(source_cd, source_layer_i)) { + continue; + } int source_layer_type_index = source_layer_i - source_cd->typemap[ty]; BLI_assert(target_layer_type_index != -1 && source_layer_type_index >= 0); for (int j = 0; j < orig_mp->totloop; ++j) { @@ -763,23 +759,23 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) * Do Exact Boolean directly, without a round trip through #BMesh. * The Mesh operands are in `meshes`, with corresponding transforms in in `obmats`. */ -static Mesh *direct_mesh_boolean(const Mesh **meshes, - const float (*obmats[])[4][4], - const int meshes_len, +static Mesh *direct_mesh_boolean(Span<const Mesh *> meshes, + Span<const float4x4 *> obmats, const bool use_self, const BoolOpType boolean_mode) { const int dbg_level = 0; + BLI_assert(meshes.size() == obmats.size()); + const int meshes_len = meshes.size(); if (meshes_len <= 0) { return nullptr; } if (dbg_level > 0) { std::cout << "\nDIRECT_MESH_INTERSECT, nmeshes = " << meshes_len << "\n"; } - Span<const Mesh *> mesh_span(meshes, meshes_len); MeshesToIMeshInfo mim; IMeshArena arena; - IMesh m_in = meshes_to_imesh(mesh_span, obmats, arena, &mim); + IMesh m_in = meshes_to_imesh(meshes, obmats, arena, &mim); std::function<int(int)> shape_fn = [&mim](int f) { for (int mi = 0; mi < mim.mesh_poly_offset.size() - 1; ++mi) { if (f < mim.mesh_poly_offset[mi + 1]) { @@ -814,10 +810,10 @@ Mesh *BKE_mesh_boolean(const Mesh **meshes, const bool use_self, const int boolean_mode) { + const blender::float4x4 **transforms = (const blender::float4x4 **)obmats; return blender::meshintersect::direct_mesh_boolean( - meshes, - obmats, - meshes_len, + blender::Span(meshes, meshes_len), + blender::Span(transforms, meshes_len), use_self, static_cast<blender::meshintersect::BoolOpType>(boolean_mode)); } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 7bd7fb4a29b..6b46ae3430b 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -372,7 +372,8 @@ static ID *node_owner_get(Main *bmain, ID *id) if ((id->flag & LIB_EMBEDDED_DATA) == 0) { return id; } - BLI_assert((id->tag & LIB_TAG_NO_MAIN) == 0); + /* TODO: Sort this NO_MAIN or not for embedded node trees. See T86119. */ + // BLI_assert((id->tag & LIB_TAG_NO_MAIN) == 0); ListBase *lists[] = {&bmain->materials, &bmain->lights, @@ -3554,7 +3555,8 @@ void nodeSetActive(bNodeTree *ntree, bNode *node) tnode->flag &= ~NODE_ACTIVE_ID; } } - if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) { + if ((node->typeinfo->nclass == NODE_CLASS_TEXTURE) || + (node->typeinfo->type == GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE)) { tnode->flag &= ~NODE_ACTIVE_TEXTURE; } } @@ -3563,7 +3565,8 @@ void nodeSetActive(bNodeTree *ntree, bNode *node) if (node->id) { node->flag |= NODE_ACTIVE_ID; } - if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) { + if ((node->typeinfo->nclass == NODE_CLASS_TEXTURE) || + (node->typeinfo->type == GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE)) { node->flag |= NODE_ACTIVE_TEXTURE; } } @@ -4479,18 +4482,18 @@ void node_type_group_update(struct bNodeType *ntype, } void node_type_exec(struct bNodeType *ntype, - NodeInitExecFunction initexecfunc, - NodeFreeExecFunction freeexecfunc, - NodeExecFunction execfunc) + NodeInitExecFunction init_exec_fn, + NodeFreeExecFunction free_exec_fn, + NodeExecFunction exec_fn) { - ntype->initexecfunc = initexecfunc; - ntype->freeexecfunc = freeexecfunc; - ntype->execfunc = execfunc; + ntype->init_exec_fn = init_exec_fn; + ntype->free_exec_fn = free_exec_fn; + ntype->exec_fn = exec_fn; } -void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc) +void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn) { - ntype->gpufunc = gpufunc; + ntype->gpu_fn = gpu_fn; } void node_type_internal_links(bNodeType *ntype, diff --git a/source/blender/blenkernel/intern/node_ui_storage.cc b/source/blender/blenkernel/intern/node_ui_storage.cc index ea492c4d36a..97f52dd3727 100644 --- a/source/blender/blenkernel/intern/node_ui_storage.cc +++ b/source/blender/blenkernel/intern/node_ui_storage.cc @@ -16,6 +16,8 @@ #include "CLG_log.h" +#include <mutex> + #include "BLI_map.hh" #include "BLI_string_ref.hh" #include "BLI_vector.hh" @@ -33,10 +35,20 @@ using blender::Map; using blender::StringRef; using blender::Vector; +/* Use a global mutex because otherwise it would have to be stored directly in the + * bNodeTree struct in DNA. This could change if the node tree had a runtime struct. */ +static std::mutex global_ui_storage_mutex; + static void ui_storage_ensure(bNodeTree &ntree) { + /* As an optimization, only acquire a lock if the UI storage doesn't exist, + * because it only needs to be allocated once for every node tree. */ if (ntree.ui_storage == nullptr) { - ntree.ui_storage = new NodeTreeUIStorage(); + std::lock_guard<std::mutex> lock(global_ui_storage_mutex); + /* Check again-- another thread may have allocated the storage while this one waited. */ + if (ntree.ui_storage == nullptr) { + ntree.ui_storage = new NodeTreeUIStorage(); + } } } @@ -50,8 +62,12 @@ const NodeUIStorage *BKE_node_tree_ui_storage_get_from_context(const bContext *C } const Object *active_object = CTX_data_active_object(C); + if (active_object == nullptr) { + return nullptr; + } + const ModifierData *active_modifier = BKE_object_active_modifier(active_object); - if (active_object == nullptr || active_modifier == nullptr) { + if (active_modifier == nullptr) { return nullptr; } @@ -74,6 +90,7 @@ void BKE_nodetree_ui_storage_free_for_context(bNodeTree &ntree, { NodeTreeUIStorage *ui_storage = ntree.ui_storage; if (ui_storage != nullptr) { + std::lock_guard<std::mutex> lock(ui_storage->context_map_mutex); ui_storage->context_map.remove(context); } } @@ -109,13 +126,14 @@ static void node_error_message_log(bNodeTree &ntree, } } -static NodeUIStorage &find_node_ui_storage(bNodeTree &ntree, - const NodeTreeEvaluationContext &context, - const bNode &node) +static NodeUIStorage &node_ui_storage_ensure(bNodeTree &ntree, + const NodeTreeEvaluationContext &context, + const bNode &node) { ui_storage_ensure(ntree); NodeTreeUIStorage &ui_storage = *ntree.ui_storage; + std::lock_guard<std::mutex> lock(ui_storage.context_map_mutex); Map<std::string, NodeUIStorage> &node_tree_ui_storage = ui_storage.context_map.lookup_or_add_default(context); @@ -133,7 +151,7 @@ void BKE_nodetree_error_message_add(bNodeTree &ntree, { node_error_message_log(ntree, node, message, type); - NodeUIStorage &node_ui_storage = find_node_ui_storage(ntree, context, node); + NodeUIStorage &node_ui_storage = node_ui_storage_ensure(ntree, context, node); node_ui_storage.warnings.append({type, std::move(message)}); } @@ -142,6 +160,6 @@ void BKE_nodetree_attribute_hint_add(bNodeTree &ntree, const bNode &node, const StringRef attribute_name) { - NodeUIStorage &node_ui_storage = find_node_ui_storage(ntree, context, node); + NodeUIStorage &node_ui_storage = node_ui_storage_ensure(ntree, context, node); node_ui_storage.attribute_name_hints.add_as(attribute_name); } diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c index 05873d20f7f..b9497d389e7 100644 --- a/source/blender/blenkernel/intern/outliner_treehash.c +++ b/source/blender/blenkernel/intern/outliner_treehash.c @@ -101,7 +101,7 @@ static unsigned int tse_hash(const void *ptr) unsigned int u_int; } hash; - BLI_assert(tse->type || !tse->nr); + BLI_assert((tse->type != TSE_SOME_ID) || !tse->nr); hash.h_pair[0] = tse->type; hash.h_pair[1] = tse->nr; @@ -193,7 +193,7 @@ static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short { TreeStoreElem tse_template; tse_template.type = type; - tse_template.nr = type ? nr : 0; /* we're picky! :) */ + tse_template.nr = (type == TSE_SOME_ID) ? 0 : nr; /* we're picky! :) */ tse_template.id = id; BLI_assert(th); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 0a2441bbf74..a374c3252b9 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1423,6 +1423,12 @@ static void sculptsession_free_pbvh(Object *object) MEM_SAFE_FREE(ss->pmap); MEM_SAFE_FREE(ss->pmap_mem); + MEM_SAFE_FREE(ss->epmap); + MEM_SAFE_FREE(ss->epmap_mem); + + MEM_SAFE_FREE(ss->vemap); + MEM_SAFE_FREE(ss->vemap_mem); + MEM_SAFE_FREE(ss->persistent_base); MEM_SAFE_FREE(ss->preview_vert_index_list); @@ -1472,6 +1478,13 @@ void BKE_sculptsession_free(Object *ob) MEM_SAFE_FREE(ss->pmap); MEM_SAFE_FREE(ss->pmap_mem); + + MEM_SAFE_FREE(ss->epmap); + MEM_SAFE_FREE(ss->epmap_mem); + + MEM_SAFE_FREE(ss->vemap); + MEM_SAFE_FREE(ss->vemap_mem); + if (ss->bm_log) { BM_log_free(ss->bm_log); } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 8b911143668..623f3a349d8 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -1681,6 +1681,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) sfile->op = NULL; sfile->previews_timer = NULL; sfile->tags = 0; + sfile->runtime = NULL; BLO_read_data_address(reader, &sfile->params); BLO_read_data_address(reader, &sfile->asset_params); } diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index 5bffcd4d9e7..4cc2d101b02 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -514,7 +514,7 @@ static void studiolight_create_matcap_gputexture(StudioLightImage *sli) ImBuf *ibuf = sli->ibuf; float *gpu_matcap_3components = MEM_callocN(sizeof(float[3]) * ibuf->x * ibuf->y, __func__); - float(*offset4)[4] = (float(*)[4])ibuf->rect_float; + const float(*offset4)[4] = (const float(*)[4])ibuf->rect_float; float(*offset3)[3] = (float(*)[3])gpu_matcap_3components; for (int i = 0; i < ibuf->x * ibuf->y; i++, offset4++, offset3++) { copy_v3_v3(*offset3, *offset4); diff --git a/source/blender/blenlib/BLI_multi_value_map.hh b/source/blender/blenlib/BLI_multi_value_map.hh index 018f080e633..4113085a1e3 100644 --- a/source/blender/blenlib/BLI_multi_value_map.hh +++ b/source/blender/blenlib/BLI_multi_value_map.hh @@ -104,6 +104,22 @@ template<typename Key, typename Value> class MultiValueMap { } /** + * Get a mutable span to all the values that are stored for the given key. + */ + MutableSpan<Value> lookup(const Key &key) + { + return this->lookup_as(key); + } + template<typename ForwardKey> MutableSpan<Value> lookup_as(const ForwardKey &key) + { + Vector<Value> *vector = map_.lookup_ptr_as(key); + if (vector != nullptr) { + return vector->as_mutable_span(); + } + return {}; + } + + /** * Note: This signature will change when the implementation changes. */ typename MapType::ItemIterator items() const diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index bb00755e901..287334a34ee 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -377,7 +377,7 @@ int BLI_exists(const char *path) struct stat st; BLI_assert(!BLI_path_is_rel(path)); if (stat(path, &st)) { - return (0); + return 0; } #endif return (st.st_mode); diff --git a/source/blender/blenlib/intern/string_search.cc b/source/blender/blenlib/intern/string_search.cc index a09aa7a4bc2..44baff1f5e3 100644 --- a/source/blender/blenlib/intern/string_search.cc +++ b/source/blender/blenlib/intern/string_search.cc @@ -395,6 +395,7 @@ void extract_normalized_words(StringRef str, struct SearchItem { blender::Span<blender::StringRef> normalized_words; + int length; void *user_data; }; @@ -416,8 +417,10 @@ void BLI_string_search_add(StringSearch *search, const char *str, void *user_dat { using namespace blender; Vector<StringRef, 64> words; - string_search::extract_normalized_words(str, search->allocator, words); - search->items.append({search->allocator.construct_array_copy(words.as_span()), user_data}); + StringRef str_ref{str}; + string_search::extract_normalized_words(str_ref, search->allocator, words); + search->items.append( + {search->allocator.construct_array_copy(words.as_span()), (int)str_ref.size(), user_data}); } /** @@ -453,7 +456,15 @@ int BLI_string_search_query(StringSearch *search, const char *query, void ***r_d * score. Results with the same score are in the order they have been added to the search. */ Vector<int> sorted_result_indices; for (const int score : found_scores) { - Span<int> indices = result_indices_by_score.lookup(score); + MutableSpan<int> indices = result_indices_by_score.lookup(score); + if (score == found_scores[0]) { + /* Sort items with best score by length. Shorter items are more likely the ones you are + * looking for. This also ensures that exact matches will be at the top, even if the query is + * a substring of another item. */ + std::sort(indices.begin(), indices.end(), [&](int a, int b) { + return search->items[a].length < search->items[b].length; + }); + } sorted_result_indices.extend(indices); } diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index dbeb75570fb..dbe5c96260b 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -333,11 +333,6 @@ bool BLI_uniquename_cb(UniquenameCheckCallback unique_check, return false; } -/* little helper macro for BLI_uniquename */ -#ifndef GIVE_STRADDR -# define GIVE_STRADDR(data, offset) (((char *)data) + offset) -#endif - /** * Generic function to set a unique name. It is only designed to be used in situations * where the name is part of the struct. @@ -353,7 +348,7 @@ static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, for (link = list->first; link; link = link->next) { if (link != vlink) { - if (STREQ(GIVE_STRADDR(link, name_offs), name)) { + if (STREQ(POINTER_OFFSET((const char *)link, name_offs), name)) { return true; } } @@ -403,7 +398,7 @@ bool BLI_uniquename( } return BLI_uniquename_cb( - uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len); + uniquename_unique_check, &data, defname, delim, POINTER_OFFSET(vlink, name_offs), name_len); } /* ------------------------------------------------------------------------- */ diff --git a/source/blender/blenlib/tests/BLI_multi_value_map_test.cc b/source/blender/blenlib/tests/BLI_multi_value_map_test.cc index 7501fbe0d87..a910f2935d4 100644 --- a/source/blender/blenlib/tests/BLI_multi_value_map_test.cc +++ b/source/blender/blenlib/tests/BLI_multi_value_map_test.cc @@ -29,6 +29,27 @@ TEST(multi_value_map, LookupExistant) EXPECT_EQ(map.lookup(3)[0], 6); } +TEST(multi_value_map, LookupMutable) +{ + MultiValueMap<int, int> map; + map.add(1, 2); + map.add(4, 5); + map.add(4, 6); + map.add(6, 7); + + MutableSpan<int> span = map.lookup(4); + EXPECT_EQ(span.size(), 2); + span[0] = 10; + span[1] = 20; + + map.add(4, 5); + MutableSpan<int> new_span = map.lookup(4); + EXPECT_EQ(new_span.size(), 3); + EXPECT_EQ(new_span[0], 10); + EXPECT_EQ(new_span[1], 20); + EXPECT_EQ(new_span[2], 5); +} + TEST(multi_value_map, AddMultiple) { MultiValueMap<int, int> map; diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c index 7261db5d3a6..f3fc1453461 100644 --- a/source/blender/blenloader/intern/blend_validate.c +++ b/source/blender/blenloader/intern/blend_validate.c @@ -60,7 +60,7 @@ bool BLO_main_validate_libraries(Main *bmain, ReportList *reports) blo_split_main(&mainlist, bmain); - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int i = set_listbasepointers(bmain, lbarray); while (i--) { for (ID *id = lbarray[i]->first; id != NULL; id = id->next) { diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c0293c1f8f2..2200f7c291b 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -449,7 +449,7 @@ static void oldnewmap_free(OldNewMap *onm) static void add_main_to_main(Main *mainvar, Main *from) { - ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX], *fromarray[INDEX_ID_MAX]; int a; set_listbasepointers(mainvar, lbarray); @@ -517,7 +517,7 @@ void blo_split_main(ListBase *mainlist, Main *main) lib_main_array[i] = libmain; } - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; i = set_listbasepointers(main, lbarray); while (i--) { ID *id = lbarray[i]->first; @@ -1965,7 +1965,7 @@ void blo_end_packed_pointer_map(FileData *fd, Main *oldmain) /* undo file support: add all library pointers in lookup */ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd) { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; LISTBASE_FOREACH (Main *, ptr, old_mainlist) { int i = set_listbasepointers(ptr, lbarray); @@ -4543,7 +4543,7 @@ void BLO_main_expander(BLOExpandDoitCallback expand_doit_func) */ void BLO_expand_main(void *fdhandle, Main *mainvar) { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; FileData *fd = fdhandle; ID *id; int a; @@ -4713,7 +4713,7 @@ static void add_loose_object_data_to_scene(Main *mainvar, } /* Loop over all ID types, instancing object-data for ID types that have support for it. */ - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int i = set_listbasepointers(mainvar, lbarray); while (i--) { const short idcode = BKE_idtype_idcode_from_index(i); @@ -4979,7 +4979,7 @@ static bool library_link_idcode_needs_tag_check(const short idcode, const int fl */ static void library_link_clear_tag(Main *mainvar, const int flag) { - for (int i = 0; i < MAX_LIBARRAY; i++) { + for (int i = 0; i < INDEX_ID_MAX; i++) { const short idcode = BKE_idtype_idcode_from_index(i); BLI_assert(idcode != -1); if (library_link_idcode_needs_tag_check(idcode, flag)) { @@ -5068,8 +5068,8 @@ static void split_main_newid(Main *mainptr, Main *main_newid) BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name)); main_newid->curlib = mainptr->curlib; - ListBase *lbarray[MAX_LIBARRAY]; - ListBase *lbarray_newid[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; + ListBase *lbarray_newid[INDEX_ID_MAX]; int i = set_listbasepointers(mainptr, lbarray); set_listbasepointers(main_newid, lbarray_newid); while (i--) { @@ -5227,7 +5227,7 @@ void *BLO_library_read_struct(FileData *fd, BHead *bh, const char *blockname) static int has_linked_ids_to_read(Main *mainvar) { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int a = set_listbasepointers(mainvar, lbarray); while (a--) { @@ -5295,7 +5295,7 @@ static void read_library_linked_ids(FileData *basefd, { GHash *loaded_ids = BLI_ghash_str_new(__func__); - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int a = set_listbasepointers(mainvar, lbarray); while (a--) { @@ -5344,7 +5344,7 @@ static void read_library_clear_weak_links(FileData *basefd, ListBase *mainlist, { /* Any remaining weak links at this point have been lost, silently drop * those by setting them to NULL pointers. */ - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int a = set_listbasepointers(mainvar, lbarray); while (a--) { diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index d86ddc5b646..289092f7f19 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1141,7 +1141,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) } } if (!MAIN_VERSION_ATLEAST(bmain, 276, 5)) { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int a; /* Important to clear all non-persistent flags from older versions here, diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index ef2e196094e..1ecaee10e6a 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -3684,7 +3684,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) if (!MAIN_VERSION_ATLEAST(bmain, 280, 48)) { for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { /* Those are not currently used, but are accessible through RNA API and were not - * properly initialized previously. This is mere copy of BKE_init_scene() code. */ + * properly initialized previously. This is mere copy of #scene_init_data code. */ if (scene->r.im_format.view_settings.look[0] == '\0') { BKE_color_managed_display_settings_init(&scene->r.im_format.display_settings); BKE_color_managed_view_settings_init_render( diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 2f3e2ae09a7..f1245a31c70 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -69,6 +69,8 @@ #include "SEQ_proxy.h" #include "SEQ_render.h" #include "SEQ_sequencer.h" +#include "SEQ_time.h" +#include "SEQ_transform.h" #include "BLO_readfile.h" #include "readfile.h" @@ -332,6 +334,37 @@ static void seq_convert_transform_crop_lb_2(const Scene *scene, } } +static void seq_update_meta_disp_range(Editing *ed) +{ + if (ed == NULL) { + return; + } + + LISTBASE_FOREACH_BACKWARD (MetaStack *, ms, &ed->metastack) { + /* Update ms->disp_range from meta. */ + if (ms->disp_range[0] == ms->disp_range[1]) { + copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp); + } + + /* Update meta strip endpoints. */ + SEQ_transform_set_left_handle_frame(ms->parseq, ms->disp_range[0]); + SEQ_transform_set_right_handle_frame(ms->parseq, ms->disp_range[1]); + SEQ_transform_fix_single_image_seq_offsets(ms->parseq); + + /* Recalculate effects using meta strip. */ + LISTBASE_FOREACH (Sequence *, seq, ms->oldbasep) { + if (seq->seq2) { + seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp); + seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp); + } + } + + /* Ensure that active seqbase points to active meta strip seqbase. */ + MetaStack *active_ms = SEQ_meta_stack_active_get(ed); + SEQ_seqbase_active_set(ed, &active_ms->parseq->seqbase); + } +} + void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) { if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) { @@ -606,6 +639,10 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) */ { /* Keep this block, even when empty. */ + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + seq_update_meta_disp_range(SEQ_editing_get(scene, false)); + } } } @@ -1762,6 +1799,24 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_ATLEAST(bmain, 293, 10)) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_GEOMETRY) { + version_node_socket_name(ntree, GEO_NODE_ATTRIBUTE_PROXIMITY, "Location", "Position"); + } + } + FOREACH_NODETREE_END; + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + /* Fix old scene with too many samples that were not being used. + * Now they are properly used and might produce a huge slowdown. + * So we clamp to what the old max actual was. */ + if (scene->eevee.volumetric_shadow_samples > 32) { + scene->eevee.volumetric_shadow_samples = 32; + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 0a4f2fde93f..6fbd4b77487 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -768,7 +768,7 @@ static void write_userdef(BlendWriter *writer, const UserDef *userdef) /* Keep it last of write_foodata functions. */ static void write_libraries(WriteData *wd, Main *main) { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; ID *id; int a, tot; bool found_one; @@ -954,7 +954,7 @@ static bool write_file_handle(Main *mainvar, * if needed, without duplicating whole code. */ Main *bmain = mainvar; do { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int a = set_listbasepointers(bmain, lbarray); while (a--) { ID *id = lbarray[a]->first; diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index 49204d2a2b0..5c43720f635 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -46,7 +46,7 @@ static void recount_totsels(BMesh *bm) int *tots[3]; int i; - /* recount (tot * sel) variables */ + /* Recount total selection variables. */ bm->totvertsel = bm->totedgesel = bm->totfacesel = 0; tots[0] = &bm->totvertsel; tots[1] = &bm->totedgesel; diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index 7d980299771..535df52c1e1 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -924,7 +924,7 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) len = 2 * dia * sinf(phid / 2.0f); - /* length of one segment in shortest parallen */ + /* Length of one segment in shortest parallel. */ vec[0] = dia * sinf(phid); vec[1] = 0.0f; vec[2] = dia * cosf(phid); diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index a17724895f1..6cdf3278908 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -6445,7 +6445,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) if (bmv) { BLI_array_append(vv, bmv); BLI_array_append(ee, bme); /* TODO: Maybe better edge here. */ - if (corner3special && v->ebev && !v->ebev->is_seam && k != vm->seg) { + if (corner3special && v->ebev && !bv->any_seam && k != vm->seg) { BLI_array_append(vv_fix, bmv); } } @@ -6474,7 +6474,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) if (bmv) { BLI_array_append(vv, bmv); BLI_array_append(ee, bme); - if (corner3special && v->ebev && !v->ebev->is_seam && k != 0) { + if (corner3special && v->ebev && !bv->any_seam && k != 0) { BLI_array_append(vv_fix, bmv); } } diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index ba66d7f0dfe..4aae5471858 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -113,11 +113,11 @@ extern "C" { * * When the chunk-order is determined, the first few chunks will be checked if they can be scheduled. * Chunks can have three states: - * - [@ref ChunkExecutionState.COM_ES_NOT_SCHEDULED]: + * - [@ref eChunkExecutionState.NOT_SCHEDULED]: * Chunk is not yet scheduled, or dependencies are not met. - * - [@ref ChunkExecutionState.COM_ES_SCHEDULED]: + * - [@ref eChunkExecutionState.SCHEDULED]: * All dependencies are met, chunk is scheduled, but not finished. - * - [@ref ChunkExecutionState.COM_ES_EXECUTED]: + * - [@ref eChunkExecutionState.EXECUTED]: * Chunk is finished. * * \see ExecutionGroup.execute diff --git a/source/blender/compositor/intern/COM_CPUDevice.cpp b/source/blender/compositor/intern/COM_CPUDevice.cpp index 7ea12866148..b520a437008 100644 --- a/source/blender/compositor/intern/COM_CPUDevice.cpp +++ b/source/blender/compositor/intern/COM_CPUDevice.cpp @@ -24,8 +24,8 @@ CPUDevice::CPUDevice(int thread_id) : m_thread_id(thread_id) void CPUDevice::execute(WorkPackage *work) { - const unsigned int chunkNumber = work->getChunkNumber(); - ExecutionGroup *executionGroup = work->getExecutionGroup(); + const unsigned int chunkNumber = work->chunk_number; + ExecutionGroup *executionGroup = work->execution_group; rcti rect; executionGroup->determineChunkRect(&rect, chunkNumber); diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp index 08035940667..7d897d29576 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cpp @@ -115,9 +115,9 @@ #include "COM_ViewerNode.h" #include "COM_ZCombineNode.h" -bool Converter::is_fast_node(bNode *b_node) +bool COM_bnode_is_fast_node(const bNode &b_node) { - return !ELEM(b_node->type, + return !ELEM(b_node.type, CMP_NODE_BLUR, CMP_NODE_VECBLUR, CMP_NODE_BILATERALBLUR, @@ -132,7 +132,7 @@ bool Converter::is_fast_node(bNode *b_node) CMP_NODE_DENOISE); } -Node *Converter::convert(bNode *b_node) +Node *COM_convert_bnode(bNode *b_node) { Node *node = nullptr; @@ -419,36 +419,37 @@ Node *Converter::convert(bNode *b_node) return node; } -NodeOperation *Converter::convertDataType(NodeOperationOutput *from, NodeOperationInput *to) +/* TODO(jbakker): make this an std::optional<NodeOperation>. */ +NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const NodeOperationInput &to) { - DataType fromDatatype = from->getDataType(); - DataType toDatatype = to->getDataType(); + const DataType src_data_type = from.getDataType(); + const DataType dst_data_type = to.getDataType(); - if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_COLOR) { + if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_COLOR) { return new ConvertValueToColorOperation(); } - if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_VECTOR) { + if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_VECTOR) { return new ConvertValueToVectorOperation(); } - if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VALUE) { + if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VALUE) { return new ConvertColorToValueOperation(); } - if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VECTOR) { + if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VECTOR) { return new ConvertColorToVectorOperation(); } - if (fromDatatype == COM_DT_VECTOR && toDatatype == COM_DT_VALUE) { + if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_VALUE) { return new ConvertVectorToValueOperation(); } - if (fromDatatype == COM_DT_VECTOR && toDatatype == COM_DT_COLOR) { + if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_COLOR) { return new ConvertVectorToColorOperation(); } return nullptr; } -void Converter::convertResolution(NodeOperationBuilder &builder, - NodeOperationOutput *fromSocket, - NodeOperationInput *toSocket) +void COM_convert_resolution(NodeOperationBuilder &builder, + NodeOperationOutput *fromSocket, + NodeOperationInput *toSocket) { InputResizeMode mode = toSocket->getResizeMode(); diff --git a/source/blender/compositor/intern/COM_Converter.h b/source/blender/compositor/intern/COM_Converter.h index fe3b8b75ccc..59be34bf0e3 100644 --- a/source/blender/compositor/intern/COM_Converter.h +++ b/source/blender/compositor/intern/COM_Converter.h @@ -31,56 +31,37 @@ class NodeOperationOutput; class NodeOperationBuilder; /** - * \brief Conversion methods for the compositor + * \brief Wraps a bNode in its Node instance. + * + * For all nodetypes a wrapper class is created. + * + * \note When adding a new node to blender, this method needs to be changed to return the correct + * Node instance. + * + * \see Node */ -class Converter { - public: - /** - * \brief Convert/wraps a bNode in its Node instance. - * - * For all nodetypes a wrapper class is created. - * - * \note When adding a new node to blender, this method needs to be changed to return the correct - * Node instance. - * - * \see Node - */ - static Node *convert(bNode *b_node); - - /** - * \brief True if the node is considered 'fast'. - * - * Slow nodes will be skipped if fast execution is required. - */ - static bool is_fast_node(bNode *b_node); +Node *COM_convert_bnode(bNode *b_node); - /** - * \brief This method will add a datetype conversion rule when the to-socket does not support the - * from-socket actual data type. - * - * \note this method is called when conversion is needed. - * - * \param link: the NodeLink what needs conversion - * \param system: the ExecutionSystem to add the conversion to. - * \see NodeLink - a link between two sockets - */ - static NodeOperation *convertDataType(NodeOperationOutput *from, NodeOperationInput *to); +/** + * \brief True if the node is considered 'fast'. + * + * Slow nodes will be skipped if fast execution is required. + */ +bool COM_bnode_is_fast_node(const bNode &b_node); - /** - * \brief This method will add a resolution rule based on the settings of the NodeInput. - * - * \note Conversion logic is implemented in this method - * \see InputSocketResizeMode for the possible conversions. - * - * \param link: the NodeLink what needs conversion - * \param system: the ExecutionSystem to add the conversion to. - * \see NodeLink - a link between two sockets - */ - static void convertResolution(NodeOperationBuilder &builder, - NodeOperationOutput *fromSocket, - NodeOperationInput *toSocket); +/** + * \brief This function will add a datetype conversion rule when the to-socket does not support the + * from-socket actual data type. + */ +NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, + const NodeOperationInput &to); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("COM:Converter") -#endif -}; +/** + * \brief This function will add a resolution rule based on the settings of the NodeInput. + * + * \note Conversion logic is implemented in this function. + * \see InputSocketResizeMode for the possible conversions. + */ +void COM_convert_resolution(NodeOperationBuilder &builder, + NodeOperationOutput *fromSocket, + NodeOperationInput *toSocket); diff --git a/source/blender/compositor/intern/COM_Device.h b/source/blender/compositor/intern/COM_Device.h index bb95f1e953c..0b0f0f5c1c6 100644 --- a/source/blender/compositor/intern/COM_Device.h +++ b/source/blender/compositor/intern/COM_Device.h @@ -55,7 +55,7 @@ class Device { * \brief execute a WorkPackage * \param work: the WorkPackage to execute */ - virtual void execute(WorkPackage *work) = 0; + virtual void execute(struct WorkPackage *work) = 0; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:Device") diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index 9c21c91c370..37623228183 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -43,20 +43,19 @@ ExecutionGroup::ExecutionGroup() { - this->m_isOutput = false; + this->m_is_output = false; this->m_complex = false; - this->m_chunkExecutionStates = nullptr; this->m_bTree = nullptr; this->m_height = 0; this->m_width = 0; - this->m_cachedMaxReadBufferOffset = 0; - this->m_numberOfXChunks = 0; - this->m_numberOfYChunks = 0; - this->m_numberOfChunks = 0; + this->m_max_read_buffer_offset = 0; + this->m_x_chunks_len = 0; + this->m_y_chunks_len = 0; + this->m_chunks_len = 0; this->m_initialized = false; this->m_openCL = false; this->m_singleThreaded = false; - this->m_chunksFinished = 0; + this->m_chunks_finished = 0; BLI_rcti_init(&this->m_viewerBorder, 0, 0, 0, 0); this->m_executionStartTime = 0; } @@ -108,7 +107,7 @@ bool ExecutionGroup::addOperation(NodeOperation *operation) m_initialized = true; } - m_operations.push_back(operation); + m_operations.append(operation); return true; } @@ -121,45 +120,36 @@ NodeOperation *ExecutionGroup::getOutputOperation() const void ExecutionGroup::initExecution() { - if (this->m_chunkExecutionStates != nullptr) { - MEM_freeN(this->m_chunkExecutionStates); - } - unsigned int index; + m_chunk_execution_states.clear(); determineNumberOfChunks(); - this->m_chunkExecutionStates = nullptr; - if (this->m_numberOfChunks != 0) { - this->m_chunkExecutionStates = (ChunkExecutionState *)MEM_mallocN( - sizeof(ChunkExecutionState) * this->m_numberOfChunks, __func__); - for (index = 0; index < this->m_numberOfChunks; index++) { - this->m_chunkExecutionStates[index] = COM_ES_NOT_SCHEDULED; + if (this->m_chunks_len != 0) { + m_chunk_execution_states.resize(this->m_chunks_len); + for (int index = 0; index < this->m_chunks_len; index++) { + m_chunk_execution_states[index] = eChunkExecutionState::NOT_SCHEDULED; } } - unsigned int maxNumber = 0; + unsigned int max_offset = 0; - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; + for (NodeOperation *operation : m_operations) { if (operation->isReadBufferOperation()) { - ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; - this->m_cachedReadOperations.push_back(readOperation); - maxNumber = max(maxNumber, readOperation->getOffset()); + ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation); + this->m_read_operations.append(readOperation); + max_offset = MAX2(max_offset, readOperation->getOffset()); } } - maxNumber++; - this->m_cachedMaxReadBufferOffset = maxNumber; + max_offset++; + this->m_max_read_buffer_offset = max_offset; } void ExecutionGroup::deinitExecution() { - if (this->m_chunkExecutionStates != nullptr) { - MEM_freeN(this->m_chunkExecutionStates); - this->m_chunkExecutionStates = nullptr; - } - this->m_numberOfChunks = 0; - this->m_numberOfXChunks = 0; - this->m_numberOfYChunks = 0; - this->m_cachedReadOperations.clear(); + m_chunk_execution_states.clear(); + this->m_chunks_len = 0; + this->m_x_chunks_len = 0; + this->m_y_chunks_len = 0; + this->m_read_operations.clear(); this->m_bTree = nullptr; } void ExecutionGroup::determineResolution(unsigned int resolution[2]) @@ -174,17 +164,17 @@ void ExecutionGroup::determineResolution(unsigned int resolution[2]) void ExecutionGroup::determineNumberOfChunks() { if (this->m_singleThreaded) { - this->m_numberOfXChunks = 1; - this->m_numberOfYChunks = 1; - this->m_numberOfChunks = 1; + this->m_x_chunks_len = 1; + this->m_y_chunks_len = 1; + this->m_chunks_len = 1; } else { const float chunkSizef = this->m_chunkSize; const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); - this->m_numberOfXChunks = ceil(border_width / chunkSizef); - this->m_numberOfYChunks = ceil(border_height / chunkSizef); - this->m_numberOfChunks = this->m_numberOfXChunks * this->m_numberOfYChunks; + this->m_x_chunks_len = ceil(border_width / chunkSizef); + this->m_y_chunks_len = ceil(border_height / chunkSizef); + this->m_chunks_len = this->m_x_chunks_len * this->m_y_chunks_len; } } @@ -202,20 +192,20 @@ void ExecutionGroup::execute(ExecutionSystem *graph) if (bTree->test_break && bTree->test_break(bTree->tbh)) { return; } /** \note Early break out for blur and preview nodes. */ - if (this->m_numberOfChunks == 0) { + if (this->m_chunks_len == 0) { return; } /** \note Early break out. */ unsigned int chunkNumber; this->m_executionStartTime = PIL_check_seconds_timer(); - this->m_chunksFinished = 0; + this->m_chunks_finished = 0; this->m_bTree = bTree; unsigned int index; - unsigned int *chunkOrder = (unsigned int *)MEM_mallocN( - sizeof(unsigned int) * this->m_numberOfChunks, __func__); + unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(sizeof(unsigned int) * this->m_chunks_len, + __func__); - for (chunkNumber = 0; chunkNumber < this->m_numberOfChunks; chunkNumber++) { + for (chunkNumber = 0; chunkNumber < this->m_chunks_len; chunkNumber++) { chunkOrder[chunkNumber] = chunkNumber; } NodeOperation *operation = this->getOutputOperation(); @@ -235,9 +225,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) switch (chunkorder) { case COM_TO_RANDOM: - for (index = 0; index < 2 * this->m_numberOfChunks; index++) { - int index1 = rand() % this->m_numberOfChunks; - int index2 = rand() % this->m_numberOfChunks; + for (index = 0; index < 2 * this->m_chunks_len; index++) { + int index1 = rand() % this->m_chunks_len; + int index2 = rand() % this->m_chunks_len; int s = chunkOrder[index1]; chunkOrder[index1] = chunkOrder[index2]; chunkOrder[index2] = s; @@ -247,9 +237,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) ChunkOrderHotspot *hotspots[1]; hotspots[0] = new ChunkOrderHotspot(border_width * centerX, border_height * centerY, 0.0f); rcti rect; - ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN( - sizeof(ChunkOrder) * this->m_numberOfChunks, __func__); - for (index = 0; index < this->m_numberOfChunks; index++) { + ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len, + __func__); + for (index = 0; index < this->m_chunks_len; index++) { determineChunkRect(&rect, index); chunkOrders[index].number = index; chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin; @@ -257,8 +247,8 @@ void ExecutionGroup::execute(ExecutionSystem *graph) chunkOrders[index].update_distance(hotspots, 1); } - std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]); - for (index = 0; index < this->m_numberOfChunks; index++) { + std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len - 1]); + for (index = 0; index < this->m_chunks_len; index++) { chunkOrder[index] = chunkOrders[index].number; } @@ -275,7 +265,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph) unsigned int bx = mx + 2 * tx; unsigned int by = my + 2 * ty; - float addition = this->m_numberOfChunks / COM_RULE_OF_THIRDS_DIVIDER; + float addition = this->m_chunks_len / COM_RULE_OF_THIRDS_DIVIDER; hotspots[0] = new ChunkOrderHotspot(mx, my, addition * 0); hotspots[1] = new ChunkOrderHotspot(tx, my, addition * 1); hotspots[2] = new ChunkOrderHotspot(bx, my, addition * 2); @@ -286,9 +276,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) hotspots[7] = new ChunkOrderHotspot(mx, ty, addition * 7); hotspots[8] = new ChunkOrderHotspot(mx, by, addition * 8); rcti rect; - ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN( - sizeof(ChunkOrder) * this->m_numberOfChunks, __func__); - for (index = 0; index < this->m_numberOfChunks; index++) { + ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len, + __func__); + for (index = 0; index < this->m_chunks_len; index++) { determineChunkRect(&rect, index); chunkOrders[index].number = index; chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin; @@ -296,9 +286,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) chunkOrders[index].update_distance(hotspots, 9); } - std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]); + std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len]); - for (index = 0; index < this->m_numberOfChunks; index++) { + for (index = 0; index < this->m_chunks_len; index++) { chunkOrder[index] = chunkOrders[index].number; } @@ -332,31 +322,35 @@ void ExecutionGroup::execute(ExecutionSystem *graph) finished = true; int numberEvaluated = 0; - for (index = startIndex; - index < this->m_numberOfChunks && numberEvaluated < maxNumberEvaluated; + for (index = startIndex; index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated; index++) { chunkNumber = chunkOrder[index]; - int yChunk = chunkNumber / this->m_numberOfXChunks; - int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks); - const ChunkExecutionState state = this->m_chunkExecutionStates[chunkNumber]; - if (state == COM_ES_NOT_SCHEDULED) { - scheduleChunkWhenPossible(graph, xChunk, yChunk); - finished = false; - startEvaluated = true; - numberEvaluated++; - - if (bTree->update_draw) { - bTree->update_draw(bTree->udh); + int yChunk = chunkNumber / this->m_x_chunks_len; + int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); + switch (m_chunk_execution_states[chunkNumber]) { + case eChunkExecutionState::NOT_SCHEDULED: { + scheduleChunkWhenPossible(graph, xChunk, yChunk); + finished = false; + startEvaluated = true; + numberEvaluated++; + + if (bTree->update_draw) { + bTree->update_draw(bTree->udh); + } + break; } - } - else if (state == COM_ES_SCHEDULED) { - finished = false; - startEvaluated = true; - numberEvaluated++; - } - else if (state == COM_ES_EXECUTED && !startEvaluated) { - startIndex = index + 1; - } + case eChunkExecutionState::SCHEDULED: { + finished = false; + startEvaluated = true; + numberEvaluated++; + break; + } + case eChunkExecutionState::EXECUTED: { + if (!startEvaluated) { + startIndex = index + 1; + } + } + }; } WorkScheduler::finish(); @@ -374,17 +368,14 @@ void ExecutionGroup::execute(ExecutionSystem *graph) MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber) { rcti rect; - vector<MemoryProxy *> memoryproxies; - unsigned int index; + std::vector<MemoryProxy *> memoryproxies; determineChunkRect(&rect, chunkNumber); this->determineDependingMemoryProxies(&memoryproxies); MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN( - sizeof(MemoryBuffer *) * this->m_cachedMaxReadBufferOffset, __func__); + sizeof(MemoryBuffer *) * this->m_max_read_buffer_offset, __func__); rcti output; - for (index = 0; index < this->m_cachedReadOperations.size(); index++) { - ReadBufferOperation *readOperation = - (ReadBufferOperation *)this->m_cachedReadOperations[index]; + for (ReadBufferOperation *readOperation : m_read_operations) { MemoryProxy *memoryProxy = readOperation->getMemoryProxy(); this->determineDependingAreaOfInterest(&rect, readOperation, &output); MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer( @@ -405,13 +396,13 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *mem void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers) { - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) { - this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED; + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { + this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::EXECUTED; } - atomic_add_and_fetch_u(&this->m_chunksFinished, 1); + atomic_add_and_fetch_u(&this->m_chunks_finished, 1); if (memoryBuffers) { - for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) { + for (unsigned int index = 0; index < this->m_max_read_buffer_offset; index++) { MemoryBuffer *buffer = memoryBuffers[index]; if (buffer) { if (buffer->isTemporarily()) { @@ -424,16 +415,16 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo } if (this->m_bTree) { // status report is only performed for top level Execution Groups. - float progress = this->m_chunksFinished; - progress /= this->m_numberOfChunks; + float progress = this->m_chunks_finished; + progress /= this->m_chunks_len; this->m_bTree->progress(this->m_bTree->prh, progress); char buf[128]; BLI_snprintf(buf, sizeof(buf), TIP_("Compositing | Tile %u-%u"), - this->m_chunksFinished, - this->m_numberOfChunks); + this->m_chunks_finished, + this->m_chunks_len); this->m_bTree->stats_draw(this->m_bTree->sdh, buf); } } @@ -452,20 +443,20 @@ inline void ExecutionGroup::determineChunkRect(rcti *rect, else { const unsigned int minx = xChunk * this->m_chunkSize + this->m_viewerBorder.xmin; const unsigned int miny = yChunk * this->m_chunkSize + this->m_viewerBorder.ymin; - const unsigned int width = min((unsigned int)this->m_viewerBorder.xmax, this->m_width); - const unsigned int height = min((unsigned int)this->m_viewerBorder.ymax, this->m_height); + const unsigned int width = MIN2((unsigned int)this->m_viewerBorder.xmax, this->m_width); + const unsigned int height = MIN2((unsigned int)this->m_viewerBorder.ymax, this->m_height); BLI_rcti_init(rect, - min(minx, this->m_width), - min(minx + this->m_chunkSize, width), - min(miny, this->m_height), - min(miny + this->m_chunkSize, height)); + MIN2(minx, this->m_width), + MIN2(minx + this->m_chunkSize, width), + MIN2(miny, this->m_height), + MIN2(miny + this->m_chunkSize, height)); } } void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumber) const { - const unsigned int yChunk = chunkNumber / this->m_numberOfXChunks; - const unsigned int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks); + const unsigned int yChunk = chunkNumber / this->m_x_chunks_len; + const unsigned int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); determineChunkRect(rect, xChunk, yChunk); } @@ -500,8 +491,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area int maxychunk = (maxy + (int)m_chunkSize - 1) / (int)m_chunkSize; minxchunk = max_ii(minxchunk, 0); minychunk = max_ii(minychunk, 0); - maxxchunk = min_ii(maxxchunk, (int)m_numberOfXChunks); - maxychunk = min_ii(maxychunk, (int)m_numberOfYChunks); + maxxchunk = min_ii(maxxchunk, (int)m_x_chunks_len); + maxychunk = min_ii(maxychunk, (int)m_y_chunks_len); bool result = true; for (indexx = minxchunk; indexx < maxxchunk; indexx++) { @@ -517,8 +508,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) { - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_NOT_SCHEDULED) { - this->m_chunkExecutionStates[chunkNumber] = COM_ES_SCHEDULED; + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::NOT_SCHEDULED) { + this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::SCHEDULED; WorkScheduler::schedule(this, chunkNumber); return true; } @@ -527,25 +518,25 @@ bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk) { - if (xChunk < 0 || xChunk >= (int)this->m_numberOfXChunks) { + if (xChunk < 0 || xChunk >= (int)this->m_x_chunks_len) { return true; } - if (yChunk < 0 || yChunk >= (int)this->m_numberOfYChunks) { + if (yChunk < 0 || yChunk >= (int)this->m_y_chunks_len) { return true; } - int chunkNumber = yChunk * this->m_numberOfXChunks + xChunk; + int chunkNumber = yChunk * this->m_x_chunks_len + xChunk; // chunk is already executed - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_EXECUTED) { + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::EXECUTED) { return true; } // chunk is scheduled, but not executed - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) { + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { return false; } // chunk is nor executed nor scheduled. - vector<MemoryProxy *> memoryProxies; + std::vector<MemoryProxy *> memoryProxies; this->determineDependingMemoryProxies(&memoryProxies); rcti rect; @@ -554,9 +545,8 @@ bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChun bool canBeExecuted = true; rcti area; - for (index = 0; index < this->m_cachedReadOperations.size(); index++) { - ReadBufferOperation *readOperation = - (ReadBufferOperation *)this->m_cachedReadOperations[index]; + for (index = 0; index < m_read_operations.size(); index++) { + ReadBufferOperation *readOperation = m_read_operations[index]; BLI_rcti_init(&area, 0, 0, 0, 0); MemoryProxy *memoryProxy = memoryProxies[index]; determineDependingAreaOfInterest(&rect, readOperation, &area); @@ -586,12 +576,9 @@ void ExecutionGroup::determineDependingAreaOfInterest(rcti *input, this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output); } -void ExecutionGroup::determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies) +void ExecutionGroup::determineDependingMemoryProxies(std::vector<MemoryProxy *> *memoryProxies) { - unsigned int index; - for (index = 0; index < this->m_cachedReadOperations.size(); index++) { - ReadBufferOperation *readOperation = - (ReadBufferOperation *)this->m_cachedReadOperations[index]; + for (ReadBufferOperation *readOperation : m_read_operations) { memoryProxies->push_back(readOperation->getMemoryProxy()); } } diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index dd079415d09..f73f4473b5d 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -23,6 +23,8 @@ #endif #include "BLI_rect.h" +#include "BLI_vector.hh" + #include "COM_CompositorContext.h" #include "COM_Device.h" #include "COM_MemoryProxy.h" @@ -30,8 +32,6 @@ #include "COM_NodeOperation.h" #include <vector> -using std::vector; - class ExecutionSystem; class MemoryProxy; class ReadBufferOperation; @@ -41,20 +41,20 @@ class Device; * \brief the execution state of a chunk in an ExecutionGroup * \ingroup Execution */ -typedef enum ChunkExecutionState { +enum class eChunkExecutionState { /** * \brief chunk is not yet scheduled */ - COM_ES_NOT_SCHEDULED = 0, + NOT_SCHEDULED = 0, /** * \brief chunk is scheduled, but not yet executed */ - COM_ES_SCHEDULED = 1, + SCHEDULED = 1, /** * \brief chunk is executed. */ - COM_ES_EXECUTED = 2, -} ChunkExecutionState; + EXECUTED = 2, +}; /** * \brief Class ExecutionGroup is a group of Operations that are executed as one. @@ -63,23 +63,20 @@ typedef enum ChunkExecutionState { * \ingroup Execution */ class ExecutionGroup { - public: - typedef std::vector<NodeOperation *> Operations; - private: // fields /** * \brief list of operations in this ExecutionGroup */ - Operations m_operations; + blender::Vector<NodeOperation *> m_operations; /** * \brief is this ExecutionGroup an input ExecutionGroup * an input execution group is a group that is at the end of the calculation * (the output is important for the user). */ - int m_isOutput; + bool m_is_output; /** * \brief Width of the output @@ -100,17 +97,17 @@ class ExecutionGroup { /** * \brief number of chunks in the x-axis */ - unsigned int m_numberOfXChunks; + unsigned int m_x_chunks_len; /** * \brief number of chunks in the y-axis */ - unsigned int m_numberOfYChunks; + unsigned int m_y_chunks_len; /** * \brief total number of chunks */ - unsigned int m_numberOfChunks; + unsigned int m_chunks_len; /** * \brief contains this ExecutionGroup a complex NodeOperation. @@ -131,12 +128,12 @@ class ExecutionGroup { * \brief what is the maximum number field of all ReadBufferOperation in this ExecutionGroup. * \note this is used to construct the MemoryBuffers that will be passed during execution. */ - unsigned int m_cachedMaxReadBufferOffset; + unsigned int m_max_read_buffer_offset; /** - * \brief a cached vector of all read operations in the execution group. + * \brief All read operations of this execution group. */ - Operations m_cachedReadOperations; + blender::Vector<ReadBufferOperation *> m_read_operations; /** * \brief reference to the original bNodeTree, @@ -148,15 +145,15 @@ class ExecutionGroup { /** * \brief total number of chunks that have been calculated for this ExecutionGroup */ - unsigned int m_chunksFinished; + unsigned int m_chunks_finished; /** - * \brief the chunkExecutionStates holds per chunk the execution state. this state can be - * - COM_ES_NOT_SCHEDULED: not scheduled - * - COM_ES_SCHEDULED: scheduled - * - COM_ES_EXECUTED: executed + * \brief m_chunk_execution_states holds per chunk the execution state. this state can be + * - eChunkExecutionState::NOT_SCHEDULED: not scheduled + * - eChunkExecutionState::SCHEDULED: scheduled + * - eChunkExecutionState::EXECUTED: executed */ - ChunkExecutionState *m_chunkExecutionStates; + blender::Vector<eChunkExecutionState> m_chunk_execution_states; /** * \brief indicator when this ExecutionGroup has valid Operations in its vector for Execution @@ -272,18 +269,18 @@ class ExecutionGroup { * \note ViewerOperation, CompositeOperation, PreviewOperation. * \see NodeOperation.isOutputOperation */ - int isOutputExecutionGroup() const + bool isOutputExecutionGroup() const { - return this->m_isOutput; + return this->m_is_output; } /** * \brief set whether this ExecutionGroup is an output * \param isOutput: */ - void setOutputExecutionGroup(int isOutput) + void setOutputExecutionGroup(bool is_output) { - this->m_isOutput = isOutput; + this->m_is_output = is_output; } /** @@ -405,7 +402,7 @@ class ExecutionGroup { * \note the area of the MemoryProxy.creator that has to be executed. * \param memoryProxies: result */ - void determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies); + void determineDependingMemoryProxies(std::vector<MemoryProxy *> *memoryProxies); /** * \brief Determine the rect (minx, maxx, miny, maxy) of a chunk. diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp index 4c0c7d2103e..6691e5feb5f 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp @@ -121,7 +121,8 @@ ExecutionSystem::~ExecutionSystem() this->m_groups.clear(); } -void ExecutionSystem::set_operations(const Operations &operations, const Groups &groups) +void ExecutionSystem::set_operations(const blender::Vector<NodeOperation *> &operations, + const blender::Vector<ExecutionGroup *> &groups) { m_operations = operations; m_groups = groups; @@ -135,10 +136,7 @@ void ExecutionSystem::execute() DebugInfo::execute_started(this); unsigned int order = 0; - for (vector<NodeOperation *>::iterator iter = this->m_operations.begin(); - iter != this->m_operations.end(); - ++iter) { - NodeOperation *operation = *iter; + for (NodeOperation *operation : m_operations) { if (operation->isReadBufferOperation()) { ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; readOperation->setOffset(order); @@ -179,10 +177,10 @@ void ExecutionSystem::execute() WorkScheduler::start(this->m_context); - executeGroups(COM_PRIORITY_HIGH); + execute_groups(COM_PRIORITY_HIGH); if (!this->getContext().isFastCalculation()) { - executeGroups(COM_PRIORITY_MEDIUM); - executeGroups(COM_PRIORITY_LOW); + execute_groups(COM_PRIORITY_MEDIUM); + execute_groups(COM_PRIORITY_LOW); } WorkScheduler::finish(); @@ -199,37 +197,23 @@ void ExecutionSystem::execute() } } -void ExecutionSystem::executeGroups(CompositorPriority priority) +void ExecutionSystem::execute_groups(CompositorPriority priority) { - unsigned int index; - vector<ExecutionGroup *> executionGroups; - this->findOutputExecutionGroup(&executionGroups, priority); - - for (index = 0; index < executionGroups.size(); index++) { - ExecutionGroup *group = executionGroups[index]; + blender::Vector<ExecutionGroup *> execution_groups = find_output_execution_groups(priority); + for (ExecutionGroup *group : execution_groups) { group->execute(this); } } -void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result, - CompositorPriority priority) const +blender::Vector<ExecutionGroup *> ExecutionSystem::find_output_execution_groups( + CompositorPriority priority) const { - unsigned int index; - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *group = this->m_groups[index]; - if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) { - result->push_back(group); - } - } -} + blender::Vector<ExecutionGroup *> result; -void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result) const -{ - unsigned int index; - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *group = this->m_groups[index]; - if (group->isOutputExecutionGroup()) { - result->push_back(group); + for (ExecutionGroup *group : m_groups) { + if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) { + result.append(group); } } + return result; } diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index 44b47787b06..9a51baf55d7 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -21,12 +21,16 @@ class ExecutionGroup; #pragma once #include "BKE_text.h" + #include "COM_ExecutionGroup.h" #include "COM_Node.h" #include "COM_NodeOperation.h" + #include "DNA_color_types.h" #include "DNA_node_types.h" +#include "BLI_vector.hh" + /** * \page execution Execution model * In order to get to an efficient model for execution, several steps are being done. these steps @@ -79,7 +83,7 @@ class ExecutionGroup; * - [@ref InputSocketResizeMode.COM_SC_NO_RESIZE]: * Bottom left of the images are aligned. * - * \see Converter.convertDataType Datatype conversions + * \see COM_convert_data_type Datatype conversions * \see Converter.convertResolution Image size conversions * * \section EM_Step4 Step4: group operations in executions groups @@ -113,9 +117,6 @@ class ExecutionGroup; * \brief the ExecutionSystem contains the whole compositor tree. */ class ExecutionSystem { - public: - typedef std::vector<NodeOperation *> Operations; - typedef std::vector<ExecutionGroup *> Groups; private: /** @@ -126,24 +127,19 @@ class ExecutionSystem { /** * \brief vector of operations */ - Operations m_operations; + blender::Vector<NodeOperation *> m_operations; /** * \brief vector of groups */ - Groups m_groups; + blender::Vector<ExecutionGroup *> m_groups; private: // methods /** * find all execution group with output nodes */ - void findOutputExecutionGroup(vector<ExecutionGroup *> *result, - CompositorPriority priority) const; - - /** - * find all execution group with output nodes - */ - void findOutputExecutionGroup(vector<ExecutionGroup *> *result) const; + blender::Vector<ExecutionGroup *> find_output_execution_groups( + CompositorPriority priority) const; public: /** @@ -167,7 +163,8 @@ class ExecutionSystem { */ ~ExecutionSystem(); - void set_operations(const Operations &operations, const Groups &groups); + void set_operations(const blender::Vector<NodeOperation *> &operations, + const blender::Vector<ExecutionGroup *> &groups); /** * \brief execute this system @@ -186,7 +183,7 @@ class ExecutionSystem { } private: - void executeGroups(CompositorPriority priority); + void execute_groups(CompositorPriority priority); /* allow the DebugInfo class to look at internals */ friend class DebugInfo; diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cpp index a13db6bb09e..17a73efeab2 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cpp @@ -20,9 +20,6 @@ #include "MEM_guardedalloc.h" -using std::max; -using std::min; - static unsigned int determine_num_channels(DataType datatype) { switch (datatype) { @@ -156,10 +153,10 @@ void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer) return; } unsigned int otherY; - unsigned int minX = max(this->m_rect.xmin, otherBuffer->m_rect.xmin); - unsigned int maxX = min(this->m_rect.xmax, otherBuffer->m_rect.xmax); - unsigned int minY = max(this->m_rect.ymin, otherBuffer->m_rect.ymin); - unsigned int maxY = min(this->m_rect.ymax, otherBuffer->m_rect.ymax); + unsigned int minX = MAX2(this->m_rect.xmin, otherBuffer->m_rect.xmin); + unsigned int maxX = MIN2(this->m_rect.xmax, otherBuffer->m_rect.xmax); + unsigned int minY = MAX2(this->m_rect.ymin, otherBuffer->m_rect.ymin); + unsigned int maxY = MIN2(this->m_rect.ymax, otherBuffer->m_rect.ymax); int offset; int otherOffset; diff --git a/source/blender/compositor/intern/COM_MetaData.cpp b/source/blender/compositor/intern/COM_MetaData.cpp index 4bc4571face..a6306f6c657 100644 --- a/source/blender/compositor/intern/COM_MetaData.cpp +++ b/source/blender/compositor/intern/COM_MetaData.cpp @@ -18,7 +18,6 @@ #include "COM_MetaData.h" -#include "BKE_cryptomatte.hh" #include "BKE_image.h" #include "RE_pipeline.h" @@ -69,3 +68,39 @@ void MetaData::addToRenderResult(RenderResult *render_result) const BKE_render_result_stamp_data(render_result, entry.key.c_str(), entry.value.c_str()); } } + +void MetaDataExtractCallbackData::addMetaData(blender::StringRef key, blender::StringRefNull value) +{ + if (!meta_data) { + meta_data = std::make_unique<MetaData>(); + } + meta_data->add(key, value); +} + +void MetaDataExtractCallbackData::setCryptomatteKeys(blender::StringRef cryptomatte_layer_name) +{ + manifest_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, + "manifest"); + hash_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, + "hash"); + conversion_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, + "conversion"); +} + +void MetaDataExtractCallbackData::extract_cryptomatte_meta_data(void *_data, + const char *propname, + char *propvalue, + int UNUSED(len)) +{ + MetaDataExtractCallbackData *data = static_cast<MetaDataExtractCallbackData *>(_data); + blender::StringRefNull key(propname); + if (key == data->hash_key) { + data->addMetaData(META_DATA_KEY_CRYPTOMATTE_HASH, propvalue); + } + else if (key == data->conversion_key) { + data->addMetaData(META_DATA_KEY_CRYPTOMATTE_CONVERSION, propvalue); + } + else if (key == data->manifest_key) { + data->addMetaData(META_DATA_KEY_CRYPTOMATTE_MANIFEST, propvalue); + } +}
\ No newline at end of file diff --git a/source/blender/compositor/intern/COM_MetaData.h b/source/blender/compositor/intern/COM_MetaData.h index c1e34df2791..fa3de895b4e 100644 --- a/source/blender/compositor/intern/COM_MetaData.h +++ b/source/blender/compositor/intern/COM_MetaData.h @@ -20,13 +20,13 @@ #include <string> +#include "BKE_cryptomatte.hh" #include "BLI_map.hh" #include "MEM_guardedalloc.h" /* Forward declarations. */ struct RenderResult; -struct StampData; /* Cryptomatte includes hash in its meta data keys. The hash is generated from the render * layer/pass name. Compositing happens without the knowledge of the original layer and pass. The @@ -54,3 +54,18 @@ class MetaData { MEM_CXX_CLASS_ALLOC_FUNCS("COM:MetaData") #endif }; + +struct MetaDataExtractCallbackData { + std::unique_ptr<MetaData> meta_data; + std::string hash_key; + std::string conversion_key; + std::string manifest_key; + + void addMetaData(blender::StringRef key, blender::StringRefNull value); + void setCryptomatteKeys(blender::StringRef cryptomatte_layer_name); + /* C type callback function (StampCallback). */ + static void extract_cryptomatte_meta_data(void *_data, + const char *propname, + char *propvalue, + int UNUSED(len)); +}; diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cpp index b604b8ced88..421a762d9b5 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.cpp +++ b/source/blender/compositor/intern/COM_NodeGraph.cpp @@ -90,7 +90,7 @@ void NodeGraph::add_node(Node *node, void NodeGraph::add_link(NodeOutput *fromSocket, NodeInput *toSocket) { - m_links.push_back(Link(fromSocket, toSocket)); + m_links.append(Link(fromSocket, toSocket)); /* register with the input */ toSocket->setLink(fromSocket); @@ -132,7 +132,7 @@ void NodeGraph::add_bNode(const CompositorContext &context, } /* replace slow nodes with proxies for fast execution */ - if (context.isFastCalculation() && !Converter::is_fast_node(b_node)) { + if (context.isFastCalculation() && !COM_bnode_is_fast_node(*b_node)) { add_proxies_skip(b_ntree, b_node, key, is_active_group); return; } @@ -146,7 +146,7 @@ void NodeGraph::add_bNode(const CompositorContext &context, } else { /* regular nodes, handled in Converter */ - Node *node = Converter::convert(b_node); + Node *node = COM_convert_bnode(b_node); if (node) { add_node(node, b_ntree, key, is_active_group); } diff --git a/source/blender/compositor/intern/COM_NodeGraph.h b/source/blender/compositor/intern/COM_NodeGraph.h index 7252d546fce..990e3a30831 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.h +++ b/source/blender/compositor/intern/COM_NodeGraph.h @@ -18,6 +18,8 @@ #pragma once +#include "BLI_vector.hh" + #include <map> #include <set> #include <vector> @@ -39,33 +41,21 @@ class NodeOutput; */ class NodeGraph { public: - class Link { - private: - NodeOutput *m_from; - NodeInput *m_to; - - public: - Link(NodeOutput *from, NodeInput *to) : m_from(from), m_to(to) - { - } + struct Link { + NodeOutput *from; + NodeInput *to; - NodeOutput *getFromSocket() const - { - return m_from; - } - NodeInput *getToSocket() const + Link(NodeOutput *from, NodeInput *to) : from(from), to(to) { - return m_to; } }; typedef std::vector<Node *> Nodes; typedef Nodes::iterator NodeIterator; - typedef std::vector<Link> Links; private: Nodes m_nodes; - Links m_links; + blender::Vector<Link> m_links; public: NodeGraph(); @@ -75,7 +65,7 @@ class NodeGraph { { return m_nodes; } - const Links &links() const + const blender::Vector<Link> &links() const { return m_links; } diff --git a/source/blender/compositor/intern/COM_NodeOperation.cpp b/source/blender/compositor/intern/COM_NodeOperation.cpp index 1a30806f28c..ce7d3a6389e 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.cpp +++ b/source/blender/compositor/intern/COM_NodeOperation.cpp @@ -182,10 +182,10 @@ bool NodeOperation::determineDependingAreaOfInterest(rcti *input, first = false; } else { - output->xmin = min(output->xmin, tempOutput.xmin); - output->ymin = min(output->ymin, tempOutput.ymin); - output->xmax = max(output->xmax, tempOutput.xmax); - output->ymax = max(output->ymax, tempOutput.ymax); + output->xmin = MIN2(output->xmin, tempOutput.xmin); + output->ymin = MIN2(output->ymin, tempOutput.ymin); + output->xmax = MAX2(output->xmax, tempOutput.xmax); + output->ymax = MAX2(output->ymax, tempOutput.ymax); } } } diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index 0ce7c1389bd..f26279e2869 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -33,10 +33,6 @@ #include "clew.h" -using std::list; -using std::max; -using std::min; - class OpenCLDevice; class ReadBufferOperation; class WriteBufferOperation; @@ -239,8 +235,8 @@ class NodeOperation : public SocketReader { MemoryBuffer * /*outputMemoryBuffer*/, cl_mem /*clOutputBuffer*/, MemoryBuffer ** /*inputMemoryBuffers*/, - list<cl_mem> * /*clMemToCleanUp*/, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> * /*clMemToCleanUp*/, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { } virtual void deinitExecution(); diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp index 35a3314db3b..688b693080f 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp @@ -72,11 +72,9 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system) inverse_input_map[it->second].push_back(it->first); } - for (NodeGraph::Links::const_iterator it = m_graph.links().begin(); it != m_graph.links().end(); - ++it) { - const NodeGraph::Link &link = *it; - NodeOutput *from = link.getFromSocket(); - NodeInput *to = link.getToSocket(); + for (const NodeGraph::Link &link : m_graph.links()) { + NodeOutput *from = link.from; + NodeInput *to = link.to; NodeOperationOutput *op_from = find_operation_output(m_output_map, from); const OpInputs &op_to_list = find_operation_inputs(inverse_input_map, to); @@ -125,7 +123,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system) void NodeOperationBuilder::addOperation(NodeOperation *operation) { - m_operations.push_back(operation); + m_operations.append(operation); } void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket, @@ -288,7 +286,7 @@ void NodeOperationBuilder::add_datatype_conversions() } for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { const Link &link = *it; - NodeOperation *converter = Converter::convertDataType(link.from(), link.to()); + NodeOperation *converter = COM_convert_data_type(*link.from(), *link.to()); if (converter) { addOperation(converter); @@ -306,8 +304,7 @@ void NodeOperationBuilder::add_operation_input_constants() */ using Inputs = std::vector<NodeOperationInput *>; Inputs pending_inputs; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; + for (NodeOperation *op : m_operations) { for (int k = 0; k < op->getNumberOfInputSockets(); ++k) { NodeOperationInput *input = op->getInputSocket(k); if (!input->isConnected()) { @@ -408,9 +405,7 @@ void NodeOperationBuilder::resolve_proxies() void NodeOperationBuilder::determineResolutions() { /* determine all resolutions of the operations (Width/Height) */ - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { if (op->isOutputOperation(m_context->isRendering()) && !op->isPreviewOperation()) { unsigned int resolution[2] = {0, 0}; unsigned int preferredResolution[2] = {0, 0}; @@ -419,9 +414,7 @@ void NodeOperationBuilder::determineResolutions() } } - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { if (op->isOutputOperation(m_context->isRendering()) && op->isPreviewOperation()) { unsigned int resolution[2] = {0, 0}; unsigned int preferredResolution[2] = {0, 0}; @@ -446,7 +439,7 @@ void NodeOperationBuilder::determineResolutions() } for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { const Link &link = *it; - Converter::convertResolution(*this, link.from(), link.to()); + COM_convert_resolution(*this, link.from(), link.to()); } } } @@ -575,16 +568,14 @@ void NodeOperationBuilder::add_complex_operation_buffers() /* note: complex ops and get cached here first, since adding operations * will invalidate iterators over the main m_operations */ - Operations complex_ops; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - if ((*it)->isComplex()) { - complex_ops.push_back(*it); + blender::Vector<NodeOperation *> complex_ops; + for (NodeOperation *operation : m_operations) { + if (operation->isComplex()) { + complex_ops.append(operation); } } - for (Operations::const_iterator it = complex_ops.begin(); it != complex_ops.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : complex_ops) { DebugInfo::operation_read_write_buffer(op); for (int index = 0; index < op->getNumberOfInputSockets(); index++) { @@ -624,9 +615,7 @@ static void find_reachable_operations_recursive(Tags &reachable, NodeOperation * void NodeOperationBuilder::prune_operations() { Tags reachable; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { /* output operations are primary executed operations */ if (op->isOutputOperation(m_context->isRendering())) { find_reachable_operations_recursive(reachable, op); @@ -634,12 +623,10 @@ void NodeOperationBuilder::prune_operations() } /* delete unreachable operations */ - Operations reachable_ops; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + blender::Vector<NodeOperation *> reachable_ops; + for (NodeOperation *op : m_operations) { if (reachable.find(op) != reachable.end()) { - reachable_ops.push_back(op); + reachable_ops.append(op); } else { delete op; @@ -650,7 +637,7 @@ void NodeOperationBuilder::prune_operations() } /* topological (depth-first) sorting of operations */ -static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted, +static void sort_operations_recursive(blender::Vector<NodeOperation *> &sorted, Tags &visited, NodeOperation *op) { @@ -666,17 +653,17 @@ static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted, } } - sorted.push_back(op); + sorted.append(op); } void NodeOperationBuilder::sort_operations() { - Operations sorted; + blender::Vector<NodeOperation *> sorted; sorted.reserve(m_operations.size()); Tags visited; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - sort_operations_recursive(sorted, visited, *it); + for (NodeOperation *operation : m_operations) { + sort_operations_recursive(sorted, visited, operation); } m_operations = sorted; @@ -705,7 +692,7 @@ static void add_group_operations_recursive(Tags &visited, NodeOperation *op, Exe ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op) { ExecutionGroup *group = new ExecutionGroup(); - m_groups.push_back(group); + m_groups.append(group); Tags visited; add_group_operations_recursive(visited, op, group); @@ -715,9 +702,7 @@ ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op) void NodeOperationBuilder::group_operations() { - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { if (op->isOutputOperation(m_context->isRendering())) { ExecutionGroup *group = make_group(op); group->setOutputExecutionGroup(true); diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h index 5dd4022b127..b502a12d9b1 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h @@ -24,8 +24,6 @@ #include "COM_NodeGraph.h" -using std::vector; - class CompositorContext; class Node; @@ -64,9 +62,7 @@ class NodeOperationBuilder { } }; - typedef std::vector<NodeOperation *> Operations; typedef std::vector<Link> Links; - typedef std::vector<ExecutionGroup *> Groups; typedef std::map<NodeOperationInput *, NodeInput *> InputSocketMap; typedef std::map<NodeOutput *, NodeOperationOutput *> OutputSocketMap; @@ -78,9 +74,9 @@ class NodeOperationBuilder { const CompositorContext *m_context; NodeGraph m_graph; - Operations m_operations; + blender::Vector<NodeOperation *> m_operations; Links m_links; - Groups m_groups; + blender::Vector<ExecutionGroup *> m_groups; /** Maps operation inputs to node inputs */ InputSocketMap m_input_map; diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp index acfe800e433..34450366aec 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp +++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp @@ -61,8 +61,8 @@ void OpenCLDevice::deinitialize() void OpenCLDevice::execute(WorkPackage *work) { - const unsigned int chunkNumber = work->getChunkNumber(); - ExecutionGroup *executionGroup = work->getExecutionGroup(); + const unsigned int chunkNumber = work->chunk_number; + ExecutionGroup *executionGroup = work->execution_group; rcti rect; executionGroup->determineChunkRect(&rect, chunkNumber); @@ -79,7 +79,7 @@ void OpenCLDevice::execute(WorkPackage *work) cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list<cl_mem> *cleanup, + std::list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, SocketReader *reader) { @@ -111,7 +111,7 @@ const cl_image_format *OpenCLDevice::determineImageFormat(MemoryBuffer *memoryBu cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list<cl_mem> *cleanup, + std::list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, ReadBufferOperation *reader) { @@ -258,7 +258,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, } cl_kernel OpenCLDevice::COM_clCreateKernel(const char *kernelname, - list<cl_kernel> *clKernelsToCleanUp) + std::list<cl_kernel> *clKernelsToCleanUp) { cl_int error; cl_kernel kernel = clCreateKernel(this->m_program, kernelname, &error); diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h index d502f5aa34b..e4fd397b4e8 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.h +++ b/source/blender/compositor/intern/COM_OpenCLDevice.h @@ -25,8 +25,6 @@ class OpenCLDevice; #include "COM_WorkScheduler.h" #include "clew.h" -using std::list; - /** * \brief device representing an GPU OpenCL device. * an instance of this class represents a single cl_device @@ -107,13 +105,13 @@ class OpenCLDevice : public Device { cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list<cl_mem> *cleanup, + std::list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, SocketReader *reader); cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list<cl_mem> *cleanup, + std::list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, ReadBufferOperation *reader); void COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel, @@ -130,5 +128,5 @@ class OpenCLDevice : public Device { MemoryBuffer *outputMemoryBuffer, int offsetIndex, NodeOperation *operation); - cl_kernel COM_clCreateKernel(const char *kernelname, list<cl_kernel> *clKernelsToCleanUp); + cl_kernel COM_clCreateKernel(const char *kernelname, std::list<cl_kernel> *clKernelsToCleanUp); }; diff --git a/source/blender/compositor/intern/COM_WorkPackage.cpp b/source/blender/compositor/intern/COM_WorkPackage.cpp index 795f8d88d50..60684f2c45c 100644 --- a/source/blender/compositor/intern/COM_WorkPackage.cpp +++ b/source/blender/compositor/intern/COM_WorkPackage.cpp @@ -18,8 +18,8 @@ #include "COM_WorkPackage.h" -WorkPackage::WorkPackage(ExecutionGroup *group, unsigned int chunkNumber) +WorkPackage::WorkPackage(ExecutionGroup *execution_group, unsigned int chunk_number) { - this->m_executionGroup = group; - this->m_chunkNumber = chunkNumber; + this->execution_group = execution_group; + this->chunk_number = chunk_number; } diff --git a/source/blender/compositor/intern/COM_WorkPackage.h b/source/blender/compositor/intern/COM_WorkPackage.h index f4370aa41be..db5eb3d3072 100644 --- a/source/blender/compositor/intern/COM_WorkPackage.h +++ b/source/blender/compositor/intern/COM_WorkPackage.h @@ -16,8 +16,6 @@ * Copyright 2011, Blender Foundation. */ -class WorkPackage; - #pragma once class ExecutionGroup; @@ -27,41 +25,23 @@ class ExecutionGroup; * \brief contains data about work that can be scheduled * \see WorkScheduler */ -class WorkPackage { - private: +struct WorkPackage { /** * \brief executionGroup with the operations-setup to be evaluated */ - ExecutionGroup *m_executionGroup; + ExecutionGroup *execution_group; /** * \brief number of the chunk to be executed */ - unsigned int m_chunkNumber; + unsigned int chunk_number; - public: /** * constructor * \param group: the ExecutionGroup - * \param chunkNumber: the number of the chunk - */ - WorkPackage(ExecutionGroup *group, unsigned int chunkNumber); - - /** - * \brief get the ExecutionGroup - */ - ExecutionGroup *getExecutionGroup() const - { - return this->m_executionGroup; - } - - /** - * \brief get the number of the chunk + * \param chunk_number: the number of the chunk */ - unsigned int getChunkNumber() const - { - return this->m_chunkNumber; - } + WorkPackage(ExecutionGroup *group, unsigned int chunk_number); #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:WorkPackage") diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp index 9ca704afdea..a70b6ba4abe 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cpp +++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp @@ -48,7 +48,7 @@ static ThreadLocal(CPUDevice *) g_thread_device; static struct { /** \brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is created */ - vector<CPUDevice *> cpu_devices; + std::vector<CPUDevice *> cpu_devices; #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE /** \brief list of all thread for every CPUDevice in cpudevices a thread exists. */ @@ -62,7 +62,7 @@ static struct { cl_program opencl_program; /** \brief list of all OpenCLDevices. for every OpenCL GPU device an instance of OpenCLDevice is * created. */ - vector<OpenCLDevice *> gpu_devices; + std::vector<OpenCLDevice *> gpu_devices; /** \brief list of all thread for every GPUDevice in cpudevices a thread exists. */ ListBase gpu_threads; /** \brief all scheduled work for the GPU. */ diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cpp index 596a448e6a0..69729e018d7 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.cpp +++ b/source/blender/compositor/nodes/COM_ImageNode.cpp @@ -34,12 +34,12 @@ ImageNode::ImageNode(bNode *editorNode) : Node(editorNode) /* pass */ } NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter, - RenderLayer *rl, + RenderLayer *render_layer, + RenderPass *render_pass, Image *image, ImageUser *user, int framenumber, int outputsocketIndex, - int passindex, int view, DataType datatype) const { @@ -47,19 +47,18 @@ NodeOperation *ImageNode::doMultilayerCheck(NodeConverter &converter, MultilayerBaseOperation *operation = nullptr; switch (datatype) { case COM_DT_VALUE: - operation = new MultilayerValueOperation(passindex, view); + operation = new MultilayerValueOperation(render_layer, render_pass, view); break; case COM_DT_VECTOR: - operation = new MultilayerVectorOperation(passindex, view); + operation = new MultilayerVectorOperation(render_layer, render_pass, view); break; case COM_DT_COLOR: - operation = new MultilayerColorOperation(passindex, view); + operation = new MultilayerColorOperation(render_layer, render_pass, view); break; default: break; } operation->setImage(image); - operation->setRenderLayer(rl); operation->setImageUser(user); operation->setFramenumber(framenumber); @@ -128,16 +127,15 @@ void ImageNode::convertToOperations(NodeConverter &converter, } if (rpass) { - int passindex = BLI_findindex(&rl->passes, rpass); switch (rpass->channels) { case 1: operation = doMultilayerCheck(converter, rl, + rpass, image, imageuser, framenumber, index, - passindex, view, COM_DT_VALUE); break; @@ -146,22 +144,22 @@ void ImageNode::convertToOperations(NodeConverter &converter, case 3: operation = doMultilayerCheck(converter, rl, + rpass, image, imageuser, framenumber, index, - passindex, view, COM_DT_VECTOR); break; case 4: operation = doMultilayerCheck(converter, rl, + rpass, image, imageuser, framenumber, index, - passindex, view, COM_DT_COLOR); break; diff --git a/source/blender/compositor/nodes/COM_ImageNode.h b/source/blender/compositor/nodes/COM_ImageNode.h index 1a811fe855d..b99fc07f105 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.h +++ b/source/blender/compositor/nodes/COM_ImageNode.h @@ -24,6 +24,7 @@ #include "DNA_node_types.h" #include "RE_engine.h" +#include "RE_pipeline.h" /** * \brief ImageNode @@ -32,12 +33,12 @@ class ImageNode : public Node { private: NodeOperation *doMultilayerCheck(NodeConverter &converter, - RenderLayer *rl, + RenderLayer *render_layer, + RenderPass *render_pass, Image *image, ImageUser *user, int framenumber, int outputsocketIndex, - int passindex, int view, DataType datatype) const; diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp index e4a946e2e9d..e534ebfac9a 100644 --- a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp +++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cpp @@ -33,7 +33,7 @@ void SwitchViewNode::convertToOperations(NodeConverter &converter, /* get the internal index of the socket with a matching name */ int nr = BLI_findstringindex(&bnode->inputs, viewName, offsetof(bNodeSocket, name)); - nr = max(nr, 0); + nr = MAX2(nr, 0); result = converter.addInputProxy(getInputSocket(nr), false); converter.mapOutputSocket(getOutputSocket(0), result); diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp index f7b7816e1a1..a8ad2a11790 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp @@ -62,7 +62,7 @@ void BokehBlurOperation::initExecution() int width = this->m_inputBokehProgram->getWidth(); int height = this->m_inputBokehProgram->getHeight(); - float dimension = min(width, height); + float dimension = MIN2(width, height); this->m_bokehMidX = width / 2.0f; this->m_bokehMidY = height / 2.0f; @@ -84,7 +84,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) int bufferwidth = inputBuffer->getWidth(); int bufferstartx = inputBuffer->getRect()->xmin; int bufferstarty = inputBuffer->getRect()->ymin; - const float max_dim = max(this->getWidth(), this->getHeight()); + const float max_dim = MAX2(this->getWidth(), this->getHeight()); int pixelSize = this->m_size * max_dim / 100.0f; zero_v4(color_accum); @@ -99,10 +99,10 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) int maxy = y + pixelSize; int minx = x - pixelSize; int maxx = x + pixelSize; - miny = max(miny, inputBuffer->getRect()->ymin); - minx = max(minx, inputBuffer->getRect()->xmin); - maxy = min(maxy, inputBuffer->getRect()->ymax); - maxx = min(maxx, inputBuffer->getRect()->xmax); + miny = MAX2(miny, inputBuffer->getRect()->ymin); + minx = MAX2(minx, inputBuffer->getRect()->xmin); + maxy = MIN2(maxy, inputBuffer->getRect()->ymax); + maxx = MIN2(maxx, inputBuffer->getRect()->xmax); int step = getStep(); int offsetadd = getOffsetAdd() * COM_NUM_CHANNELS_COLOR; @@ -144,7 +144,7 @@ bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input, { rcti newInput; rcti bokehInput; - const float max_dim = max(this->getWidth(), this->getHeight()); + const float max_dim = MAX2(this->getWidth(), this->getHeight()); if (this->m_sizeavailable) { newInput.xmax = input->xmax + (this->m_size * max_dim / 100.0f); @@ -193,14 +193,14 @@ void BokehBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", nullptr); if (!this->m_sizeavailable) { updateSize(); } - const float max_dim = max(this->getWidth(), this->getHeight()); + const float max_dim = MAX2(this->getWidth(), this->getHeight()); cl_int radius = this->m_size * max_dim / 100.0f; cl_int step = this->getStep(); @@ -235,7 +235,7 @@ void BokehBlurOperation::determineResolution(unsigned int resolution[2], { NodeOperation::determineResolution(resolution, preferredResolution); if (this->m_extend_bounds) { - const float max_dim = max(resolution[0], resolution[1]); + const float max_dim = MAX2(resolution[0], resolution[1]); resolution[0] += 2 * this->m_size * max_dim / 100.0f; resolution[1] += 2 * this->m_size * max_dim / 100.0f; } diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.h b/source/blender/compositor/operations/COM_BokehBlurOperation.h index 335574a381d..a2e320dfdad 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.h @@ -67,8 +67,8 @@ class BokehBlurOperation : public NodeOperation, public QualityStepHelper { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); void setExtendBounds(bool extend_bounds) { diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp b/source/blender/compositor/operations/COM_BoxMaskOperation.cpp index 662b08bdee9..bb10f3425e2 100644 --- a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_BoxMaskOperation.cpp @@ -64,7 +64,7 @@ void BoxMaskOperation::executePixelSampled(float output[4], float x, float y, Pi switch (this->m_maskType) { case CMP_NODE_MASKTYPE_ADD: if (inside) { - output[0] = max(inputMask[0], inputValue[0]); + output[0] = MAX2(inputMask[0], inputValue[0]); } else { output[0] = inputMask[0]; diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp b/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp index a2c6fd47771..15375589888 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp @@ -95,7 +95,7 @@ void ChannelMatteOperation::executePixelSampled(float output[4], this->m_inputImageProgram->readSampled(inColor, x, y, sampler); /* matte operation */ - alpha = inColor[this->m_ids[0]] - max(inColor[this->m_ids[1]], inColor[this->m_ids[2]]); + alpha = inColor[this->m_ids[0]] - MAX2(inColor[this->m_ids[1]], inColor[this->m_ids[2]]); /* flip because 0.0 is transparent, not 1.0 */ alpha = 1.0f - alpha; @@ -116,5 +116,5 @@ void ChannelMatteOperation::executePixelSampled(float output[4], */ /* Don't make something that was more transparent less transparent. */ - output[0] = min(alpha, inColor[3]); + output[0] = MIN2(alpha, inColor[3]); } diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.h b/source/blender/compositor/operations/COM_ChannelMatteOperation.h index 24a5e03a1bf..9a0b888b5a2 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.h +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.h @@ -38,12 +38,12 @@ class ChannelMatteOperation : public NodeOperation { float m_limit_range; /** ids to use for the operations (max and simple) - * alpha = in[ids[0]] - max(in[ids[1]], in[ids[2]]) + * alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]]) * the simple operation is using: * alpha = in[ids[0]] - in[ids[1]] * but to use the same formula and operation for both we do: * ids[2] = ids[1] - * alpha = in[ids[0]] - max(in[ids[1]], in[ids[2]]) + * alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]]) */ int m_ids[3]; diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp index f9eaaf6f7a0..44eef1e19cd 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp @@ -59,7 +59,7 @@ void ColorBalanceASCCDLOperation::executePixelSampled(float output[4], this->m_inputColorOperation->readSampled(inputColor, x, y, sampler); float fac = value[0]; - fac = min(1.0f, fac); + fac = MIN2(1.0f, fac); const float mfac = 1.0f - fac; output[0] = mfac * inputColor[0] + diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp index df44e87a86a..934b7e51aee 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp @@ -64,7 +64,7 @@ void ColorBalanceLGGOperation::executePixelSampled(float output[4], this->m_inputColorOperation->readSampled(inputColor, x, y, sampler); float fac = value[0]; - fac = min(1.0f, fac); + fac = MIN2(1.0f, fac); const float mfac = 1.0f - fac; output[0] = mfac * inputColor[0] + diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp index 60343c28662..02c109e8acd 100644 --- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp @@ -66,7 +66,7 @@ void ColorCorrectionOperation::executePixelSampled(float output[4], float r, g, b; float value = inputMask[0]; - value = min(1.0f, value); + value = MIN2(1.0f, value); const float mvalue = 1.0f - value; float levelShadows = 0.0; diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp b/source/blender/compositor/operations/COM_ColorSpillOperation.cpp index 050792d8dab..8139d71c637 100644 --- a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorSpillOperation.cpp @@ -90,7 +90,7 @@ void ColorSpillOperation::executePixelSampled(float output[4], float input[4]; this->m_inputFacReader->readSampled(fac, x, y, sampler); this->m_inputImageReader->readSampled(input, x, y, sampler); - float rfac = min(1.0f, fac[0]); + float rfac = MIN2(1.0f, fac[0]); float map; switch (this->m_spillMethod) { diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp index fe395ecae9e..abf423cc48a 100644 --- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp @@ -63,13 +63,13 @@ void ConvertDepthToRadiusOperation::initExecution() (this->getHeight() / (float)this->getWidth()) : (this->getWidth() / (float)this->getHeight()); this->m_aperture = 0.5f * (this->m_cam_lens / (this->m_aspect * cam_sensor)) / this->m_fStop; - const float minsz = min(getWidth(), getHeight()); + const float minsz = MIN2(getWidth(), getHeight()); this->m_dof_sp = minsz / ((cam_sensor / 2.0f) / - this->m_cam_lens); // <- == aspect * min(img->x, img->y) / tan(0.5f * fov); + this->m_cam_lens); // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov); if (this->m_blurPostOperation) { - m_blurPostOperation->setSigma(min(m_aperture * 128.0f, this->m_maxRadius)); + m_blurPostOperation->setSigma(MIN2(m_aperture * 128.0f, this->m_maxRadius)); } } diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp index 1c2570cd251..a5f2ae404e3 100644 --- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp @@ -92,8 +92,8 @@ void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, output[3] = in2[3]; /* Make sure we don't return negative color. */ - output[0] = max(output[0], 0.0f); - output[1] = max(output[1], 0.0f); - output[2] = max(output[2], 0.0f); - output[3] = max(output[3], 0.0f); + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); + output[3] = MAX2(output[3], 0.0f); } diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp index 7e35f6fb4f6..425e87ffa7e 100644 --- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp @@ -105,10 +105,10 @@ void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, voi output[3] = output[3] * value[0] + in2[3] * mval; /* Make sure we don't return negative color. */ - output[0] = max(output[0], 0.0f); - output[1] = max(output[1], 0.0f); - output[2] = max(output[2], 0.0f); - output[3] = max(output[3], 0.0f); + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); + output[3] = MAX2(output[3], 0.0f); } bool ConvolutionFilterOperation::determineDependingAreaOfInterest( diff --git a/source/blender/compositor/operations/COM_CropOperation.cpp b/source/blender/compositor/operations/COM_CropOperation.cpp index 408f588871e..9364557169c 100644 --- a/source/blender/compositor/operations/COM_CropOperation.cpp +++ b/source/blender/compositor/operations/COM_CropOperation.cpp @@ -54,10 +54,10 @@ void CropBaseOperation::updateArea() local_settings.y2 = height - 1; } - this->m_xmax = max(local_settings.x1, local_settings.x2) + 1; - this->m_xmin = min(local_settings.x1, local_settings.x2); - this->m_ymax = max(local_settings.y1, local_settings.y2) + 1; - this->m_ymin = min(local_settings.y1, local_settings.y2); + this->m_xmax = MAX2(local_settings.x1, local_settings.x2) + 1; + this->m_xmin = MIN2(local_settings.x1, local_settings.x2); + this->m_ymax = MAX2(local_settings.y1, local_settings.y2) + 1; + this->m_ymin = MIN2(local_settings.y1, local_settings.y2); } else { this->m_xmax = 0; diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp index b2dfb558028..fbe9fe8ea27 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp @@ -41,7 +41,7 @@ void DilateErodeThresholdOperation::initExecution() } else { if (this->m_inset * 2 > this->m_distance) { - this->m_scope = max(this->m_inset * 2 - this->m_distance, this->m_distance); + this->m_scope = MAX2(this->m_inset * 2 - this->m_distance, this->m_distance); } else { this->m_scope = this->m_distance; @@ -71,10 +71,10 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); rcti *rect = inputBuffer->getRect(); - const int minx = max(x - this->m_scope, rect->xmin); - const int miny = max(y - this->m_scope, rect->ymin); - const int maxx = min(x + this->m_scope, rect->xmax); - const int maxy = min(y + this->m_scope, rect->ymax); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); const int bufferWidth = BLI_rcti_size_x(rect); int offset; @@ -87,7 +87,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, if (buffer[offset] < sw) { const float dx = xi - x; const float dis = dx * dx + dy * dy; - mindist = min(mindist, dis); + mindist = MIN2(mindist, dis); } offset++; } @@ -102,7 +102,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, if (buffer[offset] > sw) { const float dx = xi - x; const float dis = dx * dx + dy * dy; - mindist = min(mindist, dis); + mindist = MIN2(mindist, dis); } offset++; } @@ -191,10 +191,10 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void * MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); rcti *rect = inputBuffer->getRect(); - const int minx = max(x - this->m_scope, rect->xmin); - const int miny = max(y - this->m_scope, rect->ymin); - const int maxx = min(x + this->m_scope, rect->xmax); - const int maxy = min(y + this->m_scope, rect->ymax); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); const int bufferWidth = BLI_rcti_size_x(rect); int offset; @@ -207,7 +207,7 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void * const float dx = xi - x; const float dis = dx * dx + dy * dy; if (dis <= mindist) { - value = max(buffer[offset], value); + value = MAX2(buffer[offset], value); } offset++; } @@ -238,8 +238,8 @@ void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", nullptr); @@ -270,10 +270,10 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); rcti *rect = inputBuffer->getRect(); - const int minx = max(x - this->m_scope, rect->xmin); - const int miny = max(y - this->m_scope, rect->ymin); - const int maxx = min(x + this->m_scope, rect->xmax); - const int maxy = min(y + this->m_scope, rect->ymax); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); const int bufferWidth = BLI_rcti_size_x(rect); int offset; @@ -286,7 +286,7 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d const float dx = xi - x; const float dis = dx * dx + dy * dy; if (dis <= mindist) { - value = min(buffer[offset], value); + value = MIN2(buffer[offset], value); } offset++; } @@ -298,8 +298,8 @@ void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", nullptr); @@ -360,10 +360,10 @@ void *DilateStepOperation::initializeTileData(rcti *rect) int half_window = this->m_iterations; int window = half_window * 2 + 1; - int xmin = max(0, rect->xmin - half_window); - int ymin = max(0, rect->ymin - half_window); - int xmax = min(width, rect->xmax + half_window); - int ymax = min(height, rect->ymax + half_window); + int xmin = MAX2(0, rect->xmin - half_window); + int ymin = MAX2(0, rect->ymin - half_window); + int xmax = MIN2(width, rect->xmax + half_window); + int ymax = MIN2(height, rect->ymax + half_window); int bwidth = rect->xmax - rect->xmin; int bheight = rect->ymax - rect->ymin; @@ -378,7 +378,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect) // single row or column of input values, padded with FLT_MAX's to // simplify the logic. float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); - float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), + float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window), "dilate erode buf"); // The following is based on the van Herk/Gil-Werman algorithm for morphology operations. @@ -396,13 +396,13 @@ void *DilateStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (x = 1; x < window; x++) { - temp[window - 1 - x] = max(temp[window - x], buf[start - x]); - temp[window - 1 + x] = max(temp[window + x - 2], buf[start + x]); + temp[window - 1 - x] = MAX2(temp[window - x], buf[start - x]); + temp[window - 1 + x] = MAX2(temp[window + x - 2], buf[start + x]); } start = half_window + (i - 1) * window + 1; - for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) { - rectf[bwidth * (y - ymin) + (start + x)] = max(temp[x], temp[x + window - 1]); + for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) { + rectf[bwidth * (y - ymin) + (start + x)] = MAX2(temp[x], temp[x + window - 1]); } } } @@ -421,13 +421,14 @@ void *DilateStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (y = 1; y < window; y++) { - temp[window - 1 - y] = max(temp[window - y], buf[start - y]); - temp[window - 1 + y] = max(temp[window + y - 2], buf[start + y]); + temp[window - 1 - y] = MAX2(temp[window - y], buf[start - y]); + temp[window - 1 + y] = MAX2(temp[window + y - 2], buf[start + y]); } start = half_window + (i - 1) * window + 1; - for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) { - rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = max(temp[y], temp[y + window - 1]); + for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { + rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MAX2(temp[y], + temp[y + window - 1]); } } } @@ -489,10 +490,10 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) int half_window = this->m_iterations; int window = half_window * 2 + 1; - int xmin = max(0, rect->xmin - half_window); - int ymin = max(0, rect->ymin - half_window); - int xmax = min(width, rect->xmax + half_window); - int ymax = min(height, rect->ymax + half_window); + int xmin = MAX2(0, rect->xmin - half_window); + int ymin = MAX2(0, rect->ymin - half_window); + int xmax = MIN2(width, rect->xmax + half_window); + int ymax = MIN2(height, rect->ymax + half_window); int bwidth = rect->xmax - rect->xmin; int bheight = rect->ymax - rect->ymin; @@ -507,7 +508,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) // single row or column of input values, padded with FLT_MAX's to // simplify the logic. float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); - float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), + float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window), "dilate erode buf"); // The following is based on the van Herk/Gil-Werman algorithm for morphology operations. @@ -525,13 +526,13 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (x = 1; x < window; x++) { - temp[window - 1 - x] = min(temp[window - x], buf[start - x]); - temp[window - 1 + x] = min(temp[window + x - 2], buf[start + x]); + temp[window - 1 - x] = MIN2(temp[window - x], buf[start - x]); + temp[window - 1 + x] = MIN2(temp[window + x - 2], buf[start + x]); } start = half_window + (i - 1) * window + 1; - for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) { - rectf[bwidth * (y - ymin) + (start + x)] = min(temp[x], temp[x + window - 1]); + for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) { + rectf[bwidth * (y - ymin) + (start + x)] = MIN2(temp[x], temp[x + window - 1]); } } } @@ -550,13 +551,14 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (y = 1; y < window; y++) { - temp[window - 1 - y] = min(temp[window - y], buf[start - y]); - temp[window - 1 + y] = min(temp[window + y - 2], buf[start + y]); + temp[window - 1 - y] = MIN2(temp[window - y], buf[start - y]); + temp[window - 1 + y] = MIN2(temp[window + y - 2], buf[start + y]); } start = half_window + (i - 1) * window + 1; - for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) { - rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = min(temp[y], temp[y + window - 1]); + for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { + rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MIN2(temp[y], + temp[y + window - 1]); } } } diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.h b/source/blender/compositor/operations/COM_DilateErodeOperation.h index 2af5c8990ee..35f9be89220 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.h +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.h @@ -115,8 +115,8 @@ class DilateDistanceOperation : public NodeOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); }; class ErodeDistanceOperation : public DilateDistanceOperation { public: @@ -131,8 +131,8 @@ class ErodeDistanceOperation : public DilateDistanceOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); }; class DilateStepOperation : public NodeOperation { diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp index c0b9c9b6f1d..3f0cd4ef255 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp @@ -100,8 +100,8 @@ void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", nullptr); diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h index fdb7b82779e..0c220f0e239 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h @@ -61,6 +61,6 @@ class DirectionalBlurOperation : public NodeOperation, public QualityStepHelper MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); }; diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp b/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp index 38541f91fc8..a6985a40625 100644 --- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp @@ -73,7 +73,7 @@ void EllipseMaskOperation::executePixelSampled(float output[4], switch (this->m_maskType) { case CMP_NODE_MASKTYPE_ADD: if (inside) { - output[0] = max(inputMask[0], inputValue[0]); + output[0] = MAX2(inputMask[0], inputValue[0]); } else { output[0] = inputMask[0]; diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp index 157c595afcb..b3c1b6b4413 100644 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp @@ -209,7 +209,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, (void)0 // intermediate buffers - sz = max(src_width, src_height); + sz = MAX2(src_width, src_height); X = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss X buf"); Y = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss Y buf"); W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf"); diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp index d489c64953e..ca3173001cb 100644 --- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp @@ -256,7 +256,7 @@ void GaussianBlurReferenceOperation::initExecution() void GaussianBlurReferenceOperation::updateGauss() { int i; - int x = max(m_filtersizex, m_filtersizey); + int x = MAX2(m_filtersizex, m_filtersizey); m_maintabs = (float **)MEM_mallocN(x * sizeof(float *), "gauss array"); for (i = 0; i < x; i++) { m_maintabs[i] = make_gausstab(i + 1, i + 1); @@ -333,7 +333,7 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y, void GaussianBlurReferenceOperation::deinitExecution() { int x, i; - x = max(this->m_filtersizex, this->m_filtersizey); + x = MAX2(this->m_filtersizex, this->m_filtersizey); for (i = 0; i < x; i++) { MEM_freeN(this->m_maintabs[i]); } diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp index 90333f7dd79..596d439658c 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp @@ -122,8 +122,8 @@ void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel( "gaussianXBlurOperationKernel", nullptr); diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h index b2bcd79e716..78ea6aa3cc2 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h @@ -42,8 +42,8 @@ class GaussianXBlurOperation : public BlurBaseOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); /** * \brief initialize the execution diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp index c5b3cf24239..55c1551ca42 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp @@ -122,8 +122,8 @@ void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel( "gaussianYBlurOperationKernel", nullptr); diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h index d921780876a..8e7440b6fe4 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h @@ -42,8 +42,8 @@ class GaussianYBlurOperation : public BlurBaseOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); /** * \brief initialize the execution diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp index 1a1922f828c..cfa4b99cd70 100644 --- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp @@ -54,9 +54,9 @@ void GlareThresholdOperation::executePixelSampled(float output[4], output[1] -= threshold; output[2] -= threshold; - output[0] = max(output[0], 0.0f); - output[1] = max(output[1], 0.0f); - output[2] = max(output[2], 0.0f); + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); } else { zero_v3(output); diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp index 72bf86facfb..c9cc8ebc045 100644 --- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp @@ -50,7 +50,7 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data float average = 0.0f; if (this->m_axis == 0) { - const int start = max(0, x - this->m_size + 1), end = min(bufferWidth, x + this->m_size); + const int start = MAX2(0, x - this->m_size + 1), end = MIN2(bufferWidth, x + this->m_size); for (int cx = start; cx < end; cx++) { int bufferIndex = (y * bufferWidth + cx); average += buffer[bufferIndex]; @@ -58,8 +58,8 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data } } else { - const int start = max(0, y - this->m_size + 1), - end = min(inputBuffer->getHeight(), y + this->m_size); + const int start = MAX2(0, y - this->m_size + 1), + end = MIN2(inputBuffer->getHeight(), y + this->m_size); for (int cy = start; cy < end; cy++) { int bufferIndex = (cy * bufferWidth + x); average += buffer[bufferIndex]; diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp b/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp index b9bb316462d..f4d0d6c6a00 100644 --- a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp @@ -63,8 +63,8 @@ void KeyingDespillOperation::executePixelSampled(float output[4], const int other_1 = (screen_primary_channel + 1) % 3; const int other_2 = (screen_primary_channel + 2) % 3; - const int min_channel = min(other_1, other_2); - const int max_channel = max(other_1, other_2); + const int min_channel = MIN2(other_1, other_2); + const int max_channel = MAX2(other_1, other_2); float average_value, amount; diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cpp b/source/blender/compositor/operations/COM_KeyingOperation.cpp index 9ef4217d300..94e65181207 100644 --- a/source/blender/compositor/operations/COM_KeyingOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingOperation.cpp @@ -30,8 +30,8 @@ static float get_pixel_saturation(const float pixelColor[4], const int other_1 = (primary_channel + 1) % 3; const int other_2 = (primary_channel + 2) % 3; - const int min_channel = min(other_1, other_2); - const int max_channel = max(other_1, other_2); + const int min_channel = MIN2(other_1, other_2); + const int max_channel = MAX2(other_1, other_2); const float val = screen_balance * pixelColor[min_channel] + (1.0f - screen_balance) * pixelColor[max_channel]; diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp index 096930d0a83..2bd7493625e 100644 --- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp @@ -54,7 +54,7 @@ void LuminanceMatteOperation::executePixelSampled(float output[4], float alpha; /* one line thread-friend algorithm: - * output[0] = min(inputValue[3], min(1.0f, max(0.0f, ((luminance - low) / (high - low)))); + * output[0] = MIN2(inputValue[3], MIN2(1.0f, MAX2(0.0f, ((luminance - low) / (high - low)))); */ /* test range */ diff --git a/source/blender/compositor/operations/COM_MaskOperation.h b/source/blender/compositor/operations/COM_MaskOperation.h index eba14d10373..67e6b64315c 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.h +++ b/source/blender/compositor/operations/COM_MaskOperation.h @@ -84,7 +84,7 @@ class MaskOperation : public NodeOperation { void setMotionBlurSamples(int samples) { - this->m_rasterMaskHandleTot = min(max(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX); + this->m_rasterMaskHandleTot = MIN2(MAX2(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX); } void setMotionBlurShutter(float shutter) { diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp index dbec6dd1874..692c1e70462 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cpp @@ -351,7 +351,7 @@ void MathMinimumOperation::executePixelSampled(float output[4], this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - output[0] = min(inputValue1[0], inputValue2[0]); + output[0] = MIN2(inputValue1[0], inputValue2[0]); clampIfNeeded(output); } @@ -367,7 +367,7 @@ void MathMaximumOperation::executePixelSampled(float output[4], this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - output[0] = max(inputValue1[0], inputValue2[0]); + output[0] = MAX2(inputValue1[0], inputValue2[0]); clampIfNeeded(output); } diff --git a/source/blender/compositor/operations/COM_MixOperation.cpp b/source/blender/compositor/operations/COM_MixOperation.cpp index 76a66727a75..11df0900345 100644 --- a/source/blender/compositor/operations/COM_MixOperation.cpp +++ b/source/blender/compositor/operations/COM_MixOperation.cpp @@ -523,9 +523,9 @@ void MixGlareOperation::executePixelSampled(float output[4], inputColor1[2] = 0.0f; } - output[0] = mf * max(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); - output[1] = mf * max(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); - output[2] = mf * max(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); + output[0] = mf * MAX2(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); + output[1] = mf * MAX2(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); + output[2] = mf * MAX2(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); output[3] = inputColor1[3]; clampIfNeeded(output); diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp index 023538ee5b1..60936ee1939 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp @@ -21,10 +21,14 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -MultilayerBaseOperation::MultilayerBaseOperation(int passindex, int view) +MultilayerBaseOperation::MultilayerBaseOperation(RenderLayer *render_layer, + RenderPass *render_pass, + int view) { - this->m_passId = passindex; + this->m_passId = BLI_findindex(&render_layer->passes, render_pass); this->m_view = view; + this->m_renderLayer = render_layer; + this->m_renderPass = render_pass; } ImBuf *MultilayerBaseOperation::getImBuf() @@ -45,6 +49,32 @@ ImBuf *MultilayerBaseOperation::getImBuf() return nullptr; } +std::unique_ptr<MetaData> MultilayerColorOperation::getMetaData() const +{ + BLI_assert(this->m_buffer); + MetaDataExtractCallbackData callback_data = {nullptr}; + RenderResult *render_result = this->m_image->rr; + if (render_result && render_result->stamp_data) { + RenderLayer *render_layer = this->m_renderLayer; + RenderPass *render_pass = this->m_renderPass; + std::string full_layer_name = + std::string(render_layer->name, + BLI_strnlen(render_layer->name, sizeof(render_layer->name))) + + "." + + std::string(render_pass->name, BLI_strnlen(render_pass->name, sizeof(render_pass->name))); + blender::StringRef cryptomatte_layer_name = + blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(full_layer_name); + callback_data.setCryptomatteKeys(cryptomatte_layer_name); + + BKE_stamp_info_callback(&callback_data, + render_result->stamp_data, + MetaDataExtractCallbackData::extract_cryptomatte_meta_data, + false); + } + + return std::move(callback_data.meta_data); +} + void MultilayerColorOperation::executePixelSampled(float output[4], float x, float y, diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h index adfcc975ade..f5176b0a4db 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h @@ -24,34 +24,34 @@ class MultilayerBaseOperation : public BaseImageOperation { private: int m_passId; int m_view; - RenderLayer *m_renderlayer; protected: + RenderLayer *m_renderLayer; + RenderPass *m_renderPass; ImBuf *getImBuf(); public: /** * Constructor */ - MultilayerBaseOperation(int passindex, int view); - void setRenderLayer(RenderLayer *renderlayer) - { - this->m_renderlayer = renderlayer; - } + MultilayerBaseOperation(RenderLayer *render_layer, RenderPass *render_pass, int view); }; class MultilayerColorOperation : public MultilayerBaseOperation { public: - MultilayerColorOperation(int passindex, int view) : MultilayerBaseOperation(passindex, view) + MultilayerColorOperation(RenderLayer *render_layer, RenderPass *render_pass, int view) + : MultilayerBaseOperation(render_layer, render_pass, view) { this->addOutputSocket(COM_DT_COLOR); } void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + std::unique_ptr<MetaData> getMetaData() const override; }; class MultilayerValueOperation : public MultilayerBaseOperation { public: - MultilayerValueOperation(int passindex, int view) : MultilayerBaseOperation(passindex, view) + MultilayerValueOperation(RenderLayer *render_layer, RenderPass *render_pass, int view) + : MultilayerBaseOperation(render_layer, render_pass, view) { this->addOutputSocket(COM_DT_VALUE); } @@ -60,7 +60,8 @@ class MultilayerValueOperation : public MultilayerBaseOperation { class MultilayerVectorOperation : public MultilayerBaseOperation { public: - MultilayerVectorOperation(int passindex, int view) : MultilayerBaseOperation(passindex, view) + MultilayerVectorOperation(RenderLayer *render_layer, RenderPass *render_pass, int view) + : MultilayerBaseOperation(render_layer, render_pass, view) { this->addOutputSocket(COM_DT_VECTOR); } diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp index 19d49bc2ae7..bb1b312ffec 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp @@ -26,7 +26,6 @@ #include "BLI_path_util.h" #include "BLI_string.h" -#include "BKE_cryptomatte.hh" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp index 4f4116d6faa..73de60f4c34 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp @@ -20,7 +20,6 @@ #include "COM_MetaData.h" -#include "BKE_cryptomatte.hh" #include "BKE_image.h" #include "BKE_scene.h" @@ -217,74 +216,32 @@ void RenderLayersProg::determineResolution(unsigned int resolution[2], } } -struct CallbackData { - std::unique_ptr<MetaData> meta_data; - std::string hash_key; - std::string conversion_key; - std::string manifest_key; - - void addMetaData(blender::StringRef key, blender::StringRefNull value) - { - if (!meta_data) { - meta_data = std::make_unique<MetaData>(); - } - meta_data->add(key, value); - } - - void setCryptomatteKeys(blender::StringRef cryptomatte_layer_name) - { - manifest_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, - "manifest"); - hash_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key(cryptomatte_layer_name, - "hash"); - conversion_key = blender::bke::cryptomatte::BKE_cryptomatte_meta_data_key( - cryptomatte_layer_name, "conversion"); - } -}; - -/* C type callback function (StampCallback). */ -static void extract_cryptomatte_meta_data(void *_data, - const char *propname, - char *propvalue, - int UNUSED(len)) -{ - CallbackData *data = static_cast<CallbackData *>(_data); - blender::StringRefNull key(propname); - if (key == data->hash_key) { - data->addMetaData(META_DATA_KEY_CRYPTOMATTE_HASH, propvalue); - } - else if (key == data->conversion_key) { - data->addMetaData(META_DATA_KEY_CRYPTOMATTE_CONVERSION, propvalue); - } - else if (key == data->manifest_key) { - data->addMetaData(META_DATA_KEY_CRYPTOMATTE_MANIFEST, propvalue); - } -} - std::unique_ptr<MetaData> RenderLayersProg::getMetaData() const { Scene *scene = this->getScene(); Render *re = (scene) ? RE_GetSceneRender(scene) : nullptr; - RenderResult *rr = nullptr; - CallbackData callback_data = {nullptr}; + RenderResult *render_result = nullptr; + MetaDataExtractCallbackData callback_data = {nullptr}; if (re) { - rr = RE_AcquireResultRead(re); + render_result = RE_AcquireResultRead(re); } - if (rr && rr->stamp_data) { + if (render_result && render_result->stamp_data) { ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene->view_layers, getLayerId()); if (view_layer) { std::string full_layer_name = std::string( view_layer->name, BLI_strnlen(view_layer->name, sizeof(view_layer->name))) + "." + m_passName; - blender::StringRef cryptomatte_layer_name = blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name( - full_layer_name); + blender::StringRef cryptomatte_layer_name = + blender::bke::cryptomatte::BKE_cryptomatte_extract_layer_name(full_layer_name); callback_data.setCryptomatteKeys(cryptomatte_layer_name); - BKE_stamp_info_callback( - &callback_data, rr->stamp_data, extract_cryptomatte_meta_data, false); + BKE_stamp_info_callback(&callback_data, + render_result->stamp_data, + MetaDataExtractCallbackData::extract_cryptomatte_meta_data, + false); } } diff --git a/source/blender/compositor/operations/COM_RotateOperation.cpp b/source/blender/compositor/operations/COM_RotateOperation.cpp index 7a21e960c13..9a1f54a6e10 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.cpp +++ b/source/blender/compositor/operations/COM_RotateOperation.cpp @@ -93,10 +93,10 @@ bool RotateOperation::determineDependingAreaOfInterest(rcti *input, const float y2 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymin); const float y3 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymax); const float y4 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymax); - const float minx = min(x1, min(x2, min(x3, x4))); - const float maxx = max(x1, max(x2, max(x3, x4))); - const float miny = min(y1, min(y2, min(y3, y4))); - const float maxy = max(y1, max(y2, max(y3, y4))); + const float minx = MIN2(x1, MIN2(x2, MIN2(x3, x4))); + const float maxx = MAX2(x1, MAX2(x2, MAX2(x3, x4))); + const float miny = MIN2(y1, MIN2(y2, MIN2(y3, y4))); + const float maxy = MAX2(y1, MAX2(y2, MAX2(y3, y4))); newInput.xmax = ceil(maxx) + 1; newInput.xmin = floor(minx) - 1; diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp index 7cfa4de7a61..28811d479a5 100644 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp @@ -33,7 +33,7 @@ void SunBeamsOperation::initExecution() /* convert to pixels */ this->m_source_px[0] = this->m_data.source[0] * this->getWidth(); this->m_source_px[1] = this->m_data.source[1] * this->getHeight(); - this->m_ray_length_px = this->m_data.ray_length * max(this->getWidth(), this->getHeight()); + this->m_ray_length_px = this->m_data.ray_length * MAX2(this->getWidth(), this->getHeight()); } /** diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cpp b/source/blender/compositor/operations/COM_TonemapOperation.cpp index cb0fc747dcb..4c1d285a69f 100644 --- a/source/blender/compositor/operations/COM_TonemapOperation.cpp +++ b/source/blender/compositor/operations/COM_TonemapOperation.cpp @@ -51,9 +51,9 @@ void TonemapOperation::executePixel(float output[4], int x, int y, void *data) output[2] /= ((db == 0.0f) ? 1.0f : db); const float igm = avg->igm; if (igm != 0.0f) { - output[0] = powf(max(output[0], 0.0f), igm); - output[1] = powf(max(output[1], 0.0f), igm); - output[2] = powf(max(output[2], 0.0f), igm); + output[0] = powf(MAX2(output[0], 0.0f), igm); + output[1] = powf(MAX2(output[1], 0.0f), igm); + output[2] = powf(MAX2(output[2], 0.0f), igm); } } void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y, void *data) diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp index 414b5bd980a..909a2f73d25 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp @@ -74,7 +74,7 @@ void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect) this->determineDependingAreaOfInterest( rect, (ReadBufferOperation *)this->m_inputSizeProgram, &rect2); - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; data->maxBlurScalar = (int)(data->size->getMaximumValue(&rect2) * scalar); @@ -102,7 +102,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, float multiplier_accum[4]; float color_accum[4]; - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; int maxBlurScalar = tileData->maxBlurScalar; @@ -120,10 +120,10 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, int maxx = search[2]; int maxy = search[3]; #else - int minx = max(x - maxBlurScalar, 0); - int miny = max(y - maxBlurScalar, 0); - int maxx = min(x + maxBlurScalar, (int)m_width); - int maxy = min(y + maxBlurScalar, (int)m_height); + int minx = MAX2(x - maxBlurScalar, 0); + int miny = MAX2(y - maxBlurScalar, 0); + int maxx = MIN2(x + maxBlurScalar, (int)m_width); + int maxy = MIN2(y + maxBlurScalar, (int)m_height); #endif { inputSizeBuffer->readNoCheck(tempSize, x, y); @@ -145,7 +145,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, int offsetColorNxNy = offsetValueNxNy * COM_NUM_CHANNELS_COLOR; for (int nx = minx; nx < maxx; nx += addXStepValue) { if (nx != x || ny != y) { - float size = min(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center); + float size = MIN2(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center); if (size > this->m_threshold) { float dx = nx - x; if (size > fabsf(dx) && size > fabsf(dy)) { @@ -185,8 +185,8 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", nullptr); @@ -197,7 +197,7 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *sizeMemoryBuffer = this->m_inputSizeProgram->getInputMemoryBuffer( inputMemoryBuffers); - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; maxBlur = (cl_int)min_ff(sizeMemoryBuffer->getMaximumValue() * scalar, (float)this->m_maxBlur); @@ -235,7 +235,7 @@ bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest( rcti newInput; rcti bokehInput; - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; int maxBlurScalar = this->m_maxBlur * scalar; diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h index 258b5d385c0..fe927f791fa 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h @@ -80,8 +80,8 @@ class VariableSizeBokehBlurOperation : public NodeOperation, public QualityStepH MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); }; #ifdef COM_DEFOCUS_SEARCH diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp index 9fb995bf463..8d38dbfe180 100644 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp @@ -143,9 +143,9 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, } // STEP 2 - list<cl_mem> *clMemToCleanUp = new list<cl_mem>(); + std::list<cl_mem> *clMemToCleanUp = new std::list<cl_mem>(); clMemToCleanUp->push_back(clOutputBuffer); - list<cl_kernel> *clKernelsToCleanUp = new list<cl_kernel>(); + std::list<cl_kernel> *clKernelsToCleanUp = new std::list<cl_kernel>(); this->m_input->executeOpenCL(device, outputBuffer, diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cpp b/source/blender/compositor/operations/COM_ZCombineOperation.cpp index 22a37a4583e..26d3f2c7dc4 100644 --- a/source/blender/compositor/operations/COM_ZCombineOperation.cpp +++ b/source/blender/compositor/operations/COM_ZCombineOperation.cpp @@ -83,7 +83,7 @@ void ZCombineAlphaOperation::executePixelSampled(float output[4], output[0] = fac * color1[0] + ifac * color2[0]; output[1] = fac * color1[1] + ifac * color2[1]; output[2] = fac * color1[2] + ifac * color2[2]; - output[3] = max(color1[3], color2[3]); + output[3] = MAX2(color1[3], color2[3]); } void ZCombineOperation::deinitExecution() @@ -149,7 +149,7 @@ void ZCombineMaskAlphaOperation::executePixelSampled(float output[4], output[0] = color1[0] * mfac + color2[0] * fac; output[1] = color1[1] * mfac + color2[1] * fac; output[2] = color1[2] * mfac + color2[2] * fac; - output[3] = max(color1[3], color2[3]); + output[3] = MAX2(color1[3], color2[3]); } void ZCombineMaskOperation::deinitExecution() diff --git a/source/blender/datatoc/datatoc_icon.c b/source/blender/datatoc/datatoc_icon.c index 4a9c5875c17..f4f510891e0 100644 --- a/source/blender/datatoc/datatoc_icon.c +++ b/source/blender/datatoc/datatoc_icon.c @@ -72,6 +72,27 @@ static void endian_switch_uint32(unsigned int *val) *val = ((tval >> 24)) | ((tval << 8) & 0x00ff0000) | ((tval >> 8) & 0x0000ff00) | ((tval << 24)); } +static const char *path_slash_rfind(const char *string) +{ + const char *const lfslash = strrchr(string, '/'); + const char *const lbslash = strrchr(string, '\\'); + + if (!lfslash) { + return lbslash; + } + if (!lbslash) { + return lfslash; + } + + return (lfslash > lbslash) ? lfslash : lbslash; +} + +static const char *path_basename(const char *path) +{ + const char *const filename = path_slash_rfind(path); + return filename ? filename + 1 : path; +} + /* -------------------------------------------------------------------- */ /* Write a PNG from RGBA pixels */ @@ -183,6 +204,71 @@ struct IconHead { unsigned int canvas_w, canvas_h; }; +struct IconInfo { + struct IconHead head; + char *file_name; +}; + +struct IconMergeContext { + /* Information about all icons read from disk. + * Is used for sanity checks like prevention of two files defining icon for + * the same position on canvas. */ + int num_read_icons; + struct IconInfo *read_icons; +}; + +static void icon_merge_context_init(struct IconMergeContext *context) +{ + context->num_read_icons = 0; + context->read_icons = NULL; +} + +/* Get icon information from the context which matches given icon head. + * Is used to check whether icon is re-defined, and to provide useful information about which + * files are conflicting. */ +static struct IconInfo *icon_merge_context_info_for_icon_head(struct IconMergeContext *context, + struct IconHead *icon_head) +{ + if (context->read_icons == NULL) { + return NULL; + } + + for (int i = 0; i < context->num_read_icons; i++) { + struct IconInfo *read_icon_info = &context->read_icons[i]; + const struct IconHead *read_icon_head = &read_icon_info->head; + if (read_icon_head->orig_x == icon_head->orig_x && + read_icon_head->orig_y == icon_head->orig_y) { + return read_icon_info; + } + } + + return NULL; +} + +static void icon_merge_context_register_icon(struct IconMergeContext *context, + const char *file_name, + struct IconHead *icon_head) +{ + context->read_icons = realloc(context->read_icons, + sizeof(struct IconInfo) * (context->num_read_icons + 1)); + + struct IconInfo *icon_info = &context->read_icons[context->num_read_icons]; + icon_info->head = *icon_head; + icon_info->file_name = strdup(path_basename(file_name)); + + context->num_read_icons++; +} + +static void icon_merge_context_free(struct IconMergeContext *context) +{ + if (context->read_icons != NULL) { + for (int i = 0; i < context->num_read_icons; i++) { + free(context->read_icons[i].file_name); + } + free(context->read_icons); + } +} + static bool icon_decode_head(FILE *f_src, struct IconHead *r_head) { if (fread(r_head, 1, sizeof(*r_head), f_src) == sizeof(*r_head)) { @@ -247,7 +333,8 @@ static bool icon_read(const char *file_src, struct IconHead *r_head, unsigned in return success; } -static bool icon_merge(const char *file_src, +static bool icon_merge(struct IconMergeContext *context, + const char *file_src, unsigned int **r_pixels_canvas, unsigned int *r_canvas_w, unsigned int *r_canvas_h) @@ -265,6 +352,15 @@ static bool icon_merge(const char *file_src, return false; } + struct IconInfo *read_icon_info = icon_merge_context_info_for_icon_head(context, &head); + if (read_icon_info != NULL) { + printf( + "Conflicting icon files %s and %s\n", path_basename(file_src), read_icon_info->file_name); + free(pixels); + return false; + } + icon_merge_context_register_icon(context, file_src, &head); + if (*r_canvas_w == 0) { /* init once */ *r_canvas_w = head.canvas_w; @@ -315,9 +411,13 @@ static bool icondir_to_png(const char *path_src, const char *file_dst) int path_str_len; int found = 0, fail = 0; + struct IconMergeContext context; + unsigned int *pixels_canvas = NULL; unsigned int canvas_w = 0, canvas_h = 0; + icon_merge_context_init(&context); + errno = 0; dir = opendir(path_src); if (dir == NULL) { @@ -335,7 +435,7 @@ static bool icondir_to_png(const char *path_src, const char *file_dst) strcpy(filename, fname->d_name); - if (icon_merge(filepath, &pixels_canvas, &canvas_w, &canvas_h)) { + if (icon_merge(&context, filepath, &pixels_canvas, &canvas_w, &canvas_h)) { found++; } else { @@ -344,6 +444,8 @@ static bool icondir_to_png(const char *path_src, const char *file_dst) } } + icon_merge_context_free(&context); + closedir(dir); if (found == 0) { @@ -359,7 +461,7 @@ static bool icondir_to_png(const char *path_src, const char *file_dst) free(pixels_canvas); - return true; + return (fail == 0); } /* -------------------------------------------------------------------- */ diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 14c91834739..df8c8215d2f 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -33,9 +33,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_ID.h" /* for ID_Type */ - -#include "BKE_main.h" /* for MAX_LIBARRAY */ +#include "DNA_ID.h" /* for ID_Type and INDEX_ID_MAX */ #include "BLI_threads.h" /* for SpinLock */ @@ -111,10 +109,10 @@ struct Depsgraph { bool need_update; /* Indicates which ID types were updated. */ - char id_type_updated[MAX_LIBARRAY]; + char id_type_updated[INDEX_ID_MAX]; /* Indicates type of IDs present in the depsgraph. */ - char id_type_exist[MAX_LIBARRAY]; + char id_type_exist[INDEX_ID_MAX]; /* Quick-Access Temp Data ............. */ diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 34465c12914..ed002321729 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -86,7 +86,7 @@ void verify_id_properties_freed(DEGObjectIterData *data) const Object *dupli_object = data->dupli_object_current->ob; Object *temp_dupli_object = &data->temp_dupli_object; if (temp_dupli_object->id.properties == nullptr) { - // No ID properties in temp datablock -- no leak is possible. + // No ID properties in temp data-block -- no leak is possible. return; } if (temp_dupli_object->id.properties == dupli_object->id.properties) { @@ -435,7 +435,7 @@ static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) { bNodeTree *ntree = ntreeFromID(id_cow); - /* Nodetree is considered part of the datablock. */ + /* Node-tree is considered part of the data-block. */ if (!(ntree && (ntree->id.recalc & ID_RECALC_ALL))) { iter->skip = true; return; diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index c60ec4351bc..2051ee3657a 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -253,7 +253,7 @@ void depsgraph_update_editors_tag(Main *bmain, Depsgraph *graph, ID *id) { /* NOTE: We handle this immediately, without delaying anything, to be * sure we don't cause threading issues with OpenGL. */ - /* TODO(sergey): Make sure this works for CoW-ed datablocks as well. */ + /* TODO(sergey): Make sure this works for CoW-ed data-blocks as well. */ DEGEditorUpdateContext update_ctx = {nullptr}; update_ctx.bmain = bmain; update_ctx.depsgraph = (::Depsgraph *)graph; @@ -306,7 +306,7 @@ void depsgraph_tag_component(Depsgraph *graph, /* This is a tag compatibility with legacy code. * * Mainly, old code was tagging object with ID_RECALC_GEOMETRY tag to inform - * that object's data datablock changed. Now API expects that ID is given + * that object's data data-block changed. Now API expects that ID is given * explicitly, but not all areas are aware of this yet. */ void deg_graph_id_tag_legacy_compat( Main *bmain, Depsgraph *depsgraph, ID *id, IDRecalcFlag tag, eUpdateSource update_source) @@ -667,7 +667,7 @@ void graph_id_tag_update( IDRecalcFlag tag = (IDRecalcFlag)(1 << bitscan_forward_clear_i(¤t_flag)); graph_id_tag_update_single_flag(bmain, graph, id, id_node, tag, update_source); } - /* Special case for nested node tree datablocks. */ + /* Special case for nested node tree data-blocks. */ id_tag_update_ntree_special(bmain, graph, id, flag, update_source); /* Direct update tags means that something outside of simulated/cached * physics did change and that cache is to be invalidated. @@ -777,12 +777,12 @@ void DEG_graph_time_tag_update(struct Depsgraph *depsgraph) deg_graph->tag_time_source(); } -/* Mark a particular datablock type as having changing. */ +/* Mark a particular data-block type as having changing. */ void DEG_graph_id_type_tag(Depsgraph *depsgraph, short id_type) { if (id_type == ID_NT) { - /* Stupid workaround so parent datablocks of nested nodetree get looped - * over when we loop over tagged datablock types. */ + /* Stupid workaround so parent data-blocks of nested node-tree get looped + * over when we loop over tagged data-block types. */ DEG_graph_id_type_tag(depsgraph, ID_MA); DEG_graph_id_type_tag(depsgraph, ID_TE); DEG_graph_id_type_tag(depsgraph, ID_LA); diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc index 3c0df93f4b9..c1d2dd8b6cc 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.cc @@ -59,14 +59,14 @@ void animated_property_store_cb(ID *id, FCurve *fcurve, void *data_v) /* Resolve path to the property. */ PathResolvedRNA resolved_rna; - if (!BKE_animsys_store_rna_setting( + if (!BKE_animsys_rna_path_resolve( &data->id_pointer_rna, fcurve->rna_path, fcurve->array_index, &resolved_rna)) { return; } /* Read property value. */ float value; - if (!BKE_animsys_read_rna_setting(&resolved_rna, &value)) { + if (!BKE_animsys_read_from_rna_path(&resolved_rna, &value)) { return; } @@ -127,15 +127,15 @@ void AnimationBackup::restore_to_id(ID *id) * NOTE: Do it again (after storing), since the sub-data pointers might be * changed after copy-on-write. */ PathResolvedRNA resolved_rna; - if (!BKE_animsys_store_rna_setting(&id_pointer_rna, - value_backup.rna_path.c_str(), - value_backup.array_index, - &resolved_rna)) { + if (!BKE_animsys_rna_path_resolve(&id_pointer_rna, + value_backup.rna_path.c_str(), + value_backup.array_index, + &resolved_rna)) { return; } /* Write property value. */ - if (!BKE_animsys_write_rna_setting(&resolved_rna, value_backup.value)) { + if (!BKE_animsys_write_to_rna_path(&resolved_rna, value_backup.value)) { return; } } diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c index c95279fc078..0cb2d55d1eb 100644 --- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c +++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c @@ -124,8 +124,20 @@ void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata) if (!DRW_state_is_image_render()) { return; } - if (eevee_cryptomatte_active_layers(view_layer) != 0) { - g_data->cryptomatte_session = BKE_cryptomatte_init(); + const eViewLayerCryptomatteFlags active_layers = eevee_cryptomatte_active_layers(view_layer); + if (active_layers) { + struct CryptomatteSession *session = BKE_cryptomatte_init(); + if ((active_layers & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) { + BKE_cryptomatte_add_layer(session, "CryptoObject"); + } + if ((active_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) { + BKE_cryptomatte_add_layer(session, "CryptoMaterial"); + } + if ((active_layers & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) { + BKE_cryptomatte_add_layer(session, "CryptoAsset"); + } + g_data->cryptomatte_session = session; + g_data->render_passes |= EEVEE_RENDER_PASS_CRYPTOMATTE | EEVEE_RENDER_PASS_VOLUME_LIGHT; g_data->cryptomatte_accurate_mode = (view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ACCURATE) != 0; @@ -208,20 +220,22 @@ static DRWShadingGroup *eevee_cryptomatte_shading_group_create(EEVEE_Data *vedat EEVEE_PassList *psl = vedata->psl; int layer_offset = 0; if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) { - uint32_t cryptomatte_hash = BKE_cryptomatte_object_hash(g_data->cryptomatte_session, ob); + uint32_t cryptomatte_hash = BKE_cryptomatte_object_hash( + g_data->cryptomatte_session, "CryptoObject", ob); float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash); cryptohash[layer_offset] = cryptomatte_color_value; layer_offset++; } if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) { - uint32_t cryptomatte_hash = BKE_cryptomatte_material_hash(g_data->cryptomatte_session, - material); + uint32_t cryptomatte_hash = BKE_cryptomatte_material_hash( + g_data->cryptomatte_session, "CryptoMaterial", material); float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash); cryptohash[layer_offset] = cryptomatte_color_value; layer_offset++; } if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) { - uint32_t cryptomatte_hash = BKE_cryptomatte_asset_hash(g_data->cryptomatte_session, ob); + uint32_t cryptomatte_hash = BKE_cryptomatte_asset_hash( + g_data->cryptomatte_session, "CryptoAsset", ob); float cryptomatte_color_value = BKE_cryptomatte_hash_to_float(cryptomatte_hash); cryptohash[layer_offset] = cryptomatte_color_value; layer_offset++; @@ -693,30 +707,9 @@ void EEVEE_cryptomatte_store_metadata(EEVEE_Data *vedata, RenderResult *render_r EEVEE_PrivateData *g_data = vedata->stl->g_data; const DRWContextState *draw_ctx = DRW_context_state_get(); const ViewLayer *view_layer = draw_ctx->view_layer; - const eViewLayerCryptomatteFlags cryptomatte_layers = view_layer->cryptomatte_flag & - VIEW_LAYER_CRYPTOMATTE_ALL; BLI_assert(g_data->cryptomatte_session); - if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_OBJECT) != 0) { - BKE_cryptomatte_store_metadata(g_data->cryptomatte_session, - render_result, - view_layer, - VIEW_LAYER_CRYPTOMATTE_OBJECT, - "CryptoObject"); - } - if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_MATERIAL) != 0) { - BKE_cryptomatte_store_metadata(g_data->cryptomatte_session, - render_result, - view_layer, - VIEW_LAYER_CRYPTOMATTE_MATERIAL, - "CryptoMaterial"); - } - if ((cryptomatte_layers & VIEW_LAYER_CRYPTOMATTE_ASSET) != 0) { - BKE_cryptomatte_store_metadata(g_data->cryptomatte_session, - render_result, - view_layer, - VIEW_LAYER_CRYPTOMATTE_ASSET, - "CryptoAsset"); - } + + BKE_cryptomatte_store_metadata(g_data->cryptomatte_session, render_result, view_layer); } /** \} */ diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c index 33d45d61d42..5f8e0106337 100644 --- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -273,9 +273,12 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), float minimal_overblur = 1.0f / sqrtf(sample_count); float user_overblur = scene_eval->eevee.bokeh_overblur / 100.0f; - effects->dof_coc_params[1] *= minimal_overblur + user_overblur; + minimal_overblur *= effects->dof_coc_params[1]; + user_overblur *= effects->dof_coc_params[1]; + + effects->dof_coc_params[1] = minimal_overblur + user_overblur; /* Avoid dilating the shape. Over-blur only soften. */ - effects->dof_jitter_radius -= effects->dof_coc_params[1]; + effects->dof_jitter_radius -= minimal_overblur + user_overblur * 0.5f; } } else { diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 145fddf62a0..37ecdb20651 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -196,7 +196,7 @@ static uint eevee_lightcache_memsize_get(LightCache *lcache) return size; } -static bool eevee_lightcache_version_check(LightCache *lcache) +static bool eevee_lightcache_version_check(const LightCache *lcache) { switch (lcache->type) { case LIGHTCACHE_TYPE_STATIC: @@ -313,7 +313,14 @@ static bool EEVEE_lightcache_validate(const LightCache *light_cache, const int grid_len, const int irr_size[3]) { - if (light_cache && !(light_cache->flag & LIGHTCACHE_INVALID)) { + if (light_cache == NULL) { + return false; + } + if (!eevee_lightcache_version_check(light_cache)) { + return false; + } + + if (!(light_cache->flag & LIGHTCACHE_INVALID)) { /* See if we need the same amount of texture space. */ if ((irr_size[0] == light_cache->grid_tx.tex_size[0]) && (irr_size[1] == light_cache->grid_tx.tex_size[1]) && diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index ae01aee5dae..7fd39007263 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -208,12 +208,14 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, DRW_shgroup_stencil_mask(shgrp, sss_id); { + eGPUSamplerState state = GPU_SAMPLER_DEFAULT; + DRWShadingGroup *grp = DRW_shgroup_create(EEVEE_shaders_subsurface_first_pass_sh_get(), psl->sss_blur_ps); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_irradiance); - DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); + DRW_shgroup_uniform_texture_ref_ex(grp, "sssIrradiance", &effects->sss_irradiance, state); + DRW_shgroup_uniform_texture_ref_ex(grp, "sssRadius", &effects->sss_radius, state); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); @@ -223,9 +225,9 @@ void EEVEE_subsurface_add_pass(EEVEE_ViewLayerData *sldata, grp = DRW_shgroup_create(EEVEE_shaders_subsurface_second_pass_sh_get(), psl->sss_resolve_ps); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", depth_src); - DRW_shgroup_uniform_texture_ref(grp, "sssIrradiance", &effects->sss_blur); - DRW_shgroup_uniform_texture_ref(grp, "sssAlbedo", &effects->sss_albedo); - DRW_shgroup_uniform_texture_ref(grp, "sssRadius", &effects->sss_radius); + DRW_shgroup_uniform_texture_ref_ex(grp, "sssIrradiance", &effects->sss_blur, state); + DRW_shgroup_uniform_texture_ref_ex(grp, "sssAlbedo", &effects->sss_albedo, state); + DRW_shgroup_uniform_texture_ref_ex(grp, "sssRadius", &effects->sss_radius, state); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_block(grp, "renderpass_block", sldata->renderpass_ubo.combined); diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index bc2895ef3df..5f0fde134d1 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -135,6 +135,60 @@ void accumulate_light(vec3 light, float fac, inout vec4 accum) accum += vec4(light, 1.0) * min(fac, (1.0 - accum.a)); } +/* Same thing as Cycles without the comments to make it shorter. */ +vec3 ensure_valid_reflection(vec3 Ng, vec3 I, vec3 N) +{ + vec3 R = -reflect(I, N); + + /* Reflection rays may always be at least as shallow as the incoming ray. */ + float threshold = min(0.9 * dot(Ng, I), 0.025); + if (dot(Ng, R) >= threshold) { + return N; + } + + float NdotNg = dot(N, Ng); + vec3 X = normalize(N - NdotNg * Ng); + + float Ix = dot(I, X), Iz = dot(I, Ng); + float Ix2 = sqr(Ix), Iz2 = sqr(Iz); + float a = Ix2 + Iz2; + + float b = sqrt(Ix2 * (a - sqr(threshold))); + float c = Iz * threshold + a; + + float fac = 0.5 / a; + float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c); + bool valid1 = (N1_z2 > 1e-5) && (N1_z2 <= (1.0 + 1e-5)); + bool valid2 = (N2_z2 > 1e-5) && (N2_z2 <= (1.0 + 1e-5)); + + vec2 N_new; + if (valid1 && valid2) { + /* If both are possible, do the expensive reflection-based check. */ + vec2 N1 = vec2(sqrt(1.0 - N1_z2), sqrt(N1_z2)); + vec2 N2 = vec2(sqrt(1.0 - N2_z2), sqrt(N2_z2)); + + float R1 = 2.0 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz; + float R2 = 2.0 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz; + + valid1 = (R1 >= 1e-5); + valid2 = (R2 >= 1e-5); + if (valid1 && valid2) { + N_new = (R1 < R2) ? N1 : N2; + } + else { + N_new = (R1 > R2) ? N1 : N2; + } + } + else if (valid1 || valid2) { + float Nz2 = valid1 ? N1_z2 : N2_z2; + N_new = vec2(sqrt(1.0 - Nz2), sqrt(Nz2)); + } + else { + return Ng; + } + return N_new.x * X + N_new.y * Ng; +} + /* ----------- Cone angle Approximation --------- */ /* Return a fitted cone angle given the input roughness */ diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl index 5c10a7f451f..00d265a48b0 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl @@ -3,6 +3,7 @@ #pragma BLENDER_REQUIRE(lights_lib.glsl) #pragma BLENDER_REQUIRE(lightprobe_lib.glsl) #pragma BLENDER_REQUIRE(ambient_occlusion_lib.glsl) +#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl) struct ClosureInputGlossy { vec3 N; /** Shading normal. */ @@ -39,6 +40,10 @@ ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in, cl_in.roughness = clamp(cl_in.roughness, 1e-8, 0.9999); cl_out.radiance = vec3(0.0); +#ifndef STEP_RESOLVE /* SSR */ + cl_in.N = ensure_valid_reflection(cl_common.Ng, cl_common.V, cl_in.N); +#endif + float NV = dot(cl_in.N, cl_common.V); vec2 lut_uv = lut_coords(NV, cl_in.roughness); diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index a4b29d68ac4..ecff28dcd38 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -80,25 +80,24 @@ void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); vec3 R = reflect(-V, H); + const float bad_ray_threshold = 0.01; + + vec3 vNg = safe_normalize(cross(dFdx(vP), dFdy(vP))); + /* If ray is bad (i.e. going below the surface) regenerate. */ - /* This threshold is a bit higher than 0 to improve self intersection cases. */ - const float bad_ray_threshold = 0.085; - if (dot(R, N) <= bad_ray_threshold) { + if (dot(R, vNg) < bad_ray_threshold) { H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); R = reflect(-V, H); } - - if (dot(R, N) <= bad_ray_threshold) { + if (dot(R, vNg) < bad_ray_threshold) { H = sample_ggx(rand.xzw * vec3(1.0, 1.0, -1.0), a2, N, T, B, NH); R = reflect(-V, H); } - - if (dot(R, N) <= bad_ray_threshold) { + if (dot(R, vNg) < bad_ray_threshold) { H = sample_ggx(rand.xzw * vec3(1.0, -1.0, 1.0), a2, N, T, B, NH); R = reflect(-V, H); } - - if (dot(R, N) <= bad_ray_threshold) { + if (dot(R, vNg) < bad_ray_threshold) { /* Not worth tracing. */ return; } diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index 2a53a4f119f..1964adf3059 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -26,7 +26,7 @@ void main(void) vec2 pixel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); /* TODO precompute */ vec2 uvs = gl_FragCoord.xy * pixel_size; vec3 sss_irradiance = texture(sssIrradiance, uvs).rgb; - float sss_radius = texture(sssRadius, uvs).r; + float sss_radius = texture(sssRadius, uvs).r * radii_max_radius.w; float depth = texture(depthBuffer, uvs).r; float depth_view = get_view_z_from_depth(depth); @@ -43,8 +43,7 @@ void main(void) /* Compute kernel bounds in 2D. */ float homcoord = ProjectionMatrix[2][3] * depth_view + ProjectionMatrix[3][3]; vec2 scale = vec2(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) * sss_radius / homcoord; - vec2 finalStep = scale * radii_max_radius.w; - finalStep *= 0.5; /* samples range -1..1 */ + vec2 finalStep = scale * 0.5; /* samples range -1..1 */ /* Center sample */ vec3 accum = sss_irradiance * kernel[0].rgb; @@ -55,15 +54,18 @@ void main(void) vec3 color = texture(sssIrradiance, sample_uv).rgb; float sample_depth = texture(depthBuffer, sample_uv).r; sample_depth = get_view_z_from_depth(sample_depth); - /* Depth correction factor. */ - float depth_delta = depth_view - sample_depth; - float s = clamp(1.0 - exp(-(depth_delta * depth_delta) / (2.0 * sss_radius)), 0.0, 1.0); + /* Depth correction factor. See Real Time Realistic Skin Translucency 2010 + * by Jimenez, eqs. 2 and 9, and D9740. + * Coefficient -2 follows from gaussian_profile() from gpu_material.c and + * from the definition of finalStep. */ + float depth_delta = (depth_view - sample_depth) / sss_radius; + float s = exp(-2.0 * sqr(depth_delta)); /* Out of view samples. */ if (any(lessThan(sample_uv, vec2(0.0))) || any(greaterThan(sample_uv, vec2(1.0)))) { - s = 1.0; + s = 0.0; } /* Mix with first sample in failure case and apply kernel color. */ - accum += kernel[i].rgb * mix(color, sss_irradiance, s); + accum += kernel[i].rgb * mix(sss_irradiance, color, s); } #if defined(FIRST_PASS) diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index de384146b80..c9b5d0dea36 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -304,5 +304,8 @@ vec3 probe_evaluate_grid(GridData gd, vec3 P, vec3 N, vec3 localpos) vec3 probe_evaluate_world_diff(vec3 N) { + if (prbNumRenderGrid == 0) { + return vec3(0); + } return irradiance_from_cell_get(0, N); } diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl index 9b852a57ec4..b1e3a40e8d2 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl @@ -98,7 +98,7 @@ vec3 light_volume(LightData ld, vec4 l_vector) return tint * lum; } -#define VOLUMETRIC_SHADOW_MAX_STEP 32.0 +#define VOLUMETRIC_SHADOW_MAX_STEP 128.0 vec3 participating_media_extinction(vec3 wpos, sampler3D volume_extinction) { @@ -115,10 +115,10 @@ vec3 light_volume_shadow(LightData ld, vec3 ray_wpos, vec4 l_vector, sampler3D v #if defined(VOLUME_SHADOW) /* Heterogeneous volume shadows */ float dd = l_vector.w / volShadowSteps; - vec3 L = l_vector.xyz * l_vector.w; + vec3 L = l_vector.xyz / volShadowSteps; vec3 shadow = vec3(1.0); - for (float s = 0.5; s < VOLUMETRIC_SHADOW_MAX_STEP && s < (volShadowSteps - 0.1); s += 1.0) { - vec3 pos = ray_wpos + L * (s / volShadowSteps); + for (float s = 1.0; s < VOLUMETRIC_SHADOW_MAX_STEP && s <= volShadowSteps; s += 1.0) { + vec3 pos = ray_wpos + L * s; vec3 s_extinction = participating_media_extinction(pos, volume_extinction); shadow *= exp(-s_extinction * dd); } diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 66ba558c4f4..739723b3af0 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -970,8 +970,15 @@ GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob) int DRW_cache_object_material_count_get(struct Object *ob) { + short type = ob->type; + Mesh *me = BKE_object_get_evaluated_mesh(ob); - short type = (me != NULL) ? OB_MESH : ob->type; + if (me != NULL && type != OB_POINTCLOUD) { + /* Some object types (e.g. curves) can have a Curve in ob->data, but will be rendered as mesh. + * For point clouds this never happens. Ideally this check would happen at another level and we + * would just have to care about ob->data here. */ + type = OB_MESH; + } switch (type) { case OB_MESH: diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index f540ff09032..84bc0327aa2 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -46,10 +46,10 @@ struct DupliObject; struct Object; -/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */ +/** Use draw manager to call GPU_select, see: #DRW_draw_select_loop */ #define USE_GPU_SELECT -/* Use drawcall batching using instanced rendering. */ +/** Use draw-call batching using instanced rendering. */ #define USE_BATCHING 1 // #define DRW_DEBUG_CULLING diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c index 98a6b2bff00..9bfc8d98fe4 100644 --- a/source/blender/draw/intern/draw_manager_profiling.c +++ b/source/blender/draw/intern/draw_manager_profiling.c @@ -151,7 +151,6 @@ void DRW_stats_group_end(void) void DRW_stats_query_start(const char *name) { GPU_debug_group_begin(name); - drw_stats_timer_start_ex(name, false); drw_stats_timer_start_ex(name, true); } diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 38820e05869..711ec0a9d22 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -2544,7 +2544,7 @@ static bool animchannels_find_poll(bContext *C) } /* find_invoke() - Get initial channels */ -static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *evt) +static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; @@ -2557,7 +2557,7 @@ static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent * RNA_string_set(op->ptr, "query", ac.ads->searchstr); /* defer to popup */ - return WM_operator_props_popup(C, op, evt); + return WM_operator_props_popup(C, op, event); } /* find_exec() - Called to set the value */ diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index b344e67f62d..1809daa3fcb 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -305,6 +305,7 @@ static void fmodifier_frame_range_draw(const bContext *C, Panel *panel) PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL); uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); FModifier *fcm = (FModifier *)ptr->data; uiLayoutSetActive(layout, fcm->flag & FMODIFIER_FLAG_RANGERESTRICT); @@ -478,6 +479,7 @@ static void fn_generator_panel_draw(const bContext *C, Panel *panel) uiItemR(layout, ptr, "function_type", 0, "", ICON_NONE); uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_additive", 0, NULL, ICON_NONE); @@ -698,6 +700,7 @@ static void envelope_panel_draw(const bContext *C, Panel *panel) FMod_Envelope *env = (FMod_Envelope *)fcm->data; uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); /* General settings. */ col = uiLayoutColumn(layout, true); @@ -792,6 +795,7 @@ static void limits_panel_draw(const bContext *C, Panel *panel) PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL); uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); /* Minimums. */ col = uiLayoutColumn(layout, false); @@ -853,6 +857,7 @@ static void stepped_panel_draw(const bContext *C, Panel *panel) PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL); uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); /* Stepping Settings. */ col = uiLayoutColumn(layout, false); diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index bb5bcd4083e..66ca38ce218 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -552,9 +552,12 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n } } -/* Helper function for armature separating - remove certain bones from the given armature - * sel: remove selected bones from the armature, otherwise the unselected bones are removed - * (ob is not in edit-mode) +/** + * Helper function for armature separating - remove certain bones from the given armature. + * + * \param ob: Armature object (must not be is not in edit-mode). + * \param is_select: remove selected bones from the armature, + * otherwise the unselected bones are removed. */ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_select) { @@ -621,7 +624,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op) bool ok = false; /* set wait cursor in case this takes a while */ - WM_cursor_wait(1); + WM_cursor_wait(true); uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( @@ -706,7 +709,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op) MEM_freeN(bases); /* Recalculate/redraw + cleanup */ - WM_cursor_wait(0); + WM_cursor_wait(false); if (ok) { BKE_report(op->reports, RPT_INFO, "Separated bones"); diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 78bce8679bb..e65871c0896 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -476,9 +476,9 @@ static int pose_clear_paths_exec(bContext *C, wmOperator *op) } /* operator callback/wrapper */ -static int pose_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *evt) +static int pose_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if ((evt->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) { + if ((event->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) { RNA_boolean_set(op->ptr, "only_selected", true); } return pose_clear_paths_exec(C, op); diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 45f623f3a9d..dd90f9f2cc3 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -1321,10 +1321,10 @@ static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step) } /* specially handle events for searching */ -static void poselib_preview_handle_search(tPoseLib_PreviewData *pld, ushort event, char ascii) +static void poselib_preview_handle_search(tPoseLib_PreviewData *pld, ushort event_type, char ascii) { /* try doing some form of string manipulation first */ - switch (event) { + switch (event_type) { case EVT_BACKSPACEKEY: if (pld->searchstr[0] && pld->search_cursor) { short len = strlen(pld->searchstr); diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 0593cedb5a1..33ef6a5d026 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1359,7 +1359,7 @@ static int separate_exec(bContext *C, wmOperator *op) int error_generic; } status = {0}; - WM_cursor_wait(1); + WM_cursor_wait(true); uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( @@ -1426,7 +1426,7 @@ static int separate_exec(bContext *C, wmOperator *op) status.changed++; } MEM_freeN(bases); - WM_cursor_wait(0); + WM_cursor_wait(false); if (status.unselected == bases_len) { BKE_report(op->reports, RPT_ERROR, "No point was selected"); diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index c8bd38d58fe..e9817f82090 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -2093,7 +2093,7 @@ static void annotation_draw_apply_event( p->mval[1] = (float)event->mval[1] - y; /* Key to toggle stabilization. */ - if (event->shift > 0 && p->paintmode == GP_PAINTMODE_DRAW) { + if (event->shift && p->paintmode == GP_PAINTMODE_DRAW) { /* Using permanent stabilization, shift will deactivate the flag. */ if (p->flags & GP_PAINTFLAG_USE_STABILIZER) { if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) { @@ -2108,7 +2108,7 @@ static void annotation_draw_apply_event( } } /* verify key status for straight lines */ - else if ((event->ctrl > 0) || (event->alt > 0)) { + else if (event->ctrl || event->alt) { if (p->straight[0] == 0) { int dx = abs((int)(p->mval[0] - p->mvalo[0])); int dy = abs((int)(p->mval[1] - p->mvalo[1])); @@ -2348,7 +2348,7 @@ static int annotation_draw_invoke(bContext *C, wmOperator *op, const wmEvent *ev p->flags |= GP_PAINTFLAG_USE_STABILIZER | GP_PAINTFLAG_USE_STABILIZER_TEMP; annotation_draw_toggle_stabilizer_cursor(p, true); } - else if (event->shift > 0) { + else if (event->shift) { p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP; annotation_draw_toggle_stabilizer_cursor(p, true); } diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index c76c2e55d2b..fd2758c8a08 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -1420,7 +1420,7 @@ void GPENCIL_OT_layer_merge(wmOperatorType *ot) /* ********************** Change Layer ***************************** */ -static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt)) +static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { uiPopupMenu *pup; uiLayout *layout; @@ -1676,7 +1676,7 @@ void GPENCIL_OT_stroke_arrange(wmOperatorType *ot) /* identifiers */ ot->name = "Arrange Stroke"; ot->idname = "GPENCIL_OT_stroke_arrange"; - ot->description = "Arrange selected strokes up/down in the drawing order of the active layer"; + ot->description = "Arrange selected strokes up/down in the display order of the active layer"; /* callbacks */ ot->exec = gpencil_stroke_arrange_exec; diff --git a/source/blender/editors/gpencil/gpencil_edit_curve.c b/source/blender/editors/gpencil/gpencil_edit_curve.c index 0f9a8c93df9..e766a410889 100644 --- a/source/blender/editors/gpencil/gpencil_edit_curve.c +++ b/source/blender/editors/gpencil/gpencil_edit_curve.c @@ -131,7 +131,7 @@ void GPENCIL_OT_stroke_enter_editcurve_mode(wmOperatorType *ot) "Error Threshold", "Threshold on the maximum deviation from the actual stroke", FLT_MIN, - 10.f); + 10.0f); RNA_def_property_ui_range(prop, FLT_MIN, 10.0f, 0.1f, 5); } diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 406daf9f92e..85130e89ad1 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -55,6 +55,7 @@ #include "BKE_screen.h" #include "ED_gpencil.h" +#include "ED_keyframing.h" #include "ED_screen.h" #include "ED_space_api.h" #include "ED_view3d.h" @@ -542,12 +543,18 @@ static void gpencil_draw_datablock(tGPDfill *tgpf, const float ink[4]) if (gpl == tgpf->gpl) { if ((gpl->actframe == NULL) || (gpl->actframe->framenum != tgpf->active_cfra)) { short add_frame_mode; - if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { - add_frame_mode = GP_GETFRAME_ADD_COPY; + if (IS_AUTOKEY_ON(tgpf->scene)) { + if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { + add_frame_mode = GP_GETFRAME_ADD_COPY; + } + else { + add_frame_mode = GP_GETFRAME_ADD_NEW; + } } else { - add_frame_mode = GP_GETFRAME_ADD_NEW; + add_frame_mode = GP_GETFRAME_USE_PREV; } + BKE_gpencil_layer_frame_get(gpl, tgpf->active_cfra, add_frame_mode); } } @@ -1456,7 +1463,10 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) tgpf->done = true; /* Get frame or create a new one. */ - tgpf->gpf = BKE_gpencil_layer_frame_get(tgpf->gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW); + tgpf->gpf = BKE_gpencil_layer_frame_get(tgpf->gpl, + tgpf->active_cfra, + IS_AUTOKEY_ON(tgpf->scene) ? GP_GETFRAME_ADD_NEW : + GP_GETFRAME_USE_PREV); /* Set frame as selected. */ tgpf->gpf->flag |= GP_FRAME_SELECT; @@ -2064,6 +2074,12 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) estate = OPERATOR_CANCELLED; break; case LEFTMOUSE: + if (!IS_AUTOKEY_ON(tgpf->scene) && (!is_multiedit) && (tgpf->gpl->actframe == NULL)) { + BKE_report(op->reports, RPT_INFO, "No available frame for creating stroke"); + estate = OPERATOR_CANCELLED; + break; + } + /* first time the event is not enabled to show help lines. */ if ((tgpf->oldkey != -1) || (!help_lines)) { ARegion *region = BKE_area_find_region_xy( @@ -2088,17 +2104,24 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) gpencil_stroke_convertcoords_tpoint( tgpf->scene, tgpf->region, tgpf->ob, &point2D, NULL, &pt->x); + /* Hash of selected frames.*/ + GHash *frame_list = BLI_ghash_int_new_ex(__func__, 64); + /* If not multiframe and there is no frame in CFRA for the active layer, create - * a new frame before to make the hash function can find something. */ + * a new frame. */ if (!is_multiedit) { tgpf->gpf = BKE_gpencil_layer_frame_get( - tgpf->gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW); + tgpf->gpl, + tgpf->active_cfra, + IS_AUTOKEY_ON(tgpf->scene) ? GP_GETFRAME_ADD_NEW : GP_GETFRAME_USE_PREV); tgpf->gpf->flag |= GP_FRAME_SELECT; - } - /* Hash of selected frames.*/ - GHash *frame_list = BLI_ghash_int_new_ex(__func__, 64); - BKE_gpencil_frame_selected_hash(tgpf->gpd, frame_list); + BLI_ghash_insert( + frame_list, POINTER_FROM_INT(tgpf->active_cfra), tgpf->gpl->actframe); + } + else { + BKE_gpencil_frame_selected_hash(tgpf->gpd, frame_list); + } /* Loop all frames. */ wmWindow *win = CTX_wm_window(C); diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c index 7e6b42f284b..b7ed77801c0 100644 --- a/source/blender/editors/gpencil/gpencil_mesh.c +++ b/source/blender/editors/gpencil/gpencil_mesh.c @@ -251,7 +251,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op) gpd->draw_mode = (project_type == GP_REPROJECT_KEEP) ? GP_DRAWMODE_3D : GP_DRAWMODE_2D; /* Set cursor to indicate working. */ - WM_cursor_wait(1); + WM_cursor_wait(true); GP_SpaceConversion gsc = {NULL}; SnapObjectContext *sctx = NULL; @@ -385,7 +385,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); /* Reset cursor. */ - WM_cursor_wait(0); + WM_cursor_wait(false); /* done */ return OPERATOR_FINISHED; diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 974f51ff90b..1217a3a7e8f 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -67,6 +67,7 @@ #include "ED_clip.h" #include "ED_gpencil.h" +#include "ED_keyframing.h" #include "ED_object.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -2155,6 +2156,10 @@ static void gpencil_paint_initstroke(tGPsdata *p, continue; } + if (!IS_AUTOKEY_ON(scene) && (gpl->actframe == NULL)) { + continue; + } + /* Add a new frame if needed (and based off the active frame, * as we need some existing strokes to erase) * @@ -2164,7 +2169,8 @@ static void gpencil_paint_initstroke(tGPsdata *p, */ if (gpl->actframe && gpl->actframe->strokes.first) { if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { - gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY); + short frame_mode = IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_COPY : GP_GETFRAME_USE_PREV; + gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, frame_mode); } has_layer_to_erase = true; break; @@ -2187,11 +2193,16 @@ static void gpencil_paint_initstroke(tGPsdata *p, /* Drawing Modes - Add a new frame if needed on the active layer */ short add_frame_mode; - if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { - add_frame_mode = GP_GETFRAME_ADD_COPY; + if (IS_AUTOKEY_ON(scene)) { + if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { + add_frame_mode = GP_GETFRAME_ADD_COPY; + } + else { + add_frame_mode = GP_GETFRAME_ADD_NEW; + } } else { - add_frame_mode = GP_GETFRAME_ADD_NEW; + add_frame_mode = GP_GETFRAME_USE_PREV; } bool need_tag = p->gpl->actframe == NULL; @@ -2206,6 +2217,10 @@ static void gpencil_paint_initstroke(tGPsdata *p, if (G.debug & G_DEBUG) { printf("Error: No frame created (gpencil_paint_init)\n"); } + if (!IS_AUTOKEY_ON(scene)) { + BKE_report(p->reports, RPT_INFO, "No available frame for creating stroke"); + } + return; } p->gpf->flag |= GP_FRAME_PAINT; @@ -2469,6 +2484,8 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) return 0; } + p->reports = op->reports; + /* init painting data */ gpencil_paint_initstroke(p, paintmode, CTX_data_ensure_evaluated_depsgraph(C)); if (p->status == GP_STATUS_ERROR) { @@ -2483,8 +2500,6 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) p->keymodifier = -1; } - p->reports = op->reports; - /* everything is now setup ok */ return 1; } @@ -2835,7 +2850,7 @@ static void gpencil_draw_apply_event(bContext *C, /* verify direction for straight lines and guides */ if ((is_speed_guide) || - ((event->alt > 0) && (RNA_boolean_get(op->ptr, "disable_straight") == false))) { + (event->alt && (RNA_boolean_get(op->ptr, "disable_straight") == false))) { if (p->straight == 0) { int dx = (int)fabsf(p->mval[0] - p->mvali[0]); int dy = (int)fabsf(p->mval[1] - p->mvali[1]); @@ -2876,13 +2891,13 @@ static void gpencil_draw_apply_event(bContext *C, /* special eraser modes */ if (p->paintmode == GP_PAINTMODE_ERASER) { - if (event->shift > 0) { + if (event->shift) { p->flags |= GP_PAINTFLAG_HARD_ERASER; } else { p->flags &= ~GP_PAINTFLAG_HARD_ERASER; } - if (event->alt > 0) { + if (event->alt) { p->flags |= GP_PAINTFLAG_STROKE_ERASER; } else { diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 12d399f32ca..b29ef2e7ee2 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -71,6 +71,7 @@ #include "RNA_enum_types.h" #include "ED_gpencil.h" +#include "ED_keyframing.h" #include "ED_object.h" #include "ED_screen.h" #include "ED_space_api.h" @@ -1253,9 +1254,18 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); + Scene *scene = CTX_data_scene(C); bGPdata *gpd = CTX_data_gpencil_data(C); tGPDprimitive *tgpi = NULL; + if (!IS_AUTOKEY_ON(scene)) { + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); + if ((gpl == NULL) || (gpl->actframe == NULL)) { + BKE_report(op->reports, RPT_INFO, "No available frame for creating stroke"); + return OPERATOR_CANCELLED; + } + } + /* initialize operator runtime data */ gpencil_primitive_init(C, op); tgpi = op->customdata; @@ -1310,11 +1320,16 @@ static void gpencil_primitive_interaction_end(bContext *C, /* insert keyframes as required... */ short add_frame_mode; - if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { - add_frame_mode = GP_GETFRAME_ADD_COPY; + if (IS_AUTOKEY_ON(tgpi->scene)) { + if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { + add_frame_mode = GP_GETFRAME_ADD_COPY; + } + else { + add_frame_mode = GP_GETFRAME_ADD_NEW; + } } else { - add_frame_mode = GP_GETFRAME_ADD_NEW; + add_frame_mode = GP_GETFRAME_USE_PREV; } bool need_tag = tgpi->gpl->actframe == NULL; diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 0d3ab9011d6..9666aca5254 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -73,6 +73,7 @@ #include "UI_view2d.h" #include "ED_gpencil.h" +#include "ED_keyframing.h" #include "ED_screen.h" #include "ED_view3d.h" @@ -1019,7 +1020,11 @@ static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso) if (gpl == NULL) { gpl = CTX_data_active_gpencil_layer(C); } - bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW); + bGPDframe *gpf = BKE_gpencil_layer_frame_get( + gpl, CFRA, IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_NEW : GP_GETFRAME_USE_PREV); + if (gpf == NULL) { + continue; + } /* Make a new stroke */ new_stroke = BKE_gpencil_stroke_duplicate(gps, true, true); @@ -1334,6 +1339,10 @@ static void gpencil_sculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso /* go through each layer, and ensure that we've got a valid frame to use */ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (!IS_AUTOKEY_ON(scene) && (gpl->actframe == NULL)) { + continue; + } + /* only editable and visible layers are considered */ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; @@ -1343,7 +1352,7 @@ static void gpencil_sculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso * - This is useful when animating as it saves that "uh-oh" moment when you realize you've * spent too much time editing the wrong frame. */ - if (gpf->framenum != cfra) { + if ((IS_AUTOKEY_ON(scene)) && (gpf->framenum != cfra)) { BKE_gpencil_frame_addcopy(gpl, cfra); /* Need tag to recalculate evaluated data to avoid crashes. */ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c index 677451eaabc..6bd0540a9d4 100644 --- a/source/blender/editors/gpencil/gpencil_uv.c +++ b/source/blender/editors/gpencil/gpencil_uv.c @@ -44,6 +44,7 @@ #include "ED_numinput.h" #include "ED_screen.h" #include "ED_space_api.h" +#include "ED_util.h" #include "ED_view3d.h" #include "DEG_depsgraph.h" diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 2415c85e299..4b440aa7367 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -55,7 +55,6 @@ struct FModifier; struct bAction; struct uiBlock; -struct uiLayout; struct PointerRNA; struct PropertyRNA; diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 7538dac1354..983ae94b637 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -145,6 +145,13 @@ void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile); bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile); +struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile); + +/* Activate the file that corresponds to the given ID. + * Pass deferred=true to wait for the next refresh before activating. */ +void ED_fileselect_activate_by_id(struct SpaceFile *sfile, + struct ID *asset_id, + const bool deferred); void ED_fileselect_window_params_get(const struct wmWindow *win, int win_size[2], diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 5dfce6071f0..0767ce21382 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -163,8 +163,8 @@ extern struct EnumPropertyItem prop_make_parent_types[]; bool ED_object_parent_set(struct ReportList *reports, const struct bContext *C, struct Scene *scene, - struct Object *ob, - struct Object *par, + struct Object *const ob, + struct Object *const par, int partype, const bool xmirror, const bool keep_transform, diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index deb6b7502c7..b3205acb8ee 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -52,7 +52,6 @@ struct rcti; struct uiBlock; struct uiLayout; struct wmKeyConfig; -struct wmMsgBus; struct wmMsgSubscribeKey; struct wmMsgSubscribeValue; struct wmNotifier; @@ -123,8 +122,6 @@ void ED_region_info_draw_multiline(ARegion *region, const char *text_array[], float fill_color[4], const bool full_redraw); -void ED_region_image_metadata_draw( - int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy); void ED_region_image_metadata_panel_draw(struct ImBuf *ibuf, struct uiLayout *layout); void ED_region_grid_draw(struct ARegion *region, float zoomx, float zoomy, float x0, float y0); float ED_region_blend_alpha(struct ARegion *region); diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h index c50bbc2f1e9..fc474ea464d 100644 --- a/source/blender/editors/include/ED_space_api.h +++ b/source/blender/editors/include/ED_space_api.h @@ -76,11 +76,6 @@ void ED_region_draw_cb_exit(struct ARegionType *, void *); void ED_region_draw_cb_remove_by_type(struct ARegionType *art, void *draw_fn, void (*free)(void *)); -/* generic callbacks */ -/* ed_util.c */ -void ED_region_draw_mouse_line_cb(const struct bContext *C, - struct ARegion *region, - void *arg_info); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 073186f6335..953f26aa45f 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -53,6 +53,14 @@ void ED_spacedata_id_remap(struct ScrArea *area, void ED_operatortypes_edutils(void); +/* Drawing */ +void ED_region_draw_mouse_line_cb(const struct bContext *C, + struct ARegion *region, + void *arg_info); + +void ED_region_image_metadata_draw( + int x, int y, struct ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy); + /* ************** XXX OLD CRUFT WARNING ************* */ void apply_keyb_grid( diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 81641239c6a..5620d39ab16 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -499,10 +499,14 @@ typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg); typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C, struct ARegion *butregion, struct uiButSearch *search_but); +/* `is_first` is typically used to ignore search filtering when the menu is first opened in order + * to display the full list of options. The value will be false after the button's text is edited + * (for every call except the first). */ typedef void (*uiButSearchUpdateFn)(const struct bContext *C, void *arg, const char *str, - uiSearchItems *items); + uiSearchItems *items, + const bool is_first); typedef void (*uiButSearchArgFreeFn)(void *arg); typedef bool (*uiButSearchContextMenuFn)(struct bContext *C, void *arg, @@ -1602,6 +1606,7 @@ void UI_but_func_search_set(uiBut *but, void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn); void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn); void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string); +void UI_but_func_search_set_results_are_suggestions(uiBut *but, const bool value); /* height in pixels, it's using hardcoded values still */ int UI_searchbox_size_y(void); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 6e25ec9d275..c7f5385eac3 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -6661,11 +6661,20 @@ void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn) but_search->item_tooltip_fn = tooltip_fn; } +void UI_but_func_search_set_results_are_suggestions(uiBut *but, const bool value) +{ + uiButSearch *but_search = (uiButSearch *)but; + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); + + but_search->results_are_suggestions = value; +} + /* Callbacks for operator search button. */ static void operator_enum_search_update_fn(const struct bContext *C, void *but, const char *str, - uiSearchItems *items) + uiSearchItems *items, + const bool UNUSED(is_first)) { wmOperatorType *ot = ((uiBut *)but)->optype; PropertyRNA *prop = ot->prop; diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index d10cdc207c2..40cfcaea883 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -120,7 +120,7 @@ void UI_draw_roundbox_4fv_ex(const rctf *rect, }; GPUBatch *batch = ui_batch_roundbox_widget_get(); GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); - GPU_batch_uniform_4fv_array(batch, "parameters", 11, (float(*)[4]) & widget_params); + GPU_batch_uniform_4fv_array(batch, "parameters", 11, (const float(*)[4]) & widget_params); GPU_blend(GPU_BLEND_ALPHA); GPU_batch_draw(batch); GPU_blend(GPU_BLEND_NONE); @@ -2376,7 +2376,7 @@ void ui_draw_dropshadow( GPUBatch *batch = ui_batch_roundbox_shadow_get(); GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_SHADOW); - GPU_batch_uniform_4fv_array(batch, "parameters", 4, (float(*)[4]) & widget_params); + GPU_batch_uniform_4fv_array(batch, "parameters", 4, (const float(*)[4]) & widget_params); GPU_batch_uniform_1f(batch, "alpha", 1.0f - visibility); GPU_batch_draw(batch); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 5de330d7136..042f10ddded 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -168,12 +168,14 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve #define PIE_MENU_INTERVAL 0.01 #define BUTTON_AUTO_OPEN_THRESH 0.2 #define BUTTON_MOUSE_TOWARDS_THRESH 1.0 -/* pixels to move the cursor to get out of keyboard navigation */ +/** Pixels to move the cursor to get out of keyboard navigation. */ #define BUTTON_KEYNAV_PX_LIMIT 8 -#define MENU_TOWARDS_MARGIN 20 /* margin in pixels */ -#define MENU_TOWARDS_WIGGLE_ROOM 64 /* tolerance in pixels */ -/* drag-lock distance threshold in pixels */ +/** Margin around the menu, use to check if we're moving towards this rectangle (in pixels). */ +#define MENU_TOWARDS_MARGIN 20 +/** Tolerance for closing menus (in pixels). */ +#define MENU_TOWARDS_WIGGLE_ROOM 64 +/** Drag-lock distance threshold (in pixels). */ #define BUTTON_DRAGLOCK_THRESH 3 typedef enum uiButtonActivateType { @@ -3408,8 +3410,12 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) if (data->searchbox) { if (data->cancel == false) { + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); + uiButSearch *but_search = (uiButSearch *)but; + if ((ui_searchbox_apply(but, data->searchbox) == false) && - (ui_searchbox_find_index(data->searchbox, but->editstr) == -1)) { + (ui_searchbox_find_index(data->searchbox, but->editstr) == -1) && + !but_search->results_are_suggestions) { data->cancel = true; /* ensure menu (popup) too is closed! */ @@ -10440,7 +10446,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle } } - if (event->type == block->pie_data.event && !is_click_style) { + if (event->type == block->pie_data.event_type && !is_click_style) { if (event->val != KM_RELEASE) { ui_handle_menu_button(C, event, menu); @@ -10614,7 +10620,7 @@ static int ui_handle_menus_recursive(bContext *C, /* root pie menus accept the key that spawned * them as double click to improve responsiveness */ const bool do_recursion = (!(block->flag & UI_BLOCK_RADIAL) || - event->type != block->pie_data.event); + event->type != block->pie_data.event_type); if (do_recursion) { if (is_parent_inside == false) { @@ -10907,7 +10913,7 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata) /* set last pie event to allow chained pie spawning */ if (block->flag & UI_BLOCK_RADIAL) { - win->last_pie_event = block->pie_data.event; + win->pie_event_type_last = block->pie_data.event_type; reset_pie = true; } @@ -10950,7 +10956,7 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata) wmWindow *win = CTX_wm_window(C); if (win) { - win->last_pie_event = EVENT_NONE; + win->pie_event_type_last = EVENT_NONE; } } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 3da66d45abd..1d4a44e0c76 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -31,6 +31,10 @@ #include "UI_interface.h" #include "UI_resources.h" +#ifdef __cplusplus +extern "C" { +#endif + struct ARegion; struct AnimationEvalContext; struct CurveMapping; @@ -316,6 +320,12 @@ typedef struct uiButSearch { struct PointerRNA rnasearchpoin; struct PropertyRNA *rnasearchprop; + + /** + * The search box only provides suggestions, it does not force + * the string to match one of the search items when applying. + */ + bool results_are_suggestions; } uiButSearch; /** Derived struct for #UI_BTYPE_DECORATOR */ @@ -414,8 +424,8 @@ struct PieMenuData { float last_pos[2]; double duration_gesture; int flags; - /** initial event used to fire the pie menu, store here so we can query for release */ - int event; + /** Initial event used to fire the pie menu, store here so we can query for release */ + short event_type; float alphafac; }; @@ -1193,10 +1203,15 @@ typedef struct uiRNACollectionSearch { void ui_rna_collection_search_update_fn(const struct bContext *C, void *arg, const char *str, - uiSearchItems *items); + uiSearchItems *items, + const bool is_first); /* interface_ops.c */ bool ui_jump_to_target_button_poll(struct bContext *C); /* interface_queries.c */ void ui_interface_tag_script_reload_queries(void); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c index 81c627816b9..05aa139e055 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.c +++ b/source/blender/editors/interface/interface_region_menu_pie.c @@ -122,26 +122,26 @@ uiPieMenu *UI_pie_menu_begin(struct bContext *C, const char *title, int icon, co * it is always assumed to be click style */ if (event->type == LEFTMOUSE || ELEM(event->val, KM_RELEASE, KM_CLICK)) { pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE; - pie->block_radial->pie_data.event = EVENT_NONE; - win->lock_pie_event = EVENT_NONE; + pie->block_radial->pie_data.event_type = EVENT_NONE; + win->pie_event_type_lock = EVENT_NONE; } else { - if (win->last_pie_event != EVENT_NONE) { + if (win->pie_event_type_last != EVENT_NONE) { /* original pie key has been released, so don't propagate the event */ - if (win->lock_pie_event == EVENT_NONE) { + if (win->pie_event_type_lock == EVENT_NONE) { event_type = EVENT_NONE; pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE; } else { - event_type = win->last_pie_event; + event_type = win->pie_event_type_last; } } else { event_type = event->type; } - pie->block_radial->pie_data.event = event_type; - win->lock_pie_event = event_type; + pie->block_radial->pie_data.event_type = event_type; + win->pie_event_type_lock = event_type; } pie->layout = UI_block_layout( diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c index 2c07f5c3c03..12044863b8c 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.c @@ -468,7 +468,8 @@ static void ui_searchbox_update_fn(bContext *C, wmWindow *win = CTX_wm_window(C); WM_tooltip_clear(C, win); } - search_but->items_update_fn(C, search_but->arg, str, items); + const bool is_first_search = !search_but->but.changed; + search_but->items_update_fn(C, search_but->arg, str, items, is_first_search); } /* region is the search box itself */ @@ -1052,14 +1053,16 @@ void ui_but_search_refresh(uiButSearch *search_but) ui_searchbox_update_fn(but->block->evil_C, search_but, but->drawstr, items); - /* Only red-alert when we are sure of it, this can miss cases when >10 matches. */ - if (items->totitem == 0) { - UI_but_flag_enable(but, UI_BUT_REDALERT); - } - else if (items->more == 0) { - if (UI_search_items_find_index(items, but->drawstr) == -1) { + if (!search_but->results_are_suggestions) { + /* Only red-alert when we are sure of it, this can miss cases when >10 matches. */ + if (items->totitem == 0) { UI_but_flag_enable(but, UI_BUT_REDALERT); } + else if (items->more == 0) { + if (UI_search_items_find_index(items, but->drawstr) == -1) { + UI_but_flag_enable(but, UI_BUT_REDALERT); + } + } } for (x1 = 0; x1 < items->maxitem; x1++) { diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c index 25cf2e12377..e1f8f63dcbf 100644 --- a/source/blender/editors/interface/interface_template_search_menu.c +++ b/source/blender/editors/interface/interface_template_search_menu.c @@ -990,7 +990,8 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) static void menu_search_update_fn(const bContext *UNUSED(C), void *arg, const char *str, - uiSearchItems *items) + uiSearchItems *items, + const bool UNUSED(is_first)) { struct MenuSearch_Data *data = arg; diff --git a/source/blender/editors/interface/interface_template_search_operator.c b/source/blender/editors/interface/interface_template_search_operator.c index ff0f9a2e5cd..2c83f184ff0 100644 --- a/source/blender/editors/interface/interface_template_search_operator.c +++ b/source/blender/editors/interface/interface_template_search_operator.c @@ -59,7 +59,8 @@ static void operator_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) static void operator_search_update_fn(const bContext *C, void *UNUSED(arg), const char *str, - uiSearchItems *items) + uiSearchItems *items, + const bool UNUSED(is_first)) { GHashIterator iter; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 67446ca681f..c5e67e0334e 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -393,7 +393,8 @@ static bool id_search_add(const bContext *C, TemplateID *template_ui, uiSearchIt static void id_search_cb(const bContext *C, void *arg_template, const char *str, - uiSearchItems *items) + uiSearchItems *items, + const bool UNUSED(is_first)) { TemplateID *template_ui = (TemplateID *)arg_template; ListBase *lb = template_ui->idlb; @@ -464,7 +465,8 @@ static void id_search_cb_tagged(const bContext *C, static void id_search_cb_objects_from_scene(const bContext *C, void *arg_template, const char *str, - uiSearchItems *items) + uiSearchItems *items, + const bool UNUSED(is_first)) { TemplateID *template_ui = (TemplateID *)arg_template; ListBase *lb = template_ui->idlb; @@ -518,7 +520,7 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem) static TemplateID template_ui; PointerRNA active_item_ptr; void (*id_search_update_fn)( - const bContext *, void *, const char *, uiSearchItems *) = id_search_cb; + const bContext *, void *, const char *, uiSearchItems *, const bool) = id_search_cb; /* arg_litem is malloced, can be freed by parent button */ template_ui = *((TemplateID *)arg_litem); @@ -3985,7 +3987,7 @@ static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event) BKE_curvemapping_changed(cumap, false); break; case UICURVE_FUNC_RESET_VIEW: - cumap->curr = cumap->clipr; + BKE_curvemapping_reset_view(cumap); break; case UICURVE_FUNC_HANDLE_VECTOR: /* set vector */ BKE_curvemap_handle_set(cuma, HD_VECT); diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 5311bb57da9..877800c1ba2 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -405,7 +405,8 @@ static bool add_collection_search_item(CollItemSearch *cis, void ui_rna_collection_search_update_fn(const struct bContext *C, void *arg, const char *str, - uiSearchItems *items) + uiSearchItems *items, + const bool is_first) { uiRNACollectionSearch *data = arg; const int flag = RNA_property_flag(data->target_prop); @@ -415,7 +416,7 @@ void ui_rna_collection_search_update_fn(const struct bContext *C, * match the RNA name exactly. So only for pointer properties, the name can be modified to add * further UI hints. */ const bool requires_exact_data_name = !is_ptr_target; - const bool skip_filter = data->search_but && !data->search_but->changed; + const bool skip_filter = is_first; char name_buf[UI_MAX_DRAW_STR]; char *name; bool has_id_icon = false; diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 0fa5999976b..06b87dd857f 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1180,7 +1180,7 @@ void UI_widgetbase_draw_cache_flush(void) /* draw single */ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); GPU_batch_uniform_4fv_array( - batch, "parameters", MAX_WIDGET_PARAMETERS, (float(*)[4])g_widget_base_batch.params); + batch, "parameters", MAX_WIDGET_PARAMETERS, (const float(*)[4])g_widget_base_batch.params); GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params); GPU_batch_draw(batch); } diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index 66a7b97b440..340a7ae92ff 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -50,6 +50,7 @@ #include "ED_screen.h" #include "ED_space_api.h" #include "ED_transform.h" +#include "ED_util.h" #include "ED_view3d.h" #include "mesh_intern.h" /* own include */ diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 9000a942e50..73d79805f60 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -46,6 +46,7 @@ #include "ED_screen.h" #include "ED_space_api.h" #include "ED_transform.h" +#include "ED_util.h" #include "ED_view3d.h" #include "mesh_intern.h" /* own include */ diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 1f894ec0f1d..b5ec3f388a0 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -966,7 +966,7 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) float planes[4][4]; planes_from_projmat( - (float(*)[4])kcd->projmat, planes[2], planes[0], planes[3], planes[1], NULL, NULL); + (const float(*)[4])kcd->projmat, planes[2], planes[0], planes[3], planes[1], NULL, NULL); /* ray-cast all planes */ { diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 334afdfb2d9..88151b07fb9 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -1967,9 +1967,9 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op) static int edbm_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - WM_cursor_wait(1); + WM_cursor_wait(true); edbm_duplicate_exec(C, op); - WM_cursor_wait(0); + WM_cursor_wait(false); return OPERATOR_FINISHED; } @@ -4172,15 +4172,7 @@ static Base *mesh_separate_tagged( })); BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */ - CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0); - CustomData_copy(&bm_old->edata, &bm_new->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0); - CustomData_copy(&bm_old->ldata, &bm_new->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0); - CustomData_copy(&bm_old->pdata, &bm_new->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0); - - CustomData_bmesh_init_pool(&bm_new->vdata, bm_mesh_allocsize_default.totvert, BM_VERT); - CustomData_bmesh_init_pool(&bm_new->edata, bm_mesh_allocsize_default.totedge, BM_EDGE); - CustomData_bmesh_init_pool(&bm_new->ldata, bm_mesh_allocsize_default.totloop, BM_LOOP); - CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE); + BM_mesh_copy_init_customdata(bm_new, bm_old, &bm_mesh_allocsize_default); /* Take into account user preferences for duplicating actions. */ const eDupli_ID_Flags dupflag = USER_DUP_MESH | (U.dupflag & USER_DUP_ACT); diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 9618774eea8..a5cad4e087c 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -572,7 +572,7 @@ static int multiresbake_image_exec(bContext *C, wmOperator *op) G.is_break = false; WM_jobs_start(CTX_wm_manager(C), wm_job); - WM_cursor_wait(0); + WM_cursor_wait(false); /* add modal handler for ESC */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 9ec0c625f71..610551e8539 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -1897,7 +1897,7 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event) WM_jobs_start(CTX_wm_manager(C), wm_job); - WM_cursor_wait(0); + WM_cursor_wait(false); /* add modal handler for ESC */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index da14d4ef52a..c774bc9f9cc 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1330,9 +1330,9 @@ static int object_clear_paths_exec(bContext *C, wmOperator *op) } /* operator callback/wrapper */ -static int object_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *evt) +static int object_clear_paths_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if ((evt->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) { + if ((event->shift) && !RNA_struct_property_is_set(op->ptr, "only_selected")) { RNA_boolean_set(op->ptr, "only_selected", true); } return object_clear_paths_exec(C, op); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 5a2ef1c6556..e74d04ab17f 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -893,10 +893,10 @@ bool ED_object_parent_set(ReportList *reports, reports, depsgraph, scene, ob, par, ARM_GROUPS_ENVELOPE, xmirror); } else if (partype == PAR_ARMATURE_AUTO) { - WM_cursor_wait(1); + WM_cursor_wait(true); ED_object_vgroup_calc_from_armature( reports, depsgraph, scene, ob, par, ARM_GROUPS_AUTO, xmirror); - WM_cursor_wait(0); + WM_cursor_wait(false); } /* get corrected inverse */ ob->partype = PAROBJECT; @@ -912,9 +912,9 @@ bool ED_object_parent_set(ReportList *reports, ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME); } else if (ELEM(partype, PAR_ARMATURE_AUTO, PAR_ARMATURE_ENVELOPE)) { - WM_cursor_wait(1); + WM_cursor_wait(true); ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_AUTO); - WM_cursor_wait(0); + WM_cursor_wait(false); } /* get corrected inverse */ ob->partype = PAROBJECT; diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index b525d8a373e..1f59e361526 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -938,7 +938,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even } /* handle UI stuff */ - WM_cursor_wait(1); + WM_cursor_wait(true); /* flush sculpt and editmode changes */ ED_editors_flush_edits_ex(bmain, true, false); @@ -1058,7 +1058,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even WM_jobs_start(CTX_wm_manager(C), wm_job); - WM_cursor_wait(0); + WM_cursor_wait(false); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); /* we set G.is_rendering here already instead of only in the job, this ensure diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 32d4abcabd4..bfad79a1da9 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -1224,7 +1224,7 @@ static int light_cache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *U WM_jobs_start(wm, wm_job); - WM_cursor_wait(0); + WM_cursor_wait(false); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 2c71345699f..bd2b1c4c553 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -3516,297 +3516,6 @@ void ED_region_info_draw(ARegion *region, ED_region_info_draw_multiline(region, text_array, fill_color, full_redraw); } -#define MAX_METADATA_STR 1024 - -static const char *meta_data_list[] = { - "File", - "Strip", - "Date", - "RenderTime", - "Note", - "Marker", - "Time", - "Frame", - "Camera", - "Scene", -}; - -BLI_INLINE bool metadata_is_valid(ImBuf *ibuf, char *r_str, short index, int offset) -{ - return (IMB_metadata_get_field( - ibuf->metadata, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && - r_str[0]); -} - -BLI_INLINE bool metadata_is_custom_drawable(const char *field) -{ - /* Metadata field stored by Blender for multilayer EXR images. Is rather - * useless to be viewed all the time. Can still be seen in the Metadata - * panel. */ - if (STREQ(field, "BlenderMultiChannel")) { - return false; - } - /* Is almost always has value "scanlineimage", also useless to be seen - * all the time. */ - if (STREQ(field, "type")) { - return false; - } - return !BKE_stamp_is_known_field(field); -} - -typedef struct MetadataCustomDrawContext { - int fontid; - int xmin, ymin; - int vertical_offset; - int current_y; -} MetadataCustomDrawContext; - -static void metadata_custom_draw_fields(const char *field, const char *value, void *ctx_v) -{ - if (!metadata_is_custom_drawable(field)) { - return; - } - MetadataCustomDrawContext *ctx = (MetadataCustomDrawContext *)ctx_v; - char temp_str[MAX_METADATA_STR]; - BLI_snprintf(temp_str, MAX_METADATA_STR, "%s: %s", field, value); - BLF_position(ctx->fontid, ctx->xmin, ctx->ymin + ctx->current_y, 0.0f); - BLF_draw(ctx->fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); - ctx->current_y += ctx->vertical_offset; -} - -static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const bool is_top) -{ - char temp_str[MAX_METADATA_STR]; - int ofs_y = 0; - const float height = BLF_height_max(fontid); - const float margin = height / 8; - const float vertical_offset = (height + margin); - - /* values taking margins into account */ - const float descender = BLF_descender(fontid); - const float xmin = (rect->xmin + margin); - const float xmax = (rect->xmax - margin); - const float ymin = (rect->ymin + margin) - descender; - const float ymax = (rect->ymax - margin) - descender; - - if (is_top) { - for (int i = 0; i < 4; i++) { - /* first line */ - if (i == 0) { - bool do_newline = false; - int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]); - if (metadata_is_valid(ibuf, temp_str, 0, len)) { - BLF_position(fontid, xmin, ymax - vertical_offset, 0.0f); - BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); - do_newline = true; - } - - len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]); - if (metadata_is_valid(ibuf, temp_str, 1, len)) { - int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); - BLF_position(fontid, xmax - line_width, ymax - vertical_offset, 0.0f); - BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); - do_newline = true; - } - - if (do_newline) { - ofs_y += vertical_offset; - } - } /* Strip */ - else if (ELEM(i, 1, 2)) { - int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); - if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { - BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f); - BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); - ofs_y += vertical_offset; - } - } /* Note (wrapped) */ - else if (i == 3) { - int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); - if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { - struct ResultBLF info; - BLF_enable(fontid, BLF_WORD_WRAP); - BLF_wordwrap(fontid, ibuf->x - (margin * 2)); - BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f); - BLF_draw_ex(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX, &info); - BLF_wordwrap(fontid, 0); - BLF_disable(fontid, BLF_WORD_WRAP); - ofs_y += vertical_offset * info.lines; - } - } - else { - int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); - if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { - int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); - BLF_position(fontid, xmax - line_width, ymax - vertical_offset - ofs_y, 0.0f); - BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); - ofs_y += vertical_offset; - } - } - } - } - else { - MetadataCustomDrawContext ctx; - ctx.fontid = fontid; - ctx.xmin = xmin; - ctx.ymin = ymin; - ctx.current_y = ofs_y; - ctx.vertical_offset = vertical_offset; - IMB_metadata_foreach(ibuf, metadata_custom_draw_fields, &ctx); - int ofs_x = 0; - ofs_y = ctx.current_y; - for (int i = 5; i < 10; i++) { - int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]); - if (metadata_is_valid(ibuf, temp_str, i, len)) { - BLF_position(fontid, xmin + ofs_x, ymin + ofs_y, 0.0f); - BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); - - ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X; - } - } - } -} - -typedef struct MetadataCustomCountContext { - int count; -} MetadataCustomCountContext; - -static void metadata_custom_count_fields(const char *field, const char *UNUSED(value), void *ctx_v) -{ - if (!metadata_is_custom_drawable(field)) { - return; - } - MetadataCustomCountContext *ctx = (MetadataCustomCountContext *)ctx_v; - ctx->count++; -} - -static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top) -{ - const float height = BLF_height_max(fontid); - const float margin = (height / 8); - char str[MAX_METADATA_STR] = ""; - short count = 0; - - if (is_top) { - if (metadata_is_valid(ibuf, str, 0, 0) || metadata_is_valid(ibuf, str, 1, 0)) { - count++; - } - for (int i = 2; i < 5; i++) { - if (metadata_is_valid(ibuf, str, i, 0)) { - if (i == 4) { - struct { - struct ResultBLF info; - rctf rect; - } wrap; - - BLF_enable(fontid, BLF_WORD_WRAP); - BLF_wordwrap(fontid, ibuf->x - (margin * 2)); - BLF_boundbox_ex(fontid, str, sizeof(str), &wrap.rect, &wrap.info); - BLF_wordwrap(fontid, 0); - BLF_disable(fontid, BLF_WORD_WRAP); - - count += wrap.info.lines; - } - else { - count++; - } - } - } - } - else { - for (int i = 5; i < 10; i++) { - if (metadata_is_valid(ibuf, str, i, 0)) { - count = 1; - break; - } - } - MetadataCustomCountContext ctx; - ctx.count = 0; - IMB_metadata_foreach(ibuf, metadata_custom_count_fields, &ctx); - count += ctx.count; - } - - if (count) { - return (height + margin) * count; - } - - return 0; -} - -#undef MAX_METADATA_STR - -void ED_region_image_metadata_draw( - int x, int y, ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy) -{ - const uiStyle *style = UI_style_get_dpi(); - - if (!ibuf->metadata) { - return; - } - - /* find window pixel coordinates of origin */ - GPU_matrix_push(); - - /* offset and zoom using ogl */ - GPU_matrix_translate_2f(x, y); - GPU_matrix_scale_2f(zoomx, zoomy); - - BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f * U.pixelsize, U.dpi); - - /* *** upper box*** */ - - /* get needed box height */ - float box_y = metadata_box_height_get(ibuf, blf_mono_font, true); - - if (box_y) { - /* set up rect */ - rctf rect; - BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymax, frame->ymax + box_y); - /* draw top box */ - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColor(TH_METADATA_BG); - immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - immUnbindProgram(); - - BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - BLF_enable(blf_mono_font, BLF_CLIPPING); - - UI_FontThemeColor(blf_mono_font, TH_METADATA_TEXT); - metadata_draw_imbuf(ibuf, &rect, blf_mono_font, true); - - BLF_disable(blf_mono_font, BLF_CLIPPING); - } - - /* *** lower box*** */ - - box_y = metadata_box_height_get(ibuf, blf_mono_font, false); - - if (box_y) { - /* set up box rect */ - rctf rect; - BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymin - box_y, frame->ymin); - /* draw top box */ - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColor(TH_METADATA_BG); - immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - immUnbindProgram(); - - BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - BLF_enable(blf_mono_font, BLF_CLIPPING); - - UI_FontThemeColor(blf_mono_font, TH_METADATA_TEXT); - metadata_draw_imbuf(ibuf, &rect, blf_mono_font, false); - - BLF_disable(blf_mono_font, BLF_CLIPPING); - } - - GPU_matrix_pop(); -} - typedef struct MetadataPanelDrawContext { uiLayout *layout; } MetadataPanelDrawContext; diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 5b426e827e7..e4996e8196b 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -62,10 +62,12 @@ set(SRC sculpt_cloth.c sculpt_detail.c sculpt_dyntopo.c + sculpt_expand.c sculpt_face_set.c sculpt_filter_color.c sculpt_filter_mask.c sculpt_filter_mesh.c + sculpt_geodesic.c sculpt_mask_expand.c sculpt_multiplane_scrape.c sculpt_paint_color.c diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 38810d6e131..c76fa01816b 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1626,6 +1626,16 @@ static void paint_cursor_draw_3d_view_brush_cursor_inactive(PaintCursorContext * paint_cursor_pose_brush_origins_draw(pcontext); } + /* Expand operation origin. */ + if (pcontext->ss->expand_cache) { + cursor_draw_point_screen_space( + pcontext->pos, + pcontext->region, + SCULPT_vertex_co_get(pcontext->ss, pcontext->ss->expand_cache->initial_active_vertex), + pcontext->vc.obact->obmat, + 2); + } + if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) { paint_cursor_preview_boundary_data_update(pcontext, update_previews); paint_cursor_preview_boundary_data_pivot_draw(pcontext); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index f4586fa130d..e1dc8fa30b9 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -1393,4 +1393,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf) /* paint stroke */ keymap = paint_stroke_modal_keymap(keyconf); WM_modalkeymap_assign(keymap, "SCULPT_OT_brush_stroke"); + + /* sculpt expand. */ + sculpt_expand_modal_keymap(keyconf); } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index b593b51c1e5..4bb9bcfdc0a 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1405,12 +1405,14 @@ void SCULPT_floodfill_add_initial(SculptFloodFill *flood, SculptVertRef index) BLI_gsqueue_push(flood->queue, &index); } -void SCULPT_floodfill_add_initial_with_symmetry(Sculpt *sd, - Object *ob, - SculptSession *ss, - SculptFloodFill *flood, - SculptVertRef vertex, - float radius) +void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index) +{ + BLI_gsqueue_push(flood->queue, &index); + BLI_BITMAP_ENABLE(flood->visited_vertices, index); +} + +void SCULPT_floodfill_add_initial_with_symmetry( + Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, SculptVertRef index, float radius) { /* Add active vertex and symmetric vertices to the queue. */ const char symm = SCULPT_mesh_symmetry_xyz_get(ob); @@ -9543,7 +9545,7 @@ static bool SCULPT_connected_components_floodfill_cb(SculptSession *ss, return true; } -static void sculpt_connected_components_ensure(Object *ob) +void SCULPT_connected_components_ensure(Object *ob) { SculptSession *ss = ob->sculpt; @@ -9622,7 +9624,7 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist) return; } - sculpt_connected_components_ensure(ob); + SCULPT_connected_components_ensure(ob); SCULPT_fake_neighbor_init(ss, max_dist); for (int i = 0; i < totvert; i++) { @@ -10335,4 +10337,6 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_color_filter); WM_operatortype_append(SCULPT_OT_mask_by_color); WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit); + + WM_operatortype_append(SCULPT_OT_expand); } diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c index 4636654c3a9..a92b14eb661 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -555,11 +555,13 @@ SculptBoundary *SCULPT_boundary_data_init(Object *object, SculptBoundary *boundary = MEM_callocN(sizeof(SculptBoundary), "Boundary edit data"); - const bool init_boundary_distances = brush->boundary_falloff_type != - BRUSH_BOUNDARY_FALLOFF_CONSTANT; + const bool init_boundary_distances = brush ? brush->boundary_falloff_type != + BRUSH_BOUNDARY_FALLOFF_CONSTANT : + false; + sculpt_boundary_indices_init(ss, boundary, init_boundary_distances, boundary_initial_vertex); - const float boundary_radius = radius * (1.0f + brush->boundary_offset); + const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius; sculpt_boundary_edit_data_init(ss, boundary, boundary_initial_vertex, boundary_radius); return boundary; diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c new file mode 100644 index 00000000000..892b30048f6 --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -0,0 +1,2291 @@ +/* + * 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) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_linklist_stack.h" +#include "BLI_math.h" +#include "BLI_task.h" + +#include "BLT_translation.h" + +#include "DNA_brush_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_brush.h" +#include "BKE_ccg.h" +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_image.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_multires.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_subdiv_ccg.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" +#include "WM_message.h" +#include "WM_toolsystem.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_sculpt.h" +#include "ED_view3d.h" +#include "paint_intern.h" +#include "sculpt_intern.h" + +#include "IMB_colormanagement.h" +#include "IMB_imbuf.h" + +#include "bmesh.h" + +#include <math.h> +#include <stdlib.h> + +/* Sculpt Expand. */ +/* Operator for creating selections and patterns in Sculpt Mode. Expand can create masks, face sets + * and fill vertex colors. */ +/* The main functionality of the operator + * - The operator initializes a value per vertex, called "falloff". There are multiple algorithms + * to generate these falloff values which will create different patterns in the result when using + * the operator. These falloff values require algorithms that rely on mesh connectivity, so they + * are only valid on parts of the mesh that are in the same connected component as the given + * initial vertices. If needed, these falloff values are propagated from vertex or grids into the + * base mesh faces. + * + * - On each modal callback, the operator gets the active vertex and face and gets its falloff + * value from its precalculated falloff. This is now the active falloff value. + * - Using the active falloff value and the settings of the expand operation (which can be modified + * during execution using the modal key-map), the operator loops over all elements in the mesh to + * check if they are enabled of not. + * - Based on each element state after evaluating the settings, the desired mesh data (mask, face + * sets, colors...) is updated. + */ + +/** + * Used for defining an invalid vertex state (for example, when the cursor is not over the mesh). + */ +#define SCULPT_EXPAND_VERTEX_NONE -1 + +/** Used for defining an uninitialized active component index for an unused symmetry pass. */ +#define EXPAND_ACTIVE_COMPONENT_NONE -1 +/** + * Defines how much each time the texture distortion is increased/decreased + * when using the modal key-map. + */ +#define SCULPT_EXPAND_TEXTURE_DISTORTION_STEP 0.01f + +/** + * This threshold offsets the required falloff value to start a new loop. This is needed because in + * some situations, vertices which have the same falloff value as max_falloff will start a new + * loop, which is undesired. + */ +#define SCULPT_EXPAND_LOOP_THRESHOLD 0.00001f + +/** + * Defines how much changes in curvature in the mesh affect the falloff shape when using normal + * falloff. This default was found experimentally and it works well in most cases, but can be + * exposed for tweaking if needed. + */ +#define SCULPT_EXPAND_NORMALS_FALLOFF_EDGE_SENSITIVITY 300 + +/* Expand Modal Key-map. */ +enum { + SCULPT_EXPAND_MODAL_CONFIRM = 1, + SCULPT_EXPAND_MODAL_CANCEL, + SCULPT_EXPAND_MODAL_INVERT, + SCULPT_EXPAND_MODAL_PRESERVE_TOGGLE, + SCULPT_EXPAND_MODAL_GRADIENT_TOGGLE, + SCULPT_EXPAND_MODAL_FALLOFF_CYCLE, + SCULPT_EXPAND_MODAL_RECURSION_STEP_GEODESIC, + SCULPT_EXPAND_MODAL_RECURSION_STEP_TOPOLOGY, + SCULPT_EXPAND_MODAL_MOVE_TOGGLE, + SCULPT_EXPAND_MODAL_FALLOFF_GEODESIC, + SCULPT_EXPAND_MODAL_FALLOFF_TOPOLOGY, + SCULPT_EXPAND_MODAL_FALLOFF_TOPOLOGY_DIAGONALS, + SCULPT_EXPAND_MODAL_FALLOFF_SPHERICAL, + SCULPT_EXPAND_MODAL_SNAP_TOGGLE, + SCULPT_EXPAND_MODAL_LOOP_COUNT_INCREASE, + SCULPT_EXPAND_MODAL_LOOP_COUNT_DECREASE, + SCULPT_EXPAND_MODAL_BRUSH_GRADIENT_TOGGLE, + SCULPT_EXPAND_MODAL_TEXTURE_DISTORTION_INCREASE, + SCULPT_EXPAND_MODAL_TEXTURE_DISTORTION_DECREASE, +}; + +/* Functions for getting the state of mesh elements (vertices and base mesh faces). When the main + * functions for getting the state of an element return true it means that data associated to that + * element will be modified by expand. */ + +/** + * Returns true if the vertex is in a connected component with correctly initialized falloff + * values. + */ +static bool sculpt_expand_is_vert_in_active_component(SculptSession *ss, + ExpandCache *expand_cache, + const int v) +{ + for (int i = 0; i < EXPAND_SYMM_AREAS; i++) { + if (ss->vertex_info.connected_component[v] == expand_cache->active_connected_components[i]) { + return true; + } + } + return false; +} + +/** + * Returns true if the face is in a connected component with correctly initialized falloff values. + */ +static bool sculpt_expand_is_face_in_active_component(SculptSession *ss, + ExpandCache *expand_cache, + const int f) +{ + const MLoop *loop = &ss->mloop[ss->mpoly[f].loopstart]; + return sculpt_expand_is_vert_in_active_component(ss, expand_cache, loop->v); +} + +/** + * Returns the falloff value of a vertex. This function includes texture distortion, which is not + * precomputed into the initial falloff values. + */ +static float sculpt_expand_falloff_value_vertex_get(SculptSession *ss, + ExpandCache *expand_cache, + const int v) +{ + if (expand_cache->texture_distortion_strength == 0.0f) { + return expand_cache->vert_falloff[v]; + } + + if (!expand_cache->brush->mtex.tex) { + return expand_cache->vert_falloff[v]; + } + + float rgba[4]; + const float *vertex_co = SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, v)); + const float avg = BKE_brush_sample_tex_3d( + expand_cache->scene, expand_cache->brush, vertex_co, rgba, 0, ss->tex_pool); + + const float distortion = (avg - 0.5f) * expand_cache->texture_distortion_strength * + expand_cache->max_vert_falloff; + return expand_cache->vert_falloff[v] + distortion; +} + +/** + * Returns the maximum valid falloff value stored in the falloff array, taking the maximum possible + * texture distortion into account. + */ +static float sculpt_expand_max_vertex_falloff_get(ExpandCache *expand_cache) +{ + if (expand_cache->texture_distortion_strength == 0.0f) { + return expand_cache->max_vert_falloff; + } + + if (!expand_cache->brush->mtex.tex) { + return expand_cache->max_vert_falloff; + } + + return expand_cache->max_vert_falloff + + (0.5f * expand_cache->texture_distortion_strength * expand_cache->max_vert_falloff); +} + +/** + * Main function to get the state of a vertex for the current state and settings of a #ExpandCache. + * Returns true when the target data should be modified by expand. + */ +static bool sculpt_expand_state_get(SculptSession *ss, ExpandCache *expand_cache, const int v) +{ + SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, v); + + if (!SCULPT_vertex_visible_get(ss, vref)) { + return false; + } + + if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, v)) { + return false; + } + + if (expand_cache->all_enabled) { + return true; + } + + bool enabled = false; + + if (expand_cache->snap) { + /* Face Sets are not being modified when using this function, so it is ok to get this directly + * from the Sculpt API instead of implementing a custom function to get them from + * expand_cache->original_face_sets. */ + const int face_set = SCULPT_vertex_face_set_get(ss, vref); + enabled = BLI_gset_haskey(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(face_set)); + } + else { + const float max_falloff_factor = sculpt_expand_max_vertex_falloff_get(expand_cache); + const float loop_len = (max_falloff_factor / expand_cache->loop_count) + + SCULPT_EXPAND_LOOP_THRESHOLD; + + const float vertex_falloff_factor = sculpt_expand_falloff_value_vertex_get( + ss, expand_cache, v); + const float active_factor = fmod(expand_cache->active_falloff, loop_len); + const float falloff_factor = fmod(vertex_falloff_factor, loop_len); + + enabled = falloff_factor < active_factor; + } + + if (expand_cache->invert) { + enabled = !enabled; + } + return enabled; +} + +/** + * Main function to get the state of a face for the current state and settings of a #ExpandCache. + * Returns true when the target data should be modified by expand. + */ +static bool sculpt_expand_face_state_get(SculptSession *ss, ExpandCache *expand_cache, const int f) +{ + if (ss->face_sets[f] <= 0) { + return false; + } + + if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, f)) { + return false; + } + + if (expand_cache->all_enabled) { + return true; + } + + bool enabled = false; + + if (expand_cache->snap_enabled_face_sets) { + const int face_set = expand_cache->original_face_sets[f]; + enabled = BLI_gset_haskey(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(face_set)); + } + else { + const float loop_len = (expand_cache->max_face_falloff / expand_cache->loop_count) + + SCULPT_EXPAND_LOOP_THRESHOLD; + + const float active_factor = fmod(expand_cache->active_falloff, loop_len); + const float falloff_factor = fmod(expand_cache->face_falloff[f], loop_len); + enabled = falloff_factor < active_factor; + } + + if (expand_cache->falloff_type == SCULPT_EXPAND_FALLOFF_ACTIVE_FACE_SET) { + if (ss->face_sets[f] == expand_cache->initial_active_face_set) { + enabled = false; + } + } + + if (expand_cache->invert) { + enabled = !enabled; + } + + return enabled; +} + +/** + * For target modes that support gradients (such as sculpt masks or colors), this function returns + * the corresponding gradient value for an enabled vertex. + */ +static float sculpt_expand_gradient_value_get(SculptSession *ss, + ExpandCache *expand_cache, + const int v) +{ + if (!expand_cache->falloff_gradient) { + return 1.0f; + } + + const float max_falloff_factor = sculpt_expand_max_vertex_falloff_get(expand_cache); + const float loop_len = (max_falloff_factor / expand_cache->loop_count) + + SCULPT_EXPAND_LOOP_THRESHOLD; + + const float vertex_falloff_factor = sculpt_expand_falloff_value_vertex_get(ss, expand_cache, v); + const float active_factor = fmod(expand_cache->active_falloff, loop_len); + const float falloff_factor = fmod(vertex_falloff_factor, loop_len); + + float linear_falloff; + + if (expand_cache->invert) { + /* Active factor is the result of a modulus operation using loop_len, so they will never be + * equal and loop_len - active_factor should never be 0. */ + BLI_assert((loop_len - active_factor) != 0.0f); + linear_falloff = (falloff_factor - active_factor) / (loop_len - active_factor); + } + else { + linear_falloff = 1.0f - (falloff_factor / active_factor); + } + + if (!expand_cache->brush_gradient) { + return linear_falloff; + } + + return BKE_brush_curve_strength(expand_cache->brush, linear_falloff, 1.0f); +} + +/* Utility functions for getting all vertices state during expand. */ + +/** + * Returns a bitmap indexed by vertex index which contains if the vertex was enabled or not for a + * give expand_cache state. + */ +static BLI_bitmap *sculpt_expand_bitmap_from_enabled(SculptSession *ss, ExpandCache *expand_cache) +{ + const int totvert = SCULPT_vertex_count_get(ss); + BLI_bitmap *enabled_vertices = BLI_BITMAP_NEW(totvert, "enabled vertices"); + for (int i = 0; i < totvert; i++) { + const bool enabled = sculpt_expand_state_get(ss, expand_cache, i); + BLI_BITMAP_SET(enabled_vertices, i, enabled); + } + return enabled_vertices; +} + +/** + * Returns a bitmap indexed by vertex index which contains if the vertex is in the boundary of the + * enabled vertices. This is defined as vertices that are enabled and at least have one connected + * vertex that is not enabled. + */ +static BLI_bitmap *sculpt_expand_boundary_from_enabled(SculptSession *ss, + const BLI_bitmap *enabled_vertices, + const bool use_mesh_boundary) +{ + const int totvert = SCULPT_vertex_count_get(ss); + BLI_bitmap *boundary_vertices = BLI_BITMAP_NEW(totvert, "boundary vertices"); + for (int i = 0; i < totvert; i++) { + SculptVertRef vertex = BKE_pbvh_table_index_to_vertex(ss->pbvh, i); + + if (!BLI_BITMAP_TEST(enabled_vertices, i)) { + continue; + } + + bool is_expand_boundary = false; + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vertex, ni) { + if (!BLI_BITMAP_TEST(enabled_vertices, ni.index)) { + is_expand_boundary = true; + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + if (use_mesh_boundary && SCULPT_vertex_is_boundary(ss, vertex)) { + is_expand_boundary = true; + } + + BLI_BITMAP_SET(boundary_vertices, i, is_expand_boundary); + } + + return boundary_vertices; +} + +/* Functions implementing different algorithms for initializing falloff values. */ + +/** + * Utility function to get the closet vertex after flipping an original vertex position based on + * an symmetry pass iteration index. + */ +static SculptVertRef sculpt_expand_get_vertex_index_for_symmetry_pass(Object *ob, + const char symm_it, + const SculptVertRef original_vertex) +{ + SculptSession *ss = ob->sculpt; + SculptVertRef symm_vertex = {SCULPT_EXPAND_VERTEX_NONE}; + + if (symm_it == 0) { + symm_vertex = original_vertex; + } + else { + float location[3]; + flip_v3_v3(location, SCULPT_vertex_co_get(ss, original_vertex), symm_it); + symm_vertex = SCULPT_nearest_vertex_get(NULL, ob, location, FLT_MAX, false); + } + return symm_vertex; +} + +/** + * Geodesic: Initializes the falloff with geodesic distances from the given active vertex, taking + * symmetry into account. + */ +static float *sculpt_expand_geodesic_falloff_create(Sculpt *sd, Object *ob, const int v) +{ + return SCULPT_geodesic_from_vertex_and_symm(sd, ob, v, FLT_MAX); +} + +/** + * Topology: Initializes the falloff using a flood-fill operation, + * increasing the falloff value by 1 when visiting a new vertex. + */ +typedef struct ExpandFloodFillData { + float original_normal[3]; + float edge_sensitivity; + float *dists; + float *edge_factor; +} ExpandFloodFillData; + +static bool expand_topology_floodfill_cb( + SculptSession *ss, SculptVertRef from_v, SculptVertRef to_v, bool is_duplicate, void *userdata) +{ + ExpandFloodFillData *data = userdata; + int from_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v); + + if (!is_duplicate) { + const float to_it = data->dists[from_v_i] + 1.0f; + data->dists[to_v_i] = to_it; + } + else { + data->dists[to_v_i] = data->dists[from_v_i]; + } + return true; +} + +static float *sculpt_expand_topology_falloff_create(Sculpt *sd, Object *ob, const SculptVertRef v) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + float *dists = MEM_calloc_arrayN(sizeof(float), totvert, "topology dist"); + + SculptFloodFill flood; + SCULPT_floodfill_init(ss, &flood); + SCULPT_floodfill_add_initial_with_symmetry(sd, ob, ss, &flood, v, FLT_MAX); + + ExpandFloodFillData fdata; + fdata.dists = dists; + + SCULPT_floodfill_execute(ss, &flood, expand_topology_floodfill_cb, &fdata); + SCULPT_floodfill_free(&flood); + + return dists; +} + +/** + * Normals: Flood-fills the mesh and reduces the falloff depending on the normal difference between + * each vertex and the previous one. + * This creates falloff patterns that follow and snap to the hard edges of the object. + */ +static bool mask_expand_normal_floodfill_cb( + SculptSession *ss, SculptVertRef from_v, SculptVertRef to_v, bool is_duplicate, void *userdata) +{ + ExpandFloodFillData *data = userdata; + int from_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v); + int to_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v); + + if (!is_duplicate) { + float current_normal[3], prev_normal[3]; + SCULPT_vertex_normal_get(ss, to_v, current_normal); + SCULPT_vertex_normal_get(ss, from_v, prev_normal); + const float from_edge_factor = data->edge_factor[from_v_i]; + data->edge_factor[to_v_i] = dot_v3v3(current_normal, prev_normal) * from_edge_factor; + data->dists[to_v_i] = dot_v3v3(data->original_normal, current_normal) * + powf(from_edge_factor, data->edge_sensitivity); + CLAMP(data->dists[to_v_i], 0.0f, 1.0f); + } + else { + /* PBVH_GRIDS duplicate handling. */ + data->edge_factor[to_v_i] = data->edge_factor[from_v_i]; + data->dists[to_v_i] = data->dists[from_v_i]; + } + + return true; +} + +static float *sculpt_expand_normal_falloff_create(Sculpt *sd, + Object *ob, + const SculptVertRef v, + const float edge_sensitivity) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + float *dists = MEM_malloc_arrayN(sizeof(float), totvert, "normal dist"); + float *edge_factor = MEM_callocN(sizeof(float) * totvert, "mask edge factor"); + for (int i = 0; i < totvert; i++) { + edge_factor[i] = 1.0f; + } + + SculptFloodFill flood; + SCULPT_floodfill_init(ss, &flood); + SCULPT_floodfill_add_initial_with_symmetry(sd, ob, ss, &flood, v, FLT_MAX); + + ExpandFloodFillData fdata; + fdata.dists = dists; + fdata.edge_factor = edge_factor; + fdata.edge_sensitivity = edge_sensitivity; + SCULPT_vertex_normal_get(ss, v, fdata.original_normal); + + SCULPT_floodfill_execute(ss, &flood, mask_expand_normal_floodfill_cb, &fdata); + SCULPT_floodfill_free(&flood); + + for (int repeat = 0; repeat < 2; repeat++) { + for (int i = 0; i < totvert; i++) { + float avg = 0.0f; + SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i); + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vref, ni) { + avg += dists[ni.index]; + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + dists[i] = avg / ni.size; + } + } + + MEM_SAFE_FREE(edge_factor); + + return dists; +} + +/** + * Spherical: Initializes the falloff based on the distance from a vertex, taking symmetry into + * account. + */ +static float *sculpt_expand_spherical_falloff_create(Object *ob, const SculptVertRef v) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + + float *dists = MEM_malloc_arrayN(sizeof(float), totvert, "spherical dist"); + for (int i = 0; i < totvert; i++) { + dists[i] = FLT_MAX; + } + const char symm = SCULPT_mesh_symmetry_xyz_get(ob); + + for (char symm_it = 0; symm_it <= symm; symm_it++) { + if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) { + continue; + } + const int symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v); + if (symm_vertex != -1) { + const float *co = SCULPT_vertex_co_get(ss, symm_vertex); + for (int i = 0; i < totvert; i++) { + dists[i] = min_ff(dists[i], len_v3v3(co, SCULPT_vertex_co_get(ss, BKE_pbvh_table_index_to_vertex(ss->pbvh, i)))); + } + } + } + + return dists; +} + +/** + * Boundary: This falloff mode uses the code from sculpt_boundary to initialize the closest mesh + * boundary to a falloff value of 0. Then, it propagates that falloff to the rest of the mesh so it + * stays parallel to the boundary, increasing the falloff value by 1 on each step. + */ +static float *sculpt_expand_boundary_topology_falloff_create(Object *ob, const SculptVertRef v) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + float *dists = MEM_calloc_arrayN(sizeof(float), totvert, "spherical dist"); + BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices"); + GSQueue *queue = BLI_gsqueue_new(sizeof(SculptVertRef)); + + /* Search and initialize a boundary per symmetry pass, then mark those vertices as visited. */ + const char symm = SCULPT_mesh_symmetry_xyz_get(ob); + for (char symm_it = 0; symm_it <= symm; symm_it++) { + if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) { + continue; + } + + const SculptVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v); + + SculptBoundary *boundary = SCULPT_boundary_data_init(ob, NULL, symm_vertex, FLT_MAX); + if (!boundary) { + continue; + } + + for (int i = 0; i < boundary->num_vertices; i++) { + BLI_gsqueue_push(queue, &boundary->vertices[i]); + BLI_BITMAP_ENABLE(visited_vertices, boundary->vertices[i]); + } + SCULPT_boundary_data_free(boundary); + } + + /* If there are no boundaries, return a falloff with all values set to 0. */ + if (BLI_gsqueue_is_empty(queue)) { + return dists; + } + + /* Propagate the values from the boundaries to the rest of the mesh. */ + while (!BLI_gsqueue_is_empty(queue)) { + SculptVertRef v_next; + BLI_gsqueue_pop(queue, &v_next); + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_next, ni) { + if (BLI_BITMAP_TEST(visited_vertices, ni.index)) { + continue; + } + + const int v_next_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, v_next); + + dists[ni.index] = dists[v_next_i] + 1.0f; + BLI_BITMAP_ENABLE(visited_vertices, ni.index); + BLI_gsqueue_push(queue, &ni.index); + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + } + + BLI_gsqueue_free(queue); + MEM_freeN(visited_vertices); + return dists; +} + +/** + * Topology diagonals. This falloff is similar to topology, but it also considers the diagonals of + * the base mesh faces when checking a vertex neighbor. For this reason, this is not implement + * using the general flood-fill and sculpt neighbors accessors. + */ +static float *sculpt_expand_diagonals_falloff_create(Object *ob, const SculptVertRef v) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + float *dists = MEM_calloc_arrayN(sizeof(float), totvert, "spherical dist"); + + /* This algorithm uses mesh data (polys and loops), so this falloff type can't be initialized for + * Multires. It also does not make sense to implement it for dyntopo as the result will be the + * same as Topology falloff. */ + if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) { + return dists; + } + + /* Search and mask as visited the initial vertices using the enabled symmetry passes. */ + BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(totvert, "visited vertices"); + GSQueue *queue = BLI_gsqueue_new(sizeof(SculptVertRef)); + const char symm = SCULPT_mesh_symmetry_xyz_get(ob); + for (char symm_it = 0; symm_it <= symm; symm_it++) { + if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) { + continue; + } + + const SculptVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass(ob, symm_it, v); + + BLI_gsqueue_push(queue, &symm_vertex); + BLI_BITMAP_ENABLE(visited_vertices, symm_vertex); + } + + if (BLI_gsqueue_is_empty(queue)) { + return dists; + } + + /* Propagate the falloff increasing the value by 1 each time a new vertex is visited. */ + Mesh *mesh = ob->data; + while (!BLI_gsqueue_is_empty(queue)) { + SculptVertRef v_next; + BLI_gsqueue_pop(queue, &v_next); + + int v_next_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, v_next); + + for (int j = 0; j < ss->pmap[v_next_i].count; j++) { + MPoly *p = &ss->mpoly[ss->pmap[v_next_i].indices[j]]; + for (int l = 0; l < p->totloop; l++) { + const int neighbor_v = mesh->mloop[p->loopstart + l].v; + + if (BLI_BITMAP_TEST(visited_vertices, neighbor_v)) { + continue; + } + + dists[neighbor_v] = dists[v_next_i] + 1.0f; + BLI_BITMAP_ENABLE(visited_vertices, neighbor_v); + BLI_gsqueue_push(queue, &neighbor_v); + } + } + } + + BLI_gsqueue_free(queue); + MEM_freeN(visited_vertices); + return dists; +} + +/* Functions to update the max_falloff value in the #ExpandCache. These functions are called after + * initializing a new falloff to make sure that this value is always updated. */ + +/** + * Updates the max_falloff value for vertices in a #ExpandCache based on the current values of the + * falloff, skipping any invalid values initialized to FLT_MAX and not initialized components. + */ +static void sculpt_expand_update_max_vert_falloff_value(SculptSession *ss, + ExpandCache *expand_cache) +{ + const int totvert = SCULPT_vertex_count_get(ss); + expand_cache->max_vert_falloff = -FLT_MAX; + for (int i = 0; i < totvert; i++) { + if (expand_cache->vert_falloff[i] == FLT_MAX) { + continue; + } + + if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, i)) { + continue; + } + + expand_cache->max_vert_falloff = max_ff(expand_cache->max_vert_falloff, + expand_cache->vert_falloff[i]); + } +} + +/** + * Updates the max_falloff value for faces in a ExpandCache based on the current values of the + * falloff, skipping any invalid values initialized to FLT_MAX and not initialized components. + */ +static void sculpt_expand_update_max_face_falloff_factor(SculptSession *ss, + ExpandCache *expand_cache) +{ + const int totface = ss->totfaces; + expand_cache->max_face_falloff = -FLT_MAX; + for (int i = 0; i < totface; i++) { + if (expand_cache->face_falloff[i] == FLT_MAX) { + continue; + } + + if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, i)) { + continue; + } + + expand_cache->max_face_falloff = max_ff(expand_cache->max_face_falloff, + expand_cache->face_falloff[i]); + } +} + +/** + * Functions to get falloff values for faces from the values from the vertices. This is used for + * expanding Face Sets. Depending on the data type of the #SculptSession, this needs to get the per + * face falloff value from the connected vertices of each face or from the grids stored per loops + * for each face. + */ +static void sculpt_expand_grids_to_faces_falloff(SculptSession *ss, + Mesh *mesh, + ExpandCache *expand_cache) +{ + + const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh); + + for (int p = 0; p < mesh->totpoly; p++) { + MPoly *poly = &mesh->mpoly[p]; + float accum = 0.0f; + for (int l = 0; l < poly->totloop; l++) { + const int grid_loop_index = (poly->loopstart + l) * key->grid_area; + for (int g = 0; g < key->grid_area; g++) { + accum += expand_cache->vert_falloff[grid_loop_index + g]; + } + } + expand_cache->face_falloff[p] = accum / (poly->totloop * key->grid_area); + } +} + +static void sculpt_expand_vertex_to_faces_falloff(Mesh *mesh, ExpandCache *expand_cache) +{ + for (int p = 0; p < mesh->totpoly; p++) { + MPoly *poly = &mesh->mpoly[p]; + float accum = 0.0f; + for (int l = 0; l < poly->totloop; l++) { + MLoop *loop = &mesh->mloop[l + poly->loopstart]; + accum += expand_cache->vert_falloff[loop->v]; + } + expand_cache->face_falloff[p] = accum / poly->totloop; + } +} + +/** + * Main function to update the faces falloff from a already calculated vertex falloff. + */ +static void sculpt_expand_mesh_face_falloff_from_vertex_falloff(SculptSession *ss, + Mesh *mesh, + ExpandCache *expand_cache) +{ + BLI_assert(expand_cache->vert_falloff != NULL); + + if (!expand_cache->face_falloff) { + expand_cache->face_falloff = MEM_malloc_arrayN( + mesh->totpoly, sizeof(float), "face falloff factors"); + } + + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { + sculpt_expand_vertex_to_faces_falloff(mesh, expand_cache); + } + else if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { + sculpt_expand_grids_to_faces_falloff(ss, mesh, expand_cache); + } + else { + BLI_assert(false); + } +} + +/* Recursions. These functions will generate new falloff values based on the state of the vertices + * from the current ExpandCache options and falloff values. */ + +/** + * Geodesic recursion: Initializes falloff values using geodesic distances from the boundary of the + * current vertices state. + */ +static void sculpt_expand_geodesics_from_state_boundary(Object *ob, + ExpandCache *expand_cache, + BLI_bitmap *enabled_vertices) +{ + SculptSession *ss = ob->sculpt; + BLI_assert(BKE_pbvh_type(ss->pbvh) == PBVH_FACES); + + GSet *initial_vertices = BLI_gset_int_new("initial_vertices"); + BLI_bitmap *boundary_vertices = sculpt_expand_boundary_from_enabled(ss, enabled_vertices, false); + const int totvert = SCULPT_vertex_count_get(ss); + for (int i = 0; i < totvert; i++) { + if (!BLI_BITMAP_TEST(boundary_vertices, i)) { + continue; + } + BLI_gset_add(initial_vertices, POINTER_FROM_INT(i)); + } + MEM_freeN(boundary_vertices); + + MEM_SAFE_FREE(expand_cache->vert_falloff); + MEM_SAFE_FREE(expand_cache->face_falloff); + + expand_cache->vert_falloff = SCULPT_geodesic_distances_create(ob, initial_vertices, FLT_MAX); + BLI_gset_free(initial_vertices, NULL); +} + +/** + * Topology recursion: Initializes falloff values using topology steps from the boundary of the + * current vertices state, increasing the value by 1 each time a new vertex is visited. + */ +static void sculpt_expand_topology_from_state_boundary(Object *ob, + ExpandCache *expand_cache, + BLI_bitmap *enabled_vertices) +{ + MEM_SAFE_FREE(expand_cache->vert_falloff); + MEM_SAFE_FREE(expand_cache->face_falloff); + + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + + float *dists = MEM_calloc_arrayN(sizeof(float), totvert, "topology dist"); + BLI_bitmap *boundary_vertices = sculpt_expand_boundary_from_enabled(ss, enabled_vertices, false); + + SculptFloodFill flood; + SCULPT_floodfill_init(ss, &flood); + for (int i = 0; i < totvert; i++) { + if (!BLI_BITMAP_TEST(boundary_vertices, i)) { + continue; + } + SCULPT_floodfill_add_and_skip_initial(&flood, i); + } + MEM_freeN(boundary_vertices); + + ExpandFloodFillData fdata; + fdata.dists = dists; + SCULPT_floodfill_execute(ss, &flood, expand_topology_floodfill_cb, &fdata); + SCULPT_floodfill_free(&flood); + + expand_cache->vert_falloff = dists; +} + +/** + * Main function to create a recursion step from the current #ExpandCache state. + */ +static void sculpt_expand_resursion_step_add(Object *ob, + ExpandCache *expand_cache, + const eSculptExpandRecursionType recursion_type) +{ + SculptSession *ss = ob->sculpt; + if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) { + return; + } + + BLI_bitmap *enabled_vertices = sculpt_expand_bitmap_from_enabled(ss, expand_cache); + + /* Each time a new recursion step is created, reset the distortion strength. This is the expected + * result from the recursion, as otherwise the new falloff will render with undesired distortion + * from the beginning. */ + expand_cache->texture_distortion_strength = 0.0f; + + switch (recursion_type) { + case SCULPT_EXPAND_RECURSION_GEODESICS: + sculpt_expand_geodesics_from_state_boundary(ob, expand_cache, enabled_vertices); + break; + case SCULPT_EXPAND_RECURSION_TOPOLOGY: + sculpt_expand_topology_from_state_boundary(ob, expand_cache, enabled_vertices); + break; + } + + sculpt_expand_update_max_vert_falloff_value(ss, expand_cache); + if (expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS) { + sculpt_expand_mesh_face_falloff_from_vertex_falloff(ss, ob->data, expand_cache); + sculpt_expand_update_max_face_falloff_factor(ss, expand_cache); + } + + MEM_freeN(enabled_vertices); +} + +/* Face Set Boundary falloff. */ + +/** + * When internal falloff is set to true, the falloff will fill the active Face Set with a gradient, + * otherwise the active Face Set will be filled with a constant falloff of 0.0f. + */ +static void sculpt_expand_initialize_from_face_set_boundary(Object *ob, + ExpandCache *expand_cache, + const int active_face_set, + const bool internal_falloff) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + + BLI_bitmap *enabled_vertices = BLI_BITMAP_NEW(totvert, "enabled vertices"); + for (int i = 0; i < totvert; i++) { + SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_has_unique_face_set(ss, vref)) { + continue; + } + if (!SCULPT_vertex_has_face_set(ss, vref, active_face_set)) { + continue; + } + BLI_BITMAP_ENABLE(enabled_vertices, i); + } + + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { + sculpt_expand_geodesics_from_state_boundary(ob, expand_cache, enabled_vertices); + } + else { + sculpt_expand_topology_from_state_boundary(ob, expand_cache, enabled_vertices); + } + + MEM_freeN(enabled_vertices); + + if (internal_falloff) { + for (int i = 0; i < totvert; i++) { + SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i); + + if (!(SCULPT_vertex_has_face_set(ss, vref, active_face_set) && + SCULPT_vertex_has_unique_face_set(ss, vref))) { + continue; + } + expand_cache->vert_falloff[i] *= -1.0f; + } + + float min_factor = FLT_MAX; + for (int i = 0; i < totvert; i++) { + min_factor = min_ff(expand_cache->vert_falloff[i], min_factor); + } + + const float additional_falloff = fabsf(min_factor); + for (int i = 0; i < totvert; i++) { + expand_cache->vert_falloff[i] += additional_falloff; + } + } + else { + for (int i = 0; i < totvert; i++) { + SculptVertRef vref = BKE_pbvh_table_index_to_vertex(ss->pbvh, i); + + if (!SCULPT_vertex_has_face_set(ss, vref, active_face_set)) { + continue; + } + expand_cache->vert_falloff[i] = 0.0f; + } + } +} + +/** + * Main function to initialize new falloff values in a #ExpandCache given an initial vertex and a + * falloff type. + */ +static void sculpt_expand_falloff_factors_from_vertex_and_symm_create( + ExpandCache *expand_cache, + Sculpt *sd, + Object *ob, + const int v, + eSculptExpandFalloffType falloff_type) +{ + MEM_SAFE_FREE(expand_cache->vert_falloff); + expand_cache->falloff_type = falloff_type; + + SculptSession *ss = ob->sculpt; + const bool has_topology_info = BKE_pbvh_type(ss->pbvh) == PBVH_FACES; + + switch (falloff_type) { + case SCULPT_EXPAND_FALLOFF_GEODESIC: + expand_cache->vert_falloff = has_topology_info ? + sculpt_expand_geodesic_falloff_create(sd, ob, v) : + sculpt_expand_spherical_falloff_create(ob, v); + break; + case SCULPT_EXPAND_FALLOFF_TOPOLOGY: + expand_cache->vert_falloff = sculpt_expand_topology_falloff_create(sd, ob, v); + break; + case SCULPT_EXPAND_FALLOFF_TOPOLOGY_DIAGONALS: + expand_cache->vert_falloff = has_topology_info ? + sculpt_expand_diagonals_falloff_create(ob, v) : + sculpt_expand_topology_falloff_create(sd, ob, v); + break; + case SCULPT_EXPAND_FALLOFF_NORMALS: + expand_cache->vert_falloff = sculpt_expand_normal_falloff_create( + sd, ob, v, SCULPT_EXPAND_NORMALS_FALLOFF_EDGE_SENSITIVITY); + break; + case SCULPT_EXPAND_FALLOFF_SPHERICAL: + expand_cache->vert_falloff = sculpt_expand_spherical_falloff_create(ob, v); + break; + case SCULPT_EXPAND_FALLOFF_BOUNDARY_TOPOLOGY: + expand_cache->vert_falloff = sculpt_expand_boundary_topology_falloff_create(ob, v); + break; + case SCULPT_EXPAND_FALLOFF_BOUNDARY_FACE_SET: + sculpt_expand_initialize_from_face_set_boundary( + ob, expand_cache, expand_cache->initial_active_face_set, true); + break; + case SCULPT_EXPAND_FALLOFF_ACTIVE_FACE_SET: + sculpt_expand_initialize_from_face_set_boundary( + ob, expand_cache, expand_cache->initial_active_face_set, false); + break; + } + + /* Update max falloff values and propagate to base mesh faces if needed. */ + sculpt_expand_update_max_vert_falloff_value(ss, expand_cache); + if (expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS) { + sculpt_expand_mesh_face_falloff_from_vertex_falloff(ss, ob->data, expand_cache); + sculpt_expand_update_max_face_falloff_factor(ss, expand_cache); + } +} + +/** + * Adds to the snapping Face Set `gset` all Face Sets which contain all enabled vertices for the + * current #ExpandCache state. This improves the usability of snapping, as already enabled elements + * won't switch their state when toggling snapping with the modal key-map. + */ +static void sculpt_expand_snap_initialize_from_enabled(SculptSession *ss, + ExpandCache *expand_cache) +{ + if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) { + return; + } + + /* Make sure this code runs with snapping and invert disabled. This simplifies the code and + * prevents using this function with snapping already enabled. */ + const bool prev_snap_state = expand_cache->snap; + const bool prev_invert_state = expand_cache->invert; + expand_cache->snap = false; + expand_cache->invert = false; + + BLI_bitmap *enabled_vertices = sculpt_expand_bitmap_from_enabled(ss, expand_cache); + + const int totface = ss->totfaces; + for (int i = 0; i < totface; i++) { + const int face_set = expand_cache->original_face_sets[i]; + BLI_gset_add(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(face_set)); + } + + for (int p = 0; p < totface; p++) { + MPoly *poly = &ss->mpoly[p]; + bool any_disabled = false; + for (int l = 0; l < poly->totloop; l++) { + MLoop *loop = &ss->mloop[l + poly->loopstart]; + if (!BLI_BITMAP_TEST(enabled_vertices, loop->v)) { + any_disabled = true; + break; + } + } + if (any_disabled) { + const int face_set = expand_cache->original_face_sets[p]; + BLI_gset_remove(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(face_set), NULL); + } + } + + MEM_freeN(enabled_vertices); + expand_cache->snap = prev_snap_state; + expand_cache->invert = prev_invert_state; +} + +/** + * Functions to free a #ExpandCache. + */ +static void sculpt_expand_cache_data_free(ExpandCache *expand_cache) +{ + if (expand_cache->snap_enabled_face_sets) { + BLI_gset_free(expand_cache->snap_enabled_face_sets, NULL); + } + MEM_SAFE_FREE(expand_cache->nodes); + MEM_SAFE_FREE(expand_cache->vert_falloff); + MEM_SAFE_FREE(expand_cache->face_falloff); + MEM_SAFE_FREE(expand_cache->original_mask); + MEM_SAFE_FREE(expand_cache->original_face_sets); + MEM_SAFE_FREE(expand_cache->initial_face_sets); + MEM_SAFE_FREE(expand_cache->original_colors); + MEM_SAFE_FREE(expand_cache); +} + +static void sculpt_expand_cache_free(SculptSession *ss) +{ + sculpt_expand_cache_data_free(ss->expand_cache); + /* Needs to be set to NULL as the paint cursor relies on checking this pointer detecting if an + * expand operation is running. */ + ss->expand_cache = NULL; +} + +/** + * Functions to restore the original state from the #ExpandCache when canceling the operator. + */ +static void sculpt_expand_restore_face_set_data(SculptSession *ss, ExpandCache *expand_cache) +{ + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + for (int n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + BKE_pbvh_node_mark_redraw(node); + } + MEM_freeN(nodes); + for (int i = 0; i < ss->totfaces; i++) { + ss->face_sets[i] = expand_cache->original_face_sets[i]; + } +} + +static void sculpt_expand_restore_color_data(SculptSession *ss, ExpandCache *expand_cache) +{ + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + for (int n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + { + copy_v4_v4(vd.col, expand_cache->original_colors[vd.index]); + } + BKE_pbvh_vertex_iter_end; + BKE_pbvh_node_mark_redraw(node); + } + MEM_freeN(nodes); +} + +static void sculpt_expand_restore_mask_data(SculptSession *ss, ExpandCache *expand_cache) +{ + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + for (int n = 0; n < totnode; n++) { + PBVHNode *node = nodes[n]; + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) + { + *vd.mask = expand_cache->original_mask[vd.index]; + } + BKE_pbvh_vertex_iter_end; + BKE_pbvh_node_mark_redraw(node); + } + MEM_freeN(nodes); +} + +/* Main function to restore the original state of the data to how it was before starting the expand + * operation. */ +static void sculpt_expand_restore_original_state(bContext *C, + Object *ob, + ExpandCache *expand_cache) +{ + + SculptSession *ss = ob->sculpt; + switch (expand_cache->target) { + case SCULPT_EXPAND_TARGET_MASK: + sculpt_expand_restore_mask_data(ss, expand_cache); + SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK); + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); + SCULPT_tag_update_overlays(C); + break; + case SCULPT_EXPAND_TARGET_FACE_SETS: + sculpt_expand_restore_face_set_data(ss, expand_cache); + SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK); + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); + SCULPT_tag_update_overlays(C); + break; + case SCULPT_EXPAND_TARGET_COLORS: + sculpt_expand_restore_color_data(ss, expand_cache); + SCULPT_flush_update_step(C, SCULPT_UPDATE_COLOR); + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COLOR); + break; + } +} + +/** + * Cancel operator callback. + */ +static void sculpt_expand_cancel(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + sculpt_expand_restore_original_state(C, ob, ss->expand_cache); + + SCULPT_undo_push_end(); + sculpt_expand_cache_free(ss); +} + +/* Functions to update the sculpt mesh data. */ + +/** + * Callback to update mask data per PBVH node. + */ +static void sculpt_expand_mask_update_task_cb(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + PBVHNode *node = data->nodes[i]; + ExpandCache *expand_cache = ss->expand_cache; + + bool any_changed = false; + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) + { + const float initial_mask = *vd.mask; + const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index); + + float new_mask; + + if (enabled) { + new_mask = sculpt_expand_gradient_value_get(ss, expand_cache, vd.index); + } + else { + new_mask = 0.0f; + } + + if (expand_cache->preserve) { + new_mask = max_ff(new_mask, expand_cache->original_mask[vd.index]); + } + + if (new_mask == initial_mask) { + continue; + } + + *vd.mask = clamp_f(new_mask, 0.0f, 1.0f); + any_changed = true; + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; + if (any_changed) { + BKE_pbvh_node_mark_update_mask(node); + } +} + +/** + * Update Face Set data. Not multi-threaded per node as nodes don't contain face arrays. + */ +static void sculpt_expand_face_sets_update(SculptSession *ss, ExpandCache *expand_cache) +{ + const int totface = ss->totfaces; + for (int f = 0; f < totface; f++) { + const bool enabled = sculpt_expand_face_state_get(ss, expand_cache, f); + if (!enabled) { + continue; + } + if (expand_cache->preserve) { + ss->face_sets[f] += expand_cache->next_face_set; + } + else { + ss->face_sets[f] = expand_cache->next_face_set; + } + } + + for (int i = 0; i < expand_cache->totnode; i++) { + BKE_pbvh_node_mark_redraw(ss->expand_cache->nodes[i]); + } +} + +/** + * Callback to update vertex colors per PBVH node. + */ +static void sculpt_expand_colors_update_task_cb(void *__restrict userdata, + const int i, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + PBVHNode *node = data->nodes[i]; + ExpandCache *expand_cache = ss->expand_cache; + + bool any_changed = false; + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) + { + float initial_color[4]; + copy_v4_v4(initial_color, vd.col); + + const bool enabled = sculpt_expand_state_get(ss, expand_cache, vd.index); + float fade; + + if (enabled) { + fade = sculpt_expand_gradient_value_get(ss, expand_cache, vd.index); + } + else { + fade = 0.0f; + } + + fade *= 1.0f - *vd.mask; + fade = clamp_f(fade, 0.0f, 1.0f); + + float final_color[4]; + float final_fill_color[4]; + mul_v4_v4fl(final_fill_color, expand_cache->fill_color, fade); + IMB_blend_color_float(final_color, + expand_cache->original_colors[vd.index], + final_fill_color, + expand_cache->blend_mode); + + if (equals_v4v4(initial_color, final_color)) { + continue; + } + + copy_v4_v4(vd.col, final_color); + any_changed = true; + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; + if (any_changed) { + BKE_pbvh_node_mark_update_color(node); + } +} + +static void sculpt_expand_flush_updates(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + switch (ss->expand_cache->target) { + case SCULPT_EXPAND_TARGET_MASK: + SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK); + break; + case SCULPT_EXPAND_TARGET_FACE_SETS: + SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK); + break; + case SCULPT_EXPAND_TARGET_COLORS: + SCULPT_flush_update_step(C, SCULPT_UPDATE_COLOR); + break; + default: + break; + } +} + +/* Store the original mesh data state in the expand cache. */ +static void sculpt_expand_original_state_store(Object *ob, ExpandCache *expand_cache) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + const int totface = ss->totfaces; + + /* Face Sets are always stored as they are needed for snapping. */ + expand_cache->initial_face_sets = MEM_malloc_arrayN(totface, sizeof(int), "initial face set"); + expand_cache->original_face_sets = MEM_malloc_arrayN(totface, sizeof(int), "original face set"); + for (int i = 0; i < totface; i++) { + expand_cache->initial_face_sets[i] = ss->face_sets[i]; + expand_cache->original_face_sets[i] = ss->face_sets[i]; + } + + if (expand_cache->target == SCULPT_EXPAND_TARGET_MASK) { + expand_cache->original_mask = MEM_malloc_arrayN(totvert, sizeof(float), "initial mask"); + for (int i = 0; i < totvert; i++) { + expand_cache->original_mask[i] = SCULPT_vertex_mask_get(ss, i); + } + } + + if (expand_cache->target == SCULPT_EXPAND_TARGET_COLORS) { + expand_cache->original_colors = MEM_malloc_arrayN(totvert, sizeof(float[4]), "initial colors"); + for (int i = 0; i < totvert; i++) { + copy_v4_v4(expand_cache->original_colors[i], SCULPT_vertex_color_get(ss, i)); + } + } +} + +/** + * Restore the state of the Face Sets before a new update. + */ +static void sculpt_expand_face_sets_restore(SculptSession *ss, ExpandCache *expand_cache) +{ + const int totfaces = ss->totfaces; + for (int i = 0; i < totfaces; i++) { + ss->face_sets[i] = expand_cache->initial_face_sets[i]; + } +} + +static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const SculptVertRef vertex) +{ + SculptSession *ss = ob->sculpt; + const int vertex_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, vertex); + + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + ExpandCache *expand_cache = ss->expand_cache; + + /* Update the active factor in the cache. */ + if (vertex.i == SCULPT_EXPAND_VERTEX_NONE) { + /* This means that the cursor is not over the mesh, so a valid active falloff can't be + * determined. In this situations, don't evaluate enabled states and default all vertices in + * connected components to enabled. */ + expand_cache->active_falloff = expand_cache->max_vert_falloff; + expand_cache->all_enabled = true; + } + else { + expand_cache->active_falloff = expand_cache->vert_falloff[vertex_i]; + expand_cache->all_enabled = false; + } + + if (expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS) { + /* Face sets needs to be restored their initial state on each iteration as the overwrite + * existing data. */ + sculpt_expand_face_sets_restore(ss, expand_cache); + } + + /* Update the mesh sculpt data. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .nodes = expand_cache->nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, expand_cache->totnode); + + switch (expand_cache->target) { + case SCULPT_EXPAND_TARGET_MASK: + BLI_task_parallel_range( + 0, expand_cache->totnode, &data, sculpt_expand_mask_update_task_cb, &settings); + break; + case SCULPT_EXPAND_TARGET_FACE_SETS: + sculpt_expand_face_sets_update(ss, expand_cache); + break; + case SCULPT_EXPAND_TARGET_COLORS: + BLI_task_parallel_range( + 0, expand_cache->totnode, &data, sculpt_expand_colors_update_task_cb, &settings); + break; + } + + sculpt_expand_flush_updates(C); +} + +/** + * Updates the #SculptSession cursor data and gets the active vertex + * if the cursor is over the mesh. + */ +static SculptVertRef sculpt_expand_target_vertex_update_and_get(bContext *C, + Object *ob, + const float mouse[2]) +{ + SculptSession *ss = ob->sculpt; + SculptCursorGeometryInfo sgi; + if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) { + return SCULPT_active_vertex_get(ss); + } + + SculptVertRef ret = {SCULPT_EXPAND_VERTEX_NONE}; + return ret; +} + +/** + * Moves the sculpt pivot to the average point of the boundary enabled vertices of the current + * expand state. Take symmetry and active components into account. + */ +static void sculpt_expand_reposition_pivot(bContext *C, Object *ob, ExpandCache *expand_cache) +{ + SculptSession *ss = ob->sculpt; + const char symm = SCULPT_mesh_symmetry_xyz_get(ob); + const int totvert = SCULPT_vertex_count_get(ss); + + const bool initial_invert_state = expand_cache->invert; + expand_cache->invert = false; + BLI_bitmap *enabled_vertices = sculpt_expand_bitmap_from_enabled(ss, expand_cache); + + /* For boundary topology, position the pivot using only the boundary of the enabled vertices, + * without taking mesh boundary into account. This allows to create deformations like bending the + * mesh from the boundary of the mask that was just created. */ + const float use_mesh_boundary = expand_cache->falloff_type != + SCULPT_EXPAND_FALLOFF_BOUNDARY_TOPOLOGY; + + BLI_bitmap *boundary_vertices = sculpt_expand_boundary_from_enabled( + ss, enabled_vertices, use_mesh_boundary); + + /* Ignore invert state, as this is the expected behavior in most cases and mask are created in + * inverted state by default. */ + expand_cache->invert = initial_invert_state; + + int total = 0; + float avg[3] = {0.0f}; + + const float *expand_init_co = SCULPT_vertex_co_get(ss, expand_cache->initial_active_vertex); + + for (int i = 0; i < totvert; i++) { + if (!BLI_BITMAP_TEST(boundary_vertices, i)) { + continue; + } + + if (!sculpt_expand_is_vert_in_active_component(ss, expand_cache, i)) { + continue; + } + + const float *vertex_co = SCULPT_vertex_co_get(ss, i); + + if (!SCULPT_check_vertex_pivot_symmetry(vertex_co, expand_init_co, symm)) { + continue; + } + + add_v3_v3(avg, vertex_co); + total++; + } + + MEM_freeN(enabled_vertices); + MEM_freeN(boundary_vertices); + + if (total > 0) { + mul_v3_v3fl(ss->pivot_pos, avg, 1.0f / total); + } + + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); +} + +static void sculpt_expand_finish(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + SCULPT_undo_push_end(); + + /* Tag all nodes to redraw to avoid artifacts after the fast partial updates. */ + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + for (int n = 0; n < totnode; n++) { + BKE_pbvh_node_mark_update_mask(nodes[n]); + } + MEM_freeN(nodes); + + switch (ss->expand_cache->target) { + case SCULPT_EXPAND_TARGET_MASK: + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); + break; + case SCULPT_EXPAND_TARGET_FACE_SETS: + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); + break; + case SCULPT_EXPAND_TARGET_COLORS: + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COLOR); + break; + } + + sculpt_expand_cache_free(ss); + ED_workspace_status_text(C, NULL); +} + +/** + * Finds and stores in the #ExpandCache the sculpt connected component index for each symmetry pass + * needed for expand. + */ +static void sculpt_expand_find_active_connected_components_from_vert(Object *ob, + ExpandCache *expand_cache, + const SculptVertRef initial_vertex) +{ + SculptSession *ss = ob->sculpt; + for (int i = 0; i < EXPAND_SYMM_AREAS; i++) { + expand_cache->active_connected_components[i] = EXPAND_ACTIVE_COMPONENT_NONE; + } + + const char symm = SCULPT_mesh_symmetry_xyz_get(ob); + for (char symm_it = 0; symm_it <= symm; symm_it++) { + if (!SCULPT_is_symmetry_iteration_valid(symm_it, symm)) { + continue; + } + + const SculptVertRef symm_vertex = sculpt_expand_get_vertex_index_for_symmetry_pass( + ob, symm_it, initial_vertex); + const int symm_vertex_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, symm_vertex); + + expand_cache->active_connected_components[(int)symm_it] = + ss->vertex_info.connected_component[symm_vertex_i]; + } +} + +/** + * Stores the active vertex, Face Set and mouse coordinates in the #ExpandCache based on the + * current cursor position. + */ +static void sculpt_expand_set_initial_components_for_mouse(bContext *C, + Object *ob, + ExpandCache *expand_cache, + const float mouse[2]) +{ + SculptSession *ss = ob->sculpt; + SculptVertRef initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse); + + if (initial_vertex.i == SCULPT_EXPAND_VERTEX_NONE) { + /* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active + * vertex in the sculpt session. */ + initial_vertex = SCULPT_active_vertex_get(ss); + } + copy_v2_v2(ss->expand_cache->initial_mouse, mouse); + expand_cache->initial_active_vertex = initial_vertex; + expand_cache->initial_active_face_set = SCULPT_active_face_set_get(ss); + + if (expand_cache->next_face_set == SCULPT_FACE_SET_NONE) { + /* Only set the next face set once, otherwise this ID will constantly update to a new one each + * time this function is called for using a new initial vertex from a different cursor + * position. */ + if (expand_cache->modify_active_face_set) { + expand_cache->next_face_set = SCULPT_active_face_set_get(ss); + } + else { + expand_cache->next_face_set = ED_sculpt_face_sets_find_next_available_id(ob->data); + } + } + + /* The new mouse position can be over a different connected component, so this needs to be + * updated. */ + sculpt_expand_find_active_connected_components_from_vert(ob, expand_cache, initial_vertex); +} + +/** + * Displaces the initial mouse coordinates using the new mouse position to get a new active vertex. + * After that, initializes a new falloff of the same type with the new active vertex. + */ +static void sculpt_expand_move_propagation_origin(bContext *C, + Object *ob, + const wmEvent *event, + ExpandCache *expand_cache) +{ + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + + const float mouse[2] = {event->mval[0], event->mval[1]}; + float move_disp[2]; + sub_v2_v2v2(move_disp, mouse, expand_cache->initial_mouse_move); + + float new_mouse[2]; + add_v2_v2v2(new_mouse, move_disp, expand_cache->original_mouse_move); + + sculpt_expand_set_initial_components_for_mouse(C, ob, expand_cache, new_mouse); + sculpt_expand_falloff_factors_from_vertex_and_symm_create( + expand_cache, + sd, + ob, + expand_cache->initial_active_vertex, + expand_cache->move_preview_falloff_type); +} + +/** + * Ensures that the #SculptSession contains the required data needed for Expand. + */ +static void sculpt_expand_ensure_sculptsession_data(Object *ob) +{ + SculptSession *ss = ob->sculpt; + SCULPT_vertex_random_access_ensure(ss); + SCULPT_connected_components_ensure(ob); + SCULPT_boundary_info_ensure(ob); + if (!ss->tex_pool) { + ss->tex_pool = BKE_image_pool_new(); + } +} + +/** + * Returns the active Face Sets ID from the enabled face or grid in the #SculptSession. + */ +static int sculpt_expand_active_face_set_id_get(SculptSession *ss, ExpandCache *expand_cache) +{ + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + return expand_cache->original_face_sets[ss->active_face_index]; + case PBVH_GRIDS: { + const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, + ss->active_grid_index); + return expand_cache->original_face_sets[face_index]; + } + case PBVH_BMESH: { + /* Dyntopo does not support Face Set functionality. */ + BLI_assert(false); + } + } + return SCULPT_FACE_SET_NONE; +} + +static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + + /* Skips INBETWEEN_MOUSEMOVE events and other events that may cause unnecessary updates. */ + if (!ELEM(event->type, MOUSEMOVE, EVT_MODAL_MAP)) { + return OPERATOR_RUNNING_MODAL; + } + + /* Update SculptSession data. */ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); + sculpt_expand_ensure_sculptsession_data(ob); + + /* Update and get the active vertex (and face) from the cursor. */ + const float mouse[2] = {event->mval[0], event->mval[1]}; + const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse); + + /* Handle the modal keymap state changes. */ + ExpandCache *expand_cache = ss->expand_cache; + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case SCULPT_EXPAND_MODAL_CANCEL: { + sculpt_expand_cancel(C, op); + return OPERATOR_FINISHED; + } + case SCULPT_EXPAND_MODAL_INVERT: { + expand_cache->invert = !expand_cache->invert; + break; + } + case SCULPT_EXPAND_MODAL_PRESERVE_TOGGLE: { + expand_cache->preserve = !expand_cache->preserve; + break; + } + case SCULPT_EXPAND_MODAL_GRADIENT_TOGGLE: { + expand_cache->falloff_gradient = !expand_cache->falloff_gradient; + break; + } + case SCULPT_EXPAND_MODAL_BRUSH_GRADIENT_TOGGLE: { + expand_cache->brush_gradient = !expand_cache->brush_gradient; + if (expand_cache->brush_gradient) { + expand_cache->falloff_gradient = true; + } + break; + } + case SCULPT_EXPAND_MODAL_SNAP_TOGGLE: { + if (expand_cache->snap) { + expand_cache->snap = false; + if (expand_cache->snap_enabled_face_sets) { + BLI_gset_free(expand_cache->snap_enabled_face_sets, NULL); + expand_cache->snap_enabled_face_sets = NULL; + } + } + else { + expand_cache->snap = true; + if (!expand_cache->snap_enabled_face_sets) { + expand_cache->snap_enabled_face_sets = BLI_gset_int_new("snap face sets"); + } + sculpt_expand_snap_initialize_from_enabled(ss, expand_cache); + } + } break; + case SCULPT_EXPAND_MODAL_MOVE_TOGGLE: { + if (expand_cache->move) { + expand_cache->move = false; + sculpt_expand_falloff_factors_from_vertex_and_symm_create( + expand_cache, + sd, + ob, + expand_cache->initial_active_vertex, + expand_cache->move_original_falloff_type); + break; + } + expand_cache->move = true; + expand_cache->move_original_falloff_type = expand_cache->falloff_type; + copy_v2_v2(expand_cache->initial_mouse_move, mouse); + copy_v2_v2(expand_cache->original_mouse_move, expand_cache->initial_mouse); + if (expand_cache->falloff_type == SCULPT_EXPAND_FALLOFF_GEODESIC && + SCULPT_vertex_count_get(ss) > expand_cache->max_geodesic_move_preview) { + /* Set to spherical falloff for preview in high poly meshes as it is the fastest one. + * In most cases it should match closely the preview from geodesic. */ + expand_cache->move_preview_falloff_type = SCULPT_EXPAND_FALLOFF_SPHERICAL; + } + else { + expand_cache->move_preview_falloff_type = expand_cache->falloff_type; + } + break; + } + case SCULPT_EXPAND_MODAL_RECURSION_STEP_GEODESIC: { + sculpt_expand_resursion_step_add(ob, expand_cache, SCULPT_EXPAND_RECURSION_GEODESICS); + break; + } + case SCULPT_EXPAND_MODAL_RECURSION_STEP_TOPOLOGY: { + sculpt_expand_resursion_step_add(ob, expand_cache, SCULPT_EXPAND_RECURSION_TOPOLOGY); + break; + } + case SCULPT_EXPAND_MODAL_CONFIRM: { + sculpt_expand_update_for_vertex(C, ob, target_expand_vertex); + + if (expand_cache->reposition_pivot) { + sculpt_expand_reposition_pivot(C, ob, expand_cache); + } + + sculpt_expand_finish(C); + return OPERATOR_FINISHED; + } + case SCULPT_EXPAND_MODAL_FALLOFF_GEODESIC: { + sculpt_expand_falloff_factors_from_vertex_and_symm_create( + expand_cache, + sd, + ob, + expand_cache->initial_active_vertex, + SCULPT_EXPAND_FALLOFF_GEODESIC); + break; + } + case SCULPT_EXPAND_MODAL_FALLOFF_TOPOLOGY: { + sculpt_expand_falloff_factors_from_vertex_and_symm_create( + expand_cache, + sd, + ob, + expand_cache->initial_active_vertex, + SCULPT_EXPAND_FALLOFF_TOPOLOGY); + break; + } + case SCULPT_EXPAND_MODAL_FALLOFF_TOPOLOGY_DIAGONALS: { + sculpt_expand_falloff_factors_from_vertex_and_symm_create( + expand_cache, + sd, + ob, + expand_cache->initial_active_vertex, + SCULPT_EXPAND_FALLOFF_TOPOLOGY_DIAGONALS); + break; + } + case SCULPT_EXPAND_MODAL_FALLOFF_SPHERICAL: { + sculpt_expand_falloff_factors_from_vertex_and_symm_create( + expand_cache, + sd, + ob, + expand_cache->initial_active_vertex, + SCULPT_EXPAND_FALLOFF_SPHERICAL); + break; + } + case SCULPT_EXPAND_MODAL_LOOP_COUNT_INCREASE: { + expand_cache->loop_count += 1; + break; + } + case SCULPT_EXPAND_MODAL_LOOP_COUNT_DECREASE: { + expand_cache->loop_count -= 1; + expand_cache->loop_count = max_ii(expand_cache->loop_count, 1); + break; + } + case SCULPT_EXPAND_MODAL_TEXTURE_DISTORTION_INCREASE: { + if (expand_cache->texture_distortion_strength == 0.0f) { + if (expand_cache->brush->mtex.tex == NULL) { + BKE_report(op->reports, + RPT_WARNING, + "Active brush does not contain any texture to distort the expand boundary"); + break; + } + if (expand_cache->brush->mtex.brush_map_mode != MTEX_MAP_MODE_3D) { + BKE_report(op->reports, + RPT_WARNING, + "Texture mapping not set to 3D, results may be unpredictable"); + } + } + expand_cache->texture_distortion_strength += SCULPT_EXPAND_TEXTURE_DISTORTION_STEP; + break; + } + case SCULPT_EXPAND_MODAL_TEXTURE_DISTORTION_DECREASE: { + expand_cache->texture_distortion_strength -= SCULPT_EXPAND_TEXTURE_DISTORTION_STEP; + expand_cache->texture_distortion_strength = max_ff( + expand_cache->texture_distortion_strength, 0.0f); + break; + } + } + } + + /* Handle expand origin movement if enabled. */ + if (expand_cache->move) { + sculpt_expand_move_propagation_origin(C, ob, event, expand_cache); + } + + /* Add new Face Sets IDs to the snapping gset if enabled. */ + if (expand_cache->snap) { + const int active_face_set_id = sculpt_expand_active_face_set_id_get(ss, expand_cache); + if (!BLI_gset_haskey(expand_cache->snap_enabled_face_sets, + POINTER_FROM_INT(active_face_set_id))) { + BLI_gset_add(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(active_face_set_id)); + } + } + + /* Update the sculpt data with the current state of the #ExpandCache. */ + sculpt_expand_update_for_vertex(C, ob, target_expand_vertex); + + return OPERATOR_RUNNING_MODAL; +} + +/** + * Deletes the `delete_id` Face Set ID from the mesh Face Sets + * and stores the result in `r_face_set`. + * The faces that were using the `delete_id` Face Set are filled + * using the content from their neighbors. + */ +static void sculpt_expand_delete_face_set_id( + int *r_face_sets, Mesh *mesh, MeshElemMap *pmap, const int totface, const int delete_id) +{ + /* Check that all the face sets IDs in the mesh are not equal to `delete_id` + * before attempting to delete it. */ + bool all_same_id = true; + for (int i = 0; i < totface; i++) { + if (r_face_sets[i] != delete_id) { + all_same_id = false; + break; + } + } + if (all_same_id) { + return; + } + + BLI_LINKSTACK_DECLARE(queue, void *); + BLI_LINKSTACK_DECLARE(queue_next, void *); + + BLI_LINKSTACK_INIT(queue); + BLI_LINKSTACK_INIT(queue_next); + + for (int i = 0; i < totface; i++) { + if (r_face_sets[i] == delete_id) { + BLI_LINKSTACK_PUSH(queue, POINTER_FROM_INT(i)); + } + } + + while (BLI_LINKSTACK_SIZE(queue)) { + while (BLI_LINKSTACK_SIZE(queue)) { + const int f_index = POINTER_AS_INT(BLI_LINKSTACK_POP(queue)); + int other_id = delete_id; + const MPoly *c_poly = &mesh->mpoly[f_index]; + for (int l = 0; l < c_poly->totloop; l++) { + const MLoop *c_loop = &mesh->mloop[c_poly->loopstart + l]; + const MeshElemMap *vert_map = &pmap[c_loop->v]; + for (int i = 0; i < vert_map->count; i++) { + + const int neighbor_face_index = vert_map->indices[i]; + if (r_face_sets[neighbor_face_index] != delete_id) { + other_id = r_face_sets[neighbor_face_index]; + } + } + } + + if (other_id != delete_id) { + r_face_sets[f_index] = other_id; + } + else { + BLI_LINKSTACK_PUSH(queue_next, POINTER_FROM_INT(f_index)); + } + } + + BLI_LINKSTACK_SWAP(queue, queue_next); + } + + BLI_LINKSTACK_FREE(queue); + BLI_LINKSTACK_FREE(queue_next); +} + +static void sculpt_expand_cache_initial_config_set(bContext *C, + wmOperator *op, + ExpandCache *expand_cache) +{ + /* RNA properties. */ + expand_cache->invert = RNA_boolean_get(op->ptr, "invert"); + expand_cache->preserve = RNA_boolean_get(op->ptr, "use_mask_preserve"); + expand_cache->falloff_gradient = RNA_boolean_get(op->ptr, "use_falloff_gradient"); + expand_cache->target = RNA_enum_get(op->ptr, "target"); + expand_cache->modify_active_face_set = RNA_boolean_get(op->ptr, "use_modify_active"); + expand_cache->reposition_pivot = RNA_boolean_get(op->ptr, "use_reposition_pivot"); + expand_cache->max_geodesic_move_preview = RNA_int_get(op->ptr, "max_geodesic_move_preview"); + + /* These can be exposed in RNA if needed. */ + expand_cache->loop_count = 1; + expand_cache->brush_gradient = false; + + /* Texture and color data from the active Brush. */ + Object *ob = CTX_data_active_object(C); + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + expand_cache->brush = BKE_paint_brush(&sd->paint); + BKE_curvemapping_init(expand_cache->brush->curve); + copy_v4_fl(expand_cache->fill_color, 1.0f); + copy_v3_v3(expand_cache->fill_color, BKE_brush_color_get(ss->scene, expand_cache->brush)); + IMB_colormanagement_srgb_to_scene_linear_v3(expand_cache->fill_color); + + expand_cache->scene = CTX_data_scene(C); + expand_cache->mtex = &expand_cache->brush->mtex; + expand_cache->texture_distortion_strength = 0.0f; + expand_cache->blend_mode = expand_cache->brush->blend; +} + +/** + * Does the undo sculpt push for the affected target data of the #ExpandCache. + */ +static void sculpt_expand_undo_push(Object *ob, ExpandCache *expand_cache) +{ + SculptSession *ss = ob->sculpt; + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + + switch (expand_cache->target) { + case SCULPT_EXPAND_TARGET_MASK: + for (int i = 0; i < totnode; i++) { + SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK); + } + break; + case SCULPT_EXPAND_TARGET_FACE_SETS: + SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS); + break; + case SCULPT_EXPAND_TARGET_COLORS: + for (int i = 0; i < totnode; i++) { + SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COLOR); + } + break; + } + + MEM_freeN(nodes); +} + +static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + + /* Create and configure the Expand Cache. */ + ss->expand_cache = MEM_callocN(sizeof(ExpandCache), "expand cache"); + sculpt_expand_cache_initial_config_set(C, op, ss->expand_cache); + + /* Update object. */ + const bool needs_colors = ss->expand_cache->target == SCULPT_EXPAND_TARGET_COLORS; + + if (needs_colors) { + /* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of + * earlier steps modifying the data. */ + BKE_sculpt_color_layer_create_if_needed(ob); + depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + } + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, needs_colors); + + /* Do nothing when the mesh has 0 vertices. */ + const int totvert = SCULPT_vertex_count_get(ss); + if (totvert == 0) { + sculpt_expand_cache_free(ss); + return OPERATOR_CANCELLED; + } + + /* Face Set operations are not supported in dyntopo. */ + if (ss->expand_cache->target == SCULPT_EXPAND_TARGET_FACE_SETS && + BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) { + sculpt_expand_cache_free(ss); + return OPERATOR_CANCELLED; + } + + sculpt_expand_ensure_sculptsession_data(ob); + + /* Initialize undo. */ + SCULPT_undo_push_begin(ob, "expand"); + sculpt_expand_undo_push(ob, ss->expand_cache); + + /* Set the initial element for expand from the event position. */ + const float mouse[2] = {event->mval[0], event->mval[1]}; + sculpt_expand_set_initial_components_for_mouse(C, ob, ss->expand_cache, mouse); + + /* Cache PBVH nodes. */ + BKE_pbvh_search_gather( + ss->pbvh, NULL, NULL, &ss->expand_cache->nodes, &ss->expand_cache->totnode); + + /* Store initial state. */ + sculpt_expand_original_state_store(ob, ss->expand_cache); + + if (ss->expand_cache->modify_active_face_set) { + sculpt_expand_delete_face_set_id(ss->expand_cache->initial_face_sets, + ob->data, + ss->pmap, + ss->totfaces, + ss->expand_cache->next_face_set); + } + + /* Initialize the falloff. */ + eSculptExpandFalloffType falloff_type = RNA_enum_get(op->ptr, "falloff_type"); + + /* When starting from a boundary vertex, set the initial falloff to boundary. */ + if (SCULPT_vertex_is_boundary(ss, ss->expand_cache->initial_active_vertex)) { + falloff_type = SCULPT_EXPAND_FALLOFF_BOUNDARY_TOPOLOGY; + } + + sculpt_expand_falloff_factors_from_vertex_and_symm_create( + ss->expand_cache, sd, ob, ss->expand_cache->initial_active_vertex, falloff_type); + + /* Initial mesh data update, resets all target data in the sculpt mesh. */ + sculpt_expand_update_for_vertex(C, ob, ss->expand_cache->initial_active_vertex); + + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; +} + +void sculpt_expand_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {SCULPT_EXPAND_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + {SCULPT_EXPAND_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {SCULPT_EXPAND_MODAL_INVERT, "INVERT", 0, "Invert", ""}, + {SCULPT_EXPAND_MODAL_PRESERVE_TOGGLE, "PRESERVE", 0, "Toggle Preserve State", ""}, + {SCULPT_EXPAND_MODAL_GRADIENT_TOGGLE, "GRADIENT", 0, "Toggle Gradient", ""}, + {SCULPT_EXPAND_MODAL_RECURSION_STEP_GEODESIC, + "RECURSION_STEP_GEODESIC", + 0, + "Geodesic recursion step", + ""}, + {SCULPT_EXPAND_MODAL_RECURSION_STEP_TOPOLOGY, + "RECURSION_STEP_TOPOLOGY", + 0, + "Topology recursion Step", + ""}, + {SCULPT_EXPAND_MODAL_MOVE_TOGGLE, "MOVE_TOGGLE", 0, "Move Origin", ""}, + {SCULPT_EXPAND_MODAL_FALLOFF_GEODESIC, "FALLOFF_GEODESICS", 0, "Geodesic Falloff", ""}, + {SCULPT_EXPAND_MODAL_FALLOFF_TOPOLOGY, "FALLOFF_TOPOLOGY", 0, "Topology Falloff", ""}, + {SCULPT_EXPAND_MODAL_FALLOFF_TOPOLOGY_DIAGONALS, + "FALLOFF_TOPOLOGY_DIAGONALS", + 0, + "Diagonals Falloff", + ""}, + {SCULPT_EXPAND_MODAL_FALLOFF_SPHERICAL, "FALLOFF_SPHERICAL", 0, "Spherical Falloff", ""}, + {SCULPT_EXPAND_MODAL_SNAP_TOGGLE, "SNAP_TOGGLE", 0, "Snap expand to Face Sets", ""}, + {SCULPT_EXPAND_MODAL_LOOP_COUNT_INCREASE, + "LOOP_COUNT_INCREASE", + 0, + "Loop Count Increase", + ""}, + {SCULPT_EXPAND_MODAL_LOOP_COUNT_DECREASE, + "LOOP_COUNT_DECREASE", + 0, + "Loop Count Decrease", + ""}, + {SCULPT_EXPAND_MODAL_BRUSH_GRADIENT_TOGGLE, + "BRUSH_GRADIENT_TOGGLE", + 0, + "Toggle Brush Gradient", + ""}, + {SCULPT_EXPAND_MODAL_TEXTURE_DISTORTION_INCREASE, + "TEXTURE_DISTORTION_INCREASE", + 0, + "Texture Distortion Increase", + ""}, + {SCULPT_EXPAND_MODAL_TEXTURE_DISTORTION_DECREASE, + "TEXTURE_DISTORTION_DECREASE", + 0, + "Texture Distortion Decrease", + ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static const char *name = "Sculpt Expand Modal"; + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, name); + + /* This function is called for each spacetype, only needs to add map once. */ + if (keymap && keymap->modal_items) { + return; + } + + keymap = WM_modalkeymap_ensure(keyconf, name, modal_items); + WM_modalkeymap_assign(keymap, "SCULPT_OT_expand"); +} + +void SCULPT_OT_expand(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Expand"; + ot->idname = "SCULPT_OT_expand"; + ot->description = "Generic sculpt expand operator"; + + /* API callbacks. */ + ot->invoke = sculpt_expand_invoke; + ot->modal = sculpt_expand_modal; + ot->cancel = sculpt_expand_cancel; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + static EnumPropertyItem prop_sculpt_expand_falloff_type_items[] = { + {SCULPT_EXPAND_FALLOFF_GEODESIC, "GEODESIC", 0, "Geodesic", ""}, + {SCULPT_EXPAND_FALLOFF_TOPOLOGY, "TOPOLOGY", 0, "Topology", ""}, + {SCULPT_EXPAND_FALLOFF_TOPOLOGY_DIAGONALS, + "TOPOLOGY_DIAGONALS", + 0, + "Topology Diagonals", + ""}, + {SCULPT_EXPAND_FALLOFF_NORMALS, "NORMALS", 0, "Normals", ""}, + {SCULPT_EXPAND_FALLOFF_SPHERICAL, "SPHERICAL", 0, "Spherical", ""}, + {SCULPT_EXPAND_FALLOFF_BOUNDARY_TOPOLOGY, "BOUNDARY_TOPOLOGY", 0, "Boundary Topology", ""}, + {SCULPT_EXPAND_FALLOFF_BOUNDARY_FACE_SET, "BOUNDARY_FACE_SET", 0, "Boundary Face Set", ""}, + {SCULPT_EXPAND_FALLOFF_ACTIVE_FACE_SET, "ACTIVE_FACE_SET", 0, "Active Face Set", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + static EnumPropertyItem prop_sculpt_expand_target_type_items[] = { + {SCULPT_EXPAND_TARGET_MASK, "MASK", 0, "Mask", ""}, + {SCULPT_EXPAND_TARGET_FACE_SETS, "FACE_SETS", 0, "Face Sets", ""}, + {SCULPT_EXPAND_TARGET_COLORS, "COLOR", 0, "Color", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_enum(ot->srna, + "target", + prop_sculpt_expand_target_type_items, + SCULPT_EXPAND_TARGET_MASK, + "Data Target", + "Data that is going to be modified in the expand operation"); + + RNA_def_enum(ot->srna, + "falloff_type", + prop_sculpt_expand_falloff_type_items, + SCULPT_EXPAND_FALLOFF_GEODESIC, + "Falloff Type", + "Initial falloff of the expand operation"); + + ot->prop = RNA_def_boolean( + ot->srna, "invert", false, "Invert", "Invert the expand active elements"); + ot->prop = RNA_def_boolean(ot->srna, + "use_mask_preserve", + false, + "Preserve Previous", + "Preserve the previous state of the target data"); + ot->prop = RNA_def_boolean(ot->srna, + "use_falloff_gradient", + false, + "Falloff Gradient", + "Expand Using a linear falloff"); + + ot->prop = RNA_def_boolean(ot->srna, + "use_modify_active", + false, + "Modify Active", + "Modify the active Face Set instead of creating a new one"); + + ot->prop = RNA_def_boolean( + ot->srna, + "use_reposition_pivot", + true, + "Reposition Pivot", + "Reposition the sculpt transform pivot to the boundary of the expand active area"); + + ot->prop = RNA_def_int(ot->srna, + "max_geodesic_move_preview", + 10000, + 0, + INT_MAX, + "Max Vertex Count for Geodesic Move Preview", + "Maximum number of vertices in the mesh for using geodesic falloff when " + "moving the origin of expand. If the total number of vertices is greater " + "than this value, the falloff will be set to spherical when moving", + 0, + 1000000); +} diff --git a/source/blender/editors/sculpt_paint/sculpt_geodesic.c b/source/blender/editors/sculpt_paint/sculpt_geodesic.c new file mode 100644 index 00000000000..d86d0938300 --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_geodesic.c @@ -0,0 +1,360 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_linklist_stack.h" +#include "BLI_math.h" +#include "BLI_task.h" + +#include "BLT_translation.h" + +#include "DNA_brush_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_brush.h" +#include "BKE_ccg.h" +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_image.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_multires.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" +#include "BKE_scene.h" +#include "BKE_subdiv_ccg.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" +#include "WM_message.h" +#include "WM_toolsystem.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_sculpt.h" +#include "ED_view3d.h" +#include "paint_intern.h" +#include "sculpt_intern.h" + +#include "IMB_colormanagement.h" +#include "IMB_imbuf.h" + +#include "bmesh.h" + +#include <math.h> +#include <stdlib.h> +#define SCULPT_GEODESIC_VERTEX_NONE -1 + +/* Propagate distance from v1 and v2 to v0. */ +static bool sculpt_geodesic_mesh_test_dist_add( + MVert *mvert, const int v0, const int v1, const int v2, float *dists, GSet *initial_vertices) +{ + if (BLI_gset_haskey(initial_vertices, POINTER_FROM_INT(v0))) { + return false; + } + + BLI_assert(dists[v1] != FLT_MAX); + if (dists[v0] <= dists[v1]) { + return false; + } + + float dist0; + if (v2 != SCULPT_GEODESIC_VERTEX_NONE) { + BLI_assert(dists[v2] != FLT_MAX); + if (dists[v0] <= dists[v2]) { + return false; + } + dist0 = geodesic_distance_propagate_across_triangle( + mvert[v0].co, mvert[v1].co, mvert[v2].co, dists[v1], dists[v2]); + } + else { + float vec[3]; + sub_v3_v3v3(vec, mvert[v1].co, mvert[v0].co); + dist0 = dists[v1] + len_v3(vec); + } + + if (dist0 < dists[v0]) { + dists[v0] = dist0; + return true; + } + + return false; +} + +static float *SCULPT_geodesic_mesh_create(Object *ob, + GSet *initial_vertices, + const float limit_radius) +{ + SculptSession *ss = ob->sculpt; + Mesh *mesh = BKE_object_get_original_mesh(ob); + + const int totvert = mesh->totvert; + const int totedge = mesh->totedge; + + const float limit_radius_sq = limit_radius * limit_radius; + + MEdge *edges = mesh->medge; + MVert *verts = SCULPT_mesh_deformed_mverts_get(ss); + + float *dists = MEM_malloc_arrayN(totvert, sizeof(float), "distances"); + BLI_bitmap *edge_tag = BLI_BITMAP_NEW(totedge, "edge tag"); + + if (!ss->epmap) { + BKE_mesh_edge_poly_map_create(&ss->epmap, + &ss->epmap_mem, + mesh->medge, + mesh->totedge, + mesh->mpoly, + mesh->totpoly, + mesh->mloop, + mesh->totloop); + } + if (!ss->vemap) { + BKE_mesh_vert_edge_map_create( + &ss->vemap, &ss->vemap_mem, mesh->medge, mesh->totvert, mesh->totedge); + } + + /* Both contain edge indices encoded as *void. */ + BLI_LINKSTACK_DECLARE(queue, void *); + BLI_LINKSTACK_DECLARE(queue_next, void *); + + BLI_LINKSTACK_INIT(queue); + BLI_LINKSTACK_INIT(queue_next); + + for (int i = 0; i < totvert; i++) { + if (BLI_gset_haskey(initial_vertices, POINTER_FROM_INT(i))) { + dists[i] = 0.0f; + } + else { + dists[i] = FLT_MAX; + } + } + + /* Masks vertices that are further than limit radius from an initial vertex. As there is no need + * to define a distance to them the algorithm can stop earlier by skipping them. */ + BLI_bitmap *affected_vertex = BLI_BITMAP_NEW(totvert, "affected vertex"); + GSetIterator gs_iter; + + if (limit_radius == FLT_MAX) { + /* In this case, no need to loop through all initial vertices to check distances as they are + * all going to be affected. */ + BLI_bitmap_set_all(affected_vertex, true, totvert); + } + else { + /* This is an O(n^2) loop used to limit the geodesic distance calculation to a radius. When + * this optimization is needed, it is expected for the tool to request the distance to a low + * number of vertices (usually just 1 or 2). */ + GSET_ITER (gs_iter, initial_vertices) { + const int v = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); + float *v_co = verts[v].co; + for (int i = 0; i < totvert; i++) { + if (len_squared_v3v3(v_co, verts[i].co) <= limit_radius_sq) { + BLI_BITMAP_ENABLE(affected_vertex, i); + } + } + } + } + + /* Add edges adjacent to an initial vertex to the queue. */ + for (int i = 0; i < totedge; i++) { + const int v1 = edges[i].v1; + const int v2 = edges[i].v2; + if (!BLI_BITMAP_TEST(affected_vertex, v1) && !BLI_BITMAP_TEST(affected_vertex, v2)) { + continue; + } + if (dists[v1] != FLT_MAX || dists[v2] != FLT_MAX) { + BLI_LINKSTACK_PUSH(queue, POINTER_FROM_INT(i)); + } + } + + do { + while (BLI_LINKSTACK_SIZE(queue)) { + const int e = POINTER_AS_INT(BLI_LINKSTACK_POP(queue)); + int v1 = edges[e].v1; + int v2 = edges[e].v2; + + if (dists[v1] == FLT_MAX || dists[v2] == FLT_MAX) { + if (dists[v1] > dists[v2]) { + SWAP(int, v1, v2); + } + sculpt_geodesic_mesh_test_dist_add( + verts, v2, v1, SCULPT_GEODESIC_VERTEX_NONE, dists, initial_vertices); + } + + if (ss->epmap[e].count != 0) { + for (int poly_map_index = 0; poly_map_index < ss->epmap[e].count; poly_map_index++) { + const int poly = ss->epmap[e].indices[poly_map_index]; + if (ss->face_sets[poly] <= 0) { + continue; + } + const MPoly *mpoly = &mesh->mpoly[poly]; + + for (int loop_index = 0; loop_index < mpoly->totloop; loop_index++) { + const MLoop *mloop = &mesh->mloop[loop_index + mpoly->loopstart]; + const int v_other = mloop->v; + if (ELEM(v_other, v1, v2)) { + continue; + } + if (sculpt_geodesic_mesh_test_dist_add( + verts, v_other, v1, v2, dists, initial_vertices)) { + for (int edge_map_index = 0; edge_map_index < ss->vemap[v_other].count; + edge_map_index++) { + const int e_other = ss->vemap[v_other].indices[edge_map_index]; + int ev_other; + if (edges[e_other].v1 == (uint)v_other) { + ev_other = edges[e_other].v2; + } + else { + ev_other = edges[e_other].v1; + } + + if (e_other != e && !BLI_BITMAP_TEST(edge_tag, e_other) && + (ss->epmap[e_other].count == 0 || dists[ev_other] != FLT_MAX)) { + if (BLI_BITMAP_TEST(affected_vertex, v_other) || + BLI_BITMAP_TEST(affected_vertex, ev_other)) { + BLI_BITMAP_ENABLE(edge_tag, e_other); + BLI_LINKSTACK_PUSH(queue_next, POINTER_FROM_INT(e_other)); + } + } + } + } + } + } + } + } + + for (LinkNode *lnk = queue_next; lnk; lnk = lnk->next) { + const int e = POINTER_AS_INT(lnk->link); + BLI_BITMAP_DISABLE(edge_tag, e); + } + + BLI_LINKSTACK_SWAP(queue, queue_next); + + } while (BLI_LINKSTACK_SIZE(queue)); + + BLI_LINKSTACK_FREE(queue); + BLI_LINKSTACK_FREE(queue_next); + MEM_SAFE_FREE(edge_tag); + MEM_SAFE_FREE(affected_vertex); + + return dists; +} + +/* For sculpt mesh data that does not support a geodesic distances algorithm, fallback to the + * distance to each vertex. In this case, only one of the initial vertices will be used to + * calculate the distance. */ +static float *SCULPT_geodesic_fallback_create(Object *ob, GSet *initial_vertices) +{ + + SculptSession *ss = ob->sculpt; + Mesh *mesh = BKE_object_get_original_mesh(ob); + const int totvert = mesh->totvert; + float *dists = MEM_malloc_arrayN(totvert, sizeof(float), "distances"); + int first_affected = SCULPT_GEODESIC_VERTEX_NONE; + GSetIterator gs_iter; + GSET_ITER (gs_iter, initial_vertices) { + first_affected = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter)); + break; + } + + if (first_affected == SCULPT_GEODESIC_VERTEX_NONE) { + for (int i = 0; i < totvert; i++) { + dists[i] = FLT_MAX; + } + return dists; + } + + const float *first_affected_co = SCULPT_vertex_co_get(ss, first_affected); + for (int i = 0; i < totvert; i++) { + dists[i] = len_v3v3(first_affected_co, SCULPT_vertex_co_get(ss, i)); + } + + return dists; +} + +float *SCULPT_geodesic_distances_create(Object *ob, + GSet *initial_vertices, + const float limit_radius) +{ + SculptSession *ss = ob->sculpt; + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + return SCULPT_geodesic_mesh_create(ob, initial_vertices, limit_radius); + case PBVH_BMESH: + case PBVH_GRIDS: + return SCULPT_geodesic_fallback_create(ob, initial_vertices); + } + BLI_assert(false); + return NULL; +} + +float *SCULPT_geodesic_from_vertex_and_symm(Sculpt *sd, + Object *ob, + const int vertex, + const float limit_radius) +{ + SculptSession *ss = ob->sculpt; + GSet *initial_vertices = BLI_gset_int_new("initial_vertices"); + + const char symm = SCULPT_mesh_symmetry_xyz_get(ob); + for (char i = 0; i <= symm; ++i) { + if (SCULPT_is_symmetry_iteration_valid(i, symm)) { + int v = -1; + if (i == 0) { + v = vertex; + } + else { + float location[3]; + flip_v3_v3(location, SCULPT_vertex_co_get(ss, vertex), i); + v = SCULPT_nearest_vertex_get(sd, ob, location, FLT_MAX, false); + } + if (v != -1) { + BLI_gset_add(initial_vertices, POINTER_FROM_INT(v)); + } + } + } + + float *dists = SCULPT_geodesic_distances_create(ob, initial_vertices, limit_radius); + BLI_gset_free(initial_vertices, NULL); + return dists; +} + +float *SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius) +{ + GSet *initial_vertices = BLI_gset_int_new("initial_vertices"); + BLI_gset_add(initial_vertices, POINTER_FROM_INT(vertex)); + float *dists = SCULPT_geodesic_distances_create(ob, initial_vertices, limit_radius); + BLI_gset_free(initial_vertices, NULL); + return dists; +} diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 10433b90e16..6ec6f923a1d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -194,6 +194,8 @@ void SCULPT_boundary_info_ensure(Object *object); /* Boundary Info needs to be initialized in order to use this function. */ bool SCULPT_vertex_is_boundary(const SculptSession *ss, const SculptVertRef index); +void SCULPT_connected_components_ensure(Object *ob); + /* Sculpt Visibility API */ void SCULPT_vertex_visible_set(SculptSession *ss, SculptVertRef index, bool visible); @@ -304,15 +306,14 @@ void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd, SculptFloodFill *flood, SculptVertRef index, float radius); + void SCULPT_floodfill_add_initial(SculptFloodFill *flood, SculptVertRef index); -void SCULPT_floodfill_execute(struct SculptSession *ss, - SculptFloodFill *flood, - bool (*func)(SculptSession *ss, - SculptVertRef from_v, - SculptVertRef to_v, - bool is_duplicate, - void *userdata), - void *userdata); +void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index); +void SCULPT_floodfill_execute( + struct SculptSession *ss, + SculptFloodFill *flood, + bool (*func)(SculptSession *ss, SculptVertRef from_v, SculptVertRef to_v, bool is_duplicate, void *userdata), + void *userdata); void SCULPT_floodfill_free(SculptFloodFill *flood); /* Dynamic topology */ @@ -374,6 +375,21 @@ float *SCULPT_boundary_automasking_init(Object *ob, int propagation_steps, float *automask_factor); +/* Geodesic distances. */ + +/* Returns an array indexed by vertex index containing the geodesic distance to the closest vertex +in the initial vertex set. The caller is responsible for freeing the array. +Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will +fallback to euclidean distances to one of the initial vertices in the set. */ +float *SCULPT_geodesic_distances_create(struct Object *ob, + struct GSet *initial_vertices, + const float limit_radius); +float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd, + struct Object *ob, + const int vertex, + const float limit_radius); +float *SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius); + /* Filters. */ void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, const int undo_type); void SCULPT_filter_cache_free(SculptSession *ss); @@ -1091,6 +1107,155 @@ void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cache); void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache); +/* Sculpt Expand. */ +typedef enum eSculptExpandFalloffType { + SCULPT_EXPAND_FALLOFF_GEODESIC, + SCULPT_EXPAND_FALLOFF_TOPOLOGY, + SCULPT_EXPAND_FALLOFF_TOPOLOGY_DIAGONALS, + SCULPT_EXPAND_FALLOFF_NORMALS, + SCULPT_EXPAND_FALLOFF_SPHERICAL, + SCULPT_EXPAND_FALLOFF_BOUNDARY_TOPOLOGY, + SCULPT_EXPAND_FALLOFF_BOUNDARY_FACE_SET, + SCULPT_EXPAND_FALLOFF_ACTIVE_FACE_SET, +} eSculptExpandFalloffType; + +typedef enum eSculptExpandTargetType { + SCULPT_EXPAND_TARGET_MASK, + SCULPT_EXPAND_TARGET_FACE_SETS, + SCULPT_EXPAND_TARGET_COLORS, +} eSculptExpandTargetType; + +typedef enum eSculptExpandRecursionType { + SCULPT_EXPAND_RECURSION_TOPOLOGY, + SCULPT_EXPAND_RECURSION_GEODESICS, +} eSculptExpandRecursionType; + +#define EXPAND_SYMM_AREAS 8 + +typedef struct ExpandCache { + /* Target data elements that the expand operation will affect. */ + eSculptExpandTargetType target; + + /* Falloff data. */ + eSculptExpandFalloffType falloff_type; + + /* Indexed by vertex index, precalculated falloff value of that vertex (without any falloff + * editing modification applied). */ + float *vert_falloff; + /* Max falloff value in *vert_falloff. */ + float max_vert_falloff; + + /* Indexed by base mesh poly index, precalculated falloff value of that face. These values are + * calculated from the per vertex falloff (*vert_falloff) when needed. */ + float *face_falloff; + float max_face_falloff; + + /* Falloff value of the active element (vertex or base mesh face) that Expand will expand to. */ + float active_falloff; + + /* When set to true, expand skips all falloff computations and considers all elements as enabled. + */ + bool all_enabled; + + /* Initial mouse and cursor data from where the current falloff started. This data can be changed + * during the execution of Expand by moving the origin. */ + float initial_mouse_move[2]; + float initial_mouse[2]; + SculptVertRef initial_active_vertex; + int initial_active_face_set; + + /* Maximum number of vertices allowed in the SculptSession for previewing the falloff using + * geodesic distances. */ + int max_geodesic_move_preview; + + /* Original falloff type before starting the move operation. */ + eSculptExpandFalloffType move_original_falloff_type; + /* Falloff type using when moving the origin for preview. */ + eSculptExpandFalloffType move_preview_falloff_type; + + /* Face set ID that is going to be used when creating a new Face Set. */ + int next_face_set; + + /* Face Set ID of the Face set selected for editing. */ + int update_face_set; + + /* Mouse position since the last time the origin was moved. Used for reference when moving the + * initial position of Expand. */ + float original_mouse_move[2]; + + /* Active components checks. */ + /* Indexed by symmetry pass index, contains the connected component ID found in + * SculptSession->vertex_info.connected_component. Other connected components not found in this + * array will be ignored by Expand. */ + int active_connected_components[EXPAND_SYMM_AREAS]; + + /* Snapping. */ + /* GSet containing all Face Sets IDs that Expand will use to snap the new data. */ + GSet *snap_enabled_face_sets; + + /* Texture distortion data. */ + Brush *brush; + struct Scene *scene; + struct MTex *mtex; + + /* Controls how much texture distortion will be applied to the current falloff */ + float texture_distortion_strength; + + /* Cached PBVH nodes. This allows to skip gathering all nodes from the PBVH each time expand + * needs to update the state of the elements. */ + PBVHNode **nodes; + int totnode; + + /* Expand state options. */ + + /* Number of loops (times that the falloff is going to be repeated). */ + int loop_count; + + /* Invert the falloff result. */ + bool invert; + + /* When set to true, preserves the previous state of the data and adds the new one on top. */ + bool preserve; + + /* When set to true, the mask or colors will be applied as a gradient. */ + bool falloff_gradient; + + /* When set to true, Expand will use the Brush falloff curve data to shape the gradient. */ + bool brush_gradient; + + /* When set to true, Expand will move the origin (initial active vertex and cursor position) + * instead of updating the active vertex and active falloff. */ + bool move; + + /* When set to true, Expand will snap the new data to the Face Sets IDs found in + * *original_face_sets. */ + bool snap; + + /* When set to true, Expand will use the current Face Set ID to modify an existing Face Set + * instead of creating a new one. */ + bool modify_active_face_set; + + /* When set to true, Expand will reposition the sculpt pivot to the boundary of the expand result + * after finishing the operation. */ + bool reposition_pivot; + + /* Color target data type related data. */ + float fill_color[4]; + short blend_mode; + + /* Face Sets at the first step of the expand operation, before starting modifying the active + * vertex and active falloff. These are not the original Face Sets of the sculpt before starting + * the operator as they could have been modified by Expand when initializing the operator and + * before starting changing the active vertex. These Face Sets are used for restoring and + * checking the Face Sets state while the Expand operation modal runs. */ + int *initial_face_sets; + + /* Original data of the sculpt as it was before running the Expand operator. */ + float *original_mask; + int *original_face_sets; + float (*original_colors)[4]; +} ExpandCache; + typedef struct FilterCache { bool enabled_axis[3]; bool enabled_force_axis[3]; @@ -1184,6 +1349,10 @@ bool SCULPT_get_redraw_rect(struct ARegion *region, /* Operators. */ +/* Expand. */ +void SCULPT_OT_expand(struct wmOperatorType *ot); +void sculpt_expand_modal_keymap(struct wmKeyConfig *keyconf); + /* Gestures. */ void SCULPT_OT_face_set_lasso_gesture(struct wmOperatorType *ot); void SCULPT_OT_face_set_box_gesture(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index 3a584a7f0cb..efa714e315d 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -663,11 +663,11 @@ static int action_unlink_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *evt) +static int action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* NOTE: this is hardcoded to match the behavior for the unlink button * (in interface_templates.c). */ - RNA_boolean_set(op->ptr, "force_delete", evt->shift != 0); + RNA_boolean_set(op->ptr, "force_delete", event->shift != 0); return action_unlink_exec(C, op); } diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index c112c678a09..1bd8d13b25b 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -274,9 +274,7 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type) void ED_region_draw_cb_remove_by_type(ARegionType *art, void *draw_fn, void (*free)(void *)) { - RegionDrawCB *rdc = art->drawcalls.first; - while (rdc) { - RegionDrawCB *rdc_next = rdc->next; + LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, &art->drawcalls) { if (rdc->draw == draw_fn) { if (free) { free(rdc->customdata); @@ -284,7 +282,6 @@ void ED_region_draw_cb_remove_by_type(ARegionType *art, void *draw_fn, void (*fr BLI_remlink(&art->drawcalls, rdc); MEM_freeN(rdc); } - rdc = rdc_next; } } diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 4847e8738df..43128ed00fa 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -64,13 +64,42 @@ #include "ED_screen.h" #include "WM_api.h" +#include "WM_types.h" #include "../interface/interface_intern.h" #include "buttons_intern.h" /* own include */ +static ScrArea *find_area_properties(const bContext *C); +static SpaceProperties *find_space_properties(const bContext *C); + /************************* Texture User **************************/ +static void buttons_texture_user_node_property_add(ListBase *users, + ID *id, + PointerRNA ptr, + PropertyRNA *prop, + bNodeTree *ntree, + bNode *node, + const char *category, + int icon, + const char *name) +{ + ButsTextureUser *user = MEM_callocN(sizeof(ButsTextureUser), "ButsTextureUser"); + + user->id = id; + user->ptr = ptr; + user->prop = prop; + user->ntree = ntree; + user->node = node; + user->category = category; + user->icon = icon; + user->name = name; + user->index = BLI_listbase_count(users); + + BLI_addtail(users, user); +} + static void buttons_texture_user_property_add(ListBase *users, ID *id, PointerRNA ptr, @@ -139,20 +168,66 @@ static void buttons_texture_users_find_nodetree(ListBase *users, } } +static void buttons_texture_modifier_geonodes_users_add(Object *ob, + NodesModifierData *nmd, + bNodeTree *node_tree, + ListBase *users) +{ + PointerRNA ptr; + PropertyRNA *prop; + + LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) { + if (node->type == NODE_GROUP && node->id) { + /* Recurse into the node group */ + buttons_texture_modifier_geonodes_users_add(ob, nmd, (bNodeTree *)node->id, users); + } + else if (node->type == GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE) { + RNA_pointer_create(&node_tree->id, &RNA_Node, node, &ptr); + prop = RNA_struct_find_property(&ptr, "texture"); + if (prop == NULL) { + continue; + } + + PointerRNA texptr = RNA_property_pointer_get(&ptr, prop); + Tex *tex = (RNA_struct_is_a(texptr.type, &RNA_Texture)) ? (Tex *)texptr.data : NULL; + if (tex != NULL) { + buttons_texture_user_node_property_add(users, + &ob->id, + ptr, + prop, + node_tree, + node, + N_("Geometry Nodes"), + RNA_struct_ui_icon(ptr.type), + nmd->modifier.name); + } + } + } +} + static void buttons_texture_modifier_foreach(void *userData, Object *ob, ModifierData *md, const char *propname) { - PointerRNA ptr; - PropertyRNA *prop; ListBase *users = userData; - RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr); - prop = RNA_struct_find_property(&ptr, propname); + if (md->type == eModifierType_Nodes) { + NodesModifierData *nmd = (NodesModifierData *)md; + if (nmd->node_group != NULL) { + buttons_texture_modifier_geonodes_users_add(ob, nmd, nmd->node_group, users); + } + } + else { + PointerRNA ptr; + PropertyRNA *prop; - buttons_texture_user_property_add( - users, &ob->id, ptr, prop, N_("Modifiers"), RNA_struct_ui_icon(ptr.type), md->name); + RNA_pointer_create(&ob->id, &RNA_Modifier, md, &ptr); + prop = RNA_struct_find_property(&ptr, propname); + + buttons_texture_user_property_add( + users, &ob->id, ptr, prop, N_("Modifiers"), RNA_struct_ui_icon(ptr.type), md->name); + } } static void buttons_texture_modifier_gpencil_foreach(void *userData, @@ -325,31 +400,32 @@ void buttons_texture_context_compute(const bContext *C, SpaceProperties *sbuts) ct->texture = NULL; if (ct->user) { + if (ct->user->node != NULL) { + /* Detect change of active texture node in same node tree, in that + * case we also automatically switch to the other node. */ + if ((ct->user->node->flag & NODE_ACTIVE_TEXTURE) == 0) { + ButsTextureUser *user; + for (user = ct->users.first; user; user = user->next) { + if (user->ntree == ct->user->ntree && user->node != ct->user->node) { + if (user->node->flag & NODE_ACTIVE_TEXTURE) { + ct->user = user; + ct->index = BLI_findindex(&ct->users, user); + break; + } + } + } + } + } if (ct->user->ptr.data) { PointerRNA texptr; Tex *tex; - /* get texture datablock pointer if it's a property */ + /* Get texture datablock pointer if it's a property. */ texptr = RNA_property_pointer_get(&ct->user->ptr, ct->user->prop); tex = (RNA_struct_is_a(texptr.type, &RNA_Texture)) ? texptr.data : NULL; ct->texture = tex; } - else if (ct->user->node && !(ct->user->node->flag & NODE_ACTIVE_TEXTURE)) { - ButsTextureUser *user; - - /* detect change of active texture node in same node tree, in that - * case we also automatically switch to the other node */ - for (user = ct->users.first; user; user = user->next) { - if (user->ntree == ct->user->ntree && user->node != ct->user->node) { - if (user->node->flag & NODE_ACTIVE_TEXTURE) { - ct->user = user; - ct->index = BLI_findindex(&ct->users, user); - break; - } - } - } - } } } } @@ -357,7 +433,7 @@ void buttons_texture_context_compute(const bContext *C, SpaceProperties *sbuts) static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg)) { /* callback when selecting a texture user in the menu */ - SpaceProperties *sbuts = CTX_wm_space_properties(C); + SpaceProperties *sbuts = find_space_properties(C); ButsContextTexture *ct = (sbuts) ? sbuts->texuser : NULL; ButsTextureUser *user = (ButsTextureUser *)user_p; PointerRNA texptr; @@ -371,8 +447,15 @@ static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg) if (user->node) { ED_node_set_active(CTX_data_main(C), user->ntree, user->node, NULL); ct->texture = NULL; + + /* Not totally sure if we should also change selection? */ + LISTBASE_FOREACH (bNode *, node, &user->ntree->nodes) { + nodeSetSelected(node, false); + } + nodeSetSelected(user->node, true); + WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); } - else { + if (user->ptr.data) { texptr = RNA_property_pointer_get(&user->ptr, user->prop); tex = (RNA_struct_is_a(texptr.type, &RNA_Texture)) ? texptr.data : NULL; @@ -511,16 +594,53 @@ void uiTemplateTextureUser(uiLayout *layout, bContext *C) /************************* Texture Show **************************/ +static ScrArea *find_area_properties(const bContext *C) +{ + bScreen *screen = CTX_wm_screen(C); + Object *ob = CTX_data_active_object(C); + + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + if (area->spacetype == SPACE_PROPERTIES) { + /* Only if unpinned, or if pinned object matches. */ + SpaceProperties *sbuts = area->spacedata.first; + ID *pinid = sbuts->pinid; + if (pinid == NULL || ((GS(pinid->name) == ID_OB) && (Object *)pinid == ob)) { + return area; + } + } + } + + return NULL; +} + +static SpaceProperties *find_space_properties(const bContext *C) +{ + ScrArea *area = find_area_properties(C); + if (area != NULL) { + return area->spacedata.first; + } + + return NULL; +} + static void template_texture_show(bContext *C, void *data_p, void *prop_p) { - SpaceProperties *sbuts = CTX_wm_space_properties(C); - ButsContextTexture *ct = (sbuts) ? sbuts->texuser : NULL; - ButsTextureUser *user; + if (data_p == NULL || prop_p == NULL) { + return; + } + + ScrArea *area = find_area_properties(C); + if (area == NULL) { + return; + } + SpaceProperties *sbuts = (SpaceProperties *)area->spacedata.first; + ButsContextTexture *ct = (sbuts) ? sbuts->texuser : NULL; if (!ct) { return; } + ButsTextureUser *user; for (user = ct->users.first; user; user = user->next) { if (user->ptr.data == data_p && user->prop == prop_p) { break; @@ -537,48 +657,65 @@ static void template_texture_show(bContext *C, void *data_p, void *prop_p) sbuts->preview = 1; /* redraw editor */ - ED_area_tag_redraw(CTX_wm_area(C)); + ED_area_tag_redraw(area); } } +/* Button to quickly show texture in Properties Editor texture tab. */ void uiTemplateTextureShow(uiLayout *layout, const bContext *C, PointerRNA *ptr, PropertyRNA *prop) { - /* button to quickly show texture in texture tab */ - SpaceProperties *sbuts = CTX_wm_space_properties(C); - ButsContextTexture *ct = (sbuts) ? sbuts->texuser : NULL; - ButsTextureUser *user; + /* Only show the button if there is actually a texture assigned. */ + Tex *texture = RNA_property_pointer_get(ptr, prop).data; + if (texture == NULL) { + return; + } - /* only show button in other tabs in properties editor */ - if (!ct || sbuts->mainb == BCONTEXT_TEXTURE) { + /* Only show the button if we are not in the Properties Editor's texture tab. */ + SpaceProperties *sbuts_context = CTX_wm_space_properties(C); + if (sbuts_context != NULL && sbuts_context->mainb == BCONTEXT_TEXTURE) { return; } + SpaceProperties *sbuts = find_space_properties(C); + ButsContextTexture *ct = (sbuts) ? sbuts->texuser : NULL; + /* find corresponding texture user */ - for (user = ct->users.first; user; user = user->next) { - if (user->ptr.data == ptr->data && user->prop == prop) { - break; + ButsTextureUser *user; + bool user_found = false; + if (ct != NULL) { + for (user = ct->users.first; user; user = user->next) { + if (user->ptr.data == ptr->data && user->prop == prop) { + user_found = true; + break; + } } } - /* draw button */ - if (user) { - uiBlock *block = uiLayoutGetBlock(layout); - uiBut *but; - - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_PROPERTIES, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - TIP_("Show texture in texture tab")); - UI_but_func_set(but, template_texture_show, user->ptr.data, user->prop); + /* Draw button (disabled if we cannot find a Properties Editor to display this in). */ + uiBlock *block = uiLayoutGetBlock(layout); + uiBut *but; + but = uiDefIconBut(block, + UI_BTYPE_BUT, + 0, + ICON_PROPERTIES, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + TIP_("Show texture in texture tab")); + UI_but_func_set(but, + template_texture_show, + user_found ? user->ptr.data : NULL, + user_found ? user->prop : NULL); + if (ct == NULL) { + UI_but_disable(but, TIP_("No (unpinned) Properties Editor found to display texture in")); + } + else if (!user_found) { + UI_but_disable(but, TIP_("No texture user found")); } } diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index cbe8ec4ba00..471b4a4bf5b 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -46,6 +46,7 @@ #include "ED_gpencil.h" #include "ED_mask.h" #include "ED_screen.h" +#include "ED_util.h" #include "BIF_glutil.h" diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c index b65dc909d5f..96504651e44 100644 --- a/source/blender/editors/space_clip/tracking_ops_solve.c +++ b/source/blender/editors/space_clip/tracking_ops_solve.c @@ -244,7 +244,7 @@ static int solve_camera_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE G.is_break = false; WM_jobs_start(CTX_wm_manager(C), wm_job); - WM_cursor_wait(0); + WM_cursor_wait(false); /* add modal handler for ESC */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c index e480ec2db05..9882304d97d 100644 --- a/source/blender/editors/space_clip/tracking_ops_track.c +++ b/source/blender/editors/space_clip/tracking_ops_track.c @@ -356,7 +356,7 @@ static int track_markers(bContext *C, wmOperator *op, bool use_job) G.is_break = false; WM_jobs_start(CTX_wm_manager(C), wm_job); - WM_cursor_wait(0); + WM_cursor_wait(false); /* Add modal handler for ESC. */ WM_event_add_modal_handler(C, op); diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 56fb588776e..deb32812f44 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -112,6 +112,21 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v); void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params); +typedef void *onReloadFnData; +typedef void (*onReloadFn)(struct SpaceFile *space_data, onReloadFnData custom_data); +typedef struct SpaceFile_Runtime { + /* Called once after the file browser has reloaded. Reset to NULL after calling. + * Use file_on_reload_callback_register() to register a callback. */ + onReloadFn on_reload; + onReloadFnData on_reload_custom_data; +} SpaceFile_Runtime; + +/* Register an on-reload callback function. Note that there can only be one such function at a + * time; registering a new one will overwrite the previous one. */ +void file_on_reload_callback_register(struct SpaceFile *sfile, + onReloadFn callback, + onReloadFnData custom_data); + /* file_panels.c */ void file_tool_props_region_panels_register(struct ARegionType *art); void file_execute_region_panels_register(struct ARegionType *art); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 33c37875372..757ec7c741f 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -410,14 +410,14 @@ typedef struct FileList { /* Set given path as root directory, * if last bool is true may change given string in place to a valid value. * Returns True if valid dir. */ - bool (*checkdirf)(struct FileList *, char *, const bool); + bool (*check_dir_fn)(struct FileList *, char *, const bool); /* Fill filelist (to be called by read job). */ - void (*read_jobf)( + void (*read_job_fn)( Main *, struct FileList *, const char *, short *, short *, float *, ThreadMutex *); /* Filter an entry of current filelist. */ - bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *); + bool (*filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *); short tags; /* FileListTags */ } FileList; @@ -963,7 +963,7 @@ void filelist_filter(FileList *filelist) /* Filter remap & count how many files are left after filter in a single loop. */ for (file = filelist->filelist_intern.entries.first; file; file = file->next) { - if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) { + if (filelist->filter_fn(file, filelist->filelist.root, &filelist->filter_data)) { filtered_tmp[num_filtered++] = file; } } @@ -1742,25 +1742,25 @@ void filelist_settype(FileList *filelist, short type) filelist->tags = 0; switch (filelist->type) { case FILE_MAIN: - filelist->checkdirf = filelist_checkdir_main; - filelist->read_jobf = filelist_readjob_main; - filelist->filterf = is_filtered_main; + filelist->check_dir_fn = filelist_checkdir_main; + filelist->read_job_fn = filelist_readjob_main; + filelist->filter_fn = is_filtered_main; break; case FILE_LOADLIB: - filelist->checkdirf = filelist_checkdir_lib; - filelist->read_jobf = filelist_readjob_lib; - filelist->filterf = is_filtered_lib; + filelist->check_dir_fn = filelist_checkdir_lib; + filelist->read_job_fn = filelist_readjob_lib; + filelist->filter_fn = is_filtered_lib; break; case FILE_MAIN_ASSET: - filelist->checkdirf = filelist_checkdir_main_assets; - filelist->read_jobf = filelist_readjob_main_assets; - filelist->filterf = is_filtered_main_assets; + filelist->check_dir_fn = filelist_checkdir_main_assets; + filelist->read_job_fn = filelist_readjob_main_assets; + filelist->filter_fn = is_filtered_main_assets; filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA | FILELIST_TAGS_NO_THREADS; break; default: - filelist->checkdirf = filelist_checkdir_dir; - filelist->read_jobf = filelist_readjob_dir; - filelist->filterf = is_filtered_file; + filelist->check_dir_fn = filelist_checkdir_dir; + filelist->read_job_fn = filelist_readjob_dir; + filelist->filter_fn = is_filtered_file; break; } @@ -1867,7 +1867,7 @@ const char *filelist_dir(struct FileList *filelist) bool filelist_is_dir(struct FileList *filelist, const char *path) { - return filelist->checkdirf(filelist, (char *)path, false); + return filelist->check_dir_fn(filelist, (char *)path, false); } /** @@ -1879,7 +1879,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir) BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir); - const bool is_valid_path = filelist->checkdirf(filelist, r_dir, !allow_invalid); + const bool is_valid_path = filelist->check_dir_fn(filelist, r_dir, !allow_invalid); BLI_assert(is_valid_path || allow_invalid); UNUSED_VARS_NDEBUG(is_valid_path); @@ -1990,9 +1990,7 @@ static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry) filelist_entry_free(entry); } -static FileDirEntry *filelist_file_ex(struct FileList *filelist, - const int index, - const bool use_request) +FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request) { FileDirEntry *ret = NULL, *old; FileListEntryCache *cache = &filelist->filelist_cache; @@ -3358,13 +3356,13 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update BLI_mutex_unlock(&flrj->lock); - flrj->tmp_filelist->read_jobf(flrj->current_main, - flrj->tmp_filelist, - flrj->main_name, - stop, - do_update, - progress, - &flrj->lock); + flrj->tmp_filelist->read_job_fn(flrj->current_main, + flrj->tmp_filelist, + flrj->main_name, + stop, + do_update, + progress, + &flrj->lock); } static void filelist_readjob_update(void *flrjv) @@ -3464,7 +3462,7 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) filelist_readjob_endjob(flrj); filelist_readjob_free(flrj); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED, NULL); return; } @@ -3476,7 +3474,10 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) WM_JOB_PROGRESS, WM_JOB_TYPE_FILESEL_READDIR); WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free); - WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); + WM_jobs_timer(wm_job, + 0.01, + NC_SPACE | ND_SPACE_FILE_LIST, + NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED); WM_jobs_callbacks( wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob); diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 16984bb6e43..7eecd7a05de 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -93,6 +93,8 @@ void filelist_setdir(struct FileList *filelist, char *r_dir); int filelist_files_ensure(struct FileList *filelist); int filelist_needs_reading(struct FileList *filelist); FileDirEntry *filelist_file(struct FileList *filelist, int index); +FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request); + int filelist_file_findpath(struct FileList *filelist, const char *file); struct ID *filelist_file_get_id(const struct FileDirEntry *file); FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 6917893ab5f..7015ca970a3 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -454,6 +454,66 @@ bool ED_fileselect_is_asset_browser(const SpaceFile *sfile) return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS); } +struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile) +{ + if (!ED_fileselect_is_asset_browser(sfile)) { + return NULL; + } + + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + const FileDirEntry *file = filelist_file(sfile->files, params->active_file); + if (file == NULL) { + return NULL; + } + + return filelist_file_get_id(file); +} + +static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data) +{ + ID *asset_id = (ID *)custom_data; + ED_fileselect_activate_by_id(sfile, asset_id, false); +} + +void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool deferred) +{ + if (!ED_fileselect_is_asset_browser(sfile)) { + return; + } + + /* If there are filelist operations running now ("pending" true) or soon ("force reset" true), + * there is a fair chance that the to-be-activated ID will only be present after these operations + * have completed. Defer activation until then. */ + if (deferred || filelist_pending(sfile->files) || filelist_needs_force_reset(sfile->files)) { + /* This should be thread-safe, as this function is likely called from the main thread, and + * notifiers (which cause a call to the on-reload callback function) are handled on the main + * thread as well. */ + file_on_reload_callback_register(sfile, on_reload_activate_by_id, asset_id); + return; + } + + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + struct FileList *files = sfile->files; + + const int num_files_filtered = filelist_files_ensure(files); + for (int file_index = 0; file_index < num_files_filtered; ++file_index) { + const FileDirEntry *file = filelist_file_ex(files, file_index, false); + + if (filelist_file_get_id(file) != asset_id) { + filelist_entry_select_set(files, file, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); + continue; + } + + params->active_file = file_index; + filelist_entry_select_set(files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + + /* Keep looping to deselect the other files. */ + } + + WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, NULL); + WM_main_add_notifier(NC_ASSET | NA_SELECTED, NULL); +} + /* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA * may also be remembered, but only conditionally. */ #define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index b175844a710..2c9c2688e88 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -173,6 +173,7 @@ static void file_free(SpaceLink *sl) MEM_SAFE_FREE(sfile->params); MEM_SAFE_FREE(sfile->asset_params); + MEM_SAFE_FREE(sfile->runtime); if (sfile->layout) { MEM_freeN(sfile->layout); @@ -188,6 +189,10 @@ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *area) if (sfile->layout) { sfile->layout->dirty = true; } + + if (sfile->runtime == NULL) { + sfile->runtime = MEM_callocN(sizeof(*sfile->runtime), __func__); + } } static void file_exit(wmWindowManager *wm, ScrArea *area) @@ -209,6 +214,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl) /* clear or remove stuff from old */ sfilen->op = NULL; /* file window doesn't own operators */ + sfilen->runtime = NULL; sfilen->previews_timer = NULL; sfilen->smoothscroll_timer = NULL; @@ -392,6 +398,26 @@ static void file_refresh(const bContext *C, ScrArea *area) ED_area_tag_redraw(area); } +void file_on_reload_callback_register(SpaceFile *sfile, + onReloadFn callback, + onReloadFnData custom_data) +{ + sfile->runtime->on_reload = callback; + sfile->runtime->on_reload_custom_data = custom_data; +} + +static void file_on_reload_callback_call(SpaceFile *sfile) +{ + if (sfile->runtime->on_reload == NULL) { + return; + } + + sfile->runtime->on_reload(sfile, sfile->runtime->on_reload_custom_data); + + sfile->runtime->on_reload = NULL; + sfile->runtime->on_reload_custom_data = NULL; +} + static void file_listener(const wmSpaceTypeListenerParams *params) { ScrArea *area = params->area; @@ -419,12 +445,26 @@ static void file_listener(const wmSpaceTypeListenerParams *params) } break; } + switch (wmn->action) { + case NA_JOB_FINISHED: + file_on_reload_callback_call(sfile); + break; + } break; case NC_ASSET: { - if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { - /* Full refresh of the file list if local asset data was changed. Refreshing this view is - * cheap and users expect this to be updated immediately. */ - file_tag_reset_list(area, sfile); + switch (wmn->action) { + case NA_SELECTED: + case NA_ACTIVATED: + ED_area_tag_refresh(area); + break; + case NA_ADDED: + case NA_REMOVED: + if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { + /* Full refresh of the file list if local asset data was changed. Refreshing this view + * is cheap and users expect this to be updated immediately. */ + file_tag_reset_list(area, sfile); + } + break; } break; } @@ -464,8 +504,7 @@ static void file_main_region_listener(const wmRegionListenerParams *params) } break; case NC_ID: - if (ELEM(wmn->action, NA_RENAME)) { - /* In case the filelist shows ID names. */ + if (ELEM(wmn->action, NA_SELECTED, NA_ACTIVATED, NA_RENAME)) { ED_region_tag_redraw(region); } break; diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 67d5055ec65..2be6d31369c 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -68,6 +68,7 @@ #include "ED_mask.h" #include "ED_render.h" #include "ED_screen.h" +#include "ED_util.h" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 4008ca228ac..fc3619f01b9 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1816,11 +1816,11 @@ static bool save_image_op( opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") && RNA_boolean_get(op->ptr, "save_as_render")); - WM_cursor_wait(1); + WM_cursor_wait(true); bool ok = BKE_image_save(op->reports, bmain, ima, iuser, opts); - WM_cursor_wait(0); + WM_cursor_wait(false); /* Remember file path for next save. */ BLI_strncpy(G.ima, opts->filepath, sizeof(G.ima)); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 95ca8aba399..c51d2f25efd 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -54,6 +54,7 @@ #include "ED_screen.h" #include "ED_space_api.h" #include "ED_transform.h" +#include "ED_util.h" #include "ED_uvedit.h" #include "WM_api.h" diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index fb297672f0f..f2cea23af76 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -594,11 +594,11 @@ static int nla_action_unlink_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static int nla_action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *evt) +static int nla_action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* NOTE: this is hardcoded to match the behavior for the unlink button * (in interface_templates.c) */ - RNA_boolean_set(op->ptr, "force_delete", evt->shift != 0); + RNA_boolean_set(op->ptr, "force_delete", event->shift != 0); return nla_action_unlink_exec(C, op); } diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index c640b076ba4..bc043a4e665 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -42,6 +42,7 @@ set(SRC node_buttons.c node_draw.cc node_edit.c + node_geometry_attribute_search.cc node_gizmo.c node_group.c node_ops.c diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 82a1cd818c9..977c2053187 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3389,7 +3389,15 @@ static void std_node_socket_draw( case SOCK_STRING: { uiLayout *row = uiLayoutSplit(layout, 0.5f, false); uiItemL(row, text, 0); - uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0); + + const bNodeTree *node_tree = (const bNodeTree *)node_ptr->owner_id; + if (node_tree->type == NTREE_GEOMETRY) { + node_geometry_add_attribute_search_button(node_tree, node, ptr, row); + } + else { + uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0); + } + break; } case SOCK_OBJECT: { diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 162f3878f7e..5a0cacf070b 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -1236,16 +1236,15 @@ static char *node_errors_tooltip_fn(bContext *UNUSED(C), void *argN, const char for (const NodeWarning &warning : warnings.drop_back(1)) { complete_string += warning.message; + /* Adding the period is not ideal for multi-line messages, but it is consistent + * with other tooltip implementations in Blender, so it is added here. */ + complete_string += '.'; complete_string += '\n'; } + /* Let the tooltip system automatically add the last period. */ complete_string += warnings.last().message; - /* Remove the last period-- the tooltip system adds this automatically. */ - if (complete_string.back() == '.') { - complete_string.pop_back(); - } - return BLI_strdupn(complete_string.c_str(), complete_string.size()); } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 4826b6c72ba..5205e50b0bf 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2231,10 +2231,13 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) link->tosock->new_sock); } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); + Main *bmain = CTX_data_main(C); + ntreeUpdateTree(bmain, snode->edittree); snode_notify(C, snode); snode_dag_update(C, snode); + /* Pasting nodes can create arbitrary new relations, because nodes can reference IDs. */ + DEG_relations_tag_update(bmain); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc new file mode 100644 index 00000000000..b03346577a8 --- /dev/null +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -0,0 +1,151 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_index_range.hh" +#include "BLI_listbase.h" +#include "BLI_map.hh" +#include "BLI_set.hh" +#include "BLI_string_ref.hh" +#include "BLI_string_search.h" + +#include "DNA_modifier_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" + +#include "BKE_context.h" +#include "BKE_node_ui_storage.hh" +#include "BKE_object.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "node_intern.h" + +using blender::IndexRange; +using blender::Map; +using blender::Set; +using blender::StringRef; + +struct AttributeSearchData { + const bNodeTree &node_tree; + const bNode &node; + + uiBut *search_button; + + /* Used to keep track of a button pointer over multiple redraws. Since the UI code + * may reallocate the button, without this we might end up with a dangling pointer. */ + uiButStore *button_store; + uiBlock *button_store_block; +}; + +static void attribute_search_update_fn( + const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first) +{ + AttributeSearchData *data = static_cast<AttributeSearchData *>(arg); + const NodeUIStorage *ui_storage = BKE_node_tree_ui_storage_get_from_context( + C, data->node_tree, data->node); + if (ui_storage == nullptr) { + return; + } + + const Set<std::string> &attribute_name_hints = ui_storage->attribute_name_hints; + + if (str[0] != '\0' && !attribute_name_hints.contains_as(StringRef(str))) { + /* Any string may be valid, so add the current search string with the hints. */ + UI_search_item_add(items, str, (void *)str, ICON_ADD, 0, 0); + } + + if (str[0] == '\0' && !is_first) { + /* Allow clearing the text field when the string is empty, but not on the first pass, + * or opening an attribute field for the first time would show this search item. */ + UI_search_item_add(items, str, (void *)str, ICON_X, 0, 0); + } + + /* Don't filter when the menu is first opened, but still run the search + * so the items are in the same order they will appear in while searching. */ + const char *string = is_first ? "" : str; + + StringSearch *search = BLI_string_search_new(); + for (const std::string &attribute_name : attribute_name_hints) { + BLI_string_search_add(search, attribute_name.c_str(), (void *)&attribute_name); + } + + std::string **filtered_items; + const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items); + + for (const int i : IndexRange(filtered_amount)) { + std::string *item = filtered_items[i]; + if (!UI_search_item_add(items, item->c_str(), item, ICON_NONE, 0, 0)) { + break; + } + } + + MEM_freeN(filtered_items); + BLI_string_search_free(search); +} + +static void attribute_search_free_fn(void *arg) +{ + AttributeSearchData *data = static_cast<AttributeSearchData *>(arg); + + UI_butstore_free(data->button_store_block, data->button_store); + delete data; +} + +void node_geometry_add_attribute_search_button(const bNodeTree *node_tree, + const bNode *node, + PointerRNA *socket_ptr, + uiLayout *layout) +{ + uiBlock *block = uiLayoutGetBlock(layout); + uiBut *but = uiDefIconTextButR(block, + UI_BTYPE_SEARCH_MENU, + 0, + ICON_NONE, + "", + 0, + 0, + 10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */ + UI_UNIT_Y, + socket_ptr, + "default_value", + 0, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + ""); + + AttributeSearchData *data = new AttributeSearchData{ + *node_tree, + *node, + but, + UI_butstore_create(block), + block, + }; + + UI_butstore_register(data->button_store, &data->search_button); + + UI_but_func_search_set_results_are_suggestions(but, true); + UI_but_func_search_set(but, + nullptr, + attribute_search_update_fn, + static_cast<void *>(data), + attribute_search_free_fn, + nullptr, + nullptr); +} diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 5973d59e68f..19700b258ae 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -57,6 +57,9 @@ typedef struct bNodeLinkDrag { ListBase links; bool from_multi_input_socket; int in_out; + + /** Temporarily stores the last picked link from multi input socket operator. */ + struct bNodeLink *last_picked_multi_input_socket_link; } bNodeLinkDrag; typedef struct SpaceNode_Runtime { @@ -289,6 +292,12 @@ void NODE_GGT_backdrop_corner_pin(struct wmGizmoGroupType *gzgt); void NODE_OT_cryptomatte_layer_add(struct wmOperatorType *ot); void NODE_OT_cryptomatte_layer_remove(struct wmOperatorType *ot); +/* node_geometry_attribute_search.cc */ +void node_geometry_add_attribute_search_button(const struct bNodeTree *node_tree, + const struct bNode *node, + struct PointerRNA *socket_ptr, + struct uiLayout *layout); + extern const char *node_context_dir[]; /* XXXXXX */ diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index d6edfcce8e8..35dd865047e 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -280,7 +280,7 @@ static void pick_input_link_by_link_intersect(const bContext *C, float distance = dist_squared_to_line_segment_v2(cursor, l1, l2); if (distance < cursor_link_touch_distance) { link_to_pick = link; - RNA_int_set(op->ptr, "last_picked_link_index", link->multi_input_socket_index); + nldrag->last_picked_multi_input_socket_link = link_to_pick; } } } @@ -290,13 +290,9 @@ static void pick_input_link_by_link_intersect(const bContext *C, * Not essential for the basic behavior, but can make interaction feel a bit better if * the mouse moves to the right and loses the "selection." */ if (!link_to_pick) { - int last_picked_link_index = RNA_int_get(op->ptr, "last_picked_link_index"); - if (last_picked_link_index > -1) { - LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) { - if (link->multi_input_socket_index == last_picked_link_index) { - link_to_pick = link; - } - } + bNodeLink *last_picked_link = nldrag->last_picked_multi_input_socket_link; + if (last_picked_link) { + link_to_pick = last_picked_link; } } @@ -1032,7 +1028,6 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) float cursor[2]; UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &cursor[0], &cursor[1]); RNA_float_set_array(op->ptr, "drag_start", cursor); - RNA_int_set(op->ptr, "last_picked_link_index", -1); RNA_boolean_set(op->ptr, "has_link_picked", false); ED_preview_kill_jobs(CTX_wm_manager(C), bmain); @@ -1102,15 +1097,6 @@ void NODE_OT_link(wmOperatorType *ot) -UI_PRECISION_FLOAT_MAX, UI_PRECISION_FLOAT_MAX); RNA_def_property_flag(prop, PROP_HIDDEN); - RNA_def_int(ot->srna, - "last_picked_link_index", - -1, - -1, - 4095, - "Last Picked Link Index", - "The index of the last picked link on a multi-input socket", - -1, - 4095); RNA_def_property_flag(prop, PROP_HIDDEN); } diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 58d22c2864f..704b7350bb9 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -1178,7 +1178,8 @@ static void node_find_create_label(const bNode *node, char *str, int maxlen) static void node_find_update_fn(const struct bContext *C, void *UNUSED(arg), const char *str, - uiSearchItems *items) + uiSearchItems *items, + const bool UNUSED(is_first)) { SpaceNode *snode = CTX_wm_space_node(C); diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index d54265aa292..7b9bc44f986 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -57,6 +57,8 @@ set(SRC tree/tree_element.cc tree/tree_element_anim_data.cc tree/tree_element_driver_base.cc + tree/tree_element_gpencil_layer.cc + tree/tree_element_id.cc tree/tree_element_nla.cc outliner_intern.h @@ -66,6 +68,8 @@ set(SRC tree/tree_element.hh tree/tree_element_anim_data.hh tree/tree_element_driver_base.hh + tree/tree_element_gpencil_layer.hh + tree/tree_element_id.hh tree/tree_element_nla.hh ) diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 0afc26e0d8a..d54e35f659c 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -71,7 +71,7 @@ bool outliner_is_collection_tree_element(const TreeElement *te) TSE_VIEW_COLLECTION_BASE)) { return true; } - if (tselem->type == 0 && te->idcode == ID_GR) { + if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_GR) { return true; } @@ -94,7 +94,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) Scene *scene = (Scene *)tselem->id; return scene->master_collection; } - if (tselem->type == 0 && te->idcode == ID_GR) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_GR)) { return (Collection *)tselem->id; } @@ -111,7 +111,7 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu return TRAVERSE_CONTINUE; } - if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id && GS(tselem->id->name) != ID_GR)) { return TRAVERSE_SKIP_CHILDS; } @@ -127,7 +127,7 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom return TRAVERSE_CONTINUE; } - if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { return TRAVERSE_SKIP_CHILDS; } @@ -1367,7 +1367,7 @@ void OUTLINER_OT_collection_enable(wmOperatorType *ot) /* identifiers */ ot->name = "Enable Collection"; ot->idname = "OUTLINER_OT_collection_enable"; - ot->description = "Enable viewport drawing in the view layers"; + ot->description = "Enable viewport display in the view layers"; /* api callbacks */ ot->exec = collection_flag_exec; @@ -1382,7 +1382,7 @@ void OUTLINER_OT_collection_disable(wmOperatorType *ot) /* identifiers */ ot->name = "Disable Collection"; ot->idname = "OUTLINER_OT_collection_disable"; - ot->description = "Disable viewport drawing in the view layers"; + ot->description = "Disable viewport display in the view layers"; /* api callbacks */ ot->exec = collection_flag_exec; @@ -1458,7 +1458,7 @@ static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void BLI_gset_add(data->collections_to_edit, lc); } } - else if (tselem->type == 0 && te->idcode == ID_OB) { + else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; Base *base = BKE_view_layer_base_find(data->view_layer, ob); BLI_gset_add(data->bases_to_edit, base); diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.c index e2b3b79e027..4293d8da73e 100644 --- a/source/blender/editors/space_outliner/outliner_context.c +++ b/source/blender/editors/space_outliner/outliner_context.c @@ -34,7 +34,7 @@ static void outliner_context_selected_ids_recursive(const ListBase *subtree, { LISTBASE_FOREACH (const TreeElement *, te, subtree) { const TreeStoreElem *tse = TREESTORE(te); - if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, 0, TSE_LAYER_COLLECTION))) { + if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, TSE_SOME_ID, TSE_LAYER_COLLECTION))) { CTX_data_id_list_add(result, tse->id); } outliner_context_selected_ids_recursive(&te->subtree, result); diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index 3090cab75ae..01fb0fc6f78 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -124,7 +124,7 @@ static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode TreeElement *te = outliner_drop_find(C, event); TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL; - if (te && te->idcode == idcode && tselem->type == 0) { + if (te && (te->idcode == idcode) && (tselem->type == TSE_SOME_ID)) { return tselem->id; } return NULL; @@ -215,7 +215,7 @@ static bool is_collection_element(TreeElement *te) static bool is_object_element(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - return tselem->type == 0 && te->idcode == ID_OB; + return (tselem->type == TSE_SOME_ID) && te->idcode == ID_OB; } static bool is_pchan_element(TreeElement *te) @@ -281,7 +281,7 @@ static int outliner_get_insert_index(TreeElement *drag_te, static bool parent_drop_allowed(TreeElement *te, Object *potential_child) { TreeStoreElem *tselem = TREESTORE(te); - if (te->idcode != ID_OB || tselem->type != 0) { + if ((te->idcode != ID_OB) || (tselem->type != TSE_SOME_ID)) { return false; } @@ -421,7 +421,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) TreeElement *te = outliner_drop_find(C, event); TreeStoreElem *tselem = te ? TREESTORE(te) : NULL; - if (!(te && te->idcode == ID_OB && tselem->type == 0)) { + if (!(te && (te->idcode == ID_OB) && (tselem->type == TSE_SOME_ID))) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 008ae727947..690adb09570 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -675,7 +675,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) if (ts && tselem) { TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem); - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { BLI_libblock_ensure_unique_name(bmain, tselem->id->name); switch (GS(tselem->id->name)) { @@ -1100,11 +1100,11 @@ static void outliner_draw_restrictbuts(uiBlock *block, UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } } - else if ((tselem->type == 0 && te->idcode == ID_OB) && + else if (((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) && (te->flag & TE_CHILD_NOT_IN_COLLECTION)) { /* Don't show restrict columns for children that are not directly inside the collection. */ } - else if (tselem->type == 0 && te->idcode == ID_OB) { + else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { PointerRNA ptr; Object *ob = (Object *)tselem->id; RNA_id_pointer_create(&ob->id, &ptr); @@ -1699,7 +1699,7 @@ static void outliner_draw_userbuts(uiBlock *block, LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) { - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { uiBut *bt; ID *id = tselem->id; const char *tip = NULL; @@ -1949,7 +1949,7 @@ static void outliner_draw_mode_column_toggle(uiBlock *block, TreeStoreElem *tselem, const bool lock_object_modes) { - if (tselem->type != 0 || te->idcode != ID_OB) { + if ((tselem->type != TSE_SOME_ID) || (te->idcode != ID_OB)) { return; } @@ -2046,7 +2046,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) { TreeElementIcon data = {0}; - if (tselem->type) { + if (tselem->type != TSE_SOME_ID) { switch (tselem->type) { case TSE_ANIM_DATA: data.icon = ICON_ANIM_DATA; /* XXX */ @@ -2825,7 +2825,8 @@ int tree_element_id_type_to_index(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - const int id_index = tselem->type == 0 ? BKE_idtype_idcode_to_index(te->idcode) : INDEX_ID_GR; + const int id_index = (tselem->type == TSE_SOME_ID) ? BKE_idtype_idcode_to_index(te->idcode) : + INDEX_ID_GR; if (id_index < INDEX_ID_OB) { return id_index; } @@ -2862,9 +2863,9 @@ static void outliner_draw_iconrow(bContext *C, te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED); /* object hierarchy always, further constrained on level */ - if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) { + if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) { /* active blocks get white circle */ - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { if (te->idcode == ID_OB) { active = (tvc->obact == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE; } @@ -2879,7 +2880,7 @@ static void outliner_draw_iconrow(bContext *C, active = tree_element_type_active_state_get(C, tvc, te, tselem); } - if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) { + if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) { outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); } else { @@ -2954,7 +2955,7 @@ static bool element_should_draw_faded(const TreeViewContext *tvc, const TreeElement *te, const TreeStoreElem *tselem) { - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { switch (te->idcode) { case ID_OB: { const Object *ob = (const Object *)tselem->id; @@ -3023,7 +3024,7 @@ static void outliner_draw_tree_element(bContext *C, GPU_blend(GPU_BLEND_ALPHA); /* Colors for active/selected data. */ - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { if (te->idcode == ID_OB) { Object *ob = (Object *)tselem->id; Base *base = (te->directdata) ? (Base *)te->directdata : @@ -3080,7 +3081,7 @@ static void outliner_draw_tree_element(bContext *C, if (tselem->type == TSE_VIEW_COLLECTION_BASE) { /* Scene collection in view layer can't expand/collapse. */ } - else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || + else if (te->subtree.first || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) || (te->flag & TE_LAZY_CLOSED)) { /* Open/close icon, only when sub-levels, except for scene. */ int icon_x = startx; @@ -3117,7 +3118,7 @@ static void outliner_draw_tree_element(bContext *C, offsx += 2 * ufac; } - if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) || + if (ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION) || ((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) { const BIFIconID lib_icon = UI_icon_from_library(tselem->id); if (lib_icon != ICON_NONE) { @@ -3143,7 +3144,7 @@ static void outliner_draw_tree_element(bContext *C, /* Closed item, we draw the icons, not when it's a scene, or master-server list though. */ if (!TSELEM_OPEN(tselem, space_outliner)) { if (te->subtree.first) { - if (tselem->type == 0 && te->idcode == ID_SCE) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) { /* Pass. */ } /* this tree element always has same amount of branches, so don't draw */ @@ -3210,7 +3211,7 @@ static bool subtree_contains_object(ListBase *lb) { LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { return true; } } @@ -3265,7 +3266,7 @@ static void outliner_draw_hierarchy_lines_recursive(uint pos, y = *starty; } - else if (tselem->type == 0 && te->idcode == ID_OB) { + else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { if (subtree_contains_object(&te->subtree)) { draw_hierarchy_line = true; is_object_line = true; diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index d1260f02c67..18abe17d515 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -464,7 +464,8 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto ID *id = tselem->id; BLI_assert(id != NULL); - BLI_assert(ELEM(tselem->type, 0 && te->idcode != 0, TSE_LAYER_COLLECTION)); + BLI_assert(((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) || + (tselem->type == TSE_LAYER_COLLECTION)); UNUSED_VARS_NDEBUG(te); if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) { @@ -638,7 +639,7 @@ static bool outliner_id_remap_find_tree_element(bContext *C, if (y > te->ys && y < te->ys + UI_UNIT_Y) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && tselem->id) { + if ((tselem->type == TSE_SOME_ID) && tselem->id) { printf("found id %s (%p)!\n", tselem->id->name, tselem->id); RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name)); @@ -763,7 +764,7 @@ static int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree) TreeStoreElem *tselem = TREESTORE(te); /* if item is selected and is an ID, tag it as needing to be copied. */ - if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) { ID *id = tselem->id; if (!(id->tag & LIB_TAG_DOIT)) { BKE_copybuffer_tag_ID(tselem->id); @@ -1640,7 +1641,7 @@ static int subtree_has_objects(ListBase *lb) { LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { return 1; } if (subtree_has_objects(&te->subtree)) { @@ -1658,7 +1659,7 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outli TreeStoreElem *tselem = TREESTORE(te); if (ELEM(tselem->type, - 0, + TSE_SOME_ID, TSE_SCENE_OBJECTS_BASE, TSE_VIEW_COLLECTION_BASE, TSE_LAYER_COLLECTION)) { @@ -2267,7 +2268,7 @@ static bool ed_operator_outliner_id_orphans_active(bContext *C) /** \} */ -static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt)) +static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Main *bmain = CTX_data_main(C); int num_tagged[INDEX_ID_MAX] = {0}; diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index e31af48ab7e..d53a37fa60e 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -198,7 +198,7 @@ void outliner_item_mode_toggle(bContext *C, { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); @@ -301,7 +301,7 @@ static void tree_element_object_activate(bContext *C, Object *ob = NULL; /* if id is not object, we search back */ - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { ob = (Object *)tselem->id; } else { @@ -443,7 +443,7 @@ static void tree_element_world_activate(bContext *C, Scene *scene, TreeElement * TreeElement *tep = te->parent; if (tep) { TreeStoreElem *tselem = TREESTORE(tep); - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { sce = (Scene *)tselem->id; } } @@ -1165,7 +1165,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE int context = 0; /* ID Types */ - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { RNA_id_pointer_create(tselem->id, &ptr); switch (te->idcode) { @@ -1374,12 +1374,12 @@ static void do_outliner_item_activate_tree_element(bContext *C, tvc->scene, tvc->view_layer, te, - (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : - OL_SETSEL_NORMAL, - recursive && tselem->type == 0); + (extend && tselem->type == TSE_SOME_ID) ? OL_SETSEL_EXTEND : + OL_SETSEL_NORMAL, + recursive && tselem->type == TSE_SOME_ID); } - if (tselem->type == 0) { /* The lib blocks. */ + if (tselem->type == TSE_SOME_ID) { /* The lib blocks. */ if (do_activate_data == false) { /* Only select in outliner. */ } diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c index 8bd5e3a130a..6543a909a41 100644 --- a/source/blender/editors/space_outliner/outliner_sync.c +++ b/source/blender/editors/space_outliner/outliner_sync.c @@ -326,7 +326,7 @@ static void outliner_sync_selection_from_outliner(Scene *scene, LISTBASE_FOREACH (TreeElement *, te, tree) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { if (sync_types->object) { outliner_select_sync_to_object(view_layer, te, tselem, selected_items->objects); } @@ -503,7 +503,7 @@ static void outliner_sync_selection_to_outliner(ViewLayer *view_layer, LISTBASE_FOREACH (TreeElement *, te, tree) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) { if (sync_types->object) { outliner_select_sync_from_object(view_layer, active_data->object, te, tselem); } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 8726fd768d4..9af2ba6a82b 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -106,7 +106,7 @@ static void get_element_operation_type( TreeStoreElem *tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { /* Layer collection points to collection ID. */ - if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) { if (*datalevel == 0) { *datalevel = tselem->type; } @@ -402,7 +402,8 @@ static void outliner_do_libdata_operation(bContext *C, LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { - if ((tselem->type == 0 && te->idcode != 0) || tselem->type == TSE_LAYER_COLLECTION) { + if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) || + tselem->type == TSE_LAYER_COLLECTION) { TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; operation_fn(C, reports, scene, te, tsep, tselem, user_data); } @@ -554,7 +555,8 @@ static void merged_element_search_fn_recursive( static void merged_element_search_update_fn(const bContext *UNUSED(C), void *data, const char *str, - uiSearchItems *items) + uiSearchItems *items, + const bool UNUSED(is_first)) { MergedSearchData *search_data = (MergedSearchData *)data; TreeElement *parent = search_data->parent_element; @@ -1043,7 +1045,7 @@ void outliner_do_object_operation_ex(bContext *C, TreeStoreElem *tselem = TREESTORE(te); bool select_handled = false; if (tselem->flag & TSE_SELECTED) { - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { /* When objects selected in other scenes... dunno if that should be allowed. */ Scene *scene_owner = (Scene *)outliner_search_back(te, ID_SCE); if (scene_owner && scene_act != scene_owner) { @@ -1600,7 +1602,7 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void return TRAVERSE_CONTINUE; } - if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { return TRAVERSE_SKIP_CHILDS; } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index f94f19246fa..6ca986660c1 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -307,7 +307,7 @@ static void outliner_add_line_styles(SpaceOutliner *space_outliner, continue; } linestyle->id.tag &= ~LIB_TAG_DOIT; - outliner_add_element(space_outliner, lb, linestyle, te, 0, 0); + outliner_add_element(space_outliner, lb, linestyle, te, TSE_SOME_ID, 0); } } } @@ -332,7 +332,7 @@ static void outliner_add_scene_contents(SpaceOutliner *space_outliner, } /* World */ - outliner_add_element(space_outliner, lb, sce->world, te, 0, 0); + outliner_add_element(space_outliner, lb, sce->world, te, TSE_SOME_ID, 0); /* Collections */ ten = outliner_add_element(space_outliner, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); @@ -343,7 +343,7 @@ static void outliner_add_scene_contents(SpaceOutliner *space_outliner, ten = outliner_add_element(space_outliner, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); ten->name = IFACE_("Objects"); FOREACH_SCENE_OBJECT_BEGIN (sce, ob) { - outliner_add_element(space_outliner, &ten->subtree, ob, ten, 0, 0); + outliner_add_element(space_outliner, &ten->subtree, ob, ten, TSE_SOME_ID, 0); } FOREACH_SCENE_OBJECT_END; outliner_make_object_parent_hierarchy(&ten->subtree); @@ -368,14 +368,14 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, &te->subtree, ob->poselib, te, - 0, + TSE_SOME_ID, 0); /* XXX FIXME.. add a special type for this. */ if (ob->proxy && !ID_IS_LINKED(ob)) { outliner_add_element(space_outliner, &te->subtree, ob->proxy, te, TSE_PROXY, 0); } - outliner_add_element(space_outliner, &te->subtree, ob->data, te, 0, 0); + outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0); if (ob->pose) { bArmature *arm = ob->data; @@ -458,7 +458,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } for (int a = 0; a < ob->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, TSE_SOME_ID, a); } if (!BLI_listbase_is_empty(&ob->constraints)) { @@ -624,7 +624,8 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, /* duplicated group */ if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) { - outliner_add_element(space_outliner, &te->subtree, ob->instance_collection, te, 0, 0); + outliner_add_element( + space_outliner, &te->subtree, ob->instance_collection, te, TSE_SOME_ID, 0); } } @@ -686,9 +687,9 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, outliner_add_element(space_outliner, &te->subtree, me, te, TSE_ANIM_DATA, 0); } - outliner_add_element(space_outliner, &te->subtree, me->key, te, 0, 0); + outliner_add_element(space_outliner, &te->subtree, me->key, te, TSE_SOME_ID, 0); for (int a = 0; a < me->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, TSE_SOME_ID, a); } /* could do tfaces with image links, but the images are not grouped nicely. * would require going over all tfaces, sort images in use. etc... */ @@ -702,7 +703,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } for (int a = 0; a < cu->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, TSE_SOME_ID, a); } break; } @@ -714,7 +715,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } for (int a = 0; a < mb->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, TSE_SOME_ID, a); } break; } @@ -730,7 +731,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, if (outliner_animdata_test(tex->adt)) { outliner_add_element(space_outliner, &te->subtree, tex, te, TSE_ANIM_DATA, 0); } - outliner_add_element(space_outliner, &te->subtree, tex->ima, te, 0, 0); + outliner_add_element(space_outliner, &te->subtree, tex->ima, te, TSE_SOME_ID, 0); break; } case ID_CA: { @@ -991,24 +992,23 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, else if (type == TSE_ID_BASE) { /* pass */ } + else if (type == TSE_SOME_ID) { + if (!te->type) { + BLI_assert(!"Expected this ID type to be ported to new Outliner tree-element design"); + } + } else { /* Other cases must be caught above. */ BLI_assert(TSE_IS_REAL_ID(tselem)); - /* do here too, for blend file viewer, own ID_LI then shows file name */ - if (GS(id->name) == ID_LI) { - te->name = ((Library *)id)->filepath; - } - else { - te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */ - } + te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */ te->idcode = GS(id->name); } - if (te->type) { + if (te->type && outliner_tree_element_type_is_expand_valid(te->type)) { outliner_tree_element_type_expand(te->type, space_outliner); } - else if (type == 0) { + else if (type == TSE_SOME_ID) { TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; /* ID data-block. */ @@ -1016,16 +1016,16 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, outliner_add_id_contents(space_outliner, te, tselem, id); } } - else if (ELEM(type, TSE_ANIM_DATA, TSE_DRIVER_BASE, TSE_NLA, TSE_NLA_ACTION, TSE_NLA_TRACK)) { + else if (ELEM(type, + TSE_ANIM_DATA, + TSE_DRIVER_BASE, + TSE_NLA, + TSE_NLA_ACTION, + TSE_NLA_TRACK, + TSE_GP_LAYER)) { /* Should already use new AbstractTreeElement design. */ BLI_assert(0); } - else if (type == TSE_GP_LAYER) { - bGPDlayer *gpl = (bGPDlayer *)idv; - - te->name = gpl->info; - te->directdata = gpl; - } else if (type == TSE_SEQUENCE) { Sequence *seq = (Sequence *)idv; @@ -1229,7 +1229,7 @@ BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *space_outliner, TreeElement *parent) { LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - outliner_add_element(space_outliner, tree, cob->ob, parent, 0, 0); + outliner_add_element(space_outliner, tree, cob->ob, parent, TSE_SOME_ID, 0); } } @@ -1240,7 +1240,8 @@ static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outli outliner_add_collection_init(ten, collection); LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - outliner_add_element(space_outliner, &ten->subtree, &child->collection->id, ten, 0, 0); + outliner_add_element( + space_outliner, &ten->subtree, &child->collection->id, ten, TSE_SOME_ID, 0); } if (space_outliner->outlinevis != SO_SCENES) { @@ -1265,7 +1266,7 @@ void outliner_make_object_parent_hierarchy(ListBase *lb) TreeElement *ten = te->next; TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) { Object *ob = (Object *)tselem->id; if (ob->parent && ob->parent->id.newid) { BLI_remlink(lb, te); @@ -1406,7 +1407,7 @@ static void outliner_sort(ListBase *lb) /* sorting rules; only object lists, ID lists, or deformgroups */ if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || - (tselem->type == 0 && te->idcode == ID_OB)) { + ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) { int totelem = BLI_listbase_count(lb); if (totelem > 1) { @@ -1420,7 +1421,7 @@ static void outliner_sort(ListBase *lb) tp->name = te->name; tp->idcode = te->idcode; - if (tselem->type && tselem->type != TSE_DEFGROUP) { + if ((tselem->type != TSE_SOME_ID) && tselem->type != TSE_DEFGROUP) { tp->idcode = 0; /* Don't sort this. */ } if (tselem->type == TSE_ID_BASE) { @@ -1471,7 +1472,7 @@ static void outliner_collections_children_sort(ListBase *lb) TreeStoreElem *tselem = TREESTORE(te); /* Sorting rules: only object lists. */ - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { int totelem = BLI_listbase_count(lb); if (totelem > 1) { @@ -1546,7 +1547,7 @@ static bool test_collection_callback(TreeElement *te) static bool test_object_callback(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - return ((tselem->type == 0) && (te->idcode == ID_OB)); + return ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)); } /** @@ -1707,7 +1708,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, } TreeStoreElem *tselem = TREESTORE(te); - if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) { return false; } @@ -1790,14 +1791,15 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, return is_visible; } - if ((te->parent != NULL) && (TREESTORE(te->parent)->type == 0) && + if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) && (te->parent->idcode == ID_OB)) { if (exclude_filter & SO_FILTER_NO_CHILDREN) { return false; } } } - else if (te->parent != NULL && TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB) { + else if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) && + (te->parent->idcode == ID_OB)) { if (exclude_filter & SO_FILTER_NO_OB_CONTENT) { return false; } @@ -1821,7 +1823,7 @@ static bool outliner_element_is_collection_or_object(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { return true; } diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index 92178cfdfc9..562457c62e9 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -226,7 +226,7 @@ TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const { LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { if (tselem->id == id) { return te; } @@ -266,7 +266,7 @@ TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone) } TreeStoreElem *tselem = TREESTORE(te); - if (ELEM(tselem->type, 0, TSE_EBONE)) { + if (ELEM(tselem->type, TSE_SOME_ID, TSE_EBONE)) { TreeElement *tes = outliner_find_editbone(&te->subtree, ebone); if (tes) { return tes; @@ -283,7 +283,7 @@ TreeElement *outliner_search_back_te(TreeElement *te, short idcode) while (te) { tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == idcode) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == idcode)) { return te; } te = te->parent; @@ -510,7 +510,7 @@ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2]) te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]); if (te) { TreeStoreElem *tselem = TREESTORE(te); - if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(view_layer, ob); } diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc index cb5f42f08e1..91b690d35fa 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc @@ -111,7 +111,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, { const short filter_id_type = id_filter_get(); - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int tot; if (filter_id_type) { lbarray[0] = which_libbase(&mainvar, space_outliner_.filter_id_type); @@ -144,7 +144,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, if (!tenlib) { /* Create library tree element on demand, depending if there are any data-blocks. */ if (lib) { - tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, 0, 0); + tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, TSE_SOME_ID, 0); } else { tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0); @@ -168,7 +168,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, for (ID *id : List<ID>(lbarray[a])) { if (library_id_filter_poll(lib, id)) { - outliner_add_element(&space_outliner_, &ten->subtree, id, ten, 0, 0); + outliner_add_element(&space_outliner_, &ten->subtree, id, ten, TSE_SOME_ID, 0); } } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc index 0b17ea98831..69ccf014642 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc @@ -42,7 +42,7 @@ TreeDisplayIDOrphans::TreeDisplayIDOrphans(SpaceOutliner &space_outliner) ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) { ListBase tree = {nullptr}; - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; short filter_id_type = (space_outliner_.filter & SO_FILTER_ID_TYPE) ? space_outliner_.filter_id_type : 0; @@ -76,7 +76,8 @@ ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) /* Add the orphaned data-blocks - these will not be added with any subtrees attached. */ for (ID *id : List<ID>(lbarray[a])) { if (ID_REAL_USERS(id) <= 0) { - outliner_add_element(&space_outliner_, (te) ? &te->subtree : &tree, id, te, 0, 0); + outliner_add_element( + &space_outliner_, (te) ? &te->subtree : &tree, id, te, TSE_SOME_ID, 0); } } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc index f377512d81e..390f81cfcd1 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc @@ -46,7 +46,8 @@ ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data) for (ID *id : List<ID>(source_data.bmain->scenes)) { Scene *scene = reinterpret_cast<Scene *>(id); - TreeElement *te = outliner_add_element(&space_outliner_, &tree, scene, nullptr, 0, 0); + TreeElement *te = outliner_add_element( + &space_outliner_, &tree, scene, nullptr, TSE_SOME_ID, 0); TreeStoreElem *tselem = TREESTORE(te); /* New scene elements open by default */ diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index a0ebac5f451..89c9960a24f 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -80,7 +80,7 @@ ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data) /* Show objects in the view layer. */ for (Base *base : List<Base>(view_layer_->object_bases)) { TreeElement *te_object = outliner_add_element( - &space_outliner_, &tree, base->object, nullptr, 0, 0); + &space_outliner_, &tree, base->object, nullptr, TSE_SOME_ID, 0); te_object->directdata = base; } @@ -158,7 +158,7 @@ void TreeDisplayViewLayer::add_layer_collection_objects(ListBase &tree, for (CollectionObject *cob : List<CollectionObject>(lc.collection->gobject)) { Base *base = BKE_view_layer_base_find(view_layer_, cob->ob); TreeElement *te_object = outliner_add_element( - &space_outliner_, &tree, base->object, &ten, 0, 0); + &space_outliner_, &tree, base->object, &ten, TSE_SOME_ID, 0); te_object->directdata = base; } } @@ -203,7 +203,7 @@ void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeEl continue; } - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; /* Lookup children or add new, empty children vector. */ Vector<TreeElement *> &tree_elements = object_tree_elements_map_.lookup_or_add(ob, {}); @@ -261,8 +261,12 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections() if (!found) { /* We add the child in the tree even if it is not in the collection. * We deliberately clear its sub-tree though, to make it less prominent. */ - TreeElement *child_ob_tree_element = outliner_add_element( - &outliner_, &parent_ob_tree_element->subtree, child, parent_ob_tree_element, 0, 0); + TreeElement *child_ob_tree_element = outliner_add_element(&outliner_, + &parent_ob_tree_element->subtree, + child, + parent_ob_tree_element, + TSE_SOME_ID, + 0); outliner_free_tree(&child_ob_tree_element->subtree); child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION; child_ob_tree_elements.append(child_ob_tree_element); diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 27846614994..79c2831475f 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -22,6 +22,8 @@ #include "tree_element_anim_data.hh" #include "tree_element_driver_base.hh" +#include "tree_element_gpencil_layer.hh" +#include "tree_element_id.hh" #include "tree_element_nla.hh" #include "tree_element.h" @@ -36,6 +38,8 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te ID &id = *static_cast<ID *>(idv); switch (type) { + case TSE_SOME_ID: + return TreeElementID::createFromID(legacy_te, id); case TSE_ANIM_DATA: return new TreeElementAnimData(legacy_te, id); case TSE_DRIVER_BASE: @@ -46,6 +50,8 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te return new TreeElementNLATrack(legacy_te, *static_cast<NlaTrack *>(idv)); case TSE_NLA_ACTION: return new TreeElementNLAAction(legacy_te); + case TSE_GP_LAYER: + return new TreeElementGPencilLayer(legacy_te, *static_cast<bGPDlayer *>(idv)); default: break; } @@ -79,6 +85,12 @@ void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *spa outliner::tree_element_expand(reinterpret_cast<outliner::AbstractTreeElement &>(*type), *space_outliner); } +bool outliner_tree_element_type_is_expand_valid(TreeElementType *type) +{ + outliner::AbstractTreeElement &element = reinterpret_cast<outliner::AbstractTreeElement &>( + *type); + return element.isExpandValid(); +} void outliner_tree_element_type_free(TreeElementType **type) { diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h index d88c37180b3..c3dec1bf68a 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.h +++ b/source/blender/editors/space_outliner/tree/tree_element.h @@ -39,6 +39,7 @@ TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy void outliner_tree_element_type_free(TreeElementType **type); void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner); +bool outliner_tree_element_type_is_expand_valid(TreeElementType *type); #ifdef __cplusplus } diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh index 8a1ebb51eae..3e61dd25898 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.hh +++ b/source/blender/editors/space_outliner/tree/tree_element.hh @@ -48,6 +48,15 @@ class AbstractTreeElement { virtual void expand(SpaceOutliner &) const { } + + /** + * Just while transitioning to the new tree-element design: Some types are only partially ported, + * and the expanding isn't done yet. + */ + virtual bool isExpandValid() const + { + return true; + } }; } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc index 13a25800800..5a9568ea906 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc @@ -44,7 +44,8 @@ TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, ID &id) void TreeElementAnimData::expand(SpaceOutliner &space_outliner) const { /* Animation data-block itself. */ - outliner_add_element(&space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, 0, 0); + outliner_add_element( + &space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, TSE_SOME_ID, 0); expand_drivers(space_outliner); expand_NLA_tracks(space_outliner); diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc new file mode 100644 index 00000000000..91e6fdcde4b --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc @@ -0,0 +1,40 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_utildefines.h" + +#include "DNA_gpencil_types.h" + +#include "../outliner_intern.h" + +#include "tree_element_gpencil_layer.hh" + +namespace blender::ed::outliner { + +TreeElementGPencilLayer::TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer) + : AbstractTreeElement(legacy_te) +{ + BLI_assert(legacy_te.store_elem->type == TSE_GP_LAYER); + /* this element's info */ + legacy_te.name = gplayer.info; + legacy_te.directdata = &gplayer; +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh new file mode 100644 index 00000000000..da57ef63f1f --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +struct bGPDlayer; + +namespace blender::ed::outliner { + +class TreeElementGPencilLayer final : public AbstractTreeElement { + public: + TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer); +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc new file mode 100644 index 00000000000..26787475635 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_ID.h" + +#include "BLI_utildefines.h" + +#include "../outliner_intern.h" + +#include "tree_element_id.hh" + +namespace blender::ed::outliner { + +TreeElementID::TreeElementID(TreeElement &legacy_te, const ID &id) : AbstractTreeElement(legacy_te) +{ + BLI_assert(legacy_te_.store_elem->type == TSE_SOME_ID); + BLI_assert(TSE_IS_REAL_ID(legacy_te_.store_elem)); + + /* Default, some specific types override this. */ + legacy_te_.name = id.name + 2; + legacy_te_.idcode = GS(id.name); +} + +TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, const ID &id) +{ + switch (ID_Type type = GS(id.name); type) { + case ID_LI: + return new TreeElementIDLibrary(legacy_te, id); + case ID_SCE: + case ID_OB: + case ID_ME: + case ID_CU: + case ID_MB: + case ID_MA: + case ID_TE: + case ID_LT: + case ID_LA: + case ID_CA: + case ID_KE: + case ID_SCR: + case ID_WO: + case ID_SPK: + case ID_GR: + case ID_NT: + case ID_BR: + case ID_PA: + case ID_MC: + case ID_MSK: + case ID_LS: + case ID_LP: + case ID_GD: + case ID_WS: + case ID_HA: + case ID_PT: + case ID_VO: + case ID_SIM: + case ID_WM: + case ID_IM: + case ID_VF: + case ID_TXT: + case ID_SO: + case ID_AR: + case ID_AC: + case ID_PAL: + case ID_PC: + case ID_CF: + return new TreeElementID(legacy_te, id); + /* Deprecated */ + case ID_IP: + BLI_assert(!"Outliner trying to build tree-element for deprecated ID type"); + return nullptr; + } + + return nullptr; +} + +TreeElementIDLibrary::TreeElementIDLibrary(TreeElement &legacy_te, const ID &id) + : TreeElementID(legacy_te, id) +{ + legacy_te.name = ((Library &)id).filepath; +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh new file mode 100644 index 00000000000..612c1cd4a6f --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh @@ -0,0 +1,48 @@ +/* + * 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. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementID : public AbstractTreeElement { + public: + TreeElementID(TreeElement &legacy_te, const ID &id); + + static TreeElementID *createFromID(TreeElement &legacy_te, const ID &id); + + /** + * Expanding not implemented for all types yet. Once it is, this can be set to true or + * `AbstractTreeElement::expandValid()` can be removed altogether. + */ + bool isExpandValid() const override + { + return false; + } +}; + +class TreeElementIDLibrary final : public TreeElementID { + public: + TreeElementIDLibrary(TreeElement &legacy_te, const ID &id); +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index a9033b98708..844dbe6a0a5 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -36,6 +36,7 @@ #include "DNA_mask_types.h" #include "DNA_scene_types.h" +#include "DNA_sound_types.h" #include "BKE_context.h" #include "BKE_lib_id.h" @@ -44,6 +45,8 @@ #include "BKE_movieclip.h" #include "BKE_report.h" +#include "IMB_imbuf.h" + #include "WM_api.h" #include "WM_types.h" @@ -89,8 +92,6 @@ typedef struct SequencerAddData { #define SEQPROP_NOCHAN (1 << 3) #define SEQPROP_FIT_METHOD (1 << 4) -#define SELECT 1 - static const EnumPropertyItem scale_fit_methods[] = { {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"}, {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image to completely fill the canvas"}, @@ -216,7 +217,7 @@ static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, i } } -static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperator *op) +static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -224,69 +225,56 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato const bool relative = (prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop); int is_file = -1; - memset(seq_load, 0, sizeof(SeqLoadInfo)); + memset(load_data, 0, sizeof(SeqLoadData)); - seq_load->start_frame = RNA_int_get(op->ptr, "frame_start"); - seq_load->end_frame = seq_load->start_frame; - seq_load->channel = RNA_int_get(op->ptr, "channel"); - seq_load->len = 1; - seq_load->fit_method = RNA_enum_get(op->ptr, "fit_method"); - SEQ_tool_settings_fit_method_set(CTX_data_scene(C), seq_load->fit_method); + load_data->start_frame = RNA_int_get(op->ptr, "frame_start"); + load_data->channel = RNA_int_get(op->ptr, "channel"); + load_data->image.end_frame = load_data->start_frame; + load_data->image.len = 1; + load_data->fit_method = RNA_enum_get(op->ptr, "fit_method"); + SEQ_tool_settings_fit_method_set(CTX_data_scene(C), load_data->fit_method); if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { /* Full path, file is set by the caller. */ - RNA_property_string_get(op->ptr, prop, seq_load->path); + RNA_property_string_get(op->ptr, prop, load_data->path); is_file = 1; } else if ((prop = RNA_struct_find_property(op->ptr, "directory"))) { /* Full path, file is set by the caller. */ - RNA_property_string_get(op->ptr, prop, seq_load->path); + RNA_property_string_get(op->ptr, prop, load_data->path); is_file = 0; } if ((is_file != -1) && relative) { - BLI_path_rel(seq_load->path, BKE_main_blendfile_path(bmain)); + BLI_path_rel(load_data->path, BKE_main_blendfile_path(bmain)); } if ((prop = RNA_struct_find_property(op->ptr, "frame_end"))) { - seq_load->end_frame = RNA_property_int_get(op->ptr, prop); - } - - if ((prop = RNA_struct_find_property(op->ptr, "replace_sel")) && - RNA_property_boolean_get(op->ptr, prop)) { - seq_load->flag |= SEQ_LOAD_REPLACE_SEL; + load_data->image.end_frame = RNA_property_int_get(op->ptr, prop); } if ((prop = RNA_struct_find_property(op->ptr, "cache")) && RNA_property_boolean_get(op->ptr, prop)) { - seq_load->flag |= SEQ_LOAD_SOUND_CACHE; + load_data->flags |= SEQ_LOAD_SOUND_CACHE; } if ((prop = RNA_struct_find_property(op->ptr, "mono")) && RNA_property_boolean_get(op->ptr, prop)) { - seq_load->flag |= SEQ_LOAD_SOUND_MONO; - } - - if ((prop = RNA_struct_find_property(op->ptr, "sound")) && - RNA_property_boolean_get(op->ptr, prop)) { - seq_load->flag |= SEQ_LOAD_MOVIE_SOUND; + load_data->flags |= SEQ_LOAD_SOUND_MONO; } if ((prop = RNA_struct_find_property(op->ptr, "use_framerate")) && RNA_property_boolean_get(op->ptr, prop)) { - seq_load->flag |= SEQ_LOAD_SYNC_FPS; + load_data->flags |= SEQ_LOAD_MOVIE_SYNC_FPS; } - /* Create consecutive array of strips. */ - seq_load->flag |= SEQ_LOAD_FRAME_ADVANCE; - if (is_file == 1) { - BLI_strncpy(seq_load->name, BLI_path_basename(seq_load->path), sizeof(seq_load->name)); + BLI_strncpy(load_data->name, BLI_path_basename(load_data->path), sizeof(load_data->name)); } else if ((prop = RNA_struct_find_property(op->ptr, "files"))) { RNA_PROP_BEGIN (op->ptr, itemptr, prop) { char *name = RNA_string_get_alloc(&itemptr, "name", NULL, 0); - BLI_strncpy(seq_load->name, name, sizeof(seq_load->name)); + BLI_strncpy(load_data->name, name, sizeof(load_data->name)); MEM_freeN(name); break; } @@ -299,36 +287,31 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato SequencerAddData *sad = op->customdata; ImageFormatData *imf = &sad->im_format; - seq_load->views_format = imf->views_format; - seq_load->flag |= SEQ_USE_VIEWS; - seq_load->stereo3d_format = &imf->stereo3d_format; + load_data->use_multiview = true; + load_data->views_format = imf->views_format; + load_data->stereo3d_format = &imf->stereo3d_format; } } } -/** - * Apply generic operator options. - */ -static void sequencer_add_apply_overlap(bContext *C, wmOperator *op, Sequence *seq) +static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence *seq) { Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, false); - if (RNA_boolean_get(op->ptr, "overlap") == false) { - if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { - SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); - } + if (seq == NULL) { + return; } -} - -static void sequencer_add_apply_replace_sel(bContext *C, wmOperator *op, Sequence *seq) -{ - Scene *scene = CTX_data_scene(C); if (RNA_boolean_get(op->ptr, "replace_sel")) { - ED_sequencer_deselect_all(scene); - SEQ_select_active_set(scene, seq); seq->flag |= SELECT; + SEQ_select_active_set(scene, seq); + } + + if (RNA_boolean_get(op->ptr, "overlap") == false) { + if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); + } } } @@ -356,34 +339,24 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = SEQ_editing_get(scene, true); - Scene *sce_seq; - Sequence *seq; - - int start_frame, channel; - start_frame = RNA_int_get(op->ptr, "frame_start"); - channel = RNA_int_get(op->ptr, "channel"); - sce_seq = BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene")); + const Editing *ed = SEQ_editing_get(scene, true); + Scene *sce_seq = BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene")); if (sce_seq == NULL) { BKE_report(op->reports, RPT_ERROR, "Scene not found"); return OPERATOR_CANCELLED; } - seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE); - seq->blend_mode = SEQ_TYPE_CROSS; - seq->scene = sce_seq; - seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1; - - BLI_strncpy(seq->name + 2, sce_seq->id.name + 2, sizeof(seq->name) - 2); - SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); + if (RNA_boolean_get(op->ptr, "replace_sel")) { + ED_sequencer_deselect_all(scene); + } - SEQ_time_update_sequence_bounds(scene, seq); - SEQ_sort(scene); + SeqLoadData load_data; + load_data_init_from_operator(&load_data, C, op); + load_data.scene = sce_seq; - sequencer_add_apply_replace_sel(C, op, seq); - sequencer_add_apply_overlap(C, op, seq); - SEQ_relations_invalidate_cache_composite(scene, seq); + Sequence *seq = SEQ_add_scene_strip(scene, ed->seqbasep, &load_data); + seq_load_apply_generic_options(C, op, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); DEG_relations_tag_update(bmain); @@ -430,36 +403,24 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = SEQ_editing_get(scene, true); - MovieClip *clip; - Sequence *seq; - - int start_frame, channel; - start_frame = RNA_int_get(op->ptr, "frame_start"); - channel = RNA_int_get(op->ptr, "channel"); - clip = BLI_findlink(&bmain->movieclips, RNA_enum_get(op->ptr, "clip")); + const Editing *ed = SEQ_editing_get(scene, true); + MovieClip *clip = BLI_findlink(&bmain->movieclips, RNA_enum_get(op->ptr, "clip")); if (clip == NULL) { BKE_report(op->reports, RPT_ERROR, "Movie clip not found"); return OPERATOR_CANCELLED; } - seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP); - seq->blend_mode = SEQ_TYPE_CROSS; - seq->clip = clip; - seq->len = BKE_movieclip_get_duration(clip); - - id_us_ensure_real(&seq->clip->id); - - BLI_strncpy(seq->name + 2, clip->id.name + 2, sizeof(seq->name) - 2); - SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); + if (RNA_boolean_get(op->ptr, "replace_sel")) { + ED_sequencer_deselect_all(scene); + } - SEQ_time_update_sequence_bounds(scene, seq); - SEQ_sort(scene); + SeqLoadData load_data; + load_data_init_from_operator(&load_data, C, op); + load_data.clip = clip; - sequencer_add_apply_replace_sel(C, op, seq); - sequencer_add_apply_overlap(C, op, seq); - SEQ_relations_invalidate_cache_composite(scene, seq); + Sequence *seq = SEQ_add_movieclip_strip(scene, ed->seqbasep, &load_data); + seq_load_apply_generic_options(C, op, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -506,36 +467,24 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Editing *ed = SEQ_editing_get(scene, true); - Mask *mask; - Sequence *seq; - - int start_frame, channel; - start_frame = RNA_int_get(op->ptr, "frame_start"); - channel = RNA_int_get(op->ptr, "channel"); - mask = BLI_findlink(&bmain->masks, RNA_enum_get(op->ptr, "mask")); + const Editing *ed = SEQ_editing_get(scene, true); + Mask *mask = BLI_findlink(&bmain->masks, RNA_enum_get(op->ptr, "mask")); if (mask == NULL) { BKE_report(op->reports, RPT_ERROR, "Mask not found"); return OPERATOR_CANCELLED; } - seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK); - seq->blend_mode = SEQ_TYPE_CROSS; - seq->mask = mask; - seq->len = BKE_mask_get_duration(mask); - - id_us_ensure_real(&seq->mask->id); - - BLI_strncpy(seq->name + 2, mask->id.name + 2, sizeof(seq->name) - 2); - SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); + if (RNA_boolean_get(op->ptr, "replace_sel")) { + ED_sequencer_deselect_all(scene); + } - SEQ_time_update_sequence_bounds(scene, seq); - SEQ_sort(scene); + SeqLoadData load_data; + load_data_init_from_operator(&load_data, C, op); + load_data.mask = mask; - sequencer_add_apply_replace_sel(C, op, seq); - sequencer_add_apply_overlap(C, op, seq); - SEQ_relations_invalidate_cache_composite(scene, seq); + Sequence *seq = SEQ_add_mask_strip(scene, ed->seqbasep, &load_data); + seq_load_apply_generic_options(C, op, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -577,100 +526,120 @@ void SEQUENCER_OT_mask_strip_add(struct wmOperatorType *ot) ot->prop = prop; } -static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoadFn seq_load_fn) +static void sequencer_add_init(bContext *UNUSED(C), wmOperator *op) { - Scene *scene = CTX_data_scene(C); - Editing *ed = SEQ_editing_get(scene, true); - SeqLoadInfo seq_load; - int tot_files; - - seq_load_operator_info(&seq_load, C, op); + op->customdata = MEM_callocN(sizeof(SequencerAddData), __func__); +} - if (seq_load.flag & SEQ_LOAD_REPLACE_SEL) { - ED_sequencer_deselect_all(scene); +static void sequencer_add_cancel(bContext *UNUSED(C), wmOperator *op) +{ + if (op->customdata) { + MEM_freeN(op->customdata); } + op->customdata = NULL; +} - tot_files = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files")); - - if (tot_files > 1) { - char dir_only[FILE_MAX]; - char file_only[FILE_MAX]; - - RNA_BEGIN (op->ptr, itemptr, "files") { - Sequence *seq; +static bool sequencer_add_draw_check_fn(PointerRNA *UNUSED(ptr), + PropertyRNA *prop, + void *UNUSED(user_data)) +{ + const char *prop_id = RNA_property_identifier(prop); - RNA_string_get(op->ptr, "directory", dir_only); - RNA_string_get(&itemptr, "name", file_only); - BLI_join_dirfile(seq_load.path, sizeof(seq_load.path), dir_only, file_only); + return !(STR_ELEM(prop_id, "filepath", "directory", "filename")); +} - /* Set seq_load.name, otherwise all video/audio files get the same name. */ - BLI_strncpy(seq_load.name, file_only, sizeof(seq_load.name)); +static void sequencer_add_movie_multiple_strips(bContext *C, + wmOperator *op, + SeqLoadData *load_data) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + const Editing *ed = SEQ_editing_get(scene, true); - seq = seq_load_fn(C, ed->seqbasep, &seq_load); - if (seq) { - if (seq_load.seq_sound) { - sequencer_add_apply_overlap(C, op, seq_load.seq_sound); - } - sequencer_add_apply_overlap(C, op, seq); - } + RNA_BEGIN (op->ptr, itemptr, "files") { + char dir_only[FILE_MAX]; + char file_only[FILE_MAX]; + RNA_string_get(op->ptr, "directory", dir_only); + RNA_string_get(&itemptr, "name", file_only); + BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only); + BLI_strncpy(load_data->name, file_only, sizeof(load_data->name)); + Sequence *seq_movie = NULL; + Sequence *seq_sound = NULL; + load_data->channel++; + seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data); + load_data->channel--; + if (seq_movie == NULL) { + BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path); } - RNA_END; - } - else { /* Single file./ */ - Sequence *seq; - seq = seq_load_fn(C, ed->seqbasep, &seq_load); - - if (seq) { - if (seq_load.seq_sound) { - sequencer_add_apply_overlap(C, op, seq_load.seq_sound); + else { + if (RNA_boolean_get(op->ptr, "sound")) { + seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); } - sequencer_add_apply_overlap(C, op, seq); + load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp; + seq_load_apply_generic_options(C, op, seq_sound); + seq_load_apply_generic_options(C, op, seq_movie); } } + RNA_END; +} - if (op->customdata) { - MEM_freeN(op->customdata); - } +static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoadData *load_data) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + const Editing *ed = SEQ_editing_get(scene, true); - if (seq_load.tot_success == 0) { - BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", seq_load.path); + Sequence *seq_movie = NULL; + Sequence *seq_sound = NULL; + load_data->channel++; + seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data); + load_data->channel--; - return OPERATOR_CANCELLED; + if (seq_movie == NULL) { + BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path); + return false; } + if (RNA_boolean_get(op->ptr, "sound")) { + seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); + } + seq_load_apply_generic_options(C, op, seq_sound); + seq_load_apply_generic_options(C, op, seq_movie); - SEQ_sort(scene); - - DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); - WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); - - return OPERATOR_FINISHED; + return true; } -static void sequencer_add_init(bContext *UNUSED(C), wmOperator *op) +static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op) { - op->customdata = MEM_callocN(sizeof(SequencerAddData), __func__); -} + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + SeqLoadData load_data; + + load_data_init_from_operator(&load_data, C, op); + + if (RNA_boolean_get(op->ptr, "replace_sel")) { + ED_sequencer_deselect_all(scene); + } + + const int tot_files = RNA_property_collection_length(op->ptr, + RNA_struct_find_property(op->ptr, "files")); + if (tot_files > 1) { + sequencer_add_movie_multiple_strips(C, op, &load_data); + } + else { + if (!sequencer_add_movie_single_strip(C, op, &load_data)) { + return OPERATOR_CANCELLED; + } + } -static void sequencer_add_cancel(bContext *UNUSED(C), wmOperator *op) -{ if (op->customdata) { MEM_freeN(op->customdata); } - op->customdata = NULL; -} - -static bool sequencer_add_draw_check_fn(PointerRNA *UNUSED(ptr), - PropertyRNA *prop, - void *UNUSED(user_data)) -{ - const char *prop_id = RNA_property_identifier(prop); - return !(STR_ELEM(prop_id, "filepath", "directory", "filename")); -} + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); -static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op) -{ - return sequencer_add_generic_strip_exec(C, op, SEQ_add_movie_strip); + return OPERATOR_FINISHED; } static int sequencer_add_movie_strip_invoke(bContext *C, @@ -681,7 +650,8 @@ static int sequencer_add_movie_strip_invoke(bContext *C, Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, false); - /* Only enable "use_framerate" if there aren't any existing strips, unless overridden by user. */ + /* Only enable "use_framerate" if there aren't any existing strips, unless overridden by user. + */ if (ed && ed->seqbasep && ed->seqbasep->first) { RNA_boolean_set(op->ptr, "use_framerate", false); } @@ -761,9 +731,80 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot) "Use framerate from the movie to keep sound and video in sync"); } +static void sequencer_add_sound_multiple_strips(bContext *C, + wmOperator *op, + SeqLoadData *load_data) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Editing *ed = SEQ_editing_get(scene, true); + + RNA_BEGIN (op->ptr, itemptr, "files") { + char dir_only[FILE_MAX]; + char file_only[FILE_MAX]; + RNA_string_get(op->ptr, "directory", dir_only); + RNA_string_get(&itemptr, "name", file_only); + BLI_join_dirfile(load_data->path, sizeof(load_data->path), dir_only, file_only); + BLI_strncpy(load_data->name, file_only, sizeof(load_data->name)); + Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); + if (seq == NULL) { + BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path); + } + else { + seq_load_apply_generic_options(C, op, seq); + load_data->start_frame += seq->enddisp - seq->startdisp; + } + } + RNA_END; +} + +static bool sequencer_add_sound_single_strip(bContext *C, wmOperator *op, SeqLoadData *load_data) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Editing *ed = SEQ_editing_get(scene, true); + + Sequence *seq = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); + if (seq == NULL) { + BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path); + return false; + } + seq_load_apply_generic_options(C, op, seq); + + return true; +} + static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op) { - return sequencer_add_generic_strip_exec(C, op, SEQ_add_sound_strip); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + SeqLoadData load_data; + load_data_init_from_operator(&load_data, C, op); + + if (RNA_boolean_get(op->ptr, "replace_sel")) { + ED_sequencer_deselect_all(scene); + } + + const int tot_files = RNA_property_collection_length(op->ptr, + RNA_struct_find_property(op->ptr, "files")); + if (tot_files > 1) { + sequencer_add_sound_multiple_strips(C, op, &load_data); + } + else { + if (!sequencer_add_sound_single_strip(C, op, &load_data)) { + return OPERATOR_CANCELLED; + } + } + + if (op->customdata) { + MEM_freeN(op->customdata); + } + + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + + return OPERATOR_FINISHED; } static int sequencer_add_sound_strip_invoke(bContext *C, @@ -873,78 +914,80 @@ void sequencer_image_seq_reserve_frames( } } -static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) +static int sequencer_add_image_strip_calculate_length(wmOperator *op, + const int start_frame, + int *minframe, + int *numdigits) { - int minframe, numdigits; - Scene *scene = CTX_data_scene(C); - Editing *ed = SEQ_editing_get(scene, true); - SeqLoadInfo seq_load; - Sequence *seq; - Strip *strip; - StripElem *se; const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders"); - seq_load_operator_info(&seq_load, C, op); - - /* Images are unique in how they handle this - 1 per strip elem. */ if (use_placeholders) { - seq_load.len = sequencer_image_seq_get_minmax_frame( - op, seq_load.start_frame, &minframe, &numdigits); - } - else { - seq_load.len = RNA_property_collection_length(op->ptr, - RNA_struct_find_property(op->ptr, "files")); - } - - if (seq_load.len == 0) { - return OPERATOR_CANCELLED; + return sequencer_image_seq_get_minmax_frame(op, start_frame, minframe, numdigits); } + return RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files")); +} - if (seq_load.flag & SEQ_LOAD_REPLACE_SEL) { - ED_sequencer_deselect_all(scene); - } +static void sequencer_add_image_strip_load_files( + wmOperator *op, Sequence *seq, SeqLoadData *load_data, const int minframe, const int numdigits) +{ + const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders"); - /* Main adding function. */ - seq = SEQ_add_image_strip(C, ed->seqbasep, &seq_load); - strip = seq->strip; - se = strip->stripdata; - seq->blend_mode = SEQ_TYPE_ALPHAOVER; + SEQ_add_image_set_directory(seq, load_data->path); if (use_placeholders) { - sequencer_image_seq_reserve_frames(op, se, seq_load.len, minframe, numdigits); + sequencer_image_seq_reserve_frames( + op, seq->strip->stripdata, load_data->image.len, minframe, numdigits); } else { + size_t strip_frame = 0; RNA_BEGIN (op->ptr, itemptr, "files") { char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0); - BLI_strncpy(se->name, filename, sizeof(se->name)); + SEQ_add_image_load_file(seq, strip_frame, filename); MEM_freeN(filename); - se++; + strip_frame++; } RNA_END; } +} - if (seq_load.len == 1) { - if (seq_load.start_frame < seq_load.end_frame) { - seq->endstill = seq_load.end_frame - seq_load.start_frame; - } +static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Editing *ed = SEQ_editing_get(scene, true); + + SeqLoadData load_data; + load_data_init_from_operator(&load_data, C, op); + + int minframe, numdigits; + load_data.image.len = sequencer_add_image_strip_calculate_length( + op, load_data.start_frame, &minframe, &numdigits); + if (load_data.image.len == 0) { + return OPERATOR_CANCELLED; } - SEQ_render_init_colorspace(seq); - SEQ_time_update_sequence_bounds(scene, seq); - SEQ_sort(scene); + if (RNA_boolean_get(op->ptr, "replace_sel")) { + ED_sequencer_deselect_all(scene); + } - /* Last active name. */ - BLI_strncpy(ed->act_imagedir, strip->dir, sizeof(ed->act_imagedir)); - sequencer_add_apply_overlap(C, op, seq); + Sequence *seq = SEQ_add_image_strip(CTX_data_main(C), scene, ed->seqbasep, &load_data); + sequencer_add_image_strip_load_files(op, seq, &load_data, minframe, numdigits); + SEQ_add_image_init_alpha_mode(seq); - if (op->customdata) { - MEM_freeN(op->customdata); + /* Adjust length. */ + if (load_data.image.len == 1) { + SEQ_transform_set_right_handle_frame(seq, load_data.image.end_frame); + SEQ_time_update_sequence(scene, seq); } - SEQ_relations_invalidate_cache_composite(scene, seq); + seq_load_apply_generic_options(C, op, seq); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + if (op->customdata) { + MEM_freeN(op->customdata); + } + return OPERATOR_FINISHED; } @@ -1016,80 +1059,46 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, true); - Sequence *seq; - struct SeqEffectHandle sh; - Sequence *seq1, *seq2, *seq3; const char *error_msg; - int start_frame, end_frame, channel, type; - start_frame = RNA_int_get(op->ptr, "frame_start"); - end_frame = RNA_int_get(op->ptr, "frame_end"); - channel = RNA_int_get(op->ptr, "channel"); - type = RNA_enum_get(op->ptr, "type"); + SeqLoadData load_data; + load_data_init_from_operator(&load_data, C, op); + load_data.effect.type = RNA_enum_get(op->ptr, "type"); - if (!seq_effect_find_selected(scene, NULL, type, &seq1, &seq2, &seq3, &error_msg)) { + Sequence *seq1, *seq2, *seq3; + if (!seq_effect_find_selected( + scene, NULL, load_data.effect.type, &seq1, &seq2, &seq3, &error_msg)) { BKE_report(op->reports, RPT_ERROR, error_msg); return OPERATOR_CANCELLED; } - /* Check its start and end frames are valid. */ - if (seq1 == NULL && end_frame <= start_frame) { - end_frame = start_frame + 1; - RNA_int_set(op->ptr, "frame_end", end_frame); - } - - seq = SEQ_sequence_alloc(ed->seqbasep, start_frame, channel, type); - BLI_strncpy(seq->name + 2, SEQ_sequence_give_name(seq), sizeof(seq->name) - 2); - SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seq); - - sh = SEQ_effect_handle_get(seq); - sh.init(seq); - seq->seq1 = seq1; - seq->seq2 = seq2; - seq->seq3 = seq3; - - if (!seq1) { - seq->len = 1; /* Effect is generator, set non zero length. */ - SEQ_transform_set_right_handle_frame(seq, end_frame); + if (RNA_boolean_get(op->ptr, "replace_sel")) { + ED_sequencer_deselect_all(scene); } - seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE; - SEQ_time_update_sequence(scene, seq); - - if (seq->type == SEQ_TYPE_COLOR) { - SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; - RNA_float_get_array(op->ptr, "color", colvars->col); - seq->blend_mode = SEQ_TYPE_CROSS; - } - else if (seq->type == SEQ_TYPE_ADJUSTMENT) { - seq->blend_mode = SEQ_TYPE_CROSS; - } - else if (seq->type == SEQ_TYPE_TEXT) { - seq->blend_mode = SEQ_TYPE_ALPHAOVER; - } - else if (SEQ_effect_get_num_inputs(seq->type) == 1) { - seq->blend_mode = seq1->blend_mode; - } + load_data.effect.seq1 = seq1; + load_data.effect.seq2 = seq2; + load_data.effect.seq3 = seq3; /* Set channel. If unset, use lowest free one above strips. */ if (!RNA_struct_property_is_set(op->ptr, "channel")) { - if (seq->seq1) { - int chan = max_iii(seq->seq1 ? seq->seq1->machine : 0, - seq->seq2 ? seq->seq2->machine : 0, - seq->seq3 ? seq->seq3->machine : 0); + if (seq1 != NULL) { + int chan = max_iii( + seq1 ? seq1->machine : 0, seq2 ? seq2->machine : 0, seq3 ? seq3->machine : 0); if (chan < MAXSEQ) { - seq->machine = chan; + load_data.channel = chan; } } } - sequencer_add_apply_replace_sel(C, op, seq); - sequencer_add_apply_overlap(C, op, seq); + Sequence *seq = SEQ_add_effect_strip(scene, ed->seqbasep, &load_data); + seq_load_apply_generic_options(C, op, seq); - SEQ_relations_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs SEQ_time_update_sequence. */ - SEQ_sort(scene); + if (seq->type == SEQ_TYPE_COLOR) { + SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; + RNA_float_get_array(op->ptr, "color", colvars->col); + } - SEQ_relations_invalidate_cache_composite(scene, seq); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index b9fb577eb43..9828368ccf7 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -66,6 +66,7 @@ #include "ED_sequencer.h" #include "ED_space_api.h" #include "ED_time_scrub_ui.h" +#include "ED_util.h" #include "BIF_glutil.h" diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 608e220c582..78d263dffad 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1870,93 +1870,28 @@ void SEQUENCER_OT_images_separate(wmOperatorType *ot) /** \name Toggle Meta Strip Operator * \{ */ -void recurs_sel_seq(Sequence *seqm) -{ - Sequence *seq; - - seq = seqm->seqbase.first; - while (seq) { - - if (seqm->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) { - seq->flag &= ~SEQ_ALLSEL; - } - else if (seqm->flag & SELECT) { - seq->flag |= SELECT; - } - else { - seq->flag &= ~SEQ_ALLSEL; - } - - if (seq->seqbase.first) { - recurs_sel_seq(seq); - } - - seq = seq->next; - } -} - static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, false); - Sequence *last_seq = SEQ_select_active_get(scene); - MetaStack *ms; + Sequence *active_seq = SEQ_select_active_get(scene); - if (last_seq && last_seq->type == SEQ_TYPE_META && last_seq->flag & SELECT) { + if (active_seq && active_seq->type == SEQ_TYPE_META && active_seq->flag & SELECT) { /* Enter metastrip. */ - ms = MEM_mallocN(sizeof(MetaStack), "metastack"); - BLI_addtail(&ed->metastack, ms); - ms->parseq = last_seq; - ms->oldbasep = ed->seqbasep; - copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp); - - ed->seqbasep = &last_seq->seqbase; - + SEQ_meta_stack_alloc(ed, active_seq); + SEQ_seqbase_active_set(ed, &active_seq->seqbase); SEQ_select_active_set(scene, NULL); } else { /* Exit metastrip if possible. */ - - Sequence *seq; - if (BLI_listbase_is_empty(&ed->metastack)) { return OPERATOR_CANCELLED; } - ms = ed->metastack.last; - BLI_remlink(&ed->metastack, ms); - - ed->seqbasep = ms->oldbasep; - - /* For old files, update from meta. */ - if (ms->disp_range[0] == ms->disp_range[1]) { - copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp); - } - - /* Recalc all: the meta can have effects connected to it. */ - for (seq = ed->seqbasep->first; seq; seq = seq->next) { - SEQ_time_update_sequence(scene, seq); - } - - /* 2.73+, keeping endpoints is important! - * Moving them around means you can't usefully use metas in a complex edit. */ -#if 1 - SEQ_transform_set_left_handle_frame(ms->parseq, ms->disp_range[0]); - SEQ_transform_set_right_handle_frame(ms->parseq, ms->disp_range[1]); - SEQ_transform_fix_single_image_seq_offsets(ms->parseq); - SEQ_time_update_sequence(scene, ms->parseq); -#else - if (SEQ_transform_test_overlap(ed->seqbasep, ms->parseq)) { - SEQ_transform_seqbase_shuffle(ed->seqbasep, ms->parseq, scene); - } -#endif - + MetaStack *ms = SEQ_meta_stack_active_get(ed); + SEQ_seqbase_active_set(ed, ms->oldbasep); SEQ_select_active_set(scene, ms->parseq); - - ms->parseq->flag |= SELECT; - recurs_sel_seq(ms->parseq); - - MEM_freeN(ms); + SEQ_meta_stack_free(ed, ms); } DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -1990,48 +1925,44 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, false); + Sequence *active_seq = SEQ_select_active_get(scene); + ListBase *active_seqbase = SEQ_active_seqbase_get(ed); - Sequence *seq, *seqm, *next, *last_seq = SEQ_select_active_get(scene); - int channel_max = 1; - - if (SEQ_transform_seqbase_isolated_sel_check(ed->seqbasep) == false) { + if (SEQ_transform_seqbase_isolated_sel_check(active_seqbase) == false) { BKE_report(op->reports, RPT_ERROR, "Please select all related strips"); return OPERATOR_CANCELLED; } SEQ_prefetch_stop(scene); - /* Remove all selected from main list, and put in meta. */ - - seqm = SEQ_sequence_alloc(ed->seqbasep, 1, 1, SEQ_TYPE_META); /* Channel number set later. */ - strcpy(seqm->name + 2, "MetaStrip"); - seqm->flag = SELECT; + int channel_max = 1, meta_start_frame = MAXFRAME, meta_end_frame = MINFRAME; + Sequence *seqm = SEQ_sequence_alloc(active_seqbase, 1, 1, SEQ_TYPE_META); - seq = ed->seqbasep->first; - while (seq) { - next = seq->next; - if (seq != seqm && (seq->flag & SELECT)) { - SEQ_relations_invalidate_cache_composite(scene, seq); - channel_max = max_ii(seq->machine, channel_max); - /* Sequence is moved within the same edit, no need to re-generate the UUID. */ - BLI_remlink(ed->seqbasep, seq); + /* Remove all selected from main list, and put in meta. + * Sequence is moved within the same edit, no need to re-generate the UUID. */ + LISTBASE_FOREACH_MUTABLE (Sequence *, seq, active_seqbase) { + if (seq != seqm && seq->flag & SELECT) { + BLI_remlink(active_seqbase, seq); BLI_addtail(&seqm->seqbase, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + channel_max = max_ii(seq->machine, channel_max); + meta_start_frame = min_ii(seq->startdisp, meta_start_frame); + meta_end_frame = max_ii(seq->enddisp, meta_end_frame); } - seq = next; } - seqm->machine = last_seq ? last_seq->machine : channel_max; - SEQ_time_update_sequence(scene, seqm); + seqm->machine = active_seq ? active_seq->machine : channel_max; + strcpy(seqm->name + 2, "MetaStrip"); + SEQ_sequence_base_unique_name_recursive(&ed->seqbase, seqm); + seqm->start = meta_start_frame; + seqm->len = meta_end_frame - meta_start_frame; + SEQ_time_update_sequence(scene, seqm); SEQ_select_active_set(scene, seqm); - - if (SEQ_transform_test_overlap(ed->seqbasep, seqm)) { - SEQ_transform_seqbase_shuffle(ed->seqbasep, seqm, scene); + if (SEQ_transform_test_overlap(active_seqbase, seqm)) { + SEQ_transform_seqbase_shuffle(active_seqbase, seqm, scene); } DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); - - SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqm); - SEQ_relations_invalidate_cache_composite(scene, seqm); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -2058,95 +1989,43 @@ void SEQUENCER_OT_meta_make(wmOperatorType *ot) /** \name UnMeta Strip Operator * \{ */ -static int seq_depends_on_meta(Sequence *seq, Sequence *seqm) -{ - if (seq == seqm) { - return 1; - } - if (seq->seq1 && seq_depends_on_meta(seq->seq1, seqm)) { - return 1; - } - if (seq->seq2 && seq_depends_on_meta(seq->seq2, seqm)) { - return 1; - } - if (seq->seq3 && seq_depends_on_meta(seq->seq3, seqm)) { - return 1; - } - return 0; -} - -static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall) -{ - Sequence *seq, *seqn; - Sequence *last_seq = SEQ_select_active_get(scene); - - seq = lb->first; - while (seq) { - seqn = seq->next; - if ((seq->flag & flag) || deleteall) { - BLI_remlink(lb, seq); - if (seq == last_seq) { - SEQ_select_active_set(scene, NULL); - } - if (seq->type == SEQ_TYPE_META) { - recurs_del_seq_flag(scene, &seq->seqbase, flag, 1); - } - SEQ_sequence_free(scene, seq, true); - } - seq = seqn; - } -} - static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); Editing *ed = SEQ_editing_get(scene, false); + Sequence *active_seq = SEQ_select_active_get(scene); - Sequence *seq, *last_seq = SEQ_select_active_get(scene); /* last_seq checks (ed == NULL) */ - - if (last_seq == NULL || last_seq->type != SEQ_TYPE_META) { + if (active_seq == NULL || active_seq->type != SEQ_TYPE_META) { return OPERATOR_CANCELLED; } SEQ_prefetch_stop(scene); - for (seq = last_seq->seqbase.first; seq != NULL; seq = seq->next) { - SEQ_relations_invalidate_cache_composite(scene, seq); + LISTBASE_FOREACH (Sequence *, seq, &active_seq->seqbase) { + SEQ_relations_invalidate_cache_preprocessed(scene, seq); } - /* This moves strips from meta to parent, sating within same edit and no new strips are - * allocated. If the UUID was unique already (as it should) it will stay unique. - * No need to re-generate the UUIDs. */ - BLI_movelisttolist(ed->seqbasep, &last_seq->seqbase); + /* Remove all selected from meta, and put in main list. + * Sequence is moved within the same edit, no need to re-generate the UUID. */ + BLI_movelisttolist(ed->seqbasep, &active_seq->seqbase); + BLI_listbase_clear(&active_seq->seqbase); - BLI_listbase_clear(&last_seq->seqbase); + ListBase *active_seqbase = SEQ_active_seqbase_get(ed); + SEQ_edit_flag_for_removal(scene, active_seqbase, active_seq); + SEQ_edit_remove_flagged_sequences(scene, active_seqbase); - BLI_remlink(ed->seqbasep, last_seq); - SEQ_sequence_free(scene, last_seq, true); - - /* Empty meta strip, delete all effects depending on it. */ - for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if ((seq->type & SEQ_TYPE_EFFECT) && seq_depends_on_meta(seq, last_seq)) { - seq->flag |= SEQ_FLAG_DELETE; - } - } - - recurs_del_seq_flag(scene, ed->seqbasep, SEQ_FLAG_DELETE, 0); - - /* Test for effects and overlap - * don't use SEQ_CURRENT_BEGIN since that would be recursive. */ - for (seq = ed->seqbasep->first; seq; seq = seq->next) { + /* Test for effects and overlap. */ + LISTBASE_FOREACH (Sequence *, seq, active_seqbase) { if (seq->flag & SELECT) { seq->flag &= ~SEQ_OVERLAP; - if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { - SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); + if (SEQ_transform_test_overlap(active_seqbase, seq)) { + SEQ_transform_seqbase_shuffle(active_seqbase, seq, scene); } } } SEQ_sort(scene); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); - WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 4c942a83f2b..767ac76efe6 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -79,7 +79,7 @@ struct Sequence *find_neighboring_sequence(struct Scene *scene, struct Sequence *test, int lr, int sel); -void recurs_sel_seq(struct Sequence *seqm); +void recurs_sel_seq(struct Sequence *seq_meta); int seq_effect_find_selected(struct Scene *scene, struct Sequence *activeseq, int type, diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index ffcb3d35d5a..5f0a18fbd0b 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -360,6 +360,31 @@ static void select_neighbor_from_last(Scene *scene, int lr) } #endif +void recurs_sel_seq(Sequence *seq_meta) +{ + Sequence *seq; + + seq = seq_meta->seqbase.first; + while (seq) { + + if (seq_meta->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) { + seq->flag &= ~SEQ_ALLSEL; + } + else if (seq_meta->flag & SELECT) { + seq->flag |= SELECT; + } + else { + seq->flag &= ~SEQ_ALLSEL; + } + + if (seq->seqbase.first) { + recurs_sel_seq(seq); + } + + seq = seq->next; + } +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 93d5d41e121..2037981e655 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -550,7 +550,7 @@ static void applyObjectConstraintSize(TransInfo *t, } static void constraints_rotation_impl(TransInfo *t, - float axismtx[3][3], + const float axismtx[3][3], float r_vec[3], float *r_angle) { @@ -572,7 +572,8 @@ static void constraints_rotation_impl(TransInfo *t, break; } /* don't flip axis if asked to or if num input */ - if (r_angle && !((mode & CON_NOFLIP) || hasNumInput(&t->num) || (t->flag & T_INPUT_IS_VALUES_FINAL))) { + if (r_angle && + !((mode & CON_NOFLIP) || hasNumInput(&t->num) || (t->flag & T_INPUT_IS_VALUES_FINAL))) { float view_vector[3]; view_vector_calc(t, t->center_global, view_vector); if (dot_v3v3(r_vec, view_vector) > 0.0f) { @@ -620,7 +621,7 @@ static void applyObjectConstraintRot( { if (t->con.mode & CON_APPLY) { float tmp_axismtx[3][3]; - float(*axismtx)[3]; + const float(*axismtx)[3]; /* on setup call, use first object */ if (td == NULL) { diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c index 244cd552495..45df0e66691 100644 --- a/source/blender/editors/transform/transform_convert_gpencil.c +++ b/source/blender/editors/transform/transform_convert_gpencil.c @@ -37,6 +37,7 @@ #include "BKE_gpencil_geom.h" #include "ED_gpencil.h" +#include "ED_keyframing.h" #include "transform.h" #include "transform_convert.h" @@ -114,6 +115,7 @@ static void createTransGPencil_curves(bContext *C, #define SEL_F3 (1 << 2) View3D *v3d = t->view; + Scene *scene = CTX_data_scene(C); const bool handle_only_selected_visible = (v3d->overlay.handle_display == CURVE_HANDLE_SELECTED); const bool handle_all_visible = (v3d->overlay.handle_display == CURVE_HANDLE_ALL); @@ -230,7 +232,9 @@ static void createTransGPencil_curves(bContext *C, } if ((gpf->framenum != cfra) && (!is_multiedit)) { - gpf = BKE_gpencil_frame_addcopy(gpl, cfra); + if (IS_AUTOKEY_ON(scene)) { + gpf = BKE_gpencil_frame_addcopy(gpl, cfra); + } /* in some weird situations (framelock enabled) return NULL */ if (gpf == NULL) { continue; @@ -405,6 +409,7 @@ static void createTransGPencil_strokes(bContext *C, const bool is_prop_edit_connected, const bool is_scale_thickness) { + Scene *scene = CTX_data_scene(C); TransData *td = NULL; float mtx[3][3], smtx[3][3]; @@ -517,7 +522,9 @@ static void createTransGPencil_strokes(bContext *C, * spent too much time editing the wrong frame... */ if ((gpf->framenum != cfra) && (!is_multiedit)) { - gpf = BKE_gpencil_frame_addcopy(gpl, cfra); + if (IS_AUTOKEY_ON(scene)) { + gpf = BKE_gpencil_frame_addcopy(gpl, cfra); + } /* in some weird situations (framelock enabled) return NULL */ if (gpf == NULL) { continue; diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 4ab52b78002..30418471d6d 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -90,35 +90,17 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c Scene *scene = t->scene; int cfra = CFRA; - int left = SEQ_transform_get_left_handle_frame(seq, true); - int right = SEQ_transform_get_right_handle_frame(seq, true); + int left = SEQ_transform_get_left_handle_frame(seq, false); + int right = SEQ_transform_get_right_handle_frame(seq, false); if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) { *r_recursive = false; *r_count = 0; *r_flag = 0; } - else if (seq->type == SEQ_TYPE_META) { - - /* for meta's we only ever need to extend their children, no matter what depth - * just check the meta's are in the bounds */ - if (t->frame_side == 'R' && right <= cfra) { - *r_recursive = false; - } - else if (t->frame_side == 'L' && left >= cfra) { - *r_recursive = false; - } - else { - *r_recursive = true; - } - - *r_count = 1; - *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); - } else { - - *r_recursive = false; /* not a meta, so no thinking here */ - *r_count = 1; /* unless its set to 0, extend will never set 2 handles at once */ + *r_recursive = false; + *r_count = 1; /* unless its set to 0, extend will never set 2 handles at once */ *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); if (t->frame_side == 'R') { @@ -183,26 +165,9 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_c else { /* Nested, different rules apply */ -#ifdef SEQ_TX_NESTED_METAS *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); *r_count = 1; /* ignore the selection for nested */ *r_recursive = (seq->type == SEQ_TYPE_META); -#else - if (seq->type == SEQ_TYPE_META) { - /* Meta's can only directly be moved between channels since they - * don't have their start and length set directly (children affect that) - * since this Meta is nested we don't need any of its data in fact. - * SEQ_time_update_sequence() will update its settings when run on the top-level meta. */ - *r_flag = 0; - *r_count = 0; - *r_recursive = true; - } - else { - *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL); - *r_count = 1; /* ignore the selection for nested */ - *r_recursive = false; - } -#endif } } } @@ -645,8 +610,6 @@ void createTransSeqData(TransInfo *t) /* commented _only_ because the meta may have animation data which * needs moving too T28158. */ -#define SEQ_TX_NESTED_METAS - BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag) { if (seq->depth == 0) { @@ -693,17 +656,10 @@ static void flushTransSeq(TransInfo *t) switch (tdsq->sel_flag) { case SELECT: -#ifdef SEQ_TX_NESTED_METAS if ((seq->depth != 0 || SEQ_transform_sequence_can_be_translated(seq))) { /* for meta's, their children move */ seq->start = new_frame - tdsq->start_offset; } -#else - if (seq->type != SEQ_TYPE_META && (seq->depth != 0 || seq_tx_test(seq))) { - /* for meta's, their children move */ - seq->start = new_frame - tdsq->start_offset; - } -#endif if (seq->depth == 0) { seq->machine = round_fl_to_int(td2d->loc[1]); CLAMP(seq->machine, 1, MAXSEQ); diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index 4fd8c180a4b..9189adaf4d1 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -152,7 +152,7 @@ static void memfile_undosys_step_decode(struct bContext *C, bool use_old_bmain_data = true; - if (USER_EXPERIMENTAL_TEST(&U, use_undo_legacy)) { + if (USER_EXPERIMENTAL_TEST(&U, use_undo_legacy) || !(U.uiflag & USER_GLOBALUNDO)) { use_old_bmain_data = false; } else if (undo_direction == STEP_REDO) { diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 38655b8490e..7d7d10004a3 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -21,6 +21,7 @@ set(INC ../../blenkernel ../../blenlib ../../blentranslation + ../../blenfont ../../bmesh ../../depsgraph ../../gpu @@ -36,6 +37,7 @@ set(INC set(SRC + ed_draw.c ed_transverts.c ed_util.c ed_util_imbuf.c diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c new file mode 100644 index 00000000000..d7b22b4f601 --- /dev/null +++ b/source/blender/editors/util/ed_draw.c @@ -0,0 +1,385 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edutil + */ + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_rect.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_image.h" + +#include "BLF_api.h" + +#include "IMB_imbuf_types.h" +#include "IMB_metadata.h" + +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_util.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "RNA_access.h" +#include "WM_api.h" +#include "WM_types.h" + +/** + * Callback that draws a line between the mouse and a position given as the initial argument. + */ +void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *region, void *arg_info) +{ + wmWindow *win = CTX_wm_window(C); + const float *mval_src = (float *)arg_info; + const float mval_dst[2] = { + win->eventstate->x - region->winrct.xmin, + win->eventstate->y - region->winrct.ymin, + }; + + const uint shdr_pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + GPU_line_width(1.0f); + + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + + immUniform1i("colors_len", 0); /* "simple" mode */ + immUniformThemeColor3(TH_VIEW_OVERLAY); + immUniform1f("dash_width", 6.0f); + immUniform1f("dash_factor", 0.5f); + + immBegin(GPU_PRIM_LINES, 2); + immVertex2fv(shdr_pos, mval_src); + immVertex2fv(shdr_pos, mval_dst); + immEnd(); + + immUnbindProgram(); +} + +#define MAX_METADATA_STR 1024 + +static const char *meta_data_list[] = { + "File", + "Strip", + "Date", + "RenderTime", + "Note", + "Marker", + "Time", + "Frame", + "Camera", + "Scene", +}; + +BLI_INLINE bool metadata_is_valid(ImBuf *ibuf, char *r_str, short index, int offset) +{ + return (IMB_metadata_get_field( + ibuf->metadata, meta_data_list[index], r_str + offset, MAX_METADATA_STR - offset) && + r_str[0]); +} + +BLI_INLINE bool metadata_is_custom_drawable(const char *field) +{ + /* Metadata field stored by Blender for multi-layer EXR images. Is rather + * useless to be viewed all the time. Can still be seen in the Metadata + * panel. */ + if (STREQ(field, "BlenderMultiChannel")) { + return false; + } + /* Is almost always has value "scanlineimage", also useless to be seen + * all the time. */ + if (STREQ(field, "type")) { + return false; + } + return !BKE_stamp_is_known_field(field); +} + +typedef struct MetadataCustomDrawContext { + int fontid; + int xmin, ymin; + int vertical_offset; + int current_y; +} MetadataCustomDrawContext; + +static void metadata_custom_draw_fields(const char *field, const char *value, void *ctx_v) +{ + if (!metadata_is_custom_drawable(field)) { + return; + } + MetadataCustomDrawContext *ctx = (MetadataCustomDrawContext *)ctx_v; + char temp_str[MAX_METADATA_STR]; + BLI_snprintf(temp_str, MAX_METADATA_STR, "%s: %s", field, value); + BLF_position(ctx->fontid, ctx->xmin, ctx->ymin + ctx->current_y, 0.0f); + BLF_draw(ctx->fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + ctx->current_y += ctx->vertical_offset; +} + +static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const bool is_top) +{ + char temp_str[MAX_METADATA_STR]; + int ofs_y = 0; + const float height = BLF_height_max(fontid); + const float margin = height / 8; + const float vertical_offset = (height + margin); + + /* values taking margins into account */ + const float descender = BLF_descender(fontid); + const float xmin = (rect->xmin + margin); + const float xmax = (rect->xmax - margin); + const float ymin = (rect->ymin + margin) - descender; + const float ymax = (rect->ymax - margin) - descender; + + if (is_top) { + for (int i = 0; i < 4; i++) { + /* first line */ + if (i == 0) { + bool do_newline = false; + int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]); + if (metadata_is_valid(ibuf, temp_str, 0, len)) { + BLF_position(fontid, xmin, ymax - vertical_offset, 0.0f); + BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + do_newline = true; + } + + len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]); + if (metadata_is_valid(ibuf, temp_str, 1, len)) { + int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + BLF_position(fontid, xmax - line_width, ymax - vertical_offset, 0.0f); + BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + do_newline = true; + } + + if (do_newline) { + ofs_y += vertical_offset; + } + } /* Strip */ + else if (i == 1 || i == 2) { + int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); + if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { + BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f); + BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + ofs_y += vertical_offset; + } + } /* Note (wrapped) */ + else if (i == 3) { + int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); + if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { + struct ResultBLF info; + BLF_enable(fontid, BLF_WORD_WRAP); + BLF_wordwrap(fontid, ibuf->x - (margin * 2)); + BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f); + BLF_draw_ex(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX, &info); + BLF_wordwrap(fontid, 0); + BLF_disable(fontid, BLF_WORD_WRAP); + ofs_y += vertical_offset * info.lines; + } + } + else { + int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); + if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { + int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + BLF_position(fontid, xmax - line_width, ymax - vertical_offset - ofs_y, 0.0f); + BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + ofs_y += vertical_offset; + } + } + } + } + else { + MetadataCustomDrawContext ctx; + ctx.fontid = fontid; + ctx.xmin = xmin; + ctx.ymin = ymin; + ctx.current_y = ofs_y; + ctx.vertical_offset = vertical_offset; + IMB_metadata_foreach(ibuf, metadata_custom_draw_fields, &ctx); + int ofs_x = 0; + ofs_y = ctx.current_y; + for (int i = 5; i < 10; i++) { + int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]); + if (metadata_is_valid(ibuf, temp_str, i, len)) { + BLF_position(fontid, xmin + ofs_x, ymin + ofs_y, 0.0f); + BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + + ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X; + } + } + } +} + +typedef struct MetadataCustomCountContext { + int count; +} MetadataCustomCountContext; + +static void metadata_custom_count_fields(const char *field, const char *UNUSED(value), void *ctx_v) +{ + if (!metadata_is_custom_drawable(field)) { + return; + } + MetadataCustomCountContext *ctx = (MetadataCustomCountContext *)ctx_v; + ctx->count++; +} + +static float metadata_box_height_get(ImBuf *ibuf, int fontid, const bool is_top) +{ + const float height = BLF_height_max(fontid); + const float margin = (height / 8); + char str[MAX_METADATA_STR] = ""; + short count = 0; + + if (is_top) { + if (metadata_is_valid(ibuf, str, 0, 0) || metadata_is_valid(ibuf, str, 1, 0)) { + count++; + } + for (int i = 2; i < 5; i++) { + if (metadata_is_valid(ibuf, str, i, 0)) { + if (i == 4) { + struct { + struct ResultBLF info; + rctf rect; + } wrap; + + BLF_enable(fontid, BLF_WORD_WRAP); + BLF_wordwrap(fontid, ibuf->x - (margin * 2)); + BLF_boundbox_ex(fontid, str, sizeof(str), &wrap.rect, &wrap.info); + BLF_wordwrap(fontid, 0); + BLF_disable(fontid, BLF_WORD_WRAP); + + count += wrap.info.lines; + } + else { + count++; + } + } + } + } + else { + for (int i = 5; i < 10; i++) { + if (metadata_is_valid(ibuf, str, i, 0)) { + count = 1; + break; + } + } + MetadataCustomCountContext ctx; + ctx.count = 0; + IMB_metadata_foreach(ibuf, metadata_custom_count_fields, &ctx); + count += ctx.count; + } + + if (count) { + return (height + margin) * count; + } + + return 0; +} + +/* Should be kept in sync with BKE_image_stamp_buf */ +void ED_region_image_metadata_draw( + int x, int y, ImBuf *ibuf, const rctf *frame, float zoomx, float zoomy) +{ + const uiStyle *style = UI_style_get_dpi(); + + if (!ibuf->metadata) { + return; + } + + /* find window pixel coordinates of origin */ + GPU_matrix_push(); + + /* offset and zoom using ogl */ + GPU_matrix_translate_2f(x, y); + GPU_matrix_scale_2f(zoomx, zoomy); + + BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f * U.pixelsize, U.dpi); + + /* *** upper box*** */ + + /* get needed box height */ + float box_y = metadata_box_height_get(ibuf, blf_mono_font, true); + + if (box_y) { + /* set up rect */ + rctf rect; + BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymax, frame->ymax + box_y); + /* draw top box */ + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_METADATA_BG); + immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + immUnbindProgram(); + + BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + BLF_enable(blf_mono_font, BLF_CLIPPING); + + UI_FontThemeColor(blf_mono_font, TH_METADATA_TEXT); + metadata_draw_imbuf(ibuf, &rect, blf_mono_font, true); + + BLF_disable(blf_mono_font, BLF_CLIPPING); + } + + /* *** lower box*** */ + + box_y = metadata_box_height_get(ibuf, blf_mono_font, false); + + if (box_y) { + /* set up box rect */ + rctf rect; + BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymin - box_y, frame->ymin); + /* draw top box */ + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_METADATA_BG); + immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + immUnbindProgram(); + + BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + BLF_enable(blf_mono_font, BLF_CLIPPING); + + UI_FontThemeColor(blf_mono_font, TH_METADATA_TEXT); + metadata_draw_imbuf(ibuf, &rect, blf_mono_font, false); + + BLF_disable(blf_mono_font, BLF_CLIPPING); + } + + GPU_matrix_pop(); +} + +#undef MAX_METADATA_STR diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 695db9ba246..9903711834a 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -434,44 +434,6 @@ void unpack_menu(bContext *C, UI_popup_menu_end(C, pup); } -/* ********************* generic callbacks for drawcall api *********************** */ - -/** - * Callback that draws a line between the mouse and a position given as the initial argument. - */ -void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *region, void *arg_info) -{ - wmWindow *win = CTX_wm_window(C); - const float *mval_src = (float *)arg_info; - const float mval_dst[2] = { - win->eventstate->x - region->winrct.xmin, - win->eventstate->y - region->winrct.ymin, - }; - - const uint shdr_pos = GPU_vertformat_attr_add( - immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - GPU_line_width(1.0f); - - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); - - float viewport_size[4]; - GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); - - immUniform1i("colors_len", 0); /* "simple" mode */ - immUniformThemeColor3(TH_VIEW_OVERLAY); - immUniform1f("dash_width", 6.0f); - immUniform1f("dash_factor", 0.5f); - - immBegin(GPU_PRIM_LINES, 2); - immVertex2fv(shdr_pos, mval_src); - immVertex2fv(shdr_pos, mval_dst); - immEnd(); - - immUnbindProgram(); -} - /** * Use to free ID references within runtime data (stored outside of DNA) * diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c index 88802e0d868..f46975c9378 100644 --- a/source/blender/editors/uvedit/uvedit_select.c +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -3313,7 +3313,6 @@ static bool do_lasso_select_mesh_uv(bContext *C, uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); } - /* don't indent to avoid diff noise! */ for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; @@ -3323,7 +3322,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - if (use_face_center) { /* Face Center Sel */ + if (use_face_center) { /* Face Center Select. */ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { BM_elem_flag_disable(efa, BM_ELEM_TAG); /* assume not touched */ @@ -3366,7 +3365,7 @@ static bool do_lasso_select_mesh_uv(bContext *C, } } } - else { /* Vert Sel */ + else { /* Vert Selection. */ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index e56dcd16528..062741a6270 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -606,7 +606,7 @@ void immUniform4fv(const char *name, const float data[4]) /* Note array index is not supported for name (i.e: "array[0]"). */ void immUniformArray4fv(const char *name, const float *data, int count) { - GPU_shader_uniform_4fv_array(imm->shader, name, count, (float(*)[4])data); + GPU_shader_uniform_4fv_array(imm->shader, name, count, (const float(*)[4])data); } void immUniformMatrix4fv(const char *name, const float data[4][4]) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl index 8131958313b..ec49cc86761 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_anisotropic.glsl @@ -5,12 +5,13 @@ void node_bsdf_anisotropic(vec4 color, float rotation, vec3 N, vec3 T, - float use_multiscatter, + const float use_multiscatter, + const float ssr_id, out Closure result) { - node_bsdf_glossy(color, roughness, N, -1, use_multiscatter, result); + node_bsdf_glossy(color, roughness, N, use_multiscatter, ssr_id, result); } #else /* Stub anisotropic because it is not compatible with volumetrics. */ -# define node_bsdf_anisotropic(a, b, c, d, e, f, g, result) (result = CLOSURE_DEFAULT) +# define node_bsdf_anisotropic(a, b, c, d, e, f, g, h, result) (result = CLOSURE_DEFAULT) #endif diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h index 31dca888732..89e648a7d6a 100644 --- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h +++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h @@ -32,7 +32,6 @@ extern "C" { struct ImBuf; struct OCIO_ConstCPUProcessorRcPtr; -struct OCIO_ConstProcessorRcPtr; extern float imbuf_luma_coefficients[3]; extern float imbuf_xyz_to_rgb[3][3]; diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 28bf26aa343..d36c7bbe486 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -1149,7 +1149,7 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ } } else { - pos = (int64_t)(position - anim->preseek) * AV_TIME_BASE / frame_rate; + pos = (int64_t)position * AV_TIME_BASE / frame_rate; av_log(anim->pFormatCtx, AV_LOG_DEBUG, diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 9d01617905f..14f0fef5270 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -168,7 +168,7 @@ typedef struct IDOverrideLibraryPropertyOperation { int subitem_local_index; } IDOverrideLibraryPropertyOperation; -/* IDOverridePropertyOperation->operation. */ +/* IDOverrideLibraryPropertyOperation->operation. */ enum { /* Basic operations. */ IDOVERRIDE_LIBRARY_OP_NOOP = 0, /* Special value, forbids any overriding. */ @@ -188,7 +188,7 @@ enum { /* We can add more if needed (move, delete, ...). */ }; -/* IDOverridePropertyOperation->flag. */ +/* IDOverrideLibraryPropertyOperation->flag. */ enum { /** User cannot remove that override operation. */ IDOVERRIDE_LIBRARY_FLAG_MANDATORY = 1 << 0, @@ -210,10 +210,14 @@ typedef struct IDOverrideLibraryProperty { */ char *rna_path; - /** List of overriding operations (IDOverridePropertyOperation) applied to this property. */ + /** + * List of overriding operations (IDOverrideLibraryPropertyOperation) applied to this property. + */ ListBase operations; - /** Runtime, tags are common to both IDOverrideProperty and IDOverridePropertyOperation. */ + /** + * Runtime, tags are common to both IDOverrideLibraryProperty and + * IDOverrideLibraryPropertyOperation. */ short tag; char _pad[2]; @@ -221,7 +225,7 @@ typedef struct IDOverrideLibraryProperty { unsigned int rna_prop_type; } IDOverrideLibraryProperty; -/* IDOverrideProperty->tag and IDOverridePropertyOperation->tag. */ +/* IDOverrideLibraryProperty->tag and IDOverrideLibraryPropertyOperation->tag. */ enum { /** This override property (operation) is unused and should be removed by cleanup process. */ IDOVERRIDE_LIBRARY_TAG_UNUSED = 1 << 0, @@ -244,7 +248,7 @@ enum { typedef struct IDOverrideLibrary { /** Reference linked ID which this one overrides. */ struct ID *reference; - /** List of IDOverrideProperty structs. */ + /** List of IDOverrideLibraryProperty structs. */ ListBase properties; /* Read/write data. */ @@ -718,8 +722,36 @@ typedef enum IDRecalcFlag { FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | FILTER_ID_WS | \ FILTER_ID_LP | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO | FILTER_ID_SIM) -/* IMPORTANT: this enum matches the order currently use in set_listbasepointers, - * keep them in sync! */ +/** + * This enum defines the index assigned to each type of IDs in the array returned by + * #set_listbasepointers, and by extension, controls the default order in which each ID type is + * processed during standard 'foreach' looping over all IDs of a #Main data-base. + * + * About Order: + * ------------ + * + * This is (loosely) defined with a relationship order in mind, from lowest level (ID types using, + * referencing almost no other ID types) to highest level (ID types potentially using many other ID + * types). + * + * So e.g. it ensures that this dependency chain is respected: + * #Material <- #Mesh <- #Object <- #Collection <- #Scene + * + * Default order of processing of IDs in 'foreach' macros (#FOREACH_MAIN_ID_BEGIN and the like), + * built on top of #set_listbasepointers, is actually reversed compared to the order defined here, + * since processing usually needs to happen on users before it happens on used IDs (when freeing + * e.g.). + * + * DO NOT rely on this order as being full-proofed dependency order, there are many cases were it + * can be violated (most obvious cases being custom properties and drivers, which can reference any + * other ID types). + * + * However, this order can be considered as an optimization heuristic, especially when processing + * relationships in a non-recursive pattern: in typical cases, a vast majority of those + * relationships can be processed fine in the first pass, and only few additional passes are + * required to address all remaining relationship cases. + * See e.g. how #BKE_library_unused_linked_data_set_tag is doing this. + */ enum { INDEX_ID_LI = 0, INDEX_ID_IP, @@ -759,6 +791,8 @@ enum { INDEX_ID_SCE, INDEX_ID_WS, INDEX_ID_WM, + /* TODO: This should probably be tweaked, #Mask and #Simulation are rather low-level types that + * should most likely be defined //before// #Object and geometry type indices? */ INDEX_ID_MSK, INDEX_ID_SIM, INDEX_ID_NULL, diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 16129768b60..7a39e0caef3 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -73,6 +73,16 @@ enum { /** #TreeStoreElem.types */ typedef enum eTreeStoreElemType { + /** + * If an element is of this type, `TreeStoreElem.id` points to a valid ID and the ID-type can be + * received through `TreeElement.idcode` (or `GS(TreeStoreElem.id->name)`). Note however that the + * types below may also have a valid ID pointer (see #TSE_IS_REAL_ID()). + * + * In cases where the type is still checked against "0" (even implicitly), please replace it with + * an explicit check against `TSE_SOME_ID`. + */ + TSE_SOME_ID = 0, + TSE_NLA = 1, /* NO ID */ TSE_NLA_ACTION = 2, TSE_DEFGROUP_BASE = 3, diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index dc1775b09c6..856fa569645 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -66,6 +66,9 @@ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; /* Defined in `node_intern.h`. */ typedef struct SpaceNode_Runtime SpaceNode_Runtime; +/* Defined in `file_intern.h`. */ +typedef struct SpaceFile_Runtime SpaceFile_Runtime; + /* -------------------------------------------------------------------- */ /** \name SpaceLink (Base) * \{ */ @@ -846,6 +849,8 @@ typedef struct SpaceFile { short recentnr, bookmarknr; short systemnr, system_bookmarknr; + + SpaceFile_Runtime *runtime; } SpaceFile; /* SpaceFile.browse_mode (File Space Browsing Mode) */ diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 1635aa7646b..68d69a671ba 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -154,8 +154,8 @@ typedef struct wmWindowManager { /** Operator registry. */ ListBase operators; - /** Refresh/redraw wmNotifier structs. */ - ListBase queue; + /** Refresh/redraw #wmNotifier structs. */ + ListBase notifier_queue; /** Information and error reports. */ struct ReportList reports; @@ -251,13 +251,14 @@ typedef struct wmWindow { struct bScreen *screen DNA_DEPRECATED; + /** Winid also in screens, is for retrieving this window after read. */ + int winid; /** Window coords. */ short posx, posy, sizex, sizey; /** Borderless, full. */ char windowstate; /** Set to 1 if an active window, for quick rejects. */ char active; - char _pad0[4]; /** Current mouse cursor type. */ short cursor; /** Previous cursor when setting modal one. */ @@ -271,16 +272,22 @@ typedef struct wmWindow { char addmousemove; char tag_cursor_refresh; - /** Winid also in screens, is for retrieving this window after read. */ - int winid; + /* Track the state of the event queue, + * these store the state that needs to be kept between handling events in the queue. */ + /** Enable when #KM_PRESS events are not handled (keyboard/mouse-buttons only). */ + char event_queue_check_click; + /** Enable when #KM_PRESS events are not handled (keyboard/mouse-buttons only). */ + char event_queue_check_drag; + + char _pad0[2]; /** Internal, lock pie creation from this event until released. */ - short lock_pie_event; + short pie_event_type_lock; /** * Exception to the above rule for nested pies, store last pie event for operators * that spawn a new pie right after destruction of last pie. */ - short last_pie_event; + short pie_event_type_last; /** Storage for event system. */ struct wmEvent *eventstate; @@ -292,8 +299,8 @@ typedef struct wmWindow { * Currently WIN32, runtime-only data. */ struct wmIMEData *ime_data; - /** All events (ghost level events were handled). */ - ListBase queue; + /** All events #wmEvent (ghost level events were handled). */ + ListBase event_queue; /** Window+screen handlers, handled last. */ ListBase handlers; /** Priority handlers, handled first. */ @@ -355,7 +362,7 @@ typedef struct wmKeyMapItem { short val; /** Oskey is apple or windowskey, value denotes order of pressed. */ short shift, ctrl, alt, oskey; - /** Rawkey modifier. */ + /** Raw-key modifier. */ short keymodifier; /* flag: inactive, expanded */ diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index c12426ffcd0..c49a52ceed7 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -421,7 +421,7 @@ void RNA_def_property_string_funcs(PropertyRNA *prop, const char *length, const char *set); void RNA_def_property_pointer_funcs( - PropertyRNA *prop, const char *get, const char *set, const char *typef, const char *poll); + PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll); void RNA_def_property_collection_funcs(PropertyRNA *prop, const char *begin, const char *next, diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index bec3db10905..1f887c2eec3 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3671,7 +3671,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr } } else { - if (!defaultfound && !(eprop->itemf && eprop->item == DummyRNA_NULL_items)) { + if (!defaultfound && !(eprop->item_fn && eprop->item == DummyRNA_NULL_items)) { CLOG_ERROR(&LOG, "%s%s.%s, enum default is not in items.", srna->identifier, @@ -3992,7 +3992,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr "\t%s, %s, %s, %s, %s, NULL, ", rna_function_string(eprop->get), rna_function_string(eprop->set), - rna_function_string(eprop->itemf), + rna_function_string(eprop->item_fn), rna_function_string(eprop->get_ex), rna_function_string(eprop->set_ex)); if (eprop->item) { @@ -4010,7 +4010,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr "\t%s, %s, %s, %s,", rna_function_string(pprop->get), rna_function_string(pprop->set), - rna_function_string(pprop->typef), + rna_function_string(pprop->type_fn), rna_function_string(pprop->poll)); if (pprop->type) { fprintf(f, "&RNA_%s\n", (const char *)pprop->type); diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index fd19352a9a5..6e2005b7314 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -528,6 +528,9 @@ static ID *rna_ID_copy(ID *id, Main *bmain) if (newid != NULL) { id_us_min(newid); } + + WM_main_add_notifier(NC_ID | NA_ADDED, NULL); + return newid; } diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index c5dd516d16e..8e5e70642cc 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1571,8 +1571,8 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop) if (prop->type == PROP_POINTER) { PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop; - if (pprop->typef) { - return pprop->typef(ptr); + if (pprop->type_fn) { + return pprop->type_fn(ptr); } if (pprop->type) { return pprop->type; @@ -1623,14 +1623,14 @@ void RNA_property_enum_items_ex(bContext *C, *r_free = false; - if (!use_static && eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { + if (!use_static && eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { const EnumPropertyItem *item; if (prop->flag & PROP_ENUM_NO_CONTEXT) { - item = eprop->itemf(NULL, ptr, prop, r_free); + item = eprop->item_fn(NULL, ptr, prop, r_free); } else { - item = eprop->itemf(C, ptr, prop, r_free); + item = eprop->item_fn(C, ptr, prop, r_free); } /* any callbacks returning NULL should be fixed */ @@ -1753,16 +1753,16 @@ void RNA_property_enum_items_gettexted_all(bContext *C, *r_totitem = eprop->totitem; } - if (eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { + if (eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { const EnumPropertyItem *item; int i; bool free = false; if (prop->flag & PROP_ENUM_NO_CONTEXT) { - item = eprop->itemf(NULL, ptr, prop, &free); + item = eprop->item_fn(NULL, ptr, prop, &free); } else { - item = eprop->itemf(C, ptr, prop, &free); + item = eprop->item_fn(C, ptr, prop, &free); } /* any callbacks returning NULL should be fixed */ @@ -3662,8 +3662,8 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop) } /* for groups, data is idprop itself */ - if (pprop->typef) { - return rna_pointer_inherit_refine(ptr, pprop->typef(ptr), idprop); + if (pprop->type_fn) { + return rna_pointer_inherit_refine(ptr, pprop->type_fn(ptr), idprop); } return rna_pointer_inherit_refine(ptr, pprop->type, idprop); } diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c index 8e95388fe2b..7be155605e6 100644 --- a/source/blender/makesrna/intern/rna_animviz.c +++ b/source/blender/makesrna/intern/rna_animviz.c @@ -150,7 +150,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "line_thickness"); RNA_def_property_range(prop, 1, 6); - RNA_def_property_ui_text(prop, "Line Thickness", "Line thickness for drawing path"); + RNA_def_property_ui_text(prop, "Line Thickness", "Line thickness for motion path"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* Settings */ @@ -176,7 +176,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) /* Draw lines between keyframes */ prop = RNA_def_property(srna, "lines", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_LINES); - RNA_def_property_ui_text(prop, "Lines", "Draw straight lines between keyframe points"); + RNA_def_property_ui_text(prop, "Lines", "Use straight lines between keyframe points"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); } diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 32162b068f6..554f04ca23c 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -966,10 +966,11 @@ static void rna_def_bone_common(StructRNA *srna, int editbone) prop = RNA_def_property(srna, "show_wire", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BONE_DRAWWIRE); - RNA_def_property_ui_text(prop, - "Display Wire", - "Bone is always drawn as Wireframe regardless of viewport draw mode " - "(useful for non-obstructive custom bone shapes)"); + RNA_def_property_ui_text( + prop, + "Display Wire", + "Bone is always displayed in wireframe regardless of viewport shading mode " + "(useful for non-obstructive custom bone shapes)"); RNA_def_property_update(prop, 0, "rna_Armature_redraw_data"); /* XXX: use_cyclic_offset is deprecated in 2.5. May/may not return */ diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index f662b6d2709..d603fea5a4a 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1895,7 +1895,8 @@ static void rna_def_gpencil_options(BlenderRNA *brna) prop = RNA_def_property(srna, "show_lasso", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_BRUSH_DISSABLE_LASSO); - RNA_def_property_ui_text(prop, "Show Lasso", "Do not draw fill color while drawing the stroke"); + RNA_def_property_ui_text( + prop, "Show Lasso", "Do not display fill color while drawing the stroke"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); prop = RNA_def_property(srna, "use_occlude_eraser", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index ea019c70445..206ebc2cb14 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -896,6 +896,9 @@ static void rna_def_curvemapping(BlenderRNA *brna) func = RNA_def_function(srna, "update", "BKE_curvemapping_changed_all"); RNA_def_function_ui_description(func, "Update curve mapping after making changes"); + func = RNA_def_function(srna, "reset_view", "BKE_curvemapping_reset_view"); + RNA_def_function_ui_description(func, "Reset the curve mapping grid to its clipping size"); + func = RNA_def_function(srna, "initialize", "rna_CurveMap_initialize"); RNA_def_function_ui_description(func, "Initialize curve"); @@ -1107,7 +1110,7 @@ static void rna_def_histogram(BlenderRNA *brna) prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, prop_mode_items); - RNA_def_property_ui_text(prop, "Mode", "Channels to display when drawing the histogram"); + RNA_def_property_ui_text(prop, "Mode", "Channels to display in the histogram"); prop = RNA_def_property(srna, "show_line", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", HISTO_FLAG_LINE); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index df3bd0cca29..5e188285e39 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -3267,7 +3267,7 @@ void RNA_def_property_enum_funcs(PropertyRNA *prop, eprop->set = (PropEnumSetFunc)set; } if (item) { - eprop->itemf = (PropEnumItemFunc)item; + eprop->item_fn = (PropEnumItemFunc)item; } break; } @@ -3292,7 +3292,7 @@ void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop, eprop->set_ex = setfunc; } if (itemfunc) { - eprop->itemf = itemfunc; + eprop->item_fn = itemfunc; } if (getfunc || setfunc) { @@ -3373,7 +3373,7 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop, } void RNA_def_property_pointer_funcs( - PropertyRNA *prop, const char *get, const char *set, const char *typef, const char *poll) + PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll) { StructRNA *srna = DefRNA.laststruct; @@ -3392,8 +3392,8 @@ void RNA_def_property_pointer_funcs( if (set) { pprop->set = (PropPointerSetFunc)set; } - if (typef) { - pprop->typef = (PropPointerTypeFunc)typef; + if (type_fn) { + pprop->type_fn = (PropPointerTypeFunc)type_fn; } if (poll) { pprop->poll = (PropPointerPollFunc)poll; @@ -3821,7 +3821,7 @@ PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont_, void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc) { EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop; - eprop->itemf = itemfunc; + eprop->item_fn = itemfunc; } PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont_, diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index a34c3c7b536..dab76c84e6a 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -2553,7 +2553,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "display_thickness"); RNA_def_property_range(prop, 0.001, 1000.0); RNA_def_property_ui_range(prop, 0.1, 100.0, 0.1, 3); - RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke drawing in the viewport"); + RNA_def_property_ui_text(prop, "Thickness", "Thickness of smoke display in the viewport"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); prop = RNA_def_property(srna, "display_interpolation", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index f9caa746dac..1a0497b72f4 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1632,7 +1632,7 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna) prop = RNA_def_property(srna, "display_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, stroke_display_mode_items); - RNA_def_property_ui_text(prop, "Draw Mode", "Coordinate space that stroke is in"); + RNA_def_property_ui_text(prop, "Display Mode", "Coordinate space that stroke is in"); RNA_def_property_update(prop, 0, "rna_GPencil_update"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); @@ -2227,13 +2227,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_DRAWDEBUG); RNA_def_property_ui_text( - prop, "Show Points", "Draw the points which make up the strokes (for debugging purposes)"); + prop, "Show Points", "Show the points which make up the strokes (for debugging purposes)"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* In Front */ prop = RNA_def_property(srna, "show_in_front", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GP_LAYER_NO_XRAY); - RNA_def_property_ui_text(prop, "In Front", "Make the layer draw in front of objects"); + RNA_def_property_ui_text(prop, "In Front", "Make the layer display in front of objects"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Parent object */ diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index bfcb0039ca8..95972dd444f 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -424,6 +424,7 @@ void RNA_api_window(struct StructRNA *srna); void RNA_api_wm(struct StructRNA *srna); void RNA_api_space_node(struct StructRNA *srna); void RNA_api_space_text(struct StructRNA *srna); +void RNA_api_space_filebrowser(struct StructRNA *srna); void RNA_api_region_view3d(struct StructRNA *srna); void RNA_api_texture(struct StructRNA *srna); void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip); diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index e6ed0f69300..1dd08bb1074 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -453,7 +453,7 @@ typedef struct EnumPropertyRNA { PropEnumGetFunc get; PropEnumSetFunc set; - PropEnumItemFunc itemf; + PropEnumItemFunc item_fn; PropEnumGetFuncEx get_ex; PropEnumSetFuncEx set_ex; @@ -471,7 +471,7 @@ typedef struct PointerPropertyRNA { PropPointerGetFunc get; PropPointerSetFunc set; - PropPointerTypeFunc typef; + PropPointerTypeFunc type_fn; /** unlike operators, 'set' can still run if poll fails, used for filtering display. */ PropPointerPollFunc poll; diff --git a/source/blender/makesrna/intern/rna_lattice.c b/source/blender/makesrna/intern/rna_lattice.c index 319aeb69a2b..707799e5633 100644 --- a/source/blender/makesrna/intern/rna_lattice.c +++ b/source/blender/makesrna/intern/rna_lattice.c @@ -371,7 +371,7 @@ static void rna_def_lattice(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", LT_OUTSIDE); RNA_def_property_boolean_funcs(prop, NULL, "rna_Lattice_use_outside_set"); RNA_def_property_ui_text( - prop, "Outside", "Only draw, and take into account, the outer vertices"); + prop, "Outside", "Only display and take into account the outer vertices"); RNA_def_property_update(prop, 0, "rna_Lattice_update_data_editlatt"); prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_light.c b/source/blender/makesrna/intern/rna_light.c index 433d499b4c1..52ebd5af993 100644 --- a/source/blender/makesrna/intern/rna_light.c +++ b/source/blender/makesrna/intern/rna_light.c @@ -504,7 +504,7 @@ static void rna_def_spot_light(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Show Cone", - "Draw transparent cone in 3D view to visualize which objects are contained in it"); + "Display transparent cone in 3D view to visualize which objects are contained in it"); RNA_def_property_update(prop, 0, "rna_Light_draw_update"); } diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 94b56e4f4e0..84c831a178e 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -616,7 +616,7 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode"); RNA_def_property_enum_items(prop, gpcolordata_mode_types_items); - RNA_def_property_ui_text(prop, "Mode Type", "Select draw mode for stroke"); + RNA_def_property_ui_text(prop, "Line Type", "Select line type for strokes"); RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); /* stroke style */ diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index fe375cda24a..2635d8b9669 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1743,8 +1743,7 @@ static void rna_def_modifier_subsurf(BlenderRNA *brna) prop = RNA_def_property(srna, "show_only_control_edges", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", eSubsurfModifierFlag_ControlEdges); - RNA_def_property_ui_text( - prop, "Optimal Display", "Skip drawing/rendering of interior subdivided edges"); + RNA_def_property_ui_text(prop, "Optimal Display", "Skip displaying interior subdivided edges"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "use_creases", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index d32872d1682..c9520c939f4 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -290,7 +290,7 @@ static void rna_def_moviecliUser(BlenderRNA *brna) RNA_def_property_enum_items(prop, clip_render_size_items); RNA_def_property_ui_text(prop, "Proxy Render Size", - "Draw preview using full resolution or different proxy resolutions"); + "Display preview using full resolution or different proxy resolutions"); RNA_def_property_update( prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClipUser_proxy_render_settings_update"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 2c0d7ba3d06..dfb882cde33 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -10366,7 +10366,7 @@ static void rna_def_node(BlenderRNA *brna) prop = RNA_def_property(srna, "show_texture", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_ACTIVE_TEXTURE); - RNA_def_property_ui_text(prop, "Show Texture", "Draw node in viewport textured draw mode"); + RNA_def_property_ui_text(prop, "Show Texture", "Display node in viewport textured shading mode"); RNA_def_property_update(prop, 0, "rna_Node_update"); /* generic property update function */ diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 799d1e8190c..a70b776b07a 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -3316,7 +3316,8 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "show_wire", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWWIRE); - RNA_def_property_ui_text(prop, "Display Wire", "Add the object's wireframe over solid drawing"); + RNA_def_property_ui_text( + prop, "Display Wire", "Display the object's wireframe over solid shading"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); prop = RNA_def_property(srna, "show_all_edges", PROP_BOOLEAN, PROP_NONE); @@ -3338,7 +3339,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "show_in_front", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAW_IN_FRONT); - RNA_def_property_ui_text(prop, "In Front", "Make the object draw in front of others"); + RNA_def_property_ui_text(prop, "In Front", "Make the object display in front of others"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_GPencil_update"); /* pose */ diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index f81f965d0c8..d94e68a6808 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -2694,7 +2694,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "show_health", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_HEALTH); - RNA_def_property_ui_text(prop, "Health", "Draw boid health"); + RNA_def_property_ui_text(prop, "Health", "Display boid health"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); prop = RNA_def_property(srna, "use_absolute_path_time", PROP_BOOLEAN, PROP_NONE); @@ -2742,7 +2742,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "use_render_adaptive", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_REN_ADAPT); - RNA_def_property_ui_text(prop, "Adaptive Render", "Draw steps of the particle path"); + RNA_def_property_ui_text(prop, "Adaptive Render", "Display steps of the particle path"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); prop = RNA_def_property(srna, "use_velocity_length", PROP_BOOLEAN, PROP_NONE); @@ -2764,7 +2764,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "draw_as"); RNA_def_property_enum_items(prop, part_draw_as_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Particle_draw_as_itemf"); - RNA_def_property_ui_text(prop, "Particle Drawing", "How particles are drawn in viewport"); + RNA_def_property_ui_text(prop, "Particle Display", "How particles are displayed in viewport"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); prop = RNA_def_property(srna, "render_type", PROP_ENUM, PROP_NONE); @@ -2777,14 +2777,14 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "display_color", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "draw_col"); RNA_def_property_enum_items(prop, draw_col_items); - RNA_def_property_ui_text(prop, "Draw Color", "Draw additional particle data as a color"); + RNA_def_property_ui_text(prop, "Display Color", "Display additional particle data as a color"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); prop = RNA_def_property(srna, "display_size", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "draw_size"); RNA_def_property_range(prop, 0, 1000); RNA_def_property_ui_range(prop, 0, 100, 1, -1); - RNA_def_property_ui_text(prop, "Draw Size", "Size of particles on viewport"); + RNA_def_property_ui_text(prop, "Display Size", "Size of particles on viewport"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); prop = RNA_def_property(srna, "child_type", PROP_ENUM, PROP_NONE); @@ -2797,7 +2797,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "draw_step"); RNA_def_property_range(prop, 0, 10); RNA_def_property_ui_range(prop, 0, 7, 1, -1); - RNA_def_property_ui_text(prop, "Steps", "How many steps paths are drawn with (power of 2)"); + RNA_def_property_ui_text(prop, "Steps", "How many steps paths are displayed with (power of 2)"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); prop = RNA_def_property(srna, "render_step", PROP_INT, PROP_NONE); @@ -3418,13 +3418,13 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "path_start", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "path_start"); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_PartSetting_pathstartend_range"); - RNA_def_property_ui_text(prop, "Path Start", "Starting time of drawn path"); + RNA_def_property_ui_text(prop, "Path Start", "Starting time of path"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); prop = RNA_def_property(srna, "path_end", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "path_end"); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_PartSetting_pathstartend_range"); - RNA_def_property_ui_text(prop, "Path End", "End time of drawn path"); + RNA_def_property_ui_text(prop, "Path End", "End time of path"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); prop = RNA_def_property(srna, "trail_count", PROP_INT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index bd45990fe30..ba65e42895c 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -425,22 +425,6 @@ static void rna_Itasc_update_rebuild(Main *bmain, Scene *scene, PointerRNA *ptr) rna_Itasc_update(bmain, scene, ptr); } -static void rna_PoseChannel_bone_custom_set(PointerRNA *ptr, - PointerRNA value, - struct ReportList *UNUSED(reports)) -{ - bPoseChannel *pchan = (bPoseChannel *)ptr->data; - - if (pchan->custom) { - id_us_min(&pchan->custom->id); - pchan->custom = NULL; - } - - pchan->custom = value.data; - - id_us_plus(&pchan->custom->id); -} - static PointerRNA rna_PoseChannel_bone_group_get(PointerRNA *ptr) { Object *ob = (Object *)ptr->owner_id; @@ -1368,11 +1352,10 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop = RNA_def_property(srna, "custom_shape", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "custom"); RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_NO_COMPARISON); - RNA_def_property_pointer_funcs(prop, NULL, "rna_PoseChannel_bone_custom_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( - prop, "Custom Object", "Object that defines custom draw type for this bone"); + prop, "Custom Object", "Object that defines custom display shape for this bone"); RNA_def_property_editable_func(prop, "rna_PoseChannel_proxy_editable"); RNA_def_property_update(prop, NC_OBJECT | ND_POSE, "rna_Pose_dependency_update"); diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c index 59704b00391..d93972aa0ad 100644 --- a/source/blender/makesrna/intern/rna_pose_api.c +++ b/source/blender/makesrna/intern/rna_pose_api.c @@ -38,9 +38,14 @@ #ifdef RNA_RUNTIME -/* #include "DNA_anim_types.h" */ +# include "BKE_animsys.h" # include "BKE_armature.h" -# include "DNA_action_types.h" /* bPose */ +# include "BKE_context.h" + +# include "DNA_action_types.h" +# include "DNA_anim_types.h" + +# include "BLI_ghash.h" static float rna_PoseBone_do_envelope(bPoseChannel *chan, float *vec) { @@ -102,12 +107,49 @@ static void rna_PoseBone_compute_bbone_handles(bPoseChannel *pchan, BKE_pchan_bbone_handles_compute( ¶ms, ret_h1, ret_roll1, ret_h2, ret_roll2, ease || offsets, offsets); } + +static void rna_Pose_apply_pose_from_action(ID *pose_owner, + bContext *C, + bAction *action, + const float evaluation_time) +{ + BLI_assert(GS(pose_owner->name) == ID_OB); + Object *pose_owner_ob = (Object *)pose_owner; + + AnimationEvalContext anim_eval_context = {CTX_data_depsgraph_pointer(C), evaluation_time}; + BKE_pose_apply_action(pose_owner_ob, action, &anim_eval_context); + + /* Do NOT tag with ID_RECALC_ANIMATION, as that would overwrite the just-applied pose. */ + DEG_id_tag_update(pose_owner, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pose_owner); +} + #else -void RNA_api_pose(StructRNA *UNUSED(srna)) +void RNA_api_pose(StructRNA *srna) { - /* FunctionRNA *func; */ - /* PropertyRNA *parm; */ + FunctionRNA *func; + PropertyRNA *parm; + + func = RNA_def_function(srna, "apply_pose_from_action", "rna_Pose_apply_pose_from_action"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT); + RNA_def_function_ui_description( + func, + "Apply the given action to this pose by evaluating it at a specific time. Only updates the " + "pose of selected bones, or all bones if none are selected"); + + parm = RNA_def_pointer(func, "action", "Action", "Action", "The Action containing the pose"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + parm = RNA_def_float(func, + "evaluation_time", + 0.0f, + -FLT_MAX, + FLT_MAX, + "Evaluation Time", + "Time at which the given action is evaluated to obtain the pose", + -FLT_MAX, + FLT_MAX); } void RNA_api_pose_channel(StructRNA *srna) diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index b0a942cd39e..d553ead1e45 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -910,14 +910,14 @@ static const EnumPropertyItem *rna_EnumProperty_default_itemf(bContext *C, return DummyRNA_NULL_items; } - if ((eprop->itemf == NULL) || (eprop->itemf == rna_EnumProperty_default_itemf) || + if ((eprop->item_fn == NULL) || (eprop->item_fn == rna_EnumProperty_default_itemf) || (ptr->type == &RNA_EnumProperty) || (C == NULL)) { if (eprop->item) { return eprop->item; } } - return eprop->itemf(C, ptr, prop, r_free); + return eprop->item_fn(C, ptr, prop, r_free); } /* XXX - not sure this is needed? */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 170bbc7e372..1ac224b27e4 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5977,7 +5977,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "frs_sec"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 1, SHRT_MAX); - RNA_def_property_ui_range(prop, 1, 120, 1, -1); + RNA_def_property_ui_range(prop, 1, 240, 1, -1); RNA_def_property_ui_text(prop, "FPS", "Framerate, expressed in frames per second"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_fps_update"); @@ -6445,7 +6445,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "seq_prev_type"); RNA_def_property_enum_items(prop, rna_enum_shading_type_items); RNA_def_property_ui_text( - prop, "Sequencer Preview Shading", "Method to draw in the sequencer view"); + prop, "Sequencer Preview Shading", "Display method used in the sequencer view"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SceneSequencer_update"); # if 0 /* UNUSED, see R_SEQ_GL_REND comment */ @@ -6454,7 +6454,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_enum_items(prop, rna_enum_shading_type_items); /* XXX Label and tooltips are obviously wrong! */ RNA_def_property_ui_text( - prop, "Sequencer Preview Shading", "Method to draw in the sequencer view"); + prop, "Sequencer Preview Shading", "Display method used in the sequencer view"); # endif prop = RNA_def_property(srna, "use_sequencer_override_scene_strip", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 070fb08c3b4..00d8c43a111 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -53,6 +53,7 @@ # include "SEQ_add.h" # include "SEQ_edit.h" +# include "SEQ_effects.h" # include "SEQ_relations.h" # include "SEQ_render.h" # include "SEQ_sequencer.h" @@ -80,34 +81,6 @@ static void rna_Sequence_swap_internal(Sequence *seq_self, } } -static Sequence *alloc_generic_sequence( - ListBase *seqbase, const char *name, int frame_start, int channel, int type, const char *file) -{ - Sequence *seq; - StripElem *se; - - seq = SEQ_sequence_alloc(seqbase, frame_start, channel, type); - - BLI_strncpy(seq->name + 2, name, sizeof(seq->name) - 2); - SEQ_sequence_base_unique_name_recursive(seqbase, seq); - - Strip *strip = seq->strip; - - /* Don't allocate StripElem for clip, mask and scene types. This struct is not handled in - * seq_dupli() function. */ - if (file && !ELEM(type, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK, SEQ_TYPE_SCENE)) { - strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem"); - BLI_split_dirfile(file, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name)); - - SEQ_render_init_colorspace(seq); - } - else { - strip->stripdata = NULL; - } - - return seq; -} - static Sequence *rna_Sequences_new_clip(ID *id, ListBase *seqbase, Main *bmain, @@ -117,15 +90,10 @@ static Sequence *rna_Sequences_new_clip(ID *id, int frame_start) { Scene *scene = (Scene *)id; - Sequence *seq; - - seq = alloc_generic_sequence( - seqbase, name, frame_start, channel, SEQ_TYPE_MOVIECLIP, clip->filepath); - seq->clip = clip; - seq->len = BKE_movieclip_get_duration(clip); - id_us_plus((ID *)clip); - - SEQ_time_update_sequence_bounds(scene, seq); + SeqLoadData load_data; + SEQ_add_load_data_init(&load_data, name, NULL, frame_start, channel); + load_data.clip = clip; + Sequence *seq = SEQ_add_movieclip_strip(scene, seqbase, &load_data); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -165,15 +133,10 @@ static Sequence *rna_Sequences_new_mask(ID *id, int frame_start) { Scene *scene = (Scene *)id; - Sequence *seq; - - seq = alloc_generic_sequence(seqbase, name, frame_start, channel, SEQ_TYPE_MASK, mask->id.name); - seq->mask = mask; - seq->len = BKE_mask_get_duration(mask); - id_us_plus((ID *)mask); - - SEQ_time_update_sequence_bounds(scene, seq); - SEQ_relations_invalidate_cache_composite(scene, seq); + SeqLoadData load_data; + SEQ_add_load_data_init(&load_data, name, NULL, frame_start, channel); + load_data.mask = mask; + Sequence *seq = SEQ_add_mask_strip(scene, seqbase, &load_data); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -202,15 +165,10 @@ static Sequence *rna_Sequences_new_scene(ID *id, int frame_start) { Scene *scene = (Scene *)id; - Sequence *seq; - - seq = alloc_generic_sequence(seqbase, name, frame_start, channel, SEQ_TYPE_SCENE, NULL); - seq->scene = sce_seq; - seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1; - id_us_plus((ID *)sce_seq); - - SEQ_time_update_sequence_bounds(scene, seq); - SEQ_relations_invalidate_cache_composite(scene, seq); + SeqLoadData load_data; + SEQ_add_load_data_init(&load_data, name, NULL, frame_start, channel); + load_data.scene = sce_seq; + Sequence *seq = SEQ_add_scene_strip(scene, seqbase, &load_data); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -244,27 +202,24 @@ static Sequence *rna_Sequences_meta_new_scene(ID *id, static Sequence *rna_Sequences_new_image(ID *id, ListBase *seqbase, Main *bmain, - ReportList *reports, + ReportList *UNUSED(reports), const char *name, const char *file, int channel, int frame_start) { Scene *scene = (Scene *)id; - Sequence *seq; - seq = alloc_generic_sequence(seqbase, name, frame_start, channel, SEQ_TYPE_IMAGE, file); - seq->len = 1; + SeqLoadData load_data; + SEQ_add_load_data_init(&load_data, name, file, frame_start, channel); + load_data.image.len = 1; + Sequence *seq = SEQ_add_image_strip(bmain, scene, seqbase, &load_data); - if (seq->strip->stripdata->name[0] == '\0') { - BKE_report(reports, RPT_ERROR, "Sequences.new_image: unable to open image file"); - BLI_remlink(seqbase, seq); - SEQ_sequence_free(scene, seq, true); - return NULL; - } - - SEQ_time_update_sequence_bounds(scene, seq); - SEQ_relations_invalidate_cache_composite(scene, seq); + char dir[FILE_MAX], filename[FILE_MAX]; + BLI_split_dirfile(file, dir, filename, sizeof(dir), sizeof(filename)); + SEQ_add_image_set_directory(seq, dir); + SEQ_add_image_load_file(seq, 0, filename); + SEQ_add_image_init_alpha_mode(seq); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -299,48 +254,47 @@ static Sequence *rna_Sequences_meta_new_image(ID *id, id, &seq->seqbase, bmain, reports, name, file, channel, frame_start); } -static Sequence *rna_Sequences_new_movie( - ID *id, ListBase *seqbase, const char *name, const char *file, int channel, int frame_start) +static Sequence *rna_Sequences_new_movie(ID *id, + ListBase *seqbase, + Main *bmain, + const char *name, + const char *file, + int channel, + int frame_start) { Scene *scene = (Scene *)id; - Sequence *seq; - StripAnim *sanim; - - seq = alloc_generic_sequence(seqbase, name, frame_start, channel, SEQ_TYPE_MOVIE, file); - - struct anim *an = openanim(file, IB_rect, 0, NULL); - if (an == NULL) { - /* Without anim, the strip gets duration 0, which makes it impossible to select in the UI. */ - seq->len = 1; - } - else { - sanim = MEM_mallocN(sizeof(StripAnim), "Strip Anim"); - BLI_addtail(&seq->anims, sanim); - sanim->anim = an; - - seq->anim_preseek = IMB_anim_get_preseek(an); - seq->len = IMB_anim_get_duration(an, IMB_TC_RECORD_RUN); - } - - SEQ_time_update_sequence_bounds(scene, seq); - SEQ_relations_invalidate_cache_composite(scene, seq); + SeqLoadData load_data; + SEQ_add_load_data_init(&load_data, name, file, frame_start, channel); + load_data.allow_invalid_file = true; + Sequence *seq = SEQ_add_movie_strip(bmain, scene, seqbase, &load_data); + DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); return seq; } -static Sequence *rna_Sequences_editing_new_movie( - ID *id, Editing *ed, const char *name, const char *file, int channel, int frame_start) +static Sequence *rna_Sequences_editing_new_movie(ID *id, + Editing *ed, + Main *bmain, + const char *name, + const char *file, + int channel, + int frame_start) { - return rna_Sequences_new_movie(id, &ed->seqbase, name, file, channel, frame_start); + return rna_Sequences_new_movie(id, &ed->seqbase, bmain, name, file, channel, frame_start); } -static Sequence *rna_Sequences_meta_new_movie( - ID *id, Sequence *seq, const char *name, const char *file, int channel, int frame_start) +static Sequence *rna_Sequences_meta_new_movie(ID *id, + Sequence *seq, + Main *bmain, + const char *name, + const char *file, + int channel, + int frame_start) { - return rna_Sequences_new_movie(id, &seq->seqbase, name, file, channel, frame_start); + return rna_Sequences_new_movie(id, &seq->seqbase, bmain, name, file, channel, frame_start); } # ifdef WITH_AUDASPACE @@ -354,22 +308,15 @@ static Sequence *rna_Sequences_new_sound(ID *id, int frame_start) { Scene *scene = (Scene *)id; - Sequence *seq; + SeqLoadData load_data; + SEQ_add_load_data_init(&load_data, name, file, frame_start, channel); + load_data.allow_invalid_file = true; + Sequence *seq = SEQ_add_sound_strip(bmain, scene, seqbase, &load_data); - bSound *sound = BKE_sound_new_file(bmain, file); - - SoundInfo info; - if (!BKE_sound_info_get(bmain, sound, &info)) { - BKE_id_free(bmain, sound); + if (seq == NULL) { BKE_report(reports, RPT_ERROR, "Sequences.new_sound: unable to open sound file"); return NULL; } - seq = alloc_generic_sequence( - seqbase, name, frame_start, channel, SEQ_TYPE_SOUND_RAM, sound->filepath); - seq->sound = sound; - seq->len = ceil((double)info.length * FPS); - - SEQ_time_update_sequence_bounds(scene, seq); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -432,8 +379,7 @@ static Sequence *rna_Sequences_new_effect(ID *id, { Scene *scene = (Scene *)id; Sequence *seq; - struct SeqEffectHandle sh; - int num_inputs = SEQ_effect_get_num_inputs(type); + const int num_inputs = SEQ_effect_get_num_inputs(type); switch (num_inputs) { case 0: @@ -469,26 +415,14 @@ static Sequence *rna_Sequences_new_effect(ID *id, return NULL; } - seq = alloc_generic_sequence(seqbase, name, frame_start, channel, type, NULL); - - sh = SEQ_effect_handle_get(seq); - - seq->seq1 = seq1; - seq->seq2 = seq2; - seq->seq3 = seq3; - - sh.init(seq); - - if (!seq1) { /* effect has no deps */ - seq->len = 1; - SEQ_transform_set_right_handle_frame(seq, frame_end); - } - - seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE; - - SEQ_time_update_sequence(scene, seq); - SEQ_time_update_sequence_bounds(scene, seq); - SEQ_relations_invalidate_cache_composite(scene, seq); + SeqLoadData load_data; + SEQ_add_load_data_init(&load_data, name, NULL, frame_start, channel); + load_data.effect.end_frame = frame_end; + load_data.effect.type = type; + load_data.effect.seq1 = seq1; + load_data.effect.seq2 = seq2; + load_data.effect.seq3 = seq3; + seq = SEQ_add_effect_strip(scene, seqbase, &load_data); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); @@ -865,7 +799,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastri RNA_def_function_return(func, parm); func = RNA_def_function(srna, "new_movie", new_movie_func_name); - RNA_def_function_flag(func, FUNC_USE_SELF_ID); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Add a new movie sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 3b43ad5e766..5312aea9295 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3178,7 +3178,7 @@ static void rna_def_space_image_uv(BlenderRNA *brna) prop = RNA_def_property(srna, "display_stretch_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "dt_uvstretch"); RNA_def_property_enum_items(prop, dt_uvstretch_items); - RNA_def_property_ui_text(prop, "Display Stretch Type", "Type of stretch to draw"); + RNA_def_property_ui_text(prop, "Display Stretch Type", "Type of stretch to display"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); prop = RNA_def_property(srna, "show_modified_edges", PROP_BOOLEAN, PROP_NONE); @@ -3562,7 +3562,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) prop = RNA_def_property(srna, "cavity_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, cavity_type_items); - RNA_def_property_ui_text(prop, "Cavity Type", "Way to draw the cavity shading"); + RNA_def_property_ui_text(prop, "Cavity Type", "Way to display the cavity shading"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL); prop = RNA_def_property(srna, "curvature_ridge_factor", PROP_FLOAT, PROP_FACTOR); @@ -3671,7 +3671,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) prop = RNA_def_property(srna, "background_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, background_type_items); - RNA_def_property_ui_text(prop, "Background", "Way to draw the background"); + RNA_def_property_ui_text(prop, "Background", "Way to display the background"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL); prop = RNA_def_property(srna, "background_color", PROP_FLOAT, PROP_COLOR); @@ -4028,56 +4028,56 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) prop = RNA_def_property(srna, "show_edges", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_EDGES); - RNA_def_property_ui_text(prop, "Draw Edges", "Highlight selected edges"); + RNA_def_property_ui_text(prop, "Display Edges", "Highlight selected edges"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_faces", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FACES); - RNA_def_property_ui_text(prop, "Draw Faces", "Highlight selected faces"); + RNA_def_property_ui_text(prop, "Display Faces", "Highlight selected faces"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_face_center", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FACE_DOT); RNA_def_property_ui_text( prop, - "Draw Face Center", + "Display Face Center", "Display face center when face selection is enabled in solid shading modes"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_edge_crease", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_CREASES); RNA_def_property_ui_text( - prop, "Draw Creases", "Display creases created for Subdivision Surface modifier"); + prop, "Display Creases", "Display creases created for Subdivision Surface modifier"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_edge_bevel_weight", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_BWEIGHTS); RNA_def_property_ui_text( - prop, "Draw Bevel Weights", "Display weights created for the Bevel modifier"); + prop, "Display Bevel Weights", "Display weights created for the Bevel modifier"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_edge_seams", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_SEAMS); - RNA_def_property_ui_text(prop, "Draw Seams", "Display UV unwrapping seams"); + RNA_def_property_ui_text(prop, "Display Seams", "Display UV unwrapping seams"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_edge_sharp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_SHARP); RNA_def_property_ui_text( - prop, "Draw Sharp", "Display sharp edges, used with the Edge Split modifier"); + prop, "Display Sharp", "Display sharp edges, used with the Edge Split modifier"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_freestyle_edge_marks", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FREESTYLE_EDGE); RNA_def_property_ui_text(prop, - "Draw Freestyle Edge Marks", + "Display Freestyle Edge Marks", "Display Freestyle edge marks, used with the Freestyle renderer"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_freestyle_face_marks", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.edit_flag", V3D_OVERLAY_EDIT_FREESTYLE_FACE); RNA_def_property_ui_text(prop, - "Draw Freestyle Face Marks", + "Display Freestyle Face Marks", "Display Freestyle face marks, used with the Freestyle renderer"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); @@ -4563,7 +4563,7 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "multiview_eye"); RNA_def_property_enum_items(prop, stereo3d_eye_items); RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceView3D_stereo3d_camera_itemf"); - RNA_def_property_ui_text(prop, "Stereo Eye", "Current stereo eye being drawn"); + RNA_def_property_ui_text(prop, "Stereo Eye", "Current stereo eye being displayed"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); prop = RNA_def_property(srna, "stereo_3d_camera", PROP_ENUM, PROP_NONE); @@ -4977,7 +4977,7 @@ static void rna_def_space_image(BlenderRNA *brna) "rna_SpaceImageEditor_display_channels_get", NULL, "rna_SpaceImageEditor_display_channels_itemf"); - RNA_def_property_ui_text(prop, "Display Channels", "Channels of the image to draw"); + RNA_def_property_ui_text(prop, "Display Channels", "Channels of the image to display"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); prop = RNA_def_property(srna, "show_stereo_3d", PROP_BOOLEAN, PROP_NONE); @@ -5125,17 +5125,17 @@ static void rna_def_space_sequencer(BlenderRNA *brna) "NO_WAVEFORMS", 0, "Waveforms Off", - "No waveforms drawn for any sound strips"}, + "Don't display waveforms for any sound strips"}, {SEQ_ALL_WAVEFORMS, "ALL_WAVEFORMS", 0, "Waveforms On", - "Waveforms drawn for all sound strips"}, + "Display waveforms for all sound strips"}, {0, "DEFAULT_WAVEFORMS", 0, "Use Strip Option", - "Waveforms drawn according to strip setting"}, + "Display waveforms depending on strip setting"}, {0, NULL, 0, NULL, NULL}, }; @@ -5226,13 +5226,13 @@ static void rna_def_space_sequencer(BlenderRNA *brna) prop = RNA_def_property(srna, "preview_channels", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, preview_channels_items); - RNA_def_property_ui_text(prop, "Display Channels", "Channels of the preview to draw"); + RNA_def_property_ui_text(prop, "Display Channels", "Channels of the preview to display"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, "rna_SequenceEditor_update_cache"); prop = RNA_def_property(srna, "waveform_display_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, waveform_type_display_items); - RNA_def_property_ui_text(prop, "Waveform Display", "How Waveforms are drawn"); + RNA_def_property_ui_text(prop, "Waveform Display", "How Waveforms are displayed"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); prop = RNA_def_property(srna, "use_zoom_to_fit", PROP_BOOLEAN, PROP_NONE); @@ -5268,7 +5268,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna) prop = RNA_def_property(srna, "overlay_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "overlay_type"); RNA_def_property_enum_items(prop, overlay_type_items); - RNA_def_property_ui_text(prop, "Overlay Type", "Overlay draw type"); + RNA_def_property_ui_text(prop, "Overlay Type", "Overlay display method"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); prop = RNA_def_property(srna, "show_backdrop", PROP_BOOLEAN, PROP_NONE); @@ -6154,7 +6154,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna) prop = RNA_def_property(srna, "show_details_size", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "details_flags", FILE_DETAILS_SIZE); - RNA_def_property_ui_text(prop, "File Size", "Draw a column listing the size of each file"); + RNA_def_property_ui_text(prop, "File Size", "Show a column listing the size of each file"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "show_details_datetime", PROP_BOOLEAN, PROP_NONE); @@ -6162,7 +6162,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_ui_text( prop, "File Modification Date", - "Draw a column listing the date and time of modification for each file"); + "Show a column listing the date and time of modification for each file"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_filter", PROP_BOOLEAN, PROP_NONE); @@ -6569,6 +6569,8 @@ static void rna_def_space_filebrowser(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update( prop, NC_SPACE | ND_SPACE_FILE_PARAMS, "rna_FileBrowser_FSMenu_active_update"); + + RNA_api_space_filebrowser(srna); } static void rna_def_space_info(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index e4c0ade1533..205a88edf84 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -27,6 +27,7 @@ # include "BKE_global.h" +# include "ED_fileselect.h" # include "ED_screen.h" # include "ED_text.h" @@ -115,4 +116,24 @@ void RNA_api_space_text(StructRNA *srna) RNA_def_function_output(func, parm); } +void RNA_api_space_filebrowser(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func = RNA_def_function(srna, "activate_asset_by_id", "ED_fileselect_activate_by_id"); + RNA_def_function_ui_description(func, "Activate the asset entry that represents the given ID"); + + parm = RNA_def_property(func, "id_to_activate", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(parm, "ID"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + parm = RNA_def_boolean( + func, + "deferred", + 0, + "", + "Whether to activate the ID immediately (false) or after the file browser refreshes (true)"); +} + #endif diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 5e5b3549986..aefb77c4077 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -1357,7 +1357,7 @@ static void rna_def_panel(BlenderRNA *brna) 0, "Expand Header Layout", "Allow buttons in the header to stretch and shrink to fill the entire layout width"}, - {PANEL_TYPE_DRAW_BOX, "DRAW_BOX", 0, "Box Style", "Draw panel with the box widget theme"}, + {PANEL_TYPE_DRAW_BOX, "DRAW_BOX", 0, "Box Style", "Display panel with the box widget theme"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 4a50718c91d..b06ec674e81 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -3879,8 +3879,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna) srna = RNA_def_struct(brna, "Theme", NULL); RNA_def_struct_sdna(srna, "bTheme"); RNA_def_struct_clear_flag(srna, STRUCT_UNDO); - RNA_def_struct_ui_text( - srna, "Theme", "Theme settings defining draw style and colors in the user interface"); + RNA_def_struct_ui_text(srna, "Theme", "User interface styling and color settings"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Name", "Name of the theme"); @@ -4270,12 +4269,13 @@ static void rna_def_userdef_solidlight(BlenderRNA *brna) srna = RNA_def_struct(brna, "UserSolidLight", NULL); RNA_def_struct_sdna(srna, "SolidLight"); RNA_def_struct_clear_flag(srna, STRUCT_UNDO); - RNA_def_struct_ui_text(srna, "Solid Light", "Light used for Studio lighting in solid draw mode"); + RNA_def_struct_ui_text( + srna, "Solid Light", "Light used for Studio lighting in solid shading mode"); prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", 1); RNA_def_property_boolean_default(prop, true); - RNA_def_property_ui_text(prop, "Enabled", "Enable this light in solid draw mode"); + RNA_def_property_ui_text(prop, "Enabled", "Enable this light in solid shading mode"); RNA_def_property_update(prop, 0, "rna_UserDef_viewport_lights_update"); prop = RNA_def_property(srna, "smooth", PROP_FLOAT, PROP_FACTOR); @@ -4815,7 +4815,8 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop = RNA_def_property(srna, "use_text_antialiasing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_AA); - RNA_def_property_ui_text(prop, "Text Anti-Aliasing", "Draw user interface text anti-aliased"); + RNA_def_property_ui_text( + prop, "Text Anti-Aliasing", "Smooth jagged edges of user interface text"); RNA_def_property_update(prop, 0, "rna_userdef_text_update"); prop = RNA_def_property(srna, "text_hinting", PROP_ENUM, PROP_NONE); @@ -5321,12 +5322,12 @@ static void rna_def_userdef_system(BlenderRNA *brna) "2DTEXTURE", 0, "2D Texture", - "Use CPU for display transform and draw image with 2D texture"}, + "Use CPU for display transform and display image with 2D texture"}, {IMAGE_DRAW_METHOD_GLSL, "GLSL", 0, "GLSL", - "Use GLSL shaders for display transform and draw image with 2D texture"}, + "Use GLSL shaders for display transform and display image with 2D texture"}, {0, NULL, 0, NULL, NULL}, }; @@ -5363,7 +5364,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text( prop, "UI Scale", - "Size multiplier to use when drawing custom user interface elements, so that " + "Size multiplier to use when displaying custom user interface elements, so that " "they are scaled correctly on screens with different DPI. This value is based " "on operating system DPI settings and Blender display scale"); @@ -5373,7 +5374,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text( prop, "UI Line Width", - "Suggested line thickness and point size in pixels, for add-ons drawing custom " + "Suggested line thickness and point size in pixels, for add-ons displaying custom " "user interface elements, based on operating system settings and Blender UI scale"); prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE); @@ -5442,7 +5443,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop = RNA_def_property(srna, "use_region_overlap", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag2", USER_REGION_OVERLAP); RNA_def_property_ui_text( - prop, "Region Overlap", "Draw tool/property regions over the main region"); + prop, "Region Overlap", "Display tool/property regions over the main region"); RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); prop = RNA_def_property(srna, "viewport_aa", PROP_ENUM, PROP_NONE); @@ -5456,7 +5457,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "light_param", ""); RNA_def_property_struct_type(prop, "UserSolidLight"); RNA_def_property_ui_text( - prop, "Solid Lights", "Lights user to display objects in solid draw mode"); + prop, "Solid Lights", "Lights user to display objects in solid shading mode"); prop = RNA_def_property(srna, "light_ambient", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "light_ambient"); @@ -6061,7 +6062,9 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) prop = RNA_def_property(srna, "use_relative_paths", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_RELPATHS); RNA_def_property_ui_text( - prop, "Relative Paths", "Default relative path option for the file selector"); + prop, + "Relative Paths", + "Default relative path option for the file selector, when no path is defined yet"); prop = RNA_def_property(srna, "use_file_compression", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_FILECOMPRESS); @@ -6186,7 +6189,8 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_SAVE_PREVIEWS); RNA_def_property_ui_text(prop, "Save Preview Images", - "Enables automatic saving of preview images in the .blend file"); + "Enables automatic saving of preview images in the .blend file " + "as well as a thumbnail of the .blend"); rna_def_userdef_filepaths_asset_library(brna); diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c index d71dcc0700b..1bddd9152db 100644 --- a/source/blender/makesrna/intern/rna_volume.c +++ b/source/blender/makesrna/intern/rna_volume.c @@ -366,7 +366,7 @@ static void rna_def_volume_display(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.00001, FLT_MAX); RNA_def_property_ui_range(prop, 0.1, 100.0, 1, 3); - RNA_def_property_ui_text(prop, "Density", "Thickness of volume drawing in the viewport"); + RNA_def_property_ui_text(prop, "Density", "Thickness of volume display in the viewport"); RNA_def_property_update(prop, 0, "rna_Volume_update_display"); static const EnumPropertyItem wireframe_type_items[] = { diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c index e61482c91e2..f7d139dd706 100644 --- a/source/blender/makesrna/intern/rna_wm_gizmo.c +++ b/source/blender/makesrna/intern/rna_wm_gizmo.c @@ -1238,20 +1238,20 @@ static void rna_def_gizmo(BlenderRNA *brna, PropertyRNA *cprop) prop = RNA_def_property(srna, "use_draw_hover", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( prop, "rna_Gizmo_flag_use_draw_hover_get", "rna_Gizmo_flag_use_draw_hover_set"); - RNA_def_property_ui_text(prop, "Draw Hover", ""); + RNA_def_property_ui_text(prop, "Show Hover", ""); RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_DRAW_MODAL */ prop = RNA_def_property(srna, "use_draw_modal", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( prop, "rna_Gizmo_flag_use_draw_modal_get", "rna_Gizmo_flag_use_draw_modal_set"); - RNA_def_property_ui_text(prop, "Draw Active", "Draw while dragging"); + RNA_def_property_ui_text(prop, "Show Active", "Show while dragging"); RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_DRAW_VALUE */ prop = RNA_def_property(srna, "use_draw_value", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs( prop, "rna_Gizmo_flag_use_draw_value_get", "rna_Gizmo_flag_use_draw_value_set"); RNA_def_property_ui_text( - prop, "Draw Value", "Show an indicator for the current value while dragging"); + prop, "Show Value", "Show an indicator for the current value while dragging"); RNA_def_property_update(prop, 0, "rna_Gizmo_update_redraw"); /* WM_GIZMO_DRAW_OFFSET_SCALE */ prop = RNA_def_property(srna, "use_draw_offset_scale", PROP_BOOLEAN, PROP_NONE); @@ -1391,7 +1391,7 @@ static void rna_def_gizmogroup(BlenderRNA *brna) "SCALE", 0, "Scale", - "Scale to respect zoom (otherwise zoom independent draw size)"}, + "Scale to respect zoom (otherwise zoom independent display size)"}, {WM_GIZMOGROUPTYPE_DEPTH_3D, "DEPTH_3D", 0, diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index c7731815a2a..4d1823b8951 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -77,6 +77,7 @@ #include "NOD_type_callbacks.hh" using blender::float3; +using blender::FunctionRef; using blender::IndexRange; using blender::Map; using blender::Set; @@ -90,8 +91,8 @@ using blender::bke::PersistentObjectHandle; using blender::fn::GMutablePointer; using blender::fn::GValueMap; using blender::nodes::GeoNodeExecParams; -using namespace blender::nodes::derived_node_tree_types; using namespace blender::fn::multi_function_types; +using namespace blender::nodes::derived_node_tree_types; static void initData(ModifierData *md) { @@ -233,6 +234,11 @@ static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *u &settings); } +static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData) +{ + walk(userData, ob, md, "texture"); +} + static bool isDisabled(const struct Scene *UNUSED(scene), ModifierData *md, bool UNUSED(useRenderParams)) @@ -249,8 +255,8 @@ static bool isDisabled(const struct Scene *UNUSED(scene), class GeometryNodesEvaluator { private: blender::LinearAllocator<> allocator_; - Map<std::pair<const DInputSocket *, const DOutputSocket *>, GMutablePointer> value_by_input_; - Vector<const DInputSocket *> group_outputs_; + Map<std::pair<DInputSocket, DOutputSocket>, GMutablePointer> value_by_input_; + Vector<DInputSocket> group_outputs_; blender::nodes::MultiFunctionByNode &mf_by_node_; const blender::nodes::DataTypeConversions &conversions_; const PersistentDataHandleMap &handle_map_; @@ -259,8 +265,8 @@ class GeometryNodesEvaluator { Depsgraph *depsgraph_; public: - GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data, - Vector<const DInputSocket *> group_outputs, + GeometryNodesEvaluator(const Map<DOutputSocket, GMutablePointer> &group_input_data, + Vector<DInputSocket> group_outputs, blender::nodes::MultiFunctionByNode &mf_by_node, const PersistentDataHandleMap &handle_map, const Object *self_object, @@ -275,15 +281,15 @@ class GeometryNodesEvaluator { depsgraph_(depsgraph) { for (auto item : group_input_data.items()) { - this->forward_to_inputs(*item.key, item.value); + this->forward_to_inputs(item.key, item.value); } } Vector<GMutablePointer> execute() { Vector<GMutablePointer> results; - for (const DInputSocket *group_output : group_outputs_) { - Vector<GMutablePointer> result = this->get_input_values(*group_output); + for (const DInputSocket &group_output : group_outputs_) { + Vector<GMutablePointer> result = this->get_input_values(group_output); results.append(result[0]); } for (GMutablePointer value : value_by_input_.values()) { @@ -293,62 +299,63 @@ class GeometryNodesEvaluator { } private: - Vector<GMutablePointer> get_input_values(const DInputSocket &socket_to_compute) + Vector<GMutablePointer> get_input_values(const DInputSocket socket_to_compute) { + Vector<DSocket> from_sockets; + socket_to_compute.foreach_origin_socket([&](DSocket socket) { from_sockets.append(socket); }); - Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets(); - Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs(); - const int total_inputs = from_sockets.size() + from_group_inputs.size(); + /* Multi-input sockets contain a vector of inputs. */ + if (socket_to_compute->is_multi_input_socket()) { + Vector<GMutablePointer> values; + for (const DSocket from_socket : from_sockets) { + GMutablePointer value = get_input_from_incoming_link(socket_to_compute, from_socket); + values.append(value); + } + return values; + } - if (total_inputs == 0) { + if (from_sockets.is_empty()) { /* The input is not connected, use the value from the socket itself. */ - return {get_unlinked_input_value(socket_to_compute)}; + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo()); + return {get_unlinked_input_value(socket_to_compute, type)}; } - if (from_group_inputs.size() == 1) { - return {get_unlinked_input_value(socket_to_compute)}; - } + const DSocket from_socket = from_sockets[0]; + GMutablePointer value = this->get_input_from_incoming_link(socket_to_compute, from_socket); + return {value}; + } - /* Multi-input sockets contain a vector of inputs. */ - if (socket_to_compute.is_multi_input_socket()) { - Vector<GMutablePointer> values; - for (const DOutputSocket *from_socket : from_sockets) { - const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( - &socket_to_compute, from_socket); - std::optional<GMutablePointer> value = value_by_input_.pop_try(key); - if (value.has_value()) { - values.append(*value); - } - else { - this->compute_output_and_forward(*from_socket); - GMutablePointer value = value_by_input_.pop(key); - values.append(value); - } + GMutablePointer get_input_from_incoming_link(const DInputSocket socket_to_compute, + const DSocket from_socket) + { + if (from_socket->is_output()) { + const DOutputSocket from_output_socket{from_socket}; + const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(socket_to_compute, + from_output_socket); + std::optional<GMutablePointer> value = value_by_input_.pop_try(key); + if (value.has_value()) { + /* This input has been computed before, return it directly. */ + return {*value}; } - return values; - } - const DOutputSocket &from_socket = *from_sockets[0]; - const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( - &socket_to_compute, &from_socket); - std::optional<GMutablePointer> value = value_by_input_.pop_try(key); - if (value.has_value()) { - /* This input has been computed before, return it directly. */ - return {*value}; + /* Compute the socket now. */ + this->compute_output_and_forward(from_output_socket); + return {value_by_input_.pop(key)}; } - /* Compute the socket now. */ - this->compute_output_and_forward(from_socket); - return {value_by_input_.pop(key)}; + /* Get value from an unlinked input socket. */ + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo()); + const DInputSocket from_input_socket{from_socket}; + return {get_unlinked_input_value(from_input_socket, type)}; } - void compute_output_and_forward(const DOutputSocket &socket_to_compute) + void compute_output_and_forward(const DOutputSocket socket_to_compute) { - const DNode &node = socket_to_compute.node(); + const DNode node{socket_to_compute.context(), &socket_to_compute->node()}; - if (!socket_to_compute.is_available()) { + if (!socket_to_compute->is_available()) { /* If the output is not available, use a default value. */ - const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute.typeinfo()); + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo()); void *buffer = allocator_.allocate(type.size(), type.alignment()); type.copy_to_uninitialized(type.default_value(), buffer); this->forward_to_inputs(socket_to_compute, {type, buffer}); @@ -357,9 +364,9 @@ class GeometryNodesEvaluator { /* Prepare inputs required to execute the node. */ GValueMap<StringRef> node_inputs_map{allocator_}; - for (const DInputSocket *input_socket : node.inputs()) { + for (const InputSocketRef *input_socket : node->inputs()) { if (input_socket->is_available()) { - Vector<GMutablePointer> values = this->get_input_values(*input_socket); + Vector<GMutablePointer> values = this->get_input_values({node.context(), input_socket}); for (int i = 0; i < values.size(); ++i) { /* Values from Multi Input Sockets are stored in input map with the format * <identifier>[<index>]. */ @@ -377,15 +384,15 @@ class GeometryNodesEvaluator { this->execute_node(node, params); /* Forward computed outputs to linked input sockets. */ - for (const DOutputSocket *output_socket : node.outputs()) { + for (const OutputSocketRef *output_socket : node->outputs()) { if (output_socket->is_available()) { GMutablePointer value = node_outputs_map.extract(output_socket->identifier()); - this->forward_to_inputs(*output_socket, value); + this->forward_to_inputs({node.context(), output_socket}, value); } } } - void execute_node(const DNode &node, GeoNodeExecParams params) + void execute_node(const DNode node, GeoNodeExecParams params) { const bNode &bnode = params.node(); @@ -398,7 +405,7 @@ class GeometryNodesEvaluator { } /* Use the multi-function implementation if it exists. */ - const MultiFunction *multi_function = mf_by_node_.lookup_default(&node, nullptr); + const MultiFunction *multi_function = mf_by_node_.lookup_default(node, nullptr); if (multi_function != nullptr) { this->execute_multi_function_node(node, params, *multi_function); return; @@ -408,51 +415,52 @@ class GeometryNodesEvaluator { this->execute_unknown_node(node, params); } - void store_ui_hints(const DNode &node, GeoNodeExecParams params) const + void store_ui_hints(const DNode node, GeoNodeExecParams params) const { - for (const DInputSocket *dsocket : node.inputs()) { - if (!dsocket->is_available()) { + for (const InputSocketRef *socket_ref : node->inputs()) { + if (!socket_ref->is_available()) { continue; } - if (dsocket->bsocket()->type != SOCK_GEOMETRY) { + if (socket_ref->bsocket()->type != SOCK_GEOMETRY) { continue; } - bNodeTree *btree_cow = node.node_ref().tree().btree(); + bNodeTree *btree_cow = node->btree(); bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow); const NodeTreeEvaluationContext context(*self_object_, *modifier_); - const GeometrySet &geometry_set = params.get_input<GeometrySet>(dsocket->identifier()); + const GeometrySet &geometry_set = params.get_input<GeometrySet>(socket_ref->identifier()); const Vector<const GeometryComponent *> components = geometry_set.get_components_for_read(); for (const GeometryComponent *component : components) { - component->attribute_foreach([&](StringRefNull attribute_name, - const AttributeMetaData &UNUSED(meta_data)) { - BKE_nodetree_attribute_hint_add(*btree_original, context, *node.bnode(), attribute_name); - return true; - }); + component->attribute_foreach( + [&](StringRefNull attribute_name, const AttributeMetaData &UNUSED(meta_data)) { + BKE_nodetree_attribute_hint_add( + *btree_original, context, *node->bnode(), attribute_name); + return true; + }); } } } - void execute_multi_function_node(const DNode &node, + void execute_multi_function_node(const DNode node, GeoNodeExecParams params, const MultiFunction &fn) { MFContextBuilder fn_context; MFParamsBuilder fn_params{fn, 1}; Vector<GMutablePointer> input_data; - for (const DInputSocket *dsocket : node.inputs()) { - if (dsocket->is_available()) { - GMutablePointer data = params.extract_input(dsocket->identifier()); + for (const InputSocketRef *socket_ref : node->inputs()) { + if (socket_ref->is_available()) { + GMutablePointer data = params.extract_input(socket_ref->identifier()); fn_params.add_readonly_single_input(GSpan(*data.type(), data.get(), 1)); input_data.append(data); } } Vector<GMutablePointer> output_data; - for (const DOutputSocket *dsocket : node.outputs()) { - if (dsocket->is_available()) { - const CPPType &type = *blender::nodes::socket_cpp_type_get(*dsocket->typeinfo()); + for (const OutputSocketRef *socket_ref : node->outputs()) { + if (socket_ref->is_available()) { + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_ref->typeinfo()); void *buffer = allocator_.allocate(type.size(), type.alignment()); fn_params.add_uninitialized_single_output(GMutableSpan(type, buffer, 1)); output_data.append(GMutablePointer(type, buffer)); @@ -463,19 +471,19 @@ class GeometryNodesEvaluator { value.destruct(); } int output_index = 0; - for (const int i : node.outputs().index_range()) { - if (node.output(i).is_available()) { + for (const int i : node->outputs().index_range()) { + if (node->output(i).is_available()) { GMutablePointer value = output_data[output_index]; - params.set_output_by_move(node.output(i).identifier(), value); + params.set_output_by_move(node->output(i).identifier(), value); value.destruct(); output_index++; } } } - void execute_unknown_node(const DNode &node, GeoNodeExecParams params) + void execute_unknown_node(const DNode node, GeoNodeExecParams params) { - for (const DOutputSocket *socket : node.outputs()) { + for (const OutputSocketRef *socket : node->outputs()) { if (socket->is_available()) { const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); params.set_output_by_copy(socket->identifier(), {type, type.default_value()}); @@ -483,17 +491,18 @@ class GeometryNodesEvaluator { } } - void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward) + void forward_to_inputs(const DOutputSocket from_socket, GMutablePointer value_to_forward) { /* For all sockets that are linked with the from_socket push the value to their node. */ - Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets(); + Vector<DInputSocket> to_sockets_all; + from_socket.foreach_target_socket( + [&](DInputSocket to_socket) { to_sockets_all.append(to_socket); }); const CPPType &from_type = *value_to_forward.type(); - Vector<const DInputSocket *> to_sockets_same_type; - for (const DInputSocket *to_socket : to_sockets_all) { + Vector<DInputSocket> to_sockets_same_type; + for (const DInputSocket &to_socket : to_sockets_all) { const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo()); - const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( - to_socket, &from_socket); + const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket); if (from_type == to_type) { to_sockets_same_type.append(to_socket); } @@ -515,23 +524,21 @@ class GeometryNodesEvaluator { } else if (to_sockets_same_type.size() == 1) { /* This value is only used on one input socket, no need to copy it. */ - const DInputSocket *to_socket = to_sockets_same_type[0]; - const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( - to_socket, &from_socket); + const DInputSocket to_socket = to_sockets_same_type[0]; + const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket); add_value_to_input_socket(key, value_to_forward); } else { /* Multiple inputs use the value, make a copy for every input except for one. */ - const DInputSocket *first_to_socket = to_sockets_same_type[0]; - Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1); + const DInputSocket first_to_socket = to_sockets_same_type[0]; + Span<DInputSocket> other_to_sockets = to_sockets_same_type.as_span().drop_front(1); const CPPType &type = *value_to_forward.type(); - const std::pair<const DInputSocket *, const DOutputSocket *> first_key = std::make_pair( - first_to_socket, &from_socket); + const std::pair<DInputSocket, DOutputSocket> first_key = std::make_pair(first_to_socket, + from_socket); add_value_to_input_socket(first_key, value_to_forward); - for (const DInputSocket *to_socket : other_to_sockets) { - const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( - to_socket, &from_socket); + for (const DInputSocket &to_socket : other_to_sockets) { + const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket); void *buffer = allocator_.allocate(type.size(), type.alignment()); type.copy_to_uninitialized(value_to_forward.get(), buffer); add_value_to_input_socket(key, GMutablePointer{type, buffer}); @@ -539,22 +546,17 @@ class GeometryNodesEvaluator { } } - void add_value_to_input_socket(const std::pair<const DInputSocket *, const DOutputSocket *> key, + void add_value_to_input_socket(const std::pair<DInputSocket, DOutputSocket> key, GMutablePointer value) { value_by_input_.add_new(key, value); } - GMutablePointer get_unlinked_input_value(const DInputSocket &socket) + GMutablePointer get_unlinked_input_value(const DInputSocket &socket, + const CPPType &required_type) { - bNodeSocket *bsocket; - if (socket.linked_group_inputs().size() == 0) { - bsocket = socket.bsocket(); - } - else { - bsocket = socket.linked_group_inputs()[0]->bsocket(); - } - const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket.typeinfo()); + bNodeSocket *bsocket = socket->bsocket(); + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); void *buffer = allocator_.allocate(type.size(), type.alignment()); if (bsocket->type == SOCK_OBJECT) { @@ -571,7 +573,19 @@ class GeometryNodesEvaluator { blender::nodes::socket_cpp_value_get(*bsocket, buffer); } - return {type, buffer}; + if (type == required_type) { + return {type, buffer}; + } + if (conversions_.is_convertible(type, required_type)) { + void *converted_buffer = allocator_.allocate(required_type.size(), + required_type.alignment()); + conversions_.convert(type, required_type, buffer, converted_buffer); + type.destruct(buffer); + return {required_type, converted_buffer}; + } + void *default_buffer = allocator_.allocate(required_type.size(), required_type.alignment()); + type.copy_to_uninitialized(type.default_value(), default_buffer); + return {required_type, default_buffer}; } }; @@ -980,7 +994,7 @@ static void fill_data_handle_map(const NodesModifierSettings &settings, { Set<ID *> used_ids; find_used_ids_from_settings(settings, used_ids); - find_used_ids_from_nodes(*tree.btree(), used_ids); + find_used_ids_from_nodes(*tree.root_context().tree().btree(), used_ids); int current_handle = 0; for (ID *id : used_ids) { @@ -1008,8 +1022,8 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree * often than necessary. It's going to be replaced soon. */ static GeometrySet compute_geometry(const DerivedNodeTree &tree, - Span<const DOutputSocket *> group_input_sockets, - const DInputSocket &socket_to_compute, + Span<const OutputSocketRef *> group_input_sockets, + const InputSocketRef &socket_to_compute, GeometrySet input_geometry_set, NodesModifierData *nmd, const ModifierEvalContext *ctx) @@ -1021,32 +1035,33 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, PersistentDataHandleMap handle_map; fill_data_handle_map(nmd->settings, tree, handle_map); - Map<const DOutputSocket *, GMutablePointer> group_inputs; + Map<DOutputSocket, GMutablePointer> group_inputs; + const DTreeContext *root_context = &tree.root_context(); if (group_input_sockets.size() > 0) { - Span<const DOutputSocket *> remaining_input_sockets = group_input_sockets; + Span<const OutputSocketRef *> remaining_input_sockets = group_input_sockets; /* If the group expects a geometry as first input, use the geometry that has been passed to * modifier. */ - const DOutputSocket *first_input_socket = group_input_sockets[0]; + const OutputSocketRef *first_input_socket = group_input_sockets[0]; if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) { GeometrySet *geometry_set_in = allocator.construct<GeometrySet>( std::move(input_geometry_set)); - group_inputs.add_new(first_input_socket, geometry_set_in); + group_inputs.add_new({root_context, first_input_socket}, geometry_set_in); remaining_input_sockets = remaining_input_sockets.drop_front(1); } /* Initialize remaining group inputs. */ - for (const DOutputSocket *socket : remaining_input_sockets) { + for (const OutputSocketRef *socket : remaining_input_sockets) { const CPPType &cpp_type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment()); initialize_group_input(*nmd, handle_map, *socket->bsocket(), cpp_type, value_in); - group_inputs.add_new(socket, {cpp_type, value_in}); + group_inputs.add_new({root_context, socket}, {cpp_type, value_in}); } } - Vector<const DInputSocket *> group_outputs; - group_outputs.append(&socket_to_compute); + Vector<DInputSocket> group_outputs; + group_outputs.append({root_context, &socket_to_compute}); GeometryNodesEvaluator evaluator{group_inputs, group_outputs, @@ -1121,16 +1136,17 @@ static void modifyGeometry(ModifierData *md, check_property_socket_sync(ctx->object, md); - blender::nodes::NodeTreeRefMap tree_refs; - DerivedNodeTree tree{nmd->node_group, tree_refs}; + NodeTreeRefMap tree_refs; + DerivedNodeTree tree{*nmd->node_group, tree_refs}; if (tree.has_link_cycles()) { BKE_modifier_set_error(ctx->object, md, "Node group has cycles"); return; } - Span<const DNode *> input_nodes = tree.nodes_by_type("NodeGroupInput"); - Span<const DNode *> output_nodes = tree.nodes_by_type("NodeGroupOutput"); + const NodeTreeRef &root_tree_ref = tree.root_context().tree(); + Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); + Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); if (input_nodes.size() > 1) { return; @@ -1139,16 +1155,18 @@ static void modifyGeometry(ModifierData *md, return; } - Span<const DOutputSocket *> group_inputs = (input_nodes.size() == 1) ? - input_nodes[0]->outputs().drop_back(1) : - Span<const DOutputSocket *>{}; - Span<const DInputSocket *> group_outputs = output_nodes[0]->inputs().drop_back(1); + Span<const OutputSocketRef *> group_inputs; + if (input_nodes.size() == 1) { + group_inputs = input_nodes[0]->outputs().drop_back(1); + } + + Span<const InputSocketRef *> group_outputs = output_nodes[0]->inputs().drop_back(1); if (group_outputs.size() == 0) { return; } - const DInputSocket *group_output = group_outputs[0]; + const InputSocketRef *group_output = group_outputs[0]; if (group_output->idname() != "NodeSocketGeometry") { return; } @@ -1348,7 +1366,7 @@ ModifierTypeInfo modifierType_Nodes = { /* dependsOnTime */ nullptr, /* dependsOnNormals */ nullptr, /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ nullptr, + /* foreachTexLink */ foreachTexLink, /* freeRuntimeData */ nullptr, /* panelRegister */ panelRegister, /* blendWrite */ blendWrite, diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 8122f4617c1..a6b83ed60ea 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -135,10 +135,11 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, return mesh; } - /* make sure there are UV Maps available */ - + /* Create a new layer if no UV Maps are available + * (e.g. if a preceding modifier could not preserve it). */ if (!CustomData_has_layer(&mesh->ldata, CD_MLOOPUV)) { - return mesh; + CustomData_add_layer_named( + &mesh->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, mesh->totloop, umd->uvlayer_name); } /* make sure we're using an existing layer */ diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 8c5081555fc..e21959d839c 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -62,7 +62,7 @@ set(SRC composite/nodes/node_composite_composite.c composite/nodes/node_composite_cornerpin.c composite/nodes/node_composite_crop.c - composite/nodes/node_composite_cryptomatte.c + composite/nodes/node_composite_cryptomatte.cc composite/nodes/node_composite_curves.c composite/nodes/node_composite_defocus.c composite/nodes/node_composite_denoise.c @@ -259,7 +259,7 @@ set(SRC shader/nodes/node_shader_vectTransform.c shader/nodes/node_shader_vector_displacement.c shader/nodes/node_shader_vector_math.cc - shader/nodes/node_shader_vector_rotate.c + shader/nodes/node_shader_vector_rotate.cc shader/nodes/node_shader_vertex_color.c shader/nodes/node_shader_volume_absorption.c shader/nodes/node_shader_volume_info.c diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index 62affe43895..f1dbb2caf29 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -19,546 +19,360 @@ /** \file * \ingroup nodes * - * DerivedNodeTree provides a flattened view on a bNodeTree, i.e. node groups are inlined. It - * builds on top of NodeTreeRef and supports similar queries efficiently. - * - * Every inlined node remembers its path to the parent ("call stack"). - * - * Unlinked group node inputs are handled separately from other sockets. - * - * There is a dot graph exporter for debugging purposes. + * DerivedNodeTree builds on top of NodeTreeRef and makes working with (nested) node groups more + * convenient and safe. It does so by pairing nodes and sockets with a context. The context + * contains information about the current "instance" of the node or socket. A node might be + * "instanced" multiple times when it is in a node group that is used multiple times. */ -#include "NOD_node_tree_ref.hh" - +#include "BLI_function_ref.hh" #include "BLI_vector_set.hh" +#include "NOD_node_tree_ref.hh" + namespace blender::nodes { +class DTreeContext; +class DerivedNodeTree; + +class DNode; class DSocket; class DInputSocket; class DOutputSocket; -class DNode; -class DParentNode; -class DGroupInput; -class DerivedNodeTree; -class DSocket : NonCopyable, NonMovable { - protected: - DNode *node_; - const SocketRef *socket_ref_; - int id_; +/** + * The context attached to every node or socket in a derived node tree. It can be used to determine + * the place of a node in a hierarchy of node groups. + * + * Contexts are organized in a tree data structure to avoid having to store the entire path to the + * root node group for every node/socket. + */ +class DTreeContext { + private: + /* Null when this context is for the root node group. Otherwise it points to the context one + * level up. */ + DTreeContext *parent_context_; + /* Null when this context is for the root node group. Otherwise it points to the group node in + * the parent node group that contains this context. */ + const NodeRef *parent_node_; + /* The current node tree. */ + const NodeTreeRef *tree_; + /* All the children contexts of this context. */ + Map<const NodeRef *, DTreeContext *> children_; friend DerivedNodeTree; public: - const DNode &node() const; - - int id() const; - int index() const; - - bool is_input() const; - bool is_output() const; - - const DSocket &as_base() const; - const DInputSocket &as_input() const; - const DOutputSocket &as_output() const; - - PointerRNA *rna() const; - StringRefNull idname() const; - StringRefNull name() const; - StringRefNull identifier() const; - bNodeSocketType *typeinfo() const; - - const SocketRef &socket_ref() const; - bNodeSocket *bsocket() const; - - bool is_available() const; + const NodeTreeRef &tree() const; + const DTreeContext *parent_context() const; + const NodeRef *parent_node() const; + const DTreeContext *child_context(const NodeRef &node) const; + bool is_root() const; }; -class DInputSocket : public DSocket { +/* A (nullable) reference to a node and the context it is in. It is unique within an entire nested + * node group hierarchy. This type is small and can be passed around by value. */ +class DNode { private: - Vector<DOutputSocket *> linked_sockets_; - Vector<DGroupInput *> linked_group_inputs_; - bool is_multi_input_socket_; - - friend DerivedNodeTree; + const DTreeContext *context_ = nullptr; + const NodeRef *node_ref_ = nullptr; public: - const InputSocketRef &socket_ref() const; - - Span<const DOutputSocket *> linked_sockets() const; - Span<const DGroupInput *> linked_group_inputs() const; - - bool is_linked() const; - bool is_multi_input_socket() const; -}; + DNode() = default; + DNode(const DTreeContext *context, const NodeRef *node); -class DOutputSocket : public DSocket { - private: - Vector<DInputSocket *> linked_sockets_; + const DTreeContext *context() const; + const NodeRef *node_ref() const; + const NodeRef *operator->() const; - friend DerivedNodeTree; + friend bool operator==(const DNode &a, const DNode &b); + friend bool operator!=(const DNode &a, const DNode &b); + operator bool() const; - public: - const OutputSocketRef &socket_ref() const; - Span<const DInputSocket *> linked_sockets() const; + uint64_t hash() const; }; -class DGroupInput : NonCopyable, NonMovable { - private: - const InputSocketRef *socket_ref_; - DParentNode *parent_; - Vector<DInputSocket *> linked_sockets_; - int id_; - - friend DerivedNodeTree; +/* A (nullable) reference to a socket and the context it is in. It is unique within an entire + * nested node group hierarchy. This type is small and can be passed around by value. + * + * A #DSocket can represent an input or an output socket. If the type of a socket is known at + * compile time is is preferable to use #DInputSocket or #DOutputSocket instead. */ +class DSocket { + protected: + const DTreeContext *context_ = nullptr; + const SocketRef *socket_ref_ = nullptr; public: - const InputSocketRef &socket_ref() const; - bNodeSocket *bsocket() const; - const DParentNode *parent() const; - Span<const DInputSocket *> linked_sockets() const; - int id() const; - StringRefNull name() const; -}; - -class DNode : NonCopyable, NonMovable { - private: - const NodeRef *node_ref_; - DParentNode *parent_; + DSocket() = default; + DSocket(const DTreeContext *context, const SocketRef *socket); + DSocket(const DInputSocket &input_socket); + DSocket(const DOutputSocket &output_socket); - Span<DInputSocket *> inputs_; - Span<DOutputSocket *> outputs_; + const DTreeContext *context() const; + const SocketRef *socket_ref() const; + const SocketRef *operator->() const; - int id_; + friend bool operator==(const DSocket &a, const DSocket &b); + friend bool operator!=(const DSocket &a, const DSocket &b); + operator bool() const; - friend DerivedNodeTree; + uint64_t hash() const; +}; +/* A (nullable) reference to an input socket and the context it is in. */ +class DInputSocket : public DSocket { public: - const NodeRef &node_ref() const; - const DParentNode *parent() const; - - Span<const DInputSocket *> inputs() const; - Span<const DOutputSocket *> outputs() const; - - const DInputSocket &input(int index) const; - const DOutputSocket &output(int index) const; - - const DInputSocket &input(int index, StringRef expected_name) const; - const DOutputSocket &output(int index, StringRef expected_name) const; + DInputSocket() = default; + DInputSocket(const DTreeContext *context, const InputSocketRef *socket); + explicit DInputSocket(const DSocket &base_socket); - int id() const; + const InputSocketRef *socket_ref() const; + const InputSocketRef *operator->() const; - PointerRNA *rna() const; - StringRefNull idname() const; - StringRefNull name() const; - bNode *bnode() const; - bNodeType *typeinfo() const; + DOutputSocket get_corresponding_group_node_output() const; + Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const; - private: - void destruct_with_sockets(); + void foreach_origin_socket(FunctionRef<void(DSocket)> callback) const; }; -class DParentNode : NonCopyable, NonMovable { - private: - const NodeRef *node_ref_; - DParentNode *parent_; - int id_; +/* A (nullable) reference to an output socket and the context it is in. */ +class DOutputSocket : public DSocket { + public: + DOutputSocket() = default; + DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket); + explicit DOutputSocket(const DSocket &base_socket); - friend DerivedNodeTree; + const OutputSocketRef *socket_ref() const; + const OutputSocketRef *operator->() const; - public: - const DParentNode *parent() const; - const NodeRef &node_ref() const; - int id() const; -}; + DInputSocket get_corresponding_group_node_input() const; + DInputSocket get_active_corresponding_group_output_socket() const; -using NodeTreeRefMap = Map<bNodeTree *, std::unique_ptr<const NodeTreeRef>>; + void foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const; +}; -class DerivedNodeTree : NonCopyable, NonMovable { +class DerivedNodeTree { private: LinearAllocator<> allocator_; - Vector<DNode *> nodes_by_id_; - Vector<DGroupInput *> group_inputs_; - Vector<DParentNode *> parent_nodes_; - - Vector<DSocket *> sockets_by_id_; - Vector<DInputSocket *> input_sockets_; - Vector<DOutputSocket *> output_sockets_; - - MultiValueMap<const bNodeType *, DNode *> nodes_by_type_; + DTreeContext *root_context_; VectorSet<const NodeTreeRef *> used_node_tree_refs_; - bNodeTree *btree_; public: - DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs); + DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs); ~DerivedNodeTree(); - bNodeTree *btree() const; - - Span<const DNode *> nodes() const; - Span<const DNode *> nodes_by_type(StringRefNull idname) const; - Span<const DNode *> nodes_by_type(const bNodeType *nodetype) const; - - Span<const DSocket *> sockets() const; - Span<const DInputSocket *> input_sockets() const; - Span<const DOutputSocket *> output_sockets() const; - - Span<const DGroupInput *> group_inputs() const; - + const DTreeContext &root_context() const; Span<const NodeTreeRef *> used_node_tree_refs() const; bool has_link_cycles() const; - - std::string to_dot() const; + void foreach_node(FunctionRef<void(DNode)> callback) const; private: - /* Utility functions used during construction. */ - void insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref, - DParentNode *parent, - Vector<DNode *> &all_nodes); - DNode &create_node(const NodeRef &node_ref, - DParentNode *parent, - MutableSpan<DSocket *> r_sockets_map); - void expand_groups(Vector<DNode *> &all_nodes, - Vector<DGroupInput *> &all_group_inputs, - Vector<DParentNode *> &all_parent_nodes, - NodeTreeRefMap &node_tree_refs); - void expand_group_node(DNode &group_node, - Vector<DNode *> &all_nodes, - Vector<DGroupInput *> &all_group_inputs, - Vector<DParentNode *> &all_parent_nodes, - NodeTreeRefMap &node_tree_refs); - void create_group_inputs_for_unlinked_inputs(DNode &node, - Vector<DGroupInput *> &all_group_inputs); - void relink_group_inputs(const NodeTreeRef &group_ref, - Span<DNode *> nodes_by_id, - DNode &group_node); - void relink_group_outputs(const NodeTreeRef &group_ref, - Span<DNode *> nodes_by_id, - DNode &group_node); - void remove_expanded_group_interfaces(Vector<DNode *> &all_nodes); - void remove_unused_group_inputs(Vector<DGroupInput *> &all_group_inputs); - void relink_and_remove_muted_nodes(Vector<DNode *> &all_nodes); - void relink_muted_node(DNode &muted_node); - void store_in_this_and_init_ids(Vector<DNode *> &&all_nodes, - Vector<DGroupInput *> &&all_group_inputs, - Vector<DParentNode *> &&all_parent_nodes); + DTreeContext &construct_context_recursively(DTreeContext *parent_context, + const NodeRef *parent_node, + bNodeTree &btree, + NodeTreeRefMap &node_tree_refs); + void destruct_context_recursively(DTreeContext *context); + + void foreach_node_in_context_recursive(const DTreeContext &context, + FunctionRef<void(DNode)> callback) const; }; namespace derived_node_tree_types { +using namespace node_tree_ref_types; using nodes::DerivedNodeTree; -using nodes::DGroupInput; using nodes::DInputSocket; using nodes::DNode; using nodes::DOutputSocket; -using nodes::DParentNode; -}; // namespace derived_node_tree_types +using nodes::DSocket; +using nodes::DTreeContext; +} // namespace derived_node_tree_types /* -------------------------------------------------------------------- - * DSocket inline methods. + * DTreeContext inline methods. */ -inline const DNode &DSocket::node() const -{ - return *node_; -} - -inline int DSocket::id() const +inline const NodeTreeRef &DTreeContext::tree() const { - return id_; + return *tree_; } -inline int DSocket::index() const +inline const DTreeContext *DTreeContext::parent_context() const { - return socket_ref_->index(); + return parent_context_; } -inline bool DSocket::is_input() const +inline const NodeRef *DTreeContext::parent_node() const { - return socket_ref_->is_input(); + return parent_node_; } -inline bool DSocket::is_output() const +inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) const { - return socket_ref_->is_output(); + return children_.lookup_default(&node, nullptr); } -inline const DSocket &DSocket::as_base() const +inline bool DTreeContext::is_root() const { - return *this; + return parent_context_ == nullptr; } -inline const DInputSocket &DSocket::as_input() const -{ - return static_cast<const DInputSocket &>(*this); -} - -inline const DOutputSocket &DSocket::as_output() const -{ - return static_cast<const DOutputSocket &>(*this); -} +/* -------------------------------------------------------------------- + * DNode inline methods. + */ -inline PointerRNA *DSocket::rna() const +inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref) + : context_(context), node_ref_(node_ref) { - return socket_ref_->rna(); + BLI_assert(node_ref == nullptr || &node_ref->tree() == &context->tree()); } -inline StringRefNull DSocket::idname() const +inline const DTreeContext *DNode::context() const { - return socket_ref_->idname(); + return context_; } -inline StringRefNull DSocket::name() const +inline const NodeRef *DNode::node_ref() const { - return socket_ref_->name(); + return node_ref_; } -inline StringRefNull DSocket::identifier() const +inline bool operator==(const DNode &a, const DNode &b) { - return socket_ref_->identifier(); + return a.context_ == b.context_ && a.node_ref_ == b.node_ref_; } -inline bNodeSocketType *DSocket::typeinfo() const +inline bool operator!=(const DNode &a, const DNode &b) { - return socket_ref_->bsocket()->typeinfo; + return !(a == b); } -inline const SocketRef &DSocket::socket_ref() const +inline DNode::operator bool() const { - return *socket_ref_; + return node_ref_ != nullptr; } -inline bNodeSocket *DSocket::bsocket() const +inline const NodeRef *DNode::operator->() const { - return socket_ref_->bsocket(); + return node_ref_; } -inline bool DSocket::is_available() const +inline uint64_t DNode::hash() const { - return (socket_ref_->bsocket()->flag & SOCK_UNAVAIL) == 0; + return DefaultHash<const DTreeContext *>{}(context_) ^ DefaultHash<const NodeRef *>{}(node_ref_); } /* -------------------------------------------------------------------- - * DInputSocket inline methods. + * DSocket inline methods. */ -inline const InputSocketRef &DInputSocket::socket_ref() const +inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref) + : context_(context), socket_ref_(socket_ref) { - return socket_ref_->as_input(); + BLI_assert(socket_ref == nullptr || &socket_ref->tree() == &context->tree()); } -inline Span<const DOutputSocket *> DInputSocket::linked_sockets() const +inline DSocket::DSocket(const DInputSocket &input_socket) + : DSocket(input_socket.context_, input_socket.socket_ref_) { - return linked_sockets_; } -inline Span<const DGroupInput *> DInputSocket::linked_group_inputs() const +inline DSocket::DSocket(const DOutputSocket &output_socket) + : DSocket(output_socket.context_, output_socket.socket_ref_) { - return linked_group_inputs_; } -inline bool DInputSocket::is_linked() const +inline const DTreeContext *DSocket::context() const { - return linked_sockets_.size() > 0 || linked_group_inputs_.size() > 0; + return context_; } -inline bool DInputSocket::is_multi_input_socket() const +inline const SocketRef *DSocket::socket_ref() const { - return is_multi_input_socket_; + return socket_ref_; } -/* -------------------------------------------------------------------- - * DOutputSocket inline methods. - */ - -inline const OutputSocketRef &DOutputSocket::socket_ref() const +inline bool operator==(const DSocket &a, const DSocket &b) { - return socket_ref_->as_output(); + return a.context_ == b.context_ && a.socket_ref_ == b.socket_ref_; } -inline Span<const DInputSocket *> DOutputSocket::linked_sockets() const +inline bool operator!=(const DSocket &a, const DSocket &b) { - return linked_sockets_; + return !(a == b); } -/* -------------------------------------------------------------------- - * DGroupInput inline methods. - */ - -inline const InputSocketRef &DGroupInput::socket_ref() const +inline DSocket::operator bool() const { - return *socket_ref_; + return socket_ref_ != nullptr; } -inline bNodeSocket *DGroupInput::bsocket() const +inline const SocketRef *DSocket::operator->() const { - return socket_ref_->bsocket(); + return socket_ref_; } -inline const DParentNode *DGroupInput::parent() const +inline uint64_t DSocket::hash() const { - return parent_; -} - -inline Span<const DInputSocket *> DGroupInput::linked_sockets() const -{ - return linked_sockets_; -} - -inline int DGroupInput::id() const -{ - return id_; -} - -inline StringRefNull DGroupInput::name() const -{ - return socket_ref_->name(); + return DefaultHash<const DTreeContext *>{}(context_) ^ + DefaultHash<const SocketRef *>{}(socket_ref_); } /* -------------------------------------------------------------------- - * DNode inline methods. + * DInputSocket inline methods. */ -inline const NodeRef &DNode::node_ref() const -{ - return *node_ref_; -} - -inline const DParentNode *DNode::parent() const -{ - return parent_; -} - -inline Span<const DInputSocket *> DNode::inputs() const -{ - return inputs_; -} - -inline Span<const DOutputSocket *> DNode::outputs() const +inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref) + : DSocket(context, socket_ref) { - return outputs_; } -inline const DInputSocket &DNode::input(int index) const +inline DInputSocket::DInputSocket(const DSocket &base_socket) : DSocket(base_socket) { - return *inputs_[index]; + BLI_assert(base_socket->is_input()); } -inline const DOutputSocket &DNode::output(int index) const +inline const InputSocketRef *DInputSocket::socket_ref() const { - return *outputs_[index]; + return (const InputSocketRef *)socket_ref_; } -inline const DInputSocket &DNode::input(int index, StringRef expected_name) const +inline const InputSocketRef *DInputSocket::operator->() const { - const DInputSocket &socket = *inputs_[index]; - BLI_assert(socket.name() == expected_name); - UNUSED_VARS_NDEBUG(expected_name); - return socket; + return (const InputSocketRef *)socket_ref_; } -inline const DOutputSocket &DNode::output(int index, StringRef expected_name) const -{ - const DOutputSocket &socket = *outputs_[index]; - BLI_assert(socket.name() == expected_name); - UNUSED_VARS_NDEBUG(expected_name); - return socket; -} - -inline int DNode::id() const -{ - return id_; -} - -inline PointerRNA *DNode::rna() const -{ - return node_ref_->rna(); -} - -inline StringRefNull DNode::idname() const -{ - return node_ref_->idname(); -} - -inline StringRefNull DNode::name() const -{ - return node_ref_->name(); -} - -inline bNode *DNode::bnode() const -{ - return node_ref_->bnode(); -} +/* -------------------------------------------------------------------- + * DOutputSocket inline methods. + */ -inline bNodeType *DNode::typeinfo() const +inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref) + : DSocket(context, socket_ref) { - return node_ref_->bnode()->typeinfo; } -/* -------------------------------------------------------------------- - * DParentNode inline methods. - */ - -inline const DParentNode *DParentNode::parent() const +inline DOutputSocket::DOutputSocket(const DSocket &base_socket) : DSocket(base_socket) { - return parent_; + BLI_assert(base_socket->is_output()); } -inline const NodeRef &DParentNode::node_ref() const +inline const OutputSocketRef *DOutputSocket::socket_ref() const { - return *node_ref_; + return (const OutputSocketRef *)socket_ref_; } -inline int DParentNode::id() const +inline const OutputSocketRef *DOutputSocket::operator->() const { - return id_; + return (const OutputSocketRef *)socket_ref_; } /* -------------------------------------------------------------------- * DerivedNodeTree inline methods. */ -inline bNodeTree *DerivedNodeTree::btree() const -{ - return btree_; -} - -inline Span<const DNode *> DerivedNodeTree::nodes() const -{ - return nodes_by_id_; -} - -inline Span<const DNode *> DerivedNodeTree::nodes_by_type(StringRefNull idname) const -{ - const bNodeType *nodetype = nodeTypeFind(idname.c_str()); - return this->nodes_by_type(nodetype); -} - -inline Span<const DNode *> DerivedNodeTree::nodes_by_type(const bNodeType *nodetype) const -{ - return nodes_by_type_.lookup(nodetype); -} - -inline Span<const DSocket *> DerivedNodeTree::sockets() const -{ - return sockets_by_id_; -} - -inline Span<const DInputSocket *> DerivedNodeTree::input_sockets() const -{ - return input_sockets_; -} - -inline Span<const DOutputSocket *> DerivedNodeTree::output_sockets() const -{ - return output_sockets_; -} - -inline Span<const DGroupInput *> DerivedNodeTree::group_inputs() const +inline const DTreeContext &DerivedNodeTree::root_context() const { - return group_inputs_; + return *root_context_; } inline Span<const NodeTreeRef *> DerivedNodeTree::used_node_tree_refs() const diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index e648d77337b..1772f92c4b6 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -59,7 +59,7 @@ using fn::GValueMap; class GeoNodeExecParams { private: - const DNode &node_; + const DNode node_; GValueMap<StringRef> &input_values_; GValueMap<StringRef> &output_values_; const PersistentDataHandleMap &handle_map_; @@ -68,7 +68,7 @@ class GeoNodeExecParams { Depsgraph *depsgraph_; public: - GeoNodeExecParams(const DNode &node, + GeoNodeExecParams(const DNode node, GValueMap<StringRef> &input_values, GValueMap<StringRef> &output_values, const PersistentDataHandleMap &handle_map, @@ -182,7 +182,7 @@ class GeoNodeExecParams { */ const bNode &node() const { - return *node_.bnode(); + return *node_->bnode(); } const PersistentDataHandleMap &handle_map() const diff --git a/source/blender/nodes/NOD_node_tree_multi_function.hh b/source/blender/nodes/NOD_node_tree_multi_function.hh index 552ef5509fa..df31ee18369 100644 --- a/source/blender/nodes/NOD_node_tree_multi_function.hh +++ b/source/blender/nodes/NOD_node_tree_multi_function.hh @@ -28,14 +28,15 @@ #include "NOD_derived_node_tree.hh" #include "NOD_type_callbacks.hh" +#include "BLI_multi_value_map.hh" #include "BLI_resource_collector.hh" namespace blender::nodes { /** - * A MFNetworkTreeMap maps various components of a DerivedNodeTree to components of a - * fn::MFNetwork. This is necessary for further processing of a multi-function network that has - * been generated from a node tree. + * A MFNetworkTreeMap maps various components of a node tree to components of a fn::MFNetwork. This + * is necessary for further processing of a multi-function network that has been generated from a + * node tree. */ class MFNetworkTreeMap { private: @@ -47,15 +48,11 @@ class MFNetworkTreeMap { */ const DerivedNodeTree &tree_; fn::MFNetwork &network_; - Array<Vector<fn::MFSocket *, 1>> sockets_by_dsocket_id_; - Array<fn::MFOutputSocket *> socket_by_group_input_id_; + MultiValueMap<DSocket, fn::MFSocket *> sockets_by_dsocket_; public: MFNetworkTreeMap(const DerivedNodeTree &tree, fn::MFNetwork &network) - : tree_(tree), - network_(network), - sockets_by_dsocket_id_(tree.sockets().size()), - socket_by_group_input_id_(tree.group_inputs().size(), nullptr) + : tree_(tree), network_(network) { } @@ -76,96 +73,95 @@ class MFNetworkTreeMap { void add(const DSocket &dsocket, fn::MFSocket &socket) { - BLI_assert(dsocket.is_input() == socket.is_input()); - BLI_assert(dsocket.is_input() || sockets_by_dsocket_id_[dsocket.id()].size() == 0); - sockets_by_dsocket_id_[dsocket.id()].append(&socket); + BLI_assert(dsocket->is_input() == socket.is_input()); + BLI_assert(dsocket->is_input() || sockets_by_dsocket_.lookup(dsocket).is_empty()); + sockets_by_dsocket_.add(dsocket, &socket); } void add(const DInputSocket &dsocket, fn::MFInputSocket &socket) { - sockets_by_dsocket_id_[dsocket.id()].append(&socket); + sockets_by_dsocket_.add(dsocket, &socket); } void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket) { /* There can be at most one matching output socket. */ - BLI_assert(sockets_by_dsocket_id_[dsocket.id()].size() == 0); - sockets_by_dsocket_id_[dsocket.id()].append(&socket); + BLI_assert(sockets_by_dsocket_.lookup(dsocket).is_empty()); + sockets_by_dsocket_.add(dsocket, &socket); } - void add(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets) + void add(const DTreeContext &context, + Span<const InputSocketRef *> dsockets, + Span<fn::MFInputSocket *> sockets) { assert_same_size(dsockets, sockets); for (int i : dsockets.index_range()) { - this->add(*dsockets[i], *sockets[i]); + this->add(DInputSocket(&context, dsockets[i]), *sockets[i]); } } - void add(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets) + void add(const DTreeContext &context, + Span<const OutputSocketRef *> dsockets, + Span<fn::MFOutputSocket *> sockets) { assert_same_size(dsockets, sockets); for (int i : dsockets.index_range()) { - this->add(*dsockets[i], *sockets[i]); + this->add(DOutputSocket(&context, dsockets[i]), *sockets[i]); } } - void add(const DGroupInput &group_input, fn::MFOutputSocket &socket) - { - BLI_assert(socket_by_group_input_id_[group_input.id()] == nullptr); - socket_by_group_input_id_[group_input.id()] = &socket; - } - void add_try_match(const DNode &dnode, fn::MFNode &node) { - this->add_try_match(dnode.inputs().cast<const DSocket *>(), + this->add_try_match(*dnode.context(), + dnode->inputs().cast<const SocketRef *>(), node.inputs().cast<fn::MFSocket *>()); - this->add_try_match(dnode.outputs().cast<const DSocket *>(), + this->add_try_match(*dnode.context(), + dnode->outputs().cast<const SocketRef *>(), node.outputs().cast<fn::MFSocket *>()); } - void add_try_match(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets) + void add_try_match(const DTreeContext &context, + Span<const InputSocketRef *> dsockets, + Span<fn::MFInputSocket *> sockets) { - this->add_try_match(dsockets.cast<const DSocket *>(), sockets.cast<fn::MFSocket *>()); + this->add_try_match( + context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>()); } - void add_try_match(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets) + void add_try_match(const DTreeContext &context, + Span<const OutputSocketRef *> dsockets, + Span<fn::MFOutputSocket *> sockets) { - this->add_try_match(dsockets.cast<const DSocket *>(), sockets.cast<fn::MFSocket *>()); + this->add_try_match( + context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>()); } - void add_try_match(Span<const DSocket *> dsockets, Span<fn::MFSocket *> sockets) + void add_try_match(const DTreeContext &context, + Span<const SocketRef *> dsockets, + Span<fn::MFSocket *> sockets) { int used_sockets = 0; - for (const DSocket *dsocket : dsockets) { + for (const SocketRef *dsocket : dsockets) { if (!dsocket->is_available()) { continue; } - if (!socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) { + if (!socket_is_mf_data_socket(*dsocket->typeinfo())) { continue; } fn::MFSocket *socket = sockets[used_sockets]; - this->add(*dsocket, *socket); + this->add(DSocket(&context, dsocket), *socket); used_sockets++; } } - fn::MFOutputSocket &lookup(const DGroupInput &group_input) - { - fn::MFOutputSocket *socket = socket_by_group_input_id_[group_input.id()]; - BLI_assert(socket != nullptr); - return *socket; - } - fn::MFOutputSocket &lookup(const DOutputSocket &dsocket) { - auto &sockets = sockets_by_dsocket_id_[dsocket.id()]; - BLI_assert(sockets.size() == 1); - return sockets[0]->as_output(); + return sockets_by_dsocket_.lookup(dsocket)[0]->as_output(); } Span<fn::MFInputSocket *> lookup(const DInputSocket &dsocket) { - return sockets_by_dsocket_id_[dsocket.id()].as_span().cast<fn::MFInputSocket *>(); + return sockets_by_dsocket_.lookup(dsocket).cast<fn::MFInputSocket *>(); } fn::MFInputSocket &lookup_dummy(const DInputSocket &dsocket) @@ -186,7 +182,7 @@ class MFNetworkTreeMap { bool is_mapped(const DSocket &dsocket) const { - return sockets_by_dsocket_id_[dsocket.id()].size() >= 1; + return !sockets_by_dsocket_.lookup(dsocket).is_empty(); } }; @@ -258,12 +254,7 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase { public: SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DSocket &dsocket) - : MFNetworkBuilderBase(common), bsocket_(dsocket.bsocket()) - { - } - - SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DGroupInput &group_input) - : MFNetworkBuilderBase(common), bsocket_(group_input.bsocket()) + : MFNetworkBuilderBase(common), bsocket_(dsocket->bsocket()) { } @@ -331,10 +322,10 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase { */ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { private: - const DNode &dnode_; + DNode dnode_; public: - NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DNode &dnode) + NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, DNode dnode) : MFNetworkBuilderBase(common), dnode_(dnode) { } @@ -352,7 +343,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { const fn::MultiFunction &get_not_implemented_fn() { - return this->get_default_fn("Not Implemented (" + dnode_.name() + ")"); + return this->get_default_fn("Not Implemented (" + dnode_->name() + ")"); } const fn::MultiFunction &get_default_fn(StringRef name); @@ -377,7 +368,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { */ bNode &bnode() { - return *dnode_.node_ref().bnode(); + return *dnode_->bnode(); } /** @@ -393,7 +384,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, const DerivedNodeTree &tree, ResourceCollector &resources); -using MultiFunctionByNode = Map<const DNode *, const fn::MultiFunction *>; +using MultiFunctionByNode = Map<DNode, const fn::MultiFunction *>; MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, ResourceCollector &resources); diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh index 7fcc117ba93..3c898aaf0ff 100644 --- a/source/blender/nodes/NOD_node_tree_ref.hh +++ b/source/blender/nodes/NOD_node_tree_ref.hh @@ -25,6 +25,7 @@ * The following queries are supported efficiently: * - socket -> index of socket * - socket -> directly linked sockets + * - socket -> directly linked links * - socket -> linked sockets when skipping reroutes * - socket -> node * - socket/node -> rna pointer @@ -65,6 +66,8 @@ class InputSocketRef; class OutputSocketRef; class NodeRef; class NodeTreeRef; +class LinkRef; +class InternalLinkRef; class SocketRef : NonCopyable, NonMovable { protected: @@ -76,12 +79,14 @@ class SocketRef : NonCopyable, NonMovable { PointerRNA rna_; Vector<SocketRef *> linked_sockets_; Vector<SocketRef *> directly_linked_sockets_; + Vector<LinkRef *> directly_linked_links_; friend NodeTreeRef; public: Span<const SocketRef *> linked_sockets() const; Span<const SocketRef *> directly_linked_sockets() const; + Span<const LinkRef *> directly_linked_links() const; bool is_linked() const; const NodeRef &node() const; @@ -102,16 +107,21 @@ class SocketRef : NonCopyable, NonMovable { StringRefNull idname() const; StringRefNull name() const; StringRefNull identifier() const; + bNodeSocketType *typeinfo() const; bNodeSocket *bsocket() const; bNode *bnode() const; bNodeTree *btree() const; + + bool is_available() const; }; class InputSocketRef final : public SocketRef { public: Span<const OutputSocketRef *> linked_sockets() const; Span<const OutputSocketRef *> directly_linked_sockets() const; + + bool is_multi_input_socket() const; }; class OutputSocketRef final : public SocketRef { @@ -128,6 +138,7 @@ class NodeRef : NonCopyable, NonMovable { int id_; Vector<InputSocketRef *> inputs_; Vector<OutputSocketRef *> outputs_; + Vector<InternalLinkRef *> internal_links_; friend NodeTreeRef; @@ -136,6 +147,7 @@ class NodeRef : NonCopyable, NonMovable { Span<const InputSocketRef *> inputs() const; Span<const OutputSocketRef *> outputs() const; + Span<const InternalLinkRef *> internal_links() const; const InputSocketRef &input(int index) const; const OutputSocketRef &output(int index) const; @@ -146,6 +158,7 @@ class NodeRef : NonCopyable, NonMovable { PointerRNA *rna() const; StringRefNull idname() const; StringRefNull name() const; + bNodeType *typeinfo() const; int id() const; @@ -156,6 +169,36 @@ class NodeRef : NonCopyable, NonMovable { bool is_muted() const; }; +class LinkRef : NonCopyable, NonMovable { + private: + OutputSocketRef *from_; + InputSocketRef *to_; + bNodeLink *blink_; + + friend NodeTreeRef; + + public: + const OutputSocketRef &from() const; + const InputSocketRef &to() const; + + bNodeLink *blink() const; +}; + +class InternalLinkRef : NonCopyable, NonMovable { + private: + InputSocketRef *from_; + OutputSocketRef *to_; + bNodeLink *blink_; + + friend NodeTreeRef; + + public: + const InputSocketRef &from() const; + const OutputSocketRef &to() const; + + bNodeLink *blink() const; +}; + class NodeTreeRef : NonCopyable, NonMovable { private: LinearAllocator<> allocator_; @@ -164,6 +207,7 @@ class NodeTreeRef : NonCopyable, NonMovable { Vector<SocketRef *> sockets_by_id_; Vector<InputSocketRef *> input_sockets_; Vector<OutputSocketRef *> output_sockets_; + Vector<LinkRef *> links_; MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_; public: @@ -178,6 +222,8 @@ class NodeTreeRef : NonCopyable, NonMovable { Span<const InputSocketRef *> input_sockets() const; Span<const OutputSocketRef *> output_sockets() const; + Span<const LinkRef *> links() const; + bool has_link_cycles() const; bNodeTree *btree() const; @@ -195,6 +241,19 @@ class NodeTreeRef : NonCopyable, NonMovable { void find_targets_skipping_reroutes(OutputSocketRef &socket_ref, Vector<SocketRef *> &r_targets); }; +using NodeTreeRefMap = Map<bNodeTree *, std::unique_ptr<const NodeTreeRef>>; + +const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree); + +namespace node_tree_ref_types { +using nodes::InputSocketRef; +using nodes::NodeRef; +using nodes::NodeTreeRef; +using nodes::NodeTreeRefMap; +using nodes::OutputSocketRef; +using nodes::SocketRef; +} // namespace node_tree_ref_types + /* -------------------------------------------------------------------- * SocketRef inline methods. */ @@ -209,6 +268,11 @@ inline Span<const SocketRef *> SocketRef::directly_linked_sockets() const return directly_linked_sockets_; } +inline Span<const LinkRef *> SocketRef::directly_linked_links() const +{ + return directly_linked_links_; +} + inline bool SocketRef::is_linked() const { return linked_sockets_.size() > 0; @@ -281,6 +345,11 @@ inline StringRefNull SocketRef::identifier() const return bsocket_->identifier; } +inline bNodeSocketType *SocketRef::typeinfo() const +{ + return bsocket_->typeinfo; +} + inline bNodeSocket *SocketRef::bsocket() const { return bsocket_; @@ -296,6 +365,11 @@ inline bNodeTree *SocketRef::btree() const return node_->btree(); } +inline bool SocketRef::is_available() const +{ + return (bsocket_->flag & SOCK_UNAVAIL) == 0; +} + /* -------------------------------------------------------------------- * InputSocketRef inline methods. */ @@ -310,6 +384,11 @@ inline Span<const OutputSocketRef *> InputSocketRef::directly_linked_sockets() c return directly_linked_sockets_.as_span().cast<const OutputSocketRef *>(); } +inline bool InputSocketRef::is_multi_input_socket() const +{ + return bsocket_->flag & SOCK_MULTI_INPUT; +} + /* -------------------------------------------------------------------- * OutputSocketRef inline methods. */ @@ -343,6 +422,11 @@ inline Span<const OutputSocketRef *> NodeRef::outputs() const return outputs_; } +inline Span<const InternalLinkRef *> NodeRef::internal_links() const +{ + return internal_links_; +} + inline const InputSocketRef &NodeRef::input(int index) const { return *inputs_[index]; @@ -378,6 +462,11 @@ inline StringRefNull NodeRef::name() const return bnode_->name; } +inline bNodeType *NodeRef::typeinfo() const +{ + return bnode_->typeinfo; +} + inline int NodeRef::id() const { return id_; @@ -409,7 +498,45 @@ inline bool NodeRef::is_muted() const } /* -------------------------------------------------------------------- - * NodeRef inline methods. + * LinkRef inline methods. + */ + +inline const OutputSocketRef &LinkRef::from() const +{ + return *from_; +} + +inline const InputSocketRef &LinkRef::to() const +{ + return *to_; +} + +inline bNodeLink *LinkRef::blink() const +{ + return blink_; +} + +/* -------------------------------------------------------------------- + * InternalLinkRef inline methods. + */ + +inline const InputSocketRef &InternalLinkRef::from() const +{ + return *from_; +} + +inline const OutputSocketRef &InternalLinkRef::to() const +{ + return *to_; +} + +inline bNodeLink *InternalLinkRef::blink() const +{ + return blink_; +} + +/* -------------------------------------------------------------------- + * NodeTreeRef inline methods. */ inline Span<const NodeRef *> NodeTreeRef::nodes() const @@ -443,6 +570,11 @@ inline Span<const OutputSocketRef *> NodeTreeRef::output_sockets() const return output_sockets_; } +inline Span<const LinkRef *> NodeTreeRef::links() const +{ + return links_; +} + inline bNodeTree *NodeTreeRef::btree() const { return btree_; diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc index f5308fe2671..84cd84e41c7 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c +++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc @@ -27,35 +27,36 @@ #include "BLI_utildefines.h" #include "node_composite_util.h" -static CryptomatteEntry *cryptomatte_find(NodeCryptomatte *n, float encoded_hash) +extern "C" { +static CryptomatteEntry *cryptomatte_find(const NodeCryptomatte &n, float encoded_hash) { - LISTBASE_FOREACH (CryptomatteEntry *, entry, &n->entries) { + LISTBASE_FOREACH (CryptomatteEntry *, entry, &n.entries) { if (entry->encoded_hash == encoded_hash) { return entry; } } - return NULL; + return nullptr; } -static void cryptomatte_add(NodeCryptomatte *n, float f) +static void cryptomatte_add(NodeCryptomatte &n, float f) { /* Check if entry already exist. */ - if (cryptomatte_find(n, f) != NULL) { + if (cryptomatte_find(n, f)) { return; } - CryptomatteEntry *entry = MEM_callocN(sizeof(CryptomatteEntry), __func__); + CryptomatteEntry *entry = static_cast<CryptomatteEntry *>( + MEM_callocN(sizeof(CryptomatteEntry), __func__)); entry->encoded_hash = f; - BLI_addtail(&n->entries, entry); + BLI_addtail(&n.entries, entry); } -static void cryptomatte_remove(NodeCryptomatte *n, float f) +static void cryptomatte_remove(NodeCryptomatte &n, float f) { CryptomatteEntry *entry = cryptomatte_find(n, f); - if (entry == NULL) { + if (!entry) { return; } - - BLI_remlink(&n->entries, entry); + BLI_remlink(&n.entries, entry); MEM_freeN(entry); } @@ -68,44 +69,40 @@ static bNodeSocketTemplate outputs[] = { void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *UNUSED(ntree), bNode *node) { - NodeCryptomatte *n = node->storage; + NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage); if (n->add[0] != 0.0f) { - cryptomatte_add(n, n->add[0]); - n->add[0] = 0.0f; - n->add[1] = 0.0f; - n->add[2] = 0.0f; + cryptomatte_add(*n, n->add[0]); + zero_v3(n->add); } } void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *UNUSED(ntree), bNode *node) { - NodeCryptomatte *n = node->storage; + NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage); if (n->remove[0] != 0.0f) { - cryptomatte_remove(n, n->remove[0]); - n->remove[0] = 0.0f; - n->remove[1] = 0.0f; - n->remove[2] = 0.0f; + cryptomatte_remove(*n, n->remove[0]); + zero_v3(n->remove); } } bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node) { - NodeCryptomatte *n = node->storage; + NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage); char sockname[32]; n->num_inputs++; BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1); bNodeSocket *sock = nodeAddStaticSocket( - ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, sockname); + ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, sockname); return sock; } int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node) { - NodeCryptomatte *n = node->storage; + NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage); if (n->num_inputs < 2) { return 0; } - bNodeSocket *sock = node->inputs.last; + bNodeSocket *sock = static_cast<bNodeSocket *>(node->inputs.last); nodeRemoveSocket(ntree, node, sock); n->num_inputs--; return 1; @@ -113,7 +110,8 @@ int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node) static void init(bNodeTree *ntree, bNode *node) { - NodeCryptomatte *user = MEM_callocN(sizeof(NodeCryptomatte), "cryptomatte user"); + NodeCryptomatte *user = static_cast<NodeCryptomatte *>( + MEM_callocN(sizeof(NodeCryptomatte), __func__)); node->storage = user; nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image"); @@ -126,7 +124,7 @@ static void init(bNodeTree *ntree, bNode *node) static void node_free_cryptomatte(bNode *node) { - NodeCryptomatte *nc = node->storage; + NodeCryptomatte *nc = static_cast<NodeCryptomatte *>(node->storage); if (nc) { BLI_freelistN(&nc->entries); @@ -138,8 +136,8 @@ static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node) { - NodeCryptomatte *src_nc = src_node->storage; - NodeCryptomatte *dest_nc = MEM_dupallocN(src_nc); + NodeCryptomatte *src_nc = static_cast<NodeCryptomatte *>(src_node->storage); + NodeCryptomatte *dest_nc = static_cast<NodeCryptomatte *>(MEM_dupallocN(src_nc)); BLI_duplicatelist(&dest_nc->entries, &src_nc->entries); dest_node->storage = dest_nc; @@ -150,8 +148,9 @@ void register_node_type_cmp_cryptomatte(void) static bNodeType ntype; cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_CONVERTOR, 0); - node_type_socket_templates(&ntype, NULL, outputs); + node_type_socket_templates(&ntype, nullptr, outputs); node_type_init(&ntype, init); node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte); nodeRegisterType(&ntype); } +} diff --git a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc index 1e22cde721d..3d0ea201239 100644 --- a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc +++ b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc @@ -26,9 +26,10 @@ static void fn_node_group_instance_id_expand_in_mf_network( { const blender::nodes::DNode &node = builder.dnode(); std::string id = "/"; - for (const blender::nodes::DParentNode *parent = node.parent(); parent; - parent = parent->parent()) { - id = "/" + parent->node_ref().name() + id; + for (const blender::nodes::DTreeContext *context = node.context(); + context->parent_node() != nullptr; + context = context->parent_context()) { + id = "/" + context->parent_node()->name() + id; } builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<std::string>>( std::move(id)); diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/node_fn_random_float.cc index f3401a2c00d..d0ecb5592da 100644 --- a/source/blender/nodes/function/nodes/node_fn_random_float.cc +++ b/source/blender/nodes/function/nodes/node_fn_random_float.cc @@ -67,12 +67,13 @@ static void fn_node_random_float_expand_in_mf_network( blender::nodes::NodeMFNetworkBuilder &builder) { uint32_t function_seed = 1746872341u; - const blender::nodes::DNode &node = builder.dnode(); + blender::nodes::DNode node = builder.dnode(); const blender::DefaultHash<blender::StringRefNull> hasher; - function_seed = 33 * function_seed + hasher(node.name()); - for (const blender::nodes::DParentNode *parent = node.parent(); parent != nullptr; - parent = parent->parent()) { - function_seed = 33 * function_seed + hasher(parent->node_ref().name()); + function_seed = 33 * function_seed + hasher(node->name()); + for (const blender::nodes::DTreeContext *context = node.context(); + context->parent_node() != nullptr; + context = context->parent_context()) { + function_seed = 33 * function_seed + hasher(context->parent_node()->name()); } builder.construct_and_set_matching_fn<RandomFloatFunction>(function_seed); diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc index 2ab76540bdf..f09a9bf056e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc @@ -32,7 +32,7 @@ static bNodeSocketTemplate geo_node_attribute_proximity_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, {SOCK_GEOMETRY, N_("Target")}, {SOCK_STRING, N_("Distance")}, - {SOCK_STRING, N_("Location")}, + {SOCK_STRING, N_("Position")}, {-1, ""}, }; @@ -172,7 +172,7 @@ static void attribute_calc_proximity(GeometryComponent &component, OutputAttributePtr distance_attribute = component.attribute_try_get_for_output( distance_attribute_name, result_domain, CD_PROP_FLOAT); - const std::string location_attribute_name = params.get_input<std::string>("Location"); + const std::string location_attribute_name = params.get_input<std::string>("Position"); OutputAttributePtr location_attribute = component.attribute_try_get_for_output( location_attribute_name, result_domain, CD_PROP_FLOAT3); diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc index bb5b5073c32..27c35da7d37 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc @@ -224,7 +224,7 @@ static void randomize_attribute_on_component(GeometryComponent &component, if (operation != GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) { if (!component.attribute_exists(attribute_name)) { params.error_message_add(NodeWarningType::Error, - "No attribute with name '" + attribute_name + "'."); + TIP_("No attribute with name \"") + attribute_name + "\""); return; } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 4e15f232934..9dce52c072d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -222,8 +222,9 @@ static void join_components(Span<const MeshComponent *> src_components, Geometry dst_component.replace(new_mesh); /* Don't copy attributes that are stored directly in the mesh data structs. */ - join_attributes( - to_base_components(src_components), dst_component, {"position", "material_index"}); + join_attributes(to_base_components(src_components), + dst_component, + {"position", "material_index", "vertex_normal"}); } static void join_components(Span<const PointCloudComponent *> src_components, GeometrySet &result) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index d9878d54353..c40cb2bb0ae 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -429,7 +429,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) params.node().custom1); if (!geometry_set.has_mesh()) { - params.error_message_add(NodeWarningType::Error, "Geometry must contain a mesh."); + params.error_message_add(NodeWarningType::Error, TIP_("Geometry must contain a mesh")); params.set_output("Geometry", std::move(geometry_set_out)); return; } @@ -446,7 +446,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) const Mesh *mesh_in = mesh_component.get_for_read(); if (mesh_in->mpoly == nullptr) { - params.error_message_add(NodeWarningType::Error, "Mesh has no faces."); + params.error_message_add(NodeWarningType::Error, TIP_("Mesh has no faces")); params.set_output("Geometry", std::move(geometry_set_out)); return; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc index 669b5ee4614..dbbb73bd36d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc @@ -103,7 +103,7 @@ static void get_instanced_data__collection( if (BLI_listbase_is_empty(&collection->children) && BLI_listbase_is_empty(&collection->gobject)) { - params.error_message_add(NodeWarningType::Info, "Collection is empty."); + params.error_message_add(NodeWarningType::Info, TIP_("Collection is empty")); return; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc index e28013a8bfc..9df103ff057 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc @@ -47,6 +47,9 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co static const float3 scale_default = float3(1.0f); OutputAttributePtr scale_attribute = component.attribute_try_get_for_output( "scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, &scale_default); + if (!scale_attribute) { + return; + } ReadAttributePtr attribute = params.get_input_attribute( "Factor", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr); if (!attribute) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc index 2a0cb727cd6..38560d277e3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc @@ -49,7 +49,7 @@ static void geo_node_subdivision_surface_simple_exec(GeoNodeExecParams params) #ifndef WITH_OPENSUBDIV params.error_message_add(NodeWarningType::Error, - "Disabled, Blender was built without OpenSubdiv"); + TIP_("Disabled, Blender was built without OpenSubdiv")); params.set_output("Geometry", std::move(geometry_set)); return; #endif diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index f5a0e14f18b..c20d6fa943e 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -16,523 +16,256 @@ #include "NOD_derived_node_tree.hh" -#include "BLI_dot_export.hh" - -#define UNINITIALIZED_ID UINT32_MAX - namespace blender::nodes { -static const NodeTreeRef &get_tree_ref(NodeTreeRefMap &node_tree_refs, bNodeTree *btree) +/* Construct a new derived node tree for a given root node tree. The generated derived node tree + * does not own the used node tree refs (so that those can be used by others as well). The caller + * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the + * derived node tree. */ +DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs) { - return *node_tree_refs.lookup_or_add_cb(btree, - [&]() { return std::make_unique<NodeTreeRef>(btree); }); + /* Construct all possible contexts immediately. This is significantly cheaper than inlining all + * node groups. If it still becomes a performance issue in the future, contexts could be + * constructed lazily when they are needed. */ + root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs); } -DerivedNodeTree::DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs) : btree_(btree) +DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context, + const NodeRef *parent_node, + bNodeTree &btree, + NodeTreeRefMap &node_tree_refs) { - BLI_assert(btree != nullptr); - - const NodeTreeRef &main_tree_ref = get_tree_ref(node_tree_refs, btree); - used_node_tree_refs_.add_new(&main_tree_ref); - - Vector<DNode *> all_nodes; - Vector<DGroupInput *> all_group_inputs; - Vector<DParentNode *> all_parent_nodes; - - this->insert_nodes_and_links_in_id_order(main_tree_ref, nullptr, all_nodes); - this->expand_groups(all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs); - this->relink_and_remove_muted_nodes(all_nodes); - this->remove_expanded_group_interfaces(all_nodes); - this->remove_unused_group_inputs(all_group_inputs); - this->store_in_this_and_init_ids( - std::move(all_nodes), std::move(all_group_inputs), std::move(all_parent_nodes)); -} - -BLI_NOINLINE void DerivedNodeTree::insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref, - DParentNode *parent, - Vector<DNode *> &all_nodes) -{ - Array<DSocket *, 64> sockets_map(tree_ref.sockets().size()); - - /* Insert nodes. */ - for (const NodeRef *node_ref : tree_ref.nodes()) { - DNode &node = this->create_node(*node_ref, parent, sockets_map); - all_nodes.append(&node); - } - - /* Insert links. */ - for (const NodeRef *node_ref : tree_ref.nodes()) { - for (const InputSocketRef *to_socket_ref : node_ref->inputs()) { - DInputSocket *to_socket = static_cast<DInputSocket *>(sockets_map[to_socket_ref->id()]); - for (const OutputSocketRef *from_socket_ref : to_socket_ref->linked_sockets()) { - DOutputSocket *from_socket = static_cast<DOutputSocket *>( - sockets_map[from_socket_ref->id()]); - to_socket->linked_sockets_.append(from_socket); - from_socket->linked_sockets_.append(to_socket); + DTreeContext &context = *allocator_.construct<DTreeContext>(); + context.parent_context_ = parent_context; + context.parent_node_ = parent_node; + context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree); + used_node_tree_refs_.add(context.tree_); + + for (const NodeRef *node : context.tree_->nodes()) { + if (node->is_group_node()) { + bNode *bnode = node->bnode(); + bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id); + if (child_btree != nullptr) { + DTreeContext &child = this->construct_context_recursively( + &context, node, *child_btree, node_tree_refs); + context.children_.add_new(node, &child); } } } + + return context; } -DNode &DerivedNodeTree::create_node(const NodeRef &node_ref, - DParentNode *parent, - MutableSpan<DSocket *> r_sockets_map) +DerivedNodeTree::~DerivedNodeTree() { - DNode &node = *allocator_.construct<DNode>(); - node.node_ref_ = &node_ref; - node.parent_ = parent; - node.id_ = UNINITIALIZED_ID; - - node.inputs_ = allocator_.construct_elements_and_pointer_array<DInputSocket>( - node_ref.inputs().size()); - node.outputs_ = allocator_.construct_elements_and_pointer_array<DOutputSocket>( - node_ref.outputs().size()); - - for (int i : node.inputs_.index_range()) { - const InputSocketRef &socket_ref = node_ref.input(i); - DInputSocket &socket = *node.inputs_[i]; - socket.is_multi_input_socket_ = socket_ref.bsocket()->flag & SOCK_MULTI_INPUT; - socket.id_ = UNINITIALIZED_ID; - socket.node_ = &node; - socket.socket_ref_ = &socket_ref; - - r_sockets_map[socket_ref.id()] = &socket; - } - - for (int i : node.outputs_.index_range()) { - const OutputSocketRef &socket_ref = node_ref.output(i); - DOutputSocket &socket = *node.outputs_[i]; - - socket.id_ = UNINITIALIZED_ID; - socket.node_ = &node; - socket.socket_ref_ = &socket_ref; - - r_sockets_map[socket_ref.id()] = &socket; - } - - return node; + /* Has to be destructed manually, because the context info is allocated in a linear allocator. */ + this->destruct_context_recursively(root_context_); } -BLI_NOINLINE void DerivedNodeTree::expand_groups(Vector<DNode *> &all_nodes, - Vector<DGroupInput *> &all_group_inputs, - Vector<DParentNode *> &all_parent_nodes, - NodeTreeRefMap &node_tree_refs) +void DerivedNodeTree::destruct_context_recursively(DTreeContext *context) { - for (int i = 0; i < all_nodes.size(); i++) { - DNode &node = *all_nodes[i]; - if (node.node_ref_->is_group_node()) { - /* Muted nodes are relinked in a separate step. */ - if (!node.node_ref_->is_muted()) { - this->expand_group_node( - node, all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs); - } - } + for (DTreeContext *child : context->children_.values()) { + this->destruct_context_recursively(child); } + context->~DTreeContext(); } -BLI_NOINLINE void DerivedNodeTree::expand_group_node(DNode &group_node, - Vector<DNode *> &all_nodes, - Vector<DGroupInput *> &all_group_inputs, - Vector<DParentNode *> &all_parent_nodes, - NodeTreeRefMap &node_tree_refs) +/* Returns true if there are any cycles in the node tree. */ +bool DerivedNodeTree::has_link_cycles() const { - const NodeRef &group_node_ref = *group_node.node_ref_; - BLI_assert(group_node_ref.is_group_node()); - - bNodeTree *btree = reinterpret_cast<bNodeTree *>(group_node_ref.bnode()->id); - if (btree == nullptr) { - return; + for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { + if (tree_ref->has_link_cycles()) { + return true; + } } - - const NodeTreeRef &group_ref = get_tree_ref(node_tree_refs, btree); - used_node_tree_refs_.add(&group_ref); - - DParentNode &parent = *allocator_.construct<DParentNode>(); - parent.id_ = all_parent_nodes.append_and_get_index(&parent); - parent.parent_ = group_node.parent_; - parent.node_ref_ = &group_node_ref; - - this->insert_nodes_and_links_in_id_order(group_ref, &parent, all_nodes); - Span<DNode *> new_nodes_by_id = all_nodes.as_span().take_back(group_ref.nodes().size()); - - this->create_group_inputs_for_unlinked_inputs(group_node, all_group_inputs); - this->relink_group_inputs(group_ref, new_nodes_by_id, group_node); - this->relink_group_outputs(group_ref, new_nodes_by_id, group_node); + return false; } -BLI_NOINLINE void DerivedNodeTree::create_group_inputs_for_unlinked_inputs( - DNode &node, Vector<DGroupInput *> &all_group_inputs) +/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */ +void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const { - for (DInputSocket *input_socket : node.inputs_) { - if (input_socket->is_linked()) { - continue; - } - - DGroupInput &group_input = *allocator_.construct<DGroupInput>(); - group_input.id_ = UNINITIALIZED_ID; - group_input.socket_ref_ = &input_socket->socket_ref(); - group_input.parent_ = node.parent_; - - group_input.linked_sockets_.append(input_socket); - input_socket->linked_group_inputs_.append(&group_input); - all_group_inputs.append(&group_input); - } + this->foreach_node_in_context_recursive(*root_context_, callback); } -BLI_NOINLINE void DerivedNodeTree::relink_group_inputs(const NodeTreeRef &group_ref, - Span<DNode *> nodes_by_id, - DNode &group_node) +void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context, + FunctionRef<void(DNode)> callback) const { - Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupInput"); - if (node_refs.size() == 0) { - return; + for (const NodeRef *node_ref : context.tree_->nodes()) { + callback(DNode(&context, node_ref)); } - /* TODO: Pick correct group input node if there are more than one. */ - const NodeRef &input_node_ref = *node_refs[0]; - DNode &input_node = *nodes_by_id[input_node_ref.id()]; - - int input_amount = group_node.inputs().size(); - BLI_assert(input_amount == input_node_ref.outputs().size() - 1); - - for (int input_index : IndexRange(input_amount)) { - DInputSocket *outside_group = group_node.inputs_[input_index]; - DOutputSocket *inside_group = input_node.outputs_[input_index]; - - for (DOutputSocket *outside_connected : outside_group->linked_sockets_) { - outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group); - } - - for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) { - outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group); - } - - for (DInputSocket *inside_connected : inside_group->linked_sockets_) { - inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group); - - for (DOutputSocket *outside_connected : outside_group->linked_sockets_) { - inside_connected->linked_sockets_.append(outside_connected); - outside_connected->linked_sockets_.append(inside_connected); - } - - for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) { - inside_connected->linked_group_inputs_.append(outside_connected); - outside_connected->linked_sockets_.append(inside_connected); - } - } - - inside_group->linked_sockets_.clear(); - outside_group->linked_sockets_.clear(); - outside_group->linked_group_inputs_.clear(); + for (const DTreeContext *child_context : context.children_.values()) { + this->foreach_node_in_context_recursive(*child_context, callback); } } -BLI_NOINLINE void DerivedNodeTree::relink_group_outputs(const NodeTreeRef &group_ref, - Span<DNode *> nodes_by_id, - DNode &group_node) +DOutputSocket DInputSocket::get_corresponding_group_node_output() const { - Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupOutput"); - if (node_refs.size() == 0) { - return; - } - /* TODO: Pick correct group output node if there are more than one. */ - const NodeRef &output_node_ref = *node_refs[0]; - DNode &output_node = *nodes_by_id[output_node_ref.id()]; - - int output_amount = group_node.outputs().size(); - BLI_assert(output_amount == output_node_ref.inputs().size() - 1); + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_output_node()); + BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1); - for (int output_index : IndexRange(output_amount)) { - DOutputSocket *outside_group = group_node.outputs_[output_index]; - DInputSocket *inside_group = output_node.inputs_[output_index]; - - for (DInputSocket *outside_connected : outside_group->linked_sockets_) { - outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group); - } + const DTreeContext *parent_context = context_->parent_context(); + const NodeRef *parent_node = context_->parent_node(); + BLI_assert(parent_context != nullptr); + BLI_assert(parent_node != nullptr); - for (DOutputSocket *inside_connected : inside_group->linked_sockets_) { - inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group); - - for (DInputSocket *outside_connected : outside_group->linked_sockets_) { - inside_connected->linked_sockets_.append(outside_connected); - outside_connected->linked_sockets_.append(inside_connected); - } - } - - for (DGroupInput *inside_connected : inside_group->linked_group_inputs_) { - inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group); - - for (DInputSocket *outside_connected : outside_group->linked_sockets_) { - inside_connected->linked_sockets_.append(outside_connected); - outside_connected->linked_group_inputs_.append(inside_connected); - } - } - - outside_group->linked_sockets_.clear(); - inside_group->linked_sockets_.clear(); - } + const int socket_index = socket_ref_->index(); + return {parent_context, &parent_node->output(socket_index)}; } -BLI_NOINLINE void DerivedNodeTree::remove_expanded_group_interfaces(Vector<DNode *> &all_nodes) +Vector<DOutputSocket> DInputSocket::get_corresponding_group_input_sockets() const { - int index = 0; - while (index < all_nodes.size()) { - DNode &node = *all_nodes[index]; - const NodeRef &node_ref = *node.node_ref_; - if (node_ref.is_group_node() || - (node.parent_ != nullptr && - (node_ref.is_group_input_node() || node_ref.is_group_output_node()))) { - all_nodes.remove_and_reorder(index); - node.destruct_with_sockets(); - } - else { - index++; - } + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_node()); + + const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + BLI_assert(child_context != nullptr); + + const NodeTreeRef &child_tree = child_context->tree(); + Span<const NodeRef *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput"); + const int socket_index = socket_ref_->index(); + Vector<DOutputSocket> sockets; + for (const NodeRef *group_input_node : group_input_nodes) { + sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index))); } + return sockets; } -BLI_NOINLINE void DerivedNodeTree::remove_unused_group_inputs( - Vector<DGroupInput *> &all_group_inputs) +DInputSocket DOutputSocket::get_corresponding_group_node_input() const { - int index = 0; - while (index < all_group_inputs.size()) { - DGroupInput &group_input = *all_group_inputs[index]; - if (group_input.linked_sockets_.is_empty()) { - all_group_inputs.remove_and_reorder(index); - group_input.~DGroupInput(); - } - else { - index++; - } - } + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_input_node()); + BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1); + + const DTreeContext *parent_context = context_->parent_context(); + const NodeRef *parent_node = context_->parent_node(); + BLI_assert(parent_context != nullptr); + BLI_assert(parent_node != nullptr); + + const int socket_index = socket_ref_->index(); + return {parent_context, &parent_node->input(socket_index)}; } -BLI_NOINLINE void DerivedNodeTree::relink_and_remove_muted_nodes(Vector<DNode *> &all_nodes) +DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const { - int index = 0; - while (index < all_nodes.size()) { - DNode &node = *all_nodes[index]; - const NodeRef &node_ref = *node.node_ref_; - if (node_ref.is_muted()) { - this->relink_muted_node(node); - all_nodes.remove_and_reorder(index); - node.destruct_with_sockets(); - } - else { - index++; + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_node()); + + const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + BLI_assert(child_context != nullptr); + + const NodeTreeRef &child_tree = child_context->tree(); + Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput"); + const int socket_index = socket_ref_->index(); + for (const NodeRef *group_output_node : group_output_nodes) { + if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) { + return {child_context, &group_output_node->input(socket_index)}; } } + return {}; } -BLI_NOINLINE void DerivedNodeTree::relink_muted_node(DNode &node) +/* Call the given callback for every "real" origin socket. "Real" means that reroutes, muted nodes + * and node groups are handled by this function. Origin sockets are ones where a node gets its + * inputs from. */ +void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback) const { - const bNode &bnode = *node.bnode(); - LISTBASE_FOREACH (const bNodeLink *, internal_link, &bnode.internal_links) { - BLI_assert(internal_link->fromnode == &bnode); - BLI_assert(internal_link->tonode == &bnode); - bNodeSocket *input_bsocket = internal_link->fromsock; - bNodeSocket *output_bsocket = internal_link->tosock; - - /* Find internally linked sockets. */ - DInputSocket *input_socket = nullptr; - DOutputSocket *output_socket = nullptr; - for (DInputSocket *socket : node.inputs_) { - if (socket->bsocket() == input_bsocket) { - input_socket = socket; - break; + BLI_assert(*this); + for (const OutputSocketRef *linked_socket : socket_ref_->as_input().linked_sockets()) { + const NodeRef &linked_node = linked_socket->node(); + DOutputSocket linked_dsocket{context_, linked_socket}; + + if (linked_node.is_muted()) { + /* If the node is muted, follow the internal links of the node. */ + for (const InternalLinkRef *internal_link : linked_node.internal_links()) { + if (&internal_link->to() == linked_socket) { + DInputSocket input_of_muted_node{context_, &internal_link->from()}; + input_of_muted_node.foreach_origin_socket(callback); + } } } - for (DOutputSocket *socket : node.outputs_) { - if (socket->bsocket() == output_bsocket) { - output_socket = socket; - break; + else if (linked_node.is_group_input_node()) { + if (context_->is_root()) { + /* This is a group input in the root node group. */ + callback(linked_dsocket); } - } - BLI_assert(input_socket != nullptr); - BLI_assert(output_socket != nullptr); - - /* Link sockets connected to the input to sockets that are connected to the internally linked - * output. */ - for (DInputSocket *to_socket : output_socket->linked_sockets_) { - for (DOutputSocket *from_socket : input_socket->linked_sockets_) { - from_socket->linked_sockets_.append_non_duplicates(to_socket); - to_socket->linked_sockets_.append_non_duplicates(from_socket); - } - for (DGroupInput *group_input : input_socket->linked_group_inputs_) { - group_input->linked_sockets_.append_non_duplicates(to_socket); - to_socket->linked_group_inputs_.append_non_duplicates(group_input); + else { + DInputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_input(); + if (socket_in_parent_group->is_linked()) { + /* Follow the links coming into the corresponding socket on the parent group node. */ + socket_in_parent_group.foreach_origin_socket(callback); + } + else { + /* The corresponding input on the parent group node is not connected. Therefore, we use + * the value of that input socket directly. */ + callback(socket_in_parent_group); + } } } - } - - /* Remove remaining links from muted node. */ - for (DInputSocket *to_socket : node.inputs_) { - for (DOutputSocket *from_socket : to_socket->linked_sockets_) { - from_socket->linked_sockets_.remove_first_occurrence_and_reorder(to_socket); - } - for (DGroupInput *from_group_input : to_socket->linked_group_inputs_) { - from_group_input->linked_sockets_.remove_first_occurrence_and_reorder(to_socket); - } - to_socket->linked_sockets_.clear(); - to_socket->linked_group_inputs_.clear(); - } - for (DOutputSocket *from_socket : node.outputs_) { - for (DInputSocket *to_socket : from_socket->linked_sockets_) { - to_socket->linked_sockets_.remove_first_occurrence_and_reorder(from_socket); - } - from_socket->linked_sockets_.clear(); - } -} - -void DNode::destruct_with_sockets() -{ - for (DInputSocket *socket : inputs_) { - socket->~DInputSocket(); - } - for (DOutputSocket *socket : outputs_) { - socket->~DOutputSocket(); - } - this->~DNode(); -} - -BLI_NOINLINE void DerivedNodeTree::store_in_this_and_init_ids( - Vector<DNode *> &&all_nodes, - Vector<DGroupInput *> &&all_group_inputs, - Vector<DParentNode *> &&all_parent_nodes) -{ - nodes_by_id_ = std::move(all_nodes); - group_inputs_ = std::move(all_group_inputs); - parent_nodes_ = std::move(all_parent_nodes); - - for (int node_index : nodes_by_id_.index_range()) { - DNode *node = nodes_by_id_[node_index]; - node->id_ = node_index; - - const bNodeType *nodetype = node->node_ref_->bnode()->typeinfo; - nodes_by_type_.add(nodetype, node); - - for (DInputSocket *socket : node->inputs_) { - socket->id_ = sockets_by_id_.append_and_get_index(socket); - input_sockets_.append(socket); - } - for (DOutputSocket *socket : node->outputs_) { - socket->id_ = sockets_by_id_.append_and_get_index(socket); - output_sockets_.append(socket); + else if (linked_node.is_group_node()) { + DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket(); + if (socket_in_group) { + if (socket_in_group->is_linked()) { + /* Follow the links coming into the group output node of the child node group. */ + socket_in_group.foreach_origin_socket(callback); + } + else { + /* The output of the child node group is not connected, so we have to get the value from + * that socket. */ + callback(socket_in_group); + } + } } - } - - for (int i : group_inputs_.index_range()) { - group_inputs_[i]->id_ = i; - } -} - -DerivedNodeTree::~DerivedNodeTree() -{ - for (DInputSocket *socket : input_sockets_) { - socket->~DInputSocket(); - } - for (DOutputSocket *socket : output_sockets_) { - socket->~DOutputSocket(); - } - for (DNode *node : nodes_by_id_) { - node->~DNode(); - } - for (DGroupInput *group_input : group_inputs_) { - group_input->~DGroupInput(); - } - for (DParentNode *parent : parent_nodes_) { - parent->~DParentNode(); - } -} - -bool DerivedNodeTree::has_link_cycles() const -{ - for (const NodeTreeRef *tree : used_node_tree_refs_) { - if (tree->has_link_cycles()) { - return true; + else { + /* The normal case: just use the value of a linked output socket. */ + callback(linked_dsocket); } } - return false; -} - -static dot::Cluster *get_cluster_for_parent(dot::DirectedGraph &graph, - Map<const DParentNode *, dot::Cluster *> &clusters, - const DParentNode *parent) -{ - if (parent == nullptr) { - return nullptr; - } - return clusters.lookup_or_add_cb(parent, [&]() { - dot::Cluster *parent_cluster = get_cluster_for_parent(graph, clusters, parent->parent()); - bNodeTree *btree = reinterpret_cast<bNodeTree *>(parent->node_ref().bnode()->id); - dot::Cluster *new_cluster = &graph.new_cluster(parent->node_ref().name() + " / " + - StringRef(btree->id.name + 2)); - new_cluster->set_parent_cluster(parent_cluster); - return new_cluster; - }); } -std::string DerivedNodeTree::to_dot() const +/* Calls the given callback for every "real" target socket. "Real" means that reroutes, muted nodes + * and node groups are handled by this function. Target sockets are on the nodes that use the value + * from this socket. */ +void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const { - dot::DirectedGraph digraph; - digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); - - Map<const DNode *, dot::NodeWithSocketsRef> dot_nodes; - Map<const DGroupInput *, dot::NodeWithSocketsRef> dot_group_inputs; - Map<const DParentNode *, dot::Cluster *> dot_clusters; - - for (const DNode *node : nodes_by_id_) { - dot::Node &dot_node = digraph.new_node(""); - dot_node.set_background_color("white"); - - Vector<std::string> input_names; - for (const DInputSocket *socket : node->inputs()) { - input_names.append(socket->name()); - } - Vector<std::string> output_names; - for (const DOutputSocket *socket : node->outputs()) { - output_names.append(socket->name()); + for (const InputSocketRef *linked_socket : socket_ref_->as_output().linked_sockets()) { + const NodeRef &linked_node = linked_socket->node(); + DInputSocket linked_dsocket{context_, linked_socket}; + + if (linked_node.is_muted()) { + /* If the target node is muted, follow its internal links. */ + for (const InternalLinkRef *internal_link : linked_node.internal_links()) { + if (&internal_link->from() == linked_socket) { + DOutputSocket output_of_muted_node{context_, &internal_link->to()}; + output_of_muted_node.foreach_target_socket(callback); + } + } } - - dot_nodes.add_new(node, - dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names)); - - dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, node->parent()); - dot_node.set_parent_cluster(cluster); - } - - for (const DGroupInput *group_input : group_inputs_) { - dot::Node &dot_node = digraph.new_node(""); - dot_node.set_background_color("white"); - - std::string group_input_name = group_input->name(); - dot_group_inputs.add_new( - group_input, dot::NodeWithSocketsRef(dot_node, "Group Input", {}, {group_input_name})); - - dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, group_input->parent()); - dot_node.set_parent_cluster(cluster); - } - - for (const DNode *to_node : nodes_by_id_) { - dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(to_node); - - for (const DInputSocket *to_socket : to_node->inputs()) { - for (const DOutputSocket *from_socket : to_socket->linked_sockets()) { - const DNode *from_node = &from_socket->node(); - dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(from_node); - - digraph.new_edge(from_dot_node.output(from_socket->index()), - to_dot_node.input(to_socket->index())); + else if (linked_node.is_group_output_node()) { + if (context_->is_root()) { + /* This is a group output in the root node group. */ + callback(linked_dsocket); } - for (const DGroupInput *group_input : to_socket->linked_group_inputs()) { - dot::NodeWithSocketsRef &from_dot_node = dot_group_inputs.lookup(group_input); - - digraph.new_edge(from_dot_node.output(0), to_dot_node.input(to_socket->index())); + else { + /* Follow the links going out of the group node in the parent node group. */ + DOutputSocket socket_in_parent_group = + linked_dsocket.get_corresponding_group_node_output(); + socket_in_parent_group.foreach_target_socket(callback); + } + } + else if (linked_node.is_group_node()) { + /* Follow the links within the nested node group. */ + Vector<DOutputSocket> sockets_in_group = + linked_dsocket.get_corresponding_group_input_sockets(); + for (DOutputSocket socket_in_group : sockets_in_group) { + socket_in_group.foreach_target_socket(callback); } } + else { + /* The normal case: just use the linked input socket as target. */ + callback(linked_dsocket); + } } - - digraph.set_random_cluster_bgcolors(); - return digraph.to_dot_string(); } } // namespace blender::nodes diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c index 0d46119ab60..6207a1bf024 100644 --- a/source/blender/nodes/intern/node_exec.c +++ b/source/blender/nodes/intern/node_exec.c @@ -218,7 +218,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, /* prepare all nodes for execution */ for (n = 0, nodeexec = exec->nodeexec; n < totnodes; n++, nodeexec++) { node = nodeexec->node = nodelist[n]; - nodeexec->freeexecfunc = node->typeinfo->freeexecfunc; + nodeexec->free_exec_fn = node->typeinfo->free_exec_fn; /* tag inputs */ for (sock = node->inputs.first; sock; sock = sock->next) { @@ -242,8 +242,8 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, nodeexec->data.preview = context->previews ? BKE_node_instance_hash_lookup(context->previews, nodekey) : NULL; - if (node->typeinfo->initexecfunc) { - nodeexec->data.data = node->typeinfo->initexecfunc(context, node, nodekey); + if (node->typeinfo->init_exec_fn) { + nodeexec->data.data = node->typeinfo->init_exec_fn(context, node, nodekey); } } @@ -264,8 +264,8 @@ void ntree_exec_end(bNodeTreeExec *exec) } for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) { - if (nodeexec->freeexecfunc) { - nodeexec->freeexecfunc(nodeexec->data.data); + if (nodeexec->free_exec_fn) { + nodeexec->free_exec_fn(nodeexec->data.data); } } @@ -323,8 +323,8 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call * If the mute func is not set, assume the node should never be muted, * and hence execute it! */ - if (node->typeinfo->execfunc && !(node->flag & NODE_MUTED)) { - node->typeinfo->execfunc(callerdata, thread, node, &nodeexec->data, nsin, nsout); + if (node->typeinfo->exec_fn && !(node->flag & NODE_MUTED)) { + node->typeinfo->exec_fn(callerdata, thread, node, &nodeexec->data, nsin, nsout); } } } diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h index 806dd10d9bf..de7cbb8cedb 100644 --- a/source/blender/nodes/intern/node_exec.h +++ b/source/blender/nodes/intern/node_exec.h @@ -48,7 +48,7 @@ typedef struct bNodeExec { bNodeExecData data; /** Free function, stored in exec itself to avoid dangling node pointer access. */ - NodeFreeExecFunction freeexecfunc; + NodeFreeExecFunction free_exec_fn; } bNodeExec; /* Execution Data for each instance of node tree execution */ diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index a2e0a4dd6a4..a4fb99a988e 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -20,7 +20,6 @@ #include "DEG_depsgraph_query.h" -#include "NOD_derived_node_tree.hh" #include "NOD_geometry_exec.hh" #include "NOD_type_callbacks.hh" @@ -30,7 +29,7 @@ namespace blender::nodes { void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const { - bNodeTree *btree_cow = node_.node_ref().tree().btree(); + bNodeTree *btree_cow = node_->btree(); BLI_assert(btree_cow != nullptr); if (btree_cow == nullptr) { return; @@ -40,12 +39,12 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin const NodeTreeEvaluationContext context(*self_object_, *modifier_); BKE_nodetree_error_message_add( - *btree_original, context, *node_.bnode(), type, std::move(message)); + *btree_original, context, *node_->bnode(), type, std::move(message)); } const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const { - for (const DSocket *socket : node_.inputs()) { + for (const InputSocketRef *socket : node_->inputs()) { if (socket->is_available() && socket->name() == name) { return socket->bsocket(); } @@ -79,7 +78,7 @@ ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name, * the domain is empty and we don't expect an attribute anyway). */ if (!name.empty() && component.attribute_domain_size(domain) != 0) { this->error_message_add(NodeWarningType::Error, - std::string("No attribute with name '") + name + "'."); + TIP_("No attribute with name \"") + name + "\""); } return component.attribute_get_constant_for_read(domain, type, default_value); } @@ -176,7 +175,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier, const CPPType *requested_type) const { bNodeSocket *found_socket = nullptr; - for (const DSocket *socket : node_.inputs()) { + for (const InputSocketRef *socket : node_->inputs()) { if (socket->identifier() == identifier) { found_socket = socket->bsocket(); break; @@ -186,7 +185,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier, if (found_socket == nullptr) { std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const DSocket *socket : node_.inputs()) { + for (const InputSocketRef *socket : node_->inputs()) { if (socket->is_available()) { std::cout << "'" << socket->identifier() << "', "; } @@ -218,7 +217,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier, void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &value_type) const { bNodeSocket *found_socket = nullptr; - for (const DSocket *socket : node_.outputs()) { + for (const OutputSocketRef *socket : node_->outputs()) { if (socket->identifier() == identifier) { found_socket = socket->bsocket(); break; @@ -228,7 +227,7 @@ void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &va if (found_socket == nullptr) { std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const DSocket *socket : node_.outputs()) { + for (const OutputSocketRef *socket : node_->outputs()) { if (socket->is_available()) { std::cout << "'" << socket->identifier() << "', "; } diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index c2391667e86..bb1367573f8 100644 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -29,17 +29,17 @@ const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name) Vector<fn::MFDataType, 10> input_types; Vector<fn::MFDataType, 10> output_types; - for (const DInputSocket *dsocket : dnode_.inputs()) { + for (const InputSocketRef *dsocket : dnode_->inputs()) { if (dsocket->is_available()) { - std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); + std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo()); if (data_type.has_value()) { input_types.append(*data_type); } } } - for (const DOutputSocket *dsocket : dnode_.outputs()) { + for (const OutputSocketRef *dsocket : dnode_->outputs()) { if (dsocket->is_available()) { - std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); + std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo()); if (data_type.has_value()) { output_types.append(*data_type); } @@ -57,9 +57,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d Vector<fn::MFDataType, stack_capacity> input_types; Vector<StringRef, stack_capacity> input_names; - Vector<const DInputSocket *, stack_capacity> input_dsockets; + Vector<const InputSocketRef *, stack_capacity> input_dsockets; - for (const DInputSocket *dsocket : dnode.inputs()) { + for (const InputSocketRef *dsocket : dnode->inputs()) { if (dsocket->is_available()) { std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); if (data_type.has_value()) { @@ -72,9 +72,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d Vector<fn::MFDataType, stack_capacity> output_types; Vector<StringRef, stack_capacity> output_names; - Vector<const DOutputSocket *, stack_capacity> output_dsockets; + Vector<const OutputSocketRef *, stack_capacity> output_dsockets; - for (const DOutputSocket *dsocket : dnode.outputs()) { + for (const OutputSocketRef *dsocket : dnode->outputs()) { if (dsocket->is_available()) { std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); if (data_type.has_value()) { @@ -86,20 +86,20 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d } fn::MFDummyNode &dummy_node = common.network.add_dummy( - dnode.name(), input_types, output_types, input_names, output_names); + dnode->name(), input_types, output_types, input_names, output_names); - common.network_map.add(input_dsockets, dummy_node.inputs()); - common.network_map.add(output_dsockets, dummy_node.outputs()); + common.network_map.add(*dnode.context(), input_dsockets, dummy_node.inputs()); + common.network_map.add(*dnode.context(), output_dsockets, dummy_node.outputs()); } static bool has_data_sockets(const DNode &dnode) { - for (const DInputSocket *socket : dnode.inputs()) { + for (const InputSocketRef *socket : dnode->inputs()) { if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) { return true; } } - for (const DOutputSocket *socket : dnode.outputs()) { + for (const OutputSocketRef *socket : dnode->outputs()) { if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) { return true; } @@ -107,70 +107,39 @@ static bool has_data_sockets(const DNode &dnode) return false; } +static void foreach_node_to_insert(CommonMFNetworkBuilderData &common, + FunctionRef<void(DNode)> callback) +{ + common.tree.foreach_node([&](const DNode dnode) { + if (dnode->is_group_node()) { + return; + } + /* Don't insert non-root group input/output nodes, because they will be inlined. */ + if (!dnode.context()->is_root()) { + if (dnode->is_group_input_node() || dnode->is_group_output_node()) { + return; + } + } + callback(dnode); + }); +} + /** * Expands all function nodes in the multi-function network. Nodes that don't have an expand * function, but do have data sockets, will get corresponding dummy nodes. */ static void insert_nodes(CommonMFNetworkBuilderData &common) { - for (const DNode *dnode : common.tree.nodes()) { - const bNodeType *node_type = dnode->node_ref().bnode()->typeinfo; + foreach_node_to_insert(common, [&](const DNode dnode) { + const bNodeType *node_type = dnode->typeinfo(); if (node_type->expand_in_mf_network != nullptr) { - NodeMFNetworkBuilder builder{common, *dnode}; + NodeMFNetworkBuilder builder{common, dnode}; node_type->expand_in_mf_network(builder); } - else if (has_data_sockets(*dnode)) { - insert_dummy_node(common, *dnode); - } - } -} - -static void insert_group_inputs(CommonMFNetworkBuilderData &common) -{ - for (const DGroupInput *group_input : common.tree.group_inputs()) { - bNodeSocket *bsocket = group_input->bsocket(); - if (socket_is_mf_data_socket(*bsocket->typeinfo)) { - bNodeSocketType *socktype = bsocket->typeinfo; - BLI_assert(socktype->expand_in_mf_network != nullptr); - - SocketMFNetworkBuilder builder{common, *group_input}; - socktype->expand_in_mf_network(builder); - - fn::MFOutputSocket *from_socket = builder.built_socket(); - BLI_assert(from_socket != nullptr); - common.network_map.add(*group_input, *from_socket); - } - } -} - -static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common, - const DInputSocket &to_dsocket) -{ - Span<const DOutputSocket *> from_dsockets = to_dsocket.linked_sockets(); - Span<const DGroupInput *> from_group_inputs = to_dsocket.linked_group_inputs(); - int total_linked_amount = from_dsockets.size() + from_group_inputs.size(); - BLI_assert(total_linked_amount <= 1); - - if (total_linked_amount == 0) { - return nullptr; - } - - if (from_dsockets.size() == 1) { - const DOutputSocket &from_dsocket = *from_dsockets[0]; - if (!from_dsocket.is_available()) { - return nullptr; - } - if (socket_is_mf_data_socket(*from_dsocket.bsocket()->typeinfo)) { - return &common.network_map.lookup(from_dsocket); + else if (has_data_sockets(dnode)) { + insert_dummy_node(common, dnode); } - return nullptr; - } - - const DGroupInput &from_group_input = *from_group_inputs[0]; - if (socket_is_mf_data_socket(*from_group_input.bsocket()->typeinfo)) { - return &common.network_map.lookup(from_group_input); - } - return nullptr; + }); } template<typename From, typename To> @@ -286,78 +255,82 @@ static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderD return node.output(0); } -static void insert_links(CommonMFNetworkBuilderData &common) +static fn::MFOutputSocket *insert_unlinked_input(CommonMFNetworkBuilderData &common, + const DInputSocket &dsocket) { - for (const DInputSocket *to_dsocket : common.tree.input_sockets()) { - if (!to_dsocket->is_available()) { - continue; - } - if (!to_dsocket->is_linked()) { - continue; - } - if (!socket_is_mf_data_socket(*to_dsocket->bsocket()->typeinfo)) { - continue; - } - - Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(*to_dsocket); - BLI_assert(to_sockets.size() >= 1); - fn::MFDataType to_type = to_sockets[0]->data_type(); + BLI_assert(socket_is_mf_data_socket(*dsocket->typeinfo())); - fn::MFOutputSocket *from_socket = try_find_origin(common, *to_dsocket); - if (from_socket == nullptr) { - from_socket = &insert_default_value_for_type(common, to_type); - } - - fn::MFDataType from_type = from_socket->data_type(); - - if (from_type != to_type) { - const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion( - from_type, to_type); - if (conversion_fn != nullptr) { - fn::MFNode &node = common.network.add_function(*conversion_fn); - common.network.add_link(*from_socket, node.input(0)); - from_socket = &node.output(0); - } - else { - from_socket = &insert_default_value_for_type(common, to_type); - } - } + SocketMFNetworkBuilder builder{common, dsocket}; + socket_expand_in_mf_network(builder); - for (fn::MFInputSocket *to_socket : to_sockets) { - common.network.add_link(*from_socket, *to_socket); - } - } + fn::MFOutputSocket *built_socket = builder.built_socket(); + BLI_assert(built_socket != nullptr); + return built_socket; } -static void insert_unlinked_input(CommonMFNetworkBuilderData &common, const DInputSocket &dsocket) +static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common) { - bNodeSocket *bsocket = dsocket.bsocket(); - bNodeSocketType *socktype = bsocket->typeinfo; - BLI_assert(socktype->expand_in_mf_network != nullptr); - - SocketMFNetworkBuilder builder{common, dsocket}; - socktype->expand_in_mf_network(builder); - - fn::MFOutputSocket *from_socket = builder.built_socket(); - BLI_assert(from_socket != nullptr); + foreach_node_to_insert(common, [&](const DNode dnode) { + for (const InputSocketRef *socket_ref : dnode->inputs()) { + const DInputSocket to_dsocket{dnode.context(), socket_ref}; + if (!to_dsocket->is_available()) { + continue; + } + if (!socket_is_mf_data_socket(*to_dsocket->typeinfo())) { + continue; + } - for (fn::MFInputSocket *to_socket : common.network_map.lookup(dsocket)) { - common.network.add_link(*from_socket, *to_socket); - } -} + Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(to_dsocket); + BLI_assert(to_sockets.size() >= 1); + const fn::MFDataType to_type = to_sockets[0]->data_type(); -static void insert_unlinked_inputs(CommonMFNetworkBuilderData &common) -{ - Vector<const DInputSocket *> unlinked_data_inputs; - for (const DInputSocket *dsocket : common.tree.input_sockets()) { - if (dsocket->is_available()) { - if (socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) { - if (!dsocket->is_linked()) { - insert_unlinked_input(common, *dsocket); + Vector<DSocket> from_dsockets; + to_dsocket.foreach_origin_socket([&](DSocket socket) { from_dsockets.append(socket); }); + if (from_dsockets.size() > 1) { + fn::MFOutputSocket &from_socket = insert_default_value_for_type(common, to_type); + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(from_socket, *to_socket); + } + continue; + } + if (from_dsockets.is_empty()) { + /* The socket is not linked. Need to use the value of the socket itself. */ + fn::MFOutputSocket *built_socket = insert_unlinked_input(common, to_dsocket); + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(*built_socket, *to_socket); } + continue; + } + if (from_dsockets[0]->is_input()) { + DInputSocket from_dsocket{from_dsockets[0]}; + fn::MFOutputSocket *built_socket = insert_unlinked_input(common, from_dsocket); + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(*built_socket, *to_socket); + } + continue; + } + DOutputSocket from_dsocket{from_dsockets[0]}; + fn::MFOutputSocket *from_socket = &common.network_map.lookup(from_dsocket); + const fn::MFDataType from_type = from_socket->data_type(); + + if (from_type != to_type) { + const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion( + from_type, to_type); + if (conversion_fn != nullptr) { + fn::MFNode &node = common.network.add_function(*conversion_fn); + common.network.add_link(*from_socket, node.input(0)); + from_socket = &node.output(0); + } + else { + from_socket = &insert_default_value_for_type(common, to_type); + } + } + + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(*from_socket, *to_socket); } } - } + }); } /** @@ -376,9 +349,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, CommonMFNetworkBuilderData common{resources, network, network_map, tree}; insert_nodes(common); - insert_group_inputs(common); - insert_links(common); - insert_unlinked_inputs(common); + insert_links_and_unlinked_inputs(common); return network_map; } @@ -420,16 +391,17 @@ static NodeExpandType get_node_expand_type(MFNetworkTreeMap &network_map, } }; - for (const DInputSocket *dsocket : dnode.inputs()) { + for (const InputSocketRef *dsocket : dnode->inputs()) { if (dsocket->is_available()) { - for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) { + for (fn::MFInputSocket *mf_input : + network_map.lookup(DInputSocket(dnode.context(), dsocket))) { check_mf_node(mf_input->node()); } } } - for (const DOutputSocket *dsocket : dnode.outputs()) { + for (const OutputSocketRef *dsocket : dnode->outputs()) { if (dsocket->is_available()) { - fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket); + fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket)); check_mf_node(mf_output.node()); } } @@ -451,20 +423,21 @@ static const fn::MultiFunction &create_function_for_node_that_expands_into_multi ResourceCollector &resources) { Vector<const fn::MFOutputSocket *> dummy_fn_inputs; - for (const DInputSocket *dsocket : dnode.inputs()) { + for (const InputSocketRef *dsocket : dnode->inputs()) { if (dsocket->is_available()) { MFDataType data_type = *socket_mf_type_get(*dsocket->typeinfo()); fn::MFOutputSocket &fn_input = network.add_input(data_type.to_string(), data_type); - for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) { + for (fn::MFInputSocket *mf_input : + network_map.lookup(DInputSocket(dnode.context(), dsocket))) { network.add_link(fn_input, *mf_input); dummy_fn_inputs.append(&fn_input); } } } Vector<const fn::MFInputSocket *> dummy_fn_outputs; - for (const DOutputSocket *dsocket : dnode.outputs()) { + for (const OutputSocketRef *dsocket : dnode->outputs()) { if (dsocket->is_available()) { - fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket); + fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket)); MFDataType data_type = mf_output.data_type(); fn::MFInputSocket &fn_output = network.add_output(data_type.to_string(), data_type); network.add_link(mf_output, fn_output); @@ -492,18 +465,18 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, CommonMFNetworkBuilderData common{resources, network, network_map, tree}; - for (const DNode *dnode : tree.nodes()) { + tree.foreach_node([&](DNode dnode) { const bNodeType *node_type = dnode->typeinfo(); if (node_type->expand_in_mf_network == nullptr) { /* This node does not have a multi-function implementation. */ - continue; + return; } - NodeMFNetworkBuilder builder{common, *dnode}; + NodeMFNetworkBuilder builder{common, dnode}; node_type->expand_in_mf_network(builder); const fn::MultiFunction *single_function = nullptr; - const NodeExpandType expand_type = get_node_expand_type(network_map, *dnode, &single_function); + const NodeExpandType expand_type = get_node_expand_type(network_map, dnode, &single_function); switch (expand_type) { case NodeExpandType::HasDummyNodes: { @@ -519,12 +492,12 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, /* If a node expanded into multiple functions, a new function has to be created that * combines those. */ const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple( - *dnode, network, network_map, resources); + dnode, network, network_map, resources); functions_by_node.add_new(dnode, &fn); break; } } - } + }); return functions_by_node; } diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index 9dcd90f9f50..7fe21ec8582 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -52,6 +52,24 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) RNA_pointer_create(&btree->id, &RNA_NodeSocket, bsocket, &socket.rna_); } + LISTBASE_FOREACH (bNodeLink *, blink, &bnode->internal_links) { + InternalLinkRef &internal_link = *allocator_.construct<InternalLinkRef>(); + internal_link.blink_ = blink; + for (InputSocketRef *socket_ref : node.inputs_) { + if (socket_ref->bsocket_ == blink->fromsock) { + internal_link.from_ = socket_ref; + break; + } + } + for (OutputSocketRef *socket_ref : node.outputs_) { + if (socket_ref->bsocket_ == blink->tosock) { + internal_link.to_ = socket_ref; + break; + } + } + node.internal_links_.append(&internal_link); + } + input_sockets_.extend(node.inputs_.as_span()); output_sockets_.extend(node.outputs_.as_span()); @@ -64,8 +82,16 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) InputSocketRef &to_socket = this->find_input_socket( node_mapping, blink->tonode, blink->tosock); + LinkRef &link = *allocator_.construct<LinkRef>(); + link.from_ = &from_socket; + link.to_ = &to_socket; + link.blink_ = blink; + + links_.append(&link); from_socket.directly_linked_sockets_.append(&to_socket); to_socket.directly_linked_sockets_.append(&from_socket); + from_socket.directly_linked_links_.append(&link); + to_socket.directly_linked_links_.append(&link); } for (OutputSocketRef *socket : output_sockets_) { @@ -85,6 +111,8 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) NodeTreeRef::~NodeTreeRef() { + /* The destructor has to be called manually, because these types are allocated in a linear + * allocator. */ for (NodeRef *node : nodes_by_id_) { node->~NodeRef(); } @@ -94,6 +122,9 @@ NodeTreeRef::~NodeTreeRef() for (OutputSocketRef *socket : output_sockets_) { socket->~OutputSocketRef(); } + for (LinkRef *link : links_) { + link->~LinkRef(); + } } InputSocketRef &NodeTreeRef::find_input_socket(Map<bNode *, NodeRef *> &node_mapping, @@ -216,4 +247,10 @@ std::string NodeTreeRef::to_dot() const return digraph.to_dot_string(); } +const NodeTreeRef &get_tree_ref_from_map(NodeTreeRefMap &node_tree_refs, bNodeTree &btree) +{ + return *node_tree_refs.lookup_or_add_cb(&btree, + [&]() { return std::make_unique<NodeTreeRef>(&btree); }); +} + } // namespace blender::nodes diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index 25d6aef69e5..1a2405e021f 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -257,11 +257,11 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node } if (do_it) { - if (node->typeinfo->gpufunc) { + if (node->typeinfo->gpu_fn) { node_get_stack(node, stack, nsin, nsout); gpu_stack_from_data_list(gpuin, &node->inputs, nsin); gpu_stack_from_data_list(gpuout, &node->outputs, nsout); - if (node->typeinfo->gpufunc(mat, node, &nodeexec->data, gpuin, gpuout)) { + if (node->typeinfo->gpu_fn(mat, node, &nodeexec->data, gpuin, gpuout)) { data_from_gpu_stack_list(&node->outputs, nsout, gpuout); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c index 7ce085d2c82..499f62da683 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c @@ -55,8 +55,13 @@ static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; - return GPU_stack_link( - mat, node, "node_bsdf_anisotropic", in, out, GPU_constant(&use_multi_scatter)); + return GPU_stack_link(mat, + node, + "node_bsdf_anisotropic", + in, + out, + GPU_constant(&use_multi_scatter), + GPU_constant(&node->ssr_id)); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index f54914ceba9..7a846031456 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -116,7 +116,7 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild blender::fn::MFNetwork &network = builder.network(); blender::fn::MFFunctionNode &base_node = network.add_function(base_function); - builder.network_map().add_try_match(dnode.inputs(), base_node.inputs()); + builder.network_map().add_try_match(*dnode.context(), dnode->inputs(), base_node.inputs()); const bool clamp_output = builder.bnode().custom2 != 0; if (clamp_output) { @@ -126,10 +126,12 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild }}; blender::fn::MFFunctionNode &clamp_node = network.add_function(clamp_fn); network.add_link(base_node.output(0), clamp_node.input(0)); - builder.network_map().add(dnode.output(0), clamp_node.output(0)); + builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)), + clamp_node.output(0)); } else { - builder.network_map().add(dnode.output(0), base_node.output(0)); + builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)), + base_node.output(0)); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index 41c978e75ba..26a1db1f3a6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -90,7 +90,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, sampler &= ~GPU_SAMPLER_REPEAT; } - const char *gpufunc; + const char *gpu_fn; static const char *names[] = { "node_tex_image_linear", "node_tex_image_cubic", @@ -98,19 +98,19 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, switch (tex->interpolation) { case SHD_INTERP_LINEAR: - gpufunc = names[0]; + gpu_fn = names[0]; break; case SHD_INTERP_CLOSEST: sampler &= ~(GPU_SAMPLER_FILTER | GPU_SAMPLER_MIPMAP); - gpufunc = names[0]; + gpu_fn = names[0]; break; default: - gpufunc = names[1]; + gpu_fn = names[1]; break; } /* Sample texture with correct interpolation. */ - GPU_link(mat, gpufunc, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha); + GPU_link(mat, gpu_fn, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha); if (out[0].hasoutput) { if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) || diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index 5a8a1b847cc..495c8d12824 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -41,7 +41,7 @@ static int gpu_shader_value(GPUMaterial *mat, static void sh_node_value_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { - const bNodeSocket *bsocket = builder.dnode().output(0).bsocket(); + const bNodeSocket *bsocket = builder.dnode()->output(0).bsocket(); const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value; builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index b2132c59cde..d6ead5a8b99 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -32,7 +32,28 @@ static bNodeSocketTemplate sh_node_vector_rotate_in[] = { {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER}, {-1, ""}}; -static bNodeSocketTemplate sh_node_vector_rotate_out[] = {{SOCK_VECTOR, N_("Vector")}, {-1, ""}}; +static bNodeSocketTemplate sh_node_vector_rotate_out[] = { + {SOCK_VECTOR, N_("Vector")}, + {-1, ""}, +}; + +static const char *gpu_shader_get_name(int mode) +{ + switch (mode) { + case NODE_VECTOR_ROTATE_TYPE_AXIS: + return "node_vector_rotate_axis_angle"; + case NODE_VECTOR_ROTATE_TYPE_AXIS_X: + return "node_vector_rotate_axis_x"; + case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: + return "node_vector_rotate_axis_y"; + case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: + return "node_vector_rotate_axis_z"; + case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: + return "node_vector_rotate_euler_xyz"; + } + + return nullptr; +} static int gpu_shader_vector_rotate(GPUMaterial *mat, bNode *node, @@ -40,18 +61,11 @@ static int gpu_shader_vector_rotate(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { + const char *name = gpu_shader_get_name(node->custom1); - static const char *names[] = { - [NODE_VECTOR_ROTATE_TYPE_AXIS] = "node_vector_rotate_axis_angle", - [NODE_VECTOR_ROTATE_TYPE_AXIS_X] = "node_vector_rotate_axis_x", - [NODE_VECTOR_ROTATE_TYPE_AXIS_Y] = "node_vector_rotate_axis_y", - [NODE_VECTOR_ROTATE_TYPE_AXIS_Z] = "node_vector_rotate_axis_z", - [NODE_VECTOR_ROTATE_TYPE_EULER_XYZ] = "node_vector_rotate_euler_xyz", - }; - - if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) { + if (name != nullptr) { float invert = (node->custom2) ? -1.0 : 1.0; - return GPU_stack_link(mat, node, names[node->custom1], in, out, GPU_constant(&invert)); + return GPU_stack_link(mat, node, name, in, out, GPU_constant(&invert)); } return 0; diff --git a/source/blender/python/gpu/gpu_py_api.c b/source/blender/python/gpu/gpu_py_api.c index 68f7eb9816c..0bc18e73d0c 100644 --- a/source/blender/python/gpu/gpu_py_api.c +++ b/source/blender/python/gpu/gpu_py_api.c @@ -73,6 +73,9 @@ PyObject *BPyInit_gpu(void) PyModule_AddObject(mod, "state", (submodule = bpygpu_state_init())); PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + PyModule_AddObject(mod, "texture", (submodule = bpygpu_texture_init())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + return mod; } diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c index ef795268158..8e803350b53 100644 --- a/source/blender/python/gpu/gpu_py_batch.c +++ b/source/blender/python/gpu/gpu_py_batch.c @@ -279,8 +279,8 @@ static void pygpu_batch__tp_dealloc(BPyGPUBatch *self) GPU_batch_discard(self->batch); #ifdef USE_GPU_PY_REFERENCES + PyObject_GC_UnTrack(self); if (self->references) { - PyObject_GC_UnTrack(self); pygpu_batch__tp_clear(self); Py_XDECREF(self->references); } diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c index b89d2c6a69f..420a7873517 100644 --- a/source/blender/python/gpu/gpu_py_buffer.c +++ b/source/blender/python/gpu/gpu_py_buffer.c @@ -202,8 +202,7 @@ static void pygpu_buffer__tp_dealloc(BPyGPUBuffer *self) { if (self->parent) { PyObject_GC_UnTrack(self); - pygpu_buffer__tp_clear(self); - Py_XDECREF(self->parent); + Py_CLEAR(self->parent); } else { MEM_freeN(self->buf.as_void); diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 9d5671ff702..dff4b169f9a 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -336,8 +336,8 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar region, GPU_offscreen_width(self->ofs), GPU_offscreen_height(self->ofs), - (float(*)[4])py_mat_view->matrix, - (float(*)[4])py_mat_projection->matrix, + (const float(*)[4])py_mat_view->matrix, + (const float(*)[4])py_mat_projection->matrix, true, true, "", diff --git a/source/blender/python/gpu/gpu_py_texture.c b/source/blender/python/gpu/gpu_py_texture.c index 12855b8dbcc..14f901624fe 100644 --- a/source/blender/python/gpu/gpu_py_texture.c +++ b/source/blender/python/gpu/gpu_py_texture.c @@ -27,9 +27,13 @@ #include "BLI_string.h" +#include "DNA_image_types.h" + #include "GPU_context.h" #include "GPU_texture.h" +#include "BKE_image.h" + #include "../generic/py_capi_utils.h" #include "gpu_py.h" @@ -510,6 +514,53 @@ PyTypeObject BPyGPUTexture_Type = { /** \} */ /* -------------------------------------------------------------------- */ +/** \name GPU Texture module + * \{ */ +PyDoc_STRVAR(pygpu_texture_from_image_doc, + ".. function:: from_image(image)\n" + "\n" + " Get GPUTexture corresponding to an Image datablock. The GPUTexture memory is " + "shared with Blender.\n" + " Note: Colors read from the texture will be in scene linear color space and have " + "premultiplied or straight alpha matching the image alpha mode.\n" + "\n" + " :arg image: The Image datablock.\n" + " :type image: `bpy.types.Image`\n" + " :return: The GPUTexture used by the image.\n" + " :rtype: :class:`gpu.types.GPUTexture`\n"); +static PyObject *pygpu_texture_from_image(PyObject *UNUSED(self), PyObject *arg) +{ + Image *ima = PyC_RNA_AsPointer(arg, "Image"); + if (ima == NULL) { + return NULL; + } + + ImageUser iuser; + BKE_imageuser_default(&iuser); + GPUTexture *tex = BKE_image_get_gpu_texture(ima, &iuser, NULL); + + /* Increase the texture reference count. */ + GPU_texture_ref(tex); + + return BPyGPUTexture_CreatePyObject(tex); +} + +static struct PyMethodDef pygpu_texture__m_methods[] = { + {"from_image", (PyCFunction)pygpu_texture_from_image, METH_O, pygpu_texture_from_image_doc}, + {NULL, NULL, 0, NULL}, +}; + +PyDoc_STRVAR(pygpu_texure__m_doc, "This module provides utils for textures."); +static PyModuleDef pygpu_texture_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "gpu.texture", + .m_doc = pygpu_texure__m_doc, + .m_methods = pygpu_texture__m_methods, +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Local API * \{ */ @@ -534,6 +585,14 @@ int bpygpu_ParseTexture(PyObject *o, void *p) return 1; } +PyObject *bpygpu_texture_init(void) +{ + PyObject *submodule; + submodule = PyModule_Create(&pygpu_texture_module_def); + + return submodule; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/python/gpu/gpu_py_texture.h b/source/blender/python/gpu/gpu_py_texture.h index be7348b2bd4..5130273f971 100644 --- a/source/blender/python/gpu/gpu_py_texture.h +++ b/source/blender/python/gpu/gpu_py_texture.h @@ -31,4 +31,6 @@ typedef struct BPyGPUTexture { } BPyGPUTexture; int bpygpu_ParseTexture(PyObject *o, void *p); +PyObject *bpygpu_texture_init(void); + PyObject *BPyGPUTexture_CreatePyObject(struct GPUTexture *tex) ATTR_NONNULL(1); diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index c7e195b586d..927ec11c376 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -216,7 +216,7 @@ static PyObject *make_app_info(void) #undef SetObjItem if (PyErr_Occurred()) { - Py_CLEAR(app_info); + Py_DECREF(app_info); return NULL; } return app_info; diff --git a/source/blender/python/intern/bpy_app_alembic.c b/source/blender/python/intern/bpy_app_alembic.c index d5640045977..bb218c57d06 100644 --- a/source/blender/python/intern/bpy_app_alembic.c +++ b/source/blender/python/intern/bpy_app_alembic.c @@ -79,8 +79,8 @@ static PyObject *make_alembic_info(void) SetStrItem("Unknown"); #endif - if (PyErr_Occurred()) { - Py_CLEAR(alembic_info); + if (UNLIKELY(PyErr_Occurred())) { + Py_DECREF(alembic_info); return NULL; } diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c index 4e396668450..d2261ee7311 100644 --- a/source/blender/python/intern/bpy_app_ffmpeg.c +++ b/source/blender/python/intern/bpy_app_ffmpeg.c @@ -116,8 +116,8 @@ static PyObject *make_ffmpeg_info(void) #undef FFMPEG_LIB_VERSION - if (PyErr_Occurred()) { - Py_CLEAR(ffmpeg_info); + if (UNLIKELY(PyErr_Occurred())) { + Py_DECREF(ffmpeg_info); return NULL; } diff --git a/source/blender/python/intern/bpy_app_ocio.c b/source/blender/python/intern/bpy_app_ocio.c index 3a36e90018f..8ce87bd0150 100644 --- a/source/blender/python/intern/bpy_app_ocio.c +++ b/source/blender/python/intern/bpy_app_ocio.c @@ -81,8 +81,8 @@ static PyObject *make_ocio_info(void) SetStrItem("Unknown"); #endif - if (PyErr_Occurred()) { - Py_CLEAR(ocio_info); + if (UNLIKELY(PyErr_Occurred())) { + Py_DECREF(ocio_info); return NULL; } diff --git a/source/blender/python/intern/bpy_app_oiio.c b/source/blender/python/intern/bpy_app_oiio.c index 0038f982170..8436296680b 100644 --- a/source/blender/python/intern/bpy_app_oiio.c +++ b/source/blender/python/intern/bpy_app_oiio.c @@ -77,8 +77,8 @@ static PyObject *make_oiio_info(void) SetStrItem("Unknown"); #endif - if (PyErr_Occurred()) { - Py_CLEAR(oiio_info); + if (UNLIKELY(PyErr_Occurred())) { + Py_DECREF(oiio_info); return NULL; } diff --git a/source/blender/python/intern/bpy_app_opensubdiv.c b/source/blender/python/intern/bpy_app_opensubdiv.c index 90aab2a4500..635013a1f9e 100644 --- a/source/blender/python/intern/bpy_app_opensubdiv.c +++ b/source/blender/python/intern/bpy_app_opensubdiv.c @@ -74,8 +74,8 @@ static PyObject *make_opensubdiv_info(void) SetStrItem("Unknown"); #endif - if (PyErr_Occurred()) { - Py_CLEAR(opensubdiv_info); + if (UNLIKELY(PyErr_Occurred())) { + Py_DECREF(opensubdiv_info); return NULL; } diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c index c98c6ec0137..20a61ba170a 100644 --- a/source/blender/python/intern/bpy_app_openvdb.c +++ b/source/blender/python/intern/bpy_app_openvdb.c @@ -81,8 +81,8 @@ static PyObject *make_openvdb_info(void) SetStrItem("Unknown"); #endif - if (PyErr_Occurred()) { - Py_CLEAR(openvdb_info); + if (UNLIKELY(PyErr_Occurred())) { + Py_DECREF(openvdb_info); return NULL; } diff --git a/source/blender/python/intern/bpy_app_sdl.c b/source/blender/python/intern/bpy_app_sdl.c index 645119c1c5d..e45e73fb4de 100644 --- a/source/blender/python/intern/bpy_app_sdl.c +++ b/source/blender/python/intern/bpy_app_sdl.c @@ -114,8 +114,8 @@ static PyObject *make_sdl_info(void) SetObjItem(PyBool_FromLong(0)); #endif - if (PyErr_Occurred()) { - Py_CLEAR(sdl_info); + if (UNLIKELY(PyErr_Occurred())) { + Py_DECREF(sdl_info); return NULL; } diff --git a/source/blender/python/intern/bpy_app_usd.c b/source/blender/python/intern/bpy_app_usd.c index 4a0ee96061a..72287d45b93 100644 --- a/source/blender/python/intern/bpy_app_usd.c +++ b/source/blender/python/intern/bpy_app_usd.c @@ -80,8 +80,8 @@ static PyObject *make_usd_info(void) SetStrItem("Unknown"); #endif - if (PyErr_Occurred()) { - Py_CLEAR(usd_info); + if (UNLIKELY(PyErr_Occurred())) { + Py_DECREF(usd_info); return NULL; } diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 020c8f7ea49..03771a8c294 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -34,7 +34,6 @@ #include "BLI_string.h" #include "BLI_utildefines.h" -#include "BKE_context.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -68,9 +67,11 @@ typedef struct { BlendHandle *blo_handle; int flag; PyObject *dict; + /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries. */ + Main *bmain; } BPy_Library; -static PyObject *bpy_lib_load(PyObject *self, PyObject *args, PyObject *kwds); +static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kwds); static PyObject *bpy_lib_enter(BPy_Library *self); static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *args); static PyObject *bpy_lib_dir(BPy_Library *self); @@ -182,9 +183,9 @@ PyDoc_STRVAR( " :type relative: bool\n" " :arg assets_only: If True, only list data-blocks marked as assets.\n" " :type assets_only: bool\n"); -static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kw) { - Main *bmain = CTX_data_main(BPY_context_get()); + Main *bmain = self->ptr.data; /* Typically #G_MAIN */ BPy_Library *ret; const char *filename = NULL; bool is_rel = false, is_link = false, use_assets_only = false; @@ -210,11 +211,13 @@ static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject * BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath)); BLI_path_abs(ret->abspath, BKE_main_blendfile_path(bmain)); + ret->bmain = bmain; + ret->blo_handle = NULL; ret->flag = ((is_link ? FILE_LINK : 0) | (is_rel ? FILE_RELPATH : 0) | (use_assets_only ? FILE_ASSETS_ONLY : 0)); - ret->dict = _PyDict_NewPresized(MAX_LIBARRAY); + ret->dict = _PyDict_NewPresized(INDEX_ID_MAX); return (PyObject *)ret; } @@ -245,7 +248,7 @@ static PyObject *bpy_lib_enter(BPy_Library *self) { PyObject *ret; BPy_Library *self_from; - PyObject *from_dict = _PyDict_NewPresized(MAX_LIBARRAY); + PyObject *from_dict = _PyDict_NewPresized(INDEX_ID_MAX); ReportList reports; BKE_reports_init(&reports, RPT_STORE); @@ -333,7 +336,7 @@ static void bpy_lib_exit_warn_type(BPy_Library *self, PyObject *item) static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) { - Main *bmain = CTX_data_main(BPY_context_get()); + Main *bmain = self->bmain; Main *mainl = NULL; const int err = 0; const bool do_append = ((self->flag & FILE_LINK) == 0); @@ -477,7 +480,7 @@ static PyObject *bpy_lib_dir(BPy_Library *self) PyMethodDef BPY_library_load_method_def = { "load", (PyCFunction)bpy_lib_load, - METH_STATIC | METH_VARARGS | METH_KEYWORDS, + METH_VARARGS | METH_KEYWORDS, bpy_lib_load_doc, }; diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c index 66d20dd357f..f26f305cca8 100644 --- a/source/blender/python/intern/bpy_library_write.c +++ b/source/blender/python/intern/bpy_library_write.c @@ -71,7 +71,7 @@ PyDoc_STRVAR( " :type fake_user: bool\n" " :arg compress: When True, write a compressed blend file.\n" " :type compress: bool\n"); -static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +static PyObject *bpy_lib_write(BPy_PropertyRNA *self, PyObject *args, PyObject *kw) { /* args */ const char *filepath; @@ -114,7 +114,7 @@ static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject return NULL; } - Main *bmain_src = G_MAIN; + Main *bmain_src = self->ptr.data; /* Typically #G_MAIN */ int write_flags = 0; if (use_compress) { @@ -220,6 +220,6 @@ finally: PyMethodDef BPY_library_write_method_def = { "write", (PyCFunction)bpy_lib_write, - METH_STATIC | METH_VARARGS | METH_KEYWORDS, + METH_VARARGS | METH_KEYWORDS, bpy_lib_write_doc, }; diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index b2812e0eba7..246387486be 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -203,10 +203,8 @@ static const EnumPropertyItem property_subtype_array_items[] = { static void bpy_prop_deferred_dealloc(BPy_PropDeferred *self) { - if (self->kw) { - PyObject_GC_UnTrack(self); - Py_CLEAR(self->kw); - } + PyObject_GC_UnTrack(self); + Py_CLEAR(self->kw); PyObject_GC_Del(self); } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 189d8308c14..ecaa5791e38 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1204,15 +1204,15 @@ static void pyrna_struct_dealloc(BPy_StructRNA *self) static void pyrna_struct_reference_set(BPy_StructRNA *self, PyObject *reference) { if (self->reference) { - // PyObject_GC_UnTrack(self); /* INITIALIZED TRACKED ? */ - pyrna_struct_clear(self); + PyObject_GC_UnTrack(self); + Py_CLEAR(self->reference); } /* Reference is now NULL. */ if (reference) { self->reference = reference; Py_INCREF(reference); - // PyObject_GC_Track(self); /* INITIALIZED TRACKED ? */ + PyObject_GC_Track(self); } } #endif /* !USE_PYRNA_STRUCT_REFERENCE */ @@ -2022,45 +2022,54 @@ static int pyrna_py_to_prop( } } - if (!BPy_StructRNA_Check(value) && value != Py_None) { - PyErr_Format(PyExc_TypeError, - "%.200s %.200s.%.200s expected a %.200s type, not %.200s", - error_prefix, - RNA_struct_identifier(ptr->type), - RNA_property_identifier(prop), - RNA_struct_identifier(ptr_type), - Py_TYPE(value)->tp_name); - Py_XDECREF(value_new); - return -1; - } - if ((flag & PROP_NEVER_NULL) && value == Py_None) { - PyErr_Format(PyExc_TypeError, - "%.200s %.200s.%.200s does not support a 'None' assignment %.200s type", - error_prefix, - RNA_struct_identifier(ptr->type), - RNA_property_identifier(prop), - RNA_struct_identifier(ptr_type)); - Py_XDECREF(value_new); - return -1; + BPy_StructRNA *param; + if (value == Py_None) { + if (flag & PROP_NEVER_NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s %.200s.%.200s does not support a 'None' assignment %.200s type", + error_prefix, + RNA_struct_identifier(ptr->type), + RNA_property_identifier(prop), + RNA_struct_identifier(ptr_type)); + Py_XDECREF(value_new); + return -1; + } + param = NULL; } - if ((value != Py_None) && ((flag & PROP_ID_SELF_CHECK) && - ptr->owner_id == ((BPy_StructRNA *)value)->ptr.owner_id)) { - PyErr_Format(PyExc_TypeError, - "%.200s %.200s.%.200s ID type does not support assignment to itself", - error_prefix, - RNA_struct_identifier(ptr->type), - RNA_property_identifier(prop)); - Py_XDECREF(value_new); - return -1; + else { + if (!BPy_StructRNA_Check(value)) { + PyErr_Format(PyExc_TypeError, + "%.200s %.200s.%.200s expected a %.200s type, not %.200s", + error_prefix, + RNA_struct_identifier(ptr->type), + RNA_property_identifier(prop), + RNA_struct_identifier(ptr_type), + Py_TYPE(value)->tp_name); + Py_XDECREF(value_new); + return -1; + } + param = (BPy_StructRNA *)value; + + const ID *value_owner_id = ((BPy_StructRNA *)value)->ptr.owner_id; + if (value_owner_id != NULL) { + if ((flag & PROP_ID_SELF_CHECK) && (ptr->owner_id == value_owner_id)) { + PyErr_Format(PyExc_TypeError, + "%.200s %.200s.%.200s ID type does not support assignment to itself", + error_prefix, + RNA_struct_identifier(ptr->type), + RNA_property_identifier(prop)); + Py_XDECREF(value_new); + return -1; + } + } } - BPy_StructRNA *param = (BPy_StructRNA *)value; bool raise_error = false; if (data) { if (flag_parameter & PARM_RNAPTR) { if (flag & PROP_THICK_WRAP) { - if (value == Py_None) { + if (param == NULL) { memset(data, 0, sizeof(PointerRNA)); } else if (RNA_struct_is_a(param->ptr.type, ptr_type)) { @@ -2075,7 +2084,7 @@ static int pyrna_py_to_prop( * but watch out that it remains valid! * We could possibly support this later if needed. */ BLI_assert(value_new == NULL); - if (value == Py_None) { + if (param == NULL) { *((void **)data) = NULL; } else if (RNA_struct_is_a(param->ptr.type, ptr_type)) { @@ -2086,7 +2095,7 @@ static int pyrna_py_to_prop( } } } - else if (value == Py_None) { + else if (param == NULL) { *((void **)data) = NULL; } else if (RNA_struct_is_a(param->ptr.type, ptr_type)) { @@ -2098,11 +2107,11 @@ static int pyrna_py_to_prop( } else { /* Data == NULL, assign to RNA. */ - if (value == Py_None || RNA_struct_is_a(param->ptr.type, ptr_type)) { + if ((param == NULL) || RNA_struct_is_a(param->ptr.type, ptr_type)) { ReportList reports; BKE_reports_init(&reports, RPT_STORE); RNA_property_pointer_set( - ptr, prop, value == Py_None ? PointerRNA_NULL : param->ptr, &reports); + ptr, prop, (param == NULL) ? PointerRNA_NULL : param->ptr, &reports); const int err = (BPy_reports_to_error(&reports, PyExc_RuntimeError, true)); if (err == -1) { Py_XDECREF(value_new); @@ -4589,13 +4598,12 @@ static PyObject *pyrna_prop_collection_getattro(BPy_PropertyRNA *self, PyObject #else { /* Could just do this except for 1 awkward case. - * PyObject_GenericGetAttr((PyObject *)self, pyname); - * so as to support 'bpy.data.library.load()' - * note, this _only_ supports static methods */ + * `PyObject_GenericGetAttr((PyObject *)self, pyname);` + * so as to support `bpy.data.library.load()` */ PyObject *ret = PyObject_GenericGetAttr((PyObject *)self, pyname); - if (ret == NULL && name[0] != '_') { /* Avoid inheriting __call__ and similar. */ + if (ret == NULL && name[0] != '_') { /* Avoid inheriting `__call__` and similar. */ /* Since this is least common case, handle it last. */ PointerRNA r_ptr; if (RNA_property_collection_type_get(&self->ptr, self->prop, &r_ptr)) { @@ -4613,6 +4621,19 @@ static PyObject *pyrna_prop_collection_getattro(BPy_PropertyRNA *self, PyObject if (ret == NULL) { PyErr_Restore(error_type, error_value, error_traceback); } + else { + if (Py_TYPE(ret) == &PyMethodDescr_Type) { + PyMethodDef *m = ((PyMethodDescrObject *)ret)->d_method; + /* TODO: #METH_CLASS */ + if (m->ml_flags & METH_STATIC) { + /* Keep 'ret' as-is. */ + } + else { + Py_DECREF(ret); + ret = PyCMethod_New(m, (PyObject *)self, NULL, NULL); + } + } + } } } @@ -5813,6 +5834,11 @@ static PyObject *pyrna_struct_new(PyTypeObject *type, PyObject *args, PyObject * BPy_StructRNA *ret; if ((ret = (BPy_StructRNA *)type->tp_alloc(type, 0))) { ret->ptr = base->ptr; +#ifdef USE_PYRNA_STRUCT_REFERENCE + /* #PyType_GenericAlloc will have set tracking. + * We only want tracking when `StructRNA.reference` has been set. */ + PyObject_GC_UnTrack(ret); +#endif } /* Pass on exception & NULL if tp_alloc fails. */ return (PyObject *)ret; @@ -6516,7 +6542,11 @@ PyTypeObject pyrna_struct_Type = { NULL, /* PyBufferProcs *tp_as_buffer; */ /*** Flags to define presence of optional/expanded features ***/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE +#ifdef USE_PYRNA_STRUCT_REFERENCE + | Py_TPFLAGS_HAVE_GC +#endif + , /* long tp_flags; */ NULL, /* char *tp_doc; Documentation string */ /*** Assigned meaning in release 2.0 ***/ @@ -7453,13 +7483,28 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) if (tp) { pyrna = (BPy_StructRNA *)tp->tp_alloc(tp, 0); +#ifdef USE_PYRNA_STRUCT_REFERENCE + /* #PyType_GenericAlloc will have set tracking. + * We only want tracking when `StructRNA.reference` has been set. */ + if (pyrna != NULL) { + PyObject_GC_UnTrack(pyrna); + } +#endif Py_DECREF(tp); /* srna owns, can't hold a reference. */ } else { CLOG_WARN(BPY_LOG_RNA, "could not make type '%s'", RNA_struct_identifier(ptr->type)); + +#ifdef USE_PYRNA_STRUCT_REFERENCE pyrna = (BPy_StructRNA *)PyObject_GC_New(BPy_StructRNA, &pyrna_struct_Type); +#else + pyrna = (BPy_StructRNA *)PyObject_New(BPy_StructRNA, &pyrna_struct_Type); +#endif + #ifdef USE_WEAKREFS - pyrna->in_weakreflist = NULL; + if (pyrna != NULL) { + pyrna->in_weakreflist = NULL; + } #endif } } @@ -8961,7 +9006,7 @@ static PyObject *pyrna_unregister_class(PyObject *UNUSED(self), PyObject *py_cla #if 0 if (PyDict_GetItem(((PyTypeObject *)py_class)->tp_dict, bpy_intern_str_bl_rna) == NULL) { - PWM_cursor_wait(0); + PWM_cursor_wait(false); PyErr_SetString(PyExc_ValueError, "unregister_class(): not a registered as a subclass"); return NULL; } diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h index b136cb35e09..7d728b25a30 100644 --- a/source/blender/sequencer/SEQ_add.h +++ b/source/blender/sequencer/SEQ_add.h @@ -30,50 +30,74 @@ extern "C" { struct ListBase; struct Scene; struct Sequence; -struct bContext; -/* api for adding new sequence strips */ -typedef struct SeqLoadInfo { +/* SeqLoadData.flags */ +typedef enum eSeqLoadFlags { + SEQ_LOAD_SOUND_CACHE = (1 << 1), + SEQ_LOAD_SOUND_MONO = (1 << 2), + SEQ_LOAD_MOVIE_SYNC_FPS = (1 << 3), +} eSeqLoadFlags; + +/* Api for adding new sequence strips. */ +typedef struct SeqLoadData { int start_frame; - int end_frame; int channel; - int flag; /* use sound, replace sel */ - int type; - int len; /* only for image strips */ + char name[64]; /* Strip name. */ char path[1024]; /* 1024 = FILE_MAX */ + struct { + int len; + int end_frame; + } image; /* Only for image strips. */ + struct Scene *scene; /* Only for scene strips. */ + struct MovieClip *clip; /* Only for clip strips. */ + struct Mask *mask; /* Only for mask strips. */ + struct { + int type; + int end_frame; + struct Sequence *seq1; + struct Sequence *seq2; + struct Sequence *seq3; + } effect; /* Only for effect strips. */ + eSeqLoadFlags flags; eSeqImageFitMethod fit_method; - - /* multiview */ + bool use_multiview; char views_format; struct Stereo3dFormat *stereo3d_format; + bool allow_invalid_file; /* Used by RNA API to create placeholder strips. */ +} SeqLoadData; - /* return values */ - char name[64]; - struct Sequence *seq_sound; /* for movie's */ - int tot_success; - int tot_error; -} SeqLoadInfo; - -/* SeqLoadInfo.flag */ -#define SEQ_LOAD_REPLACE_SEL (1 << 0) -#define SEQ_LOAD_FRAME_ADVANCE (1 << 1) -#define SEQ_LOAD_MOVIE_SOUND (1 << 2) -#define SEQ_LOAD_SOUND_CACHE (1 << 3) -#define SEQ_LOAD_SYNC_FPS (1 << 4) -#define SEQ_LOAD_SOUND_MONO (1 << 5) - -/* use as an api function */ -typedef struct Sequence *(*SeqLoadFn)(struct bContext *, ListBase *, struct SeqLoadInfo *); - -struct Sequence *SEQ_add_image_strip(struct bContext *C, - ListBase *seqbasep, - struct SeqLoadInfo *seq_load); -struct Sequence *SEQ_add_sound_strip(struct bContext *C, - ListBase *seqbasep, - struct SeqLoadInfo *seq_load); -struct Sequence *SEQ_add_movie_strip(struct bContext *C, - ListBase *seqbasep, - struct SeqLoadInfo *seq_load); +void SEQ_add_load_data_init(struct SeqLoadData *load_data, + const char *name, + const char *path, + const int start_frame, + const int channel); +struct Sequence *SEQ_add_image_strip(struct Main *bmain, + struct Scene *scene, + struct ListBase *seqbase, + struct SeqLoadData *load_data); +struct Sequence *SEQ_add_sound_strip(struct Main *bmain, + struct Scene *scene, + struct ListBase *seqbase, + struct SeqLoadData *load_data); +struct Sequence *SEQ_add_movie_strip(struct Main *bmain, + struct Scene *scene, + struct ListBase *seqbase, + struct SeqLoadData *load_data); +struct Sequence *SEQ_add_scene_strip(struct Scene *scene, + struct ListBase *seqbase, + struct SeqLoadData *load_data); +struct Sequence *SEQ_add_movieclip_strip(struct Scene *scene, + struct ListBase *seqbase, + struct SeqLoadData *load_data); +struct Sequence *SEQ_add_mask_strip(struct Scene *scene, + struct ListBase *seqbase, + struct SeqLoadData *load_data); +struct Sequence *SEQ_add_effect_strip(struct Scene *scene, + struct ListBase *seqbase, + struct SeqLoadData *load_data); +void SEQ_add_image_set_directory(struct Sequence *seq, char *path); +void SEQ_add_image_load_file(struct Sequence *seq, size_t strip_frame, char *filename); +void SEQ_add_image_init_alpha_mode(struct Sequence *seq); void SEQ_add_reload_new_file(struct Main *bmain, struct Scene *scene, struct Sequence *seq, diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h index ccadfc54e1d..85513faf3e6 100644 --- a/source/blender/sequencer/SEQ_sequencer.h +++ b/source/blender/sequencer/SEQ_sequencer.h @@ -62,8 +62,12 @@ struct Editing *SEQ_editing_get(struct Scene *scene, bool alloc); struct Editing *SEQ_editing_ensure(struct Scene *scene); void SEQ_editing_free(struct Scene *scene, const bool do_id_user); struct ListBase *SEQ_active_seqbase_get(const struct Editing *ed); +void SEQ_seqbase_active_set(struct Editing *ed, struct ListBase *seqbase); struct Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int type); void SEQ_sequence_free(struct Scene *scene, struct Sequence *seq, const bool do_clean_animdata); +struct MetaStack *SEQ_meta_stack_alloc(struct Editing *ed, struct Sequence *seq_meta); +struct MetaStack *SEQ_meta_stack_active_get(const struct Editing *ed); +void SEQ_meta_stack_free(struct Editing *ed, struct MetaStack *ms); void SEQ_offset_animdata(struct Scene *scene, struct Sequence *seq, int ofs); void SEQ_dupe_animdata(struct Scene *scene, const char *name_src, const char *name_dst); struct Sequence *SEQ_sequence_dupli_recursive(const struct Scene *scene_src, diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index e9de73bc093..cf07fc7bc19 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -203,34 +203,6 @@ void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4 } } -void SEQ_render_init_colorspace(Sequence *seq) -{ - if (seq->strip && seq->strip->stripdata) { - char name[FILE_MAX]; - ImBuf *ibuf; - - BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); - BLI_path_abs(name, BKE_main_blendfile_path_from_global()); - - /* initialize input color space */ - if (seq->type == SEQ_TYPE_IMAGE) { - ibuf = IMB_loadiffname( - name, IB_test | IB_alphamode_detect, seq->strip->colorspace_settings.name); - - /* byte images are default to straight alpha, however sequencer - * works in premul space, so mark strip to be premultiplied first - */ - seq->alpha_mode = SEQ_ALPHA_STRAIGHT; - if (ibuf) { - if (ibuf->flags & IB_alphamode_premul) { - seq->alpha_mode = IMA_ALPHA_PREMUL; - } - - IMB_freeImBuf(ibuf); - } - } - } -} /** \} */ /* -------------------------------------------------------------------- */ @@ -611,6 +583,7 @@ static bool seq_need_scale_to_render_size(const Sequence *seq, bool is_proxy_ima return true; } if ((seq->type & SEQ_TYPE_EFFECT) != 0 || seq->type == SEQ_TYPE_MASK || + seq->type == SEQ_TYPE_META || (seq->type == SEQ_TYPE_SCENE && ((seq->flag & SEQ_SCENE_STRIPS) != 0))) { return true; } diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index 4a0e4f1d9ad..4db7350544b 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -344,6 +344,58 @@ ListBase *SEQ_active_seqbase_get(const Editing *ed) return ed->seqbasep; } + +/** + * Set seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase + * + * \param ed: sequence editor data + * \param seqbase: ListBase with strips + */ +void SEQ_seqbase_active_set(Editing *ed, ListBase *seqbase) +{ + ed->seqbasep = seqbase; +} + +/** + * Create and initialize #MetaStack, append it to `ed->metastack` ListBase + * + * \param ed: sequence editor data + * \param seq_meta: meta strip + * \return pointer to created meta stack + */ +MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta) +{ + MetaStack *ms = MEM_mallocN(sizeof(MetaStack), "metastack"); + BLI_addtail(&ed->metastack, ms); + ms->parseq = seq_meta; + ms->oldbasep = ed->seqbasep; + copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp); + return ms; +} + +/** + * Free #MetaStack and remove it from `ed->metastack` ListBase. + * + * \param ed: sequence editor data + * \param ms: meta stack + */ +void SEQ_meta_stack_free(Editing *ed, MetaStack *ms) +{ + BLI_remlink(&ed->metastack, ms); + MEM_freeN(ms); +} + +/** + * Get #MetaStack that corresponds to current level that is being viewed + * + * \param ed: sequence editor data + * \return pointer to meta stack + */ +MetaStack *SEQ_meta_stack_active_get(const Editing *ed) +{ + return ed->metastack.last; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index ba080a07879..54e71ff0698 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -29,6 +29,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_mask_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" #include "DNA_sound_types.h" @@ -54,7 +55,9 @@ #include "IMB_metadata.h" #include "SEQ_add.h" +#include "SEQ_effects.h" #include "SEQ_relations.h" +#include "SEQ_render.h" #include "SEQ_select.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" @@ -65,168 +68,372 @@ #include "proxy.h" #include "utils.h" -static void seq_load_apply(Main *bmain, Scene *scene, Sequence *seq, SeqLoadInfo *seq_load) +/** + * Initialize common SeqLoadData members + * + * \param load_data: SeqLoadData to be initialized + * \param name: strip name (can be NULL) + * \param path: path to file that is used as strip input (can be NULL) + * \param start_frame: timeline frame where strip will be created + * \param channel: timeline channel where strip will be created + * + */ +void SEQ_add_load_data_init(SeqLoadData *load_data, + const char *name, + const char *path, + const int start_frame, + const int channel) { - if (seq) { - BLI_strncpy_utf8(seq->name + 2, seq_load->name, sizeof(seq->name) - 2); - BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2)); - SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); + memset(load_data, 0, sizeof(SeqLoadData)); + if (name != NULL) { + BLI_strncpy(load_data->name, name, sizeof(load_data->name)); + } + if (path != NULL) { + BLI_strncpy(load_data->path, path, sizeof(load_data->path)); + } + load_data->start_frame = start_frame; + load_data->channel = channel; +} - if (seq_load->flag & SEQ_LOAD_FRAME_ADVANCE) { - seq_load->start_frame += (seq->enddisp - seq->startdisp); - } +static void seq_add_generic_update(Scene *scene, ListBase *seqbase, Sequence *seq) +{ + SEQ_sequence_base_unique_name_recursive(seqbase, seq); + SEQ_time_update_sequence_bounds(scene, seq); + SEQ_sort(scene); + SEQ_relations_invalidate_cache_composite(scene, seq); +} - if (seq_load->flag & SEQ_LOAD_REPLACE_SEL) { - seq_load->flag |= SELECT; - SEQ_select_active_set(scene, seq); +static void seq_add_set_name(Sequence *seq, SeqLoadData *load_data) +{ + if (load_data->name != NULL) { + BLI_strncpy(seq->name + 2, load_data->name, sizeof(seq->name) - 2); + } + else { + if (seq->type == SEQ_TYPE_SCENE) { + BLI_strncpy(seq->name + 2, load_data->scene->id.name + 2, sizeof(seq->name) - 2); } - - if (seq_load->flag & SEQ_LOAD_SOUND_MONO) { - seq->sound->flags |= SOUND_FLAGS_MONO; - BKE_sound_load(bmain, seq->sound); + else if (seq->type == SEQ_TYPE_MOVIECLIP) { + BLI_strncpy(seq->name + 2, load_data->clip->id.name + 2, sizeof(seq->name) - 2); } - - if (seq_load->flag & SEQ_LOAD_SOUND_CACHE) { - if (seq->sound) { - seq->sound->flags |= SOUND_FLAGS_CACHING; - } + else if (seq->type == SEQ_TYPE_MASK) { + BLI_strncpy(seq->name + 2, load_data->mask->id.name + 2, sizeof(seq->name) - 2); + } + else if ((seq->type & SEQ_TYPE_EFFECT) != 0) { + BLI_strncpy(seq->name + 2, SEQ_sequence_give_name(seq), sizeof(seq->name) - 2); + } + else { /* Image, sound and movie. */ + BLI_strncpy_utf8(seq->name + 2, load_data->name, sizeof(seq->name) - 2); + BLI_utf8_invalid_strip(seq->name + 2, strlen(seq->name + 2)); } - - seq_load->tot_success++; - } - else { - seq_load->tot_error++; } } -/* NOTE: this function doesn't fill in image names */ -Sequence *SEQ_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) +/** + * Add scene strip. + * + * \param scene: Scene where strips will be added + * \param seqbase: ListBase where strips will be added + * \param load_data: SeqLoadData with information necessary to create strip + * \return created strip + */ +Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data) { - Scene *scene = CTX_data_scene(C); /* only for active seq */ - Sequence *seq; - Strip *strip; + Sequence *seq = SEQ_sequence_alloc( + seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE); + seq->blend_mode = SEQ_TYPE_CROSS; + seq->scene = load_data->scene; + seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1; + id_us_ensure_real((ID *)load_data->scene); + seq_add_set_name(seq, load_data); + seq_add_generic_update(scene, seqbase, seq); + return seq; +} - seq = SEQ_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_IMAGE); - seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ +/** + * Add movieclip strip. + * + * \param scene: Scene where strips will be added + * \param seqbase: ListBase where strips will be added + * \param load_data: SeqLoadData with information necessary to create strip + * \return created strip + */ +Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data) +{ + Sequence *seq = SEQ_sequence_alloc( + seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP); + seq->blend_mode = SEQ_TYPE_CROSS; + seq->clip = load_data->clip; + seq->len = BKE_movieclip_get_duration(load_data->clip); + id_us_ensure_real((ID *)load_data->clip); + seq_add_set_name(seq, load_data); + seq_add_generic_update(scene, seqbase, seq); + return seq; +} - /* basic defaults */ - seq->len = seq_load->len ? seq_load->len : 1; +/** + * Add mask strip. + * + * \param scene: Scene where strips will be added + * \param seqbase: ListBase where strips will be added + * \param load_data: SeqLoadData with information necessary to create strip + * \return created strip + */ +Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data) +{ + Sequence *seq = SEQ_sequence_alloc( + seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK); + seq->blend_mode = SEQ_TYPE_CROSS; + seq->mask = load_data->mask; + seq->len = BKE_mask_get_duration(load_data->mask); + id_us_ensure_real((ID *)load_data->mask); + seq_add_set_name(seq, load_data); + seq_add_generic_update(scene, seqbase, seq); + return seq; +} - strip = seq->strip; - strip->stripdata = MEM_callocN(seq->len * sizeof(StripElem), "stripelem"); - BLI_strncpy(strip->dir, seq_load->path, sizeof(strip->dir)); +/** + * Add effect strip. + * + * \param scene: Scene where strips will be added + * \param seqbase: ListBase where strips will be added + * \param load_data: SeqLoadData with information necessary to create strip + * \return created strip + */ +Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data) +{ + Sequence *seq = SEQ_sequence_alloc( + seqbase, load_data->start_frame, load_data->channel, load_data->effect.type); + + seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE; + struct SeqEffectHandle sh = SEQ_effect_handle_get(seq); + sh.init(seq); + seq->seq1 = load_data->effect.seq1; + seq->seq2 = load_data->effect.seq2; + seq->seq3 = load_data->effect.seq3; + + if (seq->type == SEQ_TYPE_COLOR) { + seq->blend_mode = SEQ_TYPE_CROSS; + } + else if (seq->type == SEQ_TYPE_ADJUSTMENT) { + seq->blend_mode = SEQ_TYPE_CROSS; + } + else if (seq->type == SEQ_TYPE_TEXT) { + seq->blend_mode = SEQ_TYPE_ALPHAOVER; + } + else if (SEQ_effect_get_num_inputs(seq->type) == 1) { + seq->blend_mode = seq->seq1->blend_mode; + } - if (seq_load->stereo3d_format) { - *seq->stereo3d_format = *seq_load->stereo3d_format; + if (!load_data->effect.seq1) { + seq->len = 1; /* Effect is generator, set non zero length. */ + SEQ_transform_set_right_handle_frame(seq, load_data->image.end_frame); } + SEQ_relations_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs SEQ_time_update_sequence. */ + seq_add_set_name(seq, load_data); + seq_add_generic_update(scene, seqbase, seq); + + return seq; +} + +/** + * Set directory used by image strip. + * + * \param seq: image strip to be changed + * \param path: directory path + */ +void SEQ_add_image_set_directory(Sequence *seq, char *path) +{ + BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir)); +} - seq->views_format = seq_load->views_format; - seq->flag |= seq_load->flag & SEQ_USE_VIEWS; +/** + * Set directory used by image strip. + * + * \param seq: image strip to be changed + * \param strip_frame: frame index of strip to be changed + * \param filename: image filename (only filename, not complete path) + */ +void SEQ_add_image_load_file(Sequence *seq, size_t strip_frame, char *filename) +{ + StripElem *se = SEQ_render_give_stripelem(seq, seq->start + strip_frame); + BLI_strncpy(se->name, filename, sizeof(se->name)); +} - seq_load_apply(CTX_data_main(C), scene, seq, seq_load); +/** + * Set image strip alpha mode + * + * \param seq: image strip to be changed + */ +void SEQ_add_image_init_alpha_mode(Sequence *seq) +{ + if (seq->strip && seq->strip->stripdata) { + char name[FILE_MAX]; + ImBuf *ibuf; + + BLI_join_dirfile(name, sizeof(name), seq->strip->dir, seq->strip->stripdata->name); + BLI_path_abs(name, BKE_main_blendfile_path_from_global()); + + /* Initialize input color space. */ + if (seq->type == SEQ_TYPE_IMAGE) { + ibuf = IMB_loadiffname( + name, IB_test | IB_alphamode_detect, seq->strip->colorspace_settings.name); + + /* Byte images are default to straight alpha, however sequencer + * works in premul space, so mark strip to be premultiplied first. + */ + seq->alpha_mode = SEQ_ALPHA_STRAIGHT; + if (ibuf) { + if (ibuf->flags & IB_alphamode_premul) { + seq->alpha_mode = IMA_ALPHA_PREMUL; + } + IMB_freeImBuf(ibuf); + } + } + } +} + +/** + * Add image strip. + * NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences + * + * \param main: Main reference + * \param scene: Scene where strips will be added + * \param seqbase: ListBase where strips will be added + * \param load_data: SeqLoadData with information necessary to create strip + * \return created strip + */ +Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data) +{ + Sequence *seq = SEQ_sequence_alloc( + seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE); + seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ + seq->len = load_data->image.len; + Strip *strip = seq->strip; + strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem"); + + /* Multiview settings. */ + if (load_data->use_multiview) { + seq->flag |= SEQ_USE_VIEWS; + seq->views_format = load_data->views_format; + } + if (load_data->stereo3d_format) { + seq->stereo3d_format = load_data->stereo3d_format; + } + + /* Set initial scale based on load_data->fit_method. */ char file_path[FILE_MAX]; - BLI_join_dirfile(file_path, sizeof(file_path), seq_load->path, seq_load->name); - BLI_path_abs(file_path, BKE_main_blendfile_path(CTX_data_main(C))); + BLI_join_dirfile(file_path, sizeof(file_path), load_data->path, load_data->name); + BLI_path_abs(file_path, BKE_main_blendfile_path(bmain)); ImBuf *ibuf = IMB_loadiffname(file_path, IB_rect, seq->strip->colorspace_settings.name); if (ibuf != NULL) { SEQ_set_scale_to_fit( - seq, ibuf->x, ibuf->y, scene->r.xsch, scene->r.ysch, seq_load->fit_method); + seq, ibuf->x, ibuf->y, scene->r.xsch, scene->r.ysch, load_data->fit_method); IMB_freeImBuf(ibuf); } - SEQ_relations_invalidate_cache_composite(scene, seq); + /* Set Last active directory. */ + BLI_strncpy(scene->ed->act_imagedir, seq->strip->dir, sizeof(scene->ed->act_imagedir)); + seq_add_set_name(seq, load_data); + seq_add_generic_update(scene, seqbase, seq); return seq; } #ifdef WITH_AUDASPACE -Sequence *SEQ_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); /* only for sound */ - Editing *ed = SEQ_editing_get(scene, false); - bSound *sound; - - Sequence *seq; /* generic strip vars */ - Strip *strip; - StripElem *se; - - sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */ +/** + * Add sound strip. + * NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences + * + * \param main: Main reference + * \param scene: Scene where strips will be added + * \param seqbase: ListBase where strips will be added + * \param load_data: SeqLoadData with information necessary to create strip + * \return created strip + */ +Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data) +{ + bSound *sound = BKE_sound_new_file(bmain, load_data->path); /* Handles relative paths. */ SoundInfo info; - if (!BKE_sound_info_get(bmain, sound, &info)) { + bool sound_loaded = BKE_sound_info_get(bmain, sound, &info); + + if (!sound_loaded && !load_data->allow_invalid_file) { BKE_id_free(bmain, sound); return NULL; } - if (info.specs.channels == SOUND_CHANNELS_INVALID) { + if (info.specs.channels == SOUND_CHANNELS_INVALID && !load_data->allow_invalid_file) { BKE_id_free(bmain, sound); return NULL; } - seq = SEQ_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_SOUND_RAM); + Sequence *seq = SEQ_sequence_alloc( + seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SOUND_RAM); seq->sound = sound; - BLI_strncpy(seq->name + 2, "Sound", SEQ_NAME_MAXSTR - 2); - SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); + seq->scene_sound = NULL; - /* basic defaults */ /* We add a very small negative offset here, because * ceil(132.0) == 133.0, not nice with videos, see T47135. */ - seq->len = (int)ceil((double)info.length * FPS - 1e-4); - strip = seq->strip; - - /* we only need 1 element to store the filename */ - strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem"); - - BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name)); + seq->len = MAX2(1, (int)ceil((double)info.length * FPS - 1e-4)); - seq->scene_sound = NULL; - - SEQ_time_update_sequence_bounds(scene, seq); + Strip *strip = seq->strip; + /* We only need 1 element to store the filename. */ + StripElem *se = strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem"); + BLI_split_dirfile(load_data->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name)); - /* last active name */ - BLI_strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR); + if (seq != NULL && seq->sound != NULL) { + if (load_data->flags & SEQ_LOAD_SOUND_MONO) { + seq->sound->flags |= SOUND_FLAGS_MONO; + } - seq_load_apply(bmain, scene, seq, seq_load); + if (load_data->flags & SEQ_LOAD_SOUND_CACHE) { + if (seq->sound) { + seq->sound->flags |= SOUND_FLAGS_CACHING; + } + } + } - /* TODO(sergey): Shall we tag here or in the operator? */ - DEG_relations_tag_update(bmain); + /* Set Last active directory. */ + BLI_strncpy(scene->ed->act_sounddir, strip->dir, FILE_MAXDIR); + seq_add_set_name(seq, load_data); + seq_add_generic_update(scene, seqbase, seq); return seq; } + #else // WITH_AUDASPACE -Sequence *SEQ_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) +Sequence *SEQ_add_sound_strip(Main *UNUSED(bmain), + Scene *UNUSED(scene), + ListBase *UNUSED(seqbase), + SeqLoadData *UNUSED(load_data)) { - (void)C; - (void)seqbasep; - (void)seq_load; return NULL; } #endif // WITH_AUDASPACE -Sequence *SEQ_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_load) +/** + * Add movie strip. + * + * \param main: Main reference + * \param scene: Scene where strips will be added + * \param seqbase: ListBase where strips will be added + * \param load_data: SeqLoadData with information necessary to create strip + * \return created strip + */ +Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); /* only for sound */ - char path[sizeof(seq_load->path)]; + char path[sizeof(load_data->path)]; + BLI_strncpy(path, load_data->path, sizeof(path)); + BLI_path_abs(path, BKE_main_blendfile_path(bmain)); - Sequence *seq; /* generic strip vars */ - Strip *strip; - StripElem *se; char colorspace[64] = "\0"; /* MAX_COLORSPACE_NAME */ bool is_multiview_loaded = false; - const bool is_multiview = (seq_load->flag & SEQ_USE_VIEWS) != 0; - const int totfiles = seq_num_files(scene, seq_load->views_format, is_multiview); - struct anim **anim_arr; + const int totfiles = seq_num_files(scene, load_data->views_format, load_data->use_multiview); + struct anim **anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files"); int i; - BLI_strncpy(path, seq_load->path, sizeof(path)); - BLI_path_abs(path, BKE_main_blendfile_path(bmain)); - - anim_arr = MEM_callocN(sizeof(struct anim *) * totfiles, "Video files"); - - if (is_multiview && (seq_load->views_format == R_IMF_VIEWS_INDIVIDUAL)) { + if (load_data->use_multiview && (load_data->views_format == R_IMF_VIEWS_INDIVIDUAL)) { char prefix[FILE_MAX]; const char *ext = NULL; size_t j = 0; @@ -245,38 +452,30 @@ Sequence *SEQ_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_ j++; } } - - if (j == 0) { - MEM_freeN(anim_arr); - return NULL; - } is_multiview_loaded = true; } } if (is_multiview_loaded == false) { anim_arr[0] = openanim(path, IB_rect, 0, colorspace); - - if (anim_arr[0] == NULL) { - MEM_freeN(anim_arr); - return NULL; - } } - if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) { - seq_load->channel++; + if (anim_arr[0] == NULL && !load_data->allow_invalid_file) { + MEM_freeN(anim_arr); + return NULL; } - seq = SEQ_sequence_alloc(seqbasep, seq_load->start_frame, seq_load->channel, SEQ_TYPE_MOVIE); - /* multiview settings */ - if (seq_load->stereo3d_format) { - *seq->stereo3d_format = *seq_load->stereo3d_format; - seq->views_format = seq_load->views_format; - } - seq->flag |= seq_load->flag & SEQ_USE_VIEWS; + Sequence *seq = SEQ_sequence_alloc( + seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIE); - seq->type = SEQ_TYPE_MOVIE; - seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ + /* Multiview settings. */ + if (load_data->use_multiview) { + seq->flag |= SEQ_USE_VIEWS; + seq->views_format = load_data->views_format; + } + if (load_data->stereo3d_format) { + seq->stereo3d_format = load_data->stereo3d_format; + } for (i = 0; i < totfiles; i++) { if (anim_arr[i]) { @@ -289,51 +488,38 @@ Sequence *SEQ_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo *seq_ } } - IMB_anim_load_metadata(anim_arr[0]); + seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ - seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]); + if (anim_arr[0] != NULL) { + seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]); + seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN); - const float width = IMB_anim_get_image_width(anim_arr[0]); - const float height = IMB_anim_get_image_height(anim_arr[0]); - SEQ_set_scale_to_fit(seq, width, height, scene->r.xsch, scene->r.ysch, seq_load->fit_method); + IMB_anim_load_metadata(anim_arr[0]); - BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2); - SEQ_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); + /* Adjust scene's frame rate settings to match. */ + if (load_data->flags & SEQ_LOAD_MOVIE_SYNC_FPS) { + IMB_anim_get_fps(anim_arr[0], &scene->r.frs_sec, &scene->r.frs_sec_base, true); + } - /* adjust scene's frame rate settings to match */ - if (seq_load->flag & SEQ_LOAD_SYNC_FPS) { - IMB_anim_get_fps(anim_arr[0], &scene->r.frs_sec, &scene->r.frs_sec_base, true); + /* Set initial scale based on load_data->fit_method. */ + const float width = IMB_anim_get_image_width(anim_arr[0]); + const float height = IMB_anim_get_image_height(anim_arr[0]); + SEQ_set_scale_to_fit(seq, width, height, scene->r.xsch, scene->r.ysch, load_data->fit_method); } - /* basic defaults */ - seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN); - strip = seq->strip; - + seq->len = MAX2(1, seq->len); BLI_strncpy(seq->strip->colorspace_settings.name, colorspace, sizeof(seq->strip->colorspace_settings.name)); - /* we only need 1 element for MOVIE strips */ + Strip *strip = seq->strip; + /* We only need 1 element for MOVIE strips. */ + StripElem *se; strip->stripdata = se = MEM_callocN(sizeof(StripElem), "stripelem"); + BLI_split_dirfile(load_data->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name)); - BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name)); - - SEQ_time_update_sequence_bounds(scene, seq); - - if (seq_load->name[0] == '\0') { - BLI_strncpy(seq_load->name, se->name, sizeof(seq_load->name)); - } - - if (seq_load->flag & SEQ_LOAD_MOVIE_SOUND) { - int start_frame_back = seq_load->start_frame; - seq_load->channel--; - seq_load->seq_sound = SEQ_add_sound_strip(C, seqbasep, seq_load); - seq_load->start_frame = start_frame_back; - } - - /* can be NULL */ - seq_load_apply(CTX_data_main(C), scene, seq, seq_load); - SEQ_relations_invalidate_cache_composite(scene, seq); + seq_add_set_name(seq, load_data); + seq_add_generic_update(scene, seqbase, seq); MEM_freeN(anim_arr); return seq; @@ -525,9 +711,9 @@ void SEQ_add_movie_reload_if_needed(struct Main *bmain, bool must_reload = false; - /* The Sequence struct allows for multiple anim structs to be associated with one strip. This - * function will return true only if there is at least one 'anim' AND all anims can produce - * frames. */ + /* The Sequence struct allows for multiple anim structs to be associated with one strip. + * This function will return true only if there is at least one 'anim' AND all anims can + * produce frames. */ if (BLI_listbase_is_empty(&seq->anims)) { /* No anim present, so reloading is always necessary. */ diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index c495ad6d8f1..21dc9aa2cdd 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -164,7 +164,6 @@ void SEQ_time_update_sequence_bounds(Scene *scene, Sequence *seq) void SEQ_time_update_sequence(Scene *scene, Sequence *seq) { Sequence *seqm; - int min, max; /* check all metas recursively */ seqm = seq->seqbase.first; @@ -212,27 +211,6 @@ void SEQ_time_update_sequence(Scene *scene, Sequence *seq) } } else { - if (seq->type == SEQ_TYPE_META) { - seqm = seq->seqbase.first; - if (seqm) { - min = MAXFRAME * 2; - max = -MAXFRAME * 2; - while (seqm) { - if (seqm->startdisp < min) { - min = seqm->startdisp; - } - if (seqm->enddisp > max) { - max = seqm->enddisp; - } - seqm = seqm->next; - } - seq->start = min + seq->anim_startofs; - seq->len = max - min; - seq->len -= seq->anim_startofs; - seq->len -= seq->anim_endofs; - } - seq_update_sound_bounds_recursive(scene, seq); - } SEQ_time_update_sequence_bounds(scene, seq); } } diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index d40c0715a09..084ca2d2df5 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -461,6 +461,7 @@ typedef struct wmNotifier { #define NA_SELECTED 6 #define NA_ACTIVATED 7 #define NA_PAINTING 8 +#define NA_JOB_FINISHED 9 /* ************** Gesture Manager data ************** */ @@ -543,17 +544,36 @@ typedef struct wmTabletData { /** * Each event should have full modifier state. * event comes from event manager and from keymap. + * + * + * Previous State + * ============== + * + * Events hold information about the previous event, + * this is used for detecting click and double-click events (the timer is needed for double-click). + * See #wm_event_add_ghostevent for implementation details. + * + * Notes: + * + * - The previous values are only set for mouse button and keyboard events. + * See: #ISMOUSE_BUTTON & #ISKEYBOARD macros. + * + * - Previous x/y are exceptions: #wmEvent.prevx & #wmEvent.prevy + * these are set on mouse motion, see #MOUSEMOVE & track-pad events. + * + * - Modal key-map handling sets `prevval` & `prevtype` to `val` & `type`, + * this allows modal keys-maps to check the original values (needed in some cases). */ typedef struct wmEvent { struct wmEvent *next, *prev; - /** Event code itself (short, is also in keymap). */ + /** Event code itself (short, is also in key-map). */ short type; /** Press, release, scroll-value. */ short val; /** Mouse pointer position, screen coord. */ int x, y; - /** Region mouse position, name convention pre 2.5 :). */ + /** Region relative mouse position (name convention before Blender 2.5). */ int mval[2]; /** * From, ghost if utf8 is enabled for the platform, @@ -572,37 +592,43 @@ typedef struct wmEvent { */ char is_repeat; - /** Previous state, used for double click and the 'click'. */ + /** The previous value of `type`. */ short prevtype; + /** The previous value of `val`. */ short prevval; - int prevx, prevy; + /** The time when the key is pressed, see #PIL_check_seconds_timer. */ double prevclicktime; + /** The location when the key is pressed (used to enforce drag thresholds). */ int prevclickx, prevclicky; + /** + * The previous value of #wmEvent.x #wmEvent.y, + * Unlike other previous state variables, this is set on any mouse motion. + * Use `prevclickx` & `prevclicky` for the value at time of pressing. + */ + int prevx, prevy; /** Modifier states. */ /** 'oskey' is apple or windows-key, value denotes order of pressed. */ short shift, ctrl, alt, oskey; - /** rawkey modifier. */ + /** Raw-key modifier (allow using any key as a modifier). */ short keymodifier; - /** Set in case a #KM_PRESS went by unhandled. */ - char check_click; - char check_drag; - /** Tablet info, available for mouse move and button events. */ wmTabletData tablet; - /* custom data */ + /* Custom data. */ /** Custom data type, stylus, 6dof, see wm_event_types.h */ short custom; short customdatafree; int pad2; - /** Ascii, unicode, mouse coords, angles, vectors, dragdrop info. */ + /** Ascii, unicode, mouse-coords, angles, vectors, NDOF data, drag-drop info. */ void *customdata; - /* True if the operating system inverted the delta x/y values and resulting - * prev x/y values, for natural scroll direction. For absolute scroll direction, - * the delta must be negated again. */ + /** + * True if the operating system inverted the delta x/y values and resulting + * `prevx`, `prevy` values, for natural scroll direction. + * For absolute scroll direction, the delta must be negated again. + */ char is_direction_inverted; } wmEvent; diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index a9c0d1dd8fe..c5a429d7839 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -172,7 +172,7 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id) win->ime_data = NULL; #endif - BLI_listbase_clear(&win->queue); + BLI_listbase_clear(&win->event_queue); BLI_listbase_clear(&win->handlers); BLI_listbase_clear(&win->modalhandlers); BLI_listbase_clear(&win->gesture); @@ -184,6 +184,8 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id) win->modalcursor = 0; win->grabcursor = 0; win->addmousemove = true; + win->event_queue_check_click = 0; + win->event_queue_check_drag = 0; BLO_read_data_address(reader, &win->stereo3d_format); /* Multi-view always fallback to anaglyph at file opening @@ -198,7 +200,7 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id) BLI_listbase_clear(&wm->timers); BLI_listbase_clear(&wm->operators); BLI_listbase_clear(&wm->paintcursors); - BLI_listbase_clear(&wm->queue); + BLI_listbase_clear(&wm->notifier_queue); BKE_reports_init(&wm->reports, RPT_STORE); BLI_listbase_clear(&wm->keyconfigs); @@ -590,7 +592,7 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) WM_keyconfig_free(keyconf); } - BLI_freelistN(&wm->queue); + BLI_freelistN(&wm->notifier_queue); if (wm->message_bus != NULL) { WM_msgbus_destroy(wm->message_bus); diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index e32552063af..d6e4a93f6a6 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -303,7 +303,7 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y) { /* note: don't use wmEvent coords because of continuous grab T36409. */ int cx, cy; - wm_get_cursor_position(win, &cx, &cy); + wm_cursor_position_get(win, &cx, &cy); WM_cursor_warp(win, cx + x, cy + y); } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 85611a0be93..071bce822a5 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -117,7 +117,7 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region) if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) { int x = 0, y = 0; - wm_get_cursor_position(win, &x, &y); + wm_cursor_position_get(win, &x, &y); pc->draw(C, x, y, pc->customdata); } else { diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index ab8f37548b7..9b9be6bb497 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -281,6 +281,10 @@ int WM_event_drag_threshold(const struct wmEvent *event) drag_threshold = U.drag_threshold_tablet; } else if (ISMOUSE(event->prevtype)) { + BLI_assert(event->prevtype != MOUSEMOVE); + /* Using the previous type is important is we want to check the last pressed/released button, + * The `event->type` would include #MOUSEMOVE which is always the case when dragging + * and does not help us know which threshold to use. */ drag_threshold = U.drag_threshold_mouse; } else { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index dc38bd79b7d..4c4523c80bc 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -126,12 +126,12 @@ wmEvent *wm_event_add_ex(wmWindow *win, *event = *event_to_add; if (event_to_add_after == NULL) { - BLI_addtail(&win->queue, event); + BLI_addtail(&win->event_queue, event); } else { /* Note: strictly speaking this breaks const-correctness, * however we're only changing 'next' member. */ - BLI_insertlinkafter(&win->queue, (void *)event_to_add_after, event); + BLI_insertlinkafter(&win->event_queue, (void *)event_to_add_after, event); } return event; } @@ -149,23 +149,25 @@ wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add) } wmEvent *event = wm_event_add(win, event_to_add); + /* Logic for setting previous value is documented on the #wmEvent struct, + * see #wm_event_add_ghostevent for the implementation of logic this follows. */ + win->eventstate->x = event->x; win->eventstate->y = event->y; - win->eventstate->prevval = event->prevval = win->eventstate->val; - win->eventstate->prevtype = event->prevtype = win->eventstate->type; - win->eventstate->prevx = event->prevx = win->eventstate->x; - win->eventstate->prevy = event->prevy = win->eventstate->y; - if (event->type == MOUSEMOVE) { - /* Pass. */ + win->eventstate->prevx = event->prevx = win->eventstate->x; + win->eventstate->prevy = event->prevy = win->eventstate->y; } - else { + else if (ISMOUSE_BUTTON(event->type) || ISKEYBOARD(event->type)) { + win->eventstate->prevval = event->prevval = win->eventstate->val; + win->eventstate->prevtype = event->prevtype = win->eventstate->type; + win->eventstate->val = event->val; win->eventstate->type = event->type; - if (ISMOUSE_BUTTON(event->type)) { - if (event->val == KM_PRESS) { + if (event->val == KM_PRESS) { + if (event->is_repeat == false) { win->eventstate->prevclickx = event->x; win->eventstate->prevclicky = event->y; } @@ -203,7 +205,7 @@ void wm_event_free(wmEvent *event) static void wm_event_free_last(wmWindow *win) { - wmEvent *event = BLI_poptail(&win->queue); + wmEvent *event = BLI_poptail(&win->event_queue); if (event != NULL) { wm_event_free(event); } @@ -212,7 +214,7 @@ static void wm_event_free_last(wmWindow *win) void wm_event_free_all(wmWindow *win) { wmEvent *event; - while ((event = BLI_pophead(&win->queue))) { + while ((event = BLI_pophead(&win->event_queue))) { wm_event_free(event); } } @@ -230,7 +232,7 @@ void wm_event_init_from_window(wmWindow *win, wmEvent *event) static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, void *reference) { - LISTBASE_FOREACH (wmNotifier *, note, &wm->queue) { + LISTBASE_FOREACH (wmNotifier *, note, &wm->notifier_queue) { if ((note->category | note->data | note->subtype | note->action) == type && note->reference == reference) { return true; @@ -248,7 +250,7 @@ void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint typ wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier"); - BLI_addtail(&wm->queue, note); + BLI_addtail(&wm->notifier_queue, note); note->window = win; @@ -277,7 +279,7 @@ void WM_main_add_notifier(unsigned int type, void *reference) wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier"); - BLI_addtail(&wm->queue, note); + BLI_addtail(&wm->notifier_queue, note); note->category = type & NOTE_CATEGORY; note->data = type & NOTE_DATA; @@ -296,7 +298,7 @@ void WM_main_remove_notifier_reference(const void *reference) wmWindowManager *wm = bmain->wm.first; if (wm) { - LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->queue) { + LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) { if (note->reference == reference) { /* Don't remove because this causes problems for #wm_event_do_notifiers * which may be looping on the data (deleting screens). */ @@ -448,7 +450,7 @@ void wm_event_do_notifiers(bContext *C) CTX_wm_window_set(C, win); - LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->queue) { + LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) { if (note->category == NC_WM) { if (ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) { wm->file_saved = 1; @@ -537,7 +539,7 @@ void wm_event_do_notifiers(bContext *C) /* The notifiers are sent without context, to keep it clean. */ wmNotifier *note; - while ((note = BLI_pophead(&wm->queue))) { + while ((note = BLI_pophead(&wm->notifier_queue))) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { Scene *scene = WM_window_get_active_scene(win); bScreen *screen = WM_window_get_active_screen(win); @@ -1957,6 +1959,13 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap, return NULL; } +struct wmEvent_ModalMapStore { + short prevtype; + short prevval; + + bool dbl_click_disabled; +}; + /** * This function prepares events for use with #wmOperatorType.modal by: * @@ -1970,7 +1979,7 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap, static void wm_event_modalkeymap_begin(const bContext *C, wmOperator *op, wmEvent *event, - bool *dbl_click_disabled) + struct wmEvent_ModalMapStore *event_backup) { BLI_assert(event->type != EVT_MODAL_MAP); @@ -1979,6 +1988,8 @@ static void wm_event_modalkeymap_begin(const bContext *C, op = op->opm; } + event_backup->dbl_click_disabled = false; + if (op->type->modalkeymap) { wmKeyMap *keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap); wmKeyMapItem *kmi = NULL; @@ -1998,6 +2009,9 @@ static void wm_event_modalkeymap_begin(const bContext *C, } if (event_match != NULL) { + event_backup->prevtype = event->prevtype; + event_backup->prevval = event->prevval; + event->prevtype = event_match->type; event->prevval = event_match->val; event->type = EVT_MODAL_MAP; @@ -2008,7 +2022,7 @@ static void wm_event_modalkeymap_begin(const bContext *C, * which would break when modal functions expect press/release. */ if (event->prevtype == KM_DBL_CLICK) { event->prevtype = KM_PRESS; - *dbl_click_disabled = true; + event_backup->dbl_click_disabled = true; } } } @@ -2017,7 +2031,7 @@ static void wm_event_modalkeymap_begin(const bContext *C, /* This bypass just disables support for double-click in modal handlers. */ if (event->val == KM_DBL_CLICK) { event->val = KM_PRESS; - *dbl_click_disabled = true; + event_backup->dbl_click_disabled = true; } } } @@ -2029,16 +2043,18 @@ static void wm_event_modalkeymap_begin(const bContext *C, * better restore event type for checking of #KM_CLICK for example. * Modal maps could use different method (ton). */ -static void wm_event_modalkeymap_end(wmEvent *event, bool dbl_click_disabled) +static void wm_event_modalkeymap_end(wmEvent *event, + const struct wmEvent_ModalMapStore *event_backup) { if (event->type == EVT_MODAL_MAP) { event->type = event->prevtype; - event->prevtype = 0; event->val = event->prevval; - event->prevval = 0; + + event->prevtype = event_backup->prevtype; + event->prevval = event_backup->prevval; } - if (dbl_click_disabled) { + if (event_backup->dbl_click_disabled) { event->val = KM_DBL_CLICK; } } @@ -2070,11 +2086,12 @@ static int wm_handler_operator_call(bContext *C, wmWindowManager *wm = CTX_wm_manager(C); ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); - bool dbl_click_disabled = false; wm_handler_op_context(C, handler, event); wm_region_mouse_co(C, event); - wm_event_modalkeymap_begin(C, op, event, &dbl_click_disabled); + + struct wmEvent_ModalMapStore event_backup; + wm_event_modalkeymap_begin(C, op, event, &event_backup); if (ot->flag & OPTYPE_UNDO) { wm->op_undo_depth++; @@ -2089,7 +2106,7 @@ static int wm_handler_operator_call(bContext *C, * the event, operator etc have all been freed. - campbell */ if (CTX_wm_manager(C) == wm) { - wm_event_modalkeymap_end(event, dbl_click_disabled); + wm_event_modalkeymap_end(event, &event_backup); if (ot->flag & OPTYPE_UNDO) { wm->op_undo_depth--; @@ -2326,7 +2343,7 @@ static int wm_handler_fileselect_do(bContext *C, wm_window_make_drawable(wm, ctx_win); /* Ensure correct cursor position, otherwise, popups may close immediately after * opening (UI_BLOCK_MOVEMOUSE_QUIT). */ - wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y); + wm_cursor_position_get(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y); wm->winactive = ctx_win; /* Reports use this... */ if (handler->context.win == win) { handler->context.win = NULL; @@ -2934,27 +2951,26 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) { int action = wm_handlers_do_intern(C, event, handlers); - /* Fileread case. */ - if (CTX_wm_window(C) == NULL) { + /* Will be NULL in the file read case. */ + wmWindow *win = CTX_wm_window(C); + if (win == NULL) { return action; } if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { - /* Test for CLICK_DRAG events. */ if (wm_action_not_handled(action)) { - if (event->check_drag) { - wmWindow *win = CTX_wm_window(C); - if (WM_event_drag_test(event, &win->eventstate->prevclickx)) { + if (win->event_queue_check_drag) { + if (WM_event_drag_test(event, &event->prevclickx)) { int x = event->x; int y = event->y; short val = event->val; short type = event->type; - event->x = win->eventstate->prevclickx; - event->y = win->eventstate->prevclicky; + event->x = event->prevclickx; + event->y = event->prevclicky; event->val = KM_CLICK_DRAG; - event->type = win->eventstate->type; + event->type = event->prevtype; CLOG_INFO(WM_LOG_HANDLERS, 1, "handling PRESS_DRAG"); @@ -2965,16 +2981,16 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) event->x = x; event->y = y; - win->eventstate->check_click = false; - win->eventstate->check_drag = false; + win->event_queue_check_click = false; + if (!wm_action_not_handled(action)) { + /* Only disable when handled as other handlers may use this drag event. */ + win->event_queue_check_drag = false; + } } } } else { - wmWindow *win = CTX_wm_window(C); - if (win) { - win->eventstate->check_drag = false; - } + win->event_queue_check_drag = false; } } else if (ISMOUSE_BUTTON(event->type) || ISKEYBOARD(event->type)) { @@ -2982,46 +2998,47 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) /* Test for CLICK events. */ if (wm_action_not_handled(action)) { - wmWindow *win = CTX_wm_window(C); - /* eventstate stores if previous event was a KM_PRESS, in case that * wasn't handled, the KM_RELEASE will become a KM_CLICK */ - if (win != NULL) { - if (event->val == KM_PRESS) { - win->eventstate->check_click = true; - win->eventstate->check_drag = true; - } - else if (event->val == KM_RELEASE) { - win->eventstate->check_drag = false; + if (event->val == KM_PRESS) { + if (event->prevval != KM_PRESS) { + win->event_queue_check_click = true; + win->event_queue_check_drag = true; } } + else if (event->val == KM_RELEASE) { + win->event_queue_check_drag = false; + } - if (win && win->eventstate->prevtype == event->type) { + if (event->prevtype == event->type) { - if ((event->val == KM_RELEASE) && (win->eventstate->prevval == KM_PRESS) && - (win->eventstate->check_click == true)) { - if (WM_event_drag_test(event, &win->eventstate->prevclickx)) { - win->eventstate->check_click = 0; - win->eventstate->check_drag = 0; - } - else { - /* Position is where the actual click happens, for more - * accurate selecting in case the mouse drifts a little. */ - int x = event->x; - int y = event->y; + if (event->val == KM_RELEASE) { + if (event->prevval == KM_PRESS) { + if (win->event_queue_check_click == true) { + if (WM_event_drag_test(event, &event->prevclickx)) { + win->event_queue_check_click = false; + win->event_queue_check_drag = false; + } + else { + /* Position is where the actual click happens, for more + * accurate selecting in case the mouse drifts a little. */ + int x = event->x; + int y = event->y; - event->x = win->eventstate->prevclickx; - event->y = win->eventstate->prevclicky; - event->val = KM_CLICK; + event->x = event->prevclickx; + event->y = event->prevclicky; + event->val = KM_CLICK; - CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK"); + CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK"); - action |= wm_handlers_do_intern(C, event, handlers); + action |= wm_handlers_do_intern(C, event, handlers); - event->val = KM_RELEASE; - event->x = x; - event->y = y; + event->val = KM_RELEASE; + event->x = x; + event->y = y; + } + } } } else if (event->val == KM_DBL_CLICK) { @@ -3037,11 +3054,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } else { - wmWindow *win = CTX_wm_window(C); - if (win) { - win->eventstate->check_click = 0; - win->eventstate->check_drag = 0; - } + win->event_queue_check_click = false; + win->event_queue_check_drag = false; } } else if (ISMOUSE_WHEEL(event->type) || ISMOUSE_GESTURE(event->type)) { @@ -3051,11 +3065,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) /* pass */ } else { - wmWindow *win = CTX_wm_window(C); - if (win) { - if (ISKEYMODIFIER(win->eventstate->type)) { - win->eventstate->check_click = 0; - } + if (ISKEYMODIFIER(event->prevtype)) { + win->event_queue_check_click = false; } } } @@ -3201,9 +3212,9 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv /* Filter out all events of the pie that spawned the last pie unless it's a release event. */ static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event) { - if (win->lock_pie_event && win->lock_pie_event == event->type) { + if (win->pie_event_type_lock && win->pie_event_type_lock == event->type) { if (event->val == KM_RELEASE) { - win->lock_pie_event = EVENT_NONE; + win->pie_event_type_lock = EVENT_NONE; return false; } return true; @@ -3214,7 +3225,7 @@ static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event) /** * Account for the special case when events are being handled and a file is loaded. * In this case event handling exits early, however when "Load UI" is disabled - * the even will still be in #wmWindow.queue. + * the even will still be in #wmWindow.event_queue. * * Without this it's possible to continuously handle the same event, see: T76484. */ @@ -3222,7 +3233,7 @@ static void wm_event_free_and_remove_from_queue_if_valid(wmEvent *event) { LISTBASE_FOREACH (wmWindowManager *, wm, &G_MAIN->wm) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - if (BLI_remlink_safe(&win->queue, event)) { + if (BLI_remlink_safe(&win->event_queue, event)) { wm_event_free(event); return; } @@ -3311,7 +3322,7 @@ void wm_event_do_handlers(bContext *C) } wmEvent *event; - while ((event = win->queue.first)) { + while ((event = win->event_queue.first)) { int action = WM_HANDLER_CONTINUE; /* Active screen might change during handlers, update pointer. */ @@ -3328,7 +3339,7 @@ void wm_event_do_handlers(bContext *C) if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { CLOG_INFO(WM_LOG_HANDLERS, 1, "event filtered due to pie button pressed"); } - BLI_remlink(&win->queue, event); + BLI_remlink(&win->event_queue, event); wm_event_free(event); continue; } @@ -3477,7 +3488,7 @@ void wm_event_do_handlers(bContext *C) * press in tool keymap can override click in editor keymap.*/ if (ISMOUSE_BUTTON(event->type) && event->val == KM_PRESS && !wm_action_not_handled(action)) { - win->eventstate->check_click = false; + win->event_queue_check_click = false; } /* Update previous mouse position for following events to use. */ @@ -3485,11 +3496,11 @@ void wm_event_do_handlers(bContext *C) win->eventstate->prevy = event->y; /* Unlink and free here, blender-quit then frees all. */ - BLI_remlink(&win->queue, event); + BLI_remlink(&win->event_queue, event); wm_event_free(event); } - /* Only add mousemove when queue was read entirely. */ + /* Only add mouse-move when the event queue was read entirely. */ if (win->addmousemove && win->eventstate) { wmEvent tevent = *(win->eventstate); // printf("adding MOUSEMOVE %d %d\n", tevent.x, tevent.y); @@ -4330,25 +4341,25 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi } } - wmWindow *owin; - if (WM_window_find_under_cursor(wm, win, win, mval, &owin, mval)) { + wmWindow *win_other; + if (WM_window_find_under_cursor(wm, win, win, mval, &win_other, mval)) { event->x = mval[0]; event->y = mval[1]; - return owin; + return win_other; } } return NULL; } -static bool wm_event_is_double_click(const wmEvent *event, const wmEvent *event_state) +static bool wm_event_is_double_click(const wmEvent *event) { - if ((event->type == event_state->prevtype) && (event_state->prevval == KM_RELEASE) && + if ((event->type == event->prevtype) && (event->prevval == KM_RELEASE) && (event->val == KM_PRESS)) { - if (ISMOUSE(event->type) && WM_event_drag_test(event, &event_state->prevclickx)) { + if (ISMOUSE(event->type) && WM_event_drag_test(event, &event->prevclickx)) { /* Pass. */ } else { - if ((PIL_check_seconds_timer() - event_state->prevclicktime) * 1000 < U.dbl_click_time) { + if ((PIL_check_seconds_timer() - event->prevclicktime) * 1000 < U.dbl_click_time) { return true; } } @@ -4357,9 +4368,25 @@ static bool wm_event_is_double_click(const wmEvent *event, const wmEvent *event_ return false; } +/** + * Copy the current state to the previous event state. + */ +static void wm_event_prev_values_set(wmEvent *event, wmEvent *event_state) +{ + event->prevval = event_state->prevval = event_state->val; + event->prevtype = event_state->prevtype = event_state->type; +} + +static void wm_event_prev_click_set(wmEvent *event, wmEvent *event_state) +{ + event->prevclicktime = event_state->prevclicktime = PIL_check_seconds_timer(); + event->prevclickx = event_state->prevclickx = event_state->x; + event->prevclicky = event_state->prevclicky = event_state->y; +} + static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event) { - wmEvent *event_last = win->queue.last; + wmEvent *event_last = win->event_queue.last; /* Some painting operators want accurate mouse events, they can * handle in between mouse move moves, others can happily ignore @@ -4381,7 +4408,7 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d { /* Ignore in between trackpad events for performance, we only need high accuracy * for painting with mouse moves, for navigation using the accumulated value is ok. */ - wmEvent *event_last = win->queue.last; + wmEvent *event_last = win->event_queue.last; if (event_last && event_last->type == event->type) { deltax += event_last->x - event_last->prevx; deltay += event_last->y - event_last->prevy; @@ -4397,8 +4424,9 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d return event_new; } -/* Windows store own event queues, no bContext here. */ -/* Time is in 1000s of seconds, from Ghost. */ +/** + * Windows store own event queues #wmWindow.event_queue (no #bContext here). + */ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata) { if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) { @@ -4406,21 +4434,50 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void } /** - * Having both, \a event and \a evt, can be highly confusing to work with, + * Having both, \a event and \a event_state, can be highly confusing to work with, * but is necessary for our current event system, so let's clear things up a bit: * * - Data added to event only will be handled immediately, * but will not be copied to the next event. - * - Data added to \a evt only stays, + * - Data added to \a event_state only stays, * but is handled with the next event -> execution delay. - * - Data added to event and \a evt stays and is handled immediately. + * - Data added to event and \a event_state stays and is handled immediately. */ - wmEvent event, *evt = win->eventstate; + wmEvent event, *event_state = win->eventstate; /* Initialize and copy state (only mouse x y and modifiers). */ - event = *evt; + event = *event_state; event.is_repeat = false; + /** + * Always support accessing the last key press/release. This is set from `win->eventstate`, + * so it will always be a valid event type to store in the previous state. + * + * Note that these values are intentionally _not_ set in the `win->eventstate`, + * as copying these values only makes sense when `win->eventstate->{val/type}` would be + * written to (which only happens for some kinds of events). + * If this was done it could leave `win->eventstate` previous and current value + * set to the same key press/release state which doesn't make sense. + */ + event.prevtype = event.type; + event.prevval = event.val; + + /* Ensure the event state is correct, any deviation from this may cause bugs. */ +#ifndef NDEBUG + if ((event_state->type || event_state->val) && /* Ignore cleared event state. */ + !(ISMOUSE_BUTTON(event_state->type) || ISKEYBOARD(event_state->type))) { + CLOG_WARN(WM_LOG_HANDLERS, + "Non-keyboard/mouse button found in 'win->eventstate->type = %d'", + event_state->type); + } + if ((event_state->prevtype || event_state->prevval) && /* Ignore cleared event state. */ + !(ISMOUSE_BUTTON(event_state->prevtype) || ISKEYBOARD(event_state->prevtype))) { + CLOG_WARN(WM_LOG_HANDLERS, + "Non-keyboard/mouse button found in 'win->eventstate->prevtype = %d'", + event_state->prevtype); + } +#endif + switch (type) { /* Mouse move, also to inactive window (X11 does this). */ case GHOST_kEventCursorMove: { @@ -4430,31 +4487,29 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void wm_stereo3d_mouse_offset_apply(win, &event.x); wm_tablet_data_from_ghost(&cd->tablet, &event.tablet); - event.prevtype = event.type; - event.prevval = event.val; event.type = MOUSEMOVE; { wmEvent *event_new = wm_event_add_mousemove(win, &event); - copy_v2_v2_int(&evt->x, &event_new->x); - evt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute; + copy_v2_v2_int(&event_state->x, &event_new->x); + event_state->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute; } /* Also add to other window if event is there, this makes overdraws disappear nicely. */ /* It remaps mousecoord to other window in event. */ - wmWindow *owin = wm_event_cursor_other_windows(wm, win, &event); - if (owin) { - wmEvent oevent, *oevt = owin->eventstate; + wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event); + if (win_other) { + wmEvent event_other = *win_other->eventstate; - oevent = *oevt; + /* See comment for this operation on `event` for details. */ + event_other.prevtype = event_other.type; + event_other.prevval = event_other.val; - copy_v2_v2_int(&oevent.x, &event.x); - oevent.prevtype = oevent.type; - oevent.prevval = oevent.val; - oevent.type = MOUSEMOVE; + copy_v2_v2_int(&event_other.x, &event.x); + event_other.type = MOUSEMOVE; { - wmEvent *event_new = wm_event_add_mousemove(owin, &oevent); - copy_v2_v2_int(&oevt->x, &event_new->x); - oevt->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute; + wmEvent *event_new = wm_event_add_mousemove(win_other, &event_other); + copy_v2_v2_int(&win_other->eventstate->x, &event_new->x); + win_other->eventstate->tablet.is_motion_absolute = event_new->tablet.is_motion_absolute; } } @@ -4480,8 +4535,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void break; } - event.x = evt->x = pd->x; - event.y = evt->y = pd->y; + event.x = event_state->x = pd->x; + event.y = event_state->y = pd->y; event.val = KM_NOTHING; /* The direction is inverted from the device due to system preferences. */ @@ -4524,38 +4579,37 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void wm_tablet_data_from_ghost(&bd->tablet, &event.tablet); wm_eventemulation(&event, false); - - /* Copy previous state to prev event state (two old!). */ - evt->prevval = evt->val; - evt->prevtype = evt->type; + wm_event_prev_values_set(&event, event_state); /* Copy to event state. */ - evt->val = event.val; - evt->type = event.type; + event_state->val = event.val; + event_state->type = event.type; /* Double click test. */ - if (wm_event_is_double_click(&event, evt)) { + if (wm_event_is_double_click(&event)) { CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click"); event.val = KM_DBL_CLICK; } if (event.val == KM_PRESS) { - evt->prevclicktime = PIL_check_seconds_timer(); - evt->prevclickx = event.x; - evt->prevclicky = event.y; + wm_event_prev_click_set(&event, event_state); } /* Add to other window if event is there (not to both!). */ - wmWindow *owin = wm_event_cursor_other_windows(wm, win, &event); - if (owin) { - wmEvent oevent = *(owin->eventstate); + wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event); + if (win_other) { + wmEvent event_other = *win_other->eventstate; - oevent.x = event.x; - oevent.y = event.y; - oevent.type = event.type; - oevent.val = event.val; - oevent.tablet = event.tablet; + /* See comment for this operation on `event` for details. */ + event_other.prevtype = event_other.type; + event_other.prevval = event_other.val; - wm_event_add(owin, &oevent); + copy_v2_v2_int(&event_other.x, &event.x); + + event_other.type = event.type; + event_other.val = event.val; + event_other.tablet = event.tablet; + + wm_event_add(win_other, &event_other); } else { wm_event_add(win, &event); @@ -4576,15 +4630,12 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void event.val = (type == GHOST_kEventKeyDown) ? KM_PRESS : KM_RELEASE; wm_eventemulation(&event, false); - - /* Copy previous state to prev event state (two old!). */ - evt->prevval = evt->val; - evt->prevtype = evt->type; + wm_event_prev_values_set(&event, event_state); /* Copy to event state. */ - evt->val = event.val; - evt->type = event.type; - evt->is_repeat = event.is_repeat; + event_state->val = event.val; + event_state->type = event.type; + event_state->is_repeat = event.is_repeat; /* Exclude arrow keys, esc, etc from text input. */ if (type == GHOST_kEventKeyUp) { @@ -4620,64 +4671,64 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void case EVT_LEFTSHIFTKEY: case EVT_RIGHTSHIFTKEY: if (event.val == KM_PRESS) { - if (evt->ctrl || evt->alt || evt->oskey) { + if (event_state->ctrl || event_state->alt || event_state->oskey) { keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); } else { keymodifier = KM_MOD_FIRST; } } - event.shift = evt->shift = keymodifier; + event.shift = event_state->shift = keymodifier; break; case EVT_LEFTCTRLKEY: case EVT_RIGHTCTRLKEY: if (event.val == KM_PRESS) { - if (evt->shift || evt->alt || evt->oskey) { + if (event_state->shift || event_state->alt || event_state->oskey) { keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); } else { keymodifier = KM_MOD_FIRST; } } - event.ctrl = evt->ctrl = keymodifier; + event.ctrl = event_state->ctrl = keymodifier; break; case EVT_LEFTALTKEY: case EVT_RIGHTALTKEY: if (event.val == KM_PRESS) { - if (evt->ctrl || evt->shift || evt->oskey) { + if (event_state->ctrl || event_state->shift || event_state->oskey) { keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); } else { keymodifier = KM_MOD_FIRST; } } - event.alt = evt->alt = keymodifier; + event.alt = event_state->alt = keymodifier; break; case EVT_OSKEY: if (event.val == KM_PRESS) { - if (evt->ctrl || evt->alt || evt->shift) { + if (event_state->ctrl || event_state->alt || event_state->shift) { keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); } else { keymodifier = KM_MOD_FIRST; } } - event.oskey = evt->oskey = keymodifier; + event.oskey = event_state->oskey = keymodifier; break; default: if (event.val == KM_PRESS && event.keymodifier == 0) { /* Only set in eventstate, for next event. */ - evt->keymodifier = event.type; + event_state->keymodifier = event.type; } else if (event.val == KM_RELEASE && event.keymodifier == event.type) { - event.keymodifier = evt->keymodifier = 0; + event.keymodifier = event_state->keymodifier = 0; } break; } /* Double click test. */ /* If previous event was same type, and previous was release, and now it presses... */ - if (wm_event_is_double_click(&event, evt)) { + if (wm_event_is_double_click(&event)) { CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click"); event.val = KM_DBL_CLICK; } @@ -4693,7 +4744,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void * Since it's impossible to map a key modifier to an unknown key, * it shouldn't harm to clear it. */ if (event.keymodifier == EVT_UNKNOWNKEY) { - evt->keymodifier = event.keymodifier = 0; + event_state->keymodifier = event.keymodifier = 0; } /* If test_break set, it catches this. Do not set with modifier presses. @@ -4707,10 +4758,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void /* Double click test - only for press. */ if (event.val == KM_PRESS) { /* Don't reset timer & location when holding the key generates repeat events. */ - if ((evt->prevtype != event.type) || (evt->prevval != KM_PRESS)) { - evt->prevclicktime = PIL_check_seconds_timer(); - evt->prevclickx = event.x; - evt->prevclicky = event.y; + if (event.is_repeat == false) { + wm_event_prev_click_set(&event, event_state); } } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index d2d080a9a68..13f3afdfc4c 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -711,7 +711,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* so we can get the error message */ errno = 0; - WM_cursor_wait(1); + WM_cursor_wait(true); wm_file_read_pre(C, use_data, use_userdef); @@ -809,7 +809,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } } - WM_cursor_wait(0); + WM_cursor_wait(false); return success; } @@ -1498,7 +1498,7 @@ static bool wm_file_write(bContext *C, } /* don't forget not to return without! */ - WM_cursor_wait(1); + WM_cursor_wait(true); ED_editors_flush_edits(bmain); @@ -1560,7 +1560,7 @@ static bool wm_file_write(bContext *C, MEM_freeN(thumb); } - WM_cursor_wait(0); + WM_cursor_wait(false); return ok; } @@ -1776,7 +1776,12 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) filepath, fileflags, &(const struct BlendFileWriteParams){ - .remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE, + /* Make all paths absolute when saving the startup file. + * On load the `G.relbase_valid` will be false so the paths + * wont have a base for resolving the relative paths. */ + .remap_mode = BLO_WRITE_PATH_REMAP_ABSOLUTE, + /* Don't apply any path changes to the current blend file. */ + .use_save_as_copy = true, }, op->reports) == 0) { printf("fail\n"); diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index d4495821672..6a1fc84774c 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -804,7 +804,7 @@ static void lib_relocate_do(Main *bmain, ReportList *reports, const bool do_reload) { - ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray[INDEX_ID_MAX]; int lba_idx; LinkNode *itemlink; diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index aeab1ee6fca..ba236988c1d 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -291,7 +291,7 @@ void WM_operator_properties_select_random(wmOperatorType *ot) 1.0f, "Ratio", "Portion of items to select randomly", - 0.f, + 0.0f, 1.0f); RNA_def_int(ot->srna, "seed", diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index f96c45f8a05..660e502a3d7 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1809,7 +1809,7 @@ static void WM_OT_call_menu(wmOperatorType *ot) { ot->name = "Call Menu"; ot->idname = "WM_OT_call_menu"; - ot->description = "Call (draw) a predefined menu"; + ot->description = "Open a predefined menu"; ot->exec = wm_call_menu_exec; ot->poll = WM_operator_winactive; @@ -1840,7 +1840,7 @@ static void WM_OT_call_menu_pie(wmOperatorType *ot) { ot->name = "Call Pie Menu"; ot->idname = "WM_OT_call_menu_pie"; - ot->description = "Call (draw) a predefined pie menu"; + ot->description = "Open a predefined pie menu"; ot->invoke = wm_call_pie_menu_invoke; ot->exec = wm_call_pie_menu_exec; @@ -1874,7 +1874,7 @@ static void WM_OT_call_panel(wmOperatorType *ot) { ot->name = "Call Panel"; ot->idname = "WM_OT_call_panel"; - ot->description = "Call (draw) a predefined panel"; + ot->description = "Open a predefined panel"; ot->exec = wm_call_panel_exec; ot->poll = WM_operator_winactive; @@ -2046,7 +2046,7 @@ wmPaintCursor *WM_paint_cursor_activate(short space_type, bool WM_paint_cursor_end(wmPaintCursor *handle) { wmWindowManager *wm = G_MAIN->wm.first; - for (wmPaintCursor *pc = wm->paintcursors.first; pc; pc = pc->next) { + LISTBASE_FOREACH (wmPaintCursor *, pc, &wm->paintcursors) { if (pc == (wmPaintCursor *)handle) { BLI_remlink(&wm->paintcursors, pc); MEM_freeN(pc); @@ -2058,9 +2058,7 @@ bool WM_paint_cursor_end(wmPaintCursor *handle) void WM_paint_cursor_remove_by_type(wmWindowManager *wm, void *draw_fn, void (*free)(void *)) { - wmPaintCursor *pc = wm->paintcursors.first; - while (pc) { - wmPaintCursor *pc_next = pc->next; + LISTBASE_FOREACH_MUTABLE (wmPaintCursor *, pc, &wm->paintcursors) { if (pc->draw == draw_fn) { if (free) { free(pc->customdata); @@ -2068,7 +2066,6 @@ void WM_paint_cursor_remove_by_type(wmWindowManager *wm, void *draw_fn, void (*f BLI_remlink(&wm->paintcursors, pc); MEM_freeN(pc); } - pc = pc_next; } } @@ -3237,7 +3234,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) */ struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - WM_cursor_wait(1); + WM_cursor_wait(true); double time_start = PIL_check_seconds_timer(); @@ -3260,7 +3257,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) RNA_enum_description(redraw_timer_type_items, type, &infostr); - WM_cursor_wait(0); + WM_cursor_wait(false); BKE_reportf(op->reports, RPT_WARNING, diff --git a/source/blender/windowmanager/intern/wm_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c index 65e1cd45e02..45618e9d6d3 100644 --- a/source/blender/windowmanager/intern/wm_platform_support.c +++ b/source/blender/windowmanager/intern/wm_platform_support.c @@ -43,7 +43,9 @@ #define WM_PLATFORM_SUPPORT_TEXT_SIZE 1024 -/* Check if user has already approved the given platform_support_key. */ +/** + * Check if user has already approved the given `platform_support_key`. + */ static bool wm_platform_support_check_approval(const char *platform_support_key, bool update) { const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); @@ -120,11 +122,11 @@ bool WM_platform_support_perform_checks() eGPUSupportLevel support_level = GPU_platform_support_level(); const char *platform_key = GPU_platform_support_level_key(); - /* check if previous check matches the current check. Don't update the approval when running in - * `background`. this could have been triggered by installing addons via installers. */ + /* Check if previous check matches the current check. Don't update the approval when running in + * `background`. this could have been triggered by installing add-ons via installers. */ if (support_level != GPU_SUPPORT_LEVEL_UNSUPPORTED && !G.factory_startup && wm_platform_support_check_approval(platform_key, !G.background)) { - /* if it matches the user has confirmed and whishes to use it */ + /* If it matches the user has confirmed and wishes to use it. */ return result; } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index ada4093080c..2fc941c3d6b 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -520,7 +520,7 @@ void WM_window_set_dpi(const wmWindow *win) static void wm_window_update_eventstate(wmWindow *win) { /* Update mouse position when a window is activated. */ - wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y); + wm_cursor_position_get(win, &win->eventstate->x, &win->eventstate->y); } static void wm_window_ensure_eventstate(wmWindow *win) @@ -983,15 +983,15 @@ void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y) GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y); } -void wm_get_cursor_position(wmWindow *win, int *x, int *y) +void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y) { if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) { - *x = win->eventstate->x; - *y = win->eventstate->y; + *r_x = win->eventstate->x; + *r_y = win->eventstate->y; return; } - GHOST_GetCursorPosition(g_system, x, y); - wm_cursor_position_from_ghost(win, x, y); + GHOST_GetCursorPosition(g_system, r_x, r_y); + wm_cursor_position_from_ghost(win, r_x, r_y); } typedef enum { @@ -1691,7 +1691,7 @@ void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer * /* there might be events in queue with this timer as customdata */ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { - LISTBASE_FOREACH (wmEvent *, event, &win->queue) { + LISTBASE_FOREACH (wmEvent *, event, &win->event_queue) { if (event->customdata == wt) { event->customdata = NULL; event->type = EVENT_NONE; /* timer users customdata, dont want NULL == NULL */ diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 0ac67b987d7..f205f923ec8 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -69,8 +69,8 @@ void wm_window_swap_buffers(wmWindow *win); void wm_window_set_swap_interval(wmWindow *win, int interval); bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut); -void wm_get_cursor_position(wmWindow *win, int *x, int *y); -void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y); +void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y); +void wm_cursor_position_from_ghost(wmWindow *win, int *r_x, int *r_y); void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y); #ifdef WITH_INPUT_IME diff --git a/source/creator/creator.c b/source/creator/creator.c index fbc97028d35..b40718d1f7c 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -47,7 +47,7 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" -/* Mostly init functions. */ +/* Mostly initialization functions. */ #include "BKE_appdir.h" #include "BKE_blender.h" #include "BKE_brush.h" @@ -109,8 +109,6 @@ #include "creator_intern.h" /* Own include. */ -/* Local Function prototypes. */ - /* -------------------------------------------------------------------- */ /** \name Local Application State * \{ */ @@ -264,7 +262,7 @@ int main(int argc, # endif /* Win32 Unicode Arguments. */ - /* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized + /* NOTE: cannot use `guardedalloc` allocation here, as it's not yet initialized * (it depends on the arguments passed in, which is what we're getting here!) */ { @@ -453,8 +451,8 @@ int main(int argc, /* Background render uses this font too. */ BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size); - /* Initialize ffmpeg if built in, also needed for background-mode if videos are - * rendered via ffmpeg. */ + /* Initialize FFMPEG if built in, also needed for background-mode if videos are + * rendered via FFMPEG. */ BKE_sound_init_once(); BKE_materials_init(); @@ -524,7 +522,7 @@ int main(int argc, #endif /* WITH_PYTHON_MODULE */ return 0; -} /* End of int main(...) function. */ +} /* End of `int main(...)` function. */ #ifdef WITH_PYTHON_MODULE void main_python_exit(void) diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index e31be24ec7b..0e0d66d40a9 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -84,6 +84,8 @@ # include "DEG_depsgraph_build.h" # include "DEG_depsgraph_debug.h" +# include "WM_types.h" + # include "creator_intern.h" /* own include */ /* -------------------------------------------------------------------- */ @@ -608,6 +610,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo printf("\n"); printf("Misc Options:\n"); + BLI_args_print_arg_doc(ba, "--open-last"); BLI_args_print_arg_doc(ba, "--app-template"); BLI_args_print_arg_doc(ba, "--factory-startup"); BLI_args_print_arg_doc(ba, "--enable-event-simulate"); @@ -1146,7 +1149,7 @@ static const char arg_handle_env_system_set_doc_python[] = static int arg_handle_env_system_set(int argc, const char **argv, void *UNUSED(data)) { - /* "--env-system-scripts" --> "BLENDER_SYSTEM_SCRIPTS" */ + /* `--env-system-scripts` -> `BLENDER_SYSTEM_SCRIPTS` */ char env[64] = "BLENDER"; char *ch_dst = env + 7; /* skip BLENDER */ @@ -1994,6 +1997,21 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data) return 0; } +static const char arg_handle_load_last_file_doc[] = + "\n\t" + "Open the most recently opened blend file, instead of the default startup file."; +static int arg_handle_load_last_file(int UNUSED(argc), const char **UNUSED(argv), void *data) +{ + if (BLI_listbase_is_empty(&G.recent_files)) { + printf("Warning: no recent files known, opening default startup file instead.\n"); + return -1; + } + + const RecentFile *recent_file = G.recent_files.first; + const char *fake_argv[] = {recent_file->filepath}; + return arg_handle_load_file(ARRAY_SIZE(fake_argv), fake_argv, data); +} + void main_args_setup(bContext *C, bArgs *ba) { @@ -2217,6 +2235,8 @@ void main_args_setup(bContext *C, bArgs *ba) BLI_args_add(ba, "-F", "--render-format", CB(arg_handle_image_type_set), C); BLI_args_add(ba, "-x", "--use-extension", CB(arg_handle_extension_set), C); + BLI_args_add(ba, NULL, "--open-last", CB(arg_handle_load_last_file), C); + # undef CB # undef CB_EX } diff --git a/tests/gtests/runner/CMakeLists.txt b/tests/gtests/runner/CMakeLists.txt index 1fe8cf21810..b18eff59016 100644 --- a/tests/gtests/runner/CMakeLists.txt +++ b/tests/gtests/runner/CMakeLists.txt @@ -82,6 +82,7 @@ elseif(APPLE) # are used as dependencies of other test libraries. foreach(_lib ${_test_libs}) list(REMOVE_ITEM _test_libs_dependencies ${_lib}) + add_dependencies(blender_test ${_lib}) target_link_options(blender_test PRIVATE "LINKER:-force_load,$<TARGET_FILE:${_lib}>") endforeach() diff --git a/tests/python/bl_blendfile_io.py b/tests/python/bl_blendfile_io.py index 2c27b60f34e..38b3a93bbbc 100644 --- a/tests/python/bl_blendfile_io.py +++ b/tests/python/bl_blendfile_io.py @@ -15,7 +15,8 @@ class TestBlendFileSaveLoadBasic(TestHelper): self.args = args def test_save_load(self): - bpy.ops.wm.read_factory_settings() + bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True) + bpy.data.meshes.new("OrphanedMesh") output_dir = self.args.output_dir @@ -71,6 +72,9 @@ def argparse_create(): def main(): args = argparse_create().parse_args() + # Don't write thumbnails into the home directory. + bpy.context.preferences.filepaths.use_save_preview_images = False + for Test in TESTS: Test(args).run_all_tests() diff --git a/tests/python/bl_blendfile_liblink.py b/tests/python/bl_blendfile_liblink.py index fc618314216..a5f2571c902 100644 --- a/tests/python/bl_blendfile_liblink.py +++ b/tests/python/bl_blendfile_liblink.py @@ -15,7 +15,9 @@ class TestBlendLibLinkSaveLoadBasic(TestHelper): self.args = args def test_link_save_load(self): - bpy.ops.wm.read_factory_settings() + + bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True) + me = bpy.data.meshes.new("LibMesh") me.use_fake_user = True @@ -26,7 +28,7 @@ class TestBlendLibLinkSaveLoadBasic(TestHelper): bpy.ops.wm.save_as_mainfile(filepath=output_path, check_existing=False, compress=False) - bpy.ops.wm.read_factory_settings() + bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True) bpy.data.orphans_purge() link_dir = os.path.join(output_path, "Mesh") @@ -68,6 +70,9 @@ def argparse_create(): def main(): args = argparse_create().parse_args() + # Don't write thumbnails into the home directory. + bpy.context.preferences.filepaths.use_save_preview_images = False + for Test in TESTS: Test(args).run_all_tests() |