Compare commits
25 Commits
temp-sculp
...
spreadshee
Author | SHA1 | Date | |
---|---|---|---|
83ccca8675 | |||
77c8070b11 | |||
1db976521e | |||
f053bc2ddf | |||
51b4162fed | |||
4a7736ce1d | |||
26071531d0 | |||
131550dac1 | |||
7bcd0e01af | |||
d6fcecc471 | |||
e945564068 | |||
1598d57663 | |||
42a40f4e7c | |||
80865399a8 | |||
9ed2a7e680 | |||
3af1903ac7 | |||
214a49aae4 | |||
45aa341dd4 | |||
e0aab87f54 | |||
fca8d0f91f | |||
8262c2577e | |||
993e8af943 | |||
a535c07417 | |||
5cbecde9c7 | |||
4472178094 |
@@ -141,6 +141,12 @@ class GeometryComponent {
|
||||
/* The returned component should be of the same type as the type this is called on. */
|
||||
virtual GeometryComponent *copy() const = 0;
|
||||
|
||||
/* Direct data is everything except for instances of objects/collections.
|
||||
* If this returns true, the geometry set can be cached and is still valid after e.g. modifier
|
||||
* evaluation ends. Instances can only be valid as long as the data they instance is valid. */
|
||||
virtual bool owns_direct_data() const = 0;
|
||||
virtual void ensure_owns_direct_data() = 0;
|
||||
|
||||
void user_add() const;
|
||||
void user_remove() const;
|
||||
bool is_mutable() const;
|
||||
@@ -315,6 +321,8 @@ struct GeometrySet {
|
||||
|
||||
void clear();
|
||||
|
||||
void ensure_owns_direct_data();
|
||||
|
||||
/* Utility methods for creation. */
|
||||
static GeometrySet create_with_mesh(
|
||||
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
|
||||
@@ -374,6 +382,9 @@ class MeshComponent : public GeometryComponent {
|
||||
|
||||
bool is_empty() const final;
|
||||
|
||||
bool owns_direct_data() const override;
|
||||
void ensure_owns_direct_data() override;
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_MESH;
|
||||
|
||||
private:
|
||||
@@ -404,6 +415,9 @@ class PointCloudComponent : public GeometryComponent {
|
||||
|
||||
bool is_empty() const final;
|
||||
|
||||
bool owns_direct_data() const override;
|
||||
void ensure_owns_direct_data() override;
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
|
||||
|
||||
private:
|
||||
@@ -444,6 +458,9 @@ class InstancesComponent : public GeometryComponent {
|
||||
|
||||
bool is_empty() const final;
|
||||
|
||||
bool owns_direct_data() const override;
|
||||
void ensure_owns_direct_data() override;
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
|
||||
};
|
||||
|
||||
@@ -466,5 +483,8 @@ class VolumeComponent : public GeometryComponent {
|
||||
const Volume *get_for_read() const;
|
||||
Volume *get_for_write();
|
||||
|
||||
bool owns_direct_data() const override;
|
||||
void ensure_owns_direct_data() override;
|
||||
|
||||
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_VOLUME;
|
||||
};
|
||||
|
@@ -34,6 +34,7 @@ struct Base;
|
||||
struct BoundBox;
|
||||
struct Curve;
|
||||
struct Depsgraph;
|
||||
struct GeometrySet;
|
||||
struct GpencilModifierData;
|
||||
struct HookGpencilModifierData;
|
||||
struct HookModifierData;
|
||||
@@ -69,6 +70,8 @@ void BKE_object_free_curve_cache(struct Object *ob);
|
||||
void BKE_object_free_derived_caches(struct Object *ob);
|
||||
void BKE_object_free_caches(struct Object *object);
|
||||
|
||||
void BKE_object_preview_geometry_set(struct Object *ob, struct GeometrySet *geometry_set);
|
||||
|
||||
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
|
||||
void BKE_object_modifier_gpencil_hook_reset(struct Object *ob,
|
||||
struct HookGpencilModifierData *hmd);
|
||||
|
@@ -108,6 +108,16 @@ bool InstancesComponent::is_empty() const
|
||||
return transforms_.size() == 0;
|
||||
}
|
||||
|
||||
bool InstancesComponent::owns_direct_data() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstancesComponent::ensure_owns_direct_data()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
}
|
||||
|
||||
static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids)
|
||||
{
|
||||
using namespace blender;
|
||||
|
@@ -157,6 +157,20 @@ bool MeshComponent::is_empty() const
|
||||
return mesh_ == nullptr;
|
||||
}
|
||||
|
||||
bool MeshComponent::owns_direct_data() const
|
||||
{
|
||||
return ownership_ == GeometryOwnershipType::Owned;
|
||||
}
|
||||
|
||||
void MeshComponent::ensure_owns_direct_data()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
if (ownership_ != GeometryOwnershipType::Owned) {
|
||||
mesh_ = BKE_mesh_copy_for_eval(mesh_, false);
|
||||
ownership_ = GeometryOwnershipType::Owned;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@@ -107,6 +107,20 @@ bool PointCloudComponent::is_empty() const
|
||||
return pointcloud_ == nullptr;
|
||||
}
|
||||
|
||||
bool PointCloudComponent::owns_direct_data() const
|
||||
{
|
||||
return ownership_ == GeometryOwnershipType::Owned;
|
||||
}
|
||||
|
||||
void PointCloudComponent::ensure_owns_direct_data()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
if (ownership_ != GeometryOwnershipType::Owned) {
|
||||
pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false);
|
||||
ownership_ = GeometryOwnershipType::Owned;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@@ -97,4 +97,18 @@ Volume *VolumeComponent::get_for_write()
|
||||
return volume_;
|
||||
}
|
||||
|
||||
bool VolumeComponent::owns_direct_data() const
|
||||
{
|
||||
return ownership_ == GeometryOwnershipType::Owned;
|
||||
}
|
||||
|
||||
void VolumeComponent::ensure_owns_direct_data()
|
||||
{
|
||||
BLI_assert(this->is_mutable());
|
||||
if (ownership_ != GeometryOwnershipType::Owned) {
|
||||
volume_ = BKE_volume_copy_for_eval(volume_, false);
|
||||
ownership_ = GeometryOwnershipType::Owned;
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -211,6 +211,19 @@ void GeometrySet::clear()
|
||||
components_.clear();
|
||||
}
|
||||
|
||||
/* Make sure that the geometry can be cached. This does not ensure ownership of object/collection
|
||||
* instances. */
|
||||
void GeometrySet::ensure_owns_direct_data()
|
||||
{
|
||||
for (GeometryComponentType type : components_.keys()) {
|
||||
const GeometryComponent *component = this->get_component_for_read(type);
|
||||
if (!component->owns_direct_data()) {
|
||||
GeometryComponent &component_for_write = this->get_component_for_write(type);
|
||||
component_for_write.ensure_owns_direct_data();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns a read-only mesh or null. */
|
||||
const Mesh *GeometrySet::get_mesh_for_read() const
|
||||
{
|
||||
|
@@ -1756,6 +1756,10 @@ void BKE_object_free_derived_caches(Object *ob)
|
||||
BKE_geometry_set_free(ob->runtime.geometry_set_eval);
|
||||
ob->runtime.geometry_set_eval = NULL;
|
||||
}
|
||||
if (ob->runtime.geometry_set_preview != NULL) {
|
||||
BKE_geometry_set_free(ob->runtime.geometry_set_preview);
|
||||
ob->runtime.geometry_set_preview = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_object_free_caches(Object *object)
|
||||
@@ -1806,6 +1810,18 @@ void BKE_object_free_caches(Object *object)
|
||||
}
|
||||
}
|
||||
|
||||
/* Can be called from multiple threads. */
|
||||
void BKE_object_preview_geometry_set(Object *ob, struct GeometrySet *geometry_set)
|
||||
{
|
||||
static ThreadMutex mutex = BLI_MUTEX_INITIALIZER;
|
||||
BLI_mutex_lock(&mutex);
|
||||
if (ob->runtime.geometry_set_preview != NULL) {
|
||||
BKE_geometry_set_free(ob->runtime.geometry_set_preview);
|
||||
}
|
||||
ob->runtime.geometry_set_preview = geometry_set;
|
||||
BLI_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actual check for internal data, not context or flags.
|
||||
*/
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_workspace.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
@@ -670,6 +671,21 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_acti
|
||||
|
||||
nodeSetActive(ntree, node);
|
||||
|
||||
/* Tag for update, so that dependend objects are reevaluated. This is necessary when a
|
||||
* spreadsheet editor displays data from a node. */
|
||||
LISTBASE_FOREACH (wmWindow *, window, &((wmWindowManager *)bmain->wm.first)->windows) {
|
||||
bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
if (area->spacetype == SPACE_SPREADSHEET) {
|
||||
SpaceSpreadsheet *sspreadsheet = area->spacedata.first;
|
||||
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) {
|
||||
DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE);
|
||||
ED_area_tag_redraw(area);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node->type != NODE_GROUP) {
|
||||
const bool was_output = (node->flag & NODE_DO_OUTPUT) != 0;
|
||||
bool do_update = false;
|
||||
|
@@ -200,25 +200,7 @@ static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
|
||||
const GeometryComponentType used_component_type)
|
||||
{
|
||||
GeometrySet 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
|
||||
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>();
|
||||
@@ -247,6 +229,30 @@ static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
|
||||
pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
|
||||
}
|
||||
}
|
||||
else {
|
||||
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 (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) {
|
||||
if (object_eval->runtime.geometry_set_preview != nullptr) {
|
||||
geometry_set = *object_eval->runtime.geometry_set_preview;
|
||||
}
|
||||
}
|
||||
else if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) {
|
||||
if (object_eval->runtime.geometry_set_eval != nullptr) {
|
||||
geometry_set = *object_eval->runtime.geometry_set_eval;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return geometry_set;
|
||||
}
|
||||
|
||||
@@ -377,7 +383,7 @@ static Span<int64_t> filter_mesh_elements_by_selection(const bContext *C,
|
||||
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) {
|
||||
if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
|
||||
return (GeometryComponentType)sspreadsheet->geometry_component_type;
|
||||
}
|
||||
if (object_eval->type == OB_POINTCLOUD) {
|
||||
|
@@ -168,6 +168,11 @@ typedef struct Object_Runtime {
|
||||
*/
|
||||
struct GeometrySet *geometry_set_eval;
|
||||
|
||||
/**
|
||||
* Data from this geometry set is previewed in the spreadsheet editor.
|
||||
*/
|
||||
struct GeometrySet *geometry_set_preview;
|
||||
|
||||
/**
|
||||
* Mesh structure created during object evaluation.
|
||||
* It has deformation only modifiers applied on it.
|
||||
|
@@ -1886,6 +1886,7 @@ typedef enum eSpaceSpreadsheet_FilterFlag {
|
||||
typedef enum eSpaceSpreadsheet_ObjectEvalState {
|
||||
SPREADSHEET_OBJECT_EVAL_STATE_FINAL = 0,
|
||||
SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL = 1,
|
||||
SPREADSHEET_OBJECT_EVAL_STATE_NODE = 2,
|
||||
} eSpaceSpreadsheet_Context;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@@ -7344,6 +7344,11 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
|
||||
ICON_NONE,
|
||||
"Original",
|
||||
"Use data from original object without any modifiers applied"},
|
||||
{SPREADSHEET_OBJECT_EVAL_STATE_NODE,
|
||||
"NODE",
|
||||
ICON_NONE,
|
||||
"Node",
|
||||
"Use data from the first geometry output of the active node"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
|
@@ -43,17 +43,22 @@
|
||||
#include "DNA_pointcloud_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_lib_query.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_node_ui_storage.hh"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_pointcloud.h"
|
||||
#include "BKE_screen.h"
|
||||
#include "BKE_simulation.h"
|
||||
#include "BKE_workspace.h"
|
||||
|
||||
#include "BLO_read_write.h"
|
||||
|
||||
@@ -1088,6 +1093,71 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree
|
||||
}
|
||||
}
|
||||
|
||||
static DNode find_matching_active_derived_node(const SpaceNode &snode, const DerivedNodeTree &tree)
|
||||
{
|
||||
const DTreeContext &root_context = tree.root_context();
|
||||
bNodeTree *root_tree_eval = root_context.tree().btree();
|
||||
bNodeTree *root_tree_orig = (bNodeTree *)DEG_get_original_id(&root_tree_eval->id);
|
||||
if (snode.nodetree != root_tree_orig) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const DTreeContext *current_context = &root_context;
|
||||
bool is_first = true;
|
||||
LISTBASE_FOREACH (const bNodeTreePath *, path, &snode.treepath) {
|
||||
if (is_first) {
|
||||
is_first = false;
|
||||
continue;
|
||||
}
|
||||
StringRef parent_node_name = path->node_name;
|
||||
const NodeTreeRef &tree_ref = current_context->tree();
|
||||
const NodeRef *parent_node_ref = nullptr;
|
||||
for (const NodeRef *node_ref : tree_ref.nodes()) {
|
||||
if (node_ref->name() == parent_node_name) {
|
||||
parent_node_ref = node_ref;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parent_node_ref == nullptr) {
|
||||
return {};
|
||||
}
|
||||
current_context = current_context->child_context(*parent_node_ref);
|
||||
if (current_context == nullptr) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const NodeTreeRef &tree_ref = current_context->tree();
|
||||
for (const NodeRef *node_ref : tree_ref.nodes()) {
|
||||
if (node_ref->bnode()->flag & NODE_ACTIVE) {
|
||||
return {current_context, node_ref};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static DNode find_matching_active_derived_node(Depsgraph *depsgraph, const DerivedNodeTree &tree)
|
||||
{
|
||||
Main *bmain = DEG_get_bmain(depsgraph);
|
||||
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
|
||||
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
|
||||
bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
SpaceLink *sl = (SpaceLink *)area->spacedata.first;
|
||||
if (sl->spacetype != SPACE_NODE) {
|
||||
continue;
|
||||
}
|
||||
SpaceNode *snode = (SpaceNode *)sl;
|
||||
DNode active_node = find_matching_active_derived_node(*snode, tree);
|
||||
if (!active_node) {
|
||||
continue;
|
||||
}
|
||||
return active_node;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate a node group to compute the output geometry.
|
||||
* Currently, this uses a fairly basic and inefficient algorithm that might compute things more
|
||||
@@ -1143,6 +1213,28 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
||||
Vector<DInputSocket> group_outputs;
|
||||
group_outputs.append({root_context, &socket_to_compute});
|
||||
|
||||
const DNode active_node = find_matching_active_derived_node(ctx->depsgraph, tree);
|
||||
|
||||
auto log_socket_value = [&](const DSocket socket, const Span<GPointer> values) {
|
||||
const DNode node = socket.node();
|
||||
if (node != active_node) {
|
||||
return;
|
||||
}
|
||||
if (socket->is_input() && !node->outputs().is_empty()) {
|
||||
return;
|
||||
}
|
||||
if (values.size() != 1) {
|
||||
return;
|
||||
}
|
||||
const GPointer value = values[0];
|
||||
if (*value.type() != CPPType::get<GeometrySet>()) {
|
||||
return;
|
||||
}
|
||||
GeometrySet geometry_set = *(const GeometrySet *)value.get();
|
||||
geometry_set.ensure_owns_direct_data();
|
||||
BKE_object_preview_geometry_set(ctx->object, new GeometrySet(std::move(geometry_set)));
|
||||
};
|
||||
|
||||
GeometryNodesEvaluator evaluator{group_inputs,
|
||||
group_outputs,
|
||||
mf_by_node,
|
||||
@@ -1150,7 +1242,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
||||
ctx->object,
|
||||
(ModifierData *)nmd,
|
||||
ctx->depsgraph,
|
||||
{}};
|
||||
log_socket_value};
|
||||
|
||||
Vector<GMutablePointer> results = evaluator.execute();
|
||||
BLI_assert(results.size() == 1);
|
||||
|
Reference in New Issue
Block a user