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_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_space_types.h"
41 #include "BKE_context.h"
42 #include "BKE_global.h"
44 #include "BKE_report.h"
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"
52 #include "BLT_translation.h"
54 #include "RNA_access.h"
55 #include "RNA_define.h"
56 #include "RNA_enum_types.h"
58 #include "UI_interface.h"
59 #include "UI_resources.h"
64 #include "io_alembic.h"
66 #include "ABC_alembic.h"
68 static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event)
70 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
71 char filepath[FILE_MAX];
72 BLI_strncpy(filepath, G.main->name, sizeof(filepath));
73 BLI_replace_extension(filepath, sizeof(filepath), ".abc");
74 RNA_string_set(op->ptr, "filepath", filepath);
77 WM_event_add_fileselect(C, op);
79 return OPERATOR_RUNNING_MODAL;
84 static int wm_alembic_export_exec(bContext *C, wmOperator *op)
86 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
87 BKE_report(op->reports, RPT_ERROR, "No filename given");
88 return OPERATOR_CANCELLED;
91 char filename[FILE_MAX];
92 RNA_string_get(op->ptr, "filepath", filename);
94 const struct AlembicExportParams params = {
95 .frame_start = RNA_int_get(op->ptr, "start"),
96 .frame_end = RNA_int_get(op->ptr, "end"),
98 .frame_step_xform = 1.0 / (double)RNA_int_get(op->ptr, "xsamples"),
99 .frame_step_shape = 1.0 / (double)RNA_int_get(op->ptr, "gsamples"),
101 .shutter_open = RNA_float_get(op->ptr, "sh_open"),
102 .shutter_close = RNA_float_get(op->ptr, "sh_close"),
104 .selected_only = RNA_boolean_get(op->ptr, "selected"),
105 .uvs = RNA_boolean_get(op->ptr, "uvs"),
106 .normals = RNA_boolean_get(op->ptr, "normals"),
107 .vcolors = RNA_boolean_get(op->ptr, "vcolors"),
108 .apply_subdiv = RNA_boolean_get(op->ptr, "apply_subdiv"),
109 .flatten_hierarchy = RNA_boolean_get(op->ptr, "flatten"),
110 .visible_layers_only = RNA_boolean_get(op->ptr, "visible_layers_only"),
111 .renderable_only = RNA_boolean_get(op->ptr, "renderable_only"),
112 .face_sets = RNA_boolean_get(op->ptr, "face_sets"),
113 .use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"),
114 .compression_type = RNA_enum_get(op->ptr, "compression_type"),
115 .packuv = RNA_boolean_get(op->ptr, "packuv"),
117 .global_scale = RNA_float_get(op->ptr, "global_scale"),
120 ABC_export(CTX_data_scene(C), C, filename, ¶ms);
122 return OPERATOR_FINISHED;
125 static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
127 uiLayout *box = uiLayoutBox(layout);
130 #ifdef WITH_ALEMBIC_HDF5
131 row = uiLayoutRow(box, false);
132 uiItemL(row, IFACE_("Archive Options:"), ICON_NONE);
134 row = uiLayoutRow(box, false);
135 uiItemR(row, imfptr, "compression_type", 0, NULL, ICON_NONE);
138 box = uiLayoutBox(layout);
139 row = uiLayoutRow(box, false);
140 uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
142 row = uiLayoutRow(box, false);
143 uiItemR(row, imfptr, "global_scale", 0, NULL, ICON_NONE);
146 box = uiLayoutBox(layout);
147 row = uiLayoutRow(box, false);
148 uiItemL(row, IFACE_("Scene Options:"), ICON_SCENE_DATA);
150 row = uiLayoutRow(box, false);
151 uiItemR(row, imfptr, "start", 0, NULL, ICON_NONE);
153 row = uiLayoutRow(box, false);
154 uiItemR(row, imfptr, "end", 0, NULL, ICON_NONE);
156 row = uiLayoutRow(box, false);
157 uiItemR(row, imfptr, "xsamples", 0, NULL, ICON_NONE);
159 row = uiLayoutRow(box, false);
160 uiItemR(row, imfptr, "gsamples", 0, NULL, ICON_NONE);
162 row = uiLayoutRow(box, false);
163 uiItemR(row, imfptr, "sh_open", 0, NULL, ICON_NONE);
165 row = uiLayoutRow(box, false);
166 uiItemR(row, imfptr, "sh_close", 0, NULL, ICON_NONE);
168 row = uiLayoutRow(box, false);
169 uiItemR(row, imfptr, "selected", 0, NULL, ICON_NONE);
171 row = uiLayoutRow(box, false);
172 uiItemR(row, imfptr, "renderable_only", 0, NULL, ICON_NONE);
174 row = uiLayoutRow(box, false);
175 uiItemR(row, imfptr, "visible_layers_only", 0, NULL, ICON_NONE);
177 row = uiLayoutRow(box, false);
178 uiItemR(row, imfptr, "flatten", 0, NULL, ICON_NONE);
181 box = uiLayoutBox(layout);
182 row = uiLayoutRow(box, false);
183 uiItemL(row, IFACE_("Object Options:"), ICON_OBJECT_DATA);
185 row = uiLayoutRow(box, false);
186 uiItemR(row, imfptr, "uvs", 0, NULL, ICON_NONE);
188 row = uiLayoutRow(box, false);
189 uiItemR(row, imfptr, "packuv", 0, NULL, ICON_NONE);
190 uiLayoutSetEnabled(row, RNA_boolean_get(imfptr, "uvs"));
192 row = uiLayoutRow(box, false);
193 uiItemR(row, imfptr, "normals", 0, NULL, ICON_NONE);
195 row = uiLayoutRow(box, false);
196 uiItemR(row, imfptr, "vcolors", 0, NULL, ICON_NONE);
198 row = uiLayoutRow(box, false);
199 uiItemR(row, imfptr, "face_sets", 0, NULL, ICON_NONE);
201 row = uiLayoutRow(box, false);
202 uiItemR(row, imfptr, "subdiv_schema", 0, NULL, ICON_NONE);
204 row = uiLayoutRow(box, false);
205 uiItemR(row, imfptr, "apply_subdiv", 0, NULL, ICON_NONE);
208 static void wm_alembic_export_draw(bContext *UNUSED(C), wmOperator *op)
212 RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
213 ui_alembic_export_settings(op->layout, &ptr);
216 void WM_OT_alembic_export(wmOperatorType *ot)
218 ot->name = "Export Alembic Archive";
219 ot->idname = "WM_OT_alembic_export";
221 ot->invoke = wm_alembic_export_invoke;
222 ot->exec = wm_alembic_export_exec;
223 ot->poll = WM_operator_winactive;
224 ot->ui = wm_alembic_export_draw;
226 WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
227 FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
228 FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
230 RNA_def_int(ot->srna, "start", 1, INT_MIN, INT_MAX,
231 "Start Frame", "Start Frame", INT_MIN, INT_MAX);
233 RNA_def_int(ot->srna, "end", 1, INT_MIN, INT_MAX,
234 "End Frame", "End Frame", INT_MIN, INT_MAX);
236 RNA_def_int(ot->srna, "xsamples", 1, 1, 128,
237 "Transform Samples", "Number of times per frame transformations are sampled", 1, 128);
239 RNA_def_int(ot->srna, "gsamples", 1, 1, 128,
240 "Geometry Samples", "Number of times per frame object datas are sampled", 1, 128);
242 RNA_def_float(ot->srna, "sh_open", 0.0f, -1.0f, 1.0f,
243 "Shutter Open", "Time at which the shutter is open", -1.0f, 1.0f);
245 RNA_def_float(ot->srna, "sh_close", 1.0f, -1.0f, 1.0f,
246 "Shutter Close", "Time at which the shutter is closed", -1.0f, 1.0f);
248 RNA_def_boolean(ot->srna, "selected", 0,
249 "Selected Objects Only", "Export only selected objects");
251 RNA_def_boolean(ot->srna, "renderable_only", 1,
252 "Renderable Objects Only",
253 "Export only objects marked renderable in the outliner");
255 RNA_def_boolean(ot->srna, "visible_layers_only", 0,
256 "Visible Layers Only", "Export only objects in visible layers");
258 RNA_def_boolean(ot->srna, "flatten", 0,
260 "Do not preserve objects' parent/children relationship");
262 RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Export UVs");
264 RNA_def_boolean(ot->srna, "packuv", 1, "Pack UV Islands",
265 "Export UVs with packed island");
267 RNA_def_boolean(ot->srna, "normals", 1, "Normals", "Export normals");
269 RNA_def_boolean(ot->srna, "vcolors", 0, "Vertex colors", "Export vertex colors");
271 RNA_def_boolean(ot->srna, "face_sets", 0, "Face Sets", "Export per face shading group assignments");
273 RNA_def_boolean(ot->srna, "subdiv_schema", 0,
274 "Use Subdivision Schema",
275 "Export meshes using Alembic's subdivision schema");
277 RNA_def_boolean(ot->srna, "apply_subdiv", 0,
278 "Apply Subsurf", "Export subdivision surfaces as meshes");
280 RNA_def_enum(ot->srna, "compression_type", rna_enum_abc_compression_items,
281 ABC_ARCHIVE_OGAWA, "Compression", "");
283 RNA_def_float(ot->srna, "global_scale", 1.0f, 0.0001f, 1000.0f, "Scale",
284 "Value by which to enlarge or shrink the objects with respect to the world's origin",
288 /* ************************************************************************** */
290 /* TODO(kevin): check on de-duplicating all this with code in image_ops.c */
292 typedef struct CacheFrame {
293 struct CacheFrame *next, *prev;
297 static int cmp_frame(const void *a, const void *b)
299 const CacheFrame *frame_a = a;
300 const CacheFrame *frame_b = b;
302 if (frame_a->framenr < frame_b->framenr) return -1;
303 if (frame_a->framenr > frame_b->framenr) return 1;
307 static int get_sequence_len(char *filename, int *ofs)
312 if (!BLI_path_frame_get(filename, &frame, &numdigit)) {
317 BLI_split_dir_part(filename, path, FILE_MAX);
319 DIR *dir = opendir(path);
321 const char *ext = ".abc";
322 const char *basename = BLI_path_basename(filename);
323 const int len = strlen(basename) - (numdigit + strlen(ext));
326 BLI_listbase_clear(&frames);
328 struct dirent *fname;
329 while ((fname = readdir(dir)) != NULL) {
330 /* do we have the right extension? */
331 if (!strstr(fname->d_name, ext)) {
335 if (!STREQLEN(basename, fname->d_name, len)) {
339 CacheFrame *cache_frame = MEM_callocN(sizeof(CacheFrame), "abc_frame");
341 BLI_path_frame_get(fname->d_name, &cache_frame->framenr, &numdigit);
343 BLI_addtail(&frames, cache_frame);
348 BLI_listbase_sort(&frames, cmp_frame);
350 CacheFrame *cache_frame = frames.first;
353 int frame_curr = cache_frame->framenr;
356 while (cache_frame && (cache_frame->framenr == frame_curr)) {
358 cache_frame = cache_frame->next;
361 BLI_freelistN(&frames);
363 return frame_curr - (*ofs);
369 /* ************************************************************************** */
371 static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
373 uiLayout *box = uiLayoutBox(layout);
374 uiLayout *row = uiLayoutRow(box, false);
375 uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE);
377 row = uiLayoutRow(box, false);
378 uiItemR(row, imfptr, "scale", 0, NULL, ICON_NONE);
380 box = uiLayoutBox(layout);
381 row = uiLayoutRow(box, false);
382 uiItemL(row, IFACE_("Options:"), ICON_NONE);
384 row = uiLayoutRow(box, false);
385 uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE);
387 row = uiLayoutRow(box, false);
388 uiItemR(row, imfptr, "is_sequence", 0, NULL, ICON_NONE);
390 row = uiLayoutRow(box, false);
391 uiItemR(row, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
394 static void wm_alembic_import_draw(bContext *UNUSED(C), wmOperator *op)
398 RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
399 ui_alembic_import_settings(op->layout, &ptr);
402 static int wm_alembic_import_exec(bContext *C, wmOperator *op)
404 if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
405 BKE_report(op->reports, RPT_ERROR, "No filename given");
406 return OPERATOR_CANCELLED;
409 char filename[FILE_MAX];
410 RNA_string_get(op->ptr, "filepath", filename);
412 const float scale = RNA_float_get(op->ptr, "scale");
413 const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence");
414 const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range");
415 const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
418 int sequence_len = 1;
421 sequence_len = get_sequence_len(filename, &offset);
424 ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes);
426 return OPERATOR_FINISHED;
429 void WM_OT_alembic_import(wmOperatorType *ot)
431 ot->name = "Import Alembic Archive";
432 ot->idname = "WM_OT_alembic_import";
434 ot->invoke = WM_operator_filesel;
435 ot->exec = wm_alembic_import_exec;
436 ot->poll = WM_operator_winactive;
437 ot->ui = wm_alembic_import_draw;
439 WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
440 FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH,
441 FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
443 RNA_def_float(ot->srna, "scale", 1.0f, 0.0001f, 1000.0f, "Scale",
444 "Value by which to enlarge or shrink the objects with respect to the world's origin",
447 RNA_def_boolean(ot->srna, "set_frame_range", true,
449 "If checked, update scene's start and end frame to match those of the Alembic archive");
451 RNA_def_boolean(ot->srna, "validate_meshes", 0,
452 "Validate Meshes", "Check imported mesh objects for invalid data (slow)");
454 RNA_def_boolean(ot->srna, "is_sequence", false, "Is Sequence",
455 "Set to true if the cache is split into separate files");