Blender V4.5
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
8
9#include <algorithm>
10#include <cstddef>
11#include <cstring>
12
13#include "BLI_array.hh"
14#include "BLI_listbase.h"
15#include "BLI_math_geom.h"
16#include "BLI_math_vector.hh"
17#include "BLI_string.h"
18#include "BLI_string_utils.hh"
19#include "BLI_task.hh"
20
21#include "BLT_translation.hh"
22
23#include "DNA_mask_types.h"
24#include "DNA_sequence_types.h"
25
26#include "BKE_colortools.hh"
27
29#include "IMB_imbuf.hh"
30#include "IMB_imbuf_types.hh"
31
32#include "SEQ_modifier.hh"
33#include "SEQ_render.hh"
34#include "SEQ_sound.hh"
35#include "SEQ_time.hh"
36#include "SEQ_utils.hh"
37
38#include "BLO_read_write.hh"
39
40#include "render.hh"
41
42namespace blender::seq {
43
44/* -------------------------------------------------------------------- */
45
47{
48 float4 res;
50 return res;
51}
52
53static float4 load_pixel_premul(const float *ptr)
54{
55 return float4(ptr);
56}
57
62
63static void store_pixel_premul(float4 pix, float *ptr)
64{
65 *reinterpret_cast<float4 *>(ptr) = pix;
66}
67
69{
70 float4 res;
72 return res;
73}
74
75static float4 load_pixel_raw(const float *ptr)
76{
77 return float4(ptr);
78}
79
80static void store_pixel_raw(float4 pix, uchar *ptr)
81{
83}
84
85static void store_pixel_raw(float4 pix, float *ptr)
86{
87 *reinterpret_cast<float4 *>(ptr) = pix;
88}
89
90/* Byte mask */
92{
93 float3 m;
95 result.x = math::interpolate(input.x, result.x, m.x);
96 result.y = math::interpolate(input.y, result.y, m.y);
97 result.z = math::interpolate(input.z, result.z, m.z);
98 mask += 4;
99}
100
101/* Float mask */
103{
104 float3 m(mask);
105 result.x = math::interpolate(input.x, result.x, m.x);
106 result.y = math::interpolate(input.y, result.y, m.y);
107 result.z = math::interpolate(input.z, result.z, m.z);
108 mask += 4;
109}
110
111/* No mask */
112static void apply_and_advance_mask(float4 /*input*/, float4 & /*result*/, const void *& /*mask*/)
113{
114}
115
116/* Given `T` that implements an `apply` function:
117 *
118 * template <typename ImageT, typename MaskT>
119 * void apply(ImageT* image, const MaskT* mask, IndexRange size);
120 *
121 * this function calls the apply() function in parallel
122 * chunks of the image to process, and with needed
123 * uchar, float or void types (void is used for mask, when there is
124 * no masking). Both input and mask images are expected to have
125 * 4 (RGBA) color channels. Input is modified. */
126template<typename T> static void apply_modifier_op(T &op, ImBuf *ibuf, const ImBuf *mask)
127{
128 if (ibuf == nullptr) {
129 return;
130 }
131 BLI_assert_msg(ibuf->channels == 0 || ibuf->channels == 4,
132 "Sequencer only supports 4 channel images");
133 BLI_assert_msg(mask == nullptr || mask->channels == 0 || mask->channels == 4,
134 "Sequencer only supports 4 channel images");
135
136 threading::parallel_for(IndexRange(size_t(ibuf->x) * ibuf->y), 32 * 1024, [&](IndexRange range) {
137 uchar *image_byte = ibuf->byte_buffer.data;
138 float *image_float = ibuf->float_buffer.data;
139 const uchar *mask_byte = mask ? mask->byte_buffer.data : nullptr;
140 const float *mask_float = mask ? mask->float_buffer.data : nullptr;
141 const void *mask_none = nullptr;
142 int64_t offset = range.first() * 4;
143
144 /* Instantiate the needed processing function based on image/mask
145 * data types. */
146 if (image_byte) {
147 if (mask_byte) {
148 op.apply(image_byte + offset, mask_byte + offset, range);
149 }
150 else if (mask_float) {
151 op.apply(image_byte + offset, mask_float + offset, range);
152 }
153 else {
154 op.apply(image_byte + offset, mask_none, range);
155 }
156 }
157 else if (image_float) {
158 if (mask_byte) {
159 op.apply(image_float + offset, mask_byte + offset, range);
160 }
161 else if (mask_float) {
162 op.apply(image_float + offset, mask_float + offset, range);
163 }
164 else {
165 op.apply(image_float + offset, mask_none, range);
166 }
167 }
168 });
169}
170
175 int mask_input_type,
176 Strip *mask_strip,
177 Mask *mask_id,
178 int timeline_frame,
179 int fra_offset)
180{
181 ImBuf *mask_input = nullptr;
182
183 if (mask_input_type == SEQUENCE_MASK_INPUT_STRIP) {
184 if (mask_strip) {
186 mask_input = seq_render_strip(context, &state, mask_strip, timeline_frame);
187 }
188 }
189 else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) {
190 /* Note that we do not request mask to be float image: if it is that is
191 * fine, but if it is a byte image then we also just take that without
192 * extra memory allocations or conversions. All modifiers are expected
193 * to handle mask being either type. */
194 mask_input = seq_render_mask(context, mask_id, timeline_frame - fra_offset, false);
195 }
196
197 return mask_input;
198}
199
201 const RenderData *context,
202 int timeline_frame,
203 int fra_offset)
204{
206 context, smd->mask_input_type, smd->mask_strip, smd->mask_id, timeline_frame, fra_offset);
207}
208
209/* -------------------------------------------------------------------- */
212
213/* Lift-Gamma-Gain math. NOTE: lift is actually (2-lift). */
214static float color_balance_lgg(
215 float in, const float lift, const float gain, const float gamma, const float mul)
216{
217 float x = (((in - 1.0f) * lift) + 1.0f) * gain;
218
219 /* prevent NaN */
220 x = std::max(x, 0.0f);
221
222 x = powf(x, gamma) * mul;
223 CLAMP(x, FLT_MIN, FLT_MAX);
224 return x;
225}
226
227/* Slope-Offset-Power (ASC CDL) math, see https://en.wikipedia.org/wiki/ASC_CDL */
228static float color_balance_sop(
229 float in, const float slope, const float offset, const float power, float mul)
230{
231 float x = in * slope + offset;
232
233 /* prevent NaN */
234 x = std::max(x, 0.0f);
235
236 x = powf(x, power);
237 x *= mul;
238 CLAMP(x, FLT_MIN, FLT_MAX);
239 return x;
240}
241
246static constexpr int CB_TABLE_SIZE = 1024;
247
249 float lift, float gain, float gamma, float mul, float r_table[CB_TABLE_SIZE])
250{
251 for (int i = 0; i < CB_TABLE_SIZE; i++) {
252 float x = float(i) * (1.0f / (CB_TABLE_SIZE - 1.0f));
253 r_table[i] = color_balance_lgg(x, lift, gain, gamma, mul);
254 }
255}
256
258 float slope, float offset, float power, float mul, float r_table[CB_TABLE_SIZE])
259{
260 for (int i = 0; i < CB_TABLE_SIZE; i++) {
261 float x = float(i) * (1.0f / (CB_TABLE_SIZE - 1.0f));
262 r_table[i] = color_balance_sop(x, slope, offset, power, mul);
263 }
264}
265
272
273 /* Apply on a byte image via a table lookup. */
274 template<typename MaskT> void apply(uchar *image, const MaskT *mask, IndexRange size)
275 {
276 for ([[maybe_unused]] int64_t i : size) {
278
280 int p0 = int(input.x * (CB_TABLE_SIZE - 1.0f) + 0.5f);
281 int p1 = int(input.y * (CB_TABLE_SIZE - 1.0f) + 0.5f);
282 int p2 = int(input.z * (CB_TABLE_SIZE - 1.0f) + 0.5f);
283 result.x = this->lut[0][p0];
284 result.y = this->lut[1][p1];
285 result.z = this->lut[2][p2];
286 result.w = input.w;
287
290 image += 4;
291 }
292 }
293
294 /* Apply on a float image by doing full math. */
295 template<typename MaskT> void apply(float *image, const MaskT *mask, IndexRange size)
296 {
297 if (this->method == SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN) {
298 /* Lift/Gamma/Gain */
299 for ([[maybe_unused]] int64_t i : size) {
301
304 input.x, this->lift.x, this->gain.x, this->gamma.x, this->multiplier);
306 input.y, this->lift.y, this->gain.y, this->gamma.y, this->multiplier);
308 input.z, this->lift.z, this->gain.z, this->gamma.z, this->multiplier);
309 result.w = input.w;
310
313 image += 4;
314 }
315 }
316 else if (this->method == SEQ_COLOR_BALANCE_METHOD_SLOPEOFFSETPOWER) {
317 /* Slope/Offset/Power */
318 for ([[maybe_unused]] int64_t i : size) {
320
323 input.x, this->slope.x, this->offset.x, this->power.x, this->multiplier);
325 input.y, this->slope.y, this->offset.y, this->power.y, this->multiplier);
327 input.z, this->slope.z, this->offset.z, this->power.z, this->multiplier);
328 result.w = input.w;
329
332 image += 4;
333 }
334 }
335 else {
337 }
338 }
339
341 {
343
344 this->lift = 2.0f - float3(data.lift);
346 for (int c = 0; c < 3; c++) {
347 /* tweak to give more subtle results
348 * values above 1.0 are scaled */
349 if (this->lift[c] > 1.0f) {
350 this->lift[c] = powf(this->lift[c] - 1.0f, 2.0f) + 1.0f;
351 }
352 this->lift[c] = 2.0f - this->lift[c];
353 }
354 }
355
356 this->gain = float3(data.gain);
358 this->gain = math::rcp(math::max(this->gain, float3(1.0e-6f)));
359 }
360
361 this->gamma = float3(data.gamma);
363 this->gamma = math::rcp(math::max(this->gamma, float3(1.0e-6f)));
364 }
365 }
366
368 {
370
371 this->slope = float3(data.slope);
373 this->slope = math::rcp(math::max(this->slope, float3(1.0e-6f)));
374 }
375
376 this->offset = float3(data.offset) - 1.0f;
378 this->offset = -this->offset;
379 }
380
381 this->power = float3(data.power);
383 this->power = math::rcp(math::max(this->power, float3(1.0e-6f)));
384 }
385 }
386
387 void init(const ColorBalanceModifierData &data, bool byte_image)
388 {
389 this->multiplier = data.color_multiply;
390 this->method = data.color_balance.method;
391
392 if (this->method == SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN) {
393 init_lgg(data.color_balance);
394 if (byte_image) {
395 for (int c = 0; c < 3; c++) {
397 this->lift[c], this->gain[c], this->gamma[c], this->multiplier, this->lut[c]);
398 }
399 }
400 }
401 else if (this->method == SEQ_COLOR_BALANCE_METHOD_SLOPEOFFSETPOWER) {
402 init_sop(data.color_balance);
403 if (byte_image) {
404 for (int c = 0; c < 3; c++) {
406 this->slope[c], this->offset[c], this->power[c], this->multiplier, this->lut[c]);
407 }
408 }
409 }
410 else {
412 }
413 }
414};
415
417{
419
420 cbmd->color_multiply = 1.0f;
421 cbmd->color_balance.method = 0;
422
423 for (int c = 0; c < 3; c++) {
424 cbmd->color_balance.lift[c] = 1.0f;
425 cbmd->color_balance.gamma[c] = 1.0f;
426 cbmd->color_balance.gain[c] = 1.0f;
427 cbmd->color_balance.slope[c] = 1.0f;
428 cbmd->color_balance.offset[c] = 1.0f;
429 cbmd->color_balance.power[c] = 1.0f;
430 }
431}
432
433static void colorBalance_apply(const StripScreenQuad & /*quad*/,
435 ImBuf *ibuf,
436 ImBuf *mask)
437{
438 const ColorBalanceModifierData *cbmd = (const ColorBalanceModifierData *)smd;
439
441 op.init(*cbmd, ibuf->byte_buffer.data != nullptr);
442 apply_modifier_op(op, ibuf, mask);
443}
444
446
447/* -------------------------------------------------------------------- */
450
456
458 float multiplier[3];
459
460 template<typename ImageT, typename MaskT>
461 void apply(ImageT *image, const MaskT *mask, IndexRange size)
462 {
463 for ([[maybe_unused]] int64_t i : size) {
465
467 result.w = input.w;
468#if 0
470#else
471 /* similar to division without the clipping */
472 for (int i = 0; i < 3; i++) {
473 /* Prevent pow argument from being negative. This whole math
474 * breaks down overall with any HDR colors; would be good to
475 * revisit and do something more proper. */
476 float f = max_ff(1.0f - input[i], 0.0f);
477 result[i] = 1.0f - powf(f, this->multiplier[i]);
478 }
479#endif
480
483 image += 4;
484 }
485 }
486};
487
488static void whiteBalance_apply(const StripScreenQuad & /*quad*/,
490 ImBuf *ibuf,
491 ImBuf *mask)
492{
494
496 op.multiplier[0] = (data->white_value[0] != 0.0f) ? 1.0f / data->white_value[0] : FLT_MAX;
497 op.multiplier[1] = (data->white_value[1] != 0.0f) ? 1.0f / data->white_value[1] : FLT_MAX;
498 op.multiplier[2] = (data->white_value[2] != 0.0f) ? 1.0f / data->white_value[2] : FLT_MAX;
499 apply_modifier_op(op, ibuf, mask);
500}
501
503
504/* -------------------------------------------------------------------- */
507
509{
511
512 BKE_curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
513}
514
521
523{
525 CurvesModifierData *cmd_target = (CurvesModifierData *)target;
526
528}
529
532
533 template<typename ImageT, typename MaskT>
534 void apply(ImageT *image, const MaskT *mask, IndexRange size)
535 {
536 for ([[maybe_unused]] int64_t i : size) {
538
541 result.w = input.w;
542
545 image += 4;
546 }
547 }
548};
549
550static void curves_apply(const StripScreenQuad & /*quad*/,
552 ImBuf *ibuf,
553 ImBuf *mask)
554{
556
557 const float black[3] = {0.0f, 0.0f, 0.0f};
558 const float white[3] = {1.0f, 1.0f, 1.0f};
559
561
564
565 CurvesApplyOp op;
566 op.curve_mapping = &cmd->curve_mapping;
567 apply_modifier_op(op, ibuf, mask);
568
570}
571
573
574/* -------------------------------------------------------------------- */
577
579{
581 int c;
582
583 BKE_curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f, HD_AUTO);
585
586 for (c = 0; c < 3; c++) {
587 CurveMap *cuma = &hcmd->curve_mapping.cm[c];
590 }
591 /* use wrapping for all hue correct modifiers */
593 /* default to showing Saturation */
594 hcmd->curve_mapping.cur = 1;
595}
596
603
611
614
615 template<typename ImageT, typename MaskT>
616 void apply(ImageT *image, const MaskT *mask, IndexRange size)
617 {
618 for ([[maybe_unused]] int64_t i : size) {
619 /* NOTE: arguably incorrect usage of "raw" values, should be un-premultiplied.
620 * Not changing behavior for now, but would be good to fix someday. */
621 float4 input = load_pixel_raw(image);
623 result.w = input.w;
624
625 float3 hsv;
626 rgb_to_hsv(input.x, input.y, input.z, &hsv.x, &hsv.y, &hsv.z);
627
628 /* adjust hue, scaling returned default 0.5 up to 1 */
629 float f;
630 f = BKE_curvemapping_evaluateF(this->curve_mapping, 0, hsv.x);
631 hsv.x += f - 0.5f;
632
633 /* adjust saturation, scaling returned default 0.5 up to 1 */
634 f = BKE_curvemapping_evaluateF(this->curve_mapping, 1, hsv.x);
635 hsv.y *= (f * 2.0f);
636
637 /* adjust value, scaling returned default 0.5 up to 1 */
638 f = BKE_curvemapping_evaluateF(this->curve_mapping, 2, hsv.x);
639 hsv.z *= (f * 2.0f);
640
641 hsv.x = hsv.x - floorf(hsv.x); /* mod 1.0 */
642 hsv.y = math::clamp(hsv.y, 0.0f, 1.0f);
643
644 /* convert back to rgb */
645 hsv_to_rgb(hsv.x, hsv.y, hsv.z, &result.x, &result.y, &result.z);
646
648 store_pixel_raw(result, image);
649 image += 4;
650 }
651 }
652};
653
654static void hue_correct_apply(const StripScreenQuad & /*quad*/,
656 ImBuf *ibuf,
657 ImBuf *mask)
658{
660
662
664 op.curve_mapping = &hcmd->curve_mapping;
665 apply_modifier_op(op, ibuf, mask);
666}
667
669
670/* -------------------------------------------------------------------- */
673
675 float mul;
676 float add;
677
678 template<typename ImageT, typename MaskT>
679 void apply(ImageT *image, const MaskT *mask, IndexRange size)
680 {
681 for ([[maybe_unused]] int64_t i : size) {
682 /* NOTE: arguably incorrect usage of "raw" values, should be un-premultiplied.
683 * Not changing behavior for now, but would be good to fix someday. */
684 float4 input = load_pixel_raw(image);
685
687 result = input * this->mul + this->add;
688 result.w = input.w;
689
691 store_pixel_raw(result, image);
692 image += 4;
693 }
694 }
695};
696
697static void brightcontrast_apply(const StripScreenQuad & /*quad*/,
699 ImBuf *ibuf,
700 ImBuf *mask)
701{
703
705
706 /* The algorithm is by Werner D. Streidt
707 * (http://visca.com/ffactory/archives/5-99/msg00021.html)
708 * Extracted from OpenCV `demhist.cpp`. */
709 const float brightness = bcmd->bright / 100.0f;
710 const float contrast = bcmd->contrast;
711 float delta = contrast / 200.0f;
712
713 if (contrast > 0) {
714 op.mul = 1.0f - delta * 2.0f;
715 op.mul = 1.0f / max_ff(op.mul, FLT_EPSILON);
716 op.add = op.mul * (brightness - delta);
717 }
718 else {
719 delta *= -1;
720 op.mul = max_ff(1.0f - delta * 2.0f, 0.0f);
721 op.add = op.mul * brightness + delta;
722 }
723
724 apply_modifier_op(op, ibuf, mask);
725}
726
728
729/* -------------------------------------------------------------------- */
732
733static float load_mask_min(const uchar *&mask)
734{
735 float m = float(min_iii(mask[0], mask[1], mask[2])) * (1.0f / 255.0f);
736 mask += 4;
737 return m;
738}
739static float load_mask_min(const float *&mask)
740{
741 float m = min_fff(mask[0], mask[1], mask[2]);
742 mask += 4;
743 return m;
744}
745static float load_mask_min(const void *& /*mask*/)
746{
747 return 1.0f;
748}
749
751 template<typename ImageT, typename MaskT>
752 void apply(ImageT *image, const MaskT *mask, IndexRange size)
753 {
754 for ([[maybe_unused]] int64_t i : size) {
755 float m = load_mask_min(mask);
756
757 if constexpr (std::is_same_v<ImageT, uchar>) {
758 /* Byte buffer is straight, so only affect on alpha itself, this is
759 * the only way to alpha-over byte strip after applying mask modifier. */
760 image[3] = uchar(image[3] * m);
761 }
762 else if constexpr (std::is_same_v<ImageT, float>) {
763 /* Float buffers are premultiplied, so need to premul color as well to make it
764 * easy to alpha-over masked strip. */
765 float4 pix(image);
766 pix *= m;
767 *reinterpret_cast<float4 *>(image) = pix;
768 }
769 image += 4;
770 }
771 }
772};
773
774static void maskmodifier_apply(const StripScreenQuad & /*quad*/,
775 StripModifierData * /*smd*/,
776 ImBuf *ibuf,
777 ImBuf *mask)
778{
779 if (mask == nullptr || (mask->byte_buffer.data == nullptr && mask->float_buffer.data == nullptr))
780 {
781 return;
782 }
783
784 MaskApplyOp op;
785 apply_modifier_op(op, ibuf, mask);
786
787 /* Image has gained transparency. */
789}
790
792
793/* -------------------------------------------------------------------- */
796
805
807{
809 /* Same as tone-map compositor node. */
811 tmmd->key = 0.18f;
812 tmmd->offset = 1.0f;
813 tmmd->gamma = 1.0f;
814 tmmd->intensity = 0.0f;
815 tmmd->contrast = 0.0f;
816 tmmd->adaptation = 1.0f;
817 tmmd->correction = 0.0f;
818}
819
820/* Convert chunk of float image pixels to scene linear space, in-place. */
821static void pixels_to_scene_linear_float(const ColorSpace *colorspace,
822 float4 *pixels,
824{
826 (float *)(pixels), int(count), 1, 4, colorspace, false);
827}
828
829/* Convert chunk of byte image pixels to scene linear space, into a destination array. */
830static void pixels_to_scene_linear_byte(const ColorSpace *colorspace,
831 const uchar *pixels,
832 float4 *dst,
834{
835 const uchar *bptr = pixels;
836 float4 *dst_ptr = dst;
837 for (int64_t i = 0; i < count; i++) {
838 straight_uchar_to_premul_float(*dst_ptr, bptr);
839 bptr += 4;
840 dst_ptr++;
841 }
843 (float *)dst, int(count), 1, 4, colorspace, false);
844}
845
847{
848 const ColorSpace *colorspace = ibuf->float_buffer.colorspace;
849 float4 *fptr = reinterpret_cast<float4 *>(ibuf->float_buffer.data);
851 (float *)(fptr + range.first()), int(range.size()), 1, 4, colorspace);
852}
853
855{
856 const ColorSpace *colorspace = ibuf->byte_buffer.colorspace;
858 (float *)src, int(range.size()), 1, 4, colorspace);
859 const float4 *src_ptr = src;
860 uchar *bptr = ibuf->byte_buffer.data;
861 for (const int64_t idx : range) {
862 premul_float_to_straight_uchar(bptr + idx * 4, *src_ptr);
863 src_ptr++;
864 }
865}
866
867static void tonemap_simple(float4 *scene_linear,
868 ImBuf *mask,
869 IndexRange range,
870 const AvgLogLum &avg)
871{
872 const float4 *mask_float = mask != nullptr ? (const float4 *)mask->float_buffer.data : nullptr;
873 const uchar4 *mask_byte = mask != nullptr ? (const uchar4 *)mask->byte_buffer.data : nullptr;
874
875 int64_t index = 0;
876 for (const int64_t pixel_index : range) {
877 float4 input = scene_linear[index];
878
879 /* Apply correction. */
880 float3 pixel = input.xyz() * avg.al;
881 float3 d = pixel + avg.tmmd->offset;
882 pixel.x /= (d.x == 0.0f) ? 1.0f : d.x;
883 pixel.y /= (d.y == 0.0f) ? 1.0f : d.y;
884 pixel.z /= (d.z == 0.0f) ? 1.0f : d.z;
885 const float igm = avg.igm;
886 if (igm != 0.0f) {
887 pixel.x = powf(math::max(pixel.x, 0.0f), igm);
888 pixel.y = powf(math::max(pixel.y, 0.0f), igm);
889 pixel.z = powf(math::max(pixel.z, 0.0f), igm);
890 }
891
892 /* Apply mask. */
893 if (mask != nullptr) {
894 float3 msk(1.0f);
895 if (mask_byte != nullptr) {
896 rgb_uchar_to_float(msk, mask_byte[pixel_index]);
897 }
898 else if (mask_float != nullptr) {
899 msk = mask_float[pixel_index].xyz();
900 }
901 pixel = math::interpolate(input.xyz(), pixel, msk);
902 }
903
904 scene_linear[index] = float4(pixel.x, pixel.y, pixel.z, input.w);
905 index++;
906 }
907}
908
909static void tonemap_rd_photoreceptor(float4 *scene_linear,
910 ImBuf *mask,
911 IndexRange range,
912 const AvgLogLum &avg)
913{
914 const float4 *mask_float = mask != nullptr ? (const float4 *)mask->float_buffer.data : nullptr;
915 const uchar4 *mask_byte = mask != nullptr ? (const uchar4 *)mask->byte_buffer.data : nullptr;
916
917 const float f = expf(-avg.tmmd->intensity);
918 const float m = (avg.tmmd->contrast > 0.0f) ? avg.tmmd->contrast :
919 (0.3f + 0.7f * powf(avg.auto_key, 1.4f));
920 const float ic = 1.0f - avg.tmmd->correction, ia = 1.0f - avg.tmmd->adaptation;
921
922 int64_t index = 0;
923 for (const int64_t pixel_index : range) {
924 float4 input = scene_linear[index];
925
926 /* Apply correction. */
927 float3 pixel = input.xyz();
928 const float L = IMB_colormanagement_get_luminance(pixel);
929 float I_l = pixel.x + ic * (L - pixel.x);
930 float I_g = avg.cav.x + ic * (avg.lav - avg.cav.x);
931 float I_a = I_l + ia * (I_g - I_l);
932 pixel.x /= std::max(pixel.x + powf(f * I_a, m), 1.0e-30f);
933 I_l = pixel.y + ic * (L - pixel.y);
934 I_g = avg.cav.y + ic * (avg.lav - avg.cav.y);
935 I_a = I_l + ia * (I_g - I_l);
936 pixel.y /= std::max(pixel.y + powf(f * I_a, m), 1.0e-30f);
937 I_l = pixel.z + ic * (L - pixel.z);
938 I_g = avg.cav.z + ic * (avg.lav - avg.cav.z);
939 I_a = I_l + ia * (I_g - I_l);
940 pixel.z /= std::max(pixel.z + powf(f * I_a, m), 1.0e-30f);
941
942 /* Apply mask. */
943 if (mask != nullptr) {
944 float3 msk(1.0f);
945 if (mask_byte != nullptr) {
946 rgb_uchar_to_float(msk, mask_byte[pixel_index]);
947 }
948 else if (mask_float != nullptr) {
949 msk = mask_float[pixel_index].xyz();
950 }
951 pixel = math::interpolate(input.xyz(), pixel, msk);
952 }
953
954 scene_linear[index] = float4(pixel.x, pixel.y, pixel.z, input.w);
955 index++;
956 }
957}
958
959static bool is_point_inside_quad(const StripScreenQuad &quad, int x, int y)
960{
961 float2 pt(x + 0.5f, y + 0.5f);
962 return isect_point_quad_v2(pt, quad.v0, quad.v1, quad.v2, quad.v3);
963}
964
967 double sum = 0.0f;
968 float3 color_sum = {0, 0, 0};
969 double log_sum = 0.0;
970 float min = FLT_MAX;
971 float max = -FLT_MAX;
972};
973
975 const bool all_pixels_inside_quad,
976 const int width,
977 const IndexRange y_range,
978 const float4 *scene_linear,
979 AreaLuminance &r_lum)
980{
981 for (const int y : y_range) {
982 for (int x = 0; x < width; x++) {
983 if (all_pixels_inside_quad || is_point_inside_quad(quad, x, y)) {
984 float4 pixel = *scene_linear;
985 r_lum.pixel_count++;
987 r_lum.sum += L;
988 r_lum.color_sum.x += pixel.x;
989 r_lum.color_sum.y += pixel.y;
990 r_lum.color_sum.z += pixel.z;
991 r_lum.log_sum += logf(math::max(L, 0.0f) + 1e-5f);
992 r_lum.max = math::max(r_lum.max, L);
993 r_lum.min = math::min(r_lum.min, L);
994 }
995 scene_linear++;
996 }
997 }
998}
999
1001{
1002 /* Pixels outside the pre-transform strip area are ignored for luminance calculations.
1003 * If strip area covers whole image, we can trivially accept all pixels. */
1004 const bool all_pixels_inside_quad = is_point_inside_quad(quad, 0, 0) &&
1005 is_point_inside_quad(quad, ibuf->x - 1, 0) &&
1006 is_point_inside_quad(quad, 0, ibuf->y - 1) &&
1007 is_point_inside_quad(quad, ibuf->x - 1, ibuf->y - 1);
1008
1009 AreaLuminance lum;
1011 IndexRange(ibuf->y),
1012 32,
1013 lum,
1014 /* Calculate luminance for a chunk. */
1015 [&](const IndexRange y_range, const AreaLuminance &init) {
1016 AreaLuminance lum = init;
1017 const int64_t chunk_size = y_range.size() * ibuf->x;
1018 /* For float images, convert to scene-linear in place. The rest
1019 * of tone-mapper can then continue with scene-linear values. */
1020 if (ibuf->float_buffer.data != nullptr) {
1021 float4 *fptr = reinterpret_cast<float4 *>(ibuf->float_buffer.data);
1022 fptr += y_range.first() * ibuf->x;
1023 pixels_to_scene_linear_float(ibuf->float_buffer.colorspace, fptr, chunk_size);
1024 tonemap_calc_chunk_luminance(quad, all_pixels_inside_quad, ibuf->x, y_range, fptr, lum);
1025 }
1026 else {
1027 const uchar *bptr = ibuf->byte_buffer.data + y_range.first() * ibuf->x * 4;
1028 Array<float4> scene_linear(chunk_size);
1029 pixels_to_scene_linear_byte(
1030 ibuf->byte_buffer.colorspace, bptr, scene_linear.data(), chunk_size);
1031 tonemap_calc_chunk_luminance(
1032 quad, all_pixels_inside_quad, ibuf->x, y_range, scene_linear.data(), lum);
1033 }
1034 return lum;
1035 },
1036 /* Reduce luminance results. */
1037 [&](const AreaLuminance &a, const AreaLuminance &b) {
1038 AreaLuminance res;
1039 res.pixel_count = a.pixel_count + b.pixel_count;
1040 res.sum = a.sum + b.sum;
1041 res.color_sum = a.color_sum + b.color_sum;
1042 res.log_sum = a.log_sum + b.log_sum;
1043 res.min = math::min(a.min, b.min);
1044 res.max = math::max(a.max, b.max);
1045 return res;
1046 });
1047 return lum;
1048}
1049
1051 StripModifierData *smd,
1052 ImBuf *ibuf,
1053 ImBuf *mask)
1054{
1056
1058 if (lum.pixel_count == 0) {
1059 return; /* Strip is zero size or off-screen. */
1060 }
1061
1063 data.tmmd = tmmd;
1064 data.lav = lum.sum / lum.pixel_count;
1065 data.cav.x = lum.color_sum.x / lum.pixel_count;
1066 data.cav.y = lum.color_sum.y / lum.pixel_count;
1067 data.cav.z = lum.color_sum.z / lum.pixel_count;
1068 float maxl = log(double(lum.max) + 1e-5f);
1069 float minl = log(double(lum.min) + 1e-5f);
1070 float avl = lum.log_sum / lum.pixel_count;
1071 data.auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
1072 float al = exp(double(avl));
1073 data.al = (al == 0.0f) ? 0.0f : (tmmd->key / al);
1074 data.igm = (tmmd->gamma == 0.0f) ? 1.0f : (1.0f / tmmd->gamma);
1075
1077 IndexRange(int64_t(ibuf->x) * ibuf->y), 64 * 1024, [&](IndexRange range) {
1078 if (ibuf->float_buffer.data != nullptr) {
1079 /* Float pixels: no need for temporary storage. Luminance calculation already converted
1080 * data to scene linear. */
1081 float4 *pixels = (float4 *)(ibuf->float_buffer.data) + range.first();
1082 if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
1083 tonemap_rd_photoreceptor(pixels, mask, range, data);
1084 }
1085 else {
1086 BLI_assert(tmmd->type == SEQ_TONEMAP_RH_SIMPLE);
1087 tonemap_simple(pixels, mask, range, data);
1088 }
1089 scene_linear_to_image_chunk_float(ibuf, range);
1090 }
1091 else {
1092 /* Byte pixels: temporary storage for scene linear pixel values. */
1093 Array<float4> scene_linear(range.size());
1094 pixels_to_scene_linear_byte(ibuf->byte_buffer.colorspace,
1095 ibuf->byte_buffer.data + range.first() * 4,
1096 scene_linear.data(),
1097 range.size());
1098 if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
1099 tonemap_rd_photoreceptor(scene_linear.data(), mask, range, data);
1100 }
1101 else {
1102 BLI_assert(tmmd->type == SEQ_TONEMAP_RH_SIMPLE);
1103 tonemap_simple(scene_linear.data(), mask, range, data);
1104 }
1105 scene_linear_to_image_chunk_byte(scene_linear.data(), ibuf, range);
1106 }
1107 });
1108}
1109
1111
1112/* -------------------------------------------------------------------- */
1115
1117 {}, /* First entry is unused. */
1118 {
1119 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color Balance"),
1120 /*struct_name*/ "ColorBalanceModifierData",
1121 /*struct_size*/ sizeof(ColorBalanceModifierData),
1122 /*init_data*/ colorBalance_init_data,
1123 /*free_data*/ nullptr,
1124 /*copy_data*/ nullptr,
1125 /*apply*/ colorBalance_apply,
1126 },
1127 {
1128 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Curves"),
1129 /*struct_name*/ "CurvesModifierData",
1130 /*struct_size*/ sizeof(CurvesModifierData),
1131 /*init_data*/ curves_init_data,
1132 /*free_data*/ curves_free_data,
1133 /*copy_data*/ curves_copy_data,
1134 /*apply*/ curves_apply,
1135 },
1136 {
1137 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Hue Correct"),
1138 /*struct_name*/ "HueCorrectModifierData",
1139 /*struct_size*/ sizeof(HueCorrectModifierData),
1140 /*init_data*/ hue_correct_init_data,
1141 /*free_data*/ hue_correct_free_data,
1142 /*copy_data*/ hue_correct_copy_data,
1143 /*apply*/ hue_correct_apply,
1144 },
1145 {
1146 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Brightness/Contrast"),
1147 /*struct_name*/ "BrightContrastModifierData",
1148 /*struct_size*/ sizeof(BrightContrastModifierData),
1149 /*init_data*/ nullptr,
1150 /*free_data*/ nullptr,
1151 /*copy_data*/ nullptr,
1152 /*apply*/ brightcontrast_apply,
1153 },
1154 {
1155 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Mask"),
1156 /*struct_name*/ "SequencerMaskModifierData",
1157 /*struct_size*/ sizeof(SequencerMaskModifierData),
1158 /*init_data*/ nullptr,
1159 /*free_data*/ nullptr,
1160 /*copy_data*/ nullptr,
1161 /*apply*/ maskmodifier_apply,
1162 },
1163 {
1164 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "White Balance"),
1165 /*struct_name*/ "WhiteBalanceModifierData",
1166 /*struct_size*/ sizeof(WhiteBalanceModifierData),
1167 /*init_data*/ whiteBalance_init_data,
1168 /*free_data*/ nullptr,
1169 /*copy_data*/ nullptr,
1170 /*apply*/ whiteBalance_apply,
1171 },
1172 {
1173 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Tonemap"),
1174 /*struct_name*/ "SequencerTonemapModifierData",
1175 /*struct_size*/ sizeof(SequencerTonemapModifierData),
1176 /*init_data*/ tonemapmodifier_init_data,
1177 /*free_data*/ nullptr,
1178 /*copy_data*/ nullptr,
1179 /*apply*/ tonemapmodifier_apply,
1180 },
1181 {
1182 /*name*/ CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Equalizer"),
1183 /*struct_name*/ "SoundEqualizerModifierData",
1184 /*struct_size*/ sizeof(SoundEqualizerModifierData),
1186 /*free_data*/ sound_equalizermodifier_free,
1188 /*apply*/ nullptr,
1189 },
1190};
1191
1193{
1194 if (type <= 0 || type >= NUM_SEQUENCE_MODIFIER_TYPES) {
1195 return nullptr;
1196 }
1197 return &modifiersTypes[type];
1198}
1199
1200StripModifierData *modifier_new(Strip *strip, const char *name, int type)
1201{
1202 StripModifierData *smd;
1204
1205 smd = static_cast<StripModifierData *>(MEM_callocN(smti->struct_size, "sequence modifier"));
1206
1207 smd->type = type;
1209
1210 if (!name || !name[0]) {
1212 }
1213 else {
1214 STRNCPY(smd->name, name);
1215 }
1216
1217 BLI_addtail(&strip->modifiers, smd);
1218
1219 modifier_unique_name(strip, smd);
1220
1221 if (smti->init_data) {
1222 smti->init_data(smd);
1223 }
1224
1225 return smd;
1226}
1227
1229{
1230 if (BLI_findindex(&strip->modifiers, smd) == -1) {
1231 return false;
1232 }
1233
1234 BLI_remlink(&strip->modifiers, smd);
1235 modifier_free(smd);
1236
1237 return true;
1238}
1239
1241{
1242 StripModifierData *smd, *smd_next;
1243
1244 for (smd = static_cast<StripModifierData *>(strip->modifiers.first); smd; smd = smd_next) {
1245 smd_next = smd->next;
1246 modifier_free(smd);
1247 }
1248
1250}
1251
1253{
1255
1256 if (smti && smti->free_data) {
1257 smti->free_data(smd);
1258 }
1259
1260 MEM_freeN(smd);
1261}
1262
1264{
1266
1267 BLI_uniquename(&strip->modifiers,
1268 smd,
1270 '.',
1272 sizeof(smd->name));
1273}
1274
1276{
1277 return static_cast<StripModifierData *>(
1278 BLI_findstring(&(strip->modifiers), name, offsetof(StripModifierData, name)));
1279}
1280
1281static bool skip_modifier(Scene *scene, const StripModifierData *smd, int timeline_frame)
1282{
1283 using namespace blender::seq;
1284
1285 if (smd->mask_strip == nullptr) {
1286 return false;
1287 }
1288 const bool strip_has_ended_skip = smd->mask_input_type == SEQUENCE_MASK_INPUT_STRIP &&
1291 scene, smd->mask_strip, timeline_frame);
1292 const bool missing_data_skip = !strip_has_valid_data(smd->mask_strip) ||
1294
1295 return strip_has_ended_skip || missing_data_skip;
1296}
1297
1299 const Strip *strip,
1300 ImBuf *ibuf,
1301 int timeline_frame)
1302{
1303 const StripScreenQuad quad = get_strip_screen_quad(context, strip);
1304
1305 if (strip->modifiers.first && (strip->flag & SEQ_USE_LINEAR_MODIFIERS)) {
1306 render_imbuf_from_sequencer_space(context->scene, ibuf);
1307 }
1308
1309 LISTBASE_FOREACH (StripModifierData *, smd, &strip->modifiers) {
1310 const StripModifierTypeInfo *smti = modifier_type_info_get(smd->type);
1311
1312 /* could happen if modifier is being removed or not exists in current version of blender */
1313 if (!smti) {
1314 continue;
1315 }
1316
1317 /* modifier is muted, do nothing */
1318 if (smd->flag & SEQUENCE_MODIFIER_MUTE) {
1319 continue;
1320 }
1321
1322 if (smti->apply && !skip_modifier(context->scene, smd, timeline_frame)) {
1323 int frame_offset;
1324 if (smd->mask_time == SEQUENCE_MASK_TIME_RELATIVE) {
1325 frame_offset = strip->start;
1326 }
1327 else /* if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE) */ {
1328 frame_offset = smd->mask_id ? ((Mask *)smd->mask_id)->sfra : 0;
1329 }
1330
1331 ImBuf *mask = modifier_mask_get(smd, context, timeline_frame, frame_offset);
1332 smti->apply(quad, smd, ibuf, mask);
1333 if (mask) {
1335 }
1336 }
1337 }
1338
1339 if (strip->modifiers.first && (strip->flag & SEQ_USE_LINEAR_MODIFIERS)) {
1340 seq_imbuf_to_sequencer_space(context->scene, ibuf, false);
1341 }
1342}
1343
1344void modifier_list_copy(Strip *strip_new, Strip *strip)
1345{
1346 LISTBASE_FOREACH (StripModifierData *, smd, &strip->modifiers) {
1347 StripModifierData *smdn;
1348 const StripModifierTypeInfo *smti = modifier_type_info_get(smd->type);
1349
1350 smdn = static_cast<StripModifierData *>(MEM_dupallocN(smd));
1351
1352 if (smti && smti->copy_data) {
1353 smti->copy_data(smdn, smd);
1354 }
1355
1356 BLI_addtail(&strip_new->modifiers, smdn);
1357 BLI_uniquename(&strip_new->modifiers,
1358 smdn,
1359 "Strip Modifier",
1360 '.',
1362 sizeof(StripModifierData::name));
1363 }
1364}
1365
1367{
1368 return (strip->type != STRIP_TYPE_SOUND_RAM);
1369}
1370
1372
1373/* -------------------------------------------------------------------- */
1376
1378{
1379 LISTBASE_FOREACH (StripModifierData *, smd, modbase) {
1380 const StripModifierTypeInfo *smti = modifier_type_info_get(smd->type);
1381
1382 if (smti) {
1383 BLO_write_struct_by_name(writer, smti->struct_name, smd);
1384
1385 if (smd->type == seqModifierType_Curves) {
1387
1389 }
1390 else if (smd->type == seqModifierType_HueCorrect) {
1392
1394 }
1395 else if (smd->type == seqModifierType_SoundEqualizer) {
1397 LISTBASE_FOREACH (EQCurveMappingData *, eqcmd, &semd->graphics) {
1398 BLO_write_struct_by_name(writer, "EQCurveMappingData", eqcmd);
1399 BKE_curvemapping_blend_write(writer, &eqcmd->curve_mapping);
1400 }
1401 }
1402 }
1403 else {
1404 BLO_write_struct(writer, StripModifierData, smd);
1405 }
1406 }
1407}
1408
1410{
1412
1413 LISTBASE_FOREACH (StripModifierData *, smd, lb) {
1414 if (smd->mask_strip) {
1415 BLO_read_struct(reader, Strip, &smd->mask_strip);
1416 }
1417
1418 if (smd->type == seqModifierType_Curves) {
1420
1422 }
1423 else if (smd->type == seqModifierType_HueCorrect) {
1425
1427 }
1428 else if (smd->type == seqModifierType_SoundEqualizer) {
1431 LISTBASE_FOREACH (EQCurveMappingData *, eqcmd, &semd->graphics) {
1432 BKE_curvemapping_blend_read(reader, &eqcmd->curve_mapping);
1433 }
1434 }
1435 }
1436}
1437
1439
1440} // namespace blender::seq
void BKE_curvemapping_evaluate_premulRGBF(const CurveMapping *cumap, float vecout[3], const float vecin[3])
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
@ CURVEMAP_SLOPE_POSITIVE
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)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void * BLI_findstring(const ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:608
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
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 rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4])
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[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 mul_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
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
@ SEQUENCE_MODIFIER_MUTE
@ SEQUENCE_MODIFIER_EXPANDED
@ SEQUENCE_MASK_INPUT_STRIP
@ SEQUENCE_MASK_INPUT_ID
@ STRIP_TYPE_SOUND_RAM
@ NUM_SEQUENCE_MODIFIER_TYPES
@ seqModifierType_Curves
@ seqModifierType_SoundEqualizer
@ seqModifierType_HueCorrect
@ SEQ_TONEMAP_RD_PHOTORECEPTOR
@ SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN
@ SEQ_COLOR_BALANCE_METHOD_SLOPEOFFSETPOWER
@ SEQ_USE_LINEAR_MODIFIERS
@ 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
@ SEQUENCE_MASK_TIME_RELATIVE
void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, const ColorSpace *colorspace, bool predivide)
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, const ColorSpace *colorspace)
blender::ocio::ColorSpace ColorSpace
void IMB_freeImBuf(ImBuf *ibuf)
static void curves_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *id_src, const int)
static void curves_init_data(ID *id)
static void curves_free_data(ID *id)
BMesh const char void * data
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static void mul(btAlignedObjectArray< T > &items, const Q &value)
constexpr int64_t first() const
constexpr int64_t size() const
#define logf(x)
#define expf(x)
#define powf(x, y)
#define floorf(x)
#define offsetof(t, d)
blender::gpu::Batch * quad
#define log
#define input
#define exp
#define this
VecBase< float, 4 > float4
VecBase< float, 3 > float3
#define in
int count
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 power(const float2 v, const float e)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong state[N]
#define T
#define L
T clamp(const T &a, const T &min, const T &max)
T min(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
T rcp(const T &a)
T max(const T &a, const T &b)
static void scene_linear_to_image_chunk_float(ImBuf *ibuf, IndexRange range)
static void tonemap_simple(float4 *scene_linear, ImBuf *mask, IndexRange range, const AvgLogLum &avg)
static float load_mask_min(const uchar *&mask)
void seq_imbuf_to_sequencer_space(const Scene *scene, ImBuf *ibuf, bool make_float)
Definition render.cc:111
static void whiteBalance_init_data(StripModifierData *smd)
static void colorBalance_init_data(StripModifierData *smd)
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 void colorBalance_apply(const StripScreenQuad &, StripModifierData *smd, ImBuf *ibuf, ImBuf *mask)
void sound_equalizermodifier_init_data(StripModifierData *smd)
bool media_presence_is_missing(Scene *scene, const Strip *strip)
static void hue_correct_apply(const StripScreenQuad &, StripModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static constexpr int CB_TABLE_SIZE
static void brightcontrast_apply(const StripScreenQuad &, StripModifierData *smd, 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_init_data(StripModifierData *smd)
static void curves_apply(const StripScreenQuad &, StripModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static float color_balance_sop(float in, const float slope, const float offset, const float power, float mul)
static void store_pixel_raw(float4 pix, uchar *ptr)
static void store_pixel_premul(float4 pix, uchar *ptr)
void modifier_unique_name(Strip *strip, StripModifierData *smd)
static void hue_correct_init_data(StripModifierData *smd)
StripModifierData * modifier_find_by_name(Strip *strip, const char *name)
static void make_cb_table_sop(float slope, float offset, float power, float mul, float r_table[CB_TABLE_SIZE])
static void whiteBalance_apply(const StripScreenQuad &, StripModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static void curves_free_data(StripModifierData *smd)
int sequence_supports_modifiers(Strip *strip)
static float4 load_pixel_raw(const uchar *ptr)
static void make_cb_table_lgg(float lift, float gain, float gamma, float mul, float r_table[CB_TABLE_SIZE])
void sound_equalizermodifier_free(StripModifierData *smd)
static StripModifierTypeInfo modifiersTypes[NUM_SEQUENCE_MODIFIER_TYPES]
bool strip_has_valid_data(const Strip *strip)
static ImBuf * modifier_mask_get(StripModifierData *smd, const RenderData *context, int timeline_frame, int fra_offset)
void modifier_blend_read_data(BlendDataReader *reader, ListBase *lb)
static void maskmodifier_apply(const StripScreenQuad &, StripModifierData *, ImBuf *ibuf, ImBuf *mask)
bool time_strip_intersects_frame(const Scene *scene, const Strip *strip, const int timeline_frame)
void modifier_free(StripModifierData *smd)
bool modifier_remove(Strip *strip, StripModifierData *smd)
const StripModifierTypeInfo * modifier_type_info_get(int type)
StripScreenQuad get_strip_screen_quad(const RenderData *context, const Strip *strip)
Definition render.cc:276
static void curves_copy_data(StripModifierData *target, StripModifierData *smd)
void modifier_clear(Strip *strip)
static void pixels_to_scene_linear_float(const ColorSpace *colorspace, float4 *pixels, int64_t count)
void sound_equalizermodifier_copy_data(StripModifierData *target, StripModifierData *smd)
static void tonemapmodifier_apply(const StripScreenQuad &quad, StripModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static void hue_correct_free_data(StripModifierData *smd)
static void apply_and_advance_mask(float4 input, float4 &result, const uchar *&mask)
StripModifierData * modifier_new(Strip *strip, const char *name, int type)
ImBuf * seq_render_mask(const RenderData *context, Mask *mask, float frame_index, bool make_float)
Definition render.cc:1259
static float4 load_pixel_premul(const uchar *ptr)
static void curves_init_data(StripModifierData *smd)
static bool is_point_inside_quad(const StripScreenQuad &quad, int x, int y)
static bool skip_modifier(Scene *scene, const StripModifierData *smd, int timeline_frame)
static AreaLuminance tonemap_calc_input_luminance(const StripScreenQuad &quad, const ImBuf *ibuf)
void modifier_list_copy(Strip *strip_new, Strip *strip)
void render_imbuf_from_sequencer_space(const Scene *scene, ImBuf *ibuf)
Definition render.cc:163
static void tonemap_rd_photoreceptor(float4 *scene_linear, ImBuf *mask, IndexRange range, const AvgLogLum &avg)
static void hue_correct_copy_data(StripModifierData *target, StripModifierData *smd)
static void pixels_to_scene_linear_byte(const ColorSpace *colorspace, const uchar *pixels, float4 *dst, int64_t count)
static void apply_modifier_op(T &op, ImBuf *ibuf, const ImBuf *mask)
static void scene_linear_to_image_chunk_byte(float4 *src, ImBuf *ibuf, IndexRange range)
void modifier_apply_stack(const RenderData *context, const Strip *strip, ImBuf *ibuf, int timeline_frame)
ImBuf * seq_render_strip(const RenderData *context, SeqRenderState *state, Strip *strip, float timeline_frame)
Definition render.cc:1747
static ImBuf * modifier_render_mask_input(const RenderData *context, int mask_input_type, Strip *mask_strip, Mask *mask_id, int timeline_frame, int fra_offset)
void modifier_blend_write(BlendWriter *writer, ListBase *modbase)
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:93
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
blender::VecBase< uint8_t, 4 > uchar4
VecBase< float, 4 > float4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
static void init(bNodeTree *, bNode *node)
#define FLT_MAX
Definition stdcycles.h:14
StripColorBalance color_balance
CurveMap cm[4]
struct CurveMapping curve_mapping
struct CurveMapping curve_mapping
const ColorSpace * colorspace
const ColorSpace * colorspace
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
unsigned char planes
void * first
struct StripModifierData * next
struct Strip * mask_strip
ListBase modifiers
VecBase< T, 3 > xyz() const
const SequencerTonemapModifierData * tmmd
void apply(ImageT *image, const MaskT *mask, IndexRange size)
void init_sop(const StripColorBalance &data)
void init_lgg(const StripColorBalance &data)
void apply(uchar *image, const MaskT *mask, IndexRange size)
void apply(float *image, const MaskT *mask, IndexRange size)
void init(const ColorBalanceModifierData &data, bool byte_image)
void apply(ImageT *image, const MaskT *mask, IndexRange size)
void apply(ImageT *image, const MaskT *mask, IndexRange size)
void apply(ImageT *image, const MaskT *mask, IndexRange size)
void(* free_data)(StripModifierData *smd)
void(* init_data)(StripModifierData *smd)
void(* copy_data)(StripModifierData *smd, StripModifierData *target)
void(* apply)(const StripScreenQuad &quad, StripModifierData *smd, ImBuf *ibuf, ImBuf *mask)
void apply(ImageT *image, const MaskT *mask, IndexRange size)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4226