Blender  V3.3
sequencer/intern/modifier.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2012 Blender Foundation. All rights reserved. */
3 
8 #include <stddef.h>
9 #include <string.h>
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "BLI_listbase.h"
14 #include "BLI_math.h"
15 #include "BLI_string.h"
16 #include "BLI_string_utils.h"
17 #include "BLI_utildefines.h"
18 
19 #include "BLT_translation.h"
20 
21 #include "DNA_mask_types.h"
22 #include "DNA_scene_types.h"
23 #include "DNA_sequence_types.h"
24 
25 #include "BKE_colortools.h"
26 
27 #include "IMB_colormanagement.h"
28 #include "IMB_imbuf.h"
29 #include "IMB_imbuf_types.h"
30 
31 #include "SEQ_modifier.h"
32 #include "SEQ_render.h"
33 
34 #include "BLO_read_write.h"
35 
36 #include "render.h"
37 
39 static bool modifierTypesInit = false;
40 
41 /* -------------------------------------------------------------------- */
46  int height,
47  unsigned char *rect,
48  float *rect_float,
49  unsigned char *mask_rect,
50  const float *mask_rect_float,
51  void *data_v);
52 
53 typedef struct ModifierInitData {
56  void *user_data;
57 
60 
61 typedef struct ModifierThread {
62  int width, height;
63 
64  unsigned char *rect, *mask_rect;
66 
67  void *user_data;
68 
71 
76  int mask_input_type,
77  Sequence *mask_sequence,
78  Mask *mask_id,
79  int timeline_frame,
80  int fra_offset,
81  bool make_float)
82 {
83  ImBuf *mask_input = NULL;
84 
85  if (mask_input_type == SEQUENCE_MASK_INPUT_STRIP) {
86  if (mask_sequence) {
89 
90  mask_input = seq_render_strip(context, &state, mask_sequence, timeline_frame);
91 
92  if (make_float) {
93  if (!mask_input->rect_float) {
94  IMB_float_from_rect(mask_input);
95  }
96  }
97  else {
98  if (!mask_input->rect) {
99  IMB_rect_from_float(mask_input);
100  }
101  }
102  }
103  }
104  else if (mask_input_type == SEQUENCE_MASK_INPUT_ID) {
105  mask_input = seq_render_mask(context, mask_id, timeline_frame - fra_offset, make_float);
106  }
107 
108  return mask_input;
109 }
110 
112  const SeqRenderData *context,
113  int timeline_frame,
114  int fra_offset,
115  bool make_float)
116 {
118  smd->mask_input_type,
119  smd->mask_sequence,
120  smd->mask_id,
121  timeline_frame,
122  fra_offset,
123  make_float);
124 }
125 
126 static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
127 {
128  ModifierThread *handle = (ModifierThread *)handle_v;
129  ModifierInitData *init_data = (ModifierInitData *)init_data_v;
130  ImBuf *ibuf = init_data->ibuf;
131  ImBuf *mask = init_data->mask;
132 
133  int offset = 4 * start_line * ibuf->x;
134 
135  memset(handle, 0, sizeof(ModifierThread));
136 
137  handle->width = ibuf->x;
138  handle->height = tot_line;
139  handle->apply_callback = init_data->apply_callback;
140  handle->user_data = init_data->user_data;
141 
142  if (ibuf->rect) {
143  handle->rect = (unsigned char *)ibuf->rect + offset;
144  }
145 
146  if (ibuf->rect_float) {
147  handle->rect_float = ibuf->rect_float + offset;
148  }
149 
150  if (mask) {
151  if (mask->rect) {
152  handle->mask_rect = (unsigned char *)mask->rect + offset;
153  }
154 
155  if (mask->rect_float) {
156  handle->mask_rect_float = mask->rect_float + offset;
157  }
158  }
159  else {
160  handle->mask_rect = NULL;
161  handle->mask_rect_float = NULL;
162  }
163 }
164 
165 static void *modifier_do_thread(void *thread_data_v)
166 {
167  ModifierThread *td = (ModifierThread *)thread_data_v;
168 
169  td->apply_callback(td->width,
170  td->height,
171  td->rect,
172  td->rect_float,
173  td->mask_rect,
174  td->mask_rect_float,
175  td->user_data);
176 
177  return NULL;
178 }
179 
180 static void modifier_apply_threaded(ImBuf *ibuf,
181  ImBuf *mask,
182  modifier_apply_threaded_cb apply_callback,
183  void *user_data)
184 {
186 
187  init_data.ibuf = ibuf;
188  init_data.mask = mask;
189  init_data.user_data = user_data;
190 
191  init_data.apply_callback = apply_callback;
192 
195 }
196 
199 /* -------------------------------------------------------------------- */
204 {
205  StripColorBalance cb = *cb_;
206  int c;
207 
208  for (c = 0; c < 3; c++) {
209  cb.lift[c] = 2.0f - cb.lift[c];
210  }
211 
213  for (c = 0; c < 3; c++) {
214  /* tweak to give more subtle results
215  * values above 1.0 are scaled */
216  if (cb.lift[c] > 1.0f) {
217  cb.lift[c] = pow(cb.lift[c] - 1.0f, 2.0) + 1.0;
218  }
219 
220  cb.lift[c] = 2.0f - cb.lift[c];
221  }
222  }
223 
225  for (c = 0; c < 3; c++) {
226  if (cb.gain[c] != 0.0f) {
227  cb.gain[c] = 1.0f / cb.gain[c];
228  }
229  else {
230  cb.gain[c] = 1000000; /* should be enough :) */
231  }
232  }
233  }
234 
236  for (c = 0; c < 3; c++) {
237  if (cb.gamma[c] != 0.0f) {
238  cb.gamma[c] = 1.0f / cb.gamma[c];
239  }
240  else {
241  cb.gamma[c] = 1000000; /* should be enough :) */
242  }
243  }
244  }
245 
246  return cb;
247 }
248 
250 {
251  StripColorBalance cb = *cb_;
252  int c;
253 
254  for (c = 0; c < 3; c++) {
256  if (cb.slope[c] != 0.0f) {
257  cb.slope[c] = 1.0f / cb.slope[c];
258  }
259  else {
260  cb.slope[c] = 1000000;
261  }
262  }
263 
265  cb.offset[c] = -1.0f * (cb.offset[c] - 1.0f);
266  }
267  else {
268  cb.offset[c] = cb.offset[c] - 1.0f;
269  }
270 
272  if (cb.power[c] != 0.0f) {
273  cb.power[c] = 1.0f / cb.power[c];
274  }
275  else {
276  cb.power[c] = 1000000;
277  }
278  }
279  }
280 
281  return cb;
282 }
283 
285 {
287  return calc_cb_lgg(cb_);
288  }
289  /* `cb_->method == SEQ_COLOR_BALANCE_METHOD_SLOPEOFFSETPOWER`. */
290  return calc_cb_sop(cb_);
291 }
292 
293 /* NOTE: lift is actually 2-lift. */
295  float in, const float lift, const float gain, const float gamma, const float mul)
296 {
297  float x = (((in - 1.0f) * lift) + 1.0f) * gain;
298 
299  /* prevent NaN */
300  if (x < 0.0f) {
301  x = 0.0f;
302  }
303 
304  x = powf(x, gamma) * mul;
305  CLAMP(x, FLT_MIN, FLT_MAX);
306  return x;
307 }
308 
310  const float slope,
311  const float offset,
312  const float power,
313  const float pivot,
314  float mul)
315 {
316  float x = in * slope + offset;
317 
318  /* prevent NaN */
319  if (x < 0.0f) {
320  x = 0.0f;
321  }
322 
323  x = powf(x / pivot, power) * pivot;
324  x *= mul;
325  CLAMP(x, FLT_MIN, FLT_MAX);
326  return x;
327 }
328 
329 static void make_cb_table_float_lgg(float lift, float gain, float gamma, float *table, float mul)
330 {
331  for (int y = 0; y < 256; y++) {
332  float v = color_balance_fl_lgg((float)y * (1.0f / 255.0f), lift, gain, gamma, mul);
333 
334  table[y] = v;
335  }
336 }
337 
339  float slope, float offset, float power, float pivot, float *table, float mul)
340 {
341  for (int y = 0; y < 256; y++) {
342  float v = color_balance_fl_sop((float)y * (1.0f / 255.0f), slope, offset, power, pivot, mul);
343 
344  table[y] = v;
345  }
346 }
347 
349  unsigned char *rect,
350  unsigned char *mask_rect,
351  int width,
352  int height,
353  float mul)
354 {
355  // unsigned char cb_tab[3][256];
356  unsigned char *cp = rect;
357  unsigned char *e = cp + width * 4 * height;
358  unsigned char *m = mask_rect;
359 
360  StripColorBalance cb = calc_cb(cb_);
361 
362  while (cp < e) {
363  float p[4];
364  int c;
365 
367 
368  for (c = 0; c < 3; c++) {
369  float t;
371  t = color_balance_fl_lgg(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
372  }
373  else {
374  t = color_balance_fl_sop(p[c], cb.slope[c], cb.offset[c], cb.power[c], 1.0, mul);
375  }
376 
377  if (m) {
378  float m_normal = (float)m[c] / 255.0f;
379 
380  p[c] = p[c] * (1.0f - m_normal) + t * m_normal;
381  }
382  else {
383  p[c] = t;
384  }
385  }
386 
388 
389  cp += 4;
390  if (m) {
391  m += 4;
392  }
393  }
394 }
395 
397  unsigned char *rect,
398  float *rect_float,
399  unsigned char *mask_rect,
400  int width,
401  int height,
402  float mul)
403 {
404  float cb_tab[4][256];
405  int c, i;
406  unsigned char *p = rect;
407  unsigned char *e = p + width * 4 * height;
408  unsigned char *m = mask_rect;
409  float *o;
411 
412  o = rect_float;
413 
414  cb = calc_cb(cb_);
415 
416  for (c = 0; c < 3; c++) {
418  make_cb_table_float_lgg(cb.lift[c], cb.gain[c], cb.gamma[c], cb_tab[c], mul);
419  }
420  else {
421  make_cb_table_float_sop(cb.slope[c], cb.offset[c], cb.power[c], 1.0, cb_tab[c], mul);
422  }
423  }
424 
425  for (i = 0; i < 256; i++) {
426  cb_tab[3][i] = ((float)i) * (1.0f / 255.0f);
427  }
428 
429  while (p < e) {
430  if (m) {
431  const float t[3] = {m[0] / 255.0f, m[1] / 255.0f, m[2] / 255.0f};
432 
433  p[0] = p[0] * (1.0f - t[0]) + t[0] * cb_tab[0][p[0]];
434  p[1] = p[1] * (1.0f - t[1]) + t[1] * cb_tab[1][p[1]];
435  p[2] = p[2] * (1.0f - t[2]) + t[2] * cb_tab[2][p[2]];
436 
437  m += 4;
438  }
439  else {
440  o[0] = cb_tab[0][p[0]];
441  o[1] = cb_tab[1][p[1]];
442  o[2] = cb_tab[2][p[2]];
443  }
444 
445  o[3] = cb_tab[3][p[3]];
446 
447  p += 4;
448  o += 4;
449  }
450 }
451 
453  float *rect_float,
454  const float *mask_rect_float,
455  int width,
456  int height,
457  float mul)
458 {
459  float *p = rect_float;
460  const float *e = rect_float + width * 4 * height;
461  const float *m = mask_rect_float;
462  StripColorBalance cb = calc_cb(cb_);
463 
464  while (p < e) {
465  int c;
466  for (c = 0; c < 3; c++) {
467  float t;
469  t = color_balance_fl_lgg(p[c], cb.lift[c], cb.gain[c], cb.gamma[c], mul);
470  }
471  else {
472  t = color_balance_fl_sop(p[c], cb.slope[c], cb.offset[c], cb.power[c], 1.0, mul);
473  }
474 
475  if (m) {
476  p[c] = p[c] * (1.0f - m[c]) + t * m[c];
477  }
478  else {
479  p[c] = t;
480  }
481  }
482 
483  p += 4;
484  if (m) {
485  m += 4;
486  }
487  }
488 }
489 
490 typedef struct ColorBalanceInitData {
493  float mul;
497 
498 typedef struct ColorBalanceThread {
500  float mul;
501 
502  int width, height;
503 
504  unsigned char *rect, *mask_rect;
506 
509 
510 static void color_balance_init_handle(void *handle_v,
511  int start_line,
512  int tot_line,
513  void *init_data_v)
514 {
515  ColorBalanceThread *handle = (ColorBalanceThread *)handle_v;
517  ImBuf *ibuf = init_data->ibuf;
518  ImBuf *mask = init_data->mask;
519 
520  int offset = 4 * start_line * ibuf->x;
521 
522  memset(handle, 0, sizeof(ColorBalanceThread));
523 
524  handle->cb = init_data->cb;
525  handle->mul = init_data->mul;
526  handle->width = ibuf->x;
527  handle->height = tot_line;
528  handle->make_float = init_data->make_float;
529 
530  if (ibuf->rect) {
531  handle->rect = (unsigned char *)ibuf->rect + offset;
532  }
533 
534  if (ibuf->rect_float) {
535  handle->rect_float = ibuf->rect_float + offset;
536  }
537 
538  if (mask) {
539  if (mask->rect) {
540  handle->mask_rect = (unsigned char *)mask->rect + offset;
541  }
542 
543  if (mask->rect_float) {
544  handle->mask_rect_float = mask->rect_float + offset;
545  }
546  }
547  else {
548  handle->mask_rect = NULL;
549  handle->mask_rect_float = NULL;
550  }
551 }
552 
553 static void *color_balance_do_thread(void *thread_data_v)
554 {
555  ColorBalanceThread *thread_data = (ColorBalanceThread *)thread_data_v;
556  StripColorBalance *cb = thread_data->cb;
557  int width = thread_data->width, height = thread_data->height;
558  unsigned char *rect = thread_data->rect;
559  unsigned char *mask_rect = thread_data->mask_rect;
560  float *rect_float = thread_data->rect_float;
561  float *mask_rect_float = thread_data->mask_rect_float;
562  float mul = thread_data->mul;
563 
564  if (rect_float) {
565  color_balance_float_float(cb, rect_float, mask_rect_float, width, height, mul);
566  }
567  else if (thread_data->make_float) {
568  color_balance_byte_float(cb, rect, rect_float, mask_rect, width, height, mul);
569  }
570  else {
571  color_balance_byte_byte(cb, rect, mask_rect, width, height, mul);
572  }
573 
574  return NULL;
575 }
576 
578 {
580  int c;
581 
582  cbmd->color_multiply = 1.0f;
583  cbmd->color_balance.method = 0;
584 
585  for (c = 0; c < 3; c++) {
586  cbmd->color_balance.lift[c] = 1.0f;
587  cbmd->color_balance.gamma[c] = 1.0f;
588  cbmd->color_balance.gain[c] = 1.0f;
589  cbmd->color_balance.slope[c] = 1.0f;
590  cbmd->color_balance.offset[c] = 1.0f;
591  cbmd->color_balance.power[c] = 1.0f;
592  }
593 }
594 
596  StripColorBalance *cb, ImBuf *ibuf, float mul, bool make_float, ImBuf *mask_input)
597 {
599 
600  if (!ibuf->rect_float && make_float) {
601  imb_addrectfloatImBuf(ibuf, 4);
602  }
603 
604  init_data.cb = cb;
605  init_data.ibuf = ibuf;
606  init_data.mul = mul;
607  init_data.make_float = make_float;
608  init_data.mask = mask_input;
609 
611  sizeof(ColorBalanceThread),
612  &init_data,
615 
616  /* color balance either happens on float buffer or byte buffer, but never on both,
617  * free byte buffer if there's float buffer since float buffer would be used for
618  * color balance in favor of byte buffer
619  */
620  if (ibuf->rect_float && ibuf->rect) {
621  imb_freerectImBuf(ibuf);
622  }
623 }
624 
626 {
628 
629  modifier_color_balance_apply(&cbmd->color_balance, ibuf, cbmd->color_multiply, false, mask);
630 }
631 
633  CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Color Balance"), /* name */
634  "ColorBalanceModifierData", /* struct_name */
635  sizeof(ColorBalanceModifierData), /* struct_size */
636  colorBalance_init_data, /* init_data */
637  NULL, /* free_data */
638  NULL, /* copy_data */
639  colorBalance_apply, /* apply */
640 };
641 
644 /* -------------------------------------------------------------------- */
649 {
651  copy_v3_fl(cbmd->white_value, 1.0f);
652 }
653 
654 typedef struct WhiteBalanceThreadData {
655  float white[3];
657 
659  int height,
660  unsigned char *rect,
661  float *rect_float,
662  unsigned char *mask_rect,
663  const float *mask_rect_float,
664  void *data_v)
665 {
666  int x, y;
667  float multiplier[3];
668 
670 
671  multiplier[0] = (data->white[0] != 0.0f) ? 1.0f / data->white[0] : FLT_MAX;
672  multiplier[1] = (data->white[1] != 0.0f) ? 1.0f / data->white[1] : FLT_MAX;
673  multiplier[2] = (data->white[2] != 0.0f) ? 1.0f / data->white[2] : FLT_MAX;
674 
675  for (y = 0; y < height; y++) {
676  for (x = 0; x < width; x++) {
677  int pixel_index = (y * width + x) * 4;
678  float rgba[4], result[4], mask[3] = {1.0f, 1.0f, 1.0f};
679 
680  if (rect_float) {
681  copy_v3_v3(rgba, rect_float + pixel_index);
682  }
683  else {
684  straight_uchar_to_premul_float(rgba, rect + pixel_index);
685  }
686 
688 #if 0
689  mul_v3_v3(result, multiplier);
690 #else
691  /* similar to division without the clipping */
692  for (int i = 0; i < 3; i++) {
693  result[i] = 1.0f - powf(1.0f - rgba[i], multiplier[i]);
694  }
695 #endif
696 
697  if (mask_rect_float) {
698  copy_v3_v3(mask, mask_rect_float + pixel_index);
699  }
700  else if (mask_rect) {
701  rgb_uchar_to_float(mask, mask_rect + pixel_index);
702  }
703 
704  result[0] = rgba[0] * (1.0f - mask[0]) + result[0] * mask[0];
705  result[1] = rgba[1] * (1.0f - mask[1]) + result[1] * mask[1];
706  result[2] = rgba[2] * (1.0f - mask[2]) + result[2] * mask[2];
707 
708  if (rect_float) {
709  copy_v3_v3(rect_float + pixel_index, result);
710  }
711  else {
712  premul_float_to_straight_uchar(rect + pixel_index, result);
713  }
714  }
715  }
716 }
717 
719 {
722 
723  copy_v3_v3(data.white, wbmd->white_value);
724 
726 }
727 
729  CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "White Balance"), /* name */
730  "WhiteBalanceModifierData", /* struct_name */
731  sizeof(WhiteBalanceModifierData), /* struct_size */
732  whiteBalance_init_data, /* init_data */
733  NULL, /* free_data */
734  NULL, /* copy_data */
735  whiteBalance_apply, /* apply */
736 };
737 
740 /* -------------------------------------------------------------------- */
745 {
747 
748  BKE_curvemapping_set_defaults(&cmd->curve_mapping, 4, 0.0f, 0.0f, 1.0f, 1.0f);
749 }
750 
752 {
754 
756 }
757 
759 {
761  CurvesModifierData *cmd_target = (CurvesModifierData *)target;
762 
764 }
765 
766 static void curves_apply_threaded(int width,
767  int height,
768  unsigned char *rect,
769  float *rect_float,
770  unsigned char *mask_rect,
771  const float *mask_rect_float,
772  void *data_v)
773 {
774  CurveMapping *curve_mapping = (CurveMapping *)data_v;
775  int x, y;
776 
777  for (y = 0; y < height; y++) {
778  for (x = 0; x < width; x++) {
779  int pixel_index = (y * width + x) * 4;
780 
781  if (rect_float) {
782  float *pixel = rect_float + pixel_index;
783  float result[3];
784 
785  BKE_curvemapping_evaluate_premulRGBF(curve_mapping, result, pixel);
786 
787  if (mask_rect_float) {
788  const float *m = mask_rect_float + pixel_index;
789 
790  pixel[0] = pixel[0] * (1.0f - m[0]) + result[0] * m[0];
791  pixel[1] = pixel[1] * (1.0f - m[1]) + result[1] * m[1];
792  pixel[2] = pixel[2] * (1.0f - m[2]) + result[2] * m[2];
793  }
794  else {
795  pixel[0] = result[0];
796  pixel[1] = result[1];
797  pixel[2] = result[2];
798  }
799  }
800  if (rect) {
801  unsigned char *pixel = rect + pixel_index;
802  float result[3], tempc[4];
803 
804  straight_uchar_to_premul_float(tempc, pixel);
805 
806  BKE_curvemapping_evaluate_premulRGBF(curve_mapping, result, tempc);
807 
808  if (mask_rect) {
809  float t[3];
810 
811  rgb_uchar_to_float(t, mask_rect + pixel_index);
812 
813  tempc[0] = tempc[0] * (1.0f - t[0]) + result[0] * t[0];
814  tempc[1] = tempc[1] * (1.0f - t[1]) + result[1] * t[1];
815  tempc[2] = tempc[2] * (1.0f - t[2]) + result[2] * t[2];
816  }
817  else {
818  tempc[0] = result[0];
819  tempc[1] = result[1];
820  tempc[2] = result[2];
821  }
822 
823  premul_float_to_straight_uchar(pixel, tempc);
824  }
825  }
826  }
827 }
828 
829 static void curves_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
830 {
832 
833  const float black[3] = {0.0f, 0.0f, 0.0f};
834  const float white[3] = {1.0f, 1.0f, 1.0f};
835 
837 
839  BKE_curvemapping_set_black_white(&cmd->curve_mapping, black, white);
840 
842 
844 }
845 
847  CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Curves"), /* name */
848  "CurvesModifierData", /* struct_name */
849  sizeof(CurvesModifierData), /* struct_size */
850  curves_init_data, /* init_data */
851  curves_free_data, /* free_data */
852  curves_copy_data, /* copy_data */
853  curves_apply, /* apply */
854 };
855 
858 /* -------------------------------------------------------------------- */
863 {
865  int c;
866 
867  BKE_curvemapping_set_defaults(&hcmd->curve_mapping, 1, 0.0f, 0.0f, 1.0f, 1.0f);
869 
870  for (c = 0; c < 3; c++) {
871  CurveMap *cuma = &hcmd->curve_mapping.cm[c];
872 
875  }
876 
877  /* default to showing Saturation */
878  hcmd->curve_mapping.cur = 1;
879 }
880 
882 {
884 
886 }
887 
889 {
891  HueCorrectModifierData *hcmd_target = (HueCorrectModifierData *)target;
892 
894 }
895 
897  int height,
898  unsigned char *rect,
899  float *rect_float,
900  unsigned char *mask_rect,
901  const float *mask_rect_float,
902  void *data_v)
903 {
904  CurveMapping *curve_mapping = (CurveMapping *)data_v;
905  int x, y;
906 
907  for (y = 0; y < height; y++) {
908  for (x = 0; x < width; x++) {
909  int pixel_index = (y * width + x) * 4;
910  float pixel[3], result[3], mask[3] = {1.0f, 1.0f, 1.0f};
911  float hsv[3], f;
912 
913  if (rect_float) {
914  copy_v3_v3(pixel, rect_float + pixel_index);
915  }
916  else {
917  rgb_uchar_to_float(pixel, rect + pixel_index);
918  }
919 
920  rgb_to_hsv(pixel[0], pixel[1], pixel[2], hsv, hsv + 1, hsv + 2);
921 
922  /* adjust hue, scaling returned default 0.5 up to 1 */
923  f = BKE_curvemapping_evaluateF(curve_mapping, 0, hsv[0]);
924  hsv[0] += f - 0.5f;
925 
926  /* adjust saturation, scaling returned default 0.5 up to 1 */
927  f = BKE_curvemapping_evaluateF(curve_mapping, 1, hsv[0]);
928  hsv[1] *= (f * 2.0f);
929 
930  /* adjust value, scaling returned default 0.5 up to 1 */
931  f = BKE_curvemapping_evaluateF(curve_mapping, 2, hsv[0]);
932  hsv[2] *= (f * 2.0f);
933 
934  hsv[0] = hsv[0] - floorf(hsv[0]); /* mod 1.0 */
935  CLAMP(hsv[1], 0.0f, 1.0f);
936 
937  /* convert back to rgb */
938  hsv_to_rgb(hsv[0], hsv[1], hsv[2], result, result + 1, result + 2);
939 
940  if (mask_rect_float) {
941  copy_v3_v3(mask, mask_rect_float + pixel_index);
942  }
943  else if (mask_rect) {
944  rgb_uchar_to_float(mask, mask_rect + pixel_index);
945  }
946 
947  result[0] = pixel[0] * (1.0f - mask[0]) + result[0] * mask[0];
948  result[1] = pixel[1] * (1.0f - mask[1]) + result[1] * mask[1];
949  result[2] = pixel[2] * (1.0f - mask[2]) + result[2] * mask[2];
950 
951  if (rect_float) {
952  copy_v3_v3(rect_float + pixel_index, result);
953  }
954  else {
955  rgb_float_to_uchar(rect + pixel_index, result);
956  }
957  }
958  }
959 }
960 
961 static void hue_correct_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
962 {
964 
966 
968 }
969 
971  CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Hue Correct"), /* name */
972  "HueCorrectModifierData", /* struct_name */
973  sizeof(HueCorrectModifierData), /* struct_size */
974  hue_correct_init_data, /* init_data */
975  hue_correct_free_data, /* free_data */
976  hue_correct_copy_data, /* copy_data */
977  hue_correct_apply, /* apply */
978 };
979 
982 /* -------------------------------------------------------------------- */
986 typedef struct BrightContrastThreadData {
987  float bright;
988  float contrast;
990 
992  int height,
993  unsigned char *rect,
994  float *rect_float,
995  unsigned char *mask_rect,
996  const float *mask_rect_float,
997  void *data_v)
998 {
1000  int x, y;
1001 
1002  float i;
1003  int c;
1004  float a, b, v;
1005  float brightness = data->bright / 100.0f;
1006  float contrast = data->contrast;
1007  float delta = contrast / 200.0f;
1008  /*
1009  * The algorithm is by Werner D. Streidt
1010  * (http://visca.com/ffactory/archives/5-99/msg00021.html)
1011  * Extracted of OpenCV demhist.c
1012  */
1013  if (contrast > 0) {
1014  a = 1.0f - delta * 2.0f;
1015  a = 1.0f / max_ff(a, FLT_EPSILON);
1016  b = a * (brightness - delta);
1017  }
1018  else {
1019  delta *= -1;
1020  a = max_ff(1.0f - delta * 2.0f, 0.0f);
1021  b = a * brightness + delta;
1022  }
1023 
1024  for (y = 0; y < height; y++) {
1025  for (x = 0; x < width; x++) {
1026  int pixel_index = (y * width + x) * 4;
1027 
1028  if (rect) {
1029  unsigned char *pixel = rect + pixel_index;
1030 
1031  for (c = 0; c < 3; c++) {
1032  i = (float)pixel[c] / 255.0f;
1033  v = a * i + b;
1034 
1035  if (mask_rect) {
1036  unsigned char *m = mask_rect + pixel_index;
1037  float t = (float)m[c] / 255.0f;
1038 
1039  v = (float)pixel[c] / 255.0f * (1.0f - t) + v * t;
1040  }
1041 
1042  pixel[c] = unit_float_to_uchar_clamp(v);
1043  }
1044  }
1045  else if (rect_float) {
1046  float *pixel = rect_float + pixel_index;
1047 
1048  for (c = 0; c < 3; c++) {
1049  i = pixel[c];
1050  v = a * i + b;
1051 
1052  if (mask_rect_float) {
1053  const float *m = mask_rect_float + pixel_index;
1054 
1055  pixel[c] = pixel[c] * (1.0f - m[c]) + v * m[c];
1056  }
1057  else {
1058  pixel[c] = v;
1059  }
1060  }
1061  }
1062  }
1063  }
1064 }
1065 
1066 static void brightcontrast_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
1067 {
1070 
1071  data.bright = bcmd->bright;
1072  data.contrast = bcmd->contrast;
1073 
1075 }
1076 
1078  CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Bright/Contrast"), /* name */
1079  "BrightContrastModifierData", /* struct_name */
1080  sizeof(BrightContrastModifierData), /* struct_size */
1081  NULL, /* init_data */
1082  NULL, /* free_data */
1083  NULL, /* copy_data */
1084  brightcontrast_apply, /* apply */
1085 };
1086 
1089 /* -------------------------------------------------------------------- */
1094  int height,
1095  unsigned char *rect,
1096  float *rect_float,
1097  unsigned char *mask_rect,
1098  const float *mask_rect_float,
1099  void *UNUSED(data_v))
1100 {
1101  int x, y;
1102 
1103  if (rect && !mask_rect) {
1104  return;
1105  }
1106 
1107  if (rect_float && !mask_rect_float) {
1108  return;
1109  }
1110 
1111  for (y = 0; y < height; y++) {
1112  for (x = 0; x < width; x++) {
1113  int pixel_index = (y * width + x) * 4;
1114 
1115  if (rect) {
1116  unsigned char *pixel = rect + pixel_index;
1117  unsigned char *mask_pixel = mask_rect + pixel_index;
1118  unsigned char mask = min_iii(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
1119 
1120  /* byte buffer is straight, so only affect on alpha itself,
1121  * this is the only way to alpha-over byte strip after
1122  * applying mask modifier.
1123  */
1124  pixel[3] = (float)(pixel[3] * mask) / 255.0f;
1125  }
1126  else if (rect_float) {
1127  int c;
1128  float *pixel = rect_float + pixel_index;
1129  const float *mask_pixel = mask_rect_float + pixel_index;
1130  float mask = min_fff(mask_pixel[0], mask_pixel[1], mask_pixel[2]);
1131 
1132  /* float buffers are premultiplied, so need to premul color
1133  * as well to make it easy to alpha-over masted strip.
1134  */
1135  for (c = 0; c < 4; c++) {
1136  pixel[c] = pixel[c] * mask;
1137  }
1138  }
1139  }
1140  }
1141 }
1142 
1143 static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *ibuf, ImBuf *mask)
1144 {
1145  // SequencerMaskModifierData *bcmd = (SequencerMaskModifierData *)smd;
1146 
1148  ibuf->planes = R_IMF_PLANES_RGBA;
1149 }
1150 
1152  CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Mask"), /* name */
1153  "SequencerMaskModifierData", /* struct_name */
1154  sizeof(SequencerMaskModifierData), /* struct_size */
1155  NULL, /* init_data */
1156  NULL, /* free_data */
1157  NULL, /* copy_data */
1158  maskmodifier_apply, /* apply */
1159 };
1160 
1163 /* -------------------------------------------------------------------- */
1167 typedef struct AvgLogLum {
1170  float al;
1171  float auto_key;
1172  float lav;
1173  float cav[4];
1174  float igm;
1176 
1178 {
1180  /* Same as tonemap compositor node. */
1182  tmmd->key = 0.18f;
1183  tmmd->offset = 1.0f;
1184  tmmd->gamma = 1.0f;
1185  tmmd->intensity = 0.0f;
1186  tmmd->contrast = 0.0f;
1187  tmmd->adaptation = 1.0f;
1188  tmmd->correction = 0.0f;
1189 }
1190 
1192  int height,
1193  unsigned char *rect,
1194  float *rect_float,
1195  unsigned char *mask_rect,
1196  const float *mask_rect_float,
1197  void *data_v)
1198 {
1199  AvgLogLum *avg = (AvgLogLum *)data_v;
1200  for (int y = 0; y < height; y++) {
1201  for (int x = 0; x < width; x++) {
1202  int pixel_index = (y * width + x) * 4;
1203  float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
1204  /* Get input value. */
1205  if (rect_float) {
1206  copy_v4_v4(input, &rect_float[pixel_index]);
1207  }
1208  else {
1209  straight_uchar_to_premul_float(input, &rect[pixel_index]);
1210  }
1213  /* Get mask value. */
1214  if (mask_rect_float) {
1215  copy_v3_v3(mask, mask_rect_float + pixel_index);
1216  }
1217  else if (mask_rect) {
1218  rgb_uchar_to_float(mask, mask_rect + pixel_index);
1219  }
1220  /* Apply correction. */
1221  mul_v3_fl(output, avg->al);
1222  float dr = output[0] + avg->tmmd->offset;
1223  float dg = output[1] + avg->tmmd->offset;
1224  float db = output[2] + avg->tmmd->offset;
1225  output[0] /= ((dr == 0.0f) ? 1.0f : dr);
1226  output[1] /= ((dg == 0.0f) ? 1.0f : dg);
1227  output[2] /= ((db == 0.0f) ? 1.0f : db);
1228  const float igm = avg->igm;
1229  if (igm != 0.0f) {
1230  output[0] = powf(max_ff(output[0], 0.0f), igm);
1231  output[1] = powf(max_ff(output[1], 0.0f), igm);
1232  output[2] = powf(max_ff(output[2], 0.0f), igm);
1233  }
1234  /* Apply mask. */
1235  output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
1236  output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
1237  output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
1238  /* Copy result back. */
1240  if (rect_float) {
1241  copy_v4_v4(&rect_float[pixel_index], output);
1242  }
1243  else {
1244  premul_float_to_straight_uchar(&rect[pixel_index], output);
1245  }
1246  }
1247  }
1248 }
1249 
1251  int height,
1252  unsigned char *rect,
1253  float *rect_float,
1254  unsigned char *mask_rect,
1255  const float *mask_rect_float,
1256  void *data_v)
1257 {
1258  AvgLogLum *avg = (AvgLogLum *)data_v;
1259  const float f = expf(-avg->tmmd->intensity);
1260  const float m = (avg->tmmd->contrast > 0.0f) ? avg->tmmd->contrast :
1261  (0.3f + 0.7f * powf(avg->auto_key, 1.4f));
1262  const float ic = 1.0f - avg->tmmd->correction, ia = 1.0f - avg->tmmd->adaptation;
1263  for (int y = 0; y < height; y++) {
1264  for (int x = 0; x < width; x++) {
1265  int pixel_index = (y * width + x) * 4;
1266  float input[4], output[4], mask[3] = {1.0f, 1.0f, 1.0f};
1267  /* Get input value. */
1268  if (rect_float) {
1269  copy_v4_v4(input, &rect_float[pixel_index]);
1270  }
1271  else {
1272  straight_uchar_to_premul_float(input, &rect[pixel_index]);
1273  }
1276  /* Get mask value. */
1277  if (mask_rect_float) {
1278  copy_v3_v3(mask, mask_rect_float + pixel_index);
1279  }
1280  else if (mask_rect) {
1281  rgb_uchar_to_float(mask, mask_rect + pixel_index);
1282  }
1283  /* Apply correction. */
1285  float I_l = output[0] + ic * (L - output[0]);
1286  float I_g = avg->cav[0] + ic * (avg->lav - avg->cav[0]);
1287  float I_a = I_l + ia * (I_g - I_l);
1288  output[0] /= (output[0] + powf(f * I_a, m));
1289  I_l = output[1] + ic * (L - output[1]);
1290  I_g = avg->cav[1] + ic * (avg->lav - avg->cav[1]);
1291  I_a = I_l + ia * (I_g - I_l);
1292  output[1] /= (output[1] + powf(f * I_a, m));
1293  I_l = output[2] + ic * (L - output[2]);
1294  I_g = avg->cav[2] + ic * (avg->lav - avg->cav[2]);
1295  I_a = I_l + ia * (I_g - I_l);
1296  output[2] /= (output[2] + powf(f * I_a, m));
1297  /* Apply mask. */
1298  output[0] = input[0] * (1.0f - mask[0]) + output[0] * mask[0];
1299  output[1] = input[1] * (1.0f - mask[1]) + output[1] * mask[1];
1300  output[2] = input[2] * (1.0f - mask[2]) + output[2] * mask[2];
1301  /* Copy result back. */
1303  if (rect_float) {
1304  copy_v4_v4(&rect_float[pixel_index], output);
1305  }
1306  else {
1307  premul_float_to_straight_uchar(&rect[pixel_index], output);
1308  }
1309  }
1310  }
1311 }
1312 
1313 static void tonemapmodifier_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
1314 {
1316  AvgLogLum data;
1317  data.tmmd = tmmd;
1318  data.colorspace = (ibuf->rect_float != NULL) ? ibuf->float_colorspace : ibuf->rect_colorspace;
1319  float lsum = 0.0f;
1320  int p = ibuf->x * ibuf->y;
1321  float *fp = ibuf->rect_float;
1322  unsigned char *cp = (unsigned char *)ibuf->rect;
1323  float avl, maxl = -FLT_MAX, minl = FLT_MAX;
1324  const float sc = 1.0f / p;
1325  float Lav = 0.0f;
1326  float cav[4] = {0.0f, 0.0f, 0.0f, 0.0f};
1327  while (p--) {
1328  float pixel[4];
1329  if (fp != NULL) {
1330  copy_v4_v4(pixel, fp);
1331  }
1332  else {
1333  straight_uchar_to_premul_float(pixel, cp);
1334  }
1336  float L = IMB_colormanagement_get_luminance(pixel);
1337  Lav += L;
1338  add_v3_v3(cav, pixel);
1339  lsum += logf(max_ff(L, 0.0f) + 1e-5f);
1340  maxl = (L > maxl) ? L : maxl;
1341  minl = (L < minl) ? L : minl;
1342  if (fp != NULL) {
1343  fp += 4;
1344  }
1345  else {
1346  cp += 4;
1347  }
1348  }
1349  data.lav = Lav * sc;
1350  mul_v3_v3fl(data.cav, cav, sc);
1351  maxl = logf(maxl + 1e-5f);
1352  minl = logf(minl + 1e-5f);
1353  avl = lsum * sc;
1354  data.auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.0f;
1355  float al = expf(avl);
1356  data.al = (al == 0.0f) ? 0.0f : (tmmd->key / al);
1357  data.igm = (tmmd->gamma == 0.0f) ? 1.0f : (1.0f / tmmd->gamma);
1358 
1359  if (tmmd->type == SEQ_TONEMAP_RD_PHOTORECEPTOR) {
1361  }
1362  else /* if (tmmd->type == SEQ_TONEMAP_RD_SIMPLE) */ {
1364  }
1365 }
1366 
1368  CTX_N_(BLT_I18NCONTEXT_ID_SEQUENCE, "Tonemap"), /* name */
1369  "SequencerTonemapModifierData", /* struct_name */
1370  sizeof(SequencerTonemapModifierData), /* struct_size */
1371  tonemapmodifier_init_data, /* init_data */
1372  NULL, /* free_data */
1373  NULL, /* copy_data */
1374  tonemapmodifier_apply, /* apply */
1375 };
1376 
1379 /* -------------------------------------------------------------------- */
1384 {
1385 #define INIT_TYPE(typeName) (modifiersTypes[seqModifierType_##typeName] = &seqModifier_##typeName)
1386 
1387  INIT_TYPE(ColorBalance);
1388  INIT_TYPE(Curves);
1389  INIT_TYPE(HueCorrect);
1391  INIT_TYPE(Mask);
1392  INIT_TYPE(WhiteBalance);
1393  INIT_TYPE(Tonemap);
1394 
1395 #undef INIT_TYPE
1396 }
1397 
1399 {
1400  if (!modifierTypesInit) {
1402  modifierTypesInit = true;
1403  }
1404 
1405  return modifiersTypes[type];
1406 }
1407 
1409 {
1410  SequenceModifierData *smd;
1412 
1413  smd = MEM_callocN(smti->struct_size, "sequence modifier");
1414 
1415  smd->type = type;
1417 
1418  if (!name || !name[0]) {
1419  BLI_strncpy(smd->name, smti->name, sizeof(smd->name));
1420  }
1421  else {
1422  BLI_strncpy(smd->name, name, sizeof(smd->name));
1423  }
1424 
1425  BLI_addtail(&seq->modifiers, smd);
1426 
1427  SEQ_modifier_unique_name(seq, smd);
1428 
1429  if (smti->init_data) {
1430  smti->init_data(smd);
1431  }
1432 
1433  return smd;
1434 }
1435 
1437 {
1438  if (BLI_findindex(&seq->modifiers, smd) == -1) {
1439  return false;
1440  }
1441 
1442  BLI_remlink(&seq->modifiers, smd);
1443  SEQ_modifier_free(smd);
1444 
1445  return true;
1446 }
1447 
1449 {
1450  SequenceModifierData *smd, *smd_next;
1451 
1452  for (smd = seq->modifiers.first; smd; smd = smd_next) {
1453  smd_next = smd->next;
1454  SEQ_modifier_free(smd);
1455  }
1456 
1458 }
1459 
1461 {
1463 
1464  if (smti && smti->free_data) {
1465  smti->free_data(smd);
1466  }
1467 
1468  MEM_freeN(smd);
1469 }
1470 
1472 {
1474 
1475  BLI_uniquename(&seq->modifiers,
1476  smd,
1478  '.',
1479  offsetof(SequenceModifierData, name),
1480  sizeof(smd->name));
1481 }
1482 
1484 {
1485  return BLI_findstring(&(seq->modifiers), name, offsetof(SequenceModifierData, name));
1486 }
1487 
1489  Sequence *seq,
1490  ImBuf *ibuf,
1491  int timeline_frame)
1492 {
1493  SequenceModifierData *smd;
1494  ImBuf *processed_ibuf = ibuf;
1495 
1496  if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
1497  processed_ibuf = IMB_dupImBuf(ibuf);
1498  SEQ_render_imbuf_from_sequencer_space(context->scene, processed_ibuf);
1499  }
1500 
1501  for (smd = seq->modifiers.first; smd; smd = smd->next) {
1503 
1504  /* could happen if modifier is being removed or not exists in current version of blender */
1505  if (!smti) {
1506  continue;
1507  }
1508 
1509  /* modifier is muted, do nothing */
1510  if (smd->flag & SEQUENCE_MODIFIER_MUTE) {
1511  continue;
1512  }
1513 
1514  if (smti->apply) {
1515  int frame_offset;
1516  if (smd->mask_time == SEQUENCE_MASK_TIME_RELATIVE) {
1517  frame_offset = seq->start;
1518  }
1519  else /* if (smd->mask_time == SEQUENCE_MASK_TIME_ABSOLUTE) */ {
1520  frame_offset = smd->mask_id ? ((Mask *)smd->mask_id)->sfra : 0;
1521  }
1522 
1524  smd, context, timeline_frame, frame_offset, ibuf->rect_float != NULL);
1525 
1526  if (processed_ibuf == ibuf) {
1527  processed_ibuf = IMB_dupImBuf(ibuf);
1528  }
1529 
1530  smti->apply(smd, processed_ibuf, mask);
1531 
1532  if (mask) {
1534  }
1535  }
1536  }
1537 
1538  if (seq->modifiers.first && (seq->flag & SEQ_USE_LINEAR_MODIFIERS)) {
1539  seq_imbuf_to_sequencer_space(context->scene, processed_ibuf, false);
1540  }
1541 
1542  return processed_ibuf;
1543 }
1544 
1546 {
1547  SequenceModifierData *smd;
1548 
1549  for (smd = seq->modifiers.first; smd; smd = smd->next) {
1550  SequenceModifierData *smdn;
1552 
1553  smdn = MEM_dupallocN(smd);
1554 
1555  if (smti && smti->copy_data) {
1556  smti->copy_data(smdn, smd);
1557  }
1558 
1559  smdn->next = smdn->prev = NULL;
1560  BLI_addtail(&seqn->modifiers, smdn);
1561  }
1562 }
1563 
1565 {
1567 }
1568 
1571 /* -------------------------------------------------------------------- */
1576 {
1577  LISTBASE_FOREACH (SequenceModifierData *, smd, modbase) {
1578  const SequenceModifierTypeInfo *smti = SEQ_modifier_type_info_get(smd->type);
1579 
1580  if (smti) {
1581  BLO_write_struct_by_name(writer, smti->struct_name, smd);
1582 
1583  if (smd->type == seqModifierType_Curves) {
1584  CurvesModifierData *cmd = (CurvesModifierData *)smd;
1585 
1587  }
1588  else if (smd->type == seqModifierType_HueCorrect) {
1590 
1592  }
1593  }
1594  else {
1595  BLO_write_struct(writer, SequenceModifierData, smd);
1596  }
1597  }
1598 }
1599 
1601 {
1602  BLO_read_list(reader, lb);
1603 
1604  LISTBASE_FOREACH (SequenceModifierData *, smd, lb) {
1605  if (smd->mask_sequence) {
1606  BLO_read_data_address(reader, &smd->mask_sequence);
1607  }
1608 
1609  if (smd->type == seqModifierType_Curves) {
1610  CurvesModifierData *cmd = (CurvesModifierData *)smd;
1611 
1613  }
1614  else if (smd->type == seqModifierType_HueCorrect) {
1616 
1618  }
1619  }
1620 }
1621 
1623 {
1624  LISTBASE_FOREACH (SequenceModifierData *, smd, lb) {
1625  if (smd->mask_id) {
1626  BLO_read_id_address(reader, scene->id.lib, &smd->mask_id);
1627  }
1628  }
1629 }
1630 
typedef float(TangentPoint)[2]
void BKE_curvemapping_evaluate_premulRGBF(const struct CurveMapping *cumap, float vecout[3], const float vecin[3])
void BKE_curvemapping_premultiply(struct CurveMapping *cumap, bool restore)
Definition: colortools.c:782
void BKE_curvemapping_free_data(struct CurveMapping *cumap)
Definition: colortools.c:83
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1235
void BKE_curvemapping_set_black_white(struct CurveMapping *cumap, const float black[3], const float white[3])
Definition: colortools.c:152
void BKE_curvemapping_set_defaults(struct CurveMapping *cumap, int tot, float minx, float miny, float maxx, float maxy)
Definition: colortools.c:37
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value)
void BKE_curvemapping_blend_read(struct BlendDataReader *reader, struct CurveMapping *cumap)
Definition: colortools.c:1300
void BKE_curvemap_reset(struct CurveMap *cuma, const struct rctf *clipr, int preset, int slope)
void BKE_curvemapping_blend_write(struct BlendWriter *writer, const struct CurveMapping *cumap)
@ CURVEMAP_SLOPE_POSITIVE
void BKE_curvemapping_copy_data(struct CurveMapping *target, const struct CurveMapping *cumap)
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE int min_iii(int a, int b, int c)
MINLINE float min_fff(float a, float b, float c)
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4])
void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v)
Definition: math_color.c:208
void hsv_to_rgb(float h, float s, float v, float *r_r, float *r_g, float *r_b)
Definition: math_color.c:13
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3])
Definition: math_color.c:376
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3])
Definition: math_color.c:391
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4])
#define MINLINE
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
bool BLI_uniquename(struct ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_len)
Definition: string_utils.c:309
#define UNUSED(x)
#define ELEM(...)
#define BLO_read_data_address(reader, ptr_p)
void BLO_write_struct_by_name(BlendWriter *writer, const char *struct_name, const void *data_ptr)
Definition: writefile.c:1494
#define BLO_write_struct(writer, struct_name, data_ptr)
void BLO_read_list(BlendDataReader *reader, struct ListBase *list)
Definition: readfile.c:5172
#define BLO_read_id_address(reader, lib, id_ptr_p)
#define CTX_N_(context, msgid)
#define BLT_I18NCONTEXT_ID_SEQUENCE
#define CTX_DATA_(context, msgid)
@ CURVE_PRESET_MID9
#define R_IMF_PLANES_RGBA
@ SEQ_TYPE_SOUND_RAM
@ SEQ_TYPE_SOUND_HD
#define SEQ_COLOR_BALANCE_INVERSE_GAMMA
@ SEQUENCE_MODIFIER_MUTE
@ SEQUENCE_MODIFIER_EXPANDED
struct WhiteBalanceModifierData WhiteBalanceModifierData
@ NUM_SEQUENCE_MODIFIER_TYPES
@ seqModifierType_Curves
@ seqModifierType_HueCorrect
@ SEQUENCE_MASK_INPUT_STRIP
@ SEQUENCE_MASK_INPUT_ID
struct ColorBalanceModifierData ColorBalanceModifierData
struct CurvesModifierData CurvesModifierData
#define SEQ_COLOR_BALANCE_INVERSE_POWER
struct SequencerTonemapModifierData SequencerTonemapModifierData
@ SEQ_TONEMAP_RD_PHOTORECEPTOR
#define SEQ_COLOR_BALANCE_INVERSE_GAIN
@ SEQUENCE_MASK_TIME_RELATIVE
@ SEQ_COLOR_BALANCE_METHOD_LIFTGAMMAGAIN
@ SEQ_USE_LINEAR_MODIFIERS
struct HueCorrectModifierData HueCorrectModifierData
#define SEQ_COLOR_BALANCE_INVERSE_SLOPE
#define SEQ_COLOR_BALANCE_INVERSE_LIFT
struct BrightContrastModifierData BrightContrastModifierData
#define SEQ_COLOR_BALANCE_INVERSE_OFFSET
struct SequencerMaskModifierData SequencerMaskModifierData
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3])
void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], struct ColorSpace *colorspace)
void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], struct ColorSpace *colorspace)
void IMB_float_from_rect(struct ImBuf *ibuf)
Definition: divers.c:805
bool imb_addrectfloatImBuf(struct ImBuf *ibuf, const unsigned int channels)
Definition: allocimbuf.c:367
struct ImBuf * IMB_dupImBuf(const struct ImBuf *ibuf1)
void IMB_rect_from_float(struct ImBuf *ibuf)
Definition: divers.c:696
void imb_freerectImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:97
void IMB_processor_apply_threaded(int buffer_lines, int handle_size, void *init_customdata, void(init_handle)(void *handle, int start_line, int tot_line, void *customdata), void *(do_thread)(void *))
Definition: imageprocess.c:355
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
static void init_data(ModifierData *md)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product BrightContrast
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static void mul(btAlignedObjectArray< T > &items, const Q &value)
#define logf(x)
Definition: cuda/compat.h:105
#define expf(x)
Definition: cuda/compat.h:106
#define powf(x, y)
Definition: cuda/compat.h:103
Scene scene
void * user_data
SyclQueue void void size_t num_bytes void
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
ccl_global KernelShaderEvalInput * input
const int state
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
ccl_device_inline float3 pow(float3 v, float e)
Definition: math_float3.h:533
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
#define L
#define floorf(x)
Definition: metal/compat.h:224
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static const pxr::TfToken rgba("rgba", pxr::TfToken::Immortal)
ImBuf * seq_render_mask(const SeqRenderData *context, Mask *mask, float frame_index, bool make_float)
Definition: render.c:1238
ImBuf * seq_render_strip(const SeqRenderData *context, SeqRenderState *state, Sequence *seq, float timeline_frame)
Definition: render.c:1723
void seq_render_state_init(SeqRenderState *state)
Definition: render.c:231
void seq_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make_float)
Definition: render.c:101
void SEQ_render_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf)
Definition: render.c:167
struct ColorBalanceThread ColorBalanceThread
static void 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)
static void curves_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
void SEQ_modifier_blend_write(BlendWriter *writer, ListBase *modbase)
bool SEQ_modifier_remove(Sequence *seq, SequenceModifierData *smd)
struct BrightContrastThreadData BrightContrastThreadData
static void tonemapmodifier_init_data(SequenceModifierData *smd)
static void 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)
void(* modifier_apply_threaded_cb)(int width, int height, unsigned char *rect, float *rect_float, unsigned char *mask_rect, const float *mask_rect_float, void *data_v)
struct WhiteBalanceThreadData WhiteBalanceThreadData
static void hue_correct_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static void modifier_apply_threaded(ImBuf *ibuf, ImBuf *mask, modifier_apply_threaded_cb apply_callback, void *user_data)
SequenceModifierData * SEQ_modifier_new(Sequence *seq, const char *name, int type)
static StripColorBalance calc_cb_lgg(StripColorBalance *cb_)
static void make_cb_table_float_lgg(float lift, float gain, float gamma, float *table, float mul)
static void hue_correct_free_data(SequenceModifierData *smd)
void SEQ_modifier_free(SequenceModifierData *smd)
ImBuf * SEQ_modifier_apply_stack(const SeqRenderData *context, Sequence *seq, ImBuf *ibuf, int timeline_frame)
static void tonemapmodifier_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
MINLINE float color_balance_fl_lgg(float in, const float lift, const float gain, const float gamma, const float mul)
static void maskmodifier_apply(struct SequenceModifierData *UNUSED(smd), ImBuf *ibuf, ImBuf *mask)
static void sequence_modifier_type_info_init(void)
void SEQ_modifier_blend_read_lib(BlendLibReader *reader, Scene *scene, ListBase *lb)
static void * modifier_do_thread(void *thread_data_v)
static void modifier_color_balance_apply(StripColorBalance *cb, ImBuf *ibuf, float mul, bool make_float, ImBuf *mask_input)
#define INIT_TYPE(typeName)
static SequenceModifierTypeInfo seqModifier_HueCorrect
static void brightcontrast_apply(struct SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
MINLINE float color_balance_fl_sop(float in, const float slope, const float offset, const float power, const float pivot, float mul)
struct ModifierInitData ModifierInitData
static ImBuf * modifier_mask_get(SequenceModifierData *smd, const SeqRenderData *context, int timeline_frame, int fra_offset, bool make_float)
static void 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)
SequenceModifierData * SEQ_modifier_find_by_name(Sequence *seq, const char *name)
static void hue_correct_init_data(SequenceModifierData *smd)
static SequenceModifierTypeInfo seqModifier_Curves
void SEQ_modifier_clear(Sequence *seq)
static void hue_correct_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
static void curves_copy_data(SequenceModifierData *target, SequenceModifierData *smd)
struct AvgLogLum AvgLogLum
static void 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))
static void curves_free_data(SequenceModifierData *smd)
void SEQ_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb)
static void 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)
static SequenceModifierTypeInfo seqModifier_Mask
static SequenceModifierTypeInfo seqModifier_ColorBalance
static StripColorBalance calc_cb(StripColorBalance *cb_)
static SequenceModifierTypeInfo seqModifier_WhiteBalance
static SequenceModifierTypeInfo seqModifier_BrightContrast
static void * color_balance_do_thread(void *thread_data_v)
const SequenceModifierTypeInfo * SEQ_modifier_type_info_get(int type)
static void curves_init_data(SequenceModifierData *smd)
static SequenceModifierTypeInfo * modifiersTypes[NUM_SEQUENCE_MODIFIER_TYPES]
void SEQ_modifier_list_copy(Sequence *seqn, Sequence *seq)
static void whiteBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
static void color_balance_byte_float(StripColorBalance *cb_, unsigned char *rect, float *rect_float, unsigned char *mask_rect, int width, int height, float mul)
static void whiteBalance_init_data(SequenceModifierData *smd)
static SequenceModifierTypeInfo seqModifier_Tonemap
static void modifier_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
int SEQ_sequence_supports_modifiers(Sequence *seq)
struct ColorBalanceInitData ColorBalanceInitData
static StripColorBalance calc_cb_sop(StripColorBalance *cb_)
static ImBuf * modifier_render_mask_input(const SeqRenderData *context, int mask_input_type, Sequence *mask_sequence, Mask *mask_id, int timeline_frame, int fra_offset, bool make_float)
struct ModifierThread ModifierThread
static void color_balance_byte_byte(StripColorBalance *cb_, unsigned char *rect, unsigned char *mask_rect, int width, int height, float mul)
static void colorBalance_init_data(SequenceModifierData *smd)
static void color_balance_float_float(StripColorBalance *cb_, float *rect_float, const float *mask_rect_float, int width, int height, float mul)
static void 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)
static void colorBalance_apply(SequenceModifierData *smd, ImBuf *ibuf, ImBuf *mask)
void SEQ_modifier_unique_name(Sequence *seq, SequenceModifierData *smd)
static void color_balance_init_handle(void *handle_v, int start_line, int tot_line, void *init_data_v)
static void make_cb_table_float_sop(float slope, float offset, float power, float pivot, float *table, float mul)
static void 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)
static bool modifierTypesInit
SequencerTonemapModifierData * tmmd
struct ColorSpace * colorspace
StripColorBalance color_balance
char name[MAX_COLORSPACE_NAME]
CurveMap cm[4]
struct CurveMapping curve_mapping
struct CurveMapping curve_mapping
struct Library * lib
Definition: DNA_ID.h:372
struct ColorSpace * rect_colorspace
unsigned char planes
unsigned int * rect
float * rect_float
struct ColorSpace * float_colorspace
void * first
Definition: DNA_listBase.h:31
int sfra
modifier_apply_threaded_cb apply_callback
modifier_apply_threaded_cb apply_callback
unsigned char * mask_rect
struct SequenceModifierData * next
struct SequenceModifierData * prev
struct Sequence * mask_sequence
void(* init_data)(struct SequenceModifierData *smd)
Definition: SEQ_modifier.h:35
void(* free_data)(struct SequenceModifierData *smd)
Definition: SEQ_modifier.h:41
void(* apply)(struct SequenceModifierData *smd, struct ImBuf *ibuf, struct ImBuf *mask)
Definition: SEQ_modifier.h:47
void(* copy_data)(struct SequenceModifierData *smd, struct SequenceModifierData *target)
Definition: SEQ_modifier.h:44
ListBase modifiers