Collection Export: Enable STL and PLY exporters

Enables the STL and PLY formats for Collection export.

Changes
- Set the export operator on the File handlers
- Plumb through the `collection` property and make use of it while
  building the depsgraph
- Skip drawing the "Selection only" and "Batch" mode options when used
  with collections

Pull Request: https://projects.blender.org/blender/blender/pulls/120944
This commit is contained in:
Jesse Yurkovich
2024-04-22 20:05:34 +02:00
committed by Jesse Yurkovich
parent 49bd285529
commit 32ed9bb107
6 changed files with 142 additions and 56 deletions

View File

@@ -28,8 +28,6 @@
# include "BLT_translation.hh"
# include "MEM_guardedalloc.h"
# include "UI_interface.hh"
# include "UI_resources.hh"
@@ -85,6 +83,8 @@ static int wm_ply_export_exec(bContext *C, wmOperator *op)
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);
@@ -92,8 +92,11 @@ static int wm_ply_export_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static void ui_ply_export_settings(uiLayout *layout, PointerRNA *imfptr)
static void wm_ply_export_draw(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
PointerRNA *ptr = op->ptr;
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -103,40 +106,33 @@ static void ui_ply_export_settings(uiLayout *layout, PointerRNA *imfptr)
box = uiLayoutBox(layout);
col = uiLayoutColumn(box, false);
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Format"));
uiItemR(sub, imfptr, "ascii_format", UI_ITEM_NONE, IFACE_("ASCII"), ICON_NONE);
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Limit to"));
uiItemR(
sub, imfptr, "export_selected_objects", UI_ITEM_NONE, IFACE_("Selected Only"), ICON_NONE);
uiItemR(sub, imfptr, "global_scale", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(sub, ptr, "ascii_format", UI_ITEM_NONE, IFACE_("ASCII"), ICON_NONE);
uiItemR(sub, imfptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
uiItemR(sub, imfptr, "up_axis", UI_ITEM_NONE, IFACE_("Up Axis"), ICON_NONE);
/* The Selection only options only make sense when using regular export. */
if (CTX_wm_space_file(C)) {
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Limit to"));
uiItemR(sub, ptr, "export_selected_objects", UI_ITEM_NONE, IFACE_("Selected Only"), ICON_NONE);
}
uiItemR(sub, ptr, "global_scale", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(sub, ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward Axis"), ICON_NONE);
uiItemR(sub, ptr, "up_axis", UI_ITEM_NONE, IFACE_("Up Axis"), ICON_NONE);
col = uiLayoutColumn(box, false);
sub = uiLayoutColumn(col, false);
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Objects"));
uiItemR(sub, imfptr, "apply_modifiers", UI_ITEM_NONE, IFACE_("Apply Modifiers"), ICON_NONE);
uiItemR(sub, ptr, "apply_modifiers", UI_ITEM_NONE, IFACE_("Apply Modifiers"), ICON_NONE);
/* Geometry options. */
box = uiLayoutBox(layout);
col = uiLayoutColumn(box, false);
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Geometry"));
uiItemR(sub, imfptr, "export_uv", UI_ITEM_NONE, IFACE_("UV Coordinates"), ICON_NONE);
uiItemR(sub, imfptr, "export_normals", UI_ITEM_NONE, IFACE_("Vertex Normals"), ICON_NONE);
uiItemR(sub, imfptr, "export_colors", UI_ITEM_NONE, IFACE_("Vertex Colors"), ICON_NONE);
uiItemR(sub, imfptr, "export_attributes", UI_ITEM_NONE, IFACE_("Vertex Attributes"), ICON_NONE);
uiItemR(sub,
imfptr,
"export_triangulated_mesh",
UI_ITEM_NONE,
IFACE_("Triangulated Mesh"),
ICON_NONE);
}
static void wm_ply_export_draw(bContext * /*C*/, wmOperator *op)
{
PointerRNA ptr = RNA_pointer_create(nullptr, op->type->srna, op->properties);
ui_ply_export_settings(op->layout, &ptr);
uiItemR(sub, ptr, "export_uv", UI_ITEM_NONE, IFACE_("UV Coordinates"), ICON_NONE);
uiItemR(sub, ptr, "export_normals", UI_ITEM_NONE, IFACE_("Vertex Normals"), ICON_NONE);
uiItemR(sub, ptr, "export_colors", UI_ITEM_NONE, IFACE_("Vertex Colors"), ICON_NONE);
uiItemR(sub, ptr, "export_attributes", UI_ITEM_NONE, IFACE_("Vertex Attributes"), ICON_NONE);
uiItemR(
sub, ptr, "export_triangulated_mesh", UI_ITEM_NONE, IFACE_("Triangulated Mesh"), ICON_NONE);
}
/**
@@ -203,6 +199,14 @@ void WM_OT_ply_export(wmOperatorType *ot)
false,
"Export Selected Objects",
"Export only selected objects instead of all supported objects");
prop = RNA_def_string(ot->srna,
"collection",
nullptr,
MAX_IDPROP_NAME,
"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,
@@ -346,6 +350,7 @@ void ply_file_handler_add()
auto fh = std::make_unique<blender::bke::FileHandlerType>();
STRNCPY(fh->idname, "IO_FH_ply");
STRNCPY(fh->import_operator, "WM_OT_ply_import");
STRNCPY(fh->export_operator, "WM_OT_ply_export");
STRNCPY(fh->label, "Stanford PLY");
STRNCPY(fh->file_extensions_str, ".ply");
fh->poll_drop = poll_file_object_drop;

View File

@@ -59,6 +59,8 @@ static int wm_stl_export_execute(bContext *C, wmOperator *op)
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);
@@ -66,8 +68,11 @@ static int wm_stl_export_execute(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static void ui_stl_export_settings(uiLayout *layout, PointerRNA *op_props_ptr)
static void wm_stl_export_draw(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
PointerRNA *ptr = op->ptr;
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -75,35 +80,27 @@ static void ui_stl_export_settings(uiLayout *layout, PointerRNA *op_props_ptr)
box = uiLayoutBox(layout);
col = uiLayoutColumn(box, false);
uiItemR(col, op_props_ptr, "ascii_format", UI_ITEM_NONE, IFACE_("ASCII"), ICON_NONE);
uiItemR(col, op_props_ptr, "use_batch", UI_ITEM_NONE, IFACE_("Batch"), ICON_NONE);
sub = uiLayoutColumnWithHeading(col, false, IFACE_("Format"));
uiItemR(sub, ptr, "ascii_format", UI_ITEM_NONE, IFACE_("ASCII"), ICON_NONE);
box = uiLayoutBox(layout);
sub = uiLayoutColumnWithHeading(box, false, IFACE_("Include"));
uiItemR(sub,
op_props_ptr,
"export_selected_objects",
UI_ITEM_NONE,
IFACE_("Selection Only"),
ICON_NONE);
/* The Batch mode and Selection only options only make sense when using regular export. */
if (CTX_wm_space_file(C)) {
uiItemR(col, ptr, "use_batch", UI_ITEM_NONE, IFACE_("Batch"), ICON_NONE);
box = uiLayoutBox(layout);
sub = uiLayoutColumnWithHeading(box, false, IFACE_("Transform"));
uiItemR(sub, op_props_ptr, "global_scale", UI_ITEM_NONE, IFACE_("Scale"), ICON_NONE);
uiItemR(sub, op_props_ptr, "use_scene_unit", UI_ITEM_NONE, IFACE_("Scene Unit"), ICON_NONE);
uiItemR(sub, op_props_ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward"), ICON_NONE);
uiItemR(sub, op_props_ptr, "up_axis", UI_ITEM_NONE, IFACE_("Up"), ICON_NONE);
box = uiLayoutBox(layout);
sub = uiLayoutColumnWithHeading(box, false, IFACE_("Include"));
uiItemR(
sub, ptr, "export_selected_objects", UI_ITEM_NONE, IFACE_("Selection Only"), ICON_NONE);
}
uiItemR(sub, ptr, "global_scale", UI_ITEM_NONE, IFACE_("Scale"), ICON_NONE);
uiItemR(sub, ptr, "use_scene_unit", UI_ITEM_NONE, IFACE_("Scene Unit"), ICON_NONE);
uiItemR(sub, ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward"), ICON_NONE);
uiItemR(sub, ptr, "up_axis", UI_ITEM_NONE, IFACE_("Up"), ICON_NONE);
box = uiLayoutBox(layout);
sub = uiLayoutColumnWithHeading(box, false, IFACE_("Geometry"));
uiItemR(
sub, op_props_ptr, "apply_modifiers", UI_ITEM_NONE, IFACE_("Apply Modifiers"), ICON_NONE);
}
static void wm_stl_export_draw(bContext * /*C*/, wmOperator *op)
{
PointerRNA ptr = RNA_pointer_create(nullptr, op->type->srna, op->properties);
ui_stl_export_settings(op->layout, &ptr);
uiItemR(sub, ptr, "apply_modifiers", UI_ITEM_NONE, IFACE_("Apply Modifiers"), ICON_NONE);
}
/**
@@ -163,6 +160,14 @@ void WM_OT_stl_export(wmOperatorType *ot)
"Export Selected Objects",
"Export only selected objects instead of all supported objects");
prop = RNA_def_string(ot->srna,
"collection",
nullptr,
MAX_IDPROP_NAME,
"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",
@@ -303,6 +308,7 @@ void stl_file_handler_add()
auto fh = std::make_unique<blender::bke::FileHandlerType>();
STRNCPY(fh->idname, "IO_FH_stl");
STRNCPY(fh->import_operator, "WM_OT_stl_import");
STRNCPY(fh->export_operator, "WM_OT_stl_export");
STRNCPY(fh->label, "STL");
STRNCPY(fh->file_extensions_str, ".stl");
fh->poll_drop = poll_file_object_drop;

View File

@@ -9,6 +9,9 @@
#pragma once
#include "BLI_path_util.h"
#include "DNA_ID.h"
#include "IO_orientation.hh"
struct bContext;
@@ -45,6 +48,7 @@ struct PLYExportParams {
ePLYVertexColorMode vertex_colors;
bool export_attributes;
bool export_triangulated_mesh;
char collection[MAX_IDPROP_NAME] = "";
ReportList *reports = nullptr;
};

View File

@@ -9,7 +9,11 @@
#include <cstdio>
#include "BKE_context.hh"
#include "BKE_lib_id.hh"
#include "BKE_report.hh"
#include "BKE_scene.hh"
#include "DEG_depsgraph_query.hh"
#include "IO_ply.hh"
@@ -26,7 +30,39 @@ namespace blender::io::ply {
void exporter_main(bContext *C, const PLYExportParams &export_params)
{
std::unique_ptr<blender::io::ply::PlyData> plyData = std::make_unique<PlyData>();
load_plydata(*plyData, CTX_data_ensure_evaluated_depsgraph(C), export_params);
Depsgraph *depsgraph = nullptr;
bool needs_free = false;
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
if (strlen(export_params.collection) > 0) {
Collection *collection = reinterpret_cast<Collection *>(
BKE_libblock_find_name(bmain, ID_GR, export_params.collection));
if (!collection) {
BKE_reportf(export_params.reports,
RPT_ERROR,
"PLY Export: Unable to find collection '%s'",
export_params.collection);
return;
}
ViewLayer *view_layer = CTX_data_view_layer(C);
depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
needs_free = true;
DEG_graph_build_from_collection(depsgraph, collection);
BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
}
else {
depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
}
load_plydata(*plyData, depsgraph, export_params);
if (needs_free) {
DEG_graph_free(depsgraph);
}
std::unique_ptr<FileBuffer> buffer;

View File

@@ -9,6 +9,9 @@
#pragma once
#include "BLI_path_util.h"
#include "DNA_ID.h"
#include "IO_orientation.hh"
struct bContext;
@@ -38,6 +41,7 @@ struct STLExportParams {
bool apply_modifiers;
bool ascii_format;
bool use_batch;
char collection[MAX_IDPROP_NAME] = "";
ReportList *reports = nullptr;
};

View File

@@ -6,13 +6,14 @@
* \ingroup stl
*/
#include <algorithm>
#include <cstring>
#include <memory>
#include <string>
#include "BKE_context.hh"
#include "BKE_lib_id.hh"
#include "BKE_object.hh"
#include "BKE_report.hh"
#include "BKE_scene.hh"
#include "BLI_string.h"
#include "BLI_string_utils.hh"
@@ -136,13 +137,43 @@ void export_frame(Depsgraph *depsgraph,
void exporter_main(bContext *C, const STLExportParams &export_params)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Depsgraph *depsgraph = nullptr;
bool needs_free = false;
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
if (strlen(export_params.collection) > 0) {
Collection *collection = reinterpret_cast<Collection *>(
BKE_libblock_find_name(bmain, ID_GR, export_params.collection));
if (!collection) {
BKE_reportf(export_params.reports,
RPT_ERROR,
"STL Export: Unable to find collection '%s'",
export_params.collection);
return;
}
ViewLayer *view_layer = CTX_data_view_layer(C);
depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
needs_free = true;
DEG_graph_build_from_collection(depsgraph, collection);
BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
}
else {
depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
}
float scene_unit_scale = 1.0f;
if ((scene->unit.system != USER_UNIT_NONE) && export_params.use_scene_unit) {
scene_unit_scale = scene->unit.scale_length;
}
export_frame(depsgraph, scene_unit_scale, export_params);
if (needs_free) {
DEG_graph_free(depsgraph);
}
}
} // namespace blender::io::stl