Fix for wrong channel number in ImBuf when file node output format is something other...
[blender.git] / source / blender / nodes / composite / nodes / node_composite_outputFile.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) 2006 Blender Foundation.
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/nodes/composite/nodes/node_composite_outputFile.c
29  *  \ingroup cmpnodes
30  */
31
32
33 #include <string.h>
34 #include "BLI_path_util.h"
35
36 #include "BKE_utildefines.h"
37
38 #include "node_composite_util.h"
39
40 #include "IMB_imbuf.h"
41 #include "IMB_imbuf_types.h"
42
43 #include "intern/openexr/openexr_multi.h"
44
45
46 /* **************** OUTPUT FILE ******************** */
47
48 bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, const char *name, ImageFormatData *im_format)
49 {
50         bNodeSocket *sock = nodeAddSocket(ntree, node, SOCK_IN, name, SOCK_RGBA);
51         
52         /* create format data for the input socket */
53         NodeImageMultiFileSocket *sockdata = MEM_callocN(sizeof(NodeImageMultiFileSocket), "socket image format");
54         sock->storage = sockdata;
55         sock->struct_type = SOCK_STRUCT_OUTPUT_FILE;
56         
57         if(im_format) {
58                 sockdata->format= *im_format;
59                 if (BKE_imtype_is_movie(sockdata->format.imtype)) {
60                         sockdata->format.imtype= R_IMF_IMTYPE_OPENEXR;
61                 }
62         }
63         /* use node data format by default */
64         sockdata->use_node_format = 1;
65         
66         return sock;
67 }
68
69 int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node)
70 {
71         NodeImageMultiFile *nimf = node->storage;
72         bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input);
73         
74         if (!sock)
75                 return 0;
76         
77         /* free format data */
78         MEM_freeN(sock->storage);
79         
80         nodeRemoveSocket(ntree, node, sock);
81         return 1;
82 }
83
84 static void init_output_file(bNodeTree *ntree, bNode* node, bNodeTemplate *ntemp)
85 {
86         RenderData *rd = &ntemp->scene->r;
87         NodeImageMultiFile *nimf= MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file");
88         node->storage= nimf;
89
90         BLI_strncpy(nimf->base_path, rd->pic, sizeof(nimf->base_path));
91         nimf->format = rd->im_format;
92         
93         /* add one socket by default */
94         ntreeCompositOutputFileAddSocket(ntree, node, "Image", &rd->im_format);
95 }
96
97 static void free_output_file(bNode *node)
98 {
99         bNodeSocket *sock;
100         
101         /* free storage data in sockets */
102         for (sock=node->inputs.first; sock; sock=sock->next) {
103                 MEM_freeN(sock->storage);
104         }
105         
106         MEM_freeN(node->storage);
107 }
108
109 static void copy_output_file(struct bNode *node, struct bNode *target)
110 {
111         bNodeSocket *sock, *newsock;
112         
113         target->storage = MEM_dupallocN(node->storage);
114         
115         /* duplicate storage data in sockets */
116         for (sock=node->inputs.first, newsock=target->inputs.first; sock && newsock; sock=sock->next, newsock=newsock->next) {
117                 newsock->storage = MEM_dupallocN(sock->storage);
118         }
119 }
120
121 static void update_output_file(bNodeTree *UNUSED(ntree), bNode *node)
122 {
123         bNodeSocket *sock;
124         
125         /* automatically update the socket type based on linked input */
126         for (sock=node->inputs.first; sock; sock=sock->next) {
127                 if (sock->link) {
128                         int linktype = sock->link->fromsock->type;
129                         if (linktype != sock->type)
130                                 nodeSocketSetType(sock, linktype);
131                 }
132         }
133 }
134
135 /* write input data into individual files */
136 static void exec_output_file_singlelayer(RenderData *rd, bNode *node, bNodeStack **in)
137 {
138         Main *bmain= G.main; /* TODO, have this passed along */
139         NodeImageMultiFile *nimf= node->storage;
140         bNodeSocket *sock;
141         int i;
142         int has_preview = 0;
143         
144         for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) {
145                 if (in[i]->data) {
146                         NodeImageMultiFileSocket *sockdata = sock->storage;
147                         ImageFormatData *format = (sockdata->use_node_format ? &nimf->format : &sockdata->format);
148                         char path[FILE_MAX];
149                         char filename[FILE_MAX];
150                         CompBuf *cbuf;
151                         ImBuf *ibuf;
152                         
153                         switch (format->planes) {
154                         case R_IMF_PLANES_BW:
155                                 cbuf = typecheck_compbuf(in[i]->data, CB_VAL);
156                                 break;
157                         case R_IMF_PLANES_RGB:
158                                 cbuf = typecheck_compbuf(in[i]->data, CB_VEC3);
159                                 break;
160                         case R_IMF_PLANES_RGBA:
161                                 cbuf = typecheck_compbuf(in[i]->data, CB_RGBA);
162                                 break;
163                         }
164                         
165                         ibuf = IMB_allocImBuf(cbuf->x, cbuf->y, format->planes, 0);
166                         /* XXX have to set this explicitly it seems */
167                         switch (format->planes) {
168                         case R_IMF_PLANES_BW:   ibuf->channels = 1;     break;
169                         case R_IMF_PLANES_RGB:  ibuf->channels = 3;     break;
170                         case R_IMF_PLANES_RGBA: ibuf->channels = 4;     break;
171                         }
172                         ibuf->rect_float = cbuf->rect;
173                         ibuf->dither = rd->dither_intensity;
174                         
175                         if (rd->color_mgt_flag & R_COLOR_MANAGEMENT)
176                                 ibuf->profile = IB_PROFILE_LINEAR_RGB;
177                         
178                         /* get full path */
179                         BLI_join_dirfile(path, FILE_MAX, nimf->base_path, sock->name);
180                         BKE_makepicstring(filename, path, bmain->name, rd->cfra, format->imtype, (rd->scemode & R_EXTENSION), TRUE);
181                         
182                         if(0 == BKE_write_ibuf(ibuf, filename, format))
183                                 printf("Cannot save Node File Output to %s\n", filename);
184                         else
185                                 printf("Saved: %s\n", filename);
186                         
187                         IMB_freeImBuf(ibuf);
188                         
189                         /* simply pick the first valid input for preview */
190                         if (!has_preview) {
191                                 generate_preview(rd, node, cbuf);
192                                 has_preview = 1;
193                         }
194                         
195                         if(in[i]->data != cbuf) 
196                                 free_compbuf(cbuf);
197                 }
198         }
199 }
200
201 /* write input data into layers */
202 static void exec_output_file_multilayer(RenderData *rd, bNode *node, bNodeStack **in)
203 {
204         Main *bmain= G.main; /* TODO, have this passed along */
205         NodeImageMultiFile *nimf= node->storage;
206         void *exrhandle= IMB_exr_get_handle();
207         char filename[FILE_MAX];
208         bNodeSocket *sock;
209         int i;
210         /* Must have consistent pixel size for exr file, simply take the first valid input size. */
211         int rectx = -1;
212         int recty = -1;
213         int has_preview = 0;
214         
215         BKE_makepicstring(filename, nimf->base_path, bmain->name, rd->cfra, R_IMF_IMTYPE_MULTILAYER, (rd->scemode & R_EXTENSION), TRUE);
216         BLI_make_existing_file(filename);
217         
218         for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) {
219                 if (in[i]->data) {
220                         CompBuf *cbuf = in[i]->data;
221                         char layname[EXR_LAY_MAXNAME];
222                         char channelname[EXR_PASS_MAXNAME];
223                         char *channelname_ext;
224                         
225                         if (cbuf->rect_procedural) {
226                                 printf("Error writing multilayer EXR: Procedural buffer not supported\n");
227                                 continue;
228                         }
229                         if (rectx < 0) {
230                                 rectx = cbuf->x;
231                                 recty = cbuf->y;
232                         }
233                         else if (cbuf->x != rectx || cbuf->y != recty) {
234                                 printf("Error: Multilayer EXR output node %s expects same resolution for all input buffers. Layer %s skipped.\n", node->name, sock->name);
235                                 continue;
236                         }
237                         
238                         BLI_strncpy(layname, sock->name, sizeof(layname));
239                         BLI_strncpy(channelname, sock->name, sizeof(channelname)-2);
240                         channelname_ext = channelname + strlen(channelname);
241                         
242                         /* create channels */
243                         switch (cbuf->type) {
244                         case CB_VAL:
245                                 strcpy(channelname_ext, ".V");
246                                 IMB_exr_add_channel(exrhandle, layname, channelname, 1, rectx, cbuf->rect);
247                                 break;
248                         case CB_VEC2:
249                                 strcpy(channelname_ext, ".X");
250                                 IMB_exr_add_channel(exrhandle, layname, channelname, 2, 2*rectx, cbuf->rect);
251                                 strcpy(channelname_ext, ".Y");
252                                 IMB_exr_add_channel(exrhandle, layname, channelname, 2, 2*rectx, cbuf->rect+1);
253                                 break;
254                         case CB_VEC3:
255                                 strcpy(channelname_ext, ".X");
256                                 IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect);
257                                 strcpy(channelname_ext, ".Y");
258                                 IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect+1);
259                                 strcpy(channelname_ext, ".Z");
260                                 IMB_exr_add_channel(exrhandle, layname, channelname, 3, 3*rectx, cbuf->rect+2);
261                                 break;
262                         case CB_RGBA:
263                                 strcpy(channelname_ext, ".R");
264                                 IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect);
265                                 strcpy(channelname_ext, ".G");
266                                 IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+1);
267                                 strcpy(channelname_ext, ".B");
268                                 IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+2);
269                                 strcpy(channelname_ext, ".A");
270                                 IMB_exr_add_channel(exrhandle, layname, channelname, 4, 4*rectx, cbuf->rect+3);
271                                 break;
272                         }
273                         
274                         /* simply pick the first valid input for preview */
275                         if (!has_preview) {
276                                 generate_preview(rd, node, cbuf);
277                                 has_preview = 1;
278                         }
279                 }
280         }
281         
282         /* when the filename has no permissions, this can fail */
283         if(IMB_exr_begin_write(exrhandle, filename, rectx, recty, nimf->format.compress)) {
284                 IMB_exr_write_channels(exrhandle);
285         }
286         else {
287                 /* TODO, get the error from openexr's exception */
288                 /* XXX nice way to do report? */
289                 printf("Error Writing Render Result, see console\n");
290         }
291         
292         IMB_exr_close(exrhandle);
293 }
294
295 static void exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
296 {
297         RenderData *rd= data;
298         NodeImageMultiFile *nimf= node->storage;
299         
300         if (!G.rendering) {
301                 /* only output files when rendering a sequence -
302                  * otherwise, it overwrites the output files just 
303                  * scrubbing through the timeline when the compositor updates */
304                 return;
305         }
306         
307         if (nimf->format.imtype==R_IMF_IMTYPE_MULTILAYER)
308                 exec_output_file_multilayer(rd, node, in);
309         else
310                 exec_output_file_singlelayer(rd, node, in);
311 }
312
313 void register_node_type_cmp_output_file(bNodeTreeType *ttype)
314 {
315         static bNodeType ntype;
316
317         node_type_base(ttype, &ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_OPTIONS|NODE_PREVIEW);
318         node_type_socket_templates(&ntype, NULL, NULL);
319         node_type_size(&ntype, 140, 80, 300);
320         node_type_init(&ntype, init_output_file);
321         node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file);
322         node_type_update(&ntype, update_output_file, NULL);
323         node_type_exec(&ntype, exec_output_file);
324
325         nodeRegisterType(ttype, &ntype);
326 }