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
This commit is contained in:
parent
b617b44419
commit
4ed208bcd8
Notes:
blender-bot
2023-02-13 19:24:11 +01:00
Referenced by issue #86141, Context data for attribute spreadsheet
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
* \{ */
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue