imbuf, mathutils & readfile: floats were being implicitly promoted to doubles, adjust...
[blender.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 static void imb_float_from_rect_nonlinear(struct ImBuf *ibuf, float *fbuf)
201 {
202         float *tof = fbuf;
203         int i;
204         unsigned char *to = (unsigned char *) ibuf->rect;
205
206         for (i = ibuf->x * ibuf->y; i > 0; i--) 
207         {
208                 tof[0] = ((float)to[0])*(1.0f/255.0f);
209                 tof[1] = ((float)to[1])*(1.0f/255.0f);
210                 tof[2] = ((float)to[2])*(1.0f/255.0f);
211                 tof[3] = ((float)to[3])*(1.0f/255.0f);
212                 to += 4; 
213                 tof += 4;
214         }
215 }
216
217
218 static void imb_float_from_rect_linear(struct ImBuf *ibuf, float *fbuf)
219 {
220         float *tof = fbuf;
221         int i;
222         unsigned char *to = (unsigned char *) ibuf->rect;
223
224         for (i = ibuf->x * ibuf->y; i > 0; i--) 
225         {
226                 tof[0] = srgb_to_linearrgb(((float)to[0])*(1.0f/255.0f));
227                 tof[1] = srgb_to_linearrgb(((float)to[1])*(1.0f/255.0f));
228                 tof[2] = srgb_to_linearrgb(((float)to[2])*(1.0f/255.0f));
229                 tof[3] = ((float)to[3])*(1.0f/255.0f);
230                 to += 4; 
231                 tof += 4;
232         }
233 }
234
235 void IMB_float_from_rect(struct ImBuf *ibuf)
236 {
237         /* quick method to convert byte to floatbuf */
238         if(ibuf->rect==NULL) return;
239         if(ibuf->rect_float==NULL) {
240                 if (imb_addrectfloatImBuf(ibuf) == 0) return;
241         }
242         
243         /* Float bufs should be stored linear */
244
245         if (ibuf->profile != IB_PROFILE_NONE) {
246                 /* if the image has been given a profile then we're working 
247                  * with color management in mind, so convert it to linear space */
248                 imb_float_from_rect_linear(ibuf, ibuf->rect_float);
249         } else {
250                 imb_float_from_rect_nonlinear(ibuf, ibuf->rect_float);
251         }
252 }
253
254 /* no profile conversion */
255 void IMB_float_from_rect_simple(struct ImBuf *ibuf)
256 {
257         if(ibuf->rect_float==NULL)
258                 imb_addrectfloatImBuf(ibuf);
259         imb_float_from_rect_nonlinear(ibuf, ibuf->rect_float);
260 }
261
262 void IMB_convert_profile(struct ImBuf *ibuf, int profile)
263 {
264         int ok= FALSE;
265         int i;
266
267         unsigned char *rct= (unsigned char *)ibuf->rect;
268         float *rctf= ibuf->rect_float;
269
270         if(ibuf->profile == profile)
271                 return;
272
273         if(ELEM(ibuf->profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { /* from */
274                 if(profile == IB_PROFILE_LINEAR_RGB) { /* to */
275                         if(ibuf->rect_float) {
276                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) {
277                                         rctf[0]= srgb_to_linearrgb(rctf[0]);
278                                         rctf[1]= srgb_to_linearrgb(rctf[1]);
279                                         rctf[2]= srgb_to_linearrgb(rctf[2]);
280                                 }
281                         }
282                         if(ibuf->rect) {
283                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) {
284                                         rct[0]= (unsigned char)((srgb_to_linearrgb((float)rct[0]/255.0f) * 255.0f) + 0.5f);
285                                         rct[1]= (unsigned char)((srgb_to_linearrgb((float)rct[1]/255.0f) * 255.0f) + 0.5f);
286                                         rct[2]= (unsigned char)((srgb_to_linearrgb((float)rct[2]/255.0f) * 255.0f) + 0.5f);
287                                 }
288                         }
289                         ok= TRUE;
290                 }
291         }
292         else if (ibuf->profile == IB_PROFILE_LINEAR_RGB) { /* from */
293                 if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { /* to */
294                         if(ibuf->rect_float) {
295                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) {
296                                         rctf[0]= linearrgb_to_srgb(rctf[0]);
297                                         rctf[1]= linearrgb_to_srgb(rctf[1]);
298                                         rctf[2]= linearrgb_to_srgb(rctf[2]);
299                                 }
300                         }
301                         if(ibuf->rect) {
302                                 for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) {
303                                         rct[0]= (unsigned char)((linearrgb_to_srgb((float)rct[0]/255.0f) * 255.0f) + 0.5f);
304                                         rct[1]= (unsigned char)((linearrgb_to_srgb((float)rct[1]/255.0f) * 255.0f) + 0.5f);
305                                         rct[2]= (unsigned char)((linearrgb_to_srgb((float)rct[2]/255.0f) * 255.0f) + 0.5f);
306                                 }
307                         }
308                         ok= TRUE;
309                 }
310         }
311
312         if(ok==FALSE){
313                 printf("IMB_convert_profile: failed profile conversion %d -> %d\n", ibuf->profile, profile);
314                 return;
315         }
316
317         ibuf->profile= profile;
318 }
319
320 /* use when you need to get a buffer with a certain profile
321  * if the return  */
322 float *IMB_float_profile_ensure(struct ImBuf *ibuf, int profile, int *alloc)
323 {
324         /* stupid but it works like this everywhere now */
325         const short is_lin_from= (ibuf->profile != IB_PROFILE_NONE);
326         const short is_lin_to= (profile != IB_PROFILE_NONE);
327
328         
329         if(is_lin_from == is_lin_to) {
330                 *alloc= 0;
331
332                 /* simple case, just allocate the buffer and return */
333                 if(ibuf->rect_float == NULL) {
334                         IMB_float_from_rect(ibuf);
335                 }
336
337                 return ibuf->rect_float;
338         }
339         else {
340                 /* conversion is needed, first check */
341                 float *fbuf= MEM_mallocN(ibuf->x * ibuf->y * sizeof(float) * 4, "IMB_float_profile_ensure");
342                 *alloc= 1;
343
344                 if(ibuf->rect_float == NULL) {
345                         if(is_lin_to) {
346                                 imb_float_from_rect_linear(ibuf, fbuf);
347                         }
348                         else {
349                                 imb_float_from_rect_nonlinear(ibuf, fbuf);
350                         }
351                 }
352                 else {
353                         if(is_lin_to) { /* lin -> nonlin */
354                                 linearrgb_to_srgb_rgba_rgba_buf(fbuf, ibuf->rect_float, ibuf->x * ibuf->y);
355                         }
356                         else { /* nonlin -> lin */
357                                 srgb_to_linearrgb_rgba_rgba_buf(fbuf, ibuf->rect_float, ibuf->x * ibuf->y);
358                         }
359                 }
360
361                 return fbuf;
362         }
363 }