90ee2692cf0323417dbf2af08fbdd8ed7ad87277
[blender-staging.git] / source / blender / imbuf / intern / divers.c
1 /*
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  * allocimbuf.c
28  *
29  * $Id$
30  */
31
32 /** \file blender/imbuf/intern/divers.c
33  *  \ingroup imbuf
34  */
35
36
37 #include "BLI_blenlib.h"
38 #include "BLI_rand.h"
39 #include "BLI_math.h"
40 #include "BLI_utildefines.h"
41
42 #include "imbuf.h"
43 #include "IMB_imbuf_types.h"
44 #include "IMB_imbuf.h"
45 #include "IMB_allocimbuf.h"
46
47 #include "BKE_colortools.h"
48
49 #include "MEM_guardedalloc.h"
50
51 void IMB_de_interlace(struct ImBuf *ibuf)
52 {
53         struct ImBuf * tbuf1, * tbuf2;
54         
55         if (ibuf == NULL) return;
56         if (ibuf->flags & IB_fields) return;
57         ibuf->flags |= IB_fields;
58         
59         if (ibuf->rect) {
60                 /* make copies */
61                 tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
62                 tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
63                 
64                 ibuf->x *= 2;   
65                 IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
66                 IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
67         
68                 ibuf->x /= 2;
69                 IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
70                 IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y);
71                 
72                 IMB_freeImBuf(tbuf1);
73                 IMB_freeImBuf(tbuf2);
74         }
75         ibuf->y /= 2;
76 }
77
78 void IMB_interlace(struct ImBuf *ibuf)
79 {
80         struct ImBuf * tbuf1, * tbuf2;
81
82         if (ibuf == NULL) return;
83         ibuf->flags &= ~IB_fields;
84
85         ibuf->y *= 2;
86
87         if (ibuf->rect) {
88                 /* make copies */
89                 tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
90                 tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect);
91
92                 IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
93                 IMB_rectcpy(tbuf2, ibuf, 0, 0, 0, tbuf2->y, ibuf->x, ibuf->y);
94
95                 ibuf->x *= 2;
96                 IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
97                 IMB_rectcpy(ibuf, tbuf2, tbuf2->x, 0, 0, 0, tbuf2->x, tbuf2->y);
98                 ibuf->x /= 2;
99
100                 IMB_freeImBuf(tbuf1);
101                 IMB_freeImBuf(tbuf2);
102         }
103 }
104
105
106 /* assume converting from linear float to sRGB byte */
107 void IMB_rect_from_float(struct ImBuf *ibuf)
108 {
109         /* quick method to convert floatbuf to byte */
110         float *tof = (float *)ibuf->rect_float;
111 //      int do_dither = ibuf->dither != 0.f;
112         float dither= ibuf->dither / 255.0f;
113         float srgb[4];
114         int i, channels= ibuf->channels;
115         short profile= ibuf->profile;
116         unsigned char *to = (unsigned char *) ibuf->rect;
117         
118         if(tof==NULL) return;
119         if(to==NULL) {
120                 imb_addrectImBuf(ibuf);
121                 to = (unsigned char *) ibuf->rect;
122         }
123         
124         if(channels==1) {
125                 for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof++)
126                         to[1]= to[2]= to[3]= to[0] = FTOCHAR(tof[0]);
127         }
128         else if (profile == IB_PROFILE_LINEAR_RGB) {
129                 if(channels == 3) {
130                         for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) {
131                                 srgb[0]= linearrgb_to_srgb(tof[0]);
132                                 srgb[1]= linearrgb_to_srgb(tof[1]);
133                                 srgb[2]= linearrgb_to_srgb(tof[2]);
134
135                                 to[0] = FTOCHAR(srgb[0]);
136                                 to[1] = FTOCHAR(srgb[1]);
137                                 to[2] = FTOCHAR(srgb[2]);
138                                 to[3] = 255;
139                         }
140                 }
141                 else if (channels == 4) {
142                         if (dither != 0.f) {
143                                 for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
144                                         const float d = (BLI_frand()-0.5f)*dither;
145                                         
146                                         srgb[0]= d + linearrgb_to_srgb(tof[0]);
147                                         srgb[1]= d + linearrgb_to_srgb(tof[1]);
148                                         srgb[2]= d + linearrgb_to_srgb(tof[2]);
149                                         srgb[3]= d + tof[3]; 
150                                         
151                                         to[0] = FTOCHAR(srgb[0]);
152                                         to[1] = FTOCHAR(srgb[1]);
153                                         to[2] = FTOCHAR(srgb[2]);
154                                         to[3] = FTOCHAR(srgb[3]);
155                                 }
156                         } else {
157                                 floatbuf_to_srgb_byte(tof, to, 0, ibuf->x, 0, ibuf->y, ibuf->x);
158                         }
159                 }
160         }
161         else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) {
162                 if(channels==3) {
163                         for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) {
164                                 to[0] = FTOCHAR(tof[0]);
165                                 to[1] = FTOCHAR(tof[1]);
166                                 to[2] = FTOCHAR(tof[2]);
167                                 to[3] = 255;
168                         }
169                 }
170                 else {
171                         if (dither != 0.f) {
172                                 for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
173                                         const float d = (BLI_frand()-0.5f)*dither;
174                                         float col[4];
175
176                                         col[0]= d + tof[0];
177                                         col[1]= d + tof[1];
178                                         col[2]= d + tof[2];
179                                         col[3]= d + tof[3];
180
181                                         to[0] = FTOCHAR(col[0]);
182                                         to[1] = FTOCHAR(col[1]);
183                                         to[2] = FTOCHAR(col[2]);
184                                         to[3] = FTOCHAR(col[3]);
185                                 }
186                         } else {
187                                 for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
188                                         to[0] = FTOCHAR(tof[0]);
189                                         to[1] = FTOCHAR(tof[1]);
190                                         to[2] = FTOCHAR(tof[2]);
191                                         to[3] = FTOCHAR(tof[3]);
192                                 }
193                         }
194                 }
195         }
196         /* ensure user flag is reset */
197         ibuf->userflags &= ~IB_RECT_INVALID;
198 }
199
200  
201
202 /* converts from linear float to sRGB byte for part of the texture, buffer will hold the changed part */
203 void IMB_partial_rect_from_float(struct ImBuf *ibuf,float *buffer, int x, int y, int w, int h)
204 {
205         /* indices to source and destination image pixels */
206         float *srcFloatPxl;
207         unsigned char *dstBytePxl;
208         /* buffer index will fill buffer */
209         float *bufferIndex;
210
211         /* convenience pointers to start of image buffers */
212         float *init_srcFloatPxl = (float *)ibuf->rect_float;
213         unsigned char *init_dstBytePxl = (unsigned char *) ibuf->rect;
214
215         /* Dithering factor */
216         float dither= ibuf->dither / 255.0f;
217         /* respective attributes of image */
218         short profile= ibuf->profile;
219         int channels= ibuf->channels;
220         
221         int i, j;
222         
223         /*
224                 if called -only- from GPU_paint_update_image this test will never fail
225                 but leaving it here for better or worse
226         */
227         if(init_srcFloatPxl==NULL || (buffer == NULL)){
228                 return;
229         }
230         if(init_dstBytePxl==NULL) {
231                 imb_addrectImBuf(ibuf);
232                 init_dstBytePxl = (unsigned char *) ibuf->rect;
233         }
234         if(channels==1) {
235                         for (j = 0; j < h; j++){
236                                 bufferIndex = buffer + w*j*4;
237                                 dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
238                                 srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x);
239                                 for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl++, bufferIndex+=4) {
240                                         dstBytePxl[1]= dstBytePxl[2]= dstBytePxl[3]= dstBytePxl[0] = FTOCHAR(srcFloatPxl[0]);
241                                         bufferIndex[0] = bufferIndex[1] = bufferIndex[2] = bufferIndex[3] = srcFloatPxl[0];
242                                 }
243                         }
244         }
245         else if (profile == IB_PROFILE_LINEAR_RGB) {
246                 if(channels == 3) {
247                         for (j = 0; j < h; j++){
248                                 bufferIndex = buffer + w*j*4;
249                                 dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
250                                 srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*3;
251                                 for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=3, bufferIndex += 4) {
252                                         linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl);
253                                         F3TOCHAR4(bufferIndex, dstBytePxl);
254                                         bufferIndex[3]= 1.0;
255                                 }
256                         }
257                 }
258                 else if (channels == 4) {
259                         if (dither != 0.f) {
260                                 for (j = 0; j < h; j++){
261                                         bufferIndex = buffer + w*j*4;
262                                         dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
263                                         srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
264                                         for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
265                                                 const float d = (BLI_frand()-0.5f)*dither;
266                                                 linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl);
267                                                 bufferIndex[3] = srcFloatPxl[3];
268                                                 add_v4_fl(bufferIndex, d);
269                                                 F4TOCHAR4(bufferIndex, dstBytePxl);
270                                         }
271                                 }
272                         } else {
273                                 for (j = 0; j < h; j++){
274                                         bufferIndex = buffer + w*j*4;
275                                         dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
276                                         srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
277                                         for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
278                                                 linearrgb_to_srgb_v3_v3(bufferIndex, srcFloatPxl);
279                                                 bufferIndex[3]= srcFloatPxl[3];
280                                                 F4TOCHAR4(bufferIndex, dstBytePxl);
281                                         }
282                                 }
283                         }
284                 }
285         }
286         else if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) {
287                 if(channels==3) {
288                         for (j = 0; j < h; j++){
289                                 bufferIndex = buffer + w*j*4;
290                                 dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
291                                 srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*3;
292                                 for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=3, bufferIndex+=4) {
293                                         copy_v3_v3(bufferIndex, srcFloatPxl);
294                                         F3TOCHAR4(bufferIndex, dstBytePxl);
295                                         bufferIndex[3] = 1.0;
296                                 }
297                         }
298                 }
299                 else {
300                         if (dither != 0.f) {
301                                 for (j = 0; j < h; j++){
302                                         bufferIndex = buffer + w*j*4;
303                                         dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
304                                         srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
305                                         for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
306                                                 const float d = (BLI_frand()-0.5f)*dither;
307                                                 copy_v4_v4(bufferIndex, srcFloatPxl);
308                                                 add_v4_fl(bufferIndex,d);
309                                                 F4TOCHAR4(bufferIndex, dstBytePxl);
310                                         }
311                                 }
312                         } else {
313                                 for (j = 0; j < h; j++){
314                                         bufferIndex = buffer + w*j*4;
315                                         dstBytePxl = init_dstBytePxl + (ibuf->x*(y + j) + x)*4;
316                                         srcFloatPxl = init_srcFloatPxl + (ibuf->x*(y + j) + x)*4;
317                                         for(i = 0;  i < w; i++, dstBytePxl+=4, srcFloatPxl+=4, bufferIndex+=4) {
318                                                 copy_v4_v4(bufferIndex, srcFloatPxl);
319                                                 F4TOCHAR4(bufferIndex, dstBytePxl);
320                                         }
321                                 }
322                         }
323                 }
324         }
325         /* ensure user flag is reset */
326         ibuf->userflags &= ~IB_RECT_INVALID;
327 }
328
329 static void imb_float_from_rect_nonlinear(struct ImBuf *ibuf, float *fbuf)
330 {
331         float *tof = fbuf;
332         int i;
333         unsigned char *to = (unsigned char *) ibuf->rect;
334
335         for (i = ibuf->x * ibuf->y; i > 0; i--) 
336         {
337                 tof[0] = ((float)to[0])*(1.0f/255.0f);
338                 tof[1] = ((float)to[1])*(1.0f/255.0f);
339                 tof[2] = ((float)to[2])*(1.0f/255.0f);
340                 tof[3] = ((float)to[3])*(1.0f/255.0f);
341                 to += 4; 
342                 tof += 4;
343         }
344 }
345
346
347 static void imb_float_from_rect_linear(struct ImBuf *ibuf, float *fbuf)
348 {
349         float *tof = fbuf;
350         int i;
351         unsigned char *to = (unsigned char *) ibuf->rect;
352
353         for (i = ibuf->x * ibuf->y; i > 0; i--) 
354         {
355                 tof[0] = srgb_to_linearrgb(((float)to[0])*(1.0f/255.0f));
356                 tof[1] = srgb_to_linearrgb(((float)to[1])*(1.0f/255.0f));
357                 tof[2] = srgb_to_linearrgb(((float)to[2])*(1.0f/255.0f));
358                 tof[3] = ((float)to[3])*(1.0f/255.0f);
359                 to += 4; 
360                 tof += 4;
361         }
362 }
363
364 void IMB_float_from_rect(struct ImBuf *ibuf)
365 {
366         /* quick method to convert byte to floatbuf */
367         if(ibuf->rect==NULL) return;
368         if(ibuf->rect_float==NULL) {
369                 if (imb_addrectfloatImBuf(ibuf) == 0) return;
370         }
371         
372         /* Float bufs should be stored linear */
373
374         if (ibuf->profile != IB_PROFILE_NONE) {
375                 /* if the image has been given a profile then we're working 
376                  * with color management in mind, so convert it to linear space */
377                 imb_float_from_rect_linear(ibuf, ibuf->rect_float);
378         } else {
379                 imb_float_from_rect_nonlinear(ibuf, ibuf->rect_float);
380         }
381 }
382
383 /* no profile conversion */
384 void IMB_float_from_rect_simple(struct ImBuf *ibuf)
385 {
386         if(ibuf->rect_float==NULL)
387                 imb_addrectfloatImBuf(ibuf);
388         imb_float_from_rect_nonlinear(ibuf, ibuf->rect_float);
389 }
390
391 void IMB_convert_profile(struct ImBuf *ibuf, int profile)
392 {
393         int ok= FALSE;
394         int i;
395
396         unsigned char *rct= (unsigned char *)ibuf->rect;
397         float *rctf= ibuf->rect_float;
398
399         if(ibuf->profile == profile)
400                 return;
401
402         if(ELEM(ibuf->profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { /* from */
403                 if(profile == IB_PROFILE_LINEAR_RGB) { /* to */
404                         if(ibuf->rect_float) {
405                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) {
406                                         rctf[0]= srgb_to_linearrgb(rctf[0]);
407                                         rctf[1]= srgb_to_linearrgb(rctf[1]);
408                                         rctf[2]= srgb_to_linearrgb(rctf[2]);
409                                 }
410                         }
411                         if(ibuf->rect) {
412                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) {
413                                         rct[0]= (unsigned char)((srgb_to_linearrgb((float)rct[0]/255.0f) * 255.0f) + 0.5f);
414                                         rct[1]= (unsigned char)((srgb_to_linearrgb((float)rct[1]/255.0f) * 255.0f) + 0.5f);
415                                         rct[2]= (unsigned char)((srgb_to_linearrgb((float)rct[2]/255.0f) * 255.0f) + 0.5f);
416                                 }
417                         }
418                         ok= TRUE;
419                 }
420         }
421         else if (ibuf->profile == IB_PROFILE_LINEAR_RGB) { /* from */
422                 if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { /* to */
423                         if(ibuf->rect_float) {
424                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) {
425                                         rctf[0]= linearrgb_to_srgb(rctf[0]);
426                                         rctf[1]= linearrgb_to_srgb(rctf[1]);
427                                         rctf[2]= linearrgb_to_srgb(rctf[2]);
428                                 }
429                         }
430                         if(ibuf->rect) {
431                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) {
432                                         rct[0]= (unsigned char)((linearrgb_to_srgb((float)rct[0]/255.0f) * 255.0f) + 0.5f);
433                                         rct[1]= (unsigned char)((linearrgb_to_srgb((float)rct[1]/255.0f) * 255.0f) + 0.5f);
434                                         rct[2]= (unsigned char)((linearrgb_to_srgb((float)rct[2]/255.0f) * 255.0f) + 0.5f);
435                                 }
436                         }
437                         ok= TRUE;
438                 }
439         }
440
441         if(ok==FALSE){
442                 printf("IMB_convert_profile: failed profile conversion %d -> %d\n", ibuf->profile, profile);
443                 return;
444         }
445
446         ibuf->profile= profile;
447 }
448
449 /* use when you need to get a buffer with a certain profile
450  * if the return  */
451 float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc)
452 {
453         /* stupid but it works like this everywhere now */
454         const short is_lin_from= (ibuf->profile != IB_PROFILE_NONE);
455         const short is_lin_to= (profile != IB_PROFILE_NONE);
456
457         
458         if(is_lin_from == is_lin_to) {
459                 *alloc= 0;
460
461                 /* simple case, just allocate the buffer and return */
462                 if(ibuf->rect_float == NULL) {
463                         IMB_float_from_rect(ibuf);
464                 }
465
466                 return ibuf->rect_float;
467         }
468         else {
469                 /* conversion is needed, first check */
470                 float *fbuf= MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "IMB_float_profile_ensure");
471                 *alloc= 1;
472
473                 if(ibuf->rect_float == NULL) {
474                         if(is_lin_to) {
475                                 imb_float_from_rect_linear(ibuf, fbuf);
476                         }
477                         else {
478                                 imb_float_from_rect_nonlinear(ibuf, fbuf);
479                         }
480                 }
481                 else {
482                         if(is_lin_to) { /* lin -> nonlin */
483                                 linearrgb_to_srgb_rgba_rgba_buf(fbuf, ibuf->rect_float, ibuf->x * ibuf->y);
484                         }
485                         else { /* nonlin -> lin */
486                                 srgb_to_linearrgb_rgba_rgba_buf(fbuf, ibuf->rect_float, ibuf->x * ibuf->y);
487                         }
488                 }
489
490                 return fbuf;
491         }
492 }