Blender V4.3
transform_convert_sequencer_image.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "DNA_sequence_types.h"
12#include "DNA_space_types.h"
13
14#include "BLI_math_matrix.h"
15#include "BLI_math_rotation.h"
16#include "BLI_math_vector.h"
17
18#include "BKE_report.hh"
19
20#include "SEQ_channels.hh"
21#include "SEQ_iterator.hh"
22#include "SEQ_relations.hh"
23#include "SEQ_sequencer.hh"
24#include "SEQ_transform.hh"
25
26#include "ANIM_keyframing.hh"
27
28#include "RNA_access.hh"
29#include "RNA_prototypes.hh"
30
31#include "transform.hh"
32#include "transform_convert.hh"
33
35struct TransDataSeq {
39 float orig_scale[2];
41};
42
43static TransData *SeqToTransData(const Scene *scene,
44 Sequence *seq,
45 TransData *td,
46 TransData2D *td2d,
47 TransDataSeq *tdseq,
48 int vert_index)
49{
50 const StripTransform *transform = seq->strip->transform;
51 float origin[2];
53 float vertex[2] = {origin[0], origin[1]};
54
55 /* Add control vertex, so rotation and scale can be calculated.
56 * All three vertices will form a "L" shape that is aligned to the local strip axis.
57 */
58 if (vert_index == 1) {
59 vertex[0] += cosf(transform->rotation);
60 vertex[1] += sinf(transform->rotation);
61 }
62 else if (vert_index == 2) {
63 vertex[0] -= sinf(transform->rotation);
64 vertex[1] += cosf(transform->rotation);
65 }
66
67 td2d->loc[0] = vertex[0];
68 td2d->loc[1] = vertex[1];
69 td2d->loc2d = nullptr;
70 td->loc = td2d->loc;
71 copy_v3_v3(td->iloc, td->loc);
72
73 td->center[0] = origin[0];
74 td->center[1] = origin[1];
75
76 unit_m3(td->mtx);
77 unit_m3(td->smtx);
78
79 axis_angle_to_mat3_single(td->axismtx, 'Z', transform->rotation);
81
82 tdseq->seq = seq;
83 copy_v2_v2(tdseq->orig_origin_position, origin);
84 tdseq->orig_translation[0] = transform->xofs;
85 tdseq->orig_translation[1] = transform->yofs;
86 tdseq->orig_scale[0] = transform->scale_x;
87 tdseq->orig_scale[1] = transform->scale_y;
88 tdseq->orig_rotation = transform->rotation;
89
90 td->extra = (void *)tdseq;
91 td->ext = nullptr;
92 td->flag |= TD_SELECTED;
93 td->dist = 0.0;
94
95 return td;
96}
97
98static void freeSeqData(TransInfo * /*t*/,
100 TransCustomData * /*custom_data*/)
101{
102 TransData *td = (TransData *)tc->data;
103 MEM_freeN(td->extra);
104}
105
107{
108 Editing *ed = SEQ_editing_get(t->scene);
109 const SpaceSeq *sseq = static_cast<const SpaceSeq *>(t->area->spacedata.first);
110 const ARegion *region = t->region;
111
112 if (ed == nullptr) {
113 return;
114 }
115 if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
116 return;
117 }
118 if (region->regiontype == RGN_TYPE_PREVIEW && sseq->view == SEQ_VIEW_SEQUENCE_PREVIEW) {
119 return;
120 }
121
122 ListBase *seqbase = SEQ_active_seqbase_get(ed);
123 ListBase *channels = SEQ_channels_displayed_get(ed);
125 t->scene, channels, seqbase, t->scene->r.cfra, 0);
126 strips.remove_if([&](Sequence *seq) { return (seq->flag & SELECT) == 0; });
127
128 if (strips.is_empty()) {
129 return;
130 }
131
134
135 tc->data_len = strips.size() * 3; /* 3 vertices per sequence are needed. */
136 TransData *td = tc->data = static_cast<TransData *>(
137 MEM_callocN(tc->data_len * sizeof(TransData), "TransSeq TransData"));
138 TransData2D *td2d = tc->data_2d = static_cast<TransData2D *>(
139 MEM_callocN(tc->data_len * sizeof(TransData2D), "TransSeq TransData2D"));
140 TransDataSeq *tdseq = static_cast<TransDataSeq *>(
141 MEM_callocN(tc->data_len * sizeof(TransDataSeq), "TransSeq TransDataSeq"));
142
143 for (Sequence *seq : strips) {
144 /* One `Sequence` needs 3 `TransData` entries - center point placed in image origin, then 2
145 * points offset by 1 in X and Y direction respectively, so rotation and scale can be
146 * calculated from these points. */
147 SeqToTransData(t->scene, seq, td++, td2d++, tdseq++, 0);
148 SeqToTransData(t->scene, seq, td++, td2d++, tdseq++, 1);
149 SeqToTransData(t->scene, seq, td++, td2d++, tdseq++, 2);
150 }
151}
152
154 Scene *scene,
155 StripTransform *transform,
156 const int tmode)
157{
158 PropertyRNA *prop;
159 PointerRNA ptr = RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform);
160
161 const bool around_cursor = scene->toolsettings->sequencer_tool_settings->pivot_point ==
163 const bool do_loc = tmode == TFM_TRANSLATION || around_cursor;
164 const bool do_rot = tmode == TFM_ROTATION;
165 const bool do_scale = tmode == TFM_RESIZE;
166 const bool only_when_keyed = blender::animrig::is_keying_flag(scene,
168
169 bool changed = false;
170 if (do_rot) {
171 prop = RNA_struct_find_property(&ptr, "rotation");
173 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
174 }
175 if (do_loc) {
176 prop = RNA_struct_find_property(&ptr, "offset_x");
178 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
179 prop = RNA_struct_find_property(&ptr, "offset_y");
181 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
182 }
183 if (do_scale) {
184 prop = RNA_struct_find_property(&ptr, "scale_x");
186 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
187 prop = RNA_struct_find_property(&ptr, "scale_y");
189 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
190 }
191
192 return changed;
193}
194
196{
198 TransData *td = nullptr;
199 TransData2D *td2d = nullptr;
200 int i;
201
202 for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
203 /* Origin. */
204 float origin[2];
205 copy_v2_v2(origin, td2d->loc);
206 i++;
207 td++;
208 td2d++;
209
210 /* X and Y control points used to read scale and rotation. */
211 float handle_x[2];
212 copy_v2_v2(handle_x, td2d->loc);
213 sub_v2_v2(handle_x, origin);
214 i++;
215 td++;
216 td2d++;
217
218 float handle_y[2];
219 copy_v2_v2(handle_y, td2d->loc);
220 sub_v2_v2(handle_y, origin);
221
222 TransDataSeq *tdseq = static_cast<TransDataSeq *>(td->extra);
223 Sequence *seq = tdseq->seq;
224 StripTransform *transform = seq->strip->transform;
225 float mirror[2];
227
228 /* Calculate translation. */
229 float translation[2];
230 copy_v2_v2(translation, tdseq->orig_origin_position);
231 sub_v2_v2(translation, origin);
232 mul_v2_v2(translation, mirror);
233 translation[0] *= t->scene->r.yasp / t->scene->r.xasp;
234
235 /* Round resulting position to integer pixels. Resulting strip
236 * will more often end up using faster interpolation (without bilinear),
237 * and avoids "text edges are too dark" artifacts with light text strips
238 * on light backgrounds. The latter happens because bilinear filtering
239 * does not do full alpha pre-multiplication. */
240 transform->xofs = roundf(tdseq->orig_translation[0] - translation[0]);
241 transform->yofs = roundf(tdseq->orig_translation[1] - translation[1]);
242
243 /* Scale. */
244 transform->scale_x = tdseq->orig_scale[0] * fabs(len_v2(handle_x));
245 transform->scale_y = tdseq->orig_scale[1] * fabs(len_v2(handle_y));
246
247 /* Rotation. Scaling can cause negative rotation. */
248 if (t->mode == TFM_ROTATION) {
249 transform->rotation = tdseq->orig_rotation - t->values_final[0];
250 }
251
254 autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode);
255 }
256
258 }
259}
260
262{
263
265 TransData *td = nullptr;
266 TransData2D *td2d = nullptr;
267 int i;
268
269 for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
270 TransDataSeq *tdseq = static_cast<TransDataSeq *>(td->extra);
271 Sequence *seq = tdseq->seq;
272 StripTransform *transform = seq->strip->transform;
273 if (t->state == TRANS_CANCEL) {
274 if (t->mode == TFM_ROTATION) {
275 transform->rotation = tdseq->orig_rotation;
276 }
277 continue;
278 }
279
281 autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode);
282 }
283 }
284}
285
287 /*flags*/ (T_POINTS | T_2D_EDIT),
288 /*create_trans_data*/ createTransSeqImageData,
289 /*recalc_data*/ recalcData_sequencer_image,
290 /*special_aftertrans_update*/ special_aftertrans_update__sequencer_image,
291};
Functions to insert, delete or modify keyframes.
void unit_m3(float m[3][3])
void normalize_m3(float R[3][3]) ATTR_NONNULL()
void axis_angle_to_mat3_single(float R[3][3], char axis, float angle)
MINLINE float len_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE void mul_v2_v2(float r[2], const float a[2])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
@ RGN_TYPE_PREVIEW
@ SEQ_VIEW_SEQUENCE_PREVIEW
@ SEQ_DRAW_IMG_IMBUF
@ AUTOKEY_FLAG_INSERTAVAILABLE
@ V3D_AROUND_CURSOR
@ TFM_RESIZE
@ TFM_ROTATION
@ TFM_TRANSLATION
Read Guarded memory(de)allocation.
ListBase * SEQ_channels_displayed_get(Editing *ed)
Definition channels.cc:23
int64_t size() const
int64_t remove_if(Predicate &&predicate)
#define SELECT
#define sinf(x)
#define cosf(x)
VectorSet< Sequence * > SEQ_query_rendered_strips(const Scene *scene, ListBase *channels, ListBase *seqbase, const int timeline_frame, const int displayed_channel)
Definition iterator.cc:184
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float2 fabs(const float2 a)
bool is_autokey_on(const Scene *scene)
bool autokeyframe_property(bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra, bool only_if_property_keyed)
bool is_keying_flag(const Scene *scene, eKeying_Flag flag)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
ListBase * SEQ_active_seqbase_get(const Editing *ed)
Definition sequencer.cc:416
Editing * SEQ_editing_get(const Scene *scene)
Definition sequencer.cc:262
void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq)
void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene, const Sequence *seq, float r_origin[2])
void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2])
void * first
struct RenderData r
ListBase spacedata
StripTransform * transform
TransCustomData type
Definition transform.hh:425
void(* free_cb)(TransInfo *, TransDataContainer *tc, TransCustomData *custom_data)
Definition transform.hh:409
TransCustomDataContainer custom
Definition transform.hh:501
TransData * data
Definition transform.hh:445
TransData2D * data_2d
Definition transform.hh:449
float smtx[3][3]
float axismtx[3][3]
float mtx[3][3]
TransDataExtension * ext
eTfmMode mode
Definition transform.hh:517
wmTimer * animtimer
Definition transform.hh:657
eTState state
Definition transform.hh:527
Scene * scene
Definition transform.hh:654
ARegion * region
Definition transform.hh:652
float values_final[4]
Definition transform.hh:632
bContext * context
Definition transform.hh:649
ScrArea * area
Definition transform.hh:651
@ T_2D_EDIT
Definition transform.hh:104
@ T_POINTS
Definition transform.hh:93
#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t)
Definition transform.hh:851
@ TRANS_CANCEL
Definition transform.hh:210
void animrecord_check_state(TransInfo *t, ID *id)
conversion and adaptation of different datablocks to a common struct.
static void freeSeqData(TransInfo *, TransDataContainer *tc, TransCustomData *)
static bool autokeyframe_sequencer_image(bContext *C, Scene *scene, StripTransform *transform, const int tmode)
static void recalcData_sequencer_image(TransInfo *t)
static void special_aftertrans_update__sequencer_image(bContext *, TransInfo *t)
static void createTransSeqImageData(bContext *, TransInfo *t)
static TransData * SeqToTransData(const Scene *scene, Sequence *seq, TransData *td, TransData2D *td2d, TransDataSeq *tdseq, int vert_index)
TransConvertTypeInfo TransConvertType_SequencerImage
@ TD_SELECTED
PointerRNA * ptr
Definition wm_files.cc:4126