Add support for attributes storage in simulation state #107133
|
@ -13,21 +13,89 @@ class SimulationStateItem {
|
|||
virtual ~SimulationStateItem() = default;
|
||||
};
|
||||
|
||||
class GeometrySimulationStateItem : public SimulationStateItem {
|
||||
template <typename T>
|
||||
class TypedSimulationStateItem : public SimulationStateItem {
|
||||
public:
|
||||
using DataType = T;
|
||||
|
||||
private:
|
||||
GeometrySet geometry_;
|
||||
T data_;
|
||||
|
||||
public:
|
||||
GeometrySimulationStateItem(GeometrySet geometry) : geometry_(std::move(geometry))
|
||||
TypedSimulationStateItem() = default;
|
||||
TypedSimulationStateItem(const T &data)
|
||||
{
|
||||
data_ = std::move(data);
|
||||
}
|
||||
TypedSimulationStateItem(T &&data)
|
||||
{
|
||||
data_ = std::move(data);
|
||||
}
|
||||
template <typename U>
|
||||
TypedSimulationStateItem(const U &data)
|
||||
{
|
||||
data_ = data;
|
||||
}
|
||||
|
||||
const GeometrySet &geometry() const
|
||||
TypedSimulationStateItem(const TypedSimulationStateItem &) = delete;
|
||||
TypedSimulationStateItem(TypedSimulationStateItem &&) = delete;
|
||||
|
||||
virtual ~TypedSimulationStateItem() {
|
||||
}
|
||||
|
||||
TypedSimulationStateItem &operator=(const TypedSimulationStateItem &) = delete;
|
||||
TypedSimulationStateItem &operator=(TypedSimulationStateItem &&) = delete;
|
||||
|
||||
const T &data() const
|
||||
{
|
||||
return geometry_;
|
||||
return data_;
|
||||
}
|
||||
};
|
||||
|
||||
/** Specialization for GeometrySet which ensures the state owns the geometry data. */
|
||||
template <>
|
||||
class TypedSimulationStateItem<GeometrySet> : public SimulationStateItem {
|
||||
public:
|
||||
using DataType = GeometrySet;
|
||||
|
||||
private:
|
||||
GeometrySet data_;
|
||||
|
||||
public:
|
||||
TypedSimulationStateItem() = default;
|
||||
TypedSimulationStateItem(const GeometrySet &data)
|
||||
{
|
||||
data_ = std::move(data);
|
||||
data_.ensure_owns_direct_data();
|
||||
}
|
||||
TypedSimulationStateItem(GeometrySet &&data)
|
||||
{
|
||||
data_ = std::move(data);
|
||||
data_.ensure_owns_direct_data();
|
||||
}
|
||||
template <typename U>
|
||||
TypedSimulationStateItem(const U &data)
|
||||
{
|
||||
data_ = data;
|
||||
data_.ensure_owns_direct_data();
|
||||
}
|
||||
|
||||
TypedSimulationStateItem(const TypedSimulationStateItem &) = delete;
|
||||
TypedSimulationStateItem(TypedSimulationStateItem &&) = delete;
|
||||
|
||||
virtual ~TypedSimulationStateItem() {
|
||||
}
|
||||
|
||||
TypedSimulationStateItem &operator=(const TypedSimulationStateItem &) = delete;
|
||||
TypedSimulationStateItem &operator=(TypedSimulationStateItem &&) = delete;
|
||||
|
||||
const GeometrySet &data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SimulationZoneState {
|
||||
public:
|
||||
Vector<std::unique_ptr<SimulationStateItem>> items;
|
||||
|
|
|
@ -12,6 +12,128 @@
|
|||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
namespace blender::nodes {
|
||||
|
||||
template <typename T>
|
||||
static void copy_typed_initial_simulation_state(lf::Params ¶ms, int index)
|
||||
{
|
||||
T *data = params.try_get_input_data_ptr_or_request<T>(index);
|
||||
if (data != nullptr) {
|
||||
params.set_output(index + 1, std::move(*data));
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_initial_simulation_state(
|
||||
lf::Params ¶ms,
|
||||
int index,
|
||||
short socket_type)
|
||||
{
|
||||
switch (socket_type) {
|
||||
case SOCK_FLOAT:
|
||||
LukasTonne marked this conversation as resolved
|
||||
copy_typed_initial_simulation_state<ValueOrField<float>>(params, index);
|
||||
break;
|
||||
case SOCK_VECTOR:
|
||||
copy_typed_initial_simulation_state<ValueOrField<float3>>(params, index);
|
||||
break;
|
||||
case SOCK_RGBA:
|
||||
copy_typed_initial_simulation_state<ValueOrField<ColorGeometry4f>>(params, index);
|
||||
break;
|
||||
case SOCK_BOOLEAN:
|
||||
copy_typed_initial_simulation_state<ValueOrField<bool>>(params, index);
|
||||
break;
|
||||
case SOCK_INT:
|
||||
copy_typed_initial_simulation_state<ValueOrField<int>>(params, index);
|
||||
break;
|
||||
case SOCK_STRING:
|
||||
copy_typed_initial_simulation_state<ValueOrField<std::string>>(params, index);
|
||||
break;
|
||||
case SOCK_OBJECT:
|
||||
copy_typed_initial_simulation_state<Object *>(params, index);
|
||||
break;
|
||||
case SOCK_GEOMETRY:
|
||||
copy_typed_initial_simulation_state<GeometrySet>(params, index);
|
||||
break;
|
||||
case SOCK_COLLECTION:
|
||||
copy_typed_initial_simulation_state<Collection *>(params, index);
|
||||
break;
|
||||
case SOCK_TEXTURE:
|
||||
copy_typed_initial_simulation_state<Tex *>(params, index);
|
||||
break;
|
||||
case SOCK_IMAGE:
|
||||
copy_typed_initial_simulation_state<Image *>(params, index);
|
||||
break;
|
||||
case SOCK_MATERIAL:
|
||||
copy_typed_initial_simulation_state<Material *>(params, index);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
copy_typed_initial_simulation_state<GeometrySet>(params, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void copy_typed_next_simulation_state(lf::Params ¶ms,
|
||||
int index,
|
||||
const bke::sim::SimulationStateItem &state_item)
|
||||
{
|
||||
if (auto *typed_state_item = dynamic_cast<const bke::sim::TypedSimulationStateItem<T> *>(
|
||||
&state_item)) {
|
||||
params.set_output(index + 1, typed_state_item->data());
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_next_simulation_state(lf::Params ¶ms,
|
||||
int index,
|
||||
short socket_type,
|
||||
const bke::sim::SimulationStateItem &state_item)
|
||||
{
|
||||
switch (socket_type) {
|
||||
case SOCK_FLOAT:
|
||||
copy_typed_next_simulation_state<ValueOrField<float>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_VECTOR:
|
||||
copy_typed_next_simulation_state<ValueOrField<float3>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_RGBA:
|
||||
copy_typed_next_simulation_state<ValueOrField<ColorGeometry4f>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_BOOLEAN:
|
||||
copy_typed_next_simulation_state<ValueOrField<bool>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_INT:
|
||||
copy_typed_next_simulation_state<ValueOrField<int>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_STRING:
|
||||
copy_typed_next_simulation_state<ValueOrField<std::string>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_OBJECT:
|
||||
copy_typed_next_simulation_state<Object *>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_GEOMETRY:
|
||||
copy_typed_next_simulation_state<GeometrySet>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_COLLECTION:
|
||||
copy_typed_next_simulation_state<Collection *>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_TEXTURE:
|
||||
copy_typed_next_simulation_state<Tex *>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_IMAGE:
|
||||
copy_typed_next_simulation_state<Image *>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_MATERIAL:
|
||||
copy_typed_next_simulation_state<Material *>(params, index, state_item);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
copy_typed_next_simulation_state<GeometrySet>(params, index, state_item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace blender::nodes::node_geo_simulation_input_cc {
|
||||
|
||||
NODE_STORAGE_FUNCS(NodeGeometrySimulationInput);
|
||||
|
@ -63,10 +185,7 @@ class LazyFunctionForSimulationInputNode final : public LazyFunction {
|
|||
if (params.output_was_set(i + 1)) {
|
||||
continue;
|
||||
}
|
||||
GeometrySet *geometry = params.try_get_input_data_ptr_or_request<GeometrySet>(i);
|
||||
if (geometry != nullptr) {
|
||||
params.set_output(i + 1, std::move(*geometry));
|
||||
}
|
||||
copy_initial_simulation_state(params, i, simulation_items_[i].socket_type);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -75,10 +194,9 @@ class LazyFunctionForSimulationInputNode final : public LazyFunction {
|
|||
params.set_output(i + 1, GeometrySet());
|
||||
continue;
|
||||
}
|
||||
const bke::sim::SimulationStateItem *item = prev_zone_state->items[i].get();
|
||||
if (auto *geometry_item = dynamic_cast<const bke::sim::GeometrySimulationStateItem *>(
|
||||
item)) {
|
||||
params.set_output(i + 1, geometry_item->geometry());
|
||||
const bke::sim::SimulationStateItem *state_item = prev_zone_state->items[i].get();
|
||||
if (state_item != nullptr) {
|
||||
copy_next_simulation_state(params, i, simulation_items_[i].socket_type, *state_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,6 +155,112 @@ const CPPType &get_simulation_item_cpp_type(const NodeSimulationItem &item)
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::unique_ptr<bke::sim::TypedSimulationStateItem<T>> make_typed_simulation_state_item(lf::Params ¶ms, int index)
|
||||
{
|
||||
using bke::sim::TypedSimulationStateItem;
|
||||
|
||||
if (const T *data = params.try_get_input_data_ptr_or_request<T>(index)) {
|
||||
return std::make_unique<TypedSimulationStateItem<T>>(*data);
|
||||
}
|
||||
|
||||
return std::make_unique<TypedSimulationStateItem<T>>();
|
||||
}
|
||||
|
||||
static std::unique_ptr<bke::sim::SimulationStateItem> make_simulation_state_item(
|
||||
lf::Params ¶ms, int index, short socket_type)
|
||||
{
|
||||
switch (socket_type) {
|
||||
case SOCK_FLOAT:
|
||||
return make_typed_simulation_state_item<ValueOrField<float>>(params, index);
|
||||
case SOCK_VECTOR:
|
||||
return make_typed_simulation_state_item<ValueOrField<float3>>(params, index);
|
||||
case SOCK_RGBA:
|
||||
return make_typed_simulation_state_item<ValueOrField<ColorGeometry4f>>(params, index);
|
||||
case SOCK_BOOLEAN:
|
||||
return make_typed_simulation_state_item<ValueOrField<bool>>(params, index);
|
||||
case SOCK_INT:
|
||||
return make_typed_simulation_state_item<ValueOrField<int>>(params, index);
|
||||
case SOCK_STRING:
|
||||
return make_typed_simulation_state_item<ValueOrField<std::string>>(params, index);
|
||||
case SOCK_OBJECT:
|
||||
return make_typed_simulation_state_item<Object *>(params, index);
|
||||
case SOCK_GEOMETRY:
|
||||
return make_typed_simulation_state_item<GeometrySet>(params, index);
|
||||
case SOCK_COLLECTION:
|
||||
return make_typed_simulation_state_item<Collection *>(params, index);
|
||||
case SOCK_TEXTURE:
|
||||
return make_typed_simulation_state_item<Tex *>(params, index);
|
||||
case SOCK_IMAGE:
|
||||
return make_typed_simulation_state_item<Image *>(params, index);
|
||||
case SOCK_MATERIAL:
|
||||
return make_typed_simulation_state_item<Material *>(params, index);
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return make_typed_simulation_state_item<GeometrySet>(params, index);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void copy_typed_simulation_state_output(lf::Params ¶ms, int index, const bke::sim::SimulationStateItem &state_item)
|
||||
{
|
||||
using bke::sim::TypedSimulationStateItem;
|
||||
|
||||
if (auto *typed_state_item = dynamic_cast<const bke::sim::TypedSimulationStateItem<T> *>(&state_item)) {
|
||||
params.set_output(index, typed_state_item->data());
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_simulation_state_output(
|
||||
lf::Params ¶ms,
|
||||
int index,
|
||||
short socket_type,
|
||||
const bke::sim::SimulationStateItem &state_item)
|
||||
{
|
||||
switch (socket_type) {
|
||||
case SOCK_FLOAT:
|
||||
copy_typed_simulation_state_output<ValueOrField<float>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_VECTOR:
|
||||
copy_typed_simulation_state_output<ValueOrField<float3>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_RGBA:
|
||||
copy_typed_simulation_state_output<ValueOrField<ColorGeometry4f>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_BOOLEAN:
|
||||
copy_typed_simulation_state_output<ValueOrField<bool>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_INT:
|
||||
copy_typed_simulation_state_output<ValueOrField<int>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_STRING:
|
||||
copy_typed_simulation_state_output<ValueOrField<std::string>>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_OBJECT:
|
||||
copy_typed_simulation_state_output<Object *>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_GEOMETRY:
|
||||
copy_typed_simulation_state_output<GeometrySet>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_COLLECTION:
|
||||
copy_typed_simulation_state_output<Collection *>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_TEXTURE:
|
||||
copy_typed_simulation_state_output<Tex *>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_IMAGE:
|
||||
copy_typed_simulation_state_output<Image *>(params, index, state_item);
|
||||
break;
|
||||
case SOCK_MATERIAL:
|
||||
copy_typed_simulation_state_output<Material *>(params, index, state_item);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
copy_typed_simulation_state_output<GeometrySet>(params, index, state_item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
||||
namespace blender::nodes::node_geo_simulation_output_cc {
|
||||
|
@ -224,14 +330,15 @@ class LazyFunctionForSimulationOutputNode final : public LazyFunction {
|
|||
|
||||
bool all_available = true;
|
||||
for (const int i : simulation_items_.index_range()) {
|
||||
GeometrySet *input_geometry = params.try_get_input_data_ptr_or_request<GeometrySet>(i);
|
||||
if (input_geometry == nullptr) {
|
||||
const NodeSimulationItem &item = simulation_items_[i];
|
||||
|
||||
void *input_data = params.try_get_input_data_ptr_or_request(i);
|
||||
if (input_data == nullptr) {
|
||||
all_available = false;
|
||||
continue;
|
||||
}
|
||||
input_geometry->ensure_owns_direct_data();
|
||||
new_zone_state.items[i] = std::make_unique<bke::sim::GeometrySimulationStateItem>(
|
||||
std::move(*input_geometry));
|
||||
|
||||
new_zone_state.items[i] = make_simulation_state_item(params, i, item.socket_type);
|
||||
}
|
||||
|
||||
if (all_available) {
|
||||
|
@ -242,17 +349,16 @@ class LazyFunctionForSimulationOutputNode final : public LazyFunction {
|
|||
void output_cached_state(lf::Params ¶ms, const bke::sim::SimulationZoneState &state) const
|
||||
{
|
||||
for (const int i : simulation_items_.index_range()) {
|
||||
const NodeSimulationItem &item = simulation_items_[i];
|
||||
|
||||
if (i >= state.items.size()) {
|
||||
continue;
|
||||
}
|
||||
const bke::sim::SimulationStateItem *item = state.items[i].get();
|
||||
if (item == nullptr) {
|
||||
const bke::sim::SimulationStateItem *state_item = state.items[i].get();
|
||||
if (state_item == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (auto *geometry_item = dynamic_cast<const bke::sim::GeometrySimulationStateItem *>(
|
||||
item)) {
|
||||
params.set_output(i, geometry_item->geometry());
|
||||
}
|
||||
copy_simulation_state_output(params, i, item.socket_type, *state_item);
|
||||
}
|
||||
params.set_default_remaining_outputs();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Maybe I'm being stupid, but I don't get what's meant by "next" here.
Was just an ad-hoc name: it's copying from the simulation state into the output parameter for the next iteration. I'll add some comments.
Renamed the functions and added comments for clarity. Also the
copy_simulation_state_to_output_param
function is now shared by input and output node, they both need to do this: input node when preparing the next iteration, output node when outputting the sim result.