Cleanup: style, use braces for imbuf
[blender.git] / source / blender / imbuf / intern / divers.c
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) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  * allocimbuf.c
19  */
20
21 /** \file
22  * \ingroup imbuf
23  */
24
25 #include "BLI_math.h"
26 #include "BLI_utildefines.h"
27
28 #include "imbuf.h"
29 #include "IMB_imbuf_types.h"
30 #include "IMB_imbuf.h"
31 #include "IMB_filter.h"
32
33 #include "IMB_colormanagement.h"
34 #include "IMB_colormanagement_intern.h"
35
36 #include "MEM_guardedalloc.h"
37
38 /************************* Floyd-Steinberg dithering *************************/
39
40 typedef struct DitherContext {
41   float dither;
42 } DitherContext;
43
44 static DitherContext *create_dither_context(float dither)
45 {
46   DitherContext *di;
47
48   di = MEM_mallocN(sizeof(DitherContext), "dithering context");
49   di->dither = dither;
50
51   return di;
52 }
53
54 static void clear_dither_context(DitherContext *di)
55 {
56   MEM_freeN(di);
57 }
58
59 /************************* Generic Buffer Conversion *************************/
60
61 MINLINE void ushort_to_byte_v4(uchar b[4], const unsigned short us[4])
62 {
63   b[0] = unit_ushort_to_uchar(us[0]);
64   b[1] = unit_ushort_to_uchar(us[1]);
65   b[2] = unit_ushort_to_uchar(us[2]);
66   b[3] = unit_ushort_to_uchar(us[3]);
67 }
68
69 MINLINE unsigned char ftochar(float value)
70 {
71   return unit_float_to_uchar_clamp(value);
72 }
73
74 MINLINE void ushort_to_byte_dither_v4(
75     uchar b[4], const unsigned short us[4], DitherContext *di, float s, float t)
76 {
77 #define USHORTTOFLOAT(val) ((float)val / 65535.0f)
78   float dither_value = dither_random_value(s, t) * 0.005f * di->dither;
79
80   b[0] = ftochar(dither_value + USHORTTOFLOAT(us[0]));
81   b[1] = ftochar(dither_value + USHORTTOFLOAT(us[1]));
82   b[2] = ftochar(dither_value + USHORTTOFLOAT(us[2]));
83   b[3] = unit_ushort_to_uchar(us[3]);
84
85 #undef USHORTTOFLOAT
86 }
87
88 MINLINE void float_to_byte_dither_v4(
89     uchar b[4], const float f[4], DitherContext *di, float s, float t)
90 {
91   float dither_value = dither_random_value(s, t) * 0.005f * di->dither;
92
93   b[0] = ftochar(dither_value + f[0]);
94   b[1] = ftochar(dither_value + f[1]);
95   b[2] = ftochar(dither_value + f[2]);
96   b[3] = unit_float_to_uchar_clamp(f[3]);
97 }
98
99 /* float to byte pixels, output 4-channel RGBA */
100 void IMB_buffer_byte_from_float(uchar *rect_to,
101                                 const float *rect_from,
102                                 int channels_from,
103                                 float dither,
104                                 int profile_to,
105                                 int profile_from,
106                                 bool predivide,
107                                 int width,
108                                 int height,
109                                 int stride_to,
110                                 int stride_from)
111 {
112   float tmp[4];
113   int x, y;
114   DitherContext *di = NULL;
115   float inv_width = 1.0f / width;
116   float inv_height = 1.0f / height;
117
118   /* we need valid profiles */
119   BLI_assert(profile_to != IB_PROFILE_NONE);
120   BLI_assert(profile_from != IB_PROFILE_NONE);
121
122   if (dither) {
123     di = create_dither_context(dither);
124   }
125
126   for (y = 0; y < height; y++) {
127     float t = y * inv_height;
128
129     if (channels_from == 1) {
130       /* single channel input */
131       const float *from = rect_from + ((size_t)stride_from) * y;
132       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
133
134       for (x = 0; x < width; x++, from++, to += 4) {
135         to[0] = to[1] = to[2] = to[3] = unit_float_to_uchar_clamp(from[0]);
136       }
137     }
138     else if (channels_from == 3) {
139       /* RGB input */
140       const float *from = rect_from + ((size_t)stride_from) * y * 3;
141       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
142
143       if (profile_to == profile_from) {
144         /* no color space conversion */
145         for (x = 0; x < width; x++, from += 3, to += 4) {
146           rgb_float_to_uchar(to, from);
147           to[3] = 255;
148         }
149       }
150       else if (profile_to == IB_PROFILE_SRGB) {
151         /* convert from linear to sRGB */
152         for (x = 0; x < width; x++, from += 3, to += 4) {
153           linearrgb_to_srgb_v3_v3(tmp, from);
154           rgb_float_to_uchar(to, tmp);
155           to[3] = 255;
156         }
157       }
158       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
159         /* convert from sRGB to linear */
160         for (x = 0; x < width; x++, from += 3, to += 4) {
161           srgb_to_linearrgb_v3_v3(tmp, from);
162           rgb_float_to_uchar(to, tmp);
163           to[3] = 255;
164         }
165       }
166     }
167     else if (channels_from == 4) {
168       /* RGBA input */
169       const float *from = rect_from + ((size_t)stride_from) * y * 4;
170       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
171
172       if (profile_to == profile_from) {
173         float straight[4];
174
175         /* no color space conversion */
176         if (dither && predivide) {
177           for (x = 0; x < width; x++, from += 4, to += 4) {
178             premul_to_straight_v4_v4(straight, from);
179             float_to_byte_dither_v4(to, straight, di, (float)x * inv_width, t);
180           }
181         }
182         else if (dither) {
183           for (x = 0; x < width; x++, from += 4, to += 4) {
184             float_to_byte_dither_v4(to, from, di, (float)x * inv_width, t);
185           }
186         }
187         else if (predivide) {
188           for (x = 0; x < width; x++, from += 4, to += 4) {
189             premul_to_straight_v4_v4(straight, from);
190             rgba_float_to_uchar(to, straight);
191           }
192         }
193         else {
194           for (x = 0; x < width; x++, from += 4, to += 4) {
195             rgba_float_to_uchar(to, from);
196           }
197         }
198       }
199       else if (profile_to == IB_PROFILE_SRGB) {
200         /* convert from linear to sRGB */
201         unsigned short us[4];
202         float straight[4];
203
204         if (dither && predivide) {
205           for (x = 0; x < width; x++, from += 4, to += 4) {
206             premul_to_straight_v4_v4(straight, from);
207             linearrgb_to_srgb_ushort4(us, from);
208             ushort_to_byte_dither_v4(to, us, di, (float)x * inv_width, t);
209           }
210         }
211         else if (dither) {
212           for (x = 0; x < width; x++, from += 4, to += 4) {
213             linearrgb_to_srgb_ushort4(us, from);
214             ushort_to_byte_dither_v4(to, us, di, (float)x * inv_width, t);
215           }
216         }
217         else if (predivide) {
218           for (x = 0; x < width; x++, from += 4, to += 4) {
219             premul_to_straight_v4_v4(straight, from);
220             linearrgb_to_srgb_ushort4(us, from);
221             ushort_to_byte_v4(to, us);
222           }
223         }
224         else {
225           for (x = 0; x < width; x++, from += 4, to += 4) {
226             linearrgb_to_srgb_ushort4(us, from);
227             ushort_to_byte_v4(to, us);
228           }
229         }
230       }
231       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
232         /* convert from sRGB to linear */
233         if (dither && predivide) {
234           for (x = 0; x < width; x++, from += 4, to += 4) {
235             srgb_to_linearrgb_predivide_v4(tmp, from);
236             float_to_byte_dither_v4(to, tmp, di, (float)x * inv_width, t);
237           }
238         }
239         else if (dither) {
240           for (x = 0; x < width; x++, from += 4, to += 4) {
241             srgb_to_linearrgb_v4(tmp, from);
242             float_to_byte_dither_v4(to, tmp, di, (float)x * inv_width, t);
243           }
244         }
245         else if (predivide) {
246           for (x = 0; x < width; x++, from += 4, to += 4) {
247             srgb_to_linearrgb_predivide_v4(tmp, from);
248             rgba_float_to_uchar(to, tmp);
249           }
250         }
251         else {
252           for (x = 0; x < width; x++, from += 4, to += 4) {
253             srgb_to_linearrgb_v4(tmp, from);
254             rgba_float_to_uchar(to, tmp);
255           }
256         }
257       }
258     }
259   }
260
261   if (dither) {
262     clear_dither_context(di);
263   }
264 }
265
266 /* float to byte pixels, output 4-channel RGBA */
267 void IMB_buffer_byte_from_float_mask(uchar *rect_to,
268                                      const float *rect_from,
269                                      int channels_from,
270                                      float dither,
271                                      bool predivide,
272                                      int width,
273                                      int height,
274                                      int stride_to,
275                                      int stride_from,
276                                      char *mask)
277 {
278   int x, y;
279   DitherContext *di = NULL;
280   float inv_width = 1.0f / width, inv_height = 1.0f / height;
281
282   if (dither) {
283     di = create_dither_context(dither);
284   }
285
286   for (y = 0; y < height; y++) {
287     float t = y * inv_height;
288
289     if (channels_from == 1) {
290       /* single channel input */
291       const float *from = rect_from + ((size_t)stride_from) * y;
292       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
293
294       for (x = 0; x < width; x++, from++, to += 4) {
295         if (*mask++ == FILTER_MASK_USED) {
296           to[0] = to[1] = to[2] = to[3] = unit_float_to_uchar_clamp(from[0]);
297         }
298       }
299     }
300     else if (channels_from == 3) {
301       /* RGB input */
302       const float *from = rect_from + ((size_t)stride_from) * y * 3;
303       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
304
305       for (x = 0; x < width; x++, from += 3, to += 4) {
306         if (*mask++ == FILTER_MASK_USED) {
307           rgb_float_to_uchar(to, from);
308           to[3] = 255;
309         }
310       }
311     }
312     else if (channels_from == 4) {
313       /* RGBA input */
314       const float *from = rect_from + ((size_t)stride_from) * y * 4;
315       uchar *to = rect_to + ((size_t)stride_to) * y * 4;
316
317       float straight[4];
318
319       if (dither && predivide) {
320         for (x = 0; x < width; x++, from += 4, to += 4) {
321           if (*mask++ == FILTER_MASK_USED) {
322             premul_to_straight_v4_v4(straight, from);
323             float_to_byte_dither_v4(to, straight, di, (float)x * inv_width, t);
324           }
325         }
326       }
327       else if (dither) {
328         for (x = 0; x < width; x++, from += 4, to += 4) {
329           if (*mask++ == FILTER_MASK_USED) {
330             float_to_byte_dither_v4(to, from, di, (float)x * inv_width, t);
331           }
332         }
333       }
334       else if (predivide) {
335         for (x = 0; x < width; x++, from += 4, to += 4) {
336           if (*mask++ == FILTER_MASK_USED) {
337             premul_to_straight_v4_v4(straight, from);
338             rgba_float_to_uchar(to, straight);
339           }
340         }
341       }
342       else {
343         for (x = 0; x < width; x++, from += 4, to += 4) {
344           if (*mask++ == FILTER_MASK_USED) {
345             rgba_float_to_uchar(to, from);
346           }
347         }
348       }
349     }
350   }
351
352   if (dither) {
353     clear_dither_context(di);
354   }
355 }
356
357 /* byte to float pixels, input and output 4-channel RGBA  */
358 void IMB_buffer_float_from_byte(float *rect_to,
359                                 const uchar *rect_from,
360                                 int profile_to,
361                                 int profile_from,
362                                 bool predivide,
363                                 int width,
364                                 int height,
365                                 int stride_to,
366                                 int stride_from)
367 {
368   float tmp[4];
369   int x, y;
370
371   /* we need valid profiles */
372   BLI_assert(profile_to != IB_PROFILE_NONE);
373   BLI_assert(profile_from != IB_PROFILE_NONE);
374
375   /* RGBA input */
376   for (y = 0; y < height; y++) {
377     const uchar *from = rect_from + stride_from * y * 4;
378     float *to = rect_to + ((size_t)stride_to) * y * 4;
379
380     if (profile_to == profile_from) {
381       /* no color space conversion */
382       for (x = 0; x < width; x++, from += 4, to += 4) {
383         rgba_uchar_to_float(to, from);
384       }
385     }
386     else if (profile_to == IB_PROFILE_LINEAR_RGB) {
387       /* convert sRGB to linear */
388       if (predivide) {
389         for (x = 0; x < width; x++, from += 4, to += 4) {
390           srgb_to_linearrgb_uchar4_predivide(to, from);
391         }
392       }
393       else {
394         for (x = 0; x < width; x++, from += 4, to += 4) {
395           srgb_to_linearrgb_uchar4(to, from);
396         }
397       }
398     }
399     else if (profile_to == IB_PROFILE_SRGB) {
400       /* convert linear to sRGB */
401       if (predivide) {
402         for (x = 0; x < width; x++, from += 4, to += 4) {
403           rgba_uchar_to_float(tmp, from);
404           linearrgb_to_srgb_predivide_v4(to, tmp);
405         }
406       }
407       else {
408         for (x = 0; x < width; x++, from += 4, to += 4) {
409           rgba_uchar_to_float(tmp, from);
410           linearrgb_to_srgb_v4(to, tmp);
411         }
412       }
413     }
414   }
415 }
416
417 /* float to float pixels, output 4-channel RGBA */
418 void IMB_buffer_float_from_float(float *rect_to,
419                                  const float *rect_from,
420                                  int channels_from,
421                                  int profile_to,
422                                  int profile_from,
423                                  bool predivide,
424                                  int width,
425                                  int height,
426                                  int stride_to,
427                                  int stride_from)
428 {
429   int x, y;
430
431   /* we need valid profiles */
432   BLI_assert(profile_to != IB_PROFILE_NONE);
433   BLI_assert(profile_from != IB_PROFILE_NONE);
434
435   if (channels_from == 1) {
436     /* single channel input */
437     for (y = 0; y < height; y++) {
438       const float *from = rect_from + ((size_t)stride_from) * y;
439       float *to = rect_to + ((size_t)stride_to) * y * 4;
440
441       for (x = 0; x < width; x++, from++, to += 4) {
442         to[0] = to[1] = to[2] = to[3] = from[0];
443       }
444     }
445   }
446   else if (channels_from == 3) {
447     /* RGB input */
448     for (y = 0; y < height; y++) {
449       const float *from = rect_from + ((size_t)stride_from) * y * 3;
450       float *to = rect_to + ((size_t)stride_to) * y * 4;
451
452       if (profile_to == profile_from) {
453         /* no color space conversion */
454         for (x = 0; x < width; x++, from += 3, to += 4) {
455           copy_v3_v3(to, from);
456           to[3] = 1.0f;
457         }
458       }
459       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
460         /* convert from sRGB to linear */
461         for (x = 0; x < width; x++, from += 3, to += 4) {
462           srgb_to_linearrgb_v3_v3(to, from);
463           to[3] = 1.0f;
464         }
465       }
466       else if (profile_to == IB_PROFILE_SRGB) {
467         /* convert from linear to sRGB */
468         for (x = 0; x < width; x++, from += 3, to += 4) {
469           linearrgb_to_srgb_v3_v3(to, from);
470           to[3] = 1.0f;
471         }
472       }
473     }
474   }
475   else if (channels_from == 4) {
476     /* RGBA input */
477     for (y = 0; y < height; y++) {
478       const float *from = rect_from + ((size_t)stride_from) * y * 4;
479       float *to = rect_to + ((size_t)stride_to) * y * 4;
480
481       if (profile_to == profile_from) {
482         /* same profile, copy */
483         memcpy(to, from, sizeof(float) * ((size_t)4) * width);
484       }
485       else if (profile_to == IB_PROFILE_LINEAR_RGB) {
486         /* convert to sRGB to linear */
487         if (predivide) {
488           for (x = 0; x < width; x++, from += 4, to += 4) {
489             srgb_to_linearrgb_predivide_v4(to, from);
490           }
491         }
492         else {
493           for (x = 0; x < width; x++, from += 4, to += 4) {
494             srgb_to_linearrgb_v4(to, from);
495           }
496         }
497       }
498       else if (profile_to == IB_PROFILE_SRGB) {
499         /* convert from linear to sRGB */
500         if (predivide) {
501           for (x = 0; x < width; x++, from += 4, to += 4) {
502             linearrgb_to_srgb_predivide_v4(to, from);
503           }
504         }
505         else {
506           for (x = 0; x < width; x++, from += 4, to += 4) {
507             linearrgb_to_srgb_v4(to, from);
508           }
509         }
510       }
511     }
512   }
513 }
514
515 typedef struct FloatToFloatThreadData {
516   float *rect_to;
517   const float *rect_from;
518   int channels_from;
519   int profile_to;
520   int profile_from;
521   bool predivide;
522   int width;
523   int stride_to;
524   int stride_from;
525 } FloatToFloatThreadData;
526
527 static void imb_buffer_float_from_float_thread_do(void *data_v,
528                                                   int start_scanline,
529                                                   int num_scanlines)
530 {
531   FloatToFloatThreadData *data = (FloatToFloatThreadData *)data_v;
532   size_t offset_from = ((size_t)start_scanline) * data->stride_from * data->channels_from;
533   size_t offset_to = ((size_t)start_scanline) * data->stride_to * data->channels_from;
534   IMB_buffer_float_from_float(data->rect_to + offset_to,
535                               data->rect_from + offset_from,
536                               data->channels_from,
537                               data->profile_to,
538                               data->profile_from,
539                               data->predivide,
540                               data->width,
541                               num_scanlines,
542                               data->stride_to,
543                               data->stride_from);
544 }
545
546 void IMB_buffer_float_from_float_threaded(float *rect_to,
547                                           const float *rect_from,
548                                           int channels_from,
549                                           int profile_to,
550                                           int profile_from,
551                                           bool predivide,
552                                           int width,
553                                           int height,
554                                           int stride_to,
555                                           int stride_from)
556 {
557   if (((size_t)width) * height < 64 * 64) {
558     IMB_buffer_float_from_float(rect_to,
559                                 rect_from,
560                                 channels_from,
561                                 profile_to,
562                                 profile_from,
563                                 predivide,
564                                 width,
565                                 height,
566                                 stride_to,
567                                 stride_from);
568   }
569   else {
570     FloatToFloatThreadData data;
571     data.rect_to = rect_to;
572     data.rect_from = rect_from;
573     data.channels_from = channels_from;
574     data.profile_to = profile_to;
575     data.profile_from = profile_from;
576     data.predivide = predivide;
577     data.width = width;
578     data.stride_to = stride_to;
579     data.stride_from = stride_from;
580     IMB_processor_apply_threaded_scanlines(height, imb_buffer_float_from_float_thread_do, &data);
581   }
582 }
583
584 /* float to float pixels, output 4-channel RGBA */
585 void IMB_buffer_float_from_float_mask(float *rect_to,
586                                       const float *rect_from,
587                                       int channels_from,
588                                       int width,
589                                       int height,
590                                       int stride_to,
591                                       int stride_from,
592                                       char *mask)
593 {
594   int x, y;
595
596   if (channels_from == 1) {
597     /* single channel input */
598     for (y = 0; y < height; y++) {
599       const float *from = rect_from + ((size_t)stride_from) * y;
600       float *to = rect_to + ((size_t)stride_to) * y * 4;
601
602       for (x = 0; x < width; x++, from++, to += 4) {
603         if (*mask++ == FILTER_MASK_USED) {
604           to[0] = to[1] = to[2] = to[3] = from[0];
605         }
606       }
607     }
608   }
609   else if (channels_from == 3) {
610     /* RGB input */
611     for (y = 0; y < height; y++) {
612       const float *from = rect_from + ((size_t)stride_from) * y * 3;
613       float *to = rect_to + ((size_t)stride_to) * y * 4;
614
615       for (x = 0; x < width; x++, from += 3, to += 4) {
616         if (*mask++ == FILTER_MASK_USED) {
617           copy_v3_v3(to, from);
618           to[3] = 1.0f;
619         }
620       }
621     }
622   }
623   else if (channels_from == 4) {
624     /* RGBA input */
625     for (y = 0; y < height; y++) {
626       const float *from = rect_from + ((size_t)stride_from) * y * 4;
627       float *to = rect_to + ((size_t)stride_to) * y * 4;
628
629       for (x = 0; x < width; x++, from += 4, to += 4) {
630         if (*mask++ == FILTER_MASK_USED) {
631           copy_v4_v4(to, from);
632         }
633       }
634     }
635   }
636 }
637
638 /* byte to byte pixels, input and output 4-channel RGBA */
639 void IMB_buffer_byte_from_byte(uchar *rect_to,
640                                const uchar *rect_from,
641                                int profile_to,
642                                int profile_from,
643                                bool predivide,
644                                int width,
645                                int height,
646                                int stride_to,
647                                int stride_from)
648 {
649   float tmp[4];
650   int x, y;
651
652   /* we need valid profiles */
653   BLI_assert(profile_to != IB_PROFILE_NONE);
654   BLI_assert(profile_from != IB_PROFILE_NONE);
655
656   /* always RGBA input */
657   for (y = 0; y < height; y++) {
658     const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
659     uchar *to = rect_to + ((size_t)stride_to) * y * 4;
660
661     if (profile_to == profile_from) {
662       /* same profile, copy */
663       memcpy(to, from, sizeof(uchar) * 4 * width);
664     }
665     else if (profile_to == IB_PROFILE_LINEAR_RGB) {
666       /* convert to sRGB to linear */
667       if (predivide) {
668         for (x = 0; x < width; x++, from += 4, to += 4) {
669           rgba_uchar_to_float(tmp, from);
670           srgb_to_linearrgb_predivide_v4(tmp, tmp);
671           rgba_float_to_uchar(to, tmp);
672         }
673       }
674       else {
675         for (x = 0; x < width; x++, from += 4, to += 4) {
676           rgba_uchar_to_float(tmp, from);
677           srgb_to_linearrgb_v4(tmp, tmp);
678           rgba_float_to_uchar(to, tmp);
679         }
680       }
681     }
682     else if (profile_to == IB_PROFILE_SRGB) {
683       /* convert from linear to sRGB */
684       if (predivide) {
685         for (x = 0; x < width; x++, from += 4, to += 4) {
686           rgba_uchar_to_float(tmp, from);
687           linearrgb_to_srgb_predivide_v4(tmp, tmp);
688           rgba_float_to_uchar(to, tmp);
689         }
690       }
691       else {
692         for (x = 0; x < width; x++, from += 4, to += 4) {
693           rgba_uchar_to_float(tmp, from);
694           linearrgb_to_srgb_v4(tmp, tmp);
695           rgba_float_to_uchar(to, tmp);
696         }
697       }
698     }
699   }
700 }
701
702 /****************************** ImBuf Conversion *****************************/
703
704 void IMB_rect_from_float(ImBuf *ibuf)
705 {
706   float *buffer;
707   const char *from_colorspace;
708
709   /* verify we have a float buffer */
710   if (ibuf->rect_float == NULL) {
711     return;
712   }
713
714   /* create byte rect if it didn't exist yet */
715   if (ibuf->rect == NULL) {
716     if (imb_addrectImBuf(ibuf) == 0) {
717       return;
718     }
719   }
720
721   if (ibuf->float_colorspace == NULL) {
722     from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
723   }
724   else {
725     from_colorspace = ibuf->float_colorspace->name;
726   }
727
728   buffer = MEM_dupallocN(ibuf->rect_float);
729
730   /* first make float buffer in byte space */
731   IMB_colormanagement_transform(buffer,
732                                 ibuf->x,
733                                 ibuf->y,
734                                 ibuf->channels,
735                                 from_colorspace,
736                                 ibuf->rect_colorspace->name,
737                                 true);
738
739   /* convert from float's premul alpha to byte's straight alpha */
740   IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y);
741
742   /* convert float to byte */
743   IMB_buffer_byte_from_float((unsigned char *)ibuf->rect,
744                              buffer,
745                              ibuf->channels,
746                              ibuf->dither,
747                              IB_PROFILE_SRGB,
748                              IB_PROFILE_SRGB,
749                              false,
750                              ibuf->x,
751                              ibuf->y,
752                              ibuf->x,
753                              ibuf->x);
754
755   MEM_freeN(buffer);
756
757   /* ensure user flag is reset */
758   ibuf->userflags &= ~IB_RECT_INVALID;
759 }
760
761 typedef struct PartialThreadData {
762   ImBuf *ibuf;
763   float *buffer;
764   uchar *rect_byte;
765   const float *rect_float;
766   int width;
767   bool is_data;
768 } PartialThreadData;
769
770 static void partial_rect_from_float_slice(float *buffer,
771                                           uchar *rect_byte,
772                                           ImBuf *ibuf,
773                                           const float *rect_float,
774                                           const int w,
775                                           const int h,
776                                           const bool is_data)
777 {
778   const int profile_from = IB_PROFILE_LINEAR_RGB;
779   if (is_data) {
780     /* exception for non-color data, just copy float */
781     IMB_buffer_float_from_float(buffer,
782                                 rect_float,
783                                 ibuf->channels,
784                                 IB_PROFILE_LINEAR_RGB,
785                                 IB_PROFILE_LINEAR_RGB,
786                                 0,
787                                 w,
788                                 h,
789                                 w,
790                                 ibuf->x);
791
792     /* and do color space conversion to byte */
793     IMB_buffer_byte_from_float(rect_byte,
794                                rect_float,
795                                4,
796                                ibuf->dither,
797                                IB_PROFILE_SRGB,
798                                profile_from,
799                                true,
800                                w,
801                                h,
802                                ibuf->x,
803                                w);
804   }
805   else {
806     IMB_buffer_float_from_float(
807         buffer, rect_float, ibuf->channels, IB_PROFILE_SRGB, profile_from, true, w, h, w, ibuf->x);
808
809     IMB_buffer_float_unpremultiply(buffer, w, h);
810     /* XXX: need to convert to image buffer's rect space */
811     IMB_buffer_byte_from_float(
812         rect_byte, buffer, 4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0, w, h, ibuf->x, w);
813   }
814 }
815
816 static void partial_rect_from_float_thread_do(void *data_v, int start_scanline, int num_scanlines)
817 {
818   PartialThreadData *data = (PartialThreadData *)data_v;
819   ImBuf *ibuf = data->ibuf;
820   size_t global_offset = ((size_t)ibuf->x) * start_scanline;
821   size_t local_offset = ((size_t)data->width) * start_scanline;
822   partial_rect_from_float_slice(data->buffer + local_offset * ibuf->channels,
823                                 data->rect_byte + global_offset * 4,
824                                 ibuf,
825                                 data->rect_float + global_offset * ibuf->channels,
826                                 data->width,
827                                 num_scanlines,
828                                 data->is_data);
829 }
830
831 /**
832  * Converts from linear float to sRGB byte for part of the texture,
833  * buffer will hold the changed part.
834  */
835 void IMB_partial_rect_from_float(
836     ImBuf *ibuf, float *buffer, int x, int y, int w, int h, bool is_data)
837 {
838   const float *rect_float;
839   uchar *rect_byte;
840
841   /* verify we have a float buffer */
842   if (ibuf->rect_float == NULL || buffer == NULL) {
843     return;
844   }
845
846   /* create byte rect if it didn't exist yet */
847   if (ibuf->rect == NULL) {
848     imb_addrectImBuf(ibuf);
849   }
850
851   /* do conversion */
852   rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels;
853   rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4;
854
855   if (((size_t)w) * h < 64 * 64) {
856     partial_rect_from_float_slice(buffer, rect_byte, ibuf, rect_float, w, h, is_data);
857   }
858   else {
859     PartialThreadData data;
860     data.ibuf = ibuf;
861     data.buffer = buffer;
862     data.rect_byte = rect_byte;
863     data.rect_float = rect_float;
864     data.width = w;
865     data.is_data = is_data;
866     IMB_processor_apply_threaded_scanlines(h, partial_rect_from_float_thread_do, &data);
867   }
868
869   /* ensure user flag is reset */
870   ibuf->userflags &= ~IB_RECT_INVALID;
871 }
872
873 void IMB_float_from_rect(ImBuf *ibuf)
874 {
875   float *rect_float;
876
877   /* verify if we byte and float buffers */
878   if (ibuf->rect == NULL) {
879     return;
880   }
881
882   /* allocate float buffer outside of image buffer,
883    * so work-in-progress color space conversion doesn't
884    * interfere with other parts of blender
885    */
886   rect_float = ibuf->rect_float;
887   if (rect_float == NULL) {
888     size_t size;
889
890     size = ((size_t)ibuf->x) * ibuf->y;
891     size = size * 4 * sizeof(float);
892     ibuf->channels = 4;
893
894     rect_float = MEM_mapallocN(size, "IMB_float_from_rect");
895
896     if (rect_float == NULL) {
897       return;
898     }
899   }
900
901   /* first, create float buffer in non-linear space */
902   IMB_buffer_float_from_byte(rect_float,
903                              (unsigned char *)ibuf->rect,
904                              IB_PROFILE_SRGB,
905                              IB_PROFILE_SRGB,
906                              false,
907                              ibuf->x,
908                              ibuf->y,
909                              ibuf->x,
910                              ibuf->x);
911
912   /* then make float be in linear space */
913   IMB_colormanagement_colorspace_to_scene_linear(
914       rect_float, ibuf->x, ibuf->y, ibuf->channels, ibuf->rect_colorspace, false);
915
916   /* byte buffer is straight alpha, float should always be premul */
917   IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y);
918
919   if (ibuf->rect_float == NULL) {
920     ibuf->rect_float = rect_float;
921     ibuf->mall |= IB_rectfloat;
922     ibuf->flags |= IB_rectfloat;
923   }
924 }
925
926 /**************************** Color to Grayscale *****************************/
927
928 /* no profile conversion */
929 void IMB_color_to_bw(ImBuf *ibuf)
930 {
931   float *rct_fl = ibuf->rect_float;
932   uchar *rct = (uchar *)ibuf->rect;
933   size_t i;
934
935   if (rct_fl) {
936     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
937       rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
938     }
939   }
940
941   if (rct) {
942     for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4) {
943       rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
944     }
945   }
946 }
947
948 void IMB_buffer_float_clamp(float *buf, int width, int height)
949 {
950   size_t i, total = ((size_t)width) * height * 4;
951   for (i = 0; i < total; i++) {
952     buf[i] = min_ff(1.0, buf[i]);
953   }
954 }
955
956 void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
957 {
958   size_t total = ((size_t)width) * height;
959   float *fp = buf;
960   while (total--) {
961     premul_to_straight_v4(fp);
962     fp += 4;
963   }
964 }
965
966 void IMB_buffer_float_premultiply(float *buf, int width, int height)
967 {
968   size_t total = ((size_t)width) * height;
969   float *fp = buf;
970   while (total--) {
971     straight_to_premul_v4(fp);
972     fp += 4;
973   }
974 }
975
976 /**************************** alter saturation *****************************/
977
978 void IMB_saturation(ImBuf *ibuf, float sat)
979 {
980   size_t i;
981   unsigned char *rct = (unsigned char *)ibuf->rect;
982   float *rct_fl = ibuf->rect_float;
983   float hsv[3];
984
985   if (rct) {
986     float rgb[3];
987     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
988       rgb_uchar_to_float(rgb, rct);
989       rgb_to_hsv_v(rgb, hsv);
990       hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
991       rgb_float_to_uchar(rct, rgb);
992     }
993   }
994
995   if (rct_fl) {
996     for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
997       rgb_to_hsv_v(rct_fl, hsv);
998       hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
999     }
1000   }
1001 }