Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h8
-rw-r--r--source/blender/blenlib/intern/math_matrix.c53
-rw-r--r--source/blender/blenloader/intern/versioning_290.c169
-rw-r--r--source/blender/imbuf/IMB_imbuf.h2
-rw-r--r--source/blender/imbuf/intern/rectop.c77
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h7
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c69
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h2
-rw-r--r--source/blender/sequencer/intern/sequencer.c296
10 files changed, 533 insertions, 152 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 59e6b5629f0..289caae7f94 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 1
+#define BLENDER_FILE_SUBVERSION 2
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 9f6c56d698a..d971f48c4cf 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -322,9 +322,13 @@ void mat4_to_size(float size[3], const float M[4][4]);
void mat4_to_size_fix_shear(float size[3], const float M[4][4]);
+void translate_m3(float mat[3][3], float tx, float ty);
void translate_m4(float mat[4][4], float tx, float ty, float tz);
+void rotate_m3(float mat[3][3], const float angle);
void rotate_m4(float mat[4][4], const char axis, const float angle);
+void rescale_m3(float mat[3][3], const float scale[2]);
void rescale_m4(float mat[4][4], const float scale[3]);
+void transform_pivot_set_m3(float mat[3][3], const float pivot[2]);
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]);
@@ -334,6 +338,10 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat
void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]);
+void loc_rot_size_to_mat3(float R[3][3],
+ const float loc[2],
+ const float angle,
+ const float size[2]);
void loc_rot_size_to_mat4(float R[4][4],
const float loc[3],
const float rot[3][3],
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index cf6945529f2..9769d2baf9b 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -2223,6 +2223,12 @@ void scale_m4_fl(float R[4][4], float scale)
R[3][0] = R[3][1] = R[3][2] = 0.0;
}
+void translate_m3(float mat[3][3], float tx, float ty)
+{
+ mat[2][0] += (tx * mat[0][0] + ty * mat[1][0]);
+ mat[2][1] += (tx * mat[0][1] + ty * mat[1][1]);
+}
+
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
{
mat[3][0] += (Tx * mat[0][0] + Ty * mat[1][0] + Tz * mat[2][0]);
@@ -2230,6 +2236,18 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
mat[3][2] += (Tx * mat[0][2] + Ty * mat[1][2] + Tz * mat[2][2]);
}
+void rotate_m3(float mat[3][3], const float angle)
+{
+ const float angle_cos = cosf(angle);
+ const float angle_sin = sinf(angle);
+
+ for (int col = 0; col < 3; col++) {
+ float temp = angle_cos * mat[0][col] + angle_sin * mat[1][col];
+ mat[1][col] = -angle_sin * mat[0][col] + angle_cos * mat[1][col];
+ mat[0][col] = temp;
+ }
+}
+
/* TODO: enum for axis? */
/**
* Rotate a matrix in-place.
@@ -2275,6 +2293,12 @@ void rotate_m4(float mat[4][4], const char axis, const float angle)
}
}
+void rescale_m3(float mat[3][3], const float scale[2])
+{
+ mul_v3_fl(mat[0], scale[0]);
+ mul_v3_fl(mat[1], scale[1]);
+}
+
/** Scale a matrix in-place. */
void rescale_m4(float mat[4][4], const float scale[3])
{
@@ -2305,6 +2329,20 @@ void transform_pivot_set_m4(float mat[4][4], const float pivot[3])
mul_m4_m4m4(mat, mat, tmat);
}
+void transform_pivot_set_m3(float mat[3][3], const float pivot[2])
+{
+ float tmat[3][3];
+
+ unit_m3(tmat);
+
+ copy_v2_v2(tmat[2], pivot);
+ mul_m3_m3m3(mat, tmat, mat);
+
+ /* invert the matrix */
+ negate_v2(tmat[2]);
+ mul_m3_m3m3(mat, mat, tmat);
+}
+
void blend_m3_m3m3(float out[3][3],
const float dst[3][3],
const float src[3][3],
@@ -2485,6 +2523,21 @@ bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
}
/**
+ * Make a 3x3 matrix out of 3 transform components.
+ * Matrices are made in the order: `loc * rot * scale`
+ */
+void loc_rot_size_to_mat3(float R[3][3],
+ const float loc[2],
+ const float angle,
+ const float size[2])
+{
+ unit_m3(R);
+ translate_m3(R, loc[0], loc[1]);
+ rotate_m3(R, angle);
+ rescale_m3(R, size);
+}
+
+/**
* Make a 4x4 matrix out of 3 transform components.
* Matrices are made in the order: `scale * rot * loc`
*/
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 37987b2c31d..d3d6eeeb3dd 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -44,12 +44,14 @@
#include "DNA_rigidbody_types.h"
#include "DNA_screen_types.h"
#include "DNA_shader_fx_types.h"
+#include "DNA_space_types.h"
#include "DNA_tracking_types.h"
#include "DNA_workspace_types.h"
#include "BKE_animsys.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
+#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -59,12 +61,154 @@
#include "MEM_guardedalloc.h"
+#include "RNA_access.h"
+
+#include "SEQ_sequencer.h"
+
#include "BLO_readfile.h"
#include "readfile.h"
/* Make preferences read-only, use versioning_userdef.c. */
#define U (*((const UserDef *)&U))
+/* image_size is width or height depending what RNA property is converted - X or Y. */
+static void seq_convert_transform_animation(const Scene *scene,
+ const char *path,
+ const int image_size)
+{
+ if (scene->adt == NULL || scene->adt->action == NULL) {
+ return;
+ }
+
+ FCurve *fcu = BKE_fcurve_find(&scene->adt->action->curves, path, 0);
+ if (fcu != NULL && !BKE_fcurve_is_empty(fcu)) {
+ BezTriple *bezt = fcu->bezt;
+ for (int i = 0; i < fcu->totvert; i++, bezt++) {
+ /* Same math as with old_image_center_*, but simplified. */
+ bezt->vec[1][1] = image_size / 2 + bezt->vec[1][1] - scene->r.xsch / 2;
+ }
+ }
+}
+
+static void seq_convert_transform_crop(const Scene *scene,
+ Sequence *seq,
+ const eSpaceSeq_Proxy_RenderSize render_size)
+{
+ StripCrop *c = seq->strip->crop;
+ StripTransform *t = seq->strip->transform;
+ int old_image_center_x = scene->r.xsch / 2;
+ int old_image_center_y = scene->r.ysch / 2;
+ int image_size_x = scene->r.xsch;
+ int image_size_y = scene->r.ysch;
+
+ /* Hardcoded legacy bit-flags which has been removed. */
+ const uint32_t use_transform_flag = (1 << 16);
+ const uint32_t use_crop_flag = (1 << 17);
+
+ const StripElem *s_elem = BKE_sequencer_give_stripelem(seq, seq->start);
+ if (s_elem != NULL) {
+ image_size_x = s_elem->orig_width;
+ image_size_y = s_elem->orig_height;
+
+ if (SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(render_size))) {
+ image_size_x /= BKE_sequencer_rendersize_to_scale_factor(render_size);
+ image_size_y /= BKE_sequencer_rendersize_to_scale_factor(render_size);
+ }
+ }
+
+ /* Default scale. */
+ if (t->scale_x == 0.0f && t->scale_y == 0.0f) {
+ t->scale_x = 1.0f;
+ t->scale_y = 1.0f;
+ }
+
+ /* Clear crop if it was unused. This must happen before converting values. */
+ if ((seq->flag & use_crop_flag) == 0) {
+ c->bottom = c->top = c->left = c->right = 0;
+ }
+
+ if ((seq->flag & use_transform_flag) == 0) {
+ t->xofs = t->yofs = 0;
+
+ /* Reverse scale to fit for strips not using offset. */
+ float project_aspect = (float)scene->r.xsch / (float)scene->r.ysch;
+ float image_aspect = (float)image_size_x / (float)image_size_y;
+ if (project_aspect > image_aspect) {
+ t->scale_x = project_aspect / image_aspect;
+ }
+ else {
+ t->scale_y = image_aspect / project_aspect;
+ }
+ }
+
+ if ((seq->flag & use_crop_flag) != 0 && (seq->flag & use_transform_flag) == 0) {
+ /* Calculate image offset. */
+ float s_x = scene->r.xsch / image_size_x;
+ float s_y = scene->r.ysch / image_size_y;
+ old_image_center_x += c->right * s_x - c->left * s_x;
+ old_image_center_y += c->top * s_y - c->bottom * s_y;
+
+ /* Convert crop to scale. */
+ int cropped_image_size_x = image_size_x - c->right - c->left;
+ int cropped_image_size_y = image_size_y - c->top - c->bottom;
+ c->bottom = c->top = c->left = c->right = 0;
+ t->scale_x *= (float)image_size_x / (float)cropped_image_size_x;
+ t->scale_y *= (float)image_size_y / (float)cropped_image_size_y;
+ }
+
+ if ((seq->flag & use_transform_flag) != 0) {
+ /* Convert image offset. */
+ old_image_center_x = image_size_x / 2 - c->left + t->xofs;
+ old_image_center_y = image_size_y / 2 - c->bottom + t->yofs;
+
+ /* Preserve original image size. */
+ t->scale_x = t->scale_y = MAX2((float)image_size_x / (float)scene->r.xsch,
+ (float)image_size_y / (float)scene->r.ysch);
+
+ /* Convert crop. */
+ if ((seq->flag & use_crop_flag) != 0) {
+ c->top /= t->scale_x;
+ c->bottom /= t->scale_x;
+ c->left /= t->scale_x;
+ c->right /= t->scale_x;
+ }
+ }
+
+ t->xofs = old_image_center_x - scene->r.xsch / 2;
+ t->yofs = old_image_center_y - scene->r.ysch / 2;
+
+ /* Convert offset animation, but only if crop is not used. */
+ if ((seq->flag & use_transform_flag) != 0 && (seq->flag & use_crop_flag) == 0) {
+ char name_esc[(sizeof(seq->name) - 2) * 2], *path;
+ BLI_strescape(name_esc, seq->name + 2, sizeof(name_esc));
+
+ path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_x", name_esc);
+ seq_convert_transform_animation(scene, path, image_size_x);
+ MEM_freeN(path);
+ path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_y", name_esc);
+ seq_convert_transform_animation(scene, path, image_size_y);
+ MEM_freeN(path);
+ }
+
+ seq->flag &= ~use_transform_flag;
+ seq->flag &= ~use_crop_flag;
+}
+
+static void seq_convert_transform_crop_lb(const Scene *scene,
+ const ListBase *lb,
+ const eSpaceSeq_Proxy_RenderSize render_size)
+{
+
+ LISTBASE_FOREACH (Sequence *, seq, lb) {
+ if (seq->type != SEQ_TYPE_SOUND_RAM) {
+ seq_convert_transform_crop(scene, seq, render_size);
+ }
+ if (seq->type == SEQ_TYPE_META) {
+ seq_convert_transform_crop_lb(scene, &seq->seqbase, render_size);
+ }
+ }
+}
+
void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
{
if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) {
@@ -292,6 +436,31 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
}
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 292, 2)) {
+
+ eSpaceSeq_Proxy_RenderSize render_size = 100;
+
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ switch (sl->spacetype) {
+ case SPACE_SEQ: {
+ SpaceSeq *sseq = (SpaceSeq *)sl;
+ render_size = sseq->render_size;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->ed != NULL) {
+ seq_convert_transform_crop_lb(scene, &scene->ed->seqbase, render_size);
+ }
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 839b0b12b83..2f848b5be08 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -684,6 +684,8 @@ void IMB_rectfill_area(struct ImBuf *ibuf,
int x2,
int y2,
struct ColorManagedDisplay *display);
+void IMB_rectfill_area_replace(
+ const struct ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2);
void IMB_rectfill_alpha(struct ImBuf *ibuf, const float value);
/* This should not be here, really,
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 8b4f33bb306..8e348ead756 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -1069,8 +1069,11 @@ void IMB_rectblend_threaded(ImBuf *dbuf,
}
}
-/* fill */
-
+/**
+ * Replace pixels of entire image with solid color.
+ * \param ibuf an image to be filled with color. It must be 4 channel image.
+ * \param col RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
+ */
void IMB_rectfill(ImBuf *drect, const float col[4])
{
int num;
@@ -1103,6 +1106,61 @@ void IMB_rectfill(ImBuf *drect, const float col[4])
}
}
+/**
+ * Replace pixels of image area with solid color.
+ * \param ibuf an image to be filled with color. It must be 4 channel image.
+ * \param col RGBA color, which is assigned directly to both byte (via scaling) and float buffers.
+ * \param x1, y1, x2, y2 (x1, y1) defines starting point of the rectangular area to be filled,
+ * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
+ * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
+ * order the area between x1 and x2, and y1 and y2 is filled.
+ */
+void IMB_rectfill_area_replace(
+ const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2)
+{
+ /* Sanity checks. */
+ BLI_assert(ibuf->channels == 4);
+
+ if (ibuf->channels != 4) {
+ return;
+ }
+
+ int width = ibuf->x;
+ int height = ibuf->y;
+ CLAMP(x1, 0, width);
+ CLAMP(x2, 0, width);
+ CLAMP(y1, 0, height);
+ CLAMP(y2, 0, height);
+
+ if (x1 > x2) {
+ SWAP(int, x1, x2);
+ }
+ if (y1 > y2) {
+ SWAP(int, y1, y2);
+ }
+ if (x1 == x2 || y1 == y2) {
+ return;
+ }
+
+ unsigned char col_char[4] = {col[0] * 255, col[1] * 255, col[2] * 255, col[3] * 255};
+
+ for (int y = y1; y < y2; y++) {
+ for (int x = x1; x < x2; x++) {
+ size_t offset = ((size_t)ibuf->x) * y * 4 + 4 * x;
+
+ if (ibuf->rect) {
+ unsigned char *rrect = (unsigned char *)ibuf->rect + offset;
+ memcpy(rrect, &col_char, sizeof(unsigned char) * 4);
+ }
+
+ if (ibuf->rect_float) {
+ float *rrectf = ibuf->rect_float + offset;
+ memcpy(rrectf, &col, sizeof(float) * 4);
+ }
+ }
+ }
+}
+
void buf_rectfill_area(unsigned char *rect,
float *rectf,
int width,
@@ -1214,6 +1272,21 @@ void buf_rectfill_area(unsigned char *rect,
}
}
+/**
+ * Blend pixels of image area with solid color.
+ *
+ * For images with uchar buffer use color matching image colorspace.
+ * For images with float buffer use color display colorspace.
+ * If display colorspace can not be referenced, use color in SRGB colorspace.
+ *
+ * \param ibuf an image to be filled with color. It must be 4 channel image.
+ * \param col RGBA color.
+ * \param x1, y1, x2, y2 (x1, y1) defines starting point of the rectangular area to be filled,
+ * (x2, y2) is the end point. Note that values are allowed to be loosely ordered, which means that
+ * x2 is allowed to be lower than x1, as well as y2 is allowed to be lower than y1. No matter the
+ * order the area between x1 and x2, and y1 and y2 is filled.
+ * \param display colorspace reference for display space.
+ */
void IMB_rectfill_area(ImBuf *ibuf,
const float col[4],
int x1,
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 1d89657faf6..1847fbfa986 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -68,6 +68,9 @@ typedef struct StripCrop {
typedef struct StripTransform {
int xofs;
int yofs;
+ float scale_x;
+ float scale_y;
+ float rotation;
} StripTransform;
typedef struct StripColorBalance {
@@ -494,8 +497,8 @@ enum {
SEQ_MAKE_FLOAT = (1 << 13),
SEQ_LOCK = (1 << 14),
SEQ_USE_PROXY = (1 << 15),
- SEQ_USE_TRANSFORM = (1 << 16),
- SEQ_USE_CROP = (1 << 17),
+ SEQ_FLAG_UNUSED_23 = (1 << 16), /* cleared */
+ SEQ_FLAG_UNUSED_22 = (1 << 17), /* cleared */
SEQ_FLAG_UNUSED_18 = (1 << 18), /* cleared */
SEQ_FLAG_UNUSED_19 = (1 << 19), /* cleared */
SEQ_FLAG_UNUSED_21 = (1 << 21), /* cleared */
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 8da2d762c94..eed30b05c82 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -473,34 +473,6 @@ static void rna_Sequence_use_proxy_set(PointerRNA *ptr, bool value)
BKE_sequencer_proxy_set(seq, value != 0);
}
-static void rna_Sequence_use_translation_set(PointerRNA *ptr, bool value)
-{
- Sequence *seq = (Sequence *)ptr->data;
- if (value) {
- seq->flag |= SEQ_USE_TRANSFORM;
- if (seq->strip->transform == NULL) {
- seq->strip->transform = MEM_callocN(sizeof(struct StripTransform), "StripTransform");
- }
- }
- else {
- seq->flag &= ~SEQ_USE_TRANSFORM;
- }
-}
-
-static void rna_Sequence_use_crop_set(PointerRNA *ptr, bool value)
-{
- Sequence *seq = (Sequence *)ptr->data;
- if (value) {
- seq->flag |= SEQ_USE_CROP;
- if (seq->strip->crop == NULL) {
- seq->strip->crop = MEM_callocN(sizeof(struct StripCrop), "StripCrop");
- }
- }
- else {
- seq->flag &= ~SEQ_USE_CROP;
- }
-}
-
static int transform_seq_cmp_fn(Sequence *seq, void *arg_pt)
{
SequenceSearchData *data = arg_pt;
@@ -1409,18 +1381,35 @@ static void rna_def_strip_transform(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Sequence Transform", "Transform parameters for a sequence strip");
RNA_def_struct_sdna(srna, "StripTransform");
+ prop = RNA_def_property(srna, "scale_x", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_sdna(prop, NULL, "scale_x");
+ RNA_def_property_ui_text(prop, "Scale X", "Scale along X axis");
+ RNA_def_property_ui_range(prop, 0, FLT_MAX, 3, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
+
+ prop = RNA_def_property(srna, "scale_y", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_sdna(prop, NULL, "scale_y");
+ RNA_def_property_ui_text(prop, "Scale Y", "Scale along Y axis");
+ RNA_def_property_ui_range(prop, 0, FLT_MAX, 3, 3);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
+
prop = RNA_def_property(srna, "offset_x", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "xofs");
- RNA_def_property_ui_text(
- prop, "Offset X", "Amount to move the input on the X axis within its boundaries");
- RNA_def_property_ui_range(prop, -4096, 4096, 1, -1);
+ RNA_def_property_ui_text(prop, "Translate X", "Move along X axis");
+ RNA_def_property_ui_range(prop, INT_MIN, INT_MAX, 1, 6);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
prop = RNA_def_property(srna, "offset_y", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "yofs");
- RNA_def_property_ui_text(
- prop, "Offset Y", "Amount to move the input on the Y axis within its boundaries");
- RNA_def_property_ui_range(prop, -4096, 4096, 1, -1);
+ RNA_def_property_ui_text(prop, "Translate Y", "Move along Y axis");
+ RNA_def_property_ui_range(prop, INT_MIN, INT_MAX, 1, 6);
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
+
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "rotation");
+ RNA_def_property_ui_text(prop, "Rotation", "Rotate around image centr");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
RNA_def_struct_path_func(srna, "rna_SequenceTransform_path");
@@ -2175,22 +2164,10 @@ static void rna_def_filter_video(StructRNA *srna)
RNA_def_property_ui_text(prop, "Strobe", "Only display every nth frame");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
- prop = RNA_def_property(srna, "use_translation", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_TRANSFORM);
- RNA_def_property_ui_text(prop, "Use Translation", "Translate image before processing");
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Sequence_use_translation_set");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
-
prop = RNA_def_property(srna, "transform", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "strip->transform");
RNA_def_property_ui_text(prop, "Transform", "");
- prop = RNA_def_property(srna, "use_crop", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_USE_CROP);
- RNA_def_property_ui_text(prop, "Use Crop", "Crop image before processing");
- RNA_def_property_boolean_funcs(prop, NULL, "rna_Sequence_use_crop_set");
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
-
prop = RNA_def_property(srna, "crop", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "strip->crop");
RNA_def_property_ui_text(prop, "Crop", "");
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index 90b1d611842..a154b5d908b 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -156,6 +156,8 @@ void BKE_sequencer_new_render_data(struct Main *bmain,
int preview_render_size,
int for_render,
SeqRenderData *r_context);
+bool SEQ_can_use_proxy(struct Sequence *seq, int psize);
+int SEQ_rendersize_to_proxysize(int render_size);
/* **********************************************************************
* sequencer.c
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 42134b38666..4dd737cdbd2 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -1631,7 +1631,7 @@ typedef struct SeqIndexBuildContext {
#define PROXY_MAXFILE (2 * FILE_MAXDIR + FILE_MAXFILE)
-static IMB_Proxy_Size seq_rendersize_to_proxysize(int render_size)
+int SEQ_rendersize_to_proxysize(int render_size)
{
switch (render_size) {
case SEQ_RENDER_SIZE_PROXY_25:
@@ -1904,7 +1904,7 @@ static bool seq_proxy_get_fname(Editing *ed,
return true;
}
-static bool seq_can_use_proxy(Sequence *seq, IMB_Proxy_Size psize)
+bool SEQ_can_use_proxy(Sequence *seq, int psize)
{
if (seq->strip->proxy == NULL) {
return false;
@@ -1922,7 +1922,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
StripAnim *sanim;
/* only use proxies, if they are enabled (even if present!) */
- if (!seq_can_use_proxy(seq, seq_rendersize_to_proxysize(psize))) {
+ if (!SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(psize))) {
return NULL;
}
@@ -2653,6 +2653,28 @@ void BKE_sequencer_color_balance_apply(
* - Premultiply
*/
+static bool sequencer_use_transform(const Sequence *seq)
+{
+ const StripTransform *transform = seq->strip->transform;
+
+ if (transform->xofs != 0 || transform->yofs != 0 || transform->scale_x != 1 ||
+ transform->scale_y != 1 || transform->rotation != 0) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool sequencer_use_crop(const Sequence *seq)
+{
+ const StripCrop *crop = seq->strip->crop;
+ if (crop->left > 0 || crop->right > 0 || crop->top > 0 || crop->bottom > 0) {
+ return true;
+ }
+
+ return false;
+}
+
bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context,
Sequence *seq,
float UNUSED(cfra))
@@ -2663,8 +2685,8 @@ bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context,
return false;
}
- if (seq->flag &
- (SEQ_FILTERY | SEQ_USE_CROP | SEQ_USE_TRANSFORM | SEQ_FLIPX | SEQ_FLIPY | SEQ_MAKE_FLOAT)) {
+ if ((seq->flag & (SEQ_FILTERY | SEQ_FLIPX | SEQ_FLIPY | SEQ_MAKE_FLOAT)) ||
+ sequencer_use_crop(seq) || sequencer_use_transform(seq)) {
return true;
}
@@ -2689,6 +2711,83 @@ bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context,
return false;
}
+typedef struct ImageTransformThreadInitData {
+ ImBuf *ibuf_source;
+ ImBuf *ibuf_out;
+ StripTransform *transform;
+ float scale_to_fit;
+ float image_scale_factor;
+ bool for_render;
+} ImageTransformThreadInitData;
+
+typedef struct ImageTransformThreadData {
+ ImBuf *ibuf_source;
+ ImBuf *ibuf_out;
+ StripTransform *transform;
+ float scale_to_fit;
+ float image_scale_factor;
+ bool for_render;
+ int start_line;
+ int tot_line;
+} ImageTransformThreadData;
+
+static void sequencer_image_transform_init(void *handle_v,
+ int start_line,
+ int tot_line,
+ void *init_data_v)
+{
+ ImageTransformThreadData *handle = (ImageTransformThreadData *)handle_v;
+ const ImageTransformThreadInitData *init_data = (ImageTransformThreadInitData *)init_data_v;
+
+ handle->ibuf_source = init_data->ibuf_source;
+ handle->ibuf_out = init_data->ibuf_out;
+ handle->transform = init_data->transform;
+ handle->scale_to_fit = init_data->scale_to_fit;
+ handle->image_scale_factor = init_data->image_scale_factor;
+ handle->for_render = init_data->for_render;
+
+ handle->start_line = start_line;
+ handle->tot_line = tot_line;
+}
+
+static void *sequencer_image_transform_do_thread(void *data_v)
+{
+ const ImageTransformThreadData *data = (ImageTransformThreadData *)data_v;
+ const StripTransform *transform = data->transform;
+ const float scale_x = transform->scale_x * data->scale_to_fit;
+ const float scale_y = transform->scale_y * data->scale_to_fit;
+ const float scale_to_fit_offs_x = (data->ibuf_out->x - data->ibuf_source->x) / 2;
+ const float scale_to_fit_offs_y = (data->ibuf_out->y - data->ibuf_source->y) / 2;
+ const float translate_x = transform->xofs * data->image_scale_factor + scale_to_fit_offs_x;
+ const float translate_y = transform->yofs * data->image_scale_factor + scale_to_fit_offs_y;
+ const int width = data->ibuf_out->x;
+ const int height = data->ibuf_out->y;
+ const float pivot[2] = {width / 2 - scale_to_fit_offs_x, height / 2 - scale_to_fit_offs_y};
+ float transform_matrix[3][3];
+ loc_rot_size_to_mat3(transform_matrix,
+ (const float[]){translate_x, translate_y},
+ transform->rotation,
+ (const float[]){scale_x, scale_y});
+ invert_m3(transform_matrix);
+ transform_pivot_set_m3(transform_matrix, pivot);
+
+ for (int yi = data->start_line; yi < data->start_line + data->tot_line; yi++) {
+ for (int xi = 0; xi < width; xi++) {
+ float uv[2] = {xi, yi};
+ mul_v2_m3v2(uv, transform_matrix, uv);
+
+ if (data->for_render) {
+ bilinear_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi);
+ }
+ else {
+ nearest_interpolation(data->ibuf_source, data->ibuf_out, uv[0], uv[1], xi, yi);
+ }
+ }
+ }
+
+ return NULL;
+}
+
static ImBuf *input_preprocess(const SeqRenderData *context,
Sequence *seq,
float cfra,
@@ -2696,131 +2795,124 @@ static ImBuf *input_preprocess(const SeqRenderData *context,
const bool is_proxy_image)
{
Scene *scene = context->scene;
- float mul;
-
- ibuf = IMB_makeSingleUser(ibuf);
+ ImBuf *preprocessed_ibuf = NULL;
+ /* Deinterlace. */
if ((seq->flag & SEQ_FILTERY) && !ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_MOVIECLIP)) {
- IMB_filtery(ibuf);
- }
-
- if (seq->flag & (SEQ_USE_CROP | SEQ_USE_TRANSFORM)) {
- StripCrop c = {0};
- StripTransform t = {0};
+ /* Change original image pointer to avoid another duplication in SEQ_USE_TRANSFORM. */
+ preprocessed_ibuf = IMB_makeSingleUser(ibuf);
+ ibuf = preprocessed_ibuf;
- if (seq->flag & SEQ_USE_CROP && seq->strip->crop) {
- c = *seq->strip->crop;
- }
- if (seq->flag & SEQ_USE_TRANSFORM && seq->strip->transform) {
- t = *seq->strip->transform;
- }
-
- /* Calculate scale factor for current image if needed. */
- double scale_factor, image_scale_factor = 1.0;
- if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) {
- scale_factor = image_scale_factor = (double)scene->r.size / 100;
- }
- else {
- scale_factor = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
- if (!is_proxy_image) {
- image_scale_factor = scale_factor;
- }
- }
-
- if (image_scale_factor != 1.0) {
- if (context->for_render) {
- IMB_scaleImBuf(ibuf, ibuf->x * image_scale_factor, ibuf->y * image_scale_factor);
- }
- else {
- IMB_scalefastImBuf(ibuf, ibuf->x * image_scale_factor, ibuf->y * image_scale_factor);
- }
- }
-
- t.xofs *= scale_factor;
- t.yofs *= scale_factor;
- c.left *= scale_factor;
- c.right *= scale_factor;
- c.top *= scale_factor;
- c.bottom *= scale_factor;
-
- int sx, sy, dx, dy;
- sx = ibuf->x - c.left - c.right;
- sy = ibuf->y - c.top - c.bottom;
-
- if (seq->flag & SEQ_USE_TRANSFORM) {
- dx = context->rectx;
- dy = context->recty;
- }
- else {
- dx = sx;
- dy = sy;
- }
+ IMB_filtery(preprocessed_ibuf);
+ }
- if (c.top + c.bottom >= ibuf->y || c.left + c.right >= ibuf->x || t.xofs >= dx ||
- t.yofs >= dy) {
- return NULL;
- }
+ /* Calculate scale factor, so image fits in preview area with original aspect ratio. */
+ const float scale_to_fit_factor = MIN2((float)context->rectx / (float)ibuf->x,
+ (float)context->recty / (float)ibuf->y);
- ImBuf *i = IMB_allocImBuf(dx, dy, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
- IMB_rectcpy(i, ibuf, t.xofs, t.yofs, c.left, c.bottom, sx, sy);
- sequencer_imbuf_assign_spaces(scene, i);
- IMB_metadata_copy(i, ibuf);
+ /* Get scale factor if preview resolution doesn't match project resolution. */
+ float preview_scale_factor;
+ if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) {
+ preview_scale_factor = (float)scene->r.size / 100;
+ }
+ else {
+ preview_scale_factor = BKE_sequencer_rendersize_to_scale_factor(context->preview_render_size);
+ }
+
+ if (sequencer_use_crop(seq)) {
+ /* Change original image pointer to avoid another duplication in SEQ_USE_TRANSFORM. */
+ preprocessed_ibuf = IMB_makeSingleUser(ibuf);
+ ibuf = preprocessed_ibuf;
+
+ const int width = ibuf->x;
+ const int height = ibuf->y;
+ const StripCrop *c = seq->strip->crop;
+
+ const int left = c->left / scale_to_fit_factor * preview_scale_factor;
+ const int right = c->right / scale_to_fit_factor * preview_scale_factor;
+ const int top = c->top / scale_to_fit_factor * preview_scale_factor;
+ const int bottom = c->bottom / scale_to_fit_factor * preview_scale_factor;
+ const float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ /* Left. */
+ IMB_rectfill_area_replace(preprocessed_ibuf, col, 0, 0, left, height);
+ /* Bottom. */
+ IMB_rectfill_area_replace(preprocessed_ibuf, col, left, 0, width, bottom);
+ /* Right. */
+ IMB_rectfill_area_replace(preprocessed_ibuf, col, width - right, bottom, width, height);
+ /* Top. */
+ IMB_rectfill_area_replace(preprocessed_ibuf, col, left, height - top, width - right, height);
+ }
+
+ if (sequencer_use_transform(seq) || context->rectx != ibuf->x || context->recty != ibuf->y) {
+ const int x = context->rectx;
+ const int y = context->recty;
+ preprocessed_ibuf = IMB_allocImBuf(x, y, 32, ibuf->rect_float ? IB_rectfloat : IB_rect);
+
+ ImageTransformThreadInitData init_data = {NULL};
+ init_data.ibuf_source = ibuf;
+ init_data.ibuf_out = preprocessed_ibuf;
+ init_data.transform = seq->strip->transform;
+ init_data.scale_to_fit = scale_to_fit_factor;
+ init_data.image_scale_factor = preview_scale_factor;
+ init_data.for_render = context->for_render;
+ IMB_processor_apply_threaded(context->recty,
+ sizeof(ImageTransformThreadData),
+ &init_data,
+ sequencer_image_transform_init,
+ sequencer_image_transform_do_thread);
+ sequencer_imbuf_assign_spaces(scene, preprocessed_ibuf);
+ IMB_metadata_copy(preprocessed_ibuf, ibuf);
IMB_freeImBuf(ibuf);
- ibuf = i;
+ }
+
+ /* Duplicate ibuf if we still have original. */
+ if (preprocessed_ibuf == NULL) {
+ preprocessed_ibuf = IMB_makeSingleUser(ibuf);
}
if (seq->flag & SEQ_FLIPX) {
- IMB_flipx(ibuf);
+ IMB_flipx(preprocessed_ibuf);
}
if (seq->flag & SEQ_FLIPY) {
- IMB_flipy(ibuf);
+ IMB_flipy(preprocessed_ibuf);
}
if (seq->sat != 1.0f) {
- IMB_saturation(ibuf, seq->sat);
- }
-
- mul = seq->mul;
-
- if (seq->blend_mode == SEQ_BLEND_REPLACE) {
- mul *= seq->blend_opacity / 100.0f;
+ IMB_saturation(preprocessed_ibuf, seq->sat);
}
if (seq->flag & SEQ_MAKE_FLOAT) {
- if (!ibuf->rect_float) {
- BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf, true);
+ if (!preprocessed_ibuf->rect_float) {
+ BKE_sequencer_imbuf_to_sequencer_space(scene, preprocessed_ibuf, true);
}
- if (ibuf->rect) {
- imb_freerectImBuf(ibuf);
+ if (preprocessed_ibuf->rect) {
+ imb_freerectImBuf(preprocessed_ibuf);
}
}
- if (mul != 1.0f) {
- multibuf(ibuf, mul);
+ float mul = seq->mul;
+ if (seq->blend_mode == SEQ_BLEND_REPLACE) {
+ mul *= seq->blend_opacity / 100.0f;
}
- if (ibuf->x != context->rectx || ibuf->y != context->recty) {
- if (context->for_render) {
- IMB_scaleImBuf(ibuf, (short)context->rectx, (short)context->recty);
- }
- else {
- IMB_scalefastImBuf(ibuf, (short)context->rectx, (short)context->recty);
- }
+ if (mul != 1.0f) {
+ multibuf(preprocessed_ibuf, mul);
}
if (seq->modifiers.first) {
- ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, ibuf, cfra);
+ ImBuf *ibuf_new = BKE_sequence_modifier_apply_stack(context, seq, preprocessed_ibuf, cfra);
- if (ibuf_new != ibuf) {
- IMB_metadata_copy(ibuf_new, ibuf);
- IMB_freeImBuf(ibuf);
- ibuf = ibuf_new;
+ if (ibuf_new != preprocessed_ibuf) {
+ IMB_metadata_copy(ibuf_new, preprocessed_ibuf);
+ IMB_freeImBuf(preprocessed_ibuf);
+ preprocessed_ibuf = ibuf_new;
}
}
- return ibuf;
+ return preprocessed_ibuf;
}
/*********************** strip rendering functions *************************/
@@ -3190,11 +3282,11 @@ static ImBuf *seq_render_movie_strip_view(const SeqRenderData *context,
bool *r_is_proxy_image)
{
ImBuf *ibuf = NULL;
- IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_Proxy_Size psize = SEQ_rendersize_to_proxysize(context->preview_render_size);
IMB_anim_set_preseek(sanim->anim, seq->anim_preseek);
- if (seq_can_use_proxy(seq, psize)) {
+ if (SEQ_can_use_proxy(seq, psize)) {
/* Try to get a proxy image.
* Movie proxies are handled by ImBuf module with exception of `custom file` setting. */
if (context->scene->ed->proxy_storage != SEQ_EDIT_PROXY_DIR_STORAGE &&
@@ -3326,7 +3418,7 @@ static ImBuf *seq_render_movieclip_strip(const SeqRenderData *context,
{
ImBuf *ibuf = NULL;
MovieClipUser user;
- IMB_Proxy_Size psize = seq_rendersize_to_proxysize(context->preview_render_size);
+ IMB_Proxy_Size psize = SEQ_rendersize_to_proxysize(context->preview_render_size);
if (!seq->clip) {
return NULL;
@@ -5347,6 +5439,8 @@ static Strip *seq_strip_alloc(int type)
if (ELEM(type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) == 0) {
strip->transform = MEM_callocN(sizeof(struct StripTransform), "StripTransform");
+ strip->transform->scale_x = 1;
+ strip->transform->scale_y = 1;
strip->crop = MEM_callocN(sizeof(struct StripCrop), "StripCrop");
}