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