302 lines
9.9 KiB
C++
302 lines
9.9 KiB
C++
/*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "FN_generic_value_map.hh"
|
|
|
|
#include "BKE_attribute_access.hh"
|
|
#include "BKE_geometry_set.hh"
|
|
#include "BKE_geometry_set_instances.hh"
|
|
#include "BKE_node_ui_storage.hh"
|
|
|
|
#include "DNA_node_types.h"
|
|
|
|
#include "NOD_derived_node_tree.hh"
|
|
|
|
struct Depsgraph;
|
|
struct ModifierData;
|
|
|
|
namespace blender::nodes {
|
|
|
|
using bke::geometry_set_realize_instances;
|
|
using bke::OutputAttribute;
|
|
using bke::OutputAttribute_Typed;
|
|
using bke::ReadAttributeLookup;
|
|
using bke::WriteAttributeLookup;
|
|
using fn::CPPType;
|
|
using fn::GMutablePointer;
|
|
using fn::GMutableSpan;
|
|
using fn::GPointer;
|
|
using fn::GSpan;
|
|
using fn::GValueMap;
|
|
using fn::GVArray;
|
|
using fn::GVArray_GSpan;
|
|
using fn::GVArray_Span;
|
|
using fn::GVArray_Typed;
|
|
using fn::GVArrayPtr;
|
|
using fn::GVMutableArray;
|
|
using fn::GVMutableArray_GSpan;
|
|
using fn::GVMutableArray_Typed;
|
|
using fn::GVMutableArrayPtr;
|
|
|
|
/**
|
|
* This class exists to separate the memory management details of the geometry nodes evaluator from
|
|
* the node execution functions and related utilities.
|
|
*/
|
|
class GeoNodeExecParamsProvider {
|
|
public:
|
|
DNode dnode;
|
|
const Object *self_object = nullptr;
|
|
const ModifierData *modifier = nullptr;
|
|
Depsgraph *depsgraph = nullptr;
|
|
|
|
/**
|
|
* Returns true when the node is allowed to get/extract the input value. The identifier is
|
|
* expected to be valid. This may return false if the input value has been consumed already.
|
|
*/
|
|
virtual bool can_get_input(StringRef identifier) const = 0;
|
|
|
|
/**
|
|
* Returns true when the node is allowed to set the output value. The identifier is expected to
|
|
* be valid. This may return false if the output value has been set already.
|
|
*/
|
|
virtual bool can_set_output(StringRef identifier) const = 0;
|
|
|
|
/**
|
|
* Take ownership of an input value. The caller is responsible for destructing the value. It does
|
|
* not have to be freed, because the memory is managed by the geometry nodes evaluator.
|
|
*/
|
|
virtual GMutablePointer extract_input(StringRef identifier) = 0;
|
|
|
|
/**
|
|
* Similar to #extract_input, but has to be used for multi-input sockets.
|
|
*/
|
|
virtual Vector<GMutablePointer> extract_multi_input(StringRef identifier) = 0;
|
|
|
|
/**
|
|
* Get the input value for the identifier without taking ownership of it.
|
|
*/
|
|
virtual GPointer get_input(StringRef identifier) const = 0;
|
|
|
|
/**
|
|
* Prepare a memory buffer for an output value of the node. The returned memory has to be
|
|
* initialized by the caller. The identifier and type are expected to be correct.
|
|
*/
|
|
virtual GMutablePointer alloc_output_value(const CPPType &type) = 0;
|
|
|
|
/**
|
|
* The value has been allocated with #alloc_output_value.
|
|
*/
|
|
virtual void set_output(StringRef identifier, GMutablePointer value) = 0;
|
|
|
|
/* A description for these methods is provided in GeoNodeExecParams. */
|
|
virtual void set_input_unused(StringRef identifier) = 0;
|
|
virtual bool output_is_required(StringRef identifier) const = 0;
|
|
virtual bool lazy_require_input(StringRef identifier) = 0;
|
|
virtual bool lazy_output_is_required(StringRef identifier) const = 0;
|
|
};
|
|
|
|
class GeoNodeExecParams {
|
|
private:
|
|
GeoNodeExecParamsProvider *provider_;
|
|
|
|
public:
|
|
GeoNodeExecParams(GeoNodeExecParamsProvider &provider) : provider_(&provider)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Get the input value for the input socket with the given identifier.
|
|
*
|
|
* The node calling becomes responsible for destructing the value before it is done
|
|
* executing. This method can only be called once for each identifier.
|
|
*/
|
|
GMutablePointer extract_input(StringRef identifier)
|
|
{
|
|
#ifdef DEBUG
|
|
this->check_input_access(identifier);
|
|
#endif
|
|
return provider_->extract_input(identifier);
|
|
}
|
|
|
|
/**
|
|
* Get the input value for the input socket with the given identifier.
|
|
*
|
|
* This method can only be called once for each identifier.
|
|
*/
|
|
template<typename T> T extract_input(StringRef identifier)
|
|
{
|
|
#ifdef DEBUG
|
|
this->check_input_access(identifier, &CPPType::get<T>());
|
|
#endif
|
|
GMutablePointer gvalue = this->extract_input(identifier);
|
|
return gvalue.relocate_out<T>();
|
|
}
|
|
|
|
/**
|
|
* Get input as vector for multi input socket with the given identifier.
|
|
*
|
|
* This method can only be called once for each identifier.
|
|
*/
|
|
template<typename T> Vector<T> extract_multi_input(StringRef identifier)
|
|
{
|
|
Vector<GMutablePointer> gvalues = provider_->extract_multi_input(identifier);
|
|
Vector<T> values;
|
|
for (GMutablePointer gvalue : gvalues) {
|
|
values.append(gvalue.relocate_out<T>());
|
|
}
|
|
return values;
|
|
}
|
|
|
|
/**
|
|
* Get the input value for the input socket with the given identifier.
|
|
*/
|
|
template<typename T> const T &get_input(StringRef identifier) const
|
|
{
|
|
#ifdef DEBUG
|
|
this->check_input_access(identifier, &CPPType::get<T>());
|
|
#endif
|
|
GPointer gvalue = provider_->get_input(identifier);
|
|
BLI_assert(gvalue.is_type<T>());
|
|
return *(const T *)gvalue.get();
|
|
}
|
|
|
|
/**
|
|
* Store the output value for the given socket identifier.
|
|
*/
|
|
template<typename T> void set_output(StringRef identifier, T &&value)
|
|
{
|
|
using StoredT = std::decay_t<T>;
|
|
const CPPType &type = CPPType::get<std::decay_t<T>>();
|
|
#ifdef DEBUG
|
|
this->check_output_access(identifier, type);
|
|
#endif
|
|
GMutablePointer gvalue = provider_->alloc_output_value(type);
|
|
new (gvalue.get()) StoredT(std::forward<T>(value));
|
|
provider_->set_output(identifier, gvalue);
|
|
}
|
|
|
|
/**
|
|
* Tell the evaluator that a specific input won't be used anymore.
|
|
*/
|
|
void set_input_unused(StringRef identifier)
|
|
{
|
|
provider_->set_input_unused(identifier);
|
|
}
|
|
|
|
/**
|
|
* Returns true when the output has to be computed.
|
|
* Nodes that support laziness could use the #lazy_output_is_required variant to possibly avoid
|
|
* some computations.
|
|
*/
|
|
bool output_is_required(StringRef identifier) const
|
|
{
|
|
return provider_->output_is_required(identifier);
|
|
}
|
|
|
|
/**
|
|
* Tell the evaluator that a specific input is required.
|
|
* This returns true when the input will only be available in the next execution.
|
|
* False is returned if the input is available already.
|
|
* This can only be used when the node supports laziness.
|
|
*/
|
|
bool lazy_require_input(StringRef identifier)
|
|
{
|
|
return provider_->lazy_require_input(identifier);
|
|
}
|
|
|
|
/**
|
|
* Asks the evaluator if a specific output is required right now. If this returns false, the
|
|
* value might still need to be computed later.
|
|
* This can only be used when the node supports laziness.
|
|
*/
|
|
bool lazy_output_is_required(StringRef identifier)
|
|
{
|
|
return provider_->lazy_output_is_required(identifier);
|
|
}
|
|
|
|
/**
|
|
* Get the node that is currently being executed.
|
|
*/
|
|
const bNode &node() const
|
|
{
|
|
return *provider_->dnode->bnode();
|
|
}
|
|
|
|
const Object *self_object() const
|
|
{
|
|
return provider_->self_object;
|
|
}
|
|
|
|
Depsgraph *depsgraph() const
|
|
{
|
|
return provider_->depsgraph;
|
|
}
|
|
|
|
/**
|
|
* Add an error message displayed at the top of the node when displaying the node tree,
|
|
* and potentially elsewhere in Blender.
|
|
*/
|
|
void error_message_add(const NodeWarningType type, std::string message) const;
|
|
|
|
/**
|
|
* Creates a read-only attribute based on node inputs. The method automatically detects which
|
|
* input socket with the given name is available.
|
|
*
|
|
* \note This will add an error message if the string socket is active and
|
|
* the input attribute does not exist.
|
|
*/
|
|
GVArrayPtr get_input_attribute(const StringRef name,
|
|
const GeometryComponent &component,
|
|
const AttributeDomain domain,
|
|
const CustomDataType type,
|
|
const void *default_value) const;
|
|
|
|
template<typename T>
|
|
GVArray_Typed<T> get_input_attribute(const StringRef name,
|
|
const GeometryComponent &component,
|
|
const AttributeDomain domain,
|
|
const T &default_value) const
|
|
{
|
|
const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>());
|
|
GVArrayPtr varray = this->get_input_attribute(name, component, domain, type, &default_value);
|
|
return GVArray_Typed<T>(std::move(varray));
|
|
}
|
|
|
|
/**
|
|
* Get the type of an input property or the associated constant socket types with the
|
|
* same names. Fall back to the default value if no attribute exists with the name.
|
|
*/
|
|
CustomDataType get_input_attribute_data_type(const StringRef name,
|
|
const GeometryComponent &component,
|
|
const CustomDataType default_type) const;
|
|
|
|
AttributeDomain get_highest_priority_input_domain(Span<std::string> names,
|
|
const GeometryComponent &component,
|
|
const AttributeDomain default_domain) const;
|
|
|
|
private:
|
|
/* Utilities for detecting common errors at when using this class. */
|
|
void check_input_access(StringRef identifier, const CPPType *requested_type = nullptr) const;
|
|
void check_output_access(StringRef identifier, const CPPType &value_type) const;
|
|
|
|
/* Find the active socket socket with the input name (not the identifier). */
|
|
const bNodeSocket *find_available_socket(const StringRef name) const;
|
|
};
|
|
|
|
} // namespace blender::nodes
|