e008e17cbb08adb5918fbca6aca41f3fd91e6c5f
[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_utildefines.h"
35 #include "BLI_path_util.h"
36
37 #include "BKE_context.h"
38
39 #include "RNA_access.h"
40
41 #include "node_composite_util.h"
42
43 #include "IMB_imbuf.h"
44 #include "IMB_imbuf_types.h"
45
46 #include "intern/openexr/openexr_multi.h"
47
48
49 /* **************** OUTPUT FILE ******************** */
50
51 /* find unique path */
52 static bool unique_path_unique_check(void *arg, const char *name)
53 {
54         struct {ListBase *lb; bNodeSocket *sock;} *data= arg;
55         bNodeSocket *sock;
56         for (sock=data->lb->first; sock; sock=sock->next) {
57                 if (sock != data->sock) {
58                         NodeImageMultiFileSocket *sockdata = sock->storage;
59                         if (strcmp(sockdata->path, name)==0)
60                                 return true;
61                 }
62         }
63         return false;
64 }
65 void ntreeCompositOutputFileUniquePath(ListBase *list, bNodeSocket *sock, const char defname[], char delim)
66 {
67         NodeImageMultiFileSocket *sockdata;
68         struct {ListBase *lb; bNodeSocket *sock;} data;
69         data.lb = list;
70         data.sock = sock;
71
72         /* See if we are given an empty string */
73         if (ELEM(NULL, sock, defname))
74                 return;
75
76         sockdata = sock->storage;
77         BLI_uniquename_cb(unique_path_unique_check, &data, defname, delim, sockdata->path, sizeof(sockdata->path));
78 }
79
80 /* find unique EXR layer */
81 static bool unique_layer_unique_check(void *arg, const char *name)
82 {
83         struct {ListBase *lb; bNodeSocket *sock;} *data= arg;
84         bNodeSocket *sock;
85         for (sock=data->lb->first; sock; sock=sock->next) {
86                 if (sock != data->sock) {
87                         NodeImageMultiFileSocket *sockdata = sock->storage;
88                         if (strcmp(sockdata->layer, name)==0)
89                                 return true;
90                 }
91         }
92         return false;
93 }
94 void ntreeCompositOutputFileUniqueLayer(ListBase *list, bNodeSocket *sock, const char defname[], char delim)
95 {
96         NodeImageMultiFileSocket *sockdata;
97         struct {ListBase *lb; bNodeSocket *sock;} data;
98         data.lb = list;
99         data.sock = sock;
100
101         /* See if we are given an empty string */
102         if (ELEM(NULL, sock, defname))
103                 return;
104
105         sockdata = sock->storage;
106         BLI_uniquename_cb(unique_layer_unique_check, &data, defname, delim, sockdata->layer, sizeof(sockdata->layer));
107 }
108
109 bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, bNode *node, const char *name, ImageFormatData *im_format)
110 {
111         NodeImageMultiFile *nimf = node->storage;
112         bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, name);
113         
114         /* create format data for the input socket */
115         NodeImageMultiFileSocket *sockdata = MEM_callocN(sizeof(NodeImageMultiFileSocket), "socket image format");
116         sock->storage = sockdata;
117         
118         BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path));
119         ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_');
120         BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer));
121         ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_');
122         
123         if (im_format) {
124                 sockdata->format= *im_format;
125                 if (BKE_imtype_is_movie(sockdata->format.imtype)) {
126                         sockdata->format.imtype= R_IMF_IMTYPE_OPENEXR;
127                 }
128         }
129         else
130                 BKE_imformat_defaults(&sockdata->format);
131         /* use node data format by default */
132         sockdata->use_node_format = TRUE;
133         
134         nimf->active_input = BLI_findindex(&node->inputs, sock);
135         
136         return sock;
137 }
138
139 int ntreeCompositOutputFileRemoveActiveSocket(bNodeTree *ntree, bNode *node)
140 {
141         NodeImageMultiFile *nimf = node->storage;
142         bNodeSocket *sock = BLI_findlink(&node->inputs, nimf->active_input);
143         int totinputs = BLI_countlist(&node->inputs);
144         
145         if (!sock)
146                 return 0;
147         
148         if (nimf->active_input == totinputs-1)
149                 --nimf->active_input;
150         
151         /* free format data */
152         MEM_freeN(sock->storage);
153         
154         nodeRemoveSocket(ntree, node, sock);
155         return 1;
156 }
157
158 void ntreeCompositOutputFileSetPath(bNode *node, bNodeSocket *sock, const char *name)
159 {
160         NodeImageMultiFileSocket *sockdata = sock->storage;
161         BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path));
162         ntreeCompositOutputFileUniquePath(&node->inputs, sock, name, '_');
163 }
164
165 void ntreeCompositOutputFileSetLayer(bNode *node, bNodeSocket *sock, const char *name)
166 {
167         NodeImageMultiFileSocket *sockdata = sock->storage;
168         BLI_strncpy_utf8(sockdata->layer, name, sizeof(sockdata->layer));
169         ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_');
170 }
171
172 /* XXX uses initfunc_api callback, regular initfunc does not support context yet */
173 static void init_output_file(const bContext *C, PointerRNA *ptr)
174 {
175         Scene *scene = CTX_data_scene(C);
176         bNodeTree *ntree = ptr->id.data;
177         bNode *node = ptr->data;
178         NodeImageMultiFile *nimf= MEM_callocN(sizeof(NodeImageMultiFile), "node image multi file");
179         ImageFormatData *format = NULL;
180         node->storage= nimf;
181         
182         if (scene) {
183                 RenderData *rd = &scene->r;
184
185                 BLI_strncpy(nimf->base_path, rd->pic, sizeof(nimf->base_path));
186                 nimf->format = rd->im_format;
187                 if (BKE_imtype_is_movie(nimf->format.imtype)) {
188                         nimf->format.imtype= R_IMF_IMTYPE_OPENEXR;
189                 }
190                 
191                 format = &nimf->format;
192         }
193         else
194                 BKE_imformat_defaults(&nimf->format);
195         
196         /* add one socket by default */
197         ntreeCompositOutputFileAddSocket(ntree, node, "Image", format);
198 }
199
200 static void free_output_file(bNode *node)
201 {
202         bNodeSocket *sock;
203         
204         /* free storage data in sockets */
205         for (sock=node->inputs.first; sock; sock=sock->next) {
206                 MEM_freeN(sock->storage);
207         }
208         
209         MEM_freeN(node->storage);
210 }
211
212 static void copy_output_file(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, bNode *src_node)
213 {
214         bNodeSocket *src_sock, *dest_sock;
215         
216         dest_node->storage = MEM_dupallocN(src_node->storage);
217         
218         /* duplicate storage data in sockets */
219         for (src_sock=src_node->inputs.first, dest_sock=dest_node->inputs.first; src_sock && dest_sock; src_sock=src_sock->next, dest_sock=dest_sock->next) {
220                 dest_sock->storage = MEM_dupallocN(src_sock->storage);
221         }
222 }
223
224 static void update_output_file(bNodeTree *ntree, bNode *node)
225 {
226         bNodeSocket *sock;
227         PointerRNA ptr;
228         
229         cmp_node_update_default(ntree, node);
230         
231         /* automatically update the socket type based on linked input */
232         for (sock=node->inputs.first; sock; sock=sock->next) {
233                 if (sock->link) {
234                         RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
235                         RNA_enum_set(&ptr, "type", sock->link->fromsock->type);
236                 }
237         }
238 }
239
240 void register_node_type_cmp_output_file()
241 {
242         static bNodeType ntype;
243
244         cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_OPTIONS|NODE_PREVIEW);
245         node_type_socket_templates(&ntype, NULL, NULL);
246         ntype.initfunc_api = init_output_file;
247         node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file);
248         node_type_update(&ntype, update_output_file, NULL);
249
250         nodeRegisterType(&ntype);
251 }