Add Chromium-only Blender WebEngine parity work
This commit is contained in:
118
blender-5.2.0/source/blender/editors/io/CMakeLists.txt
Normal file
118
blender-5.2.0/source/blender/editors/io/CMakeLists.txt
Normal file
@@ -0,0 +1,118 @@
|
||||
# SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(INC
|
||||
../include
|
||||
../../io/alembic
|
||||
../../io/common
|
||||
../../io/fbx
|
||||
../../io/grease_pencil
|
||||
../../io/ply
|
||||
../../io/stl
|
||||
../../io/usd
|
||||
../../io/wavefront_obj
|
||||
../../makesrna
|
||||
${CMAKE_BINARY_DIR}/source/blender/makesrna
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
)
|
||||
|
||||
set(SRC
|
||||
io_alembic.cc
|
||||
io_cache.cc
|
||||
io_drop_import_file.cc
|
||||
io_fbx_ops.cc
|
||||
io_grease_pencil.cc
|
||||
io_obj.cc
|
||||
io_ops.cc
|
||||
io_ply_ops.cc
|
||||
io_stl_ops.cc
|
||||
io_usd.cc
|
||||
io_utils.cc
|
||||
|
||||
io_alembic.hh
|
||||
io_cache.hh
|
||||
io_drop_import_file.hh
|
||||
io_fbx_ops.hh
|
||||
io_grease_pencil.hh
|
||||
io_obj.hh
|
||||
io_ops.hh
|
||||
io_ply_ops.hh
|
||||
io_stl_ops.hh
|
||||
io_usd.hh
|
||||
io_utils.hh
|
||||
)
|
||||
|
||||
set(LIB
|
||||
PRIVATE bf::blenkernel
|
||||
PRIVATE bf::blenlib
|
||||
PRIVATE bf::blentranslation
|
||||
PRIVATE bf::bmesh
|
||||
PRIVATE bf::depsgraph
|
||||
PRIVATE bf::dna
|
||||
PRIVATE bf::intern::guardedalloc
|
||||
PRIVATE bf::intern::clog
|
||||
PRIVATE bf::windowmanager
|
||||
)
|
||||
|
||||
if(WITH_IO_WAVEFRONT_OBJ)
|
||||
list(APPEND LIB
|
||||
bf_io_wavefront_obj
|
||||
)
|
||||
add_definitions(-DWITH_IO_WAVEFRONT_OBJ)
|
||||
endif()
|
||||
|
||||
if(WITH_IO_PLY)
|
||||
list(APPEND LIB
|
||||
bf_io_ply
|
||||
)
|
||||
add_definitions(-DWITH_IO_PLY)
|
||||
endif()
|
||||
|
||||
if(WITH_IO_STL)
|
||||
list(APPEND LIB
|
||||
bf_io_stl
|
||||
)
|
||||
add_definitions(-DWITH_IO_STL)
|
||||
endif()
|
||||
|
||||
if(WITH_IO_FBX)
|
||||
list(APPEND LIB
|
||||
bf_io_fbx
|
||||
)
|
||||
add_definitions(-DWITH_IO_FBX)
|
||||
endif()
|
||||
|
||||
if(WITH_IO_GREASE_PENCIL)
|
||||
list(APPEND LIB
|
||||
bf_io_grease_pencil
|
||||
)
|
||||
add_definitions(-DWITH_IO_GREASE_PENCIL)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
list(APPEND LIB
|
||||
bf_io_alembic
|
||||
)
|
||||
add_definitions(-DWITH_ALEMBIC)
|
||||
endif()
|
||||
|
||||
if(WITH_USD)
|
||||
list(APPEND LIB
|
||||
bf_io_usd
|
||||
PRIVATE bf::dependencies::optional::usd
|
||||
)
|
||||
add_definitions(-DWITH_USD)
|
||||
endif()
|
||||
|
||||
if(WITH_PUGIXML)
|
||||
add_definitions(-DWITH_PUGIXML)
|
||||
endif()
|
||||
|
||||
if(WITH_HARU)
|
||||
add_definitions(-DWITH_HARU)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_editor_io "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
738
blender-5.2.0/source/blender/editors/io/io_alembic.cc
Normal file
738
blender-5.2.0/source/blender/editors/io/io_alembic.cc
Normal file
@@ -0,0 +1,738 @@
|
||||
/* SPDX-FileCopyrightText: 2016 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
|
||||
/* needed for directory lookup */
|
||||
# ifndef WIN32
|
||||
# include <dirent.h>
|
||||
# else
|
||||
# include "BLI_winstuff.h"
|
||||
# endif
|
||||
|
||||
# include <cerrno>
|
||||
# include <cstring>
|
||||
|
||||
# include "DNA_modifier_types.h"
|
||||
# include "DNA_object_types.h"
|
||||
# include "DNA_scene_types.h"
|
||||
# include "DNA_space_enums.h"
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_main.hh"
|
||||
# include "BKE_report.hh"
|
||||
|
||||
# include "BLI_path_utils.hh"
|
||||
# include "BLI_string_utf8.h"
|
||||
# include "BLI_utildefines.h"
|
||||
# include "BLI_vector.hh"
|
||||
|
||||
# include "BLT_translation.hh"
|
||||
|
||||
# include "RNA_access.hh"
|
||||
# include "RNA_define.hh"
|
||||
# include "RNA_enum_types.hh"
|
||||
|
||||
# include "ED_fileselect.hh"
|
||||
# include "ED_object.hh"
|
||||
|
||||
# include "UI_interface.hh"
|
||||
# include "UI_resources.hh"
|
||||
|
||||
# include "WM_api.hh"
|
||||
# include "WM_types.hh"
|
||||
|
||||
# include "DEG_depsgraph.hh"
|
||||
|
||||
# include "io_alembic.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
# include "ABC_alembic.h"
|
||||
# include "UI_interface_layout.hh"
|
||||
|
||||
# include "CLG_log.h"
|
||||
|
||||
namespace blender {
|
||||
|
||||
static CLG_LogRef LOG = {"io.alembic"};
|
||||
|
||||
static const EnumPropertyItem rna_enum_abc_export_evaluation_mode_items[] = {
|
||||
{DAG_EVAL_RENDER,
|
||||
"RENDER",
|
||||
0,
|
||||
"Render",
|
||||
"Use Render settings for object visibility, modifier settings, etc"},
|
||||
{DAG_EVAL_VIEWPORT,
|
||||
"VIEWPORT",
|
||||
0,
|
||||
"Viewport",
|
||||
"Use Viewport settings for object visibility, modifier settings, etc"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static wmOperatorStatus wm_alembic_export_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "as_background_job")) {
|
||||
RNA_boolean_set(op->ptr, "as_background_job", true);
|
||||
}
|
||||
|
||||
RNA_boolean_set(op->ptr, "init_scene_frame_range", true);
|
||||
|
||||
ED_fileselect_ensure_default_filepath(C, op, ".abc");
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_alembic_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;
|
||||
}
|
||||
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
AlembicExportParams params{};
|
||||
params.frame_start = RNA_int_get(op->ptr, "start");
|
||||
params.frame_end = RNA_int_get(op->ptr, "end");
|
||||
|
||||
params.frame_samples_xform = RNA_int_get(op->ptr, "xsamples");
|
||||
params.frame_samples_shape = RNA_int_get(op->ptr, "gsamples");
|
||||
|
||||
params.shutter_open = RNA_float_get(op->ptr, "sh_open");
|
||||
params.shutter_close = RNA_float_get(op->ptr, "sh_close");
|
||||
|
||||
params.selected_only = RNA_boolean_get(op->ptr, "selected");
|
||||
params.uvs = RNA_boolean_get(op->ptr, "uvs");
|
||||
params.normals = RNA_boolean_get(op->ptr, "normals");
|
||||
params.vcolors = RNA_boolean_get(op->ptr, "vcolors");
|
||||
params.orcos = RNA_boolean_get(op->ptr, "orcos");
|
||||
params.apply_subdiv = RNA_boolean_get(op->ptr, "apply_subdiv");
|
||||
params.curves_as_mesh = RNA_boolean_get(op->ptr, "curves_as_mesh");
|
||||
params.flatten_hierarchy = RNA_boolean_get(op->ptr, "flatten");
|
||||
params.face_sets = RNA_boolean_get(op->ptr, "face_sets");
|
||||
params.use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema");
|
||||
params.export_hair = RNA_boolean_get(op->ptr, "export_hair");
|
||||
params.export_particles = RNA_boolean_get(op->ptr, "export_particles");
|
||||
params.export_custom_properties = RNA_boolean_get(op->ptr, "export_custom_properties");
|
||||
params.use_instancing = RNA_boolean_get(op->ptr, "use_instancing");
|
||||
params.packuv = RNA_boolean_get(op->ptr, "packuv");
|
||||
params.triangulate = RNA_boolean_get(op->ptr, "triangulate");
|
||||
params.quad_method = RNA_enum_get(op->ptr, "quad_method");
|
||||
params.ngon_method = RNA_enum_get(op->ptr, "ngon_method");
|
||||
params.evaluation_mode = eEvaluationMode(RNA_enum_get(op->ptr, "evaluation_mode"));
|
||||
|
||||
params.global_scale = RNA_float_get(op->ptr, "global_scale");
|
||||
|
||||
RNA_string_get(op->ptr, "collection", params.collection);
|
||||
|
||||
/* Take some defaults from the scene, if not specified explicitly. */
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
if (params.frame_start == INT_MIN) {
|
||||
params.frame_start = scene->r.sfra;
|
||||
}
|
||||
if (params.frame_end == INT_MIN) {
|
||||
params.frame_end = scene->r.efra;
|
||||
}
|
||||
|
||||
const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job");
|
||||
bool ok = ABC_export(scene, C, filepath, ¶ms, as_background_job);
|
||||
|
||||
return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static void ui_alembic_export_settings(const bContext *C, ui::Layout &layout, PointerRNA *ptr)
|
||||
{
|
||||
layout.use_property_split_set(true);
|
||||
layout.use_property_decorate_set(false);
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "ABC_export_general", false, IFACE_("General"))) {
|
||||
ui::Layout *col = &panel->column(false);
|
||||
col->prop(ptr, "global_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
col = &panel->column(false);
|
||||
if (CTX_wm_space_file(C)) {
|
||||
ui::Layout &sub = col->column(true, IFACE_("Include"));
|
||||
sub.prop(ptr, "selected", UI_ITEM_NONE, IFACE_("Selection Only"), ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Scene Options */
|
||||
if (ui::Layout *panel = layout.panel(C, "ABC_export_scene", false, IFACE_("Scene"))) {
|
||||
ui::Layout *col = &panel->column(false);
|
||||
|
||||
ui::Layout *sub = &col->column(true);
|
||||
sub->prop(ptr, "start", UI_ITEM_NONE, IFACE_("Frame Start"), ICON_NONE);
|
||||
sub->prop(ptr, "end", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
|
||||
|
||||
sub = &col->column(true);
|
||||
sub->prop(ptr, "xsamples", UI_ITEM_NONE, IFACE_("Samples Transform"), ICON_NONE);
|
||||
sub->prop(ptr, "gsamples", UI_ITEM_NONE, IFACE_("Geometry"), ICON_NONE);
|
||||
|
||||
sub = &col->column(true);
|
||||
sub->prop(ptr, "sh_open", ui::ITEM_R_SLIDER, std::nullopt, ICON_NONE);
|
||||
sub->prop(ptr,
|
||||
"sh_close",
|
||||
ui::ITEM_R_SLIDER,
|
||||
CTX_IFACE_(BLT_I18NCONTEXT_ID_CAMERA, "Close"),
|
||||
ICON_NONE);
|
||||
|
||||
col->separator();
|
||||
|
||||
col->prop(ptr, "use_instancing", UI_ITEM_NONE, IFACE_("Use Instancing"), ICON_NONE);
|
||||
col->prop(
|
||||
ptr, "export_custom_properties", UI_ITEM_NONE, IFACE_("Custom Properties"), ICON_NONE);
|
||||
col->prop(ptr, "flatten", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
col = &panel->column(true);
|
||||
col->prop(ptr, "evaluation_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
|
||||
/* Object Data */
|
||||
if (ui::Layout *panel = layout.panel(C, "ABC_export_geometry", false, IFACE_("Geometry"))) {
|
||||
ui::Layout *col = &panel->column(true);
|
||||
col->prop(ptr, "uvs", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
ui::Layout &row = col->row(false);
|
||||
row.active_set(RNA_boolean_get(ptr, "uvs"));
|
||||
row.prop(ptr, "packuv", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
col->prop(ptr, "normals", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(ptr, "vcolors", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(ptr, "orcos", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(ptr, "face_sets", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col->prop(ptr, "curves_as_mesh", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
col->separator();
|
||||
|
||||
ui::Layout *sub = &col->column(true, IFACE_("Subdivision"));
|
||||
sub->prop(ptr, "apply_subdiv", UI_ITEM_NONE, IFACE_("Apply"), ICON_NONE);
|
||||
sub->prop(ptr, "subdiv_schema", UI_ITEM_NONE, IFACE_("Use Schema"), ICON_NONE);
|
||||
|
||||
col = &panel->column(false);
|
||||
col->prop(ptr, "triangulate", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
sub = &col->column(false);
|
||||
sub->active_set(RNA_boolean_get(ptr, "triangulate"));
|
||||
sub->prop(ptr, "quad_method", UI_ITEM_NONE, IFACE_("Method Quads"), ICON_NONE);
|
||||
sub->prop(ptr, "ngon_method", UI_ITEM_NONE, IFACE_("Polygons"), ICON_NONE);
|
||||
}
|
||||
|
||||
/* Particle Data */
|
||||
if (ui::Layout *panel = layout.panel(
|
||||
C, "ABC_export_particles", false, IFACE_("Particle Systems")))
|
||||
{
|
||||
ui::Layout &col = panel->column(true);
|
||||
col.prop(ptr, "export_hair", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "export_particles", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_alembic_export_draw(bContext *C, wmOperator *op)
|
||||
{
|
||||
/* Conveniently set start and end frame to match the scene's frame range. */
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
if (scene != nullptr && RNA_boolean_get(op->ptr, "init_scene_frame_range")) {
|
||||
RNA_int_set(op->ptr, "start", scene->r.sfra);
|
||||
RNA_int_set(op->ptr, "end", scene->r.efra);
|
||||
|
||||
RNA_boolean_set(op->ptr, "init_scene_frame_range", false);
|
||||
}
|
||||
|
||||
ui_alembic_export_settings(C, *op->layout, op->ptr);
|
||||
}
|
||||
|
||||
static bool wm_alembic_export_check(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
if (!BLI_path_extension_check(filepath, ".abc")) {
|
||||
BLI_path_extension_ensure(filepath, FILE_MAX, ".abc");
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WM_OT_alembic_export(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Export Alembic";
|
||||
ot->description = "Export current scene in an Alembic archive";
|
||||
ot->idname = "WM_OT_alembic_export";
|
||||
|
||||
ot->invoke = wm_alembic_export_invoke;
|
||||
ot->exec = wm_alembic_export_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->ui = wm_alembic_export_draw;
|
||||
ot->check = wm_alembic_export_check;
|
||||
ot->flag = OPTYPE_PRESET;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
|
||||
FILE_BLENDER,
|
||||
FILE_SAVE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
|
||||
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.abc", 0, "", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"start",
|
||||
INT_MIN,
|
||||
INT_MIN,
|
||||
INT_MAX,
|
||||
"Start Frame",
|
||||
"Start frame of the export, use the default value to "
|
||||
"take the start frame of the current scene",
|
||||
INT_MIN,
|
||||
INT_MAX);
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"end",
|
||||
INT_MIN,
|
||||
INT_MIN,
|
||||
INT_MAX,
|
||||
"End Frame",
|
||||
"End frame of the export, use the default value to "
|
||||
"take the end frame of the current scene",
|
||||
INT_MIN,
|
||||
INT_MAX);
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"xsamples",
|
||||
1,
|
||||
1,
|
||||
128,
|
||||
"Transform Samples",
|
||||
"Number of times per frame transformations are sampled",
|
||||
1,
|
||||
128);
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"gsamples",
|
||||
1,
|
||||
1,
|
||||
128,
|
||||
"Geometry Samples",
|
||||
"Number of times per frame object data are sampled",
|
||||
1,
|
||||
128);
|
||||
|
||||
RNA_def_float(ot->srna,
|
||||
"sh_open",
|
||||
0.0f,
|
||||
-1.0f,
|
||||
1.0f,
|
||||
"Shutter Open",
|
||||
"Time at which the shutter is open",
|
||||
-1.0f,
|
||||
1.0f);
|
||||
|
||||
RNA_def_float(ot->srna,
|
||||
"sh_close",
|
||||
1.0f,
|
||||
-1.0f,
|
||||
1.0f,
|
||||
"Shutter Close",
|
||||
"Time at which the shutter is closed",
|
||||
-1.0f,
|
||||
1.0f);
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna, "selected", false, "Selected Objects Only", "Export only selected objects");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"flatten",
|
||||
false,
|
||||
"Flatten Hierarchy",
|
||||
"Do not preserve objects' parent/children relationship");
|
||||
|
||||
prop = RNA_def_string(ot->srna, "collection", nullptr, MAX_ID_NAME - 2, "Collection", nullptr);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
RNA_def_boolean(ot->srna, "uvs", true, "UV Coordinates", "Export UV coordinates");
|
||||
|
||||
RNA_def_boolean(ot->srna, "packuv", true, "Merge UVs", "");
|
||||
|
||||
RNA_def_boolean(ot->srna, "normals", true, "Normals", "Export normals");
|
||||
|
||||
RNA_def_boolean(ot->srna, "vcolors", false, "Color Attributes", "Export color attributes");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"orcos",
|
||||
true,
|
||||
"Generated Coordinates",
|
||||
"Export undeformed mesh vertex coordinates");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna, "face_sets", false, "Face Sets", "Export per face shading group assignments");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"subdiv_schema",
|
||||
false,
|
||||
"Use Subdivision Schema",
|
||||
"Export meshes using Alembic's subdivision schema");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"apply_subdiv",
|
||||
false,
|
||||
"Apply Subdivision Surface",
|
||||
"Export subdivision surfaces as meshes");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"curves_as_mesh",
|
||||
false,
|
||||
"Curves as Mesh",
|
||||
"Export curves and NURBS surfaces as meshes");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_instancing",
|
||||
true,
|
||||
"Use Instancing",
|
||||
"Export data of duplicated objects as Alembic instances; speeds up the export "
|
||||
"and can be disabled for compatibility with other software");
|
||||
|
||||
RNA_def_float(
|
||||
ot->srna,
|
||||
"global_scale",
|
||||
1.0f,
|
||||
0.0001f,
|
||||
1000.0f,
|
||||
"Scale",
|
||||
"Value by which to enlarge or shrink the objects with respect to the world's origin",
|
||||
0.0001f,
|
||||
1000.0f);
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"triangulate",
|
||||
false,
|
||||
"Triangulate",
|
||||
"Export polygons (quads and n-gons) as triangles");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"quad_method",
|
||||
rna_enum_modifier_triangulate_quad_method_items,
|
||||
MOD_TRIANGULATE_QUAD_SHORTEDGE,
|
||||
"Quad Method",
|
||||
"Method for splitting the quads into triangles");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"ngon_method",
|
||||
rna_enum_modifier_triangulate_ngon_method_items,
|
||||
MOD_TRIANGULATE_NGON_BEAUTY,
|
||||
"N-gon Method",
|
||||
"Method for splitting the n-gons into triangles");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"export_hair",
|
||||
true,
|
||||
"Export Hair",
|
||||
"Exports hair particle systems as animated curves");
|
||||
RNA_def_boolean(
|
||||
ot->srna, "export_particles", true, "Export Particles", "Exports non-hair particle systems");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"export_custom_properties",
|
||||
true,
|
||||
"Export Custom Properties",
|
||||
"Export custom properties to Alembic .userProperties");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"as_background_job",
|
||||
false,
|
||||
"Run as Background Job",
|
||||
"Enable this to run the import in the background, disable to block Blender while importing. "
|
||||
"This option is deprecated; EXECUTE this operator to run in the foreground, and INVOKE it "
|
||||
"to run as a background job");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"evaluation_mode",
|
||||
rna_enum_abc_export_evaluation_mode_items,
|
||||
DAG_EVAL_RENDER,
|
||||
"Settings",
|
||||
"Determines visibility of objects, modifier settings, and other areas where there "
|
||||
"are different settings for viewport and rendering");
|
||||
|
||||
/* This dummy prop is used to check whether we need to init the start and
|
||||
* end frame values to that of the scene's, otherwise they are reset at
|
||||
* every change, draw update. */
|
||||
RNA_def_boolean(ot->srna, "init_scene_frame_range", true, "", "");
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
/* TODO(kevin): check on de-duplicating all this with code in `image_ops.cc` */
|
||||
|
||||
struct CacheFrame {
|
||||
CacheFrame *next, *prev;
|
||||
int framenr;
|
||||
};
|
||||
|
||||
static int get_sequence_len(const char *filepath, int *ofs)
|
||||
{
|
||||
int frame;
|
||||
int numdigit;
|
||||
|
||||
if (!BLI_path_frame_get(filepath, &frame, &numdigit)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
char dirpath[FILE_MAX];
|
||||
BLI_path_split_dir_part(filepath, dirpath, FILE_MAX);
|
||||
|
||||
if (dirpath[0] == '\0') {
|
||||
/* The `filepath` had no directory component, so just use the blend files directory. */
|
||||
BLI_path_split_dir_part(BKE_main_blendfile_path_from_global(), dirpath, sizeof(dirpath));
|
||||
}
|
||||
else {
|
||||
BLI_path_abs(dirpath, BKE_main_blendfile_path_from_global());
|
||||
}
|
||||
|
||||
DIR *dir = opendir(dirpath);
|
||||
if (dir == nullptr) {
|
||||
CLOG_ERROR(&LOG,
|
||||
"Error opening directory '%s': %s",
|
||||
dirpath,
|
||||
errno ? strerror(errno) : "unknown error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *ext = ".abc";
|
||||
const char *basename = BLI_path_basename(filepath);
|
||||
const int len = strlen(basename) - (numdigit + strlen(ext));
|
||||
|
||||
Vector<CacheFrame> frames;
|
||||
|
||||
dirent *fname;
|
||||
while ((fname = readdir(dir)) != nullptr) {
|
||||
/* do we have the right extension? */
|
||||
if (!strstr(fname->d_name, ext)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!STREQLEN(basename, fname->d_name, len)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CacheFrame cache_frame{};
|
||||
|
||||
BLI_path_frame_get(fname->d_name, &cache_frame.framenr, &numdigit);
|
||||
|
||||
frames.append(cache_frame);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
std::ranges::sort(
|
||||
frames, [](const CacheFrame &a, const CacheFrame &b) { return a.framenr < b.framenr; });
|
||||
|
||||
if (frames.is_empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int frame_curr = frames.first().framenr;
|
||||
(*ofs) = frame_curr;
|
||||
|
||||
for (CacheFrame &cache_frame : frames) {
|
||||
if (cache_frame.framenr != frame_curr) {
|
||||
break;
|
||||
}
|
||||
frame_curr++;
|
||||
}
|
||||
|
||||
return frame_curr - (*ofs);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
static void ui_alembic_import_settings(const bContext *C, ui::Layout *layout, PointerRNA *ptr)
|
||||
{
|
||||
layout->use_property_split_set(true);
|
||||
layout->use_property_decorate_set(false);
|
||||
|
||||
if (ui::Layout *panel = layout->panel(C, "ABC_import_general", false, IFACE_("General"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
|
||||
if (ui::Layout *panel = layout->panel(C, "ABC_import_options", false, IFACE_("Options"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "relative_path", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "set_frame_range", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "is_sequence", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "validate_meshes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "always_add_cache_reader", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_alembic_import_draw(bContext *C, wmOperator *op)
|
||||
{
|
||||
ui_alembic_import_settings(C, op->layout, op->ptr);
|
||||
}
|
||||
|
||||
/* op->invoke, opens fileselect if path property not set, otherwise executes */
|
||||
static wmOperatorStatus wm_alembic_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "as_background_job")) {
|
||||
RNA_boolean_set(op->ptr, "as_background_job", true);
|
||||
}
|
||||
return ed::io::filesel_drop_import_invoke(C, op, event);
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_alembic_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Vector<std::string> paths = ed::io::paths_from_operator_properties(op->ptr);
|
||||
if (paths.is_empty()) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
const float scale = RNA_float_get(op->ptr, "scale");
|
||||
const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence");
|
||||
const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range");
|
||||
const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
|
||||
const bool always_add_cache_reader = RNA_boolean_get(op->ptr, "always_add_cache_reader");
|
||||
const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job");
|
||||
|
||||
int sequence_min_frame = std::numeric_limits<int>::max();
|
||||
int sequence_max_frame = std::numeric_limits<int>::min();
|
||||
|
||||
if (is_sequence) {
|
||||
for (const std::string &path : paths) {
|
||||
int offset = 0;
|
||||
int sequence_len = get_sequence_len(path.c_str(), &offset);
|
||||
if (sequence_len < 0) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Unable to determine ABC sequence length");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
sequence_min_frame = std::min(sequence_min_frame, offset);
|
||||
sequence_max_frame = std::max(sequence_max_frame, offset + (sequence_len - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/* Switch out of edit mode to avoid being stuck in it (#54326). */
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
if (obedit) {
|
||||
ed::object::mode_set(C, OB_MODE_OBJECT);
|
||||
}
|
||||
|
||||
AlembicImportParams params{};
|
||||
params.paths = std::move(paths);
|
||||
params.global_scale = scale;
|
||||
params.sequence_min_frame = sequence_min_frame;
|
||||
params.sequence_max_frame = sequence_max_frame;
|
||||
params.is_sequence = is_sequence;
|
||||
params.set_frame_range = set_frame_range;
|
||||
params.validate_meshes = validate_meshes;
|
||||
params.always_add_cache_reader = always_add_cache_reader;
|
||||
|
||||
bool ok = ABC_import(C, ¶ms, as_background_job);
|
||||
|
||||
return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
void WM_OT_alembic_import(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Import Alembic";
|
||||
ot->description = "Load an Alembic archive";
|
||||
ot->idname = "WM_OT_alembic_import";
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
ot->invoke = wm_alembic_import_invoke;
|
||||
ot->exec = wm_alembic_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->ui = wm_alembic_import_draw;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
|
||||
FILE_BLENDER,
|
||||
FILE_OPENFILE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS |
|
||||
WM_FILESEL_DIRECTORY | WM_FILESEL_FILES,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
|
||||
PropertyRNA *prop = RNA_def_string(ot->srna, "filter_glob", "*.abc", 0, "", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
RNA_def_float(
|
||||
ot->srna,
|
||||
"scale",
|
||||
1.0f,
|
||||
0.0001f,
|
||||
1000.0f,
|
||||
"Scale",
|
||||
"Value by which to enlarge or shrink the objects with respect to the world's origin",
|
||||
0.0001f,
|
||||
1000.0f);
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"set_frame_range",
|
||||
true,
|
||||
"Set Frame Range",
|
||||
"If checked, update scene's start and end frame to match those of the Alembic archive");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"validate_meshes",
|
||||
false,
|
||||
"Validate Meshes",
|
||||
"Ensure the data is valid "
|
||||
"(when disabled, data may be imported which causes crashes displaying or editing)");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"always_add_cache_reader",
|
||||
false,
|
||||
"Always Add Cache Reader",
|
||||
"Add cache modifiers and constraints to imported objects even if they are not "
|
||||
"animated so that they can be updated when reloading the Alembic archive");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"is_sequence",
|
||||
false,
|
||||
"Is Sequence",
|
||||
"Set to true if the cache is split into separate files");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"as_background_job",
|
||||
false,
|
||||
"Run as Background Job",
|
||||
"Enable this to run the export in the background, disable to block Blender while exporting. "
|
||||
"This option is deprecated; EXECUTE this operator to run in the foreground, and INVOKE it "
|
||||
"to run as a background job");
|
||||
}
|
||||
|
||||
namespace ed::io {
|
||||
void alembic_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<bke::FileHandlerType>();
|
||||
STRNCPY_UTF8(fh->idname, "IO_FH_alembic");
|
||||
STRNCPY_UTF8(fh->import_operator, "WM_OT_alembic_import");
|
||||
STRNCPY_UTF8(fh->export_operator, "WM_OT_alembic_export");
|
||||
STRNCPY_UTF8(fh->label, "Alembic");
|
||||
STRNCPY_UTF8(fh->file_extensions_str, ".abc");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace ed::io
|
||||
} // namespace blender
|
||||
|
||||
#endif
|
||||
22
blender-5.2.0/source/blender/editors/io/io_alembic.hh
Normal file
22
blender-5.2.0/source/blender/editors/io/io_alembic.hh
Normal file
@@ -0,0 +1,22 @@
|
||||
/* SPDX-FileCopyrightText: 2016 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_alembic_export(wmOperatorType *ot);
|
||||
void WM_OT_alembic_import(wmOperatorType *ot);
|
||||
|
||||
namespace ed::io {
|
||||
void alembic_file_handler_add();
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
323
blender-5.2.0/source/blender/editors/io/io_cache.cc
Normal file
323
blender-5.2.0/source/blender/editors/io/io_cache.cc
Normal file
@@ -0,0 +1,323 @@
|
||||
/* SPDX-FileCopyrightText: 2016 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_path_utils.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_cachefile.hh"
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_report.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "io_cache.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
static void reload_cachefile(bContext *C, CacheFile *cache_file)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
BKE_cachefile_reload(depsgraph, cache_file);
|
||||
}
|
||||
|
||||
static void cachefile_init(bContext *C, wmOperator *op)
|
||||
{
|
||||
PropertyPointerRNA *pprop;
|
||||
|
||||
op->customdata = pprop = MEM_new<PropertyPointerRNA>("OpenPropertyPointerRNA");
|
||||
ui::context_active_but_prop_get_templateID(C, &pprop->ptr, &pprop->prop);
|
||||
}
|
||||
|
||||
static wmOperatorStatus cachefile_open_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
|
||||
char filepath[FILE_MAX];
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
/* Default to the same directory as the blend file. */
|
||||
BLI_path_split_dir_part(BKE_main_blendfile_path(bmain), filepath, sizeof(filepath));
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
}
|
||||
|
||||
cachefile_init(C, op);
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static void open_cancel(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
if (op->customdata) {
|
||||
PropertyPointerRNA *prop_ptr = static_cast<PropertyPointerRNA *>(op->customdata);
|
||||
op->customdata = nullptr;
|
||||
MEM_delete(prop_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static wmOperatorStatus cachefile_open_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
CacheFile *cache_file = static_cast<CacheFile *>(
|
||||
BKE_libblock_alloc(bmain, ID_CF, BLI_path_basename(filepath), 0));
|
||||
STRNCPY(cache_file->filepath, filepath);
|
||||
DEG_id_tag_update(&cache_file->id, ID_RECALC_SYNC_TO_EVAL);
|
||||
|
||||
/* Will be set when running invoke, not exec directly. */
|
||||
if (op->customdata != nullptr) {
|
||||
/* hook into UI */
|
||||
PropertyPointerRNA *pprop = static_cast<PropertyPointerRNA *>(op->customdata);
|
||||
if (pprop->prop != nullptr) {
|
||||
/* When creating new ID blocks, use is already 1, but RNA
|
||||
* pointer see also increases user, so this compensates it. */
|
||||
id_us_min(&cache_file->id);
|
||||
|
||||
PointerRNA idptr = RNA_id_pointer_create(&cache_file->id);
|
||||
RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, nullptr);
|
||||
RNA_property_update(C, &pprop->ptr, pprop->prop);
|
||||
}
|
||||
|
||||
op->customdata = nullptr;
|
||||
MEM_delete(pprop);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void CACHEFILE_OT_open(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Open Cache File";
|
||||
ot->description = "Load a cache file";
|
||||
ot->idname = "CACHEFILE_OT_open";
|
||||
|
||||
ot->invoke = cachefile_open_invoke;
|
||||
ot->exec = cachefile_open_exec;
|
||||
ot->cancel = open_cancel;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_ALEMBIC | FILE_TYPE_USD | FILE_TYPE_FOLDER,
|
||||
FILE_BLENDER,
|
||||
FILE_OPENFILE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
}
|
||||
|
||||
/* ***************************** Reload Operator **************************** */
|
||||
|
||||
static wmOperatorStatus cachefile_reload_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
CacheFile *cache_file = CTX_data_edit_cachefile(C);
|
||||
|
||||
if (cache_file == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
reload_cachefile(C, cache_file);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void CACHEFILE_OT_reload(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Refresh Archive";
|
||||
ot->description = "Update objects paths list with new data from the archive";
|
||||
ot->idname = "CACHEFILE_OT_reload";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = cachefile_reload_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ***************************** Add Layer Operator **************************** */
|
||||
|
||||
static wmOperatorStatus cachefile_layer_open_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
|
||||
char filepath[FILE_MAX];
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
/* Default to the same directory as the blend file. */
|
||||
BLI_path_split_dir_part(BKE_main_blendfile_path(bmain), filepath, sizeof(filepath));
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
}
|
||||
|
||||
/* There is no more CacheFile set when returning from the file selector, so store it here. */
|
||||
op->customdata = CTX_data_edit_cachefile(C);
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus cachefile_layer_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
CacheFile *cache_file = static_cast<CacheFile *>(op->customdata);
|
||||
|
||||
if (cache_file == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filepath);
|
||||
|
||||
if (layer == nullptr) {
|
||||
WM_global_report(RPT_ERROR, "Could not add a layer to the cache file");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
reload_cachefile(C, cache_file);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, nullptr);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void CACHEFILE_OT_layer_add(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Add layer";
|
||||
ot->description = "Add an override layer to the archive";
|
||||
ot->idname = "CACHEFILE_OT_layer_add";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->invoke = cachefile_layer_open_invoke;
|
||||
ot->exec = cachefile_layer_add_exec;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_ALEMBIC | FILE_TYPE_USD | FILE_TYPE_FOLDER,
|
||||
FILE_BLENDER,
|
||||
FILE_OPENFILE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
}
|
||||
|
||||
/* ***************************** Remove Layer Operator **************************** */
|
||||
|
||||
static wmOperatorStatus cachefile_layer_remove_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
CacheFile *cache_file = CTX_data_edit_cachefile(C);
|
||||
|
||||
if (cache_file == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file);
|
||||
BKE_cachefile_remove_layer(cache_file, layer);
|
||||
|
||||
reload_cachefile(C, cache_file);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, nullptr);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void CACHEFILE_OT_layer_remove(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Add layer";
|
||||
ot->description = "Remove an override layer from the archive";
|
||||
ot->idname = "CACHEFILE_OT_layer_remove";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = cachefile_layer_remove_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ***************************** Move Layer Operator **************************** */
|
||||
|
||||
static wmOperatorStatus cachefile_layer_move_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
CacheFile *cache_file = CTX_data_edit_cachefile(C);
|
||||
|
||||
if (cache_file == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file);
|
||||
|
||||
if (layer == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
const int dir = RNA_enum_get(op->ptr, "direction");
|
||||
|
||||
if (BLI_listbase_link_move(&cache_file->layers, layer, dir)) {
|
||||
cache_file->active_layer = BLI_findindex(&cache_file->layers, layer) + 1;
|
||||
/* Only reload if something moved, might be expensive. */
|
||||
reload_cachefile(C, cache_file);
|
||||
WM_main_add_notifier(NC_OBJECT | ND_DRAW, nullptr);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void CACHEFILE_OT_layer_move(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem layer_slot_move[] = {
|
||||
{-1, "UP", 0, "Up", ""},
|
||||
{1, "DOWN", 0, "Down", ""},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
ot->name = "Move layer";
|
||||
ot->description =
|
||||
"Move layer in the list, layers further down the list will overwrite data from the layers "
|
||||
"higher up";
|
||||
ot->idname = "CACHEFILE_OT_layer_move";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->exec = cachefile_layer_move_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"direction",
|
||||
layer_slot_move,
|
||||
0,
|
||||
"Direction",
|
||||
"Direction to move the active layer towards");
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
22
blender-5.2.0/source/blender/editors/io/io_cache.hh
Normal file
22
blender-5.2.0/source/blender/editors/io/io_cache.hh
Normal file
@@ -0,0 +1,22 @@
|
||||
/* SPDX-FileCopyrightText: 2016 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void CACHEFILE_OT_open(wmOperatorType *ot);
|
||||
void CACHEFILE_OT_reload(wmOperatorType *ot);
|
||||
|
||||
void CACHEFILE_OT_layer_add(wmOperatorType *ot);
|
||||
void CACHEFILE_OT_layer_remove(wmOperatorType *ot);
|
||||
void CACHEFILE_OT_layer_move(wmOperatorType *ot);
|
||||
|
||||
} // namespace blender
|
||||
225
blender-5.2.0/source/blender/editors/io/io_drop_import_file.cc
Normal file
225
blender-5.2.0/source/blender/editors/io/io_drop_import_file.cc
Normal file
@@ -0,0 +1,225 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_path_utils.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BKE_file_handler.hh"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_define.hh"
|
||||
#include "RNA_prototypes.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_interface_layout.hh"
|
||||
|
||||
#include "io_drop_import_file.hh"
|
||||
#include "io_utils.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
static CLG_LogRef LOG = {"io.drop_import_file"};
|
||||
|
||||
/**
|
||||
* Return a vector of file handlers that support any file path in `paths` and the call to
|
||||
* `poll_drop` returns #true. Unlike `bke::file_handlers_poll_file_drop`, it ensures that file
|
||||
* handlers have a valid import operator.
|
||||
*/
|
||||
static Vector<bke::FileHandlerType *> drop_import_file_poll_file_handlers(
|
||||
const bContext *C, const Span<std::string> paths, const bool quiet = true)
|
||||
{
|
||||
auto file_handlers = bke::file_handlers_poll_file_drop(C, paths);
|
||||
file_handlers.remove_if([quiet](const bke::FileHandlerType *file_handler) {
|
||||
return WM_operatortype_find(file_handler->import_operator, quiet) == nullptr;
|
||||
});
|
||||
return file_handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets in the RNA pointer all file paths supported by the file handler.
|
||||
*/
|
||||
static void file_handler_import_operator_write_ptr(const bke::FileHandlerType *file_handler,
|
||||
PointerRNA &props,
|
||||
const Span<std::string> paths)
|
||||
{
|
||||
|
||||
const auto supported_paths = file_handler->filter_supported_paths(paths);
|
||||
|
||||
PropertyRNA *filepath_prop = RNA_struct_find_property_check(props, "filepath", PROP_STRING);
|
||||
if (filepath_prop) {
|
||||
RNA_property_string_set(&props, filepath_prop, paths[supported_paths[0]].c_str());
|
||||
}
|
||||
|
||||
PropertyRNA *directory_prop = RNA_struct_find_property_check(props, "directory", PROP_STRING);
|
||||
char dir[FILE_MAX];
|
||||
BLI_path_split_dir_part(paths[0].c_str(), dir, sizeof(dir));
|
||||
if (directory_prop) {
|
||||
RNA_property_string_set(&props, directory_prop, dir);
|
||||
}
|
||||
|
||||
PropertyRNA *files_prop = RNA_struct_find_collection_property_check(
|
||||
props, "files", RNA_OperatorFileListElement);
|
||||
if (files_prop) {
|
||||
RNA_property_collection_clear(&props, files_prop);
|
||||
for (const auto &index : supported_paths) {
|
||||
char file[FILE_MAX];
|
||||
STRNCPY(file, paths[index].c_str());
|
||||
BLI_path_rel(file, dir);
|
||||
|
||||
PointerRNA item_ptr{};
|
||||
RNA_property_collection_add(&props, files_prop, &item_ptr);
|
||||
BLI_assert_msg(BLI_path_is_rel(file), "Expected path to be relative (start with '//')");
|
||||
RNA_string_set(&item_ptr, "name", file + 2);
|
||||
}
|
||||
}
|
||||
const bool has_any_filepath_prop = filepath_prop || directory_prop || files_prop;
|
||||
if (!has_any_filepath_prop) {
|
||||
CLOG_WARN(&LOG,
|
||||
"The '%s' file handler import operator ('%s') is missing the required operator "
|
||||
"properties.",
|
||||
file_handler->idname,
|
||||
file_handler->import_operator);
|
||||
}
|
||||
if (directory_prop && !files_prop) {
|
||||
CLOG_WARN(
|
||||
&LOG,
|
||||
"The '%s' file handler import operator ('%s') is missing the 'files' operator property.",
|
||||
file_handler->idname,
|
||||
file_handler->import_operator);
|
||||
}
|
||||
if (!directory_prop && files_prop) {
|
||||
CLOG_WARN(&LOG,
|
||||
"The '%s' file handler import operator ('%s') is missing the 'directory' operator "
|
||||
"property.",
|
||||
file_handler->idname,
|
||||
file_handler->import_operator);
|
||||
}
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_drop_import_file_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
const auto paths = ed::io::paths_from_operator_properties(op->ptr);
|
||||
if (paths.is_empty()) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
auto file_handlers = drop_import_file_poll_file_handlers(C, paths, false);
|
||||
if (file_handlers.is_empty()) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
wmOperatorType *ot = WM_operatortype_find(file_handlers[0]->import_operator, false);
|
||||
PointerRNA file_props = WM_operator_properties_create_ptr(ot);
|
||||
file_handler_import_operator_write_ptr(file_handlers[0], file_props, paths);
|
||||
|
||||
WM_operator_name_call_ptr(C, ot, wm::OpCallContext::InvokeDefault, &file_props, nullptr);
|
||||
WM_operator_properties_free(&file_props);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_drop_import_file_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
const auto paths = ed::io::paths_from_operator_properties(op->ptr);
|
||||
if (paths.is_empty()) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
auto file_handlers = drop_import_file_poll_file_handlers(C, paths, false);
|
||||
if (file_handlers.size() == 1) {
|
||||
return wm_drop_import_file_exec(C, op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a menu with all file handler import operators that can support any files in paths and
|
||||
* let user decide which to use.
|
||||
*/
|
||||
ui::PopupMenu *pup = ui::popup_menu_begin(C, "", ICON_NONE);
|
||||
ui::Layout &layout = *popup_menu_layout(pup);
|
||||
layout.operator_context_set(wm::OpCallContext::InvokeDefault);
|
||||
|
||||
for (auto *file_handler : file_handlers) {
|
||||
wmOperatorType *ot = WM_operatortype_find(file_handler->import_operator, false);
|
||||
PointerRNA file_props = layout.op(ot,
|
||||
CTX_TIP_(ot->translation_context, ot->name),
|
||||
ICON_NONE,
|
||||
wm::OpCallContext::InvokeDefault,
|
||||
UI_ITEM_NONE);
|
||||
file_handler_import_operator_write_ptr(file_handler, file_props, paths);
|
||||
}
|
||||
|
||||
popup_menu_end(C, pup);
|
||||
return OPERATOR_INTERFACE;
|
||||
}
|
||||
|
||||
void WM_OT_drop_import_file(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Drop to Import File";
|
||||
ot->description = "Operator that allows file handlers to receive file drops";
|
||||
ot->idname = "WM_OT_drop_import_file";
|
||||
ot->flag = OPTYPE_INTERNAL;
|
||||
ot->exec = wm_drop_import_file_exec;
|
||||
ot->invoke = wm_drop_import_file_invoke;
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
prop = RNA_def_string_dir_path(
|
||||
ot->srna, "directory", nullptr, FILE_MAX, "Directory", "Directory of the file");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||
|
||||
prop = RNA_def_collection_runtime(ot->srna, "files", RNA_OperatorFileListElement, "Files", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
static void drop_import_file_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
|
||||
{
|
||||
ed::io::paths_to_operator_properties(drop->ptr, WM_drag_get_paths(drag));
|
||||
}
|
||||
|
||||
static bool drop_import_file_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
|
||||
{
|
||||
if (drag->type != WM_DRAG_PATH) {
|
||||
return false;
|
||||
}
|
||||
const auto paths = WM_drag_get_paths(drag);
|
||||
return !drop_import_file_poll_file_handlers(C, paths, true).is_empty();
|
||||
}
|
||||
|
||||
static std::string drop_import_file_tooltip(bContext *C,
|
||||
wmDrag *drag,
|
||||
const int /*xy*/[2],
|
||||
wmDropBox * /*drop*/)
|
||||
{
|
||||
const auto paths = WM_drag_get_paths(drag);
|
||||
const auto file_handlers = drop_import_file_poll_file_handlers(C, paths, true);
|
||||
if (file_handlers.size() == 1) {
|
||||
wmOperatorType *ot = WM_operatortype_find(file_handlers[0]->import_operator, false);
|
||||
return TIP_(ot->name);
|
||||
}
|
||||
|
||||
return TIP_("Multiple file handlers can be used, drop to pick which to use");
|
||||
}
|
||||
|
||||
void ED_dropbox_drop_import_file()
|
||||
{
|
||||
ListBaseT<wmDropBox> *lb = WM_dropboxmap_find("Window", SPACE_EMPTY, RGN_TYPE_WINDOW);
|
||||
WM_dropbox_add(lb,
|
||||
"WM_OT_drop_import_file",
|
||||
drop_import_file_poll,
|
||||
drop_import_file_copy,
|
||||
nullptr,
|
||||
drop_import_file_tooltip);
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
@@ -0,0 +1,14 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_drop_import_file(wmOperatorType *ot);
|
||||
void ED_dropbox_drop_import_file();
|
||||
|
||||
} // namespace blender
|
||||
265
blender-5.2.0/source/blender/editors/io/io_fbx_ops.cc
Normal file
265
blender-5.2.0/source/blender/editors/io/io_fbx_ops.cc
Normal file
@@ -0,0 +1,265 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#ifdef WITH_IO_FBX
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_report.hh"
|
||||
|
||||
# include "BLI_string.h"
|
||||
# include "BLI_string_utf8.h"
|
||||
|
||||
# include "WM_api.hh"
|
||||
|
||||
# include "DNA_space_types.h"
|
||||
|
||||
# include "ED_outliner.hh"
|
||||
|
||||
# include "RNA_access.hh"
|
||||
# include "RNA_define.hh"
|
||||
|
||||
# include "BLT_translation.hh"
|
||||
|
||||
# include "UI_interface.hh"
|
||||
# include "UI_interface_layout.hh"
|
||||
|
||||
# include "IO_fbx.hh"
|
||||
# include "io_fbx_ops.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
const EnumPropertyItem rna_enum_fbx_mtl_name_collision_mode_items[] = {
|
||||
{int(eFBXMtlNameCollisionMode::MakeUnique),
|
||||
"MAKE_UNIQUE",
|
||||
0,
|
||||
"Make Unique",
|
||||
"Import each FBX material as a unique Blender material"},
|
||||
{int(eFBXMtlNameCollisionMode::ReferenceExisting),
|
||||
"REFERENCE_EXISTING",
|
||||
0,
|
||||
"Reference Existing",
|
||||
"If a material with the same name already exists, reference that instead of importing"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem fbx_vertex_colors_mode[] = {
|
||||
{int(eFBXVertexColorMode::None), "NONE", 0, "None", "Do not import color attributes"},
|
||||
{int(eFBXVertexColorMode::sRGB),
|
||||
"SRGB",
|
||||
0,
|
||||
"sRGB",
|
||||
"Vertex colors in the file are in sRGB color space"},
|
||||
{int(eFBXVertexColorMode::Linear),
|
||||
"LINEAR",
|
||||
0,
|
||||
"Linear",
|
||||
"Vertex colors in the file are in linear color space"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
static wmOperatorStatus wm_fbx_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
FBXImportParams params;
|
||||
params.global_scale = RNA_float_get(op->ptr, "global_scale");
|
||||
params.use_custom_normals = RNA_boolean_get(op->ptr, "use_custom_normals");
|
||||
params.use_custom_props = RNA_boolean_get(op->ptr, "use_custom_props");
|
||||
params.props_enum_as_string = RNA_boolean_get(op->ptr, "use_custom_props_enum_as_string");
|
||||
params.ignore_leaf_bones = RNA_boolean_get(op->ptr, "ignore_leaf_bones");
|
||||
params.import_subdivision = RNA_boolean_get(op->ptr, "import_subdivision");
|
||||
params.validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
|
||||
params.use_anim = RNA_boolean_get(op->ptr, "use_anim");
|
||||
params.anim_offset = RNA_float_get(op->ptr, "anim_offset");
|
||||
params.vertex_colors = eFBXVertexColorMode(RNA_enum_get(op->ptr, "import_colors"));
|
||||
params.mtl_name_collision_mode = eFBXMtlNameCollisionMode(
|
||||
RNA_enum_get(op->ptr, "mtl_name_collision_mode"));
|
||||
|
||||
params.reports = op->reports;
|
||||
|
||||
const auto paths = ed::io::paths_from_operator_properties(op->ptr);
|
||||
|
||||
if (paths.is_empty()) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
for (const auto &path : paths) {
|
||||
STRNCPY(params.filepath, path.c_str());
|
||||
FBX_import(C, params);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static bool wm_fbx_import_check(bContext * /*C*/, wmOperator * /*op*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ui_fbx_import_settings(const bContext *C, ui::Layout &layout, PointerRNA *ptr)
|
||||
{
|
||||
layout.use_property_split_set(true);
|
||||
layout.use_property_decorate_set(false);
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "FBX_import_general", false, IFACE_("General"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "global_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "use_custom_props", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
ui::Layout &subcol = col.column(false);
|
||||
subcol.active_set(RNA_boolean_get(ptr, "use_custom_props"));
|
||||
subcol.prop(ptr, "use_custom_props_enum_as_string", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "FBX_import_geometry", false, IFACE_("Geometry"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "use_custom_normals", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "import_subdivision", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "import_colors", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "validate_meshes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "FBX_import_material", true, IFACE_("Materials"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "mtl_name_collision_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
|
||||
{
|
||||
ui::PanelLayout panel = layout.panel(C, "FBX_import_anim", true);
|
||||
panel.header->use_property_split_set(false);
|
||||
panel.header->prop(ptr, "use_anim", UI_ITEM_NONE, "", ICON_NONE);
|
||||
panel.header->label(IFACE_("Animation"), ICON_NONE);
|
||||
if (panel.body) {
|
||||
ui::Layout &col = panel.body->column(false);
|
||||
col.prop(ptr, "anim_offset", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "FBX_import_armature", false, IFACE_("Armature"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "ignore_leaf_bones", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_fbx_import_draw(bContext *C, wmOperator *op)
|
||||
{
|
||||
ui_fbx_import_settings(C, *op->layout, op->ptr);
|
||||
}
|
||||
|
||||
void WM_OT_fbx_import(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
ot->name = "Import FBX";
|
||||
ot->description = "Import FBX file into current scene";
|
||||
ot->idname = "WM_OT_fbx_import";
|
||||
|
||||
ot->invoke = ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = wm_fbx_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->check = wm_fbx_import_check;
|
||||
ot->ui = wm_fbx_import_draw;
|
||||
ot->flag = 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_enum(
|
||||
ot->srna,
|
||||
"mtl_name_collision_mode",
|
||||
rna_enum_fbx_mtl_name_collision_mode_items,
|
||||
int(eFBXMtlNameCollisionMode::MakeUnique),
|
||||
"Material Name Collision",
|
||||
"Behavior when the name of an imported material conflicts with an existing material");
|
||||
RNA_def_enum(ot->srna,
|
||||
"import_colors",
|
||||
fbx_vertex_colors_mode,
|
||||
int(eFBXVertexColorMode::sRGB),
|
||||
"Vertex Colors",
|
||||
"Import vertex color attributes");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_custom_normals",
|
||||
true,
|
||||
"Custom Normals",
|
||||
"Import custom normals, if available (otherwise Blender will compute them)");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_custom_props",
|
||||
true,
|
||||
"Custom Properties",
|
||||
"Import user properties as custom properties");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_custom_props_enum_as_string",
|
||||
true,
|
||||
"Enums As Strings",
|
||||
"Store custom property enumeration values as strings");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"import_subdivision",
|
||||
false,
|
||||
"Subdivision Data",
|
||||
"Import FBX subdivision information as subdivision surface modifiers");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"ignore_leaf_bones",
|
||||
false,
|
||||
"Ignore Leaf Bones",
|
||||
"Ignore the last bone at the end of each chain (used to mark the length of the "
|
||||
"previous bone)");
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"validate_meshes",
|
||||
true,
|
||||
"Validate Meshes",
|
||||
"Ensure the data is valid "
|
||||
"(when disabled, data may be imported which causes crashes displaying or editing)");
|
||||
|
||||
RNA_def_boolean(ot->srna, "use_anim", true, "Import Animation", "Import FBX animation");
|
||||
prop = RNA_def_float(ot->srna,
|
||||
"anim_offset",
|
||||
1.0f,
|
||||
-1e6f,
|
||||
1e6f,
|
||||
"Offset",
|
||||
"Offset to apply to animation timestamps, in frames",
|
||||
-1e4f,
|
||||
1e4f);
|
||||
RNA_def_property_ui_range(prop, -1e4f, 1e4f, 100, 1);
|
||||
|
||||
/* Only show `.fbx` files by default. */
|
||||
prop = RNA_def_string(ot->srna, "filter_glob", "*.fbx", 0, "Extension Filter", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
namespace ed::io {
|
||||
void fbx_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<bke::FileHandlerType>();
|
||||
STRNCPY_UTF8(fh->idname, "IO_FH_fbx");
|
||||
STRNCPY_UTF8(fh->import_operator, "WM_OT_fbx_import");
|
||||
STRNCPY_UTF8(fh->export_operator, "export_scene.fbx"); /* Use Python add-on for export. */
|
||||
STRNCPY_UTF8(fh->label, "FBX");
|
||||
STRNCPY_UTF8(fh->file_extensions_str, ".fbx");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
|
||||
} // namespace ed::io
|
||||
} // namespace blender
|
||||
|
||||
#endif /* WITH_IO_FBX */
|
||||
21
blender-5.2.0/source/blender/editors/io/io_fbx_ops.hh
Normal file
21
blender-5.2.0/source/blender/editors/io/io_fbx_ops.hh
Normal file
@@ -0,0 +1,21 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_fbx_import(wmOperatorType *ot);
|
||||
|
||||
namespace ed::io {
|
||||
void fbx_file_handler_add();
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
624
blender-5.2.0/source/blender/editors/io/io_grease_pencil.cc
Normal file
624
blender-5.2.0/source/blender/editors/io/io_grease_pencil.cc
Normal file
@@ -0,0 +1,624 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#ifdef WITH_IO_GREASE_PENCIL
|
||||
|
||||
# include "BLI_path_utils.hh"
|
||||
# include "BLI_string.h"
|
||||
# include "BLI_string_utf8.h"
|
||||
|
||||
# include "DNA_space_types.h"
|
||||
# include "DNA_view3d_types.h"
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_report.hh"
|
||||
# include "BKE_screen.hh"
|
||||
|
||||
# include "BLT_translation.hh"
|
||||
|
||||
# include "RNA_access.hh"
|
||||
# include "RNA_define.hh"
|
||||
|
||||
# include "ED_fileselect.hh"
|
||||
|
||||
# include "UI_interface.hh"
|
||||
# include "UI_interface_layout.hh"
|
||||
# include "UI_resources.hh"
|
||||
|
||||
# include "WM_api.hh"
|
||||
# include "WM_types.hh"
|
||||
|
||||
# include "io_grease_pencil.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
# include "grease_pencil_io.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
namespace ed::io {
|
||||
|
||||
# if defined(WITH_PUGIXML) || defined(WITH_HARU)
|
||||
|
||||
/* Definition of enum elements to export. */
|
||||
/* Common props for exporting. */
|
||||
static void grease_pencil_export_common_props_definition(wmOperatorType *ot)
|
||||
{
|
||||
using blender::io::grease_pencil::ExportParams;
|
||||
using SelectMode = ExportParams::SelectMode;
|
||||
using FrameMode = ExportParams::FrameMode;
|
||||
|
||||
static const EnumPropertyItem select_mode_items[] = {
|
||||
{int(SelectMode::Active), "ACTIVE", 0, "Active", "Include only the active object"},
|
||||
{int(SelectMode::Selected), "SELECTED", 0, "Selected", "Include selected objects"},
|
||||
{int(SelectMode::Visible), "VISIBLE", 0, "Visible", "Include all visible objects"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem frame_mode_items[] = {
|
||||
{int(FrameMode::Active), "ACTIVE", 0, "Active", "Include only active frame"},
|
||||
{int(FrameMode::Selected), "SELECTED", 0, "Selected", "Include selected frames"},
|
||||
{int(FrameMode::Scene), "SCENE", 0, "Scene", "Include all scene frames"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
RNA_def_boolean(ot->srna, "use_fill", true, "Fill", "Export strokes with fill enabled");
|
||||
RNA_def_enum(ot->srna,
|
||||
"selected_object_type",
|
||||
select_mode_items,
|
||||
int(SelectMode::Active),
|
||||
"Object",
|
||||
"Which objects to include in the export");
|
||||
ot->prop = RNA_def_enum(ot->srna,
|
||||
"frame_mode",
|
||||
frame_mode_items,
|
||||
int(FrameMode::Active),
|
||||
"Frames",
|
||||
"Which frames to include in the export");
|
||||
RNA_def_float(ot->srna,
|
||||
"stroke_sample",
|
||||
0.0f,
|
||||
0.0f,
|
||||
100.0f,
|
||||
"Sampling",
|
||||
"Precision of stroke sampling. Low values mean a more precise result, and zero "
|
||||
"disables sampling",
|
||||
0.0f,
|
||||
100.0f);
|
||||
RNA_def_boolean(
|
||||
ot->srna, "use_uniform_width", false, "Uniform Width", "Export strokes with uniform width");
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
/* Note: Region data is found using "big area" functions, rather than context. This is necessary
|
||||
* since export operators are not always invoked from a View3D. This enables the operator to find
|
||||
* the most relevant 3D view for projection of strokes. */
|
||||
static bool get_invoke_region(bContext *C,
|
||||
ARegion **r_region,
|
||||
View3D **r_view3d,
|
||||
RegionView3D **r_rv3d)
|
||||
{
|
||||
bScreen *screen = CTX_wm_screen(C);
|
||||
if (screen == nullptr) {
|
||||
return false;
|
||||
}
|
||||
ScrArea *area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
|
||||
if (area == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
|
||||
*r_region = region;
|
||||
*r_view3d = static_cast<View3D *>(area->spacedata.first);
|
||||
*r_rv3d = static_cast<RegionView3D *>(region->regiondata);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ed::io
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name SVG single frame import
|
||||
* \{ */
|
||||
|
||||
namespace ed::io {
|
||||
|
||||
static bool grease_pencil_import_svg_check(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
if (!BLI_path_extension_check(filepath, ".svg")) {
|
||||
BLI_path_extension_ensure(filepath, FILE_MAX, ".svg");
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static wmOperatorStatus grease_pencil_import_svg_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using blender::io::grease_pencil::ImportParams;
|
||||
using blender::io::grease_pencil::IOContext;
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false) ||
|
||||
!RNA_struct_find_property(op->ptr, "directory"))
|
||||
{
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ARegion *region;
|
||||
View3D *v3d;
|
||||
RegionView3D *rv3d;
|
||||
if (!get_invoke_region(C, ®ion, &v3d, &rv3d)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Unable to find valid 3D View area");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
const int resolution = RNA_int_get(op->ptr, "resolution");
|
||||
const float scale = RNA_float_get(op->ptr, "scale");
|
||||
const bool use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit");
|
||||
const bool recenter_bounds = RNA_boolean_get(op->ptr, "recenter_bounds");
|
||||
|
||||
const IOContext io_context(*C, region, v3d, rv3d, op->reports);
|
||||
const ImportParams params = {scale, scene->r.cfra, resolution, use_scene_unit, recenter_bounds};
|
||||
|
||||
/* Loop all selected files to import them. All SVG imported shared the same import
|
||||
* parameters, but they are created in separated grease pencil objects. */
|
||||
const auto paths = ed::io::paths_from_operator_properties(op->ptr);
|
||||
for (const auto &path : paths) {
|
||||
/* Do Import. */
|
||||
WM_cursor_wait(true);
|
||||
|
||||
const bool done = blender::io::grease_pencil::import_svg(io_context, params, path);
|
||||
WM_cursor_wait(false);
|
||||
if (!done) {
|
||||
BKE_reportf(op->reports, RPT_WARNING, "Unable to import '%s'", path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void grease_pencil_import_svg_draw(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
ui::Layout &layout = *op->layout;
|
||||
layout.use_property_split_set(true);
|
||||
layout.use_property_decorate_set(false);
|
||||
ui::Layout &col = layout.box().column(false);
|
||||
col.prop(op->ptr, "resolution", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(op->ptr, "scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(op->ptr, "use_scene_unit", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(op->ptr, "recenter_bounds", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
|
||||
static bool grease_pencil_import_svg_poll(bContext *C)
|
||||
{
|
||||
if ((CTX_wm_window(C) == nullptr) || (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ed::io
|
||||
|
||||
void WM_OT_grease_pencil_import_svg(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Import SVG as Grease Pencil";
|
||||
ot->description = "Import SVG into Grease Pencil";
|
||||
ot->idname = "WM_OT_grease_pencil_import_svg";
|
||||
|
||||
ot->invoke = ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = ed::io::grease_pencil_import_svg_exec;
|
||||
ot->poll = ed::io::grease_pencil_import_svg_poll;
|
||||
ot->ui = ed::io::grease_pencil_import_svg_draw;
|
||||
ot->check = ed::io::grease_pencil_import_svg_check;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
|
||||
FILE_BLENDER,
|
||||
FILE_OPENFILE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS |
|
||||
WM_FILESEL_DIRECTORY | WM_FILESEL_FILES,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"resolution",
|
||||
10,
|
||||
1,
|
||||
100000,
|
||||
"Resolution",
|
||||
"Resolution of the generated strokes",
|
||||
1,
|
||||
20);
|
||||
|
||||
RNA_def_float(ot->srna,
|
||||
"scale",
|
||||
10.0f,
|
||||
0.000001f,
|
||||
1000000.0f,
|
||||
"Scale",
|
||||
"Scale of the final strokes",
|
||||
0.001f,
|
||||
100.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");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"recenter_bounds",
|
||||
true,
|
||||
"Center on Bounds",
|
||||
"Center the imported SVG on its bounding box");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name SVG single frame export
|
||||
* \{ */
|
||||
|
||||
# ifdef WITH_PUGIXML
|
||||
|
||||
namespace ed::io {
|
||||
|
||||
static bool grease_pencil_export_svg_check(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
if (!BLI_path_extension_check(filepath, ".svg")) {
|
||||
BLI_path_extension_ensure(filepath, FILE_MAX, ".svg");
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static wmOperatorStatus grease_pencil_export_svg_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
ED_fileselect_ensure_default_filepath(C, op, ".svg");
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus grease_pencil_export_svg_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using blender::io::grease_pencil::ExportParams;
|
||||
using blender::io::grease_pencil::ExportStatus;
|
||||
using blender::io::grease_pencil::IOContext;
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
||||
if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ARegion *region;
|
||||
View3D *v3d;
|
||||
RegionView3D *rv3d;
|
||||
if (!get_invoke_region(C, ®ion, &v3d, &rv3d)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Unable to find valid 3D View area");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
const bool export_stroke_materials = true;
|
||||
const bool export_fill_materials = RNA_boolean_get(op->ptr, "use_fill");
|
||||
const bool use_uniform_width = RNA_boolean_get(op->ptr, "use_uniform_width");
|
||||
const ExportParams::SelectMode select_mode = ExportParams::SelectMode(
|
||||
RNA_enum_get(op->ptr, "selected_object_type"));
|
||||
const ExportParams::FrameMode frame_mode = ExportParams::FrameMode(
|
||||
RNA_enum_get(op->ptr, "frame_mode"));
|
||||
const bool use_clip_camera = RNA_boolean_get(op->ptr, "use_clip_camera");
|
||||
const float stroke_sample = RNA_float_get(op->ptr, "stroke_sample");
|
||||
|
||||
const IOContext io_context(*C, region, v3d, rv3d, op->reports);
|
||||
const ExportParams params = {ob,
|
||||
select_mode,
|
||||
frame_mode,
|
||||
export_stroke_materials,
|
||||
export_fill_materials,
|
||||
use_clip_camera,
|
||||
use_uniform_width,
|
||||
stroke_sample};
|
||||
|
||||
WM_cursor_wait(true);
|
||||
ExportStatus status = blender::io::grease_pencil::export_svg(
|
||||
io_context, params, *scene, filepath);
|
||||
WM_cursor_wait(false);
|
||||
|
||||
switch (status) {
|
||||
case ExportStatus::Ok:
|
||||
break;
|
||||
case ExportStatus::InvalidActiveObjectType:
|
||||
BKE_report(op->reports, RPT_WARNING, "Active object is not a Grease Pencil object");
|
||||
break;
|
||||
case ExportStatus::NoFramesSelected:
|
||||
BKE_report(op->reports, RPT_WARNING, "No frames selected in the Grease Pencil object");
|
||||
break;
|
||||
case ExportStatus::FileWriteError:
|
||||
BKE_reportf(op->reports, RPT_WARNING, "Error during file write for \"%s\"", filepath);
|
||||
break;
|
||||
case ExportStatus::UnknownError:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
enum class GreasePencilExportFiletype {
|
||||
SVG = 0,
|
||||
PDF = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines the layout of the exporter properties.
|
||||
*
|
||||
* \param ptr: RNA pointer to access the export operator's properties.
|
||||
*/
|
||||
static void ui_gpencil_export_settings(ui::Layout &layout,
|
||||
PointerRNA *ptr,
|
||||
GreasePencilExportFiletype file_type)
|
||||
{
|
||||
layout.use_property_split_set(true);
|
||||
layout.use_property_decorate_set(false);
|
||||
|
||||
ui::Layout *box = &layout.box();
|
||||
|
||||
ui::Layout *row = &box->row(false);
|
||||
row->label(IFACE_("Scene Options"), ICON_NONE);
|
||||
|
||||
row = &box->row(false);
|
||||
row->prop(ptr, "selected_object_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
box = &layout.box();
|
||||
row = &box->row(false);
|
||||
row->label(IFACE_("Export Options"), ICON_NONE);
|
||||
|
||||
ui::Layout &col = box->column(false);
|
||||
ui::Layout *sub = &col.column(false);
|
||||
sub->prop(ptr, "frame_mode", UI_ITEM_NONE, IFACE_("Frame"), ICON_NONE);
|
||||
|
||||
box->use_property_split_set(true);
|
||||
|
||||
sub = &col.column(true);
|
||||
sub->prop(ptr, "stroke_sample", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
sub->prop(ptr, "use_fill", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
sub->prop(ptr, "use_uniform_width", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
|
||||
if (file_type == GreasePencilExportFiletype::SVG) {
|
||||
col.prop(ptr, "use_clip_camera", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void grease_pencil_export_svg_draw(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
ui_gpencil_export_settings(*op->layout, op->ptr, GreasePencilExportFiletype::SVG);
|
||||
}
|
||||
|
||||
static bool grease_pencil_export_svg_poll(bContext *C)
|
||||
{
|
||||
if ((CTX_wm_window(C) == nullptr) || (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ed::io
|
||||
|
||||
void WM_OT_grease_pencil_export_svg(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Export to SVG";
|
||||
ot->description = "Export Grease Pencil to SVG";
|
||||
ot->idname = "WM_OT_grease_pencil_export_svg";
|
||||
|
||||
ot->invoke = ed::io::grease_pencil_export_svg_invoke;
|
||||
ot->exec = ed::io::grease_pencil_export_svg_exec;
|
||||
ot->poll = ed::io::grease_pencil_export_svg_poll;
|
||||
ot->ui = ed::io::grease_pencil_export_svg_draw;
|
||||
ot->check = ed::io::grease_pencil_export_svg_check;
|
||||
|
||||
ot->flag = OPTYPE_PRESET;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
|
||||
FILE_BLENDER,
|
||||
FILE_SAVE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
|
||||
ed::io::grease_pencil_export_common_props_definition(ot);
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_clip_camera",
|
||||
false,
|
||||
"Clip Camera",
|
||||
"Clip drawings to camera size when exporting in camera view");
|
||||
}
|
||||
|
||||
# endif /* WITH_PUGIXML */
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name PDF single frame export
|
||||
* \{ */
|
||||
|
||||
# ifdef WITH_HARU
|
||||
|
||||
namespace ed::io {
|
||||
|
||||
static bool grease_pencil_export_pdf_check(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
if (!BLI_path_extension_check(filepath, ".pdf")) {
|
||||
BLI_path_extension_ensure(filepath, FILE_MAX, ".pdf");
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static wmOperatorStatus grease_pencil_export_pdf_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
ED_fileselect_ensure_default_filepath(C, op, ".pdf");
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus grease_pencil_export_pdf_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using blender::io::grease_pencil::ExportParams;
|
||||
using blender::io::grease_pencil::IOContext;
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
||||
if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ARegion *region;
|
||||
View3D *v3d;
|
||||
RegionView3D *rv3d;
|
||||
if (!get_invoke_region(C, ®ion, &v3d, &rv3d)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Unable to find valid 3D View area");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
const bool export_stroke_materials = true;
|
||||
const bool export_fill_materials = RNA_boolean_get(op->ptr, "use_fill");
|
||||
const bool use_uniform_width = RNA_boolean_get(op->ptr, "use_uniform_width");
|
||||
const ExportParams::SelectMode select_mode = ExportParams::SelectMode(
|
||||
RNA_enum_get(op->ptr, "selected_object_type"));
|
||||
const ExportParams::FrameMode frame_mode = ExportParams::FrameMode(
|
||||
RNA_enum_get(op->ptr, "frame_mode"));
|
||||
const bool use_clip_camera = false;
|
||||
const float stroke_sample = RNA_float_get(op->ptr, "stroke_sample");
|
||||
|
||||
const IOContext io_context(*C, region, v3d, rv3d, op->reports);
|
||||
const ExportParams params = {ob,
|
||||
select_mode,
|
||||
frame_mode,
|
||||
export_stroke_materials,
|
||||
export_fill_materials,
|
||||
use_clip_camera,
|
||||
use_uniform_width,
|
||||
stroke_sample};
|
||||
|
||||
WM_cursor_wait(true);
|
||||
const bool done = blender::io::grease_pencil::export_pdf(io_context, params, *scene, filepath);
|
||||
WM_cursor_wait(false);
|
||||
|
||||
if (!done) {
|
||||
BKE_report(op->reports, RPT_WARNING, "Unable to export PDF");
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void grease_pencil_export_pdf_draw(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
ui_gpencil_export_settings(*op->layout, op->ptr, GreasePencilExportFiletype::PDF);
|
||||
}
|
||||
|
||||
static bool grease_pencil_export_pdf_poll(bContext *C)
|
||||
{
|
||||
if ((CTX_wm_window(C) == nullptr) || (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ed::io
|
||||
|
||||
void WM_OT_grease_pencil_export_pdf(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Export to PDF";
|
||||
ot->description = "Export Grease Pencil to PDF";
|
||||
ot->idname = "WM_OT_grease_pencil_export_pdf";
|
||||
|
||||
ot->invoke = ed::io::grease_pencil_export_pdf_invoke;
|
||||
ot->exec = ed::io::grease_pencil_export_pdf_exec;
|
||||
ot->poll = ed::io::grease_pencil_export_pdf_poll;
|
||||
ot->ui = ed::io::grease_pencil_export_pdf_draw;
|
||||
ot->check = ed::io::grease_pencil_export_pdf_check;
|
||||
|
||||
ot->flag = OPTYPE_PRESET;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
|
||||
FILE_BLENDER,
|
||||
FILE_SAVE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
|
||||
using blender::io::grease_pencil::ExportParams;
|
||||
|
||||
ed::io::grease_pencil_export_common_props_definition(ot);
|
||||
}
|
||||
|
||||
# endif /* WITH_HARU */
|
||||
|
||||
/** \} */
|
||||
|
||||
namespace ed::io {
|
||||
|
||||
void grease_pencil_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<bke::FileHandlerType>();
|
||||
STRNCPY_UTF8(fh->idname, "IO_FH_grease_pencil_svg");
|
||||
STRNCPY_UTF8(fh->import_operator, "WM_OT_grease_pencil_import_svg");
|
||||
STRNCPY_UTF8(fh->label, "SVG as Grease Pencil");
|
||||
STRNCPY_UTF8(fh->file_extensions_str, ".svg");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
|
||||
} // namespace ed::io
|
||||
} // namespace blender
|
||||
|
||||
#endif /* WITH_IO_GREASE_PENCIL */
|
||||
28
blender-5.2.0/source/blender/editors/io/io_grease_pencil.hh
Normal file
28
blender-5.2.0/source/blender/editors/io/io_grease_pencil.hh
Normal file
@@ -0,0 +1,28 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_grease_pencil_import_svg(wmOperatorType *ot);
|
||||
|
||||
#ifdef WITH_PUGIXML
|
||||
void WM_OT_grease_pencil_export_svg(wmOperatorType *ot);
|
||||
#endif
|
||||
#ifdef WITH_HARU
|
||||
void WM_OT_grease_pencil_export_pdf(wmOperatorType *ot);
|
||||
#endif
|
||||
|
||||
namespace ed::io {
|
||||
void grease_pencil_file_handler_add();
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
616
blender-5.2.0/source/blender/editors/io/io_obj.cc
Normal file
616
blender-5.2.0/source/blender/editors/io/io_obj.cc
Normal file
@@ -0,0 +1,616 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#ifdef WITH_IO_WAVEFRONT_OBJ
|
||||
|
||||
# include "DNA_space_types.h"
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_main.hh"
|
||||
# include "BKE_report.hh"
|
||||
|
||||
# include "BLI_path_utils.hh"
|
||||
# include "BLI_string.h"
|
||||
# include "BLI_string_utf8.h"
|
||||
|
||||
# include "BLT_translation.hh"
|
||||
|
||||
# include "ED_fileselect.hh"
|
||||
# include "ED_outliner.hh"
|
||||
|
||||
# include "RNA_access.hh"
|
||||
# include "RNA_define.hh"
|
||||
|
||||
# include "UI_interface.hh"
|
||||
# include "UI_interface_layout.hh"
|
||||
# include "UI_resources.hh"
|
||||
|
||||
# include "WM_api.hh"
|
||||
# include "WM_types.hh"
|
||||
|
||||
# include "DEG_depsgraph.hh"
|
||||
|
||||
# include "IO_orientation.hh"
|
||||
# include "IO_path_util_types.hh"
|
||||
# include "IO_wavefront_obj.hh"
|
||||
|
||||
# include "io_obj.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
|
||||
{DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
|
||||
{DAG_EVAL_VIEWPORT,
|
||||
"DAG_EVAL_VIEWPORT",
|
||||
0,
|
||||
"Viewport",
|
||||
"Export objects as they appear in the viewport"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
static const EnumPropertyItem io_obj_path_mode[] = {
|
||||
{PATH_REFERENCE_AUTO, "AUTO", 0, "Auto", "Use relative paths with subdirectories only"},
|
||||
{PATH_REFERENCE_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Always write absolute paths"},
|
||||
{PATH_REFERENCE_RELATIVE, "RELATIVE", 0, "Relative", "Write relative paths where possible"},
|
||||
{PATH_REFERENCE_MATCH, "MATCH", 0, "Match", "Match absolute/relative setting with input path"},
|
||||
{PATH_REFERENCE_STRIP, "STRIP", 0, "Strip", "Write filename only"},
|
||||
{PATH_REFERENCE_COPY, "COPY", 0, "Copy", "Copy the file to the destination path"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
static const EnumPropertyItem io_obj_mtl_name_collision_mode[] = {
|
||||
{OBJ_MTL_NAME_COLLISION_MAKE_UNIQUE,
|
||||
"MAKE_UNIQUE",
|
||||
0,
|
||||
"Make Unique",
|
||||
"Create new materials with unique names for each OBJ file"},
|
||||
{OBJ_MTL_NAME_COLLISION_REFERENCE_EXISTING,
|
||||
"REFERENCE_EXISTING",
|
||||
0,
|
||||
"Reference Existing",
|
||||
"Use existing materials with same name instead of creating new ones"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
static wmOperatorStatus wm_obj_export_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
ED_fileselect_ensure_default_filepath(C, op, ".obj");
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_obj_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;
|
||||
}
|
||||
OBJExportParams export_params;
|
||||
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.export_animation = RNA_boolean_get(op->ptr, "export_animation");
|
||||
export_params.start_frame = RNA_int_get(op->ptr, "start_frame");
|
||||
export_params.end_frame = RNA_int_get(op->ptr, "end_frame");
|
||||
|
||||
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.apply_transform = RNA_boolean_get(op->ptr, "apply_transform");
|
||||
export_params.export_eval_mode = eEvaluationMode(RNA_enum_get(op->ptr, "export_eval_mode"));
|
||||
|
||||
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.export_colors = RNA_boolean_get(op->ptr, "export_colors");
|
||||
export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
|
||||
export_params.path_mode = ePathReferenceMode(RNA_enum_get(op->ptr, "path_mode"));
|
||||
export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
|
||||
export_params.export_curves_as_nurbs = RNA_boolean_get(op->ptr, "export_curves_as_nurbs");
|
||||
export_params.export_pbr_extensions = RNA_boolean_get(op->ptr, "export_pbr_extensions");
|
||||
|
||||
export_params.export_object_groups = RNA_boolean_get(op->ptr, "export_object_groups");
|
||||
export_params.export_material_groups = RNA_boolean_get(op->ptr, "export_material_groups");
|
||||
export_params.export_vertex_groups = RNA_boolean_get(op->ptr, "export_vertex_groups");
|
||||
export_params.export_smooth_groups = RNA_boolean_get(op->ptr, "export_smooth_groups");
|
||||
export_params.smooth_groups_bitflags = RNA_boolean_get(op->ptr, "smooth_group_bitflags");
|
||||
|
||||
export_params.reports = op->reports;
|
||||
|
||||
RNA_string_get(op->ptr, "collection", export_params.collection);
|
||||
|
||||
OBJ_export(C, &export_params);
|
||||
|
||||
if (BKE_reports_contain(op->reports, RPT_ERROR)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_report(op->reports, RPT_INFO, "File exported successfully");
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void ui_obj_export_settings(const bContext *C, ui::Layout &layout, PointerRNA *ptr)
|
||||
{
|
||||
const bool export_animation = RNA_boolean_get(ptr, "export_animation");
|
||||
const bool export_smooth_groups = RNA_boolean_get(ptr, "export_smooth_groups");
|
||||
const bool export_materials = RNA_boolean_get(ptr, "export_materials");
|
||||
|
||||
layout.use_property_split_set(true);
|
||||
layout.use_property_decorate_set(false);
|
||||
|
||||
/* Object General options. */
|
||||
if (ui::Layout *panel = layout.panel(C, "OBJ_export_general", false, IFACE_("General"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
|
||||
if (CTX_wm_space_file(C)) {
|
||||
ui::Layout &sub = col.column(false, IFACE_("Include"));
|
||||
sub.prop(ptr, "export_selected_objects", UI_ITEM_NONE, IFACE_("Selection Only"), ICON_NONE);
|
||||
}
|
||||
|
||||
col.prop(ptr, "global_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
|
||||
col.prop(ptr, "up_axis", UI_ITEM_NONE, IFACE_("Up Axis"), ICON_NONE);
|
||||
}
|
||||
|
||||
/* Geometry options. */
|
||||
if (ui::Layout *panel = layout.panel(C, "OBJ_export_geometry", false, IFACE_("Geometry"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "export_uv", UI_ITEM_NONE, IFACE_("UV Coordinates"), ICON_NONE);
|
||||
col.prop(ptr, "export_normals", UI_ITEM_NONE, IFACE_("Normals"), ICON_NONE);
|
||||
col.prop(ptr, "export_colors", UI_ITEM_NONE, IFACE_("Colors"), ICON_NONE);
|
||||
col.prop(ptr, "export_curves_as_nurbs", UI_ITEM_NONE, IFACE_("Curves as NURBS"), ICON_NONE);
|
||||
|
||||
col.prop(
|
||||
ptr, "export_triangulated_mesh", UI_ITEM_NONE, IFACE_("Triangulated Mesh"), ICON_NONE);
|
||||
col.prop(ptr, "apply_modifiers", UI_ITEM_NONE, IFACE_("Apply Modifiers"), ICON_NONE);
|
||||
col.prop(ptr, "apply_transform", UI_ITEM_NONE, IFACE_("Apply Transform"), ICON_NONE);
|
||||
col.prop(ptr, "export_eval_mode", UI_ITEM_NONE, IFACE_("Properties"), ICON_NONE);
|
||||
}
|
||||
|
||||
/* Grouping options. */
|
||||
if (ui::Layout *panel = layout.panel(C, "OBJ_export_grouping", false, IFACE_("Grouping"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "export_object_groups", UI_ITEM_NONE, IFACE_("Object Groups"), ICON_NONE);
|
||||
col.prop(ptr, "export_material_groups", UI_ITEM_NONE, IFACE_("Material Groups"), ICON_NONE);
|
||||
col.prop(ptr, "export_vertex_groups", UI_ITEM_NONE, IFACE_("Vertex Groups"), ICON_NONE);
|
||||
col.prop(ptr, "export_smooth_groups", UI_ITEM_NONE, IFACE_("Smooth Groups"), ICON_NONE);
|
||||
ui::Layout &sub = col.column(false);
|
||||
sub.enabled_set(export_smooth_groups);
|
||||
sub.prop(
|
||||
ptr, "smooth_group_bitflags", UI_ITEM_NONE, IFACE_("Smooth Group Bitflags"), ICON_NONE);
|
||||
}
|
||||
|
||||
/* Material options. */
|
||||
ui::PanelLayout panel = layout.panel(C, "OBJ_export_materials", false);
|
||||
panel.header->use_property_split_set(false);
|
||||
panel.header->prop(ptr, "export_materials", UI_ITEM_NONE, "", ICON_NONE);
|
||||
panel.header->label(IFACE_("Materials"), ICON_NONE);
|
||||
if (panel.body) {
|
||||
ui::Layout &col = panel.body->column(false);
|
||||
col.enabled_set(export_materials);
|
||||
|
||||
col.prop(ptr, "export_pbr_extensions", UI_ITEM_NONE, IFACE_("PBR Extensions"), ICON_NONE);
|
||||
col.prop(ptr, "path_mode", UI_ITEM_NONE, IFACE_("Path Mode"), ICON_NONE);
|
||||
}
|
||||
|
||||
/* Animation options. */
|
||||
panel = layout.panel(C, "OBJ_export_animation", true);
|
||||
panel.header->use_property_split_set(false);
|
||||
panel.header->prop(ptr, "export_animation", UI_ITEM_NONE, "", ICON_NONE);
|
||||
panel.header->label(IFACE_("Animation"), ICON_NONE);
|
||||
if (panel.body) {
|
||||
ui::Layout &col = panel.body->column(false);
|
||||
col.enabled_set(export_animation);
|
||||
|
||||
col.prop(ptr, "start_frame", UI_ITEM_NONE, IFACE_("Frame Start"), ICON_NONE);
|
||||
col.prop(ptr, "end_frame", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_obj_export_draw(bContext *C, wmOperator *op)
|
||||
{
|
||||
ui_obj_export_settings(C, *op->layout, op->ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if any property in the UI is changed.
|
||||
*/
|
||||
static bool wm_obj_export_check(bContext *C, wmOperator *op)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
bool changed = false;
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
if (!BLI_path_extension_check(filepath, ".obj")) {
|
||||
BLI_path_extension_ensure(filepath, FILE_MAX, ".obj");
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
{
|
||||
int start = RNA_int_get(op->ptr, "start_frame");
|
||||
int end = RNA_int_get(op->ptr, "end_frame");
|
||||
/* Set the defaults. */
|
||||
if (start == INT_MIN) {
|
||||
start = scene->r.sfra;
|
||||
changed = true;
|
||||
}
|
||||
if (end == INT_MAX) {
|
||||
end = scene->r.efra;
|
||||
changed = true;
|
||||
}
|
||||
/* Fix user errors. */
|
||||
if (end < start) {
|
||||
end = start;
|
||||
changed = true;
|
||||
}
|
||||
RNA_int_set(op->ptr, "start_frame", start);
|
||||
RNA_int_set(op->ptr, "end_frame", end);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void WM_OT_obj_export(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
ot->name = "Export Wavefront OBJ";
|
||||
ot->description = "Save the scene to a Wavefront OBJ file";
|
||||
ot->idname = "WM_OT_obj_export";
|
||||
|
||||
ot->invoke = wm_obj_export_invoke;
|
||||
ot->exec = wm_obj_export_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->ui = wm_obj_export_draw;
|
||||
ot->check = wm_obj_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);
|
||||
|
||||
/* Animation options. */
|
||||
RNA_def_boolean(ot->srna,
|
||||
"export_animation",
|
||||
false,
|
||||
"Export Animation",
|
||||
"Export multiple frames instead of the current frame only");
|
||||
RNA_def_int(ot->srna,
|
||||
"start_frame",
|
||||
INT_MIN, /* wm_obj_export_check uses this to set scene->r.sfra. */
|
||||
INT_MIN,
|
||||
INT_MAX,
|
||||
"Start Frame",
|
||||
"The first frame to be exported",
|
||||
INT_MIN,
|
||||
INT_MAX);
|
||||
RNA_def_int(ot->srna,
|
||||
"end_frame",
|
||||
INT_MAX, /* wm_obj_export_check uses this to set scene->r.efra. */
|
||||
INT_MIN,
|
||||
INT_MAX,
|
||||
"End Frame",
|
||||
"The last frame to be exported",
|
||||
INT_MIN,
|
||||
INT_MAX);
|
||||
/* Object transform options. */
|
||||
prop = RNA_def_enum(
|
||||
ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "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_Y, "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,
|
||||
"apply_transform",
|
||||
true,
|
||||
"Apply Transform",
|
||||
"Apply object transforms to exported vertices");
|
||||
RNA_def_enum(ot->srna,
|
||||
"export_eval_mode",
|
||||
io_obj_export_evaluation_mode,
|
||||
DAG_EVAL_VIEWPORT,
|
||||
"Object Properties",
|
||||
"Determines properties like object visibility, modifiers etc., where they differ "
|
||||
"for Render and Viewport");
|
||||
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",
|
||||
true,
|
||||
"Export Normals",
|
||||
"Export per-face normals if the face is flat-shaded, per-face-corner "
|
||||
"normals if smooth-shaded");
|
||||
RNA_def_boolean(ot->srna, "export_colors", false, "Export Colors", "Export per-vertex colors");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"export_materials",
|
||||
true,
|
||||
"Export Materials",
|
||||
"Export MTL library. There must be a Principled-BSDF node for image textures to "
|
||||
"be exported to the MTL file");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"export_pbr_extensions",
|
||||
false,
|
||||
"Export Materials with PBR Extensions",
|
||||
"Export MTL library using PBR extensions (roughness, metallic, sheen, "
|
||||
"coat, anisotropy, transmission)");
|
||||
prop = RNA_def_enum(ot->srna,
|
||||
"path_mode",
|
||||
io_obj_path_mode,
|
||||
PATH_REFERENCE_AUTO,
|
||||
"Path Mode",
|
||||
"Method used to reference paths");
|
||||
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_EDITOR_FILEBROWSER);
|
||||
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,
|
||||
"export_curves_as_nurbs",
|
||||
false,
|
||||
"Export Curves as NURBS",
|
||||
"Export curves in parametric form instead of exporting as mesh");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"export_object_groups",
|
||||
false,
|
||||
"Export Object Groups",
|
||||
"Append mesh name to object name, separated by a '_'");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"export_material_groups",
|
||||
false,
|
||||
"Export Material Groups",
|
||||
"Generate an OBJ group for each part of a geometry using a different material");
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"export_vertex_groups",
|
||||
false,
|
||||
"Export Vertex Groups",
|
||||
"Export the name of the vertex group of a face. It is approximated "
|
||||
"by choosing the vertex group with the most members among the vertices of a face");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"export_smooth_groups",
|
||||
false,
|
||||
"Export Smooth Groups",
|
||||
"Generate smooth groups identifiers for each group of smooth faces, as "
|
||||
"unique integer values by default");
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"smooth_group_bitflags",
|
||||
false,
|
||||
"Bitflags Smooth Groups",
|
||||
"If exporting smoothgroups, generate 'bitflags' values for the groups, instead of "
|
||||
"unique integer values. The same bitflag value can be re-used for different groups of "
|
||||
"smooth faces, as long as they have no common sharp edges or vertices");
|
||||
|
||||
/* Only show `.obj` or `.mtl` files by default. */
|
||||
prop = RNA_def_string(ot->srna, "filter_glob", "*.obj;*.mtl", 0, "Extension Filter", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
prop = RNA_def_string(ot->srna, "collection", nullptr, MAX_ID_NAME - 2, "Collection", nullptr);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_obj_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
OBJImportParams import_params;
|
||||
import_params.global_scale = RNA_float_get(op->ptr, "global_scale");
|
||||
import_params.clamp_size = RNA_float_get(op->ptr, "clamp_size");
|
||||
import_params.forward_axis = eIOAxis(RNA_enum_get(op->ptr, "forward_axis"));
|
||||
import_params.up_axis = eIOAxis(RNA_enum_get(op->ptr, "up_axis"));
|
||||
import_params.use_split_objects = RNA_boolean_get(op->ptr, "use_split_objects");
|
||||
import_params.use_split_groups = RNA_boolean_get(op->ptr, "use_split_groups");
|
||||
import_params.import_vertex_groups = RNA_boolean_get(op->ptr, "import_vertex_groups");
|
||||
import_params.validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
|
||||
import_params.close_spline_loops = RNA_boolean_get(op->ptr, "close_spline_loops");
|
||||
char separator[2] = {};
|
||||
RNA_string_get(op->ptr, "collection_separator", separator);
|
||||
import_params.collection_separator = separator[0];
|
||||
import_params.relative_paths = ((U.flag & USER_RELPATHS) != 0);
|
||||
import_params.clear_selection = true;
|
||||
import_params.mtl_name_collision_mode = eOBJMtlNameCollisionMode(
|
||||
RNA_enum_get(op->ptr, "mtl_name_collision_mode"));
|
||||
|
||||
import_params.reports = op->reports;
|
||||
|
||||
const auto paths = ed::io::paths_from_operator_properties(op->ptr);
|
||||
|
||||
if (paths.is_empty()) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
for (const auto &path : paths) {
|
||||
STRNCPY(import_params.filepath, path.c_str());
|
||||
OBJ_import(C, &import_params);
|
||||
/* Only first import clears selection. */
|
||||
import_params.clear_selection = false;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void ui_obj_import_settings(const bContext *C, ui::Layout &layout, PointerRNA *ptr)
|
||||
{
|
||||
layout.use_property_split_set(true);
|
||||
layout.use_property_decorate_set(false);
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "OBJ_import_general", false, IFACE_("General"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "global_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "clamp_size", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
|
||||
col.prop(ptr, "up_axis", UI_ITEM_NONE, IFACE_("Up Axis"), ICON_NONE);
|
||||
}
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "OBJ_import_options", false, IFACE_("Options"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "use_split_objects", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "use_split_groups", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "import_vertex_groups", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "validate_meshes", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "close_spline_loops", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "collection_separator", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "OBJ_import_materials", false, IFACE_("Materials"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "mtl_name_collision_mode", UI_ITEM_NONE, IFACE_("Name Collision"), ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_obj_import_draw(bContext *C, wmOperator *op)
|
||||
{
|
||||
ui_obj_import_settings(C, *op->layout, op->ptr);
|
||||
}
|
||||
|
||||
void WM_OT_obj_import(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
ot->name = "Import Wavefront OBJ";
|
||||
ot->description = "Load a Wavefront OBJ scene";
|
||||
ot->idname = "WM_OT_obj_import";
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_PRESET;
|
||||
|
||||
ot->invoke = ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = wm_obj_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->ui = wm_obj_import_draw;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER,
|
||||
FILE_BLENDER,
|
||||
FILE_OPENFILE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS |
|
||||
WM_FILESEL_DIRECTORY | WM_FILESEL_FILES,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
|
||||
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);
|
||||
RNA_def_float(
|
||||
ot->srna,
|
||||
"clamp_size",
|
||||
0.0f,
|
||||
0.0f,
|
||||
1000.0f,
|
||||
"Clamp Bounding Box",
|
||||
"Resize the objects to keep bounding box under this value. Value 0 disables clamping",
|
||||
0.0f,
|
||||
1000.0f);
|
||||
prop = RNA_def_enum(
|
||||
ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "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_Y, "Up Axis", "");
|
||||
RNA_def_property_update_runtime(prop, io_ui_up_axis_update);
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_split_objects",
|
||||
true,
|
||||
"Split By Object",
|
||||
"Import each OBJ 'o' as a separate object");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_split_groups",
|
||||
false,
|
||||
"Split By Group",
|
||||
"Import each OBJ 'g' as a separate object");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"import_vertex_groups",
|
||||
false,
|
||||
"Vertex Groups",
|
||||
"Import OBJ groups as vertex groups");
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"validate_meshes",
|
||||
true,
|
||||
"Validate Meshes",
|
||||
"Ensure the data is valid "
|
||||
"(when disabled, data may be imported which causes crashes displaying or editing)");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"close_spline_loops",
|
||||
true,
|
||||
"Detect Cyclic Curves",
|
||||
"Join curve endpoints if overlapping control points are detected "
|
||||
"(if disabled, no curves will be cyclic)");
|
||||
|
||||
RNA_def_string(ot->srna,
|
||||
"collection_separator",
|
||||
nullptr,
|
||||
2,
|
||||
"Path Separator",
|
||||
"Character used to separate objects name into hierarchical structure");
|
||||
|
||||
/* Material options */
|
||||
RNA_def_enum(ot->srna,
|
||||
"mtl_name_collision_mode",
|
||||
io_obj_mtl_name_collision_mode,
|
||||
OBJ_MTL_NAME_COLLISION_MAKE_UNIQUE,
|
||||
"Material Name Collision",
|
||||
"How to handle naming collisions when importing materials");
|
||||
|
||||
/* Only show `.obj` or `.mtl` files by default. */
|
||||
prop = RNA_def_string(ot->srna, "filter_glob", "*.obj;*.mtl", 0, "Extension Filter", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
namespace ed::io {
|
||||
void obj_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<bke::FileHandlerType>();
|
||||
STRNCPY_UTF8(fh->idname, "IO_FH_obj");
|
||||
STRNCPY_UTF8(fh->import_operator, "WM_OT_obj_import");
|
||||
STRNCPY_UTF8(fh->export_operator, "WM_OT_obj_export");
|
||||
STRNCPY_UTF8(fh->label, "Wavefront OBJ");
|
||||
STRNCPY_UTF8(fh->file_extensions_str, ".obj");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace ed::io
|
||||
} // namespace blender
|
||||
|
||||
#endif /* WITH_IO_WAVEFRONT_OBJ */
|
||||
22
blender-5.2.0/source/blender/editors/io/io_obj.hh
Normal file
22
blender-5.2.0/source/blender/editors/io/io_obj.hh
Normal file
@@ -0,0 +1,22 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_obj_export(wmOperatorType *ot);
|
||||
void WM_OT_obj_import(wmOperatorType *ot);
|
||||
|
||||
namespace ed::io {
|
||||
void obj_file_handler_add();
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
87
blender-5.2.0/source/blender/editors/io/io_ops.cc
Normal file
87
blender-5.2.0/source/blender/editors/io/io_ops.cc
Normal file
@@ -0,0 +1,87 @@
|
||||
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "io_ops.hh" /* own include */
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
# include "io_alembic.hh"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_USD
|
||||
# include "io_usd.hh"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_FBX
|
||||
# include "io_fbx_ops.hh"
|
||||
#endif
|
||||
|
||||
#include "io_cache.hh"
|
||||
#include "io_drop_import_file.hh"
|
||||
#include "io_grease_pencil.hh"
|
||||
#include "io_obj.hh"
|
||||
#include "io_ply_ops.hh"
|
||||
#include "io_stl_ops.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
void ED_operatortypes_io()
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
WM_operatortype_append(WM_OT_alembic_import);
|
||||
WM_operatortype_append(WM_OT_alembic_export);
|
||||
ed::io::alembic_file_handler_add();
|
||||
#endif
|
||||
#ifdef WITH_USD
|
||||
WM_operatortype_append(WM_OT_usd_import);
|
||||
WM_operatortype_append(WM_OT_usd_export);
|
||||
ed::io::usd_file_handler_add();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_GREASE_PENCIL
|
||||
WM_operatortype_append(WM_OT_grease_pencil_import_svg);
|
||||
ed::io::grease_pencil_file_handler_add();
|
||||
# ifdef WITH_PUGIXML
|
||||
WM_operatortype_append(WM_OT_grease_pencil_export_svg);
|
||||
# endif
|
||||
# ifdef WITH_HARU
|
||||
WM_operatortype_append(WM_OT_grease_pencil_export_pdf);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
WM_operatortype_append(CACHEFILE_OT_open);
|
||||
WM_operatortype_append(CACHEFILE_OT_reload);
|
||||
|
||||
WM_operatortype_append(CACHEFILE_OT_layer_add);
|
||||
WM_operatortype_append(CACHEFILE_OT_layer_remove);
|
||||
WM_operatortype_append(CACHEFILE_OT_layer_move);
|
||||
#ifdef WITH_IO_WAVEFRONT_OBJ
|
||||
WM_operatortype_append(WM_OT_obj_export);
|
||||
WM_operatortype_append(WM_OT_obj_import);
|
||||
ed::io::obj_file_handler_add();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_PLY
|
||||
WM_operatortype_append(WM_OT_ply_export);
|
||||
WM_operatortype_append(WM_OT_ply_import);
|
||||
ed::io::ply_file_handler_add();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_STL
|
||||
WM_operatortype_append(WM_OT_stl_import);
|
||||
WM_operatortype_append(WM_OT_stl_export);
|
||||
ed::io::stl_file_handler_add();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_IO_FBX
|
||||
WM_operatortype_append(WM_OT_fbx_import);
|
||||
ed::io::fbx_file_handler_add();
|
||||
#endif
|
||||
|
||||
WM_operatortype_append(WM_OT_drop_import_file);
|
||||
ED_dropbox_drop_import_file();
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
15
blender-5.2.0/source/blender/editors/io/io_ops.hh
Normal file
15
blender-5.2.0/source/blender/editors/io/io_ops.hh
Normal file
@@ -0,0 +1,15 @@
|
||||
/* SPDX-FileCopyrightText: 2007 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender {
|
||||
|
||||
void ED_operatortypes_io();
|
||||
|
||||
} // namespace blender
|
||||
374
blender-5.2.0/source/blender/editors/io/io_ply_ops.cc
Normal file
374
blender-5.2.0/source/blender/editors/io/io_ply_ops.cc
Normal file
@@ -0,0 +1,374 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#ifdef WITH_IO_PLY
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_main.hh"
|
||||
# include "BKE_report.hh"
|
||||
|
||||
# include "BLI_string.h"
|
||||
# include "BLI_string_utf8.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.hh"
|
||||
|
||||
# include "UI_interface.hh"
|
||||
# include "UI_interface_layout.hh"
|
||||
# include "UI_resources.hh"
|
||||
|
||||
# include "IO_orientation.hh"
|
||||
|
||||
# include "IO_ply.hh"
|
||||
# include "io_ply_ops.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
static const EnumPropertyItem ply_vertex_colors_mode[] = {
|
||||
{int(ePLYVertexColorMode::None), "NONE", 0, "None", "Do not import/export color attributes"},
|
||||
{int(ePLYVertexColorMode::sRGB),
|
||||
"SRGB",
|
||||
0,
|
||||
"sRGB",
|
||||
"Vertex colors in the file are in sRGB color space"},
|
||||
{int(ePLYVertexColorMode::Linear),
|
||||
"LINEAR",
|
||||
0,
|
||||
"Linear",
|
||||
"Vertex colors in the file are in linear color space"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
static wmOperatorStatus 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 wmOperatorStatus 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;
|
||||
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");
|
||||
|
||||
RNA_string_get(op->ptr, "collection", export_params.collection);
|
||||
|
||||
export_params.reports = op->reports;
|
||||
|
||||
PLY_export(C, export_params);
|
||||
|
||||
if (BKE_reports_contain(op->reports, RPT_ERROR)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_report(op->reports, RPT_INFO, "File exported successfully");
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void wm_ply_export_draw(bContext *C, wmOperator *op)
|
||||
{
|
||||
ui::Layout &layout = *op->layout;
|
||||
PointerRNA *ptr = op->ptr;
|
||||
|
||||
layout.use_property_split_set(true);
|
||||
layout.use_property_decorate_set(false);
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "PLY_export_general", false, IFACE_("General"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
|
||||
{
|
||||
ui::Layout &sub = col.column(false, IFACE_("Format"));
|
||||
sub.prop(ptr, "ascii_format", UI_ITEM_NONE, IFACE_("ASCII"), ICON_NONE);
|
||||
}
|
||||
/* The Selection only options only make sense when using regular export. */
|
||||
if (CTX_wm_space_file(C)) {
|
||||
ui::Layout &sub = col.column(false, IFACE_("Include"));
|
||||
sub.prop(ptr, "export_selected_objects", UI_ITEM_NONE, IFACE_("Selection Only"), ICON_NONE);
|
||||
}
|
||||
|
||||
col.prop(ptr, "global_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
|
||||
col.prop(ptr, "up_axis", UI_ITEM_NONE, IFACE_("Up Axis"), ICON_NONE);
|
||||
}
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "PLY_export_geometry", false, IFACE_("Geometry"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
|
||||
col.prop(ptr, "export_uv", UI_ITEM_NONE, IFACE_("UV Coordinates"), ICON_NONE);
|
||||
col.prop(ptr, "export_normals", UI_ITEM_NONE, IFACE_("Vertex Normals"), ICON_NONE);
|
||||
col.prop(ptr, "export_attributes", UI_ITEM_NONE, IFACE_("Vertex Attributes"), ICON_NONE);
|
||||
col.prop(ptr, "export_colors", UI_ITEM_NONE, IFACE_("Vertex Colors"), ICON_NONE);
|
||||
|
||||
col.prop(
|
||||
ptr, "export_triangulated_mesh", UI_ITEM_NONE, IFACE_("Triangulated Mesh"), ICON_NONE);
|
||||
col.prop(ptr, "apply_modifiers", UI_ITEM_NONE, IFACE_("Apply Modifiers"), ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
prop = RNA_def_string(ot->srna,
|
||||
"collection",
|
||||
nullptr,
|
||||
MAX_ID_NAME - 2,
|
||||
"Source Collection",
|
||||
"Export only objects from this collection (and its children)");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
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,
|
||||
int(ePLYVertexColorMode::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 wmOperatorStatus 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"));
|
||||
|
||||
params.reports = op->reports;
|
||||
|
||||
const auto paths = ed::io::paths_from_operator_properties(op->ptr);
|
||||
|
||||
if (paths.is_empty()) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
for (const auto &path : paths) {
|
||||
STRNCPY(params.filepath, path.c_str());
|
||||
PLY_import(C, params);
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void ui_ply_import_settings(const bContext *C, ui::Layout &layout, PointerRNA *ptr)
|
||||
{
|
||||
layout.use_property_split_set(true);
|
||||
layout.use_property_decorate_set(false);
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "PLY_import_general", false, IFACE_("General"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "global_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "use_scene_unit", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "forward_axis", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "up_axis", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "PLY_import_options", false, IFACE_("Options"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "merge_verts", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "import_colors", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_ply_import_draw(bContext *C, wmOperator *op)
|
||||
{
|
||||
ui_ply_import_settings(C, *op->layout, op->ptr);
|
||||
}
|
||||
|
||||
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 = ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = wm_ply_import_exec;
|
||||
ot->ui = wm_ply_import_draw;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->flag = 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,
|
||||
int(ePLYVertexColorMode::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);
|
||||
}
|
||||
|
||||
namespace ed::io {
|
||||
void ply_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<bke::FileHandlerType>();
|
||||
STRNCPY_UTF8(fh->idname, "IO_FH_ply");
|
||||
STRNCPY_UTF8(fh->import_operator, "WM_OT_ply_import");
|
||||
STRNCPY_UTF8(fh->export_operator, "WM_OT_ply_export");
|
||||
STRNCPY_UTF8(fh->label, "Stanford PLY");
|
||||
STRNCPY_UTF8(fh->file_extensions_str, ".ply");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace ed::io
|
||||
} // namespace blender
|
||||
#endif /* WITH_IO_PLY */
|
||||
22
blender-5.2.0/source/blender/editors/io/io_ply_ops.hh
Normal file
22
blender-5.2.0/source/blender/editors/io/io_ply_ops.hh
Normal file
@@ -0,0 +1,22 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_ply_export(wmOperatorType *ot);
|
||||
void WM_OT_ply_import(wmOperatorType *ot);
|
||||
|
||||
namespace ed::io {
|
||||
void ply_file_handler_add();
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
358
blender-5.2.0/source/blender/editors/io/io_stl_ops.cc
Normal file
358
blender-5.2.0/source/blender/editors/io/io_stl_ops.cc
Normal file
@@ -0,0 +1,358 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#ifdef WITH_IO_STL
|
||||
|
||||
# include "BKE_context.hh"
|
||||
# include "BKE_file_handler.hh"
|
||||
# include "BKE_report.hh"
|
||||
|
||||
# include "BLI_string.h"
|
||||
# include "BLI_string_utf8.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.hh"
|
||||
|
||||
# include "UI_interface.hh"
|
||||
# include "UI_interface_layout.hh"
|
||||
# include "UI_resources.hh"
|
||||
|
||||
# include "IO_stl.hh"
|
||||
# include "io_stl_ops.hh"
|
||||
# include "io_utils.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
static const EnumPropertyItem io_stl_export_evaluation_mode[] = {
|
||||
{DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
|
||||
{DAG_EVAL_VIEWPORT,
|
||||
"DAG_EVAL_VIEWPORT",
|
||||
0,
|
||||
"Viewport",
|
||||
"Export objects as they appear in the viewport (Multiresolution modifiers in Sculpt Mode "
|
||||
"will not be evaluated)"},
|
||||
{0, nullptr, 0, nullptr, nullptr}};
|
||||
|
||||
static wmOperatorStatus wm_stl_export_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
{
|
||||
ED_fileselect_ensure_default_filepath(C, op, ".stl");
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_stl_export_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filename given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
STLExportParams export_params;
|
||||
RNA_string_get(op->ptr, "filepath", export_params.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.evaluation_mode = eEvaluationMode(RNA_enum_get(op->ptr, "evaluation_mode"));
|
||||
export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
|
||||
export_params.use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit");
|
||||
export_params.ascii_format = RNA_boolean_get(op->ptr, "ascii_format");
|
||||
export_params.use_batch = RNA_boolean_get(op->ptr, "use_batch");
|
||||
|
||||
RNA_string_get(op->ptr, "collection", export_params.collection);
|
||||
|
||||
export_params.reports = op->reports;
|
||||
|
||||
STL_export(C, &export_params);
|
||||
|
||||
if (BKE_reports_contain(op->reports, RPT_ERROR)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_report(op->reports, RPT_INFO, "File exported successfully");
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void wm_stl_export_draw(bContext *C, wmOperator *op)
|
||||
{
|
||||
ui::Layout &layout = *op->layout;
|
||||
PointerRNA *ptr = op->ptr;
|
||||
|
||||
layout.use_property_split_set(true);
|
||||
layout.use_property_decorate_set(false);
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "STL_export_general", false, IFACE_("General"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
|
||||
ui::Layout *sub = &col.column(false, IFACE_("Format"));
|
||||
sub->prop(ptr, "ascii_format", UI_ITEM_NONE, IFACE_("ASCII"), ICON_NONE);
|
||||
|
||||
/* The Batch mode and Selection only options only make sense when using regular export. */
|
||||
if (CTX_wm_space_file(C)) {
|
||||
col.prop(ptr, "use_batch", UI_ITEM_NONE, IFACE_("Batch"), ICON_NONE);
|
||||
|
||||
sub = &col.column(false, IFACE_("Include"));
|
||||
sub->prop(ptr, "export_selected_objects", UI_ITEM_NONE, IFACE_("Selection Only"), ICON_NONE);
|
||||
}
|
||||
|
||||
sub->prop(ptr, "global_scale", UI_ITEM_NONE, IFACE_("Scale"), ICON_NONE);
|
||||
sub->prop(ptr, "use_scene_unit", UI_ITEM_NONE, IFACE_("Scene Unit"), ICON_NONE);
|
||||
sub->prop(ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward"), ICON_NONE);
|
||||
sub->prop(ptr, "up_axis", UI_ITEM_NONE, IFACE_("Up"), ICON_NONE);
|
||||
}
|
||||
|
||||
if (ui::Layout *panel = layout.panel(C, "STL_export_geometry", false, IFACE_("Geometry"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "apply_modifiers", UI_ITEM_NONE, IFACE_("Apply Modifiers"), ICON_NONE);
|
||||
col.prop(ptr, "evaluation_mode", UI_ITEM_NONE, IFACE_("Properties"), ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if any property in the UI is changed.
|
||||
*/
|
||||
static bool wm_stl_export_check(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
bool changed = false;
|
||||
bool use_batch = RNA_boolean_get(op->ptr, "use_batch");
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
|
||||
/* Enforce an extension on the filepath unless Batch mode is used. Batch mode
|
||||
* will perform substitutions, including the extension, during its processing. */
|
||||
if (!use_batch && !BLI_path_extension_check(filepath, ".stl")) {
|
||||
BLI_path_extension_ensure(filepath, FILE_MAX, ".stl");
|
||||
RNA_string_set(op->ptr, "filepath", filepath);
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void WM_OT_stl_export(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
ot->name = "Export STL";
|
||||
ot->description = "Save the scene to an STL file";
|
||||
ot->idname = "WM_OT_stl_export";
|
||||
|
||||
ot->invoke = wm_stl_export_invoke;
|
||||
ot->exec = wm_stl_export_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->ui = wm_stl_export_draw;
|
||||
ot->check = wm_stl_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);
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"ascii_format",
|
||||
false,
|
||||
"ASCII Format",
|
||||
"Export file in ASCII format, export as binary otherwise");
|
||||
RNA_def_boolean(
|
||||
ot->srna, "use_batch", false, "Batch Export", "Export each object to a separate file");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"export_selected_objects",
|
||||
false,
|
||||
"Export Selected Objects",
|
||||
"Export only selected objects instead of all supported objects");
|
||||
|
||||
prop = RNA_def_string(ot->srna,
|
||||
"collection",
|
||||
nullptr,
|
||||
MAX_ID_NAME - 2,
|
||||
"Source Collection",
|
||||
"Export only objects from this collection (and its children)");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
|
||||
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 exported 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, "apply_modifiers", true, "Apply Modifiers", "Apply modifiers to exported meshes");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"evaluation_mode",
|
||||
io_stl_export_evaluation_mode,
|
||||
DAG_EVAL_RENDER,
|
||||
"Object Properties",
|
||||
"Determines properties like object visibility, modifiers etc., where they differ "
|
||||
"for Render and Viewport");
|
||||
|
||||
/* Only show `.stl` files by default. */
|
||||
prop = RNA_def_string(ot->srna, "filter_glob", "*.stl", 0, "Extension Filter", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
static wmOperatorStatus wm_stl_import_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
STLImportParams 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_facet_normal = RNA_boolean_get(op->ptr, "use_facet_normal");
|
||||
params.use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit");
|
||||
params.global_scale = RNA_float_get(op->ptr, "global_scale");
|
||||
params.use_mesh_validate = RNA_boolean_get(op->ptr, "use_mesh_validate");
|
||||
|
||||
params.reports = op->reports;
|
||||
|
||||
const auto paths = ed::io::paths_from_operator_properties(op->ptr);
|
||||
|
||||
if (paths.is_empty()) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No filepath given");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
for (const auto &path : paths) {
|
||||
STRNCPY(params.filepath, path.c_str());
|
||||
STL_import(C, ¶ms);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static bool wm_stl_import_check(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
const int num_axes = 3;
|
||||
/* Both forward and up axes cannot be the same (or same except opposite sign). */
|
||||
if (RNA_enum_get(op->ptr, "forward_axis") % num_axes ==
|
||||
(RNA_enum_get(op->ptr, "up_axis") % num_axes))
|
||||
{
|
||||
RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % num_axes + 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ui_stl_import_settings(const bContext *C, ui::Layout *layout, PointerRNA *ptr)
|
||||
{
|
||||
layout->use_property_split_set(true);
|
||||
layout->use_property_decorate_set(false);
|
||||
|
||||
if (ui::Layout *panel = layout->panel(C, "STL_import_general", false, IFACE_("General"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "global_scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "use_scene_unit", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
|
||||
col.prop(ptr, "up_axis", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
|
||||
if (ui::Layout *panel = layout->panel(C, "STL_import_options", false, IFACE_("Options"))) {
|
||||
ui::Layout &col = panel->column(false);
|
||||
col.prop(ptr, "use_facet_normal", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
col.prop(ptr, "use_mesh_validate", UI_ITEM_NONE, std::nullopt, ICON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_stl_import_draw(bContext *C, wmOperator *op)
|
||||
{
|
||||
ui_stl_import_settings(C, op->layout, op->ptr);
|
||||
}
|
||||
|
||||
void WM_OT_stl_import(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
ot->name = "Import STL";
|
||||
ot->description = "Import an STL file as an object";
|
||||
ot->idname = "WM_OT_stl_import";
|
||||
|
||||
ot->invoke = ed::io::filesel_drop_import_invoke;
|
||||
ot->exec = wm_stl_import_exec;
|
||||
ot->poll = WM_operator_winactive;
|
||||
ot->check = wm_stl_import_check;
|
||||
ot->ui = wm_stl_import_draw;
|
||||
ot->flag = 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");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_facet_normal",
|
||||
false,
|
||||
"Facet Normals",
|
||||
"Use (import) facet normals (note that this will still give flat shading)");
|
||||
RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", "");
|
||||
RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", "");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"use_mesh_validate",
|
||||
true,
|
||||
"Validate Mesh",
|
||||
"Ensure the data is valid "
|
||||
"(when disabled, data may be imported which causes crashes displaying or editing)");
|
||||
|
||||
/* Only show `.stl` files by default. */
|
||||
prop = RNA_def_string(ot->srna, "filter_glob", "*.stl", 0, "Extension Filter", "");
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
namespace ed::io {
|
||||
void stl_file_handler_add()
|
||||
{
|
||||
auto fh = std::make_unique<bke::FileHandlerType>();
|
||||
STRNCPY_UTF8(fh->idname, "IO_FH_stl");
|
||||
STRNCPY_UTF8(fh->import_operator, "WM_OT_stl_import");
|
||||
STRNCPY_UTF8(fh->export_operator, "WM_OT_stl_export");
|
||||
STRNCPY_UTF8(fh->label, "STL");
|
||||
STRNCPY_UTF8(fh->file_extensions_str, ".stl");
|
||||
fh->poll_drop = poll_file_object_drop;
|
||||
bke::file_handler_add(std::move(fh));
|
||||
}
|
||||
} // namespace ed::io
|
||||
} // namespace blender
|
||||
|
||||
#endif /* WITH_IO_STL */
|
||||
22
blender-5.2.0/source/blender/editors/io/io_stl_ops.hh
Normal file
22
blender-5.2.0/source/blender/editors/io/io_stl_ops.hh
Normal file
@@ -0,0 +1,22 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_stl_export(wmOperatorType *ot);
|
||||
void WM_OT_stl_import(wmOperatorType *ot);
|
||||
|
||||
namespace ed::io {
|
||||
void stl_file_handler_add();
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
1337
blender-5.2.0/source/blender/editors/io/io_usd.cc
Normal file
1337
blender-5.2.0/source/blender/editors/io/io_usd.cc
Normal file
File diff suppressed because it is too large
Load Diff
21
blender-5.2.0/source/blender/editors/io/io_usd.hh
Normal file
21
blender-5.2.0/source/blender/editors/io/io_usd.hh
Normal file
@@ -0,0 +1,21 @@
|
||||
/* SPDX-FileCopyrightText: 2019 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup editor/io
|
||||
*/
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct wmOperatorType;
|
||||
|
||||
void WM_OT_usd_export(wmOperatorType *ot);
|
||||
void WM_OT_usd_import(wmOperatorType *ot);
|
||||
namespace ed::io {
|
||||
void usd_file_handler_add();
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
136
blender-5.2.0/source/blender/editors/io/io_utils.cc
Normal file
136
blender-5.2.0/source/blender/editors/io/io_utils.cc
Normal file
@@ -0,0 +1,136 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "BLI_path_utils.hh"
|
||||
#include "BLI_string_utf8.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_main.hh"
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
|
||||
#include "io_utils.hh"
|
||||
|
||||
namespace blender::ed::io {
|
||||
|
||||
wmOperatorStatus filesel_drop_import_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
|
||||
PropertyRNA *filepath_prop = RNA_struct_find_property(op->ptr, "filepath");
|
||||
PropertyRNA *directory_prop = RNA_struct_find_property(op->ptr, "directory");
|
||||
if ((filepath_prop && RNA_property_is_set(op->ptr, filepath_prop)) ||
|
||||
(directory_prop && RNA_property_is_set(op->ptr, directory_prop)))
|
||||
{
|
||||
std::string title;
|
||||
PropertyRNA *files_prop = RNA_struct_find_property(op->ptr, "files");
|
||||
if (directory_prop && files_prop) {
|
||||
const auto files = paths_from_operator_properties(op->ptr);
|
||||
if (files.size() == 1) {
|
||||
title = files[0];
|
||||
}
|
||||
else {
|
||||
title = fmt::format(fmt::runtime(TIP_("Import {} files")), files.size());
|
||||
}
|
||||
}
|
||||
else {
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "filepath", filepath);
|
||||
title = filepath;
|
||||
}
|
||||
return WM_operator_props_dialog_popup(
|
||||
C, op, 350, std::move(title), WM_operatortype_name(op->type, op->ptr));
|
||||
}
|
||||
|
||||
WM_event_add_fileselect(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
bool poll_file_object_drop(const bContext *C, bke::FileHandlerType * /*fh*/)
|
||||
{
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
if (!region || region->regiontype != RGN_TYPE_WINDOW) {
|
||||
return false;
|
||||
}
|
||||
if (v3d) {
|
||||
return true;
|
||||
}
|
||||
if (space_outliner && space_outliner->outlinevis == SO_VIEW_LAYER) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector<std::string> paths_from_operator_properties(PointerRNA *ptr)
|
||||
{
|
||||
Vector<std::string> paths;
|
||||
PropertyRNA *directory_prop = RNA_struct_find_property(ptr, "directory");
|
||||
PropertyRNA *relative_path_prop = RNA_struct_find_property(ptr, "relative_path");
|
||||
const bool is_relative_path = relative_path_prop ?
|
||||
RNA_property_boolean_get(ptr, relative_path_prop) :
|
||||
false;
|
||||
if (RNA_property_is_set(ptr, directory_prop)) {
|
||||
char directory[FILE_MAX], name[FILE_MAX];
|
||||
|
||||
RNA_string_get(ptr, "directory", directory);
|
||||
if (is_relative_path && !BLI_path_is_rel(directory)) {
|
||||
BLI_path_rel(directory, BKE_main_blendfile_path_from_global());
|
||||
}
|
||||
|
||||
PropertyRNA *files_prop = RNA_struct_find_collection_property_check(
|
||||
*ptr, "files", RNA_OperatorFileListElement);
|
||||
|
||||
BLI_assert(files_prop);
|
||||
|
||||
RNA_PROP_BEGIN (ptr, file_ptr, files_prop) {
|
||||
RNA_string_get(&file_ptr, "name", name);
|
||||
char path[FILE_MAX];
|
||||
BLI_path_join(path, sizeof(path), directory, name);
|
||||
BLI_path_normalize(path);
|
||||
paths.append_non_duplicates(path);
|
||||
}
|
||||
RNA_PROP_END;
|
||||
}
|
||||
PropertyRNA *filepath_prop = RNA_struct_find_property(ptr, "filepath");
|
||||
if (filepath_prop && RNA_property_is_set(ptr, filepath_prop)) {
|
||||
char filepath[FILE_MAX];
|
||||
RNA_string_get(ptr, "filepath", filepath);
|
||||
if (is_relative_path && !BLI_path_is_rel(filepath)) {
|
||||
BLI_path_rel(filepath, BKE_main_blendfile_path_from_global());
|
||||
}
|
||||
paths.append_non_duplicates(filepath);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
void paths_to_operator_properties(PointerRNA *ptr, const Span<std::string> paths)
|
||||
{
|
||||
char dir[FILE_MAX];
|
||||
BLI_path_split_dir_part(paths[0].c_str(), dir, sizeof(dir));
|
||||
RNA_string_set(ptr, "directory", dir);
|
||||
|
||||
RNA_collection_clear(ptr, "files");
|
||||
for (const auto &path : paths) {
|
||||
char file[FILE_MAX];
|
||||
STRNCPY_UTF8(file, path.c_str());
|
||||
BLI_path_rel(file, dir);
|
||||
|
||||
PointerRNA itemptr{};
|
||||
RNA_collection_add(ptr, "files", &itemptr);
|
||||
BLI_assert_msg(BLI_path_is_rel(file), "Expected path to be relative (start with '//')");
|
||||
RNA_string_set(&itemptr, "name", file + 2);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::ed::io
|
||||
36
blender-5.2.0/source/blender/editors/io/io_utils.hh
Normal file
36
blender-5.2.0/source/blender/editors/io/io_utils.hh
Normal file
@@ -0,0 +1,36 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct wmOperator;
|
||||
|
||||
namespace bke {
|
||||
} // namespace bke
|
||||
|
||||
namespace ed::io {
|
||||
/**
|
||||
* Shows a import dialog if the operator was invoked with filepath properties set,
|
||||
* otherwise invokes the file-select window.
|
||||
*/
|
||||
wmOperatorStatus filesel_drop_import_invoke(bContext *C, wmOperator *op, const wmEvent *event);
|
||||
|
||||
bool poll_file_object_drop(const bContext *C, bke::FileHandlerType *fh);
|
||||
|
||||
/**
|
||||
* Return all paths stored in the pointer.
|
||||
* Properties in pointer should include a `directory` #PropertySubType::PROP_FILEPATH property and
|
||||
* a `files` #RNA_OperatorFileListElement collection property.
|
||||
* If the pointer has a `filepath` property is also returned as fallback.
|
||||
*/
|
||||
Vector<std::string> paths_from_operator_properties(PointerRNA *ptr);
|
||||
void paths_to_operator_properties(PointerRNA *ptr, const Span<std::string> paths);
|
||||
} // namespace ed::io
|
||||
} // namespace blender
|
||||
Reference in New Issue
Block a user