Fix msvc 2013 compiler errors after the ingenious cleanup in 4ca67869cc7a.
[blender.git] / source / blender / imbuf / intern / radiance_hdr.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
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  */
27
28 /** \file blender/imbuf/intern/radiance_hdr.c
29  *  \ingroup imbuf
30  */
31
32 /* ----------------------------------------------------------------------
33  * Radiance High Dynamic Range image file IO
34  * For description and code for reading/writing of radiance hdr files
35  * by Greg Ward, refer to:
36  * http://radsite.lbl.gov/radiance/refer/Notes/picture_format.html
37  * ----------------------------------------------------------------------
38  */
39
40 #ifdef WIN32
41 #  include <io.h>
42 #endif
43
44 #include "MEM_guardedalloc.h"
45
46 #include "BLI_fileops.h"
47
48 #include "imbuf.h"
49
50 #include "IMB_imbuf_types.h"
51 #include "IMB_imbuf.h"
52
53 #include "IMB_allocimbuf.h"
54 #include "IMB_filetype.h"
55
56 #include "IMB_colormanagement.h"
57 #include "IMB_colormanagement_intern.h"
58
59 /* needed constants */
60 #define MINELEN 8
61 #define MAXELEN 0x7fff
62 #define MINRUN  4   /* minimum run length */
63 #define RED 0
64 #define GRN 1
65 #define BLU 2
66 #define EXP 3
67 #define COLXS 128
68 typedef unsigned char RGBE[4];
69 typedef float fCOLOR[3];
70
71 /* copy source -> dest */
72 #define COPY_RGBE(c1, c2) (c2[RED] = c1[RED], c2[GRN] = c1[GRN], c2[BLU] = c1[BLU], c2[EXP] = c1[EXP])
73
74 /* read routines */
75 static unsigned char *oldreadcolrs(RGBE *scan, unsigned char *mem, int xmax)
76 {
77         int i, rshift = 0, len = xmax;
78         while (len > 0) {
79                 scan[0][RED] = *mem++;
80                 scan[0][GRN] = *mem++;
81                 scan[0][BLU] = *mem++;
82                 scan[0][EXP] = *mem++;
83                 if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) {
84                         for (i = scan[0][EXP] << rshift; i > 0; i--) {
85                                 COPY_RGBE(scan[-1], scan[0]);
86                                 scan++;
87                                 len--;
88                         }
89                         rshift += 8;
90                 }
91                 else {
92                         scan++;
93                         len--;
94                         rshift = 0;
95                 }
96         }
97         return mem;
98 }
99
100 static unsigned char *freadcolrs(RGBE *scan, unsigned char *mem, int xmax)
101 {
102         int i, j, code, val;
103
104         if ((xmax < MINELEN) | (xmax > MAXELEN)) return oldreadcolrs(scan, mem, xmax);
105
106         i = *mem++;
107         if (i != 2) return oldreadcolrs(scan, mem - 1, xmax);
108
109         scan[0][GRN] = *mem++;
110         scan[0][BLU] = *mem++;
111
112         i = *mem++;
113         if (((scan[0][BLU] << 8) | i) != xmax) return NULL;
114
115         for (i = 0; i < 4; i++)
116                 for (j = 0; j < xmax; ) {
117                         code = *mem++;
118                         if (code > 128) {
119                                 code &= 127;
120                                 val = *mem++;
121                                 while (code--)
122                                         scan[j++][i] = (unsigned char)val;
123                         }
124                         else
125                                 while (code--)
126                                         scan[j++][i] = *mem++;
127                 }
128         return mem;
129 }
130
131 /* helper functions */
132
133 /* rgbe -> float color */
134 static void RGBE2FLOAT(RGBE rgbe, fCOLOR fcol)
135 {
136         if (rgbe[EXP] == 0) {
137                 fcol[RED] = fcol[GRN] = fcol[BLU] = 0;
138         }
139         else {
140                 float f = ldexp(1.0, rgbe[EXP] - (COLXS + 8));
141                 fcol[RED] = f * (rgbe[RED] + 0.5f);
142                 fcol[GRN] = f * (rgbe[GRN] + 0.5f);
143                 fcol[BLU] = f * (rgbe[BLU] + 0.5f);
144         }
145 }
146
147 /* float color -> rgbe */
148 static void FLOAT2RGBE(fCOLOR fcol, RGBE rgbe)
149 {
150         int e;
151         float d = (fcol[RED] > fcol[GRN]) ? fcol[RED] : fcol[GRN];
152         if (fcol[BLU] > d) d = fcol[BLU];
153         if (d <= 1e-32f)
154                 rgbe[RED] = rgbe[GRN] = rgbe[BLU] = rgbe[EXP] = 0;
155         else {
156                 d = (float)frexp(d, &e) * 256.0f / d;
157                 rgbe[RED] = (unsigned char)(fcol[RED] * d);
158                 rgbe[GRN] = (unsigned char)(fcol[GRN] * d);
159                 rgbe[BLU] = (unsigned char)(fcol[BLU] * d);
160                 rgbe[EXP] = (unsigned char)(e + COLXS);
161         }
162 }
163
164 /* ImBuf read */
165
166 int imb_is_a_hdr(unsigned char *buf)
167 {
168         /* For recognition, Blender only loads first 32 bytes, so use #?RADIANCE id instead */
169         /* update: actually, the 'RADIANCE' part is just an optional program name, the magic word is really only the '#?' part */
170         //if (strstr((char *)buf, "#?RADIANCE")) return 1;
171         if (strstr((char *)buf, "#?")) return 1;
172         // if (strstr((char *)buf, "32-bit_rle_rgbe")) return 1;
173         return 0;
174 }
175
176 struct ImBuf *imb_loadhdr(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
177 {
178         struct ImBuf *ibuf;
179         RGBE *sline;
180         fCOLOR fcol;
181         float *rect_float;
182         int found = 0;
183         int width = 0, height = 0;
184         int x, y;
185         unsigned char *ptr;
186         char oriY[80], oriX[80];
187
188         if (imb_is_a_hdr((void *)mem)) {
189                 colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT);
190
191                 /* find empty line, next line is resolution info */
192                 for (x = 1; x < size; x++) {
193                         if ((mem[x - 1] == '\n') && (mem[x] == '\n')) {
194                                 found = 1;
195                                 break;
196                         }
197                 }
198                 if (found && (x < (size + 2))) {
199                         if (sscanf((char *)&mem[x + 1], "%79s %d %79s %d", (char *)&oriY, &height,
200                                    (char *)&oriX, &width) != 4)
201                         {
202                                 return NULL;
203                         }
204
205                         /* find end of this line, data right behind it */
206                         ptr = (unsigned char *)strchr((char *)&mem[x + 1], '\n');
207                         ptr++;
208
209                         if (flags & IB_test) ibuf = IMB_allocImBuf(width, height, 32, 0);
210                         else ibuf = IMB_allocImBuf(width, height, 32, (flags & IB_rect) | IB_rectfloat);
211
212                         if (ibuf == NULL) return NULL;
213                         ibuf->ftype = RADHDR;
214
215                         if (flags & IB_alphamode_detect)
216                                 ibuf->flags |= IB_alphamode_premul;
217
218                         if (flags & IB_test) return ibuf;
219
220                         /* read in and decode the actual data */
221                         sline = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_read_tmpscan");
222                         rect_float = ibuf->rect_float;
223                         
224                         for (y = 0; y < height; y++) {
225                                 ptr = freadcolrs(sline, ptr, width);
226                                 if (ptr == NULL) {
227                                         printf("HDR decode error\n");
228                                         MEM_freeN(sline);
229                                         return ibuf;
230                                 }
231                                 for (x = 0; x < width; x++) {
232                                         /* convert to ldr */
233                                         RGBE2FLOAT(sline[x], fcol);
234                                         *rect_float++ = fcol[RED];
235                                         *rect_float++ = fcol[GRN];
236                                         *rect_float++ = fcol[BLU];
237                                         *rect_float++ = 1.0f;
238                                 }
239                         }
240                         MEM_freeN(sline);
241                         if (oriY[0] == '-') IMB_flipy(ibuf);
242                         
243                         if (flags & IB_rect) {
244                                 IMB_rect_from_float(ibuf);
245                         }
246                         
247                         return ibuf;
248                 }
249                 //else printf("Data not found!\n");
250         }
251         //else printf("Not a valid radiance HDR file!\n");
252
253         return NULL;
254 }
255
256 /* ImBuf write */
257 static int fwritecolrs(FILE *file, int width, int channels, unsigned char *ibufscan, float *fpscan)
258 {
259         int x, i, j, beg, c2, cnt = 0;
260         fCOLOR fcol;
261         RGBE rgbe, *rgbe_scan;
262
263         if ((ibufscan == NULL) && (fpscan == NULL)) return 0;
264
265         rgbe_scan = (RGBE *)MEM_mallocN(sizeof(RGBE) * width, "radhdr_write_tmpscan");
266
267         /* convert scanline */
268         j = 0;
269         for (i = 0; i < width; i++) {
270                 if (fpscan) {
271                         fcol[RED] = fpscan[j];
272                         fcol[GRN] = (channels >= 2) ? fpscan[j + 1] : fpscan[j];
273                         fcol[BLU] = (channels >= 3) ? fpscan[j + 2] : fpscan[j];
274                 }
275                 else {
276                         fcol[RED] = (float)ibufscan[j] / 255.f;
277                         fcol[GRN] = (float)((channels >= 2) ? ibufscan[j + 1] : ibufscan[j]) / 255.f;
278                         fcol[BLU] = (float)((channels >= 3) ? ibufscan[j + 2] : ibufscan[j]) / 255.f;
279                 }
280                 FLOAT2RGBE(fcol, rgbe);
281                 COPY_RGBE(rgbe, rgbe_scan[i]);
282                 j += channels;
283         }
284
285         if ((width < MINELEN) | (width > MAXELEN)) {    /* OOBs, write out flat */
286                 x = fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width;
287                 MEM_freeN(rgbe_scan);
288                 return x;
289         }
290         /* put magic header */
291         putc(2, file);
292         putc(2, file);
293         putc((unsigned char)(width >> 8), file);
294         putc((unsigned char)(width & 255), file);
295         /* put components separately */
296         for (i = 0; i < 4; i++) {
297                 for (j = 0; j < width; j += cnt) {  /* find next run */
298                         for (beg = j; beg < width; beg += cnt) {
299                                 for (cnt = 1; (cnt < 127) && ((beg + cnt) < width) && (rgbe_scan[beg + cnt][i] == rgbe_scan[beg][i]); cnt++) ;
300                                 if (cnt >= MINRUN) break;  /* long enough */
301                         }
302                         if (((beg - j) > 1) && ((beg - j) < MINRUN)) {
303                                 c2 = j + 1;
304                                 while (rgbe_scan[c2++][i] == rgbe_scan[j][i])
305                                         if (c2 == beg) {        /* short run */
306                                                 putc((unsigned char)(128 + beg - j), file);
307                                                 putc((unsigned char)(rgbe_scan[j][i]), file);
308                                                 j = beg;
309                                                 break;
310                                         }
311                         }
312                         while (j < beg) {     /* write out non-run */
313                                 if ((c2 = beg - j) > 128) c2 = 128;
314                                 putc((unsigned char)(c2), file);
315                                 while (c2--) putc(rgbe_scan[j++][i], file);
316                         }
317                         if (cnt >= MINRUN) {      /* write out run */
318                                 putc((unsigned char)(128 + cnt), file);
319                                 putc(rgbe_scan[beg][i], file);
320                         }
321                         else {
322                                 cnt = 0;
323                         }
324                 }
325         }
326         MEM_freeN(rgbe_scan);
327         return(ferror(file) ? -1 : 0);
328 }
329
330 static void writeHeader(FILE *file, int width, int height)
331 {
332         fprintf(file, "#?RADIANCE");
333         fputc(10, file);
334         fprintf(file, "# %s", "Created with Blender");
335         fputc(10, file);
336         fprintf(file, "EXPOSURE=%25.13f", 1.0);
337         fputc(10, file);
338         fprintf(file, "FORMAT=32-bit_rle_rgbe");
339         fputc(10, file);
340         fputc(10, file);
341         fprintf(file, "-Y %d +X %d", height, width);
342         fputc(10, file);
343 }
344
345 int imb_savehdr(struct ImBuf *ibuf, const char *name, int flags)
346 {
347         FILE *file = BLI_fopen(name, "wb");
348         float *fp = NULL;
349         int y, width = ibuf->x, height = ibuf->y;
350         unsigned char *cp = NULL;
351         
352         (void)flags; /* unused */
353         
354         if (file == NULL) return 0;
355
356         writeHeader(file, width, height);
357
358         if (ibuf->rect)
359                 cp = (unsigned char *)ibuf->rect + ibuf->channels * (height - 1) * width;
360         if (ibuf->rect_float)
361                 fp = ibuf->rect_float + ibuf->channels * (height - 1) * width;
362         
363         for (y = height - 1; y >= 0; y--) {
364                 if (fwritecolrs(file, width, ibuf->channels, cp, fp) < 0) {
365                         fclose(file);
366                         printf("HDR write error\n");
367                         return 0;
368                 }
369                 if (cp) cp -= ibuf->channels * width;
370                 if (fp) fp -= ibuf->channels * width;
371         }
372
373         fclose(file);
374         return 1;
375 }