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