Quiet unused argument, shadow, array-bounds & range-loop-bind-reference warnings.
598 lines
22 KiB
C++
598 lines
22 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "NOD_geometry_nodes_lazy_function.hh"
|
|
#include "NOD_geometry_nodes_log.hh"
|
|
|
|
#include "BKE_compute_contexts.hh"
|
|
#include "BKE_curves.hh"
|
|
#include "BKE_node_runtime.hh"
|
|
#include "BKE_viewer_path.h"
|
|
|
|
#include "FN_field_cpp_type.hh"
|
|
|
|
#include "DNA_modifier_types.h"
|
|
#include "DNA_space_types.h"
|
|
|
|
#include "ED_viewer_path.hh"
|
|
|
|
namespace blender::nodes::geo_eval_log {
|
|
|
|
using fn::FieldInput;
|
|
using fn::FieldInputs;
|
|
|
|
GenericValueLog::~GenericValueLog()
|
|
{
|
|
this->value.destruct();
|
|
}
|
|
|
|
FieldInfoLog::FieldInfoLog(const GField &field) : type(field.cpp_type())
|
|
{
|
|
const std::shared_ptr<const fn::FieldInputs> &field_input_nodes = field.node().field_inputs();
|
|
|
|
/* Put the deduplicated field inputs into a vector so that they can be sorted below. */
|
|
Vector<std::reference_wrapper<const FieldInput>> field_inputs;
|
|
if (field_input_nodes) {
|
|
field_inputs.extend(field_input_nodes->deduplicated_nodes.begin(),
|
|
field_input_nodes->deduplicated_nodes.end());
|
|
}
|
|
|
|
std::sort(
|
|
field_inputs.begin(), field_inputs.end(), [](const FieldInput &a, const FieldInput &b) {
|
|
const int index_a = int(a.category());
|
|
const int index_b = int(b.category());
|
|
if (index_a == index_b) {
|
|
return a.socket_inspection_name().size() < b.socket_inspection_name().size();
|
|
}
|
|
return index_a < index_b;
|
|
});
|
|
|
|
for (const FieldInput &field_input : field_inputs) {
|
|
this->input_tooltips.append(field_input.socket_inspection_name());
|
|
}
|
|
}
|
|
|
|
GeometryInfoLog::GeometryInfoLog(const GeometrySet &geometry_set)
|
|
{
|
|
static std::array all_component_types = {GEO_COMPONENT_TYPE_CURVE,
|
|
GEO_COMPONENT_TYPE_INSTANCES,
|
|
GEO_COMPONENT_TYPE_MESH,
|
|
GEO_COMPONENT_TYPE_POINT_CLOUD,
|
|
GEO_COMPONENT_TYPE_VOLUME};
|
|
|
|
/* Keep track handled attribute names to make sure that we do not return the same name twice.
|
|
* Currently #GeometrySet::attribute_foreach does not do that. Note that this will merge
|
|
* attributes with the same name but different domains or data types on separate components. */
|
|
Set<StringRef> names;
|
|
|
|
geometry_set.attribute_foreach(
|
|
all_component_types,
|
|
true,
|
|
[&](const bke::AttributeIDRef &attribute_id,
|
|
const bke::AttributeMetaData &meta_data,
|
|
const GeometryComponent & /*component*/) {
|
|
if (!attribute_id.is_anonymous() && names.add(attribute_id.name())) {
|
|
this->attributes.append({attribute_id.name(), meta_data.domain, meta_data.data_type});
|
|
}
|
|
});
|
|
|
|
for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
|
|
this->component_types.append(component->type());
|
|
switch (component->type()) {
|
|
case GEO_COMPONENT_TYPE_MESH: {
|
|
const MeshComponent &mesh_component = *(const MeshComponent *)component;
|
|
MeshInfo &info = this->mesh_info.emplace();
|
|
info.verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
|
info.edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
|
|
info.faces_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_FACE);
|
|
break;
|
|
}
|
|
case GEO_COMPONENT_TYPE_CURVE: {
|
|
const CurveComponent &curve_component = *(const CurveComponent *)component;
|
|
CurveInfo &info = this->curve_info.emplace();
|
|
info.points_num = curve_component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
|
info.splines_num = curve_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
|
|
break;
|
|
}
|
|
case GEO_COMPONENT_TYPE_POINT_CLOUD: {
|
|
const PointCloudComponent &pointcloud_component = *(const PointCloudComponent *)component;
|
|
PointCloudInfo &info = this->pointcloud_info.emplace();
|
|
info.points_num = pointcloud_component.attribute_domain_size(ATTR_DOMAIN_POINT);
|
|
break;
|
|
}
|
|
case GEO_COMPONENT_TYPE_INSTANCES: {
|
|
const InstancesComponent &instances_component = *(const InstancesComponent *)component;
|
|
InstancesInfo &info = this->instances_info.emplace();
|
|
info.instances_num = instances_component.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
|
|
break;
|
|
}
|
|
case GEO_COMPONENT_TYPE_EDIT: {
|
|
const GeometryComponentEditData &edit_component = *(
|
|
const GeometryComponentEditData *)component;
|
|
if (const bke::CurvesEditHints *curve_edit_hints =
|
|
edit_component.curves_edit_hints_.get()) {
|
|
EditDataInfo &info = this->edit_data_info.emplace();
|
|
info.has_deform_matrices = curve_edit_hints->deform_mats.has_value();
|
|
info.has_deformed_positions = curve_edit_hints->positions.has_value();
|
|
}
|
|
break;
|
|
}
|
|
case GEO_COMPONENT_TYPE_VOLUME: {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Avoid generating these in every translation unit. */
|
|
GeoModifierLog::GeoModifierLog() = default;
|
|
GeoModifierLog::~GeoModifierLog() = default;
|
|
|
|
GeoTreeLogger::GeoTreeLogger() = default;
|
|
GeoTreeLogger::~GeoTreeLogger() = default;
|
|
|
|
GeoNodeLog::GeoNodeLog() = default;
|
|
GeoNodeLog::~GeoNodeLog() = default;
|
|
|
|
GeoTreeLog::GeoTreeLog(GeoModifierLog *modifier_log, Vector<GeoTreeLogger *> tree_loggers)
|
|
: modifier_log_(modifier_log), tree_loggers_(std::move(tree_loggers))
|
|
{
|
|
for (GeoTreeLogger *tree_logger : tree_loggers_) {
|
|
for (const ComputeContextHash &hash : tree_logger->children_hashes) {
|
|
children_hashes_.add(hash);
|
|
}
|
|
}
|
|
}
|
|
|
|
GeoTreeLog::~GeoTreeLog() = default;
|
|
|
|
void GeoTreeLogger::log_value(const bNode &node, const bNodeSocket &socket, const GPointer value)
|
|
{
|
|
const CPPType &type = *value.type();
|
|
|
|
auto store_logged_value = [&](destruct_ptr<ValueLog> value_log) {
|
|
auto &socket_values = socket.in_out == SOCK_IN ? this->input_socket_values :
|
|
this->output_socket_values;
|
|
socket_values.append({node.identifier, socket.index(), std::move(value_log)});
|
|
};
|
|
|
|
auto log_generic_value = [&](const CPPType &type, const void *value) {
|
|
void *buffer = this->allocator->allocate(type.size(), type.alignment());
|
|
type.copy_construct(value, buffer);
|
|
store_logged_value(this->allocator->construct<GenericValueLog>(GMutablePointer{type, buffer}));
|
|
};
|
|
|
|
if (type.is<GeometrySet>()) {
|
|
const GeometrySet &geometry = *value.get<GeometrySet>();
|
|
store_logged_value(this->allocator->construct<GeometryInfoLog>(geometry));
|
|
}
|
|
else if (const auto *value_or_field_type = fn::ValueOrFieldCPPType::get_from_self(type)) {
|
|
const void *value_or_field = value.get();
|
|
const CPPType &base_type = value_or_field_type->value;
|
|
if (value_or_field_type->is_field(value_or_field)) {
|
|
const GField *field = value_or_field_type->get_field_ptr(value_or_field);
|
|
if (field->node().depends_on_input()) {
|
|
store_logged_value(this->allocator->construct<FieldInfoLog>(*field));
|
|
}
|
|
else {
|
|
BUFFER_FOR_CPP_TYPE_VALUE(base_type, value);
|
|
fn::evaluate_constant_field(*field, value);
|
|
log_generic_value(base_type, value);
|
|
}
|
|
}
|
|
else {
|
|
const void *value = value_or_field_type->get_value_ptr(value_or_field);
|
|
log_generic_value(base_type, value);
|
|
}
|
|
}
|
|
else {
|
|
log_generic_value(type, value.get());
|
|
}
|
|
}
|
|
|
|
void GeoTreeLogger::log_viewer_node(const bNode &viewer_node, GeometrySet geometry)
|
|
{
|
|
destruct_ptr<ViewerNodeLog> log = this->allocator->construct<ViewerNodeLog>();
|
|
log->geometry = std::move(geometry);
|
|
log->geometry.ensure_owns_direct_data();
|
|
this->viewer_node_logs.append({viewer_node.identifier, std::move(log)});
|
|
}
|
|
|
|
void GeoTreeLog::ensure_node_warnings()
|
|
{
|
|
if (reduced_node_warnings_) {
|
|
return;
|
|
}
|
|
for (GeoTreeLogger *tree_logger : tree_loggers_) {
|
|
for (const GeoTreeLogger::WarningWithNode &warnings : tree_logger->node_warnings) {
|
|
this->nodes.lookup_or_add_default(warnings.node_id).warnings.append(warnings.warning);
|
|
this->all_warnings.append(warnings.warning);
|
|
}
|
|
}
|
|
for (const ComputeContextHash &child_hash : children_hashes_) {
|
|
GeoTreeLog &child_log = modifier_log_->get_tree_log(child_hash);
|
|
child_log.ensure_node_warnings();
|
|
const std::optional<int32_t> &group_node_id = child_log.tree_loggers_[0]->group_node_id;
|
|
if (group_node_id.has_value()) {
|
|
this->nodes.lookup_or_add_default(*group_node_id).warnings.extend(child_log.all_warnings);
|
|
}
|
|
this->all_warnings.extend(child_log.all_warnings);
|
|
}
|
|
reduced_node_warnings_ = true;
|
|
}
|
|
|
|
void GeoTreeLog::ensure_node_run_time()
|
|
{
|
|
if (reduced_node_run_times_) {
|
|
return;
|
|
}
|
|
for (GeoTreeLogger *tree_logger : tree_loggers_) {
|
|
for (const GeoTreeLogger::NodeExecutionTime &timings : tree_logger->node_execution_times) {
|
|
const std::chrono::nanoseconds duration = timings.end - timings.start;
|
|
this->nodes.lookup_or_add_default_as(timings.node_id).run_time += duration;
|
|
this->run_time_sum += duration;
|
|
}
|
|
}
|
|
for (const ComputeContextHash &child_hash : children_hashes_) {
|
|
GeoTreeLog &child_log = modifier_log_->get_tree_log(child_hash);
|
|
child_log.ensure_node_run_time();
|
|
const std::optional<int32_t> &group_node_id = child_log.tree_loggers_[0]->group_node_id;
|
|
if (group_node_id.has_value()) {
|
|
this->nodes.lookup_or_add_default(*group_node_id).run_time += child_log.run_time_sum;
|
|
}
|
|
this->run_time_sum += child_log.run_time_sum;
|
|
}
|
|
reduced_node_run_times_ = true;
|
|
}
|
|
|
|
void GeoTreeLog::ensure_socket_values()
|
|
{
|
|
if (reduced_socket_values_) {
|
|
return;
|
|
}
|
|
for (GeoTreeLogger *tree_logger : tree_loggers_) {
|
|
for (const GeoTreeLogger::SocketValueLog &value_log_data : tree_logger->input_socket_values) {
|
|
this->nodes.lookup_or_add_as(value_log_data.node_id)
|
|
.input_values_.add(value_log_data.socket_index, value_log_data.value.get());
|
|
}
|
|
for (const GeoTreeLogger::SocketValueLog &value_log_data : tree_logger->output_socket_values) {
|
|
this->nodes.lookup_or_add_as(value_log_data.node_id)
|
|
.output_values_.add(value_log_data.socket_index, value_log_data.value.get());
|
|
}
|
|
}
|
|
reduced_socket_values_ = true;
|
|
}
|
|
|
|
void GeoTreeLog::ensure_viewer_node_logs()
|
|
{
|
|
if (reduced_viewer_node_logs_) {
|
|
return;
|
|
}
|
|
for (GeoTreeLogger *tree_logger : tree_loggers_) {
|
|
for (const GeoTreeLogger::ViewerNodeLogWithNode &viewer_log : tree_logger->viewer_node_logs) {
|
|
this->viewer_node_logs.add(viewer_log.node_id, viewer_log.viewer_log.get());
|
|
}
|
|
}
|
|
reduced_viewer_node_logs_ = true;
|
|
}
|
|
|
|
void GeoTreeLog::ensure_existing_attributes()
|
|
{
|
|
if (reduced_existing_attributes_) {
|
|
return;
|
|
}
|
|
this->ensure_socket_values();
|
|
|
|
Set<StringRef> names;
|
|
|
|
auto handle_value_log = [&](const ValueLog &value_log) {
|
|
const GeometryInfoLog *geo_log = dynamic_cast<const GeometryInfoLog *>(&value_log);
|
|
if (geo_log == nullptr) {
|
|
return;
|
|
}
|
|
for (const GeometryAttributeInfo &attribute : geo_log->attributes) {
|
|
if (names.add(attribute.name)) {
|
|
this->existing_attributes.append(&attribute);
|
|
}
|
|
}
|
|
};
|
|
|
|
for (const GeoNodeLog &node_log : this->nodes.values()) {
|
|
for (const ValueLog *value_log : node_log.input_values_.values()) {
|
|
handle_value_log(*value_log);
|
|
}
|
|
for (const ValueLog *value_log : node_log.output_values_.values()) {
|
|
handle_value_log(*value_log);
|
|
}
|
|
}
|
|
reduced_existing_attributes_ = true;
|
|
}
|
|
|
|
void GeoTreeLog::ensure_used_named_attributes()
|
|
{
|
|
if (reduced_used_named_attributes_) {
|
|
return;
|
|
}
|
|
|
|
auto add_attribute = [&](const int32_t node_id,
|
|
const StringRefNull attribute_name,
|
|
const NamedAttributeUsage &usage) {
|
|
this->nodes.lookup_or_add_default(node_id).used_named_attributes.lookup_or_add(attribute_name,
|
|
usage) |= usage;
|
|
this->used_named_attributes.lookup_or_add_as(attribute_name, usage) |= usage;
|
|
};
|
|
|
|
for (GeoTreeLogger *tree_logger : tree_loggers_) {
|
|
for (const GeoTreeLogger::AttributeUsageWithNode &item : tree_logger->used_named_attributes) {
|
|
add_attribute(item.node_id, item.attribute_name, item.usage);
|
|
}
|
|
}
|
|
for (const ComputeContextHash &child_hash : children_hashes_) {
|
|
GeoTreeLog &child_log = modifier_log_->get_tree_log(child_hash);
|
|
child_log.ensure_used_named_attributes();
|
|
if (const std::optional<int32_t> &group_node_id = child_log.tree_loggers_[0]->group_node_id) {
|
|
for (const auto item : child_log.used_named_attributes.items()) {
|
|
add_attribute(*group_node_id, item.key, item.value);
|
|
}
|
|
}
|
|
}
|
|
reduced_used_named_attributes_ = true;
|
|
}
|
|
|
|
void GeoTreeLog::ensure_debug_messages()
|
|
{
|
|
if (reduced_debug_messages_) {
|
|
return;
|
|
}
|
|
for (GeoTreeLogger *tree_logger : tree_loggers_) {
|
|
for (const GeoTreeLogger::DebugMessage &debug_message : tree_logger->debug_messages) {
|
|
this->nodes.lookup_or_add_as(debug_message.node_id)
|
|
.debug_messages.append(debug_message.message);
|
|
}
|
|
}
|
|
reduced_debug_messages_ = true;
|
|
}
|
|
|
|
ValueLog *GeoTreeLog::find_socket_value_log(const bNodeSocket &query_socket)
|
|
{
|
|
/**
|
|
* Geometry nodes does not log values for every socket. That would produce a lot of redundant
|
|
* data,because often many linked sockets have the same value. To find the logged value for a
|
|
* socket one might have to look at linked sockets as well.
|
|
*/
|
|
|
|
BLI_assert(reduced_socket_values_);
|
|
if (query_socket.is_multi_input()) {
|
|
/* Not supported currently. */
|
|
return nullptr;
|
|
}
|
|
|
|
Set<const bNodeSocket *> added_sockets;
|
|
Stack<const bNodeSocket *> sockets_to_check;
|
|
sockets_to_check.push(&query_socket);
|
|
added_sockets.add(&query_socket);
|
|
|
|
while (!sockets_to_check.is_empty()) {
|
|
const bNodeSocket &socket = *sockets_to_check.pop();
|
|
const bNode &node = socket.owner_node();
|
|
if (GeoNodeLog *node_log = this->nodes.lookup_ptr(node.identifier)) {
|
|
ValueLog *value_log = socket.is_input() ?
|
|
node_log->input_values_.lookup_default(socket.index(), nullptr) :
|
|
node_log->output_values_.lookup_default(socket.index(), nullptr);
|
|
if (value_log != nullptr) {
|
|
return value_log;
|
|
}
|
|
}
|
|
|
|
if (socket.is_input()) {
|
|
const Span<const bNodeLink *> links = socket.directly_linked_links();
|
|
for (const bNodeLink *link : links) {
|
|
const bNodeSocket &from_socket = *link->fromsock;
|
|
if (added_sockets.add(&from_socket)) {
|
|
sockets_to_check.push(&from_socket);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (node.is_reroute()) {
|
|
const bNodeSocket &input_socket = node.input_socket(0);
|
|
if (added_sockets.add(&input_socket)) {
|
|
sockets_to_check.push(&input_socket);
|
|
}
|
|
const Span<const bNodeLink *> links = input_socket.directly_linked_links();
|
|
for (const bNodeLink *link : links) {
|
|
const bNodeSocket &from_socket = *link->fromsock;
|
|
if (added_sockets.add(&from_socket)) {
|
|
sockets_to_check.push(&from_socket);
|
|
}
|
|
}
|
|
}
|
|
else if (node.is_muted()) {
|
|
if (const bNodeSocket *input_socket = socket.internal_link_input()) {
|
|
if (added_sockets.add(input_socket)) {
|
|
sockets_to_check.push(input_socket);
|
|
}
|
|
const Span<const bNodeLink *> links = input_socket->directly_linked_links();
|
|
for (const bNodeLink *link : links) {
|
|
const bNodeSocket &from_socket = *link->fromsock;
|
|
if (added_sockets.add(&from_socket)) {
|
|
sockets_to_check.push(&from_socket);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
GeoTreeLogger &GeoModifierLog::get_local_tree_logger(const ComputeContext &compute_context)
|
|
{
|
|
LocalData &local_data = data_per_thread_.local();
|
|
Map<ComputeContextHash, destruct_ptr<GeoTreeLogger>> &local_tree_loggers =
|
|
local_data.tree_logger_by_context;
|
|
destruct_ptr<GeoTreeLogger> &tree_logger_ptr = local_tree_loggers.lookup_or_add_default(
|
|
compute_context.hash());
|
|
if (tree_logger_ptr) {
|
|
return *tree_logger_ptr;
|
|
}
|
|
tree_logger_ptr = local_data.allocator.construct<GeoTreeLogger>();
|
|
GeoTreeLogger &tree_logger = *tree_logger_ptr;
|
|
tree_logger.allocator = &local_data.allocator;
|
|
const ComputeContext *parent_compute_context = compute_context.parent();
|
|
if (parent_compute_context != nullptr) {
|
|
tree_logger.parent_hash = parent_compute_context->hash();
|
|
GeoTreeLogger &parent_logger = this->get_local_tree_logger(*parent_compute_context);
|
|
parent_logger.children_hashes.append(compute_context.hash());
|
|
}
|
|
if (const bke::NodeGroupComputeContext *node_group_compute_context =
|
|
dynamic_cast<const bke::NodeGroupComputeContext *>(&compute_context)) {
|
|
tree_logger.group_node_id.emplace(node_group_compute_context->node_id());
|
|
}
|
|
return tree_logger;
|
|
}
|
|
|
|
GeoTreeLog &GeoModifierLog::get_tree_log(const ComputeContextHash &compute_context_hash)
|
|
{
|
|
GeoTreeLog &reduced_tree_log = *tree_logs_.lookup_or_add_cb(compute_context_hash, [&]() {
|
|
Vector<GeoTreeLogger *> tree_logs;
|
|
for (LocalData &local_data : data_per_thread_) {
|
|
destruct_ptr<GeoTreeLogger> *tree_log = local_data.tree_logger_by_context.lookup_ptr(
|
|
compute_context_hash);
|
|
if (tree_log != nullptr) {
|
|
tree_logs.append(tree_log->get());
|
|
}
|
|
}
|
|
return std::make_unique<GeoTreeLog>(this, std::move(tree_logs));
|
|
});
|
|
return reduced_tree_log;
|
|
}
|
|
|
|
struct ObjectAndModifier {
|
|
const Object *object;
|
|
const NodesModifierData *nmd;
|
|
};
|
|
|
|
static std::optional<ObjectAndModifier> get_modifier_for_node_editor(const SpaceNode &snode)
|
|
{
|
|
if (snode.id == nullptr) {
|
|
return std::nullopt;
|
|
}
|
|
if (GS(snode.id->name) != ID_OB) {
|
|
return std::nullopt;
|
|
}
|
|
const Object *object = reinterpret_cast<Object *>(snode.id);
|
|
const NodesModifierData *used_modifier = nullptr;
|
|
if (snode.flag & SNODE_PIN) {
|
|
LISTBASE_FOREACH (const ModifierData *, md, &object->modifiers) {
|
|
if (md->type == eModifierType_Nodes) {
|
|
const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
|
|
/* Would be good to store the name of the pinned modifier in the node editor. */
|
|
if (nmd->node_group == snode.nodetree) {
|
|
used_modifier = nmd;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LISTBASE_FOREACH (const ModifierData *, md, &object->modifiers) {
|
|
if (md->type == eModifierType_Nodes) {
|
|
const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
|
|
if (nmd->node_group == snode.nodetree) {
|
|
if (md->flag & eModifierFlag_Active) {
|
|
used_modifier = nmd;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (used_modifier == nullptr) {
|
|
return std::nullopt;
|
|
}
|
|
return ObjectAndModifier{object, used_modifier};
|
|
}
|
|
|
|
std::optional<ComputeContextHash> GeoModifierLog::get_compute_context_hash_for_node_editor(
|
|
const SpaceNode &snode, const StringRefNull modifier_name)
|
|
{
|
|
Vector<const bNodeTreePath *> tree_path = snode.treepath;
|
|
if (tree_path.is_empty()) {
|
|
return std::nullopt;
|
|
}
|
|
ComputeContextBuilder compute_context_builder;
|
|
compute_context_builder.push<bke::ModifierComputeContext>(modifier_name);
|
|
for (const int i : tree_path.index_range().drop_back(1)) {
|
|
/* The tree path contains the name of the node but not its ID. */
|
|
const bNode *node = nodeFindNodebyName(tree_path[i]->nodetree, tree_path[i + 1]->node_name);
|
|
if (node == nullptr) {
|
|
/* The current tree path is invalid, probably because some parent group node has been
|
|
* deleted. */
|
|
return std::nullopt;
|
|
}
|
|
compute_context_builder.push<bke::NodeGroupComputeContext>(*node);
|
|
}
|
|
return compute_context_builder.hash();
|
|
}
|
|
|
|
GeoTreeLog *GeoModifierLog::get_tree_log_for_node_editor(const SpaceNode &snode)
|
|
{
|
|
std::optional<ObjectAndModifier> object_and_modifier = get_modifier_for_node_editor(snode);
|
|
if (!object_and_modifier) {
|
|
return nullptr;
|
|
}
|
|
GeoModifierLog *modifier_log = static_cast<GeoModifierLog *>(
|
|
object_and_modifier->nmd->runtime_eval_log);
|
|
if (modifier_log == nullptr) {
|
|
return nullptr;
|
|
}
|
|
if (const std::optional<ComputeContextHash> hash =
|
|
GeoModifierLog::get_compute_context_hash_for_node_editor(
|
|
snode, object_and_modifier->nmd->modifier.name)) {
|
|
return &modifier_log->get_tree_log(*hash);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerPath &viewer_path)
|
|
{
|
|
const std::optional<ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
|
|
ed::viewer_path::parse_geometry_nodes_viewer(viewer_path);
|
|
if (!parsed_path.has_value()) {
|
|
return nullptr;
|
|
}
|
|
const Object *object = parsed_path->object;
|
|
NodesModifierData *nmd = nullptr;
|
|
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
|
|
if (md->name == parsed_path->modifier_name) {
|
|
if (md->type == eModifierType_Nodes) {
|
|
nmd = reinterpret_cast<NodesModifierData *>(md);
|
|
}
|
|
}
|
|
}
|
|
if (nmd == nullptr) {
|
|
return nullptr;
|
|
}
|
|
if (nmd->runtime_eval_log == nullptr) {
|
|
return nullptr;
|
|
}
|
|
nodes::geo_eval_log::GeoModifierLog *modifier_log =
|
|
static_cast<nodes::geo_eval_log::GeoModifierLog *>(nmd->runtime_eval_log);
|
|
|
|
ComputeContextBuilder compute_context_builder;
|
|
compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
|
|
for (const int32_t group_node_id : parsed_path->group_node_ids) {
|
|
compute_context_builder.push<bke::NodeGroupComputeContext>(group_node_id);
|
|
}
|
|
const ComputeContextHash context_hash = compute_context_builder.hash();
|
|
nodes::geo_eval_log::GeoTreeLog &tree_log = modifier_log->get_tree_log(context_hash);
|
|
tree_log.ensure_viewer_node_logs();
|
|
|
|
const ViewerNodeLog *viewer_log = tree_log.viewer_node_logs.lookup_default(
|
|
parsed_path->viewer_node_id, nullptr);
|
|
return viewer_log;
|
|
}
|
|
|
|
} // namespace blender::nodes::geo_eval_log
|