diff options
author | Jacques Lucke <jacques@blender.org> | 2021-03-15 12:16:11 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-03-15 12:16:11 +0300 |
commit | 4ed208bcd82e912fa9a0da6137af6e87004e9365 (patch) | |
tree | 515ace29470dd5e2a785e3c18e482f54f30ff36e | |
parent | b617b44419613ae87d64b5d4692515750c83b417 (diff) |
Spreadsheet: support showing data from original/unevaluated object
There are two caveats of the current implementation which still need
to be resolved in a separate step:
* In theory the data on the original object can be editable in the spreadsheet.
* If a complex object is in edit mode, and its original data is displayed,
the drawing code can be slow, because the bmesh is converted to a mesh
every time. The proper solution is to draw the data from the bmesh directly.
This should become easier after an upcoming refactor.
Ref T86141.
Differential Revision: https://developer.blender.org/D10701
4 files changed, 110 insertions, 20 deletions
diff --git a/release/scripts/startup/bl_ui/space_spreadsheet.py b/release/scripts/startup/bl_ui/space_spreadsheet.py index 1ba650fa096..a12fe68c9a5 100644 --- a/release/scripts/startup/bl_ui/space_spreadsheet.py +++ b/release/scripts/startup/bl_ui/space_spreadsheet.py @@ -31,7 +31,9 @@ class SPREADSHEET_HT_header(bpy.types.Header): pinned_id = space.pinned_id used_id = pinned_id if pinned_id else context.active_object - layout.prop(space, "geometry_component_type", text="") + layout.prop(space, "object_eval_state", text="") + if space.object_eval_state != "ORIGINAL": + layout.prop(space, "geometry_component_type", text="") layout.prop(space, "attribute_domain", text="") if used_id: diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc index 0cb937628f5..b60a1478352 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_from_geometry.cc @@ -24,6 +24,8 @@ #include "BKE_context.h" #include "BKE_editmesh.h" +#include "BKE_lib_id.h" +#include "BKE_mesh.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" @@ -333,24 +335,56 @@ static void add_columns_for_attribute(const ReadAttribute *attribute, } } -static GeometrySet get_display_geometry_set(Object *object_eval, +static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet, + Object *object_eval, const GeometryComponentType used_component_type) { GeometrySet geometry_set; - if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) { - Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false); - if (mesh == nullptr) { - return geometry_set; + if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) { + if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) { + Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false); + if (mesh == nullptr) { + return geometry_set; + } + BKE_mesh_wrapper_ensure_mdata(mesh); + MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); + mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); + mesh_component.copy_vertex_group_names_from_object(*object_eval); + } + else { + if (object_eval->runtime.geometry_set_eval != nullptr) { + /* This does not copy the geometry data itself. */ + geometry_set = *object_eval->runtime.geometry_set_eval; + } } - BKE_mesh_wrapper_ensure_mdata(mesh); - MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); - mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); - mesh_component.copy_vertex_group_names_from_object(*object_eval); } else { - if (object_eval->runtime.geometry_set_eval != nullptr) { - /* This does not copy the geometry data itself. */ - geometry_set = *object_eval->runtime.geometry_set_eval; + Object *object_orig = DEG_get_original_object(object_eval); + if (object_orig->type == OB_MESH) { + MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); + if (object_orig->mode == OB_MODE_EDIT) { + Mesh *mesh = (Mesh *)object_orig->data; + BMEditMesh *em = mesh->edit_mesh; + if (em != nullptr) { + Mesh *new_mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); + /* This is a potentially heavy operation to do on every redraw. The best solution here is + * to display the data directly from the bmesh without a conversion, which can be + * implemented a bit later. */ + BM_mesh_bm_to_me_for_eval(em->bm, new_mesh, nullptr); + mesh_component.replace(new_mesh, GeometryOwnershipType::Owned); + } + } + else { + Mesh *mesh = (Mesh *)object_orig->data; + mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); + } + mesh_component.copy_vertex_group_names_from_object(*object_orig); + } + else if (object_orig->type == OB_POINTCLOUD) { + PointCloud *pointcloud = (PointCloud *)object_orig->data; + PointCloudComponent &pointcloud_component = + geometry_set.get_component_for_write<PointCloudComponent>(); + pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly); } } return geometry_set; @@ -480,18 +514,29 @@ static Span<int64_t> filter_mesh_elements_by_selection(const bContext *C, return IndexRange(domain_size).as_span(); } +static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval) +{ + SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); + if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) { + return (GeometryComponentType)sspreadsheet->geometry_component_type; + } + if (object_eval->type == OB_POINTCLOUD) { + return GEO_COMPONENT_TYPE_POINT_CLOUD; + } + return GEO_COMPONENT_TYPE_MESH; +} + std::unique_ptr<SpreadsheetDrawer> spreadsheet_drawer_from_geometry_attributes(const bContext *C, Object *object_eval) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; - const GeometryComponentType component_type = (GeometryComponentType) - sspreadsheet->geometry_component_type; + const GeometryComponentType component_type = get_display_component_type(C, object_eval); /* Create a resource collector that owns stuff that needs to live until drawing is done. */ std::unique_ptr<ResourceCollector> resources = std::make_unique<ResourceCollector>(); GeometrySet &geometry_set = resources->add_value( - get_display_geometry_set(object_eval, component_type), "geometry set"); + get_display_geometry_set(sspreadsheet, object_eval, component_type), "geometry set"); const GeometryComponent *component = geometry_set.get_component_for_read(component_type); if (component == nullptr) { diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 9007d3b6cf4..dec3097a9ae 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1865,8 +1865,10 @@ typedef struct SpaceSpreadsheet { uint8_t geometry_component_type; /* #AttributeDomain. */ uint8_t attribute_domain; + /* eSpaceSpreadsheet_ObjectContext. */ + uint8_t object_eval_state; - char _pad1[5]; + char _pad1[4]; SpaceSpreadsheet_Runtime *runtime; } SpaceSpreadsheet; @@ -1877,6 +1879,11 @@ typedef enum eSpaceSpreadsheet_FilterFlag { SPREADSHEET_FILTER_SELECTED_ONLY = (1 << 0), } eSpaceSpreadsheet_FilterFlag; +typedef enum eSpaceSpreadsheet_ObjectEvalState { + SPREADSHEET_OBJECT_EVAL_STATE_FINAL = 0, + SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL = 1, +} eSpaceSpreadsheet_Context; + /* -------------------------------------------------------------------- */ /** \name Space Defines (eSpace_Type) * \{ */ diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index db36909d2f9..63600571c0d 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -26,6 +26,7 @@ #include "BLT_translation.h" #include "BKE_attribute.h" +#include "BKE_context.h" #include "BKE_geometry_set.h" #include "BKE_image.h" #include "BKE_key.h" @@ -3003,17 +3004,33 @@ static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bma } } -const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *UNUSED(C), +const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data; + GeometryComponentType component_type = sspreadsheet->geometry_component_type; + if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) { + Object *active_object = CTX_data_active_object(C); + Object *used_object = (sspreadsheet->pinned_id && GS(sspreadsheet->pinned_id->name) == ID_OB) ? + (Object *)sspreadsheet->pinned_id : + active_object; + if (used_object != NULL) { + if (used_object->type == OB_POINTCLOUD) { + component_type = GEO_COMPONENT_TYPE_POINT_CLOUD; + } + else { + component_type = GEO_COMPONENT_TYPE_MESH; + } + } + } + EnumPropertyItem *item_array = NULL; int items_len = 0; for (const EnumPropertyItem *item = rna_enum_attribute_domain_items; item->identifier != NULL; item++) { - if (sspreadsheet->geometry_component_type == GEO_COMPONENT_TYPE_MESH) { + if (component_type == GEO_COMPONENT_TYPE_MESH) { if (!ELEM(item->value, ATTR_DOMAIN_CORNER, ATTR_DOMAIN_EDGE, @@ -3022,7 +3039,7 @@ const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *UN continue; } } - if (sspreadsheet->geometry_component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) { + if (component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) { if (item->value != ATTR_DOMAIN_POINT) { continue; } @@ -7254,6 +7271,20 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem object_eval_state_items[] = { + {SPREADSHEET_OBJECT_EVAL_STATE_FINAL, + "FINAL", + ICON_NONE, + "Final", + "Use data from object with all modifiers applied"}, + {SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL, + "ORIGINAL", + ICON_NONE, + "Original", + "Use data from original object without any modifiers applied"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space"); RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data"); @@ -7284,6 +7315,11 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna) RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceSpreadsheet_attribute_domain_itemf"); RNA_def_property_ui_text(prop, "Attribute Domain", "Attribute domain to display"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); + + prop = RNA_def_property(srna, "object_eval_state", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, object_eval_state_items); + RNA_def_property_ui_text(prop, "Object Evaluation State", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); } void RNA_def_space(BlenderRNA *brna) |