diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index fee9335239a..27f66c2a07e 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -29,7 +29,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 17 +#define BLENDER_FILE_SUBVERSION 18 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index 76009101187..31318cb61da 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -27,6 +27,7 @@ #include "DNA_modifier_types.h" #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" +#include "DNA_sequence_types.h" #include "DNA_world_types.h" #include "DNA_defaults.h" @@ -61,6 +62,7 @@ #include "BKE_scene.h" #include "BKE_tracking.h" +#include "SEQ_iterator.hh" #include "SEQ_retiming.hh" #include "SEQ_sequencer.hh" @@ -1936,6 +1938,15 @@ static void fix_geometry_nodes_object_info_scale(bNodeTree &ntree) } } +static bool seq_filter_bilinear_to_auto(Sequence *seq, void * /*user_data*/) +{ + StripTransform *transform = seq->strip->transform; + if (transform != nullptr && transform->filter == SEQ_TRANSFORM_FILTER_BILINEAR) { + transform->filter = SEQ_TRANSFORM_FILTER_AUTO; + } + return true; +} + void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) { if (!MAIN_VERSION_FILE_ATLEAST(bmain, 400, 1)) { @@ -2848,6 +2859,14 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) } } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 401, 18)) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->ed != nullptr) { + SEQ_for_each_callback(&scene->ed->seqbase, seq_filter_bilinear_to_auto, nullptr); + } + } + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check. diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index 66d69d003ac..d39671fa981 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -836,6 +836,7 @@ typedef enum SequenceColorTag { /* Sequence->StripTransform->filter */ enum { + SEQ_TRANSFORM_FILTER_AUTO = -1, SEQ_TRANSFORM_FILTER_NEAREST = 0, SEQ_TRANSFORM_FILTER_BILINEAR = 1, SEQ_TRANSFORM_FILTER_BOX = 2, diff --git a/source/blender/makesrna/intern/rna_sequencer.cc b/source/blender/makesrna/intern/rna_sequencer.cc index 490ae5f7561..36ddb334639 100644 --- a/source/blender/makesrna/intern/rna_sequencer.cc +++ b/source/blender/makesrna/intern/rna_sequencer.cc @@ -1696,6 +1696,11 @@ static void rna_def_strip_crop(BlenderRNA *brna) } static const EnumPropertyItem transform_filter_items[] = { + {SEQ_TRANSFORM_FILTER_AUTO, + "AUTO", + 0, + "Auto", + "Automatically choose filter based on scaling factor"}, {SEQ_TRANSFORM_FILTER_NEAREST, "NEAREST", 0, "Nearest", "Use nearest sample"}, {SEQ_TRANSFORM_FILTER_BILINEAR, "BILINEAR", @@ -1770,7 +1775,7 @@ static void rna_def_strip_transform(BlenderRNA *brna) prop = RNA_def_property(srna, "filter", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, nullptr, "filter"); RNA_def_property_enum_items(prop, transform_filter_items); - RNA_def_property_enum_default(prop, SEQ_TRANSFORM_FILTER_BILINEAR); + RNA_def_property_enum_default(prop, SEQ_TRANSFORM_FILTER_AUTO); RNA_def_property_ui_text(prop, "Filter", "Type of filter to use for image transformation"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update"); diff --git a/source/blender/sequencer/intern/render.cc b/source/blender/sequencer/intern/render.cc index de998d5f0d7..ea8d7c6e933 100644 --- a/source/blender/sequencer/intern/render.cc +++ b/source/blender/sequencer/intern/render.cc @@ -500,6 +500,30 @@ static bool seq_image_transform_transparency_gained(const SeqRenderData *context seq_image_quad[3]); } +/* Automatic filter: + * - No scale, no rotation and non-fractional position: nearest. + * - Scale up by more than 2x: cubic mitchell. + * - Scale down by more than 2x: box. + * - Otherwise: bilinear. */ +static eIMBInterpolationFilterMode get_auto_filter(const StripTransform *transform) +{ + const float sx = fabsf(transform->scale_x); + const float sy = fabsf(transform->scale_y); + if (sx > 2.0f && sy > 2.0f) { + return IMB_FILTER_CUBIC_MITCHELL; + } + if (sx < 0.5f && sy < 0.5f) { + return IMB_FILTER_BOX; + } + const float px = transform->xofs; + const float py = transform->yofs; + const float rot = transform->rotation; + if (sx == 1.0f && sy == 1.0f && roundf(px) == px && roundf(py) == py && rot == 0.0f) { + return IMB_FILTER_NEAREST; + } + return IMB_FILTER_BILINEAR; +} + static void sequencer_preprocess_transform_crop( ImBuf *in, ImBuf *out, const SeqRenderData *context, Sequence *seq, const bool is_proxy_image) { @@ -524,6 +548,9 @@ static void sequencer_preprocess_transform_crop( const StripTransform *transform = seq->strip->transform; eIMBInterpolationFilterMode filter = IMB_FILTER_NEAREST; switch (transform->filter) { + case SEQ_TRANSFORM_FILTER_AUTO: + filter = get_auto_filter(seq->strip->transform); + break; case SEQ_TRANSFORM_FILTER_NEAREST: filter = IMB_FILTER_NEAREST; break; diff --git a/source/blender/sequencer/intern/sequencer.cc b/source/blender/sequencer/intern/sequencer.cc index 332b87e5d02..3aedd7dbe83 100644 --- a/source/blender/sequencer/intern/sequencer.cc +++ b/source/blender/sequencer/intern/sequencer.cc @@ -77,7 +77,7 @@ static Strip *seq_strip_alloc(int type) strip->transform->scale_y = 1; strip->transform->origin[0] = 0.5f; strip->transform->origin[1] = 0.5f; - strip->transform->filter = SEQ_TRANSFORM_FILTER_BILINEAR; + strip->transform->filter = SEQ_TRANSFORM_FILTER_AUTO; strip->crop = static_cast(MEM_callocN(sizeof(StripCrop), "StripCrop")); }