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