Implements a new operator for detaching nodes. In the process i overhauled the node...
[blender-staging.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 /* **************** OUTPUT FILE ******************** */
41 static bNodeSocketTemplate cmp_node_output_file_in[]= {
42         {       SOCK_RGBA, 1, "Image",          0.0f, 0.0f, 0.0f, 1.0f},
43         {       SOCK_FLOAT, 1, "Z",             0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
44         {       -1, 0, ""       }
45 };
46
47 static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
48 {
49         /* image assigned to output */
50         /* stack order input sockets: col, alpha */
51         
52         if(in[0]->data) {
53                 RenderData *rd= data;
54                 NodeImageFile *nif= node->storage;
55                 if(nif->sfra!=nif->efra && (rd->cfra<nif->sfra || rd->cfra>nif->efra)) {
56                         return; /* BAIL OUT RETURN */
57                 }
58                 else if (!G.rendering) {
59                         /* only output files when rendering a sequence -
60                          * otherwise, it overwrites the output files just 
61                          * scrubbing through the timeline when the compositor updates */
62                         return;
63                 } else {
64                         Main *bmain= G.main; /* TODO, have this passed along */
65                         CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
66                         ImBuf *ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0);
67                         char string[FILE_MAX];
68                         
69                         ibuf->rect_float= cbuf->rect;
70                         ibuf->dither= rd->dither_intensity;
71                         
72                         if (rd->color_mgt_flag & R_COLOR_MANAGEMENT)
73                                 ibuf->profile = IB_PROFILE_LINEAR_RGB;
74                         
75                         if(in[1]->data) {
76                                 CompBuf *zbuf= in[1]->data;
77                                 if(zbuf->type==CB_VAL && zbuf->x==cbuf->x && zbuf->y==cbuf->y) {
78                                         nif->im_format.flag |= R_IMF_FLAG_ZBUF;
79                                         ibuf->zbuf_float= zbuf->rect;
80                                 }
81                         }
82                         
83                         BKE_makepicstring(string, nif->name, bmain->name, rd->cfra, nif->im_format.imtype, (rd->scemode & R_EXTENSION), TRUE);
84                         
85                         if(0 == BKE_write_ibuf(ibuf, string, &nif->im_format))
86                                 printf("Cannot save Node File Output to %s\n", string);
87                         else
88                                 printf("Saved: %s\n", string);
89                         
90                         IMB_freeImBuf(ibuf);    
91                         
92                         generate_preview(data, node, cbuf);
93                         
94                         if(in[0]->data != cbuf) 
95                                 free_compbuf(cbuf);
96                 }
97         }
98 }
99
100 static void node_composit_init_output_file(bNodeTree *UNUSED(ntree), bNode* node, bNodeTemplate *ntemp)
101 {
102         RenderData *rd = &ntemp->scene->r;
103         NodeImageFile *nif= MEM_callocN(sizeof(NodeImageFile), "node image file");
104         node->storage= nif;
105
106         BLI_strncpy(nif->name, rd->pic, sizeof(nif->name));
107         nif->im_format= rd->im_format;
108         if (BKE_imtype_is_movie(nif->im_format.imtype)) {
109                 nif->im_format.imtype= R_IMF_IMTYPE_OPENEXR;
110         }
111         nif->sfra= rd->sfra;
112         nif->efra= rd->efra;
113 }
114
115 void register_node_type_cmp_output_file(bNodeTreeType *ttype)
116 {
117         static bNodeType ntype;
118
119         node_type_base(ttype, &ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW|NODE_OPTIONS);
120         node_type_socket_templates(&ntype, cmp_node_output_file_in, NULL);
121         node_type_size(&ntype, 140, 80, 300);
122         node_type_init(&ntype, node_composit_init_output_file);
123         node_type_storage(&ntype, "NodeImageFile", node_free_standard_storage, node_copy_standard_storage);
124         node_type_exec(&ntype, node_composit_exec_output_file);
125
126         nodeRegisterType(ttype, &ntype);
127 }
128
129
130 /* =============================================================================== */
131
132
133 void ntreeCompositOutputMultiFileAddSocket(bNodeTree *ntree, bNode *node, ImageFormatData *im_format)
134 {
135         bNodeSocket *sock = nodeAddSocket(ntree, node, SOCK_IN, "", SOCK_RGBA);
136         
137         /* create format data for the input socket */
138         NodeImageMultiFileSocket *sockdata = MEM_callocN(sizeof(NodeImageMultiFileSocket), "socket image format");
139         sock->storage = sockdata;
140         sock->struct_type = SOCK_STRUCT_OUTPUT_MULTI_FILE;
141         
142         if(im_format) {
143                 sockdata->format= *im_format;
144                 if (BKE_imtype_is_movie(sockdata->format.imtype)) {
145                         sockdata->format.imtype= R_IMF_IMTYPE_OPENEXR;
146                 }
147         }
148         /* use render data format by default */
149         sockdata->use_render_format = 1;
150 }
151
152 int ntreeCompositOutputMultiFileRemoveActiveSocket(bNodeTree *ntree, bNode *node)
153 {
154         NodeImageMultiFile *nimf = node->storage;
155         bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input);
156         
157         if (!sock)
158                 return 0;
159         
160         /* free format data */
161         MEM_freeN(sock->storage);
162         
163         nodeRemoveSocket(ntree, node, sock);
164         return 1;
165 }
166
167 static void init_output_multi_file(bNodeTree *ntree, bNode* node, bNodeTemplate *ntemp)
168 {
169         RenderData *rd = &ntemp->scene->r;
170         NodeImageMultiFile *nimf= MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file");
171         node->storage= nimf;
172
173         BLI_strncpy(nimf->base_path, rd->pic, sizeof(nimf->base_path));
174         
175         /* add one socket by default */
176         ntreeCompositOutputMultiFileAddSocket(ntree, node, &rd->im_format);
177 }
178
179 void free_output_multi_file(bNode *node)
180 {
181         bNodeSocket *sock;
182         
183         /* free storage data in sockets */
184         for (sock=node->inputs.first; sock; sock=sock->next) {
185                 MEM_freeN(sock->storage);
186         }
187         
188         MEM_freeN(node->storage);
189 }
190
191 void copy_output_multi_file(struct bNode *node, struct bNode *target)
192 {
193         bNodeSocket *sock, *newsock;
194         
195         target->storage = MEM_dupallocN(node->storage);
196         
197         /* duplicate storage data in sockets */
198         for (sock=node->inputs.first, newsock=target->inputs.first; sock && newsock; sock=sock->next, newsock=newsock->next) {
199                 newsock->storage = MEM_dupallocN(sock->storage);
200         }
201 }
202
203 static void exec_output_multi_file(void *data, bNode *node, bNodeStack **in, bNodeStack **UNUSED(out))
204 {
205         RenderData *rd= data;
206         NodeImageMultiFile *nimf= node->storage;
207         bNodeSocket *sock;
208         int i;
209         
210         for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i) {
211                 if (!in[i]->data)
212                         continue;
213                 
214                 if (!G.rendering) {
215                         /* only output files when rendering a sequence -
216                          * otherwise, it overwrites the output files just 
217                          * scrubbing through the timeline when the compositor updates */
218                         return;
219                 } else {
220                         Main *bmain= G.main; /* TODO, have this passed along */
221                         NodeImageMultiFileSocket *sockdata = sock->storage;
222                         CompBuf *cbuf= typecheck_compbuf(in[i]->data, CB_RGBA);
223                         ImBuf *ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0);
224                         ImageFormatData *format = (sockdata->use_render_format ? &rd->im_format : &sockdata->format);
225                         char path[FILE_MAX];
226                         char string[FILE_MAX];
227                         
228                         ibuf->rect_float= cbuf->rect;
229                         ibuf->dither= rd->dither_intensity;
230                         
231                         if (rd->color_mgt_flag & R_COLOR_MANAGEMENT)
232                                 ibuf->profile = IB_PROFILE_LINEAR_RGB;
233                         
234                         /* get full path */
235                         BLI_join_dirfile(path, FILE_MAX, nimf->base_path, sock->name);
236                         
237                         BKE_makepicstring(string, path, bmain->name, rd->cfra, format->imtype, (rd->scemode & R_EXTENSION), TRUE);
238                         
239                         if(0 == BKE_write_ibuf(ibuf, string, format))
240                                 printf("Cannot save Node File Output to %s\n", string);
241                         else
242                                 printf("Saved: %s\n", string);
243                         
244                         IMB_freeImBuf(ibuf);    
245                         
246                         #if 0   /* XXX not used yet */
247                         generate_preview(data, node, cbuf);
248                         #endif
249                         
250                         if(in[i]->data != cbuf) 
251                                 free_compbuf(cbuf);
252                 }
253         }
254 }
255
256 void register_node_type_cmp_output_multi_file(bNodeTreeType *ttype)
257 {
258         static bNodeType ntype;
259
260         node_type_base(ttype, &ntype, CMP_NODE_OUTPUT_MULTI_FILE, "Multi File Output", NODE_CLASS_OUTPUT, NODE_OPTIONS);
261         node_type_socket_templates(&ntype, NULL, NULL);
262         node_type_size(&ntype, 140, 80, 300);
263         node_type_init(&ntype, init_output_multi_file);
264         node_type_storage(&ntype, "NodeImageMultiFile", free_output_multi_file, copy_output_multi_file);
265         node_type_exec(&ntype, exec_output_multi_file);
266
267         nodeRegisterType(ttype, &ntype);
268 }