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