/* SPDX-FileCopyrightText: 2023 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ /** \file * \ingroup editor/io */ #ifdef WITH_IO_PLY # include "BKE_context.h" # include "BKE_main.h" # include "BKE_report.h" # include "WM_api.hh" # include "WM_types.hh" # include "DNA_space_types.h" # include "ED_fileselect.hh" # include "ED_outliner.hh" # include "RNA_access.hh" # include "RNA_define.hh" # include "BLT_translation.h" # include "MEM_guardedalloc.h" # include "UI_interface.hh" # include "UI_resources.hh" # include "DEG_depsgraph.hh" # include "IO_orientation.hh" # include "IO_path_util_types.hh" # include "IO_ply.hh" # include "io_ply_ops.hh" static const EnumPropertyItem ply_vertex_colors_mode[] = { {PLY_VERTEX_COLOR_NONE, "NONE", 0, "None", "Do not import/export color attributes"}, {PLY_VERTEX_COLOR_SRGB, "SRGB", 0, "sRGB", "Vertex colors in the file are in sRGB color space"}, {PLY_VERTEX_COLOR_LINEAR, "LINEAR", 0, "Linear", "Vertex colors in the file are in linear color space"}, {0, nullptr, 0, nullptr, nullptr}}; static int wm_ply_export_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) { ED_fileselect_ensure_default_filepath(C, op, ".ply"); WM_event_add_fileselect(C, op); return OPERATOR_RUNNING_MODAL; } static int wm_ply_export_exec(bContext *C, wmOperator *op) { if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) { BKE_report(op->reports, RPT_ERROR, "No filepath given"); return OPERATOR_CANCELLED; } PLYExportParams export_params = {"\0"}; export_params.file_base_for_tests[0] = '\0'; RNA_string_get(op->ptr, "filepath", export_params.filepath); export_params.blen_filepath = CTX_data_main(C)->filepath; export_params.forward_axis = eIOAxis(RNA_enum_get(op->ptr, "forward_axis")); export_params.up_axis = eIOAxis(RNA_enum_get(op->ptr, "up_axis")); export_params.global_scale = RNA_float_get(op->ptr, "global_scale"); export_params.apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers"); export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects"); export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv"); export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals"); export_params.vertex_colors = ePLYVertexColorMode(RNA_enum_get(op->ptr, "export_colors")); export_params.export_attributes = RNA_boolean_get(op->ptr, "export_attributes"); export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh"); export_params.ascii_format = RNA_boolean_get(op->ptr, "ascii_format"); PLY_export(C, &export_params); return OPERATOR_FINISHED; } static void ui_ply_export_settings(uiLayout *layout, PointerRNA *imfptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiLayout *box, *col, *sub; /* Object Transform options. */ box = uiLayoutBox(layout); col = uiLayoutColumn(box, false); sub = uiLayoutColumnWithHeading(col, false, IFACE_("Format")); uiItemR(sub, imfptr, "ascii_format", UI_ITEM_NONE, IFACE_("ASCII"), ICON_NONE); sub = uiLayoutColumnWithHeading(col, false, IFACE_("Limit to")); uiItemR( sub, imfptr, "export_selected_objects", UI_ITEM_NONE, IFACE_("Selected Only"), ICON_NONE); uiItemR(sub, imfptr, "global_scale", UI_ITEM_NONE, nullptr, ICON_NONE); uiItemR(sub, imfptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE); uiItemR(sub, imfptr, "up_axis", UI_ITEM_NONE, IFACE_("Up Axis"), ICON_NONE); col = uiLayoutColumn(box, false); sub = uiLayoutColumn(col, false); sub = uiLayoutColumnWithHeading(col, false, IFACE_("Objects")); uiItemR(sub, imfptr, "apply_modifiers", UI_ITEM_NONE, IFACE_("Apply Modifiers"), ICON_NONE); /* Geometry options. */ box = uiLayoutBox(layout); col = uiLayoutColumn(box, false); sub = uiLayoutColumnWithHeading(col, false, IFACE_("Geometry")); uiItemR(sub, imfptr, "export_uv", UI_ITEM_NONE, IFACE_("UV Coordinates"), ICON_NONE); uiItemR(sub, imfptr, "export_normals", UI_ITEM_NONE, IFACE_("Vertex Normals"), ICON_NONE); uiItemR(sub, imfptr, "export_colors", UI_ITEM_NONE, IFACE_("Vertex Colors"), ICON_NONE); uiItemR(sub, imfptr, "export_attributes", UI_ITEM_NONE, IFACE_("Vertex Attributes"), ICON_NONE); uiItemR(sub, imfptr, "export_triangulated_mesh", UI_ITEM_NONE, IFACE_("Triangulated Mesh"), ICON_NONE); } static void wm_ply_export_draw(bContext * /*C*/, wmOperator *op) { PointerRNA ptr = RNA_pointer_create(nullptr, op->type->srna, op->properties); ui_ply_export_settings(op->layout, &ptr); } /** * Return true if any property in the UI is changed. */ static bool wm_ply_export_check(bContext * /*C*/, wmOperator *op) { char filepath[FILE_MAX]; bool changed = false; RNA_string_get(op->ptr, "filepath", filepath); if (!BLI_path_extension_check(filepath, ".ply")) { BLI_path_extension_ensure(filepath, FILE_MAX, ".ply"); RNA_string_set(op->ptr, "filepath", filepath); changed = true; } return changed; } void WM_OT_ply_export(wmOperatorType *ot) { PropertyRNA *prop; ot->name = "Export PLY"; ot->description = "Save the scene to a PLY file"; ot->idname = "WM_OT_ply_export"; ot->invoke = wm_ply_export_invoke; ot->exec = wm_ply_export_exec; ot->poll = WM_operator_winactive; ot->ui = wm_ply_export_draw; ot->check = wm_ply_export_check; ot->flag = OPTYPE_PRESET; WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); /* Object transform options. */ prop = RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", ""); RNA_def_property_update_runtime(prop, io_ui_forward_axis_update); prop = RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", ""); RNA_def_property_update_runtime(prop, io_ui_up_axis_update); RNA_def_float( ot->srna, "global_scale", 1.0f, 0.0001f, 10000.0f, "Scale", "Value by which to enlarge or shrink the objects with respect to the world's origin", 0.0001f, 10000.0f); /* File Writer options. */ RNA_def_boolean( ot->srna, "apply_modifiers", true, "Apply Modifiers", "Apply modifiers to exported meshes"); RNA_def_boolean(ot->srna, "export_selected_objects", false, "Export Selected Objects", "Export only selected objects instead of all supported objects"); RNA_def_boolean(ot->srna, "export_uv", true, "Export UVs", ""); RNA_def_boolean( ot->srna, "export_normals", false, "Export Vertex Normals", "Export specific vertex normals if available, export calculated normals otherwise"); RNA_def_enum(ot->srna, "export_colors", ply_vertex_colors_mode, PLY_VERTEX_COLOR_SRGB, "Export Vertex Colors", "Export vertex color attributes"); RNA_def_boolean(ot->srna, "export_attributes", true, "Export Vertex Attributes", "Export custom vertex attributes"); RNA_def_boolean(ot->srna, "export_triangulated_mesh", false, "Export Triangulated Mesh", "All ngons with four or more vertices will be triangulated. Meshes in " "the scene will not be affected. Behaves like Triangulate Modifier with " "ngon-method: \"Beauty\", quad-method: \"Shortest Diagonal\", min vertices: 4"); RNA_def_boolean(ot->srna, "ascii_format", false, "ASCII Format", "Export file in ASCII format, export as binary otherwise"); /* Only show .ply files by default. */ prop = RNA_def_string(ot->srna, "filter_glob", "*.ply", 0, "Extension Filter", ""); RNA_def_property_flag(prop, PROP_HIDDEN); } static int wm_ply_import_invoke(bContext *C, wmOperator *op, const wmEvent *event) { return WM_operator_filesel(C, op, event); } static int wm_ply_import_exec(bContext *C, wmOperator *op) { PLYImportParams params{}; params.forward_axis = eIOAxis(RNA_enum_get(op->ptr, "forward_axis")); params.up_axis = eIOAxis(RNA_enum_get(op->ptr, "up_axis")); params.use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit"); params.global_scale = RNA_float_get(op->ptr, "global_scale"); params.merge_verts = RNA_boolean_get(op->ptr, "merge_verts"); params.import_attributes = RNA_boolean_get(op->ptr, "import_attributes"); params.vertex_colors = ePLYVertexColorMode(RNA_enum_get(op->ptr, "import_colors")); int files_len = RNA_collection_length(op->ptr, "files"); if (files_len) { PointerRNA fileptr; PropertyRNA *prop; char dir_only[FILE_MAX], file_only[FILE_MAX]; RNA_string_get(op->ptr, "directory", dir_only); prop = RNA_struct_find_property(op->ptr, "files"); for (int i = 0; i < files_len; i++) { RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr); RNA_string_get(&fileptr, "name", file_only); BLI_path_join(params.filepath, sizeof(params.filepath), dir_only, file_only); PLY_import(C, ¶ms, op); } } else if (RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) { RNA_string_get(op->ptr, "filepath", params.filepath); PLY_import(C, ¶ms, op); } else { BKE_report(op->reports, RPT_ERROR, "No filepath given"); return OPERATOR_CANCELLED; } Scene *scene = CTX_data_scene(C); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); ED_outliner_select_sync_from_object_tag(C); return OPERATOR_FINISHED; } void WM_OT_ply_import(wmOperatorType *ot) { PropertyRNA *prop; ot->name = "Import PLY"; ot->description = "Import an PLY file as an object"; ot->idname = "WM_OT_ply_import"; ot->invoke = wm_ply_import_invoke; ot->exec = wm_ply_import_exec; ot->poll = WM_operator_winactive; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET; WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f); RNA_def_boolean(ot->srna, "use_scene_unit", false, "Scene Unit", "Apply current scene's unit (as defined by unit scale) to imported data"); prop = RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", ""); RNA_def_property_update_runtime(prop, io_ui_forward_axis_update); prop = RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", ""); RNA_def_property_update_runtime(prop, io_ui_up_axis_update); RNA_def_boolean(ot->srna, "merge_verts", false, "Merge Vertices", "Merges vertices by distance"); RNA_def_enum(ot->srna, "import_colors", ply_vertex_colors_mode, PLY_VERTEX_COLOR_SRGB, "Vertex Colors", "Import vertex color attributes"); RNA_def_boolean( ot->srna, "import_attributes", true, "Vertex Attributes", "Import custom vertex attributes"); /* Only show .ply files by default. */ prop = RNA_def_string(ot->srna, "filter_glob", "*.ply", 0, "Extension Filter", ""); RNA_def_property_flag(prop, PROP_HIDDEN); } #endif /* WITH_IO_PLY */