Blender V5.0
io_ply_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#ifdef WITH_IO_PLY
10
11# include "BKE_context.hh"
12# include "BKE_file_handler.hh"
13# include "BKE_main.hh"
14# include "BKE_report.hh"
15
16# include "BLI_string.h"
17# include "BLI_string_utf8.h"
18
19# include "WM_api.hh"
20# include "WM_types.hh"
21
22# include "DNA_space_types.h"
23
24# include "ED_fileselect.hh"
25# include "ED_outliner.hh"
26
27# include "RNA_access.hh"
28# include "RNA_define.hh"
29
30# include "BLT_translation.hh"
31
32# include "UI_interface.hh"
33# include "UI_interface_layout.hh"
34# include "UI_resources.hh"
35
36# include "IO_orientation.hh"
37
38# include "IO_ply.hh"
39# include "io_ply_ops.hh"
40# include "io_utils.hh"
41
42static const EnumPropertyItem ply_vertex_colors_mode[] = {
43 {int(ePLYVertexColorMode::None), "NONE", 0, "None", "Do not import/export color attributes"},
45 "SRGB",
46 0,
47 "sRGB",
48 "Vertex colors in the file are in sRGB color space"},
50 "LINEAR",
51 0,
52 "Linear",
53 "Vertex colors in the file are in linear color space"},
54 {0, nullptr, 0, nullptr, nullptr}};
55
56static wmOperatorStatus wm_ply_export_invoke(bContext *C,
57 wmOperator *op,
58 const wmEvent * /*event*/)
59{
61
64}
65
66static wmOperatorStatus wm_ply_export_exec(bContext *C, wmOperator *op)
67{
68 if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
69 BKE_report(op->reports, RPT_ERROR, "No filepath given");
70 return OPERATOR_CANCELLED;
71 }
72 PLYExportParams export_params;
73 export_params.file_base_for_tests[0] = '\0';
74 RNA_string_get(op->ptr, "filepath", export_params.filepath);
75 export_params.blen_filepath = CTX_data_main(C)->filepath;
76
77 export_params.forward_axis = eIOAxis(RNA_enum_get(op->ptr, "forward_axis"));
78 export_params.up_axis = eIOAxis(RNA_enum_get(op->ptr, "up_axis"));
79 export_params.global_scale = RNA_float_get(op->ptr, "global_scale");
80 export_params.apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers");
81
82 export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
83 export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
84 export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
85 export_params.vertex_colors = ePLYVertexColorMode(RNA_enum_get(op->ptr, "export_colors"));
86 export_params.export_attributes = RNA_boolean_get(op->ptr, "export_attributes");
87 export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
88 export_params.ascii_format = RNA_boolean_get(op->ptr, "ascii_format");
89
90 RNA_string_get(op->ptr, "collection", export_params.collection);
91
92 export_params.reports = op->reports;
93
94 PLY_export(C, export_params);
95
97 return OPERATOR_CANCELLED;
98 }
99
100 BKE_report(op->reports, RPT_INFO, "File exported successfully");
101 return OPERATOR_FINISHED;
102}
103
104static void wm_ply_export_draw(bContext *C, wmOperator *op)
105{
106 uiLayout *layout = op->layout;
107 PointerRNA *ptr = op->ptr;
108
109 layout->use_property_split_set(true);
110 layout->use_property_decorate_set(false);
111
112 if (uiLayout *panel = layout->panel(C, "PLY_export_general", false, IFACE_("General"))) {
113 uiLayout *col = &panel->column(false);
114
115 uiLayout *sub = &col->column(false, IFACE_("Format"));
116 sub->prop(ptr, "ascii_format", UI_ITEM_NONE, IFACE_("ASCII"), ICON_NONE);
117
118 /* The Selection only options only make sense when using regular export. */
119 if (CTX_wm_space_file(C)) {
120 sub = &col->column(false, IFACE_("Include"));
121 sub->prop(ptr, "export_selected_objects", UI_ITEM_NONE, IFACE_("Selection Only"), ICON_NONE);
122 }
123
124 col->prop(ptr, "global_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
125 col->prop(ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
126 col->prop(ptr, "up_axis", UI_ITEM_NONE, IFACE_("Up Axis"), ICON_NONE);
127 }
128
129 if (uiLayout *panel = layout->panel(C, "PLY_export_geometry", false, IFACE_("Geometry"))) {
130 uiLayout *col = &panel->column(false);
131
132 col->prop(ptr, "export_uv", UI_ITEM_NONE, IFACE_("UV Coordinates"), ICON_NONE);
133 col->prop(ptr, "export_normals", UI_ITEM_NONE, IFACE_("Vertex Normals"), ICON_NONE);
134 col->prop(ptr, "export_attributes", UI_ITEM_NONE, IFACE_("Vertex Attributes"), ICON_NONE);
135 col->prop(ptr, "export_colors", UI_ITEM_NONE, IFACE_("Vertex Colors"), ICON_NONE);
136
137 col->prop(
138 ptr, "export_triangulated_mesh", UI_ITEM_NONE, IFACE_("Triangulated Mesh"), ICON_NONE);
139 col->prop(ptr, "apply_modifiers", UI_ITEM_NONE, IFACE_("Apply Modifiers"), ICON_NONE);
140 }
141}
142
146static bool wm_ply_export_check(bContext * /*C*/, wmOperator *op)
147{
148 char filepath[FILE_MAX];
149 bool changed = false;
150 RNA_string_get(op->ptr, "filepath", filepath);
151
152 if (!BLI_path_extension_check(filepath, ".ply")) {
153 BLI_path_extension_ensure(filepath, FILE_MAX, ".ply");
154 RNA_string_set(op->ptr, "filepath", filepath);
155 changed = true;
156 }
157 return changed;
158}
159
161{
162 PropertyRNA *prop;
163
164 ot->name = "Export PLY";
165 ot->description = "Save the scene to a PLY file";
166 ot->idname = "WM_OT_ply_export";
167
168 ot->invoke = wm_ply_export_invoke;
169 ot->exec = wm_ply_export_exec;
171 ot->ui = wm_ply_export_draw;
172 ot->check = wm_ply_export_check;
173
174 ot->flag = OPTYPE_PRESET;
175
179 FILE_SAVE,
183
184 /* Object transform options. */
185 prop = RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", "");
187 prop = RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", "");
190 ot->srna,
191 "global_scale",
192 1.0f,
193 0.0001f,
194 10000.0f,
195 "Scale",
196 "Value by which to enlarge or shrink the objects with respect to the world's origin",
197 0.0001f,
198 10000.0f);
199 /* File Writer options. */
201 ot->srna, "apply_modifiers", true, "Apply Modifiers", "Apply modifiers to exported meshes");
202 RNA_def_boolean(ot->srna,
203 "export_selected_objects",
204 false,
205 "Export Selected Objects",
206 "Export only selected objects instead of all supported objects");
207 prop = RNA_def_string(ot->srna,
208 "collection",
209 nullptr,
210 MAX_ID_NAME - 2,
211 "Source Collection",
212 "Export only objects from this collection (and its children)");
214
215 RNA_def_boolean(ot->srna, "export_uv", true, "Export UVs", "");
217 ot->srna,
218 "export_normals",
219 false,
220 "Export Vertex Normals",
221 "Export specific vertex normals if available, export calculated normals otherwise");
222 RNA_def_enum(ot->srna,
223 "export_colors",
224 ply_vertex_colors_mode,
226 "Export Vertex Colors",
227 "Export vertex color attributes");
228 RNA_def_boolean(ot->srna,
229 "export_attributes",
230 true,
231 "Export Vertex Attributes",
232 "Export custom vertex attributes");
233 RNA_def_boolean(ot->srna,
234 "export_triangulated_mesh",
235 false,
236 "Export Triangulated Mesh",
237 "All ngons with four or more vertices will be triangulated. Meshes in "
238 "the scene will not be affected. Behaves like Triangulate Modifier with "
239 "ngon-method: \"Beauty\", quad-method: \"Shortest Diagonal\", min vertices: 4");
240 RNA_def_boolean(ot->srna,
241 "ascii_format",
242 false,
243 "ASCII Format",
244 "Export file in ASCII format, export as binary otherwise");
245
246 /* Only show `.ply` files by default. */
247 prop = RNA_def_string(ot->srna, "filter_glob", "*.ply", 0, "Extension Filter", "");
249}
250
251static wmOperatorStatus wm_ply_import_exec(bContext *C, wmOperator *op)
252{
254 params.forward_axis = eIOAxis(RNA_enum_get(op->ptr, "forward_axis"));
255 params.up_axis = eIOAxis(RNA_enum_get(op->ptr, "up_axis"));
256 params.use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit");
257 params.global_scale = RNA_float_get(op->ptr, "global_scale");
258 params.merge_verts = RNA_boolean_get(op->ptr, "merge_verts");
259 params.import_attributes = RNA_boolean_get(op->ptr, "import_attributes");
260 params.vertex_colors = ePLYVertexColorMode(RNA_enum_get(op->ptr, "import_colors"));
261
262 params.reports = op->reports;
263
265
266 if (paths.is_empty()) {
267 BKE_report(op->reports, RPT_ERROR, "No filepath given");
268 return OPERATOR_CANCELLED;
269 }
270 for (const auto &path : paths) {
271 STRNCPY(params.filepath, path.c_str());
273 };
274
275 Scene *scene = CTX_data_scene(C);
280
281 return OPERATOR_FINISHED;
282}
283
284static void ui_ply_import_settings(const bContext *C, uiLayout *layout, PointerRNA *ptr)
285{
286 layout->use_property_split_set(true);
287 layout->use_property_decorate_set(false);
288
289 if (uiLayout *panel = layout->panel(C, "PLY_import_general", false, IFACE_("General"))) {
290 uiLayout *col = &panel->column(false);
291 col->prop(ptr, "global_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
292 col->prop(ptr, "use_scene_unit", UI_ITEM_NONE, std::nullopt, ICON_NONE);
293 col->prop(ptr, "forward_axis", UI_ITEM_NONE, std::nullopt, ICON_NONE);
294 col->prop(ptr, "up_axis", UI_ITEM_NONE, std::nullopt, ICON_NONE);
295 }
296
297 if (uiLayout *panel = layout->panel(C, "PLY_import_options", false, IFACE_("Options"))) {
298 uiLayout *col = &panel->column(false);
299 col->prop(ptr, "merge_verts", UI_ITEM_NONE, std::nullopt, ICON_NONE);
300 col->prop(ptr, "import_colors", UI_ITEM_NONE, std::nullopt, ICON_NONE);
301 }
302}
303
304static void wm_ply_import_draw(bContext *C, wmOperator *op)
305{
306 ui_ply_import_settings(C, op->layout, op->ptr);
307}
308
310{
311 PropertyRNA *prop;
312
313 ot->name = "Import PLY";
314 ot->description = "Import an PLY file as an object";
315 ot->idname = "WM_OT_ply_import";
316
318 ot->exec = wm_ply_import_exec;
319 ot->ui = wm_ply_import_draw;
321 ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
322
331
332 RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f);
333 RNA_def_boolean(ot->srna,
334 "use_scene_unit",
335 false,
336 "Scene Unit",
337 "Apply current scene's unit (as defined by unit scale) to imported data");
338 prop = RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", "");
340 prop = RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", "");
342 RNA_def_boolean(ot->srna, "merge_verts", false, "Merge Vertices", "Merges vertices by distance");
343 RNA_def_enum(ot->srna,
344 "import_colors",
345 ply_vertex_colors_mode,
347 "Vertex Colors",
348 "Import vertex color attributes");
350 ot->srna, "import_attributes", true, "Vertex Attributes", "Import custom vertex attributes");
351
352 /* Only show `.ply` files by default. */
353 prop = RNA_def_string(ot->srna, "filter_glob", "*.ply", 0, "Extension Filter", "");
355}
356
357namespace blender::ed::io {
359{
360 auto fh = std::make_unique<blender::bke::FileHandlerType>();
361 STRNCPY_UTF8(fh->idname, "IO_FH_ply");
362 STRNCPY_UTF8(fh->import_operator, "WM_OT_ply_import");
363 STRNCPY_UTF8(fh->export_operator, "WM_OT_ply_export");
364 STRNCPY_UTF8(fh->label, "Stanford PLY");
365 STRNCPY_UTF8(fh->file_extensions_str, ".ply");
366 fh->poll_drop = poll_file_object_drop;
367 bke::file_handler_add(std::move(fh));
368}
369} // namespace blender::ed::io
370
371#endif /* WITH_IO_PLY */
SpaceFile * CTX_wm_space_file(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
bool BKE_reports_contain(ReportList *reports, eReportType level)
Definition report.cc:383
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#define FILE_MAX
bool BLI_path_extension_check(const char *path, const char *ext) ATTR_NONNULL(1
bool BLI_path_extension_ensure(char *path, size_t path_maxncpy, const char *ext) ATTR_NONNULL(1
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define STRNCPY_UTF8(dst, src)
#define IFACE_(msgid)
#define MAX_ID_NAME
Definition DNA_ID.h:373
@ FILE_SORT_DEFAULT
@ FILE_BLENDER
@ FILE_TYPE_FOLDER
@ FILE_DEFAULTDISPLAY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
void ED_fileselect_ensure_default_filepath(bContext *C, wmOperator *op, const char *extension)
Definition filesel.cc:1470
void ED_outliner_select_sync_from_object_tag(bContext *C)
eIOAxis
@ IO_AXIS_Y
@ IO_AXIS_Z
void PLY_import(bContext *C, const PLYImportParams &params)
Definition IO_ply.cc:37
void PLY_export(bContext *C, const PLYExportParams &params)
Definition IO_ply.cc:30
ePLYVertexColorMode
Definition IO_ply.hh:21
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
#define UI_ITEM_NONE
@ WM_FILESEL_FILES
Definition WM_api.hh:1125
@ WM_FILESEL_DIRECTORY
Definition WM_api.hh:1122
@ WM_FILESEL_SHOW_PROPS
Definition WM_api.hh:1127
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1124
@ FILE_OPENFILE
Definition WM_api.hh:1133
@ FILE_SAVE
Definition WM_api.hh:1134
#define ND_OB_ACTIVE
Definition WM_types.hh:440
#define ND_OB_SELECT
Definition WM_types.hh:442
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_PRESET
Definition WM_types.hh:195
@ OPTYPE_UNDO
Definition WM_types.hh:182
#define ND_LAYER_CONTENT
Definition WM_types.hh:453
uint col
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void WM_OT_ply_export(wmOperatorType *ot)
void WM_OT_ply_import(wmOperatorType *ot)
void file_handler_add(std::unique_ptr< FileHandlerType > file_handler)
bool poll_file_object_drop(const bContext *C, blender::bke::FileHandlerType *)
Definition io_utils.cc:58
Vector< std::string > paths_from_operator_properties(PointerRNA *ptr)
Definition io_utils.cc:75
wmOperatorStatus filesel_drop_import_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition io_utils.cc:26
void ply_file_handler_add()
const EnumPropertyItem io_transform_axis[]
void io_ui_forward_axis_update(Main *, Scene *, PointerRNA *ptr)
void io_ui_up_axis_update(Main *, Scene *, PointerRNA *ptr)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost)
float RNA_float_get(PointerRNA *ptr, const char *name)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
void RNA_def_property_update_runtime(PropertyRNA *prop, RNAPropertyUpdateFunc func)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
char filepath[1024]
Definition BKE_main.hh:179
eIOAxis forward_axis
Definition IO_ply.hh:40
const char * blen_filepath
Definition IO_ply.hh:34
bool ascii_format
Definition IO_ply.hh:37
bool apply_modifiers
Definition IO_ply.hh:46
bool export_attributes
Definition IO_ply.hh:50
eIOAxis up_axis
Definition IO_ply.hh:41
ReportList * reports
Definition IO_ply.hh:54
ePLYVertexColorMode vertex_colors
Definition IO_ply.hh:49
char file_base_for_tests[FILE_MAX]
Definition IO_ply.hh:31
char filepath[FILE_MAX]
Definition IO_ply.hh:29
float global_scale
Definition IO_ply.hh:42
bool export_triangulated_mesh
Definition IO_ply.hh:51
char collection[MAX_ID_NAME - 2]
Definition IO_ply.hh:52
bool export_selected_objects
Definition IO_ply.hh:45
bool export_normals
Definition IO_ply.hh:48
void use_property_decorate_set(bool is_sep)
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
struct ReportList * reports
struct uiLayout * layout
struct PointerRNA * ptr
void WM_event_add_fileselect(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
bool WM_operator_winactive(bContext *C)