2023-08-15 16:20:26 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2022-10-17 11:39:40 +02:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
* \ingroup bke
|
|
|
|
*
|
2022-10-19 03:52:55 +02:00
|
|
|
* #Instances is a container for geometry instances. It fulfills some key requirements:
|
2022-10-17 11:39:40 +02:00
|
|
|
* - Support nested instances.
|
|
|
|
* - Support instance attributes.
|
|
|
|
* - Support referencing different kinds of instances (objects, collections, geometry sets).
|
|
|
|
* - Support efficiently iterating over the instanced geometries, i.e. without have to iterate over
|
|
|
|
* all instances.
|
|
|
|
*
|
|
|
|
* #Instances has an ordered set of #InstanceReference. An #InstanceReference contains information
|
|
|
|
* about a particular instanced geometry. Each #InstanceReference has a handle (integer index)
|
|
|
|
* which is then stored per instance. Many instances can use the same #InstanceReference.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <mutex>
|
|
|
|
|
2023-02-06 21:25:45 +01:00
|
|
|
#include "BLI_math_matrix_types.hh"
|
2022-10-17 11:39:40 +02:00
|
|
|
#include "BLI_vector.hh"
|
|
|
|
#include "BLI_vector_set.hh"
|
|
|
|
|
|
|
|
#include "BKE_attribute.hh"
|
|
|
|
|
|
|
|
struct Object;
|
|
|
|
struct Collection;
|
|
|
|
|
|
|
|
namespace blender::bke {
|
|
|
|
|
2023-06-15 22:18:28 +02:00
|
|
|
struct GeometrySet;
|
|
|
|
|
2022-10-17 11:39:40 +02:00
|
|
|
/**
|
|
|
|
* Holds a reference to conceptually unique geometry or a pointer to object/collection data
|
|
|
|
* that is instanced with a transform in #Instances.
|
|
|
|
*/
|
|
|
|
class InstanceReference {
|
|
|
|
public:
|
|
|
|
enum class Type {
|
|
|
|
/**
|
|
|
|
* An empty instance. This allows an `InstanceReference` to be default constructed without
|
|
|
|
* being in an invalid state. There might also be other use cases that we haven't explored
|
|
|
|
* much yet (such as changing the instance later on, and "disabling" some instances).
|
|
|
|
*/
|
|
|
|
None,
|
|
|
|
Object,
|
|
|
|
Collection,
|
|
|
|
GeometrySet,
|
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
Type type_ = Type::None;
|
|
|
|
/** Depending on the type this is either null, an Object or Collection pointer. */
|
|
|
|
void *data_ = nullptr;
|
|
|
|
std::unique_ptr<GeometrySet> geometry_set_;
|
|
|
|
|
|
|
|
public:
|
|
|
|
InstanceReference() = default;
|
|
|
|
InstanceReference(Object &object);
|
|
|
|
InstanceReference(Collection &collection);
|
|
|
|
InstanceReference(GeometrySet geometry_set);
|
2023-10-18 10:26:23 +02:00
|
|
|
InstanceReference(std::unique_ptr<GeometrySet> geometry_set);
|
2022-10-17 11:39:40 +02:00
|
|
|
|
|
|
|
InstanceReference(const InstanceReference &other);
|
|
|
|
InstanceReference(InstanceReference &&other);
|
|
|
|
|
|
|
|
InstanceReference &operator=(const InstanceReference &other);
|
|
|
|
InstanceReference &operator=(InstanceReference &&other);
|
|
|
|
|
|
|
|
Type type() const;
|
|
|
|
Object &object() const;
|
|
|
|
Collection &collection() const;
|
2023-10-07 23:10:43 +02:00
|
|
|
GeometrySet &geometry_set();
|
2022-10-17 11:39:40 +02:00
|
|
|
const GeometrySet &geometry_set() const;
|
|
|
|
|
|
|
|
bool owns_direct_data() const;
|
|
|
|
void ensure_owns_direct_data();
|
|
|
|
|
|
|
|
friend bool operator==(const InstanceReference &a, const InstanceReference &b);
|
|
|
|
};
|
|
|
|
|
|
|
|
class Instances {
|
|
|
|
private:
|
|
|
|
/**
|
2023-10-07 23:10:43 +02:00
|
|
|
* Contains the data that is used by the individual instances.
|
|
|
|
* Actual instances store an index ("handle") into this vector.
|
2022-10-17 11:39:40 +02:00
|
|
|
*/
|
2023-10-19 12:28:11 +02:00
|
|
|
Vector<InstanceReference> references_;
|
2022-10-17 11:39:40 +02:00
|
|
|
|
|
|
|
/** Indices into `references_`. Determines what data is instanced. */
|
2023-10-19 12:28:11 +02:00
|
|
|
Vector<int> reference_handles_;
|
2022-10-17 11:39:40 +02:00
|
|
|
/** Transformation of the instances. */
|
2023-10-19 12:28:11 +02:00
|
|
|
Vector<float4x4> transforms_;
|
2022-10-17 11:39:40 +02:00
|
|
|
|
|
|
|
/* These almost unique ids are generated based on the `id` attribute, which might not contain
|
|
|
|
* unique ids at all. They are *almost* unique, because under certain very unlikely
|
|
|
|
* circumstances, they are not unique. Code using these ids should not crash when they are not
|
|
|
|
* unique but can generally expect them to be unique. */
|
|
|
|
mutable std::mutex almost_unique_ids_mutex_;
|
2023-10-19 12:28:11 +02:00
|
|
|
mutable Array<int> almost_unique_ids_;
|
2022-10-17 11:39:40 +02:00
|
|
|
|
2023-10-16 18:41:07 +02:00
|
|
|
CustomData attributes_;
|
2022-10-17 11:39:40 +02:00
|
|
|
|
|
|
|
public:
|
2023-10-16 18:41:07 +02:00
|
|
|
Instances();
|
|
|
|
Instances(Instances &&other);
|
2022-10-17 11:39:40 +02:00
|
|
|
Instances(const Instances &other);
|
2023-10-16 18:41:07 +02:00
|
|
|
~Instances();
|
|
|
|
|
|
|
|
Instances &operator=(const Instances &other);
|
|
|
|
Instances &operator=(Instances &&other);
|
2022-10-17 11:39:40 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Resize the transform, handles, and attributes to the specified capacity.
|
|
|
|
*
|
|
|
|
* \note This function should be used carefully, only when it's guaranteed
|
|
|
|
* that the data will be filled.
|
|
|
|
*/
|
|
|
|
void resize(int capacity);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a handle for the given reference.
|
|
|
|
* If the reference exists already, the handle of the existing reference is returned.
|
|
|
|
* Otherwise a new handle is added.
|
|
|
|
*/
|
|
|
|
int add_reference(const InstanceReference &reference);
|
2023-10-07 23:10:43 +02:00
|
|
|
std::optional<int> find_reference_handle(const InstanceReference &query);
|
2022-10-17 11:39:40 +02:00
|
|
|
/**
|
|
|
|
* Add a reference to the instance reference with an index specified by the #instance_handle
|
|
|
|
* argument. For adding many instances, using #resize and accessing the transform array
|
|
|
|
* directly is preferred.
|
|
|
|
*/
|
2023-10-19 12:28:11 +02:00
|
|
|
void add_instance(int instance_handle, const float4x4 &transform);
|
2022-10-17 11:39:40 +02:00
|
|
|
|
2023-10-19 12:28:11 +02:00
|
|
|
Span<InstanceReference> references() const;
|
2022-10-17 11:39:40 +02:00
|
|
|
void remove_unused_references();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If references have a collection or object type, convert them into geometry instances
|
|
|
|
* recursively. After that, the geometry sets can be edited. There may still be instances of
|
|
|
|
* other types of they can't be converted to geometry sets.
|
|
|
|
*/
|
|
|
|
void ensure_geometry_instances();
|
|
|
|
/**
|
|
|
|
* With write access to the instances component, the data in the instanced geometry sets can be
|
|
|
|
* changed. This is a function on the component rather than each reference to ensure `const`
|
|
|
|
* correctness for that reason.
|
|
|
|
*/
|
|
|
|
GeometrySet &geometry_set_from_reference(int reference_index);
|
|
|
|
|
2023-10-19 12:28:11 +02:00
|
|
|
Span<int> reference_handles() const;
|
|
|
|
MutableSpan<int> reference_handles();
|
|
|
|
MutableSpan<float4x4> transforms();
|
|
|
|
Span<float4x4> transforms() const;
|
2022-10-17 11:39:40 +02:00
|
|
|
|
|
|
|
int instances_num() const;
|
|
|
|
int references_num() const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove the indices that are not contained in the mask input, and remove unused instance
|
|
|
|
* references afterwards.
|
|
|
|
*/
|
2023-10-19 12:28:11 +02:00
|
|
|
void remove(const IndexMask &mask, const AnonymousAttributePropagationInfo &propagation_info);
|
2022-10-17 11:39:40 +02:00
|
|
|
/**
|
|
|
|
* Get an id for every instance. These can be used for e.g. motion blur.
|
|
|
|
*/
|
2023-10-19 12:28:11 +02:00
|
|
|
Span<int> almost_unique_ids() const;
|
2022-10-17 11:39:40 +02:00
|
|
|
|
2023-10-19 12:28:11 +02:00
|
|
|
bke::AttributeAccessor attributes() const;
|
|
|
|
bke::MutableAttributeAccessor attributes_for_write();
|
2022-10-17 11:39:40 +02:00
|
|
|
|
2023-10-16 16:39:39 +02:00
|
|
|
CustomData &custom_data_attributes();
|
|
|
|
const CustomData &custom_data_attributes() const;
|
2022-10-17 11:39:40 +02:00
|
|
|
|
|
|
|
void foreach_referenced_geometry(
|
2023-10-19 12:28:11 +02:00
|
|
|
FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
|
2022-10-17 11:39:40 +02:00
|
|
|
|
|
|
|
bool owns_direct_data() const;
|
|
|
|
void ensure_owns_direct_data();
|
|
|
|
};
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name #InstanceReference Inline Methods
|
|
|
|
* \{ */
|
|
|
|
|
2023-10-18 10:26:23 +02:00
|
|
|
inline InstanceReference::InstanceReference(std::unique_ptr<GeometrySet> geometry_set)
|
|
|
|
: type_(Type::GeometrySet), data_(nullptr), geometry_set_(std::move(geometry_set))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-10-17 11:39:40 +02:00
|
|
|
inline InstanceReference::InstanceReference(Object &object) : type_(Type::Object), data_(&object)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
inline InstanceReference::InstanceReference(Collection &collection)
|
|
|
|
: type_(Type::Collection), data_(&collection)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
inline InstanceReference::InstanceReference(const InstanceReference &other)
|
|
|
|
: type_(other.type_), data_(other.data_)
|
|
|
|
{
|
|
|
|
if (other.geometry_set_) {
|
|
|
|
geometry_set_ = std::make_unique<GeometrySet>(*other.geometry_set_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline InstanceReference::InstanceReference(InstanceReference &&other)
|
|
|
|
: type_(other.type_), data_(other.data_), geometry_set_(std::move(other.geometry_set_))
|
|
|
|
{
|
|
|
|
other.type_ = Type::None;
|
|
|
|
other.data_ = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline InstanceReference &InstanceReference::operator=(const InstanceReference &other)
|
|
|
|
{
|
|
|
|
if (this == &other) {
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
this->~InstanceReference();
|
|
|
|
new (this) InstanceReference(other);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline InstanceReference &InstanceReference::operator=(InstanceReference &&other)
|
|
|
|
{
|
|
|
|
if (this == &other) {
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
this->~InstanceReference();
|
|
|
|
new (this) InstanceReference(std::move(other));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline InstanceReference::Type InstanceReference::type() const
|
|
|
|
{
|
|
|
|
return type_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Object &InstanceReference::object() const
|
|
|
|
{
|
|
|
|
BLI_assert(type_ == Type::Object);
|
|
|
|
return *(Object *)data_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Collection &InstanceReference::collection() const
|
|
|
|
{
|
|
|
|
BLI_assert(type_ == Type::Collection);
|
|
|
|
return *(Collection *)data_;
|
|
|
|
}
|
|
|
|
|
2023-10-07 23:10:43 +02:00
|
|
|
inline GeometrySet &InstanceReference::geometry_set()
|
|
|
|
{
|
|
|
|
BLI_assert(type_ == Type::GeometrySet);
|
|
|
|
return *geometry_set_;
|
|
|
|
}
|
|
|
|
|
2022-10-17 11:39:40 +02:00
|
|
|
inline const GeometrySet &InstanceReference::geometry_set() const
|
|
|
|
{
|
|
|
|
BLI_assert(type_ == Type::GeometrySet);
|
|
|
|
return *geometry_set_;
|
|
|
|
}
|
|
|
|
|
2023-10-16 16:39:39 +02:00
|
|
|
inline CustomData &Instances::custom_data_attributes()
|
2022-10-17 11:39:40 +02:00
|
|
|
{
|
2023-10-16 18:41:07 +02:00
|
|
|
return attributes_;
|
2022-10-17 11:39:40 +02:00
|
|
|
}
|
|
|
|
|
2023-10-16 16:39:39 +02:00
|
|
|
inline const CustomData &Instances::custom_data_attributes() const
|
2022-10-17 11:39:40 +02:00
|
|
|
{
|
2023-10-16 18:41:07 +02:00
|
|
|
return attributes_;
|
2022-10-17 11:39:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
} // namespace blender::bke
|