1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2012 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bke
22 */
23
24 #include <stddef.h>
25 #include <string.h>
26
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_listbase.h"
30 #include "BLI_math.h"
31 #include "BLI_string.h"
32 #include "BLI_string_utils.h"
33 #include "BLI_utildefines.h"
34
35 #include "BLT_translation.h"
36
37 #include "DNA_mask_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_sequence_types.h"
40
41 #include "BKE_colortools.h"
42 #include "BKE_sequencer.h"
43
44 #include "IMB_colormanagement.h"
45 #include "IMB_imbuf.h"
46 #include "IMB_imbuf_types.h"
47
48 static SequenceModifierTypeInfo *modifiersTypes[NUM_SEQUENCE_MODIFIER_TYPES];
49 static bool modifierTypesInit = false;
50
51 /* -------------------------------------------------------------------- */
52 /** \name Modifier Multi-Threading Utilities
53 * \{ */
54
55 typedef void (*modifier_apply_threaded_cb)(int width,
56 int height,
57 unsigned char *rect,
58 float *rect_float,
59 unsigned char *mask_rect,
60 const float *mask_rect_float,
61 void *data_v);
62
63 typedef struct ModifierInitData {
64 ImBuf *ibuf;
65 ImBuf *mask;
66 void *user_data;
67
68 modifier_apply_threaded_cb apply_callback;
69 } ModifierInitData;
70
71 typedef struct ModifierThread {
72 int width, height;
73
74 unsigned char *rect, *mask_rect;
75 float *rect_float, *mask_rect_float;
76
77 void *user_data;
78
79 modifier_apply_threaded_cb apply_callback;
80 } ModifierThread;
81
modifier_mask_get(SequenceModifierData * smd,const SeqRenderData * context,int cfra,int fra_offset,bool make_float)82 static ImBuf *modifier_mask_get(SequenceModifierData *smd,
83 const SeqRenderData *context,
84 int cfra,
85 int fra_offset,
86 bool make_float)
87 {
88 return BKE_sequencer_render_mask_input(context,
89 smd->mask_input_type,
90 smd->mask_sequence,
91 smd->mask_id,
92 cfra,
93 fra_offset,
94 make_float);
95 }
96
modifier_init_handle(void * handle_v,int start_line,int tot_line,void * init_data_v)97 static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
98 {
99 ModifierThread *handle = (ModifierThread *)handle_v;
100 ModifierInitData *init_data = (ModifierInitData *)init_data_v;
101 ImBuf *ibuf = init_data->ibuf;
102 ImBuf *mask = init_data->mask;
103
104 int offset = 4 * start_line * ibuf->x;
105
106 memset(handle, 0, sizeof(ModifierThread));
107
108 handle->width = ibuf->x;
109 handle->height = tot_line;
110 handle->apply_callback = init_data->apply_callback;
111 handle->user_data = init_data->user_data;
112
113 if (ibuf->rect) {
114 handle->rect = (unsigned char *)ibuf->rect + offset;
115 }
116
117 if (ibuf->rect_float) {
118 handle->rect_float = ibuf->rect_float + offset;
119 }
120
121 if (mask) {
122 if (mask->rect) {
123 handle->mask_rect = (unsigned char *)mask->rect + offset;
124 }
125
126 if (mask->rect_float) {
127 handle->mask_rect_float = mask->rect_float + offset;
128 }
129 }
130 else {
131 handle->mask_rect = NULL;
132 handle->mask_rect_float = NULL;
133 }
134 }
135
modifier_do_thread(void * thread_data_v)136 static void *modifier_do_thread(void *thread_data_v)
137 {
138 ModifierThread *td = (ModifierThread *)thread_data_v;
139
140 td->apply_callback(td->width,
141 td->height,
142 td->rect,
143 td->rect_float,
144 td->mask_rect,
145 td->mask_rect_float,
146 td->user_data);
147
148 return NULL;
149 }
150
modifier_apply_threaded(ImBuf * ibuf,ImBuf * mask,modifier_apply_threaded_cb apply_callback,void * user_data)151 static void modifier_apply_threaded(ImBuf *ibuf,
152 ImBuf *mask,
153 modifier_apply_threaded_cb apply_callback,
154 void *user_data)
155 {
156 ModifierInitData init_data;
157
158 init_data.ibuf = ibuf;
159 init_data.mask = mask;
160 init_data.user_data = user_data;
161
162 init_data.apply_callback = apply_callback;
163
164 IMB_processor_apply_threaded(
165 ibuf->y, sizeof(ModifierThread), &init_data, modifier_init_handle, modifier_do_thread);
166 }
167
168 /** \} */
169
170 /* -------------------------------------------------------------------- */
171 /** \name Color Balance Modifier
172 * \{ */
173
colorBalance_init_data(SequenceModifierData * smd)174 static void colorBalance_init_data(SequenceModifierData *smd)
175 {
176 ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *)smd;
177 int c;
178
179 cbmd->color_multiply = 1.0f;
180
181 for (c = 0; c < 3; c++) {
182 cbmd->color_balance.lift[c] = 1.0f;
183 cbmd->color_balance.gamma[c] = 1.0f;
184 cbmd->color_balance.gain[c] = 1.0f;
185 }
186 }
187
colorBalance_apply(SequenceModifierData * smd,ImBuf * ibuf,ImBuf * mask)188 static void colorBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
189 {
190 ColorBalanceModifierData *cbmd = (ColorBalanceModifierData *)smd;
191
192 BKE_sequencer_color_balance_apply(&cbmd->color_balance, ibuf, cbmd->color_multiply, false, mask);
193 }
194
195 static SequenceModifierTypeInfo seqModifier_ColorBalance = {
196 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color Balance"), /* name */
197 "ColorBalanceModifierData", /* struct_name */
198 sizeof(ColorBalanceModifierData), /* struct_size */
199 colorBalance_init_data, /* init_data */
200 NULL, /* free_data */
201 NULL, /* copy_data */
202 colorBalance_apply, /* apply */
203 };
204
205 /** \} */
206
207 /* -------------------------------------------------------------------- */
208 /** \name White Balance Modifier
209 * \{ */
210
whiteBalance_init_data(SequenceModifierData * smd)211 static void whiteBalance_init_data(SequenceModifierData *smd)
212 {
213 WhiteBalanceModifierData *cbmd = (WhiteBalanceModifierData *)smd;
214 copy_v3_fl(cbmd->white_value, 1.0f);
215 }
216
217 typedef struct WhiteBalanceThreadData {
218 float white[3];
219 } WhiteBalanceThreadData;
220
whiteBalance_apply_threaded(int width,int height,unsigned char * rect,float * rect_float,unsigned char * mask_rect,const float * mask_rect_float,void * data_v)221 static void whiteBalance_apply_threaded(int width,
222 int height,
223 unsigned char *rect,
224 float *rect_float,
225 unsigned char *mask_rect,
226 const float *mask_rect_float,
227 void *data_v)
228 {
229 int x, y;
230 float multiplier[3];
231
232 WhiteBalanceThreadData *data = (WhiteBalanceThreadData *)data_v;
233
234 multiplier[0] = (data->white[0] != 0.0f) ? 1.0f / data->white[0] : FLT_MAX;
235 multiplier[1] = (data->white[1] != 0.0f) ? 1.0f / data->white[1] : FLT_MAX;
236 multiplier[2] = (data->white[2] != 0.0f) ? 1.0f / data->white[2] : FLT_MAX;
237
238 for (y = 0; y < height; y++) {
239 for (x = 0; x < width; x++) {
240 int pixel_index = (y * width + x) * 4;
241 float rgba[4], result[4], mask[3] = {1.0f, 1.0f, 1.0f};
242
243 if (rect_float) {
244 copy_v3_v3(rgba, rect_float + pixel_index);
245 }
246 else {
247 straight_uchar_to_premul_float(rgba, rect + pixel_index);
248 }
249
250 copy_v4_v4(result, rgba);
251 #if 0
252 mul_v3_v3(result, multiplier);
253 #else
254 /* similar to division without the clipping */
255 for (int i = 0; i < 3; i++) {
256 result[i] = 1.0f - powf(1.0f - rgba[i], multiplier[i]);
257 }
258 #endif
259
260 if (mask_rect_float) {
261 copy_v3_v3(mask, mask_rect_float + pixel_index);
262 }
263 else if (mask_rect) {
264 rgb_uchar_to_float(mask, mask_rect + pixel_index);
265 }
266
267 result[0] = rgba[0] * (1.0f - mask[0]) + result[0] * mask[0];
268 result[1] = rgba[1] * (1.0f - mask[1]) + result[1] * mask[1];
269 result[2] = rgba[2] * (1.0f - mask[2]) + result[2] * mask[2];
270
271 if (rect_float) {
272 copy_v3_v3(rect_float + pixel_index, result);
273 }
274 else {
275 premul_float_to_straight_uchar(rect + pixel_index, result);
276 }
277 }
278 }
279 }
280
whiteBalance_apply(SequenceModifierData * smd,ImBuf * ibuf,ImBuf * mask)281 static void whiteBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
282 {
283 WhiteBalanceThreadData data;
284 WhiteBalanceModifierData *wbmd = (WhiteBalanceModifierData *)smd;
285
286 copy_v3_v3(data.white, wbmd->white_value);
287
288 modifier_apply_threaded(ibuf, mask, whiteBalance_apply_threaded, &data);
289 }
290
291 static SequenceModifierTypeInfo seqModifier_WhiteBalance = {
292 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "White Balance"), /* name */
293 "WhiteBalanceModifierData", /* struct_name */
294 sizeof(WhiteBalanceModifierData), /* struct_size */
295 whiteBalance_init_data, /* init_data */
296 NULL, /* free_data */
297 NULL, /* copy_data */
298 whiteBalance_apply, /* apply */
299 };
300
301 /** \} */
302
303 /* -------------------------------------------------------------------- */
304 /** \name Curves Modifier
305 * \{ */
306
curves_init_data(SequenceModifierData * smd)307 static void curves_init_data(SequenceModifierData *smd)
308 {
309 CurvesModifierData *cmd = (CurvesModifierData *)smd;
310
311 BKE_curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f);
312 }
313
curves_free_data(SequenceModifierData * smd)314 static void curves_free_data(SequenceModifierData *smd)
315 {
316 CurvesModifierData *cmd = (CurvesModifierData *)smd;
317
318 BKE_curvemapping_free_data(&cmd->curve_mapping);
319 }
320
curves_copy_data(SequenceModifierData * target,SequenceModifierData * smd)321 static void curves_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
322 {
323 CurvesModifierData *cmd = (CurvesModifierData *)smd;
324 CurvesModifierData *cmd_target = (CurvesModifierData *)target;
325
326 BKE_curvemapping_copy_data(&cmd_target->curve_mapping, &cmd->curve_mapping);
327 }
328
curves_apply_threaded(int width,int height,unsigned char * rect,float * rect_float,unsigned char * mask_rect,const float * mask_rect_float,void * data_v)329 static void curves_apply_threaded(int width,
330 int height,
331 unsigned char *rect,
332 float *rect_float,
333 unsigned char *mask_rect,
334 const float *mask_rect_float,
335 void *data_v)
336 {
337 CurveMapping *curve_mapping = (CurveMapping *)data_v;
338 int x, y;
339
340 for (y = 0; y < height; y++) {
341 for (x = 0; x < width; x++) {
342 int pixel_index = (y * width + x) * 4;
343
344 if (rect_float) {
345 float *pixel = rect_float + pixel_index;
346 float result[3];
347
348 BKE_curvemapping_evaluate_premulRGBF(curve_mapping, result, pixel);
349
350 if (mask_rect_float) {
351 const float *m = mask_rect_float + pixel_index;
352
353 pixel[0] = pixel[0] * (1.0f - m[0]) + result[0] * m[0];
354 pixel[1] = pixel[1] * (1.0f - m[1]) + result[1] * m[1];
355 pixel[2] = pixel[2] * (1.0f - m[2]) + result[2] * m[2];
356 }
357 else {
358 pixel[0] = result[0];
359 pixel[1] = result[1];
360 pixel[2] = result[2];
361 }
362 }
363 if (rect) {
364 unsigned char *pixel = rect + pixel_index;
365 float result[3], tempc[4];
366
367 straight_uchar_to_premul_float(tempc, pixel);
368
369 BKE_curvemapping_evaluate_premulRGBF(curve_mapping, result, tempc);
370
371 if (mask_rect) {
372 float t[3];
373
374 rgb_uchar_to_float(t, mask_rect + pixel_index);
375
376 tempc[0] = tempc[0] * (1.0f - t[0]) + result[0] * t[0];
377 tempc[1] = tempc[1] * (1.0f - t[1]) + result[1] * t[1];
378 tempc[2] = tempc[2] * (1.0f - t[2]) + result[2] * t[2];
379 }
380 else {
381 tempc[0] = result[0];
382 tempc[1] = result[1];
383 tempc[2] = result[2];
384 }
385
386 premul_float_to_straight_uchar(pixel, tempc);
387 }
388 }
389 }
390 }
391
curves_apply(struct SequenceModifierData * smd,ImBuf * ibuf,ImBuf * mask)392 static void curves_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
393 {
394 CurvesModifierData *cmd = (CurvesModifierData *)smd;
395
396 const float black[3] = {0.0f, 0.0f, 0.0f};
397 const float white[3] = {1.0f, 1.0f, 1.0f};
398
399 BKE_curvemapping_init(&cmd->curve_mapping);
400
401 BKE_curvemapping_premultiply(&cmd->curve_mapping, 0);
402 BKE_curvemapping_set_black_white(&cmd->curve_mapping, black, white);
403
404 modifier_apply_threaded(ibuf, mask, curves_apply_threaded, &cmd->curve_mapping);
405
406 BKE_curvemapping_premultiply(&cmd->curve_mapping, 1);
407 }
408
409 static SequenceModifierTypeInfo seqModifier_Curves = {
410 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Curves"), /* name */
411 "CurvesModifierData", /* struct_name */
412 sizeof(CurvesModifierData), /* struct_size */
413 curves_init_data, /* init_data */
414 curves_free_data, /* free_data */
415 curves_copy_data, /* copy_data */
416 curves_apply, /* apply */
417 };
418
419 /** \} */
420
421 /* -------------------------------------------------------------------- */
422 /** \name Hue Correct Modifier
423 * \{ */
424
hue_correct_init_data(SequenceModifierData * smd)425 static void hue_correct_init_data(SequenceModifierData *smd)
426 {
427 HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
428 int c;
429
430 BKE_curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
431 hcmd->curve_mapping.preset = CURVE_PRESET_MID9;
432
433 for (c = 0; c < 3; c++) {
434 CurveMap *cuma = &hcmd->curve_mapping.cm[c];
435
436 BKE_curvemap_reset(
437 cuma, &hcmd->curve_mapping.clipr, hcmd->curve_mapping.preset, CURVEMAP_SLOPE_POSITIVE);
438 }
439
440 /* default to showing Saturation */
441 hcmd->curve_mapping.cur = 1;
442 }
443
hue_correct_free_data(SequenceModifierData * smd)444 static void hue_correct_free_data(SequenceModifierData *smd)
445 {
446 HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
447
448 BKE_curvemapping_free_data(&hcmd->curve_mapping);
449 }
450
hue_correct_copy_data(SequenceModifierData * target,SequenceModifierData * smd)451 static void hue_correct_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
452 {
453 HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
454 HueCorrectModifierData *hcmd_target = (HueCorrectModifierData *)target;
455
456 BKE_curvemapping_copy_data(&hcmd_target->curve_mapping, &hcmd->curve_mapping);
457 }
458
hue_correct_apply_threaded(int width,int height,unsigned char * rect,float * rect_float,unsigned char * mask_rect,const float * mask_rect_float,void * data_v)459 static void hue_correct_apply_threaded(int width,
460 int height,
461 unsigned char *rect,
462 float *rect_float,
463 unsigned char *mask_rect,
464 const float *mask_rect_float,
465 void *data_v)
466 {
467 CurveMapping *curve_mapping = (CurveMapping *)data_v;
468 int x, y;
469
470 for (y = 0; y < height; y++) {
471 for (x = 0; x < width; x++) {
472 int pixel_index = (y * width + x) * 4;
473 float pixel[3], result[3], mask[3] = {1.0f, 1.0f, 1.0f};
474 float hsv[3], f;
475
476 if (rect_float) {
477 copy_v3_v3(pixel, rect_float + pixel_index);
478 }
479 else {
480 rgb_uchar_to_float(pixel, rect + pixel_index);
481 }
482
483 rgb_to_hsv(pixel[0], pixel[1], pixel[2], hsv, hsv + 1, hsv + 2);
484
485 /* adjust hue, scaling returned default 0.5 up to 1 */
486 f = BKE_curvemapping_evaluateF(curve_mapping, 0, hsv[0]);
487 hsv[0] += f - 0.5f;
488
489 /* adjust saturation, scaling returned default 0.5 up to 1 */
490 f = BKE_curvemapping_evaluateF(curve_mapping, 1, hsv[0]);
491 hsv[1] *= (f * 2.0f);
492
493 /* adjust value, scaling returned default 0.5 up to 1 */
494 f = BKE_curvemapping_evaluateF(curve_mapping, 2, hsv[0]);
495 hsv[2] *= (f * 2.f);
496
497 hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */
498 CLAMP(hsv[1], 0.0f, 1.0f);
499
500 /* convert back to rgb */
501 hsv_to_rgb(hsv[0], hsv[1], hsv[2], result, result + 1, result + 2);
502
503 if (mask_rect_float) {
504 copy_v3_v3(mask, mask_rect_float + pixel_index);
505 }
506 else if (mask_rect) {
507 rgb_uchar_to_float(mask, mask_rect + pixel_index);
508 }
509
510 result[0] = pixel[0] * (1.0f - mask[0]) + result[0] * mask[0];
511 result[1] = pixel[1] * (1.0f - mask[1]) + result[1] * mask[1];
512 result[2] = pixel[2] * (1.0f - mask[2]) + result[2] * mask[2];
513
514 if (rect_float) {
515 copy_v3_v3(rect_float + pixel_index, result);
516 }
517 else {
518 rgb_float_to_uchar(rect + pixel_index, result);
519 }
520 }
521 }
522 }
523
hue_correct_apply(struct SequenceModifierData * smd,ImBuf * ibuf,ImBuf * mask)524 static void hue_correct_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
525 {
526 HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd;
527
528 BKE_curvemapping_init(&hcmd->curve_mapping);
529
530 modifier_apply_threaded(ibuf, mask, hue_correct_apply_threaded, &hcmd->curve_mapping);
531 }
532
533 static SequenceModifierTypeInfo seqModifier_HueCorrect = {
534 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Hue Correct"), /* name */
535 "HueCorrectModifierData", /* struct_name */
536 sizeof(HueCorrectModifierData), /* struct_size */
537 hue_correct_init_data, /* init_data */
538 hue_correct_free_data, /* free_data */
539 hue_correct_copy_data, /* copy_data */
540 hue_correct_apply, /* apply */
541 };
542
543 /** \} */
544
545 /* -------------------------------------------------------------------- */
546 /** \name Bright/Contrast Modifier
547 * \{ */
548
549 typedef struct BrightContrastThreadData {
550 float bright;
551 float contrast;
552 } BrightContrastThreadData;
553
brightcontrast_apply_threaded(int width,int height,unsigned char * rect,float * rect_float,unsigned char * mask_rect,const float * mask_rect_float,void * data_v)554 static void brightcontrast_apply_threaded(int width,
555 int height,
556 unsigned char *rect,
557 float *rect_float,
558 unsigned char *mask_rect,
559 const float *mask_rect_float,
560 void *data_v)
561 {
562 BrightContrastThreadData *data = (BrightContrastThreadData *)data_v;
563 int x, y;
564
565 float i;
566 int c;
567 float a, b, v;
568 float brightness = data->bright / 100.0f;
569 float contrast = data->contrast;
570 float delta = contrast / 200.0f;
571 /*
572 * The algorithm is by Werner D. Streidt
573 * (http://visca.com/ffactory/archives/5-99/msg00021.html)
574 * Extracted of OpenCV demhist.c
575 */
576 if (contrast > 0) {
577 a = 1.0f - delta * 2.0f;
578 a = 1.0f / max_ff(a, FLT_EPSILON);
579 b = a * (brightness - delta);
580 }
581 else {
582 delta *= -1;
583 a = max_ff(1.0f - delta * 2.0f, 0.0f);
584 b = a * brightness + delta;
585 }
586
587 for (y = 0; y < height; y++) {
588 for (x = 0; x < width; x++) {
589 int pixel_index = (y * width + x) * 4;
590
591 if (rect) {
592 unsigned char *pixel = rect + pixel_index;
593
594 for (c = 0; c < 3; c++) {
595 i = (float)pixel[c] / 255.0f;
596 v = a * i + b;
597
598 if (mask_rect) {
599 unsigned char *m = mask_rect + pixel_index;
600 float t = (float)m[c] / 255.0f;
601
602 v = (float)pixel[c] / 255.0f * (1.0f - t) + v * t;
603 }
604
605 pixel[c] = unit_float_to_uchar_clamp(v);
606 }
607 }
608 else if (rect_float) {
609 float *pixel = rect_float + pixel_index;
610
611 for (c = 0; c < 3; c++) {
612 i = pixel[c];
613 v = a * i + b;
614
615 if (mask_rect_float) {
616 const float *m = mask_rect_float + pixel_index;
617
618 pixel[c] = pixel[c] * (1.0f - m[c]) + v * m[c];
619 }
620 else {
621 pixel[c] = v;
622 }
623 }
624 }
625 }
626 }
627 }
628
brightcontrast_apply(struct SequenceModifierData * smd,ImBuf * ibuf,ImBuf * mask)629 static void brightcontrast_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
630 {
631 BrightContrastModifierData *bcmd = (BrightContrastModifierData *)smd;
632 BrightContrastThreadData data;
633
634 data.bright = bcmd->bright;
635 data.contrast = bcmd->contrast;
636
637 modifier_apply_threaded(ibuf, mask, brightcontrast_apply_threaded, &data);
638 }
639
640 static SequenceModifierTypeInfo seqModifier_BrightContrast = {
641 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Bright/Contrast"), /* name */
642 "BrightContrastModifierData", /* struct_name */
643 sizeof(BrightContrastModifierData), /* struct_size */
644 NULL, /* init_data */
645 NULL, /* free_data */
646 NULL, /* copy_data */
647 brightcontrast_apply, /* apply */
648 };
649
650 /** \} */
651
652 /* -------------------------------------------------------------------- */
653 /** \name Mask Modifier
654 * \{ */
655
maskmodifier_apply_threaded(int width,int height,unsigned char * rect,float * rect_float,unsigned char * mask_rect,const float * mask_rect_float,void * UNUSED (data_v))656 static void maskmodifier_apply_threaded(int width,
657 int height,
658 unsigned char *rect,
659 float *rect_float,
660 unsigned char *mask_rect,
661 const float *mask_rect_float,
662 void *UNUSED(data_v))
663 {
664 int x, y;
665
666 if (rect && !mask_rect) {
667 return;
668 }
669
670 if (rect_float && !mask_rect_float) {
671 return;
672 }
673
674 for (y = 0; y < height; y++) {
675 for (x = 0; x < width; x++) {
676 int pixel_index = (y * width + x) * 4;
677
678 if (rect) {
679 unsigned char *pixel = rect + pixel_index;
680 unsigned char *mask_pixel = mask_rect + pixel_index;
681 unsigned char mask = min_iii(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
682
683 /* byte buffer is straight, so only affect on alpha itself,
684 * this is the only way to alpha-over byte strip after
685 * applying mask modifier.
686 */
687 pixel[3] = (float)(pixel[3] * mask) / 255.0f;
688 }
689 else if (rect_float) {
690 int c;
691 float *pixel = rect_float + pixel_index;
692 const float *mask_pixel = mask_rect_float + pixel_index;
693 float mask = min_fff(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
694
695 /* float buffers are premultiplied, so need to premul color
696 * as well to make it easy to alpha-over masted strip.
697 */
698 for (c = 0; c < 4; c++) {
699 pixel[c] = pixel[c] * mask;
700 }
701 }
702 }
703 }
704 }
705
maskmodifier_apply(struct SequenceModifierData * UNUSED (smd),ImBuf * ibuf,ImBuf * mask)706 static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *ibuf, ImBuf *mask)
707 {
708 // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
709
710 modifier_apply_threaded(ibuf, mask, maskmodifier_apply_threaded, NULL);
711 }
712
713 static SequenceModifierTypeInfo seqModifier_Mask = {
714 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Mask"), /* name */
715 "SequencerMaskModifierData", /* struct_name */
716 sizeof(SequencerMaskModifierData), /* struct_size */
717 NULL, /* init_data */
718 NULL, /* free_data */
719 NULL, /* copy_data */
720 maskmodifier_apply, /* apply */
721 };
722
723 /** \} */
724
725 /* -------------------------------------------------------------------- */
726 /** \name Tonemap Modifier
727 * \{ */
728
729 typedef struct AvgLogLum {
730 SequencerTonemapModifierData *tmmd;
731 struct ColorSpace *colorspace;
732 float al;
733 float auto_key;
734 float lav;
735 float cav[4];
736 float igm;
737 } AvgLogLum;
738
tonemapmodifier_init_data(SequenceModifierData * smd)739 static void tonemapmodifier_init_data(SequenceModifierData *smd)
740 {
741 SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *)smd;
742 /* Same as tonemap compositor node. */
743 tmmd->type = SEQ_TONEMAP_RD_PHOTORECEPTOR;
744 tmmd->key = 0.18f;
745 tmmd->offset = 1.0f;
746 tmmd->gamma = 1.0f;
747 tmmd->intensity = 0.0f;
748 tmmd->contrast = 0.0f;
749 tmmd->adaptation = 1.0f;
750 tmmd->correction = 0.0f;
751 }
752
tonemapmodifier_apply_threaded_simple(int width,int height,unsigned char * rect,float * rect_float,unsigned char * mask_rect,const float * mask_rect_float,void * data_v)753 static void tonemapmodifier_apply_threaded_simple(int width,
754 int height,
755 unsigned char *rect,
756 float *rect_float,
757 unsigned char *mask_rect,
758 const float *mask_rect_float,
759 void *data_v)
760 {
761 AvgLogLum *avg = (AvgLogLum *)data_v;
762 for (int y = 0; y < height; y++) {
763 for (int x = 0; x < width; x++) {
764 int pixel_index = (y * width + x) * 4;
765 float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
766 /* Get input value. */
767 if (rect_float) {
768 copy_v4_v4(input, &rect_float[pixel_index]);
769 }
770 else {
771 straight_uchar_to_premul_float(input, &rect[pixel_index]);
772 }
773 IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
774 copy_v4_v4(output, input);
775 /* Get mask value. */
776 if (mask_rect_float) {
777 copy_v3_v3(mask, mask_rect_float + pixel_index);
778 }
779 else if (mask_rect) {
780 rgb_uchar_to_float(mask, mask_rect + pixel_index);
781 }
782 /* Apply correction. */
783 mul_v3_fl(output, avg->al);
784 float dr = output[0] + avg->tmmd->offset;
785 float dg = output[1] + avg->tmmd->offset;
786 float db = output[2] + avg->tmmd->offset;
787 output[0] /= ((dr == 0.0f) ? 1.0f : dr);
788 output[1] /= ((dg == 0.0f) ? 1.0f : dg);
789 output[2] /= ((db == 0.0f) ? 1.0f : db);
790 const float igm = avg->igm;
791 if (igm != 0.0f) {
792 output[0] = powf(max_ff(output[0], 0.0f), igm);
793 output[1] = powf(max_ff(output[1], 0.0f), igm);
794 output[2] = powf(max_ff(output[2], 0.0f), igm);
795 }
796 /* Apply mask. */
797 output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
798 output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
799 output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
800 /* Copy result back. */
801 IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
802 if (rect_float) {
803 copy_v4_v4(&rect_float[pixel_index], output);
804 }
805 else {
806 premul_float_to_straight_uchar(&rect[pixel_index], output);
807 }
808 }
809 }
810 }
811
tonemapmodifier_apply_threaded_photoreceptor(int width,int height,unsigned char * rect,float * rect_float,unsigned char * mask_rect,const float * mask_rect_float,void * data_v)812 static void tonemapmodifier_apply_threaded_photoreceptor(int width,
813 int height,
814 unsigned char *rect,
815 float *rect_float,
816 unsigned char *mask_rect,
817 const float *mask_rect_float,
818 void *data_v)
819 {
820 AvgLogLum *avg = (AvgLogLum *)data_v;
821 const float f = expf(-avg->tmmd->intensity);
822 const float m = (avg->tmmd->contrast > 0.0f) ? avg->tmmd->contrast :
823 (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
824 const float ic = 1.0f - avg->tmmd->correction, ia = 1.0f - avg->tmmd->adaptation;
825 for (int y = 0; y < height; y++) {
826 for (int x = 0; x < width; x++) {
827 int pixel_index = (y * width + x) * 4;
828 float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
829 /* Get input value. */
830 if (rect_float) {
831 copy_v4_v4(input, &rect_float[pixel_index]);
832 }
833 else {
834 straight_uchar_to_premul_float(input, &rect[pixel_index]);
835 }
836 IMB_colormanagement_colorspace_to_scene_linear_v3(input, avg->colorspace);
837 copy_v4_v4(output, input);
838 /* Get mask value. */
839 if (mask_rect_float) {
840 copy_v3_v3(mask, mask_rect_float + pixel_index);
841 }
842 else if (mask_rect) {
843 rgb_uchar_to_float(mask, mask_rect + pixel_index);
844 }
845 /* Apply correction. */
846 const float L = IMB_colormanagement_get_luminance(output);
847 float I_l = output[0] + ic * (L - output[0]);
848 float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
849 float I_a = I_l + ia * (I_g - I_l);
850 output[0] /= (output[0] + powf(f * I_a, m));
851 I_l = output[1] + ic * (L - output[1]);
852 I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
853 I_a = I_l + ia * (I_g - I_l);
854 output[1] /= (output[1] + powf(f * I_a, m));
855 I_l = output[2] + ic * (L - output[2]);
856 I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
857 I_a = I_l + ia * (I_g - I_l);
858 output[2] /= (output[2] + powf(f * I_a, m));
859 /* Apply mask. */
860 output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
861 output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
862 output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
863 /* Copy result back. */
864 IMB_colormanagement_scene_linear_to_colorspace_v3(output, avg->colorspace);
865 if (rect_float) {
866 copy_v4_v4(&rect_float[pixel_index], output);
867 }
868 else {
869 premul_float_to_straight_uchar(&rect[pixel_index], output);
870 }
871 }
872 }
873 }
874
tonemapmodifier_apply(struct SequenceModifierData * smd,ImBuf * ibuf,ImBuf * mask)875 static void tonemapmodifier_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
876 {
877 SequencerTonemapModifierData *tmmd = (SequencerTonemapModifierData *)smd;
878 AvgLogLum data;
879 data.tmmd = tmmd;
880 data.colorspace = (ibuf->rect_float != NULL) ? ibuf->float_colorspace : ibuf->rect_colorspace;
881 float lsum = 0.0f;
882 int p = ibuf->x * ibuf->y;
883 float *fp = ibuf->rect_float;
884 unsigned char *cp = (unsigned char *)ibuf->rect;
885 float avl, maxl = -FLT_MAX, minl = FLT_MAX;
886 const float sc = 1.0f / p;
887 float Lav = 0.f;
888 float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
889 while (p--) {
890 float pixel[4];
891 if (fp != NULL) {
892 copy_v4_v4(pixel, fp);
893 }
894 else {
895 straight_uchar_to_premul_float(pixel, cp);
896 }
897 IMB_colormanagement_colorspace_to_scene_linear_v3(pixel, data.colorspace);
898 float L = IMB_colormanagement_get_luminance(pixel);
899 Lav += L;
900 add_v3_v3(cav, pixel);
901 lsum += logf(max_ff(L, 0.0f) + 1e-5f);
902 maxl = (L > maxl) ? L : maxl;
903 minl = (L < minl) ? L : minl;
904 if (fp != NULL) {
905 fp += 4;
906 }
907 else {
908 cp += 4;
909 }
910 }
911 data.lav = Lav * sc;
912 mul_v3_v3fl(data.cav, cav, sc);
913 maxl = logf(maxl + 1e-5f);
914 minl = logf(minl + 1e-5f);
915 avl = lsum * sc;
916 data.auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
917 float al = expf(avl);
918 data.al = (al == 0.0f) ? 0.0f : (tmmd->key / al);
919 data.igm = (tmmd->gamma == 0.0f) ? 1.0f : (1.0f / tmmd->gamma);
920
921 if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
922 modifier_apply_threaded(ibuf, mask, tonemapmodifier_apply_threaded_photoreceptor, &data);
923 }
924 else /* if (tmmd->type == SEQ_TONEMAP_RD_SIMPLE) */ {
925 modifier_apply_threaded(ibuf, mask, tonemapmodifier_apply_threaded_simple, &data);
926 }
927 }
928
929 static SequenceModifierTypeInfo seqModifier_Tonemap = {
930 CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Tonemap"), /* name */
931 "SequencerTonemapModifierData", /* struct_name */
932 sizeof(SequencerTonemapModifierData), /* struct_size */
933 tonemapmodifier_init_data, /* init_data */
934 NULL, /* free_data */
935 NULL, /* copy_data */
936 tonemapmodifier_apply, /* apply */
937 };
938
939 /** \} */
940
941 /* -------------------------------------------------------------------- */
942 /** \name Public Modifier Functions
943 * \{ */
944
sequence_modifier_type_info_init(void)945 static void sequence_modifier_type_info_init(void)
946 {
947 #define INIT_TYPE(typeName) (modifiersTypes[seqModifierType_##typeName] = &seqModifier_##typeName)
948
949 INIT_TYPE(ColorBalance);
950 INIT_TYPE(Curves);
951 INIT_TYPE(HueCorrect);
952 INIT_TYPE(BrightContrast);
953 INIT_TYPE(Mask);
954 INIT_TYPE(WhiteBalance);
955 INIT_TYPE(Tonemap);
956
957 #undef INIT_TYPE
958 }
959
BKE_sequence_modifier_type_info_get(int type)960 const SequenceModifierTypeInfo *BKE_sequence_modifier_type_info_get(int type)
961 {
962 if (!modifierTypesInit) {
963 sequence_modifier_type_info_init();
964 modifierTypesInit = true;
965 }
966
967 return modifiersTypes[type];
968 }
969
BKE_sequence_modifier_new(Sequence * seq,const char * name,int type)970 SequenceModifierData *BKE_sequence_modifier_new(Sequence *seq, const char *name, int type)
971 {
972 SequenceModifierData *smd;
973 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(type);
974
975 smd = MEM_callocN(smti->struct_size, "sequence modifier");
976
977 smd->type = type;
978 smd->flag |= SEQUENCE_MODIFIER_EXPANDED;
979
980 if (!name || !name[0]) {
981 BLI_strncpy(smd->name, smti->name, sizeof(smd->name));
982 }
983 else {
984 BLI_strncpy(smd->name, name, sizeof(smd->name));
985 }
986
987 BLI_addtail(&seq->modifiers, smd);
988
989 BKE_sequence_modifier_unique_name(seq, smd);
990
991 if (smti->init_data) {
992 smti->init_data(smd);
993 }
994
995 return smd;
996 }
997
BKE_sequence_modifier_remove(Sequence * seq,SequenceModifierData * smd)998 bool BKE_sequence_modifier_remove(Sequence *seq, SequenceModifierData *smd)
999 {
1000 if (BLI_findindex(&seq->modifiers, smd) == -1) {
1001 return false;
1002 }
1003
1004 BLI_remlink(&seq->modifiers, smd);
1005 BKE_sequence_modifier_free(smd);
1006
1007 return true;
1008 }
1009
BKE_sequence_modifier_clear(Sequence * seq)1010 void BKE_sequence_modifier_clear(Sequence *seq)
1011 {
1012 SequenceModifierData *smd, *smd_next;
1013
1014 for (smd = seq->modifiers.first; smd; smd = smd_next) {
1015 smd_next = smd->next;
1016 BKE_sequence_modifier_free(smd);
1017 }
1018
1019 BLI_listbase_clear(&seq->modifiers);
1020 }
1021
BKE_sequence_modifier_free(SequenceModifierData * smd)1022 void BKE_sequence_modifier_free(SequenceModifierData *smd)
1023 {
1024 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
1025
1026 if (smti && smti->free_data) {
1027 smti->free_data(smd);
1028 }
1029
1030 MEM_freeN(smd);
1031 }
1032
BKE_sequence_modifier_unique_name(Sequence * seq,SequenceModifierData * smd)1033 void BKE_sequence_modifier_unique_name(Sequence *seq, SequenceModifierData *smd)
1034 {
1035 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
1036
1037 BLI_uniquename(&seq->modifiers,
1038 smd,
1039 CTX_DATA_(BLT_I18NCONTEXT_ID_SEQUENCE, smti->name),
1040 '.',
1041 offsetof(SequenceModifierData, name),
1042 sizeof(smd->name));
1043 }
1044
BKE_sequence_modifier_find_by_name(Sequence * seq,const char * name)1045 SequenceModifierData *BKE_sequence_modifier_find_by_name(Sequence *seq, const char *name)
1046 {
1047 return BLI_findstring(&(seq->modifiers), name, offsetof(SequenceModifierData, name));
1048 }
1049
BKE_sequence_modifier_apply_stack(const SeqRenderData * context,Sequence * seq,ImBuf * ibuf,int cfra)1050 ImBuf *BKE_sequence_modifier_apply_stack(const SeqRenderData *context,
1051 Sequence *seq,
1052 ImBuf *ibuf,
1053 int cfra)
1054 {
1055 SequenceModifierData *smd;
1056 ImBuf *processed_ibuf = ibuf;
1057
1058 if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
1059 processed_ibuf = IMB_dupImBuf(ibuf);
1060 BKE_sequencer_imbuf_from_sequencer_space(context->scene, processed_ibuf);
1061 }
1062
1063 for (smd = seq->modifiers.first; smd; smd = smd->next) {
1064 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
1065
1066 /* could happen if modifier is being removed or not exists in current version of blender */
1067 if (!smti) {
1068 continue;
1069 }
1070
1071 /* modifier is muted, do nothing */
1072 if (smd->flag & SEQUENCE_MODIFIER_MUTE) {
1073 continue;
1074 }
1075
1076 if (smti->apply) {
1077 int frame_offset;
1078 if (smd->mask_time == SEQUENCE_MASK_TIME_RELATIVE) {
1079 frame_offset = seq->start;
1080 }
1081 else /*if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE)*/ {
1082 frame_offset = smd->mask_id ? ((Mask *)smd->mask_id)->sfra : 0;
1083 }
1084
1085 ImBuf *mask = modifier_mask_get(smd, context, cfra, frame_offset, ibuf->rect_float != NULL);
1086
1087 if (processed_ibuf == ibuf) {
1088 processed_ibuf = IMB_dupImBuf(ibuf);
1089 }
1090
1091 smti->apply(smd, processed_ibuf, mask);
1092
1093 if (mask) {
1094 IMB_freeImBuf(mask);
1095 }
1096 }
1097 }
1098
1099 if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
1100 BKE_sequencer_imbuf_to_sequencer_space(context->scene, processed_ibuf, false);
1101 }
1102
1103 return processed_ibuf;
1104 }
1105
BKE_sequence_modifier_list_copy(Sequence * seqn,Sequence * seq)1106 void BKE_sequence_modifier_list_copy(Sequence *seqn, Sequence *seq)
1107 {
1108 SequenceModifierData *smd;
1109
1110 for (smd = seq->modifiers.first; smd; smd = smd->next) {
1111 SequenceModifierData *smdn;
1112 const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type);
1113
1114 smdn = MEM_dupallocN(smd);
1115
1116 if (smti && smti->copy_data) {
1117 smti->copy_data(smdn, smd);
1118 }
1119
1120 smdn->next = smdn->prev = NULL;
1121 BLI_addtail(&seqn->modifiers, smdn);
1122 }
1123 }
1124
BKE_sequence_supports_modifiers(Sequence * seq)1125 int BKE_sequence_supports_modifiers(Sequence *seq)
1126 {
1127 return !ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD);
1128 }
1129
1130 /** \} */
1131