Fix T49111: Automatically add file path suffix for Alembic and Collada
[blender.git] / source / blender / editors / io / io_alembic.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) 2016 Blender Foundation.
19  * All rights reserved.
20  *
21  * ***** END GPL LICENSE BLOCK *****
22  *
23  */
24
25 #ifdef WITH_ALEMBIC
26
27 /* needed for directory lookup */
28 #ifndef WIN32
29 #  include <dirent.h>
30 #else
31 #  include "BLI_winstuff.h"
32 #endif
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_mesh_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_space_types.h"
40
41 #include "BKE_context.h"
42 #include "BKE_global.h"
43 #include "BKE_main.h"
44 #include "BKE_report.h"
45
46 #include "BLI_listbase.h"
47 #include "BLI_math_vector.h"
48 #include "BLI_path_util.h"
49 #include "BLI_string.h"
50 #include "BLI_utildefines.h"
51
52 #include "BLT_translation.h"
53
54 #include "RNA_access.h"
55 #include "RNA_define.h"
56 #include "RNA_enum_types.h"
57
58 #include "UI_interface.h"
59 #include "UI_resources.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64 #include "io_alembic.h"
65
66 #include "ABC_alembic.h"
67
68 static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event)
69 {
70         if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
71                 Main *bmain = CTX_data_main(C);
72                 char filepath[FILE_MAX];
73
74                 if (bmain->name[0] == '\0') {
75                         BLI_strncpy(filepath, "untitled", sizeof(filepath));
76                 }
77                 else {
78                         BLI_strncpy(filepath, bmain->name, sizeof(filepath));
79                 }
80
81                 BLI_replace_extension(filepath, sizeof(filepath), ".abc");
82                 RNA_string_set(op->ptr, "filepath", filepath);
83         }
84
85         WM_event_add_fileselect(C, op);
86
87         return OPERATOR_RUNNING_MODAL;
88
89         UNUSED_VARS(event);
90 }
91
92 static int wm_alembic_export_exec(bContext *C, wmOperator *op)
93 {
94         if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
95                 BKE_report(op->reports, RPT_ERROR, "No filename given");
96                 return OPERATOR_CANCELLED;
97         }
98
99         char filename[FILE_MAX];
100         RNA_string_get(op->ptr, "filepath", filename);
101
102         const struct AlembicExportParams params = {
103             .frame_start = RNA_int_get(op->ptr, "start"),
104             .frame_end = RNA_int_get(op->ptr, "end"),
105
106             .frame_step_xform = 1.0 / (double)RNA_int_get(op->ptr, "xsamples"),
107             .frame_step_shape = 1.0 / (double)RNA_int_get(op->ptr, "gsamples"),
108
109             .shutter_open = RNA_float_get(op->ptr, "sh_open"),
110             .shutter_close = RNA_float_get(op->ptr, "sh_close"),
111
112             .selected_only = RNA_boolean_get(op->ptr, "selected"),
113             .uvs = RNA_boolean_get(op->ptr, "uvs"),
114             .normals = RNA_boolean_get(op->ptr, "normals"),
115             .vcolors = RNA_boolean_get(op->ptr, "vcolors"),
116             .apply_subdiv = RNA_boolean_get(op->ptr, "apply_subdiv"),
117             .flatten_hierarchy = RNA_boolean_get(op->ptr, "flatten"),
118             .visible_layers_only = RNA_boolean_get(op->ptr, "visible_layers_only"),
119             .renderable_only = RNA_boolean_get(op->ptr, "renderable_only"),
120             .face_sets = RNA_boolean_get(op->ptr, "face_sets"),
121             .use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"),
122             .compression_type = RNA_enum_get(op->ptr, "compression_type"),
123             .packuv = RNA_boolean_get(op->ptr, "packuv"),
124
125             .global_scale = RNA_float_get(op->ptr, "global_scale"),
126         };
127
128         ABC_export(CTX_data_scene(C), C, filename, &params);
129
130         return OPERATOR_FINISHED;
131 }
132
133 static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
134 {
135         uiLayout *box = uiLayoutBox(layout);
136         uiLayout *row;
137
138 #ifdef WITH_ALEMBIC_HDF5
139         row = uiLayoutRow(box, false);
140         uiItemL(row, IFACE_("Archive Options:"), ICON_NONE);
141
142         row = uiLayoutRow(box, false);
143         uiItemR(row, imfptr, "compression_type", 0, NULL, ICON_NONE);
144 #endif
145
146         box = uiLayoutBox(layout);
147         row = uiLayoutRow(box, false);
148         uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
149
150         row = uiLayoutRow(box, false);
151         uiItemR(row, imfptr, "global_scale", 0, NULL, ICON_NONE);
152
153         /* Scene Options */
154         box = uiLayoutBox(layout);
155         row = uiLayoutRow(box, false);
156         uiItemL(row, IFACE_("Scene Options:"), ICON_SCENE_DATA);
157
158         row = uiLayoutRow(box, false);
159         uiItemR(row, imfptr, "start", 0, NULL, ICON_NONE);
160
161         row = uiLayoutRow(box, false);
162         uiItemR(row, imfptr, "end", 0, NULL, ICON_NONE);
163
164         row = uiLayoutRow(box, false);
165         uiItemR(row, imfptr, "xsamples", 0, NULL, ICON_NONE);
166
167         row = uiLayoutRow(box, false);
168         uiItemR(row, imfptr, "gsamples", 0, NULL, ICON_NONE);
169
170         row = uiLayoutRow(box, false);
171         uiItemR(row, imfptr, "sh_open", 0, NULL, ICON_NONE);
172
173         row = uiLayoutRow(box, false);
174         uiItemR(row, imfptr, "sh_close", 0, NULL, ICON_NONE);
175
176         row = uiLayoutRow(box, false);
177         uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE);
178
179         row = uiLayoutRow(box, false);
180         uiItemR(row, imfptr, "renderable_only", 0, NULL, ICON_NONE);
181
182         row = uiLayoutRow(box, false);
183         uiItemR(row, imfptr, "visible_layers_only", 0, NULL, ICON_NONE);
184
185         row = uiLayoutRow(box, false);
186         uiItemR(row, imfptr, "flatten", 0, NULL, ICON_NONE);
187
188         /* Object Data */
189         box = uiLayoutBox(layout);
190         row = uiLayoutRow(box, false);
191         uiItemL(row, IFACE_("Object Options:"), ICON_OBJECT_DATA);
192
193         row = uiLayoutRow(box, false);
194         uiItemR(row, imfptr, "uvs", 0, NULL, ICON_NONE);
195
196         row = uiLayoutRow(box, false);
197         uiItemR(row, imfptr, "packuv", 0, NULL, ICON_NONE);
198         uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "uvs"));
199
200         row = uiLayoutRow(box, false);
201         uiItemR(row, imfptr, "normals", 0, NULL, ICON_NONE);
202
203         row = uiLayoutRow(box, false);
204         uiItemR(row, imfptr, "vcolors", 0, NULL, ICON_NONE);
205
206         row = uiLayoutRow(box, false);
207         uiItemR(row, imfptr, "face_sets", 0, NULL, ICON_NONE);
208
209         row = uiLayoutRow(box, false);
210         uiItemR(row, imfptr, "subdiv_schema", 0, NULL, ICON_NONE);
211
212         row = uiLayoutRow(box, false);
213         uiItemR(row, imfptr, "apply_subdiv", 0, NULL, ICON_NONE);
214 }
215
216 static void wm_alembic_export_draw(bContext *UNUSED(C), wmOperator *op)
217 {
218         PointerRNA ptr;
219
220         RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
221         ui_alembic_export_settings(op->layout, &ptr);
222 }
223
224 static bool wm_alembic_export_check(bContext *UNUSED(C), wmOperator *op)
225 {
226         char filepath[FILE_MAX];
227         RNA_string_get(op->ptr, "filepath", filepath);
228
229         if (!BLI_testextensie(filepath, ".abc")) {
230                 BLI_ensure_extension(filepath, FILE_MAX, ".abc");
231                 RNA_string_set(op->ptr, "filepath", filepath);
232                 return true;
233         }
234
235         return false;
236 }
237
238 void WM_OT_alembic_export(wmOperatorType *ot)
239 {
240         ot->name = "Export Alembic";
241         ot->description = "Export current scene in an Alembic archive";
242         ot->idname = "WM_OT_alembic_export";
243
244         ot->invoke = wm_alembic_export_invoke;
245         ot->exec = wm_alembic_export_exec;
246         ot->poll = WM_operator_winactive;
247         ot->ui = wm_alembic_export_draw;
248         ot->check = wm_alembic_export_check;
249
250         WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
251                                        FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
252                                        FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
253
254         RNA_def_int(ot->srna, "start", 1, INT_MIN, INT_MAX,
255                     "Start Frame", "Start Frame", INT_MIN, INT_MAX);
256
257         RNA_def_int(ot->srna, "end", 1, INT_MIN, INT_MAX,
258                     "End Frame", "End Frame", INT_MIN, INT_MAX);
259
260         RNA_def_int(ot->srna, "xsamples", 1, 1, 128,
261                     "Transform Samples", "Number of times per frame transformations are sampled", 1, 128);
262
263         RNA_def_int(ot->srna, "gsamples", 1, 1, 128,
264                     "Geometry Samples", "Number of times per frame object data are sampled", 1, 128);
265
266         RNA_def_float(ot->srna, "sh_open", 0.0f, -1.0f, 1.0f,
267                       "Shutter Open", "Time at which the shutter is open", -1.0f, 1.0f);
268
269         RNA_def_float(ot->srna, "sh_close", 1.0f, -1.0f, 1.0f,
270                       "Shutter Close", "Time at which the shutter is closed", -1.0f, 1.0f);
271
272         RNA_def_boolean(ot->srna, "selected", 0,
273                         "Selected Objects Only", "Export only selected objects");
274
275         RNA_def_boolean(ot->srna, "renderable_only", 1,
276                         "Renderable Objects Only",
277                         "Export only objects marked renderable in the outliner");
278
279         RNA_def_boolean(ot->srna, "visible_layers_only", 0,
280                         "Visible Layers Only", "Export only objects in visible layers");
281
282         RNA_def_boolean(ot->srna, "flatten", 0,
283                         "Flatten Hierarchy",
284                         "Do not preserve objects' parent/children relationship");
285
286         RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Export UVs");
287
288         RNA_def_boolean(ot->srna, "packuv", 1, "Pack UV Islands",
289                         "Export UVs with packed island");
290
291         RNA_def_boolean(ot->srna, "normals", 1, "Normals", "Export normals");
292
293         RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex Colors", "Export vertex colors");
294
295         RNA_def_boolean(ot->srna, "face_sets", 0, "Face Sets", "Export per face shading group assignments");
296
297         RNA_def_boolean(ot->srna, "subdiv_schema", 0,
298                         "Use Subdivision Schema",
299                         "Export meshes using Alembic's subdivision schema");
300
301         RNA_def_boolean(ot->srna, "apply_subdiv", 0,
302                         "Apply Subsurf", "Export subdivision surfaces as meshes");
303
304         RNA_def_enum(ot->srna, "compression_type", rna_enum_abc_compression_items,
305                      ABC_ARCHIVE_OGAWA, "Compression", "");
306
307         RNA_def_float(ot->srna, "global_scale", 1.0f, 0.0001f, 1000.0f, "Scale",
308                       "Value by which to enlarge or shrink the objects with respect to the world's origin",
309                       0.0001f, 1000.0f);
310 }
311
312 /* ************************************************************************** */
313
314 /* TODO(kevin): check on de-duplicating all this with code in image_ops.c */
315
316 typedef struct CacheFrame {
317         struct CacheFrame *next, *prev;
318         int framenr;
319 } CacheFrame;
320
321 static int cmp_frame(const void *a, const void *b)
322 {
323         const CacheFrame *frame_a = a;
324         const CacheFrame *frame_b = b;
325
326         if (frame_a->framenr < frame_b->framenr) return -1;
327         if (frame_a->framenr > frame_b->framenr) return 1;
328         return 0;
329 }
330
331 static int get_sequence_len(char *filename, int *ofs)
332 {
333         int frame;
334         int numdigit;
335
336         if (!BLI_path_frame_get(filename, &frame, &numdigit)) {
337                 return 1;
338         }
339
340         char path[FILE_MAX];
341         BLI_split_dir_part(filename, path, FILE_MAX);
342
343         DIR *dir = opendir(path);
344
345         const char *ext = ".abc";
346         const char *basename = BLI_path_basename(filename);
347         const int len = strlen(basename) - (numdigit + strlen(ext));
348
349         ListBase frames;
350         BLI_listbase_clear(&frames);
351
352         struct dirent *fname;
353         while ((fname = readdir(dir)) != NULL) {
354                 /* do we have the right extension? */
355                 if (!strstr(fname->d_name, ext)) {
356                         continue;
357                 }
358
359                 if (!STREQLEN(basename, fname->d_name, len)) {
360                         continue;
361                 }
362
363                 CacheFrame *cache_frame = MEM_callocN(sizeof(CacheFrame), "abc_frame");
364
365                 BLI_path_frame_get(fname->d_name, &cache_frame->framenr, &numdigit);
366
367                 BLI_addtail(&frames, cache_frame);
368         }
369
370         closedir(dir);
371
372         BLI_listbase_sort(&frames, cmp_frame);
373
374         CacheFrame *cache_frame = frames.first;
375
376         if (cache_frame) {
377                 int frame_curr = cache_frame->framenr;
378                 (*ofs) = frame_curr;
379
380                 while (cache_frame && (cache_frame->framenr == frame_curr)) {
381                         ++frame_curr;
382                         cache_frame = cache_frame->next;
383                 }
384
385                 BLI_freelistN(&frames);
386
387                 return frame_curr - (*ofs);
388         }
389
390         return 1;
391 }
392
393 /* ************************************************************************** */
394
395 static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
396 {
397         uiLayout *box = uiLayoutBox(layout);
398         uiLayout *row = uiLayoutRow(box, false);
399         uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
400
401         row = uiLayoutRow(box, false);
402         uiItemR(row, imfptr, "scale", 0, NULL, ICON_NONE);
403
404         box = uiLayoutBox(layout);
405         row = uiLayoutRow(box, false);
406         uiItemL(row, IFACE_("Options:"), ICON_NONE);
407
408         row = uiLayoutRow(box, false);
409         uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE);
410
411         row = uiLayoutRow(box, false);
412         uiItemR(row, imfptr, "is_sequence", 0, NULL, ICON_NONE);
413
414         row = uiLayoutRow(box, false);
415         uiItemR(row, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
416 }
417
418 static void wm_alembic_import_draw(bContext *UNUSED(C), wmOperator *op)
419 {
420         PointerRNA ptr;
421
422         RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
423         ui_alembic_import_settings(op->layout, &ptr);
424 }
425
426 static int wm_alembic_import_exec(bContext *C, wmOperator *op)
427 {
428         if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
429                 BKE_report(op->reports, RPT_ERROR, "No filename given");
430                 return OPERATOR_CANCELLED;
431         }
432
433         char filename[FILE_MAX];
434         RNA_string_get(op->ptr, "filepath", filename);
435
436         const float scale = RNA_float_get(op->ptr, "scale");
437         const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence");
438         const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range");
439         const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
440
441         int offset = 0;
442         int sequence_len = 1;
443
444         if (is_sequence) {
445                 sequence_len = get_sequence_len(filename, &offset);
446         }
447
448         ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes);
449
450         return OPERATOR_FINISHED;
451 }
452
453 void WM_OT_alembic_import(wmOperatorType *ot)
454 {
455         ot->name = "Import Alembic";
456         ot->description = "Load an Alembic archive";
457         ot->idname = "WM_OT_alembic_import";
458
459         ot->invoke = WM_operator_filesel;
460         ot->exec = wm_alembic_import_exec;
461         ot->poll = WM_operator_winactive;
462         ot->ui = wm_alembic_import_draw;
463
464         WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
465                                        FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
466                                        FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
467
468         RNA_def_float(ot->srna, "scale", 1.0f, 0.0001f, 1000.0f, "Scale",
469                       "Value by which to enlarge or shrink the objects with respect to the world's origin",
470                       0.0001f, 1000.0f);
471
472         RNA_def_boolean(ot->srna, "set_frame_range", true,
473                         "Set Frame Range",
474                         "If checked, update scene's start and end frame to match those of the Alembic archive");
475
476         RNA_def_boolean(ot->srna, "validate_meshes", 0,
477                         "Validate Meshes", "Check imported mesh objects for invalid data (slow)");
478
479         RNA_def_boolean(ot->srna, "is_sequence", false, "Is Sequence",
480                         "Set to true if the cache is split into separate files");
481 }
482
483 #endif