Simulation nodes: UI for simulation state items in sidebar #106919
|
@ -16,6 +16,8 @@
|
|||
#ifdef __cplusplus
|
||||
namespace blender {
|
||||
template<typename T> class Span;
|
||||
template<typename T> class MutableSpan;
|
||||
class IndexRange;
|
||||
class StringRef;
|
||||
class StringRefNull;
|
||||
} // namespace blender
|
||||
|
@ -1616,6 +1618,12 @@ typedef struct NodeGeometrySimulationOutput {
|
|||
/* Number to give unique IDs to state items. */
|
||||
int next_identifier;
|
||||
int _pad;
|
||||
|
||||
#ifdef __cplusplus
|
||||
blender::Span<NodeSimulationItem> items_span() const;
|
||||
blender::MutableSpan<NodeSimulationItem> items_mutable_span();
|
||||
blender::IndexRange items_range() const;
|
||||
#endif
|
||||
} NodeGeometrySimulationOutput;
|
||||
|
||||
typedef struct NodeGeometryDistributePointsInVolume {
|
||||
|
|
|
@ -55,7 +55,7 @@ static bool simulation_items_unique_name_check(void *arg, const char *name)
|
|||
{
|
||||
const SimulationItemsUniqueNameArgs &args = *static_cast<const SimulationItemsUniqueNameArgs *>(
|
||||
arg);
|
||||
for (const NodeSimulationItem &item : Span(args.sim->items, args.sim->items_num)) {
|
||||
for (const NodeSimulationItem &item : args.sim->items_span()) {
|
||||
if (&item != args.item) {
|
||||
if (STREQ(item.name, name)) {
|
||||
|
||||
return true;
|
||||
|
@ -319,7 +319,24 @@ void register_node_type_geo_simulation_output()
|
|||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
||||
bool NOD_geometry_simulation_output_item_socket_type_supported(const eNodeSocketDatatype socket_type) {
|
||||
blender::Span<NodeSimulationItem> NodeGeometrySimulationOutput::items_span() const
|
||||
{
|
||||
return blender::Span<NodeSimulationItem>(items, items_num);
|
||||
}
|
||||
Hans Goudey
commented
`NOD_geometry_simulation_output_find_node_by_data` is unused, and it doesn't seem like we should need this. If we do, I'd keep it local to RNA.
Lukas Tönne
commented
Downside of putting this in RNA is that we don't have access to the C++ functions like Downside of putting this in RNA is that we don't have access to the C++ functions like `ntree->nodes_by_type` there.
Lukas Tönne
commented
Removed the unused function though. Removed the unused function though.
|
||||
|
||||
blender::MutableSpan<NodeSimulationItem> NodeGeometrySimulationOutput::items_mutable_span()
|
||||
Hans Goudey
commented
I guess this is slightly different, but usually a method like this is called I guess this is slightly different, but usually a method like this is called `items_for_write()`. Either way is fine with me.
Lukas Tönne
commented
We already have We already have `NodeSimulationItem *items` for the array, so `Span<NodeSimulationItem> items()` is a conflict, otherwise `items` + `items_for_write` would work.
Lukas Tönne
commented
I opted for I opted for `items_span_for_write` now, if that's ok for you.
|
||||
{
|
||||
return blender::MutableSpan<NodeSimulationItem>(items, items_num);
|
||||
}
|
||||
|
||||
blender::IndexRange NodeGeometrySimulationOutput::items_range() const
|
||||
{
|
||||
return blender::IndexRange(items_num);
|
||||
}
|
||||
|
||||
bool NOD_geometry_simulation_output_item_socket_type_supported(
|
||||
const eNodeSocketDatatype socket_type)
|
||||
{
|
||||
Hans Goudey
commented
These functions should call These functions should call `ensure_topology_cache()` before they use it.
|
||||
return ELEM(socket_type, SOCK_GEOMETRY);
|
||||
}
|
||||
|
||||
|
@ -329,7 +346,7 @@ bNode *NOD_geometry_simulation_output_find_node_by_item(bNodeTree *ntree,
|
|||
ntree->ensure_topology_cache();
|
||||
for (bNode *node : ntree->nodes_by_type("GeometryNodeSimulationOutput")) {
|
||||
NodeGeometrySimulationOutput *sim = static_cast<NodeGeometrySimulationOutput *>(node->storage);
|
||||
if (NOD_geometry_simulation_output_contains_item(sim, item)) {
|
||||
if (sim->items_span().contains_ptr(item)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
@ -358,14 +375,13 @@ bool NOD_geometry_simulation_output_item_set_unique_name(NodeGeometrySimulationO
|
|||
bool NOD_geometry_simulation_output_contains_item(NodeGeometrySimulationOutput *sim,
|
||||
const NodeSimulationItem *item)
|
||||
{
|
||||
Hans Goudey
commented
A consistency suggestion: switch to return early in failure case, which is more common, and use
A consistency suggestion: switch to return early in failure case, which is more common, and use `index_range.contains()`:
```
if (!IndexRange(sim->items_num).contains(sim->active_index)) {
return nullptr;
}
return &sim->items[sim->active_index];
```
|
||||
const int index = item - sim->items;
|
||||
return index >= 0 && index < sim->items_num;
|
||||
return sim->items_span().contains_ptr(item);
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_get_active_item(
|
||||
NodeGeometrySimulationOutput *sim)
|
||||
{
|
||||
if (sim->active_index >= 0 && sim->active_index < sim->items_num) {
|
||||
if (sim->items_range().contains(sim->active_index)) {
|
||||
return &sim->items[sim->active_index];
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -374,18 +390,17 @@ NodeSimulationItem *NOD_geometry_simulation_output_get_active_item(
|
|||
void NOD_geometry_simulation_output_set_active_item(NodeGeometrySimulationOutput *sim,
|
||||
NodeSimulationItem *item)
|
||||
{
|
||||
const int index = item - sim->items;
|
||||
if (index >= 0 && index < sim->items_num) {
|
||||
sim->active_index = index;
|
||||
if (sim->items_span().contains_ptr(item)) {
|
||||
sim->active_index = item - sim->items;
|
||||
}
|
||||
Hans Goudey
commented
```
for (NodeSimulationItem &item : blender::Span(sim->items, sim->items_num)) {
if (STREQ(item.name, name)) {
return &item;
}
}
```
|
||||
}
|
||||
|
||||
NodeSimulationItem *NOD_geometry_simulation_output_find_item(NodeGeometrySimulationOutput *sim,
|
||||
const char *name)
|
||||
{
|
||||
for (const int i : blender::IndexRange(sim->items_num)) {
|
||||
if (STREQ(sim->items[i].name, name)) {
|
||||
return &sim->items[i];
|
||||
for (NodeSimulationItem &item : sim->items_mutable_span()) {
|
||||
if (STREQ(item.name, name)) {
|
||||
return &item;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -405,7 +420,7 @@ NodeSimulationItem *NOD_geometry_simulation_output_insert_item(NodeGeometrySimul
|
|||
{
|
||||
NodeSimulationItem *old_items = sim->items;
|
||||
sim->items = MEM_cnew_array<NodeSimulationItem>(sim->items_num + 1, __func__);
|
||||
for (const int i : blender::IndexRange(0, index)) {
|
||||
for (const int i : blender::IndexRange(index)) {
|
||||
sim->items[i] = old_items[i];
|
||||
}
|
||||
for (const int i : blender::IndexRange(index, sim->items_num - index)) {
|
||||
|
@ -453,7 +468,7 @@ void NOD_geometry_simulation_output_remove_item(NodeGeometrySimulationOutput *si
|
|||
|
||||
NodeSimulationItem *old_items = sim->items;
|
||||
sim->items = MEM_cnew_array<NodeSimulationItem>(sim->items_num - 1, __func__);
|
||||
for (const int i : blender::IndexRange(0, index)) {
|
||||
for (const int i : blender::IndexRange(index)) {
|
||||
sim->items[i] = old_items[i];
|
||||
}
|
||||
for (const int i : blender::IndexRange(index, sim->items_num - index).drop_front(1)) {
|
||||
|
@ -468,7 +483,7 @@ void NOD_geometry_simulation_output_remove_item(NodeGeometrySimulationOutput *si
|
|||
|
||||
void NOD_geometry_simulation_output_clear_items(struct NodeGeometrySimulationOutput *sim)
|
||||
{
|
||||
for (NodeSimulationItem &item : blender::MutableSpan(sim->items, sim->items_num)) {
|
||||
for (NodeSimulationItem &item : sim->items_mutable_span()) {
|
||||
MEM_SAFE_FREE(item.name);
|
||||
}
|
||||
MEM_SAFE_FREE(sim->items);
|
||||
|
|
This function is now also used to check for uniqueness of items that are already in the list. This check avoids detecting duplicates from the same socket.