Previously, the modifier name was used to identify it in a compute context or viewer path. Using `ModifierData.persistent_uid` (which was only introduced later) has two main benefits: * It is stable even when the modifier name changes. * It's cheaper and easier to work with since it's just an integer instead of a string. Note: Pinned viewer nodes will need to be re-pinned after the change. Pull Request: https://projects.blender.org/blender/blender/pulls/138864
415 lines
15 KiB
C++
415 lines
15 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "BKE_lib_query.hh"
|
|
#include "BKE_lib_remap.hh"
|
|
#include "BKE_viewer_path.hh"
|
|
|
|
#include "BLI_index_range.hh"
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_string.h"
|
|
#include "BLI_string_ref.hh"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLO_read_write.hh"
|
|
|
|
using blender::IndexRange;
|
|
using blender::StringRef;
|
|
|
|
void BKE_viewer_path_init(ViewerPath *viewer_path)
|
|
{
|
|
BLI_listbase_clear(&viewer_path->path);
|
|
}
|
|
|
|
void BKE_viewer_path_clear(ViewerPath *viewer_path)
|
|
{
|
|
LISTBASE_FOREACH_MUTABLE (ViewerPathElem *, elem, &viewer_path->path) {
|
|
BKE_viewer_path_elem_free(elem);
|
|
}
|
|
BLI_listbase_clear(&viewer_path->path);
|
|
}
|
|
|
|
void BKE_viewer_path_copy(ViewerPath *dst, const ViewerPath *src)
|
|
{
|
|
BKE_viewer_path_init(dst);
|
|
LISTBASE_FOREACH (const ViewerPathElem *, src_elem, &src->path) {
|
|
ViewerPathElem *new_elem = BKE_viewer_path_elem_copy(src_elem);
|
|
BLI_addtail(&dst->path, new_elem);
|
|
}
|
|
}
|
|
|
|
bool BKE_viewer_path_equal(const ViewerPath *a,
|
|
const ViewerPath *b,
|
|
const ViewerPathEqualFlag flag)
|
|
{
|
|
const ViewerPathElem *elem_a = static_cast<const ViewerPathElem *>(a->path.first);
|
|
const ViewerPathElem *elem_b = static_cast<const ViewerPathElem *>(b->path.first);
|
|
|
|
while (elem_a != nullptr && elem_b != nullptr) {
|
|
if (!BKE_viewer_path_elem_equal(elem_a, elem_b, flag)) {
|
|
return false;
|
|
}
|
|
elem_a = elem_a->next;
|
|
elem_b = elem_b->next;
|
|
}
|
|
if (elem_a == nullptr && elem_b == nullptr) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void BKE_viewer_path_blend_write(BlendWriter *writer, const ViewerPath *viewer_path)
|
|
{
|
|
LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
|
|
switch (ViewerPathElemType(elem->type)) {
|
|
case VIEWER_PATH_ELEM_TYPE_ID: {
|
|
const auto *typed_elem = reinterpret_cast<IDViewerPathElem *>(elem);
|
|
BLO_write_struct(writer, IDViewerPathElem, typed_elem);
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
|
|
const auto *typed_elem = reinterpret_cast<ModifierViewerPathElem *>(elem);
|
|
BLO_write_struct(writer, ModifierViewerPathElem, typed_elem);
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
|
const auto *typed_elem = reinterpret_cast<GroupNodeViewerPathElem *>(elem);
|
|
BLO_write_struct(writer, GroupNodeViewerPathElem, typed_elem);
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
|
const auto *typed_elem = reinterpret_cast<SimulationZoneViewerPathElem *>(elem);
|
|
BLO_write_struct(writer, SimulationZoneViewerPathElem, typed_elem);
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
|
const auto *typed_elem = reinterpret_cast<ViewerNodeViewerPathElem *>(elem);
|
|
BLO_write_struct(writer, ViewerNodeViewerPathElem, typed_elem);
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
|
|
const auto *typed_elem = reinterpret_cast<RepeatZoneViewerPathElem *>(elem);
|
|
BLO_write_struct(writer, RepeatZoneViewerPathElem, typed_elem);
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_FOREACH_GEOMETRY_ELEMENT_ZONE: {
|
|
const auto *typed_elem = reinterpret_cast<ForeachGeometryElementZoneViewerPathElem *>(
|
|
elem);
|
|
BLO_write_struct(writer, ForeachGeometryElementZoneViewerPathElem, typed_elem);
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_EVALUATE_CLOSURE: {
|
|
const auto *typed_elem = reinterpret_cast<EvaluateClosureNodeViewerPathElem *>(elem);
|
|
BLO_write_struct(writer, EvaluateClosureNodeViewerPathElem, typed_elem);
|
|
break;
|
|
}
|
|
}
|
|
BLO_write_string(writer, elem->ui_name);
|
|
}
|
|
}
|
|
|
|
void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer_path)
|
|
{
|
|
BLO_read_struct_list(reader, ViewerPathElem, &viewer_path->path);
|
|
LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
|
|
BLO_read_string(reader, &elem->ui_name);
|
|
switch (ViewerPathElemType(elem->type)) {
|
|
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
|
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
|
|
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_FOREACH_GEOMETRY_ELEMENT_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_EVALUATE_CLOSURE:
|
|
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
|
|
case VIEWER_PATH_ELEM_TYPE_ID: {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_path)
|
|
{
|
|
LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
|
|
switch (ViewerPathElemType(elem->type)) {
|
|
case VIEWER_PATH_ELEM_TYPE_ID: {
|
|
auto *typed_elem = reinterpret_cast<IDViewerPathElem *>(elem);
|
|
BKE_LIB_FOREACHID_PROCESS_ID(data, typed_elem->id, IDWALK_CB_DIRECT_WEAK_LINK);
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_EVALUATE_CLOSURE: {
|
|
auto *typed_elem = reinterpret_cast<EvaluateClosureNodeViewerPathElem *>(elem);
|
|
BKE_LIB_FOREACHID_PROCESS_ID(
|
|
data, typed_elem->source_node_tree, IDWALK_CB_DIRECT_WEAK_LINK);
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
|
|
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
|
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
|
|
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_FOREACH_GEOMETRY_ELEMENT_ZONE: {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BKE_viewer_path_id_remap(ViewerPath *viewer_path,
|
|
const blender::bke::id::IDRemapper &mappings)
|
|
{
|
|
LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
|
|
switch (ViewerPathElemType(elem->type)) {
|
|
case VIEWER_PATH_ELEM_TYPE_ID: {
|
|
auto *typed_elem = reinterpret_cast<IDViewerPathElem *>(elem);
|
|
mappings.apply(&typed_elem->id, ID_REMAP_APPLY_DEFAULT);
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
|
|
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
|
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
|
|
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_FOREACH_GEOMETRY_ELEMENT_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_EVALUATE_CLOSURE: {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename T> static T *make_elem(const ViewerPathElemType type)
|
|
{
|
|
T *elem = MEM_callocN<T>(__func__);
|
|
elem->base.type = type;
|
|
return elem;
|
|
}
|
|
|
|
ViewerPathElem *BKE_viewer_path_elem_new(const ViewerPathElemType type)
|
|
{
|
|
switch (type) {
|
|
case VIEWER_PATH_ELEM_TYPE_ID: {
|
|
return &make_elem<IDViewerPathElem>(type)->base;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
|
|
return &make_elem<ModifierViewerPathElem>(type)->base;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
|
return &make_elem<GroupNodeViewerPathElem>(type)->base;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
|
return &make_elem<SimulationZoneViewerPathElem>(type)->base;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
|
return &make_elem<ViewerNodeViewerPathElem>(type)->base;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
|
|
return &make_elem<RepeatZoneViewerPathElem>(type)->base;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_FOREACH_GEOMETRY_ELEMENT_ZONE: {
|
|
return &make_elem<ForeachGeometryElementZoneViewerPathElem>(type)->base;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_EVALUATE_CLOSURE: {
|
|
return &make_elem<EvaluateClosureNodeViewerPathElem>(type)->base;
|
|
}
|
|
}
|
|
BLI_assert_unreachable();
|
|
return nullptr;
|
|
}
|
|
|
|
IDViewerPathElem *BKE_viewer_path_elem_new_id()
|
|
{
|
|
return reinterpret_cast<IDViewerPathElem *>(BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_ID));
|
|
}
|
|
|
|
ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier()
|
|
{
|
|
return reinterpret_cast<ModifierViewerPathElem *>(
|
|
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_MODIFIER));
|
|
}
|
|
|
|
GroupNodeViewerPathElem *BKE_viewer_path_elem_new_group_node()
|
|
{
|
|
return reinterpret_cast<GroupNodeViewerPathElem *>(
|
|
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_GROUP_NODE));
|
|
}
|
|
|
|
SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone()
|
|
{
|
|
return reinterpret_cast<SimulationZoneViewerPathElem *>(
|
|
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE));
|
|
}
|
|
|
|
ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node()
|
|
{
|
|
return reinterpret_cast<ViewerNodeViewerPathElem *>(
|
|
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_VIEWER_NODE));
|
|
}
|
|
|
|
RepeatZoneViewerPathElem *BKE_viewer_path_elem_new_repeat_zone()
|
|
{
|
|
return reinterpret_cast<RepeatZoneViewerPathElem *>(
|
|
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE));
|
|
}
|
|
|
|
ForeachGeometryElementZoneViewerPathElem *BKE_viewer_path_elem_new_foreach_geometry_element_zone()
|
|
{
|
|
return reinterpret_cast<ForeachGeometryElementZoneViewerPathElem *>(
|
|
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_FOREACH_GEOMETRY_ELEMENT_ZONE));
|
|
}
|
|
|
|
EvaluateClosureNodeViewerPathElem *BKE_viewer_path_elem_new_evaluate_closure()
|
|
{
|
|
return reinterpret_cast<EvaluateClosureNodeViewerPathElem *>(
|
|
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_EVALUATE_CLOSURE));
|
|
}
|
|
|
|
ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
|
|
{
|
|
ViewerPathElem *dst = BKE_viewer_path_elem_new(ViewerPathElemType(src->type));
|
|
if (src->ui_name) {
|
|
dst->ui_name = BLI_strdup(src->ui_name);
|
|
}
|
|
switch (ViewerPathElemType(src->type)) {
|
|
case VIEWER_PATH_ELEM_TYPE_ID: {
|
|
const auto *old_elem = reinterpret_cast<const IDViewerPathElem *>(src);
|
|
auto *new_elem = reinterpret_cast<IDViewerPathElem *>(dst);
|
|
new_elem->id = old_elem->id;
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
|
|
const auto *old_elem = reinterpret_cast<const ModifierViewerPathElem *>(src);
|
|
auto *new_elem = reinterpret_cast<ModifierViewerPathElem *>(dst);
|
|
new_elem->modifier_uid = old_elem->modifier_uid;
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
|
const auto *old_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(src);
|
|
auto *new_elem = reinterpret_cast<GroupNodeViewerPathElem *>(dst);
|
|
new_elem->node_id = old_elem->node_id;
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
|
const auto *old_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(src);
|
|
auto *new_elem = reinterpret_cast<SimulationZoneViewerPathElem *>(dst);
|
|
new_elem->sim_output_node_id = old_elem->sim_output_node_id;
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
|
const auto *old_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(src);
|
|
auto *new_elem = reinterpret_cast<ViewerNodeViewerPathElem *>(dst);
|
|
new_elem->node_id = old_elem->node_id;
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
|
|
const auto *old_elem = reinterpret_cast<const RepeatZoneViewerPathElem *>(src);
|
|
auto *new_elem = reinterpret_cast<RepeatZoneViewerPathElem *>(dst);
|
|
new_elem->repeat_output_node_id = old_elem->repeat_output_node_id;
|
|
new_elem->iteration = old_elem->iteration;
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_FOREACH_GEOMETRY_ELEMENT_ZONE: {
|
|
const auto *old_elem = reinterpret_cast<const ForeachGeometryElementZoneViewerPathElem *>(
|
|
src);
|
|
auto *new_elem = reinterpret_cast<ForeachGeometryElementZoneViewerPathElem *>(dst);
|
|
new_elem->zone_output_node_id = old_elem->zone_output_node_id;
|
|
new_elem->index = old_elem->index;
|
|
break;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_EVALUATE_CLOSURE: {
|
|
const auto *old_elem = reinterpret_cast<const EvaluateClosureNodeViewerPathElem *>(src);
|
|
auto *new_elem = reinterpret_cast<EvaluateClosureNodeViewerPathElem *>(dst);
|
|
new_elem->source_output_node_id = old_elem->source_output_node_id;
|
|
new_elem->evaluate_node_id = old_elem->evaluate_node_id;
|
|
new_elem->source_node_tree = old_elem->source_node_tree;
|
|
break;
|
|
}
|
|
}
|
|
return dst;
|
|
}
|
|
|
|
bool BKE_viewer_path_elem_equal(const ViewerPathElem *a,
|
|
const ViewerPathElem *b,
|
|
const ViewerPathEqualFlag flag)
|
|
{
|
|
if (a->type != b->type) {
|
|
return false;
|
|
}
|
|
if (flag & VIEWER_PATH_EQUAL_FLAG_CONSIDER_UI_NAME) {
|
|
if (StringRef(a->ui_name) != StringRef(b->ui_name)) {
|
|
return false;
|
|
}
|
|
}
|
|
switch (ViewerPathElemType(a->type)) {
|
|
case VIEWER_PATH_ELEM_TYPE_ID: {
|
|
const auto *a_elem = reinterpret_cast<const IDViewerPathElem *>(a);
|
|
const auto *b_elem = reinterpret_cast<const IDViewerPathElem *>(b);
|
|
return a_elem->id == b_elem->id;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
|
|
const auto *a_elem = reinterpret_cast<const ModifierViewerPathElem *>(a);
|
|
const auto *b_elem = reinterpret_cast<const ModifierViewerPathElem *>(b);
|
|
return a_elem->modifier_uid == b_elem->modifier_uid;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
|
|
const auto *a_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(a);
|
|
const auto *b_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(b);
|
|
return a_elem->node_id == b_elem->node_id;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
|
|
const auto *a_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(a);
|
|
const auto *b_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(b);
|
|
return a_elem->sim_output_node_id == b_elem->sim_output_node_id;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
|
|
const auto *a_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(a);
|
|
const auto *b_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(b);
|
|
return a_elem->node_id == b_elem->node_id;
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE: {
|
|
const auto *a_elem = reinterpret_cast<const RepeatZoneViewerPathElem *>(a);
|
|
const auto *b_elem = reinterpret_cast<const RepeatZoneViewerPathElem *>(b);
|
|
return a_elem->repeat_output_node_id == b_elem->repeat_output_node_id &&
|
|
((flag & VIEWER_PATH_EQUAL_FLAG_IGNORE_ITERATION) != 0 ||
|
|
a_elem->iteration == b_elem->iteration);
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_FOREACH_GEOMETRY_ELEMENT_ZONE: {
|
|
const auto *a_elem = reinterpret_cast<const ForeachGeometryElementZoneViewerPathElem *>(a);
|
|
const auto *b_elem = reinterpret_cast<const ForeachGeometryElementZoneViewerPathElem *>(b);
|
|
return a_elem->zone_output_node_id == b_elem->zone_output_node_id &&
|
|
((flag & VIEWER_PATH_EQUAL_FLAG_IGNORE_ITERATION) != 0 ||
|
|
a_elem->index == b_elem->index);
|
|
}
|
|
case VIEWER_PATH_ELEM_TYPE_EVALUATE_CLOSURE: {
|
|
const auto *a_elem = reinterpret_cast<const EvaluateClosureNodeViewerPathElem *>(a);
|
|
const auto *b_elem = reinterpret_cast<const EvaluateClosureNodeViewerPathElem *>(b);
|
|
return a_elem->source_output_node_id == b_elem->source_output_node_id &&
|
|
a_elem->evaluate_node_id == b_elem->evaluate_node_id &&
|
|
a_elem->source_node_tree == b_elem->source_node_tree;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void BKE_viewer_path_elem_free(ViewerPathElem *elem)
|
|
{
|
|
switch (ViewerPathElemType(elem->type)) {
|
|
case VIEWER_PATH_ELEM_TYPE_ID:
|
|
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
|
|
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
|
|
case VIEWER_PATH_ELEM_TYPE_REPEAT_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_FOREACH_GEOMETRY_ELEMENT_ZONE:
|
|
case VIEWER_PATH_ELEM_TYPE_EVALUATE_CLOSURE: {
|
|
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
|
|
break;
|
|
}
|
|
}
|
|
if (elem->ui_name) {
|
|
MEM_freeN(elem->ui_name);
|
|
}
|
|
MEM_freeN(elem);
|
|
}
|