Blender V5.0
io_fbx_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#ifdef WITH_IO_FBX
10
11# include "BKE_context.hh"
12# include "BKE_file_handler.hh"
13# include "BKE_report.hh"
14
15# include "BLI_string.h"
16# include "BLI_string_utf8.h"
17
18# include "WM_api.hh"
19
20# include "DNA_space_types.h"
21
22# include "ED_outliner.hh"
23
24# include "RNA_access.hh"
25# include "RNA_define.hh"
26
27# include "BLT_translation.hh"
28
29# include "UI_interface.hh"
30# include "UI_interface_layout.hh"
31
32# include "IO_fbx.hh"
33# include "io_fbx_ops.hh"
34# include "io_utils.hh"
35
36const EnumPropertyItem rna_enum_fbx_mtl_name_collision_mode_items[] = {
38 "MAKE_UNIQUE",
39 0,
40 "Make Unique",
41 "Import each FBX material as a unique Blender material"},
43 "REFERENCE_EXISTING",
44 0,
45 "Reference Existing",
46 "If a material with the same name already exists, reference that instead of importing"},
47 {0, nullptr, 0, nullptr, nullptr},
48};
49
50static const EnumPropertyItem fbx_vertex_colors_mode[] = {
51 {int(eFBXVertexColorMode::None), "NONE", 0, "None", "Do not import color attributes"},
53 "SRGB",
54 0,
55 "sRGB",
56 "Vertex colors in the file are in sRGB color space"},
58 "LINEAR",
59 0,
60 "Linear",
61 "Vertex colors in the file are in linear color space"},
62 {0, nullptr, 0, nullptr, nullptr}};
63
64static wmOperatorStatus wm_fbx_import_exec(bContext *C, wmOperator *op)
65{
67 params.global_scale = RNA_float_get(op->ptr, "global_scale");
68 params.use_custom_normals = RNA_boolean_get(op->ptr, "use_custom_normals");
69 params.use_custom_props = RNA_boolean_get(op->ptr, "use_custom_props");
70 params.props_enum_as_string = RNA_boolean_get(op->ptr, "use_custom_props_enum_as_string");
71 params.ignore_leaf_bones = RNA_boolean_get(op->ptr, "ignore_leaf_bones");
72 params.import_subdivision = RNA_boolean_get(op->ptr, "import_subdivision");
73 params.validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
74 params.use_anim = RNA_boolean_get(op->ptr, "use_anim");
75 params.anim_offset = RNA_float_get(op->ptr, "anim_offset");
76 params.vertex_colors = eFBXVertexColorMode(RNA_enum_get(op->ptr, "import_colors"));
77 params.mtl_name_collision_mode = eFBXMtlNameCollisionMode(
78 RNA_enum_get(op->ptr, "mtl_name_collision_mode"));
79
80 params.reports = op->reports;
81
83
84 if (paths.is_empty()) {
85 BKE_report(op->reports, RPT_ERROR, "No filepath given");
86 return OPERATOR_CANCELLED;
87 }
88 for (const auto &path : paths) {
89 STRNCPY(params.filepath, path.c_str());
91 }
92
93 Scene *scene = CTX_data_scene(C);
98
99 return OPERATOR_FINISHED;
100}
101
102static bool wm_fbx_import_check(bContext * /*C*/, wmOperator * /*op*/)
103{
104 return false;
105}
106
107static void ui_fbx_import_settings(const bContext *C, uiLayout *layout, PointerRNA *ptr)
108{
109 layout->use_property_split_set(true);
110 layout->use_property_decorate_set(false);
111
112 if (uiLayout *panel = layout->panel(C, "FBX_import_general", false, IFACE_("General"))) {
113 uiLayout *col = &panel->column(false);
114 col->prop(ptr, "global_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
115 col->prop(ptr, "use_custom_props", UI_ITEM_NONE, std::nullopt, ICON_NONE);
116 uiLayout &subcol = col->column(false);
117 subcol.active_set(RNA_boolean_get(ptr, "use_custom_props"));
118 subcol.prop(ptr, "use_custom_props_enum_as_string", UI_ITEM_NONE, std::nullopt, ICON_NONE);
119 }
120
121 if (uiLayout *panel = layout->panel(C, "FBX_import_geometry", false, IFACE_("Geometry"))) {
122 uiLayout *col = &panel->column(false);
123 col->prop(ptr, "use_custom_normals", UI_ITEM_NONE, std::nullopt, ICON_NONE);
124 col->prop(ptr, "import_subdivision", UI_ITEM_NONE, std::nullopt, ICON_NONE);
125 col->prop(ptr, "import_colors", UI_ITEM_NONE, std::nullopt, ICON_NONE);
126 col->prop(ptr, "validate_meshes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
127 }
128
129 if (uiLayout *panel = layout->panel(C, "FBX_import_material", true, IFACE_("Materials"))) {
130 uiLayout *col = &panel->column(false);
131 col->prop(ptr, "mtl_name_collision_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
132 }
133
134 {
135 PanelLayout panel = layout->panel(C, "FBX_import_anim", true);
136 panel.header->use_property_split_set(false);
137 panel.header->prop(ptr, "use_anim", UI_ITEM_NONE, "", ICON_NONE);
138 panel.header->label(IFACE_("Animation"), ICON_NONE);
139 if (panel.body) {
140 uiLayout *col = &panel.body->column(false);
141 col->prop(ptr, "anim_offset", UI_ITEM_NONE, std::nullopt, ICON_NONE);
142 }
143 }
144
145 if (uiLayout *panel = layout->panel(C, "FBX_import_armature", false, IFACE_("Armature"))) {
146 uiLayout *col = &panel->column(false);
147 col->prop(ptr, "ignore_leaf_bones", UI_ITEM_NONE, std::nullopt, ICON_NONE);
148 }
149}
150
151static void wm_fbx_import_draw(bContext *C, wmOperator *op)
152{
153 ui_fbx_import_settings(C, op->layout, op->ptr);
154}
155
157{
158 PropertyRNA *prop;
159
160 ot->name = "Import FBX";
161 ot->description = "Import FBX file into current scene";
162 ot->idname = "WM_OT_fbx_import";
163
165 ot->exec = wm_fbx_import_exec;
167 ot->check = wm_fbx_import_check;
168 ot->ui = wm_fbx_import_draw;
169 ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
170
179
180 RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f);
181
183 ot->srna,
184 "mtl_name_collision_mode",
185 rna_enum_fbx_mtl_name_collision_mode_items,
187 "Material Name Collision",
188 "Behavior when the name of an imported material conflicts with an existing material");
189 RNA_def_enum(ot->srna,
190 "import_colors",
191 fbx_vertex_colors_mode,
193 "Vertex Colors",
194 "Import vertex color attributes");
195
196 RNA_def_boolean(ot->srna,
197 "use_custom_normals",
198 true,
199 "Custom Normals",
200 "Import custom normals, if available (otherwise Blender will compute them)");
201 RNA_def_boolean(ot->srna,
202 "use_custom_props",
203 true,
204 "Custom Properties",
205 "Import user properties as custom properties");
206 RNA_def_boolean(ot->srna,
207 "use_custom_props_enum_as_string",
208 true,
209 "Enums As Strings",
210 "Store custom property enumeration values as strings");
211 RNA_def_boolean(ot->srna,
212 "import_subdivision",
213 false,
214 "Subdivision Data",
215 "Import FBX subdivision information as subdivision surface modifiers");
216 RNA_def_boolean(ot->srna,
217 "ignore_leaf_bones",
218 false,
219 "Ignore Leaf Bones",
220 "Ignore the last bone at the end of each chain (used to mark the length of the "
221 "previous bone)");
223 ot->srna,
224 "validate_meshes",
225 true,
226 "Validate Meshes",
227 "Ensure the data is valid "
228 "(when disabled, data may be imported which causes crashes displaying or editing)");
229
230 RNA_def_boolean(ot->srna, "use_anim", true, "Import Animation", "Import FBX animation");
231 prop = RNA_def_float(ot->srna,
232 "anim_offset",
233 1.0f,
234 -1e6f,
235 1e6f,
236 "Offset",
237 "Offset to apply to animation timestamps, in frames",
238 -1e4f,
239 1e4f);
240 RNA_def_property_ui_range(prop, -1e4f, 1e4f, 100, 1);
241
242 /* Only show `.fbx` files by default. */
243 prop = RNA_def_string(ot->srna, "filter_glob", "*.fbx", 0, "Extension Filter", "");
245}
246
247namespace blender::ed::io {
249{
250 auto fh = std::make_unique<blender::bke::FileHandlerType>();
251 STRNCPY_UTF8(fh->idname, "IO_FH_fbx");
252 STRNCPY_UTF8(fh->import_operator, "WM_OT_fbx_import");
253 STRNCPY_UTF8(fh->export_operator, "export_scene.fbx"); /* Use Python add-on for export. */
254 STRNCPY_UTF8(fh->label, "FBX");
255 STRNCPY_UTF8(fh->file_extensions_str, ".fbx");
256 fh->poll_drop = poll_file_object_drop;
257 bke::file_handler_add(std::move(fh));
258}
259
260} // namespace blender::ed::io
261
262#endif /* WITH_IO_FBX */
Scene * CTX_data_scene(const bContext *C)
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define STRNCPY_UTF8(dst, src)
#define IFACE_(msgid)
@ FILE_SORT_DEFAULT
@ FILE_BLENDER
@ FILE_TYPE_FOLDER
@ FILE_DEFAULTDISPLAY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void ED_outliner_select_sync_from_object_tag(bContext *C)
void FBX_import(bContext *C, const FBXImportParams &params)
Definition IO_fbx.cc:29
eFBXMtlNameCollisionMode
Definition IO_fbx.hh:25
eFBXVertexColorMode
Definition IO_fbx.hh:30
@ 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
#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_fbx_import(wmOperatorType *ot)
void file_handler_add(std::unique_ptr< FileHandlerType > file_handler)
void fbx_file_handler_add()
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
float RNA_float_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)
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)
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
void use_property_decorate_set(bool is_sep)
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
void active_set(bool active)
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_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)