Blender V4.3
sequencer/intern/modifier.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012-2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstddef>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
14#include "BLI_array.hh"
15#include "BLI_listbase.h"
16#include "BLI_math_geom.h"
17#include "BLI_math_vector.hh"
18#include "BLI_string.h"
19#include "BLI_string_utils.hh"
20#include "BLI_task.hh"
21#include "BLI_utildefines.h"
22
23#include "BLT_translation.hh"
24
25#include "DNA_mask_types.h"
26#include "DNA_scene_types.h"
27#include "DNA_sequence_types.h"
28
29#include "BKE_colortools.hh"
30
32#include "IMB_imbuf.hh"
33#include "IMB_imbuf_types.hh"
34
35#include "SEQ_modifier.hh"
36#include "SEQ_render.hh"
37#include "SEQ_sound.hh"
38#include "SEQ_time.hh"
39#include "SEQ_utils.hh"
40
41#include "BLO_read_write.hh"
42
43#include "render.hh"
44
45using namespace blender;
46
48static bool modifierTypesInit = false;
49
50/* -------------------------------------------------------------------- */
54using modifier_apply_threaded_cb = void (*)(int width,
55 int height,
56 uchar *rect,
57 float *rect_float,
58 uchar *mask_rect,
59 const float *mask_rect_float,
60 void *data_v);
61
69
80
85 int mask_input_type,
86 Sequence *mask_sequence,
87 Mask *mask_id,
88 int timeline_frame,
89 int fra_offset,
90 bool make_float)
91{
92 ImBuf *mask_input = nullptr;
93
94 if (mask_input_type == SEQUENCE_MASK_INPUT_STRIP) {
95 if (mask_sequence) {
97
98 mask_input = seq_render_strip(context, &state, mask_sequence, timeline_frame);
99
100 if (make_float) {
101 if (!mask_input->float_buffer.data) {
102 IMB_float_from_rect(mask_input);
103 }
104 }
105 else {
106 if (!mask_input->byte_buffer.data) {
107 IMB_rect_from_float(mask_input);
108 }
109 }
110 }
111 }
112 else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) {
113 mask_input = seq_render_mask(context, mask_id, timeline_frame - fra_offset, make_float);
114 }
115
116 return mask_input;
117}
118
120 const SeqRenderData *context,
121 int timeline_frame,
122 int fra_offset,
123 bool make_float)
124{
125 return modifier_render_mask_input(context,
126 smd->mask_input_type,
127 smd->mask_sequence,
128 smd->mask_id,
129 timeline_frame,
130 fra_offset,
131 make_float);
132}
133
134static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
135{
136 ModifierThread *handle = (ModifierThread *)handle_v;
138 ImBuf *ibuf = init_data->ibuf;
139 ImBuf *mask = init_data->mask;
140
141 int offset = 4 * start_line * ibuf->x;
142
143 memset(handle, 0, sizeof(ModifierThread));
144
145 handle->width = ibuf->x;
146 handle->height = tot_line;
147 handle->apply_callback = init_data->apply_callback;
148 handle->user_data = init_data->user_data;
149
150 if (ibuf->byte_buffer.data) {
151 handle->rect = ibuf->byte_buffer.data + offset;
152 }
153
154 if (ibuf->float_buffer.data) {
155 handle->rect_float = ibuf->float_buffer.data + offset;
156 }
157
158 if (mask) {
159 if (mask->byte_buffer.data) {
160 handle->mask_rect = mask->byte_buffer.data + offset;
161 }
162
163 if (mask->float_buffer.data) {
164 handle->mask_rect_float = mask->float_buffer.data + offset;
165 }
166 }
167 else {
168 handle->mask_rect = nullptr;
169 handle->mask_rect_float = nullptr;
170 }
171}
172
173static void *modifier_do_thread(void *thread_data_v)
174{
175 ModifierThread *td = (ModifierThread *)thread_data_v;
176
177 td->apply_callback(td->width,
178 td->height,
179 td->rect,
180 td->rect_float,
181 td->mask_rect,
182 td->mask_rect_float,
183 td->user_data);
184
185 return nullptr;
186}
187
189 ImBuf *mask,
190 modifier_apply_threaded_cb apply_callback,
191 void *user_data)
192{
194
195 init_data.ibuf = ibuf;
196 init_data.mask = mask;
197 init_data.user_data = user_data;
198
199 init_data.apply_callback = apply_callback;
200
203}
204
207/* -------------------------------------------------------------------- */
212{
213 StripColorBalance cb = *cb_;
214 int c;
215
216 for (c = 0; c < 3; c++) {
217 cb.lift[c] = 2.0f - cb.lift[c];
218 }
219
221 for (c = 0; c < 3; c++) {
222 /* tweak to give more subtle results
223 * values above 1.0 are scaled */
224 if (cb.lift[c] > 1.0f) {
225 cb.lift[c] = pow(cb.lift[c] - 1.0f, 2.0) + 1.0;
226 }
227
228 cb.lift[c] = 2.0f - cb.lift[c];
229 }
230 }
231
233 for (c = 0; c < 3; c++) {
234 if (cb.gain[c] != 0.0f) {
235 cb.gain[c] = 1.0f / cb.gain[c];
236 }
237 else {
238 cb.gain[c] = 1000000; /* should be enough :) */
239 }
240 }
241 }
242
244 for (c = 0; c < 3; c++) {
245 if (cb.gamma[c] != 0.0f) {
246 cb.gamma[c] = 1.0f / cb.gamma[c];
247 }
248 else {
249 cb.gamma[c] = 1000000; /* should be enough :) */
250 }
251 }
252 }
253
254 return cb;
255}
256
258{
259 StripColorBalance cb = *cb_;
260 int c;
261
262 for (c = 0; c < 3; c++) {
264 if (cb.slope[c] != 0.0f) {
265 cb.slope[c] = 1.0f / cb.slope[c];
266 }
267 else {
268 cb.slope[c] = 1000000;
269 }
270 }
271
273 cb.offset[c] = -1.0f * (cb.offset[c] - 1.0f);
274 }
275 else {
276 cb.offset[c] = cb.offset[c] - 1.0f;
277 }
278
280 if (cb.power[c] != 0.0f) {
281 cb.power[c] = 1.0f / cb.power[c];
282 }
283 else {
284 cb.power[c] = 1000000;
285 }
286 }
287 }
288
289 return cb;
290}
291
293{
295 return calc_cb_lgg(cb_);
296 }
297 /* `cb_->method == SEQ_COLOR_BALANCE_METHOD_SLOPEOFFSETPOWER`. */
298 return calc_cb_sop(cb_);
299}
300
301/* Lift-Gamma-Gain math. NOTE: lift is actually (2-lift). */
302static float color_balance_lgg(
303 float in, const float lift, const float gain, const float gamma, const float mul)
304{
305 float x = (((in - 1.0f) * lift) + 1.0f) * gain;
306
307 /* prevent NaN */
308 if (x < 0.0f) {
309 x = 0.0f;
310 }
311
312 x = powf(x, gamma) * mul;
313 CLAMP(x, FLT_MIN, FLT_MAX);
314 return x;
315}
316
317/* Slope-Offset-Power (ASC CDL) math, see https://en.wikipedia.org/wiki/ASC_CDL */
318static float color_balance_sop(
319 float in, const float slope, const float offset, const float power, float mul)
320{
321 float x = in * slope + offset;
322
323 /* prevent NaN */
324 if (x < 0.0f) {
325 x = 0.0f;
326 }
327
328 x = powf(x, power);
329 x *= mul;
330 CLAMP(x, FLT_MIN, FLT_MAX);
331 return x;
332}
333
338static constexpr int CB_TABLE_SIZE = 1024;
339
341 float lift, float gain, float gamma, float mul, float r_table[CB_TABLE_SIZE])
342{
343 for (int i = 0; i < CB_TABLE_SIZE; i++) {
344 float x = float(i) * (1.0f / (CB_TABLE_SIZE - 1.0f));
345 r_table[i] = color_balance_lgg(x, lift, gain, gamma, mul);
346 }
347}
348
350 float slope, float offset, float power, float mul, float r_table[CB_TABLE_SIZE])
351{
352 for (int i = 0; i < CB_TABLE_SIZE; i++) {
353 float x = float(i) * (1.0f / (CB_TABLE_SIZE - 1.0f));
354 r_table[i] = color_balance_sop(x, slope, offset, power, mul);
355 }
356}
357
358static void color_balance_byte(const float cb_tab[3][CB_TABLE_SIZE],
359 uchar *rect,
360 const uchar *mask_rect,
361 int width,
362 int height)
363{
364 uchar *ptr = rect;
365 const uchar *ptr_end = ptr + int64_t(width) * height * 4;
366 const uchar *mask_ptr = mask_rect;
367
368 if (mask_ptr != nullptr) {
369 /* Mask is used.*/
370 while (ptr < ptr_end) {
371 float pix[4];
373
374 int p0 = int(pix[0] * (CB_TABLE_SIZE - 1.0f) + 0.5f);
375 int p1 = int(pix[1] * (CB_TABLE_SIZE - 1.0f) + 0.5f);
376 int p2 = int(pix[2] * (CB_TABLE_SIZE - 1.0f) + 0.5f);
377 const float t[3] = {mask_ptr[0] / 255.0f, mask_ptr[1] / 255.0f, mask_ptr[2] / 255.0f};
378
379 pix[0] = pix[0] * (1.0f - t[0]) + t[0] * cb_tab[0][p0];
380 pix[1] = pix[1] * (1.0f - t[1]) + t[1] * cb_tab[1][p1];
381 pix[2] = pix[2] * (1.0f - t[2]) + t[2] * cb_tab[2][p2];
382
384 ptr += 4;
385 mask_ptr += 4;
386 }
387 }
388 else {
389 /* No mask. */
390 while (ptr < ptr_end) {
391 float pix[4];
393
394 int p0 = int(pix[0] * (CB_TABLE_SIZE - 1.0f) + 0.5f);
395 int p1 = int(pix[1] * (CB_TABLE_SIZE - 1.0f) + 0.5f);
396 int p2 = int(pix[2] * (CB_TABLE_SIZE - 1.0f) + 0.5f);
397 pix[0] = cb_tab[0][p0];
398 pix[1] = cb_tab[1][p1];
399 pix[2] = cb_tab[2][p2];
401 ptr += 4;
402 }
403 }
404}
405
407 float *rect_float,
408 const float *mask_rect_float,
409 int width,
410 int height,
411 float mul)
412{
413 float *ptr = rect_float;
414 const float *ptr_end = rect_float + int64_t(width) * height * 4;
415 const float *mask_ptr = mask_rect_float;
416
418 /* Lift/Gamma/Gain */
419 const float3 lift = cb->lift;
420 const float3 gain = cb->gain;
421 const float3 gamma = cb->gamma;
422 while (ptr < ptr_end) {
423 float t0 = color_balance_lgg(ptr[0], lift.x, gain.x, gamma.x, mul);
424 float t1 = color_balance_lgg(ptr[1], lift.y, gain.y, gamma.y, mul);
425 float t2 = color_balance_lgg(ptr[2], lift.z, gain.z, gamma.z, mul);
426 if (mask_ptr) {
427 ptr[0] = ptr[0] * (1.0f - mask_ptr[0]) + t0 * mask_ptr[0];
428 ptr[1] = ptr[1] * (1.0f - mask_ptr[1]) + t1 * mask_ptr[1];
429 ptr[2] = ptr[2] * (1.0f - mask_ptr[2]) + t2 * mask_ptr[2];
430 }
431 else {
432 ptr[0] = t0;
433 ptr[1] = t1;
434 ptr[2] = t2;
435 }
436 ptr += 4;
437 if (mask_ptr) {
438 mask_ptr += 4;
439 }
440 }
441 }
442 else {
443 /* Slope/Offset/Power */
444 const float3 slope = cb->slope;
445 const float3 offset = cb->offset;
446 const float3 power = cb->power;
447 while (ptr < ptr_end) {
448 float t0 = color_balance_sop(ptr[0], slope.x, offset.x, power.x, mul);
449 float t1 = color_balance_sop(ptr[1], slope.y, offset.y, power.y, mul);
450 float t2 = color_balance_sop(ptr[2], slope.z, offset.z, power.z, mul);
451 if (mask_ptr) {
452 ptr[0] = ptr[0] * (1.0f - mask_ptr[0]) + t0 * mask_ptr[0];
453 ptr[1] = ptr[1] * (1.0f - mask_ptr[1]) + t1 * mask_ptr[1];
454 ptr[2] = ptr[2] * (1.0f - mask_ptr[2]) + t2 * mask_ptr[2];
455 }
456 else {
457 ptr[0] = t0;
458 ptr[1] = t1;
459 ptr[2] = t2;
460 }
461 ptr += 4;
462 if (mask_ptr) {
463 mask_ptr += 4;
464 }
465 }
466 }
467}
468
470{
472
473 cbmd->color_multiply = 1.0f;
474 cbmd->color_balance.method = 0;
475
476 for (int c = 0; c < 3; c++) {
477 cbmd->color_balance.lift[c] = 1.0f;
478 cbmd->color_balance.gamma[c] = 1.0f;
479 cbmd->color_balance.gain[c] = 1.0f;
480 cbmd->color_balance.slope[c] = 1.0f;
481 cbmd->color_balance.offset[c] = 1.0f;
482 cbmd->color_balance.power[c] = 1.0f;
483 }
484}
485
486static void colorBalance_apply(const StripScreenQuad & /*quad*/,
488 ImBuf *ibuf,
489 ImBuf *mask)
490{
491 const ColorBalanceModifierData *cbmd = (const ColorBalanceModifierData *)smd;
492
493 const StripColorBalance cb = calc_cb(&cbmd->color_balance);
494 const float mul = cbmd->color_multiply;
495
496 /* When working on non-float image, precalculate CB LUTs. */
497 float cb_tab[3][CB_TABLE_SIZE];
498 if (ibuf->float_buffer.data == nullptr) {
499 for (int c = 0; c < 3; c++) {
501 make_cb_table_lgg(cb.lift[c], cb.gain[c], cb.gamma[c], mul, cb_tab[c]);
502 }
503 else {
504 make_cb_table_sop(cb.slope[c], cb.offset[c], cb.power[c], mul, cb_tab[c]);
505 }
506 }
507 }
508
509 threading::parallel_for(IndexRange(ibuf->y), 32, [&](const IndexRange y_range) {
510 const int64_t offset = y_range.first() * ibuf->x * 4;
511 const int y_size = int(y_range.size());
512 if (ibuf->float_buffer.data != nullptr) {
513 /* Float pixels. */
514 color_balance_float(&cb,
515 ibuf->float_buffer.data + offset,
516 mask ? mask->float_buffer.data + offset : nullptr,
517 ibuf->x,
518 y_size,
519 mul);
520 }
521 else {
522 /* Byte pixels. */
523 color_balance_byte(cb_tab,
524 ibuf->byte_buffer.data + offset,
525 mask ? mask->byte_buffer.data + offset : nullptr,
526 ibuf->x,
527 y_size);
528 }
529 });
530}
531
533 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color Balance"),
534 /*struct_name*/ "ColorBalanceModifierData",
535 /*struct_size*/ sizeof(ColorBalanceModifierData),
536 /*init_data*/ colorBalance_init_data,
537 /*free_data*/ nullptr,
538 /*copy_data*/ nullptr,
539 /*apply*/ colorBalance_apply,
540};
541
544/* -------------------------------------------------------------------- */
553
555 float white[3];
556};
557
558static void whiteBalance_apply_threaded(int width,
559 int height,
560 uchar *rect,
561 float *rect_float,
562 uchar *mask_rect,
563 const float *mask_rect_float,
564 void *data_v)
565{
566 int x, y;
567 float multiplier[3];
568
570
571 multiplier[0] = (data->white[0] != 0.0f) ? 1.0f / data->white[0] : FLT_MAX;
572 multiplier[1] = (data->white[1] != 0.0f) ? 1.0f / data->white[1] : FLT_MAX;
573 multiplier[2] = (data->white[2] != 0.0f) ? 1.0f / data->white[2] : FLT_MAX;
574
575 for (y = 0; y < height; y++) {
576 for (x = 0; x < width; x++) {
577 int pixel_index = (y * width + x) * 4;
578 float rgba[4], result[4], mask[3] = {1.0f, 1.0f, 1.0f};
579
580 if (rect_float) {
581 copy_v3_v3(rgba, rect_float + pixel_index);
582 }
583 else {
584 straight_uchar_to_premul_float(rgba, rect + pixel_index);
585 }
586
587 copy_v4_v4(result, rgba);
588#if 0
589 mul_v3_v3(result, multiplier);
590#else
591 /* similar to division without the clipping */
592 for (int i = 0; i < 3; i++) {
593 result[i] = 1.0f - powf(1.0f - rgba[i], multiplier[i]);
594 }
595#endif
596
597 if (mask_rect_float) {
598 copy_v3_v3(mask, mask_rect_float + pixel_index);
599 }
600 else if (mask_rect) {
601 rgb_uchar_to_float(mask, mask_rect + pixel_index);
602 }
603
604 result[0] = rgba[0] * (1.0f - mask[0]) + result[0] * mask[0];
605 result[1] = rgba[1] * (1.0f - mask[1]) + result[1] * mask[1];
606 result[2] = rgba[2] * (1.0f - mask[2]) + result[2] * mask[2];
607
608 if (rect_float) {
609 copy_v3_v3(rect_float + pixel_index, result);
610 }
611 else {
612 premul_float_to_straight_uchar(rect + pixel_index, result);
613 }
614 }
615 }
616}
617
618static void whiteBalance_apply(const StripScreenQuad & /*quad*/,
620 ImBuf *ibuf,
621 ImBuf *mask)
622{
625
626 copy_v3_v3(data.white, wbmd->white_value);
627
629}
630
632 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "White Balance"),
633 /*struct_name*/ "WhiteBalanceModifierData",
634 /*struct_size*/ sizeof(WhiteBalanceModifierData),
635 /*init_data*/ whiteBalance_init_data,
636 /*free_data*/ nullptr,
637 /*copy_data*/ nullptr,
638 /*apply*/ whiteBalance_apply,
639};
640
643/* -------------------------------------------------------------------- */
648{
650
651 BKE_curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
652}
653
660
662{
664 CurvesModifierData *cmd_target = (CurvesModifierData *)target;
665
667}
668
669static void curves_apply_threaded(int width,
670 int height,
671 uchar *rect,
672 float *rect_float,
673 uchar *mask_rect,
674 const float *mask_rect_float,
675 void *data_v)
676{
677 CurveMapping *curve_mapping = (CurveMapping *)data_v;
678 int x, y;
679
680 for (y = 0; y < height; y++) {
681 for (x = 0; x < width; x++) {
682 int pixel_index = (y * width + x) * 4;
683
684 if (rect_float) {
685 float *pixel = rect_float + pixel_index;
686 float result[3];
687
688 BKE_curvemapping_evaluate_premulRGBF(curve_mapping, result, pixel);
689
690 if (mask_rect_float) {
691 const float *m = mask_rect_float + pixel_index;
692
693 pixel[0] = pixel[0] * (1.0f - m[0]) + result[0] * m[0];
694 pixel[1] = pixel[1] * (1.0f - m[1]) + result[1] * m[1];
695 pixel[2] = pixel[2] * (1.0f - m[2]) + result[2] * m[2];
696 }
697 else {
698 pixel[0] = result[0];
699 pixel[1] = result[1];
700 pixel[2] = result[2];
701 }
702 }
703 if (rect) {
704 uchar *pixel = rect + pixel_index;
705 float result[3], tempc[4];
706
707 straight_uchar_to_premul_float(tempc, pixel);
708
709 BKE_curvemapping_evaluate_premulRGBF(curve_mapping, result, tempc);
710
711 if (mask_rect) {
712 float t[3];
713
714 rgb_uchar_to_float(t, mask_rect + pixel_index);
715
716 tempc[0] = tempc[0] * (1.0f - t[0]) + result[0] * t[0];
717 tempc[1] = tempc[1] * (1.0f - t[1]) + result[1] * t[1];
718 tempc[2] = tempc[2] * (1.0f - t[2]) + result[2] * t[2];
719 }
720 else {
721 tempc[0] = result[0];
722 tempc[1] = result[1];
723 tempc[2] = result[2];
724 }
725
726 premul_float_to_straight_uchar(pixel, tempc);
727 }
728 }
729 }
730}
731
732static void curves_apply(const StripScreenQuad & /*quad*/,
734 ImBuf *ibuf,
735 ImBuf *mask)
736{
738
739 const float black[3] = {0.0f, 0.0f, 0.0f};
740 const float white[3] = {1.0f, 1.0f, 1.0f};
741
743
746
748
750}
751
753 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Curves"),
754 /*struct_name*/ "CurvesModifierData",
755 /*struct_size*/ sizeof(CurvesModifierData),
756 /*init_data*/ curves_init_data,
757 /*free_data*/ curves_free_data,
758 /*copy_data*/ curves_copy_data,
759 /*apply*/ curves_apply,
760};
761
764/* -------------------------------------------------------------------- */
769{
771 int c;
772
773 BKE_curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
775
776 for (c = 0; c < 3; c++) {
777 CurveMap *cuma = &hcmd->curve_mapping.cm[c];
780 }
781 /* use wrapping for all hue correct modifiers */
783 /* default to showing Saturation */
784 hcmd->curve_mapping.cur = 1;
785}
786
793
801
802static void hue_correct_apply_threaded(int width,
803 int height,
804 uchar *rect,
805 float *rect_float,
806 uchar *mask_rect,
807 const float *mask_rect_float,
808 void *data_v)
809{
810 CurveMapping *curve_mapping = (CurveMapping *)data_v;
811 int x, y;
812
813 for (y = 0; y < height; y++) {
814 for (x = 0; x < width; x++) {
815 int pixel_index = (y * width + x) * 4;
816 float pixel[3], result[3], mask[3] = {1.0f, 1.0f, 1.0f};
817 float hsv[3], f;
818
819 if (rect_float) {
820 copy_v3_v3(pixel, rect_float + pixel_index);
821 }
822 else {
823 rgb_uchar_to_float(pixel, rect + pixel_index);
824 }
825
826 rgb_to_hsv(pixel[0], pixel[1], pixel[2], hsv, hsv + 1, hsv + 2);
827
828 /* adjust hue, scaling returned default 0.5 up to 1 */
829 f = BKE_curvemapping_evaluateF(curve_mapping, 0, hsv[0]);
830 hsv[0] += f - 0.5f;
831
832 /* adjust saturation, scaling returned default 0.5 up to 1 */
833 f = BKE_curvemapping_evaluateF(curve_mapping, 1, hsv[0]);
834 hsv[1] *= (f * 2.0f);
835
836 /* adjust value, scaling returned default 0.5 up to 1 */
837 f = BKE_curvemapping_evaluateF(curve_mapping, 2, hsv[0]);
838 hsv[2] *= (f * 2.0f);
839
840 hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */
841 CLAMP(hsv[1], 0.0f, 1.0f);
842
843 /* convert back to rgb */
844 hsv_to_rgb(hsv[0], hsv[1], hsv[2], result, result + 1, result + 2);
845
846 if (mask_rect_float) {
847 copy_v3_v3(mask, mask_rect_float + pixel_index);
848 }
849 else if (mask_rect) {
850 rgb_uchar_to_float(mask, mask_rect + pixel_index);
851 }
852
853 result[0] = pixel[0] * (1.0f - mask[0]) + result[0] * mask[0];
854 result[1] = pixel[1] * (1.0f - mask[1]) + result[1] * mask[1];
855 result[2] = pixel[2] * (1.0f - mask[2]) + result[2] * mask[2];
856
857 if (rect_float) {
858 copy_v3_v3(rect_float + pixel_index, result);
859 }
860 else {
861 rgb_float_to_uchar(rect + pixel_index, result);
862 }
863 }
864 }
865}
866
867static void hue_correct_apply(const StripScreenQuad & /*quad*/,
869 ImBuf *ibuf,
870 ImBuf *mask)
871{
873
875
877}
878
880 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Hue Correct"),
881 /*struct_name*/ "HueCorrectModifierData",
882 /*struct_size*/ sizeof(HueCorrectModifierData),
883 /*init_data*/ hue_correct_init_data,
884 /*free_data*/ hue_correct_free_data,
885 /*copy_data*/ hue_correct_copy_data,
886 /*apply*/ hue_correct_apply,
887};
888
891/* -------------------------------------------------------------------- */
899
900static void brightcontrast_apply_threaded(int width,
901 int height,
902 uchar *rect,
903 float *rect_float,
904 uchar *mask_rect,
905 const float *mask_rect_float,
906 void *data_v)
907{
909 int x, y;
910
911 float i;
912 int c;
913 float a, b, v;
914 const float brightness = data->bright / 100.0f;
915 const float contrast = data->contrast;
916 float delta = contrast / 200.0f;
917 /*
918 * The algorithm is by Werner D. Streidt
919 * (http://visca.com/ffactory/archives/5-99/msg00021.html)
920 * Extracted of OpenCV `demhist.c`.
921 */
922 if (contrast > 0) {
923 a = 1.0f - delta * 2.0f;
924 a = 1.0f / max_ff(a, FLT_EPSILON);
925 b = a * (brightness - delta);
926 }
927 else {
928 delta *= -1;
929 a = max_ff(1.0f - delta * 2.0f, 0.0f);
930 b = a * brightness + delta;
931 }
932
933 for (y = 0; y < height; y++) {
934 for (x = 0; x < width; x++) {
935 int pixel_index = (y * width + x) * 4;
936
937 if (rect) {
938 uchar *pixel = rect + pixel_index;
939
940 for (c = 0; c < 3; c++) {
941 i = float(pixel[c]) / 255.0f;
942 v = a * i + b;
943
944 if (mask_rect) {
945 const uchar *m = mask_rect + pixel_index;
946 const float t = float(m[c]) / 255.0f;
947
948 v = float(pixel[c]) / 255.0f * (1.0f - t) + v * t;
949 }
950
951 pixel[c] = unit_float_to_uchar_clamp(v);
952 }
953 }
954 else if (rect_float) {
955 float *pixel = rect_float + pixel_index;
956
957 for (c = 0; c < 3; c++) {
958 i = pixel[c];
959 v = a * i + b;
960
961 if (mask_rect_float) {
962 const float *m = mask_rect_float + pixel_index;
963
964 pixel[c] = pixel[c] * (1.0f - m[c]) + v * m[c];
965 }
966 else {
967 pixel[c] = v;
968 }
969 }
970 }
971 }
972 }
973}
974
975static void brightcontrast_apply(const StripScreenQuad & /*quad*/,
977 ImBuf *ibuf,
978 ImBuf *mask)
979{
982
983 data.bright = bcmd->bright;
984 data.contrast = bcmd->contrast;
985
987}
988
990 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Brightness/Contrast"),
991 /*struct_name*/ "BrightContrastModifierData",
992 /*struct_size*/ sizeof(BrightContrastModifierData),
993 /*init_data*/ nullptr,
994 /*free_data*/ nullptr,
995 /*copy_data*/ nullptr,
996 /*apply*/ brightcontrast_apply,
997};
998
1001/* -------------------------------------------------------------------- */
1005static void maskmodifier_apply_threaded(int width,
1006 int height,
1007 uchar *rect,
1008 float *rect_float,
1009 uchar *mask_rect,
1010 const float *mask_rect_float,
1011 void * /*data_v*/)
1012{
1013 int x, y;
1014
1015 if (rect && !mask_rect) {
1016 return;
1017 }
1018
1019 if (rect_float && !mask_rect_float) {
1020 return;
1021 }
1022
1023 for (y = 0; y < height; y++) {
1024 for (x = 0; x < width; x++) {
1025 const int pixel_index = (y * width + x) * 4;
1026
1027 if (rect) {
1028 const uchar *mask_pixel = mask_rect + pixel_index;
1029 const uchar mask = min_iii(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
1030 uchar *pixel = rect + pixel_index;
1031
1032 /* byte buffer is straight, so only affect on alpha itself,
1033 * this is the only way to alpha-over byte strip after
1034 * applying mask modifier.
1035 */
1036 pixel[3] = float(pixel[3] * mask) / 255.0f;
1037 }
1038 else if (rect_float) {
1039 const float *mask_pixel = mask_rect_float + pixel_index;
1040 const float mask = min_fff(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
1041 float *pixel = rect_float + pixel_index;
1042
1043 /* float buffers are premultiplied, so need to premul color
1044 * as well to make it easy to alpha-over masted strip.
1045 */
1046 for (int c = 0; c < 4; c++) {
1047 pixel[c] = pixel[c] * mask;
1048 }
1049 }
1050 }
1051 }
1052}
1053
1054static void maskmodifier_apply(const StripScreenQuad & /*quad*/,
1055 SequenceModifierData * /*smd*/,
1056 ImBuf *ibuf,
1057 ImBuf *mask)
1058{
1059 // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
1060
1062 ibuf->planes = R_IMF_PLANES_RGBA;
1063}
1064
1066 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Mask"),
1067 /*struct_name*/ "SequencerMaskModifierData",
1068 /*struct_size*/ sizeof(SequencerMaskModifierData),
1069 /*init_data*/ nullptr,
1070 /*free_data*/ nullptr,
1071 /*copy_data*/ nullptr,
1072 /*apply*/ maskmodifier_apply,
1073};
1074
1077/* -------------------------------------------------------------------- */
1089
1091{
1093 /* Same as tone-map compositor node. */
1095 tmmd->key = 0.18f;
1096 tmmd->offset = 1.0f;
1097 tmmd->gamma = 1.0f;
1098 tmmd->intensity = 0.0f;
1099 tmmd->contrast = 0.0f;
1100 tmmd->adaptation = 1.0f;
1101 tmmd->correction = 0.0f;
1102}
1103
1104/* Convert chunk of float image pixels to scene linear space, in-place. */
1106{
1108 (float *)(pixels), int(count), 1, 4, colorspace, false);
1109}
1110
1111/* Convert chunk of byte image pixels to scene linear space, into a destination array. */
1113 const uchar *pixels,
1114 float4 *dst,
1115 int64_t count)
1116{
1117 const uchar *bptr = pixels;
1118 float4 *dst_ptr = dst;
1119 for (int64_t i = 0; i < count; i++) {
1120 straight_uchar_to_premul_float(*dst_ptr, bptr);
1121 bptr += 4;
1122 dst_ptr++;
1123 }
1125 (float *)dst, int(count), 1, 4, colorspace, false);
1126}
1127
1129{
1130 ColorSpace *colorspace = ibuf->float_buffer.colorspace;
1131 float4 *fptr = reinterpret_cast<float4 *>(ibuf->float_buffer.data);
1133 (float *)(fptr + range.first()), int(range.size()), 1, 4, colorspace);
1134}
1135
1137{
1138 ColorSpace *colorspace = ibuf->byte_buffer.colorspace;
1140 (float *)src, int(range.size()), 1, 4, colorspace);
1141 const float4 *src_ptr = src;
1142 uchar *bptr = ibuf->byte_buffer.data;
1143 for (const int64_t idx : range) {
1144 premul_float_to_straight_uchar(bptr + idx * 4, *src_ptr);
1145 src_ptr++;
1146 }
1147}
1148
1149static void tonemap_simple(float4 *scene_linear,
1150 ImBuf *mask,
1151 IndexRange range,
1152 const AvgLogLum &avg)
1153{
1154 const float4 *mask_float = mask != nullptr ? (const float4 *)mask->float_buffer.data : nullptr;
1155 const uchar4 *mask_byte = mask != nullptr ? (const uchar4 *)mask->byte_buffer.data : nullptr;
1156
1157 int64_t index = 0;
1158 for (const int64_t pixel_index : range) {
1159 float4 input = scene_linear[index];
1160
1161 /* Apply correction. */
1162 float3 pixel = input.xyz() * avg.al;
1163 float3 d = pixel + avg.tmmd->offset;
1164 pixel.x /= (d.x == 0.0f) ? 1.0f : d.x;
1165 pixel.y /= (d.y == 0.0f) ? 1.0f : d.y;
1166 pixel.z /= (d.z == 0.0f) ? 1.0f : d.z;
1167 const float igm = avg.igm;
1168 if (igm != 0.0f) {
1169 pixel.x = powf(math::max(pixel.x, 0.0f), igm);
1170 pixel.y = powf(math::max(pixel.y, 0.0f), igm);
1171 pixel.z = powf(math::max(pixel.z, 0.0f), igm);
1172 }
1173
1174 /* Apply mask. */
1175 if (mask != nullptr) {
1176 float3 msk(1.0f);
1177 if (mask_float != nullptr) {
1178 msk = mask_float[pixel_index].xyz();
1179 }
1180 else if (mask_byte != nullptr) {
1181 rgb_uchar_to_float(msk, mask_byte[pixel_index]);
1182 }
1183 pixel = math::interpolate(input.xyz(), pixel, msk);
1184 }
1185
1186 scene_linear[index] = float4(pixel.x, pixel.y, pixel.z, input.w);
1187 index++;
1188 }
1189}
1190
1191static void tonemap_rd_photoreceptor(float4 *scene_linear,
1192 ImBuf *mask,
1193 IndexRange range,
1194 const AvgLogLum &avg)
1195{
1196 const float4 *mask_float = mask != nullptr ? (const float4 *)mask->float_buffer.data : nullptr;
1197 const uchar4 *mask_byte = mask != nullptr ? (const uchar4 *)mask->byte_buffer.data : nullptr;
1198
1199 const float f = expf(-avg.tmmd->intensity);
1200 const float m = (avg.tmmd->contrast > 0.0f) ? avg.tmmd->contrast :
1201 (0.3f + 0.7f * powf(avg.auto_key, 1.4f));
1202 const float ic = 1.0f - avg.tmmd->correction, ia = 1.0f - avg.tmmd->adaptation;
1203
1204 int64_t index = 0;
1205 for (const int64_t pixel_index : range) {
1206 float4 input = scene_linear[index];
1207
1208 /* Apply correction. */
1209 float3 pixel = input.xyz();
1210 const float L = IMB_colormanagement_get_luminance(pixel);
1211 float I_l = pixel.x + ic * (L - pixel.x);
1212 float I_g = avg.cav.x + ic * (avg.lav - avg.cav.x);
1213 float I_a = I_l + ia * (I_g - I_l);
1214 pixel.x /= std::max(pixel.x + powf(f * I_a, m), 1.0e-30f);
1215 I_l = pixel.y + ic * (L - pixel.y);
1216 I_g = avg.cav.y + ic * (avg.lav - avg.cav.y);
1217 I_a = I_l + ia * (I_g - I_l);
1218 pixel.y /= std::max(pixel.y + powf(f * I_a, m), 1.0e-30f);
1219 I_l = pixel.z + ic * (L - pixel.z);
1220 I_g = avg.cav.z + ic * (avg.lav - avg.cav.z);
1221 I_a = I_l + ia * (I_g - I_l);
1222 pixel.z /= std::max(pixel.z + powf(f * I_a, m), 1.0e-30f);
1223
1224 /* Apply mask. */
1225 if (mask != nullptr) {
1226 float3 msk(1.0f);
1227 if (mask_float != nullptr) {
1228 msk = mask_float[pixel_index].xyz();
1229 }
1230 else if (mask_byte != nullptr) {
1231 rgb_uchar_to_float(msk, mask_byte[pixel_index]);
1232 }
1233 pixel = math::interpolate(input.xyz(), pixel, msk);
1234 }
1235
1236 scene_linear[index] = float4(pixel.x, pixel.y, pixel.z, input.w);
1237 index++;
1238 }
1239}
1240
1241static bool is_point_inside_quad(const StripScreenQuad &quad, int x, int y)
1242{
1243 float2 pt(x + 0.5f, y + 0.5f);
1244 return isect_point_quad_v2(pt, quad.v0, quad.v1, quad.v2, quad.v3);
1245}
1246
1249 double sum = 0.0f;
1250 float3 color_sum = {0, 0, 0};
1251 double log_sum = 0.0;
1252 float min = FLT_MAX;
1253 float max = -FLT_MAX;
1254};
1255
1257 const bool all_pixels_inside_quad,
1258 const int width,
1259 const IndexRange y_range,
1260 const float4 *scene_linear,
1261 AreaLuminance &r_lum)
1262{
1263 for (const int y : y_range) {
1264 for (int x = 0; x < width; x++) {
1265 if (all_pixels_inside_quad || is_point_inside_quad(quad, x, y)) {
1266 float4 pixel = *scene_linear;
1267 r_lum.pixel_count++;
1268 float L = IMB_colormanagement_get_luminance(pixel);
1269 r_lum.sum += L;
1270 r_lum.color_sum.x += pixel.x;
1271 r_lum.color_sum.y += pixel.y;
1272 r_lum.color_sum.z += pixel.z;
1273 r_lum.log_sum += logf(math::max(L, 0.0f) + 1e-5f);
1274 r_lum.max = math::max(r_lum.max, L);
1275 r_lum.min = math::min(r_lum.min, L);
1276 }
1277 scene_linear++;
1278 }
1279 }
1280}
1281
1283{
1284 /* Pixels outside the pre-transform strip area are ignored for luminance calculations.
1285 * If strip area covers whole image, we can trivially accept all pixels. */
1286 const bool all_pixels_inside_quad = is_point_inside_quad(quad, 0, 0) &&
1287 is_point_inside_quad(quad, ibuf->x - 1, 0) &&
1288 is_point_inside_quad(quad, 0, ibuf->y - 1) &&
1289 is_point_inside_quad(quad, ibuf->x - 1, ibuf->y - 1);
1290
1291 AreaLuminance lum;
1293 IndexRange(ibuf->y),
1294 32,
1295 lum,
1296 /* Calculate luminance for a chunk. */
1297 [&](const IndexRange y_range, const AreaLuminance &init) {
1298 AreaLuminance lum = init;
1299 const int64_t chunk_size = y_range.size() * ibuf->x;
1300 /* For float images, convert to scene-linear in place. The rest
1301 * of tone-mapper can then continue with scene-linear values. */
1302 if (ibuf->float_buffer.data != nullptr) {
1303 float4 *fptr = reinterpret_cast<float4 *>(ibuf->float_buffer.data);
1304 fptr += y_range.first() * ibuf->x;
1305 pixels_to_scene_linear_float(ibuf->float_buffer.colorspace, fptr, chunk_size);
1306 tonemap_calc_chunk_luminance(quad, all_pixels_inside_quad, ibuf->x, y_range, fptr, lum);
1307 }
1308 else {
1309 const uchar *bptr = ibuf->byte_buffer.data + y_range.first() * ibuf->x * 4;
1310 Array<float4> scene_linear(chunk_size);
1311 pixels_to_scene_linear_byte(
1312 ibuf->byte_buffer.colorspace, bptr, scene_linear.data(), chunk_size);
1313 tonemap_calc_chunk_luminance(
1314 quad, all_pixels_inside_quad, ibuf->x, y_range, scene_linear.data(), lum);
1315 }
1316 return lum;
1317 },
1318 /* Reduce luminance results. */
1319 [&](const AreaLuminance &a, const AreaLuminance &b) {
1320 AreaLuminance res;
1321 res.pixel_count = a.pixel_count + b.pixel_count;
1322 res.sum = a.sum + b.sum;
1323 res.color_sum = a.color_sum + b.color_sum;
1324 res.log_sum = a.log_sum + b.log_sum;
1325 res.min = math::min(a.min, b.min);
1326 res.max = math::max(a.max, b.max);
1327 return res;
1328 });
1329 return lum;
1330}
1331
1334 ImBuf *ibuf,
1335 ImBuf *mask)
1336{
1338
1340 if (lum.pixel_count == 0) {
1341 return; /* Strip is zero size or off-screen. */
1342 }
1343
1345 data.tmmd = tmmd;
1346 data.lav = lum.sum / lum.pixel_count;
1347 data.cav.x = lum.color_sum.x / lum.pixel_count;
1348 data.cav.y = lum.color_sum.y / lum.pixel_count;
1349 data.cav.z = lum.color_sum.z / lum.pixel_count;
1350 float maxl = log(double(lum.max) + 1e-5f);
1351 float minl = log(double(lum.min) + 1e-5f);
1352 float avl = lum.log_sum / lum.pixel_count;
1353 data.auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
1354 float al = exp(double(avl));
1355 data.al = (al == 0.0f) ? 0.0f : (tmmd->key / al);
1356 data.igm = (tmmd->gamma == 0.0f) ? 1.0f : (1.0f / tmmd->gamma);
1357
1359 IndexRange(int64_t(ibuf->x) * ibuf->y), 64 * 1024, [&](IndexRange range) {
1360 if (ibuf->float_buffer.data != nullptr) {
1361 /* Float pixels: no need for temporary storage. Luminance calculation already converted
1362 * data to scene linear. */
1363 float4 *pixels = (float4 *)(ibuf->float_buffer.data) + range.first();
1364 if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
1365 tonemap_rd_photoreceptor(pixels, mask, range, data);
1366 }
1367 else {
1368 BLI_assert(tmmd->type == SEQ_TONEMAP_RH_SIMPLE);
1369 tonemap_simple(pixels, mask, range, data);
1370 }
1371 scene_linear_to_image_chunk_float(ibuf, range);
1372 }
1373 else {
1374 /* Byte pixels: temporary storage for scene linear pixel values. */
1375 Array<float4> scene_linear(range.size());
1376 pixels_to_scene_linear_byte(ibuf->byte_buffer.colorspace,
1377 ibuf->byte_buffer.data + range.first() * 4,
1378 scene_linear.data(),
1379 range.size());
1380 if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
1381 tonemap_rd_photoreceptor(scene_linear.data(), mask, range, data);
1382 }
1383 else {
1384 BLI_assert(tmmd->type == SEQ_TONEMAP_RH_SIMPLE);
1385 tonemap_simple(scene_linear.data(), mask, range, data);
1386 }
1387 scene_linear_to_image_chunk_byte(scene_linear.data(), ibuf, range);
1388 }
1389 });
1390}
1391
1393 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Tonemap"),
1394 /*struct_name*/ "SequencerTonemapModifierData",
1395 /*struct_size*/ sizeof(SequencerTonemapModifierData),
1396 /*init_data*/ tonemapmodifier_init_data,
1397 /*free_data*/ nullptr,
1398 /*copy_data*/ nullptr,
1399 /*apply*/ tonemapmodifier_apply,
1400};
1401
1403 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Equalizer"),
1404 /*struct_name*/ "SoundEqualizerModifierData",
1405 /*struct_size*/ sizeof(SoundEqualizerModifierData),
1409 /*apply*/ nullptr,
1410};
1413/* -------------------------------------------------------------------- */
1418{
1419#define INIT_TYPE(typeName) (modifiersTypes[seqModifierType_##typeName] = &seqModifier_##typeName)
1420
1421 INIT_TYPE(ColorBalance);
1423 INIT_TYPE(HueCorrect);
1424 INIT_TYPE(BrightContrast);
1425 INIT_TYPE(Mask);
1426 INIT_TYPE(WhiteBalance);
1427 INIT_TYPE(Tonemap);
1428 INIT_TYPE(SoundEqualizer);
1429
1430#undef INIT_TYPE
1431}
1432
1434{
1435 if (!modifierTypesInit) {
1437 modifierTypesInit = true;
1438 }
1439
1440 return modifiersTypes[type];
1441}
1442
1443SequenceModifierData *SEQ_modifier_new(Sequence *seq, const char *name, int type)
1444{
1447
1448 smd = static_cast<SequenceModifierData *>(MEM_callocN(smti->struct_size, "sequence modifier"));
1449
1450 smd->type = type;
1452
1453 if (!name || !name[0]) {
1454 STRNCPY(smd->name, smti->name);
1455 }
1456 else {
1457 STRNCPY(smd->name, name);
1458 }
1459
1460 BLI_addtail(&seq->modifiers, smd);
1461
1462 SEQ_modifier_unique_name(seq, smd);
1463
1464 if (smti->init_data) {
1465 smti->init_data(smd);
1466 }
1467
1468 return smd;
1469}
1470
1472{
1473 if (BLI_findindex(&seq->modifiers, smd) == -1) {
1474 return false;
1475 }
1476
1477 BLI_remlink(&seq->modifiers, smd);
1478 SEQ_modifier_free(smd);
1479
1480 return true;
1481}
1482
1484{
1485 SequenceModifierData *smd, *smd_next;
1486
1487 for (smd = static_cast<SequenceModifierData *>(seq->modifiers.first); smd; smd = smd_next) {
1488 smd_next = smd->next;
1489 SEQ_modifier_free(smd);
1490 }
1491
1493}
1494
1496{
1498
1499 if (smti && smti->free_data) {
1500 smti->free_data(smd);
1501 }
1502
1503 MEM_freeN(smd);
1504}
1505
1507{
1509
1511 smd,
1513 '.',
1515 sizeof(smd->name));
1516}
1517
1519{
1520 return static_cast<SequenceModifierData *>(
1521 BLI_findstring(&(seq->modifiers), name, offsetof(SequenceModifierData, name)));
1522}
1523
1524static bool skip_modifier(Scene *scene, const SequenceModifierData *smd, int timeline_frame)
1525{
1526 using namespace blender::seq;
1527
1528 if (smd->mask_sequence == nullptr) {
1529 return false;
1530 }
1531 const bool strip_has_ended_skip = smd->mask_input_type == SEQUENCE_MASK_INPUT_STRIP &&
1534 scene, smd->mask_sequence, timeline_frame);
1535 const bool missing_data_skip = !SEQ_sequence_has_valid_data(smd->mask_sequence) ||
1536 media_presence_is_missing(scene, smd->mask_sequence);
1537
1538 return strip_has_ended_skip || missing_data_skip;
1539}
1540
1542 const Sequence *seq,
1543 ImBuf *ibuf,
1544 int timeline_frame)
1545{
1546 const StripScreenQuad quad = get_strip_screen_quad(context, seq);
1547
1548 if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
1549 SEQ_render_imbuf_from_sequencer_space(context->scene, ibuf);
1550 }
1551
1554
1555 /* could happen if modifier is being removed or not exists in current version of blender */
1556 if (!smti) {
1557 continue;
1558 }
1559
1560 /* modifier is muted, do nothing */
1561 if (smd->flag & SEQUENCE_MODIFIER_MUTE) {
1562 continue;
1563 }
1564
1565 if (smti->apply && !skip_modifier(context->scene, smd, timeline_frame)) {
1566 int frame_offset;
1567 if (smd->mask_time == SEQUENCE_MASK_TIME_RELATIVE) {
1568 frame_offset = seq->start;
1569 }
1570 else /* if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE) */ {
1571 frame_offset = smd->mask_id ? ((Mask *)smd->mask_id)->sfra : 0;
1572 }
1573
1574 ImBuf *mask = modifier_mask_get(
1575 smd, context, timeline_frame, frame_offset, ibuf->float_buffer.data != nullptr);
1576
1577 smti->apply(quad, smd, ibuf, mask);
1578
1579 if (mask) {
1580 IMB_freeImBuf(mask);
1581 }
1582 }
1583 }
1584
1585 if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
1586 seq_imbuf_to_sequencer_space(context->scene, ibuf, false);
1587 }
1588}
1589
1591{
1595
1596 smdn = static_cast<SequenceModifierData *>(MEM_dupallocN(smd));
1597
1598 if (smti && smti->copy_data) {
1599 smti->copy_data(smdn, smd);
1600 }
1601
1602 BLI_addtail(&seqn->modifiers, smdn);
1604 smdn,
1605 "Strip Modifier",
1606 '.',
1609 }
1610}
1611
1613{
1614 return (seq->type != SEQ_TYPE_SOUND_RAM);
1615}
1616
1619/* -------------------------------------------------------------------- */
1624{
1625 LISTBASE_FOREACH (SequenceModifierData *, smd, modbase) {
1627
1628 if (smti) {
1629 BLO_write_struct_by_name(writer, smti->struct_name, smd);
1630
1631 if (smd->type == seqModifierType_Curves) {
1633
1635 }
1636 else if (smd->type == seqModifierType_HueCorrect) {
1638
1640 }
1641 else if (smd->type == seqModifierType_SoundEqualizer) {
1643 LISTBASE_FOREACH (EQCurveMappingData *, eqcmd, &semd->graphics) {
1644 BLO_write_struct_by_name(writer, "EQCurveMappingData", eqcmd);
1645 BKE_curvemapping_blend_write(writer, &eqcmd->curve_mapping);
1646 }
1647 }
1648 }
1649 else {
1651 }
1652 }
1653}
1654
1656{
1658
1660 if (smd->mask_sequence) {
1661 BLO_read_struct(reader, Sequence, &smd->mask_sequence);
1662 }
1663
1664 if (smd->type == seqModifierType_Curves) {
1666
1668 }
1669 else if (smd->type == seqModifierType_HueCorrect) {
1671
1673 }
1674 else if (smd->type == seqModifierType_SoundEqualizer) {
1677 LISTBASE_FOREACH (EQCurveMappingData *, eqcmd, &semd->graphics) {
1678 BKE_curvemapping_blend_read(reader, &eqcmd->curve_mapping);
1679 }
1680 }
1681 }
1682}
1683
void BKE_curvemapping_evaluate_premulRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
@ CURVEMAP_SLOPE_POSITIVE
void BKE_curvemapping_premultiply(CurveMapping *cumap, bool restore)
void BKE_curvemapping_free_data(CurveMapping *cumap)
void BKE_curvemapping_set_black_white(CurveMapping *cumap, const float black[3], const float white[3])
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_blend_read(BlendDataReader *reader, CurveMapping *cumap)
void BKE_curvemapping_set_defaults(CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy, short default_handle_type)
Definition colortools.cc:40
void BKE_curvemapping_init(CurveMapping *cumap)
void BKE_curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
void BKE_curvemapping_blend_write(BlendWriter *writer, const CurveMapping *cumap)
void BKE_curvemapping_copy_data(CurveMapping *target, const CurveMapping *cumap)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE int min_iii(int a, int b, int c)
MINLINE float min_fff(float a, float b, float c)
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4])
void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v)
void hsv_to_rgb(float h, float s, float v, float *r_r, float *r_g, float *r_b)
Definition math_color.cc:21
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4])
int isect_point_quad_v2(const float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
void BLI_uniquename(const struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_maxncpy) ATTR_NONNULL(1
unsigned char uchar
#define CLAMP(a, b, c)
void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct(reader, struct_name, ptr_p)
#define CTX_N_(context, msgid)
#define BLT_I18NCONTEXT_ID_SEQUENCE
#define CTX_DATA_(context, msgid)
@ CUMA_USE_WRAPPING
@ CURVE_PRESET_MID8
@ HD_AUTO
@ R_IMF_PLANES_RGBA
struct SoundEqualizerModifierData SoundEqualizerModifierData
@ SEQ_TYPE_SOUND_RAM
@ NUM_SEQUENCE_MODIFIER_TYPES
@ seqModifierType_Curves
@ seqModifierType_SoundEqualizer
@ seqModifierType_HueCorrect
struct WhiteBalanceModifierData WhiteBalanceModifierData
struct ColorBalanceModifierData ColorBalanceModifierData
@ SEQ_TONEMAP_RD_PHOTORECEPTOR
struct CurvesModifierData CurvesModifierData
struct SequencerTonemapModifierData SequencerTonemapModifierData
@ SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN
@ SEQ_USE_LINEAR_MODIFIERS
struct HueCorrectModifierData HueCorrectModifierData
@ SEQUENCE_MODIFIER_MUTE
@ SEQUENCE_MODIFIER_EXPANDED
@ SEQUENCE_MASK_INPUT_STRIP
@ SEQUENCE_MASK_INPUT_ID
@ SEQUENCE_MASK_TIME_RELATIVE
struct BrightContrastModifierData BrightContrastModifierData
@ SEQ_COLOR_BALANCE_INVERSE_GAIN
@ SEQ_COLOR_BALANCE_INVERSE_LIFT
@ SEQ_COLOR_BALANCE_INVERSE_SLOPE
@ SEQ_COLOR_BALANCE_INVERSE_POWER
@ SEQ_COLOR_BALANCE_INVERSE_OFFSET
@ SEQ_COLOR_BALANCE_INVERSE_GAMMA
struct SequencerMaskModifierData SequencerMaskModifierData
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
void IMB_colormanagement_scene_linear_to_colorspace(float *buffer, int width, int height, int channels, ColorSpace *colorspace)
void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, ColorSpace *colorspace, bool predivide)
void IMB_rect_from_float(ImBuf *ibuf)
Definition divers.cc:694
void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_customdata, void(init_handle)(void *handle, int start_line, int tot_line, void *customdata), void *(do_thread)(void *))
void IMB_float_from_rect(ImBuf *ibuf)
Definition divers.cc:802
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
void init()
static void mul(btAlignedObjectArray< T > &items, const Q &value)
local_group_size(16, 16) .push_constant(Type b
pow(value.r - subtrahend, 2.0)") .do_static_compilation(true)
#define logf(x)
#define expf(x)
#define powf(x, y)
#define floorf(x)
#define offsetof(t, d)
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
blender::gpu::Batch * quad
void IMB_freeImBuf(ImBuf *)
IndexRange range
int count
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
#define unit_float_to_uchar_clamp(val)
ccl_device_inline float2 power(float2 v, float e)
ccl_device_inline float3 exp(float3 v)
ccl_device_inline float3 log(float3 v)
ccl_device_inline float4 mask(const int4 mask, const float4 a)
static ulong state[N]
#define L
T min(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
T max(const T &a, const T &b)
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
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:153
static void init_data(ModifierData *md)
VecBase< float, 4 > float4
void seq_imbuf_to_sequencer_space(const Scene *scene, ImBuf *ibuf, bool make_float)
Definition render.cc:106
StripScreenQuad get_strip_screen_quad(const SeqRenderData *context, const Sequence *seq)
Definition render.cc:296
ImBuf * seq_render_mask(const SeqRenderData *context, Mask *mask, float frame_index, bool make_float)
Definition render.cc:1337
ImBuf * seq_render_strip(const SeqRenderData *context, SeqRenderState *state, Sequence *seq, float timeline_frame)
Definition render.cc:1830
void SEQ_render_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf)
Definition render.cc:177
static ImBuf * modifier_render_mask_input(const SeqRenderData *context, int mask_input_type, Sequence *mask_sequence, Mask *mask_id, int timeline_frame, int fra_offset, bool make_float)
void SEQ_modifier_blend_write(BlendWriter *writer, ListBase *modbase)
SequenceModifierData * SEQ_modifier_new(Sequence *seq, const char *name, int type)
bool SEQ_modifier_remove(Sequence *seq, SequenceModifierData *smd)
static ImBuf * modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int timeline_frame, int fra_offset, bool make_float)
static void hue_correct_apply(const StripScreenQuad &, SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static void scene_linear_to_image_chunk_float(ImBuf *ibuf, IndexRange range)
static void tonemapmodifier_init_data(SequenceModifierData *smd)
static void modifier_apply_threaded(ImBuf *ibuf, ImBuf *mask, modifier_apply_threaded_cb apply_callback, void *user_data)
static StripColorBalance calc_cb_sop(const StripColorBalance *cb_)
SequenceModifierData * SEQ_modifier_find_by_name(Sequence *seq, const char *name)
void SEQ_modifier_apply_stack(const SeqRenderData *context, const Sequence *seq, ImBuf *ibuf, int timeline_frame)
static void hue_correct_free_data(SequenceModifierData *smd)
static void colorBalance_apply(const StripScreenQuad &, SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static bool is_point_inside_quad(const StripScreenQuad &quad, int x, int y)
void SEQ_modifier_free(SequenceModifierData *smd)
const SequenceModifierTypeInfo * SEQ_modifier_type_info_get(int type)
static void tonemap_rd_photoreceptor(float4 *scene_linear, ImBuf *mask, IndexRange range, const AvgLogLum &avg)
static float color_balance_sop(float in, const float slope, const float offset, const float power, float mul)
static void color_balance_float(const StripColorBalance *cb, float *rect_float, const float *mask_rect_float, int width, int height, float mul)
static void scene_linear_to_image_chunk_byte(float4 *src, ImBuf *ibuf, IndexRange range)
static void whiteBalance_apply_threaded(int width, int height, uchar *rect, float *rect_float, uchar *mask_rect, const float *mask_rect_float, void *data_v)
#define INIT_TYPE(typeName)
static SequenceModifierTypeInfo seqModifier_HueCorrect
static void tonemap_calc_chunk_luminance(const StripScreenQuad &quad, const bool all_pixels_inside_quad, const int width, const IndexRange y_range, const float4 *scene_linear, AreaLuminance &r_lum)
static bool skip_modifier(Scene *scene, const SequenceModifierData *smd, int timeline_frame)
static void brightcontrast_apply_threaded(int width, int height, uchar *rect, float *rect_float, uchar *mask_rect, const float *mask_rect_float, void *data_v)
static void maskmodifier_apply(const StripScreenQuad &, SequenceModifierData *, ImBuf *ibuf, ImBuf *mask)
static float color_balance_lgg(float in, const float lift, const float gain, const float gamma, const float mul)
static void tonemapmodifier_apply(const StripScreenQuad &quad, SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static AreaLuminance tonemap_calc_input_luminance(const StripScreenQuad &quad, const ImBuf *ibuf)
static void hue_correct_init_data(SequenceModifierData *smd)
static SequenceModifierTypeInfo seqModifier_Curves
void SEQ_modifier_clear(Sequence *seq)
static void hue_correct_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
static void curves_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
static void brightcontrast_apply(const StripScreenQuad &, SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static void sequence_modifier_type_info_init()
static void curves_free_data(SequenceModifierData *smd)
void SEQ_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb)
static void color_balance_byte(const float cb_tab[3][CB_TABLE_SIZE], uchar *rect, const uchar *mask_rect, int width, int height)
static SequenceModifierTypeInfo seqModifier_Mask
static SequenceModifierTypeInfo seqModifier_ColorBalance
static void * modifier_do_thread(void *thread_data_v)
static void hue_correct_apply_threaded(int width, int height, uchar *rect, float *rect_float, uchar *mask_rect, const float *mask_rect_float, void *data_v)
static void curves_apply_threaded(int width, int height, uchar *rect, float *rect_float, uchar *mask_rect, const float *mask_rect_float, void *data_v)
void(*)(int width, int height, uchar *rect, float *rect_float, uchar *mask_rect, const float *mask_rect_float, void *data_v) modifier_apply_threaded_cb
static SequenceModifierTypeInfo seqModifier_WhiteBalance
static StripColorBalance calc_cb_lgg(const StripColorBalance *cb_)
static SequenceModifierTypeInfo seqModifier_BrightContrast
static void curves_apply(const StripScreenQuad &, SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static void tonemap_simple(float4 *scene_linear, ImBuf *mask, IndexRange range, const AvgLogLum &avg)
static void curves_init_data(SequenceModifierData *smd)
static SequenceModifierTypeInfo * modifiersTypes[NUM_SEQUENCE_MODIFIER_TYPES]
static StripColorBalance calc_cb(const StripColorBalance *cb_)
void SEQ_modifier_list_copy(Sequence *seqn, Sequence *seq)
static void whiteBalance_apply(const StripScreenQuad &, SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static SequenceModifierTypeInfo seqModifier_SoundEqualizer
static void whiteBalance_init_data(SequenceModifierData *smd)
static void make_cb_table_lgg(float lift, float gain, float gamma, float mul, float r_table[CB_TABLE_SIZE])
static SequenceModifierTypeInfo seqModifier_Tonemap
static void make_cb_table_sop(float slope, float offset, float power, float mul, float r_table[CB_TABLE_SIZE])
static void maskmodifier_apply_threaded(int width, int height, uchar *rect, float *rect_float, uchar *mask_rect, const float *mask_rect_float, void *)
static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
int SEQ_sequence_supports_modifiers(Sequence *seq)
static void pixels_to_scene_linear_byte(ColorSpace *colorspace, const uchar *pixels, float4 *dst, int64_t count)
static void colorBalance_init_data(SequenceModifierData *smd)
static void pixels_to_scene_linear_float(ColorSpace *colorspace, float4 *pixels, int64_t count)
void SEQ_modifier_unique_name(Sequence *seq, SequenceModifierData *smd)
static constexpr int CB_TABLE_SIZE
static bool modifierTypesInit
void SEQ_sound_equalizermodifier_free(SequenceModifierData *smd)
void SEQ_sound_equalizermodifier_init_data(SequenceModifierData *smd)
void SEQ_sound_equalizermodifier_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
bool SEQ_sequence_has_valid_data(const Sequence *seq)
#define FLT_MAX
Definition stdcycles.h:14
__int64 int64_t
Definition stdint.h:89
bool SEQ_time_strip_intersects_frame(const Scene *scene, const Sequence *seq, const int timeline_frame)
const SequencerTonemapModifierData * tmmd
StripColorBalance color_balance
CurveMap cm[4]
struct CurveMapping curve_mapping
struct CurveMapping curve_mapping
ColorSpace * colorspace
ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
unsigned char planes
void * first
modifier_apply_threaded_cb apply_callback
modifier_apply_threaded_cb apply_callback
struct SequenceModifierData * next
struct Sequence * mask_sequence
void(* copy_data)(SequenceModifierData *smd, SequenceModifierData *target)
void(* apply)(const StripScreenQuad &quad, SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
void(* init_data)(SequenceModifierData *smd)
void(* free_data)(SequenceModifierData *smd)
ListBase modifiers
VecBase< T, 3 > xyz() const
float x
float y
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
PointerRNA * ptr
Definition wm_files.cc:4126