2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2016 Blender Foundation.
19 * All rights reserved.
21 * ***** END GPL LICENSE BLOCK *****
27 /* needed for directory lookup */
31 # include "BLI_winstuff.h"
34 #include "MEM_guardedalloc.h"
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"
42 #include "BKE_context.h"
43 #include "BKE_global.h"
45 #include "BKE_report.h"
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"
53 #include "BLT_translation.h"
55 #include "RNA_access.h"
56 #include "RNA_define.h"
57 #include "RNA_enum_types.h"
59 #include "UI_interface.h"
60 #include "UI_resources.h"
65 #include "io_alembic.h"
67 #include "ABC_alembic.h"
69 static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event)
71 RNA_boolean_set(op->ptr, "init_scene_frame_range", true);
73 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
74 Main *bmain = CTX_data_main(C);
75 char filepath[FILE_MAX];
77 if (bmain->name[0] == '\0') {
78 BLI_strncpy(filepath, "untitled", sizeof(filepath));
81 BLI_strncpy(filepath, bmain->name, sizeof(filepath));
84 BLI_replace_extension(filepath, sizeof(filepath), ".abc");
85 RNA_string_set(op->ptr, "filepath", filepath);
88 WM_event_add_fileselect(C, op);
90 return OPERATOR_RUNNING_MODAL;
95 static int wm_alembic_export_exec(bContext *C, wmOperator *op)
97 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
98 BKE_report(op->reports, RPT_ERROR, "No filename given");
99 return OPERATOR_CANCELLED;
102 char filename[FILE_MAX];
103 RNA_string_get(op->ptr, "filepath", filename);
105 const struct AlembicExportParams params = {
106 .frame_start = RNA_int_get(op->ptr, "start"),
107 .frame_end = RNA_int_get(op->ptr, "end"),
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"),
112 .shutter_open = RNA_float_get(op->ptr, "sh_open"),
113 .shutter_close = RNA_float_get(op->ptr, "sh_close"),
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"),
133 .global_scale = RNA_float_get(op->ptr, "global_scale"),
136 ABC_export(CTX_data_scene(C), C, filename, ¶ms);
138 return OPERATOR_FINISHED;
141 static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
147 #ifdef WITH_ALEMBIC_HDF5
148 box = uiLayoutBox(layout);
149 row = uiLayoutRow(box, false);
150 uiItemL(row, IFACE_("Archive Options:"), ICON_NONE);
152 row = uiLayoutRow(box, false);
153 uiItemR(row, imfptr, "compression_type", 0, NULL, ICON_NONE);
156 box = uiLayoutBox(layout);
157 row = uiLayoutRow(box, false);
158 uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
160 row = uiLayoutRow(box, false);
161 uiItemR(row, imfptr, "global_scale", 0, NULL, ICON_NONE);
164 box = uiLayoutBox(layout);
165 row = uiLayoutRow(box, false);
166 uiItemL(row, IFACE_("Scene Options:"), ICON_SCENE_DATA);
168 row = uiLayoutRow(box, false);
169 uiItemR(row, imfptr, "start", 0, NULL, ICON_NONE);
171 row = uiLayoutRow(box, false);
172 uiItemR(row, imfptr, "end", 0, NULL, ICON_NONE);
174 row = uiLayoutRow(box, false);
175 uiItemR(row, imfptr, "xsamples", 0, NULL, ICON_NONE);
177 row = uiLayoutRow(box, false);
178 uiItemR(row, imfptr, "gsamples", 0, NULL, ICON_NONE);
180 row = uiLayoutRow(box, false);
181 uiItemR(row, imfptr, "sh_open", 0, NULL, ICON_NONE);
183 row = uiLayoutRow(box, false);
184 uiItemR(row, imfptr, "sh_close", 0, NULL, ICON_NONE);
186 row = uiLayoutRow(box, false);
187 uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE);
189 row = uiLayoutRow(box, false);
190 uiItemR(row, imfptr, "renderable_only", 0, NULL, ICON_NONE);
192 row = uiLayoutRow(box, false);
193 uiItemR(row, imfptr, "visible_layers_only", 0, NULL, ICON_NONE);
195 row = uiLayoutRow(box, false);
196 uiItemR(row, imfptr, "flatten", 0, NULL, ICON_NONE);
199 box = uiLayoutBox(layout);
200 row = uiLayoutRow(box, false);
201 uiItemL(row, IFACE_("Object Options:"), ICON_OBJECT_DATA);
203 row = uiLayoutRow(box, false);
204 uiItemR(row, imfptr, "uvs", 0, NULL, ICON_NONE);
206 row = uiLayoutRow(box, false);
207 uiItemR(row, imfptr, "packuv", 0, NULL, ICON_NONE);
208 uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "uvs"));
210 row = uiLayoutRow(box, false);
211 uiItemR(row, imfptr, "normals", 0, NULL, ICON_NONE);
213 row = uiLayoutRow(box, false);
214 uiItemR(row, imfptr, "vcolors", 0, NULL, ICON_NONE);
216 row = uiLayoutRow(box, false);
217 uiItemR(row, imfptr, "face_sets", 0, NULL, ICON_NONE);
219 row = uiLayoutRow(box, false);
220 uiItemR(row, imfptr, "subdiv_schema", 0, NULL, ICON_NONE);
222 row = uiLayoutRow(box, false);
223 uiItemR(row, imfptr, "apply_subdiv", 0, NULL, ICON_NONE);
225 row = uiLayoutRow(box, false);
226 uiItemR(row, imfptr, "triangulate", 0, NULL, ICON_NONE);
228 const bool triangulate = RNA_boolean_get(imfptr, "triangulate");
230 row = uiLayoutRow(box, false);
231 uiLayoutSetEnabled(row, triangulate);
232 uiItemR(row, imfptr, "quad_method", 0, NULL, ICON_NONE);
234 row = uiLayoutRow(box, false);
235 uiLayoutSetEnabled(row, triangulate);
236 uiItemR(row, imfptr, "ngon_method", 0, NULL, ICON_NONE);
239 box = uiLayoutBox(layout);
240 row = uiLayoutRow(box, false);
241 uiItemL(row, IFACE_("Particle Systems:"), ICON_PARTICLE_DATA);
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);
248 static void wm_alembic_export_draw(bContext *C, wmOperator *op)
252 RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
254 /* Conveniently set start and end frame to match the scene's frame range. */
255 Scene *scene = CTX_data_scene(C);
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);
261 RNA_boolean_set(&ptr, "init_scene_frame_range", false);
264 ui_alembic_export_settings(op->layout, &ptr);
267 static bool wm_alembic_export_check(bContext *UNUSED(C), wmOperator *op)
269 char filepath[FILE_MAX];
270 RNA_string_get(op->ptr, "filepath", filepath);
272 if (!BLI_testextensie(filepath, ".abc")) {
273 BLI_ensure_extension(filepath, FILE_MAX, ".abc");
274 RNA_string_set(op->ptr, "filepath", filepath);
281 void WM_OT_alembic_export(wmOperatorType *ot)
283 ot->name = "Export Alembic";
284 ot->description = "Export current scene in an Alembic archive";
285 ot->idname = "WM_OT_alembic_export";
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;
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);
297 RNA_def_int(ot->srna, "start", 1, INT_MIN, INT_MAX,
298 "Start Frame", "Start Frame", INT_MIN, INT_MAX);
300 RNA_def_int(ot->srna, "end", 1, INT_MIN, INT_MAX,
301 "End Frame", "End Frame", INT_MIN, INT_MAX);
303 RNA_def_int(ot->srna, "xsamples", 1, 1, 128,
304 "Transform Samples", "Number of times per frame transformations are sampled", 1, 128);
306 RNA_def_int(ot->srna, "gsamples", 1, 1, 128,
307 "Geometry Samples", "Number of times per frame object data are sampled", 1, 128);
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);
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);
315 RNA_def_boolean(ot->srna, "selected", 0,
316 "Selected Objects Only", "Export only selected objects");
318 RNA_def_boolean(ot->srna, "renderable_only", 1,
319 "Renderable Objects Only",
320 "Export only objects marked renderable in the outliner");
322 RNA_def_boolean(ot->srna, "visible_layers_only", 0,
323 "Visible Layers Only", "Export only objects in visible layers");
325 RNA_def_boolean(ot->srna, "flatten", 0,
327 "Do not preserve objects' parent/children relationship");
329 RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Export UVs");
331 RNA_def_boolean(ot->srna, "packuv", 1, "Pack UV Islands",
332 "Export UVs with packed island");
334 RNA_def_boolean(ot->srna, "normals", 1, "Normals", "Export normals");
336 RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex Colors", "Export vertex colors");
338 RNA_def_boolean(ot->srna, "face_sets", 0, "Face Sets", "Export per face shading group assignments");
340 RNA_def_boolean(ot->srna, "subdiv_schema", 0,
341 "Use Subdivision Schema",
342 "Export meshes using Alembic's subdivision schema");
344 RNA_def_boolean(ot->srna, "apply_subdiv", 0,
345 "Apply Subsurf", "Export subdivision surfaces as meshes");
347 RNA_def_enum(ot->srna, "compression_type", rna_enum_abc_compression_items,
348 ABC_ARCHIVE_OGAWA, "Compression", "");
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",
354 RNA_def_boolean(ot->srna, "triangulate", false, "Triangulate",
355 "Export Polygons (Quads & NGons) as Triangles");
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");
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");
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");
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, "", "");
372 /* ************************************************************************** */
374 /* TODO(kevin): check on de-duplicating all this with code in image_ops.c */
376 typedef struct CacheFrame {
377 struct CacheFrame *next, *prev;
381 static int cmp_frame(const void *a, const void *b)
383 const CacheFrame *frame_a = a;
384 const CacheFrame *frame_b = b;
386 if (frame_a->framenr < frame_b->framenr) return -1;
387 if (frame_a->framenr > frame_b->framenr) return 1;
391 static int get_sequence_len(char *filename, int *ofs)
396 if (!BLI_path_frame_get(filename, &frame, &numdigit)) {
401 BLI_split_dir_part(filename, path, FILE_MAX);
403 DIR *dir = opendir(path);
405 const char *ext = ".abc";
406 const char *basename = BLI_path_basename(filename);
407 const int len = strlen(basename) - (numdigit + strlen(ext));
410 BLI_listbase_clear(&frames);
412 struct dirent *fname;
413 while ((fname = readdir(dir)) != NULL) {
414 /* do we have the right extension? */
415 if (!strstr(fname->d_name, ext)) {
419 if (!STREQLEN(basename, fname->d_name, len)) {
423 CacheFrame *cache_frame = MEM_callocN(sizeof(CacheFrame), "abc_frame");
425 BLI_path_frame_get(fname->d_name, &cache_frame->framenr, &numdigit);
427 BLI_addtail(&frames, cache_frame);
432 BLI_listbase_sort(&frames, cmp_frame);
434 CacheFrame *cache_frame = frames.first;
437 int frame_curr = cache_frame->framenr;
440 while (cache_frame && (cache_frame->framenr == frame_curr)) {
442 cache_frame = cache_frame->next;
445 BLI_freelistN(&frames);
447 return frame_curr - (*ofs);
453 /* ************************************************************************** */
455 static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
457 uiLayout *box = uiLayoutBox(layout);
458 uiLayout *row = uiLayoutRow(box, false);
459 uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
461 row = uiLayoutRow(box, false);
462 uiItemR(row, imfptr, "scale", 0, NULL, ICON_NONE);
464 box = uiLayoutBox(layout);
465 row = uiLayoutRow(box, false);
466 uiItemL(row, IFACE_("Options:"), ICON_NONE);
468 row = uiLayoutRow(box, false);
469 uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE);
471 row = uiLayoutRow(box, false);
472 uiItemR(row, imfptr, "is_sequence", 0, NULL, ICON_NONE);
474 row = uiLayoutRow(box, false);
475 uiItemR(row, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
478 static void wm_alembic_import_draw(bContext *UNUSED(C), wmOperator *op)
482 RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
483 ui_alembic_import_settings(op->layout, &ptr);
486 static int wm_alembic_import_exec(bContext *C, wmOperator *op)
488 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
489 BKE_report(op->reports, RPT_ERROR, "No filename given");
490 return OPERATOR_CANCELLED;
493 char filename[FILE_MAX];
494 RNA_string_get(op->ptr, "filepath", filename);
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");
502 int sequence_len = 1;
505 sequence_len = get_sequence_len(filename, &offset);
508 ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes);
510 return OPERATOR_FINISHED;
513 void WM_OT_alembic_import(wmOperatorType *ot)
515 ot->name = "Import Alembic";
516 ot->description = "Load an Alembic archive";
517 ot->idname = "WM_OT_alembic_import";
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;
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);
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",
532 RNA_def_boolean(ot->srna, "set_frame_range", true,
534 "If checked, update scene's start and end frame to match those of the Alembic archive");
536 RNA_def_boolean(ot->srna, "validate_meshes", 0,
537 "Validate Meshes", "Check imported mesh objects for invalid data (slow)");
539 RNA_def_boolean(ot->srna, "is_sequence", false, "Is Sequence",
540 "Set to true if the cache is split into separate files");