This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/nodes/NOD_geometry_exec.hh
2021-05-25 18:25:55 +10:00

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