Optimize projection painting with big brushes
[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 /* float to float pixels, output 4-channel RGBA */
536 void IMB_buffer_float_from_float_mask(float *rect_to, const float *rect_from, int channels_from,
537                                       int width, int height, int stride_to, int stride_from, char *mask)
538 {
539         int x, y;
540
541         if (channels_from == 1) {
542                 /* single channel input */
543                 for (y = 0; y < height; y++) {
544                         const float *from = rect_from + ((size_t)stride_from) * y;
545                         float *to = rect_to + ((size_t)stride_to) * y * 4;
546
547                         for (x = 0; x < width; x++, from++, to += 4)
548                                 if (*mask++ == FILTER_MASK_USED)
549                                         to[0] = to[1] = to[2] = to[3] = from[0];
550                 }
551         }
552         else if (channels_from == 3) {
553                 /* RGB input */
554                 for (y = 0; y < height; y++) {
555                         const float *from = rect_from + ((size_t)stride_from) * y * 3;
556                         float *to = rect_to + ((size_t)stride_to) * y * 4;
557
558                         for (x = 0; x < width; x++, from += 3, to += 4) {
559                                 if (*mask++ == FILTER_MASK_USED) {
560                                         copy_v3_v3(to, from);
561                                         to[3] = 1.0f;
562                                 }
563                         }
564                 }
565         }
566         else if (channels_from == 4) {
567                 /* RGBA input */
568                 for (y = 0; y < height; y++) {
569                         const float *from = rect_from + ((size_t)stride_from) * y * 4;
570                         float *to = rect_to + ((size_t)stride_to) * y * 4;
571
572                         for (x = 0; x < width; x++, from += 4, to += 4)
573                                 if (*mask++ == FILTER_MASK_USED)
574                                         copy_v4_v4(to, from);
575                 }
576         }
577 }
578
579 /* byte to byte pixels, input and output 4-channel RGBA */
580 void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from,
581                                int profile_to, int profile_from, bool predivide,
582                                int width, int height, int stride_to, int stride_from)
583 {
584         float tmp[4];
585         int x, y;
586
587         /* we need valid profiles */
588         BLI_assert(profile_to != IB_PROFILE_NONE);
589         BLI_assert(profile_from != IB_PROFILE_NONE);
590
591         /* always RGBA input */
592         for (y = 0; y < height; y++) {
593                 const uchar *from = rect_from + ((size_t)stride_from) * y * 4;
594                 uchar *to = rect_to + ((size_t)stride_to) * y * 4;
595
596                 if (profile_to == profile_from) {
597                         /* same profile, copy */
598                         memcpy(to, from, sizeof(uchar) * 4 * width);
599                 }
600                 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
601                         /* convert to sRGB to linear */
602                         if (predivide) {
603                                 for (x = 0; x < width; x++, from += 4, to += 4) {
604                                         rgba_uchar_to_float(tmp, from);
605                                         srgb_to_linearrgb_predivide_v4(tmp, tmp);
606                                         rgba_float_to_uchar(to, tmp);
607                                 }
608                         }
609                         else {
610                                 for (x = 0; x < width; x++, from += 4, to += 4) {
611                                         rgba_uchar_to_float(tmp, from);
612                                         srgb_to_linearrgb_v4(tmp, tmp);
613                                         rgba_float_to_uchar(to, tmp);
614                                 }
615                         }
616                 }
617                 else if (profile_to == IB_PROFILE_SRGB) {
618                         /* convert from linear to sRGB */
619                         if (predivide) {
620                                 for (x = 0; x < width; x++, from += 4, to += 4) {
621                                         rgba_uchar_to_float(tmp, from);
622                                         linearrgb_to_srgb_predivide_v4(tmp, tmp);
623                                         rgba_float_to_uchar(to, tmp);
624                                 }
625                         }
626                         else {
627                                 for (x = 0; x < width; x++, from += 4, to += 4) {
628                                         rgba_uchar_to_float(tmp, from);
629                                         linearrgb_to_srgb_v4(tmp, tmp);
630                                         rgba_float_to_uchar(to, tmp);
631                                 }
632                         }
633                 }
634         }
635 }
636
637 /****************************** ImBuf Conversion *****************************/
638
639 void IMB_rect_from_float(ImBuf *ibuf)
640 {
641         float *buffer;
642         const char *from_colorspace;
643
644         /* verify we have a float buffer */
645         if (ibuf->rect_float == NULL)
646                 return;
647
648         /* create byte rect if it didn't exist yet */
649         if (ibuf->rect == NULL) {
650                 if (imb_addrectImBuf(ibuf) == 0)
651                         return;
652         }
653
654         if (ibuf->float_colorspace == NULL)
655                 from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
656         else
657                 from_colorspace = ibuf->float_colorspace->name;
658
659         buffer = MEM_dupallocN(ibuf->rect_float);
660
661         /* first make float buffer in byte space */
662         IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, true);
663
664         /* convert from float's premul alpha to byte's straight alpha */
665         IMB_unpremultiply_rect_float(buffer, ibuf->channels, ibuf->x, ibuf->y);
666
667         /* convert float to byte */
668         IMB_buffer_byte_from_float((unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
669                                    false, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
670
671         MEM_freeN(buffer);
672
673         /* ensure user flag is reset */
674         ibuf->userflags &= ~IB_RECT_INVALID;
675 }
676
677 typedef struct PartialThreadData {
678         ImBuf *ibuf;
679         float *buffer;
680         uchar *rect_byte;
681         const float *rect_float;
682         int width;
683         bool is_data;
684 } PartialThreadData;
685
686 static void partial_rect_from_float_slice(float *buffer,
687                                           uchar *rect_byte,
688                                           ImBuf *ibuf,
689                                           const float *rect_float,
690                                           const int w,
691                                           const int h,
692                                           const bool is_data)
693 {
694         const int profile_from = IB_PROFILE_LINEAR_RGB;
695         if (is_data) {
696                 /* exception for non-color data, just copy float */
697                 IMB_buffer_float_from_float(buffer, rect_float,
698                                             ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, 0,
699                                             w, h, w, ibuf->x);
700
701                 /* and do color space conversion to byte */
702                 IMB_buffer_byte_from_float(rect_byte, rect_float,
703                                            4, ibuf->dither, IB_PROFILE_SRGB, profile_from, true,
704                                            w, h, ibuf->x, w);
705         }
706         else {
707                 IMB_buffer_float_from_float(buffer, rect_float,
708                                             ibuf->channels, IB_PROFILE_SRGB, profile_from, true,
709                                             w, h, w, ibuf->x);
710
711                 IMB_buffer_float_unpremultiply(buffer, w, h);
712                 /* XXX: need to convert to image buffer's rect space */
713                 IMB_buffer_byte_from_float(rect_byte, buffer,
714                                            4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0,
715                                            w, h, ibuf->x, w);
716         }
717 }
718
719 static void partial_rect_from_float_thread_do(void *data_v,
720                                               int start_scanline,
721                                               int num_scanlines)
722 {
723         PartialThreadData *data = (PartialThreadData *)data_v;
724         ImBuf *ibuf = data->ibuf;
725         size_t global_offset = ((size_t)ibuf->x) * start_scanline;
726         size_t local_offset = ((size_t)data->width) * start_scanline;
727         partial_rect_from_float_slice(data->buffer + local_offset * ibuf->channels,
728                                       data->rect_byte + global_offset * 4,
729                                       ibuf,
730                                       data->rect_float + global_offset * ibuf->channels,
731                                       data->width,
732                                       num_scanlines,
733                                       data->is_data);
734 }
735
736 /* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */
737 void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w, int h, bool is_data)
738 {
739         const float *rect_float;
740         uchar *rect_byte;
741
742         /* verify we have a float buffer */
743         if (ibuf->rect_float == NULL || buffer == NULL)
744                 return;
745
746         /* create byte rect if it didn't exist yet */
747         if (ibuf->rect == NULL)
748                 imb_addrectImBuf(ibuf);
749
750         /* do conversion */
751         rect_float = ibuf->rect_float + (x + ((size_t)y) * ibuf->x) * ibuf->channels;
752         rect_byte = (uchar *)ibuf->rect + (x + ((size_t)y) * ibuf->x) * 4;
753
754         if (((size_t)w) * h < 64 * 64) {
755                 partial_rect_from_float_slice(
756                         buffer, rect_byte, ibuf, rect_float, w, h, is_data);
757         }
758         else {
759                 PartialThreadData data;
760                 data.ibuf = ibuf;
761                 data.buffer = buffer;
762                 data.rect_byte = rect_byte;
763                 data.rect_float = rect_float;
764                 data.width = w;
765                 data.is_data = is_data;
766                 IMB_processor_apply_threaded_scanlines(
767                         h, partial_rect_from_float_thread_do, &data);
768         }
769
770         /* ensure user flag is reset */
771         ibuf->userflags &= ~IB_RECT_INVALID;
772 }
773
774 void IMB_float_from_rect(ImBuf *ibuf)
775 {
776         float *rect_float;
777
778         /* verify if we byte and float buffers */
779         if (ibuf->rect == NULL)
780                 return;
781
782         /* allocate float buffer outside of image buffer,
783          * so work-in-progress color space conversion doesn't
784          * interfere with other parts of blender
785          */
786         rect_float = ibuf->rect_float;
787         if (rect_float == NULL) {
788                 size_t size;
789
790                 size = ((size_t)ibuf->x) * ibuf->y;
791                 size = size * 4 * sizeof(float);
792                 ibuf->channels = 4;
793
794                 rect_float = MEM_mapallocN(size, "IMB_float_from_rect");
795
796                 if (rect_float == NULL)
797                         return;
798         }
799
800         /* first, create float buffer in non-linear space */
801         IMB_buffer_float_from_byte(rect_float, (unsigned char *) ibuf->rect, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
802                                    false, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
803
804         /* then make float be in linear space */
805         IMB_colormanagement_colorspace_to_scene_linear(rect_float, ibuf->x, ibuf->y, ibuf->channels,
806                                                        ibuf->rect_colorspace, false);
807
808         /* byte buffer is straight alpha, float should always be premul */
809         IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y);
810
811         if (ibuf->rect_float == NULL) {
812                 ibuf->rect_float = rect_float;
813                 ibuf->mall |= IB_rectfloat;
814                 ibuf->flags |= IB_rectfloat;
815         }
816 }
817
818 /**************************** Color to Grayscale *****************************/
819
820 /* no profile conversion */
821 void IMB_color_to_bw(ImBuf *ibuf)
822 {
823         float *rct_fl = ibuf->rect_float;
824         uchar *rct = (uchar *)ibuf->rect;
825         size_t i;
826
827         if (rct_fl) {
828                 for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4)
829                         rct_fl[0] = rct_fl[1] = rct_fl[2] = IMB_colormanagement_get_luminance(rct_fl);
830         }
831
832         if (rct) {
833                 for (i = ((size_t)ibuf->x * ibuf->y); i > 0; i--, rct += 4)
834                         rct[0] = rct[1] = rct[2] = IMB_colormanagement_get_luminance_byte(rct);
835         }
836 }
837
838 void IMB_buffer_float_clamp(float *buf, int width, int height)
839 {
840         size_t i, total = ((size_t)width) * height * 4;
841         for (i = 0; i < total; i++) {
842                 buf[i] = min_ff(1.0, buf[i]);
843         }
844 }
845
846 void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
847 {
848         size_t total = ((size_t)width) * height;
849         float *fp = buf;
850         while (total--) {
851                 premul_to_straight_v4(fp);
852                 fp += 4;
853         }
854 }
855
856 void IMB_buffer_float_premultiply(float *buf, int width, int height)
857 {
858         size_t total = ((size_t)width) * height;
859         float *fp = buf;
860         while (total--) {
861                 straight_to_premul_v4(fp);
862                 fp += 4;
863         }
864 }
865
866 /**************************** alter saturation *****************************/
867
868 void IMB_saturation(ImBuf *ibuf, float sat)
869 {
870         size_t i;
871         unsigned char *rct = (unsigned char *)ibuf->rect;
872         float *rct_fl = ibuf->rect_float;
873         float hsv[3];
874
875         if (rct) {
876                 float rgb[3];
877                 for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct += 4) {
878                         rgb_uchar_to_float(rgb, rct);
879                         rgb_to_hsv_v(rgb, hsv);
880                         hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
881                         rgb_float_to_uchar(rct, rgb);
882                 }
883         }
884
885         if (rct_fl) {
886                 for (i = ((size_t)ibuf->x) * ibuf->y; i > 0; i--, rct_fl += 4) {
887                         rgb_to_hsv_v(rct_fl, hsv);
888                         hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
889                 }
890         }
891 }