diff options
author | Jacques Lucke <jacques@blender.org> | 2020-12-02 18:58:44 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2020-12-02 18:58:44 +0300 |
commit | 390c4efa0c15b39e2d1971bc81464cffae56d102 (patch) | |
tree | d55cdaa779698bdf4b856221a8f826bbf43e2ce4 | |
parent | f14c9444c82662114c6e6015cbd5c187a07a297b (diff) | |
parent | 3d0c5455edf4e32e6e8120b280710cb4b531e38a (diff) |
Merge branch 'master' into geometry-nodes
33 files changed, 1184 insertions, 385 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d36bce18613..d864e08c953 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -91,3 +91,79 @@ c42a6b77b52560d257279de2cb624b4ef2c0d24c # Cleanup: use doxy sections for imbuf c207f7c22e1439e0b285fba5d2c072bdae23f981 + +# Cleanup: Clang-Tidy, modernize-use-bool-literals +af35ada2f3fa8da4d46b3a71de724d353d716820 + +# Cleanup: Use nullptr everywhere in fluid code +311031ecd03dbfbf43e1df672a395f24b2e7d4d3 + +# Cleanup: Clang-Tidy, modernize-redundant-void-arg +a331d5c99299c4514ca33c843b1c79b872f2728d + +# Cleanup: Clang-Tidy modernize-use-nullptr +16732def37c5a66f3ea28dbe247b09cc6bca6677 + +# Cleanup: Clang-tidy, modernize-concat-nested-namespaces +4525049aa0cf818f6483dce589ac9791eb562338 + +# Cleanup: Clang-tidy else-after-return +ae342ed4511cf2e144dcd27ce2c635d3d536f9ad + +# Cleanup: Clang-Tidy, readability-redundant-member-init +190170d4cc92ff34abe1744a10474ac4f1074086 + +# Cleanup: use 'filepath' instead of 'name' for ImBuf utilities +99f56b4c16323f96c0cbf54e392fb509fcac5bda + +# Cleanup: clang-format +c4d8f6a4a8ddc29ed27311ed7578b3c8c31399d2 +b5d310b569e07a937798a2d38539cfd290149f1c +8c846cccd6bdfd3e90a695fabbf05f53e5466a57 +40d4a4cb1a6b4c3c2a486e8f2868f547530e0811 +4eac03d821fa17546f562485f7d073813a5e5943 + +# Cleanup: use preprocessor version check for PyTypeObject declaration +cd9acfed4f7674b84be965d469a367aef96f8af3 + +# Cycles: fix compilation of OSL shaders following API change +b980cd163a9d5d77eeffc2e353333e739fa9e719 + +# Cleanup: clang-tidy suppress warnings for PyTypeObject.tp_print +efd71aad4f22ec0073d80b8dd296015d3f395aa8 + +# Cleanup: fix wrong merge, remove extra unique_ptr. +6507449e54a167c63a72229e4d0119dd2af68ae5 + +# Cleanup: fix some clang tidy issues +525a042c5c7513c41240b118acca002f6c60cc12 + +# Fix T82520: error building freestyle with Python3.8 +e118426e4695a97d67e65d69677f3c4e2db50a56 + +# Cleanup: Clang-tidy, readability-else-after-return +7be47dadea5066ae095c644e0b4f1f10d75f5ab3 + +# Cleanup: Add `r_` to return parameter +45dca05b1cd2a5ead59144c93d790fdfe7c35ee6 + +# Cleanup: Typo in `print_default_info` function name. +41a73909dec716642f044e60b40a28335c9fdb10 + +# Cleanup: Reduce indentation +1cc3a0e2cf73a5ff4f9e0a7f5338eda77266b300 + +# Build-system: Force C linkage for all DNA type headers +ad4b7741dba45a2be210942c18af6b6e4438f129 + +# Cleanup: Move function to proper section +c126e27cdc8b28365a9d5f9fafc4d521d1eb83df + +# Cleanup: remove break after return statements +bbdfeb751e16d939482d2e4b95c4d470f53f18a5 + +# Cleanup: clang-tidy +af013ff76feef7e8b8ba642279c62a5dc275d59f + +# Cleanup: Make panel type flag names more clear +9d28353b525ecfbcca1501be72e4276dfb2bbc2a diff --git a/CMakeLists.txt b/CMakeLists.txt index 580aa1e8d79..81fe4739da4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,9 +178,7 @@ mark_as_advanced(BUILDINFO_OVERRIDE_TIME) option(WITH_IK_ITASC "Enable ITASC IK solver (only disable for development & for incompatible C++ compilers)" ON) option(WITH_IK_SOLVER "Enable Legacy IK solver (only disable for development)" ON) option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke, ocean sim, and audio effects)" ON) -if(WIN32) - option(WITH_PUGIXML "Enable PugiXML support (Used for OpenImageIO, Grease Pencil SVG export)" ON) -endif() +option(WITH_PUGIXML "Enable PugiXML support (Used for OpenImageIO, Grease Pencil SVG export)" ON) option(WITH_BULLET "Enable Bullet (Physics Engine)" ON) option(WITH_SYSTEM_BULLET "Use the systems bullet library (currently unsupported due to missing features in upstream!)" ) mark_as_advanced(WITH_SYSTEM_BULLET) @@ -701,10 +699,8 @@ set_and_warn_dependency(WITH_BOOST WITH_OPENCOLORIO OFF) set_and_warn_dependency(WITH_BOOST WITH_QUADRIFLOW OFF) set_and_warn_dependency(WITH_BOOST WITH_USD OFF) set_and_warn_dependency(WITH_BOOST WITH_ALEMBIC OFF) -if(WIN32) - set_and_warn_dependency(WITH_PUGIXML WITH_CYCLES_OSL OFF) - set_and_warn_dependency(WITH_PUGIXML WITH_OPENIMAGEIO OFF) -endif() +set_and_warn_dependency(WITH_PUGIXML WITH_CYCLES_OSL OFF) +set_and_warn_dependency(WITH_PUGIXML WITH_OPENIMAGEIO OFF) if(WITH_BOOST AND NOT (WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_INTERNATIONAL OR WITH_OPENVDB OR WITH_OPENCOLORIO OR WITH_USD OR WITH_ALEMBIC)) @@ -883,9 +879,11 @@ if(NOT CMAKE_BUILD_TYPE MATCHES "Release") if(APPLE AND COMPILER_ASAN_LIBRARY) string(REPLACE " " ";" _list_COMPILER_ASAN_CFLAGS ${COMPILER_ASAN_CFLAGS}) - add_compile_options("$<$<NOT:$<CONFIG:Release>>:${_list_COMPILER_ASAN_CFLAGS}>") - add_link_options("$<$<NOT:$<CONFIG:Release>>:-fno-omit-frame-pointer;-fsanitize=address>") + set(_is_CONFIG_DEBUG "$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>") + add_compile_options("$<${_is_CONFIG_DEBUG}:${_list_COMPILER_ASAN_CFLAGS}>") + add_link_options("$<${_is_CONFIG_DEBUG}:-fno-omit-frame-pointer;-fsanitize=address>") unset(_list_COMPILER_ASAN_CFLAGS) + unset(_is_CONFIG_DEBUG) elseif(COMPILER_ASAN_LIBRARY) set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS};${COMPILER_ASAN_LIBRARY}") set(PLATFORM_LINKFLAGS "${COMPILER_ASAN_LIBRARY} ${COMPILER_ASAN_LINKER_FLAGS}") diff --git a/build_files/buildbot/codesign/windows_code_signer.py b/build_files/buildbot/codesign/windows_code_signer.py index 251dd856c8a..db185788a56 100644 --- a/build_files/buildbot/codesign/windows_code_signer.py +++ b/build_files/buildbot/codesign/windows_code_signer.py @@ -64,7 +64,12 @@ class WindowsCodeSigner(BaseCodeSigner): def run_codesign_tool(self, filepath: Path) -> None: command = self.get_sign_command_prefix() + [filepath] - codesign_output = self.check_output_or_mock(command, util.Platform.WINDOWS) + + try: + codesign_output = self.check_output_or_mock(command, util.Platform.WINDOWS) + except subprocess.CalledProcessError as e: + raise SigntoolException(f'Error running signtool {e}') + logger_server.info(f'signtool output:\n{codesign_output}') got_number_of_success = False diff --git a/build_files/cmake/Modules/FindPugiXML.cmake b/build_files/cmake/Modules/FindPugiXML.cmake index 5dced1c6df8..f5b1dfce4af 100644 --- a/build_files/cmake/Modules/FindPugiXML.cmake +++ b/build_files/cmake/Modules/FindPugiXML.cmake @@ -49,7 +49,7 @@ FIND_LIBRARY(PUGIXML_LIBRARY # handle the QUIETLY and REQUIRED arguments and set PUGIXML_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(PUGIXML DEFAULT_MSG +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PugiXML DEFAULT_MSG PUGIXML_LIBRARY PUGIXML_INCLUDE_DIR) IF(PUGIXML_FOUND) diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 586c72c9c7e..6baa2f3d855 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -270,6 +270,14 @@ if(WITH_INTERNATIONAL OR WITH_CODEC_FFMPEG) string(APPEND PLATFORM_LINKFLAGS " -liconv") # boost_locale and ffmpeg needs it ! endif() +if(WITH_PUGIXML) + find_package(PugiXML) + if(NOT PUGIXML_FOUND) + message(WARNING "PugiXML not found, disabling WITH_PUGIXML") + set(WITH_PUGIXML OFF) + endif() +endif() + if(WITH_OPENIMAGEIO) find_package(OpenImageIO) list(APPEND OPENIMAGEIO_LIBRARIES diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 97bd4981c22..c4d1383c767 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -350,15 +350,12 @@ if(WITH_BOOST) endif() endif() +if(WITH_PUGIXML) + find_package_wrapper(PugiXML) +endif() + if(WITH_OPENIMAGEIO) find_package_wrapper(OpenImageIO) - if(NOT OPENIMAGEIO_PUGIXML_FOUND AND WITH_CYCLES_STANDALONE) - find_package_wrapper(PugiXML) - else() - set(PUGIXML_INCLUDE_DIR "${OPENIMAGEIO_INCLUDE_DIR/OpenImageIO}") - set(PUGIXML_LIBRARIES "") - endif() - set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${PNG_LIBRARIES} diff --git a/intern/cycles/render/volume.cpp b/intern/cycles/render/volume.cpp index 4baaae6856c..a1bd16798fb 100644 --- a/intern/cycles/render/volume.cpp +++ b/intern/cycles/render/volume.cpp @@ -528,8 +528,10 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress) } /* Clear existing volume mesh, done here in case we early out due to - * empty grid or missing volume shader. */ - volume->clear(); + * empty grid or missing volume shader. + * Also keep the shaders to avoid infinite loops when synchronizing, as this will tag the shaders + * as having changed. */ + volume->clear(true); volume->need_update_rebuild = true; if (!volume_shader) { diff --git a/intern/libmv/libmv/logging/logging.h b/intern/libmv/libmv/logging/logging.h index 776d9d52f7a..0f4f99e3895 100644 --- a/intern/libmv/libmv/logging/logging.h +++ b/intern/libmv/libmv/logging/logging.h @@ -23,9 +23,20 @@ #include <glog/logging.h> -#define LG LOG(INFO) -#define V0 LOG(INFO) -#define V1 LOG(INFO) -#define V2 LOG(INFO) +// Note on logging severity and verbosity level. +// +// Reserve LOG(INFO) for messages which are always to be put to log and don't +// use the INFO severity for the debugging/troubleshooting type of messages. +// Some reasoning behind: +// +// - Library integration would want to disable "noisy" messages coming from +// algorithms. +// +// - It is not possible to disable INFO severity entirely: there is enough +// of preparation being done for the message stream. What is even worse +// is that such stream preparation causes measurable time spent in spin +// lock, ruining multi-threading. + +#define LG VLOG(1) #endif // LIBMV_LOGGING_LOGGING_H diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 866dcad5aa6e45737f0634b835adcbc0871201e +Subproject ca74197440127e56c9f6f2a277c30957f34fd07 diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index cd213b49c5b..fd600a41796 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -235,6 +235,7 @@ const struct CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh); struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh); BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh); int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh); +int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh); /* Only valid for type == PBVH_BMESH */ struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index ab87772d844..47d2ae8e283 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1707,6 +1707,12 @@ int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh) return pbvh->totgrid * pbvh->gridkey.grid_area; } +int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh) +{ + BLI_assert(pbvh->type == PBVH_GRIDS); + return pbvh->totgrid * (pbvh->gridkey.grid_size - 1) * (pbvh->gridkey.grid_size - 1); +} + BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh) { BLI_assert(pbvh->type == PBVH_BMESH); diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c index edd798b162a..05d1e427c14 100644 --- a/source/blender/blenkernel/intern/tracking_auto.c +++ b/source/blender/blenkernel/intern/tracking_auto.c @@ -41,39 +41,65 @@ #include "libmv-capi.h" #include "tracking_private.h" -typedef struct AutoTrackOptions { - int clip_index; /** Index of the clip this track belongs to. */ - int track_index; /* Index of the track in AutoTrack tracks structure. */ - MovieTrackingTrack *track; /* Pointer to an original track/ */ - libmv_TrackRegionOptions track_region_options; /* Options for the region tracker. */ - - /* Define which frame is used for reference marker. */ - eTrackFrameMatch frame_match; - - /* TODO(sergey): A bit awkward to keep it in here, only used to - * place a disabled marker once the tracking fails, - * Either find a clearer way to do it or call it track context - * or state, not options. - */ - bool is_failed; - int failed_frame; -} AutoTrackOptions; +typedef struct AutoTrackClip { + MovieClip *clip; + + /* Dimensions of movie frame, in pixels. + * + * NOTE: All frames within a clip are expected to have match3ed dimensions. */ + int width, height; +} AutoTrackClip; + +typedef struct AutoTrackTrack { + /* Index of a clip from `AutoTrackContext::autotrack_clips` this track belongs to. */ + int clip_index; + + MovieTrackingTrack *track; + + /* Options for the region tracker. */ + libmv_TrackRegionOptions track_region_options; + + /* Denotes whether this track will be tracked. + * Is usually initialized based on track's selection. Non-trackable tracks are still added to the + * context to provide AutoTrack all knowledge about what is going on in the scene. */ + bool is_trackable; +} AutoTrackTrack; + +typedef struct AutoTrackMarker { + libmv_Marker libmv_marker; +} AutoTrackMarker; + +/* Result of tracking step for a single marker. + * + * On success both marker and result are fully initialized to the position on the new frame. + * + * On failure marker's frame number is initialized to frame number where it was attempted to be + * tracked to. The position and other fields of tracked marker are the same as the input. */ +typedef struct AutoTrackTrackingResult { + struct AutoTrackTrackingResult *next, *prev; + + bool success; + libmv_Marker libmv_marker; + libmv_TrackRegionResult libmv_result; +} AutoTrackTrackingResult; typedef struct AutoTrackContext { + /* -------------------------------------------------------------------- + * Invariant part. + * Stays unchanged during the tracking process. + * If not the initialization process, all the fields here should be treated as `const`. + */ + /* Frame at which tracking process started. * NOTE: Measured in scene time frames, */ int start_scene_frame; - /* Scene frame number from which tracker will perform the trackign step. - * The direction of the step is denoted by `is_backwards`. */ - int current_scene_frame; - /* True when tracking backwards (from higher frame number to lower frame number.) */ bool is_backwards; /* Movie clips used during the trackign process. */ int num_clips; - MovieClip *clips[MAX_ACCESSOR_CLIP]; + AutoTrackClip autotrack_clips[MAX_ACCESSOR_CLIP]; /* Tracks for which the context has been created for. * This is a flat array of all tracks coming from all clips, regardless of whether track is @@ -82,35 +108,41 @@ typedef struct AutoTrackContext { * * Indexed by AutoTrackOptions::track_index. */ int num_all_tracks; - MovieTrackingTrack **all_tracks; - - /* Dimensions of movie frame, in pixels. - * - * NOTE: All clips and frames within a clip are expected to have match3ed dimensions. - * - * TODO(sergey): Make it more flexible to fully support multiple-clip tracking. Could either be - * stored as a `pair<MovieClip, Dimensions>` or even be replaced with actual frame size access - * to support variadic frame dimensions. */ - int frame_width, frame_height; + AutoTrackTrack *all_autotrack_tracks; /* Accessor for images of clip. Used by the autotrack context. */ TrackingImageAccessor *image_accessor; + /* -------------------------------------------------------------------- + * Variant part. + * Denotes tracing state and tracking result. + */ + /* Auto-track context. * * NOTE: Is accessed from multiple threads at once. */ struct libmv_AutoTrack *autotrack; - int num_track_options; - AutoTrackOptions *track_options; /* Per-tracking track options. */ + /* Markers from the current frame which will be tracked to the next frame upon the tracking + * context step. + * + * NOTE: This array is re-used across tracking steps, which might make it appear that the array + * is over-allocated when some tracks has failed to track. */ + int num_autotrack_markers; + AutoTrackMarker *autotrack_markers; - int sync_frame; - bool first_sync; - SpinLock spin_lock; + /* Tracking results which are to be synchronized from the AutoTrack context to the Blender's + * DNA to make the results visible for users. */ + ListBase results_to_sync; + int synchronized_scene_frame; - bool step_ok; + SpinLock spin_lock; } AutoTrackContext; +/* -------------------------------------------------------------------- */ +/** \name Marker coordinate system conversion. + * \{ */ + static void normalized_to_libmv_frame(const float normalized[2], const int frame_dimensions[2], float result[2]) @@ -145,8 +177,14 @@ static void libmv_frame_to_normalized_relative(const float frame_coord[2], result[1] = (frame_coord[1] - origin[1]) / frame_dimensions[1]; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Coversion of markers between Blender's DNA and Libmv. + * \{ */ + static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track, - /*const*/ MovieTrackingMarker *marker, + const MovieTrackingMarker *marker, int clip, int track_index, int frame_width, @@ -171,7 +209,9 @@ static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track, normalized_relative_to_libmv_frame( marker->search_max, marker->pos, frame_dimensions, libmv_marker->search_region_max); - /* TODO(sergey): All the markers does have 1.0 weight. */ + /* NOTE: All the markers does have 1.0 weight. + * Might support in the future, but will require more elaborated process which will involve + * F-Curve evaluation. */ libmv_marker->weight = 1.0f; if (marker->flag & MARKER_TRACKED) { @@ -184,13 +224,11 @@ static void dna_marker_to_libmv_marker(/*const*/ MovieTrackingTrack *track, libmv_marker->model_type = LIBMV_MARKER_MODEL_TYPE_POINT; libmv_marker->model_id = 0; - /* TODO(sergey): We currently don't support reference marker from - * different clip. - */ + /* NOTE: We currently don't support reference marker from different clip. */ libmv_marker->reference_clip = clip; if (track->pattern_match == TRACK_MATCH_KEYFRAME) { - MovieTrackingMarker *keyframe_marker = tracking_get_keyframed_marker( + const MovieTrackingMarker *keyframe_marker = tracking_get_keyframed_marker( track, marker->framenr, backwards); libmv_marker->reference_frame = keyframe_marker->framenr; } @@ -235,20 +273,17 @@ static void libmv_marker_to_dna_marker(libmv_Marker *libmv_marker, } } -static bool check_track_trackable(const MovieClip *clip, - MovieTrackingTrack *track, - const MovieClipUser *user) -{ - if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) { - int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr); - const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, frame); - return (marker->flag & MARKER_DISABLED) == 0; - } - return false; -} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name General helpers. + * + * TODO(sergey): Should be moved to tracking_util.c + * + * \{ */ /* Returns false if marker crossed margin area from frame bounds. */ -static bool tracking_check_marker_margin(libmv_Marker *libmv_marker, +static bool tracking_check_marker_margin(const libmv_Marker *libmv_marker, int margin, int frame_width, int frame_height) @@ -277,91 +312,234 @@ static bool tracking_check_marker_margin(libmv_Marker *libmv_marker, return true; } -/* Provide Libmv side of auto track all information about given tracks. */ -static void fill_autotrack_tracks(const int frame_width, - const int frame_height, - const ListBase *tracksbase, - const bool backwards, - struct libmv_AutoTrack *autotrack) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Autotrack context initialization. + * \{ */ + +static bool autotrack_is_marker_usable(const MovieTrackingMarker *marker) { - /* Count number of markers to be put to a context. */ - size_t num_trackable_markers = 0; - LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { - for (int i = 0; i < track->markersnr; i++) { - const MovieTrackingMarker *marker = track->markers + i; - if ((marker->flag & MARKER_DISABLED) == 0) { - num_trackable_markers++; + if ((marker->flag & MARKER_DISABLED)) { + return false; + } + return true; +} + +static bool autotrack_is_track_trackable(const AutoTrackContext *context, + const AutoTrackTrack *autotrack_track) +{ + /*const*/ MovieTrackingTrack *track = autotrack_track->track; + if (TRACK_SELECTED(track) && (track->flag & (TRACK_LOCKED | TRACK_HIDDEN)) == 0) { + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[autotrack_track->clip_index]; + MovieClip *clip = autotrack_clip->clip; + const int clip_frame_number = BKE_movieclip_remap_scene_to_clip_frame( + clip, context->start_scene_frame); + + const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame_number); + return autotrack_is_marker_usable(marker); + } + return false; +} + +static void autotrack_context_init_clips(AutoTrackContext *context, + MovieClip *clip, + MovieClipUser *user) +{ + /* NOTE: Currently only tracking within a single clip. */ + + context->num_clips = 1; + + context->autotrack_clips[0].clip = clip; + BKE_movieclip_get_size( + clip, user, &context->autotrack_clips[0].width, &context->autotrack_clips[0].height); +} + +/* Initialize flat list of tracks for quick index-based access for the specified clip. + * All the tracks from this clip are added at the end of the array of already-collected tracks. + * + * NOTE: Clips should be initialized first. */ +static void autotrack_context_init_tracks_for_clip(AutoTrackContext *context, int clip_index) +{ + BLI_assert(clip_index >= 0); + BLI_assert(clip_index < context->num_clips); + + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index]; + MovieClip *clip = autotrack_clip->clip; + MovieTracking *tracking = &clip->tracking; + ListBase *tracks_base = BKE_tracking_get_active_tracks(tracking); + + const int num_clip_tracks = BLI_listbase_count(tracks_base); + if (num_clip_tracks == 0) { + return; + } + + context->all_autotrack_tracks = MEM_reallocN(context->all_autotrack_tracks, + (context->num_all_tracks + num_clip_tracks) * + sizeof(AutoTrackTrack)); + + LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks_base) { + AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[context->num_all_tracks++]; + autotrack_track->clip_index = clip_index; + autotrack_track->track = track; + autotrack_track->is_trackable = autotrack_is_track_trackable(context, autotrack_track); + + tracking_configure_tracker(track, NULL, &autotrack_track->track_region_options); + } +} + +/* Initialize flat list of tracks for quick index-based access for all clips used for tracking. + * + * NOTE: Clips should be initialized first. */ +static void autotrack_context_init_tracks(AutoTrackContext *context) +{ + BLI_assert(context->num_clips >= 1); + + for (int clip_index = 0; clip_index < context->num_clips; ++clip_index) { + autotrack_context_init_tracks_for_clip(context, clip_index); + } +} + +/* NOTE: Clips should be initialized first. */ +static void autotrack_context_init_image_accessor(AutoTrackContext *context) +{ + BLI_assert(context->num_clips >= 1); + + /* Planarize arrays of clips and tracks, storing pointers to their base "objects". + * This allows image accessor to be independent, but adds some overhead here. Could be solved + * by either more strongly coupling accessor API with the AutoTrack, or by giving some functors + * to the accessor to access clip/track from their indices. */ + + MovieClip *clips[MAX_ACCESSOR_CLIP]; + for (int i = 0; i < context->num_clips; ++i) { + clips[i] = context->autotrack_clips[i].clip; + } + + MovieTrackingTrack **tracks = MEM_malloc_arrayN( + context->num_all_tracks, sizeof(MovieTrackingTrack *), "image accessor init tracks"); + for (int i = 0; i < context->num_all_tracks; ++i) { + tracks[i] = context->all_autotrack_tracks[i].track; + } + + context->image_accessor = tracking_image_accessor_new(clips, 1, tracks, context->num_all_tracks); + + MEM_freeN(tracks); +} + +/* Count markers which are usable to be passed to the AutoTrack context. */ +static size_t autotrack_count_all_usable_markers(AutoTrackContext *context) +{ + size_t num_usable_markers = 0; + for (int track_index = 0; track_index < context->num_all_tracks; ++track_index) { + const MovieTrackingTrack *track = context->all_autotrack_tracks[track_index].track; + for (int marker_index = 0; marker_index < track->markersnr; ++marker_index) { + const MovieTrackingMarker *marker = &track->markers[marker_index]; + if (!autotrack_is_marker_usable(marker)) { + continue; } + num_usable_markers++; + } + } + return num_usable_markers; +} + +static int autotrack_count_trackable_markers(AutoTrackContext *context) +{ + int num_trackable_markers = 0; + for (int track_index = 0; track_index < context->num_all_tracks; ++track_index) { + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + if (!autotrack_track->is_trackable) { + continue; } + num_trackable_markers++; } - /* Early output if we don't have any markers. */ + return num_trackable_markers; +} + +/* Provide Libmv side of auto track all information about given tracks. + * Information from all clips is passed to the auto tracker. + * + * NOTE: Clips and all tracks are to be initialized before calling this. */ +static void autotrack_context_init_autotrack(AutoTrackContext *context) +{ + context->autotrack = libmv_autoTrackNew(context->image_accessor->libmv_accessor); + + /* Count number of markers to be put to a context. */ + const size_t num_trackable_markers = autotrack_count_all_usable_markers(context); if (num_trackable_markers == 0) { return; } + /* Allocate memory for all the markers. */ - libmv_Marker *libmv_markers = MEM_mallocN(sizeof(libmv_Marker) * num_trackable_markers, - "libmv markers array"); + libmv_Marker *libmv_markers = MEM_malloc_arrayN( + sizeof(libmv_Marker), num_trackable_markers, "libmv markers array"); + /* Fill in markers array. */ - int track_index = 0, num_filled_libmv_markers = 0; - LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { - for (int i = 0; i < track->markersnr; i++) { - MovieTrackingMarker *marker = track->markers + i; - if ((marker->flag & MARKER_DISABLED) != 0) { + int num_filled_libmv_markers = 0; + for (int track_index = 0; track_index < context->num_all_tracks; ++track_index) { + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + /*const*/ MovieTrackingTrack *track = autotrack_track->track; + for (int marker_index = 0; marker_index < track->markersnr; ++marker_index) { + /*const*/ MovieTrackingMarker *marker = &track->markers[marker_index]; + if (!autotrack_is_marker_usable(marker)) { continue; } + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[autotrack_track->clip_index]; dna_marker_to_libmv_marker(track, marker, - 0, + autotrack_track->clip_index, track_index, - frame_width, - frame_height, - backwards, + autotrack_clip->width, + autotrack_clip->height, + context->is_backwards, &libmv_markers[num_filled_libmv_markers++]); } - /* Put all markers to autotrack at once. */ - track_index++; } + /* Add all markers to autotrack. */ - libmv_autoTrackSetMarkers(autotrack, libmv_markers, num_trackable_markers); + libmv_autoTrackSetMarkers(context->autotrack, libmv_markers, num_trackable_markers); + /* Free temporary memory. */ MEM_freeN(libmv_markers); } -static void create_per_track_tracking_options(const MovieClip *clip, - const MovieClipUser *user, - const ListBase *tracksbase, - AutoTrackContext *context) +static void autotrack_context_init_markers(AutoTrackContext *context) { /* Count number of trackable tracks. */ - LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { - if (check_track_trackable(clip, track, user)) { - context->num_track_options++; - } + context->num_autotrack_markers = autotrack_count_trackable_markers(context); + if (context->num_autotrack_markers == 0) { + return; } + /* Allocate required memory. */ - context->track_options = MEM_callocN(sizeof(AutoTrackOptions) * context->num_track_options, - "auto track options"); - /* Fill in all the settings. */ - int i = 0, track_index = 0; - LISTBASE_FOREACH (MovieTrackingTrack *, track, tracksbase) { - context->all_tracks[track_index] = track; - - if (!check_track_trackable(clip, track, user)) { - track_index++; + context->autotrack_markers = MEM_calloc_arrayN( + sizeof(AutoTrackMarker), context->num_autotrack_markers, "auto track options"); + + /* Fill in all the markers. */ + int autotrack_marker_index = 0; + for (int track_index = 0; track_index < context->num_all_tracks; ++track_index) { + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + if (!autotrack_track->is_trackable) { continue; } - AutoTrackOptions *track_options = &context->track_options[i++]; - - /* TODO(sergey): Single clip only for now. */ - track_options->clip_index = 0; - track_options->track_index = track_index; - track_options->track = track; - track_options->frame_match = track->pattern_match; - - tracking_configure_tracker(track, NULL, &track_options->track_region_options); + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[autotrack_track->clip_index]; + MovieClip *clip = autotrack_clip->clip; + const int clip_frame_number = BKE_movieclip_remap_scene_to_clip_frame( + clip, context->start_scene_frame); - track_index++; + /*const*/ MovieTrackingTrack *track = context->all_autotrack_tracks[track_index].track; + const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame_number); + + AutoTrackMarker *autotrack_marker = &context->autotrack_markers[autotrack_marker_index++]; + dna_marker_to_libmv_marker(track, + marker, + autotrack_track->clip_index, + track_index, + autotrack_clip->width, + autotrack_clip->height, + context->is_backwards, + &autotrack_marker->libmv_marker); } } @@ -370,198 +548,247 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip, const bool is_backwards) { AutoTrackContext *context = MEM_callocN(sizeof(AutoTrackContext), "autotrack context"); - MovieTracking *tracking = &clip->tracking; - ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); - int frame_width, frame_height; - /* get size of frame to convert normalized coordinates to a picture ones. */ - BKE_movieclip_get_size(clip, user, &frame_width, &frame_height); - /* TODO(sergey): Currently using only a single clip. */ - context->clips[0] = clip; - context->num_clips = 1; - context->current_scene_frame = user->framenr; - context->frame_width = frame_width; - context->frame_height = frame_height; - context->is_backwards = is_backwards; + context->start_scene_frame = user->framenr; - context->sync_frame = user->framenr; - context->first_sync = true; + context->is_backwards = is_backwards; + context->synchronized_scene_frame = context->start_scene_frame; + + autotrack_context_init_clips(context, clip, user); + autotrack_context_init_tracks(context); + autotrack_context_init_image_accessor(context); + autotrack_context_init_autotrack(context); + autotrack_context_init_markers(context); + BLI_spin_init(&context->spin_lock); - context->num_all_tracks = BLI_listbase_count(tracksbase); - context->all_tracks = MEM_callocN(sizeof(MovieTrackingTrack *) * context->num_all_tracks, - "auto track pointers"); - /* Create per-track tracking options. */ - create_per_track_tracking_options(clip, user, tracksbase, context); - /* Initialize image accessor. */ - context->image_accessor = tracking_image_accessor_new( - context->clips, 1, context->all_tracks, context->num_all_tracks); - /* Initialize auto track context and provide all information about currently - * tracked markers. - */ - context->autotrack = libmv_autoTrackNew(context->image_accessor->libmv_accessor); - fill_autotrack_tracks(frame_width, frame_height, tracksbase, is_backwards, context->autotrack); + return context; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Threaded context step (tracking process). + * \{ */ + +/* NOTE: This is a TLS in a sense that this struct is never accessed from multiple threads, and + * that threads are re-using the struct as much as possible. */ +typedef struct AutoTrackTLS { + ListBase results; /* Elements of `AutoTrackTrackingResult`. */ +} AutoTrackTLS; + static void autotrack_context_step_cb(void *__restrict userdata, - const int track, - const TaskParallelTLS *__restrict UNUSED(tls)) + const int marker_index, + const TaskParallelTLS *__restrict tls) { AutoTrackContext *context = userdata; - const int frame_delta = context->is_backwards ? -1 : 1; + AutoTrackTLS *autotrack_tls = (AutoTrackTLS *)tls->userdata_chunk; - AutoTrackOptions *track_options = &context->track_options[track]; - if (track_options->is_failed) { - return; - } + const AutoTrackMarker *autotrack_marker = &context->autotrack_markers[marker_index]; + const libmv_Marker *libmv_current_marker = &autotrack_marker->libmv_marker; - const int track_index = track_options->track_index; - const int clip_index = track_options->clip_index; + const int frame_delta = context->is_backwards ? -1 : 1; + const int clip_index = libmv_current_marker->clip; + const int track_index = libmv_current_marker->track; - libmv_Marker libmv_current_marker, libmv_reference_marker, libmv_tracked_marker; - libmv_TrackRegionResult libmv_result; + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index]; + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + const MovieTrackingTrack *track = autotrack_track->track; - MovieClip *clip = context->clips[clip_index]; - const int frame = BKE_movieclip_remap_scene_to_clip_frame(clip, context->current_scene_frame); - BLI_spin_lock(&context->spin_lock); - const bool has_marker = libmv_autoTrackGetMarker( - context->autotrack, clip_index, frame, track_index, &libmv_current_marker); - BLI_spin_unlock(&context->spin_lock); - /* Check whether we've got marker to sync with. */ - if (!has_marker) { - return; - } /* Check whether marker is going outside of allowed frame margin. */ - if (!tracking_check_marker_margin(&libmv_current_marker, - track_options->track->margin, - context->frame_width, - context->frame_height)) { + if (!tracking_check_marker_margin( + libmv_current_marker, track->margin, autotrack_clip->width, autotrack_clip->height)) { return; } - libmv_tracked_marker = libmv_current_marker; - libmv_tracked_marker.frame = frame + frame_delta; + + const int new_marker_frame = libmv_current_marker->frame + frame_delta; + + AutoTrackTrackingResult *autotrack_result = MEM_mallocN(sizeof(AutoTrackTrackingResult), + "autotrack result"); + autotrack_result->libmv_marker = *libmv_current_marker; + autotrack_result->libmv_marker.frame = new_marker_frame; + /* Update reference frame. */ - if (track_options->frame_match == TRACK_MATCH_KEYFRAME) { - libmv_tracked_marker.reference_frame = libmv_current_marker.reference_frame; + libmv_Marker libmv_reference_marker; + if (track->pattern_match == TRACK_MATCH_KEYFRAME) { + autotrack_result->libmv_marker.reference_frame = libmv_current_marker->reference_frame; libmv_autoTrackGetMarker(context->autotrack, - track_options->clip_index, - libmv_tracked_marker.reference_frame, - track_options->track_index, + clip_index, + autotrack_result->libmv_marker.reference_frame, + track_index, &libmv_reference_marker); } else { - BLI_assert(track_options->frame_match == TRACK_MATCH_PREVIOS_FRAME); - libmv_tracked_marker.reference_frame = frame; - libmv_reference_marker = libmv_current_marker; + BLI_assert(track->pattern_match == TRACK_MATCH_PREVIOS_FRAME); + autotrack_result->libmv_marker.reference_frame = libmv_current_marker->frame; + libmv_reference_marker = *libmv_current_marker; } + /* Perform actual tracking. */ - if (libmv_autoTrackMarker(context->autotrack, - &track_options->track_region_options, - &libmv_tracked_marker, - &libmv_result)) { - BLI_spin_lock(&context->spin_lock); - libmv_autoTrackAddMarker(context->autotrack, &libmv_tracked_marker); - BLI_spin_unlock(&context->spin_lock); + autotrack_result->success = libmv_autoTrackMarker(context->autotrack, + &autotrack_track->track_region_options, + &autotrack_result->libmv_marker, + &autotrack_result->libmv_result); + + /* If tracking failed restore initial position. + * This is how Blender side is currently expecting failed track to be handled. Without this the + * marker is left in an arbitrary position which did not provide good correlation. */ + if (!autotrack_result->success) { + autotrack_result->libmv_marker = *libmv_current_marker; + autotrack_result->libmv_marker.frame = new_marker_frame; } - else { - track_options->is_failed = true; - track_options->failed_frame = frame + frame_delta; + + BLI_addtail(&autotrack_tls->results, autotrack_result); +} + +static void autotrack_context_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + AutoTrackTLS *autotrack_tls = (AutoTrackTLS *)chunk; + if (BLI_listbase_is_empty(&autotrack_tls->results)) { + /* Nothing to be joined from. */ + return; } - /* Note: Atomic is probably not actually needed here, I doubt we could get - * any other result than a true bool anyway. - * But for sake of consistency, and since it costs nothing... - */ - atomic_fetch_and_or_uint8((uint8_t *)&context->step_ok, true); + AutoTrackTLS *autotrack_tls_join = (AutoTrackTLS *)chunk_join; + BLI_movelisttolist(&autotrack_tls_join->results, &autotrack_tls->results); } bool BKE_autotrack_context_step(AutoTrackContext *context) { - const int frame_delta = context->is_backwards ? -1 : 1; - context->step_ok = false; + if (context->num_autotrack_markers == 0) { + return false; + } + + AutoTrackTLS tls; + BLI_listbase_clear(&tls.results); TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (context->num_track_options > 1); + settings.use_threading = (context->num_autotrack_markers > 1); + settings.userdata_chunk = &tls; + settings.userdata_chunk_size = sizeof(AutoTrackTLS); + settings.func_reduce = autotrack_context_reduce; + BLI_task_parallel_range( - 0, context->num_track_options, context, autotrack_context_step_cb, &settings); + 0, context->num_autotrack_markers, context, autotrack_context_step_cb, &settings); + + /* Prepare next tracking step by updating the AutoTrack context with new markers and moving + * tracked markers as an input for the next iteration. */ + context->num_autotrack_markers = 0; + LISTBASE_FOREACH (AutoTrackTrackingResult *, autotrack_result, &tls.results) { + if (!autotrack_result->success) { + continue; + } + + /* Insert tracking results to the AutoTrack context to make them usable for the next frame + * tracking iteration. */ + libmv_autoTrackAddMarker(context->autotrack, &autotrack_result->libmv_marker); + + /* Update the list of markers which will be tracked on the next iteration. */ + context->autotrack_markers[context->num_autotrack_markers++].libmv_marker = + autotrack_result->libmv_marker; + } - /* Advance the frame. */ BLI_spin_lock(&context->spin_lock); - context->current_scene_frame += frame_delta; + BLI_movelisttolist(&context->results_to_sync, &tls.results); BLI_spin_unlock(&context->spin_lock); - return context->step_ok; + + return true; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Context data synchronization. + * + * Used to copy trackign result to Blender side, while the trackign is still happening in its + * thread. + * + * \{ */ + void BKE_autotrack_context_sync(AutoTrackContext *context) { - int newframe, frame_delta = context->is_backwards ? -1 : 1; + const int frame_delta = context->is_backwards ? -1 : 1; BLI_spin_lock(&context->spin_lock); - newframe = context->current_scene_frame; - for (int frame = context->sync_frame; - frame != (context->is_backwards ? newframe - 1 : newframe + 1); - frame += frame_delta) { + ListBase results_to_sync = context->results_to_sync; + BLI_listbase_clear(&context->results_to_sync); + BLI_spin_unlock(&context->spin_lock); + + LISTBASE_FOREACH_MUTABLE (AutoTrackTrackingResult *, autotrack_result, &results_to_sync) { + const libmv_Marker *libmv_marker = &autotrack_result->libmv_marker; + const int clip_index = libmv_marker->clip; + const int track_index = libmv_marker->track; + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index]; + const MovieClip *clip = autotrack_clip->clip; + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + MovieTrackingTrack *track = autotrack_track->track; + + const int start_clip_frame = BKE_movieclip_remap_scene_to_clip_frame( + clip, context->start_scene_frame); + const int first_result_frame = start_clip_frame + frame_delta; + + /* Insert marker which corresponds to the tracking result. */ MovieTrackingMarker marker; - libmv_Marker libmv_marker; - int clip = 0; - for (int i = 0; i < context->num_track_options; i++) { - AutoTrackOptions *track_options = &context->track_options[i]; - MovieTrackingTrack *track = track_options->track; - const int clip_index = track_options->clip_index; - const int track_index = track_options->track_index; - const int track_frame = BKE_movieclip_remap_scene_to_clip_frame(context->clips[clip_index], - frame); - if (track_options->is_failed) { - if (track_options->failed_frame == track_frame) { - MovieTrackingMarker *prev_marker = BKE_tracking_marker_get_exact( - track, context->is_backwards ? frame + 1 : frame - 1); - if (prev_marker) { - marker = *prev_marker; - marker.framenr = track_frame; - marker.flag |= MARKER_DISABLED; - BKE_tracking_marker_insert(track, &marker); - continue; - } - } - if ((context->is_backwards && track_options->failed_frame > track_frame) || - (!context->is_backwards && track_options->failed_frame < track_frame)) { - continue; - } - } - if (libmv_autoTrackGetMarker( - context->autotrack, clip, track_frame, track_index, &libmv_marker)) { - libmv_marker_to_dna_marker( - &libmv_marker, context->frame_width, context->frame_height, &marker); - if (context->first_sync && frame == context->sync_frame) { - tracking_marker_insert_disabled(track, &marker, !context->is_backwards, false); - } - BKE_tracking_marker_insert(track, &marker); - tracking_marker_insert_disabled(track, &marker, context->is_backwards, false); - } + libmv_marker_to_dna_marker( + &autotrack_result->libmv_marker, autotrack_clip->width, autotrack_clip->height, &marker); + if (!autotrack_result->success) { + marker.flag |= MARKER_DISABLED; } + BKE_tracking_marker_insert(track, &marker); + + /* Insetr disabled marker at the end of tracked segment. + * When tracking forward the disabled marker is added at the next frame from the result, + * when tracking backwards the marker is added at the previous frame. */ + tracking_marker_insert_disabled(track, &marker, context->is_backwards, false); + + if (marker.framenr == first_result_frame) { + MovieTrackingMarker *prev_marker = BKE_tracking_marker_get_exact( + track, marker.framenr - frame_delta); + BLI_assert(prev_marker != NULL); + + tracking_marker_insert_disabled(track, prev_marker, !context->is_backwards, false); + } + + /* Update synchronized frame to the latest tracked fame from the current results. */ + const int marker_scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, marker.framenr); + if (context->is_backwards) { + context->synchronized_scene_frame = min_ii(context->synchronized_scene_frame, + marker_scene_frame); + } + else { + context->synchronized_scene_frame = max_ii(context->synchronized_scene_frame, + marker_scene_frame); + } + + MEM_freeN(autotrack_result); } - BLI_spin_unlock(&context->spin_lock); - for (int clip = 0; clip < context->num_clips; clip++) { - MovieTracking *tracking = &context->clips[clip]->tracking; + for (int clip_index = 0; clip_index < context->num_clips; clip_index++) { + MovieTracking *tracking = &context->autotrack_clips[clip_index].clip->tracking; BKE_tracking_dopesheet_tag_update(tracking); } - - context->sync_frame = newframe; - context->first_sync = false; } /* TODO(sergey): Find a way to avoid this, somehow making all needed logic in * BKE_autotrack_context_sync(). */ void BKE_autotrack_context_sync_user(AutoTrackContext *context, MovieClipUser *user) { - user->framenr = context->sync_frame; + user->framenr = context->synchronized_scene_frame; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Finalization. + * \{ */ + void BKE_autotrack_context_finish(AutoTrackContext *context) { for (int clip_index = 0; clip_index < context->num_clips; clip_index++) { - MovieClip *clip = context->clips[clip_index]; + const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index]; + MovieClip *clip = autotrack_clip->clip; ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking); const int start_clip_frame = BKE_movieclip_remap_scene_to_clip_frame( clip, context->start_scene_frame); @@ -570,9 +797,12 @@ void BKE_autotrack_context_finish(AutoTrackContext *context) if ((plane_track->flag & PLANE_TRACK_AUTOKEY)) { continue; } - for (int i = 0; i < context->num_track_options; i++) { - const AutoTrackOptions *track_options = &context->track_options[i]; - MovieTrackingTrack *track = track_options->track; + for (int track_index = 0; track_index < context->num_all_tracks; track_index++) { + const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index]; + if (!autotrack_track->is_trackable) { + continue; + } + MovieTrackingTrack *track = autotrack_track->track; if (BKE_tracking_plane_track_has_point_track(plane_track, track)) { BKE_tracking_track_plane_from_existing_motion(plane_track, start_clip_frame); break; @@ -584,10 +814,22 @@ void BKE_autotrack_context_finish(AutoTrackContext *context) void BKE_autotrack_context_free(AutoTrackContext *context) { - libmv_autoTrackDestroy(context->autotrack); - tracking_image_accessor_destroy(context->image_accessor); - MEM_freeN(context->track_options); - MEM_freeN(context->all_tracks); + if (context->autotrack != NULL) { + libmv_autoTrackDestroy(context->autotrack); + } + + if (context->image_accessor != NULL) { + tracking_image_accessor_destroy(context->image_accessor); + } + + MEM_SAFE_FREE(context->all_autotrack_tracks); + MEM_SAFE_FREE(context->autotrack_markers); + + BLI_freelistN(&context->results_to_sync); + BLI_spin_end(&context->spin_lock); + MEM_freeN(context); } + +/** \} */ diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 7160d4fa41a..9278ff51b8d 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1204,6 +1204,18 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_WeightVGProximity) { + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; + if (wmd->cmap_curve == NULL) { + wmd->cmap_curve = BKE_curvemapping_add(1, 0.0, 0.0, 1.0, 1.0); + BKE_curvemapping_init(wmd->cmap_curve); + } + } + } + } + /* Hair and PointCloud attributes names. */ LISTBASE_FOREACH (Hair *, hair, &bmain->hairs) { do_versions_point_attribute_names(&hair->pdata); diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index 1f95eec4486..cbd2589f20f 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -1910,7 +1910,7 @@ static void draw_armature_edit(ArmatureDrawContext *ctx) edbo_compute_bbone_child(arm); - for (eBone = arm->edbo->first, index = ob->runtime.select_id; eBone; + for (eBone = arm->edbo->first, index = ob_orig->runtime.select_id; eBone; eBone = eBone->next, index += 0x10000) { if (eBone->layer & arm->layer) { if ((eBone->flag & BONE_HIDDEN_A) == 0) { @@ -2005,7 +2005,8 @@ static void draw_armature_pose(ArmatureDrawContext *ctx) DRW_state_is_select(); if (is_pose_select) { - index = ob->runtime.select_id; + const Object *ob_orig = DEG_get_original_object(ob); + index = ob_orig->runtime.select_id; } } diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c index 24943ab5318..f7caf8e4c6a 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c @@ -78,11 +78,21 @@ typedef struct SnapGizmo3D { } SnapGizmo3D; #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK -static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm, const wmEvent *event) +static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm) { - wmKeyMap *keymap = WM_keymap_active(wm, snap_gizmo->keymap); + if (!wm || !wm->winactive) { + return false; + } + if (snap_gizmo->keymap == NULL) { + /* Lazy initialization. */ + snap_gizmo->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map"); + RNA_enum_value_from_id(snap_gizmo->keymap->modal_items, "SNAP_ON", &snap_gizmo->snap_on); + } const int snap_on = snap_gizmo->snap_on; + + wmKeyMap *keymap = WM_keymap_active(wm, snap_gizmo->keymap); + const wmEvent *event = wm->winactive->eventstate; for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { if (kmi->flag & KMI_INACTIVE) { continue; @@ -254,9 +264,7 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz, } #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK - if (wm && wm->winactive) { - snap_gizmo->invert_snap = invert_snap(snap_gizmo, wm, wm->winactive->eventstate); - } + snap_gizmo->invert_snap = invert_snap(snap_gizmo, wm); if (snap_gizmo->use_snap_override == -1) { const ToolSettings *ts = scene->toolsettings; @@ -413,13 +421,7 @@ static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2]) #ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK wmWindowManager *wm = CTX_wm_manager(C); - if (snap_gizmo->keymap == NULL) { - snap_gizmo->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map"); - RNA_enum_value_from_id(snap_gizmo->keymap->modal_items, "SNAP_ON", &snap_gizmo->snap_on); - } - - const bool invert = wm->winactive ? invert_snap(snap_gizmo, wm, wm->winactive->eventstate) : - false; + const bool invert = invert_snap(snap_gizmo, wm); if (snap_gizmo->invert_snap == invert && snap_gizmo->mval[0] == mval[0] && snap_gizmo->mval[1] == mval[1]) { /* Performance, do not update. */ diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index d7ed3dca1b1..6467df0e87b 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1139,6 +1139,9 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, if (use_topology) { v_mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, i); + if (respecthide && BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) { + v_mirr = NULL; + } } else { int i_mirr; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 1ddfa0b9b17..b9427677745 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4025,13 +4025,13 @@ void SCULPT_flip_v3_by_symm_area(float v[3], const ePaintSymmetryAreas symmarea, const float pivot[3]) { - for (char i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { ePaintSymmetryFlags symm_it = 1 << i; if (symm & symm_it) { if (symmarea & symm_it) { flip_v3(v, symm_it); } - if (pivot[0] < 0) { + if (pivot[i] < 0.0f) { flip_v3(v, symm_it); } } @@ -4043,13 +4043,13 @@ void SCULPT_flip_quat_by_symm_area(float quat[3], const ePaintSymmetryAreas symmarea, const float pivot[3]) { - for (char i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) { ePaintSymmetryFlags symm_it = 1 << i; if (symm & symm_it) { if (symmarea & symm_it) { flip_qt(quat, symm_it); } - if (pivot[0] < 0) { + if (pivot[i] < 0.0f) { flip_qt(quat, symm_it); } } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 749e61955d9..9a36c88f6d1 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -659,7 +659,7 @@ static void image_main_region_draw(const bContext *C, ARegion *region) /* Draw Meta data of the image isn't added to the DrawManager as it is * used in other areas as well. */ - if (sima->flag & SI_DRAW_METADATA) { + if (sima->overlay.flag & SI_OVERLAY_SHOW_OVERLAYS && sima->flag & SI_DRAW_METADATA) { void *lock; /* `ED_space_image_get_zoom` temporarily locks the image, so this needs to be done before * the image is locked when calling `ED_space_image_acquire_buffer`. */ diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index bf21b383ba6..890bb8a64bc 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -55,6 +55,7 @@ #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_particle.h" +#include "BKE_pbvh.h" #include "BKE_scene.h" #include "BKE_subdiv_ccg.h" @@ -69,9 +70,9 @@ #define MAX_INFO_NUM_LEN 16 typedef struct SceneStats { - uint64_t totvert, totvertsel; + uint64_t totvert, totvertsel, totvertsculpt; uint64_t totedge, totedgesel; - uint64_t totface, totfacesel; + uint64_t totface, totfacesel, totfacesculpt; uint64_t totbone, totbonesel; uint64_t totobj, totobjsel; uint64_t totlamp, totlampsel; @@ -81,9 +82,9 @@ typedef struct SceneStats { typedef struct SceneStatsFmt { /* Totals */ - char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN]; + char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN], totvertsculpt[MAX_INFO_NUM_LEN]; char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN]; - char totedge[MAX_INFO_NUM_LEN], totedgesel[MAX_INFO_NUM_LEN]; + char totedge[MAX_INFO_NUM_LEN], totedgesel[MAX_INFO_NUM_LEN], totfacesculpt[MAX_INFO_NUM_LEN]; char totbone[MAX_INFO_NUM_LEN], totbonesel[MAX_INFO_NUM_LEN]; char totobj[MAX_INFO_NUM_LEN], totobjsel[MAX_INFO_NUM_LEN]; char totlamp[MAX_INFO_NUM_LEN], totlampsel[MAX_INFO_NUM_LEN]; @@ -350,15 +351,38 @@ static void stats_object_pose(Object *ob, SceneStats *stats) } } -static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats) +static bool stats_is_object_dynamic_topology_sculpt(Object *ob) { - stats->totvert = ob->sculpt->bm->totvert; - stats->tottri = ob->sculpt->bm->totface; + if (ob == NULL) { + return false; + } + const eObjectMode object_mode = ob->mode; + return ((object_mode & OB_MODE_SCULPT) && ob->sculpt && ob->sculpt->bm); } -static bool stats_is_object_dynamic_topology_sculpt(Object *ob, const eObjectMode object_mode) +static void stats_object_sculpt(Object *ob, SceneStats *stats) { - return (ob && (object_mode & OB_MODE_SCULPT) && ob->sculpt && ob->sculpt->bm); + + SculptSession *ss = ob->sculpt; + + if (!ss) { + return; + } + + switch (BKE_pbvh_type(ss->pbvh)) { + case PBVH_FACES: + stats->totvertsculpt = ss->totvert; + stats->totfacesculpt = ss->totfaces; + break; + case PBVH_BMESH: + stats->totvertsculpt = ob->sculpt->bm->totvert; + stats->tottri = ob->sculpt->bm->totface; + break; + case PBVH_GRIDS: + stats->totvertsculpt = BKE_pbvh_get_grid_num_vertices(ss->pbvh); + stats->totfacesculpt = BKE_pbvh_get_grid_num_faces(ss->pbvh); + break; + } } /* Statistics displayed in info header. Called regularly on scene changes. */ @@ -385,9 +409,9 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer) /* Pose Mode */ stats_object_pose(ob, &stats); } - else if (ob && stats_is_object_dynamic_topology_sculpt(ob, ob->mode)) { - /* Dynamic-topology sculpt mode */ - stats_object_sculpt_dynamic_topology(ob, &stats); + else if (stats_is_object_dynamic_topology_sculpt(ob)) { + /* Dynamic topology. Do not count all vertices, dynamic topology stats are initialized later as + * part of sculpt stats. */ } else { /* Objects */ @@ -399,6 +423,12 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer) BLI_gset_free(objects_gset, NULL); } + if (ob && (ob->mode & OB_MODE_SCULPT)) { + /* Sculpt Mode. When dynamic topology is not enabled both sculpt stats and scene stats are + * collected. */ + stats_object_sculpt(ob, &stats); + } + if (!view_layer->stats) { view_layer->stats = MEM_callocN(sizeof(SceneStats), "SceneStats"); } @@ -437,12 +467,14 @@ static bool format_stats(Main *bmain, SCENE_STATS_FMT_INT(totvert); SCENE_STATS_FMT_INT(totvertsel); + SCENE_STATS_FMT_INT(totvertsculpt); SCENE_STATS_FMT_INT(totedge); SCENE_STATS_FMT_INT(totedgesel); SCENE_STATS_FMT_INT(totface); SCENE_STATS_FMT_INT(totfacesel); + SCENE_STATS_FMT_INT(totfacesculpt); SCENE_STATS_FMT_INT(totbone); SCENE_STATS_FMT_INT(totbonesel); @@ -527,7 +559,7 @@ static void get_stats_string( stats_fmt->totgpstroke, stats_fmt->totgppoint); } - else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) { + else if (stats_is_object_dynamic_topology_sculpt(ob)) { *ofs += BLI_snprintf(info + *ofs, len - *ofs, TIP_("Verts:%s | Tris:%s"), @@ -727,9 +759,15 @@ void ED_info_draw_stats( stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, NULL, y, height); stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, NULL, y, height); } - else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) { - stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height); - stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + else if (ob && (object_mode & OB_MODE_SCULPT)) { + if (stats_is_object_dynamic_topology_sculpt(ob)) { + stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, NULL, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + } + else { + stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, stats_fmt.totvert, y, height); + stats_row(col1, labels[FACES], col2, stats_fmt.totfacesculpt, stats_fmt.totface, y, height); + } } else { stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height); diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index af0a8e5e505..a4d999b868d 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -228,7 +228,7 @@ static void protectedAxisAngleBits( } } -static void protectedSizeBits(short protectflag, float size[3]) +void protectedSizeBits(short protectflag, float size[3]) { if (protectflag & OB_LOCK_SCALEX) { size[0] = 1.0f; @@ -431,7 +431,7 @@ static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) } } -static void constraintSizeLim(TransInfo *t, TransData *td) +void constraintSizeLim(TransInfo *t, TransData *td) { if (td->con && td->ext) { const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT); diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index df7d10d1028..7a05506e12c 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -44,7 +44,9 @@ int transform_mode_really_used(struct bContext *C, int mode); bool transdata_check_local_center(TransInfo *t, short around); bool transform_mode_is_changeable(const int mode); void protectedTransBits(short protectflag, float vec[3]); +void protectedSizeBits(short protectflag, float size[3]); void constraintTransLim(TransInfo *t, TransData *td); +void constraintSizeLim(TransInfo *t, TransData *td); void postInputRotation(TransInfo *t, float values[3]); void headerRotation(TransInfo *t, char *str, float final); void ElementRotation_ex(TransInfo *t, diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c index 1440553de51..3aa99975fda 100644 --- a/source/blender/editors/transform/transform_mode_mirror.c +++ b/source/blender/editors/transform/transform_mode_mirror.c @@ -24,8 +24,10 @@ #include <stdlib.h> #include "BLI_math.h" +#include "BLI_math_bits.h" #include "BLI_string.h" +#include "BKE_armature.h" #include "BKE_context.h" #include "ED_screen.h" @@ -41,9 +43,130 @@ /** \name Transform (Mirror) * \{ */ +/** + * Mirrors an object by negating the scale of the object on the mirror axis, reflecting the + * location and adjusting the rotation. + * + * \param axis: Either the axis to mirror on (0 = x, 1 = y, 2 = z) in transform space or -1 for no + * axis mirror. + * \param flip: If true, a mirror on all axis will be performed additionally (point + * reflection). + */ +static void ElementMirror(TransInfo *t, TransDataContainer *tc, TransData *td, int axis, bool flip) +{ + if ((t->flag & T_V3D_ALIGN) == 0 && td->ext) { + /* Size checked needed since the 3D cursor only uses rotation fields. */ + if (td->ext->size) { + float fsize[] = {1.0, 1.0, 1.0}; + + if (axis >= 0) { + fsize[axis] = -fsize[axis]; + } + if (flip) { + negate_v3(fsize); + } + + protectedSizeBits(td->protectflag, fsize); + + mul_v3_v3v3(td->ext->size, td->ext->isize, fsize); + + constraintSizeLim(t, td); + } + + float rmat[3][3]; + if (axis >= 0) { + float imat[3][3]; + mul_m3_m3m3(rmat, t->spacemtx_inv, td->axismtx); + rmat[axis][0] = -rmat[axis][0]; + rmat[axis][1] = -rmat[axis][1]; + rmat[axis][2] = -rmat[axis][2]; + rmat[0][axis] = -rmat[0][axis]; + rmat[1][axis] = -rmat[1][axis]; + rmat[2][axis] = -rmat[2][axis]; + invert_m3_m3(imat, td->axismtx); + mul_m3_m3m3(rmat, rmat, imat); + mul_m3_m3m3(rmat, t->spacemtx, rmat); + + ElementRotation_ex(t, tc, td, rmat, td->center); + + if (td->ext->rotAngle) { + *td->ext->rotAngle = -td->ext->irotAngle; + } + } + else { + unit_m3(rmat); + ElementRotation_ex(t, tc, td, rmat, td->center); + + if (td->ext->rotAngle) { + *td->ext->rotAngle = td->ext->irotAngle; + } + } + } + + if ((td->flag & TD_NO_LOC) == 0) { + float center[3], vec[3]; + + /* Local constraint shouldn't alter center. */ + if (transdata_check_local_center(t, t->around)) { + copy_v3_v3(center, td->center); + } + else if (t->options & CTX_MOVIECLIP) { + if (td->flag & TD_INDIVIDUAL_SCALE) { + copy_v3_v3(center, td->center); + } + else { + copy_v3_v3(center, tc->center_local); + } + } + else { + copy_v3_v3(center, tc->center_local); + } + + /* For individual element center, Editmode need to use iloc. */ + if (t->flag & T_POINTS) { + sub_v3_v3v3(vec, td->iloc, center); + } + else { + sub_v3_v3v3(vec, td->center, center); + } + + if (axis >= 0) { + /* Always do the mirror in global space. */ + if (t->flag & T_EDIT) { + mul_m3_v3(td->mtx, vec); + } + reflect_v3_v3v3(vec, vec, t->spacemtx[axis]); + if (t->flag & T_EDIT) { + mul_m3_v3(td->smtx, vec); + } + } + if (flip) { + negate_v3(vec); + } + + add_v3_v3(vec, center); + if (t->flag & T_POINTS) { + sub_v3_v3(vec, td->iloc); + } + else { + sub_v3_v3(vec, td->center); + } + + if (t->flag & (T_OBJECT | T_POSE)) { + mul_m3_v3(td->smtx, vec); + } + + protectedTransBits(td->protectflag, vec); + if (td->loc) { + add_v3_v3v3(td->loc, td->iloc, vec); + } + + constraintTransLim(t, td); + } +} + static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) { - float size[3], mat[3][3]; int i; char str[UI_MAX_DRAW_STR]; copy_v3_v3(t->values_final, t->values); @@ -54,12 +177,16 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) /* if an axis has been selected */ if (t->con.mode & CON_APPLY) { - size[0] = size[1] = size[2] = -1; - - size_to_mat3(mat, size); - - if (t->con.applySize) { - t->con.applySize(t, NULL, NULL, mat); + /* #special_axis is either the constraint plane normal or the constraint axis. + * Assuming that CON_AXIS0 < CON_AXIS1 < CON_AXIS2 and CON_AXIS2 is CON_AXIS0 << 2 */ + BLI_assert(CON_AXIS2 == CON_AXIS0 << 2); + int axis_bitmap = (t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2)) / CON_AXIS0; + int special_axis_bitmap = 0; + int special_axis = -1; + int bitmap_len = count_bits_i(axis_bitmap); + if (LIKELY(!ELEM(bitmap_len, 0, 3))) { + special_axis_bitmap = (bitmap_len == 2) ? ~axis_bitmap : axis_bitmap; + special_axis = bitscan_forward_i(special_axis_bitmap); } BLI_snprintf(str, sizeof(str), TIP_("Mirror%s"), t->con.text); @@ -71,7 +198,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) continue; } - ElementResize(t, tc, td, mat); + ElementMirror(t, tc, td, special_axis, bitmap_len >= 2); } } @@ -80,10 +207,6 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) ED_area_status_text(t->area, str); } else { - size[0] = size[1] = size[2] = 1; - - size_to_mat3(mat, size); - FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { @@ -91,7 +214,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) continue; } - ElementResize(t, tc, td, mat); + ElementMirror(t, tc, td, -1, false); } } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index aeb34e34d97..7282c35ea0f 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -1040,8 +1040,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) ot->poll = ED_operator_screenactive; ot->poll_property = transform_poll_property; - Transform_Properties( - ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER); + Transform_Properties(ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_GPENCIL_EDIT | P_CENTER); } static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot) diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index b444bd1859d..7e948149a7f 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -130,6 +130,32 @@ void GLBackend::platform_init() GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED; } } + + /* Since Blender 2.91 AMD TeraScale 2 GPUs crashes during startup. */ + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_ANY)) { + if (strstr(renderer, "Radeon HD 4") || strstr(renderer, "Radeon HD 5") || + strstr(renderer, "Radeon HD 6") || strstr(renderer, "ATI FirePro V4") || + strstr(renderer, "AMD Radeon R5 2")) { + GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED; + } + } + /* Driver 20.11.2 fixes a lot of issues for the Navi cards, but introduces new ones + * for Polaris based cards cards. The viewport has glitches but doesn't crash. + * See T82856 */ + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && + strstr(version, " 20.11.2 ")) { + if (strstr(renderer, "Radeon RX 460 ") || strstr(renderer, "Radeon RX 470 ") || + strstr(renderer, "Radeon RX 480 ") || strstr(renderer, "Radeon RX 490 ") || + strstr(renderer, "Radeon RX 560 ") || strstr(renderer, "Radeon RX 570 ") || + strstr(renderer, "Radeon RX 580 ") || strstr(renderer, "Radeon RX 590 ")) { + GPG.support_level = GPU_SUPPORT_LEVEL_LIMITED; + } + } + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_ANY)) { + if (strstr(renderer, "AMD CEDAR")) { + GPG.support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED; + } + } } GPG.create_key(GPG.support_level, vendor, renderer, version); GPG.create_gpu_name(vendor, renderer, version); diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 14394509e49..edb0a4439d6 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1588,6 +1588,10 @@ typedef struct WeightVGProximityModifierData { /** Name of vertex group to modify/weight. MAX_VGROUP_NAME. */ char defgrp_name[64]; + + /* Mapping stuff. */ + /** The custom mapping curve!. */ + struct CurveMapping *cmap_curve; /* Proximity modes. */ int proximity_mode; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 736edc61d74..1e5309e5869 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -786,10 +786,6 @@ static const EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, { ePaintMode mode = BKE_paintmode_get_active_from_context(C); - static const EnumPropertyItem prop_default_items[] = { - {0, NULL, 0, NULL, NULL}, - }; - /* sculpt mode */ static const EnumPropertyItem prop_flatten_contrast_items[] = { {BRUSH_DIR_IN, "CONTRAST", ICON_ADD, "Contrast", "Subtract effect of brush"}, @@ -849,10 +845,10 @@ static const EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, return prop_direction_items; case BRUSH_MASK_SMOOTH: - return prop_default_items; + return DummyRNA_DEFAULT_items; default: - return prop_default_items; + return DummyRNA_DEFAULT_items; } case SCULPT_TOOL_FLATTEN: @@ -871,7 +867,7 @@ static const EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, return prop_inflate_deflate_items; default: - return prop_default_items; + return DummyRNA_DEFAULT_items; } case PAINT_MODE_TEXTURE_2D: @@ -881,11 +877,11 @@ static const EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, return prop_soften_sharpen_items; default: - return prop_default_items; + return DummyRNA_DEFAULT_items; } default: - return prop_default_items; + return DummyRNA_DEFAULT_items; } } diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 47d9c811609..31e920a6799 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -421,7 +421,7 @@ void RNA_api_space_node(struct StructRNA *srna); void RNA_api_space_text(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); +void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip); void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop); void RNA_api_sound(struct StructRNA *srna); void RNA_api_vfont(struct StructRNA *srna); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index fb2692910c5..f0836ae59ad 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -5339,7 +5339,7 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) static const EnumPropertyItem weightvg_proximity_falloff_type_items[] = { {MOD_WVG_MAPPING_NONE, "LINEAR", ICON_LINCURVE, "Linear", "Null action"}, - /* No curve mapping here! */ + {MOD_WVG_MAPPING_CURVE, "CURVE", ICON_RNDCURVE, "Custom Curve", ""}, {MOD_WVG_MAPPING_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", ""}, {MOD_WVG_MAPPING_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""}, {MOD_WVG_MAPPING_ROOT, "ROOT", ICON_ROOTCURVE, "Root", ""}, @@ -5427,6 +5427,11 @@ static void rna_def_modifier_weightvgproximity(BlenderRNA *brna) "Normalize the resulting weights (otherwise they are only clamped within [0.0, 1.0] range)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "map_curve", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "cmap_curve"); + RNA_def_property_ui_text(prop, "Mapping Curve", "Custom mapping curve"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_define_lib_overridable(false); /* Common masking properties. */ diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 2ffb9612486..ac45cd5c5ff 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1967,7 +1967,7 @@ static void rna_def_editor(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "seqbase", NULL); RNA_def_property_struct_type(prop, "Sequence"); RNA_def_property_ui_text(prop, "Sequences", "Top-level strips only"); - RNA_api_sequences(brna, prop); + RNA_api_sequences(brna, prop, false); prop = RNA_def_property(srna, "sequences_all", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "seqbase", NULL); @@ -2339,7 +2339,8 @@ static void rna_def_meta(BlenderRNA *brna) prop = RNA_def_property(srna, "sequences", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "seqbase", NULL); RNA_def_property_struct_type(prop, "Sequence"); - RNA_def_property_ui_text(prop, "Sequences", ""); + RNA_def_property_ui_text(prop, "Sequences", "Sequences nested in meta strip"); + RNA_api_sequences(brna, prop, true); rna_def_filter_video(srna); rna_def_proxy(srna); diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 5419fc4ac7c..6f97098900e 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -77,15 +77,15 @@ static void rna_Sequence_swap_internal(Sequence *seq_self, } static Sequence *alloc_generic_sequence( - Editing *ed, const char *name, int frame_start, int channel, int type, const char *file) + ListBase *seqbase, const char *name, int frame_start, int channel, int type, const char *file) { Sequence *seq; StripElem *se; - seq = BKE_sequence_alloc(ed->seqbasep, frame_start, channel, type); + seq = BKE_sequence_alloc(seqbase, frame_start, channel, type); BLI_strncpy(seq->name + 2, name, sizeof(seq->name) - 2); - BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); + BKE_sequence_base_unique_name_recursive(seqbase, seq); Strip *strip = seq->strip; @@ -105,7 +105,7 @@ static Sequence *alloc_generic_sequence( } static Sequence *rna_Sequences_new_clip(ID *id, - Editing *ed, + ListBase *seqbase, Main *bmain, const char *name, MovieClip *clip, @@ -115,7 +115,8 @@ static Sequence *rna_Sequences_new_clip(ID *id, Scene *scene = (Scene *)id; Sequence *seq; - seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MOVIECLIP, clip->filepath); + 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); @@ -129,13 +130,40 @@ static Sequence *rna_Sequences_new_clip(ID *id, return seq; } -static Sequence *rna_Sequences_new_mask( - ID *id, Editing *ed, Main *bmain, const char *name, Mask *mask, int channel, int frame_start) +static Sequence *rna_Sequences_editing_new_clip(ID *id, + Editing *ed, + Main *bmain, + const char *name, + MovieClip *clip, + int channel, + int frame_start) +{ + return rna_Sequences_new_clip(id, &ed->seqbase, bmain, name, clip, channel, frame_start); +} + +static Sequence *rna_Sequences_meta_new_clip(ID *id, + Sequence *seq, + Main *bmain, + const char *name, + MovieClip *clip, + int channel, + int frame_start) +{ + return rna_Sequences_new_clip(id, &seq->seqbase, bmain, name, clip, channel, frame_start); +} + +static Sequence *rna_Sequences_new_mask(ID *id, + ListBase *seqbase, + Main *bmain, + const char *name, + Mask *mask, + int channel, + int frame_start) { Scene *scene = (Scene *)id; Sequence *seq; - seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MASK, mask->id.name); + 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); @@ -149,9 +177,20 @@ static Sequence *rna_Sequences_new_mask( return seq; } +static Sequence *rna_Sequences_editing_new_mask( + ID *id, Editing *ed, Main *bmain, const char *name, Mask *mask, int channel, int frame_start) +{ + return rna_Sequences_new_mask(id, &ed->seqbase, bmain, name, mask, channel, frame_start); +} + +static Sequence *rna_Sequences_meta_new_mask( + ID *id, Sequence *seq, Main *bmain, const char *name, Mask *mask, int channel, int frame_start) +{ + return rna_Sequences_new_mask(id, &seq->seqbase, bmain, name, mask, channel, frame_start); +} static Sequence *rna_Sequences_new_scene(ID *id, - Editing *ed, + ListBase *seqbase, Main *bmain, const char *name, Scene *sce_seq, @@ -161,7 +200,7 @@ static Sequence *rna_Sequences_new_scene(ID *id, Scene *scene = (Scene *)id; Sequence *seq; - seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_SCENE, NULL); + 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); @@ -176,8 +215,30 @@ static Sequence *rna_Sequences_new_scene(ID *id, return seq; } +static Sequence *rna_Sequences_editing_new_scene(ID *id, + Editing *ed, + Main *bmain, + const char *name, + Scene *sce_seq, + int channel, + int frame_start) +{ + return rna_Sequences_new_scene(id, &ed->seqbase, bmain, name, sce_seq, channel, frame_start); +} + +static Sequence *rna_Sequences_meta_new_scene(ID *id, + Sequence *seq, + Main *bmain, + const char *name, + Scene *sce_seq, + int channel, + int frame_start) +{ + return rna_Sequences_new_scene(id, &seq->seqbase, bmain, name, sce_seq, channel, frame_start); +} + static Sequence *rna_Sequences_new_image(ID *id, - Editing *ed, + ListBase *seqbase, Main *bmain, ReportList *reports, const char *name, @@ -188,12 +249,12 @@ static Sequence *rna_Sequences_new_image(ID *id, Scene *scene = (Scene *)id; Sequence *seq; - seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_IMAGE, file); + seq = alloc_generic_sequence(seqbase, name, frame_start, channel, SEQ_TYPE_IMAGE, file); seq->len = 1; if (seq->strip->stripdata->name[0] == '\0') { BKE_report(reports, RPT_ERROR, "Sequences.new_image: unable to open image file"); - BLI_remlink(&ed->seqbase, seq); + BLI_remlink(seqbase, seq); BKE_sequence_free(scene, seq, true); return NULL; } @@ -208,14 +269,40 @@ static Sequence *rna_Sequences_new_image(ID *id, return seq; } +static Sequence *rna_Sequences_editing_new_image(ID *id, + Editing *ed, + Main *bmain, + ReportList *reports, + const char *name, + const char *file, + int channel, + int frame_start) +{ + return rna_Sequences_new_image( + id, &ed->seqbase, bmain, reports, name, file, channel, frame_start); +} + +static Sequence *rna_Sequences_meta_new_image(ID *id, + Sequence *seq, + Main *bmain, + ReportList *reports, + const char *name, + const char *file, + int channel, + int frame_start) +{ + return rna_Sequences_new_image( + id, &seq->seqbase, bmain, reports, name, file, channel, frame_start); +} + static Sequence *rna_Sequences_new_movie( - ID *id, Editing *ed, const char *name, const char *file, int channel, int frame_start) + ID *id, ListBase *seqbase, const char *name, const char *file, int channel, int frame_start) { Scene *scene = (Scene *)id; Sequence *seq; StripAnim *sanim; - seq = alloc_generic_sequence(ed, name, frame_start, channel, SEQ_TYPE_MOVIE, file); + 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) { @@ -240,9 +327,21 @@ static Sequence *rna_Sequences_new_movie( return seq; } +static Sequence *rna_Sequences_editing_new_movie( + ID *id, Editing *ed, const char *name, const char *file, int channel, int frame_start) +{ + return rna_Sequences_new_movie(id, &ed->seqbase, 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) +{ + return rna_Sequences_new_movie(id, &seq->seqbase, name, file, channel, frame_start); +} + # ifdef WITH_AUDASPACE static Sequence *rna_Sequences_new_sound(ID *id, - Editing *ed, + ListBase *seqbase, Main *bmain, ReportList *reports, const char *name, @@ -262,7 +361,7 @@ static Sequence *rna_Sequences_new_sound(ID *id, return NULL; } seq = alloc_generic_sequence( - ed, name, frame_start, channel, SEQ_TYPE_SOUND_RAM, sound->filepath); + seqbase, name, frame_start, channel, SEQ_TYPE_SOUND_RAM, sound->filepath); seq->sound = sound; seq->len = ceil((double)info.length * FPS); @@ -276,7 +375,7 @@ static Sequence *rna_Sequences_new_sound(ID *id, } # else /* WITH_AUDASPACE */ static Sequence *rna_Sequences_new_sound(ID *UNUSED(id), - Editing *UNUSED(ed), + ListBase *UNUSED(seqbase), Main *UNUSED(bmain), ReportList *reports, const char *UNUSED(name), @@ -289,8 +388,34 @@ static Sequence *rna_Sequences_new_sound(ID *UNUSED(id), } # endif /* WITH_AUDASPACE */ +static Sequence *rna_Sequences_editing_new_sound(ID *id, + Editing *ed, + Main *bmain, + ReportList *reports, + const char *name, + const char *file, + int channel, + int frame_start) +{ + return rna_Sequences_new_sound( + id, &ed->seqbase, bmain, reports, name, file, channel, frame_start); +} + +static Sequence *rna_Sequences_meta_new_sound(ID *id, + Sequence *seq, + Main *bmain, + ReportList *reports, + const char *name, + const char *file, + int channel, + int frame_start) +{ + return rna_Sequences_new_sound( + id, &seq->seqbase, bmain, reports, name, file, channel, frame_start); +} + static Sequence *rna_Sequences_new_effect(ID *id, - Editing *ed, + ListBase *seqbase, ReportList *reports, const char *name, int type, @@ -340,7 +465,7 @@ static Sequence *rna_Sequences_new_effect(ID *id, return NULL; } - seq = alloc_generic_sequence(ed, name, frame_start, channel, type, NULL); + seq = alloc_generic_sequence(seqbase, name, frame_start, channel, type, NULL); sh = BKE_sequence_get_effect(seq); @@ -367,20 +492,52 @@ static Sequence *rna_Sequences_new_effect(ID *id, return seq; } +static Sequence *rna_Sequences_editing_new_effect(ID *id, + Editing *ed, + ReportList *reports, + const char *name, + int type, + int channel, + int frame_start, + int frame_end, + Sequence *seq1, + Sequence *seq2, + Sequence *seq3) +{ + return rna_Sequences_new_effect( + id, &ed->seqbase, reports, name, type, channel, frame_start, frame_end, seq1, seq2, seq3); +} + +static Sequence *rna_Sequences_meta_new_effect(ID *id, + Sequence *seq, + ReportList *reports, + const char *name, + int type, + int channel, + int frame_start, + int frame_end, + Sequence *seq1, + Sequence *seq2, + Sequence *seq3) +{ + return rna_Sequences_new_effect( + id, &seq->seqbase, reports, name, type, channel, frame_start, frame_end, seq1, seq2, seq3); +} + static void rna_Sequences_remove( - ID *id, Editing *ed, Main *bmain, ReportList *reports, PointerRNA *seq_ptr) + ID *id, ListBase *seqbase, Main *bmain, ReportList *reports, PointerRNA *seq_ptr) { Sequence *seq = seq_ptr->data; Scene *scene = (Scene *)id; - if (BLI_findindex(&ed->seqbase, seq) == -1) { + if (BLI_findindex(seqbase, seq) == -1) { BKE_reportf( reports, RPT_ERROR, "Sequence '%s' not in scene '%s'", seq->name + 2, scene->id.name + 2); return; } - BKE_sequencer_flag_for_removal(scene, &ed->seqbase, seq); - BKE_sequencer_remove_flagged_sequences(scene, &ed->seqbase); + BKE_sequencer_flag_for_removal(scene, seqbase, seq); + BKE_sequencer_remove_flagged_sequences(scene, seqbase); RNA_POINTER_INVALIDATE(seq_ptr); DEG_relations_tag_update(bmain); @@ -388,6 +545,18 @@ static void rna_Sequences_remove( WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); } +static void rna_Sequences_editing_remove( + ID *id, Editing *ed, Main *bmain, ReportList *reports, PointerRNA *seq_ptr) +{ + rna_Sequences_remove(id, &ed->seqbase, bmain, reports, seq_ptr); +} + +static void rna_Sequences_meta_remove( + ID *id, Sequence *seq, Main *bmain, ReportList *reports, PointerRNA *seq_ptr) +{ + rna_Sequences_remove(id, &seq->seqbase, bmain, reports, seq_ptr); +} + static StripElem *rna_SequenceElements_append(ID *id, Sequence *seq, const char *filename) { Scene *scene = (Scene *)id; @@ -536,7 +705,7 @@ void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } -void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) +void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip) { StructRNA *srna; PropertyRNA *parm; @@ -564,12 +733,38 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) {0, NULL, 0, NULL, NULL}, }; - RNA_def_property_srna(cprop, "Sequences"); - srna = RNA_def_struct(brna, "Sequences", NULL); - RNA_def_struct_sdna(srna, "Editing"); + const char *new_clip_func_name = "rna_Sequences_editing_new_clip"; + const char *new_mask_func_name = "rna_Sequences_editing_new_mask"; + const char *new_scene_func_name = "rna_Sequences_editing_new_scene"; + const char *new_image_func_name = "rna_Sequences_editing_new_image"; + const char *new_movie_func_name = "rna_Sequences_editing_new_movie"; + const char *new_sound_func_name = "rna_Sequences_editing_new_sound"; + const char *new_effect_func_name = "rna_Sequences_editing_new_effect"; + const char *remove_func_name = "rna_Sequences_editing_remove"; + + if (metastrip) { + RNA_def_property_srna(cprop, "SequencesMeta"); + srna = RNA_def_struct(brna, "SequencesMeta", NULL); + RNA_def_struct_sdna(srna, "Sequence"); + + new_clip_func_name = "rna_Sequences_meta_new_clip"; + new_mask_func_name = "rna_Sequences_meta_new_mask"; + new_scene_func_name = "rna_Sequences_meta_new_scene"; + new_image_func_name = "rna_Sequences_meta_new_image"; + new_movie_func_name = "rna_Sequences_meta_new_movie"; + new_sound_func_name = "rna_Sequences_meta_new_sound"; + new_effect_func_name = "rna_Sequences_meta_new_effect"; + remove_func_name = "rna_Sequences_meta_remove"; + } + else { + RNA_def_property_srna(cprop, "SequencesTopLevel"); + srna = RNA_def_struct(brna, "SequencesTopLevel", NULL); + RNA_def_struct_sdna(srna, "Editing"); + } + RNA_def_struct_ui_text(srna, "Sequences", "Collection of Sequences"); - func = RNA_def_function(srna, "new_clip", "rna_Sequences_new_clip"); + func = RNA_def_function(srna, "new_clip", new_clip_func_name); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Add a new movie clip sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); @@ -593,7 +788,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "new_mask", "rna_Sequences_new_mask"); + func = RNA_def_function(srna, "new_mask", new_mask_func_name); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Add a new mask sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); @@ -617,7 +812,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "new_scene", "rna_Sequences_new_scene"); + func = RNA_def_function(srna, "new_scene", new_scene_func_name); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Add a new scene sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); @@ -641,7 +836,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "new_image", "rna_Sequences_new_image"); + func = RNA_def_function(srna, "new_image", new_image_func_name); RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Add a new image sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); @@ -665,7 +860,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "new_movie", "rna_Sequences_new_movie"); + func = RNA_def_function(srna, "new_movie", new_movie_func_name); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Add a new movie sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); @@ -689,7 +884,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "new_sound", "rna_Sequences_new_sound"); + func = RNA_def_function(srna, "new_sound", new_sound_func_name); RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Add a new sound sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); @@ -713,7 +908,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "new_effect", "rna_Sequences_new_effect"); + func = RNA_def_function(srna, "new_effect", new_effect_func_name); RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Add a new effect sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); @@ -750,7 +945,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Sequences_remove"); + func = RNA_def_function(srna, "remove", remove_func_name); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Remove a Sequence"); parm = RNA_def_pointer(func, "sequence", "Sequence", "", "Sequence to remove"); diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index fd8084d933c..80c69398d15 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -985,7 +985,7 @@ static void panel_draw(const bContext *C, Panel *panel) nullptr, nullptr, 0, - ICON_NONE, + false, nullptr); if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) { diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 9b21c77268e..7232ffd3d9d 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -31,6 +31,7 @@ #include "BLT_translation.h" +#include "DNA_color_types.h" /* CurveMapping. */ #include "DNA_defaults.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -39,6 +40,7 @@ #include "DNA_screen_types.h" #include "BKE_bvhutils.h" +#include "BKE_colortools.h" /* CurveMapping. */ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_customdata.h" @@ -54,6 +56,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "DEG_depsgraph_build.h" @@ -258,7 +262,8 @@ static void do_map(Object *ob, const float min_d, const float max_d, short mode, - const bool do_invert_mapping) + const bool do_invert_mapping, + CurveMapping *cmap) { const float range_inv = 1.0f / (max_d - min_d); /* invert since multiplication is faster */ uint i = nidx; @@ -294,7 +299,6 @@ static void do_map(Object *ob, } } - BLI_assert(mode != MOD_WVG_MAPPING_CURVE); if (do_invert_mapping || mode != MOD_WVG_MAPPING_NONE) { RNG *rng = NULL; @@ -302,7 +306,7 @@ static void do_map(Object *ob, rng = BLI_rng_new_srandom(BLI_ghashutil_strhash(ob->id.name + 2)); } - weightvg_do_map(nidx, weights, mode, do_invert_mapping, NULL, rng); + weightvg_do_map(nidx, weights, mode, do_invert_mapping, cmap, rng); if (rng) { BLI_rng_free(rng); @@ -320,6 +324,25 @@ static void initData(ModifierData *md) BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(wmd, modifier)); MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WeightVGProximityModifierData), modifier); + + wmd->cmap_curve = BKE_curvemapping_add(1, 0.0, 0.0, 1.0, 1.0); + BKE_curvemapping_init(wmd->cmap_curve); +} + +static void freeData(ModifierData *md) +{ + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; + BKE_curvemapping_free(wmd->cmap_curve); +} + +static void copyData(const ModifierData *md, ModifierData *target, const int flag) +{ + const WeightVGProximityModifierData *wmd = (const WeightVGProximityModifierData *)md; + WeightVGProximityModifierData *twmd = (WeightVGProximityModifierData *)target; + + BKE_modifier_copydata_generic(md, target, flag); + + twmd->cmap_curve = BKE_curvemapping_copy(wmd->cmap_curve); } static void requiredDataMask(Object *UNUSED(ob), @@ -587,7 +610,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * wmd->min_dist, wmd->max_dist, wmd->falloff_type, - (wmd->proximity_flags & MOD_WVG_PROXIMITY_INVERT_FALLOFF) != 0); + (wmd->proximity_flags & MOD_WVG_PROXIMITY_INVERT_FALLOFF) != 0, + wmd->cmap_curve); /* Do masking. */ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); @@ -680,6 +704,9 @@ static void falloff_panel_draw(const bContext *UNUSED(C), Panel *panel) sub = uiLayoutRow(row, true); uiLayoutSetPropSep(sub, false); uiItemR(row, ptr, "invert_falloff", 0, "", ICON_ARROW_LEFTRIGHT); + if (RNA_enum_get(ptr, "falloff_type") == MOD_WVG_MAPPING_CURVE) { + uiTemplateCurveMapping(layout, ptr, "map_curve", 0, false, false, false, false); + } modifier_panel_end(layout, ptr); } @@ -703,6 +730,25 @@ static void panelRegister(ARegionType *region_type) region_type, "influence", "Influence", NULL, influence_panel_draw, panel_type); } +static void blendWrite(BlendWriter *writer, const ModifierData *md) +{ + const WeightVGProximityModifierData *wmd = (const WeightVGProximityModifierData *)md; + + if (wmd->cmap_curve) { + BKE_curvemapping_blend_write(writer, wmd->cmap_curve); + } +} + +static void blendRead(BlendDataReader *reader, ModifierData *md) +{ + WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; + + BLO_read_data_address(reader, &wmd->cmap_curve); + if (wmd->cmap_curve) { + BKE_curvemapping_blend_read(reader, wmd->cmap_curve); + } +} + ModifierTypeInfo modifierType_WeightVGProximity = { /* name */ "VertexWeightProximity", /* structName */ "WeightVGProximityModifierData", @@ -713,7 +759,7 @@ ModifierTypeInfo modifierType_WeightVGProximity = { eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_UsesPreview, /* icon */ ICON_MOD_VERTEX_WEIGHT, - /* copyData */ BKE_modifier_copydata_generic, + /* copyData */ copyData, /* deformVerts */ NULL, /* deformMatrices */ NULL, @@ -726,7 +772,7 @@ ModifierTypeInfo modifierType_WeightVGProximity = { /* initData */ initData, /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, + /* freeData */ freeData, /* isDisabled */ isDisabled, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, @@ -735,6 +781,6 @@ ModifierTypeInfo modifierType_WeightVGProximity = { /* foreachTexLink */ foreachTexLink, /* freeRuntimeData */ NULL, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ blendWrite, + /* blendRead */ blendRead, }; diff --git a/source/tools b/source/tools -Subproject d7d7e9d41f7499aa4639f96c843156ff834385b +Subproject 7011d02c292ac1c91a5c9cc1a075ea2727982ce |