Blender V4.3
effects.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 * SPDX-FileCopyrightText: 2003-2024 Blender Authors
3 * SPDX-FileCopyrightText: 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later */
6
10
11#include <cmath>
12#include <cstdlib>
13#include <cstring>
14
15#include "MEM_guardedalloc.h"
16
17#include "BLI_array.hh"
18#include "BLI_math_rotation.h"
19#include "BLI_math_vector.hh"
21#include "BLI_path_utils.hh"
22#include "BLI_rect.h"
23#include "BLI_string.h"
24#include "BLI_task.hh"
25#include "BLI_threads.h"
26#include "BLI_utildefines.h"
27
29#include "DNA_scene_types.h"
30#include "DNA_sequence_types.h"
31#include "DNA_space_types.h"
32#include "DNA_vfont_types.h"
33
34#include "BKE_fcurve.hh"
35#include "BKE_lib_id.hh"
36#include "BKE_main.hh"
37
39#include "IMB_imbuf.hh"
40#include "IMB_imbuf_types.hh"
41#include "IMB_interp.hh"
42#include "IMB_metadata.hh"
43
45
46#include "RNA_prototypes.hh"
47
48#include "RE_pipeline.h"
49
50#include "SEQ_channels.hh"
51#include "SEQ_effects.hh"
52#include "SEQ_proxy.hh"
53#include "SEQ_relations.hh"
54#include "SEQ_render.hh"
55#include "SEQ_time.hh"
56#include "SEQ_utils.hh"
57
58#include "BLF_api.hh"
59
60#include "effects.hh"
61#include "render.hh"
62
63using namespace blender;
64
65static SeqEffectHandle get_sequence_effect_impl(int seq_type);
66
67/* -------------------------------------------------------------------- */
70
71static void slice_get_byte_buffers(const SeqRenderData *context,
72 const ImBuf *ibuf1,
73 const ImBuf *ibuf2,
74 const ImBuf *out,
75 int start_line,
76 uchar **rect1,
77 uchar **rect2,
78 uchar **rect_out)
79{
80 int offset = 4 * start_line * context->rectx;
81
82 *rect1 = ibuf1->byte_buffer.data + offset;
83 *rect_out = out->byte_buffer.data + offset;
84
85 if (ibuf2) {
86 *rect2 = ibuf2->byte_buffer.data + offset;
87 }
88}
89
90static void slice_get_float_buffers(const SeqRenderData *context,
91 const ImBuf *ibuf1,
92 const ImBuf *ibuf2,
93 const ImBuf *out,
94 int start_line,
95 float **rect1,
96 float **rect2,
97 float **rect_out)
98{
99 int offset = 4 * start_line * context->rectx;
100
101 *rect1 = ibuf1->float_buffer.data + offset;
102 *rect_out = out->float_buffer.data + offset;
103
104 if (ibuf2) {
105 *rect2 = ibuf2->float_buffer.data + offset;
106 }
107}
108
110{
111 float4 res;
113 return res;
114}
115
116static float4 load_premul_pixel(const float *ptr)
117{
118 return float4(ptr);
119}
120
121static void store_premul_pixel(const float4 &pix, uchar *dst)
122{
124}
125
126static void store_premul_pixel(const float4 &pix, float *dst)
127{
128 *reinterpret_cast<float4 *>(dst) = pix;
129}
130
132{
133 dst[0] = 0;
134 dst[1] = 0;
135 dst[2] = 0;
136 dst[3] = 255;
137}
138
139static void store_opaque_black_pixel(float *dst)
140{
141 dst[0] = 0.0f;
142 dst[1] = 0.0f;
143 dst[2] = 0.0f;
144 dst[3] = 1.0f;
145}
146
148
149/* -------------------------------------------------------------------- */
152
154 ImBuf *ibuf1,
155 ImBuf *ibuf2,
156 bool uninitialized_pixels = true)
157{
158 ImBuf *out;
159 Scene *scene = context->scene;
160 int x = context->rectx;
161 int y = context->recty;
162 int base_flags = uninitialized_pixels ? IB_uninitialized_pixels : 0;
163
164 if (!ibuf1 && !ibuf2) {
165 /* hmmm, global float option ? */
166 out = IMB_allocImBuf(x, y, 32, IB_rect | base_flags);
167 }
168 else if ((ibuf1 && ibuf1->float_buffer.data) || (ibuf2 && ibuf2->float_buffer.data)) {
169 /* if any inputs are float, output is float too */
170 out = IMB_allocImBuf(x, y, 32, IB_rectfloat | base_flags);
171 }
172 else {
173 out = IMB_allocImBuf(x, y, 32, IB_rect | base_flags);
174 }
175
176 if (out->float_buffer.data) {
177 if (ibuf1 && !ibuf1->float_buffer.data) {
178 seq_imbuf_to_sequencer_space(scene, ibuf1, true);
179 }
180
181 if (ibuf2 && !ibuf2->float_buffer.data) {
182 seq_imbuf_to_sequencer_space(scene, ibuf2, true);
183 }
184
186 }
187 else {
188 if (ibuf1 && !ibuf1->byte_buffer.data) {
189 IMB_rect_from_float(ibuf1);
190 }
191
192 if (ibuf2 && !ibuf2->byte_buffer.data) {
193 IMB_rect_from_float(ibuf2);
194 }
195 }
196
197 /* If effect only affecting a single channel, forward input's metadata to the output. */
198 if (ibuf1 != nullptr && ibuf1 == ibuf2) {
199 IMB_metadata_copy(out, ibuf1);
200 }
201
202 return out;
203}
204
206
207/* -------------------------------------------------------------------- */
210
212{
213 Sequence *seq1 = seq->seq1;
214 Sequence *seq2 = seq->seq2;
215
216 seq->seq2 = seq1;
217 seq->seq1 = seq2;
218}
219
220static bool alpha_opaque(uchar alpha)
221{
222 return alpha == 255;
223}
224
225static bool alpha_opaque(float alpha)
226{
227 return alpha >= 1.0f;
228}
229
230/* dst = src1 over src2 (alpha from src1) */
231template<typename T>
233 float fac, int width, int height, const T *src1, const T *src2, T *dst)
234{
235 if (fac <= 0.0f) {
236 memcpy(dst, src2, sizeof(T) * 4 * width * height);
237 return;
238 }
239
240 for (int pixel_idx = 0; pixel_idx < width * height; pixel_idx++) {
241 if (src1[3] <= 0.0f) {
242 /* Alpha of zero. No color addition will happen as the colors are pre-multiplied. */
243 memcpy(dst, src2, sizeof(T) * 4);
244 }
245 else if (fac == 1.0f && alpha_opaque(src1[3])) {
246 /* No change to `src1` as `fac == 1` and fully opaque. */
247 memcpy(dst, src1, sizeof(T) * 4);
248 }
249 else {
250 float4 col1 = load_premul_pixel(src1);
251 float mfac = 1.0f - fac * col1.w;
252 float4 col2 = load_premul_pixel(src2);
253 float4 col = fac * col1 + mfac * col2;
255 }
256 src1 += 4;
257 src2 += 4;
258 dst += 4;
259 }
260}
261
262static void do_alphaover_effect(const SeqRenderData *context,
263 Sequence * /*seq*/,
264 float /*timeline_frame*/,
265 float fac,
266 const ImBuf *ibuf1,
267 const ImBuf *ibuf2,
268 int start_line,
269 int total_lines,
270 ImBuf *out)
271{
272 if (out->float_buffer.data) {
273 float *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
274
275 slice_get_float_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
276
277 do_alphaover_effect(fac, context->rectx, total_lines, rect1, rect2, rect_out);
278 }
279 else {
280 uchar *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
281
282 slice_get_byte_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
283
284 do_alphaover_effect(fac, context->rectx, total_lines, rect1, rect2, rect_out);
285 }
286}
287
289
290/* -------------------------------------------------------------------- */
293
294/* dst = src1 under src2 (alpha from src2) */
295template<typename T>
297 float fac, int width, int height, const T *src1, const T *src2, T *dst)
298{
299 if (fac <= 0.0f) {
300 memcpy(dst, src2, sizeof(T) * 4 * width * height);
301 return;
302 }
303
304 for (int pixel_idx = 0; pixel_idx < width * height; pixel_idx++) {
305 if (src2[3] <= 0.0f && fac >= 1.0f) {
306 memcpy(dst, src1, sizeof(T) * 4);
307 }
308 else if (alpha_opaque(src2[3])) {
309 memcpy(dst, src2, sizeof(T) * 4);
310 }
311 else {
312 float4 col2 = load_premul_pixel(src2);
313 float mfac = fac * (1.0f - col2.w);
314 float4 col1 = load_premul_pixel(src1);
315 float4 col = mfac * col1 + col2;
317 }
318 src1 += 4;
319 src2 += 4;
320 dst += 4;
321 }
322}
323
324static void do_alphaunder_effect(const SeqRenderData *context,
325 Sequence * /*seq*/,
326 float /*timeline_frame*/,
327 float fac,
328 const ImBuf *ibuf1,
329 const ImBuf *ibuf2,
330 int start_line,
331 int total_lines,
332 ImBuf *out)
333{
334 if (out->float_buffer.data) {
335 float *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
336
337 slice_get_float_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
338
339 do_alphaunder_effect(fac, context->rectx, total_lines, rect1, rect2, rect_out);
340 }
341 else {
342 uchar *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
343
344 slice_get_byte_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
345
346 do_alphaunder_effect(fac, context->rectx, total_lines, rect1, rect2, rect_out);
347 }
348}
349
351
352/* -------------------------------------------------------------------- */
355
356static void do_cross_effect_byte(float fac, int x, int y, uchar *rect1, uchar *rect2, uchar *out)
357{
358 uchar *rt1 = rect1;
359 uchar *rt2 = rect2;
360 uchar *rt = out;
361
362 int temp_fac = int(256.0f * fac);
363 int temp_mfac = 256 - temp_fac;
364
365 for (int i = 0; i < y; i++) {
366 for (int j = 0; j < x; j++) {
367 rt[0] = (temp_mfac * rt1[0] + temp_fac * rt2[0]) >> 8;
368 rt[1] = (temp_mfac * rt1[1] + temp_fac * rt2[1]) >> 8;
369 rt[2] = (temp_mfac * rt1[2] + temp_fac * rt2[2]) >> 8;
370 rt[3] = (temp_mfac * rt1[3] + temp_fac * rt2[3]) >> 8;
371
372 rt1 += 4;
373 rt2 += 4;
374 rt += 4;
375 }
376 }
377}
378
379static void do_cross_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
380{
381 float *rt1 = rect1;
382 float *rt2 = rect2;
383 float *rt = out;
384
385 float mfac = 1.0f - fac;
386
387 for (int i = 0; i < y; i++) {
388 for (int j = 0; j < x; j++) {
389 rt[0] = mfac * rt1[0] + fac * rt2[0];
390 rt[1] = mfac * rt1[1] + fac * rt2[1];
391 rt[2] = mfac * rt1[2] + fac * rt2[2];
392 rt[3] = mfac * rt1[3] + fac * rt2[3];
393
394 rt1 += 4;
395 rt2 += 4;
396 rt += 4;
397 }
398 }
399}
400
401static void do_cross_effect(const SeqRenderData *context,
402 Sequence * /*seq*/,
403 float /*timeline_frame*/,
404 float fac,
405 const ImBuf *ibuf1,
406 const ImBuf *ibuf2,
407 int start_line,
408 int total_lines,
409 ImBuf *out)
410{
411 if (out->float_buffer.data) {
412 float *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
413
414 slice_get_float_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
415
416 do_cross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
417 }
418 else {
419 uchar *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
420
421 slice_get_byte_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
422
423 do_cross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
424 }
425}
426
428
429/* -------------------------------------------------------------------- */
432
433/* One could argue that gamma cross should not be hardcoded to 2.0 gamma,
434 * but instead either do proper input->linear conversion (often sRGB). Or
435 * maybe not even that, but do interpolation in some perceptual color space
436 * like OKLAB. But currently it is fixed to just 2.0 gamma. */
437
438static float gammaCorrect(float c)
439{
440 if (UNLIKELY(c < 0)) {
441 return -(c * c);
442 }
443 return c * c;
444}
445
446static float invGammaCorrect(float c)
447{
448 return sqrtf_signed(c);
449}
450
451template<typename T>
453 float fac, int width, int height, const T *src1, const T *src2, T *dst)
454{
455 float mfac = 1.0f - fac;
456
457 for (int y = 0; y < height; y++) {
458 for (int x = 0; x < width; x++) {
459 float4 col1 = load_premul_pixel(src1);
460 float4 col2 = load_premul_pixel(src2);
461 float4 col;
462 for (int c = 0; c < 4; ++c) {
463 col[c] = gammaCorrect(mfac * invGammaCorrect(col1[c]) + fac * invGammaCorrect(col2[c]));
464 }
466 src1 += 4;
467 src2 += 4;
468 dst += 4;
469 }
470 }
471}
472
473static void do_gammacross_effect(const SeqRenderData *context,
474 Sequence * /*seq*/,
475 float /*timeline_frame*/,
476 float fac,
477 const ImBuf *ibuf1,
478 const ImBuf *ibuf2,
479 int start_line,
480 int total_lines,
481 ImBuf *out)
482{
483 if (out->float_buffer.data) {
484 float *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
485
486 slice_get_float_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
487
488 do_gammacross_effect(fac, context->rectx, total_lines, rect1, rect2, rect_out);
489 }
490 else {
491 uchar *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
492
493 slice_get_byte_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
494
495 do_gammacross_effect(fac, context->rectx, total_lines, rect1, rect2, rect_out);
496 }
497}
498
500
501/* -------------------------------------------------------------------- */
504
505static void do_add_effect_byte(float fac, int x, int y, uchar *rect1, uchar *rect2, uchar *out)
506{
507 uchar *cp1 = rect1;
508 uchar *cp2 = rect2;
509 uchar *rt = out;
510
511 int temp_fac = int(256.0f * fac);
512
513 for (int i = 0; i < y; i++) {
514 for (int j = 0; j < x; j++) {
515 const int temp_fac2 = temp_fac * int(cp2[3]);
516 rt[0] = min_ii(cp1[0] + ((temp_fac2 * cp2[0]) >> 16), 255);
517 rt[1] = min_ii(cp1[1] + ((temp_fac2 * cp2[1]) >> 16), 255);
518 rt[2] = min_ii(cp1[2] + ((temp_fac2 * cp2[2]) >> 16), 255);
519 rt[3] = cp1[3];
520
521 cp1 += 4;
522 cp2 += 4;
523 rt += 4;
524 }
525 }
526}
527
528static void do_add_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
529{
530 float *rt1 = rect1;
531 float *rt2 = rect2;
532 float *rt = out;
533
534 for (int i = 0; i < y; i++) {
535 for (int j = 0; j < x; j++) {
536 const float temp_fac = (1.0f - (rt1[3] * (1.0f - fac))) * rt2[3];
537 rt[0] = rt1[0] + temp_fac * rt2[0];
538 rt[1] = rt1[1] + temp_fac * rt2[1];
539 rt[2] = rt1[2] + temp_fac * rt2[2];
540 rt[3] = rt1[3];
541
542 rt1 += 4;
543 rt2 += 4;
544 rt += 4;
545 }
546 }
547}
548
549static void do_add_effect(const SeqRenderData *context,
550 Sequence * /*seq*/,
551 float /*timeline_frame*/,
552 float fac,
553 const ImBuf *ibuf1,
554 const ImBuf *ibuf2,
555 int start_line,
556 int total_lines,
557 ImBuf *out)
558{
559 if (out->float_buffer.data) {
560 float *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
561
562 slice_get_float_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
563
564 do_add_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
565 }
566 else {
567 uchar *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
568
569 slice_get_byte_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
570
571 do_add_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
572 }
573}
574
576
577/* -------------------------------------------------------------------- */
580
581static void do_sub_effect_byte(float fac, int x, int y, uchar *rect1, uchar *rect2, uchar *out)
582{
583 uchar *cp1 = rect1;
584 uchar *cp2 = rect2;
585 uchar *rt = out;
586
587 int temp_fac = int(256.0f * fac);
588
589 for (int i = 0; i < y; i++) {
590 for (int j = 0; j < x; j++) {
591 const int temp_fac2 = temp_fac * int(cp2[3]);
592 rt[0] = max_ii(cp1[0] - ((temp_fac2 * cp2[0]) >> 16), 0);
593 rt[1] = max_ii(cp1[1] - ((temp_fac2 * cp2[1]) >> 16), 0);
594 rt[2] = max_ii(cp1[2] - ((temp_fac2 * cp2[2]) >> 16), 0);
595 rt[3] = cp1[3];
596
597 cp1 += 4;
598 cp2 += 4;
599 rt += 4;
600 }
601 }
602}
603
604static void do_sub_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
605{
606 float *rt1 = rect1;
607 float *rt2 = rect2;
608 float *rt = out;
609
610 float mfac = 1.0f - fac;
611
612 for (int i = 0; i < y; i++) {
613 for (int j = 0; j < x; j++) {
614 const float temp_fac = (1.0f - (rt1[3] * mfac)) * rt2[3];
615 rt[0] = max_ff(rt1[0] - temp_fac * rt2[0], 0.0f);
616 rt[1] = max_ff(rt1[1] - temp_fac * rt2[1], 0.0f);
617 rt[2] = max_ff(rt1[2] - temp_fac * rt2[2], 0.0f);
618 rt[3] = rt1[3];
619
620 rt1 += 4;
621 rt2 += 4;
622 rt += 4;
623 }
624 }
625}
626
627static void do_sub_effect(const SeqRenderData *context,
628 Sequence * /*seq*/,
629 float /*timeline_frame*/,
630 float fac,
631 const ImBuf *ibuf1,
632 const ImBuf *ibuf2,
633 int start_line,
634 int total_lines,
635 ImBuf *out)
636{
637 if (out->float_buffer.data) {
638 float *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
639
640 slice_get_float_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
641
642 do_sub_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
643 }
644 else {
645 uchar *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
646
647 slice_get_byte_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
648
649 do_sub_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
650 }
651}
652
654
655/* -------------------------------------------------------------------- */
658
659/* Must be > 0 or add pre-copy, etc to the function. */
660#define XOFF 8
661#define YOFF 8
662
663static void do_drop_effect_byte(float fac, int x, int y, uchar *rect2i, uchar *rect1i, uchar *outi)
664{
665 const int xoff = min_ii(XOFF, x);
666 const int yoff = min_ii(YOFF, y);
667
668 int temp_fac = int(70.0f * fac);
669
670 uchar *rt2 = rect2i + yoff * 4 * x;
671 uchar *rt1 = rect1i;
672 uchar *out = outi;
673 for (int i = 0; i < y - yoff; i++) {
674 memcpy(out, rt1, sizeof(*out) * xoff * 4);
675 rt1 += xoff * 4;
676 out += xoff * 4;
677
678 for (int j = xoff; j < x; j++) {
679 int temp_fac2 = ((temp_fac * rt2[3]) >> 8);
680
681 *(out++) = std::max(0, *rt1 - temp_fac2);
682 rt1++;
683 *(out++) = std::max(0, *rt1 - temp_fac2);
684 rt1++;
685 *(out++) = std::max(0, *rt1 - temp_fac2);
686 rt1++;
687 *(out++) = std::max(0, *rt1 - temp_fac2);
688 rt1++;
689 rt2 += 4;
690 }
691 rt2 += xoff * 4;
692 }
693 memcpy(out, rt1, sizeof(*out) * yoff * 4 * x);
694}
695
697 float fac, int x, int y, float *rect2i, float *rect1i, float *outi)
698{
699 const int xoff = min_ii(XOFF, x);
700 const int yoff = min_ii(YOFF, y);
701
702 float temp_fac = 70.0f * fac;
703
704 float *rt2 = rect2i + yoff * 4 * x;
705 float *rt1 = rect1i;
706 float *out = outi;
707 for (int i = 0; i < y - yoff; i++) {
708 memcpy(out, rt1, sizeof(*out) * xoff * 4);
709 rt1 += xoff * 4;
710 out += xoff * 4;
711
712 for (int j = xoff; j < x; j++) {
713 float temp_fac2 = temp_fac * rt2[3];
714
715 *(out++) = std::max(0.0f, *rt1 - temp_fac2);
716 rt1++;
717 *(out++) = std::max(0.0f, *rt1 - temp_fac2);
718 rt1++;
719 *(out++) = std::max(0.0f, *rt1 - temp_fac2);
720 rt1++;
721 *(out++) = std::max(0.0f, *rt1 - temp_fac2);
722 rt1++;
723 rt2 += 4;
724 }
725 rt2 += xoff * 4;
726 }
727 memcpy(out, rt1, sizeof(*out) * yoff * 4 * x);
728}
729
731
732/* -------------------------------------------------------------------- */
735
736static void do_mul_effect_byte(float fac, int x, int y, uchar *rect1, uchar *rect2, uchar *out)
737{
738 uchar *rt1 = rect1;
739 uchar *rt2 = rect2;
740 uchar *rt = out;
741
742 int temp_fac = int(256.0f * fac);
743
744 /* Formula:
745 * `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s;` // + centx
746 * `yaux = -s * px + c * py;` // + centy */
747
748 for (int i = 0; i < y; i++) {
749 for (int j = 0; j < x; j++) {
750 rt[0] = rt1[0] + ((temp_fac * rt1[0] * (rt2[0] - 255)) >> 16);
751 rt[1] = rt1[1] + ((temp_fac * rt1[1] * (rt2[1] - 255)) >> 16);
752 rt[2] = rt1[2] + ((temp_fac * rt1[2] * (rt2[2] - 255)) >> 16);
753 rt[3] = rt1[3] + ((temp_fac * rt1[3] * (rt2[3] - 255)) >> 16);
754
755 rt1 += 4;
756 rt2 += 4;
757 rt += 4;
758 }
759 }
760}
761
762static void do_mul_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
763{
764 float *rt1 = rect1;
765 float *rt2 = rect2;
766 float *rt = out;
767
768 /* Formula:
769 * `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a`. */
770
771 for (int i = 0; i < y; i++) {
772 for (int j = 0; j < x; j++) {
773 rt[0] = rt1[0] + fac * rt1[0] * (rt2[0] - 1.0f);
774 rt[1] = rt1[1] + fac * rt1[1] * (rt2[1] - 1.0f);
775 rt[2] = rt1[2] + fac * rt1[2] * (rt2[2] - 1.0f);
776 rt[3] = rt1[3] + fac * rt1[3] * (rt2[3] - 1.0f);
777
778 rt1 += 4;
779 rt2 += 4;
780 rt += 4;
781 }
782 }
783}
784
785static void do_mul_effect(const SeqRenderData *context,
786 Sequence * /*seq*/,
787 float /*timeline_frame*/,
788 float fac,
789 const ImBuf *ibuf1,
790 const ImBuf *ibuf2,
791 int start_line,
792 int total_lines,
793 ImBuf *out)
794{
795 if (out->float_buffer.data) {
796 float *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
797
798 slice_get_float_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
799
800 do_mul_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
801 }
802 else {
803 uchar *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
804
805 slice_get_byte_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
806
807 do_mul_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
808 }
809}
810
812
813/* -------------------------------------------------------------------- */
816
817/* blend_function has to be: void (T* dst, const T *src1, const T *src2) */
818template<typename T, typename Func>
820 float fac, int width, int height, const T *src1, T *src2, T *dst, Func blend_function)
821{
822 for (int y = 0; y < height; y++) {
823 for (int x = 0; x < width; x++) {
824 T achannel = src2[3];
825 src2[3] = T(achannel * fac);
826 blend_function(dst, src1, src2);
827 src2[3] = achannel;
828 dst[3] = src1[3];
829 src1 += 4;
830 src2 += 4;
831 dst += 4;
832 }
833 }
834}
835
837 float fac, int x, int y, const float *rect1, float *rect2, int btype, float *out)
838{
839 switch (btype) {
840 case SEQ_TYPE_ADD:
841 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_add_float);
842 break;
843 case SEQ_TYPE_SUB:
844 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_sub_float);
845 break;
846 case SEQ_TYPE_MUL:
847 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_mul_float);
848 break;
849 case SEQ_TYPE_DARKEN:
850 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_darken_float);
851 break;
853 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_burn_float);
854 break;
856 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_linearburn_float);
857 break;
858 case SEQ_TYPE_SCREEN:
859 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_screen_float);
860 break;
861 case SEQ_TYPE_LIGHTEN:
862 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_lighten_float);
863 break;
864 case SEQ_TYPE_DODGE:
865 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_dodge_float);
866 break;
867 case SEQ_TYPE_OVERLAY:
868 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_overlay_float);
869 break;
871 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_softlight_float);
872 break;
874 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_hardlight_float);
875 break;
877 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_pinlight_float);
878 break;
880 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_linearlight_float);
881 break;
883 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_vividlight_float);
884 break;
886 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_color_float);
887 break;
888 case SEQ_TYPE_HUE:
889 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_hue_float);
890 break;
892 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_saturation_float);
893 break;
894 case SEQ_TYPE_VALUE:
895 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_luminosity_float);
896 break;
898 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_difference_float);
899 break;
901 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_exclusion_float);
902 break;
903 default:
904 break;
905 }
906}
907
909 float fac, int x, int y, const uchar *rect1, uchar *rect2, int btype, uchar *out)
910{
911 switch (btype) {
912 case SEQ_TYPE_ADD:
913 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_add_byte);
914 break;
915 case SEQ_TYPE_SUB:
916 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_sub_byte);
917 break;
918 case SEQ_TYPE_MUL:
919 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_mul_byte);
920 break;
921 case SEQ_TYPE_DARKEN:
922 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_darken_byte);
923 break;
925 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_burn_byte);
926 break;
928 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_linearburn_byte);
929 break;
930 case SEQ_TYPE_SCREEN:
931 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_screen_byte);
932 break;
933 case SEQ_TYPE_LIGHTEN:
934 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_lighten_byte);
935 break;
936 case SEQ_TYPE_DODGE:
937 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_dodge_byte);
938 break;
939 case SEQ_TYPE_OVERLAY:
940 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_overlay_byte);
941 break;
943 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_softlight_byte);
944 break;
946 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_hardlight_byte);
947 break;
949 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_pinlight_byte);
950 break;
952 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_linearlight_byte);
953 break;
955 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_vividlight_byte);
956 break;
958 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_color_byte);
959 break;
960 case SEQ_TYPE_HUE:
961 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_hue_byte);
962 break;
964 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_saturation_byte);
965 break;
966 case SEQ_TYPE_VALUE:
967 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_luminosity_byte);
968 break;
970 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_difference_byte);
971 break;
973 apply_blend_function(fac, x, y, rect1, rect2, out, blend_color_exclusion_byte);
974 break;
975 default:
976 break;
977 }
978}
979
980static void do_blend_mode_effect(const SeqRenderData *context,
981 Sequence *seq,
982 float /*timeline_frame*/,
983 float fac,
984 const ImBuf *ibuf1,
985 const ImBuf *ibuf2,
986 int start_line,
987 int total_lines,
988 ImBuf *out)
989{
990 if (out->float_buffer.data) {
991 float *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
992 slice_get_float_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
994 fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
995 }
996 else {
997 uchar *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
998 slice_get_byte_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
1000 fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
1001 }
1002}
1003
1005
1006/* -------------------------------------------------------------------- */
1009
1011{
1013
1014 if (seq->effectdata) {
1015 MEM_freeN(seq->effectdata);
1016 }
1017 seq->effectdata = MEM_callocN(sizeof(ColorMixVars), "colormixvars");
1018 data = (ColorMixVars *)seq->effectdata;
1019 data->blend_effect = SEQ_TYPE_OVERLAY;
1020 data->factor = 1.0f;
1021}
1022
1023static void do_colormix_effect(const SeqRenderData *context,
1024 Sequence *seq,
1025 float /*timeline_frame*/,
1026 float /*fac*/,
1027 const ImBuf *ibuf1,
1028 const ImBuf *ibuf2,
1029 int start_line,
1030 int total_lines,
1031 ImBuf *out)
1032{
1033 float fac;
1034
1035 ColorMixVars *data = static_cast<ColorMixVars *>(seq->effectdata);
1036 fac = data->factor;
1037
1038 if (out->float_buffer.data) {
1039 float *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
1040 slice_get_float_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
1042 fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
1043 }
1044 else {
1045 uchar *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
1046 slice_get_byte_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
1048 fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
1049 }
1050}
1051
1053
1054/* -------------------------------------------------------------------- */
1057
1058struct WipeZone {
1059 float angle;
1060 int flip;
1061 int xo, yo;
1065 int type;
1067};
1068
1069static WipeZone precalc_wipe_zone(const WipeVars *wipe, int xo, int yo)
1070{
1071 WipeZone zone;
1072 zone.flip = (wipe->angle < 0.0f);
1073 zone.angle = tanf(fabsf(wipe->angle));
1074 zone.xo = xo;
1075 zone.yo = yo;
1076 zone.width = int(wipe->edgeWidth * ((xo + yo) / 2.0f));
1077 zone.pythangle = 1.0f / sqrtf(zone.angle * zone.angle + 1.0f);
1078 zone.clockWidth = wipe->edgeWidth * float(M_PI);
1079 zone.type = wipe->wipetype;
1080 zone.forward = wipe->forward != 0;
1081 return zone;
1082}
1083
1087static float in_band(float width, float dist, int side, int dir)
1088{
1089 float alpha;
1090
1091 if (width == 0) {
1092 return float(side);
1093 }
1094
1095 if (width < dist) {
1096 return float(side);
1097 }
1098
1099 if (side == 1) {
1100 alpha = (dist + 0.5f * width) / (width);
1101 }
1102 else {
1103 alpha = (0.5f * width - dist) / (width);
1104 }
1105
1106 if (dir == 0) {
1107 alpha = 1 - alpha;
1108 }
1109
1110 return alpha;
1111}
1112
1113static float check_zone(const WipeZone *wipezone, int x, int y, float fac)
1114{
1115 float posx, posy, hyp, hyp2, angle, hwidth, b1, b2, b3, pointdist;
1116 float temp1, temp2, temp3, temp4; /* some placeholder variables */
1117 int xo = wipezone->xo;
1118 int yo = wipezone->yo;
1119 float halfx = xo * 0.5f;
1120 float halfy = yo * 0.5f;
1121 float widthf, output = 0;
1122 int width;
1123
1124 if (wipezone->flip) {
1125 x = xo - x;
1126 }
1127 angle = wipezone->angle;
1128
1129 if (wipezone->forward) {
1130 posx = fac * xo;
1131 posy = fac * yo;
1132 }
1133 else {
1134 posx = xo - fac * xo;
1135 posy = yo - fac * yo;
1136 }
1137
1138 switch (wipezone->type) {
1139 case DO_SINGLE_WIPE:
1140 width = min_ii(wipezone->width, fac * yo);
1141 width = min_ii(width, yo - fac * yo);
1142
1143 if (angle == 0.0f) {
1144 b1 = posy;
1145 b2 = y;
1146 hyp = fabsf(y - posy);
1147 }
1148 else {
1149 b1 = posy - (-angle) * posx;
1150 b2 = y - (-angle) * x;
1151 hyp = fabsf(angle * x + y + (-posy - angle * posx)) * wipezone->pythangle;
1152 }
1153
1154 if (angle < 0) {
1155 temp1 = b1;
1156 b1 = b2;
1157 b2 = temp1;
1158 }
1159
1160 if (wipezone->forward) {
1161 if (b1 < b2) {
1162 output = in_band(width, hyp, 1, 1);
1163 }
1164 else {
1165 output = in_band(width, hyp, 0, 1);
1166 }
1167 }
1168 else {
1169 if (b1 < b2) {
1170 output = in_band(width, hyp, 0, 1);
1171 }
1172 else {
1173 output = in_band(width, hyp, 1, 1);
1174 }
1175 }
1176 break;
1177
1178 case DO_DOUBLE_WIPE:
1179 if (!wipezone->forward) {
1180 fac = 1.0f - fac; /* Go the other direction */
1181 }
1182
1183 width = wipezone->width; /* calculate the blur width */
1184 hwidth = width * 0.5f;
1185 if (angle == 0) {
1186 b1 = posy * 0.5f;
1187 b3 = yo - posy * 0.5f;
1188 b2 = y;
1189
1190 hyp = fabsf(y - posy * 0.5f);
1191 hyp2 = fabsf(y - (yo - posy * 0.5f));
1192 }
1193 else {
1194 b1 = posy * 0.5f - (-angle) * posx * 0.5f;
1195 b3 = (yo - posy * 0.5f) - (-angle) * (xo - posx * 0.5f);
1196 b2 = y - (-angle) * x;
1197
1198 hyp = fabsf(angle * x + y + (-posy * 0.5f - angle * posx * 0.5f)) * wipezone->pythangle;
1199 hyp2 = fabsf(angle * x + y + (-(yo - posy * 0.5f) - angle * (xo - posx * 0.5f))) *
1200 wipezone->pythangle;
1201 }
1202
1203 hwidth = min_ff(hwidth, fabsf(b3 - b1) / 2.0f);
1204
1205 if (b2 < b1 && b2 < b3) {
1206 output = in_band(hwidth, hyp, 0, 1);
1207 }
1208 else if (b2 > b1 && b2 > b3) {
1209 output = in_band(hwidth, hyp2, 0, 1);
1210 }
1211 else {
1212 if (hyp < hwidth && hyp2 > hwidth) {
1213 output = in_band(hwidth, hyp, 1, 1);
1214 }
1215 else if (hyp > hwidth && hyp2 < hwidth) {
1216 output = in_band(hwidth, hyp2, 1, 1);
1217 }
1218 else {
1219 output = in_band(hwidth, hyp2, 1, 1) * in_band(hwidth, hyp, 1, 1);
1220 }
1221 }
1222 if (!wipezone->forward) {
1223 output = 1 - output;
1224 }
1225 break;
1226 case DO_CLOCK_WIPE:
1227 /*
1228 * temp1: angle of effect center in rads
1229 * temp2: angle of line through (halfx, halfy) and (x, y) in rads
1230 * temp3: angle of low side of blur
1231 * temp4: angle of high side of blur
1232 */
1233 output = 1.0f - fac;
1234 widthf = wipezone->clockWidth;
1235 temp1 = 2.0f * float(M_PI) * fac;
1236
1237 if (wipezone->forward) {
1238 temp1 = 2.0f * float(M_PI) - temp1;
1239 }
1240
1241 x = x - halfx;
1242 y = y - halfy;
1243
1244 temp2 = atan2f(y, x);
1245 if (temp2 < 0.0f) {
1246 temp2 += 2.0f * float(M_PI);
1247 }
1248
1249 if (wipezone->forward) {
1250 temp3 = temp1 - widthf * fac;
1251 temp4 = temp1 + widthf * (1 - fac);
1252 }
1253 else {
1254 temp3 = temp1 - widthf * (1 - fac);
1255 temp4 = temp1 + widthf * fac;
1256 }
1257 if (temp3 < 0) {
1258 temp3 = 0;
1259 }
1260 if (temp4 > 2.0f * float(M_PI)) {
1261 temp4 = 2.0f * float(M_PI);
1262 }
1263
1264 if (temp2 < temp3) {
1265 output = 0;
1266 }
1267 else if (temp2 > temp4) {
1268 output = 1;
1269 }
1270 else {
1271 output = (temp2 - temp3) / (temp4 - temp3);
1272 }
1273 if (x == 0 && y == 0) {
1274 output = 1;
1275 }
1276 if (output != output) {
1277 output = 1;
1278 }
1279 if (wipezone->forward) {
1280 output = 1 - output;
1281 }
1282 break;
1283 case DO_IRIS_WIPE:
1284 if (xo > yo) {
1285 yo = xo;
1286 }
1287 else {
1288 xo = yo;
1289 }
1290
1291 if (!wipezone->forward) {
1292 fac = 1 - fac;
1293 }
1294
1295 width = wipezone->width;
1296 hwidth = width * 0.5f;
1297
1298 temp1 = (halfx - (halfx)*fac);
1299 pointdist = hypotf(temp1, temp1);
1300
1301 temp2 = hypotf(halfx - x, halfy - y);
1302 if (temp2 > pointdist) {
1303 output = in_band(hwidth, fabsf(temp2 - pointdist), 0, 1);
1304 }
1305 else {
1306 output = in_band(hwidth, fabsf(temp2 - pointdist), 1, 1);
1307 }
1308
1309 if (!wipezone->forward) {
1310 output = 1 - output;
1311 }
1312
1313 break;
1314 }
1315 if (output < 0) {
1316 output = 0;
1317 }
1318 else if (output > 1) {
1319 output = 1;
1320 }
1321 return output;
1322}
1323
1325{
1326 if (seq->effectdata) {
1327 MEM_freeN(seq->effectdata);
1328 }
1329
1330 seq->effectdata = MEM_callocN(sizeof(WipeVars), "wipevars");
1331}
1332
1334{
1335 return 2;
1336}
1337
1338static void free_wipe_effect(Sequence *seq, const bool /*do_id_user*/)
1339{
1340 MEM_SAFE_FREE(seq->effectdata);
1341}
1342
1343static void copy_wipe_effect(Sequence *dst, const Sequence *src, const int /*flag*/)
1344{
1345 dst->effectdata = MEM_dupallocN(src->effectdata);
1346}
1347
1348template<typename T>
1349static void do_wipe_effect(
1350 const Sequence *seq, float fac, int width, int height, const T *rect1, const T *rect2, T *out)
1351{
1352 using namespace blender;
1353 const WipeVars *wipe = (const WipeVars *)seq->effectdata;
1354 const WipeZone wipezone = precalc_wipe_zone(wipe, width, height);
1355
1356 threading::parallel_for(IndexRange(height), 64, [&](const IndexRange y_range) {
1357 const T *cp1 = rect1 ? rect1 + y_range.first() * width * 4 : nullptr;
1358 const T *cp2 = rect2 ? rect2 + y_range.first() * width * 4 : nullptr;
1359 T *rt = out + y_range.first() * width * 4;
1360 for (const int y : y_range) {
1361 for (int x = 0; x < width; x++) {
1362 float check = check_zone(&wipezone, x, y, fac);
1363 if (check) {
1364 if (cp1) {
1365 float4 col1 = load_premul_pixel(cp1);
1366 float4 col2 = load_premul_pixel(cp2);
1367 float4 col = col1 * check + col2 * (1.0f - check);
1369 }
1370 else {
1372 }
1373 }
1374 else {
1375 if (cp2) {
1376 memcpy(rt, cp2, sizeof(T) * 4);
1377 }
1378 else {
1380 }
1381 }
1382
1383 rt += 4;
1384 if (cp1 != nullptr) {
1385 cp1 += 4;
1386 }
1387 if (cp2 != nullptr) {
1388 cp2 += 4;
1389 }
1390 }
1391 }
1392 });
1393}
1394
1395static ImBuf *do_wipe_effect(const SeqRenderData *context,
1396 Sequence *seq,
1397 float /*timeline_frame*/,
1398 float fac,
1399 ImBuf *ibuf1,
1400 ImBuf *ibuf2)
1401{
1402 ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2);
1403
1404 if (out->float_buffer.data) {
1406 fac,
1407 context->rectx,
1408 context->recty,
1409 ibuf1->float_buffer.data,
1410 ibuf2->float_buffer.data,
1411 out->float_buffer.data);
1412 }
1413 else {
1415 fac,
1416 context->rectx,
1417 context->recty,
1418 ibuf1->byte_buffer.data,
1419 ibuf2->byte_buffer.data,
1420 out->byte_buffer.data);
1421 }
1422
1423 return out;
1424}
1425
1427
1428/* -------------------------------------------------------------------- */
1431
1433{
1435
1436 if (seq->effectdata) {
1437 MEM_freeN(seq->effectdata);
1438 }
1439
1440 seq->effectdata = MEM_callocN(sizeof(TransformVars), "transformvars");
1441
1442 transform = (TransformVars *)seq->effectdata;
1443
1444 transform->ScalexIni = 1.0f;
1445 transform->ScaleyIni = 1.0f;
1446
1447 transform->xIni = 0.0f;
1448 transform->yIni = 0.0f;
1449
1450 transform->rotIni = 0.0f;
1451
1452 transform->interpolation = 1;
1453 transform->percent = 1;
1454 transform->uniform_scale = 0;
1455}
1456
1458{
1459 return 1;
1460}
1461
1462static void free_transform_effect(Sequence *seq, const bool /*do_id_user*/)
1463{
1464 MEM_SAFE_FREE(seq->effectdata);
1465}
1466
1467static void copy_transform_effect(Sequence *dst, const Sequence *src, const int /*flag*/)
1468{
1469 dst->effectdata = MEM_dupallocN(src->effectdata);
1470}
1471
1472static void transform_image(int x,
1473 int y,
1474 int start_line,
1475 int total_lines,
1476 const ImBuf *ibuf,
1477 ImBuf *out,
1478 float scale_x,
1479 float scale_y,
1480 float translate_x,
1481 float translate_y,
1482 float rotate,
1483 int interpolation)
1484{
1485 /* Rotate */
1486 float s = sinf(rotate);
1487 float c = cosf(rotate);
1488
1489 float4 *dst_fl = reinterpret_cast<float4 *>(out->float_buffer.data);
1490 uchar4 *dst_ch = reinterpret_cast<uchar4 *>(out->byte_buffer.data);
1491
1492 size_t offset = size_t(x) * start_line;
1493 for (int yi = start_line; yi < start_line + total_lines; yi++) {
1494 for (int xi = 0; xi < x; xi++) {
1495 /* Translate point. */
1496 float xt = xi - translate_x;
1497 float yt = yi - translate_y;
1498
1499 /* Rotate point with center ref. */
1500 float xr = c * xt + s * yt;
1501 float yr = -s * xt + c * yt;
1502
1503 /* Scale point with center ref. */
1504 xt = xr / scale_x;
1505 yt = yr / scale_y;
1506
1507 /* Undo reference center point. */
1508 xt += (x / 2.0f);
1509 yt += (y / 2.0f);
1510
1511 /* interpolate */
1512 switch (interpolation) {
1513 case 0:
1514 if (dst_fl) {
1515 dst_fl[offset] = imbuf::interpolate_nearest_border_fl(ibuf, xt, yt);
1516 }
1517 else {
1518 dst_ch[offset] = imbuf::interpolate_nearest_border_byte(ibuf, xt, yt);
1519 }
1520 break;
1521 case 1:
1522 if (dst_fl) {
1523 dst_fl[offset] = imbuf::interpolate_bilinear_border_fl(ibuf, xt, yt);
1524 }
1525 else {
1526 dst_ch[offset] = imbuf::interpolate_bilinear_border_byte(ibuf, xt, yt);
1527 }
1528 break;
1529 case 2:
1530 if (dst_fl) {
1531 dst_fl[offset] = imbuf::interpolate_cubic_bspline_fl(ibuf, xt, yt);
1532 }
1533 else {
1534 dst_ch[offset] = imbuf::interpolate_cubic_bspline_byte(ibuf, xt, yt);
1535 }
1536 break;
1537 }
1538 offset++;
1539 }
1540 }
1541}
1542
1543static void do_transform_effect(const SeqRenderData *context,
1544 Sequence *seq,
1545 float /*timeline_frame*/,
1546 float /*fac*/,
1547 const ImBuf *ibuf1,
1548 const ImBuf * /*ibuf2*/,
1549 int start_line,
1550 int total_lines,
1551 ImBuf *out)
1552{
1553 TransformVars *transform = (TransformVars *)seq->effectdata;
1554 float scale_x, scale_y, translate_x, translate_y, rotate_radians;
1555
1556 /* Scale */
1557 if (transform->uniform_scale) {
1558 scale_x = scale_y = transform->ScalexIni;
1559 }
1560 else {
1561 scale_x = transform->ScalexIni;
1562 scale_y = transform->ScaleyIni;
1563 }
1564
1565 int x = context->rectx;
1566 int y = context->recty;
1567
1568 /* Translate */
1569 if (!transform->percent) {
1570 /* Compensate text size for preview render size. */
1571 double proxy_size_comp = context->scene->r.size / 100.0;
1572 if (context->preview_render_size != SEQ_RENDER_SIZE_SCENE) {
1573 proxy_size_comp = SEQ_rendersize_to_scale_factor(context->preview_render_size);
1574 }
1575
1576 translate_x = transform->xIni * proxy_size_comp + (x / 2.0f);
1577 translate_y = transform->yIni * proxy_size_comp + (y / 2.0f);
1578 }
1579 else {
1580 translate_x = x * (transform->xIni / 100.0f) + (x / 2.0f);
1581 translate_y = y * (transform->yIni / 100.0f) + (y / 2.0f);
1582 }
1583
1584 /* Rotate */
1585 rotate_radians = DEG2RADF(transform->rotIni);
1586
1588 y,
1589 start_line,
1590 total_lines,
1591 ibuf1,
1592 out,
1593 scale_x,
1594 scale_y,
1595 translate_x,
1596 translate_y,
1597 rotate_radians,
1598 transform->interpolation);
1599}
1600
1602
1603/* -------------------------------------------------------------------- */
1606
1608 const float4 *src, float4 *map, int width, int height, float blur, int quality)
1609{
1610 using namespace blender;
1611
1612 /* If we're not really blurring, bail out */
1613 if (blur <= 0) {
1614 return;
1615 }
1616
1617 /* If result would be no blurring, early out. */
1618 const int halfWidth = ((quality + 1) * blur);
1619 if (halfWidth == 0) {
1620 return;
1621 }
1622
1623 Array<float4> temp(width * height);
1624
1625 /* Initialize the gaussian filter. @TODO: use code from RE_filter_value */
1626 Array<float> filter(halfWidth * 2);
1627 const float k = -1.0f / (2.0f * float(M_PI) * blur * blur);
1628 float weight = 0;
1629 for (int ix = 0; ix < halfWidth; ix++) {
1630 weight = float(exp(k * (ix * ix)));
1631 filter[halfWidth - ix] = weight;
1632 filter[halfWidth + ix] = weight;
1633 }
1634 filter[0] = weight;
1635 /* Normalize the array */
1636 float fval = 0;
1637 for (int ix = 0; ix < halfWidth * 2; ix++) {
1638 fval += filter[ix];
1639 }
1640 for (int ix = 0; ix < halfWidth * 2; ix++) {
1641 filter[ix] /= fval;
1642 }
1643
1644 /* Blur the rows: read map, write temp */
1645 threading::parallel_for(IndexRange(height), 32, [&](const IndexRange y_range) {
1646 for (const int y : y_range) {
1647 for (int x = 0; x < width; x++) {
1648 float4 curColor = float4(0.0f);
1649 int xmin = math::max(x - halfWidth, 0);
1650 int xmax = math::min(x + halfWidth, width);
1651 for (int nx = xmin, index = (xmin - x) + halfWidth; nx < xmax; nx++, index++) {
1652 curColor += map[nx + y * width] * filter[index];
1653 }
1654 temp[x + y * width] = curColor;
1655 }
1656 }
1657 });
1658
1659 /* Blur the columns: read temp, write map */
1660 threading::parallel_for(IndexRange(width), 32, [&](const IndexRange x_range) {
1661 const float4 one = float4(1.0f);
1662 for (const int x : x_range) {
1663 for (int y = 0; y < height; y++) {
1664 float4 curColor = float4(0.0f);
1665 int ymin = math::max(y - halfWidth, 0);
1666 int ymax = math::min(y + halfWidth, height);
1667 for (int ny = ymin, index = (ymin - y) + halfWidth; ny < ymax; ny++, index++) {
1668 curColor += temp[x + ny * width] * filter[index];
1669 }
1670 if (src != nullptr) {
1671 curColor = math::min(one, src[x + y * width] + curColor);
1672 }
1673 map[x + y * width] = curColor;
1674 }
1675 }
1676 });
1677}
1678
1679static void blur_isolate_highlights(const float4 *in,
1680 float4 *out,
1681 int width,
1682 int height,
1683 float threshold,
1684 float boost,
1685 float clamp)
1686{
1687 using namespace blender;
1688 threading::parallel_for(IndexRange(height), 64, [&](const IndexRange y_range) {
1689 const float4 clampv = float4(clamp);
1690 for (const int y : y_range) {
1691 int index = y * width;
1692 for (int x = 0; x < width; x++, index++) {
1693
1694 /* Isolate the intensity */
1695 float intensity = (in[index].x + in[index].y + in[index].z - threshold);
1696 float4 val;
1697 if (intensity > 0) {
1698 val = math::min(clampv, in[index] * (boost * intensity));
1699 }
1700 else {
1701 val = float4(0.0f);
1702 }
1703 out[index] = val;
1704 }
1705 }
1706 });
1707}
1708
1710{
1711 GlowVars *glow;
1712
1713 if (seq->effectdata) {
1714 MEM_freeN(seq->effectdata);
1715 }
1716
1717 seq->effectdata = MEM_callocN(sizeof(GlowVars), "glowvars");
1718
1719 glow = (GlowVars *)seq->effectdata;
1720 glow->fMini = 0.25;
1721 glow->fClamp = 1.0;
1722 glow->fBoost = 0.5;
1723 glow->dDist = 3.0;
1724 glow->dQuality = 3;
1725 glow->bNoComp = 0;
1726}
1727
1729{
1730 return 1;
1731}
1732
1733static void free_glow_effect(Sequence *seq, const bool /*do_id_user*/)
1734{
1735 MEM_SAFE_FREE(seq->effectdata);
1736}
1737
1738static void copy_glow_effect(Sequence *dst, const Sequence *src, const int /*flag*/)
1739{
1740 dst->effectdata = MEM_dupallocN(src->effectdata);
1741}
1742
1744 int render_size,
1745 float fac,
1746 int x,
1747 int y,
1748 uchar *rect1,
1749 uchar * /*rect2*/,
1750 uchar *out)
1751{
1752 using namespace blender;
1753 GlowVars *glow = (GlowVars *)seq->effectdata;
1754
1755 Array<float4> inbuf(x * y);
1756 Array<float4> outbuf(x * y);
1757
1758 using namespace blender;
1759 IMB_colormanagement_transform_from_byte_threaded(*inbuf.data(), rect1, x, y, 4, "sRGB", "sRGB");
1760
1762 inbuf.data(), outbuf.data(), x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp);
1763 glow_blur_bitmap(glow->bNoComp ? nullptr : inbuf.data(),
1764 outbuf.data(),
1765 x,
1766 y,
1767 glow->dDist * (render_size / 100.0f),
1768 glow->dQuality);
1769
1770 threading::parallel_for(IndexRange(y), 64, [&](const IndexRange y_range) {
1771 size_t offset = y_range.first() * x;
1772 IMB_buffer_byte_from_float(out + offset * 4,
1773 *(outbuf.data() + offset),
1774 4,
1775 0.0f,
1778 true,
1779 x,
1780 y_range.size(),
1781 x,
1782 x);
1783 });
1784}
1785
1787 int render_size,
1788 float fac,
1789 int x,
1790 int y,
1791 float *rect1,
1792 float * /*rect2*/,
1793 float *out)
1794{
1795 using namespace blender;
1796 float4 *outbuf = reinterpret_cast<float4 *>(out);
1797 float4 *inbuf = reinterpret_cast<float4 *>(rect1);
1798 GlowVars *glow = (GlowVars *)seq->effectdata;
1799
1801 inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp);
1802 glow_blur_bitmap(glow->bNoComp ? nullptr : inbuf,
1803 outbuf,
1804 x,
1805 y,
1806 glow->dDist * (render_size / 100.0f),
1807 glow->dQuality);
1808}
1809
1810static ImBuf *do_glow_effect(const SeqRenderData *context,
1811 Sequence *seq,
1812 float /*timeline_frame*/,
1813 float fac,
1814 ImBuf *ibuf1,
1815 ImBuf *ibuf2)
1816{
1817 ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2);
1818
1819 int render_size = 100 * context->rectx / context->scene->r.xsch;
1820
1821 if (out->float_buffer.data) {
1823 render_size,
1824 fac,
1825 context->rectx,
1826 context->recty,
1827 ibuf1->float_buffer.data,
1828 nullptr,
1829 out->float_buffer.data);
1830 }
1831 else {
1833 render_size,
1834 fac,
1835 context->rectx,
1836 context->recty,
1837 ibuf1->byte_buffer.data,
1838 nullptr,
1839 out->byte_buffer.data);
1840 }
1841
1842 return out;
1843}
1844
1846
1847/* -------------------------------------------------------------------- */
1850
1852{
1853 SolidColorVars *cv;
1854
1855 if (seq->effectdata) {
1856 MEM_freeN(seq->effectdata);
1857 }
1858
1859 seq->effectdata = MEM_callocN(sizeof(SolidColorVars), "solidcolor");
1860
1861 cv = (SolidColorVars *)seq->effectdata;
1862 cv->col[0] = cv->col[1] = cv->col[2] = 0.5;
1863}
1864
1866{
1867 return 0;
1868}
1869
1870static void free_solid_color(Sequence *seq, const bool /*do_id_user*/)
1871{
1872 MEM_SAFE_FREE(seq->effectdata);
1873}
1874
1875static void copy_solid_color(Sequence *dst, const Sequence *src, const int /*flag*/)
1876{
1877 dst->effectdata = MEM_dupallocN(src->effectdata);
1878}
1879
1880static StripEarlyOut early_out_color(const Sequence * /*seq*/, float /*fac*/)
1881{
1883}
1884
1885static ImBuf *do_solid_color(const SeqRenderData *context,
1886 Sequence *seq,
1887 float /*timeline_frame*/,
1888 float /*fac*/,
1889 ImBuf *ibuf1,
1890 ImBuf *ibuf2)
1891{
1892 using namespace blender;
1893 ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2);
1894
1895 SolidColorVars *cv = (SolidColorVars *)seq->effectdata;
1896
1897 threading::parallel_for(IndexRange(out->y), 64, [&](const IndexRange y_range) {
1898 if (out->byte_buffer.data) {
1899 /* Byte image. */
1900 uchar color[4];
1901 rgb_float_to_uchar(color, cv->col);
1902 color[3] = 255;
1903
1904 uchar *dst = out->byte_buffer.data + y_range.first() * out->x * 4;
1905 uchar *dst_end = dst + y_range.size() * out->x * 4;
1906 while (dst < dst_end) {
1907 memcpy(dst, color, sizeof(color));
1908 dst += 4;
1909 }
1910 }
1911 else {
1912 /* Float image. */
1913 float color[4];
1914 color[0] = cv->col[0];
1915 color[1] = cv->col[1];
1916 color[2] = cv->col[2];
1917 color[3] = 1.0f;
1918
1919 float *dst = out->float_buffer.data + y_range.first() * out->x * 4;
1920 float *dst_end = dst + y_range.size() * out->x * 4;
1921 while (dst < dst_end) {
1922 memcpy(dst, color, sizeof(color));
1923 dst += 4;
1924 }
1925 }
1926 });
1927
1928 out->planes = R_IMF_PLANES_RGB;
1929
1930 return out;
1931}
1932
1934
1935/* -------------------------------------------------------------------- */
1938
1941{
1942 return 0;
1943}
1944
1945static StripEarlyOut early_out_multicam(const Sequence * /*seq*/, float /*fac*/)
1946{
1948}
1949
1950static ImBuf *do_multicam(const SeqRenderData *context,
1951 Sequence *seq,
1952 float timeline_frame,
1953 float /*fac*/,
1954 ImBuf * /*ibuf1*/,
1955 ImBuf * /*ibuf2*/)
1956{
1957 ImBuf *out;
1958 Editing *ed;
1959
1960 if (seq->multicam_source == 0 || seq->multicam_source >= seq->machine) {
1961 return nullptr;
1962 }
1963
1964 ed = context->scene->ed;
1965 if (!ed) {
1966 return nullptr;
1967 }
1968 ListBase *seqbasep = SEQ_get_seqbase_by_seq(context->scene, seq);
1969 ListBase *channels = SEQ_get_channels_by_seq(&ed->seqbase, &ed->channels, seq);
1970 if (!seqbasep) {
1971 return nullptr;
1972 }
1973
1975 context, timeline_frame, seq->multicam_source, channels, seqbasep);
1976
1977 return out;
1978}
1979
1981
1982/* -------------------------------------------------------------------- */
1985
1988{
1989 return 0;
1990}
1991
1992static StripEarlyOut early_out_adjustment(const Sequence * /*seq*/, float /*fac*/)
1993{
1995}
1996
1997static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, float timeline_frame)
1998{
1999 Editing *ed;
2000 ImBuf *i = nullptr;
2001
2002 ed = context->scene->ed;
2003
2004 ListBase *seqbasep = SEQ_get_seqbase_by_seq(context->scene, seq);
2005 ListBase *channels = SEQ_get_channels_by_seq(&ed->seqbase, &ed->channels, seq);
2006
2007 /* Clamp timeline_frame to strip range so it behaves as if it had "still frame" offset (last
2008 * frame is static after end of strip). This is how most strips behave. This way transition
2009 * effects that doesn't overlap or speed effect can't fail rendering outside of strip range. */
2010 timeline_frame = clamp_i(timeline_frame,
2011 SEQ_time_left_handle_frame_get(context->scene, seq),
2012 SEQ_time_right_handle_frame_get(context->scene, seq) - 1);
2013
2014 if (seq->machine > 1) {
2016 context, timeline_frame, seq->machine - 1, channels, seqbasep);
2017 }
2018
2019 /* Found nothing? so let's work the way up the meta-strip stack, so
2020 * that it is possible to group a bunch of adjustment strips into
2021 * a meta-strip and have that work on everything below the meta-strip. */
2022
2023 if (!i) {
2024 Sequence *meta;
2025
2026 meta = SEQ_find_metastrip_by_sequence(&ed->seqbase, nullptr, seq);
2027
2028 if (meta) {
2029 i = do_adjustment_impl(context, meta, timeline_frame);
2030 }
2031 }
2032
2033 return i;
2034}
2035
2036static ImBuf *do_adjustment(const SeqRenderData *context,
2037 Sequence *seq,
2038 float timeline_frame,
2039 float /*fac*/,
2040 ImBuf * /*ibuf1*/,
2041 ImBuf * /*ibuf2*/)
2042{
2043 ImBuf *out;
2044 Editing *ed;
2045
2046 ed = context->scene->ed;
2047
2048 if (!ed) {
2049 return nullptr;
2050 }
2051
2052 out = do_adjustment_impl(context, seq, timeline_frame);
2053
2054 return out;
2055}
2056
2058
2059/* -------------------------------------------------------------------- */
2062
2064{
2066
2067 if (seq->effectdata) {
2068 MEM_freeN(seq->effectdata);
2069 }
2070
2071 seq->effectdata = MEM_callocN(sizeof(SpeedControlVars), "speedcontrolvars");
2072
2073 v = (SpeedControlVars *)seq->effectdata;
2074 v->speed_control_type = SEQ_SPEED_STRETCH;
2075 v->speed_fader = 1.0f;
2076 v->speed_fader_length = 0.0f;
2077 v->speed_fader_frame_number = 0.0f;
2078}
2079
2081{
2082 SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
2083 v->frameMap = nullptr;
2084}
2085
2087{
2088 return 1;
2089}
2090
2091static void free_speed_effect(Sequence *seq, const bool /*do_id_user*/)
2092{
2093 SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
2094 if (v->frameMap) {
2095 MEM_freeN(v->frameMap);
2096 }
2097 MEM_SAFE_FREE(seq->effectdata);
2098}
2099
2100static void copy_speed_effect(Sequence *dst, const Sequence *src, const int /*flag*/)
2101{
2103 dst->effectdata = MEM_dupallocN(src->effectdata);
2104 v = (SpeedControlVars *)dst->effectdata;
2105 v->frameMap = nullptr;
2106}
2107
2108static StripEarlyOut early_out_speed(const Sequence * /*seq*/, float /*fac*/)
2109{
2111}
2112
2114{
2115 return id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, nullptr);
2116}
2117
2119{
2120 const int effect_strip_length = SEQ_time_right_handle_frame_get(scene, seq) -
2122
2123 if ((seq->seq1 == nullptr) || (effect_strip_length < 1)) {
2124 return; /* Make COVERITY happy and check for (CID 598) input strip. */
2125 }
2126
2128 if (fcu == nullptr) {
2129 return;
2130 }
2131
2132 SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
2133 if (v->frameMap) {
2134 MEM_freeN(v->frameMap);
2135 }
2136
2137 v->frameMap = static_cast<float *>(MEM_mallocN(sizeof(float) * effect_strip_length, __func__));
2138 v->frameMap[0] = 0.0f;
2139
2140 float target_frame = 0;
2141 for (int frame_index = 1; frame_index < effect_strip_length; frame_index++) {
2142 target_frame += evaluate_fcurve(fcu, SEQ_time_left_handle_frame_get(scene, seq) + frame_index);
2143 const int target_frame_max = SEQ_time_strip_length_get(scene, seq->seq1);
2144 CLAMP(target_frame, 0, target_frame_max);
2145 v->frameMap[frame_index] = target_frame;
2146 }
2147}
2148
2150{
2151 const SpeedControlVars *v = (SpeedControlVars *)seq->effectdata;
2152 if (v->frameMap != nullptr) {
2153 return;
2154 }
2155
2157}
2158
2160 Sequence *seq_speed,
2161 float timeline_frame,
2162 int input)
2163{
2164 if (seq_speed->seq1 == nullptr) {
2165 return 0.0f;
2166 }
2167
2168 SEQ_effect_handle_get(seq_speed); /* Ensure, that data are initialized. */
2169 int frame_index = round_fl_to_int(SEQ_give_frame_index(scene, seq_speed, timeline_frame));
2170 SpeedControlVars *s = (SpeedControlVars *)seq_speed->effectdata;
2171 const Sequence *source = seq_speed->seq1;
2172
2173 float target_frame = 0.0f;
2174 switch (s->speed_control_type) {
2175 case SEQ_SPEED_STRETCH: {
2176 /* Only right handle controls effect speed! */
2177 const float target_content_length = SEQ_time_strip_length_get(scene, source) -
2178 source->startofs;
2179 const float speed_effetct_length = SEQ_time_right_handle_frame_get(scene, seq_speed) -
2180 SEQ_time_left_handle_frame_get(scene, seq_speed);
2181 const float ratio = frame_index / speed_effetct_length;
2182 target_frame = target_content_length * ratio;
2183 break;
2184 }
2185 case SEQ_SPEED_MULTIPLY: {
2186 const FCurve *fcu = seq_effect_speed_speed_factor_curve_get(scene, seq_speed);
2187 if (fcu != nullptr) {
2188 seq_effect_speed_frame_map_ensure(scene, seq_speed);
2189 target_frame = s->frameMap[frame_index];
2190 }
2191 else {
2192 target_frame = frame_index * s->speed_fader;
2193 }
2194 break;
2195 }
2196 case SEQ_SPEED_LENGTH:
2197 target_frame = SEQ_time_strip_length_get(scene, source) * (s->speed_fader_length / 100.0f);
2198 break;
2200 target_frame = s->speed_fader_frame_number;
2201 break;
2202 }
2203
2204 CLAMP(target_frame, 0, SEQ_time_strip_length_get(scene, source));
2205 target_frame += seq_speed->start;
2206
2207 /* No interpolation. */
2208 if ((s->flags & SEQ_SPEED_USE_INTERPOLATION) == 0) {
2209 return target_frame;
2210 }
2211
2212 /* Interpolation is used, switch between current and next frame based on which input is
2213 * requested. */
2214 return input == 0 ? target_frame : ceil(target_frame);
2215}
2216
2218 Sequence *seq_speed,
2219 float timeline_frame)
2220{
2221 const float target_frame = seq_speed_effect_target_frame_get(
2222 scene, seq_speed, timeline_frame, 0);
2223 return target_frame - floor(target_frame);
2224}
2225
2226static ImBuf *do_speed_effect(const SeqRenderData *context,
2227 Sequence *seq,
2228 float timeline_frame,
2229 float fac,
2230 ImBuf *ibuf1,
2231 ImBuf *ibuf2)
2232{
2233 const SpeedControlVars *s = (SpeedControlVars *)seq->effectdata;
2235 ImBuf *out;
2236
2238 fac = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame);
2239 /* Current frame is ibuf1, next frame is ibuf2. */
2241 &cross_effect, context, nullptr, timeline_frame, fac, ibuf1, ibuf2);
2242 return out;
2243 }
2244
2245 /* No interpolation. */
2246 return IMB_dupImBuf(ibuf1);
2247}
2248
2250
2251/* -------------------------------------------------------------------- */
2254
2255static void do_overdrop_effect(const SeqRenderData *context,
2256 Sequence * /*seq*/,
2257 float /*timeline_frame*/,
2258 float fac,
2259 const ImBuf *ibuf1,
2260 const ImBuf *ibuf2,
2261 int start_line,
2262 int total_lines,
2263 ImBuf *out)
2264{
2265 int x = context->rectx;
2266 int y = total_lines;
2267
2268 if (out->float_buffer.data) {
2269 float *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
2270
2271 slice_get_float_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
2272
2273 do_drop_effect_float(fac, x, y, rect1, rect2, rect_out);
2274 do_alphaover_effect(fac, x, y, rect1, rect2, rect_out);
2275 }
2276 else {
2277 uchar *rect1 = nullptr, *rect2 = nullptr, *rect_out = nullptr;
2278
2279 slice_get_byte_buffers(context, ibuf1, ibuf2, out, start_line, &rect1, &rect2, &rect_out);
2280
2281 do_drop_effect_byte(fac, x, y, rect1, rect2, rect_out);
2282 do_alphaover_effect(fac, x, y, rect1, rect2, rect_out);
2283 }
2284}
2285
2287
2288/* -------------------------------------------------------------------- */
2291
2293{
2294 if (seq->effectdata) {
2295 MEM_freeN(seq->effectdata);
2296 }
2297
2298 seq->effectdata = MEM_callocN(sizeof(WipeVars), "wipevars");
2299}
2300
2302{
2303 return 1;
2304}
2305
2306static void free_gaussian_blur_effect(Sequence *seq, const bool /*do_id_user*/)
2307{
2308 MEM_SAFE_FREE(seq->effectdata);
2309}
2310
2311static void copy_gaussian_blur_effect(Sequence *dst, const Sequence *src, const int /*flag*/)
2312{
2313 dst->effectdata = MEM_dupallocN(src->effectdata);
2314}
2315
2317{
2318 GaussianBlurVars *data = static_cast<GaussianBlurVars *>(seq->effectdata);
2319 if (data->size_x == 0.0f && data->size_y == 0) {
2321 }
2323}
2324
2326{
2327 int n = 2 * size + 1;
2328 Array<float> gaussian(n);
2329
2330 float sum = 0.0f;
2331 float fac = (rad > 0.0f ? 1.0f / rad : 0.0f);
2332 for (int i = -size; i <= size; i++) {
2333 float val = RE_filter_value(R_FILTER_GAUSS, float(i) * fac);
2334 sum += val;
2335 gaussian[i + size] = val;
2336 }
2337
2338 float inv_sum = 1.0f / sum;
2339 for (int i = 0; i < n; i++) {
2340 gaussian[i] *= inv_sum;
2341 }
2342
2343 return gaussian;
2344}
2345
2346template<typename T>
2347static void gaussian_blur_x(const Span<float> gaussian,
2348 int half_size,
2349 int start_line,
2350 int width,
2351 int height,
2352 int /*frame_height*/,
2353 const T *rect,
2354 T *dst)
2355{
2356 dst += int64_t(start_line) * width * 4;
2357 for (int y = start_line; y < start_line + height; y++) {
2358 for (int x = 0; x < width; x++) {
2359 float4 accum(0.0f);
2360 float accum_weight = 0.0f;
2361
2362 int xmin = math::max(x - half_size, 0);
2363 int xmax = math::min(x + half_size, width - 1);
2364 for (int nx = xmin, index = (xmin - x) + half_size; nx <= xmax; nx++, index++) {
2365 float weight = gaussian[index];
2366 int offset = (y * width + nx) * 4;
2367 accum += float4(rect + offset) * weight;
2368 accum_weight += weight;
2369 }
2370 accum *= (1.0f / accum_weight);
2371 dst[0] = accum[0];
2372 dst[1] = accum[1];
2373 dst[2] = accum[2];
2374 dst[3] = accum[3];
2375 dst += 4;
2376 }
2377 }
2378}
2379
2380template<typename T>
2381static void gaussian_blur_y(const Span<float> gaussian,
2382 int half_size,
2383 int start_line,
2384 int width,
2385 int height,
2386 int frame_height,
2387 const T *rect,
2388 T *dst)
2389{
2390 dst += int64_t(start_line) * width * 4;
2391 for (int y = start_line; y < start_line + height; y++) {
2392 for (int x = 0; x < width; x++) {
2393 float4 accum(0.0f);
2394 float accum_weight = 0.0f;
2395 int ymin = math::max(y - half_size, 0);
2396 int ymax = math::min(y + half_size, frame_height - 1);
2397 for (int ny = ymin, index = (ymin - y) + half_size; ny <= ymax; ny++, index++) {
2398 float weight = gaussian[index];
2399 int offset = (ny * width + x) * 4;
2400 accum += float4(rect + offset) * weight;
2401 accum_weight += weight;
2402 }
2403 accum *= (1.0f / accum_weight);
2404 dst[0] = accum[0];
2405 dst[1] = accum[1];
2406 dst[2] = accum[2];
2407 dst[3] = accum[3];
2408 dst += 4;
2409 }
2410 }
2411}
2412
2414 Sequence *seq,
2415 float /*timeline_frame*/,
2416 float /*fac*/,
2417 ImBuf *ibuf1,
2418 ImBuf * /*ibuf2*/)
2419{
2420 using namespace blender;
2421
2422 /* Create blur kernel weights. */
2423 const GaussianBlurVars *data = static_cast<const GaussianBlurVars *>(seq->effectdata);
2424 const int half_size_x = int(data->size_x + 0.5f);
2425 const int half_size_y = int(data->size_y + 0.5f);
2426 Array<float> gaussian_x = make_gaussian_blur_kernel(data->size_x, half_size_x);
2427 Array<float> gaussian_y = make_gaussian_blur_kernel(data->size_y, half_size_y);
2428
2429 const int width = context->rectx;
2430 const int height = context->recty;
2431 const bool is_float = ibuf1->float_buffer.data;
2432
2433 /* Horizontal blur: create output, blur ibuf1 into it. */
2434 ImBuf *out = prepare_effect_imbufs(context, ibuf1, nullptr);
2435 threading::parallel_for(IndexRange(context->recty), 32, [&](const IndexRange y_range) {
2436 const int y_first = y_range.first();
2437 const int y_size = y_range.size();
2438 if (is_float) {
2439 gaussian_blur_x(gaussian_x,
2440 half_size_x,
2441 y_first,
2442 width,
2443 y_size,
2444 height,
2445 ibuf1->float_buffer.data,
2446 out->float_buffer.data);
2447 }
2448 else {
2449 gaussian_blur_x(gaussian_x,
2450 half_size_x,
2451 y_first,
2452 width,
2453 y_size,
2454 height,
2455 ibuf1->byte_buffer.data,
2456 out->byte_buffer.data);
2457 }
2458 });
2459
2460 /* Vertical blur: create output, blur previous output into it. */
2461 ibuf1 = out;
2462 out = prepare_effect_imbufs(context, ibuf1, nullptr);
2463 threading::parallel_for(IndexRange(context->recty), 32, [&](const IndexRange y_range) {
2464 const int y_first = y_range.first();
2465 const int y_size = y_range.size();
2466 if (is_float) {
2467 gaussian_blur_y(gaussian_y,
2468 half_size_y,
2469 y_first,
2470 width,
2471 y_size,
2472 height,
2473 ibuf1->float_buffer.data,
2474 out->float_buffer.data);
2475 }
2476 else {
2477 gaussian_blur_y(gaussian_y,
2478 half_size_y,
2479 y_first,
2480 width,
2481 y_size,
2482 height,
2483 ibuf1->byte_buffer.data,
2484 out->byte_buffer.data);
2485 }
2486 });
2487
2488 /* Free the first output. */
2489 IMB_freeImBuf(ibuf1);
2490
2491 return out;
2492}
2493
2495
2496/* -------------------------------------------------------------------- */
2499
2501{
2502 TextVars *data;
2503
2504 if (seq->effectdata) {
2505 MEM_freeN(seq->effectdata);
2506 }
2507
2508 data = static_cast<TextVars *>(seq->effectdata = MEM_callocN(sizeof(TextVars), "textvars"));
2509 data->text_font = nullptr;
2510 data->text_blf_id = -1;
2511 data->text_size = 60.0f;
2512
2513 copy_v4_fl(data->color, 1.0f);
2514 data->shadow_color[3] = 0.7f;
2515 data->shadow_angle = DEG2RADF(65.0f);
2516 data->shadow_offset = 0.04f;
2517 data->shadow_blur = 0.0f;
2518 data->box_color[0] = 0.2f;
2519 data->box_color[1] = 0.2f;
2520 data->box_color[2] = 0.2f;
2521 data->box_color[3] = 0.7f;
2522 data->box_margin = 0.01f;
2523 data->outline_color[3] = 0.7f;
2524 data->outline_width = 0.05f;
2525
2526 STRNCPY(data->text, "Text");
2527
2528 data->loc[0] = 0.5f;
2529 data->loc[1] = 0.5f;
2531 data->align_y = SEQ_TEXT_ALIGN_Y_CENTER;
2532 data->wrap_width = 1.0f;
2533}
2534
2535void SEQ_effect_text_font_unload(TextVars *data, const bool do_id_user)
2536{
2537 if (data == nullptr) {
2538 return;
2539 }
2540
2541 /* Unlink the VFont */
2542 if (do_id_user && data->text_font != nullptr) {
2543 id_us_min(&data->text_font->id);
2544 data->text_font = nullptr;
2545 }
2546
2547 /* Unload the BLF font. */
2548 if (data->text_blf_id >= 0) {
2549 BLF_unload_id(data->text_blf_id);
2550 }
2551}
2552
2553void SEQ_effect_text_font_load(TextVars *data, const bool do_id_user)
2554{
2555 VFont *vfont = data->text_font;
2556 if (vfont == nullptr) {
2557 return;
2558 }
2559
2560 if (do_id_user) {
2561 id_us_plus(&vfont->id);
2562 }
2563
2564 if (vfont->packedfile != nullptr) {
2565 PackedFile *pf = vfont->packedfile;
2566 /* Create a name that's unique between library data-blocks to avoid loading
2567 * a font per strip which will load fonts many times.
2568 *
2569 * WARNING: this isn't fool proof!
2570 * The #VFont may be renamed which will cause this to load multiple times,
2571 * in practice this isn't so likely though. */
2572 char name[MAX_ID_FULL_NAME];
2573 BKE_id_full_name_get(name, &vfont->id, 0);
2574
2575 data->text_blf_id = BLF_load_mem(name, static_cast<const uchar *>(pf->data), pf->size);
2576 }
2577 else {
2578 char filepath[FILE_MAX];
2579 STRNCPY(filepath, vfont->filepath);
2580 if (BLI_thread_is_main()) {
2581 /* FIXME: This is a band-aid fix.
2582 * A proper solution has to be worked on by the sequencer team.
2583 *
2584 * This code can be called from non-main thread, e.g. when copying sequences as part of
2585 * depsgraph evaluated copy of the evaluated scene. Just skip font loading in that case, BLF
2586 * code is not thread-safe, and if this happens from threaded context, it almost certainly
2587 * means that a previous attempt to load the font already failed, e.g. because font file-path
2588 * is invalid. Proposer fix would likely be to not attempt to reload a failed-to-load font
2589 * every time. */
2590 BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
2591
2592 data->text_blf_id = BLF_load(filepath);
2593 }
2594 }
2595}
2596
2597static void free_text_effect(Sequence *seq, const bool do_id_user)
2598{
2599 TextVars *data = static_cast<TextVars *>(seq->effectdata);
2600 SEQ_effect_text_font_unload(data, do_id_user);
2601
2602 if (data) {
2603 MEM_freeN(data);
2604 seq->effectdata = nullptr;
2605 }
2606}
2607
2609{
2610 TextVars *data = static_cast<TextVars *>(seq->effectdata);
2612}
2613
2614static void copy_text_effect(Sequence *dst, const Sequence *src, const int flag)
2615{
2616 dst->effectdata = MEM_dupallocN(src->effectdata);
2617 TextVars *data = static_cast<TextVars *>(dst->effectdata);
2618
2619 data->text_blf_id = -1;
2621}
2622
2624{
2625 return 0;
2626}
2627
2628static StripEarlyOut early_out_text(const Sequence *seq, float /*fac*/)
2629{
2630 TextVars *data = static_cast<TextVars *>(seq->effectdata);
2631 if (data->text[0] == 0 || data->text_size < 1.0f ||
2632 ((data->color[3] == 0.0f) &&
2633 (data->shadow_color[3] == 0.0f || (data->flag & SEQ_TEXT_SHADOW) == 0) &&
2634 (data->outline_color[3] == 0.0f || data->outline_width <= 0.0f ||
2635 (data->flag & SEQ_TEXT_OUTLINE) == 0)))
2636 {
2638 }
2640}
2641
2642/* Simplified version of gaussian blur specifically for text shadow blurring:
2643 * - Data is only the alpha channel,
2644 * - Skips blur outside of shadow rectangle. */
2645static void text_gaussian_blur_x(const Span<float> gaussian,
2646 int half_size,
2647 int start_line,
2648 int width,
2649 int height,
2650 const uchar *rect,
2651 uchar *dst,
2652 const rcti &shadow_rect)
2653{
2654 dst += int64_t(start_line) * width;
2655 for (int y = start_line; y < start_line + height; y++) {
2656 for (int x = 0; x < width; x++) {
2657 float accum(0.0f);
2658 if (x >= shadow_rect.xmin && x <= shadow_rect.xmax) {
2659 float accum_weight = 0.0f;
2660 int xmin = math::max(x - half_size, shadow_rect.xmin);
2661 int xmax = math::min(x + half_size, shadow_rect.xmax);
2662 for (int nx = xmin, index = (xmin - x) + half_size; nx <= xmax; nx++, index++) {
2663 float weight = gaussian[index];
2664 int offset = y * width + nx;
2665 accum += rect[offset] * weight;
2666 accum_weight += weight;
2667 }
2668 accum *= (1.0f / accum_weight);
2669 }
2670
2671 *dst = accum;
2672 dst++;
2673 }
2674 }
2675}
2676
2677static void text_gaussian_blur_y(const Span<float> gaussian,
2678 int half_size,
2679 int start_line,
2680 int width,
2681 int height,
2682 const uchar *rect,
2683 uchar *dst,
2684 const rcti &shadow_rect)
2685{
2686 dst += int64_t(start_line) * width;
2687 for (int y = start_line; y < start_line + height; y++) {
2688 for (int x = 0; x < width; x++) {
2689 float accum(0.0f);
2690 if (x >= shadow_rect.xmin && x <= shadow_rect.xmax) {
2691 float accum_weight = 0.0f;
2692 int ymin = math::max(y - half_size, shadow_rect.ymin);
2693 int ymax = math::min(y + half_size, shadow_rect.ymax);
2694 for (int ny = ymin, index = (ymin - y) + half_size; ny <= ymax; ny++, index++) {
2695 float weight = gaussian[index];
2696 int offset = ny * width + x;
2697 accum += rect[offset] * weight;
2698 accum_weight += weight;
2699 }
2700 accum *= (1.0f / accum_weight);
2701 }
2702 *dst = accum;
2703 dst++;
2704 }
2705 }
2706}
2707
2708static void clamp_rect(int width, int height, rcti &r_rect)
2709{
2710 r_rect.xmin = math::clamp(r_rect.xmin, 0, width - 1);
2711 r_rect.xmax = math::clamp(r_rect.xmax, 0, width - 1);
2712 r_rect.ymin = math::clamp(r_rect.ymin, 0, height - 1);
2713 r_rect.ymax = math::clamp(r_rect.ymax, 0, height - 1);
2714}
2715
2716static void initialize_shadow_alpha(int width,
2717 int height,
2718 int2 offset,
2719 const rcti &shadow_rect,
2720 const uchar *input,
2721 Array<uchar> &r_shadow_mask)
2722{
2723 const IndexRange shadow_y_range(shadow_rect.ymin, shadow_rect.ymax - shadow_rect.ymin + 1);
2724 threading::parallel_for(shadow_y_range, 8, [&](const IndexRange y_range) {
2725 for (const int64_t y : y_range) {
2726 const int64_t src_y = math::clamp<int64_t>(y + offset.y, 0, height - 1);
2727 for (int x = shadow_rect.xmin; x <= shadow_rect.xmax; x++) {
2728 int src_x = math::clamp(x - offset.x, 0, width - 1);
2729 size_t src_offset = width * src_y + src_x;
2730 size_t dst_offset = width * y + x;
2731 r_shadow_mask[dst_offset] = input[src_offset * 4 + 3];
2732 }
2733 }
2734 });
2735}
2736
2737static void composite_shadow(int width,
2738 const rcti &shadow_rect,
2739 const float4 &shadow_color,
2740 const Array<uchar> &shadow_mask,
2741 uchar *output)
2742{
2743 const IndexRange shadow_y_range(shadow_rect.ymin, shadow_rect.ymax - shadow_rect.ymin + 1);
2744 threading::parallel_for(shadow_y_range, 8, [&](const IndexRange y_range) {
2745 for (const int64_t y : y_range) {
2746 size_t offset = y * width + shadow_rect.xmin;
2747 uchar *dst = output + offset * 4;
2748 for (int x = shadow_rect.xmin; x <= shadow_rect.xmax; x++, offset++, dst += 4) {
2749 uchar a = shadow_mask[offset];
2750 if (a == 0) {
2751 /* Fully transparent, leave output pixel as is. */
2752 continue;
2753 }
2754 float4 col1 = load_premul_pixel(dst);
2755 float4 col2 = shadow_color * (a * (1.0f / 255.0f));
2756 /* Blend under the output. */
2757 float fac = 1.0f - col1.w;
2758 float4 col = col1 + fac * col2;
2759 store_premul_pixel(col, dst);
2760 }
2761 }
2762 });
2763}
2764
2765static void draw_text_shadow(const SeqRenderData *context,
2766 const TextVars *data,
2767 int line_height,
2768 const rcti &rect,
2769 ImBuf *out)
2770{
2771 const int width = context->rectx;
2772 const int height = context->recty;
2773 /* Blur value of 1.0 applies blur kernel that is half of text line height. */
2774 const float blur_amount = line_height * 0.5f * data->shadow_blur;
2775 bool do_blur = blur_amount >= 1.0f;
2776
2777 Array<uchar> shadow_mask(size_t(width) * height, 0);
2778
2779 const int2 offset = int2(cosf(data->shadow_angle) * line_height * data->shadow_offset,
2780 sinf(data->shadow_angle) * line_height * data->shadow_offset);
2781
2782 rcti shadow_rect = rect;
2783 BLI_rcti_translate(&shadow_rect, offset.x, -offset.y);
2784 BLI_rcti_pad(&shadow_rect, 1, 1);
2785 clamp_rect(width, height, shadow_rect);
2786
2787 /* Initialize shadow by copying existing text/outline alpha. */
2788 initialize_shadow_alpha(width, height, offset, shadow_rect, out->byte_buffer.data, shadow_mask);
2789
2790 if (do_blur) {
2791 /* Create blur kernel weights. */
2792 const int half_size = int(blur_amount + 0.5f);
2793 Array<float> gaussian = make_gaussian_blur_kernel(blur_amount, half_size);
2794
2795 BLI_rcti_pad(&shadow_rect, half_size + 1, half_size + 1);
2796 clamp_rect(width, height, shadow_rect);
2797
2798 /* Horizontal blur: blur shadow_mask into blur_buffer. */
2799 Array<uchar> blur_buffer(size_t(width) * height, NoInitialization());
2800 IndexRange blur_y_range(shadow_rect.ymin, shadow_rect.ymax - shadow_rect.ymin + 1);
2801 threading::parallel_for(blur_y_range, 8, [&](const IndexRange y_range) {
2802 const int y_first = y_range.first();
2803 const int y_size = y_range.size();
2804 text_gaussian_blur_x(gaussian,
2805 half_size,
2806 y_first,
2807 width,
2808 y_size,
2809 shadow_mask.data(),
2810 blur_buffer.data(),
2811 shadow_rect);
2812 });
2813
2814 /* Vertical blur: blur blur_buffer into shadow_mask. */
2815 threading::parallel_for(blur_y_range, 8, [&](const IndexRange y_range) {
2816 const int y_first = y_range.first();
2817 const int y_size = y_range.size();
2818 text_gaussian_blur_y(gaussian,
2819 half_size,
2820 y_first,
2821 width,
2822 y_size,
2823 blur_buffer.data(),
2824 shadow_mask.data(),
2825 shadow_rect);
2826 });
2827 }
2828
2829 /* Composite shadow under regular output. */
2830 float4 color = data->shadow_color;
2831 color.x *= color.w;
2832 color.y *= color.w;
2833 color.z *= color.w;
2834 composite_shadow(width, shadow_rect, color, shadow_mask, out->byte_buffer.data);
2835}
2836
2837/* Text outline calculation is done by Jump Flooding Algorithm (JFA).
2838 * This is similar to inpaint/jump_flooding in Compositor, also to
2839 * "The Quest for Very Wide Outlines", Ben Golus 2020
2840 * https://bgolus.medium.com/the-quest-for-very-wide-outlines-ba82ed442cd9 */
2841
2842constexpr uint16_t JFA_INVALID = 0xFFFF;
2843
2848
2851 int2 size,
2852 IndexRange x_range,
2853 IndexRange y_range,
2854 int step_size)
2855{
2856 threading::parallel_for(y_range, 8, [&](const IndexRange sub_y_range) {
2857 for (const int64_t y : sub_y_range) {
2858 size_t index = y * size.x;
2859 for (const int64_t x : x_range) {
2860 float2 coord = float2(x, y);
2861
2862 /* For each pixel, sample 9 pixels at +/- step size pattern,
2863 * and output coordinate of closest to the boundary. */
2864 JFACoord closest_texel{JFA_INVALID, JFA_INVALID};
2865 float minimum_squared_distance = std::numeric_limits<float>::max();
2866 for (int dy = -step_size; dy <= step_size; dy += step_size) {
2867 int yy = y + dy;
2868 if (yy < 0 || yy >= size.y) {
2869 continue;
2870 }
2871 for (int dx = -step_size; dx <= step_size; dx += step_size) {
2872 int xx = x + dx;
2873 if (xx < 0 || xx >= size.x) {
2874 continue;
2875 }
2876 JFACoord val = input[size_t(yy) * size.x + xx];
2877 if (val.x == JFA_INVALID) {
2878 continue;
2879 }
2880
2881 float squared_distance = math::distance_squared(float2(val.x, val.y), coord);
2882 if (squared_distance < minimum_squared_distance) {
2883 minimum_squared_distance = squared_distance;
2884 closest_texel = val;
2885 }
2886 }
2887 }
2888
2889 output[index + x] = closest_texel;
2890 }
2891 }
2892 });
2893}
2894
2896 const TextVars *data,
2897 int font,
2898 ColorManagedDisplay *display,
2899 int x,
2900 int y,
2901 int line_height,
2902 const rcti &rect,
2903 ImBuf *out)
2904{
2905 /* Outline width of 1.0 maps to half of text line height. */
2906 const int outline_width = int(line_height * 0.5f * data->outline_width);
2907 if (outline_width < 1 || data->outline_color[3] <= 0.0f) {
2908 return rect;
2909 }
2910
2911 const int2 size = int2(context->rectx, context->recty);
2912
2913 /* Draw white text into temporary buffer. */
2914 const size_t pixel_count = size_t(size.x) * size.y;
2915 Array<uchar4> tmp_buf(pixel_count, uchar4(0));
2916 BLF_buffer(font, nullptr, (uchar *)tmp_buf.data(), size.x, size.y, display);
2917 BLF_position(font, x, y, 0.0f);
2918 BLF_buffer_col(font, float4(1.0f));
2919 BLF_draw_buffer(font, data->text, sizeof(data->text));
2920
2921 rcti outline_rect = rect;
2922 BLI_rcti_pad(&outline_rect, outline_width + 1, outline_width + 1);
2923 outline_rect.xmin = clamp_i(outline_rect.xmin, 0, size.x - 1);
2924 outline_rect.xmax = clamp_i(outline_rect.xmax, 0, size.x - 1);
2925 outline_rect.ymin = clamp_i(outline_rect.ymin, 0, size.y - 1);
2926 outline_rect.ymax = clamp_i(outline_rect.ymax, 0, size.y - 1);
2927 const IndexRange rect_x_range(outline_rect.xmin, outline_rect.xmax - outline_rect.xmin + 1);
2928 const IndexRange rect_y_range(outline_rect.ymin, outline_rect.ymax - outline_rect.ymin + 1);
2929
2930 /* Initialize JFA: invalid values for empty regions, pixel coordinates
2931 * for opaque regions. */
2932 Array<JFACoord> boundary(pixel_count, NoInitialization());
2933 threading::parallel_for(IndexRange(size.y), 16, [&](const IndexRange y_range) {
2934 for (const int y : y_range) {
2935 size_t index = size_t(y) * size.x;
2936 for (int x = 0; x < size.x; x++, index++) {
2937 bool is_opaque = tmp_buf[index].w >= 128;
2938 JFACoord coord;
2939 coord.x = is_opaque ? x : JFA_INVALID;
2940 coord.y = is_opaque ? y : JFA_INVALID;
2941 boundary[index] = coord;
2942 }
2943 }
2944 });
2945
2946 /* Do jump flooding calculations. */
2947 JFACoord invalid_coord{JFA_INVALID, JFA_INVALID};
2948 Array<JFACoord> initial_flooded_result(pixel_count, invalid_coord);
2949 jump_flooding_pass(boundary, initial_flooded_result, size, rect_x_range, rect_y_range, 1);
2950
2951 Array<JFACoord> *result_to_flood = &initial_flooded_result;
2952 Array<JFACoord> intermediate_result(pixel_count, invalid_coord);
2953 Array<JFACoord> *result_after_flooding = &intermediate_result;
2954
2955 int step_size = power_of_2_max_i(outline_width) / 2;
2956
2957 while (step_size != 0) {
2959 *result_to_flood, *result_after_flooding, size, rect_x_range, rect_y_range, step_size);
2960 std::swap(result_to_flood, result_after_flooding);
2961 step_size /= 2;
2962 }
2963
2964 /* Premultiplied outline color. */
2965 float4 color = data->outline_color;
2966 color.x *= color.w;
2967 color.y *= color.w;
2968 color.z *= color.w;
2969
2970 const float text_color_alpha = data->color[3];
2971
2972 /* We have distances to the closest opaque parts of the image now. Composite the
2973 * outline into the output image. */
2974
2975 threading::parallel_for(rect_y_range, 8, [&](const IndexRange y_range) {
2976 for (const int y : y_range) {
2977 size_t index = size_t(y) * size.x + rect_x_range.start();
2978 uchar *dst = out->byte_buffer.data + index * 4;
2979 for (int x = rect_x_range.start(); x < rect_x_range.one_after_last(); x++, index++, dst += 4)
2980 {
2981 JFACoord closest_texel = (*result_to_flood)[index];
2982 if (closest_texel.x == JFA_INVALID) {
2983 /* Outside of outline, leave output pixel as is. */
2984 continue;
2985 }
2986
2987 /* Fade out / anti-alias the outline over one pixel towards outline distance. */
2988 float distance = math::distance(float2(x, y), float2(closest_texel.x, closest_texel.y));
2989 float alpha = math::clamp(outline_width - distance + 1.0f, 0.0f, 1.0f);
2990
2991 /* Do not put outline inside the text shape:
2992 * - When overall text color is fully opaque, we want to make
2993 * outline fully transparent only where text is fully opaque.
2994 * This ensures that combined anti-aliased pixels at text boundary
2995 * are properly fully opaque.
2996 * - However when text color is fully transparent, we want to
2997 * Use opposite alpha of text, to anti-alias the inner edge of
2998 * the outline.
2999 * In between those two, interpolate the alpha modulation factor. */
3000 float text_alpha = tmp_buf[index].w * (1.0f / 255.0f);
3001 float mul_opaque_text = text_alpha >= 1.0f ? 0.0f : 1.0f;
3002 float mul_transparent_text = 1.0f - text_alpha;
3003 float mul = math::interpolate(mul_transparent_text, mul_opaque_text, text_color_alpha);
3004 alpha *= mul;
3005
3006 float4 col1 = color;
3007 col1 *= alpha;
3008
3009 /* Blend over the output. */
3010 float mfac = 1.0f - col1.w;
3011 float4 col2 = load_premul_pixel(dst);
3012 float4 col = col1 + mfac * col2;
3013 store_premul_pixel(col, dst);
3014 }
3015 }
3016 });
3017 BLF_buffer(font, nullptr, out->byte_buffer.data, size.x, size.y, display);
3018
3019 return outline_rect;
3020}
3021
3022/* Similar to #IMB_rectfill_area but blends the given color under the
3023 * existing image. Also only works on byte buffers. */
3025 const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2)
3026{
3027 const int width = ibuf->x;
3028 const int height = ibuf->y;
3029 x1 = math::clamp(x1, 0, width);
3030 x2 = math::clamp(x2, 0, width);
3031 y1 = math::clamp(y1, 0, height);
3032 y2 = math::clamp(y2, 0, height);
3033 if (x1 > x2) {
3034 std::swap(x1, x2);
3035 }
3036 if (y1 > y2) {
3037 std::swap(y1, y2);
3038 }
3039 if (x1 == x2 || y1 == y2) {
3040 return;
3041 }
3042
3043 float4 premul_col = col;
3044 straight_to_premul_v4(premul_col);
3045
3046 for (int y = y1; y < y2; y++) {
3047 uchar *dst = ibuf->byte_buffer.data + (size_t(width) * y + x1) * 4;
3048 for (int x = x1; x < x2; x++) {
3049 float4 pix = load_premul_pixel(dst);
3050 float fac = 1.0f - pix.w;
3051 float4 dst_fl = fac * premul_col + pix;
3052 store_premul_pixel(dst_fl, dst);
3053 dst += 4;
3054 }
3055 }
3056}
3057
3058static ImBuf *do_text_effect(const SeqRenderData *context,
3059 Sequence *seq,
3060 float /*timeline_frame*/,
3061 float /*fac*/,
3062 ImBuf * /*ibuf1*/,
3063 ImBuf * /*ibuf2*/)
3064{
3065 /* NOTE: text rasterization only fills in part of output image,
3066 * need to clear it. */
3067 ImBuf *out = prepare_effect_imbufs(context, nullptr, nullptr, false);
3068 TextVars *data = static_cast<TextVars *>(seq->effectdata);
3069 const int width = out->x;
3070 const int height = out->y;
3071 int font = blf_mono_font_render;
3072 int y_ofs, x, y;
3073 double proxy_size_comp;
3074
3075 if (data->text_blf_id == SEQ_FONT_NOT_LOADED) {
3076 data->text_blf_id = -1;
3077
3079 }
3080
3081 if (data->text_blf_id >= 0) {
3082 font = data->text_blf_id;
3083 }
3084
3085 const char *display_device = context->scene->display_settings.display_device;
3087
3088 /* Compensate text size for preview render size. */
3089 proxy_size_comp = context->scene->r.size / 100.0;
3090 if (context->preview_render_size != SEQ_RENDER_SIZE_SCENE) {
3091 proxy_size_comp = SEQ_rendersize_to_scale_factor(context->preview_render_size);
3092 }
3093
3094 /* set before return */
3095 BLF_size(font, proxy_size_comp * data->text_size);
3096
3097 const int font_flags = BLF_WORD_WRAP | /* Always allow wrapping. */
3098 ((data->flag & SEQ_TEXT_BOLD) ? BLF_BOLD : 0) |
3099 ((data->flag & SEQ_TEXT_ITALIC) ? BLF_ITALIC : 0);
3100 BLF_enable(font, font_flags);
3101
3102 /* use max width to enable newlines only */
3103 BLF_wordwrap(font, (data->wrap_width != 0.0f) ? data->wrap_width * width : -1);
3104
3105 BLF_buffer(font, nullptr, out->byte_buffer.data, width, height, display);
3106
3107 const int line_height = BLF_height_max(font);
3108
3109 y_ofs = -BLF_descender(font);
3110
3111 x = (data->loc[0] * width);
3112 y = (data->loc[1] * height) + y_ofs;
3113
3114 /* Calculate bounding box and wrapping information. */
3115 rcti rect;
3116 ResultBLF wrap_info;
3117 BLF_boundbox(font, data->text, sizeof(data->text), &rect, &wrap_info);
3118
3119 if ((data->align == SEQ_TEXT_ALIGN_X_LEFT) && (data->align_y == SEQ_TEXT_ALIGN_Y_TOP)) {
3120 y -= line_height;
3121 }
3122 else {
3123 if (data->align == SEQ_TEXT_ALIGN_X_RIGHT) {
3124 x -= BLI_rcti_size_x(&rect);
3125 }
3126 else if (data->align == SEQ_TEXT_ALIGN_X_CENTER) {
3127 x -= BLI_rcti_size_x(&rect) / 2;
3128 }
3129
3130 if (data->align_y == SEQ_TEXT_ALIGN_Y_TOP) {
3131 y -= line_height;
3132 }
3133 else if (data->align_y == SEQ_TEXT_ALIGN_Y_BOTTOM) {
3134 y += (wrap_info.lines - 1) * line_height;
3135 }
3136 else if (data->align_y == SEQ_TEXT_ALIGN_Y_CENTER) {
3137 y += (((wrap_info.lines - 1) / 2) * line_height) - (line_height / 2);
3138 }
3139 }
3140 BLI_rcti_translate(&rect, x, y);
3141
3142 /* Draw text outline. */
3143 rcti outline_rect = rect;
3144 if (data->flag & SEQ_TEXT_OUTLINE) {
3145 outline_rect = draw_text_outline(context, data, font, display, x, y, line_height, rect, out);
3146 }
3147
3148 /* Draw text itself. */
3149 BLF_position(font, x, y, 0.0f);
3150 BLF_buffer_col(font, data->color);
3151 BLF_draw_buffer(font, data->text, sizeof(data->text));
3152
3153 BLF_buffer(font, nullptr, nullptr, 0, 0, nullptr);
3154 BLF_disable(font, font_flags);
3155
3156 /* Draw shadow. */
3157 if (data->flag & SEQ_TEXT_SHADOW) {
3158 draw_text_shadow(context, data, line_height, outline_rect, out);
3159 }
3160
3161 /* Draw box under text. */
3162 if (data->flag & SEQ_TEXT_BOX) {
3163 if (out->byte_buffer.data) {
3164 const int margin = data->box_margin * width;
3165 const int minx = rect.xmin - margin;
3166 const int maxx = rect.xmax + margin;
3167 const int miny = rect.ymin - margin;
3168 const int maxy = rect.ymax + margin;
3169 fill_rect_alpha_under(out, data->box_color, minx, miny, maxx, maxy);
3170 }
3171 }
3172
3173 return out;
3174}
3175
3177
3178/* -------------------------------------------------------------------- */
3181
3182static void init_noop(Sequence * /*seq*/) {}
3183
3184static void load_noop(Sequence * /*seq*/) {}
3185
3186static void free_noop(Sequence * /*seq*/, const bool /*do_id_user*/) {}
3187
3189{
3190 return 2;
3191}
3192
3193static void copy_effect_default(Sequence *dst, const Sequence *src, const int /*flag*/)
3194{
3195 dst->effectdata = MEM_dupallocN(src->effectdata);
3196}
3197
3198static void free_effect_default(Sequence *seq, const bool /*do_id_user*/)
3199{
3200 MEM_SAFE_FREE(seq->effectdata);
3201}
3202
3203static StripEarlyOut early_out_noop(const Sequence * /*seq*/, float /*fac*/)
3204{
3206}
3207
3208static StripEarlyOut early_out_fade(const Sequence * /*seq*/, float fac)
3209{
3210 if (fac == 0.0f) {
3212 }
3213 if (fac == 1.0f) {
3215 }
3217}
3218
3219static StripEarlyOut early_out_mul_input2(const Sequence * /*seq*/, float fac)
3220{
3221 if (fac == 0.0f) {
3223 }
3225}
3226
3227static StripEarlyOut early_out_mul_input1(const Sequence * /*seq*/, float fac)
3228{
3229 if (fac == 0.0f) {
3231 }
3233}
3234
3235static void get_default_fac_noop(const Scene * /*scene*/,
3236 const Sequence * /*seq*/,
3237 float /*timeline_frame*/,
3238 float *fac)
3239{
3240 *fac = 1.0f;
3241}
3242
3243static void get_default_fac_fade(const Scene *scene,
3244 const Sequence *seq,
3245 float timeline_frame,
3246 float *fac)
3247{
3248 *fac = float(timeline_frame - SEQ_time_left_handle_frame_get(scene, seq));
3249 *fac /= SEQ_time_strip_length_get(scene, seq);
3250 *fac = math::clamp(*fac, 0.0f, 1.0f);
3251}
3252
3253static ImBuf *init_execution(const SeqRenderData *context, ImBuf *ibuf1, ImBuf *ibuf2)
3254{
3255 ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2);
3256 return out;
3257}
3258
3260{
3261 SeqEffectHandle rval;
3262 int sequence_type = seq_type;
3263
3264 rval.multithreaded = false;
3265 rval.supports_mask = false;
3266 rval.init = init_noop;
3268 rval.load = load_noop;
3269 rval.free = free_noop;
3272 rval.execute = nullptr;
3274 rval.execute_slice = nullptr;
3275 rval.copy = nullptr;
3276
3277 switch (sequence_type) {
3278 case SEQ_TYPE_CROSS:
3279 rval.multithreaded = true;
3283 break;
3284 case SEQ_TYPE_GAMCROSS:
3285 rval.multithreaded = true;
3289 break;
3290 case SEQ_TYPE_ADD:
3291 rval.multithreaded = true;
3294 break;
3295 case SEQ_TYPE_SUB:
3296 rval.multithreaded = true;
3299 break;
3300 case SEQ_TYPE_MUL:
3301 rval.multithreaded = true;
3304 break;
3305 case SEQ_TYPE_SCREEN:
3306 case SEQ_TYPE_OVERLAY:
3309 case SEQ_TYPE_DARKEN:
3310 case SEQ_TYPE_LIGHTEN:
3311 case SEQ_TYPE_DODGE:
3314 case SEQ_TYPE_PIN_LIGHT:
3315 case SEQ_TYPE_LIN_LIGHT:
3318 case SEQ_TYPE_HUE:
3320 case SEQ_TYPE_VALUE:
3322 case SEQ_TYPE_EXCLUSION:
3323 rval.multithreaded = true;
3326 break;
3327 case SEQ_TYPE_COLORMIX:
3328 rval.multithreaded = true;
3334 break;
3335 case SEQ_TYPE_ALPHAOVER:
3336 rval.multithreaded = true;
3340 break;
3341 case SEQ_TYPE_OVERDROP:
3342 rval.multithreaded = true;
3344 break;
3346 rval.multithreaded = true;
3349 break;
3350 case SEQ_TYPE_WIPE:
3351 rval.init = init_wipe_effect;
3353 rval.free = free_wipe_effect;
3354 rval.copy = copy_wipe_effect;
3357 rval.execute = do_wipe_effect;
3358 break;
3359 case SEQ_TYPE_GLOW:
3360 rval.init = init_glow_effect;
3362 rval.free = free_glow_effect;
3363 rval.copy = copy_glow_effect;
3364 rval.execute = do_glow_effect;
3365 break;
3366 case SEQ_TYPE_TRANSFORM:
3367 rval.multithreaded = true;
3373 break;
3374 case SEQ_TYPE_SPEED:
3375 rval.init = init_speed_effect;
3377 rval.load = load_speed_effect;
3378 rval.free = free_speed_effect;
3379 rval.copy = copy_speed_effect;
3380 rval.execute = do_speed_effect;
3382 break;
3383 case SEQ_TYPE_COLOR:
3384 rval.init = init_solid_color;
3387 rval.free = free_solid_color;
3388 rval.copy = copy_solid_color;
3389 rval.execute = do_solid_color;
3390 break;
3391 case SEQ_TYPE_MULTICAM:
3394 rval.execute = do_multicam;
3395 break;
3397 rval.supports_mask = true;
3400 rval.execute = do_adjustment;
3401 break;
3409 break;
3410 case SEQ_TYPE_TEXT:
3412 rval.init = init_text_effect;
3413 rval.free = free_text_effect;
3414 rval.load = load_text_effect;
3415 rval.copy = copy_text_effect;
3417 rval.execute = do_text_effect;
3418 break;
3419 }
3420
3421 return rval;
3422}
3423
3425
3426/* -------------------------------------------------------------------- */
3429
3431{
3432 SeqEffectHandle rval = {false, false, nullptr};
3433
3434 if (seq->type & SEQ_TYPE_EFFECT) {
3435 rval = get_sequence_effect_impl(seq->type);
3436 if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) {
3437 rval.load(seq);
3438 seq->flag &= ~SEQ_EFFECT_NOT_LOADED;
3439 }
3440 }
3441
3442 return rval;
3443}
3444
3446{
3447 SeqEffectHandle rval = {false, false, nullptr};
3448
3449 if (seq->blend_mode != 0) {
3450 if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) {
3451 /* load the effect first */
3452 rval = get_sequence_effect_impl(seq->type);
3453 rval.load(seq);
3454 }
3455
3456 rval = get_sequence_effect_impl(seq->blend_mode);
3457 if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) {
3458 /* now load the blend and unset unloaded flag */
3459 rval.load(seq);
3460 seq->flag &= ~SEQ_EFFECT_NOT_LOADED;
3461 }
3462 }
3463
3464 return rval;
3465}
3466
3468{
3470
3471 int count = rval.num_inputs();
3472 if (rval.execute || (rval.execute_slice && rval.init_execution)) {
3473 return count;
3474 }
3475 return 0;
3476}
3477
float evaluate_fcurve(const FCurve *fcu, float evaltime)
FCurve * id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index, bool *r_driven)
void BKE_id_full_name_get(char name[MAX_ID_FULL_NAME], const ID *id, char separator_char)
Definition lib_id.cc:2365
void id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_min(ID *id)
Definition lib_id.cc:359
@ LIB_ID_CREATE_NO_USER_REFCOUNT
#define MAX_ID_FULL_NAME
@ BLF_ITALIC
Definition BLF_api.hh:374
@ BLF_WORD_WRAP
Definition BLF_api.hh:367
@ BLF_BOLD
Definition BLF_api.hh:373
void BLF_size(int fontid, float size)
Definition blf.cc:426
int BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:850
void BLF_draw_buffer(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:962
int blf_mono_font_render
Definition blf.cc:52
void BLF_boundbox(int fontid, const char *str, size_t str_len, rcti *r_box, ResultBLF *r_info=nullptr) ATTR_NONNULL(2)
Definition blf.cc:761
void BLF_disable(int fontid, int option)
Definition blf.cc:321
void BLF_buffer_col(int fontid, const float rgba[4]) ATTR_NONNULL(2)
Definition blf.cc:937
void BLF_buffer(int fontid, float *fbuf, unsigned char *cbuf, int w, int h, ColorManagedDisplay *display)
Definition blf.cc:924
void BLF_unload_id(int fontid)
Definition blf.cc:284
int BLF_load(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition blf.cc:174
void BLF_enable(int fontid, int option)
Definition blf.cc:312
int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:828
void BLF_wordwrap(int fontid, int wrap_width)
Definition blf.cc:893
void BLF_position(int fontid, float x, float y, float z)
Definition blf.cc:371
MINLINE int round_fl_to_int(float a)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE int power_of_2_max_i(int n)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE float sqrtf_signed(float f)
MINLINE int clamp_i(int value, int min, int max)
#define M_PI
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4])
MINLINE void straight_to_premul_v4(float color[4])
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4])
MINLINE void blend_color_add_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_linearburn_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_saturation_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_color_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_difference_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_luminosity_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_pinlight_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_screen_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_vividlight_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_luminosity_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_difference_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_burn_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_color_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_overlay_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_dodge_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_hardlight_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_softlight_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_hue_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
MINLINE void blend_color_exclusion_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_linearlight_byte(unsigned char dst[4], const uchar src1[4], const uchar src2[4])
MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], const float src2[4])
#define DEG2RADF(_deg)
MINLINE void copy_v4_fl(float r[4], float f)
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
void BLI_rcti_pad(struct rcti *rect, int pad_x, int pad_y)
Definition rct.c:623
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition rct.c:560
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
#define STRNCPY(dst, src)
Definition BLI_string.h:593
unsigned char uchar
int BLI_thread_is_main(void)
Definition threads.cc:179
#define CLAMP(a, b, c)
#define UNLIKELY(x)
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
Definition DNA_ID.h:649
@ R_IMF_PLANES_RGB
@ R_FILTER_GAUSS
@ SEQ_TYPE_TRANSFORM
@ SEQ_TYPE_COLOR_BURN
@ SEQ_TYPE_HARD_LIGHT
@ SEQ_TYPE_EXCLUSION
@ SEQ_TYPE_CROSS
@ SEQ_TYPE_GLOW
@ SEQ_TYPE_VALUE
@ SEQ_TYPE_COLORMIX
@ SEQ_TYPE_WIPE
@ SEQ_TYPE_OVERDROP
@ SEQ_TYPE_PIN_LIGHT
@ SEQ_TYPE_ALPHAUNDER
@ SEQ_TYPE_DODGE
@ SEQ_TYPE_HUE
@ SEQ_TYPE_LINEAR_BURN
@ SEQ_TYPE_GAMCROSS
@ SEQ_TYPE_MULTICAM
@ SEQ_TYPE_BLEND_COLOR
@ SEQ_TYPE_DARKEN
@ SEQ_TYPE_MUL
@ SEQ_TYPE_GAUSSIAN_BLUR
@ SEQ_TYPE_ADD
@ SEQ_TYPE_ALPHAOVER
@ SEQ_TYPE_TEXT
@ SEQ_TYPE_SCREEN
@ SEQ_TYPE_SOFT_LIGHT
@ SEQ_TYPE_SUB
@ SEQ_TYPE_VIVID_LIGHT
@ SEQ_TYPE_OVERLAY
@ SEQ_TYPE_SPEED
@ SEQ_TYPE_COLOR
@ SEQ_TYPE_SATURATION
@ SEQ_TYPE_LIN_LIGHT
@ SEQ_TYPE_EFFECT
@ SEQ_TYPE_DIFFERENCE
@ SEQ_TYPE_ADJUSTMENT
@ SEQ_TYPE_LIGHTEN
#define SEQ_FONT_NOT_LOADED
@ SEQ_TEXT_ITALIC
@ SEQ_TEXT_SHADOW
@ SEQ_TEXT_BOLD
@ SEQ_TEXT_OUTLINE
@ SEQ_TEXT_BOX
@ SEQ_TEXT_ALIGN_Y_BOTTOM
@ SEQ_TEXT_ALIGN_Y_TOP
@ SEQ_TEXT_ALIGN_Y_CENTER
@ SEQ_SPEED_USE_INTERPOLATION
@ SEQ_SPEED_STRETCH
@ SEQ_SPEED_MULTIPLY
@ SEQ_SPEED_LENGTH
@ SEQ_SPEED_FRAME_NUMBER
@ SEQ_TEXT_ALIGN_X_RIGHT
@ SEQ_TEXT_ALIGN_X_CENTER
@ SEQ_TEXT_ALIGN_X_LEFT
@ SEQ_EFFECT_NOT_LOADED
@ SEQ_RENDER_SIZE_SCENE
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
void IMB_colormanagement_assign_float_colorspace(ImBuf *ibuf, const char *name)
ColorManagedDisplay * IMB_colormanagement_display_get_named(const char *name)
void IMB_colormanagement_transform_from_byte_threaded(float *float_buffer, unsigned char *byte_buffer, int width, int height, int channels, const char *from_colorspace, const char *to_colorspace)
ImBuf * IMB_dupImBuf(const ImBuf *ibuf1)
void IMB_rect_from_float(ImBuf *ibuf)
Definition divers.cc:694
void IMB_buffer_byte_from_float(unsigned char *rect_to, const float *rect_from, int channels_from, float dither, int profile_to, int profile_from, bool predivide, int width, int height, int stride_to, int stride_from)
Definition divers.cc:96
Contains defines and structs used throughout the imbuf module.
#define IB_PROFILE_SRGB
@ IB_rectfloat
@ IB_uninitialized_pixels
@ IB_rect
void IMB_metadata_copy(ImBuf *ibuf_dst, const ImBuf *ibuf_src)
Definition metadata.cc:60
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
StripEarlyOut
@ DO_IRIS_WIPE
@ DO_CLOCK_WIPE
@ DO_DOUBLE_WIPE
@ DO_SINGLE_WIPE
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#define output
static void mul(btAlignedObjectArray< T > &items, const Q &value)
static T sum(const btAlignedObjectArray< T > &items)
ListBase * SEQ_get_channels_by_seq(ListBase *seqbase, ListBase *channels, const Sequence *seq)
Definition channels.cc:87
const T * data() const
Definition BLI_array.hh:301
constexpr int64_t first() const
constexpr int64_t size() const
#define sinf(x)
#define cosf(x)
#define tanf(x)
#define atan2f(x, y)
#define hypotf(x, y)
#define fabsf(x)
#define sqrtf(x)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static void do_blend_effect_byte(float fac, int x, int y, const uchar *rect1, uchar *rect2, int btype, uchar *out)
Definition effects.cc:908
static StripEarlyOut early_out_fade(const Sequence *, float fac)
Definition effects.cc:3208
static void gaussian_blur_y(const Span< float > gaussian, int half_size, int start_line, int width, int height, int frame_height, const T *rect, T *dst)
Definition effects.cc:2381
constexpr uint16_t JFA_INVALID
Definition effects.cc:2842
static void do_cross_effect_byte(float fac, int x, int y, uchar *rect1, uchar *rect2, uchar *out)
Definition effects.cc:356
static FCurve * seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *seq)
Definition effects.cc:2113
static void init_text_effect(Sequence *seq)
Definition effects.cc:2500
static WipeZone precalc_wipe_zone(const WipeVars *wipe, int xo, int yo)
Definition effects.cc:1069
static void do_mul_effect(const SeqRenderData *context, Sequence *, float, float fac, const ImBuf *ibuf1, const ImBuf *ibuf2, int start_line, int total_lines, ImBuf *out)
Definition effects.cc:785
static int num_inputs_default()
Definition effects.cc:3188
static ImBuf * do_text_effect(const SeqRenderData *context, Sequence *seq, float, float, ImBuf *, ImBuf *)
Definition effects.cc:3058
static int num_inputs_text()
Definition effects.cc:2623
static void free_transform_effect(Sequence *seq, const bool)
Definition effects.cc:1462
static float in_band(float width, float dist, int side, int dir)
Definition effects.cc:1087
static void do_overdrop_effect(const SeqRenderData *context, Sequence *, float, float fac, const ImBuf *ibuf1, const ImBuf *ibuf2, int start_line, int total_lines, ImBuf *out)
Definition effects.cc:2255
static bool alpha_opaque(uchar alpha)
Definition effects.cc:220
static void free_effect_default(Sequence *seq, const bool)
Definition effects.cc:3198
static void text_gaussian_blur_x(const Span< float > gaussian, int half_size, int start_line, int width, int height, const uchar *rect, uchar *dst, const rcti &shadow_rect)
Definition effects.cc:2645
static StripEarlyOut early_out_gaussian_blur(const Sequence *seq, float)
Definition effects.cc:2316
static void copy_gaussian_blur_effect(Sequence *dst, const Sequence *src, const int)
Definition effects.cc:2311
static void free_speed_effect(Sequence *seq, const bool)
Definition effects.cc:2091
static void get_default_fac_fade(const Scene *scene, const Sequence *seq, float timeline_frame, float *fac)
Definition effects.cc:3243
float seq_speed_effect_target_frame_get(Scene *scene, Sequence *seq_speed, float timeline_frame, int input)
Definition effects.cc:2159
static void copy_glow_effect(Sequence *dst, const Sequence *src, const int)
Definition effects.cc:1738
static void do_mul_effect_byte(float fac, int x, int y, uchar *rect1, uchar *rect2, uchar *out)
Definition effects.cc:736
static void init_speed_effect(Sequence *seq)
Definition effects.cc:2063
static ImBuf * prepare_effect_imbufs(const SeqRenderData *context, ImBuf *ibuf1, ImBuf *ibuf2, bool uninitialized_pixels=true)
Definition effects.cc:153
static StripEarlyOut early_out_text(const Sequence *seq, float)
Definition effects.cc:2628
static SeqEffectHandle get_sequence_effect_impl(int seq_type)
Definition effects.cc:3259
static void do_alphaunder_effect(float fac, int width, int height, const T *src1, const T *src2, T *dst)
Definition effects.cc:296
static void composite_shadow(int width, const rcti &shadow_rect, const float4 &shadow_color, const Array< uchar > &shadow_mask, uchar *output)
Definition effects.cc:2737
static void fill_rect_alpha_under(const ImBuf *ibuf, const float col[4], int x1, int y1, int x2, int y2)
Definition effects.cc:3024
static void text_gaussian_blur_y(const Span< float > gaussian, int half_size, int start_line, int width, int height, const uchar *rect, uchar *dst, const rcti &shadow_rect)
Definition effects.cc:2677
static void init_colormix_effect(Sequence *seq)
Definition effects.cc:1010
static void free_glow_effect(Sequence *seq, const bool)
Definition effects.cc:1733
static void glow_blur_bitmap(const float4 *src, float4 *map, int width, int height, float blur, int quality)
Definition effects.cc:1607
static void init_alpha_over_or_under(Sequence *seq)
Definition effects.cc:211
static void draw_text_shadow(const SeqRenderData *context, const TextVars *data, int line_height, const rcti &rect, ImBuf *out)
Definition effects.cc:2765
static void init_glow_effect(Sequence *seq)
Definition effects.cc:1709
void SEQ_effect_text_font_unload(TextVars *data, const bool do_id_user)
Definition effects.cc:2535
static rcti draw_text_outline(const SeqRenderData *context, const TextVars *data, int font, ColorManagedDisplay *display, int x, int y, int line_height, const rcti &rect, ImBuf *out)
Definition effects.cc:2895
static void initialize_shadow_alpha(int width, int height, int2 offset, const rcti &shadow_rect, const uchar *input, Array< uchar > &r_shadow_mask)
Definition effects.cc:2716
static void load_text_effect(Sequence *seq)
Definition effects.cc:2608
SeqEffectHandle SEQ_effect_handle_get(Sequence *seq)
Definition effects.cc:3430
int SEQ_effect_get_num_inputs(int seq_type)
Definition effects.cc:3467
static void free_gaussian_blur_effect(Sequence *seq, const bool)
Definition effects.cc:2306
static ImBuf * init_execution(const SeqRenderData *context, ImBuf *ibuf1, ImBuf *ibuf2)
Definition effects.cc:3253
static void get_default_fac_noop(const Scene *, const Sequence *, float, float *fac)
Definition effects.cc:3235
static StripEarlyOut early_out_multicam(const Sequence *, float)
Definition effects.cc:1945
static void do_add_effect_byte(float fac, int x, int y, uchar *rect1, uchar *rect2, uchar *out)
Definition effects.cc:505
#define YOFF
Definition effects.cc:661
static void do_add_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
Definition effects.cc:528
static void slice_get_float_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, const ImBuf *out, int start_line, float **rect1, float **rect2, float **rect_out)
Definition effects.cc:90
#define XOFF
Definition effects.cc:660
static StripEarlyOut early_out_mul_input2(const Sequence *, float fac)
Definition effects.cc:3219
static void do_sub_effect(const SeqRenderData *context, Sequence *, float, float fac, const ImBuf *ibuf1, const ImBuf *ibuf2, int start_line, int total_lines, ImBuf *out)
Definition effects.cc:627
static void init_wipe_effect(Sequence *seq)
Definition effects.cc:1324
static StripEarlyOut early_out_speed(const Sequence *, float)
Definition effects.cc:2108
static float invGammaCorrect(float c)
Definition effects.cc:446
static StripEarlyOut early_out_mul_input1(const Sequence *, float fac)
Definition effects.cc:3227
static void free_solid_color(Sequence *seq, const bool)
Definition effects.cc:1870
static int num_inputs_gaussian_blur()
Definition effects.cc:2301
static void do_glow_effect_float(Sequence *seq, int render_size, float fac, int x, int y, float *rect1, float *, float *out)
Definition effects.cc:1786
static void apply_blend_function(float fac, int width, int height, const T *src1, T *src2, T *dst, Func blend_function)
Definition effects.cc:819
static float gammaCorrect(float c)
Definition effects.cc:438
static void slice_get_byte_buffers(const SeqRenderData *context, const ImBuf *ibuf1, const ImBuf *ibuf2, const ImBuf *out, int start_line, uchar **rect1, uchar **rect2, uchar **rect_out)
Definition effects.cc:71
static void copy_speed_effect(Sequence *dst, const Sequence *src, const int)
Definition effects.cc:2100
static void do_gammacross_effect(float fac, int width, int height, const T *src1, const T *src2, T *dst)
Definition effects.cc:452
static void do_cross_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
Definition effects.cc:379
static void copy_transform_effect(Sequence *dst, const Sequence *src, const int)
Definition effects.cc:1467
static ImBuf * do_glow_effect(const SeqRenderData *context, Sequence *seq, float, float fac, ImBuf *ibuf1, ImBuf *ibuf2)
Definition effects.cc:1810
static void clamp_rect(int width, int height, rcti &r_rect)
Definition effects.cc:2708
static void do_transform_effect(const SeqRenderData *context, Sequence *seq, float, float, const ImBuf *ibuf1, const ImBuf *, int start_line, int total_lines, ImBuf *out)
Definition effects.cc:1543
static StripEarlyOut early_out_noop(const Sequence *, float)
Definition effects.cc:3203
static void copy_text_effect(Sequence *dst, const Sequence *src, const int flag)
Definition effects.cc:2614
static ImBuf * do_adjustment_impl(const SeqRenderData *context, Sequence *seq, float timeline_frame)
Definition effects.cc:1997
static int num_inputs_glow()
Definition effects.cc:1728
static void load_speed_effect(Sequence *seq)
Definition effects.cc:2080
static void transform_image(int x, int y, int start_line, int total_lines, const ImBuf *ibuf, ImBuf *out, float scale_x, float scale_y, float translate_x, float translate_y, float rotate, int interpolation)
Definition effects.cc:1472
static void do_colormix_effect(const SeqRenderData *context, Sequence *seq, float, float, const ImBuf *ibuf1, const ImBuf *ibuf2, int start_line, int total_lines, ImBuf *out)
Definition effects.cc:1023
static void do_drop_effect_float(float fac, int x, int y, float *rect2i, float *rect1i, float *outi)
Definition effects.cc:696
static int num_inputs_wipe()
Definition effects.cc:1333
static ImBuf * do_speed_effect(const SeqRenderData *context, Sequence *seq, float timeline_frame, float fac, ImBuf *ibuf1, ImBuf *ibuf2)
Definition effects.cc:2226
static int num_inputs_speed()
Definition effects.cc:2086
static void blur_isolate_highlights(const float4 *in, float4 *out, int width, int height, float threshold, float boost, float clamp)
Definition effects.cc:1679
static float4 load_premul_pixel(const uchar *ptr)
Definition effects.cc:109
static ImBuf * do_adjustment(const SeqRenderData *context, Sequence *seq, float timeline_frame, float, ImBuf *, ImBuf *)
Definition effects.cc:2036
static void free_noop(Sequence *, const bool)
Definition effects.cc:3186
static ImBuf * do_multicam(const SeqRenderData *context, Sequence *seq, float timeline_frame, float, ImBuf *, ImBuf *)
Definition effects.cc:1950
static void seq_effect_speed_frame_map_ensure(Scene *scene, Sequence *seq)
Definition effects.cc:2149
static void do_drop_effect_byte(float fac, int x, int y, uchar *rect2i, uchar *rect1i, uchar *outi)
Definition effects.cc:663
static void init_solid_color(Sequence *seq)
Definition effects.cc:1851
static void copy_wipe_effect(Sequence *dst, const Sequence *src, const int)
Definition effects.cc:1343
static void copy_solid_color(Sequence *dst, const Sequence *src, const int)
Definition effects.cc:1875
static int num_inputs_transform()
Definition effects.cc:1457
static void do_cross_effect(const SeqRenderData *context, Sequence *, float, float fac, const ImBuf *ibuf1, const ImBuf *ibuf2, int start_line, int total_lines, ImBuf *out)
Definition effects.cc:401
static void free_text_effect(Sequence *seq, const bool do_id_user)
Definition effects.cc:2597
static void copy_effect_default(Sequence *dst, const Sequence *src, const int)
Definition effects.cc:3193
static void load_noop(Sequence *)
Definition effects.cc:3184
static StripEarlyOut early_out_adjustment(const Sequence *, float)
Definition effects.cc:1992
static void do_sub_effect_byte(float fac, int x, int y, uchar *rect1, uchar *rect2, uchar *out)
Definition effects.cc:581
static void do_blend_effect_float(float fac, int x, int y, const float *rect1, float *rect2, int btype, float *out)
Definition effects.cc:836
static void do_mul_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
Definition effects.cc:762
static ImBuf * do_solid_color(const SeqRenderData *context, Sequence *seq, float, float, ImBuf *ibuf1, ImBuf *ibuf2)
Definition effects.cc:1885
static float speed_effect_interpolation_ratio_get(Scene *scene, Sequence *seq_speed, float timeline_frame)
Definition effects.cc:2217
static void do_add_effect(const SeqRenderData *context, Sequence *, float, float fac, const ImBuf *ibuf1, const ImBuf *ibuf2, int start_line, int total_lines, ImBuf *out)
Definition effects.cc:549
static void store_opaque_black_pixel(uchar *dst)
Definition effects.cc:131
static void do_wipe_effect(const Sequence *seq, float fac, int width, int height, const T *rect1, const T *rect2, T *out)
Definition effects.cc:1349
static void do_blend_mode_effect(const SeqRenderData *context, Sequence *seq, float, float fac, const ImBuf *ibuf1, const ImBuf *ibuf2, int start_line, int total_lines, ImBuf *out)
Definition effects.cc:980
static void init_noop(Sequence *)
Definition effects.cc:3182
void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq)
Definition effects.cc:2118
static int num_inputs_color()
Definition effects.cc:1865
static void gaussian_blur_x(const Span< float > gaussian, int half_size, int start_line, int width, int height, int, const T *rect, T *dst)
Definition effects.cc:2347
static void jump_flooding_pass(Span< JFACoord > input, MutableSpan< JFACoord > output, int2 size, IndexRange x_range, IndexRange y_range, int step_size)
Definition effects.cc:2849
static void store_premul_pixel(const float4 &pix, uchar *dst)
Definition effects.cc:121
static void init_transform_effect(Sequence *seq)
Definition effects.cc:1432
static void init_gaussian_blur_effect(Sequence *seq)
Definition effects.cc:2292
static int num_inputs_multicam()
Definition effects.cc:1940
static float check_zone(const WipeZone *wipezone, int x, int y, float fac)
Definition effects.cc:1113
static void do_alphaover_effect(float fac, int width, int height, const T *src1, const T *src2, T *dst)
Definition effects.cc:232
static void do_sub_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
Definition effects.cc:604
static ImBuf * do_gaussian_blur_effect(const SeqRenderData *context, Sequence *seq, float, float, ImBuf *ibuf1, ImBuf *)
Definition effects.cc:2413
static Array< float > make_gaussian_blur_kernel(float rad, int size)
Definition effects.cc:2325
static void free_wipe_effect(Sequence *seq, const bool)
Definition effects.cc:1338
static void do_glow_effect_byte(Sequence *seq, int render_size, float fac, int x, int y, uchar *rect1, uchar *, uchar *out)
Definition effects.cc:1743
void SEQ_effect_text_font_load(TextVars *data, const bool do_id_user)
Definition effects.cc:2553
static int num_inputs_adjustment()
Definition effects.cc:1987
static StripEarlyOut early_out_color(const Sequence *, float)
Definition effects.cc:1880
SeqEffectHandle seq_effect_get_sequence_blend(Sequence *seq)
Definition effects.cc:3445
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
uint col
struct ImBuf * IMB_allocImBuf(unsigned int, unsigned int, unsigned char, unsigned int)
void IMB_freeImBuf(ImBuf *)
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
float RE_filter_value(int type, float x)
int count
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
ccl_device_inline float2 floor(const float2 a)
ccl_device_inline float3 exp(float3 v)
ccl_device_inline float3 ceil(const float3 a)
#define T
int context(const bContext *C, const char *member, bContextDataResult *result)
float4 interpolate_nearest_border_fl(const ImBuf *in, float u, float v)
Definition IMB_interp.hh:27
uchar4 interpolate_nearest_border_byte(const ImBuf *in, float u, float v)
Definition IMB_interp.hh:23
uchar4 interpolate_cubic_bspline_byte(const ImBuf *in, float u, float v)
float4 interpolate_cubic_bspline_fl(const ImBuf *in, float u, float v)
uchar4 interpolate_bilinear_border_byte(const ImBuf *in, float u, float v)
Definition IMB_interp.hh:74
float4 interpolate_bilinear_border_fl(const ImBuf *in, float u, float v)
Definition IMB_interp.hh:78
T clamp(const T &a, const T &min, const T &max)
T distance(const T &a, const T &b)
T min(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
T max(const T &a, const T &b)
void index(const bNode &, void *r_value)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95
blender::VecBase< uint8_t, 4 > uchar4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
static void rotate(float new_co[3], float a, const float ax[3], const float co[3])
float distance(float a, float b)
double SEQ_rendersize_to_scale_factor(int render_size)
Definition proxy.cc:82
void seq_imbuf_to_sequencer_space(const Scene *scene, ImBuf *ibuf, bool make_float)
Definition render.cc:106
ImBuf * seq_render_give_ibuf_seqbase(const SeqRenderData *context, float timeline_frame, int chan_shown, ListBase *channels, ListBase *seqbasep)
Definition render.cc:2133
ImBuf * seq_render_effect_execute_threaded(SeqEffectHandle *sh, const SeqRenderData *context, Sequence *seq, float timeline_frame, float fac, ImBuf *ibuf1, ImBuf *ibuf2)
Definition render.cc:799
ListBase * SEQ_get_seqbase_by_seq(const Scene *scene, Sequence *seq)
unsigned short uint16_t
Definition stdint.h:79
__int64 int64_t
Definition stdint.h:89
Sequence * SEQ_find_metastrip_by_sequence(ListBase *seqbase, Sequence *meta, Sequence *seq)
float SEQ_give_frame_index(const Scene *scene, const Sequence *seq, float timeline_frame)
Definition strip_time.cc:60
int SEQ_time_strip_length_get(const Scene *scene, const Sequence *seq)
int SEQ_time_left_handle_frame_get(const Scene *, const Sequence *seq)
int SEQ_time_right_handle_frame_get(const Scene *scene, const Sequence *seq)
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
uint16_t x
Definition effects.cc:2845
uint16_t y
Definition effects.cc:2846
int lines
Definition BLF_api.hh:406
ColorManagedColorspaceSettings sequencer_colorspace_settings
void(* free)(Sequence *seq, bool do_id_user)
void(* get_default_fac)(const Scene *scene, const Sequence *seq, float timeline_frame, float *fac)
void(* copy)(Sequence *dst, const Sequence *src, int flag)
void(* init)(Sequence *seq)
ImBuf *(* init_execution)(const SeqRenderData *context, ImBuf *ibuf1, ImBuf *ibuf2)
void(* load)(Sequence *seqconst)
ImBuf *(* execute)(const SeqRenderData *context, Sequence *seq, float timeline_frame, float fac, ImBuf *ibuf1, ImBuf *ibuf2)
StripEarlyOut(* early_out)(const Sequence *seq, float fac)
int(* num_inputs)()
void(* execute_slice)(const SeqRenderData *context, Sequence *seq, float timeline_frame, float fac, const ImBuf *ibuf1, const ImBuf *ibuf2, int start_line, int total_lines, ImBuf *out)
struct Sequence * seq1
char filepath[1024]
struct PackedFile * packedfile
bool forward
Definition effects.cc:1066
float angle
Definition effects.cc:1059
float clockWidth
Definition effects.cc:1064
float pythangle
Definition effects.cc:1063
int width
Definition effects.cc:1062
int x
Definition types_int2.h:15
int y
Definition types_int2.h:15
int ymin
int ymax
int xmin
int xmax
ccl_device_inline int clamp(int a, int mn, int mx)
Definition util/math.h:379
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138