2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2012 Blender Foundation.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation,
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/blenkernel/intern/seqmodifier.c
34 #include "MEM_guardedalloc.h"
36 #include "BLI_listbase.h"
37 #include "BLI_string.h"
38 #include "BLI_string_utils.h"
39 #include "BLI_utildefines.h"
42 #include "BLT_translation.h"
44 #include "DNA_sequence_types.h"
45 #include "DNA_scene_types.h"
47 #include "BKE_colortools.h"
48 #include "BKE_sequencer.h"
50 #include "IMB_imbuf.h"
51 #include "IMB_imbuf_types.h"
52 #include "IMB_colormanagement.h"
54 static SequenceModifierTypeInfo *modifiersTypes[NUM_SEQUENCE_MODIFIER_TYPES];
55 static bool modifierTypesInit = false;
57 /*********************** Modifiers *************************/
59 typedef void (*modifier_apply_threaded_cb) (int width, int height, unsigned char *rect, float *rect_float,
60 unsigned char *mask_rect, float *mask_rect_float, void *data_v);
62 typedef struct ModifierInitData {
67 modifier_apply_threaded_cb apply_callback;
70 typedef struct ModifierThread {
73 unsigned char *rect, *mask_rect;
74 float *rect_float, *mask_rect_float;
78 modifier_apply_threaded_cb apply_callback;
82 static ImBuf *modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int cfra, int fra_offset, bool make_float)
84 return BKE_sequencer_render_mask_input(context, smd->mask_input_type, smd->mask_sequence, smd->mask_id, cfra, fra_offset, make_float);
87 static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
89 ModifierThread *handle = (ModifierThread *) handle_v;
90 ModifierInitData *init_data = (ModifierInitData *) init_data_v;
91 ImBuf *ibuf = init_data->ibuf;
92 ImBuf *mask = init_data->mask;
94 int offset = 4 * start_line * ibuf->x;
96 memset(handle, 0, sizeof(ModifierThread));
98 handle->width = ibuf->x;
99 handle->height = tot_line;
100 handle->apply_callback = init_data->apply_callback;
101 handle->user_data = init_data->user_data;
104 handle->rect = (unsigned char *) ibuf->rect + offset;
106 if (ibuf->rect_float)
107 handle->rect_float = ibuf->rect_float + offset;
111 handle->mask_rect = (unsigned char *) mask->rect + offset;
113 if (mask->rect_float)
114 handle->mask_rect_float = mask->rect_float + offset;
117 handle->mask_rect = NULL;
118 handle->mask_rect_float = NULL;
122 static void *modifier_do_thread(void *thread_data_v)
124 ModifierThread *td = (ModifierThread *) thread_data_v;
126 td->apply_callback(td->width, td->height, td->rect, td->rect_float, td->mask_rect, td->mask_rect_float, td->user_data);
131 static void modifier_apply_threaded(ImBuf *ibuf, ImBuf *mask, modifier_apply_threaded_cb apply_callback, void *user_data)
133 ModifierInitData init_data;
135 init_data.ibuf = ibuf;
136 init_data.mask = mask;
137 init_data.user_data = user_data;
139 init_data.apply_callback = apply_callback;
141 IMB_processor_apply_threaded(ibuf->y, sizeof(ModifierThread), &init_data,
142 modifier_init_handle, modifier_do_thread);
145 /* **** Color Balance Modifier **** */
147 static void colorBalance_init_data(SequenceModifierData *smd)
149 ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *) smd;
152 cbmd->color_multiply = 1.0f;
154 for (c = 0; c < 3; c++) {
155 cbmd->color_balance.lift[c] = 1.0f;
156 cbmd->color_balance.gamma[c] = 1.0f;
157 cbmd->color_balance.gain[c] = 1.0f;
161 static void colorBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
163 ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *) smd;
165 BKE_sequencer_color_balance_apply(&cbmd->color_balance, ibuf, cbmd->color_multiply, false, mask);
168 static SequenceModifierTypeInfo seqModifier_ColorBalance = {
169 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color Balance"), /* name */
170 "ColorBalanceModifierData", /* struct_name */
171 sizeof(ColorBalanceModifierData), /* struct_size */
172 colorBalance_init_data, /* init_data */
173 NULL, /* free_data */
174 NULL, /* copy_data */
175 colorBalance_apply /* apply */
178 /* **** White Balance Modifier **** */
180 static void whiteBalance_init_data(SequenceModifierData *smd)
182 WhiteBalanceModifierData *cbmd = (WhiteBalanceModifierData *) smd;
183 copy_v3_fl(cbmd->white_value, 1.0f);
186 typedef struct WhiteBalanceThreadData {
188 } WhiteBalanceThreadData;
190 static void whiteBalance_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
191 unsigned char *mask_rect, float *mask_rect_float, void *data_v)
196 WhiteBalanceThreadData *data = (WhiteBalanceThreadData *) data_v;
198 multiplier[0] = (data->white[0] != 0.0f) ? 1.0f / data->white[0] : FLT_MAX;
199 multiplier[1] = (data->white[1] != 0.0f) ? 1.0f / data->white[1] : FLT_MAX;
200 multiplier[2] = (data->white[2] != 0.0f) ? 1.0f / data->white[2] : FLT_MAX;
202 for (y = 0; y < height; y++) {
203 for (x = 0; x < width; x++) {
204 int pixel_index = (y * width + x) * 4;
205 float rgba[4], result[4], mask[3] = {1.0f, 1.0f, 1.0f};
208 copy_v3_v3(rgba, rect_float + pixel_index);
211 straight_uchar_to_premul_float(rgba, rect + pixel_index);
214 copy_v4_v4(result, rgba);
216 mul_v3_v3(result, multiplier);
218 /* similar to division without the clipping */
219 for (int i = 0; i < 3; i++) {
220 result[i] = 1.0f - powf(1.0f - rgba[i], multiplier[i]);
224 if (mask_rect_float) {
225 copy_v3_v3(mask, mask_rect_float + pixel_index);
227 else if (mask_rect) {
228 rgb_uchar_to_float(mask, mask_rect + pixel_index);
231 result[0] = rgba[0] * (1.0f - mask[0]) + result[0] * mask[0];
232 result[1] = rgba[1] * (1.0f - mask[1]) + result[1] * mask[1];
233 result[2] = rgba[2] * (1.0f - mask[2]) + result[2] * mask[2];
236 copy_v3_v3(rect_float + pixel_index, result);
239 premul_float_to_straight_uchar(rect + pixel_index, result);
245 static void whiteBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
247 WhiteBalanceThreadData data;
248 WhiteBalanceModifierData *wbmd = (WhiteBalanceModifierData *) smd;
250 copy_v3_v3(data.white, wbmd->white_value);
252 modifier_apply_threaded(ibuf, mask, whiteBalance_apply_threaded, &data);
255 static SequenceModifierTypeInfo seqModifier_WhiteBalance = {
256 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "White Balance"), /* name */
257 "WhiteBalanceModifierData", /* struct_name */
258 sizeof(WhiteBalanceModifierData), /* struct_size */
259 whiteBalance_init_data, /* init_data */
260 NULL, /* free_data */
261 NULL, /* copy_data */
262 whiteBalance_apply /* apply */
265 /* **** Curves Modifier **** */
267 static void curves_init_data(SequenceModifierData *smd)
269 CurvesModifierData *cmd = (CurvesModifierData *) smd;
271 curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f);
274 static void curves_free_data(SequenceModifierData *smd)
276 CurvesModifierData *cmd = (CurvesModifierData *) smd;
278 curvemapping_free_data(&cmd->curve_mapping);
281 static void curves_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
283 CurvesModifierData *cmd = (CurvesModifierData *) smd;
284 CurvesModifierData *cmd_target = (CurvesModifierData *) target;
286 curvemapping_copy_data(&cmd_target->curve_mapping, &cmd->curve_mapping);
289 static void curves_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
290 unsigned char *mask_rect, float *mask_rect_float, void *data_v)
292 CurveMapping *curve_mapping = (CurveMapping *) data_v;
295 for (y = 0; y < height; y++) {
296 for (x = 0; x < width; x++) {
297 int pixel_index = (y * width + x) * 4;
300 float *pixel = rect_float + pixel_index;
303 curvemapping_evaluate_premulRGBF(curve_mapping, result, pixel);
305 if (mask_rect_float) {
306 const float *m = mask_rect_float + pixel_index;
308 pixel[0] = pixel[0] * (1.0f - m[0]) + result[0] * m[0];
309 pixel[1] = pixel[1] * (1.0f - m[1]) + result[1] * m[1];
310 pixel[2] = pixel[2] * (1.0f - m[2]) + result[2] * m[2];
313 pixel[0] = result[0];
314 pixel[1] = result[1];
315 pixel[2] = result[2];
319 unsigned char *pixel = rect + pixel_index;
320 float result[3], tempc[4];
322 straight_uchar_to_premul_float(tempc, pixel);
324 curvemapping_evaluate_premulRGBF(curve_mapping, result, tempc);
329 rgb_uchar_to_float(t, mask_rect + pixel_index);
331 tempc[0] = tempc[0] * (1.0f - t[0]) + result[0] * t[0];
332 tempc[1] = tempc[1] * (1.0f - t[1]) + result[1] * t[1];
333 tempc[2] = tempc[2] * (1.0f - t[2]) + result[2] * t[2];
336 tempc[0] = result[0];
337 tempc[1] = result[1];
338 tempc[2] = result[2];
341 premul_float_to_straight_uchar(pixel, tempc);
347 static void curves_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
349 CurvesModifierData *cmd = (CurvesModifierData *) smd;
351 float black[3] = {0.0f, 0.0f, 0.0f};
352 float white[3] = {1.0f, 1.0f, 1.0f};
354 curvemapping_initialize(&cmd->curve_mapping);
356 curvemapping_premultiply(&cmd->curve_mapping, 0);
357 curvemapping_set_black_white(&cmd->curve_mapping, black, white);
359 modifier_apply_threaded(ibuf, mask, curves_apply_threaded, &cmd->curve_mapping);
361 curvemapping_premultiply(&cmd->curve_mapping, 1);
364 static SequenceModifierTypeInfo seqModifier_Curves = {
365 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Curves"), /* name */
366 "CurvesModifierData", /* struct_name */
367 sizeof(CurvesModifierData), /* struct_size */
368 curves_init_data, /* init_data */
369 curves_free_data, /* free_data */
370 curves_copy_data, /* copy_data */
371 curves_apply /* apply */
374 /* **** Hue Correct Modifier **** */
376 static void hue_correct_init_data(SequenceModifierData *smd)
378 HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
381 curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
382 hcmd->curve_mapping.preset = CURVE_PRESET_MID9;
384 for (c = 0; c < 3; c++) {
385 CurveMap *cuma = &hcmd->curve_mapping.cm[c];
387 curvemap_reset(cuma, &hcmd->curve_mapping.clipr, hcmd->curve_mapping.preset, CURVEMAP_SLOPE_POSITIVE);
390 /* default to showing Saturation */
391 hcmd->curve_mapping.cur = 1;
394 static void hue_correct_free_data(SequenceModifierData *smd)
396 HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
398 curvemapping_free_data(&hcmd->curve_mapping);
401 static void hue_correct_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
403 HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
404 HueCorrectModifierData *hcmd_target = (HueCorrectModifierData *) target;
406 curvemapping_copy_data(&hcmd_target->curve_mapping, &hcmd->curve_mapping);
409 static void hue_correct_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
410 unsigned char *mask_rect, float *mask_rect_float, void *data_v)
412 CurveMapping *curve_mapping = (CurveMapping *) data_v;
415 for (y = 0; y < height; y++) {
416 for (x = 0; x < width; x++) {
417 int pixel_index = (y * width + x) * 4;
418 float pixel[3], result[3], mask[3] = {1.0f, 1.0f, 1.0f};
422 copy_v3_v3(pixel, rect_float + pixel_index);
424 rgb_uchar_to_float(pixel, rect + pixel_index);
426 rgb_to_hsv(pixel[0], pixel[1], pixel[2], hsv, hsv + 1, hsv + 2);
428 /* adjust hue, scaling returned default 0.5 up to 1 */
429 f = curvemapping_evaluateF(curve_mapping, 0, hsv[0]);
432 /* adjust saturation, scaling returned default 0.5 up to 1 */
433 f = curvemapping_evaluateF(curve_mapping, 1, hsv[0]);
434 hsv[1] *= (f * 2.0f);
436 /* adjust value, scaling returned default 0.5 up to 1 */
437 f = curvemapping_evaluateF(curve_mapping, 2, hsv[0]);
440 hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */
441 CLAMP(hsv[1], 0.0f, 1.0f);
443 /* convert back to rgb */
444 hsv_to_rgb(hsv[0], hsv[1], hsv[2], result, result + 1, result + 2);
447 copy_v3_v3(mask, mask_rect_float + pixel_index);
449 rgb_uchar_to_float(mask, mask_rect + pixel_index);
451 result[0] = pixel[0] * (1.0f - mask[0]) + result[0] * mask[0];
452 result[1] = pixel[1] * (1.0f - mask[1]) + result[1] * mask[1];
453 result[2] = pixel[2] * (1.0f - mask[2]) + result[2] * mask[2];
456 copy_v3_v3(rect_float + pixel_index, result);
458 rgb_float_to_uchar(rect + pixel_index, result);
463 static void hue_correct_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
465 HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd;
467 curvemapping_initialize(&hcmd->curve_mapping);
469 modifier_apply_threaded(ibuf, mask, hue_correct_apply_threaded, &hcmd->curve_mapping);
472 static SequenceModifierTypeInfo seqModifier_HueCorrect = {
473 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Hue Correct"), /* name */
474 "HueCorrectModifierData", /* struct_name */
475 sizeof(HueCorrectModifierData), /* struct_size */
476 hue_correct_init_data, /* init_data */
477 hue_correct_free_data, /* free_data */
478 hue_correct_copy_data, /* copy_data */
479 hue_correct_apply /* apply */
482 /* **** Bright/Contrast Modifier **** */
484 typedef struct BrightContrastThreadData {
487 } BrightContrastThreadData;
489 static void brightcontrast_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
490 unsigned char *mask_rect, float *mask_rect_float, void *data_v)
492 BrightContrastThreadData *data = (BrightContrastThreadData *) data_v;
498 float brightness = data->bright / 100.0f;
499 float contrast = data->contrast;
500 float delta = contrast / 200.0f;
502 a = 1.0f - delta * 2.0f;
504 * The algorithm is by Werner D. Streidt
505 * (http://visca.com/ffactory/archives/5-99/msg00021.html)
506 * Extracted of OpenCV demhist.c
510 b = a * (brightness - delta);
514 b = a * (brightness + delta);
517 for (y = 0; y < height; y++) {
518 for (x = 0; x < width; x++) {
519 int pixel_index = (y * width + x) * 4;
522 unsigned char *pixel = rect + pixel_index;
524 for (c = 0; c < 3; c++) {
525 i = (float) pixel[c] / 255.0f;
529 unsigned char *m = mask_rect + pixel_index;
530 float t = (float) m[c] / 255.0f;
532 v = (float) pixel[c] / 255.0f * (1.0f - t) + v * t;
535 pixel[c] = FTOCHAR(v);
538 else if (rect_float) {
539 float *pixel = rect_float + pixel_index;
541 for (c = 0; c < 3; c++) {
545 if (mask_rect_float) {
546 const float *m = mask_rect_float + pixel_index;
548 pixel[c] = pixel[c] * (1.0f - m[c]) + v * m[c];
558 static void brightcontrast_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
560 BrightContrastModifierData *bcmd = (BrightContrastModifierData *) smd;
561 BrightContrastThreadData data;
563 data.bright = bcmd->bright;
564 data.contrast = bcmd->contrast;
566 modifier_apply_threaded(ibuf, mask, brightcontrast_apply_threaded, &data);
569 static SequenceModifierTypeInfo seqModifier_BrightContrast = {
570 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Bright/Contrast"), /* name */
571 "BrightContrastModifierData", /* struct_name */
572 sizeof(BrightContrastModifierData), /* struct_size */
573 NULL, /* init_data */
574 NULL, /* free_data */
575 NULL, /* copy_data */
576 brightcontrast_apply /* apply */
579 /* **** Mask Modifier **** */
581 static void maskmodifier_apply_threaded(int width, int height, unsigned char *rect, float *rect_float,
582 unsigned char *mask_rect, float *mask_rect_float, void *UNUSED(data_v))
586 if (rect && !mask_rect)
589 if (rect_float && !mask_rect_float)
592 for (y = 0; y < height; y++) {
593 for (x = 0; x < width; x++) {
594 int pixel_index = (y * width + x) * 4;
597 unsigned char *pixel = rect + pixel_index;
598 unsigned char *mask_pixel = mask_rect + pixel_index;
599 unsigned char mask = min_iii(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
601 /* byte buffer is straight, so only affect on alpha itself,
602 * this is the only way to alpha-over byte strip after
603 * applying mask modifier.
605 pixel[3] = (float)(pixel[3] * mask) / 255.0f;
607 else if (rect_float) {
609 float *pixel = rect_float + pixel_index;
610 const float *mask_pixel = mask_rect_float + pixel_index;
611 float mask = min_fff(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
613 /* float buffers are premultiplied, so need to premul color
614 * as well to make it easy to alpha-over masted strip.
616 for (c = 0; c < 4; c++)
617 pixel[c] = pixel[c] * mask;
623 static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *ibuf, ImBuf *mask)
625 // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
627 modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL);
630 static SequenceModifierTypeInfo seqModifier_Mask = {
631 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Mask"), /* name */
632 "SequencerMaskModifierData", /* struct_name */
633 sizeof(SequencerMaskModifierData), /* struct_size */
634 NULL, /* init_data */
635 NULL, /* free_data */
636 NULL, /* copy_data */
637 maskmodifier_apply /* apply */
640 /* **** Tonemap Modifier **** */
642 typedef struct AvgLogLum {
643 SequencerTonemapModifierData *tmmd;
644 struct ColorSpace *colorspace;
652 static void tonemapmodifier_init_data(SequenceModifierData *smd)
654 SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *) smd;
655 /* Same as tonemap compositor node. */
656 tmmd->type = SEQ_TONEMAP_RD_PHOTORECEPTOR;
660 tmmd->intensity = 0.0f;
661 tmmd->contrast = 0.0f;
662 tmmd->adaptation = 1.0f;
663 tmmd->correction = 0.0f;
666 static void tonemapmodifier_apply_threaded_simple(int width,
670 unsigned char *mask_rect,
671 float *mask_rect_float,
674 AvgLogLum *avg = (AvgLogLum *)data_v;
675 for (int y = 0; y < height; y++) {
676 for (int x = 0; x < width; x++) {
677 int pixel_index = (y * width + x) * 4;
678 float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
679 /* Get input value. */
681 copy_v4_v4(input, &rect_float[pixel_index]);
684 straight_uchar_to_premul_float(input, &rect[pixel_index]);
686 IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
687 copy_v4_v4(output, input);
688 /* Get mask value. */
689 if (mask_rect_float) {
690 copy_v3_v3(mask, mask_rect_float + pixel_index);
692 else if (mask_rect) {
693 rgb_uchar_to_float(mask, mask_rect + pixel_index);
695 /* Apply correction. */
696 mul_v3_fl(output, avg->al);
697 float dr = output[0] + avg->tmmd->offset;
698 float dg = output[1] + avg->tmmd->offset;
699 float db = output[2] + avg->tmmd->offset;
700 output[0] /= ((dr == 0.0f) ? 1.0f : dr);
701 output[1] /= ((dg == 0.0f) ? 1.0f : dg);
702 output[2] /= ((db == 0.0f) ? 1.0f : db);
703 const float igm = avg->igm;
705 output[0] = powf(max_ff(output[0], 0.0f), igm);
706 output[1] = powf(max_ff(output[1], 0.0f), igm);
707 output[2] = powf(max_ff(output[2], 0.0f), igm);
710 output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
711 output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
712 output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
713 /* Copy result back. */
714 IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
716 copy_v4_v4(&rect_float[pixel_index], output);
719 premul_float_to_straight_uchar(&rect[pixel_index], output);
725 static void tonemapmodifier_apply_threaded_photoreceptor(int width,
729 unsigned char *mask_rect,
730 float *mask_rect_float,
733 AvgLogLum *avg = (AvgLogLum *)data_v;
734 const float f = expf(-avg->tmmd->intensity);
735 const float m = (avg->tmmd->contrast > 0.0f) ? avg->tmmd->contrast : (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
736 const float ic = 1.0f - avg->tmmd->correction, ia = 1.0f - avg->tmmd->adaptation;
737 for (int y = 0; y < height; y++) {
738 for (int x = 0; x < width; x++) {
739 int pixel_index = (y * width + x) * 4;
740 float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
741 /* Get input value. */
743 copy_v4_v4(input, &rect_float[pixel_index]);
746 straight_uchar_to_premul_float(input, &rect[pixel_index]);
748 IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
749 copy_v4_v4(output, input);
750 /* Get mask value. */
751 if (mask_rect_float) {
752 copy_v3_v3(mask, mask_rect_float + pixel_index);
754 else if (mask_rect) {
755 rgb_uchar_to_float(mask, mask_rect + pixel_index);
757 /* Apply correction. */
758 const float L = IMB_colormanagement_get_luminance(output);
759 float I_l = output[0] + ic * (L - output[0]);
760 float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
761 float I_a = I_l + ia * (I_g - I_l);
762 output[0] /= (output[0] + powf(f * I_a, m));
763 I_l = output[1] + ic * (L - output[1]);
764 I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
765 I_a = I_l + ia * (I_g - I_l);
766 output[1] /= (output[1] + powf(f * I_a, m));
767 I_l = output[2] + ic * (L - output[2]);
768 I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
769 I_a = I_l + ia * (I_g - I_l);
770 output[2] /= (output[2] + powf(f * I_a, m));
772 output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
773 output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
774 output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
775 /* Copy result back. */
776 IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
778 copy_v4_v4(&rect_float[pixel_index], output);
781 premul_float_to_straight_uchar(&rect[pixel_index], output);
787 static void tonemapmodifier_apply(struct SequenceModifierData *smd,
791 SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *) smd;
794 data.colorspace = (ibuf->rect_float != NULL)
795 ? ibuf->float_colorspace
796 : ibuf->rect_colorspace;
798 int p = ibuf->x * ibuf->y;
799 float *fp = ibuf->rect_float;
800 unsigned char *cp = (unsigned char *)ibuf->rect;
801 float avl, maxl = -FLT_MAX, minl = FLT_MAX;
802 const float sc = 1.0f / p;
804 float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
808 copy_v4_v4(pixel, fp);
811 straight_uchar_to_premul_float(pixel, cp);
813 IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, data.colorspace);
814 float L = IMB_colormanagement_get_luminance(pixel);
816 add_v3_v3(cav, pixel);
817 lsum += logf(max_ff(L, 0.0f) + 1e-5f);
818 maxl = (L > maxl) ? L : maxl;
819 minl = (L < minl) ? L : minl;
828 mul_v3_v3fl(data.cav, cav, sc);
829 maxl = logf(maxl + 1e-5f);
830 minl = logf(minl + 1e-5f);
832 data.auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
833 float al = expf(avl);
834 data.al = (al == 0.0f) ? 0.0f : (tmmd->key / al);
835 data.igm = (tmmd->gamma == 0.0f) ? 1.0f : (1.0f / tmmd->gamma);
837 if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
838 modifier_apply_threaded(ibuf,
840 tonemapmodifier_apply_threaded_photoreceptor,
843 else /* if (tmmd->type == SEQ_TONEMAP_RD_SIMPLE) */ {
844 modifier_apply_threaded(ibuf,
846 tonemapmodifier_apply_threaded_simple,
851 static SequenceModifierTypeInfo seqModifier_Tonemap = {
852 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Tonemap"), /* name */
853 "SequencerTonemapModifierData", /* struct_name */
854 sizeof(SequencerTonemapModifierData), /* struct_size */
855 tonemapmodifier_init_data, /* init_data */
856 NULL, /* free_data */
857 NULL, /* copy_data */
858 tonemapmodifier_apply /* apply */
861 /*********************** Modifier functions *************************/
863 static void sequence_modifier_type_info_init(void)
865 #define INIT_TYPE(typeName) (modifiersTypes[seqModifierType_##typeName] = &seqModifier_##typeName)
867 INIT_TYPE(ColorBalance);
869 INIT_TYPE(HueCorrect);
870 INIT_TYPE(BrightContrast);
872 INIT_TYPE(WhiteBalance);
878 const SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
880 if (!modifierTypesInit) {
881 sequence_modifier_type_info_init();
882 modifierTypesInit = true;
885 return modifiersTypes[type];
888 SequenceModifierData *BKE_sequence_modifier_new(Sequence *seq, const char *name, int type)
890 SequenceModifierData *smd;
891 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type);
893 smd = MEM_callocN(smti->struct_size, "sequence modifier");
896 smd->flag |= SEQUENCE_MODIFIER_EXPANDED;
898 if (!name || !name[0])
899 BLI_strncpy(smd->name, smti->name, sizeof(smd->name));
901 BLI_strncpy(smd->name, name, sizeof(smd->name));
903 BLI_addtail(&seq->modifiers, smd);
905 BKE_sequence_modifier_unique_name(seq, smd);
908 smti->init_data(smd);
913 bool BKE_sequence_modifier_remove(Sequence *seq, SequenceModifierData *smd)
915 if (BLI_findindex(&seq->modifiers, smd) == -1)
918 BLI_remlink(&seq->modifiers, smd);
919 BKE_sequence_modifier_free(smd);
924 void BKE_sequence_modifier_clear(Sequence *seq)
926 SequenceModifierData *smd, *smd_next;
928 for (smd = seq->modifiers.first; smd; smd = smd_next) {
929 smd_next = smd->next;
930 BKE_sequence_modifier_free(smd);
933 BLI_listbase_clear(&seq->modifiers);
936 void BKE_sequence_modifier_free(SequenceModifierData *smd)
938 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
940 if (smti && smti->free_data) {
941 smti->free_data(smd);
947 void BKE_sequence_modifier_unique_name(Sequence *seq, SequenceModifierData *smd)
949 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
951 BLI_uniquename(&seq->modifiers, smd, CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, smti->name), '.',
952 offsetof(SequenceModifierData, name), sizeof(smd->name));
955 SequenceModifierData *BKE_sequence_modifier_find_by_name(Sequence *seq, const char *name)
957 return BLI_findstring(&(seq->modifiers), name, offsetof(SequenceModifierData, name));
960 ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context, Sequence *seq, ImBuf *ibuf, int cfra)
962 SequenceModifierData *smd;
963 ImBuf *processed_ibuf = ibuf;
965 if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
966 processed_ibuf = IMB_dupImBuf(ibuf);
967 BKE_sequencer_imbuf_from_sequencer_space(context->scene, processed_ibuf);
970 for (smd = seq->modifiers.first; smd; smd = smd->next) {
971 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
973 /* could happen if modifier is being removed or not exists in current version of blender */
977 /* modifier is muted, do nothing */
978 if (smd->flag & SEQUENCE_MODIFIER_MUTE)
983 if (smd->mask_time == SEQUENCE_MASK_TIME_RELATIVE) {
984 frame_offset = seq->start;
986 else /*if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE)*/ {
990 ImBuf *mask = modifier_mask_get(smd,
994 ibuf->rect_float != NULL);
996 if (processed_ibuf == ibuf)
997 processed_ibuf = IMB_dupImBuf(ibuf);
999 smti->apply(smd, processed_ibuf, mask);
1002 IMB_freeImBuf(mask);
1006 if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
1007 BKE_sequencer_imbuf_to_sequencer_space(context->scene, processed_ibuf, false);
1010 return processed_ibuf;
1013 void BKE_sequence_modifier_list_copy(Sequence *seqn, Sequence *seq)
1015 SequenceModifierData *smd;
1017 for (smd = seq->modifiers.first; smd; smd = smd->next) {
1018 SequenceModifierData *smdn;
1019 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
1021 smdn = MEM_dupallocN(smd);
1023 if (smti && smti->copy_data)
1024 smti->copy_data(smdn, smd);
1026 smdn->next = smdn->prev = NULL;
1027 BLI_addtail(&seqn->modifiers, smdn);
1031 int BKE_sequence_supports_modifiers(Sequence *seq)
1033 return !ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD);