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