Blender  V2.93
spreadsheet_data_source_geometry.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include "BKE_context.h"
18 #include "BKE_editmesh.h"
19 #include "BKE_lib_id.h"
20 #include "BKE_mesh.h"
21 #include "BKE_mesh_wrapper.h"
22 #include "BKE_modifier.h"
23 
24 #include "DNA_ID.h"
25 #include "DNA_mesh_types.h"
26 #include "DNA_meshdata_types.h"
27 #include "DNA_space_types.h"
28 #include "DNA_userdef_types.h"
29 
30 #include "DEG_depsgraph_query.h"
31 
32 #include "ED_spreadsheet.h"
33 
34 #include "bmesh.h"
35 
37 #include "spreadsheet_intern.hh"
38 
39 namespace blender::ed::spreadsheet {
40 
42  FunctionRef<void(const SpreadsheetColumnID &)> fn) const
43 {
44  component_->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
45  if (meta_data.domain != domain_) {
46  return true;
47  }
48  SpreadsheetColumnID column_id;
49  column_id.name = (char *)name.c_str();
50  fn(column_id);
51  return true;
52  });
53 }
54 
55 std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
56  const SpreadsheetColumnID &column_id) const
57 {
58  std::lock_guard lock{mutex_};
59 
60  bke::ReadAttributePtr attribute_ptr = component_->attribute_try_get_for_read(column_id.name);
61  if (!attribute_ptr) {
62  return {};
63  }
64  const bke::ReadAttribute *attribute = scope_.add(std::move(attribute_ptr), __func__);
65  if (attribute->domain() != domain_) {
66  return {};
67  }
68  int domain_size = attribute->size();
69  switch (attribute->custom_data_type()) {
70  case CD_PROP_FLOAT:
72  column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
73  float value;
74  attribute->get(index, &value);
75  r_cell_value.value_float = value;
76  });
77  case CD_PROP_INT32:
79  column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
80  int value;
81  attribute->get(index, &value);
82  r_cell_value.value_int = value;
83  });
84  case CD_PROP_BOOL:
86  column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
87  bool value;
88  attribute->get(index, &value);
89  r_cell_value.value_bool = value;
90  });
91  case CD_PROP_FLOAT2: {
93  column_id.name,
94  domain_size,
95  [attribute](int index, CellValue &r_cell_value) {
96  float2 value;
97  attribute->get(index, &value);
98  r_cell_value.value_float2 = value;
99  },
101  }
102  case CD_PROP_FLOAT3: {
104  column_id.name,
105  domain_size,
106  [attribute](int index, CellValue &r_cell_value) {
107  float3 value;
108  attribute->get(index, &value);
109  r_cell_value.value_float3 = value;
110  },
112  }
113  case CD_PROP_COLOR: {
115  column_id.name,
116  domain_size,
117  [attribute](int index, CellValue &r_cell_value) {
118  Color4f value;
119  attribute->get(index, &value);
120  r_cell_value.value_color = value;
121  },
123  }
124  default:
125  break;
126  }
127  return {};
128 }
129 
131 {
132  return component_->attribute_domain_size(domain_);
133 }
134 
135 using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>;
136 
138  const IsVertexSelectedFn is_vertex_selected_fn,
139  Vector<int64_t> &r_vertex_indices)
140 {
141  for (const int i : IndexRange(mesh.totvert)) {
142  if (is_vertex_selected_fn(i)) {
143  r_vertex_indices.append(i);
144  }
145  }
146 }
147 
149  const IsVertexSelectedFn is_vertex_selected_fn,
150  Vector<int64_t> &r_corner_indices)
151 {
152  for (const int i : IndexRange(mesh.totloop)) {
153  const MLoop &loop = mesh.mloop[i];
154  if (is_vertex_selected_fn(loop.v)) {
155  r_corner_indices.append(i);
156  }
157  }
158 }
159 
161  const IsVertexSelectedFn is_vertex_selected_fn,
162  Vector<int64_t> &r_face_indices)
163 {
164  for (const int poly_index : IndexRange(mesh.totpoly)) {
165  const MPoly &poly = mesh.mpoly[poly_index];
166  bool is_selected = true;
167  for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
168  const MLoop &loop = mesh.mloop[loop_index];
169  if (!is_vertex_selected_fn(loop.v)) {
170  is_selected = false;
171  break;
172  }
173  }
174  if (is_selected) {
175  r_face_indices.append(poly_index);
176  }
177  }
178 }
179 
181  const IsVertexSelectedFn is_vertex_selected_fn,
182  Vector<int64_t> &r_edge_indices)
183 {
184  for (const int i : IndexRange(mesh.totedge)) {
185  const MEdge &edge = mesh.medge[i];
186  if (is_vertex_selected_fn(edge.v1) && is_vertex_selected_fn(edge.v2)) {
187  r_edge_indices.append(i);
188  }
189  }
190 }
191 
193  const AttributeDomain domain,
194  const IsVertexSelectedFn is_vertex_selected_fn,
195  Vector<int64_t> &r_indices)
196 {
197  switch (domain) {
198  case ATTR_DOMAIN_POINT:
199  return get_selected_vertex_indices(mesh, is_vertex_selected_fn, r_indices);
200  case ATTR_DOMAIN_FACE:
201  return get_selected_face_indices(mesh, is_vertex_selected_fn, r_indices);
202  case ATTR_DOMAIN_CORNER:
203  return get_selected_corner_indices(mesh, is_vertex_selected_fn, r_indices);
204  case ATTR_DOMAIN_EDGE:
205  return get_selected_edge_indices(mesh, is_vertex_selected_fn, r_indices);
206  default:
207  return;
208  }
209 }
210 
212 {
213  std::lock_guard lock{mutex_};
214 
215  BLI_assert(object_eval_->mode == OB_MODE_EDIT);
216  BLI_assert(component_->type() == GEO_COMPONENT_TYPE_MESH);
217  Object *object_orig = DEG_get_original_object(object_eval_);
218  Vector<int64_t> &indices = scope_.construct<Vector<int64_t>>(__func__);
219  const MeshComponent *mesh_component = static_cast<const MeshComponent *>(component_);
220  const Mesh *mesh_eval = mesh_component->get_for_read();
221  Mesh *mesh_orig = (Mesh *)object_orig->data;
222  BMesh *bm = mesh_orig->edit_mesh->bm;
224 
225  int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
226  if (orig_indices != nullptr) {
227  /* Use CD_ORIGINDEX layer if it exists. */
228  auto is_vertex_selected = [&](int vertex_index) -> bool {
229  const int i_orig = orig_indices[vertex_index];
230  if (i_orig < 0) {
231  return false;
232  }
233  if (i_orig >= bm->totvert) {
234  return false;
235  }
236  BMVert *vert = bm->vtable[i_orig];
237  return BM_elem_flag_test(vert, BM_ELEM_SELECT);
238  };
239  get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, indices);
240  }
241  else if (mesh_eval->totvert == bm->totvert) {
242  /* Use a simple heuristic to match original vertices to evaluated ones. */
243  auto is_vertex_selected = [&](int vertex_index) -> bool {
244  BMVert *vert = bm->vtable[vertex_index];
245  return BM_elem_flag_test(vert, BM_ELEM_SELECT);
246  };
247  get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, indices);
248  }
249 
250  return indices;
251 }
252 
254  FunctionRef<void(const SpreadsheetColumnID &)> fn) const
255 {
256  if (component_->instances_amount() == 0) {
257  return;
258  }
259 
260  SpreadsheetColumnID column_id;
261  column_id.name = (char *)"Name";
262  fn(column_id);
263  for (const char *name : {"Position", "Rotation", "Scale"}) {
264  column_id.name = (char *)name;
265  fn(column_id);
266  }
267 }
268 
269 std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
270  const SpreadsheetColumnID &column_id) const
271 {
272  if (component_->instances_amount() == 0) {
273  return {};
274  }
275 
276  const int size = this->tot_rows();
277  if (STREQ(column_id.name, "Name")) {
278  Span<InstancedData> instance_data = component_->instanced_data();
279  std::unique_ptr<ColumnValues> values = column_values_from_function(
280  "Name", size, [instance_data](int index, CellValue &r_cell_value) {
281  const InstancedData &data = instance_data[index];
282  if (data.type == INSTANCE_DATA_TYPE_OBJECT) {
283  if (data.data.object != nullptr) {
284  r_cell_value.value_object = ObjectCellValue{data.data.object};
285  }
286  }
287  else if (data.type == INSTANCE_DATA_TYPE_COLLECTION) {
288  if (data.data.collection != nullptr) {
289  r_cell_value.value_collection = CollectionCellValue{data.data.collection};
290  }
291  }
292  });
293  values->default_width = 8.0f;
294  return values;
295  }
296  Span<float4x4> transforms = component_->transforms();
297  if (STREQ(column_id.name, "Position")) {
299  column_id.name,
300  size,
301  [transforms](int index, CellValue &r_cell_value) {
302  r_cell_value.value_float3 = transforms[index].translation();
303  },
305  }
306  if (STREQ(column_id.name, "Rotation")) {
308  column_id.name,
309  size,
310  [transforms](int index, CellValue &r_cell_value) {
311  r_cell_value.value_float3 = transforms[index].to_euler();
312  },
314  }
315  if (STREQ(column_id.name, "Scale")) {
317  column_id.name,
318  size,
319  [transforms](int index, CellValue &r_cell_value) {
320  r_cell_value.value_float3 = transforms[index].scale();
321  },
323  }
324  return {};
325 }
326 
327 int InstancesDataSource::tot_rows() const
328 {
329  return component_->instances_amount();
330 }
331 
333  Object *object_eval,
334  const GeometryComponentType used_component_type)
335 {
336  GeometrySet geometry_set;
338  Object *object_orig = DEG_get_original_object(object_eval);
339  if (object_orig->type == OB_MESH) {
340  MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
341  if (object_orig->mode == OB_MODE_EDIT) {
342  Mesh *mesh = (Mesh *)object_orig->data;
343  BMEditMesh *em = mesh->edit_mesh;
344  if (em != nullptr) {
345  Mesh *new_mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr);
346  /* This is a potentially heavy operation to do on every redraw. The best solution here is
347  * to display the data directly from the bmesh without a conversion, which can be
348  * implemented a bit later. */
349  BM_mesh_bm_to_me_for_eval(em->bm, new_mesh, nullptr);
350  mesh_component.replace(new_mesh, GeometryOwnershipType::Owned);
351  }
352  }
353  else {
354  Mesh *mesh = (Mesh *)object_orig->data;
356  }
357  mesh_component.copy_vertex_group_names_from_object(*object_orig);
358  }
359  else if (object_orig->type == OB_POINTCLOUD) {
360  PointCloud *pointcloud = (PointCloud *)object_orig->data;
361  PointCloudComponent &pointcloud_component =
363  pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
364  }
365  }
367  if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
369  if (mesh == nullptr) {
370  return geometry_set;
371  }
373  MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
375  mesh_component.copy_vertex_group_names_from_object(*object_eval);
376  }
377  else {
378  if (BLI_listbase_count(&sspreadsheet->context_path) == 1) {
379  /* Use final evaluated object. */
380  if (object_eval->runtime.geometry_set_eval != nullptr) {
381  geometry_set = *object_eval->runtime.geometry_set_eval;
382  }
383  }
384  else {
385  if (object_eval->runtime.geometry_set_previews != nullptr) {
386  GHash *ghash = (GHash *)object_eval->runtime.geometry_set_previews;
387  const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet);
388  GeometrySet *geometry_set_preview = (GeometrySet *)BLI_ghash_lookup_default(
389  ghash, POINTER_FROM_UINT(key), nullptr);
390  if (geometry_set_preview != nullptr) {
391  geometry_set = *geometry_set_preview;
392  }
393  }
394  }
395  }
396  }
397  return geometry_set;
398 }
399 
401 {
404  return (GeometryComponentType)sspreadsheet->geometry_component_type;
405  }
406  if (object_eval->type == OB_POINTCLOUD) {
408  }
410 }
411 
412 std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval)
413 {
415  const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
416  const GeometryComponentType component_type = get_display_component_type(C, object_eval);
417  GeometrySet geometry_set = get_display_geometry_set(sspreadsheet, object_eval, component_type);
418 
419  if (!geometry_set.has(component_type)) {
420  return {};
421  }
422 
423  if (component_type == GEO_COMPONENT_TYPE_INSTANCES) {
424  return std::make_unique<InstancesDataSource>(geometry_set);
425  }
426  return std::make_unique<GeometryDataSource>(object_eval, geometry_set, component_type, domain);
427 }
428 
429 } // namespace blender::ed::spreadsheet
AttributeDomain
Definition: BKE_attribute.h:41
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:43
@ ATTR_DOMAIN_FACE
Definition: BKE_attribute.h:46
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:45
@ ATTR_DOMAIN_EDGE
Definition: BKE_attribute.h:44
struct SpaceSpreadsheet * CTX_wm_space_spreadsheet(const bContext *C)
Definition: context.c:917
void * CustomData_get_layer(const struct CustomData *data, int type)
GeometryComponentType
@ GEO_COMPONENT_TYPE_MESH
@ GEO_COMPONENT_TYPE_POINT_CLOUD
@ GEO_COMPONENT_TYPE_INSTANCES
@ INSTANCE_DATA_TYPE_OBJECT
@ INSTANCE_DATA_TYPE_COLLECTION
void * BKE_id_new_nomain(const short type, const char *name)
Definition: lib_id.c:1196
void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me)
Definition: mesh_wrapper.c:98
struct Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval, const bool get_cage_mesh)
#define BLI_assert(a)
Definition: BLI_assert.h:58
void * BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:813
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define POINTER_FROM_UINT(i)
#define STREQ(a, b)
struct Object * DEG_get_original_object(struct Object *object)
ID and Library types, which are fundamental for sdna.
@ ID_ME
Definition: DNA_ID_enums.h:60
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
@ CD_ORIGINDEX
@ CD_PROP_COLOR
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_PROP_BOOL
@ OB_MODE_EDIT
@ OB_MESH
@ OB_POINTCLOUD
@ SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED
@ SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL
uint64_t ED_spreadsheet_context_path_hash(struct SpaceSpreadsheet *sspreadsheet)
#define C
Definition: RandGen.cpp:39
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2276
void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
virtual int attribute_domain_size(const AttributeDomain domain) const
blender::bke::ReadAttributePtr attribute_try_get_for_read(const blender::StringRef attribute_name) const
bool attribute_foreach(const AttributeForeachCallback callback) const
GeometryComponentType type() const
Definition: geometry_set.cc:88
blender::Span< InstancedData > instanced_data() const
void replace(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
void copy_vertex_group_names_from_object(const struct Object &object)
void replace(PointCloud *pointcloud, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
T & construct(const char *name, Args &&... args)
T * add(std::unique_ptr< T > resource, const char *name)
constexpr const char * c_str() const
void append(const T &value)
Definition: BLI_vector.hh:438
CustomDataType custom_data_type() const
AttributeDomain domain() const
void foreach_default_column_ids(FunctionRef< void(const SpreadsheetColumnID &)> fn) const override
std::unique_ptr< ColumnValues > get_column_values(const SpreadsheetColumnID &column_id) const override
std::unique_ptr< ColumnValues > get_column_values(const SpreadsheetColumnID &column_id) const override
void foreach_default_column_ids(FunctionRef< void(const SpreadsheetColumnID &)> fn) const override
static ushort indices[]
std::unique_ptr< ReadAttribute > ReadAttributePtr
static void get_selected_face_indices(const Mesh &mesh, const IsVertexSelectedFn is_vertex_selected_fn, Vector< int64_t > &r_face_indices)
std::unique_ptr< ColumnValues > column_values_from_function(std::string name, const int size, GetValueF get_value, const float default_width=0.0f)
static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet, Object *object_eval, const GeometryComponentType used_component_type)
static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval)
static void get_selected_corner_indices(const Mesh &mesh, const IsVertexSelectedFn is_vertex_selected_fn, Vector< int64_t > &r_corner_indices)
std::unique_ptr< DataSource > data_source_from_geometry(const bContext *C, Object *object_eval)
static constexpr float default_float2_column_width
static void get_selected_edge_indices(const Mesh &mesh, const IsVertexSelectedFn is_vertex_selected_fn, Vector< int64_t > &r_edge_indices)
static void get_selected_indices_on_domain(const Mesh &mesh, const AttributeDomain domain, const IsVertexSelectedFn is_vertex_selected_fn, Vector< int64_t > &r_indices)
static void get_selected_vertex_indices(const Mesh &mesh, const IsVertexSelectedFn is_vertex_selected_fn, Vector< int64_t > &r_vertex_indices)
static constexpr float default_color_column_width
static constexpr float default_float3_column_width
unsigned __int64 uint64_t
Definition: stdint.h:93
AttributeDomain domain
struct BMesh * bm
Definition: BKE_editmesh.h:52
int totvert
Definition: bmesh_class.h:297
BMVert ** vtable
Definition: bmesh_class.h:321
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
bool has(const GeometryComponentType component_type) const
unsigned int v1
unsigned int v2
unsigned int v
struct MEdge * medge
struct BMEditMesh * edit_mesh
int totedge
int totvert
struct MLoop * mloop
int totpoly
int totloop
struct MPoly * mpoly
void * geometry_set_previews
struct GeometrySet * geometry_set_eval
Object_Runtime runtime
void * data
uint8_t geometry_component_type