diff options
Diffstat (limited to 'source/blender/sequencer/intern')
30 files changed, 1961 insertions, 2540 deletions
diff --git a/source/blender/sequencer/intern/animation.c b/source/blender/sequencer/intern/animation.c new file mode 100644 index 00000000000..492b757a4b1 --- /dev/null +++ b/source/blender/sequencer/intern/animation.c @@ -0,0 +1,122 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2022 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup sequencer + */ + +#include <string.h> + +#include "DNA_anim_types.h" +#include "DNA_scene_types.h" +#include "DNA_sequence_types.h" + +#include "BKE_animsys.h" +#include "BKE_fcurve.h" + +#include "BLI_ghash.h" +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "DEG_depsgraph.h" + +#include "SEQ_animation.h" + +static bool seq_animation_curves_exist(Scene *scene) +{ + if (scene->adt == NULL || scene->adt->action == NULL || + BLI_listbase_is_empty(&scene->adt->action->curves)) { + return false; + } + return true; +} + +/* r_prefix + [" + escaped_name + "] + \0 */ +#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1) + +static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name) +{ + char name_esc[SEQ_NAME_MAXSTR * 2]; + + BLI_str_escape(name_esc, name, sizeof(name_esc)); + return BLI_snprintf_rlen( + str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc); +} + +GSet *SEQ_fcurves_by_strip_get(const Sequence *seq, ListBase *fcurve_base) +{ + char rna_path[SEQ_RNAPATH_MAXSTR]; + size_t rna_path_len = sequencer_rna_path_prefix(rna_path, seq->name + 2); + + GSet *fcurves = BLI_gset_ptr_new(__func__); + LISTBASE_FOREACH (FCurve *, fcurve, fcurve_base) { + if (STREQLEN(fcurve->rna_path, rna_path, rna_path_len)) { + BLI_gset_add(fcurves, fcurve); + } + } + + return fcurves; +} + +#undef SEQ_RNAPATH_MAXSTR + +void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs) +{ + if (!seq_animation_curves_exist(scene) || ofs == 0) { + return; + } + + GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves); + GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) { + unsigned int i; + if (fcu->bezt) { + for (i = 0; i < fcu->totvert; i++) { + BezTriple *bezt = &fcu->bezt[i]; + bezt->vec[0][0] += ofs; + bezt->vec[1][0] += ofs; + bezt->vec[2][0] += ofs; + } + } + if (fcu->fpt) { + for (i = 0; i < fcu->totvert; i++) { + FPoint *fpt = &fcu->fpt[i]; + fpt->vec[0] += ofs; + } + } + } + GSET_FOREACH_END(); + BLI_gset_free(fcurves, NULL); + + DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION); +} + +void SEQ_free_animdata(Scene *scene, Sequence *seq) +{ + if (!seq_animation_curves_exist(scene)) { + return; + } + + GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves); + GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) { + BLI_remlink(&scene->adt->action->curves, fcu); + BKE_fcurve_free(fcu); + } + GSET_FOREACH_END(); + BLI_gset_free(fcurves, NULL); +} diff --git a/source/blender/sequencer/intern/clipboard.c b/source/blender/sequencer/intern/clipboard.c index 05406c50303..886ee89595b 100644 --- a/source/blender/sequencer/intern/clipboard.c +++ b/source/blender/sequencer/intern/clipboard.c @@ -28,6 +28,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_anim_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" #include "DNA_sound_types.h" @@ -35,6 +36,7 @@ #include "BLI_listbase.h" #include "BLI_string.h" +#include "BKE_fcurve.h" #include "BKE_main.h" #include "BKE_movieclip.h" #include "BKE_scene.h" @@ -58,6 +60,7 @@ */ ListBase seqbase_clipboard; +ListBase fcurves_clipboard; int seqbase_clipboard_frame; static char seq_clipboard_active_seq_name[SEQ_NAME_MAXSTR]; @@ -65,15 +68,17 @@ void seq_clipboard_pointers_free(struct ListBase *seqbase); void SEQ_clipboard_free(void) { - Sequence *seq, *nseq; - seq_clipboard_pointers_free(&seqbase_clipboard); - for (seq = seqbase_clipboard.first; seq; seq = nseq) { - nseq = seq->next; - seq_free_sequence_recurse(NULL, seq, false, true); + LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqbase_clipboard) { + seq_free_sequence_recurse(NULL, seq, false); } BLI_listbase_clear(&seqbase_clipboard); + + LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &fcurves_clipboard) { + BKE_fcurve_free(fcu); + } + BLI_listbase_clear(&fcurves_clipboard); } #define ID_PT (*id_pt) @@ -194,13 +199,6 @@ void SEQ_clipboard_active_seq_name_store(Scene *scene) } } -/** - * Check if strip was active when it was copied. User should restrict this check to pasted strips - * before ensuring original name, because strip name comparison is used to check. - * - * \param pasted_seq: Strip that is pasted(duplicated) from clipboard - * \return true if strip was active, false otherwise - */ bool SEQ_clipboard_pasted_seq_was_active(Sequence *pasted_seq) { return STREQ(pasted_seq->name, seq_clipboard_active_seq_name); diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c new file mode 100644 index 00000000000..2db6a3cc8ee --- /dev/null +++ b/source/blender/sequencer/intern/disk_cache.c @@ -0,0 +1,699 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup sequencer + */ + +#include <memory.h> +#include <stddef.h> +#include <time.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" +#include "DNA_sequence_types.h" +#include "DNA_space_types.h" /* for FILE_MAX. */ + +#include "IMB_colormanagement.h" +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BLI_blenlib.h" +#include "BLI_endian_defines.h" +#include "BLI_endian_switch.h" +#include "BLI_fileops.h" +#include "BLI_fileops_types.h" +#include "BLI_ghash.h" +#include "BLI_listbase.h" +#include "BLI_mempool.h" +#include "BLI_path_util.h" +#include "BLI_threads.h" + +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "SEQ_prefetch.h" +#include "SEQ_relations.h" +#include "SEQ_render.h" +#include "SEQ_sequencer.h" + +#include "disk_cache.h" +#include "image_cache.h" +#include "prefetch.h" +#include "strip_time.h" + +/** + * Disk Cache Design Notes + * ======================= + * + * Disk cache uses directory specified in user preferences + * For each cached non-temp image, image data and supplementary info are written to HDD. + * Multiple(DCACHE_IMAGES_PER_FILE) images share the same file. + * Each of these files contains header DiskCacheHeader followed by image data. + * Zlib compression with user definable level can be used to compress image data(per image) + * Images are written in order in which they are rendered. + * Overwriting of individual entry is not possible. + * Stored images are deleted by invalidation, or when size of all files exceeds maximum + * size specified in user preferences. + * To distinguish 2 blend files with same name, scene->ed->disk_cache_timestamp + * is used as UID. Blend file can still be copied manually which may cause conflict. + */ + +/* Format string: + * `<cache type>-<resolution X>x<resolution Y>-<rendersize>%(<view_id>)-<frame no>.dcf`. */ +#define DCACHE_FNAME_FORMAT "%d-%dx%d-%d%%(%d)-%d.dcf" +#define DCACHE_IMAGES_PER_FILE 100 +#define DCACHE_CURRENT_VERSION 2 +#define COLORSPACE_NAME_MAX 64 /* XXX: defined in IMB intern. */ + +typedef struct DiskCacheHeaderEntry { + unsigned char encoding; + uint64_t frameno; + uint64_t size_compressed; + uint64_t size_raw; + uint64_t offset; + char colorspace_name[COLORSPACE_NAME_MAX]; +} DiskCacheHeaderEntry; + +typedef struct DiskCacheHeader { + DiskCacheHeaderEntry entry[DCACHE_IMAGES_PER_FILE]; +} DiskCacheHeader; + +typedef struct SeqDiskCache { + Main *bmain; + int64_t timestamp; + ListBase files; + ThreadMutex read_write_mutex; + size_t size_total; +} SeqDiskCache; + +typedef struct DiskCacheFile { + struct DiskCacheFile *next, *prev; + char path[FILE_MAX]; + char dir[FILE_MAXDIR]; + char file[FILE_MAX]; + BLI_stat_t fstat; + int cache_type; + int rectx; + int recty; + int render_size; + int view_id; + int start_frame; +} DiskCacheFile; + +static ThreadMutex cache_create_lock = BLI_MUTEX_INITIALIZER; + +static char *seq_disk_cache_base_dir(void) +{ + return U.sequencer_disk_cache_dir; +} + +static int seq_disk_cache_compression_level(void) +{ + switch (U.sequencer_disk_cache_compression) { + case USER_SEQ_DISK_CACHE_COMPRESSION_NONE: + return 0; + case USER_SEQ_DISK_CACHE_COMPRESSION_LOW: + return 1; + case USER_SEQ_DISK_CACHE_COMPRESSION_HIGH: + return 9; + } + + return U.sequencer_disk_cache_compression; +} + +static size_t seq_disk_cache_size_limit(void) +{ + return (size_t)U.sequencer_disk_cache_size_limit * (1024 * 1024 * 1024); +} + +bool seq_disk_cache_is_enabled(Main *bmain) +{ + return (U.sequencer_disk_cache_dir[0] != '\0' && U.sequencer_disk_cache_size_limit != 0 && + (U.sequencer_disk_cache_flag & SEQ_CACHE_DISK_CACHE_ENABLE) != 0 && + bmain->filepath[0] != '\0'); +} + +static DiskCacheFile *seq_disk_cache_add_file_to_list(SeqDiskCache *disk_cache, const char *path) +{ + + DiskCacheFile *cache_file = MEM_callocN(sizeof(DiskCacheFile), "SeqDiskCacheFile"); + char dir[FILE_MAXDIR], file[FILE_MAX]; + BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); + BLI_strncpy(cache_file->path, path, sizeof(cache_file->path)); + BLI_strncpy(cache_file->dir, dir, sizeof(cache_file->dir)); + BLI_strncpy(cache_file->file, file, sizeof(cache_file->file)); + sscanf(file, + DCACHE_FNAME_FORMAT, + &cache_file->cache_type, + &cache_file->rectx, + &cache_file->recty, + &cache_file->render_size, + &cache_file->view_id, + &cache_file->start_frame); + cache_file->start_frame *= DCACHE_IMAGES_PER_FILE; + BLI_addtail(&disk_cache->files, cache_file); + return cache_file; +} + +static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path) +{ + struct direntry *filelist, *fl; + uint nbr, i; + disk_cache->size_total = 0; + + i = nbr = BLI_filelist_dir_contents(path, &filelist); + fl = filelist; + while (i--) { + /* Don't follow links. */ + const eFileAttributes file_attrs = BLI_file_attributes(fl->path); + if (file_attrs & FILE_ATTR_ANY_LINK) { + fl++; + continue; + } + + char file[FILE_MAX]; + BLI_split_dirfile(fl->path, NULL, file, 0, sizeof(file)); + + bool is_dir = BLI_is_dir(fl->path); + if (is_dir && !FILENAME_IS_CURRPAR(file)) { + char subpath[FILE_MAX]; + BLI_strncpy(subpath, fl->path, sizeof(subpath)); + BLI_path_slash_ensure(subpath); + seq_disk_cache_get_files(disk_cache, subpath); + } + + if (!is_dir) { + const char *ext = BLI_path_extension(fl->path); + if (ext && ext[1] == 'd' && ext[2] == 'c' && ext[3] == 'f') { + DiskCacheFile *cache_file = seq_disk_cache_add_file_to_list(disk_cache, fl->path); + cache_file->fstat = fl->s; + disk_cache->size_total += cache_file->fstat.st_size; + } + } + fl++; + } + BLI_filelist_free(filelist, nbr); +} + +static DiskCacheFile *seq_disk_cache_get_oldest_file(SeqDiskCache *disk_cache) +{ + DiskCacheFile *oldest_file = disk_cache->files.first; + if (oldest_file == NULL) { + return NULL; + } + for (DiskCacheFile *cache_file = oldest_file->next; cache_file; cache_file = cache_file->next) { + if (cache_file->fstat.st_mtime < oldest_file->fstat.st_mtime) { + oldest_file = cache_file; + } + } + + return oldest_file; +} + +static void seq_disk_cache_delete_file(SeqDiskCache *disk_cache, DiskCacheFile *file) +{ + disk_cache->size_total -= file->fstat.st_size; + BLI_delete(file->path, false, false); + BLI_remlink(&disk_cache->files, file); + MEM_freeN(file); +} + +bool seq_disk_cache_enforce_limits(SeqDiskCache *disk_cache) +{ + BLI_mutex_lock(&disk_cache->read_write_mutex); + while (disk_cache->size_total > seq_disk_cache_size_limit()) { + DiskCacheFile *oldest_file = seq_disk_cache_get_oldest_file(disk_cache); + + if (!oldest_file) { + /* We shouldn't enforce limits with no files, do re-scan. */ + seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir()); + continue; + } + + if (BLI_exists(oldest_file->path) == 0) { + /* File may have been manually deleted during runtime, do re-scan. */ + BLI_freelistN(&disk_cache->files); + seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir()); + continue; + } + + seq_disk_cache_delete_file(disk_cache, oldest_file); + } + BLI_mutex_unlock(&disk_cache->read_write_mutex); + + return true; +} + +static DiskCacheFile *seq_disk_cache_get_file_entry_by_path(SeqDiskCache *disk_cache, char *path) +{ + DiskCacheFile *cache_file = disk_cache->files.first; + + for (; cache_file; cache_file = cache_file->next) { + if (BLI_strcasecmp(cache_file->path, path) == 0) { + return cache_file; + } + } + + return NULL; +} + +/* Update file size and timestamp. */ +static void seq_disk_cache_update_file(SeqDiskCache *disk_cache, char *path) +{ + DiskCacheFile *cache_file; + int64_t size_before; + int64_t size_after; + + cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, path); + size_before = cache_file->fstat.st_size; + + if (BLI_stat(path, &cache_file->fstat) == -1) { + BLI_assert(false); + memset(&cache_file->fstat, 0, sizeof(BLI_stat_t)); + } + + size_after = cache_file->fstat.st_size; + disk_cache->size_total += size_after - size_before; +} + +/* Path format: + * <cache dir>/<project name>_seq_cache/<scene name>-<timestamp>/<seq name>/DCACHE_FNAME_FORMAT + */ + +static void seq_disk_cache_get_project_dir(SeqDiskCache *disk_cache, char *path, size_t path_len) +{ + char cache_dir[FILE_MAX]; + BLI_split_file_part(BKE_main_blendfile_path(disk_cache->bmain), cache_dir, sizeof(cache_dir)); + /* Use suffix, so that the cache directory name does not conflict with the bmain's blend file. */ + const char *suffix = "_seq_cache"; + strncat(cache_dir, suffix, sizeof(cache_dir) - strlen(cache_dir) - 1); + BLI_strncpy(path, seq_disk_cache_base_dir(), path_len); + BLI_path_append(path, path_len, cache_dir); +} + +static void seq_disk_cache_get_dir( + SeqDiskCache *disk_cache, Scene *scene, Sequence *seq, char *path, size_t path_len) +{ + char scene_name[MAX_ID_NAME + 22]; /* + -%PRId64 */ + char seq_name[SEQ_NAME_MAXSTR]; + char project_dir[FILE_MAX]; + + seq_disk_cache_get_project_dir(disk_cache, project_dir, sizeof(project_dir)); + sprintf(scene_name, "%s-%" PRId64, scene->id.name, disk_cache->timestamp); + BLI_strncpy(seq_name, seq->name, sizeof(seq_name)); + BLI_filename_make_safe(scene_name); + BLI_filename_make_safe(seq_name); + BLI_strncpy(path, project_dir, path_len); + BLI_path_append(path, path_len, scene_name); + BLI_path_append(path, path_len, seq_name); +} + +static void seq_disk_cache_get_file_path(SeqDiskCache *disk_cache, + SeqCacheKey *key, + char *path, + size_t path_len) +{ + seq_disk_cache_get_dir(disk_cache, key->context.scene, key->seq, path, path_len); + int frameno = (int)key->frame_index / DCACHE_IMAGES_PER_FILE; + char cache_filename[FILE_MAXFILE]; + sprintf(cache_filename, + DCACHE_FNAME_FORMAT, + key->type, + key->context.rectx, + key->context.recty, + key->context.preview_render_size, + key->context.view_id, + frameno); + + BLI_path_append(path, path_len, cache_filename); +} + +static void seq_disk_cache_create_version_file(char *path) +{ + BLI_make_existing_file(path); + + FILE *file = BLI_fopen(path, "w"); + if (file) { + fprintf(file, "%d", DCACHE_CURRENT_VERSION); + fclose(file); + } +} + +static void seq_disk_cache_handle_versioning(SeqDiskCache *disk_cache) +{ + char path[FILE_MAX]; + char path_version_file[FILE_MAX]; + int version = 0; + + seq_disk_cache_get_project_dir(disk_cache, path, sizeof(path)); + BLI_strncpy(path_version_file, path, sizeof(path_version_file)); + BLI_path_append(path_version_file, sizeof(path_version_file), "cache_version"); + + if (BLI_exists(path) && BLI_is_dir(path)) { + FILE *file = BLI_fopen(path_version_file, "r"); + + if (file) { + const int num_items_read = fscanf(file, "%d", &version); + if (num_items_read == 0) { + version = -1; + } + fclose(file); + } + + if (version != DCACHE_CURRENT_VERSION) { + BLI_delete(path, false, true); + seq_disk_cache_create_version_file(path_version_file); + } + } + else { + seq_disk_cache_create_version_file(path_version_file); + } +} + +static void seq_disk_cache_delete_invalid_files(SeqDiskCache *disk_cache, + Scene *scene, + Sequence *seq, + int invalidate_types, + int range_start, + int range_end) +{ + DiskCacheFile *next_file, *cache_file = disk_cache->files.first; + char cache_dir[FILE_MAX]; + seq_disk_cache_get_dir(disk_cache, scene, seq, cache_dir, sizeof(cache_dir)); + BLI_path_slash_ensure(cache_dir); + + while (cache_file) { + next_file = cache_file->next; + if (cache_file->cache_type & invalidate_types) { + if (STREQ(cache_dir, cache_file->dir)) { + int timeline_frame_start = seq_cache_frame_index_to_timeline_frame( + seq, cache_file->start_frame); + if (timeline_frame_start > range_start && timeline_frame_start <= range_end) { + seq_disk_cache_delete_file(disk_cache, cache_file); + } + } + } + cache_file = next_file; + } +} + +void seq_disk_cache_invalidate(SeqDiskCache *disk_cache, + Scene *scene, + Sequence *seq, + Sequence *seq_changed, + int invalidate_types) +{ + int start; + int end; + + BLI_mutex_lock(&disk_cache->read_write_mutex); + + start = seq_changed->startdisp - DCACHE_IMAGES_PER_FILE; + end = seq_changed->enddisp; + + seq_disk_cache_delete_invalid_files(disk_cache, scene, seq, invalidate_types, start, end); + + BLI_mutex_unlock(&disk_cache->read_write_mutex); +} + +static size_t deflate_imbuf_to_file(ImBuf *ibuf, + FILE *file, + int level, + DiskCacheHeaderEntry *header_entry) +{ + void *data = (ibuf->rect != NULL) ? (void *)ibuf->rect : (void *)ibuf->rect_float; + + /* Apply compression if wanted, otherwise just write directly to the file. */ + if (level > 0) { + return BLI_file_zstd_from_mem_at_pos( + data, header_entry->size_raw, file, header_entry->offset, level); + } + + fseek(file, header_entry->offset, SEEK_SET); + return fwrite(data, 1, header_entry->size_raw, file); +} + +static size_t inflate_file_to_imbuf(ImBuf *ibuf, FILE *file, DiskCacheHeaderEntry *header_entry) +{ + void *data = (ibuf->rect != NULL) ? (void *)ibuf->rect : (void *)ibuf->rect_float; + char header[4]; + fseek(file, header_entry->offset, SEEK_SET); + if (fread(header, 1, sizeof(header), file) != sizeof(header)) { + return 0; + } + + /* Check if the data is compressed or raw. */ + if (BLI_file_magic_is_zstd(header)) { + return BLI_file_unzstd_to_mem_at_pos(data, header_entry->size_raw, file, header_entry->offset); + } + + fseek(file, header_entry->offset, SEEK_SET); + return fread(data, 1, header_entry->size_raw, file); +} + +static bool seq_disk_cache_read_header(FILE *file, DiskCacheHeader *header) +{ + BLI_fseek(file, 0LL, SEEK_SET); + const size_t num_items_read = fread(header, sizeof(*header), 1, file); + if (num_items_read < 1) { + BLI_assert_msg(0, "unable to read disk cache header"); + perror("unable to read disk cache header"); + return false; + } + + for (int i = 0; i < DCACHE_IMAGES_PER_FILE; i++) { + if ((ENDIAN_ORDER == B_ENDIAN) && header->entry[i].encoding == 0) { + BLI_endian_switch_uint64(&header->entry[i].frameno); + BLI_endian_switch_uint64(&header->entry[i].offset); + BLI_endian_switch_uint64(&header->entry[i].size_compressed); + BLI_endian_switch_uint64(&header->entry[i].size_raw); + } + } + + return true; +} + +static size_t seq_disk_cache_write_header(FILE *file, DiskCacheHeader *header) +{ + BLI_fseek(file, 0LL, SEEK_SET); + return fwrite(header, sizeof(*header), 1, file); +} + +static int seq_disk_cache_add_header_entry(SeqCacheKey *key, ImBuf *ibuf, DiskCacheHeader *header) +{ + int i; + uint64_t offset = sizeof(*header); + + /* Lookup free entry, get offset for new data. */ + for (i = 0; i < DCACHE_IMAGES_PER_FILE; i++) { + if (header->entry[i].size_compressed == 0) { + break; + } + } + + /* Attempt to write beyond set entry limit. + * Reset file header and start writing from beginning. + */ + if (i == DCACHE_IMAGES_PER_FILE) { + i = 0; + memset(header, 0, sizeof(*header)); + } + + /* Calculate offset for image data. */ + if (i > 0) { + offset = header->entry[i - 1].offset + header->entry[i - 1].size_compressed; + } + + if (ENDIAN_ORDER == B_ENDIAN) { + header->entry[i].encoding = 255; + } + else { + header->entry[i].encoding = 0; + } + + header->entry[i].offset = offset; + header->entry[i].frameno = key->frame_index; + + /* Store colorspace name of ibuf. */ + const char *colorspace_name; + if (ibuf->rect) { + header->entry[i].size_raw = ibuf->x * ibuf->y * ibuf->channels; + colorspace_name = IMB_colormanagement_get_rect_colorspace(ibuf); + } + else { + header->entry[i].size_raw = ibuf->x * ibuf->y * ibuf->channels * 4; + colorspace_name = IMB_colormanagement_get_float_colorspace(ibuf); + } + BLI_strncpy( + header->entry[i].colorspace_name, colorspace_name, sizeof(header->entry[i].colorspace_name)); + + return i; +} + +static int seq_disk_cache_get_header_entry(SeqCacheKey *key, DiskCacheHeader *header) +{ + for (int i = 0; i < DCACHE_IMAGES_PER_FILE; i++) { + if (header->entry[i].frameno == key->frame_index) { + return i; + } + } + + return -1; +} + +bool seq_disk_cache_write_file(SeqDiskCache *disk_cache, SeqCacheKey *key, ImBuf *ibuf) +{ + BLI_mutex_lock(&disk_cache->read_write_mutex); + + char path[FILE_MAX]; + + seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path)); + BLI_make_existing_file(path); + + FILE *file = BLI_fopen(path, "rb+"); + if (!file) { + file = BLI_fopen(path, "wb+"); + if (!file) { + BLI_mutex_unlock(&disk_cache->read_write_mutex); + return false; + } + seq_disk_cache_add_file_to_list(disk_cache, path); + } + + DiskCacheFile *cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, path); + DiskCacheHeader header; + memset(&header, 0, sizeof(header)); + /* #BLI_make_existing_file() above may create an empty file. This is fine, don't attempt reading + * the header in that case. */ + if (cache_file->fstat.st_size != 0 && !seq_disk_cache_read_header(file, &header)) { + fclose(file); + seq_disk_cache_delete_file(disk_cache, cache_file); + BLI_mutex_unlock(&disk_cache->read_write_mutex); + return false; + } + int entry_index = seq_disk_cache_add_header_entry(key, ibuf, &header); + + size_t bytes_written = deflate_imbuf_to_file( + ibuf, file, seq_disk_cache_compression_level(), &header.entry[entry_index]); + + if (bytes_written != 0) { + /* Last step is writing header, as image data can be overwritten, + * but missing data would cause problems. + */ + header.entry[entry_index].size_compressed = bytes_written; + seq_disk_cache_write_header(file, &header); + seq_disk_cache_update_file(disk_cache, path); + fclose(file); + + BLI_mutex_unlock(&disk_cache->read_write_mutex); + return true; + } + + BLI_mutex_unlock(&disk_cache->read_write_mutex); + return false; +} + +ImBuf *seq_disk_cache_read_file(SeqDiskCache *disk_cache, SeqCacheKey *key) +{ + BLI_mutex_lock(&disk_cache->read_write_mutex); + + char path[FILE_MAX]; + DiskCacheHeader header; + + seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path)); + BLI_make_existing_file(path); + + FILE *file = BLI_fopen(path, "rb"); + if (!file) { + BLI_mutex_unlock(&disk_cache->read_write_mutex); + return NULL; + } + + if (!seq_disk_cache_read_header(file, &header)) { + fclose(file); + BLI_mutex_unlock(&disk_cache->read_write_mutex); + return NULL; + } + int entry_index = seq_disk_cache_get_header_entry(key, &header); + + /* Item not found. */ + if (entry_index < 0) { + fclose(file); + BLI_mutex_unlock(&disk_cache->read_write_mutex); + return NULL; + } + + ImBuf *ibuf; + uint64_t size_char = (uint64_t)key->context.rectx * key->context.recty * 4; + uint64_t size_float = (uint64_t)key->context.rectx * key->context.recty * 16; + size_t expected_size; + + if (header.entry[entry_index].size_raw == size_char) { + expected_size = size_char; + ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rect); + IMB_colormanagement_assign_rect_colorspace(ibuf, header.entry[entry_index].colorspace_name); + } + else if (header.entry[entry_index].size_raw == size_float) { + expected_size = size_float; + ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rectfloat); + IMB_colormanagement_assign_float_colorspace(ibuf, header.entry[entry_index].colorspace_name); + } + else { + fclose(file); + BLI_mutex_unlock(&disk_cache->read_write_mutex); + return NULL; + } + + size_t bytes_read = inflate_file_to_imbuf(ibuf, file, &header.entry[entry_index]); + + /* Sanity check. */ + if (bytes_read != expected_size) { + fclose(file); + IMB_freeImBuf(ibuf); + BLI_mutex_unlock(&disk_cache->read_write_mutex); + return NULL; + } + BLI_file_touch(path); + seq_disk_cache_update_file(disk_cache, path); + fclose(file); + + BLI_mutex_unlock(&disk_cache->read_write_mutex); + return ibuf; +} + +SeqDiskCache *seq_disk_cache_create(Main *bmain, Scene *scene) +{ + SeqDiskCache *disk_cache = MEM_callocN(sizeof(SeqDiskCache), "SeqDiskCache"); + disk_cache->bmain = bmain; + BLI_mutex_init(&disk_cache->read_write_mutex); + seq_disk_cache_handle_versioning(disk_cache); + seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir()); + disk_cache->timestamp = scene->ed->disk_cache_timestamp; + BLI_mutex_unlock(&cache_create_lock); + return disk_cache; +} + +void seq_disk_cache_free(SeqDiskCache *disk_cache) +{ + BLI_freelistN(&disk_cache->files); + BLI_mutex_end(&disk_cache->read_write_mutex); + MEM_freeN(disk_cache); +} diff --git a/source/blender/sequencer/intern/disk_cache.h b/source/blender/sequencer/intern/disk_cache.h new file mode 100644 index 00000000000..a84bfaf5ea0 --- /dev/null +++ b/source/blender/sequencer/intern/disk_cache.h @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup sequencer + */ + +#pragma once + +/** \file + * \ingroup sequencer + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct ImBuf; +struct Main; +struct Scene; +struct SeqCacheKey; +struct SeqDiskCache; +struct Sequence; + +struct SeqDiskCache *seq_disk_cache_create(struct Main *bmain, struct Scene *scene); +void seq_disk_cache_free(struct SeqDiskCache *disk_cache); +bool seq_disk_cache_is_enabled(struct Main *bmain); +struct ImBuf *seq_disk_cache_read_file(struct SeqDiskCache *disk_cache, struct SeqCacheKey *key); +bool seq_disk_cache_write_file(struct SeqDiskCache *disk_cache, + struct SeqCacheKey *key, + struct ImBuf *ibuf); +bool seq_disk_cache_enforce_limits(struct SeqDiskCache *disk_cache); +void seq_disk_cache_invalidate(struct SeqDiskCache *disk_cache, + struct Scene *scene, + struct Sequence *seq, + struct Sequence *seq_changed, + int invalidate_types); +#ifdef __cplusplus +} +#endif diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index 427a8835879..a35e83a8632 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -206,69 +206,22 @@ static void init_alpha_over_or_under(Sequence *seq) seq->seq1 = seq2; } -static void do_alphaover_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) -{ - float fac2, mfac, fac, fac4; - int xo; - unsigned char *cp1, *cp2, *rt; - float tempc[4], rt1[4], rt2[4]; - - xo = x; - cp1 = rect1; - cp2 = rect2; - rt = out; - - fac2 = facf0; - fac4 = facf1; - - while (y--) { - x = xo; - while (x--) { - /* rt = rt1 over rt2 (alpha from rt1) */ - - straight_uchar_to_premul_float(rt1, cp1); - straight_uchar_to_premul_float(rt2, cp2); - - fac = fac2; - mfac = 1.0f - fac2 * rt1[3]; - - if (fac <= 0.0f) { - *((unsigned int *)rt) = *((unsigned int *)cp2); - } - else if (mfac <= 0.0f) { - *((unsigned int *)rt) = *((unsigned int *)cp1); - } - else { - tempc[0] = fac * rt1[0] + mfac * rt2[0]; - tempc[1] = fac * rt1[1] + mfac * rt2[1]; - tempc[2] = fac * rt1[2] + mfac * rt2[2]; - tempc[3] = fac * rt1[3] + mfac * rt2[3]; - - premul_float_to_straight_uchar(rt, tempc); - } - cp1 += 4; - cp2 += 4; - rt += 4; - } +static void do_alphaover_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +{ + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; - if (y == 0) { - break; - } - y--; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + /* rt = rt1 over rt2 (alpha from rt1) */ - x = xo; - while (x--) { + float tempc[4], rt1[4], rt2[4]; straight_uchar_to_premul_float(rt1, cp1); straight_uchar_to_premul_float(rt2, cp2); - fac = fac4; - mfac = 1.0f - (fac4 * rt1[3]); + float mfac = 1.0f - fac * rt1[3]; if (fac <= 0.0f) { *((unsigned int *)rt) = *((unsigned int *)cp2); @@ -292,27 +245,17 @@ static void do_alphaover_effect_byte(float facf0, } static void do_alphaover_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) + float fac, int x, int y, float *rect1, float *rect2, float *out) { - float fac2, mfac, fac, fac4; - int xo; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - fac2 = facf0; - fac4 = facf1; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - while (y--) { - x = xo; - while (x--) { + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { /* rt = rt1 over rt2 (alpha from rt1) */ - fac = fac2; - mfac = 1.0f - (fac2 * rt1[3]); + float mfac = 1.0f - (fac * rt1[3]); if (fac <= 0.0f) { memcpy(rt, rt2, sizeof(float[4])); @@ -330,41 +273,13 @@ static void do_alphaover_effect_float( rt2 += 4; rt += 4; } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - fac = fac4; - mfac = 1.0f - (fac4 * rt1[3]); - - if (fac <= 0.0f) { - memcpy(rt, rt2, sizeof(float[4])); - } - else if (mfac <= 0.0f) { - memcpy(rt, rt1, sizeof(float[4])); - } - else { - rt[0] = fac * rt1[0] + mfac * rt2[0]; - rt[1] = fac * rt1[1] + mfac * rt2[1]; - rt[2] = fac * rt1[2] + mfac * rt2[2]; - rt[3] = fac * rt1[3] + mfac * rt2[3]; - } - rt1 += 4; - rt2 += 4; - rt += 4; - } } } static void do_alphaover_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -378,7 +293,7 @@ static void do_alphaover_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaover_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_alphaover_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -386,96 +301,47 @@ static void do_alphaover_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaover_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_alphaover_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Alpha Under *************************/ -static void do_alphaunder_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) -{ - float fac2, fac, fac4; - int xo; - unsigned char *cp1, *cp2, *rt; - float tempc[4], rt1[4], rt2[4]; - - xo = x; - cp1 = rect1; - cp2 = rect2; - rt = out; - - fac2 = facf0; - fac4 = facf1; - - while (y--) { - x = xo; - while (x--) { +static void do_alphaunder_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +{ + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; + + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { /* rt = rt1 under rt2 (alpha from rt2) */ + + float tempc[4], rt1[4], rt2[4]; straight_uchar_to_premul_float(rt1, cp1); straight_uchar_to_premul_float(rt2, cp2); /* this complex optimization is because the * 'skybuf' can be crossed in */ - if (rt2[3] <= 0.0f && fac2 >= 1.0f) { + if (rt2[3] <= 0.0f && fac >= 1.0f) { *((unsigned int *)rt) = *((unsigned int *)cp1); } else if (rt2[3] >= 1.0f) { *((unsigned int *)rt) = *((unsigned int *)cp2); } else { - fac = (fac2 * (1.0f - rt2[3])); + float temp_fac = (fac * (1.0f - rt2[3])); if (fac <= 0) { *((unsigned int *)rt) = *((unsigned int *)cp2); } else { - tempc[0] = (fac * rt1[0] + rt2[0]); - tempc[1] = (fac * rt1[1] + rt2[1]); - tempc[2] = (fac * rt1[2] + rt2[2]); - tempc[3] = (fac * rt1[3] + rt2[3]); - - premul_float_to_straight_uchar(rt, tempc); - } - } - cp1 += 4; - cp2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - straight_uchar_to_premul_float(rt1, cp1); - straight_uchar_to_premul_float(rt2, cp2); - - if (rt2[3] <= 0.0f && fac4 >= 1.0f) { - *((unsigned int *)rt) = *((unsigned int *)cp1); - } - else if (rt2[3] >= 1.0f) { - *((unsigned int *)rt) = *((unsigned int *)cp2); - } - else { - fac = (fac4 * (1.0f - rt2[3])); - - if (fac <= 0) { - *((unsigned int *)rt) = *((unsigned int *)cp2); - } - else { - tempc[0] = (fac * rt1[0] + rt2[0]); - tempc[1] = (fac * rt1[1] + rt2[1]); - tempc[2] = (fac * rt1[2] + rt2[2]); - tempc[3] = (fac * rt1[3] + rt2[3]); + tempc[0] = (temp_fac * rt1[0] + rt2[0]); + tempc[1] = (temp_fac * rt1[1] + rt2[1]); + tempc[2] = (temp_fac * rt1[2] + rt2[2]); + tempc[3] = (temp_fac * rt1[3] + rt2[3]); premul_float_to_straight_uchar(rt, tempc); } @@ -488,76 +354,36 @@ static void do_alphaunder_effect_byte(float facf0, } static void do_alphaunder_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) + float fac, int x, int y, float *rect1, float *rect2, float *out) { - float fac2, fac, fac4; - int xo; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - fac2 = facf0; - fac4 = facf1; - - while (y--) { - x = xo; - while (x--) { + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { /* rt = rt1 under rt2 (alpha from rt2) */ /* this complex optimization is because the * 'skybuf' can be crossed in */ - if (rt2[3] <= 0 && fac2 >= 1.0f) { + if (rt2[3] <= 0 && fac >= 1.0f) { memcpy(rt, rt1, sizeof(float[4])); } else if (rt2[3] >= 1.0f) { memcpy(rt, rt2, sizeof(float[4])); } else { - fac = fac2 * (1.0f - rt2[3]); + float temp_fac = fac * (1.0f - rt2[3]); if (fac == 0) { memcpy(rt, rt2, sizeof(float[4])); } else { - rt[0] = fac * rt1[0] + rt2[0]; - rt[1] = fac * rt1[1] + rt2[1]; - rt[2] = fac * rt1[2] + rt2[2]; - rt[3] = fac * rt1[3] + rt2[3]; - } - } - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - if (rt2[3] <= 0 && fac4 >= 1.0f) { - memcpy(rt, rt1, sizeof(float[4])); - } - else if (rt2[3] >= 1.0f) { - memcpy(rt, rt2, sizeof(float[4])); - } - else { - fac = fac4 * (1.0f - rt2[3]); - - if (fac == 0) { - memcpy(rt, rt2, sizeof(float[4])); - } - else { - rt[0] = fac * rt1[0] + rt2[0]; - rt[1] = fac * rt1[1] + rt2[1]; - rt[2] = fac * rt1[2] + rt2[2]; - rt[3] = fac * rt1[3] + rt2[3]; + rt[0] = temp_fac * rt1[0] + rt2[0]; + rt[1] = temp_fac * rt1[1] + rt2[1]; + rt[2] = temp_fac * rt1[2] + rt2[2]; + rt[3] = temp_fac * rt1[3] + rt2[3]; } } rt1 += 4; @@ -570,8 +396,7 @@ static void do_alphaunder_effect_float( static void do_alphaunder_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -585,7 +410,7 @@ static void do_alphaunder_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaunder_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_alphaunder_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -593,58 +418,28 @@ static void do_alphaunder_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaunder_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_alphaunder_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Cross *************************/ -static void do_cross_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) +static void do_cross_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int fac1, fac2, fac3, fac4; - int xo; - unsigned char *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; + unsigned char *rt1 = rect1; + unsigned char *rt2 = rect2; + unsigned char *rt = out; - fac2 = (int)(256.0f * facf0); - fac1 = 256 - fac2; - fac4 = (int)(256.0f * facf1); - fac3 = 256 - fac4; + int temp_fac = (int)(256.0f * fac); + int temp_mfac = 256 - temp_fac; - while (y--) { - x = xo; - while (x--) { - rt[0] = (fac1 * rt1[0] + fac2 * rt2[0]) >> 8; - rt[1] = (fac1 * rt1[1] + fac2 * rt2[1]) >> 8; - rt[2] = (fac1 * rt1[2] + fac2 * rt2[2]) >> 8; - rt[3] = (fac1 * rt1[3] + fac2 * rt2[3]) >> 8; - - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - rt[0] = (fac3 * rt1[0] + fac4 * rt2[0]) >> 8; - rt[1] = (fac3 * rt1[1] + fac4 * rt2[1]) >> 8; - rt[2] = (fac3 * rt1[2] + fac4 * rt2[2]) >> 8; - rt[3] = (fac3 * rt1[3] + fac4 * rt2[3]) >> 8; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rt[0] = (temp_mfac * rt1[0] + temp_fac * rt2[0]) >> 8; + rt[1] = (temp_mfac * rt1[1] + temp_fac * rt2[1]) >> 8; + rt[2] = (temp_mfac * rt1[2] + temp_fac * rt2[2]) >> 8; + rt[3] = (temp_mfac * rt1[3] + temp_fac * rt2[3]) >> 8; rt1 += 4; rt2 += 4; @@ -653,47 +448,20 @@ static void do_cross_effect_byte(float facf0, } } -static void do_cross_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_cross_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out) { - float fac1, fac2, fac3, fac4; - int xo; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - fac2 = facf0; - fac1 = 1.0f - fac2; - fac4 = facf1; - fac3 = 1.0f - fac4; + float mfac = 1.0f - fac; - while (y--) { - x = xo; - while (x--) { - rt[0] = fac1 * rt1[0] + fac2 * rt2[0]; - rt[1] = fac1 * rt1[1] + fac2 * rt2[1]; - rt[2] = fac1 * rt1[2] + fac2 * rt2[2]; - rt[3] = fac1 * rt1[3] + fac2 * rt2[3]; - - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - rt[0] = fac3 * rt1[0] + fac4 * rt2[0]; - rt[1] = fac3 * rt1[1] + fac4 * rt2[1]; - rt[2] = fac3 * rt1[2] + fac4 * rt2[2]; - rt[3] = fac3 * rt1[3] + fac4 * rt2[3]; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rt[0] = mfac * rt1[0] + fac * rt2[0]; + rt[1] = mfac * rt1[1] + fac * rt2[1]; + rt[2] = mfac * rt1[2] + fac * rt2[2]; + rt[3] = mfac * rt1[3] + fac * rt2[3]; rt1 += 4; rt2 += 4; @@ -705,8 +473,7 @@ static void do_cross_effect_float( static void do_cross_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -720,7 +487,7 @@ static void do_cross_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_cross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_cross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -728,7 +495,7 @@ static void do_cross_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_cross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_cross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } @@ -888,58 +655,26 @@ static void free_gammacross(Sequence *UNUSED(seq), const bool UNUSED(do_id_user) { } -static void do_gammacross_effect_byte(float facf0, - float UNUSED(facf1), - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) +static void do_gammacross_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - float fac1, fac2; - int xo; - unsigned char *cp1, *cp2, *rt; - float rt1[4], rt2[4], tempc[4]; - - xo = x; - cp1 = rect1; - cp2 = rect2; - rt = out; - - fac2 = facf0; - fac1 = 1.0f - fac2; - - while (y--) { - x = xo; - while (x--) { - straight_uchar_to_premul_float(rt1, cp1); - straight_uchar_to_premul_float(rt2, cp2); + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; - tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0])); - tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1])); - tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2])); - tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3])); - - premul_float_to_straight_uchar(rt, tempc); - cp1 += 4; - cp2 += 4; - rt += 4; - } + float mfac = 1.0f - fac; - if (y == 0) { - break; - } - y--; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + float rt1[4], rt2[4], tempc[4]; - x = xo; - while (x--) { straight_uchar_to_premul_float(rt1, cp1); straight_uchar_to_premul_float(rt2, cp2); - tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0])); - tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1])); - tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2])); - tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3])); + tempc[0] = gammaCorrect(mfac * invGammaCorrect(rt1[0]) + fac * invGammaCorrect(rt2[0])); + tempc[1] = gammaCorrect(mfac * invGammaCorrect(rt1[1]) + fac * invGammaCorrect(rt2[1])); + tempc[2] = gammaCorrect(mfac * invGammaCorrect(rt1[2]) + fac * invGammaCorrect(rt2[2])); + tempc[3] = gammaCorrect(mfac * invGammaCorrect(rt1[3]) + fac * invGammaCorrect(rt2[3])); premul_float_to_straight_uchar(rt, tempc); cp1 += 4; @@ -950,38 +685,17 @@ static void do_gammacross_effect_byte(float facf0, } static void do_gammacross_effect_float( - float facf0, float UNUSED(facf1), int x, int y, float *rect1, float *rect2, float *out) + float fac, int x, int y, float *rect1, float *rect2, float *out) { - float fac1, fac2; - int xo; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - fac2 = facf0; - fac1 = 1.0f - fac2; - - while (y--) { - x = xo * 4; - while (x--) { - *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2)); - rt1++; - rt2++; - rt++; - } - - if (y == 0) { - break; - } - y--; - - x = xo * 4; - while (x--) { - *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2)); + float mfac = 1.0f - fac; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + *rt = gammaCorrect(mfac * invGammaCorrect(*rt1) + fac * invGammaCorrect(*rt2)); rt1++; rt2++; rt++; @@ -1003,8 +717,7 @@ static struct ImBuf *gammacross_init_execution(const SeqRenderData *context, static void do_gammacross_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1018,7 +731,7 @@ static void do_gammacross_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_gammacross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_gammacross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -1026,57 +739,27 @@ static void do_gammacross_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_gammacross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_gammacross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Add *************************/ -static void do_add_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) -{ - int xo, fac1, fac3; - unsigned char *cp1, *cp2, *rt; - - xo = x; - cp1 = rect1; - cp2 = rect2; - rt = out; - - fac1 = (int)(256.0f * facf0); - fac3 = (int)(256.0f * facf1); - - while (y--) { - x = xo; - - while (x--) { - const int m = fac1 * (int)cp2[3]; - rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255); - rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255); - rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255); - rt[3] = cp1[3]; +static void do_add_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +{ + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; - cp1 += 4; - cp2 += 4; - rt += 4; - } + int temp_fac = (int)(256.0f * fac); - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - const int m = fac3 * (int)cp2[3]; - rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255); - rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255); - rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + const int temp_fac2 = temp_fac * (int)cp2[3]; + rt[0] = min_ii(cp1[0] + ((temp_fac2 * cp2[0]) >> 16), 255); + rt[1] = min_ii(cp1[1] + ((temp_fac2 * cp2[1]) >> 16), 255); + rt[2] = min_ii(cp1[2] + ((temp_fac2 * cp2[2]) >> 16), 255); rt[3] = cp1[3]; cp1 += 4; @@ -1086,46 +769,18 @@ static void do_add_effect_byte(float facf0, } } -static void do_add_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_add_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out) { - int xo; - float fac1, fac3; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - fac1 = facf0; - fac3 = facf1; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - while (y--) { - x = xo; - while (x--) { - const float m = (1.0f - (rt1[3] * (1.0f - fac1))) * rt2[3]; - rt[0] = rt1[0] + m * rt2[0]; - rt[1] = rt1[1] + m * rt2[1]; - rt[2] = rt1[2] + m * rt2[2]; - rt[3] = rt1[3]; - - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - const float m = (1.0f - (rt1[3] * (1.0f - fac3))) * rt2[3]; - rt[0] = rt1[0] + m * rt2[0]; - rt[1] = rt1[1] + m * rt2[1]; - rt[2] = rt1[2] + m * rt2[2]; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + const float temp_fac = (1.0f - (rt1[3] * (1.0f - fac))) * rt2[3]; + rt[0] = rt1[0] + temp_fac * rt2[0]; + rt[1] = rt1[1] + temp_fac * rt2[1]; + rt[2] = rt1[2] + temp_fac * rt2[2]; rt[3] = rt1[3]; rt1 += 4; @@ -1138,8 +793,7 @@ static void do_add_effect_float( static void do_add_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1153,7 +807,7 @@ static void do_add_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_add_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_add_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -1161,56 +815,27 @@ static void do_add_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_add_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_add_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Sub *************************/ -static void do_sub_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) -{ - int xo, fac1, fac3; - unsigned char *cp1, *cp2, *rt; - - xo = x; - cp1 = rect1; - cp2 = rect2; - rt = out; - - fac1 = (int)(256.0f * facf0); - fac3 = (int)(256.0f * facf1); - - while (y--) { - x = xo; - while (x--) { - const int m = fac1 * (int)cp2[3]; - rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0); - rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0); - rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0); - rt[3] = cp1[3]; +static void do_sub_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +{ + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; - cp1 += 4; - cp2 += 4; - rt += 4; - } + int temp_fac = (int)(256.0f * fac); - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - const int m = fac3 * (int)cp2[3]; - rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0); - rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0); - rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + const int temp_fac2 = temp_fac * (int)cp2[3]; + rt[0] = max_ii(cp1[0] - ((temp_fac2 * cp2[0]) >> 16), 0); + rt[1] = max_ii(cp1[1] - ((temp_fac2 * cp2[1]) >> 16), 0); + rt[2] = max_ii(cp1[2] - ((temp_fac2 * cp2[2]) >> 16), 0); rt[3] = cp1[3]; cp1 += 4; @@ -1220,47 +845,20 @@ static void do_sub_effect_byte(float facf0, } } -static void do_sub_effect_float( - float UNUSED(facf0), float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_sub_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out) { - int xo; - float /* fac1, */ fac3_inv; - float *rt1, *rt2, *rt; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - /* UNUSED */ - // fac1 = facf0; - fac3_inv = 1.0f - facf1; - - while (y--) { - x = xo; - while (x--) { - const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3]; - rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f); - rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f); - rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f); - rt[3] = rt1[3]; - - rt1 += 4; - rt2 += 4; - rt += 4; - } + float mfac = 1.0f - fac; - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3]; - rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f); - rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f); - rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + const float temp_fac = (1.0f - (rt1[3] * mfac)) * rt2[3]; + rt[0] = max_ff(rt1[0] - temp_fac * rt2[0], 0.0f); + rt[1] = max_ff(rt1[1] - temp_fac * rt2[1], 0.0f); + rt[2] = max_ff(rt1[2] - temp_fac * rt2[2], 0.0f); rt[3] = rt1[3]; rt1 += 4; @@ -1273,8 +871,7 @@ static void do_sub_effect_float( static void do_sub_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1288,7 +885,7 @@ static void do_sub_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_sub_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_sub_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -1296,7 +893,7 @@ static void do_sub_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_sub_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_sub_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } @@ -1306,161 +903,95 @@ static void do_sub_effect(const SeqRenderData *context, #define XOFF 8 #define YOFF 8 -static void do_drop_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect2i, - unsigned char *rect1i, - unsigned char *outi) -{ - int temp, fac, fac1, fac2; - unsigned char *rt1, *rt2, *out; - int field = 1; - - const int width = x; - const int height = y; - const int xoff = min_ii(XOFF, width); - const int yoff = min_ii(YOFF, height); - - fac1 = (int)(70.0f * facf0); - fac2 = (int)(70.0f * facf1); - - rt2 = rect2i + yoff * 4 * width; - rt1 = rect1i; - out = outi; - for (y = 0; y < height - yoff; y++) { - if (field) { - fac = fac1; - } - else { - fac = fac2; - } - field = !field; +static void do_drop_effect_byte( + float fac, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi) +{ + const int xoff = min_ii(XOFF, x); + const int yoff = min_ii(YOFF, y); + + int temp_fac = (int)(70.0f * fac); + unsigned char *rt2 = rect2i + yoff * 4 * x; + unsigned char *rt1 = rect1i; + unsigned char *out = outi; + for (int i = 0; i < y - yoff; i++) { memcpy(out, rt1, sizeof(*out) * xoff * 4); rt1 += xoff * 4; out += xoff * 4; - for (x = xoff; x < width; x++) { - temp = ((fac * rt2[3]) >> 8); + for (int j = xoff; j < x; j++) { + int temp_fac2 = ((temp_fac * rt2[3]) >> 8); - *(out++) = MAX2(0, *rt1 - temp); + *(out++) = MAX2(0, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0, *rt1 - temp); + *(out++) = MAX2(0, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0, *rt1 - temp); + *(out++) = MAX2(0, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0, *rt1 - temp); + *(out++) = MAX2(0, *rt1 - temp_fac2); rt1++; rt2 += 4; } rt2 += xoff * 4; } - memcpy(out, rt1, sizeof(*out) * yoff * 4 * width); + memcpy(out, rt1, sizeof(*out) * yoff * 4 * x); } static void do_drop_effect_float( - float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi) -{ - float temp, fac, fac1, fac2; - float *rt1, *rt2, *out; - int field = 1; - - const int width = x; - const int height = y; - const int xoff = min_ii(XOFF, width); - const int yoff = min_ii(YOFF, height); - - fac1 = 70.0f * facf0; - fac2 = 70.0f * facf1; - - rt2 = rect2i + yoff * 4 * width; - rt1 = rect1i; - out = outi; - for (y = 0; y < height - yoff; y++) { - if (field) { - fac = fac1; - } - else { - fac = fac2; - } - field = !field; + float fac, int x, int y, float *rect2i, float *rect1i, float *outi) +{ + const int xoff = min_ii(XOFF, x); + const int yoff = min_ii(YOFF, y); + float temp_fac = 70.0f * fac; + + float *rt2 = rect2i + yoff * 4 * x; + float *rt1 = rect1i; + float *out = outi; + for (int i = 0; i < y - yoff; i++) { memcpy(out, rt1, sizeof(*out) * xoff * 4); rt1 += xoff * 4; out += xoff * 4; - for (x = xoff; x < width; x++) { - temp = fac * rt2[3]; + for (int j = xoff; j < x; j++) { + float temp_fac2 = temp_fac * rt2[3]; - *(out++) = MAX2(0.0f, *rt1 - temp); + *(out++) = MAX2(0.0f, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0.0f, *rt1 - temp); + *(out++) = MAX2(0.0f, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0.0f, *rt1 - temp); + *(out++) = MAX2(0.0f, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0.0f, *rt1 - temp); + *(out++) = MAX2(0.0f, *rt1 - temp_fac2); rt1++; rt2 += 4; } rt2 += xoff * 4; } - memcpy(out, rt1, sizeof(*out) * yoff * 4 * width); + memcpy(out, rt1, sizeof(*out) * yoff * 4 * x); } /*********************** Mul *************************/ -static void do_mul_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) +static void do_mul_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int xo, fac1, fac3; - unsigned char *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; + unsigned char *rt1 = rect1; + unsigned char *rt2 = rect2; + unsigned char *rt = out; - fac1 = (int)(256.0f * facf0); - fac3 = (int)(256.0f * facf1); + int temp_fac = (int)(256.0f * fac); /* Formula: * `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s;` // + centx * `yaux = -s * px + c * py;` // + centy */ - while (y--) { - - x = xo; - while (x--) { - - rt[0] = rt1[0] + ((fac1 * rt1[0] * (rt2[0] - 255)) >> 16); - rt[1] = rt1[1] + ((fac1 * rt1[1] * (rt2[1] - 255)) >> 16); - rt[2] = rt1[2] + ((fac1 * rt1[2] * (rt2[2] - 255)) >> 16); - rt[3] = rt1[3] + ((fac1 * rt1[3] * (rt2[3] - 255)) >> 16); - - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - - rt[0] = rt1[0] + ((fac3 * rt1[0] * (rt2[0] - 255)) >> 16); - rt[1] = rt1[1] + ((fac3 * rt1[1] * (rt2[1] - 255)) >> 16); - rt[2] = rt1[2] + ((fac3 * rt1[2] * (rt2[2] - 255)) >> 16); - rt[3] = rt1[3] + ((fac3 * rt1[3] * (rt2[3] - 255)) >> 16); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rt[0] = rt1[0] + ((temp_fac * rt1[0] * (rt2[0] - 255)) >> 16); + rt[1] = rt1[1] + ((temp_fac * rt1[1] * (rt2[1] - 255)) >> 16); + rt[2] = rt1[2] + ((temp_fac * rt1[2] * (rt2[2] - 255)) >> 16); + rt[3] = rt1[3] + ((temp_fac * rt1[3] * (rt2[3] - 255)) >> 16); rt1 += 4; rt2 += 4; @@ -1469,48 +1000,21 @@ static void do_mul_effect_byte(float facf0, } } -static void do_mul_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_mul_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out) { - int xo; - float fac1, fac3; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - fac1 = facf0; - fac3 = facf1; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; /* Formula: * `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a`. */ - while (y--) { - x = xo; - while (x--) { - rt[0] = rt1[0] + fac1 * rt1[0] * (rt2[0] - 1.0f); - rt[1] = rt1[1] + fac1 * rt1[1] * (rt2[1] - 1.0f); - rt[2] = rt1[2] + fac1 * rt1[2] * (rt2[2] - 1.0f); - rt[3] = rt1[3] + fac1 * rt1[3] * (rt2[3] - 1.0f); - - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - rt[0] = rt1[0] + fac3 * rt1[0] * (rt2[0] - 1.0f); - rt[1] = rt1[1] + fac3 * rt1[1] * (rt2[1] - 1.0f); - rt[2] = rt1[2] + fac3 * rt1[2] * (rt2[2] - 1.0f); - rt[3] = rt1[3] + fac3 * rt1[3] * (rt2[3] - 1.0f); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rt[0] = rt1[0] + fac * rt1[0] * (rt2[0] - 1.0f); + rt[1] = rt1[1] + fac * rt1[1] * (rt2[1] - 1.0f); + rt[2] = rt1[2] + fac * rt1[2] * (rt2[2] - 1.0f); + rt[3] = rt1[3] + fac * rt1[3] * (rt2[3] - 1.0f); rt1 += 4; rt2 += 4; @@ -1522,8 +1026,7 @@ static void do_mul_effect_float( static void do_mul_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1537,7 +1040,7 @@ static void do_mul_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_mul_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_mul_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -1545,7 +1048,7 @@ static void do_mul_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_mul_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_mul_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } @@ -1555,8 +1058,7 @@ typedef void (*IMB_blend_func_byte)(unsigned char *dst, const unsigned char *src2); typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2); -BLI_INLINE void apply_blend_function_byte(float facf0, - float facf1, +BLI_INLINE void apply_blend_function_byte(float fac, int x, int y, unsigned char *rect1, @@ -1564,33 +1066,16 @@ BLI_INLINE void apply_blend_function_byte(float facf0, unsigned char *out, IMB_blend_func_byte blend_function) { - int xo; - unsigned char *rt1, *rt2, *rt; - unsigned int achannel; - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - while (y--) { - for (x = xo; x > 0; x--) { - achannel = rt1[3]; - rt1[3] = (unsigned int)achannel * facf0; - blend_function(rt, rt1, rt2); - rt1[3] = achannel; - rt[3] = rt1[3]; - rt1 += 4; - rt2 += 4; - rt += 4; - } - if (y == 0) { - break; - } - y--; - for (x = xo; x > 0; x--) { - achannel = rt1[3]; - rt1[3] = (unsigned int)achannel * facf1; + unsigned char *rt1 = rect1; + unsigned char *rt2 = rect2; + unsigned char *rt = out; + + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + unsigned int achannel = rt2[3]; + rt2[3] = (unsigned int)achannel * fac; blend_function(rt, rt1, rt2); - rt1[3] = achannel; + rt2[3] = achannel; rt[3] = rt1[3]; rt1 += 4; rt2 += 4; @@ -1599,8 +1084,7 @@ BLI_INLINE void apply_blend_function_byte(float facf0, } } -BLI_INLINE void apply_blend_function_float(float facf0, - float facf1, +BLI_INLINE void apply_blend_function_float(float fac, int x, int y, float *rect1, @@ -1608,33 +1092,16 @@ BLI_INLINE void apply_blend_function_float(float facf0, float *out, IMB_blend_func_float blend_function) { - int xo; - float *rt1, *rt2, *rt; - float achannel; - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - while (y--) { - for (x = xo; x > 0; x--) { - achannel = rt1[3]; - rt1[3] = achannel * facf0; - blend_function(rt, rt1, rt2); - rt1[3] = achannel; - rt[3] = rt1[3]; - rt1 += 4; - rt2 += 4; - rt += 4; - } - if (y == 0) { - break; - } - y--; - for (x = xo; x > 0; x--) { - achannel = rt1[3]; - rt1[3] = achannel * facf1; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; + + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + float achannel = rt2[3]; + rt2[3] = achannel * fac; blend_function(rt, rt1, rt2); - rt1[3] = achannel; + rt2[3] = achannel; rt[3] = rt1[3]; rt1 += 4; rt2 += 4; @@ -1644,89 +1111,78 @@ BLI_INLINE void apply_blend_function_float(float facf0, } static void do_blend_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, int btype, float *out) + float fac, int x, int y, float *rect1, float *rect2, int btype, float *out) { switch (btype) { case SEQ_TYPE_ADD: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_add_float); break; case SEQ_TYPE_SUB: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_sub_float); break; case SEQ_TYPE_MUL: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_mul_float); break; case SEQ_TYPE_DARKEN: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_darken_float); break; case SEQ_TYPE_COLOR_BURN: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_burn_float); break; case SEQ_TYPE_LINEAR_BURN: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_linearburn_float); break; case SEQ_TYPE_SCREEN: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_screen_float); break; case SEQ_TYPE_LIGHTEN: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_lighten_float); break; case SEQ_TYPE_DODGE: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_dodge_float); break; case SEQ_TYPE_OVERLAY: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_overlay_float); break; case SEQ_TYPE_SOFT_LIGHT: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_softlight_float); break; case SEQ_TYPE_HARD_LIGHT: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_hardlight_float); break; case SEQ_TYPE_PIN_LIGHT: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_pinlight_float); break; case SEQ_TYPE_LIN_LIGHT: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_linearlight_float); break; case SEQ_TYPE_VIVID_LIGHT: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_vividlight_float); break; case SEQ_TYPE_BLEND_COLOR: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_color_float); break; case SEQ_TYPE_HUE: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_hue_float); break; case SEQ_TYPE_SATURATION: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_saturation_float); break; case SEQ_TYPE_VALUE: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_luminosity_float); break; case SEQ_TYPE_DIFFERENCE: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_difference_float); break; case SEQ_TYPE_EXCLUSION: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_exclusion_float); break; default: break; } } -static void do_blend_effect_byte(float facf0, - float facf1, +static void do_blend_effect_byte(float fac, int x, int y, unsigned char *rect1, @@ -1736,73 +1192,67 @@ static void do_blend_effect_byte(float facf0, { switch (btype) { case SEQ_TYPE_ADD: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_add_byte); break; case SEQ_TYPE_SUB: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_sub_byte); break; case SEQ_TYPE_MUL: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_mul_byte); break; case SEQ_TYPE_DARKEN: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_darken_byte); break; case SEQ_TYPE_COLOR_BURN: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_burn_byte); break; case SEQ_TYPE_LINEAR_BURN: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_linearburn_byte); break; case SEQ_TYPE_SCREEN: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_screen_byte); break; case SEQ_TYPE_LIGHTEN: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_lighten_byte); break; case SEQ_TYPE_DODGE: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_dodge_byte); break; case SEQ_TYPE_OVERLAY: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_overlay_byte); break; case SEQ_TYPE_SOFT_LIGHT: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_softlight_byte); break; case SEQ_TYPE_HARD_LIGHT: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_hardlight_byte); break; case SEQ_TYPE_PIN_LIGHT: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_pinlight_byte); break; case SEQ_TYPE_LIN_LIGHT: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_linearlight_byte); break; case SEQ_TYPE_VIVID_LIGHT: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_vividlight_byte); break; case SEQ_TYPE_BLEND_COLOR: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_color_byte); break; case SEQ_TYPE_HUE: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_hue_byte); break; case SEQ_TYPE_SATURATION: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_saturation_byte); break; case SEQ_TYPE_VALUE: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_luminosity_byte); break; case SEQ_TYPE_DIFFERENCE: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_difference_byte); break; case SEQ_TYPE_EXCLUSION: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_exclusion_byte); break; default: break; @@ -1812,8 +1262,7 @@ static void do_blend_effect_byte(float facf0, static void do_blend_mode_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1826,14 +1275,14 @@ static void do_blend_mode_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); do_blend_effect_float( - facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out); + fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); do_blend_effect_byte( - facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out); + fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out); } } /*********************** Color Mix Effect *************************/ @@ -1853,8 +1302,7 @@ static void init_colormix_effect(Sequence *seq) static void do_colormix_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1862,24 +1310,24 @@ static void do_colormix_effect(const SeqRenderData *context, int total_lines, ImBuf *out) { - float facf; + float fac; ColorMixVars *data = seq->effectdata; - facf = data->factor; + fac = data->factor; if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); do_blend_effect_float( - facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out); + fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); do_blend_effect_byte( - facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out); + fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out); } } @@ -1930,7 +1378,7 @@ static float in_band(float width, float dist, int side, int dir) return alpha; } -static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float facf0) +static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float fac) { float posx, posy, hyp, hyp2, angle, hwidth, b1, b2, b3, pointdist; /* some future stuff */ @@ -1950,18 +1398,18 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f angle = wipezone->angle; if (wipe->forward) { - posx = facf0 * xo; - posy = facf0 * yo; + posx = fac * xo; + posy = fac * yo; } else { - posx = xo - facf0 * xo; - posy = yo - facf0 * yo; + posx = xo - fac * xo; + posy = yo - fac * yo; } switch (wipe->wipetype) { case DO_SINGLE_WIPE: - width = min_ii(wipezone->width, facf0 * yo); - width = min_ii(width, yo - facf0 * yo); + width = min_ii(wipezone->width, fac * yo); + width = min_ii(width, yo - fac * yo); if (angle == 0.0f) { b1 = posy; @@ -2000,7 +1448,7 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f case DO_DOUBLE_WIPE: if (!wipe->forward) { - facf0 = 1.0f - facf0; /* Go the other direction */ + fac = 1.0f - fac; /* Go the other direction */ } width = wipezone->width; /* calculate the blur width */ @@ -2053,9 +1501,9 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f * temp3: angle of low side of blur * temp4: angle of high side of blur */ - output = 1.0f - facf0; + output = 1.0f - fac; widthf = wipe->edgeWidth * 2.0f * (float)M_PI; - temp1 = 2.0f * (float)M_PI * facf0; + temp1 = 2.0f * (float)M_PI * fac; if (wipe->forward) { temp1 = 2.0f * (float)M_PI - temp1; @@ -2076,12 +1524,12 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f } if (wipe->forward) { - temp3 = temp1 - (widthf * 0.5f) * facf0; - temp4 = temp1 + (widthf * 0.5f) * (1 - facf0); + temp3 = temp1 - (widthf * 0.5f) * fac; + temp4 = temp1 + (widthf * 0.5f) * (1 - fac); } else { - temp3 = temp1 - (widthf * 0.5f) * (1 - facf0); - temp4 = temp1 + (widthf * 0.5f) * facf0; + temp3 = temp1 - (widthf * 0.5f) * (1 - fac); + temp4 = temp1 + (widthf * 0.5f) * fac; } if (temp3 < 0) { temp3 = 0; @@ -2118,13 +1566,13 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f } if (!wipe->forward) { - facf0 = 1 - facf0; + fac = 1 - fac; } width = wipezone->width; hwidth = width * 0.5f; - temp1 = (halfx - (halfx)*facf0); + temp1 = (halfx - (halfx)*fac); pointdist = hypotf(temp1, temp1); temp2 = hypotf(halfx - x, halfy - y); @@ -2175,8 +1623,7 @@ static void copy_wipe_effect(Sequence *dst, Sequence *src, const int UNUSED(flag } static void do_wipe_effect_byte(Sequence *seq, - float facf0, - float UNUSED(facf1), + float fac, int x, int y, unsigned char *rect1, @@ -2185,20 +1632,15 @@ static void do_wipe_effect_byte(Sequence *seq, { WipeZone wipezone; WipeVars *wipe = (WipeVars *)seq->effectdata; - int xo, yo; - unsigned char *cp1, *cp2, *rt; - precalc_wipe_zone(&wipezone, wipe, x, y); - cp1 = rect1; - cp2 = rect2; - rt = out; + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; - xo = x; - yo = y; - for (y = 0; y < yo; y++) { - for (x = 0; x < xo; x++) { - float check = check_zone(&wipezone, x, y, seq, facf0); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + float check = check_zone(&wipezone, x, y, seq, fac); if (check) { if (cp1) { float rt1[4], rt2[4], tempc[4]; @@ -2246,31 +1688,20 @@ static void do_wipe_effect_byte(Sequence *seq, } } -static void do_wipe_effect_float(Sequence *seq, - float facf0, - float UNUSED(facf1), - int x, - int y, - float *rect1, - float *rect2, - float *out) +static void do_wipe_effect_float( + Sequence *seq, float fac, int x, int y, float *rect1, float *rect2, float *out) { WipeZone wipezone; WipeVars *wipe = (WipeVars *)seq->effectdata; - int xo, yo; - float *rt1, *rt2, *rt; - precalc_wipe_zone(&wipezone, wipe, x, y); - rt1 = rect1; - rt2 = rect2; - rt = out; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - xo = x; - yo = y; - for (y = 0; y < yo; y++) { - for (x = 0; x < xo; x++) { - float check = check_zone(&wipezone, x, y, seq, facf0); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + float check = check_zone(&wipezone, x, y, seq, fac); if (check) { if (rt1) { rt[0] = rt1[0] * check + rt2[0] * (1 - check); @@ -2314,8 +1745,7 @@ static void do_wipe_effect_float(Sequence *seq, static ImBuf *do_wipe_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -2324,8 +1754,7 @@ static ImBuf *do_wipe_effect(const SeqRenderData *context, if (out->rect_float) { do_wipe_effect_float(seq, - facf0, - facf1, + fac, context->rectx, context->recty, ibuf1->rect_float, @@ -2334,8 +1763,7 @@ static ImBuf *do_wipe_effect(const SeqRenderData *context, } else { do_wipe_effect_byte(seq, - facf0, - facf1, + fac, context->rectx, context->recty, (unsigned char *)ibuf1->rect, @@ -2442,8 +1870,7 @@ static void transform_image(int x, static void do_transform_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *ibuf1, ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3), @@ -2451,7 +1878,6 @@ static void do_transform_effect(const SeqRenderData *context, int total_lines, ImBuf *out) { - Scene *scene = context->scene; TransformVars *transform = (TransformVars *)seq->effectdata; float scale_x, scale_y, translate_x, translate_y, rotate_radians; @@ -2469,10 +1895,14 @@ static void do_transform_effect(const SeqRenderData *context, /* Translate */ if (!transform->percent) { - float rd_s = (scene->r.size / 100.0f); + /* Compensate text size for preview render size. */ + double proxy_size_comp = context->scene->r.size / 100.0; + if (context->preview_render_size != SEQ_RENDER_SIZE_SCENE) { + proxy_size_comp = SEQ_rendersize_to_scale_factor(context->preview_render_size); + } - translate_x = transform->xIni * rd_s + (x / 2.0f); - translate_y = transform->yIni * rd_s + (y / 2.0f); + translate_x = transform->xIni * proxy_size_comp + (x / 2.0f); + translate_y = transform->yIni * proxy_size_comp + (y / 2.0f); } else { translate_x = x * (transform->xIni / 100.0f) + (x / 2.0f); @@ -2728,8 +2158,7 @@ static void copy_glow_effect(Sequence *dst, Sequence *src, const int UNUSED(flag static void do_glow_effect_byte(Sequence *seq, int render_size, - float facf0, - float UNUSED(facf1), + float fac, int x, int y, unsigned char *rect1, @@ -2746,7 +2175,7 @@ static void do_glow_effect_byte(Sequence *seq, IMB_buffer_float_premultiply(inbuf, x, y); RVIsolateHighlights_float( - inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp); + inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp); RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality); if (!glow->bNoComp) { RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y); @@ -2762,8 +2191,7 @@ static void do_glow_effect_byte(Sequence *seq, static void do_glow_effect_float(Sequence *seq, int render_size, - float facf0, - float UNUSED(facf1), + float fac, int x, int y, float *rect1, @@ -2775,7 +2203,7 @@ static void do_glow_effect_float(Sequence *seq, GlowVars *glow = (GlowVars *)seq->effectdata; RVIsolateHighlights_float( - inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp); + inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp); RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality); if (!glow->bNoComp) { RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y); @@ -2785,8 +2213,7 @@ static void do_glow_effect_float(Sequence *seq, static ImBuf *do_glow_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -2798,8 +2225,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context, if (out->rect_float) { do_glow_effect_float(seq, render_size, - facf0, - facf1, + fac, context->rectx, context->recty, ibuf1->rect_float, @@ -2809,8 +2235,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context, else { do_glow_effect_byte(seq, render_size, - facf0, - facf1, + fac, context->rectx, context->recty, (unsigned char *)ibuf1->rect, @@ -2852,7 +2277,7 @@ static void copy_solid_color(Sequence *dst, Sequence *src, const int UNUSED(flag dst->effectdata = MEM_dupallocN(src->effectdata); } -static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_color(Sequence *UNUSED(seq), float UNUSED(fac)) { return EARLY_NO_INPUT; } @@ -2860,8 +2285,7 @@ static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNU static ImBuf *do_solid_color(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float facf0, - float facf1, + float UNUSED(fac), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -2870,75 +2294,50 @@ static ImBuf *do_solid_color(const SeqRenderData *context, SolidColorVars *cv = (SolidColorVars *)seq->effectdata; - unsigned char *rect; - float *rect_float; - int x; /*= context->rectx;*/ /*UNUSED*/ - int y; /*= context->recty;*/ /*UNUSED*/ + int x = out->x; + int y = out->y; if (out->rect) { - unsigned char col0[3]; - unsigned char col1[3]; - - col0[0] = facf0 * cv->col[0] * 255; - col0[1] = facf0 * cv->col[1] * 255; - col0[2] = facf0 * cv->col[2] * 255; + unsigned char color[4]; + color[0] = cv->col[0] * 255; + color[1] = cv->col[1] * 255; + color[2] = cv->col[2] * 255; + color[3] = 255; - col1[0] = facf1 * cv->col[0] * 255; - col1[1] = facf1 * cv->col[1] * 255; - col1[2] = facf1 * cv->col[2] * 255; + unsigned char *rect = (unsigned char *)out->rect; - rect = (unsigned char *)out->rect; - - for (y = 0; y < out->y; y++) { - for (x = 0; x < out->x; x++, rect += 4) { - rect[0] = col0[0]; - rect[1] = col0[1]; - rect[2] = col0[2]; - rect[3] = 255; - } - y++; - if (y < out->y) { - for (x = 0; x < out->x; x++, rect += 4) { - rect[0] = col1[0]; - rect[1] = col1[1]; - rect[2] = col1[2]; - rect[3] = 255; - } + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rect[0] = color[0]; + rect[1] = color[1]; + rect[2] = color[2]; + rect[3] = color[3]; + rect += 4; } } } else if (out->rect_float) { - float col0[3]; - float col1[3]; - - col0[0] = facf0 * cv->col[0]; - col0[1] = facf0 * cv->col[1]; - col0[2] = facf0 * cv->col[2]; + float color[4]; + color[0] = cv->col[0]; + color[1] = cv->col[1]; + color[2] = cv->col[2]; + color[3] = 255; - col1[0] = facf1 * cv->col[0]; - col1[1] = facf1 * cv->col[1]; - col1[2] = facf1 * cv->col[2]; + float *rect_float = out->rect_float; - rect_float = out->rect_float; - - for (y = 0; y < out->y; y++) { - for (x = 0; x < out->x; x++, rect_float += 4) { - rect_float[0] = col0[0]; - rect_float[1] = col0[1]; - rect_float[2] = col0[2]; - rect_float[3] = 1.0; - } - y++; - if (y < out->y) { - for (x = 0; x < out->x; x++, rect_float += 4) { - rect_float[0] = col1[0]; - rect_float[1] = col1[1]; - rect_float[2] = col1[2]; - rect_float[3] = 1.0; - } + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rect_float[0] = color[0]; + rect_float[1] = color[1]; + rect_float[2] = color[2]; + rect_float[3] = color[3]; + rect_float += 4; } } } + + out->planes = R_IMF_PLANES_RGB; + return out; } @@ -2950,7 +2349,7 @@ static int num_inputs_multicam(void) return 0; } -static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(fac)) { return EARLY_NO_INPUT; } @@ -2958,8 +2357,7 @@ static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float static ImBuf *do_multicam(const SeqRenderData *context, Sequence *seq, float timeline_frame, - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3)) @@ -2994,7 +2392,7 @@ static int num_inputs_adjustment(void) return 0; } -static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(fac)) { return EARLY_NO_INPUT; } @@ -3038,8 +2436,7 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl static ImBuf *do_adjustment(const SeqRenderData *context, Sequence *seq, float timeline_frame, - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3)) @@ -3105,7 +2502,7 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla v->frameMap = NULL; } -static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(fac)) { return EARLY_DO_EFFECT; } @@ -3129,8 +2526,6 @@ static FCurve *seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *s return id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL); } -/* Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated. - * This is, because `target_frame` value is integrated over time. */ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq) { if ((seq->seq1 == NULL) || (seq->len < 1)) { @@ -3169,7 +2564,6 @@ static void seq_effect_speed_frame_map_ensure(Scene *scene, Sequence *seq) seq_effect_speed_rebuild_map(scene, seq); } -/* Override timeline_frame when rendering speed effect input. */ float seq_speed_effect_target_frame_get(Scene *scene, Sequence *seq_speed, float timeline_frame, @@ -3240,8 +2634,7 @@ static float speed_effect_interpolation_ratio_get(Scene *scene, static ImBuf *do_speed_effect(const SeqRenderData *context, Sequence *seq, float timeline_frame, - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -3252,10 +2645,10 @@ static ImBuf *do_speed_effect(const SeqRenderData *context, if (s->flags & SEQ_SPEED_USE_INTERPOLATION) { out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); - facf0 = facf1 = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame); + fac = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame); /* Current frame is ibuf1, next frame is ibuf2. */ out = seq_render_effect_execute_threaded( - &cross_effect, context, NULL, timeline_frame, facf0, facf1, ibuf1, ibuf2, ibuf3); + &cross_effect, context, NULL, timeline_frame, fac, ibuf1, ibuf2, ibuf3); return out; } @@ -3268,8 +2661,7 @@ static ImBuf *do_speed_effect(const SeqRenderData *context, static void do_overdrop_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -3286,8 +2678,8 @@ static void do_overdrop_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_drop_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out); - do_alphaover_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out); + do_drop_effect_float(fac, x, y, rect1, rect2, rect_out); + do_alphaover_effect_float(fac, x, y, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -3295,8 +2687,8 @@ static void do_overdrop_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_drop_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out); - do_alphaover_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out); + do_drop_effect_byte(fac, x, y, rect1, rect2, rect_out); + do_alphaover_effect_byte(fac, x, y, rect1, rect2, rect_out); } } @@ -3334,7 +2726,7 @@ static void copy_gaussian_blur_effect(Sequence *dst, Sequence *src, const int UN dst->effectdata = MEM_dupallocN(src->effectdata); } -static int early_out_gaussian_blur(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_gaussian_blur(Sequence *seq, float UNUSED(fac)) { GaussianBlurVars *data = seq->effectdata; if (data->size_x == 0.0f && data->size_y == 0) { @@ -3688,8 +3080,7 @@ static void *render_effect_execute_do_y_thread(void *thread_data_v) static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *ibuf1, ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3)) @@ -3738,7 +3129,7 @@ static void init_text_effect(Sequence *seq) data = seq->effectdata = MEM_callocN(sizeof(TextVars), "textvars"); data->text_font = NULL; data->text_blf_id = -1; - data->text_size = 60; + data->text_size = 60.0f; copy_v4_fl(data->color, 1.0f); data->shadow_color[3] = 0.7f; @@ -3836,10 +3227,10 @@ static int num_inputs_text(void) return 0; } -static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_text(Sequence *seq, float UNUSED(fac)) { TextVars *data = seq->effectdata; - if (data->text[0] == 0 || data->text_size < 1 || + if (data->text[0] == 0 || data->text_size < 1.0f || ((data->color[3] == 0.0f) && (data->shadow_color[3] == 0.0f || (data->flag & SEQ_TEXT_SHADOW) == 0))) { return EARLY_USE_INPUT_1; @@ -3850,8 +3241,7 @@ static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1 static ImBuf *do_text_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -3954,12 +3344,12 @@ static ImBuf *do_text_effect(const SeqRenderData *context, fonty = line_height; BLF_position(font, x + max_ii(fontx / 55, 1), y - max_ii(fonty / 30, 1), 0.0f); BLF_buffer_col(font, data->shadow_color); - BLF_draw_buffer(font, data->text, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw_buffer(font, data->text, sizeof(data->text)); } BLF_position(font, x, y, 0.0f); BLF_buffer_col(font, data->color); - BLF_draw_buffer(font, data->text, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw_buffer(font, data->text, sizeof(data->text)); BLF_buffer(font, NULL, NULL, 0, 0, 0, NULL); @@ -3997,44 +3387,47 @@ static void free_effect_default(Sequence *seq, const bool UNUSED(do_id_user)) MEM_SAFE_FREE(seq->effectdata); } -static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(fac)) { return EARLY_DO_EFFECT; } -static int early_out_fade(Sequence *UNUSED(seq), float facf0, float facf1) +static int early_out_fade(Sequence *UNUSED(seq), float fac) { - if (facf0 == 0.0f && facf1 == 0.0f) { + if (fac == 0.0f) { return EARLY_USE_INPUT_1; } - if (facf0 == 1.0f && facf1 == 1.0f) { + if (fac == 1.0f) { return EARLY_USE_INPUT_2; } return EARLY_DO_EFFECT; } -static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1) +static int early_out_mul_input2(Sequence *UNUSED(seq), float fac) { - if (facf0 == 0.0f && facf1 == 0.0f) { + if (fac == 0.0f) { return EARLY_USE_INPUT_1; } return EARLY_DO_EFFECT; } -static void get_default_fac_noop(Sequence *UNUSED(seq), - float UNUSED(timeline_frame), - float *facf0, - float *facf1) +static int early_out_mul_input1(Sequence *UNUSED(seq), float fac) +{ + if (fac == 0.0f) { + return EARLY_USE_INPUT_2; + } + return EARLY_DO_EFFECT; +} + +static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *fac) { - *facf0 = *facf1 = 1.0; + *fac = 1.0f; } -static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *facf0, float *facf1) +static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *fac) { - *facf0 = (float)(timeline_frame - seq->startdisp); - *facf1 = (float)(*facf0 + 0.5f); - *facf0 /= seq->len; - *facf1 /= seq->len; + *fac = (float)(timeline_frame - seq->startdisp); + *fac /= seq->len; } static struct ImBuf *init_execution(const SeqRenderData *context, @@ -4131,6 +3524,7 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.multithreaded = true; rval.init = init_alpha_over_or_under; rval.execute_slice = do_alphaover_effect; + rval.early_out = early_out_mul_input1; break; case SEQ_TYPE_OVERDROP: rval.multithreaded = true; diff --git a/source/blender/sequencer/intern/effects.h b/source/blender/sequencer/intern/effects.h index 25ba4d8956e..c63f8f7a404 100644 --- a/source/blender/sequencer/intern/effects.h +++ b/source/blender/sequencer/intern/effects.h @@ -39,7 +39,14 @@ struct Sequence; */ struct SeqEffectHandle seq_effect_get_sequence_blend(struct Sequence *seq); +/** + * Build frame map when speed in mode #SEQ_SPEED_MULTIPLY is animated. + * This is, because `target_frame` value is integrated over time. + */ void seq_effect_speed_rebuild_map(struct Scene *scene, struct Sequence *seq); +/** + * Override timeline_frame when rendering speed effect input. + */ float seq_speed_effect_target_frame_get(struct Scene *scene, struct Sequence *seq, float timeline_frame, diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c index 86c198075e9..51e4613f088 100644 --- a/source/blender/sequencer/intern/image_cache.c +++ b/source/blender/sequencer/intern/image_cache.c @@ -50,9 +50,9 @@ #include "SEQ_prefetch.h" #include "SEQ_relations.h" -#include "SEQ_render.h" #include "SEQ_sequencer.h" +#include "disk_cache.h" #include "image_cache.h" #include "prefetch.h" #include "strip_time.h" @@ -80,67 +80,10 @@ * entries one by one in reverse order to their creation. * * User can exclude caching of some images. Such entries will have is_temp_cache set. - * - * - * Disk Cache Design Notes - * ======================= - * - * Disk cache uses directory specified in user preferences - * For each cached non-temp image, image data and supplementary info are written to HDD. - * Multiple(DCACHE_IMAGES_PER_FILE) images share the same file. - * Each of these files contains header DiskCacheHeader followed by image data. - * Zlib compression with user definable level can be used to compress image data(per image) - * Images are written in order in which they are rendered. - * Overwriting of individual entry is not possible. - * Stored images are deleted by invalidation, or when size of all files exceeds maximum - * size specified in user preferences. - * To distinguish 2 blend files with same name, scene->ed->disk_cache_timestamp - * is used as UID. Blend file can still be copied manually which may cause conflict. - * */ -/* <cache type>-<resolution X>x<resolution Y>-<rendersize>%(<view_id>)-<frame no>.dcf */ -#define DCACHE_FNAME_FORMAT "%d-%dx%d-%d%%(%d)-%d.dcf" -#define DCACHE_IMAGES_PER_FILE 100 -#define DCACHE_CURRENT_VERSION 2 -#define COLORSPACE_NAME_MAX 64 /* XXX: defined in imb intern */ #define THUMB_CACHE_LIMIT 5000 -typedef struct DiskCacheHeaderEntry { - unsigned char encoding; - uint64_t frameno; - uint64_t size_compressed; - uint64_t size_raw; - uint64_t offset; - char colorspace_name[COLORSPACE_NAME_MAX]; -} DiskCacheHeaderEntry; - -typedef struct DiskCacheHeader { - DiskCacheHeaderEntry entry[DCACHE_IMAGES_PER_FILE]; -} DiskCacheHeader; - -typedef struct SeqDiskCache { - Main *bmain; - int64_t timestamp; - ListBase files; - ThreadMutex read_write_mutex; - size_t size_total; -} SeqDiskCache; - -typedef struct DiskCacheFile { - struct DiskCacheFile *next, *prev; - char path[FILE_MAX]; - char dir[FILE_MAXDIR]; - char file[FILE_MAX]; - BLI_stat_t fstat; - int cache_type; - int rectx; - int recty; - int render_size; - int view_id; - int start_frame; -} DiskCacheFile; - typedef struct SeqCache { Main *bmain; struct GHash *hash; @@ -148,7 +91,7 @@ typedef struct SeqCache { struct BLI_mempool *keys_pool; struct BLI_mempool *items_pool; struct SeqCacheKey *last_key; - SeqDiskCache *disk_cache; + struct SeqDiskCache *disk_cache; int thumbnail_count; } SeqCache; @@ -157,577 +100,7 @@ typedef struct SeqCacheItem { struct ImBuf *ibuf; } SeqCacheItem; -typedef struct SeqCacheKey { - struct SeqCache *cache_owner; - void *userkey; - struct SeqCacheKey *link_prev; /* Used for linking intermediate items to final frame. */ - struct SeqCacheKey *link_next; /* Used for linking intermediate items to final frame. */ - struct Sequence *seq; - SeqRenderData context; - float frame_index; /* Usually same as timeline_frame. Mapped to media for RAW entries. */ - float timeline_frame; /* Only for reference - used for freeing when cache is full. */ - float cost; /* In short: render time(s) divided by playback frame duration(s) */ - bool is_temp_cache; /* this cache entry will be freed before rendering next frame */ - /* ID of task for assigning temp cache entries to particular task(thread, etc.) */ - eSeqTaskId task_id; - int type; -} SeqCacheKey; - static ThreadMutex cache_create_lock = BLI_MUTEX_INITIALIZER; -static float seq_cache_timeline_frame_to_frame_index(Sequence *seq, - float timeline_frame, - int type); -static float seq_cache_frame_index_to_timeline_frame(Sequence *seq, float frame_index); - -static char *seq_disk_cache_base_dir(void) -{ - return U.sequencer_disk_cache_dir; -} - -static int seq_disk_cache_compression_level(void) -{ - switch (U.sequencer_disk_cache_compression) { - case USER_SEQ_DISK_CACHE_COMPRESSION_NONE: - return 0; - case USER_SEQ_DISK_CACHE_COMPRESSION_LOW: - return 1; - case USER_SEQ_DISK_CACHE_COMPRESSION_HIGH: - return 9; - } - - return U.sequencer_disk_cache_compression; -} - -static size_t seq_disk_cache_size_limit(void) -{ - return (size_t)U.sequencer_disk_cache_size_limit * (1024 * 1024 * 1024); -} - -static bool seq_disk_cache_is_enabled(Main *bmain) -{ - return (U.sequencer_disk_cache_dir[0] != '\0' && U.sequencer_disk_cache_size_limit != 0 && - (U.sequencer_disk_cache_flag & SEQ_CACHE_DISK_CACHE_ENABLE) != 0 && - bmain->name[0] != '\0'); -} - -static DiskCacheFile *seq_disk_cache_add_file_to_list(SeqDiskCache *disk_cache, const char *path) -{ - - DiskCacheFile *cache_file = MEM_callocN(sizeof(DiskCacheFile), "SeqDiskCacheFile"); - char dir[FILE_MAXDIR], file[FILE_MAX]; - BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file)); - BLI_strncpy(cache_file->path, path, sizeof(cache_file->path)); - BLI_strncpy(cache_file->dir, dir, sizeof(cache_file->dir)); - BLI_strncpy(cache_file->file, file, sizeof(cache_file->file)); - sscanf(file, - DCACHE_FNAME_FORMAT, - &cache_file->cache_type, - &cache_file->rectx, - &cache_file->recty, - &cache_file->render_size, - &cache_file->view_id, - &cache_file->start_frame); - cache_file->start_frame *= DCACHE_IMAGES_PER_FILE; - BLI_addtail(&disk_cache->files, cache_file); - return cache_file; -} - -static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path) -{ - struct direntry *filelist, *fl; - uint nbr, i; - disk_cache->size_total = 0; - - i = nbr = BLI_filelist_dir_contents(path, &filelist); - fl = filelist; - while (i--) { - /* Don't follow links. */ - const eFileAttributes file_attrs = BLI_file_attributes(fl->path); - if (file_attrs & FILE_ATTR_ANY_LINK) { - fl++; - continue; - } - - char file[FILE_MAX]; - BLI_split_dirfile(fl->path, NULL, file, 0, sizeof(file)); - - bool is_dir = BLI_is_dir(fl->path); - if (is_dir && !FILENAME_IS_CURRPAR(file)) { - char subpath[FILE_MAX]; - BLI_strncpy(subpath, fl->path, sizeof(subpath)); - BLI_path_slash_ensure(subpath); - seq_disk_cache_get_files(disk_cache, subpath); - } - - if (!is_dir) { - const char *ext = BLI_path_extension(fl->path); - if (ext && ext[1] == 'd' && ext[2] == 'c' && ext[3] == 'f') { - DiskCacheFile *cache_file = seq_disk_cache_add_file_to_list(disk_cache, fl->path); - cache_file->fstat = fl->s; - disk_cache->size_total += cache_file->fstat.st_size; - } - } - fl++; - } - BLI_filelist_free(filelist, nbr); -} - -static DiskCacheFile *seq_disk_cache_get_oldest_file(SeqDiskCache *disk_cache) -{ - DiskCacheFile *oldest_file = disk_cache->files.first; - if (oldest_file == NULL) { - return NULL; - } - for (DiskCacheFile *cache_file = oldest_file->next; cache_file; cache_file = cache_file->next) { - if (cache_file->fstat.st_mtime < oldest_file->fstat.st_mtime) { - oldest_file = cache_file; - } - } - - return oldest_file; -} - -static void seq_disk_cache_delete_file(SeqDiskCache *disk_cache, DiskCacheFile *file) -{ - disk_cache->size_total -= file->fstat.st_size; - BLI_delete(file->path, false, false); - BLI_remlink(&disk_cache->files, file); - MEM_freeN(file); -} - -static bool seq_disk_cache_enforce_limits(SeqDiskCache *disk_cache) -{ - BLI_mutex_lock(&disk_cache->read_write_mutex); - while (disk_cache->size_total > seq_disk_cache_size_limit()) { - DiskCacheFile *oldest_file = seq_disk_cache_get_oldest_file(disk_cache); - - if (!oldest_file) { - /* We shouldn't enforce limits with no files, do re-scan. */ - seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir()); - continue; - } - - if (BLI_exists(oldest_file->path) == 0) { - /* File may have been manually deleted during runtime, do re-scan. */ - BLI_freelistN(&disk_cache->files); - seq_disk_cache_get_files(disk_cache, seq_disk_cache_base_dir()); - continue; - } - - seq_disk_cache_delete_file(disk_cache, oldest_file); - } - BLI_mutex_unlock(&disk_cache->read_write_mutex); - - return true; -} - -static DiskCacheFile *seq_disk_cache_get_file_entry_by_path(SeqDiskCache *disk_cache, char *path) -{ - DiskCacheFile *cache_file = disk_cache->files.first; - - for (; cache_file; cache_file = cache_file->next) { - if (BLI_strcasecmp(cache_file->path, path) == 0) { - return cache_file; - } - } - - return NULL; -} - -/* Update file size and timestamp. */ -static void seq_disk_cache_update_file(SeqDiskCache *disk_cache, char *path) -{ - DiskCacheFile *cache_file; - int64_t size_before; - int64_t size_after; - - cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, path); - size_before = cache_file->fstat.st_size; - - if (BLI_stat(path, &cache_file->fstat) == -1) { - BLI_assert(false); - memset(&cache_file->fstat, 0, sizeof(BLI_stat_t)); - } - - size_after = cache_file->fstat.st_size; - disk_cache->size_total += size_after - size_before; -} - -/* Path format: - * <cache dir>/<project name>_seq_cache/<scene name>-<timestamp>/<seq name>/DCACHE_FNAME_FORMAT - */ - -static void seq_disk_cache_get_project_dir(SeqDiskCache *disk_cache, char *path, size_t path_len) -{ - char cache_dir[FILE_MAX]; - BLI_split_file_part(BKE_main_blendfile_path(disk_cache->bmain), cache_dir, sizeof(cache_dir)); - /* Use suffix, so that the cache directory name does not conflict with the bmain's blend file. */ - const char *suffix = "_seq_cache"; - strncat(cache_dir, suffix, sizeof(cache_dir) - strlen(cache_dir) - 1); - BLI_strncpy(path, seq_disk_cache_base_dir(), path_len); - BLI_path_append(path, path_len, cache_dir); -} - -static void seq_disk_cache_get_dir( - SeqDiskCache *disk_cache, Scene *scene, Sequence *seq, char *path, size_t path_len) -{ - char scene_name[MAX_ID_NAME + 22]; /* + -%PRId64 */ - char seq_name[SEQ_NAME_MAXSTR]; - char project_dir[FILE_MAX]; - - seq_disk_cache_get_project_dir(disk_cache, project_dir, sizeof(project_dir)); - sprintf(scene_name, "%s-%" PRId64, scene->id.name, disk_cache->timestamp); - BLI_strncpy(seq_name, seq->name, sizeof(seq_name)); - BLI_filename_make_safe(scene_name); - BLI_filename_make_safe(seq_name); - BLI_strncpy(path, project_dir, path_len); - BLI_path_append(path, path_len, scene_name); - BLI_path_append(path, path_len, seq_name); -} - -static void seq_disk_cache_get_file_path(SeqDiskCache *disk_cache, - SeqCacheKey *key, - char *path, - size_t path_len) -{ - seq_disk_cache_get_dir(disk_cache, key->context.scene, key->seq, path, path_len); - int frameno = (int)key->frame_index / DCACHE_IMAGES_PER_FILE; - char cache_filename[FILE_MAXFILE]; - sprintf(cache_filename, - DCACHE_FNAME_FORMAT, - key->type, - key->context.rectx, - key->context.recty, - key->context.preview_render_size, - key->context.view_id, - frameno); - - BLI_path_append(path, path_len, cache_filename); -} - -static void seq_disk_cache_create_version_file(char *path) -{ - BLI_make_existing_file(path); - - FILE *file = BLI_fopen(path, "w"); - if (file) { - fprintf(file, "%d", DCACHE_CURRENT_VERSION); - fclose(file); - } -} - -static void seq_disk_cache_handle_versioning(SeqDiskCache *disk_cache) -{ - char path[FILE_MAX]; - char path_version_file[FILE_MAX]; - int version = 0; - - seq_disk_cache_get_project_dir(disk_cache, path, sizeof(path)); - BLI_strncpy(path_version_file, path, sizeof(path_version_file)); - BLI_path_append(path_version_file, sizeof(path_version_file), "cache_version"); - - if (BLI_exists(path) && BLI_is_dir(path)) { - FILE *file = BLI_fopen(path_version_file, "r"); - - if (file) { - const int num_items_read = fscanf(file, "%d", &version); - if (num_items_read == 0) { - version = -1; - } - fclose(file); - } - - if (version != DCACHE_CURRENT_VERSION) { - BLI_delete(path, false, true); - seq_disk_cache_create_version_file(path_version_file); - } - } - else { - seq_disk_cache_create_version_file(path_version_file); - } -} - -static void seq_disk_cache_delete_invalid_files(SeqDiskCache *disk_cache, - Scene *scene, - Sequence *seq, - int invalidate_types, - int range_start, - int range_end) -{ - DiskCacheFile *next_file, *cache_file = disk_cache->files.first; - char cache_dir[FILE_MAX]; - seq_disk_cache_get_dir(disk_cache, scene, seq, cache_dir, sizeof(cache_dir)); - BLI_path_slash_ensure(cache_dir); - - while (cache_file) { - next_file = cache_file->next; - if (cache_file->cache_type & invalidate_types) { - if (STREQ(cache_dir, cache_file->dir)) { - int timeline_frame_start = seq_cache_frame_index_to_timeline_frame( - seq, cache_file->start_frame); - if (timeline_frame_start > range_start && timeline_frame_start <= range_end) { - seq_disk_cache_delete_file(disk_cache, cache_file); - } - } - } - cache_file = next_file; - } -} - -static void seq_disk_cache_invalidate(Scene *scene, - Sequence *seq, - Sequence *seq_changed, - int invalidate_types) -{ - int start; - int end; - SeqDiskCache *disk_cache = scene->ed->cache->disk_cache; - - BLI_mutex_lock(&disk_cache->read_write_mutex); - - start = seq_changed->startdisp - DCACHE_IMAGES_PER_FILE; - end = seq_changed->enddisp; - - seq_disk_cache_delete_invalid_files(disk_cache, scene, seq, invalidate_types, start, end); - - BLI_mutex_unlock(&disk_cache->read_write_mutex); -} - -static size_t deflate_imbuf_to_file(ImBuf *ibuf, - FILE *file, - int level, - DiskCacheHeaderEntry *header_entry) -{ - void *data = (ibuf->rect != NULL) ? (void *)ibuf->rect : (void *)ibuf->rect_float; - - /* Apply compression if wanted, otherwise just write directly to the file. */ - if (level > 0) { - return BLI_file_zstd_from_mem_at_pos( - data, header_entry->size_raw, file, header_entry->offset, level); - } - - fseek(file, header_entry->offset, SEEK_SET); - return fwrite(data, 1, header_entry->size_raw, file); -} - -static size_t inflate_file_to_imbuf(ImBuf *ibuf, FILE *file, DiskCacheHeaderEntry *header_entry) -{ - void *data = (ibuf->rect != NULL) ? (void *)ibuf->rect : (void *)ibuf->rect_float; - char header[4]; - fseek(file, header_entry->offset, SEEK_SET); - if (fread(header, 1, sizeof(header), file) != sizeof(header)) { - return 0; - } - - /* Check if the data is compressed or raw. */ - if (BLI_file_magic_is_zstd(header)) { - return BLI_file_unzstd_to_mem_at_pos(data, header_entry->size_raw, file, header_entry->offset); - } - - fseek(file, header_entry->offset, SEEK_SET); - return fread(data, 1, header_entry->size_raw, file); -} - -static bool seq_disk_cache_read_header(FILE *file, DiskCacheHeader *header) -{ - BLI_fseek(file, 0LL, SEEK_SET); - const size_t num_items_read = fread(header, sizeof(*header), 1, file); - if (num_items_read < 1) { - BLI_assert_msg(0, "unable to read disk cache header"); - perror("unable to read disk cache header"); - return false; - } - - for (int i = 0; i < DCACHE_IMAGES_PER_FILE; i++) { - if ((ENDIAN_ORDER == B_ENDIAN) && header->entry[i].encoding == 0) { - BLI_endian_switch_uint64(&header->entry[i].frameno); - BLI_endian_switch_uint64(&header->entry[i].offset); - BLI_endian_switch_uint64(&header->entry[i].size_compressed); - BLI_endian_switch_uint64(&header->entry[i].size_raw); - } - } - - return true; -} - -static size_t seq_disk_cache_write_header(FILE *file, DiskCacheHeader *header) -{ - BLI_fseek(file, 0LL, SEEK_SET); - return fwrite(header, sizeof(*header), 1, file); -} - -static int seq_disk_cache_add_header_entry(SeqCacheKey *key, ImBuf *ibuf, DiskCacheHeader *header) -{ - int i; - uint64_t offset = sizeof(*header); - - /* Lookup free entry, get offset for new data. */ - for (i = 0; i < DCACHE_IMAGES_PER_FILE; i++) { - if (header->entry[i].size_compressed == 0) { - break; - } - } - - /* Attempt to write beyond set entry limit. - * Reset file header and start writing from beginning. - */ - if (i == DCACHE_IMAGES_PER_FILE) { - i = 0; - memset(header, 0, sizeof(*header)); - } - - /* Calculate offset for image data. */ - if (i > 0) { - offset = header->entry[i - 1].offset + header->entry[i - 1].size_compressed; - } - - if (ENDIAN_ORDER == B_ENDIAN) { - header->entry[i].encoding = 255; - } - else { - header->entry[i].encoding = 0; - } - - header->entry[i].offset = offset; - header->entry[i].frameno = key->frame_index; - - /* Store colorspace name of ibuf. */ - const char *colorspace_name; - if (ibuf->rect) { - header->entry[i].size_raw = ibuf->x * ibuf->y * ibuf->channels; - colorspace_name = IMB_colormanagement_get_rect_colorspace(ibuf); - } - else { - header->entry[i].size_raw = ibuf->x * ibuf->y * ibuf->channels * 4; - colorspace_name = IMB_colormanagement_get_float_colorspace(ibuf); - } - BLI_strncpy( - header->entry[i].colorspace_name, colorspace_name, sizeof(header->entry[i].colorspace_name)); - - return i; -} - -static int seq_disk_cache_get_header_entry(SeqCacheKey *key, DiskCacheHeader *header) -{ - for (int i = 0; i < DCACHE_IMAGES_PER_FILE; i++) { - if (header->entry[i].frameno == key->frame_index) { - return i; - } - } - - return -1; -} - -static bool seq_disk_cache_write_file(SeqDiskCache *disk_cache, SeqCacheKey *key, ImBuf *ibuf) -{ - char path[FILE_MAX]; - - seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path)); - BLI_make_existing_file(path); - - FILE *file = BLI_fopen(path, "rb+"); - if (!file) { - file = BLI_fopen(path, "wb+"); - if (!file) { - return false; - } - seq_disk_cache_add_file_to_list(disk_cache, path); - } - - DiskCacheFile *cache_file = seq_disk_cache_get_file_entry_by_path(disk_cache, path); - DiskCacheHeader header; - memset(&header, 0, sizeof(header)); - /* #BLI_make_existing_file() above may create an empty file. This is fine, don't attempt reading - * the header in that case. */ - if (cache_file->fstat.st_size != 0 && !seq_disk_cache_read_header(file, &header)) { - fclose(file); - seq_disk_cache_delete_file(disk_cache, cache_file); - return false; - } - int entry_index = seq_disk_cache_add_header_entry(key, ibuf, &header); - - size_t bytes_written = deflate_imbuf_to_file( - ibuf, file, seq_disk_cache_compression_level(), &header.entry[entry_index]); - - if (bytes_written != 0) { - /* Last step is writing header, as image data can be overwritten, - * but missing data would cause problems. - */ - header.entry[entry_index].size_compressed = bytes_written; - seq_disk_cache_write_header(file, &header); - seq_disk_cache_update_file(disk_cache, path); - fclose(file); - - return true; - } - - return false; -} - -static ImBuf *seq_disk_cache_read_file(SeqDiskCache *disk_cache, SeqCacheKey *key) -{ - char path[FILE_MAX]; - DiskCacheHeader header; - - seq_disk_cache_get_file_path(disk_cache, key, path, sizeof(path)); - BLI_make_existing_file(path); - - FILE *file = BLI_fopen(path, "rb"); - if (!file) { - return NULL; - } - - if (!seq_disk_cache_read_header(file, &header)) { - fclose(file); - return NULL; - } - int entry_index = seq_disk_cache_get_header_entry(key, &header); - - /* Item not found. */ - if (entry_index < 0) { - fclose(file); - return NULL; - } - - ImBuf *ibuf; - uint64_t size_char = (uint64_t)key->context.rectx * key->context.recty * 4; - uint64_t size_float = (uint64_t)key->context.rectx * key->context.recty * 16; - size_t expected_size; - - if (header.entry[entry_index].size_raw == size_char) { - expected_size = size_char; - ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rect); - IMB_colormanagement_assign_rect_colorspace(ibuf, header.entry[entry_index].colorspace_name); - } - else if (header.entry[entry_index].size_raw == size_float) { - expected_size = size_float; - ibuf = IMB_allocImBuf(key->context.rectx, key->context.recty, 32, IB_rectfloat); - IMB_colormanagement_assign_float_colorspace(ibuf, header.entry[entry_index].colorspace_name); - } - else { - fclose(file); - return NULL; - } - - size_t bytes_read = inflate_file_to_imbuf(ibuf, file, &header.entry[entry_index]); - - /* Sanity check. */ - if (bytes_read != expected_size) { - fclose(file); - IMB_freeImBuf(ibuf); - return NULL; - } - BLI_file_touch(path); - seq_disk_cache_update_file(disk_cache, path); - fclose(file); - - return ibuf; -} - -#undef DCACHE_FNAME_FORMAT -#undef DCACHE_IMAGES_PER_FILE -#undef COLORSPACE_NAME_MAX -#undef DCACHE_CURRENT_VERSION static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b) { @@ -778,14 +151,14 @@ static float seq_cache_timeline_frame_to_frame_index(Sequence *seq, float timeli /* With raw images, map timeline_frame to strip input media frame range. This means that static * images or extended frame range of movies will only generate one cache entry. No special * treatment in converting frame index to timeline_frame is needed. */ - if (type == SEQ_CACHE_STORE_RAW || type == SEQ_CACHE_STORE_THUMBNAIL) { + if (ELEM(type, SEQ_CACHE_STORE_RAW, SEQ_CACHE_STORE_THUMBNAIL)) { return seq_give_frame_index(seq, timeline_frame); } return timeline_frame - seq->start; } -static float seq_cache_frame_index_to_timeline_frame(Sequence *seq, float frame_index) +float seq_cache_frame_index_to_timeline_frame(Sequence *seq, float frame_index) { return frame_index + seq->start; } @@ -1080,9 +453,6 @@ static SeqCacheKey *seq_cache_get_item_for_removal(Scene *scene) return finalkey; } -/* Find only "base" keys. - * Sources(other types) for a frame must be freed all at once. - */ bool seq_cache_recycle_item(Scene *scene) { SeqCache *cache = seq_cache_get_from_scene(scene); @@ -1131,28 +501,6 @@ static void seq_cache_set_temp_cache_linked(Scene *scene, SeqCacheKey *base) } } -static void seq_disk_cache_create(Main *bmain, Scene *scene) -{ - BLI_mutex_lock(&cache_create_lock); - SeqCache *cache = seq_cache_get_from_scene(scene); - - if (cache == NULL) { - return; - } - - if (cache->disk_cache != NULL) { - return; - } - - cache->disk_cache = MEM_callocN(sizeof(SeqDiskCache), "SeqDiskCache"); - cache->disk_cache->bmain = bmain; - BLI_mutex_init(&cache->disk_cache->read_write_mutex); - seq_disk_cache_handle_versioning(cache->disk_cache); - seq_disk_cache_get_files(cache->disk_cache, seq_disk_cache_base_dir()); - cache->disk_cache->timestamp = scene->ed->disk_cache_timestamp; - BLI_mutex_unlock(&cache_create_lock); -} - static void seq_cache_create(Main *bmain, Scene *scene) { BLI_mutex_lock(&cache_create_lock); @@ -1246,9 +594,7 @@ void seq_cache_destruct(Scene *scene) BLI_mutex_end(&cache->iterator_mutex); if (cache->disk_cache != NULL) { - BLI_freelistN(&cache->disk_cache->files); - BLI_mutex_end(&cache->disk_cache->read_write_mutex); - MEM_freeN(cache->disk_cache); + seq_disk_cache_free(cache->disk_cache); } MEM_freeN(cache); @@ -1297,7 +643,7 @@ void seq_cache_cleanup_sequence(Scene *scene, } if (seq_disk_cache_is_enabled(cache->bmain) && cache->disk_cache != NULL) { - seq_disk_cache_invalidate(scene, seq, seq_changed, invalidate_types); + seq_disk_cache_invalidate(cache->disk_cache, scene, seq, seq_changed, invalidate_types); } seq_cache_lock(scene); @@ -1434,12 +780,10 @@ struct ImBuf *seq_cache_get(const SeqRenderData *context, /* Try disk cache: */ if (seq_disk_cache_is_enabled(context->bmain)) { if (cache->disk_cache == NULL) { - seq_disk_cache_create(context->bmain, context->scene); + cache->disk_cache = seq_disk_cache_create(context->bmain, context->scene); } - BLI_mutex_lock(&cache->disk_cache->read_write_mutex); ibuf = seq_disk_cache_read_file(cache->disk_cache, &key); - BLI_mutex_unlock(&cache->disk_cache->read_write_mutex); if (ibuf == NULL) { return NULL; @@ -1550,9 +894,7 @@ void seq_cache_put( seq_disk_cache_create(context->bmain, context->scene); } - BLI_mutex_lock(&cache->disk_cache->read_write_mutex); seq_disk_cache_write_file(cache->disk_cache, key, i); - BLI_mutex_unlock(&cache->disk_cache->read_write_mutex); seq_disk_cache_enforce_limits(cache->disk_cache); } } diff --git a/source/blender/sequencer/intern/image_cache.h b/source/blender/sequencer/intern/image_cache.h index 60031311985..65732b5d83d 100644 --- a/source/blender/sequencer/intern/image_cache.h +++ b/source/blender/sequencer/intern/image_cache.h @@ -27,15 +27,29 @@ extern "C" { #endif +#include "SEQ_render.h" /* Needed for #eSeqTaskId. */ + struct ImBuf; struct Main; struct Scene; struct SeqRenderData; struct Sequence; -#ifdef __cplusplus -} -#endif +typedef struct SeqCacheKey { + struct SeqCache *cache_owner; + void *userkey; + struct SeqCacheKey *link_prev; /* Used for linking intermediate items to final frame. */ + struct SeqCacheKey *link_next; /* Used for linking intermediate items to final frame. */ + struct Sequence *seq; + struct SeqRenderData context; + float frame_index; /* Usually same as timeline_frame. Mapped to media for RAW entries. */ + float timeline_frame; /* Only for reference - used for freeing when cache is full. */ + float cost; /* In short: render time(s) divided by playback frame duration(s) */ + bool is_temp_cache; /* this cache entry will be freed before rendering next frame */ + /* ID of task for assigning temp cache entries to particular task(thread, etc.) */ + eSeqTaskId task_id; + int type; +} SeqCacheKey; struct ImBuf *seq_cache_get(const struct SeqRenderData *context, struct Sequence *seq, @@ -56,6 +70,10 @@ bool seq_cache_put_if_possible(const struct SeqRenderData *context, float timeline_frame, int type, struct ImBuf *nval); +/** + * Find only "base" keys. + * Sources(other types) for a frame must be freed all at once. + */ bool seq_cache_recycle_item(struct Scene *scene); void seq_cache_free_temp_cache(struct Scene *scene, short id, int timeline_frame); void seq_cache_destruct(struct Scene *scene); @@ -67,6 +85,7 @@ void seq_cache_cleanup_sequence(struct Scene *scene, bool force_seq_changed_range); void seq_cache_thumbnail_cleanup(Scene *scene, rctf *view_area); bool seq_cache_is_full(void); +float seq_cache_frame_index_to_timeline_frame(struct Sequence *seq, float frame_index); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c index 2429405350b..6cd53f08b3a 100644 --- a/source/blender/sequencer/intern/iterator.c +++ b/source/blender/sequencer/intern/iterator.c @@ -44,18 +44,6 @@ /** \Iterator API * \{ */ -/** - * Utility function for SEQ_ITERATOR_FOREACH macro. - * Ensure, that iterator is initialized. During initialization return pointer to collection element - * and step gset iterator. When this function is called after iterator has been initialized, it - * will do nothing and return true. - * - * \param collection: collection to iterate - * \param iterator: iterator to be initialized - * \param r_seq: pointer to Sequence pointer - * - * \return false when iterator can not be initialized, true otherwise - */ bool SEQ_iterator_ensure(SeqCollection *collection, SeqIterator *iterator, Sequence **r_seq) { if (iterator->iterator_initialized) { @@ -76,14 +64,6 @@ bool SEQ_iterator_ensure(SeqCollection *collection, SeqIterator *iterator, Seque return true; } -/** - * Utility function for SEQ_ITERATOR_FOREACH macro. - * Yield collection element - * - * \param iterator: iterator to be initialized - * - * \return collection element or NULL when iteration has ended - */ Sequence *SEQ_iterator_yield(SeqIterator *iterator) { Sequence *seq = BLI_gsetIterator_done(&iterator->gsi) ? NULL : @@ -108,36 +88,17 @@ static bool seq_for_each_recursive(ListBase *seqbase, SeqForEachFunc callback, v return true; } -/** - * Utility function to recursively iterate through all sequence strips in a `seqbase` list. - * Uses callback to do operations on each sequence element. - * The callback can stop the iteration if needed. - * - * \param seqbase: #ListBase of sequences to be iterated over. - * \param callback: query function callback, returns false if iteration should stop. - * \param user_data: pointer to user data that can be used in the callback function. - */ void SEQ_for_each_callback(ListBase *seqbase, SeqForEachFunc callback, void *user_data) { seq_for_each_recursive(seqbase, callback, user_data); } -/** - * Free strip collection. - * - * \param collection: collection to be freed - */ void SEQ_collection_free(SeqCollection *collection) { BLI_gset_free(collection->set, NULL); MEM_freeN(collection); } -/** - * Create new empty strip collection. - * - * \return empty strip collection. - */ SeqCollection *SEQ_collection_create(const char *name) { SeqCollection *collection = MEM_callocN(sizeof(SeqCollection), name); @@ -146,30 +107,16 @@ SeqCollection *SEQ_collection_create(const char *name) return collection; } -/** - * Return number of items in collection. - */ uint SEQ_collection_len(const SeqCollection *collection) { return BLI_gset_len(collection->set); } -/** - * Check if seq is in collection. - */ bool SEQ_collection_has_strip(const Sequence *seq, const SeqCollection *collection) { return BLI_gset_haskey(collection->set, seq); } -/** - * Query strips from seqbase. seq_reference is used by query function as filter condition. - * - * \param seq_reference: reference strip for query function - * \param seqbase: ListBase in which strips are queried - * \param seq_query_func: query function callback - * \return strip collection - */ SeqCollection *SEQ_query_by_reference(Sequence *seq_reference, ListBase *seqbase, void seq_query_func(Sequence *seq_reference, @@ -180,40 +127,22 @@ SeqCollection *SEQ_query_by_reference(Sequence *seq_reference, seq_query_func(seq_reference, seqbase, collection); return collection; } -/** - * Add strip to collection. - * - * \param seq: strip to be added - * \param collection: collection to which strip will be added - * \return false if strip is already in set, otherwise true - */ bool SEQ_collection_append_strip(Sequence *seq, SeqCollection *collection) { - if (BLI_gset_lookup(collection->set, seq) != NULL) { + void **key; + if (BLI_gset_ensure_p_ex(collection->set, seq, &key)) { return false; } - BLI_gset_insert(collection->set, seq); + + *key = (void *)seq; return true; } -/** - * Remove strip from collection. - * - * \param seq: strip to be removed - * \param collection: collection from which strip will be removed - * \return true if strip exists in set and it was removed from set, otherwise false - */ bool SEQ_collection_remove_strip(Sequence *seq, SeqCollection *collection) { return BLI_gset_remove(collection->set, seq, NULL); } -/** - * Move strips from collection_src to collection_dst. Source collection will be freed. - * - * \param collection_dst: destination collection - * \param collection_src: source collection - */ void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collection_src) { Sequence *seq; @@ -223,13 +152,6 @@ void SEQ_collection_merge(SeqCollection *collection_dst, SeqCollection *collecti SEQ_collection_free(collection_src); } -/** - * Remove strips from collection that are also in `exclude_elements`. Source collection will be - * freed. - * - * \param collection: collection from which strips are removed - * \param exclude_elements: collection of strips to be removed - */ void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_elements) { Sequence *seq; @@ -239,14 +161,6 @@ void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_el SEQ_collection_free(exclude_elements); } -/** - * Expand collection by running SEQ_query() for each strip, which will be used as reference. - * Results of these queries will be merged into provided collection. - * - * \param seqbase: ListBase in which strips are queried - * \param collection: SeqCollection to be expanded - * \param seq_query_func: query function callback - */ void SEQ_collection_expand(ListBase *seqbase, SeqCollection *collection, void seq_query_func(Sequence *seq_reference, @@ -265,12 +179,6 @@ void SEQ_collection_expand(ListBase *seqbase, SEQ_collection_merge(collection, query_matches); } -/** - * Duplicate collection - * - * \param collection: collection to be duplicated - * \return duplicate of collection - */ SeqCollection *SEQ_collection_duplicate(SeqCollection *collection) { SeqCollection *duplicate = SEQ_collection_create(__func__); @@ -293,12 +201,6 @@ static void query_all_strips_recursive(ListBase *seqbase, SeqCollection *collect } } -/** - * Query all strips in seqbase and nested meta strips. - * - * \param seqbase: ListBase in which strips are queried - * \return strip collection - */ SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase) { SeqCollection *collection = SEQ_collection_create(__func__); @@ -311,25 +213,15 @@ SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase) return collection; } -/** - * Query all strips in seqbase. This does not include strips nested in meta strips. - * - * \param seqbase: ListBase in which strips are queried - * \return strip collection - */ SeqCollection *SEQ_query_all_strips(ListBase *seqbase) { SeqCollection *collection = SEQ_collection_create(__func__); - query_all_strips_recursive(seqbase, collection); + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + SEQ_collection_append_strip(seq, collection); + } return collection; } -/** - * Query all selected strips in seqbase. - * - * \param seqbase: ListBase in which strips are queried - * \return strip collection - */ SeqCollection *SEQ_query_selected_strips(ListBase *seqbase) { SeqCollection *collection = SEQ_collection_create(__func__); @@ -430,14 +322,6 @@ static void collection_filter_rendered_strips(SeqCollection *collection) } } -/** - * Query strips that are rendered at \a timeline_frame when \a displayed channel is viewed - * - * \param seqbase: ListBase in which strips are queried - * \param timeline_frame: viewed frame - * \param displayed_channel: viewed channel. when set to 0, no channel filter is applied - * \return strip collection - */ SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase, const int timeline_frame, const int displayed_channel) @@ -450,12 +334,6 @@ SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase, return collection; } -/** - * Query all unselected strips in seqbase. - * - * \param seqbase: ListBase in which strips are queried - * \return strip collection - */ SeqCollection *SEQ_query_unselected_strips(ListBase *seqbase) { SeqCollection *collection = SEQ_collection_create(__func__); @@ -468,15 +346,6 @@ SeqCollection *SEQ_query_unselected_strips(ListBase *seqbase) return collection; } -/** - * Query all effect strips that are directly or indirectly connected to seq_reference. - * This includes all effects of seq_reference, strips used by another inputs and their effects, so - * that whole chain is fully independent of other strips. - * - * \param seq_reference: reference strip - * \param seqbase: ListBase in which strips are queried - * \param collection: collection to be filled - */ void SEQ_query_strip_effect_chain(Sequence *seq_reference, ListBase *seqbase, SeqCollection *collection) diff --git a/source/blender/sequencer/intern/modifier.c b/source/blender/sequencer/intern/modifier.c index 07d09f4ae17..00ae88232fd 100644 --- a/source/blender/sequencer/intern/modifier.c +++ b/source/blender/sequencer/intern/modifier.c @@ -216,7 +216,7 @@ static void modifier_apply_threaded(ImBuf *ibuf, /** \name Color Balance Modifier * \{ */ -static StripColorBalance calc_cb(StripColorBalance *cb_) +static StripColorBalance calc_cb_lgg(StripColorBalance *cb_) { StripColorBalance cb = *cb_; int c; @@ -262,8 +262,52 @@ static StripColorBalance calc_cb(StripColorBalance *cb_) return cb; } +static StripColorBalance calc_cb_sop(StripColorBalance *cb_) +{ + StripColorBalance cb = *cb_; + int c; + + for (c = 0; c < 3; c++) { + if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_SLOPE) { + if (cb.slope[c] != 0.0f) { + cb.slope[c] = 1.0f / cb.slope[c]; + } + else { + cb.slope[c] = 1000000; + } + } + + if (cb.flag & SEQ_COLOR_BALANCE_INVERSE_OFFSET) { + cb.offset[c] = -1.0f * (cb.offset[c] - 1.0f); + } + else { + cb.offset[c] = cb.offset[c] - 1.0f; + } + + if (!(cb.flag & SEQ_COLOR_BALANCE_INVERSE_POWER)) { + if (cb.power[c] != 0.0f) { + cb.power[c] = 1.0f / cb.power[c]; + } + else { + cb.power[c] = 1000000; + } + } + } + + return cb; +} + +static StripColorBalance calc_cb(StripColorBalance *cb_) +{ + if (cb_->method == SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN) { + return calc_cb_lgg(cb_); + } + /* `cb_->method == SEQ_COLOR_BALANCE_METHOD_SLOPEOFFSETPOWER`. */ + return calc_cb_sop(cb_); +} + /* NOTE: lift is actually 2-lift. */ -MINLINE float color_balance_fl( +MINLINE float color_balance_fl_lgg( float in, const float lift, const float gain, const float gamma, const float mul) { float x = (((in - 1.0f) * lift) + 1.0f) * gain; @@ -278,12 +322,40 @@ MINLINE float color_balance_fl( return x; } -static void make_cb_table_float(float lift, float gain, float gamma, float *table, float mul) +MINLINE float color_balance_fl_sop(float in, + const float slope, + const float offset, + const float power, + const float pivot, + float mul) { - int y; + float x = in * slope + offset; + + /* prevent NaN */ + if (x < 0.0f) { + x = 0.0f; + } - for (y = 0; y < 256; y++) { - float v = color_balance_fl((float)y * (1.0f / 255.0f), lift, gain, gamma, mul); + x = powf(x / pivot, power) * pivot; + x *= mul; + CLAMP(x, FLT_MIN, FLT_MAX); + return x; +} + +static void make_cb_table_float_lgg(float lift, float gain, float gamma, float *table, float mul) +{ + for (int y = 0; y < 256; y++) { + float v = color_balance_fl_lgg((float)y * (1.0f / 255.0f), lift, gain, gamma, mul); + + table[y] = v; + } +} + +static void make_cb_table_float_sop( + float slope, float offset, float power, float pivot, float *table, float mul) +{ + for (int y = 0; y < 256; y++) { + float v = color_balance_fl_sop((float)y * (1.0f / 255.0f), slope, offset, power, pivot, mul); table[y] = v; } @@ -310,7 +382,13 @@ static void color_balance_byte_byte(StripColorBalance *cb_, straight_uchar_to_premul_float(p, cp); for (c = 0; c < 3; c++) { - float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul); + float t; + if (cb.method == SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN) { + t = color_balance_fl_lgg(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul); + } + else { + t = color_balance_fl_sop(p[c], cb.slope[c], cb.offset[c], cb.power[c], 1.0, mul); + } if (m) { float m_normal = (float)m[c] / 255.0f; @@ -352,7 +430,12 @@ static void color_balance_byte_float(StripColorBalance *cb_, cb = calc_cb(cb_); for (c = 0; c < 3; c++) { - make_cb_table_float(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul); + if (cb.method == SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN) { + make_cb_table_float_lgg(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul); + } + else { + make_cb_table_float_sop(cb.slope[c], cb.offset[c], cb.power[c], 1.0, cb_tab[c], mul); + } } for (i = 0; i < 256; i++) { @@ -397,7 +480,13 @@ static void color_balance_float_float(StripColorBalance *cb_, while (p < e) { int c; for (c = 0; c < 3; c++) { - float t = color_balance_fl(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul); + float t; + if (cb_->method == SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN) { + t = color_balance_fl_lgg(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul); + } + else { + t = color_balance_fl_sop(p[c], cb.slope[c], cb.offset[c], cb.power[c], 1.0, mul); + } if (m) { p[c] = p[c] * (1.0f - m[c]) + t * m[c]; @@ -507,11 +596,15 @@ static void colorBalance_init_data(SequenceModifierData *smd) int c; cbmd->color_multiply = 1.0f; + cbmd->color_balance.method = 0; for (c = 0; c < 3; c++) { cbmd->color_balance.lift[c] = 1.0f; cbmd->color_balance.gamma[c] = 1.0f; cbmd->color_balance.gain[c] = 1.0f; + cbmd->color_balance.slope[c] = 1.0f; + cbmd->color_balance.offset[c] = 1.0f; + cbmd->color_balance.power[c] = 1.0f; } } @@ -1068,6 +1161,7 @@ static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf * // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd; modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL); + ibuf->planes = R_IMF_PLANES_RGBA; } static SequenceModifierTypeInfo seqModifier_Mask = { diff --git a/source/blender/sequencer/intern/multiview.c b/source/blender/sequencer/intern/multiview.c index e120234ed8b..68d2a33fd5c 100644 --- a/source/blender/sequencer/intern/multiview.c +++ b/source/blender/sequencer/intern/multiview.c @@ -40,7 +40,6 @@ void seq_anim_add_suffix(Scene *scene, struct anim *anim, const int view_id) IMB_suffix_anim(anim, suffix); } -/* the number of files will vary according to the stereo format */ int seq_num_files(Scene *scene, char views_format, const bool is_multiview) { if (!is_multiview) { diff --git a/source/blender/sequencer/intern/multiview.h b/source/blender/sequencer/intern/multiview.h index bbc66c6f84c..79d99c88b50 100644 --- a/source/blender/sequencer/intern/multiview.h +++ b/source/blender/sequencer/intern/multiview.h @@ -36,14 +36,17 @@ struct Scene; * ********************************************************************** */ -void seq_anim_add_suffix(struct Scene *scene, struct anim *anim, const int view_id); +void seq_anim_add_suffix(struct Scene *scene, struct anim *anim, int view_id); void seq_multiview_name(struct Scene *scene, - const int view_id, + int view_id, const char *prefix, const char *ext, char *r_path, size_t r_size); -int seq_num_files(struct Scene *scene, char views_format, const bool is_multiview); +/** + * The number of files will vary according to the stereo format. + */ +int seq_num_files(struct Scene *scene, char views_format, bool is_multiview); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c index 3e0b4738db1..42affae26ed 100644 --- a/source/blender/sequencer/intern/prefetch.c +++ b/source/blender/sequencer/intern/prefetch.c @@ -162,14 +162,12 @@ static Sequence *sequencer_prefetch_get_original_sequence(Sequence *seq, ListBas return NULL; } -/* for cache context swapping */ Sequence *seq_prefetch_get_original_sequence(Sequence *seq, Scene *scene) { Editing *ed = scene->ed; return sequencer_prefetch_get_original_sequence(seq, &ed->seqbase); } -/* for cache context swapping */ SeqRenderData *seq_prefetch_get_original_context(const SeqRenderData *context) { PrefetchJob *pfjob = seq_prefetch_job_get(context->scene); @@ -268,9 +266,6 @@ void SEQ_prefetch_stop_all(void) } } -/* Use also to update scene and context changes - * This function should almost always be called by cache invalidation, not directly. - */ void SEQ_prefetch_stop(Scene *scene) { PrefetchJob *pfjob; @@ -333,6 +328,20 @@ static void seq_prefetch_update_scene(Scene *scene) seq_prefetch_init_depsgraph(pfjob); } +static void seq_prefetch_update_active_seqbase(PrefetchJob *pfjob) +{ + MetaStack *ms_orig = SEQ_meta_stack_active_get(SEQ_editing_get(pfjob->scene)); + Editing *ed_eval = SEQ_editing_get(pfjob->scene_eval); + + if (ms_orig != NULL) { + Sequence *meta_eval = seq_prefetch_get_original_sequence(ms_orig->parseq, pfjob->scene_eval); + SEQ_seqbase_active_set(ed_eval, &meta_eval->seqbase); + } + else { + SEQ_seqbase_active_set(ed_eval, &ed_eval->seqbase); + } +} + static void seq_prefetch_resume(Scene *scene) { PrefetchJob *pfjob = seq_prefetch_job_get(scene); @@ -491,7 +500,7 @@ static void *seq_prefetch_frames(void *job) */ pfjob->scene_eval->ed->prefetch_job = pfjob; - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(pfjob->scene)); + ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(pfjob->scene_eval)); if (seq_prefetch_must_skip_frame(pfjob, seqbase)) { pfjob->num_frames_prefetched++; continue; @@ -554,6 +563,7 @@ static PrefetchJob *seq_prefetch_start_ex(const SeqRenderData *context, float cf seq_prefetch_update_scene(context->scene); seq_prefetch_update_context(context); + seq_prefetch_update_active_seqbase(pfjob); BLI_threadpool_remove(&pfjob->threads, pfjob); BLI_threadpool_insert(&pfjob->threads, pfjob); @@ -561,7 +571,6 @@ static PrefetchJob *seq_prefetch_start_ex(const SeqRenderData *context, float cf return pfjob; } -/* Start or resume prefetching. */ void seq_prefetch_start(const SeqRenderData *context, float timeline_frame) { Scene *scene = context->scene; diff --git a/source/blender/sequencer/intern/prefetch.h b/source/blender/sequencer/intern/prefetch.h index 8cfc6bf90bd..8cc5f6d35d1 100644 --- a/source/blender/sequencer/intern/prefetch.h +++ b/source/blender/sequencer/intern/prefetch.h @@ -35,11 +35,20 @@ struct Sequence; } #endif +/** + * Start or resume prefetching. + */ void seq_prefetch_start(const struct SeqRenderData *context, float timeline_frame); void seq_prefetch_free(struct Scene *scene); bool seq_prefetch_job_is_running(struct Scene *scene); void seq_prefetch_get_time_range(struct Scene *scene, int *start, int *end); +/** + * For cache context swapping. + */ struct SeqRenderData *seq_prefetch_get_original_context(const struct SeqRenderData *context); +/** + * For cache context swapping. + */ struct Sequence *seq_prefetch_get_original_sequence(struct Sequence *seq, struct Scene *scene); #ifdef __cplusplus diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c index 2bc294c91cd..5982f89a287 100644 --- a/source/blender/sequencer/intern/proxy.c +++ b/source/blender/sequencer/intern/proxy.c @@ -34,6 +34,7 @@ #include "BLI_fileops.h" #include "BLI_listbase.h" #include "BLI_path_util.h" +#include "BLI_session_uuid.h" #include "BLI_string.h" #ifdef WIN32 @@ -54,6 +55,7 @@ #include "IMB_imbuf_types.h" #include "IMB_metadata.h" +#include "SEQ_iterator.h" #include "SEQ_proxy.h" #include "SEQ_relations.h" #include "SEQ_render.h" @@ -79,6 +81,7 @@ typedef struct SeqIndexBuildContext { Depsgraph *depsgraph; Scene *scene; Sequence *seq, *orig_seq; + SessionUUID orig_seq_uuid; } SeqIndexBuildContext; int SEQ_rendersize_to_proxysize(int render_size) @@ -412,7 +415,8 @@ bool SEQ_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list, - ListBase *queue) + ListBase *queue, + bool build_only_on_bad_performance) { SeqIndexBuildContext *context; Sequence *nseq; @@ -458,6 +462,7 @@ bool SEQ_proxy_rebuild_context(Main *bmain, context->depsgraph = depsgraph; context->scene = scene; context->orig_seq = seq; + context->orig_seq_uuid = seq->runtime.session_uuid; context->seq = nseq; context->view_id = i; /* only for images */ @@ -472,7 +477,8 @@ bool SEQ_proxy_rebuild_context(Main *bmain, context->size_flags, context->quality, context->overwrite, - file_list); + file_list, + build_only_on_bad_performance); } if (!context->index_context) { MEM_freeN(context); @@ -560,6 +566,18 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context, } } +static bool seq_orig_free_anims(Sequence *seq_iter, void *data) +{ + SessionUUID orig_seq_uuid = ((SeqIndexBuildContext *)data)->orig_seq_uuid; + + if (BLI_session_uuid_is_equal(&seq_iter->runtime.session_uuid, &orig_seq_uuid)) { + for (StripAnim *sanim = seq_iter->anims.first; sanim; sanim = sanim->next) { + IMB_close_anim_proxies(sanim->anim); + } + } + return true; +} + void SEQ_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop) { if (context->index_context) { @@ -569,14 +587,13 @@ void SEQ_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop) IMB_close_anim_proxies(sanim->anim); } - for (sanim = context->orig_seq->anims.first; sanim; sanim = sanim->next) { - IMB_close_anim_proxies(sanim->anim); - } + /* `context->seq_orig` may have been removed during building. */ + SEQ_for_each_callback(&context->scene->ed->seqbase, seq_orig_free_anims, context); IMB_anim_index_rebuild_finish(context->index_context, stop); } - seq_free_sequence_recurse(NULL, context->seq, true, true); + seq_free_sequence_recurse(NULL, context->seq, true); MEM_freeN(context); } @@ -586,10 +603,7 @@ void SEQ_proxy_set(struct Sequence *seq, bool value) if (value) { seq->flag |= SEQ_USE_PROXY; if (seq->strip->proxy == NULL) { - seq->strip->proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy"); - seq->strip->proxy->quality = 50; - seq->strip->proxy->build_tc_flags = SEQ_PROXY_TC_ALL; - seq->strip->proxy->build_size_flags = SEQ_PROXY_IMAGE_SIZE_25; + seq->strip->proxy = seq_strip_proxy_alloc(); } } else { diff --git a/source/blender/sequencer/intern/proxy.h b/source/blender/sequencer/intern/proxy.h index a65fdcd42fe..e92cd8de429 100644 --- a/source/blender/sequencer/intern/proxy.h +++ b/source/blender/sequencer/intern/proxy.h @@ -36,7 +36,7 @@ struct anim; struct ImBuf *seq_proxy_fetch(const struct SeqRenderData *context, struct Sequence *seq, int timeline_frame); -bool seq_proxy_get_custom_file_fname(struct Sequence *seq, char *name, const int view_id); +bool seq_proxy_get_custom_file_fname(struct Sequence *seq, char *name, int view_id); void free_proxy_seq(Sequence *seq); void seq_proxy_index_dir_set(struct anim *anim, const char *base_dir); diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index cf3f9d5cba5..482425e70d3 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -29,6 +29,7 @@ #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" +#include "DNA_defaults.h" #include "DNA_mask_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" @@ -69,6 +70,7 @@ #include "SEQ_iterator.h" #include "SEQ_modifier.h" #include "SEQ_proxy.h" +#include "SEQ_relations.h" #include "SEQ_render.h" #include "SEQ_sequencer.h" #include "SEQ_time.h" @@ -96,6 +98,7 @@ SequencerDrawView sequencer_view3d_fn = NULL; /* NULL in background mode */ /* -------------------------------------------------------------------- */ /** \name Color-space utility functions * \{ */ + void seq_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf) { #if 0 @@ -212,6 +215,7 @@ void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4 /* -------------------------------------------------------------------- */ /** \name Rendering utility functions * \{ */ + void SEQ_render_new_render_data(Main *bmain, struct Depsgraph *depsgraph, Scene *scene, @@ -300,25 +304,24 @@ int seq_get_shown_sequences(ListBase *seqbase, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Preprocessing and effects - * \{ */ -/* - * input preprocessing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE +/** \name Preprocessing & Effects + * + * Input preprocessing for SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP and SEQ_TYPE_SCENE. * * Do all the things you can't really do afterwards using sequence effects - * (read: before rescaling to render resolution has been done) + * (read: before re-scaling to render resolution has been done). * * Order is important! * - * - Deinterlace - * - Crop and transform in image source coordinate space - * - Flip X + Flip Y (could be done afterwards, backward compatibility) - * - Promote image to float data (affects pipeline operations afterwards) + * - De-interlace. + * - Crop and transform in image source coordinate space. + * - Flip X + Flip Y (could be done afterwards, backward compatibility). + * - Promote image to float data (affects pipeline operations afterwards). * - Color balance (is most efficient in the byte -> float * (future: half -> float should also work fine!) - * case, if done on load, since we can use lookup tables) - * - Premultiply - */ + * case, if done on load, since we can use lookup tables). + * - Pre-multiply. + * \{ */ static bool sequencer_use_transform(const Sequence *seq) { @@ -402,7 +405,7 @@ static void sequencer_image_crop_transform_matrix(const Sequence *seq, const ImBuf *out, const float image_scale_factor, const float preview_scale_factor, - float r_transform_matrix[3][3]) + float r_transform_matrix[4][4]) { const StripTransform *transform = seq->strip->transform; const float scale_x = transform->scale_x * image_scale_factor; @@ -411,13 +414,16 @@ static void sequencer_image_crop_transform_matrix(const Sequence *seq, const float image_center_offs_y = (out->y - in->y) / 2; const float translate_x = transform->xofs * preview_scale_factor + image_center_offs_x; const float translate_y = transform->yofs * preview_scale_factor + image_center_offs_y; - const float pivot[2] = {in->x * transform->origin[0], in->y * transform->origin[1]}; - loc_rot_size_to_mat3(r_transform_matrix, - (const float[]){translate_x, translate_y}, - transform->rotation, - (const float[]){scale_x, scale_y}); - transform_pivot_set_m3(r_transform_matrix, pivot); - invert_m3(r_transform_matrix); + const float pivot[3] = {in->x * transform->origin[0], in->y * transform->origin[1], 0.0f}; + + float rotation_matrix[3][3]; + axis_angle_to_mat3_single(rotation_matrix, 'Z', transform->rotation); + loc_rot_size_to_mat4(r_transform_matrix, + (const float[]){translate_x, translate_y, 0.0f}, + rotation_matrix, + (const float[]){scale_x, scale_y, 1.0f}); + transform_pivot_set_m4(r_transform_matrix, pivot); + invert_m4(r_transform_matrix); } static void sequencer_image_crop_init(const Sequence *seq, @@ -437,26 +443,64 @@ static void sequencer_image_crop_init(const Sequence *seq, static void sequencer_thumbnail_transform(ImBuf *in, ImBuf *out) { float image_scale_factor = (float)out->x / in->x; - float transform_matrix[3][3]; + float transform_matrix[4][4]; /* Set to keep same loc,scale,rot but change scale to thumb size limit. */ const float scale_x = 1 * image_scale_factor; const float scale_y = 1 * image_scale_factor; const float image_center_offs_x = (out->x - in->x) / 2; const float image_center_offs_y = (out->y - in->y) / 2; - const float pivot[2] = {in->x / 2, in->y / 2}; - loc_rot_size_to_mat3(transform_matrix, - (const float[]){image_center_offs_x, image_center_offs_y}, - 0, - (const float[]){scale_x, scale_y}); - transform_pivot_set_m3(transform_matrix, pivot); - invert_m3(transform_matrix); - - /* No crop. */ - rctf source_crop; - BLI_rctf_init(&source_crop, 0, in->x, 0, in->y); + const float pivot[3] = {in->x / 2, in->y / 2, 0.0f}; + + float rotation_matrix[3][3]; + unit_m3(rotation_matrix); + loc_rot_size_to_mat4(transform_matrix, + (const float[]){image_center_offs_x, image_center_offs_y, 0.0f}, + rotation_matrix, + (const float[]){scale_x, scale_y, 1.0f}); + transform_pivot_set_m4(transform_matrix, pivot); + invert_m4(transform_matrix); + + IMB_transform(in, out, IMB_TRANSFORM_MODE_REGULAR, IMB_FILTER_NEAREST, transform_matrix, NULL); +} - IMB_transform(in, out, transform_matrix, &source_crop, IMB_FILTER_NEAREST); +/* Check whether transform introduces transparent ares in the result (happens when the transformed + * image does not fully cover the render frame). + * + * The check is done by checking whether all corners of viewport fit inside of the transformed + * image. If they do not the image will have transparent areas. */ +static bool seq_image_transform_transparency_gained(const SeqRenderData *context, Sequence *seq) +{ + Scene *scene = context->scene; + const int x = context->rectx; + const int y = context->recty; + + float seq_image_quad[4][2]; + SEQ_image_transform_final_quad_get(scene, seq, seq_image_quad); + for (int i = 0; i < 4; i++) { + add_v2_v2(seq_image_quad[i], (float[]){x / 2, y / 2}); + } + + return !isect_point_quad_v2((float[]){x, y}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){0, y}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){x, 0}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){0, 0}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]); } static void sequencer_preprocess_transform_crop( @@ -470,7 +514,7 @@ static void sequencer_preprocess_transform_crop( const bool do_scale_to_render_size = seq_need_scale_to_render_size(seq, is_proxy_image); const float image_scale_factor = do_scale_to_render_size ? 1.0f : preview_scale_factor; - float transform_matrix[3][3]; + float transform_matrix[4][4]; sequencer_image_crop_transform_matrix( seq, in, out, image_scale_factor, preview_scale_factor, transform_matrix); @@ -482,7 +526,14 @@ static void sequencer_preprocess_transform_crop( const eIMBInterpolationFilterMode filter = context->for_render ? IMB_FILTER_BILINEAR : IMB_FILTER_NEAREST; - IMB_transform(in, out, transform_matrix, &source_crop, filter); + IMB_transform(in, out, IMB_TRANSFORM_MODE_CROP_SRC, filter, transform_matrix, &source_crop); + + if (!seq_image_transform_transparency_gained(context, seq)) { + out->planes = in->planes; + } + else { + out->planes = R_IMF_PLANES_RGBA; + } } static void multibuf(ImBuf *ibuf, const float fmul) @@ -518,6 +569,10 @@ static void multibuf(ImBuf *ibuf, const float fmul) rt_float += 4; } } + + if (ELEM(ibuf->planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB) && fmul < 1.0f) { + ibuf->planes = R_IMF_PLANES_RGBA; + } } static ImBuf *input_preprocess(const SeqRenderData *context, @@ -629,7 +684,7 @@ typedef struct RenderEffectInitData { struct SeqEffectHandle *sh; const SeqRenderData *context; Sequence *seq; - float timeline_frame, facf0, facf1; + float timeline_frame, fac; ImBuf *ibuf1, *ibuf2, *ibuf3; ImBuf *out; @@ -639,7 +694,7 @@ typedef struct RenderEffectThread { struct SeqEffectHandle *sh; const SeqRenderData *context; Sequence *seq; - float timeline_frame, facf0, facf1; + float timeline_frame, fac; ImBuf *ibuf1, *ibuf2, *ibuf3; ImBuf *out; @@ -658,8 +713,7 @@ static void render_effect_execute_init_handle(void *handle_v, handle->context = init_data->context; handle->seq = init_data->seq; handle->timeline_frame = init_data->timeline_frame; - handle->facf0 = init_data->facf0; - handle->facf1 = init_data->facf1; + handle->fac = init_data->fac; handle->ibuf1 = init_data->ibuf1; handle->ibuf2 = init_data->ibuf2; handle->ibuf3 = init_data->ibuf3; @@ -676,8 +730,7 @@ static void *render_effect_execute_do_thread(void *thread_data_v) thread_data->sh->execute_slice(thread_data->context, thread_data->seq, thread_data->timeline_frame, - thread_data->facf0, - thread_data->facf1, + thread_data->fac, thread_data->ibuf1, thread_data->ibuf2, thread_data->ibuf3, @@ -692,8 +745,7 @@ ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, const SeqRenderData *context, Sequence *seq, float timeline_frame, - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -705,8 +757,7 @@ ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, init_data.context = context; init_data.seq = seq; init_data.timeline_frame = timeline_frame; - init_data.facf0 = facf0; - init_data.facf1 = facf1; + init_data.fac = fac; init_data.ibuf1 = ibuf1; init_data.ibuf2 = ibuf2; init_data.ibuf3 = ibuf3; @@ -727,7 +778,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, float timeline_frame) { Scene *scene = context->scene; - float fac, facf; + float fac; int early_out; int i; struct SeqEffectHandle sh = SEQ_effect_handle_get(seq); @@ -749,24 +800,23 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, } if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) { - sh.get_default_fac(seq, timeline_frame, &fac, &facf); - facf = fac; + sh.get_default_fac(seq, timeline_frame, &fac); } else { fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL); if (fcu) { - fac = facf = evaluate_fcurve(fcu, timeline_frame); + fac = evaluate_fcurve(fcu, timeline_frame); } else { - fac = facf = seq->effect_fader; + fac = seq->effect_fader; } } - early_out = sh.early_out(seq, fac, facf); + early_out = sh.early_out(seq, fac); switch (early_out) { case EARLY_NO_INPUT: - out = sh.execute(context, seq, timeline_frame, fac, facf, NULL, NULL, NULL); + out = sh.execute(context, seq, timeline_frame, fac, NULL, NULL, NULL); break; case EARLY_DO_EFFECT: for (i = 0; i < 3; i++) { @@ -785,10 +835,10 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, if (ibuf[0] && (ibuf[1] || SEQ_effect_get_num_inputs(seq->type) == 1)) { if (sh.multithreaded) { out = seq_render_effect_execute_threaded( - &sh, context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]); + &sh, context, seq, timeline_frame, fac, ibuf[0], ibuf[1], ibuf[2]); } else { - out = sh.execute(context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]); + out = sh.execute(context, seq, timeline_frame, fac, ibuf[0], ibuf[1], ibuf[2]); } } break; @@ -814,11 +864,13 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, return out; } + /** \} */ /* -------------------------------------------------------------------- */ /** \name Individual strip rendering functions * \{ */ + /** * Render individual view for multi-view or single (default view) for mono-view. */ @@ -1137,15 +1189,13 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, bool *r_is_proxy_image) { ImBuf *ibuf = NULL; - MovieClipUser user; + MovieClipUser user = *DNA_struct_default_get(MovieClipUser); IMB_Proxy_Size psize = SEQ_rendersize_to_proxysize(context->preview_render_size); if (!seq->clip) { return NULL; } - memset(&user, 0, sizeof(MovieClipUser)); - BKE_movieclip_user_set_frame(&user, frame_index + seq->anim_startofs + seq->clip->start_frame); user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL; @@ -1174,7 +1224,8 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context, /* Try to get a proxy image. */ ibuf = seq_get_movieclip_ibuf(seq, user); - if (ibuf != NULL && psize != IMB_PROXY_NONE) { + /* If clip doesn't use proxies, it will fallback to full size render of original file. */ + if (ibuf != NULL && psize != IMB_PROXY_NONE && BKE_movieclip_proxy_enabled(seq->clip)) { *r_is_proxy_image = true; } @@ -1560,11 +1611,13 @@ static ImBuf *do_render_strip_seqbase(const SeqRenderData *context, return ibuf; } + /** \} */ /* -------------------------------------------------------------------- */ -/** \name Strip stack rendering functions +/** \name Strip Stack Rendering Functions * \{ */ + static ImBuf *do_render_strip_uncached(const SeqRenderData *context, SeqRenderState *state, Sequence *seq, @@ -1715,8 +1768,8 @@ static bool seq_must_swap_input_in_blend_mode(Sequence *seq) static int seq_get_early_out_for_blend_mode(Sequence *seq) { struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq); - float facf = seq->blend_opacity / 100.0f; - int early_out = sh.early_out(seq, facf, facf); + float fac = seq->blend_opacity / 100.0f; + int early_out = sh.early_out(seq, fac); if (ELEM(early_out, EARLY_DO_EFFECT, EARLY_NO_INPUT)) { return early_out; @@ -1738,25 +1791,25 @@ static ImBuf *seq_render_strip_stack_apply_effect( { ImBuf *out; struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq); - float facf = seq->blend_opacity / 100.0f; + float fac = seq->blend_opacity / 100.0f; int swap_input = seq_must_swap_input_in_blend_mode(seq); if (swap_input) { if (sh.multithreaded) { out = seq_render_effect_execute_threaded( - &sh, context, seq, timeline_frame, facf, facf, ibuf2, ibuf1, NULL); + &sh, context, seq, timeline_frame, fac, ibuf2, ibuf1, NULL); } else { - out = sh.execute(context, seq, timeline_frame, facf, facf, ibuf2, ibuf1, NULL); + out = sh.execute(context, seq, timeline_frame, fac, ibuf2, ibuf1, NULL); } } else { if (sh.multithreaded) { out = seq_render_effect_execute_threaded( - &sh, context, seq, timeline_frame, facf, facf, ibuf1, ibuf2, NULL); + &sh, context, seq, timeline_frame, fac, ibuf1, ibuf2, NULL); } else { - out = sh.execute(context, seq, timeline_frame, facf, facf, ibuf1, ibuf2, NULL); + out = sh.execute(context, seq, timeline_frame, fac, ibuf1, ibuf2, NULL); } } @@ -1796,6 +1849,20 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, early_out = seq_get_early_out_for_blend_mode(seq); + /* Early out for alpha over. It requires image to be rendered, so it can't use + * `seq_get_early_out_for_blend_mode`. */ + if (out == NULL && seq->blend_mode == SEQ_TYPE_ALPHAOVER && seq->blend_opacity == 100.0f) { + ImBuf *test = seq_render_strip(context, state, seq, timeline_frame); + if (ELEM(test->planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB)) { + early_out = EARLY_USE_INPUT_2; + } + else { + early_out = EARLY_DO_EFFECT; + } + /* Free the image. It is stored in cache, so this doesn't affect performance. */ + IMB_freeImBuf(test); + } + switch (early_out) { case EARLY_NO_INPUT: case EARLY_USE_INPUT_2: @@ -1820,6 +1887,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, } break; } + if (out) { break; } @@ -1845,11 +1913,6 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, return out; } -/** - * \return The image buffer or NULL. - * - * \note The returned #ImBuf has its reference increased, free after usage! - */ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, int chanshown) { Scene *scene = context->scene; @@ -1882,6 +1945,8 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame, } seq_cache_free_temp_cache(context->scene, context->task_id, timeline_frame); + /* Make sure we only keep the `anim` data for strips that are in view. */ + SEQ_relations_free_all_anim_ibufs(context->scene, timeline_frame); if (count && !out) { BLI_mutex_lock(&seq_render_mutex); @@ -1958,7 +2023,6 @@ static ImBuf *seq_get_uncached_thumbnail(const SeqRenderData *context, return scaled_ibuf; } -/* Get cached thumbnails. */ ImBuf *SEQ_get_thumbnail( const SeqRenderData *context, Sequence *seq, float timeline_frame, rcti *crop, bool clipped) { @@ -1983,7 +2047,6 @@ ImBuf *SEQ_get_thumbnail( return ibuf_cropped; } -/* Render the series of thumbnails and store in cache. */ void SEQ_render_thumbnails(const SeqRenderData *context, Sequence *seq, Sequence *seq_orig, @@ -2028,8 +2091,6 @@ void SEQ_render_thumbnails(const SeqRenderData *context, } } -/* Get frame step for equally spaced thumbnails. These thumbnails should always be present in - * memory, so they can be used when zooming.*/ int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq) { const int content_len = (seq->enddisp - seq->startdisp - seq->startstill - seq->endstill); @@ -2037,12 +2098,11 @@ int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq) /* Arbitrary, but due to performance reasons should be as low as possible. */ const int thumbnails_base_set_count = min_ii(content_len / 100, 30); if (thumbnails_base_set_count <= 0) { - return 0; + return content_len; } return content_len / thumbnails_base_set_count; } -/* Render set of evenly spaced thumbnails that are drawn when zooming. */ void SEQ_render_thumbnails_base_set(const SeqRenderData *context, Sequence *seq, Sequence *seq_orig, diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h index a0cdf24d84b..eb1f71769a6 100644 --- a/source/blender/sequencer/intern/render.h +++ b/source/blender/sequencer/intern/render.h @@ -54,8 +54,7 @@ struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, const struct SeqRenderData *context, struct Sequence *seq, float timeline_frame, - float facf0, - float facf1, + float fac, struct ImBuf *ibuf1, struct ImBuf *ibuf2, struct ImBuf *ibuf3); diff --git a/source/blender/sequencer/intern/sequence_lookup.c b/source/blender/sequencer/intern/sequence_lookup.c index 25b42957d99..8d451d59e92 100644 --- a/source/blender/sequencer/intern/sequence_lookup.c +++ b/source/blender/sequencer/intern/sequence_lookup.c @@ -105,11 +105,6 @@ static void seq_sequence_lookup_update_if_needed(const struct Scene *scene, seq_sequence_lookup_rebuild(scene, lookup); } -/** - * Free lookup hash data. - * - * \param scene: scene that owns lookup hash - */ void SEQ_sequence_lookup_free(const Scene *scene) { BLI_assert(scene->ed); @@ -119,16 +114,6 @@ void SEQ_sequence_lookup_free(const Scene *scene) BLI_mutex_unlock(&lookup_lock); } -/** - * Find a sequence with a given name. - * If lookup hash doesn't exist, it will be created. If hash is tagged as invalid, it will be - * rebuilt. - * - * \param scene: scene that owns lookup hash - * \param key: Sequence name without SQ prefix (seq->name + 2) - * - * \return pointer to Sequence - */ Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key) { BLI_assert(scene->ed); @@ -140,12 +125,6 @@ Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key) return seq; } -/** - * Find a sequence with a given name. - * - * \param scene: scene that owns lookup hash - * \param tag: tag to set - */ void SEQ_sequence_lookup_tag(const Scene *scene, eSequenceLookupTag tag) { if (!scene->ed) { diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index 3478c2d4f97..1c7fe927381 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -34,10 +34,7 @@ #include "DNA_sound_types.h" #include "BLI_listbase.h" -#include "BLI_string.h" -#include "BKE_animsys.h" -#include "BKE_fcurve.h" #include "BKE_idprop.h" #include "BKE_lib_id.h" #include "BKE_sound.h" @@ -65,12 +62,19 @@ #include "sequencer.h" #include "utils.h" -static void seq_free_animdata(Scene *scene, Sequence *seq); - /* -------------------------------------------------------------------- */ /** \name Allocate / Free Functions * \{ */ +StripProxy *seq_strip_proxy_alloc(void) +{ + StripProxy *strip_proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy"); + strip_proxy->quality = 50; + strip_proxy->build_tc_flags = SEQ_PROXY_TC_ALL; + strip_proxy->tc = SEQ_PROXY_TC_RECORD_RUN; + return strip_proxy; +} + static Strip *seq_strip_alloc(int type) { Strip *strip = MEM_callocN(sizeof(Strip), "strip"); @@ -140,6 +144,7 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int seq->pitch = 1.0f; seq->scene_sound = NULL; seq->type = type; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->strip = seq_strip_alloc(type); seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format"); @@ -155,8 +160,7 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int static void seq_sequence_free_ex(Scene *scene, Sequence *seq, const bool do_cache, - const bool do_id_user, - const bool do_clean_animdata) + const bool do_id_user) { if (seq->strip) { seq_free_strip(seq->strip); @@ -190,11 +194,6 @@ static void seq_sequence_free_ex(Scene *scene, if (seq->scene_sound && ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) { BKE_sound_remove_scene_sound(scene, seq->scene_sound); } - - /* XXX This must not be done in BKE code. */ - if (do_clean_animdata) { - seq_free_animdata(scene, seq); - } } if (seq->prop) { @@ -222,26 +221,21 @@ static void seq_sequence_free_ex(Scene *scene, MEM_freeN(seq); } -void SEQ_sequence_free(Scene *scene, Sequence *seq, const bool do_clean_animdata) +void SEQ_sequence_free(Scene *scene, Sequence *seq) { - seq_sequence_free_ex(scene, seq, true, true, do_clean_animdata); + seq_sequence_free_ex(scene, seq, true, true); } -/* cache must be freed before calling this function - * since it leaves the seqbase in an invalid state */ -void seq_free_sequence_recurse(Scene *scene, - Sequence *seq, - const bool do_id_user, - const bool do_clean_animdata) +void seq_free_sequence_recurse(Scene *scene, Sequence *seq, const bool do_id_user) { Sequence *iseq, *iseq_next; for (iseq = seq->seqbase.first; iseq; iseq = iseq_next) { iseq_next = iseq->next; - seq_free_sequence_recurse(scene, iseq, do_id_user, do_clean_animdata); + seq_free_sequence_recurse(scene, iseq, do_id_user); } - seq_sequence_free_ex(scene, seq, false, do_id_user, do_clean_animdata); + seq_sequence_free_ex(scene, seq, false, do_id_user); } Editing *SEQ_editing_get(const Scene *scene) @@ -277,7 +271,7 @@ void SEQ_editing_free(Scene *scene, const bool do_id_user) /* handle cache freeing above */ LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &ed->seqbase) { - seq_free_sequence_recurse(scene, seq, do_id_user, false); + seq_free_sequence_recurse(scene, seq, do_id_user); } BLI_freelistN(&ed->metastack); @@ -388,12 +382,6 @@ int SEQ_tool_settings_pivot_point_get(Scene *scene) return tool_settings->pivot_point; } -/** - * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase - * - * \param ed: sequence editor data - * \return pointer to active seqbase. returns NULL if ed is NULL - */ ListBase *SEQ_active_seqbase_get(const Editing *ed) { if (ed == NULL) { @@ -403,24 +391,11 @@ ListBase *SEQ_active_seqbase_get(const Editing *ed) return ed->seqbasep; } -/** - * Set seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase - * - * \param ed: sequence editor data - * \param seqbase: ListBase with strips - */ void SEQ_seqbase_active_set(Editing *ed, ListBase *seqbase) { ed->seqbasep = seqbase; } -/** - * Create and initialize #MetaStack, append it to `ed->metastack` ListBase - * - * \param ed: sequence editor data - * \param seq_meta: meta strip - * \return pointer to created meta stack - */ MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta) { MetaStack *ms = MEM_mallocN(sizeof(MetaStack), "metastack"); @@ -431,26 +406,18 @@ MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta) return ms; } -/** - * Free #MetaStack and remove it from `ed->metastack` ListBase. - * - * \param ed: sequence editor data - * \param ms: meta stack - */ void SEQ_meta_stack_free(Editing *ed, MetaStack *ms) { BLI_remlink(&ed->metastack, ms); MEM_freeN(ms); } -/** - * Get #MetaStack that corresponds to current level that is being viewed - * - * \param ed: sequence editor data - * \return pointer to meta stack - */ MetaStack *SEQ_meta_stack_active_get(const Editing *ed) { + if (ed == NULL) { + return NULL; + } + return ed->metastack.last; } @@ -459,6 +426,7 @@ MetaStack *SEQ_meta_stack_active_get(const Editing *ed) /* -------------------------------------------------------------------- */ /** \name Duplicate Functions * \{ */ + static Sequence *seq_dupli(const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, @@ -650,118 +618,6 @@ bool SEQ_valid_strip_channel(Sequence *seq) return true; } -/* r_prefix + [" + escaped_name + "] + \0 */ -#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1) - -static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name) -{ - char name_esc[SEQ_NAME_MAXSTR * 2]; - - BLI_str_escape(name_esc, name, sizeof(name_esc)); - return BLI_snprintf_rlen( - str, SEQ_RNAPATH_MAXSTR, "sequence_editor.sequences_all[\"%s\"]", name_esc); -} - -/* XXX: hackish function needed for transforming strips! TODO: have some better solution. */ -void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs) -{ - char str[SEQ_RNAPATH_MAXSTR]; - size_t str_len; - FCurve *fcu; - - if (scene->adt == NULL || ofs == 0 || scene->adt->action == NULL) { - return; - } - - str_len = sequencer_rna_path_prefix(str, seq->name + 2); - - for (fcu = scene->adt->action->curves.first; fcu; fcu = fcu->next) { - if (STREQLEN(fcu->rna_path, str, str_len)) { - unsigned int i; - if (fcu->bezt) { - for (i = 0; i < fcu->totvert; i++) { - BezTriple *bezt = &fcu->bezt[i]; - bezt->vec[0][0] += ofs; - bezt->vec[1][0] += ofs; - bezt->vec[2][0] += ofs; - } - } - if (fcu->fpt) { - for (i = 0; i < fcu->totvert; i++) { - FPoint *fpt = &fcu->fpt[i]; - fpt->vec[0] += ofs; - } - } - } - } - - DEG_id_tag_update(&scene->adt->action->id, ID_RECALC_ANIMATION); -} - -void SEQ_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst) -{ - char str_from[SEQ_RNAPATH_MAXSTR]; - size_t str_from_len; - FCurve *fcu; - FCurve *fcu_last; - FCurve *fcu_cpy; - ListBase lb = {NULL, NULL}; - - if (scene->adt == NULL || scene->adt->action == NULL) { - return; - } - - str_from_len = sequencer_rna_path_prefix(str_from, name_src); - - fcu_last = scene->adt->action->curves.last; - - for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) { - if (STREQLEN(fcu->rna_path, str_from, str_from_len)) { - fcu_cpy = BKE_fcurve_copy(fcu); - BLI_addtail(&lb, fcu_cpy); - } - } - - /* notice validate is 0, keep this because the seq may not be added to the scene yet */ - BKE_animdata_fix_paths_rename( - &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name_src, name_dst, 0, 0, 0); - - /* add the original fcurves back */ - BLI_movelisttolist(&scene->adt->action->curves, &lb); -} - -/* XXX: hackish function needed to remove all fcurves belonging to a sequencer strip. */ -static void seq_free_animdata(Scene *scene, Sequence *seq) -{ - char str[SEQ_RNAPATH_MAXSTR]; - size_t str_len; - FCurve *fcu; - - if (scene->adt == NULL || scene->adt->action == NULL) { - return; - } - - str_len = sequencer_rna_path_prefix(str, seq->name + 2); - - fcu = scene->adt->action->curves.first; - - while (fcu) { - if (STREQLEN(fcu->rna_path, str, str_len)) { - FCurve *next_fcu = fcu->next; - - BLI_remlink(&scene->adt->action->curves, fcu); - BKE_fcurve_free(fcu); - - fcu = next_fcu; - } - else { - fcu = fcu->next; - } - } -} - -#undef SEQ_RNAPATH_MAXSTR - SequencerToolSettings *SEQ_tool_settings_copy(SequencerToolSettings *tool_settings) { SequencerToolSettings *tool_settings_copy = MEM_dupallocN(tool_settings); @@ -1069,10 +925,6 @@ static bool seq_update_seq_cb(Sequence *seq, void *user_data) return true; } -/* Evaluate parts of sequences which needs to be done as a part of a dependency graph evaluation. - * This does NOT include actual rendering of the strips, but rather makes them up-to-date for - * animation playback and makes them ready for the sequencer's rendering pipeline to render them. - */ void SEQ_eval_sequences(Depsgraph *depsgraph, Scene *scene, ListBase *seqbase) { DEG_debug_print_eval(depsgraph, __func__, scene->id.name, scene); diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h index e43535d14ee..2a82f966f02 100644 --- a/source/blender/sequencer/intern/sequencer.h +++ b/source/blender/sequencer/intern/sequencer.h @@ -29,11 +29,13 @@ extern "C" { struct Scene; struct Sequence; - -void seq_free_sequence_recurse(struct Scene *scene, - struct Sequence *seq, - const bool do_id_user, - const bool do_clean_animdata); +struct StripProxy; +/** + * Cache must be freed before calling this function + * since it leaves the seqbase in an invalid state. + */ +void seq_free_sequence_recurse(struct Scene *scene, struct Sequence *seq, bool do_id_user); +struct StripProxy *seq_strip_proxy_alloc(void); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c index c53aacddcfe..0788003fb12 100644 --- a/source/blender/sequencer/intern/sound.c +++ b/source/blender/sequencer/intern/sound.c @@ -31,6 +31,7 @@ #include "DNA_sound_types.h" #include "BLI_listbase.h" +#include "BLI_utildefines.h" #include "BKE_main.h" #include "BKE_scene.h" @@ -51,23 +52,27 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene, for (seq = seqbase->first; seq; seq = seq->next) { if (seq->type == SEQ_TYPE_META) { if (sequencer_refresh_sound_length_recursive(bmain, scene, &seq->seqbase)) { - SEQ_time_update_sequence(scene, seq); + SEQ_time_update_sequence(scene, seqbase, seq); changed = true; } } else if (seq->type == SEQ_TYPE_SOUND_RAM && seq->sound) { - const float length = BKE_sound_get_length(bmain, seq->sound); + SoundInfo info; + if (!BKE_sound_info_get(bmain, seq->sound, &info)) { + continue; + } + int old = seq->len; float fac; - seq->len = (int)ceil((double)length * FPS); + seq->len = MAX2(1, round((info.length - seq->sound->offset_time) * FPS)); fac = (float)seq->len / (float)old; old = seq->startofs; seq->startofs *= fac; seq->endofs *= fac; seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */ - SEQ_time_update_sequence(scene, seq); + SEQ_time_update_sequence(scene, seqbase, seq); changed = true; } } @@ -111,12 +116,8 @@ void SEQ_sound_update_bounds(Scene *scene, Sequence *seq) /* We have to take into account start frame of the sequence's scene! */ int startofs = seq->startofs + seq->anim_startofs + seq->scene->r.sfra; - BKE_sound_move_scene_sound(scene, - seq->scene_sound, - seq->startdisp, - seq->enddisp, - startofs, - seq->sound->offset_time); + BKE_sound_move_scene_sound( + scene, seq->scene_sound, seq->startdisp, seq->enddisp, startofs, 0.0); } } else { diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index aa3f7c92dd8..f342765eec9 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -70,16 +70,6 @@ #include "proxy.h" #include "utils.h" -/** - * Initialize common SeqLoadData members - * - * \param load_data: SeqLoadData to be initialized - * \param name: strip name (can be NULL) - * \param path: path to file that is used as strip input (can be NULL) - * \param start_frame: timeline frame where strip will be created - * \param channel: timeline channel where strip will be created - * - */ void SEQ_add_load_data_init(SeqLoadData *load_data, const char *name, const char *path, @@ -100,7 +90,7 @@ void SEQ_add_load_data_init(SeqLoadData *load_data, static void seq_add_generic_update(Scene *scene, ListBase *seqbase, Sequence *seq) { SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq); - SEQ_time_update_sequence_bounds(scene, seq); + SEQ_time_update_sequence(scene, seqbase, seq); SEQ_sort(seqbase); SEQ_relations_invalidate_cache_composite(scene, seq); } @@ -147,19 +137,10 @@ static void seq_add_set_view_transform(Scene *scene, Sequence *seq, SeqLoadData } } -/** - * Add scene strip. - * - * \param scene: Scene where strips will be added - * \param seqbase: ListBase where strips will be added - * \param load_data: SeqLoadData with information necessary to create strip - * \return created strip - */ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data) { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE); - seq->blend_mode = SEQ_TYPE_CROSS; seq->scene = load_data->scene; seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1; id_us_ensure_real((ID *)load_data->scene); @@ -168,19 +149,10 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat return seq; } -/** - * Add movieclip strip. - * - * \param scene: Scene where strips will be added - * \param seqbase: ListBase where strips will be added - * \param load_data: SeqLoadData with information necessary to create strip - * \return created strip - */ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data) { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP); - seq->blend_mode = SEQ_TYPE_CROSS; seq->clip = load_data->clip; seq->len = BKE_movieclip_get_duration(load_data->clip); id_us_ensure_real((ID *)load_data->clip); @@ -189,19 +161,10 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa return seq; } -/** - * Add mask strip. - * - * \param scene: Scene where strips will be added - * \param seqbase: ListBase where strips will be added - * \param load_data: SeqLoadData with information necessary to create strip - * \return created strip - */ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data) { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK); - seq->blend_mode = SEQ_TYPE_CROSS; seq->mask = load_data->mask; seq->len = BKE_mask_get_duration(load_data->mask); id_us_ensure_real((ID *)load_data->mask); @@ -210,14 +173,6 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData return seq; } -/** - * Add effect strip. - * - * \param scene: Scene where strips will be added - * \param seqbase: ListBase where strips will be added - * \param load_data: SeqLoadData with information necessary to create strip - * \return created strip - */ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData *load_data) { Sequence *seq = SEQ_sequence_alloc( @@ -230,16 +185,7 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa seq->seq2 = load_data->effect.seq2; seq->seq3 = load_data->effect.seq3; - if (seq->type == SEQ_TYPE_COLOR) { - seq->blend_mode = SEQ_TYPE_CROSS; - } - else if (seq->type == SEQ_TYPE_ADJUSTMENT) { - seq->blend_mode = SEQ_TYPE_CROSS; - } - else if (seq->type == SEQ_TYPE_TEXT) { - seq->blend_mode = SEQ_TYPE_ALPHAOVER; - } - else if (SEQ_effect_get_num_inputs(seq->type) == 1) { + if (SEQ_effect_get_num_inputs(seq->type) == 1) { seq->blend_mode = seq->seq1->blend_mode; } @@ -248,42 +194,23 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa SEQ_transform_set_right_handle_frame(seq, load_data->effect.end_frame); } - SEQ_relations_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs SEQ_time_update_sequence. */ seq_add_set_name(scene, seq, load_data); seq_add_generic_update(scene, seqbase, seq); return seq; } -/** - * Set directory used by image strip. - * - * \param seq: image strip to be changed - * \param path: directory path - */ void SEQ_add_image_set_directory(Sequence *seq, char *path) { BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir)); } -/** - * Set directory used by image strip. - * - * \param seq: image strip to be changed - * \param strip_frame: frame index of strip to be changed - * \param filename: image filename (only filename, not complete path) - */ void SEQ_add_image_load_file(Sequence *seq, size_t strip_frame, char *filename) { StripElem *se = SEQ_render_give_stripelem(seq, seq->start + strip_frame); BLI_strncpy(se->name, filename, sizeof(se->name)); } -/** - * Set image strip alpha mode - * - * \param seq: image strip to be changed - */ void SEQ_add_image_init_alpha_mode(Sequence *seq) { if (seq->strip && seq->strip->stripdata) { @@ -313,21 +240,10 @@ void SEQ_add_image_init_alpha_mode(Sequence *seq) } } -/** - * Add image strip. - * NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences - * - * \param main: Main reference - * \param scene: Scene where strips will be added - * \param seqbase: ListBase where strips will be added - * \param load_data: SeqLoadData with information necessary to create strip - * \return created strip - */ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data) { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE); - seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ seq->len = load_data->image.len; Strip *strip = seq->strip; strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem"); @@ -371,17 +287,6 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL } #ifdef WITH_AUDASPACE -/** - * Add sound strip. - * NOTE: Use SEQ_add_image_set_directory() and SEQ_add_image_load_file() to load image sequences - * - * \param main: Main reference - * \param scene: Scene where strips will be added - * \param seqbase: ListBase where strips will be added - * \param load_data: SeqLoadData with information necessary to create strip - * \return created strip - */ - Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, @@ -451,15 +356,6 @@ Sequence *SEQ_add_sound_strip(Main *UNUSED(bmain), } #endif // WITH_AUDASPACE -/** - * Add meta strip. - * - * \param scene: Scene where strips will be added - * \param seqbase: ListBase where strips will be added - * \param load_data: SeqLoadData with information necessary to create strip - * \return created strip - */ - Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_data) { /* Allocate sequence. */ @@ -472,20 +368,11 @@ Sequence *SEQ_add_meta_strip(Scene *scene, ListBase *seqbase, SeqLoadData *load_ /* Set frames start and length. */ seqm->start = load_data->start_frame; seqm->len = 1; - SEQ_time_update_sequence(scene, seqm); + SEQ_time_update_sequence(scene, seqbase, seqm); return seqm; } -/** - * Add movie strip. - * - * \param main: Main reference - * \param scene: Scene where strips will be added - * \param seqbase: ListBase where strips will be added - * \param load_data: SeqLoadData with information necessary to create strip - * \return created strip - */ Sequence *SEQ_add_movie_strip( Main *bmain, Scene *scene, ListBase *seqbase, SeqLoadData *load_data, double *r_start_offset) { @@ -588,8 +475,6 @@ Sequence *SEQ_add_movie_strip( } } - seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ - if (anim_arr[0] != NULL) { seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN); @@ -624,7 +509,6 @@ Sequence *SEQ_add_movie_strip( return seq; } -/* NOTE: caller should run SEQ_time_update_sequence(scene, seq) after. */ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const bool lock_range) { char path[FILE_MAX]; @@ -644,7 +528,9 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo if (lock_range) { /* keep so we don't have to move the actual start and end points (only the data) */ - SEQ_time_update_sequence_bounds(scene, seq); + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq); + SEQ_time_update_sequence(scene, seqbase, seq); prev_startdisp = seq->startdisp; prev_enddisp = seq->enddisp; } @@ -794,7 +680,9 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo SEQ_transform_fix_single_image_seq_offsets(seq); } - SEQ_time_update_sequence(scene, seq); + ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); + SEQ_time_update_sequence(scene, seqbase, seq); + SEQ_relations_invalidate_cache_raw(scene, seq); } void SEQ_add_movie_reload_if_needed(struct Main *bmain, diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index cfac243e68f..0479d3012fa 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -43,6 +43,7 @@ #include "utils.h" #include "SEQ_add.h" +#include "SEQ_animation.h" #include "SEQ_edit.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" @@ -175,7 +176,6 @@ static void sequencer_flag_users_for_removal(Scene *scene, ListBase *seqbase, Se } } -/* Flag seq and its users (effects) for removal. */ void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq) { if (seq == NULL || (seq->flag & SEQ_FLAG_DELETE) != 0) { @@ -193,7 +193,6 @@ void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq) sequencer_flag_users_for_removal(scene, seqbase, seq); } -/* Remove all flagged sequences, return true if sequence is removed. */ void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase) { LISTBASE_FOREACH_MUTABLE (Sequence *, seq, seqbase) { @@ -201,8 +200,9 @@ void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase) if (seq->type == SEQ_TYPE_META) { SEQ_edit_remove_flagged_sequences(scene, &seq->seqbase); } + SEQ_free_animdata(scene, seq); BLI_remlink(seqbase, seq); - SEQ_sequence_free(scene, seq, true); + SEQ_sequence_free(scene, seq); SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID); } } @@ -221,6 +221,24 @@ static bool seq_exists_in_seqbase(Sequence *seq, ListBase *seqbase) return false; } +bool SEQ_edit_move_strip_to_seqbase(Scene *scene, + ListBase *seqbase, + Sequence *seq, + ListBase *dst_seqbase) +{ + /* Move to meta. */ + BLI_remlink(seqbase, seq); + BLI_addtail(dst_seqbase, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + + /* Update meta. */ + if (SEQ_transform_test_overlap(dst_seqbase, seq)) { + SEQ_transform_seqbase_shuffle(dst_seqbase, seq, scene); + } + + return true; +} + bool SEQ_edit_move_strip_to_meta(Scene *scene, Sequence *src_seq, Sequence *dst_seqm, @@ -262,16 +280,7 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene, Sequence *seq; SEQ_ITERATOR_FOREACH (seq, collection) { /* Move to meta. */ - BLI_remlink(seqbase, seq); - BLI_addtail(&dst_seqm->seqbase, seq); - SEQ_relations_invalidate_cache_preprocessed(scene, seq); - - /* Update meta. */ - SEQ_time_update_meta_strip_range(scene, dst_seqm); - SEQ_time_update_sequence(scene, dst_seqm); - if (SEQ_transform_test_overlap(&dst_seqm->seqbase, seq)) { - SEQ_transform_seqbase_shuffle(&dst_seqm->seqbase, seq, scene); - } + SEQ_edit_move_strip_to_seqbase(scene, seqbase, seq, &dst_seqm->seqbase); } SEQ_collection_free(collection); @@ -359,6 +368,7 @@ static bool seq_edit_split_effect_intersect_check(const Sequence *seq, const int static void seq_edit_split_handle_strip_offsets(Main *bmain, Scene *scene, + ListBase *seqbase, Sequence *left_seq, Sequence *right_seq, const int timeline_frame, @@ -374,7 +384,7 @@ static void seq_edit_split_handle_strip_offsets(Main *bmain, SEQ_add_reload_new_file(bmain, scene, right_seq, false); break; } - SEQ_time_update_sequence(scene, right_seq); + SEQ_time_update_sequence(scene, seqbase, right_seq); } if (seq_edit_split_effect_intersect_check(left_seq, timeline_frame)) { @@ -387,7 +397,7 @@ static void seq_edit_split_handle_strip_offsets(Main *bmain, SEQ_add_reload_new_file(bmain, scene, left_seq, false); break; } - SEQ_time_update_sequence(scene, left_seq); + SEQ_time_update_sequence(scene, seqbase, left_seq); } } @@ -442,17 +452,6 @@ static bool seq_edit_split_operation_permitted_check(SeqCollection *strips, return true; } -/** - * Split Sequence at timeline_frame in two. - * - * \param bmain: Main in which Sequence is located - * \param scene: Scene in which Sequence is located - * \param seqbase: ListBase in which Sequence is located - * \param seq: Sequence to be split - * \param timeline_frame: frame at which seq is split. - * \param method: affects type of offset to be applied to resize Sequence - * \return The newly created sequence strip. This is always Sequence on right side. - */ Sequence *SEQ_edit_strip_split(Main *bmain, Scene *scene, ListBase *seqbase, @@ -492,54 +491,46 @@ Sequence *SEQ_edit_strip_split(Main *bmain, ListBase right_strips = {NULL, NULL}; SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0); - /* Split strips. */ Sequence *left_seq = left_strips.first; Sequence *right_seq = right_strips.first; - Sequence *return_seq = right_strips.first; + Sequence *return_seq = NULL; - /* Strips can't be tagged while in detached `seqbase`. Collect all strips which needs to be - * deleted and delay tagging until they are moved back to `seqbase` in `Editing`. */ - SeqCollection *strips_to_delete = SEQ_collection_create(__func__); + /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal, + * SEQ_time_update_sequence can fail to update meta strips and they can't be renamed. + * This is because these functions check all strips in `Editing` to manage relationships. */ + BLI_movelisttolist(seqbase, &left_strips); + BLI_movelisttolist(seqbase, &right_strips); + /* Split strips. */ while (left_seq && right_seq) { if (left_seq->startdisp >= timeline_frame) { - SEQ_collection_append_strip(left_seq, strips_to_delete); + SEQ_edit_flag_for_removal(scene, seqbase, left_seq); } if (right_seq->enddisp <= timeline_frame) { - SEQ_collection_append_strip(right_seq, strips_to_delete); + SEQ_edit_flag_for_removal(scene, seqbase, right_seq); + } + else if (return_seq == NULL) { + /* Store return value - pointer to strip that will not be removed. */ + return_seq = right_seq; } - seq_edit_split_handle_strip_offsets(bmain, scene, left_seq, right_seq, timeline_frame, method); + seq_edit_split_handle_strip_offsets( + bmain, scene, seqbase, left_seq, right_seq, timeline_frame, method); left_seq = left_seq->next; right_seq = right_seq->next; } - seq = right_strips.first; - BLI_movelisttolist(seqbase, &left_strips); - BLI_movelisttolist(seqbase, &right_strips); + SEQ_edit_remove_flagged_sequences(scene, seqbase); - for (; seq; seq = seq->next) { - SEQ_ensure_unique_name(seq, scene); + /* Rename duplicated strips. */ + Sequence *seq_rename = return_seq; + for (; seq_rename; seq_rename = seq_rename->next) { + SEQ_ensure_unique_name(seq_rename, scene); } - Sequence *seq_delete; - SEQ_ITERATOR_FOREACH (seq_delete, strips_to_delete) { - SEQ_edit_flag_for_removal(scene, seqbase, seq_delete); - } - SEQ_edit_remove_flagged_sequences(scene, seqbase); - SEQ_collection_free(strips_to_delete); return return_seq; } -/** - * Find gap after initial_frame and move strips on right side to close the gap - * - * \param scene: Scene in which strips are located - * \param seqbase: ListBase in which strips are located - * \param initial_frame: frame on timeline from where gaps are searched for - * \param remove_all_gaps: remove all gaps instead of one gap - * \return true if gap is removed, otherwise false - */ bool SEQ_edit_remove_gaps(Scene *scene, ListBase *seqbase, const int initial_frame, diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c index 9822bfe38f9..7e7fc9e6bf7 100644 --- a/source/blender/sequencer/intern/strip_relations.c +++ b/source/blender/sequencer/intern/strip_relations.c @@ -29,6 +29,7 @@ #include "BLI_ghash.h" #include "BLI_listbase.h" +#include "BLI_math.h" #include "BLI_session_uuid.h" #include "BKE_main.h" @@ -281,101 +282,44 @@ void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render) } } -static bool update_changed_seq_recurs( - Scene *scene, Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change) +static void sequencer_all_free_anim_ibufs(Editing *ed, + ListBase *seqbase, + int timeline_frame, + const int frame_range[2]) { - Sequence *subseq; - bool free_imbuf = false; - - /* recurse downwards to see if this seq depends on the changed seq */ - - if (seq == NULL) { - return false; - } - - if (seq == changed_seq) { - free_imbuf = true; - } - - for (subseq = seq->seqbase.first; subseq; subseq = subseq->next) { - if (update_changed_seq_recurs(scene, subseq, changed_seq, len_change, ibuf_change)) { - free_imbuf = true; - } - } - - if (seq->seq1) { - if (update_changed_seq_recurs(scene, seq->seq1, changed_seq, len_change, ibuf_change)) { - free_imbuf = true; - } - } - if (seq->seq2 && (seq->seq2 != seq->seq1)) { - if (update_changed_seq_recurs(scene, seq->seq2, changed_seq, len_change, ibuf_change)) { - free_imbuf = true; - } - } - if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) { - if (update_changed_seq_recurs(scene, seq->seq3, changed_seq, len_change, ibuf_change)) { - free_imbuf = true; + for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) { + if (!SEQ_time_strip_intersects_frame(seq, timeline_frame) || + !((frame_range[0] <= timeline_frame) && (frame_range[1] > timeline_frame))) { + SEQ_relations_sequence_free_anim(seq); } - } + if (seq->type == SEQ_TYPE_META) { + int meta_range[2]; - if (free_imbuf) { - if (ibuf_change) { - if (seq->type == SEQ_TYPE_MOVIE) { - SEQ_relations_sequence_free_anim(seq); + MetaStack *ms = SEQ_meta_stack_active_get(ed); + if (ms != NULL && ms->parseq == seq) { + meta_range[0] = -MAXFRAME; + meta_range[1] = MAXFRAME; } - else if (seq->type == SEQ_TYPE_SPEED) { - seq_effect_speed_rebuild_map(scene, seq); + else { + /* Limit frame range to meta strip. */ + meta_range[0] = max_ii(frame_range[0], seq->startdisp); + meta_range[1] = min_ii(frame_range[1], seq->enddisp); } - } - if (len_change) { - SEQ_time_update_sequence(scene, seq); + sequencer_all_free_anim_ibufs(ed, &seq->seqbase, timeline_frame, meta_range); } } - - return free_imbuf; -} - -void SEQ_relations_update_changed_seq_and_deps(Scene *scene, - Sequence *changed_seq, - int len_change, - int ibuf_change) -{ - Editing *ed = SEQ_editing_get(scene); - Sequence *seq; - - if (ed == NULL) { - return; - } - - for (seq = ed->seqbase.first; seq; seq = seq->next) { - update_changed_seq_recurs(scene, seq, changed_seq, len_change, ibuf_change); - } } -/* Unused */ -static void sequencer_all_free_anim_ibufs(ListBase *seqbase, int timeline_frame) -{ - for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) { - if (!SEQ_time_strip_intersects_frame(seq, timeline_frame)) { - SEQ_relations_sequence_free_anim(seq); - } - if (seq->type == SEQ_TYPE_META) { - sequencer_all_free_anim_ibufs(&seq->seqbase, timeline_frame); - } - } -} - -/* Unused */ void SEQ_relations_free_all_anim_ibufs(Scene *scene, int timeline_frame) { Editing *ed = SEQ_editing_get(scene); if (ed == NULL) { return; } - sequencer_all_free_anim_ibufs(&ed->seqbase, timeline_frame); - SEQ_cache_cleanup(scene); + + const int frame_range[2] = {-MAXFRAME, MAXFRAME}; + sequencer_all_free_anim_ibufs(ed, &ed->seqbase, timeline_frame, frame_range); } static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase) @@ -428,7 +372,6 @@ bool SEQ_relations_check_scene_recursion(Scene *scene, ReportList *reports) return false; } -/* Check if "seq_main" (indirectly) uses strip "seq". */ bool SEQ_relations_render_loop_check(Sequence *seq_main, Sequence *seq) { if (seq_main == NULL || seq == NULL) { @@ -455,7 +398,6 @@ bool SEQ_relations_render_loop_check(Sequence *seq_main, Sequence *seq) return false; } -/* Function to free imbuf and anim data on changes */ void SEQ_relations_sequence_free_anim(Sequence *seq) { while (seq->anims.last) { @@ -508,7 +450,6 @@ void SEQ_relations_check_uuids_unique_and_report(const Scene *scene) BLI_gset_free(used_uuids, NULL); } -/* Return immediate parent meta of sequence */ struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase, Sequence *meta, Sequence *seq) { Sequence *iseq; diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index fd6c0805c23..31ee20cb6ca 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -131,12 +131,17 @@ static void seq_update_sound_bounds_recursive_impl(Scene *scene, endofs = seq->start + seq->len - end; } + double offset_time = 0.0f; + if (seq->sound != NULL) { + offset_time = seq->sound->offset_time; + } + BKE_sound_move_scene_sound(scene, seq->scene_sound, seq->start + startofs, seq->start + seq->len - endofs, startofs + seq->anim_startofs, - seq->sound->offset_time); + offset_time); } } } @@ -148,7 +153,7 @@ void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq) scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq)); } -void SEQ_time_update_sequence_bounds(Scene *scene, Sequence *seq) +static void seq_time_update_sequence_bounds(Scene *scene, Sequence *seq) { if (seq->startofs && seq->startstill) { seq->startstill = 0; @@ -188,6 +193,10 @@ static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta) void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta) { + if (seq_meta == NULL) { + return; + } + seq_time_update_meta_strip(scene, seq_meta); /* Prevent meta-strip to move in timeline. */ @@ -195,7 +204,7 @@ void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta) SEQ_transform_set_right_handle_frame(seq_meta, seq_meta->enddisp); } -void SEQ_time_update_sequence(Scene *scene, Sequence *seq) +void SEQ_time_update_sequence(Scene *scene, ListBase *seqbase, Sequence *seq) { Sequence *seqm; @@ -203,7 +212,7 @@ void SEQ_time_update_sequence(Scene *scene, Sequence *seq) seqm = seq->seqbase.first; while (seqm) { if (seqm->seqbase.first) { - SEQ_time_update_sequence(scene, seqm); + SEQ_time_update_sequence(scene, &seqm->seqbase, seqm); } seqm = seqm->next; } @@ -241,21 +250,83 @@ void SEQ_time_update_sequence(Scene *scene, Sequence *seq) seq->len = seq->enddisp - seq->startdisp; } else { - SEQ_time_update_sequence_bounds(scene, seq); + seq_time_update_sequence_bounds(scene, seq); } } + else if (seq->type == SEQ_TYPE_META) { + seq_time_update_meta_strip(scene, seq); + } else { - if (seq->type == SEQ_TYPE_META) { - seq_time_update_meta_strip(scene, seq); + seq_time_update_sequence_bounds(scene, seq); + } + + Editing *ed = SEQ_editing_get(scene); + + /* Strip is inside meta strip */ + if (seqbase != &ed->seqbase) { + Sequence *meta = SEQ_get_meta_by_seqbase(&ed->seqbase, seqbase); + SEQ_time_update_meta_strip_range(scene, meta); + } + + seq_time_update_sequence_bounds(scene, seq); +} + +static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *changed_seq) +{ + Sequence *subseq; + bool do_update = false; + + /* recurse downwards to see if this seq depends on the changed seq */ + + if (seq == NULL) { + return false; + } + + if (seq == changed_seq) { + do_update = true; + } + + for (subseq = seq->seqbase.first; subseq; subseq = subseq->next) { + if (update_changed_seq_recurs(scene, subseq, changed_seq)) { + do_update = true; } + } - Editing *ed = SEQ_editing_get(scene); - MetaStack *ms = SEQ_meta_stack_active_get(ed); - if (ms != NULL) { - SEQ_time_update_meta_strip_range(scene, ms->parseq); + if (seq->seq1) { + if (update_changed_seq_recurs(scene, seq->seq1, changed_seq)) { + do_update = true; + } + } + if (seq->seq2 && (seq->seq2 != seq->seq1)) { + if (update_changed_seq_recurs(scene, seq->seq2, changed_seq)) { + do_update = true; + } + } + if (seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2)) { + if (update_changed_seq_recurs(scene, seq->seq3, changed_seq)) { + do_update = true; } + } + + if (do_update) { + ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); + SEQ_time_update_sequence(scene, seqbase, seq); + } + + return do_update; +} + +void SEQ_time_update_recursive(Scene *scene, Sequence *changed_seq) +{ + Editing *ed = SEQ_editing_get(scene); + Sequence *seq; + + if (ed == NULL) { + return; + } - SEQ_time_update_sequence_bounds(scene, seq); + for (seq = ed->seqbase.first; seq; seq = seq->next) { + update_changed_seq_recurs(scene, seq, changed_seq); } } @@ -367,20 +438,16 @@ float SEQ_time_sequence_get_fps(Scene *scene, Sequence *seq) return 0.0f; } -/** - * Define boundary rectangle of sequencer timeline and fill in rect data - * - * \param scene: Scene in which strips are located - * \param seqbase: ListBase in which strips are located - * \param rect: data structure describing rectangle, that will be filled in by this function - */ -void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect) +void SEQ_timeline_init_boundbox(const Scene *scene, rctf *rect) { rect->xmin = scene->r.sfra; rect->xmax = scene->r.efra + 1; rect->ymin = 0.0f; rect->ymax = 8.0f; +} +void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect) +{ if (seqbase == NULL) { return; } @@ -398,6 +465,12 @@ void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *re } } +void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect) +{ + SEQ_timeline_init_boundbox(scene, rect); + SEQ_timeline_expand_boundbox(seqbase, rect); +} + static bool strip_exists_at_frame(SeqCollection *all_strips, const int timeline_frame) { Sequence *seq; @@ -409,14 +482,6 @@ static bool strip_exists_at_frame(SeqCollection *all_strips, const int timeline_ return false; } -/** - * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info - * - * \param scene: Scene in which strips are located - * \param seqbase: ListBase in which strips are located - * \param initial_frame: frame on timeline from where gaps are searched for - * \param r_gap_info: data structure describing gap, that will be filled in by this function - */ void seq_time_gap_info_get(const Scene *scene, ListBase *seqbase, const int initial_frame, @@ -462,15 +527,6 @@ void seq_time_gap_info_get(const Scene *scene, } } -/** - * Test if strip intersects with timeline frame. - * NOTE: This checks if strip would be rendered at this frame. For rendering it is assumed, that - * timeline frame has width of 1 frame and therefore ends at timeline_frame + 1 - * - * \param seq: Sequence to be checked - * \param timeline_frame: absolute frame position - * \return true if strip intersects with timeline frame. - */ bool SEQ_time_strip_intersects_frame(const Sequence *seq, const int timeline_frame) { return (seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame); diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h index ca9a935bc96..4fe8d03e641 100644 --- a/source/blender/sequencer/intern/strip_time.h +++ b/source/blender/sequencer/intern/strip_time.h @@ -40,9 +40,18 @@ typedef struct GapInfo { int gap_length; /* Length of the gap. */ bool gap_exists; /* False if there are no gaps. */ } GapInfo; + +/** + * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info + * + * \param scene: Scene in which strips are located. + * \param seqbase: ListBase in which strips are located. + * \param initial_frame: frame on timeline from where gaps are searched for. + * \param r_gap_info: data structure describing gap, that will be filled in by this function. + */ void seq_time_gap_info_get(const struct Scene *scene, struct ListBase *seqbase, - const int initial_frame, + int initial_frame, struct GapInfo *r_gap_info); #ifdef __cplusplus diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index 54ca4ef487f..432fc1c166f 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -33,6 +33,7 @@ #include "BKE_scene.h" #include "BKE_sound.h" +#include "SEQ_animation.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" #include "SEQ_relations.h" @@ -86,8 +87,6 @@ void SEQ_transform_set_right_handle_frame(Sequence *seq, int val) } } -/* used so we can do a quick check for single image seq - * since they work a bit differently to normal image seq's (during transform) */ bool SEQ_transform_single_image_check(Sequence *seq) { return ((seq->len == 1) && @@ -95,7 +94,6 @@ bool SEQ_transform_single_image_check(Sequence *seq) ((seq->type & SEQ_TYPE_EFFECT) && SEQ_effect_get_num_inputs(seq->type) == 0))); } -/* check if the selected seq's reference unselected seq's */ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase) { Sequence *seq; @@ -137,10 +135,6 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase) return true; } -/** - * Use to impose limits when dragging/extending - so impossible situations don't happen. - * Can't use the #SEQ_LEFTSEL and #SEQ_LEFTSEL directly because the strip may be in a meta-strip. - */ void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag) { if (leftflag) { @@ -253,10 +247,10 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt SEQ_transform_set_right_handle_frame(seq, seq->enddisp + delta); } - SEQ_time_update_sequence(evil_scene, seq); + ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(evil_scene)); + SEQ_time_update_sequence(evil_scene, seqbase, seq); } -/* return 0 if there weren't enough space */ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep, Sequence *test, Scene *evil_scene, @@ -266,7 +260,7 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep, BLI_assert(ELEM(channel_delta, -1, 1)); test->machine += channel_delta; - SEQ_time_update_sequence(evil_scene, test); + SEQ_time_update_sequence(evil_scene, seqbasep, test); while (SEQ_transform_test_overlap(seqbasep, test)) { if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) { break; @@ -275,7 +269,7 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep, test->machine += channel_delta; /* XXX: I don't think this is needed since were only moving vertically, Campbell. */ - SEQ_time_update_sequence(evil_scene, test); + SEQ_time_update_sequence(evil_scene, seqbasep, test); } if (!SEQ_valid_strip_channel(test)) { @@ -295,7 +289,7 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep, new_frame = new_frame + (test->start - test->startdisp); /* adjust by the startdisp */ SEQ_transform_translate_sequence(evil_scene, test, new_frame - test->start); - SEQ_time_update_sequence(evil_scene, test); + SEQ_time_update_sequence(evil_scene, seqbasep, test); return false; } @@ -355,7 +349,7 @@ static int shuffle_seq_time_offset(SeqCollection *strips_to_shuffle, } SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) { - SEQ_time_update_sequence_bounds(scene, seq); /* corrects dummy startdisp/enddisp values */ + SEQ_time_update_sequence(scene, seqbasep, seq); /* corrects dummy startdisp/enddisp values */ } return tot_ofs; @@ -392,14 +386,6 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle, return offset ? false : true; } -/** - * Move strips and markers (if not locked) that start after timeline_frame by delta frames - * - * \param scene: Scene in which strips are located - * \param seqbase: ListBase in which strips are located - * \param delta: offset in frames to be applied - * \param timeline_frame: frame on timeline from where strips are moved - */ void SEQ_transform_offset_after_frame(Scene *scene, ListBase *seqbase, const int delta, @@ -408,7 +394,7 @@ void SEQ_transform_offset_after_frame(Scene *scene, LISTBASE_FOREACH (Sequence *, seq, seqbase) { if (seq->startdisp >= timeline_frame) { SEQ_transform_translate_sequence(scene, seq, delta); - SEQ_time_update_sequence(scene, seq); + SEQ_time_update_sequence(scene, seqbase, seq); SEQ_relations_invalidate_cache_preprocessed(scene, seq); } } @@ -435,14 +421,6 @@ void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2 } } -/** - * Get strip transform origin offset from image center - * Note: This function does not apply axis mirror. - * - * \param scene: Scene in which strips are located - * \param seq: Sequence to calculate image transform origin - * \param r_origin: return value - */ void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene, const Sequence *seq, float r_origin[2]) @@ -462,60 +440,89 @@ void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene, r_origin[0] = (image_size[0] * transform->origin[0]) - (image_size[0] * 0.5f) + transform->xofs; r_origin[1] = (image_size[1] * transform->origin[1]) - (image_size[1] * 0.5f) + transform->yofs; + const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f}; float mirror[2]; SEQ_image_transform_mirror_factor_get(seq, mirror); mul_v2_v2(r_origin, mirror); + mul_v2_v2(r_origin, viewport_pixel_aspect); } -/** - * Get strip transform origin offset from image center - * - * \param scene: Scene in which strips are located - * \param seq: Sequence to calculate image transform origin - * \param r_origin: return value - */ - -void SEQ_image_transform_final_quad_get(const Scene *scene, - const Sequence *seq, - float r_quad[4][2]) +static void seq_image_transform_quad_get_ex(const Scene *scene, + const Sequence *seq, + bool apply_rotation, + float r_quad[4][2]) { StripTransform *transform = seq->strip->transform; StripCrop *crop = seq->strip->crop; - int imgage_size[2] = {scene->r.xsch, scene->r.ysch}; + int image_size[2] = {scene->r.xsch, scene->r.ysch}; if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) { - imgage_size[0] = seq->strip->stripdata->orig_width; - imgage_size[1] = seq->strip->stripdata->orig_height; + image_size[0] = seq->strip->stripdata->orig_width; + image_size[1] = seq->strip->stripdata->orig_height; + } + + float transform_matrix[4][4]; + float rotation_matrix[3][3]; + axis_angle_to_mat3_single(rotation_matrix, 'Z', apply_rotation ? transform->rotation : 0.0f); + loc_rot_size_to_mat4(transform_matrix, + (const float[]){transform->xofs, transform->yofs, 0.0f}, + rotation_matrix, + (const float[]){transform->scale_x, transform->scale_y, 1.0f}); + const float origin[2] = {image_size[0] * transform->origin[0], + image_size[1] * transform->origin[1]}; + const float pivot[3] = {origin[0] - (image_size[0] / 2), origin[1] - (image_size[1] / 2), 0.0f}; + transform_pivot_set_m4(transform_matrix, pivot); + + float quad_temp[4][3]; + for (int i = 0; i < 4; i++) { + zero_v2(quad_temp[i]); } - float transform_matrix[3][3]; - loc_rot_size_to_mat3(transform_matrix, - (const float[]){transform->xofs, transform->yofs}, - transform->rotation, - (const float[]){transform->scale_x, transform->scale_y}); - const float origin[2] = {imgage_size[0] * transform->origin[0], - imgage_size[1] * transform->origin[1]}; - const float pivot[2] = {origin[0] - (imgage_size[0] / 2), origin[1] - (imgage_size[1] / 2)}; - transform_pivot_set_m3(transform_matrix, pivot); - - r_quad[0][0] = (imgage_size[0] / 2) - crop->right; - r_quad[0][1] = (imgage_size[1] / 2) - crop->top; - r_quad[1][0] = (imgage_size[0] / 2) - crop->right; - r_quad[1][1] = (-imgage_size[1] / 2) + crop->bottom; - r_quad[2][0] = (-imgage_size[0] / 2) + crop->left; - r_quad[2][1] = (-imgage_size[1] / 2) + crop->bottom; - r_quad[3][0] = (-imgage_size[0] / 2) + crop->left; - r_quad[3][1] = (imgage_size[1] / 2) - crop->top; - - mul_m3_v2(transform_matrix, r_quad[0]); - mul_m3_v2(transform_matrix, r_quad[1]); - mul_m3_v2(transform_matrix, r_quad[2]); - mul_m3_v2(transform_matrix, r_quad[3]); + quad_temp[0][0] = (image_size[0] / 2) - crop->right; + quad_temp[0][1] = (image_size[1] / 2) - crop->top; + quad_temp[1][0] = (image_size[0] / 2) - crop->right; + quad_temp[1][1] = (-image_size[1] / 2) + crop->bottom; + quad_temp[2][0] = (-image_size[0] / 2) + crop->left; + quad_temp[2][1] = (-image_size[1] / 2) + crop->bottom; + quad_temp[3][0] = (-image_size[0] / 2) + crop->left; + quad_temp[3][1] = (image_size[1] / 2) - crop->top; float mirror[2]; SEQ_image_transform_mirror_factor_get(seq, mirror); - mul_v2_v2(r_quad[0], mirror); - mul_v2_v2(r_quad[1], mirror); - mul_v2_v2(r_quad[2], mirror); - mul_v2_v2(r_quad[3], mirror); + + const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f}; + + for (int i = 0; i < 4; i++) { + mul_m4_v3(transform_matrix, quad_temp[i]); + mul_v2_v2(quad_temp[i], mirror); + mul_v2_v2(quad_temp[i], viewport_pixel_aspect); + copy_v2_v2(r_quad[i], quad_temp[i]); + } +} + +void SEQ_image_transform_quad_get(const Scene *scene, + const Sequence *seq, + bool apply_rotation, + float r_quad[4][2]) +{ + seq_image_transform_quad_get_ex(scene, seq, apply_rotation, r_quad); +} + +void SEQ_image_transform_final_quad_get(const Scene *scene, + const Sequence *seq, + float r_quad[4][2]) +{ + seq_image_transform_quad_get_ex(scene, seq, true, r_quad); +} + +void SEQ_image_preview_unit_to_px(const Scene *scene, const float co_src[2], float co_dst[2]) +{ + co_dst[0] = co_src[0] * scene->r.xsch; + co_dst[1] = co_src[1] * scene->r.ysch; +} + +void SEQ_image_preview_unit_from_px(const Scene *scene, const float co_src[2], float co_dst[2]) +{ + co_dst[0] = co_src[0] / scene->r.xsch; + co_dst[1] = co_src[1] / scene->r.ysch; } diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 8421aab5217..140aa2d67c5 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -35,10 +35,12 @@ #include "BLI_blenlib.h" +#include "BKE_animsys.h" #include "BKE_image.h" #include "BKE_main.h" #include "BKE_scene.h" +#include "SEQ_animation.h" #include "SEQ_edit.h" #include "SEQ_iterator.h" #include "SEQ_relations.h" @@ -55,13 +57,6 @@ #include "proxy.h" #include "utils.h" -/** - * Sort strips in provided seqbase. Effect strips are trailing the list and they are sorted by - * channel position as well. - * This is important for SEQ_time_update_sequence to work properly - * - * \param seqbase: ListBase with strips - */ void SEQ_sort(ListBase *seqbase) { if (seqbase == NULL) { @@ -432,7 +427,6 @@ const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame) return best_seq; } -/* in cases where we don't know the sequence's listbase */ ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq) { Sequence *iseq; @@ -450,10 +444,21 @@ ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq) return NULL; } -/** - * Only use as last resort when the StripElem is available but no the Sequence. - * (needed for RNA) - */ +Sequence *SEQ_get_meta_by_seqbase(ListBase *seqbase_main, ListBase *meta_seqbase) +{ + SeqCollection *strips = SEQ_query_all_strips_recursive(seqbase_main); + + Sequence *seq = NULL; + SEQ_ITERATOR_FOREACH (seq, strips) { + if (seq->type == SEQ_TYPE_META && &seq->seqbase == meta_seqbase) { + break; + } + } + + SEQ_collection_free(strips); + return seq; +} + Sequence *SEQ_sequence_from_strip_elem(ListBase *seqbase, StripElem *se) { Sequence *iseq; @@ -510,10 +515,10 @@ void SEQ_alpha_mode_from_file_extension(Sequence *seq) } } -/* called on draw, needs to be fast, - * we could cache and use a flag if we want to make checks for file paths resolving for eg. */ bool SEQ_sequence_has_source(const Sequence *seq) { + /* Called on draw, needs to be fast, + * we could cache and use a flag if we want to make checks for file paths resolving for eg. */ switch (seq->type) { case SEQ_TYPE_MASK: return (seq->mask != NULL); @@ -574,20 +579,14 @@ void SEQ_set_scale_to_fit(const Sequence *seq, } } -/** - * Ensure, that provided Sequence has unique name. If animation data exists for this Sequence, it - * will be duplicated and mapped onto new name - * - * \param seq: Sequence which name will be ensured to be unique - * \param scene: Scene in which name must be unique - */ void SEQ_ensure_unique_name(Sequence *seq, Scene *scene) { char name[SEQ_NAME_MAXSTR]; BLI_strncpy_utf8(name, seq->name + 2, sizeof(name)); SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq); - SEQ_dupe_animdata(scene, name, seq->name + 2); + BKE_animdata_fix_paths_rename( + &scene->id, scene->adt, NULL, "sequence_editor.sequences_all", name, seq->name + 2, 0, 0, 0); if (seq->type == SEQ_TYPE_META) { LISTBASE_FOREACH (Sequence *, seq_child, &seq->seqbase) { diff --git a/source/blender/sequencer/intern/utils.h b/source/blender/sequencer/intern/utils.h index 7aee7d229c9..b5aa66804c6 100644 --- a/source/blender/sequencer/intern/utils.h +++ b/source/blender/sequencer/intern/utils.h @@ -27,10 +27,13 @@ extern "C" { #endif +struct ListBase; struct Scene; bool sequencer_seq_generates_image(struct Sequence *seq); void seq_open_anim_file(struct Scene *scene, struct Sequence *seq, bool openfile); +Sequence *SEQ_get_meta_by_seqbase(struct ListBase *seqbase_main, struct ListBase *meta_seqbase); + #ifdef __cplusplus } #endif |