Implement GPU-side dither
[blender-staging.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_allocimbuf.h"
41 #include "IMB_filter.h"
42
43 #include "IMB_colormanagement.h"
44 #include "IMB_colormanagement_intern.h"
45
46 #include "BLI_threads.h"
47
48 #include "MEM_guardedalloc.h"
49
50 /**************************** Interlace/Deinterlace **************************/
51
52 void IMB_de_interlace(ImBuf *ibuf)
53 {
54         ImBuf *tbuf1, *tbuf2;
55         
56         if (ibuf == NULL) return;
57         if (ibuf->flags & IB_fields) return;
58         ibuf->flags |= IB_fields;
59         
60         if (ibuf->rect) {
61                 /* make copies */
62                 tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
63                 tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
64                 
65                 ibuf->x *= 2;
66                 IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
67                 IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
68         
69                 ibuf->x /= 2;
70                 IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
71                 IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y);
72                 
73                 IMB_freeImBuf(tbuf1);
74                 IMB_freeImBuf(tbuf2);
75         }
76         ibuf->y /= 2;
77 }
78
79 void IMB_interlace(ImBuf *ibuf)
80 {
81         ImBuf *tbuf1, *tbuf2;
82
83         if (ibuf == NULL) return;
84         ibuf->flags &= ~IB_fields;
85
86         ibuf->y *= 2;
87
88         if (ibuf->rect) {
89                 /* make copies */
90                 tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
91                 tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
92
93                 IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
94                 IMB_rectcpy(tbuf2, ibuf, 0, 0, 0, tbuf2->y, ibuf->x, ibuf->y);
95
96                 ibuf->x *= 2;
97                 IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
98                 IMB_rectcpy(ibuf, tbuf2, tbuf2->x, 0, 0, 0, tbuf2->x, tbuf2->y);
99                 ibuf->x /= 2;
100
101                 IMB_freeImBuf(tbuf1);
102                 IMB_freeImBuf(tbuf2);
103         }
104 }
105
106 /************************* Floyd-Steinberg dithering *************************/
107
108 typedef struct DitherContext {
109         float dither;
110 } DitherContext;
111
112 static DitherContext *create_dither_context(float dither)
113 {
114         DitherContext *di;
115
116         di = MEM_mallocN(sizeof(DitherContext), "dithering context");
117         di->dither = dither;
118
119         return di;
120 }
121
122 static void clear_dither_context(DitherContext *di)
123 {
124         MEM_freeN(di);
125 }
126
127 MINLINE float dither_random_value(float s, float t)
128 {
129         static float vec[2] = {12.9898f, 78.233f};
130         float st[2];
131         float value;
132         copy_v2_fl2(st, s, t);
133
134         value = sinf(dot_v2v2(st, vec)) * 43758.5453f;
135         return value - floor(value);
136 }
137
138 /************************* Generic Buffer Conversion *************************/
139
140 MINLINE void ushort_to_byte_v4(uchar b[4], const unsigned short us[4])
141 {
142         b[0] = USHORTTOUCHAR(us[0]);
143         b[1] = USHORTTOUCHAR(us[1]);
144         b[2] = USHORTTOUCHAR(us[2]);
145         b[3] = USHORTTOUCHAR(us[3]);
146 }
147
148 MINLINE unsigned char ftochar(float value)
149 {
150         return FTOCHAR(value);
151 }
152
153 MINLINE void ushort_to_byte_dither_v4(uchar b[4], const unsigned short us[4], DitherContext *di, float s, float t)
154 {
155 #define USHORTTOFLOAT(val) ((float)val / 65535.0f)
156         float dither_value = dither_random_value(s, t) * 0.005f * di->dither;
157
158         b[0] = ftochar(dither_value + USHORTTOFLOAT(us[0]));
159         b[1] = ftochar(dither_value + USHORTTOFLOAT(us[1]));
160         b[2] = ftochar(dither_value + USHORTTOFLOAT(us[2]));
161         b[3] = USHORTTOUCHAR(us[3]);
162
163 #undef USHORTTOFLOAT
164 }
165
166 MINLINE void float_to_byte_dither_v4(uchar b[4], const float f[4], DitherContext *di, float s, float t)
167 {
168         float dither_value = dither_random_value(s, t) * 0.005f * di->dither;
169
170         b[0] = ftochar(dither_value + f[0]);
171         b[1] = ftochar(dither_value + f[1]);
172         b[2] = ftochar(dither_value + f[2]);
173         b[3] = FTOCHAR(f[3]);
174 }
175
176 /* float to byte pixels, output 4-channel RGBA */
177 void IMB_buffer_byte_from_float(uchar *rect_to, const float *rect_from,
178                                 int channels_from, float dither, int profile_to, int profile_from, int predivide,
179                                 int width, int height, int stride_to, int stride_from)
180 {
181         float tmp[4];
182         int x, y;
183         DitherContext *di = NULL;
184         float inv_width = 1.0f / width,
185               inv_height = 1.0f / height;
186
187         /* we need valid profiles */
188         BLI_assert(profile_to != IB_PROFILE_NONE);
189         BLI_assert(profile_from != IB_PROFILE_NONE);
190
191         if (dither)
192                 di = create_dither_context(dither);
193
194         for (y = 0; y < height; y++) {
195                 float t = y * inv_height;
196
197                 if (channels_from == 1) {
198                         /* single channel input */
199                         const float *from = rect_from + stride_from * y;
200                         uchar *to = rect_to + stride_to * y * 4;
201
202                         for (x = 0; x < width; x++, from++, to += 4)
203                                 to[0] = to[1] = to[2] = to[3] = FTOCHAR(from[0]);
204                 }
205                 else if (channels_from == 3) {
206                         /* RGB input */
207                         const float *from = rect_from + stride_from * y * 3;
208                         uchar *to = rect_to + stride_to * y * 4;
209
210                         if (profile_to == profile_from) {
211                                 /* no color space conversion */
212                                 for (x = 0; x < width; x++, from += 3, to += 4) {
213                                         rgb_float_to_uchar(to, from);
214                                         to[3] = 255;
215                                 }
216                         }
217                         else if (profile_to == IB_PROFILE_SRGB) {
218                                 /* convert from linear to sRGB */
219                                 for (x = 0; x < width; x++, from += 3, to += 4) {
220                                         linearrgb_to_srgb_v3_v3(tmp, from);
221                                         rgb_float_to_uchar(to, tmp);
222                                         to[3] = 255;
223                                 }
224                         }
225                         else if (profile_to == IB_PROFILE_LINEAR_RGB) {
226                                 /* convert from sRGB to linear */
227                                 for (x = 0; x < width; x++, from += 3, to += 4) {
228                                         srgb_to_linearrgb_v3_v3(tmp, from);
229                                         rgb_float_to_uchar(to, tmp);
230                                         to[3] = 255;
231                                 }
232                         }
233                 }
234                 else if (channels_from == 4) {
235                         /* RGBA input */
236                         const float *from = rect_from + stride_from * y * 4;
237                         uchar *to = rect_to + stride_to * y * 4;
238
239                         if (profile_to == profile_from) {
240                                 float straight[4];
241
242                                 /* no color space conversion */
243                                 if (dither && predivide) {
244                                         for (x = 0; x < width; x++, from += 4, to += 4) {
245                                                 premul_to_straight_v4_v4(straight, from);
246                                                 float_to_byte_dither_v4(to, straight, di, (float) x * inv_width, t);
247                                         }
248                                 }
249                                 else if (dither) {
250                                         for (x = 0; x < width; x++, from += 4, to += 4)
251                                                 float_to_byte_dither_v4(to, from, di, (float) x * inv_width, t);
252                                 }
253                                 else if (predivide) {
254                                         for (x = 0; x < width; x++, from += 4, to += 4) {
255                                                 premul_to_straight_v4_v4(straight, from);
256                                                 rgba_float_to_uchar(to, straight);
257                                         }
258                                 }
259                                 else {
260                                         for (x = 0; x < width; x++, from += 4, to += 4)
261                                                 rgba_float_to_uchar(to, from);
262                                 }
263                         }
264                         else if (profile_to == IB_PROFILE_SRGB) {
265                                 /* convert from linear to sRGB */
266                                 unsigned short us[4];
267                                 float straight[4];
268
269                                 if (dither && predivide) {
270                                         for (x = 0; x < width; x++, from += 4, to += 4) {
271                                                 premul_to_straight_v4_v4(straight, from);
272                                                 linearrgb_to_srgb_ushort4(us, from);
273                                                 ushort_to_byte_dither_v4(to, us, di, (float) x * inv_width, t);
274                                         }
275                                 }
276                                 else if (dither) {
277                                         for (x = 0; x < width; x++, from += 4, to += 4) {
278                                                 linearrgb_to_srgb_ushort4(us, from);
279                                                 ushort_to_byte_dither_v4(to, us, di, (float) x * inv_width, t);
280                                         }
281                                 }
282                                 else if (predivide) {
283                                         for (x = 0; x < width; x++, from += 4, to += 4) {
284                                                 premul_to_straight_v4_v4(straight, from);
285                                                 linearrgb_to_srgb_ushort4(us, from);
286                                                 ushort_to_byte_v4(to, us);
287                                         }
288                                 }
289                                 else {
290                                         for (x = 0; x < width; x++, from += 4, to += 4) {
291                                                 linearrgb_to_srgb_ushort4(us, from);
292                                                 ushort_to_byte_v4(to, us);
293                                         }
294                                 }
295                         }
296                         else if (profile_to == IB_PROFILE_LINEAR_RGB) {
297                                 /* convert from sRGB to linear */
298                                 if (dither && predivide) {
299                                         for (x = 0; x < width; x++, from += 4, to += 4) {
300                                                 srgb_to_linearrgb_predivide_v4(tmp, from);
301                                                 float_to_byte_dither_v4(to, tmp, di, (float) x * inv_width, t);
302                                         }
303                                 }
304                                 else if (dither) {
305                                         for (x = 0; x < width; x++, from += 4, to += 4) {
306                                                 srgb_to_linearrgb_v4(tmp, from);
307                                                 float_to_byte_dither_v4(to, tmp, di, (float) x * inv_width, t);
308                                         }
309                                 }
310                                 else if (predivide) {
311                                         for (x = 0; x < width; x++, from += 4, to += 4) {
312                                                 srgb_to_linearrgb_predivide_v4(tmp, from);
313                                                 rgba_float_to_uchar(to, tmp);
314                                         }
315                                 }
316                                 else {
317                                         for (x = 0; x < width; x++, from += 4, to += 4) {
318                                                 srgb_to_linearrgb_v4(tmp, from);
319                                                 rgba_float_to_uchar(to, tmp);
320                                         }
321                                 }
322                         }
323                 }
324         }
325
326         if (dither)
327                 clear_dither_context(di);
328 }
329
330 /* byte to float pixels, input and output 4-channel RGBA  */
331 void IMB_buffer_float_from_byte(float *rect_to, const uchar *rect_from,
332                                 int profile_to, int profile_from, int predivide,
333                                 int width, int height, int stride_to, int stride_from)
334 {
335         float tmp[4];
336         int x, y;
337
338         /* we need valid profiles */
339         BLI_assert(profile_to != IB_PROFILE_NONE);
340         BLI_assert(profile_from != IB_PROFILE_NONE);
341
342         /* RGBA input */
343         for (y = 0; y < height; y++) {
344                 const uchar *from = rect_from + stride_from * y * 4;
345                 float *to = rect_to + stride_to * y * 4;
346
347                 if (profile_to == profile_from) {
348                         /* no color space conversion */
349                         for (x = 0; x < width; x++, from += 4, to += 4)
350                                 rgba_uchar_to_float(to, from);
351                 }
352                 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
353                         /* convert sRGB to linear */
354                         if (predivide) {
355                                 for (x = 0; x < width; x++, from += 4, to += 4) {
356                                         srgb_to_linearrgb_uchar4_predivide(to, from);
357                                 }
358                         }
359                         else {
360                                 for (x = 0; x < width; x++, from += 4, to += 4) {
361                                         srgb_to_linearrgb_uchar4(to, from);
362                                 }
363                         }
364                 }
365                 else if (profile_to == IB_PROFILE_SRGB) {
366                         /* convert linear to sRGB */
367                         if (predivide) {
368                                 for (x = 0; x < width; x++, from += 4, to += 4) {
369                                         rgba_uchar_to_float(tmp, from);
370                                         linearrgb_to_srgb_predivide_v4(to, tmp);
371                                 }
372                         }
373                         else {
374                                 for (x = 0; x < width; x++, from += 4, to += 4) {
375                                         rgba_uchar_to_float(tmp, from);
376                                         linearrgb_to_srgb_v4(to, tmp);
377                                 }
378                         }
379                 }
380         }
381 }
382
383 /* float to float pixels, output 4-channel RGBA */
384 void IMB_buffer_float_from_float(float *rect_to, const float *rect_from,
385                                  int channels_from, int profile_to, int profile_from, int predivide,
386                                  int width, int height, int stride_to, int stride_from)
387 {
388         int x, y;
389
390         /* we need valid profiles */
391         BLI_assert(profile_to != IB_PROFILE_NONE);
392         BLI_assert(profile_from != IB_PROFILE_NONE);
393
394         if (channels_from == 1) {
395                 /* single channel input */
396                 for (y = 0; y < height; y++) {
397                         const float *from = rect_from + stride_from * y;
398                         float *to = rect_to + stride_to * y * 4;
399
400                         for (x = 0; x < width; x++, from++, to += 4)
401                                 to[0] = to[1] = to[2] = to[3] = from[0];
402                 }
403         }
404         else if (channels_from == 3) {
405                 /* RGB input */
406                 for (y = 0; y < height; y++) {
407                         const float *from = rect_from + stride_from * y * 3;
408                         float *to = rect_to + stride_to * y * 4;
409
410                         if (profile_to == profile_from) {
411                                 /* no color space conversion */
412                                 for (x = 0; x < width; x++, from += 3, to += 4) {
413                                         copy_v3_v3(to, from);
414                                         to[3] = 1.0f;
415                                 }
416                         }
417                         else if (profile_to == IB_PROFILE_LINEAR_RGB) {
418                                 /* convert from sRGB to linear */
419                                 for (x = 0; x < width; x++, from += 3, to += 4) {
420                                         srgb_to_linearrgb_v3_v3(to, from);
421                                         to[3] = 1.0f;
422                                 }
423                         }
424                         else if (profile_to == IB_PROFILE_SRGB) {
425                                 /* convert from linear to sRGB */
426                                 for (x = 0; x < width; x++, from += 3, to += 4) {
427                                         linearrgb_to_srgb_v3_v3(to, from);
428                                         to[3] = 1.0f;
429                                 }
430                         }
431                 }
432         }
433         else if (channels_from == 4) {
434                 /* RGBA input */
435                 for (y = 0; y < height; y++) {
436                         const float *from = rect_from + stride_from * y * 4;
437                         float *to = rect_to + stride_to * y * 4;
438
439                         if (profile_to == profile_from) {
440                                 /* same profile, copy */
441                                 memcpy(to, from, sizeof(float) * 4 * width);
442                         }
443                         else if (profile_to == IB_PROFILE_LINEAR_RGB) {
444                                 /* convert to sRGB to linear */
445                                 if (predivide) {
446                                         for (x = 0; x < width; x++, from += 4, to += 4)
447                                                 srgb_to_linearrgb_predivide_v4(to, from);
448                                 }
449                                 else {
450                                         for (x = 0; x < width; x++, from += 4, to += 4)
451                                                 srgb_to_linearrgb_v4(to, from);
452                                 }
453                         }
454                         else if (profile_to == IB_PROFILE_SRGB) {
455                                 /* convert from linear to sRGB */
456                                 if (predivide) {
457                                         for (x = 0; x < width; x++, from += 4, to += 4)
458                                                 linearrgb_to_srgb_predivide_v4(to, from);
459                                 }
460                                 else {
461                                         for (x = 0; x < width; x++, from += 4, to += 4)
462                                                 linearrgb_to_srgb_v4(to, from);
463                                 }
464                         }
465                 }
466         }
467 }
468
469 /* byte to byte pixels, input and output 4-channel RGBA */
470 void IMB_buffer_byte_from_byte(uchar *rect_to, const uchar *rect_from,
471                                int profile_to, int profile_from, int predivide,
472                                int width, int height, int stride_to, int stride_from)
473 {
474         float tmp[4];
475         int x, y;
476
477         /* we need valid profiles */
478         BLI_assert(profile_to != IB_PROFILE_NONE);
479         BLI_assert(profile_from != IB_PROFILE_NONE);
480
481         /* always RGBA input */
482         for (y = 0; y < height; y++) {
483                 const uchar *from = rect_from + stride_from * y * 4;
484                 uchar *to = rect_to + stride_to * y * 4;
485
486                 if (profile_to == profile_from) {
487                         /* same profile, copy */
488                         memcpy(to, from, sizeof(uchar) * 4 * width);
489                 }
490                 else if (profile_to == IB_PROFILE_LINEAR_RGB) {
491                         /* convert to sRGB to linear */
492                         if (predivide) {
493                                 for (x = 0; x < width; x++, from += 4, to += 4) {
494                                         rgba_uchar_to_float(tmp, from);
495                                         srgb_to_linearrgb_predivide_v4(tmp, tmp);
496                                         rgba_float_to_uchar(to, tmp);
497                                 }
498                         }
499                         else {
500                                 for (x = 0; x < width; x++, from += 4, to += 4) {
501                                         rgba_uchar_to_float(tmp, from);
502                                         srgb_to_linearrgb_v4(tmp, tmp);
503                                         rgba_float_to_uchar(to, tmp);
504                                 }
505                         }
506                 }
507                 else if (profile_to == IB_PROFILE_SRGB) {
508                         /* convert from linear to sRGB */
509                         if (predivide) {
510                                 for (x = 0; x < width; x++, from += 4, to += 4) {
511                                         rgba_uchar_to_float(tmp, from);
512                                         linearrgb_to_srgb_predivide_v4(tmp, tmp);
513                                         rgba_float_to_uchar(to, tmp);
514                                 }
515                         }
516                         else {
517                                 for (x = 0; x < width; x++, from += 4, to += 4) {
518                                         rgba_uchar_to_float(tmp, from);
519                                         linearrgb_to_srgb_v4(tmp, tmp);
520                                         rgba_float_to_uchar(to, tmp);
521                                 }
522                         }
523                 }
524         }
525 }
526
527 /****************************** ImBuf Conversion *****************************/
528
529 void IMB_rect_from_float(ImBuf *ibuf)
530 {
531         float *buffer;
532         const char *from_colorspace;
533
534         /* verify we have a float buffer */
535         if (ibuf->rect_float == NULL)
536                 return;
537
538         /* create byte rect if it didn't exist yet */
539         if (ibuf->rect == NULL) {
540                 if (imb_addrectImBuf(ibuf) == 0)
541                         return;
542         }
543
544         if (ibuf->float_colorspace == NULL)
545                 from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
546         else
547                 from_colorspace = ibuf->float_colorspace->name;
548
549         buffer = MEM_dupallocN(ibuf->rect_float);
550
551         /* first make float buffer in byte space */
552         IMB_colormanagement_transform(buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, ibuf->rect_colorspace->name, true);
553
554         /* convert from float's premul alpha to byte's straight alpha */
555         IMB_unpremultiply_rect_float(buffer, ibuf->planes, ibuf->x, ibuf->y);
556
557         /* convert float to byte */
558         IMB_buffer_byte_from_float((unsigned char *) ibuf->rect, buffer, ibuf->channels, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
559                                    FALSE, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
560
561         MEM_freeN(buffer);
562
563         /* ensure user flag is reset */
564         ibuf->userflags &= ~IB_RECT_INVALID;
565 }
566
567 /* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */
568 void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w, int h, int is_data)
569 {
570         float *rect_float;
571         uchar *rect_byte;
572         int profile_from = IB_PROFILE_LINEAR_RGB;
573
574         /* verify we have a float buffer */
575         if (ibuf->rect_float == NULL || buffer == NULL)
576                 return;
577
578         /* create byte rect if it didn't exist yet */
579         if (ibuf->rect == NULL)
580                 imb_addrectImBuf(ibuf);
581
582         /* do conversion */
583         rect_float = ibuf->rect_float + (x + y * ibuf->x) * ibuf->channels;
584         rect_byte = (uchar *)ibuf->rect + (x + y * ibuf->x) * 4;
585
586         if (is_data) {
587                 /* exception for non-color data, just copy float */
588                 IMB_buffer_float_from_float(buffer, rect_float,
589                                             ibuf->channels, IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, 0,
590                                             w, h, w, ibuf->x);
591
592                 /* and do color space conversion to byte */
593                 IMB_buffer_byte_from_float(rect_byte, rect_float,
594                                            4, ibuf->dither, IB_PROFILE_SRGB, profile_from, TRUE,
595                                            w, h, ibuf->x, w);
596         }
597         else {
598                 IMB_buffer_float_from_float(buffer, rect_float,
599                                             ibuf->channels, IB_PROFILE_SRGB, profile_from, TRUE,
600                                             w, h, w, ibuf->x);
601
602                 /* XXX: need to convert to image buffer's rect space */
603                 IMB_buffer_byte_from_float(rect_byte, buffer,
604                                            4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0,
605                                            w, h, ibuf->x, w);
606         }
607
608         /* ensure user flag is reset */
609         ibuf->userflags &= ~IB_RECT_INVALID;
610 }
611
612 void IMB_float_from_rect(ImBuf *ibuf)
613 {
614         float *rect_float;
615
616         /* verify if we byte and float buffers */
617         if (ibuf->rect == NULL)
618                 return;
619
620         /* allocate float buffer outside of image buffer,
621          * so work-in-progress color space conversion doesn't
622          * interfere with other parts of blender
623          */
624         rect_float = ibuf->rect_float;
625         if (rect_float == NULL) {
626                 int size;
627
628                 size = ibuf->x * ibuf->y;
629                 size = size * 4 * sizeof(float);
630                 ibuf->channels = 4;
631
632                 rect_float = MEM_mapallocN(size, "IMB_float_from_rect");
633
634                 if (rect_float == NULL)
635                         return;
636         }
637
638         /* first, create float buffer in non-linear space */
639         IMB_buffer_float_from_byte(rect_float, (unsigned char *) ibuf->rect, IB_PROFILE_SRGB, IB_PROFILE_SRGB,
640                                    FALSE, ibuf->x, ibuf->y, ibuf->x, ibuf->x);
641
642         /* then make float be in linear space */
643         IMB_colormanagement_colorspace_to_scene_linear(rect_float, ibuf->x, ibuf->y, ibuf->channels,
644                                                        ibuf->rect_colorspace, false);
645
646         /* byte buffer is straight alpha, float should always be premul */
647         IMB_premultiply_rect_float(rect_float, ibuf->channels, ibuf->x, ibuf->y);
648
649
650         if (ibuf->rect_float == NULL) {
651                 ibuf->rect_float = rect_float;
652                 ibuf->mall |= IB_rectfloat;
653                 ibuf->flags |= IB_rectfloat;
654         }
655 }
656
657 /**************************** Color to Grayscale *****************************/
658
659 /* no profile conversion */
660 void IMB_color_to_bw(ImBuf *ibuf)
661 {
662         float *rct_fl = ibuf->rect_float;
663         uchar *rct = (uchar *)ibuf->rect;
664         int i;
665
666         if (rct_fl) {
667                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct_fl += 4)
668                         rct_fl[0] = rct_fl[1] = rct_fl[2] = rgb_to_grayscale(rct_fl);
669         }
670
671         if (rct) {
672                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct += 4)
673                         rct[0] = rct[1] = rct[2] = rgb_to_grayscale_byte(rct);
674         }
675 }
676
677 void IMB_buffer_float_clamp(float *buf, int width, int height)
678 {
679         int i, total = width * height * 4;
680         for (i = 0; i < total; i++) {
681                 buf[i] = min_ff(1.0, buf[i]);
682         }
683 }
684
685 void IMB_buffer_float_unpremultiply(float *buf, int width, int height)
686 {
687         int total = width * height;
688         float *fp = buf;
689         while (total--) {
690                 premul_to_straight_v4(fp);
691                 fp += 4;
692         }
693 }
694
695 void IMB_buffer_float_premultiply(float *buf, int width, int height)
696 {
697         int total = width * height;
698         float *fp = buf;
699         while (total--) {
700                 straight_to_premul_v4(fp);
701                 fp += 4;
702         }
703 }
704
705 /**************************** alter saturation *****************************/
706
707 void IMB_saturation(ImBuf *ibuf, float sat)
708 {
709         int i;
710         unsigned char *rct = (unsigned char *)ibuf->rect;
711         float *rct_fl = ibuf->rect_float;
712         float hsv[3];
713
714         if (rct) {
715                 float rgb[3];
716                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct += 4) {
717                         rgb_uchar_to_float(rgb, rct);
718                         rgb_to_hsv_v(rgb, hsv);
719                         hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rgb, rgb + 1, rgb + 2);
720                         rgb_float_to_uchar(rct, rgb);
721                 }
722         }
723
724         if (rct_fl) {
725                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct_fl += 4) {
726                         rgb_to_hsv_v(rct_fl, hsv);
727                         hsv_to_rgb(hsv[0], hsv[1] * sat, hsv[2], rct_fl, rct_fl + 1, rct_fl + 2);
728                 }
729         }
730 }