2022-02-11 09:07:11 +11:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
* Copyright 2005 Blender Foundation. All rights reserved. */
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
|
* \ingroup modifiers
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2021-10-21 13:54:48 -05:00
|
|
|
#include "BLI_array.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BLI_listbase.h"
|
2023-01-04 00:14:55 +01:00
|
|
|
#include "BLI_math_vector_types.hh"
|
2021-04-15 08:57:10 +02:00
|
|
|
#include "BLI_multi_value_map.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BLI_set.hh"
|
|
|
|
|
#include "BLI_string.h"
|
2021-10-21 13:54:48 -05:00
|
|
|
#include "BLI_string_search.h"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
|
2020-12-15 10:47:58 +11:00
|
|
|
#include "DNA_collection_types.h"
|
2022-07-08 14:45:48 +02:00
|
|
|
#include "DNA_curves_types.h"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "DNA_defaults.h"
|
2021-05-27 11:06:08 -04:00
|
|
|
#include "DNA_material_types.h"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
|
#include "DNA_modifier_types.h"
|
|
|
|
|
#include "DNA_node_types.h"
|
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
#include "DNA_pointcloud_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
|
#include "DNA_screen_types.h"
|
2021-04-08 17:35:06 +02:00
|
|
|
#include "DNA_space_types.h"
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
#include "DNA_view3d_types.h"
|
2021-04-08 17:35:06 +02:00
|
|
|
#include "DNA_windowmanager_types.h"
|
2020-12-02 13:25:25 +01:00
|
|
|
|
2021-07-07 11:20:19 +02:00
|
|
|
#include "BKE_attribute_math.hh"
|
2022-09-13 08:44:26 +02:00
|
|
|
#include "BKE_compute_contexts.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BKE_customdata.h"
|
2022-04-01 08:40:45 -05:00
|
|
|
#include "BKE_geometry_fields.hh"
|
2021-04-08 12:19:09 -05:00
|
|
|
#include "BKE_geometry_set_instances.hh"
|
2021-01-13 08:13:57 -06:00
|
|
|
#include "BKE_global.h"
|
2022-07-28 15:50:39 -05:00
|
|
|
#include "BKE_idprop.hh"
|
2021-11-05 11:19:12 -05:00
|
|
|
#include "BKE_lib_id.h"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BKE_lib_query.h"
|
2021-04-08 17:35:06 +02:00
|
|
|
#include "BKE_main.h"
|
2023-03-12 22:29:15 +01:00
|
|
|
#include "BKE_mesh.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BKE_modifier.h"
|
2022-05-30 12:54:07 +02:00
|
|
|
#include "BKE_node_runtime.hh"
|
2021-12-21 15:18:56 +01:00
|
|
|
#include "BKE_node_tree_update.h"
|
2021-04-08 17:35:06 +02:00
|
|
|
#include "BKE_object.h"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "BKE_pointcloud.h"
|
|
|
|
|
#include "BKE_screen.h"
|
|
|
|
|
#include "BKE_simulation.h"
|
2021-04-08 17:35:06 +02:00
|
|
|
#include "BKE_workspace.h"
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
#include "BLO_read_write.h"
|
|
|
|
|
|
|
|
|
|
#include "UI_interface.h"
|
2021-10-21 13:54:48 -05:00
|
|
|
#include "UI_interface.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "UI_resources.h"
|
|
|
|
|
|
2021-09-21 17:17:40 -05:00
|
|
|
#include "BLT_translation.h"
|
|
|
|
|
|
2021-09-16 20:49:10 -05:00
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "RNA_access.h"
|
|
|
|
|
#include "RNA_enum_types.h"
|
2022-03-14 16:54:46 +01:00
|
|
|
#include "RNA_prototypes.h"
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
#include "DEG_depsgraph_build.h"
|
|
|
|
|
#include "DEG_depsgraph_query.h"
|
|
|
|
|
|
|
|
|
|
#include "MOD_modifiertypes.h"
|
|
|
|
|
#include "MOD_nodes.h"
|
|
|
|
|
#include "MOD_ui_common.h"
|
|
|
|
|
|
2021-11-05 11:19:12 -05:00
|
|
|
#include "ED_object.h"
|
2021-11-10 15:43:18 -06:00
|
|
|
#include "ED_screen.h"
|
2021-04-15 08:57:10 +02:00
|
|
|
#include "ED_spreadsheet.h"
|
2021-10-21 13:54:48 -05:00
|
|
|
#include "ED_undo.h"
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
#include "ED_viewer_path.hh"
|
2021-04-15 08:57:10 +02:00
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
#include "NOD_geometry.h"
|
2022-09-13 08:44:26 +02:00
|
|
|
#include "NOD_geometry_nodes_lazy_function.hh"
|
2021-09-28 12:05:42 -05:00
|
|
|
#include "NOD_node_declaration.hh"
|
2021-08-20 13:14:39 +02:00
|
|
|
|
2021-09-09 12:54:20 +02:00
|
|
|
#include "FN_field.hh"
|
2021-11-23 14:47:25 +01:00
|
|
|
#include "FN_field_cpp_type.hh"
|
2022-09-13 08:44:26 +02:00
|
|
|
#include "FN_lazy_function_execute.hh"
|
|
|
|
|
#include "FN_lazy_function_graph_executor.hh"
|
2021-08-20 13:14:39 +02:00
|
|
|
#include "FN_multi_function.hh"
|
2020-12-02 13:25:25 +01:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
namespace lf = blender::fn::lazy_function;
|
|
|
|
|
|
2021-10-21 13:54:48 -05:00
|
|
|
using blender::Array;
|
2021-09-09 09:43:00 -05:00
|
|
|
using blender::ColorGeometry4f;
|
2022-03-18 10:57:45 +01:00
|
|
|
using blender::CPPType;
|
2021-07-07 11:20:19 +02:00
|
|
|
using blender::destruct_ptr;
|
2020-12-02 13:25:25 +01:00
|
|
|
using blender::float3;
|
2021-03-06 16:51:06 +01:00
|
|
|
using blender::FunctionRef;
|
2022-03-19 08:26:29 +01:00
|
|
|
using blender::GMutablePointer;
|
|
|
|
|
using blender::GMutableSpan;
|
|
|
|
|
using blender::GPointer;
|
|
|
|
|
using blender::GVArray;
|
2020-12-02 13:25:25 +01:00
|
|
|
using blender::IndexRange;
|
|
|
|
|
using blender::Map;
|
2022-02-02 10:54:54 +01:00
|
|
|
using blender::MultiValueMap;
|
|
|
|
|
using blender::MutableSpan;
|
2020-12-02 13:25:25 +01:00
|
|
|
using blender::Set;
|
|
|
|
|
using blender::Span;
|
2022-09-13 08:44:26 +02:00
|
|
|
using blender::Stack;
|
2020-12-02 13:25:25 +01:00
|
|
|
using blender::StringRef;
|
2021-02-24 15:59:44 +01:00
|
|
|
using blender::StringRefNull;
|
2020-12-02 13:25:25 +01:00
|
|
|
using blender::Vector;
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
using blender::bke::AttributeMetaData;
|
2022-09-17 14:38:30 -05:00
|
|
|
using blender::bke::AttributeValidator;
|
2021-11-23 14:47:25 +01:00
|
|
|
using blender::fn::Field;
|
2022-09-17 14:38:30 -05:00
|
|
|
using blender::fn::FieldOperation;
|
2021-09-27 15:33:48 +02:00
|
|
|
using blender::fn::GField;
|
2021-11-23 14:47:25 +01:00
|
|
|
using blender::fn::ValueOrField;
|
2022-02-02 10:54:54 +01:00
|
|
|
using blender::fn::ValueOrFieldCPPType;
|
2021-09-28 12:05:42 -05:00
|
|
|
using blender::nodes::FieldInferencingInterface;
|
2020-12-02 13:25:25 +01:00
|
|
|
using blender::nodes::GeoNodeExecParams;
|
2021-09-28 12:05:42 -05:00
|
|
|
using blender::nodes::InputSocketFieldType;
|
2022-09-13 08:44:26 +02:00
|
|
|
using blender::nodes::geo_eval_log::GeometryAttributeInfo;
|
|
|
|
|
using blender::nodes::geo_eval_log::GeometryInfoLog;
|
2023-01-07 17:32:28 +01:00
|
|
|
using blender::nodes::geo_eval_log::GeoModifierLog;
|
2022-09-13 08:44:26 +02:00
|
|
|
using blender::nodes::geo_eval_log::GeoNodeLog;
|
|
|
|
|
using blender::nodes::geo_eval_log::GeoTreeLog;
|
|
|
|
|
using blender::nodes::geo_eval_log::NamedAttributeUsage;
|
|
|
|
|
using blender::nodes::geo_eval_log::NodeWarning;
|
|
|
|
|
using blender::nodes::geo_eval_log::NodeWarningType;
|
|
|
|
|
using blender::nodes::geo_eval_log::ValueLog;
|
2023-01-07 17:32:28 +01:00
|
|
|
using blender::threading::EnumerableThreadSpecific;
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
static void initData(ModifierData *md)
|
|
|
|
|
{
|
|
|
|
|
NodesModifierData *nmd = (NodesModifierData *)md;
|
|
|
|
|
|
|
|
|
|
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(nmd, modifier));
|
|
|
|
|
|
|
|
|
|
MEMCPY_STRUCT_AFTER(nmd, DNA_struct_default_get(NodesModifierData), modifier);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-31 15:27:35 -06:00
|
|
|
static void add_used_ids_from_sockets(const ListBase &sockets, Set<ID *> &ids)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
2022-01-31 15:27:35 -06:00
|
|
|
LISTBASE_FOREACH (const bNodeSocket *, socket, &sockets) {
|
|
|
|
|
switch (socket->type) {
|
|
|
|
|
case SOCK_OBJECT: {
|
2022-01-31 15:43:00 -06:00
|
|
|
if (Object *object = ((bNodeSocketValueObject *)socket->default_value)->value) {
|
2022-01-31 15:27:35 -06:00
|
|
|
ids.add(&object->id);
|
|
|
|
|
}
|
2022-01-31 15:43:00 -06:00
|
|
|
break;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
2022-01-31 15:27:35 -06:00
|
|
|
case SOCK_COLLECTION: {
|
2022-01-31 15:43:00 -06:00
|
|
|
if (Collection *collection =
|
|
|
|
|
((bNodeSocketValueCollection *)socket->default_value)->value) {
|
2022-01-31 15:27:35 -06:00
|
|
|
ids.add(&collection->id);
|
|
|
|
|
}
|
2022-01-31 15:43:00 -06:00
|
|
|
break;
|
2020-12-11 17:47:58 +01:00
|
|
|
}
|
2022-01-31 15:27:35 -06:00
|
|
|
case SOCK_MATERIAL: {
|
2022-01-31 15:43:00 -06:00
|
|
|
if (Material *material = ((bNodeSocketValueMaterial *)socket->default_value)->value) {
|
2022-01-31 15:27:35 -06:00
|
|
|
ids.add(&material->id);
|
|
|
|
|
}
|
2022-01-31 15:43:00 -06:00
|
|
|
break;
|
2021-05-27 11:06:08 -04:00
|
|
|
}
|
2022-01-31 15:27:35 -06:00
|
|
|
case SOCK_TEXTURE: {
|
2022-01-31 15:43:00 -06:00
|
|
|
if (Tex *texture = ((bNodeSocketValueTexture *)socket->default_value)->value) {
|
2022-01-31 15:27:35 -06:00
|
|
|
ids.add(&texture->id);
|
|
|
|
|
}
|
2022-01-31 15:43:00 -06:00
|
|
|
break;
|
2021-05-27 11:06:08 -04:00
|
|
|
}
|
2022-01-31 15:27:35 -06:00
|
|
|
case SOCK_IMAGE: {
|
2022-01-31 15:43:00 -06:00
|
|
|
if (Image *image = ((bNodeSocketValueImage *)socket->default_value)->value) {
|
2022-01-31 15:27:35 -06:00
|
|
|
ids.add(&image->id);
|
|
|
|
|
}
|
2022-01-31 15:43:00 -06:00
|
|
|
break;
|
2021-10-14 14:18:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-01 16:27:29 -06:00
|
|
|
/**
|
|
|
|
|
* \note We can only check properties here that cause the dependency graph to update relations when
|
|
|
|
|
* they are changed, otherwise there may be a missing relation after editing. So this could check
|
|
|
|
|
* more properties like whether the node is muted, but we would have to accept the cost of updating
|
|
|
|
|
* relations when those properties are changed.
|
|
|
|
|
*/
|
|
|
|
|
static bool node_needs_own_transform_relation(const bNode &node)
|
|
|
|
|
{
|
|
|
|
|
if (node.type == GEO_NODE_COLLECTION_INFO) {
|
|
|
|
|
const NodeGeometryCollectionInfo &storage = *static_cast<const NodeGeometryCollectionInfo *>(
|
|
|
|
|
node.storage);
|
|
|
|
|
return storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node.type == GEO_NODE_OBJECT_INFO) {
|
|
|
|
|
const NodeGeometryObjectInfo &storage = *static_cast<const NodeGeometryObjectInfo *>(
|
|
|
|
|
node.storage);
|
|
|
|
|
return storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-22 08:15:03 -05:00
|
|
|
if (node.type == GEO_NODE_SELF_OBJECT) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-07-08 14:45:48 +02:00
|
|
|
if (node.type == GEO_NODE_DEFORM_CURVES_ON_SURFACE) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-01 16:27:29 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void process_nodes_for_depsgraph(const bNodeTree &tree,
|
|
|
|
|
Set<ID *> &ids,
|
2022-07-22 10:49:09 -05:00
|
|
|
bool &r_needs_own_transform_relation)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
|
|
|
|
Set<const bNodeTree *> handled_groups;
|
|
|
|
|
|
|
|
|
|
LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
|
2022-01-31 15:27:35 -06:00
|
|
|
add_used_ids_from_sockets(node->inputs, ids);
|
|
|
|
|
add_used_ids_from_sockets(node->outputs, ids);
|
2020-12-02 13:25:25 +01:00
|
|
|
|
2021-04-08 16:25:09 -06:00
|
|
|
if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
|
2020-12-02 13:25:25 +01:00
|
|
|
const bNodeTree *group = (bNodeTree *)node->id;
|
|
|
|
|
if (group != nullptr && handled_groups.add(group)) {
|
2022-07-22 10:49:09 -05:00
|
|
|
process_nodes_for_depsgraph(*group, ids, r_needs_own_transform_relation);
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-07-22 10:49:09 -05:00
|
|
|
r_needs_own_transform_relation |= node_needs_own_transform_relation(*node);
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-13 08:13:57 -06:00
|
|
|
static void find_used_ids_from_settings(const NodesModifierSettings &settings, Set<ID *> &ids)
|
|
|
|
|
{
|
|
|
|
|
IDP_foreach_property(
|
|
|
|
|
settings.properties,
|
|
|
|
|
IDP_TYPE_FILTER_ID,
|
|
|
|
|
[](IDProperty *property, void *user_data) {
|
|
|
|
|
Set<ID *> *ids = (Set<ID *> *)user_data;
|
|
|
|
|
ID *id = IDP_Id(property);
|
|
|
|
|
if (id != nullptr) {
|
|
|
|
|
ids->add(id);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
&ids);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-26 16:35:22 +02:00
|
|
|
/* We don't know exactly what attributes from the other object we will need. */
|
|
|
|
|
static const CustomData_MeshMasks dependency_data_mask{CD_MASK_PROP_ALL | CD_MASK_MDEFORMVERT,
|
|
|
|
|
CD_MASK_PROP_ALL,
|
|
|
|
|
CD_MASK_PROP_ALL,
|
|
|
|
|
CD_MASK_PROP_ALL,
|
|
|
|
|
CD_MASK_PROP_ALL};
|
|
|
|
|
|
|
|
|
|
static void add_collection_relation(const ModifierUpdateDepsgraphContext *ctx,
|
|
|
|
|
Collection &collection)
|
|
|
|
|
{
|
|
|
|
|
DEG_add_collection_geometry_relation(ctx->node, &collection, "Nodes Modifier");
|
|
|
|
|
DEG_add_collection_geometry_customdata_mask(ctx->node, &collection, &dependency_data_mask);
|
|
|
|
|
}
|
2021-02-22 20:26:51 +01:00
|
|
|
|
2021-02-12 12:03:38 -06:00
|
|
|
static void add_object_relation(const ModifierUpdateDepsgraphContext *ctx, Object &object)
|
|
|
|
|
{
|
|
|
|
|
DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
|
|
|
|
|
if (&(ID &)object != &ctx->object->id) {
|
2021-04-26 16:35:22 +02:00
|
|
|
if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
|
|
|
|
|
add_collection_relation(ctx, *object.instance_collection);
|
2021-02-22 20:26:51 +01:00
|
|
|
}
|
2021-05-26 16:06:01 +02:00
|
|
|
else if (DEG_object_has_geometry_component(&object)) {
|
2021-02-12 12:03:38 -06:00
|
|
|
DEG_add_object_relation(ctx->node, &object, DEG_OB_COMP_GEOMETRY, "Nodes Modifier");
|
2021-04-26 16:35:22 +02:00
|
|
|
DEG_add_customdata_mask(ctx->node, &object, &dependency_data_mask);
|
2021-02-12 12:03:38 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
|
|
|
|
|
{
|
|
|
|
|
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
2022-01-31 15:27:35 -06:00
|
|
|
if (nmd->node_group == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier");
|
|
|
|
|
|
2022-02-01 16:27:29 -06:00
|
|
|
bool needs_own_transform_relation = false;
|
2022-01-31 15:27:35 -06:00
|
|
|
Set<ID *> used_ids;
|
|
|
|
|
find_used_ids_from_settings(nmd->settings, used_ids);
|
2022-02-01 16:27:29 -06:00
|
|
|
process_nodes_for_depsgraph(*nmd->node_group, used_ids, needs_own_transform_relation);
|
2022-07-08 14:45:48 +02:00
|
|
|
|
|
|
|
|
if (ctx->object->type == OB_CURVES) {
|
|
|
|
|
Curves *curves_id = static_cast<Curves *>(ctx->object->data);
|
|
|
|
|
if (curves_id->surface != nullptr) {
|
|
|
|
|
used_ids.add(&curves_id->surface->id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-31 15:27:35 -06:00
|
|
|
for (ID *id : used_ids) {
|
|
|
|
|
switch ((ID_Type)GS(id->name)) {
|
|
|
|
|
case ID_OB: {
|
|
|
|
|
Object *object = reinterpret_cast<Object *>(id);
|
|
|
|
|
add_object_relation(ctx, *object);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ID_GR: {
|
|
|
|
|
Collection *collection = reinterpret_cast<Collection *>(id);
|
|
|
|
|
add_collection_relation(ctx, *collection);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case ID_IM:
|
|
|
|
|
case ID_TE: {
|
|
|
|
|
DEG_add_generic_id_relation(ctx->node, id, "Nodes Modifier");
|
2022-08-31 15:58:33 +10:00
|
|
|
break;
|
2022-01-31 15:27:35 -06:00
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
/* Purposefully don't add relations for materials. While there are material sockets,
|
|
|
|
|
* the pointers are only passed around as handles rather than dereferenced. */
|
|
|
|
|
break;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-01 16:27:29 -06:00
|
|
|
|
|
|
|
|
if (needs_own_transform_relation) {
|
2022-08-04 12:11:31 +02:00
|
|
|
DEG_add_depends_on_transform_relation(ctx->node, "Nodes Modifier");
|
2022-02-01 16:27:29 -06:00
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-15 14:51:58 -06:00
|
|
|
static bool check_tree_for_time_node(const bNodeTree &tree,
|
|
|
|
|
Set<const bNodeTree *> &r_checked_trees)
|
2021-12-09 11:50:25 -06:00
|
|
|
{
|
2021-12-15 14:51:58 -06:00
|
|
|
if (!r_checked_trees.add(&tree)) {
|
2021-12-09 11:50:25 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-12-15 14:51:58 -06:00
|
|
|
LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
|
2021-12-09 11:50:25 -06:00
|
|
|
if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (node->type == NODE_GROUP) {
|
2021-12-15 14:51:58 -06:00
|
|
|
const bNodeTree *sub_tree = reinterpret_cast<const bNodeTree *>(node->id);
|
2021-12-15 15:00:20 -06:00
|
|
|
if (sub_tree && check_tree_for_time_node(*sub_tree, r_checked_trees)) {
|
2021-12-09 11:50:25 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-03 17:37:25 -05:00
|
|
|
static bool dependsOnTime(struct Scene * /*scene*/, ModifierData *md)
|
2021-12-09 11:50:25 -06:00
|
|
|
{
|
2021-12-15 14:51:58 -06:00
|
|
|
const NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
|
|
|
|
const bNodeTree *tree = nmd->node_group;
|
2021-12-09 11:50:25 -06:00
|
|
|
if (tree == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-12-15 14:51:58 -06:00
|
|
|
Set<const bNodeTree *> checked_trees;
|
|
|
|
|
return check_tree_for_time_node(*tree, checked_trees);
|
2021-12-09 11:50:25 -06:00
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
|
|
|
|
|
{
|
|
|
|
|
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
|
|
|
|
walk(userData, ob, (ID **)&nmd->node_group, IDWALK_CB_USER);
|
|
|
|
|
|
|
|
|
|
struct ForeachSettingData {
|
|
|
|
|
IDWalkFunc walk;
|
|
|
|
|
void *userData;
|
|
|
|
|
Object *ob;
|
|
|
|
|
} settings = {walk, userData, ob};
|
|
|
|
|
|
|
|
|
|
IDP_foreach_property(
|
|
|
|
|
nmd->settings.properties,
|
|
|
|
|
IDP_TYPE_FILTER_ID,
|
|
|
|
|
[](IDProperty *id_prop, void *user_data) {
|
|
|
|
|
ForeachSettingData *settings = (ForeachSettingData *)user_data;
|
|
|
|
|
settings->walk(
|
|
|
|
|
settings->userData, settings->ob, (ID **)&id_prop->data.pointer, IDWALK_CB_USER);
|
|
|
|
|
},
|
|
|
|
|
&settings);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-03 14:39:24 +01:00
|
|
|
static void foreachTexLink(ModifierData *md, Object *ob, TexWalkFunc walk, void *userData)
|
|
|
|
|
{
|
|
|
|
|
walk(userData, ob, md, "texture");
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-03 17:37:25 -05:00
|
|
|
static bool isDisabled(const struct Scene * /*scene*/, ModifierData *md, bool /*useRenderParams*/)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
|
|
|
|
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
|
|
|
|
|
|
|
|
|
if (nmd->node_group == nullptr) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 12:48:59 +02:00
|
|
|
static bool logging_enabled(const ModifierEvalContext *ctx)
|
|
|
|
|
{
|
|
|
|
|
if (!DEG_is_active(ctx->depsgraph)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if ((ctx->flag & MOD_APPLY_ORCO) != 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-16 20:49:10 -05:00
|
|
|
static const std::string use_attribute_suffix = "_use_attribute";
|
|
|
|
|
static const std::string attribute_name_suffix = "_attribute_name";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \return Whether using an attribute to input values of this type is supported.
|
|
|
|
|
*/
|
|
|
|
|
static bool socket_type_has_attribute_toggle(const bNodeSocket &socket)
|
|
|
|
|
{
|
|
|
|
|
return ELEM(socket.type, SOCK_FLOAT, SOCK_VECTOR, SOCK_BOOLEAN, SOCK_RGBA, SOCK_INT);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-28 12:05:42 -05:00
|
|
|
/**
|
|
|
|
|
* \return Whether using an attribute to input values of this type is supported, and the node
|
|
|
|
|
* group's input for this socket accepts a field rather than just single values.
|
|
|
|
|
*/
|
|
|
|
|
static bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
|
|
|
|
|
{
|
2022-05-30 12:54:07 +02:00
|
|
|
BLI_assert(node_tree.runtime->field_inferencing_interface);
|
|
|
|
|
const FieldInferencingInterface &field_interface =
|
|
|
|
|
*node_tree.runtime->field_inferencing_interface;
|
2021-09-28 12:05:42 -05:00
|
|
|
return field_interface.inputs[socket_index] != InputSocketFieldType::None;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-28 15:50:39 -05:00
|
|
|
static std::unique_ptr<IDProperty, blender::bke::idprop::IDPropertyDeleter>
|
|
|
|
|
id_property_create_from_socket(const bNodeSocket &socket)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
2022-07-28 15:50:39 -05:00
|
|
|
using namespace blender;
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
switch (socket.type) {
|
|
|
|
|
case SOCK_FLOAT: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueFloat *value = static_cast<const bNodeSocketValueFloat *>(
|
|
|
|
|
socket.default_value);
|
|
|
|
|
auto property = bke::idprop::create(socket.identifier, value->value);
|
|
|
|
|
IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get());
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ui_data->base.rna_subtype = value->subtype;
|
2023-01-13 12:49:53 -06:00
|
|
|
ui_data->soft_min = double(value->min);
|
|
|
|
|
ui_data->soft_max = double(value->max);
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ui_data->default_value = value->value;
|
|
|
|
|
return property;
|
|
|
|
|
}
|
|
|
|
|
case SOCK_INT: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueInt *value = static_cast<const bNodeSocketValueInt *>(
|
|
|
|
|
socket.default_value);
|
|
|
|
|
auto property = bke::idprop::create(socket.identifier, value->value);
|
|
|
|
|
IDPropertyUIDataInt *ui_data = (IDPropertyUIDataInt *)IDP_ui_data_ensure(property.get());
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ui_data->base.rna_subtype = value->subtype;
|
2023-01-13 12:49:53 -06:00
|
|
|
ui_data->soft_min = value->min;
|
|
|
|
|
ui_data->soft_max = value->max;
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ui_data->default_value = value->value;
|
|
|
|
|
return property;
|
|
|
|
|
}
|
|
|
|
|
case SOCK_VECTOR: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueVector *value = static_cast<const bNodeSocketValueVector *>(
|
|
|
|
|
socket.default_value);
|
|
|
|
|
auto property = bke::idprop::create(
|
|
|
|
|
socket.identifier, Span<float>{value->value[0], value->value[1], value->value[2]});
|
|
|
|
|
IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get());
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ui_data->base.rna_subtype = value->subtype;
|
2023-01-13 12:49:53 -06:00
|
|
|
ui_data->soft_min = double(value->min);
|
|
|
|
|
ui_data->soft_max = double(value->max);
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ui_data->default_array = (double *)MEM_mallocN(sizeof(double[3]), "mod_prop_default");
|
|
|
|
|
ui_data->default_array_len = 3;
|
2021-09-08 18:44:35 -05:00
|
|
|
for (const int i : IndexRange(3)) {
|
|
|
|
|
ui_data->default_array[i] = double(value->value[i]);
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
}
|
|
|
|
|
return property;
|
|
|
|
|
}
|
2021-09-09 09:43:00 -05:00
|
|
|
case SOCK_RGBA: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueRGBA *value = static_cast<const bNodeSocketValueRGBA *>(
|
|
|
|
|
socket.default_value);
|
|
|
|
|
auto property = bke::idprop::create(
|
|
|
|
|
socket.identifier,
|
|
|
|
|
Span<float>{value->value[0], value->value[1], value->value[2], value->value[3]});
|
|
|
|
|
IDPropertyUIDataFloat *ui_data = (IDPropertyUIDataFloat *)IDP_ui_data_ensure(property.get());
|
2021-09-09 09:43:00 -05:00
|
|
|
ui_data->base.rna_subtype = PROP_COLOR;
|
|
|
|
|
ui_data->default_array = (double *)MEM_mallocN(sizeof(double[4]), __func__);
|
|
|
|
|
ui_data->default_array_len = 4;
|
2022-02-21 13:01:37 -05:00
|
|
|
ui_data->min = 0.0;
|
|
|
|
|
ui_data->max = FLT_MAX;
|
|
|
|
|
ui_data->soft_min = 0.0;
|
|
|
|
|
ui_data->soft_max = 1.0;
|
2021-09-09 09:43:00 -05:00
|
|
|
for (const int i : IndexRange(4)) {
|
|
|
|
|
ui_data->default_array[i] = double(value->value[i]);
|
|
|
|
|
}
|
|
|
|
|
return property;
|
|
|
|
|
}
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
case SOCK_BOOLEAN: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueBoolean *value = static_cast<const bNodeSocketValueBoolean *>(
|
|
|
|
|
socket.default_value);
|
2023-01-20 17:36:07 -06:00
|
|
|
auto property = bke::idprop::create_bool(socket.identifier, value->value);
|
|
|
|
|
IDPropertyUIDataBool *ui_data = (IDPropertyUIDataBool *)IDP_ui_data_ensure(property.get());
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ui_data->default_value = value->value != 0;
|
|
|
|
|
return property;
|
|
|
|
|
}
|
|
|
|
|
case SOCK_STRING: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueString *value = static_cast<const bNodeSocketValueString *>(
|
|
|
|
|
socket.default_value);
|
|
|
|
|
auto property = bke::idprop::create(socket.identifier, value->value);
|
|
|
|
|
IDPropertyUIDataString *ui_data = (IDPropertyUIDataString *)IDP_ui_data_ensure(
|
|
|
|
|
property.get());
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ui_data->default_value = BLI_strdup(value->value);
|
|
|
|
|
return property;
|
|
|
|
|
}
|
|
|
|
|
case SOCK_OBJECT: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueObject *value = static_cast<const bNodeSocketValueObject *>(
|
|
|
|
|
socket.default_value);
|
2023-02-01 12:53:57 +01:00
|
|
|
auto property = bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value));
|
|
|
|
|
IDPropertyUIDataID *ui_data = (IDPropertyUIDataID *)IDP_ui_data_ensure(property.get());
|
|
|
|
|
ui_data->id_type = ID_OB;
|
|
|
|
|
return property;
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
}
|
|
|
|
|
case SOCK_COLLECTION: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueCollection *value = static_cast<const bNodeSocketValueCollection *>(
|
|
|
|
|
socket.default_value);
|
|
|
|
|
return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value));
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
}
|
|
|
|
|
case SOCK_TEXTURE: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueTexture *value = static_cast<const bNodeSocketValueTexture *>(
|
|
|
|
|
socket.default_value);
|
|
|
|
|
return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value));
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
}
|
2021-10-14 14:18:24 +01:00
|
|
|
case SOCK_IMAGE: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueImage *value = static_cast<const bNodeSocketValueImage *>(
|
|
|
|
|
socket.default_value);
|
|
|
|
|
return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value));
|
2021-10-14 14:18:24 +01:00
|
|
|
}
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
case SOCK_MATERIAL: {
|
2022-07-28 15:50:39 -05:00
|
|
|
const bNodeSocketValueMaterial *value = static_cast<const bNodeSocketValueMaterial *>(
|
|
|
|
|
socket.default_value);
|
|
|
|
|
return bke::idprop::create(socket.identifier, reinterpret_cast<ID *>(value->value));
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
static bool id_property_type_matches_socket(const bNodeSocket &socket, const IDProperty &property)
|
|
|
|
|
{
|
|
|
|
|
switch (socket.type) {
|
|
|
|
|
case SOCK_FLOAT:
|
|
|
|
|
return ELEM(property.type, IDP_FLOAT, IDP_DOUBLE);
|
|
|
|
|
case SOCK_INT:
|
|
|
|
|
return property.type == IDP_INT;
|
|
|
|
|
case SOCK_VECTOR:
|
|
|
|
|
return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT && property.len == 3;
|
2021-09-09 09:43:00 -05:00
|
|
|
case SOCK_RGBA:
|
|
|
|
|
return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT && property.len == 4;
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
case SOCK_BOOLEAN:
|
2023-01-20 17:36:07 -06:00
|
|
|
return property.type == IDP_BOOLEAN;
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
case SOCK_STRING:
|
|
|
|
|
return property.type == IDP_STRING;
|
|
|
|
|
case SOCK_OBJECT:
|
|
|
|
|
case SOCK_COLLECTION:
|
|
|
|
|
case SOCK_TEXTURE:
|
2021-10-14 14:18:24 +01:00
|
|
|
case SOCK_IMAGE:
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
case SOCK_MATERIAL:
|
|
|
|
|
return property.type == IDP_ID;
|
|
|
|
|
}
|
|
|
|
|
BLI_assert_unreachable();
|
|
|
|
|
return false;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
static void init_socket_cpp_value_from_property(const IDProperty &property,
|
|
|
|
|
const eNodeSocketDatatype socket_value_type,
|
|
|
|
|
void *r_value)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
switch (socket_value_type) {
|
2020-12-02 13:25:25 +01:00
|
|
|
case SOCK_FLOAT: {
|
2021-09-09 12:54:20 +02:00
|
|
|
float value = 0.0f;
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
if (property.type == IDP_FLOAT) {
|
2021-09-09 12:54:20 +02:00
|
|
|
value = IDP_Float(&property);
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
}
|
|
|
|
|
else if (property.type == IDP_DOUBLE) {
|
2022-09-25 18:33:28 +10:00
|
|
|
value = float(IDP_Double(&property));
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
}
|
2021-11-23 14:47:25 +01:00
|
|
|
new (r_value) ValueOrField<float>(value);
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
break;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
case SOCK_INT: {
|
2021-09-09 12:54:20 +02:00
|
|
|
int value = IDP_Int(&property);
|
2021-11-23 14:47:25 +01:00
|
|
|
new (r_value) ValueOrField<int>(value);
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
break;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
case SOCK_VECTOR: {
|
2021-09-09 12:54:20 +02:00
|
|
|
float3 value;
|
|
|
|
|
copy_v3_v3(value, (const float *)IDP_Array(&property));
|
2021-11-23 14:47:25 +01:00
|
|
|
new (r_value) ValueOrField<float3>(value);
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
break;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
2021-09-09 09:43:00 -05:00
|
|
|
case SOCK_RGBA: {
|
|
|
|
|
blender::ColorGeometry4f value;
|
|
|
|
|
copy_v4_v4((float *)value, (const float *)IDP_Array(&property));
|
2021-11-23 14:47:25 +01:00
|
|
|
new (r_value) ValueOrField<ColorGeometry4f>(value);
|
2021-09-09 09:43:00 -05:00
|
|
|
break;
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
case SOCK_BOOLEAN: {
|
2023-01-20 17:36:07 -06:00
|
|
|
const bool value = IDP_Bool(&property);
|
2021-11-23 14:47:25 +01:00
|
|
|
new (r_value) ValueOrField<bool>(value);
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
break;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
case SOCK_STRING: {
|
2021-09-09 12:54:20 +02:00
|
|
|
std::string value = IDP_String(&property);
|
2021-11-23 14:47:25 +01:00
|
|
|
new (r_value) ValueOrField<std::string>(std::move(value));
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
break;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
2021-01-13 08:13:57 -06:00
|
|
|
case SOCK_OBJECT: {
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ID *id = IDP_Id(&property);
|
|
|
|
|
Object *object = (id && GS(id->name) == ID_OB) ? (Object *)id : nullptr;
|
|
|
|
|
*(Object **)r_value = object;
|
|
|
|
|
break;
|
2021-01-13 08:13:57 -06:00
|
|
|
}
|
|
|
|
|
case SOCK_COLLECTION: {
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ID *id = IDP_Id(&property);
|
|
|
|
|
Collection *collection = (id && GS(id->name) == ID_GR) ? (Collection *)id : nullptr;
|
|
|
|
|
*(Collection **)r_value = collection;
|
|
|
|
|
break;
|
2021-01-13 08:13:57 -06:00
|
|
|
}
|
2021-05-27 11:06:08 -04:00
|
|
|
case SOCK_TEXTURE: {
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ID *id = IDP_Id(&property);
|
|
|
|
|
Tex *texture = (id && GS(id->name) == ID_TE) ? (Tex *)id : nullptr;
|
|
|
|
|
*(Tex **)r_value = texture;
|
|
|
|
|
break;
|
2021-05-27 11:06:08 -04:00
|
|
|
}
|
2021-10-14 14:18:24 +01:00
|
|
|
case SOCK_IMAGE: {
|
|
|
|
|
ID *id = IDP_Id(&property);
|
|
|
|
|
Image *image = (id && GS(id->name) == ID_IM) ? (Image *)id : nullptr;
|
|
|
|
|
*(Image **)r_value = image;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-05-27 11:06:08 -04:00
|
|
|
case SOCK_MATERIAL: {
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
ID *id = IDP_Id(&property);
|
|
|
|
|
Material *material = (id && GS(id->name) == ID_MA) ? (Material *)id : nullptr;
|
|
|
|
|
*(Material **)r_value = material;
|
|
|
|
|
break;
|
2021-05-27 11:06:08 -04:00
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
default: {
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
BLI_assert_unreachable();
|
|
|
|
|
break;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
|
|
|
|
|
{
|
|
|
|
|
if (nmd->node_group == nullptr) {
|
2022-04-28 08:39:30 -05:00
|
|
|
if (nmd->settings.properties) {
|
|
|
|
|
IDP_FreeProperty(nmd->settings.properties);
|
|
|
|
|
nmd->settings.properties = nullptr;
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IDProperty *old_properties = nmd->settings.properties;
|
|
|
|
|
{
|
|
|
|
|
IDPropertyTemplate idprop = {0};
|
|
|
|
|
nmd->settings.properties = IDP_New(IDP_GROUP, &idprop, "Nodes Modifier Settings");
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-28 12:05:42 -05:00
|
|
|
int socket_index;
|
|
|
|
|
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) {
|
2022-07-28 15:50:39 -05:00
|
|
|
IDProperty *new_prop = id_property_create_from_socket(*socket).release();
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
if (new_prop == nullptr) {
|
|
|
|
|
/* Out of the set of supported input sockets, only
|
|
|
|
|
* geometry sockets aren't added to the modifier. */
|
|
|
|
|
BLI_assert(socket->type == SOCK_GEOMETRY);
|
2020-12-02 13:25:25 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
new_prop->flag |= IDP_FLAG_OVERRIDABLE_LIBRARY;
|
|
|
|
|
if (socket->description[0] != '\0') {
|
|
|
|
|
IDPropertyUIData *ui_data = IDP_ui_data_ensure(new_prop);
|
|
|
|
|
ui_data->description = BLI_strdup(socket->description);
|
|
|
|
|
}
|
|
|
|
|
IDP_AddToGroup(nmd->settings.properties, new_prop);
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
if (old_properties != nullptr) {
|
|
|
|
|
IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, socket->identifier);
|
2023-01-20 17:36:07 -06:00
|
|
|
if (old_prop != nullptr) {
|
|
|
|
|
if (id_property_type_matches_socket(*socket, *old_prop)) {
|
|
|
|
|
/* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only
|
|
|
|
|
* want to replace the values). So release it temporarily and replace it after. */
|
|
|
|
|
IDPropertyUIData *ui_data = new_prop->ui_data;
|
|
|
|
|
new_prop->ui_data = nullptr;
|
|
|
|
|
IDP_CopyPropertyContent(new_prop, old_prop);
|
|
|
|
|
if (new_prop->ui_data != nullptr) {
|
|
|
|
|
IDP_ui_data_free(new_prop);
|
|
|
|
|
}
|
|
|
|
|
new_prop->ui_data = ui_data;
|
|
|
|
|
}
|
|
|
|
|
else if (old_prop->type == IDP_INT && new_prop->type == IDP_BOOLEAN) {
|
|
|
|
|
/* Support versioning from integer to boolean property values. The actual value is stored
|
|
|
|
|
* in the same variable for both types. */
|
|
|
|
|
new_prop->data.val = old_prop->data.val != 0;
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
2021-09-16 20:49:10 -05:00
|
|
|
|
2021-10-18 12:58:30 +02:00
|
|
|
if (socket_type_has_attribute_toggle(*socket)) {
|
2021-09-16 20:49:10 -05:00
|
|
|
const std::string use_attribute_id = socket->identifier + use_attribute_suffix;
|
|
|
|
|
const std::string attribute_name_id = socket->identifier + attribute_name_suffix;
|
|
|
|
|
|
|
|
|
|
IDPropertyTemplate idprop = {0};
|
|
|
|
|
IDProperty *use_attribute_prop = IDP_New(IDP_INT, &idprop, use_attribute_id.c_str());
|
|
|
|
|
IDP_AddToGroup(nmd->settings.properties, use_attribute_prop);
|
|
|
|
|
|
|
|
|
|
IDProperty *attribute_prop = IDP_New(IDP_STRING, &idprop, attribute_name_id.c_str());
|
|
|
|
|
IDP_AddToGroup(nmd->settings.properties, attribute_prop);
|
|
|
|
|
|
2022-04-28 08:39:30 -05:00
|
|
|
if (old_properties == nullptr) {
|
|
|
|
|
if (socket->default_attribute_name && socket->default_attribute_name[0] != '\0') {
|
|
|
|
|
IDP_AssignString(attribute_prop, socket->default_attribute_name, MAX_NAME);
|
|
|
|
|
IDP_Int(use_attribute_prop) = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2021-09-16 20:49:10 -05:00
|
|
|
IDProperty *old_prop_use_attribute = IDP_GetPropertyFromGroup(old_properties,
|
|
|
|
|
use_attribute_id.c_str());
|
|
|
|
|
if (old_prop_use_attribute != nullptr) {
|
|
|
|
|
IDP_CopyPropertyContent(use_attribute_prop, old_prop_use_attribute);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IDProperty *old_attribute_name_prop = IDP_GetPropertyFromGroup(old_properties,
|
|
|
|
|
attribute_name_id.c_str());
|
|
|
|
|
if (old_attribute_name_prop != nullptr) {
|
|
|
|
|
IDP_CopyPropertyContent(attribute_prop, old_attribute_name_prop);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-09-27 15:33:48 +02:00
|
|
|
LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->outputs) {
|
|
|
|
|
if (!socket_type_has_attribute_toggle(*socket)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string idprop_name = socket->identifier + attribute_name_suffix;
|
|
|
|
|
IDProperty *new_prop = IDP_NewString("", idprop_name.c_str(), MAX_NAME);
|
|
|
|
|
if (socket->description[0] != '\0') {
|
|
|
|
|
IDPropertyUIData *ui_data = IDP_ui_data_ensure(new_prop);
|
|
|
|
|
ui_data->description = BLI_strdup(socket->description);
|
|
|
|
|
}
|
|
|
|
|
IDP_AddToGroup(nmd->settings.properties, new_prop);
|
|
|
|
|
|
2022-04-28 08:39:30 -05:00
|
|
|
if (old_properties == nullptr) {
|
|
|
|
|
if (socket->default_attribute_name && socket->default_attribute_name[0] != '\0') {
|
|
|
|
|
IDP_AssignString(new_prop, socket->default_attribute_name, MAX_NAME);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2021-09-27 15:33:48 +02:00
|
|
|
IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, idprop_name.c_str());
|
|
|
|
|
if (old_prop != nullptr) {
|
|
|
|
|
/* #IDP_CopyPropertyContent replaces the UI data as well, which we don't (we only
|
|
|
|
|
* want to replace the values). So release it temporarily and replace it after. */
|
|
|
|
|
IDPropertyUIData *ui_data = new_prop->ui_data;
|
|
|
|
|
new_prop->ui_data = nullptr;
|
|
|
|
|
IDP_CopyPropertyContent(new_prop, old_prop);
|
|
|
|
|
if (new_prop->ui_data != nullptr) {
|
|
|
|
|
IDP_ui_data_free(new_prop);
|
|
|
|
|
}
|
|
|
|
|
new_prop->ui_data = ui_data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
if (old_properties != nullptr) {
|
|
|
|
|
IDP_FreeProperty(old_properties);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void initialize_group_input(NodesModifierData &nmd,
|
2022-09-13 08:44:26 +02:00
|
|
|
const bNodeSocket &interface_socket,
|
|
|
|
|
const int input_index,
|
2020-12-02 13:25:25 +01:00
|
|
|
void *r_value)
|
|
|
|
|
{
|
2022-09-13 08:44:26 +02:00
|
|
|
const bNodeSocketType &socket_type = *interface_socket.typeinfo;
|
|
|
|
|
const eNodeSocketDatatype socket_data_type = static_cast<eNodeSocketDatatype>(
|
|
|
|
|
interface_socket.type);
|
2020-12-02 13:25:25 +01:00
|
|
|
if (nmd.settings.properties == nullptr) {
|
2022-09-13 08:44:26 +02:00
|
|
|
socket_type.get_geometry_nodes_cpp_value(interface_socket, r_value);
|
2020-12-02 13:25:25 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties,
|
2022-09-13 08:44:26 +02:00
|
|
|
interface_socket.identifier);
|
2020-12-02 13:25:25 +01:00
|
|
|
if (property == nullptr) {
|
2022-09-13 08:44:26 +02:00
|
|
|
socket_type.get_geometry_nodes_cpp_value(interface_socket, r_value);
|
2020-12-02 13:25:25 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
if (!id_property_type_matches_socket(interface_socket, *property)) {
|
|
|
|
|
socket_type.get_geometry_nodes_cpp_value(interface_socket, r_value);
|
2021-01-13 08:13:57 -06:00
|
|
|
return;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
if (!input_has_attribute_toggle(*nmd.node_group, input_index)) {
|
2022-05-31 18:52:27 +02:00
|
|
|
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
|
2021-09-16 21:54:14 -05:00
|
|
|
return;
|
2021-09-16 20:49:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const IDProperty *property_use_attribute = IDP_GetPropertyFromGroup(
|
2022-09-13 08:44:26 +02:00
|
|
|
nmd.settings.properties, (interface_socket.identifier + use_attribute_suffix).c_str());
|
2021-09-16 20:49:10 -05:00
|
|
|
const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
|
2022-09-13 08:44:26 +02:00
|
|
|
nmd.settings.properties, (interface_socket.identifier + attribute_name_suffix).c_str());
|
2021-09-16 20:49:10 -05:00
|
|
|
if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
|
2022-05-31 18:52:27 +02:00
|
|
|
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
|
2021-09-16 20:49:10 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool use_attribute = IDP_Int(property_use_attribute) != 0;
|
|
|
|
|
if (use_attribute) {
|
|
|
|
|
const StringRef attribute_name{IDP_String(property_attribute_name)};
|
2022-05-31 18:52:27 +02:00
|
|
|
if (!blender::bke::allow_procedural_attribute_access(attribute_name)) {
|
|
|
|
|
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-09-16 20:49:10 -05:00
|
|
|
auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
|
2021-11-22 10:18:08 +01:00
|
|
|
attribute_name, *socket_type.base_cpp_type);
|
2021-11-23 14:47:25 +01:00
|
|
|
GField attribute_field{std::move(attribute_input), 0};
|
2022-11-12 18:33:31 +01:00
|
|
|
const auto *value_or_field_cpp_type = ValueOrFieldCPPType::get_from_self(
|
|
|
|
|
*socket_type.geometry_nodes_cpp_type);
|
|
|
|
|
BLI_assert(value_or_field_cpp_type != nullptr);
|
|
|
|
|
value_or_field_cpp_type->construct_from_field(r_value, std::move(attribute_field));
|
2021-09-16 20:49:10 -05:00
|
|
|
}
|
|
|
|
|
else {
|
2022-05-31 18:52:27 +02:00
|
|
|
init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
|
2021-09-16 20:49:10 -05:00
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2023-02-22 18:42:15 +01:00
|
|
|
static const lf::FunctionNode *find_viewer_lf_node(const bNode &viewer_bnode)
|
2022-09-13 08:44:26 +02:00
|
|
|
{
|
2023-02-22 18:42:15 +01:00
|
|
|
if (const blender::nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
|
|
|
|
|
blender::nodes::ensure_geometry_nodes_lazy_function_graph(viewer_bnode.owner_tree())) {
|
|
|
|
|
return lf_graph_info->mapping.viewer_node_map.lookup_default(&viewer_bnode, nullptr);
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
2022-09-13 08:44:26 +02:00
|
|
|
}
|
2023-02-22 18:42:15 +01:00
|
|
|
static const lf::FunctionNode *find_group_lf_node(const bNode &group_bnode)
|
2022-09-13 08:44:26 +02:00
|
|
|
{
|
2023-02-22 18:42:15 +01:00
|
|
|
if (const blender::nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
|
|
|
|
|
blender::nodes::ensure_geometry_nodes_lazy_function_graph(group_bnode.owner_tree())) {
|
|
|
|
|
return lf_graph_info->mapping.group_node_map.lookup_default(&group_bnode, nullptr);
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
2022-09-13 08:44:26 +02:00
|
|
|
}
|
|
|
|
|
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
static void find_side_effect_nodes_for_viewer_path(
|
|
|
|
|
const ViewerPath &viewer_path,
|
2022-09-13 08:44:26 +02:00
|
|
|
const NodesModifierData &nmd,
|
|
|
|
|
const ModifierEvalContext &ctx,
|
|
|
|
|
MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
|
2021-04-08 17:35:06 +02:00
|
|
|
{
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
const std::optional<blender::ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
|
|
|
|
|
blender::ed::viewer_path::parse_geometry_nodes_viewer(viewer_path);
|
|
|
|
|
if (!parsed_path.has_value()) {
|
2021-10-21 15:49:29 +02:00
|
|
|
return;
|
2021-04-15 08:57:10 +02:00
|
|
|
}
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
if (parsed_path->object != DEG_get_original_object(ctx.object)) {
|
2021-10-21 15:49:29 +02:00
|
|
|
return;
|
2021-04-15 08:57:10 +02:00
|
|
|
}
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
if (parsed_path->modifier_name != nmd.modifier.name) {
|
2021-10-21 15:49:29 +02:00
|
|
|
return;
|
2021-04-15 08:57:10 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
blender::ComputeContextBuilder compute_context_builder;
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
compute_context_builder.push<blender::bke::ModifierComputeContext>(parsed_path->modifier_name);
|
2021-04-15 08:57:10 +02:00
|
|
|
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
const bNodeTree *group = nmd.node_group;
|
2022-09-13 08:44:26 +02:00
|
|
|
Stack<const bNode *> group_node_stack;
|
2022-12-01 14:53:27 -06:00
|
|
|
for (const int32_t group_node_id : parsed_path->group_node_ids) {
|
|
|
|
|
const bNode *found_node = group->node_by_id(group_node_id);
|
2021-04-15 08:57:10 +02:00
|
|
|
if (found_node == nullptr) {
|
2021-10-21 15:49:29 +02:00
|
|
|
return;
|
2021-04-15 08:57:10 +02:00
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
if (found_node->id == nullptr) {
|
2021-10-21 15:49:29 +02:00
|
|
|
return;
|
2021-04-15 08:57:10 +02:00
|
|
|
}
|
2022-11-06 15:39:57 +01:00
|
|
|
if (found_node->is_muted()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
group_node_stack.push(found_node);
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
group = reinterpret_cast<bNodeTree *>(found_node->id);
|
2022-12-01 14:53:27 -06:00
|
|
|
compute_context_builder.push<blender::bke::NodeGroupComputeContext>(*found_node);
|
2021-04-15 08:57:10 +02:00
|
|
|
}
|
|
|
|
|
|
2022-12-01 14:53:27 -06:00
|
|
|
const bNode *found_viewer_node = group->node_by_id(parsed_path->viewer_node_id);
|
2022-09-13 08:44:26 +02:00
|
|
|
if (found_viewer_node == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-02-22 18:42:15 +01:00
|
|
|
const lf::FunctionNode *lf_viewer_node = find_viewer_lf_node(*found_viewer_node);
|
|
|
|
|
if (lf_viewer_node == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
|
|
|
|
|
/* Not only mark the viewer node as having side effects, but also all group nodes it is contained
|
|
|
|
|
* in. */
|
2023-02-22 18:42:15 +01:00
|
|
|
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_viewer_node);
|
2022-09-13 08:44:26 +02:00
|
|
|
compute_context_builder.pop();
|
|
|
|
|
while (!compute_context_builder.is_empty()) {
|
2023-02-22 18:42:15 +01:00
|
|
|
const lf::FunctionNode *lf_group_node = find_group_lf_node(*group_node_stack.pop());
|
|
|
|
|
if (lf_group_node == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_group_node);
|
2022-09-13 08:44:26 +02:00
|
|
|
compute_context_builder.pop();
|
|
|
|
|
}
|
2021-04-08 17:35:06 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
static void find_side_effect_nodes(
|
|
|
|
|
const NodesModifierData &nmd,
|
|
|
|
|
const ModifierEvalContext &ctx,
|
|
|
|
|
MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes)
|
2021-04-08 17:35:06 +02:00
|
|
|
{
|
2022-09-13 08:44:26 +02:00
|
|
|
Main *bmain = DEG_get_bmain(ctx.depsgraph);
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
|
|
|
|
|
if (wm == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) {
|
|
|
|
|
const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
|
|
|
|
|
const WorkSpace *workspace = BKE_workspace_active_get(window->workspace_hook);
|
|
|
|
|
find_side_effect_nodes_for_viewer_path(workspace->viewer_path, nmd, ctx, r_side_effect_nodes);
|
|
|
|
|
LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
|
|
|
|
|
const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
|
|
|
|
|
if (sl->spacetype == SPACE_SPREADSHEET) {
|
|
|
|
|
const SpaceSpreadsheet &sspreadsheet = *reinterpret_cast<const SpaceSpreadsheet *>(sl);
|
|
|
|
|
find_side_effect_nodes_for_viewer_path(
|
|
|
|
|
sspreadsheet.viewer_path, nmd, ctx, r_side_effect_nodes);
|
|
|
|
|
}
|
|
|
|
|
if (sl->spacetype == SPACE_VIEW3D) {
|
|
|
|
|
const View3D &v3d = *reinterpret_cast<const View3D *>(sl);
|
|
|
|
|
find_side_effect_nodes_for_viewer_path(v3d.viewer_path, nmd, ctx, r_side_effect_nodes);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-08 17:35:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-29 19:36:15 +01:00
|
|
|
static void find_socket_log_contexts(const NodesModifierData &nmd,
|
|
|
|
|
const ModifierEvalContext &ctx,
|
|
|
|
|
Set<blender::ComputeContextHash> &r_socket_log_contexts)
|
|
|
|
|
{
|
|
|
|
|
Main *bmain = DEG_get_bmain(ctx.depsgraph);
|
|
|
|
|
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
|
|
|
|
|
if (wm == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) {
|
|
|
|
|
const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
|
|
|
|
|
LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
|
|
|
|
|
const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
|
|
|
|
|
if (sl->spacetype == SPACE_NODE) {
|
|
|
|
|
const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
|
|
|
|
|
if (const std::optional<blender::ComputeContextHash> hash = blender::nodes::geo_eval_log::
|
|
|
|
|
GeoModifierLog::get_compute_context_hash_for_node_editor(snode,
|
|
|
|
|
nmd.modifier.name)) {
|
|
|
|
|
r_socket_log_contexts.add(*hash);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-07 11:20:19 +02:00
|
|
|
static void clear_runtime_data(NodesModifierData *nmd)
|
2021-04-08 17:35:06 +02:00
|
|
|
{
|
2021-07-07 11:20:19 +02:00
|
|
|
if (nmd->runtime_eval_log != nullptr) {
|
2022-09-13 08:44:26 +02:00
|
|
|
delete static_cast<GeoModifierLog *>(nmd->runtime_eval_log);
|
2021-07-07 11:20:19 +02:00
|
|
|
nmd->runtime_eval_log = nullptr;
|
2021-04-16 11:56:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-02 10:54:54 +01:00
|
|
|
struct OutputAttributeInfo {
|
|
|
|
|
GField field;
|
|
|
|
|
StringRefNull name;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct OutputAttributeToStore {
|
|
|
|
|
GeometryComponentType component_type;
|
2022-06-01 14:38:06 +10:00
|
|
|
eAttrDomain domain;
|
2022-02-02 10:54:54 +01:00
|
|
|
StringRefNull name;
|
|
|
|
|
GMutableSpan data;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The output attributes are organized based on their domain, because attributes on the same domain
|
|
|
|
|
* can be evaluated together.
|
|
|
|
|
*/
|
2022-06-01 14:38:06 +10:00
|
|
|
static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to_store(
|
2022-08-31 12:15:57 +02:00
|
|
|
const NodesModifierData &nmd, const bNode &output_node, Span<GMutablePointer> output_values)
|
2021-09-27 15:33:48 +02:00
|
|
|
{
|
2022-06-01 14:38:06 +10:00
|
|
|
MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain;
|
2022-08-31 12:15:57 +02:00
|
|
|
for (const bNodeSocket *socket : output_node.input_sockets().drop_front(1).drop_back(1)) {
|
|
|
|
|
if (!socket_type_has_attribute_toggle(*socket)) {
|
2022-02-02 10:54:54 +01:00
|
|
|
continue;
|
2021-09-27 15:33:48 +02:00
|
|
|
}
|
2022-02-02 10:54:54 +01:00
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
const std::string prop_name = socket->identifier + attribute_name_suffix;
|
2022-02-02 10:54:54 +01:00
|
|
|
const IDProperty *prop = IDP_GetPropertyFromGroup(nmd.settings.properties, prop_name.c_str());
|
|
|
|
|
if (prop == nullptr) {
|
|
|
|
|
continue;
|
2021-09-27 15:33:48 +02:00
|
|
|
}
|
2022-02-02 10:54:54 +01:00
|
|
|
const StringRefNull attribute_name = IDP_String(prop);
|
|
|
|
|
if (attribute_name.is_empty()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-05-31 18:52:27 +02:00
|
|
|
if (!blender::bke::allow_procedural_attribute_access(attribute_name)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-02-02 10:54:54 +01:00
|
|
|
|
|
|
|
|
const int index = socket->index();
|
|
|
|
|
const GPointer value = output_values[index];
|
2022-11-12 18:33:31 +01:00
|
|
|
const auto *value_or_field_type = ValueOrFieldCPPType::get_from_self(*value.type());
|
|
|
|
|
BLI_assert(value_or_field_type != nullptr);
|
|
|
|
|
const GField field = value_or_field_type->as_field(value.get());
|
2022-02-02 10:54:54 +01:00
|
|
|
|
|
|
|
|
const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink(
|
2022-08-31 12:15:57 +02:00
|
|
|
&nmd.node_group->outputs, index);
|
2022-06-01 14:38:06 +10:00
|
|
|
const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain;
|
2022-02-02 10:54:54 +01:00
|
|
|
OutputAttributeInfo output_info;
|
|
|
|
|
output_info.field = std::move(field);
|
|
|
|
|
output_info.name = attribute_name;
|
|
|
|
|
outputs_by_domain.add(domain, std::move(output_info));
|
2021-09-27 15:33:48 +02:00
|
|
|
}
|
2022-02-02 10:54:54 +01:00
|
|
|
return outputs_by_domain;
|
2021-09-27 15:33:48 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-02 10:54:54 +01:00
|
|
|
/**
|
|
|
|
|
* The computed values are stored in newly allocated arrays. They still have to be moved to the
|
|
|
|
|
* actual geometry.
|
|
|
|
|
*/
|
|
|
|
|
static Vector<OutputAttributeToStore> compute_attributes_to_store(
|
|
|
|
|
const GeometrySet &geometry,
|
2022-06-01 14:38:06 +10:00
|
|
|
const MultiValueMap<eAttrDomain, OutputAttributeInfo> &outputs_by_domain)
|
2021-09-27 15:33:48 +02:00
|
|
|
{
|
2022-02-02 10:54:54 +01:00
|
|
|
Vector<OutputAttributeToStore> attributes_to_store;
|
|
|
|
|
for (const GeometryComponentType component_type : {GEO_COMPONENT_TYPE_MESH,
|
|
|
|
|
GEO_COMPONENT_TYPE_POINT_CLOUD,
|
|
|
|
|
GEO_COMPONENT_TYPE_CURVE,
|
|
|
|
|
GEO_COMPONENT_TYPE_INSTANCES}) {
|
|
|
|
|
if (!geometry.has(component_type)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const GeometryComponent &component = *geometry.get_component_for_read(component_type);
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
const blender::bke::AttributeAccessor attributes = *component.attributes();
|
2022-02-02 10:54:54 +01:00
|
|
|
for (const auto item : outputs_by_domain.items()) {
|
2022-06-01 14:38:06 +10:00
|
|
|
const eAttrDomain domain = item.key;
|
2022-02-02 10:54:54 +01:00
|
|
|
const Span<OutputAttributeInfo> outputs_info = item.value;
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
if (!attributes.domain_supported(domain)) {
|
2022-02-02 10:54:54 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
const int domain_size = attributes.domain_size(domain);
|
Geometry Nodes: Use separate field context for each geometry type
Using the same `GeometryComponentFieldContext` for all situations,
even when only one geometry type is supported is misleading, and mixes
too many different abstraction levels into code that could be simpler.
With the attribute API moved out of geometry components recently,
the "component" system is just getting in the way here.
This commit adds specific field contexts for geometry types: meshes,
curves, point clouds, and instances. There are also separate field input
helper classes, to help reduce boilerplate for fields that only support
specific geometry types.
Another benefit of this change is that it separates geometry components
from fields, which makes it easier to see the purpose of the two concepts,
and how they relate.
Because we want to be able to evaluate a field on just `CurvesGeometry`
rather than the full `Curves` data-block, the generic "geometry context"
had to be changed to avoid using `GeometryComponent`, since there is
no corresponding geometry component type. The resulting void pointer
is ugly, but only turns up in three places in practice. When Apple clang
supports `std::variant`, that could be used instead.
Differential Revision: https://developer.blender.org/D15519
2022-08-30 11:08:27 -05:00
|
|
|
blender::bke::GeometryFieldContext field_context{component, domain};
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
blender::fn::FieldEvaluator field_evaluator{field_context, domain_size};
|
2022-02-02 10:54:54 +01:00
|
|
|
for (const OutputAttributeInfo &output_info : outputs_info) {
|
|
|
|
|
const CPPType &type = output_info.field.cpp_type();
|
2022-09-17 14:38:30 -05:00
|
|
|
const AttributeValidator validator = attributes.lookup_validator(output_info.name);
|
2022-02-02 10:54:54 +01:00
|
|
|
OutputAttributeToStore store{
|
|
|
|
|
component_type,
|
|
|
|
|
domain,
|
|
|
|
|
output_info.name,
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
GMutableSpan{
|
|
|
|
|
type, MEM_malloc_arrayN(domain_size, type.size(), __func__), domain_size}};
|
2022-09-17 14:38:30 -05:00
|
|
|
GField field = validator.validate_field_if_necessary(output_info.field);
|
|
|
|
|
field_evaluator.add_with_destination(std::move(field), store.data);
|
2022-02-02 10:54:54 +01:00
|
|
|
attributes_to_store.append(store);
|
|
|
|
|
}
|
|
|
|
|
field_evaluator.evaluate();
|
|
|
|
|
}
|
2021-09-27 15:33:48 +02:00
|
|
|
}
|
2022-02-02 10:54:54 +01:00
|
|
|
return attributes_to_store;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void store_computed_output_attributes(
|
|
|
|
|
GeometrySet &geometry, const Span<OutputAttributeToStore> attributes_to_store)
|
|
|
|
|
{
|
|
|
|
|
for (const OutputAttributeToStore &store : attributes_to_store) {
|
|
|
|
|
GeometryComponent &component = geometry.get_component_for_write(store.component_type);
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
blender::bke::MutableAttributeAccessor attributes = *component.attributes_for_write();
|
|
|
|
|
|
2022-06-01 14:38:06 +10:00
|
|
|
const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(
|
|
|
|
|
store.data.type());
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
const std::optional<AttributeMetaData> meta_data = attributes.lookup_meta_data(store.name);
|
2022-04-21 14:05:16 -05:00
|
|
|
|
|
|
|
|
/* Attempt to remove the attribute if it already exists but the domain and type don't match.
|
|
|
|
|
* Removing the attribute won't succeed if it is built in and non-removable. */
|
|
|
|
|
if (meta_data.has_value() &&
|
|
|
|
|
(meta_data->domain != store.domain || meta_data->data_type != data_type)) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
attributes.remove(store.name);
|
2022-02-02 10:54:54 +01:00
|
|
|
}
|
2022-04-21 14:05:16 -05:00
|
|
|
|
|
|
|
|
/* Try to create the attribute reusing the stored buffer. This will only succeed if the
|
|
|
|
|
* attribute didn't exist before, or if it existed but was removed above. */
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
if (attributes.add(store.name,
|
|
|
|
|
store.domain,
|
|
|
|
|
blender::bke::cpp_type_to_custom_data_type(store.data.type()),
|
Attributes: Improve custom data initialization options
When allocating new `CustomData` layers, often we do redundant
initialization of arrays. For example, it's common that values are
allocated, set to their default value, and then set to some other
value. This is wasteful, and it negates the benefits of optimizations
to the allocator like D15082. There are two reasons for this. The
first is array-of-structs storage that makes it annoying to initialize
values manually, and the second is confusing options in the Custom Data
API. This patch addresses the latter.
The `CustomData` "alloc type" options are rearranged. Now, besides
the options that use existing layers, there are two remaining:
* `CD_SET_DEFAULT` sets the default value.
* Usually zeroes, but for colors this is white (how it was before).
* Should be used when you add the layer but don't set all values.
* `CD_CONSTRUCT` refers to the "default construct" C++ term.
* Only necessary or defined for non-trivial types like vertex groups.
* Doesn't do anything for trivial types like `int` or `float3`.
* Should be used every other time, when all values will be set.
The attribute API's `AttributeInit` types are updated as well.
To update code, replace `CD_CALLOC` with `CD_SET_DEFAULT` and
`CD_DEFAULT` with `CD_CONSTRUCT`. This doesn't cause any functional
changes yet. Follow-up commits will change to avoid initializing
new layers where the correctness is clear.
Differential Revision: https://developer.blender.org/D15617
2022-08-30 14:54:53 -05:00
|
|
|
blender::bke::AttributeInitMoveArray(store.data.data()))) {
|
2022-04-21 14:05:16 -05:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
blender::bke::GAttributeWriter attribute = attributes.lookup_or_add_for_write(
|
2022-04-21 14:05:16 -05:00
|
|
|
store.name, store.domain, data_type);
|
|
|
|
|
if (attribute) {
|
Geometry Nodes: new geometry attribute API
Currently, there are two attribute API. The first, defined in `BKE_attribute.h` is
accessible from RNA and C code. The second is implemented with `GeometryComponent`
and is only accessible in C++ code. The second is widely used, but only being
accessible through the `GeometrySet` API makes it awkward to use, and even impossible
for types that don't correspond directly to a geometry component like `CurvesGeometry`.
This patch adds a new attribute API, designed to replace the `GeometryComponent`
attribute API now, and to eventually replace or be the basis of the other one.
The basic idea is that there is an `AttributeAccessor` class that allows code to
interact with a set of attributes owned by some geometry. The accessor itself has
no ownership. `AttributeAccessor` is a simple type that can be passed around by
value. That makes it easy to return it from functions and to store it in containers.
For const-correctness, there is also a `MutableAttributeAccessor` that allows
changing individual and can add or remove attributes.
Currently, `AttributeAccessor` is composed of two pointers. The first is a pointer
to the owner of the attribute data. The second is a pointer to a struct with
function pointers, that is similar to a virtual function table. The functions
know how to access attributes on the owner.
The actual attribute access for geometries is still implemented with the `AttributeProvider`
pattern, which makes it easy to support different sources of attributes on a
geometry and simplifies dealing with built-in attributes.
There are different ways to get an attribute accessor for a geometry:
* `GeometryComponent.attributes()`
* `CurvesGeometry.attributes()`
* `bke::mesh_attributes(const Mesh &)`
* `bke::pointcloud_attributes(const PointCloud &)`
All of these also have a `_for_write` variant that returns a `MutabelAttributeAccessor`.
Differential Revision: https://developer.blender.org/D15280
2022-07-08 16:16:56 +02:00
|
|
|
attribute.varray.set_all(store.data.data());
|
|
|
|
|
attribute.finish();
|
2022-02-02 10:54:54 +01:00
|
|
|
}
|
2022-04-21 14:05:16 -05:00
|
|
|
|
|
|
|
|
/* We were unable to reuse the data, so it must be destructed and freed. */
|
|
|
|
|
store.data.type().destruct_n(store.data.data(), store.data.size());
|
|
|
|
|
MEM_freeN(store.data.data());
|
2021-10-26 12:50:39 -05:00
|
|
|
}
|
2021-09-27 15:33:48 +02:00
|
|
|
}
|
|
|
|
|
|
2022-02-02 10:54:54 +01:00
|
|
|
static void store_output_attributes(GeometrySet &geometry,
|
|
|
|
|
const NodesModifierData &nmd,
|
2022-08-31 12:15:57 +02:00
|
|
|
const bNode &output_node,
|
2022-02-02 10:54:54 +01:00
|
|
|
Span<GMutablePointer> output_values)
|
|
|
|
|
{
|
|
|
|
|
/* All new attribute values have to be computed before the geometry is actually changed. This is
|
|
|
|
|
* necessary because some fields might depend on attributes that are overwritten. */
|
2022-06-01 14:38:06 +10:00
|
|
|
MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain =
|
2022-02-02 10:54:54 +01:00
|
|
|
find_output_attributes_to_store(nmd, output_node, output_values);
|
|
|
|
|
Vector<OutputAttributeToStore> attributes_to_store = compute_attributes_to_store(
|
|
|
|
|
geometry, outputs_by_domain);
|
|
|
|
|
store_computed_output_attributes(geometry, attributes_to_store);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
/**
|
|
|
|
|
* Evaluate a node group to compute the output geometry.
|
|
|
|
|
*/
|
2022-09-13 08:44:26 +02:00
|
|
|
static GeometrySet compute_geometry(
|
|
|
|
|
const bNodeTree &btree,
|
|
|
|
|
const blender::nodes::GeometryNodesLazyFunctionGraphInfo &lf_graph_info,
|
|
|
|
|
const bNode &output_node,
|
|
|
|
|
GeometrySet input_geometry_set,
|
|
|
|
|
NodesModifierData *nmd,
|
|
|
|
|
const ModifierEvalContext *ctx)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
2022-09-13 08:44:26 +02:00
|
|
|
const blender::nodes::GeometryNodeLazyFunctionGraphMapping &mapping = lf_graph_info.mapping;
|
|
|
|
|
|
2023-01-05 14:05:30 +01:00
|
|
|
Vector<const lf::OutputSocket *> graph_inputs = mapping.group_input_sockets;
|
|
|
|
|
graph_inputs.extend(mapping.group_output_used_sockets);
|
|
|
|
|
graph_inputs.extend(mapping.attribute_set_by_geometry_output.values().begin(),
|
|
|
|
|
mapping.attribute_set_by_geometry_output.values().end());
|
|
|
|
|
Vector<const lf::InputSocket *> graph_outputs = mapping.standard_group_output_sockets;
|
2020-12-02 13:25:25 +01:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
Array<GMutablePointer> param_inputs(graph_inputs.size());
|
|
|
|
|
Array<GMutablePointer> param_outputs(graph_outputs.size());
|
|
|
|
|
Array<std::optional<lf::ValueUsage>> param_input_usages(graph_inputs.size());
|
|
|
|
|
Array<lf::ValueUsage> param_output_usages(graph_outputs.size(), lf::ValueUsage::Used);
|
|
|
|
|
Array<bool> param_set_outputs(graph_outputs.size(), false);
|
2020-12-02 13:25:25 +01:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
blender::nodes::GeometryNodesLazyFunctionLogger lf_logger(lf_graph_info);
|
2022-09-14 12:02:27 +02:00
|
|
|
blender::nodes::GeometryNodesLazyFunctionSideEffectProvider lf_side_effect_provider;
|
2021-03-30 12:34:05 +02:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
lf::GraphExecutor graph_executor{
|
|
|
|
|
lf_graph_info.graph, graph_inputs, graph_outputs, &lf_logger, &lf_side_effect_provider};
|
2020-12-02 13:25:25 +01:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
blender::nodes::GeoNodesModifierData geo_nodes_modifier_data;
|
|
|
|
|
geo_nodes_modifier_data.depsgraph = ctx->depsgraph;
|
|
|
|
|
geo_nodes_modifier_data.self_object = ctx->object;
|
|
|
|
|
auto eval_log = std::make_unique<GeoModifierLog>();
|
2022-12-29 19:36:15 +01:00
|
|
|
|
|
|
|
|
Set<blender::ComputeContextHash> socket_log_contexts;
|
2022-09-13 08:44:26 +02:00
|
|
|
if (logging_enabled(ctx)) {
|
|
|
|
|
geo_nodes_modifier_data.eval_log = eval_log.get();
|
2022-12-29 19:36:15 +01:00
|
|
|
|
|
|
|
|
find_socket_log_contexts(*nmd, *ctx, socket_log_contexts);
|
|
|
|
|
geo_nodes_modifier_data.socket_log_contexts = &socket_log_contexts;
|
2022-09-13 08:44:26 +02:00
|
|
|
}
|
|
|
|
|
MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> r_side_effect_nodes;
|
Geometry Nodes: viewport preview
This adds support for showing geometry passed to the Viewer in the 3d
viewport (instead of just in the spreadsheet). The "viewer geometry"
bypasses the group output. So it is not necessary to change the final
output of the node group to be able to see the intermediate geometry.
**Activation and deactivation of a viewer node**
* A viewer node is activated by clicking on it.
* Ctrl+shift+click on any node/socket connects it to the viewer and
makes it active.
* Ctrl+shift+click in empty space deactivates the active viewer.
* When the active viewer is not visible anymore (e.g. another object
is selected, or the current node group is exit), it is deactivated.
* Clicking on the icon in the header of the Viewer node toggles whether
its active or not.
**Pinning**
* The spreadsheet still allows pinning the active viewer as before.
When pinned, the spreadsheet still references the viewer node even
when it becomes inactive.
* The viewport does not support pinning at the moment. It always shows
the active viewer.
**Attribute**
* When a field is linked to the second input of the viewer node it is
displayed as an overlay in the viewport.
* When possible the correct domain for the attribute is determined
automatically. This does not work in all cases. It falls back to the
face corner domain on meshes and the point domain on curves. When
necessary, the domain can be picked manually.
* The spreadsheet now only shows the "Viewer" column for the domain
that is selected in the Viewer node.
* Instance attributes are visualized as a constant color per instance.
**Viewport Options**
* The attribute overlay opacity can be controlled with the "Viewer Node"
setting in the overlays popover.
* A viewport can be configured not to show intermediate viewer-geometry
by disabling the "Viewer Node" option in the "View" menu.
**Implementation Details**
* The "spreadsheet context path" was generalized to a "viewer path" that
is used in more places now.
* The viewer node itself determines the attribute domain, evaluates the
field and stores the result in a `.viewer` attribute.
* A new "viewer attribute' overlay displays the data from the `.viewer`
attribute.
* The ground truth for the active viewer node is stored in the workspace
now. Node editors, spreadsheets and viewports retrieve the active
viewer from there unless they are pinned.
* The depsgraph object iterator has a new "viewer path" setting. When set,
the viewed geometry of the corresponding object is part of the iterator
instead of the final evaluated geometry.
* To support the instance attribute overlay `DupliObject` was extended
to contain the information necessary for drawing the overlay.
* The ctrl+shift+click operator has been refactored so that it can make
existing links to viewers active again.
* The auto-domain-detection in the Viewer node works by checking the
"preferred domain" for every field input. If there is not exactly one
preferred domain, the fallback is used.
Known limitations:
* Loose edges of meshes don't have the attribute overlay. This could be
added separately if necessary.
* Some attributes are hard to visualize as a color directly. For example,
the values might have to be normalized or some should be drawn as arrays.
For now, we encourage users to build node groups that generate appropriate
viewer-geometry. We might include some of that functionality in future versions.
Support for displaying attribute values as text in the viewport is planned as well.
* There seems to be an issue with the attribute overlay for pointclouds on
nvidia gpus, to be investigated.
Differential Revision: https://developer.blender.org/D15954
2022-09-28 17:54:59 +02:00
|
|
|
find_side_effect_nodes(*nmd, *ctx, r_side_effect_nodes);
|
2022-09-13 08:44:26 +02:00
|
|
|
geo_nodes_modifier_data.side_effect_nodes = &r_side_effect_nodes;
|
|
|
|
|
blender::nodes::GeoNodesLFUserData user_data;
|
|
|
|
|
user_data.modifier_data = &geo_nodes_modifier_data;
|
|
|
|
|
blender::bke::ModifierComputeContext modifier_compute_context{nullptr, nmd->modifier.name};
|
|
|
|
|
user_data.compute_context = &modifier_compute_context;
|
|
|
|
|
|
|
|
|
|
blender::LinearAllocator<> allocator;
|
|
|
|
|
Vector<GMutablePointer> inputs_to_destruct;
|
|
|
|
|
|
2023-01-05 14:05:30 +01:00
|
|
|
int input_index = -1;
|
|
|
|
|
for (const int i : btree.interface_inputs().index_range()) {
|
|
|
|
|
input_index++;
|
|
|
|
|
const bNodeSocket &interface_socket = *btree.interface_inputs()[i];
|
|
|
|
|
if (interface_socket.type == SOCK_GEOMETRY && input_index == 0) {
|
2022-09-13 08:44:26 +02:00
|
|
|
param_inputs[input_index] = &input_geometry_set;
|
|
|
|
|
continue;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-05 14:05:30 +01:00
|
|
|
const CPPType *type = interface_socket.typeinfo->geometry_nodes_cpp_type;
|
2022-09-13 08:44:26 +02:00
|
|
|
BLI_assert(type != nullptr);
|
|
|
|
|
void *value = allocator.allocate(type->size(), type->alignment());
|
2023-01-05 14:05:30 +01:00
|
|
|
initialize_group_input(*nmd, interface_socket, i, value);
|
2022-09-13 08:44:26 +02:00
|
|
|
param_inputs[input_index] = {type, value};
|
|
|
|
|
inputs_to_destruct.append({type, value});
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-05 14:05:30 +01:00
|
|
|
Array<bool> output_used_inputs(btree.interface_outputs().size(), true);
|
|
|
|
|
for (const int i : btree.interface_outputs().index_range()) {
|
|
|
|
|
input_index++;
|
|
|
|
|
param_inputs[input_index] = &output_used_inputs[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Array<blender::bke::AnonymousAttributeSet> attributes_to_propagate(
|
|
|
|
|
mapping.attribute_set_by_geometry_output.size());
|
|
|
|
|
for (const int i : attributes_to_propagate.index_range()) {
|
|
|
|
|
input_index++;
|
|
|
|
|
param_inputs[input_index] = &attributes_to_propagate[i];
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
for (const int i : graph_outputs.index_range()) {
|
|
|
|
|
const lf::InputSocket &socket = *graph_outputs[i];
|
|
|
|
|
const CPPType &type = socket.type();
|
|
|
|
|
void *buffer = allocator.allocate(type.size(), type.alignment());
|
|
|
|
|
param_outputs[i] = {type, buffer};
|
2021-09-27 15:33:48 +02:00
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
lf::Context lf_context;
|
|
|
|
|
lf_context.storage = graph_executor.init_storage(allocator);
|
|
|
|
|
lf_context.user_data = &user_data;
|
|
|
|
|
lf::BasicParams lf_params{graph_executor,
|
|
|
|
|
param_inputs,
|
|
|
|
|
param_outputs,
|
|
|
|
|
param_input_usages,
|
|
|
|
|
param_output_usages,
|
|
|
|
|
param_set_outputs};
|
|
|
|
|
graph_executor.execute(lf_params, lf_context);
|
|
|
|
|
graph_executor.destruct_storage(lf_context.storage);
|
2021-10-21 13:54:48 -05:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
for (GMutablePointer &ptr : inputs_to_destruct) {
|
|
|
|
|
ptr.destruct();
|
2021-07-07 11:20:19 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
GeometrySet output_geometry_set = std::move(*static_cast<GeometrySet *>(param_outputs[0].get()));
|
|
|
|
|
store_output_attributes(output_geometry_set, *nmd, output_node, param_outputs);
|
2021-04-27 13:03:40 +02:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
for (GMutablePointer &ptr : param_outputs) {
|
|
|
|
|
ptr.destruct();
|
2021-07-07 11:20:19 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
if (logging_enabled(ctx)) {
|
|
|
|
|
NodesModifierData *nmd_orig = reinterpret_cast<NodesModifierData *>(
|
|
|
|
|
BKE_modifier_get_original(ctx->object, &nmd->modifier));
|
|
|
|
|
delete static_cast<GeoModifierLog *>(nmd_orig->runtime_eval_log);
|
|
|
|
|
nmd_orig->runtime_eval_log = eval_log.release();
|
2021-09-27 15:33:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return output_geometry_set;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \note This could be done in #initialize_group_input, though that would require adding the
|
|
|
|
|
* the object as a parameter, so it's likely better to this check as a separate step.
|
|
|
|
|
*/
|
|
|
|
|
static void check_property_socket_sync(const Object *ob, ModifierData *md)
|
|
|
|
|
{
|
|
|
|
|
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
|
|
|
|
|
2021-11-11 11:47:19 -06:00
|
|
|
int geometry_socket_count = 0;
|
|
|
|
|
|
|
|
|
|
int i;
|
2020-12-02 13:25:25 +01:00
|
|
|
LISTBASE_FOREACH_INDEX (const bNodeSocket *, socket, &nmd->node_group->inputs, i) {
|
|
|
|
|
/* The first socket is the special geometry socket for the modifier object. */
|
2021-11-16 14:51:03 -06:00
|
|
|
if (i == 0 && socket->type == SOCK_GEOMETRY) {
|
|
|
|
|
geometry_socket_count++;
|
|
|
|
|
continue;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket->identifier);
|
|
|
|
|
if (property == nullptr) {
|
2021-01-13 08:13:57 -06:00
|
|
|
if (socket->type == SOCK_GEOMETRY) {
|
2021-11-11 11:47:19 -06:00
|
|
|
geometry_socket_count++;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BKE_modifier_set_error(ob, md, "Missing property for input socket \"%s\"", socket->name);
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
if (!id_property_type_matches_socket(*socket, *property)) {
|
2020-12-02 13:25:25 +01:00
|
|
|
BKE_modifier_set_error(
|
|
|
|
|
ob, md, "Property type does not match input socket \"(%s)\"", socket->name);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-11 11:47:19 -06:00
|
|
|
|
2021-11-16 14:51:03 -06:00
|
|
|
if (geometry_socket_count == 1) {
|
|
|
|
|
if (((bNodeSocket *)nmd->node_group->inputs.first)->type != SOCK_GEOMETRY) {
|
|
|
|
|
BKE_modifier_set_error(ob, md, "Node group's geometry input must be the first");
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void modifyGeometry(ModifierData *md,
|
|
|
|
|
const ModifierEvalContext *ctx,
|
|
|
|
|
GeometrySet &geometry_set)
|
|
|
|
|
{
|
|
|
|
|
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
|
|
|
|
if (nmd->node_group == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
const bNodeTree &tree = *nmd->node_group;
|
|
|
|
|
tree.ensure_topology_cache();
|
2020-12-02 13:25:25 +01:00
|
|
|
check_property_socket_sync(ctx->object, md);
|
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
const bNode *output_node = tree.group_output_node();
|
|
|
|
|
if (output_node == nullptr) {
|
|
|
|
|
BKE_modifier_set_error(ctx->object, md, "Node group must have a group output node");
|
2021-11-10 10:52:07 -06:00
|
|
|
geometry_set.clear();
|
2020-12-02 13:25:25 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
Span<const bNodeSocket *> group_outputs = output_node->input_sockets().drop_back(1);
|
2021-09-27 15:33:48 +02:00
|
|
|
if (group_outputs.is_empty()) {
|
2021-11-10 10:52:07 -06:00
|
|
|
BKE_modifier_set_error(ctx->object, md, "Node group must have an output socket");
|
|
|
|
|
geometry_set.clear();
|
2020-12-02 13:25:25 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-31 12:15:57 +02:00
|
|
|
const bNodeSocket *first_output_socket = group_outputs[0];
|
|
|
|
|
if (!STREQ(first_output_socket->idname, "NodeSocketGeometry")) {
|
2021-11-10 10:52:07 -06:00
|
|
|
BKE_modifier_set_error(ctx->object, md, "Node group's first output must be a geometry");
|
|
|
|
|
geometry_set.clear();
|
2020-12-02 13:25:25 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
const blender::nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
|
|
|
|
|
blender::nodes::ensure_geometry_nodes_lazy_function_graph(tree);
|
|
|
|
|
if (lf_graph_info == nullptr) {
|
|
|
|
|
BKE_modifier_set_error(ctx->object, md, "Cannot evaluate node group");
|
|
|
|
|
geometry_set.clear();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-02 16:10:42 +01:00
|
|
|
bool use_orig_index_verts = false;
|
|
|
|
|
bool use_orig_index_edges = false;
|
|
|
|
|
bool use_orig_index_polys = false;
|
2022-12-19 14:24:49 -06:00
|
|
|
if (const Mesh *mesh = geometry_set.get_mesh_for_read()) {
|
|
|
|
|
use_orig_index_verts = CustomData_has_layer(&mesh->vdata, CD_ORIGINDEX);
|
|
|
|
|
use_orig_index_edges = CustomData_has_layer(&mesh->edata, CD_ORIGINDEX);
|
|
|
|
|
use_orig_index_polys = CustomData_has_layer(&mesh->pdata, CD_ORIGINDEX);
|
2022-03-02 16:10:42 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
geometry_set = compute_geometry(
|
2022-09-13 08:44:26 +02:00
|
|
|
tree, *lf_graph_info, *output_node, std::move(geometry_set), nmd, ctx);
|
2022-03-02 16:10:42 +01:00
|
|
|
|
2022-12-19 14:24:49 -06:00
|
|
|
if (use_orig_index_verts || use_orig_index_edges || use_orig_index_polys) {
|
|
|
|
|
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
|
|
|
|
|
/* Add #CD_ORIGINDEX layers if they don't exist already. This is required because the
|
|
|
|
|
* #eModifierTypeFlag_SupportsMapping flag is set. If the layers did not exist before, it is
|
|
|
|
|
* assumed that the output mesh does not have a mapping to the original mesh. */
|
|
|
|
|
if (use_orig_index_verts) {
|
2023-03-14 15:30:26 +01:00
|
|
|
CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->totvert);
|
2022-12-19 14:24:49 -06:00
|
|
|
}
|
|
|
|
|
if (use_orig_index_edges) {
|
2023-03-14 15:30:26 +01:00
|
|
|
CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->totedge);
|
2022-12-19 14:24:49 -06:00
|
|
|
}
|
|
|
|
|
if (use_orig_index_polys) {
|
2023-03-14 15:30:26 +01:00
|
|
|
CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->totpoly);
|
2022-12-19 14:24:49 -06:00
|
|
|
}
|
2022-03-02 16:10:42 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2022-12-17 14:46:15 +01:00
|
|
|
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
|
|
|
|
|
{
|
|
|
|
|
GeometrySet geometry_set = GeometrySet::create_with_mesh(mesh, GeometryOwnershipType::Editable);
|
|
|
|
|
|
|
|
|
|
modifyGeometry(md, ctx, geometry_set);
|
|
|
|
|
|
|
|
|
|
Mesh *new_mesh = geometry_set.get_component_for_write<MeshComponent>().release();
|
|
|
|
|
if (new_mesh == nullptr) {
|
2023-02-27 11:09:26 -05:00
|
|
|
return BKE_mesh_new_nomain(0, 0, 0, 0);
|
2022-12-17 14:46:15 +01:00
|
|
|
}
|
|
|
|
|
return new_mesh;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-10 14:35:02 +01:00
|
|
|
static void modifyGeometrySet(ModifierData *md,
|
|
|
|
|
const ModifierEvalContext *ctx,
|
|
|
|
|
GeometrySet *geometry_set)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
|
|
|
|
modifyGeometry(md, ctx, *geometry_set);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-21 13:54:48 -05:00
|
|
|
struct AttributeSearchData {
|
2021-11-05 11:19:12 -05:00
|
|
|
uint32_t object_session_uid;
|
|
|
|
|
char modifier_name[MAX_NAME];
|
|
|
|
|
char socket_identifier[MAX_NAME];
|
2021-10-21 13:54:48 -05:00
|
|
|
bool is_output;
|
|
|
|
|
};
|
|
|
|
|
/* This class must not have a destructor, since it is used by buttons and freed with #MEM_freeN. */
|
|
|
|
|
BLI_STATIC_ASSERT(std::is_trivially_destructible_v<AttributeSearchData>, "");
|
|
|
|
|
|
2021-11-10 15:43:18 -06:00
|
|
|
static NodesModifierData *get_modifier_data(Main &bmain,
|
|
|
|
|
const wmWindowManager &wm,
|
|
|
|
|
const AttributeSearchData &data)
|
2021-10-21 13:54:48 -05:00
|
|
|
{
|
2021-11-10 15:43:18 -06:00
|
|
|
if (ED_screen_animation_playing(&wm)) {
|
|
|
|
|
/* Work around an issue where the attribute search exec function has stale pointers when data
|
|
|
|
|
* is reallocated when evaluating the node tree, causing a crash. This would be solved by
|
|
|
|
|
* allowing the UI search data to own arbitrary memory rather than just referencing it. */
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-05 11:19:12 -05:00
|
|
|
const Object *object = (Object *)BKE_libblock_find_session_uuid(
|
|
|
|
|
&bmain, ID_OB, data.object_session_uid);
|
|
|
|
|
if (object == nullptr) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
ModifierData *md = BKE_modifiers_findby_name(object, data.modifier_name);
|
|
|
|
|
if (md == nullptr) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
BLI_assert(md->type == eModifierType_Nodes);
|
|
|
|
|
return reinterpret_cast<NodesModifierData *>(md);
|
|
|
|
|
}
|
2021-10-21 13:54:48 -05:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
static GeoTreeLog *get_root_tree_log(const NodesModifierData &nmd)
|
|
|
|
|
{
|
|
|
|
|
if (nmd.runtime_eval_log == nullptr) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
GeoModifierLog &modifier_log = *static_cast<GeoModifierLog *>(nmd.runtime_eval_log);
|
|
|
|
|
blender::bke::ModifierComputeContext compute_context{nullptr, nmd.modifier.name};
|
|
|
|
|
return &modifier_log.get_tree_log(compute_context.hash());
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-05 11:19:12 -05:00
|
|
|
static void attribute_search_update_fn(
|
|
|
|
|
const bContext *C, void *arg, const char *str, uiSearchItems *items, const bool is_first)
|
|
|
|
|
{
|
|
|
|
|
AttributeSearchData &data = *static_cast<AttributeSearchData *>(arg);
|
2021-11-10 15:43:18 -06:00
|
|
|
const NodesModifierData *nmd = get_modifier_data(*CTX_data_main(C), *CTX_wm_manager(C), data);
|
2021-11-05 11:19:12 -05:00
|
|
|
if (nmd == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
if (nmd->node_group == nullptr) {
|
2021-11-05 11:19:12 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
GeoTreeLog *tree_log = get_root_tree_log(*nmd);
|
|
|
|
|
if (tree_log == nullptr) {
|
2021-10-21 13:54:48 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
tree_log->ensure_existing_attributes();
|
|
|
|
|
nmd->node_group->ensure_topology_cache();
|
2021-10-21 13:54:48 -05:00
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
Vector<const bNodeSocket *> sockets_to_check;
|
|
|
|
|
if (data.is_output) {
|
|
|
|
|
for (const bNode *node : nmd->node_group->nodes_by_type("NodeGroupOutput")) {
|
|
|
|
|
for (const bNodeSocket *socket : node->input_sockets()) {
|
|
|
|
|
if (socket->type == SOCK_GEOMETRY) {
|
|
|
|
|
sockets_to_check.append(socket);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-12-13 17:25:37 +01:00
|
|
|
for (const bNode *node : nmd->node_group->group_input_nodes()) {
|
2022-09-13 08:44:26 +02:00
|
|
|
for (const bNodeSocket *socket : node->output_sockets()) {
|
|
|
|
|
if (socket->type == SOCK_GEOMETRY) {
|
|
|
|
|
sockets_to_check.append(socket);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Set<StringRef> names;
|
|
|
|
|
Vector<const GeometryAttributeInfo *> attributes;
|
|
|
|
|
for (const bNodeSocket *socket : sockets_to_check) {
|
|
|
|
|
const ValueLog *value_log = tree_log->find_socket_value_log(*socket);
|
|
|
|
|
if (value_log == nullptr) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (const GeometryInfoLog *geo_log = dynamic_cast<const GeometryInfoLog *>(value_log)) {
|
|
|
|
|
for (const GeometryAttributeInfo &attribute : geo_log->attributes) {
|
|
|
|
|
if (names.add(attribute.name)) {
|
|
|
|
|
attributes.append(&attribute);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-21 13:54:48 -05:00
|
|
|
}
|
|
|
|
|
blender::ui::attribute_search_add_items(
|
2022-09-13 08:44:26 +02:00
|
|
|
str, data.is_output, attributes.as_span(), items, is_first);
|
2021-10-21 13:54:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
|
|
|
|
|
{
|
|
|
|
|
if (item_v == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
AttributeSearchData &data = *static_cast<AttributeSearchData *>(data_v);
|
|
|
|
|
const GeometryAttributeInfo &item = *static_cast<const GeometryAttributeInfo *>(item_v);
|
2021-11-10 15:43:18 -06:00
|
|
|
const NodesModifierData *nmd = get_modifier_data(*CTX_data_main(C), *CTX_wm_manager(C), data);
|
2021-11-05 11:19:12 -05:00
|
|
|
if (nmd == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-10-21 13:54:48 -05:00
|
|
|
|
2021-11-05 11:19:12 -05:00
|
|
|
const std::string attribute_prop_name = data.socket_identifier + attribute_name_suffix;
|
|
|
|
|
IDProperty &name_property = *IDP_GetPropertyFromGroup(nmd->settings.properties,
|
|
|
|
|
attribute_prop_name.c_str());
|
2021-10-21 13:54:48 -05:00
|
|
|
IDP_AssignString(&name_property, item.name.c_str(), 0);
|
|
|
|
|
|
|
|
|
|
ED_undo_push(C, "Assign Attribute Name");
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-05 11:19:12 -05:00
|
|
|
static void add_attribute_search_button(const bContext &C,
|
|
|
|
|
uiLayout *layout,
|
2021-10-21 13:54:48 -05:00
|
|
|
const NodesModifierData &nmd,
|
|
|
|
|
PointerRNA *md_ptr,
|
|
|
|
|
const StringRefNull rna_path_attribute_name,
|
|
|
|
|
const bNodeSocket &socket,
|
|
|
|
|
const bool is_output)
|
|
|
|
|
{
|
2022-09-13 08:44:26 +02:00
|
|
|
if (nmd.runtime_eval_log == nullptr) {
|
2021-10-21 13:54:48 -05:00
|
|
|
uiItemR(layout, md_ptr, rna_path_attribute_name.c_str(), 0, "", ICON_NONE);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiBlock *block = uiLayoutGetBlock(layout);
|
|
|
|
|
uiBut *but = uiDefIconTextButR(block,
|
|
|
|
|
UI_BTYPE_SEARCH_MENU,
|
|
|
|
|
0,
|
|
|
|
|
ICON_NONE,
|
|
|
|
|
"",
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
10 * UI_UNIT_X, /* Dummy value, replaced by layout system. */
|
|
|
|
|
UI_UNIT_Y,
|
|
|
|
|
md_ptr,
|
|
|
|
|
rna_path_attribute_name.c_str(),
|
|
|
|
|
0,
|
|
|
|
|
0.0f,
|
|
|
|
|
0.0f,
|
|
|
|
|
0.0f,
|
|
|
|
|
0.0f,
|
2022-02-17 23:44:16 -06:00
|
|
|
socket.description);
|
2021-10-21 13:54:48 -05:00
|
|
|
|
2021-11-05 11:19:12 -05:00
|
|
|
const Object *object = ED_object_context(&C);
|
|
|
|
|
BLI_assert(object != nullptr);
|
|
|
|
|
if (object == nullptr) {
|
2021-10-21 13:54:48 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-17 15:38:15 +01:00
|
|
|
AttributeSearchData *data = MEM_new<AttributeSearchData>(__func__);
|
2021-11-05 11:19:12 -05:00
|
|
|
data->object_session_uid = object->id.session_uuid;
|
|
|
|
|
STRNCPY(data->modifier_name, nmd.modifier.name);
|
|
|
|
|
STRNCPY(data->socket_identifier, socket.identifier);
|
|
|
|
|
data->is_output = is_output;
|
2021-10-21 13:54:48 -05:00
|
|
|
|
|
|
|
|
UI_but_func_search_set_results_are_suggestions(but, true);
|
|
|
|
|
UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
|
|
|
|
|
UI_but_func_search_set(but,
|
|
|
|
|
nullptr,
|
|
|
|
|
attribute_search_update_fn,
|
|
|
|
|
static_cast<void *>(data),
|
|
|
|
|
true,
|
|
|
|
|
nullptr,
|
|
|
|
|
attribute_search_exec_fn,
|
|
|
|
|
nullptr);
|
2022-05-31 18:52:27 +02:00
|
|
|
|
|
|
|
|
char *attribute_name = RNA_string_get_alloc(
|
|
|
|
|
md_ptr, rna_path_attribute_name.c_str(), nullptr, 0, nullptr);
|
|
|
|
|
const bool access_allowed = blender::bke::allow_procedural_attribute_access(attribute_name);
|
|
|
|
|
MEM_freeN(attribute_name);
|
|
|
|
|
if (!access_allowed) {
|
|
|
|
|
UI_but_flag_enable(but, UI_BUT_REDALERT);
|
|
|
|
|
}
|
2021-10-21 13:54:48 -05:00
|
|
|
}
|
|
|
|
|
|
2021-11-05 11:19:12 -05:00
|
|
|
static void add_attribute_search_or_value_buttons(const bContext &C,
|
|
|
|
|
uiLayout *layout,
|
2021-10-21 13:54:48 -05:00
|
|
|
const NodesModifierData &nmd,
|
|
|
|
|
PointerRNA *md_ptr,
|
|
|
|
|
const bNodeSocket &socket)
|
|
|
|
|
{
|
|
|
|
|
char socket_id_esc[sizeof(socket.identifier) * 2];
|
|
|
|
|
BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc));
|
|
|
|
|
const std::string rna_path = "[\"" + std::string(socket_id_esc) + "\"]";
|
|
|
|
|
const std::string rna_path_use_attribute = "[\"" + std::string(socket_id_esc) +
|
|
|
|
|
use_attribute_suffix + "\"]";
|
|
|
|
|
const std::string rna_path_attribute_name = "[\"" + std::string(socket_id_esc) +
|
|
|
|
|
attribute_name_suffix + "\"]";
|
|
|
|
|
|
2022-11-08 19:09:28 +01:00
|
|
|
/* We're handling this manually in this case. */
|
|
|
|
|
uiLayoutSetPropDecorate(layout, false);
|
|
|
|
|
|
2021-10-21 13:54:48 -05:00
|
|
|
uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
|
|
|
|
|
uiLayout *name_row = uiLayoutRow(split, false);
|
|
|
|
|
uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT);
|
2023-01-20 17:41:34 -06:00
|
|
|
|
|
|
|
|
const int use_attribute = RNA_int_get(md_ptr, rna_path_use_attribute.c_str()) != 0;
|
|
|
|
|
if (socket.type == SOCK_BOOLEAN && !use_attribute) {
|
2023-01-20 17:36:07 -06:00
|
|
|
uiItemL(name_row, "", ICON_NONE);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
uiItemL(name_row, socket.name, ICON_NONE);
|
|
|
|
|
}
|
2021-10-21 13:54:48 -05:00
|
|
|
|
2022-11-08 19:09:28 +01:00
|
|
|
uiLayout *prop_row = uiLayoutRow(split, true);
|
2023-01-20 17:36:07 -06:00
|
|
|
if (socket.type == SOCK_BOOLEAN) {
|
2023-01-20 17:41:34 -06:00
|
|
|
uiLayoutSetPropSep(prop_row, false);
|
|
|
|
|
uiLayoutSetAlignment(prop_row, UI_LAYOUT_ALIGN_EXPAND);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (use_attribute) {
|
|
|
|
|
add_attribute_search_button(C, prop_row, nmd, md_ptr, rna_path_attribute_name, socket, false);
|
|
|
|
|
uiItemL(layout, "", ICON_BLANK1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const char *name = socket.type == SOCK_BOOLEAN ? socket.name : "";
|
|
|
|
|
uiItemR(prop_row, md_ptr, rna_path.c_str(), 0, name, ICON_NONE);
|
|
|
|
|
uiItemDecoratorR(layout, md_ptr, rna_path.c_str(), -1);
|
2023-01-20 17:36:07 -06:00
|
|
|
}
|
2021-10-21 13:54:48 -05:00
|
|
|
|
|
|
|
|
PointerRNA props;
|
2022-11-08 19:09:28 +01:00
|
|
|
uiItemFullO(prop_row,
|
2021-10-21 13:54:48 -05:00
|
|
|
"object.geometry_nodes_input_attribute_toggle",
|
|
|
|
|
"",
|
|
|
|
|
ICON_SPREADSHEET,
|
|
|
|
|
nullptr,
|
|
|
|
|
WM_OP_INVOKE_DEFAULT,
|
|
|
|
|
0,
|
|
|
|
|
&props);
|
|
|
|
|
RNA_string_set(&props, "modifier_name", nmd.modifier.name);
|
|
|
|
|
RNA_string_set(&props, "prop_path", rna_path_use_attribute.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
/* Drawing the properties manually with #uiItemR instead of #uiDefAutoButsRNA allows using
|
|
|
|
|
* the node socket identifier for the property names, since they are unique, but also having
|
2021-06-24 15:56:58 +10:00
|
|
|
* the correct label displayed in the UI. */
|
2021-11-05 11:19:12 -05:00
|
|
|
static void draw_property_for_socket(const bContext &C,
|
|
|
|
|
uiLayout *layout,
|
2021-09-28 12:05:42 -05:00
|
|
|
NodesModifierData *nmd,
|
|
|
|
|
PointerRNA *bmain_ptr,
|
|
|
|
|
PointerRNA *md_ptr,
|
|
|
|
|
const bNodeSocket &socket,
|
|
|
|
|
const int socket_index)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
|
|
|
|
/* The property should be created in #MOD_nodes_update_interface with the correct type. */
|
2021-09-16 20:49:10 -05:00
|
|
|
IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket.identifier);
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
/* IDProperties can be removed with python, so there could be a situation where
|
|
|
|
|
* there isn't a property for a socket or it doesn't have the correct type. */
|
Refactor IDProperty UI data storage
The storage of IDProperty UI data (min, max, default value, etc) is
quite complicated. For every property, retrieving a single one of these
values involves three string lookups. First for the "_RNA_UI" group
property, then another for a group with the property's name, then for
the data value name. Not only is this inefficient, it's hard to reason
about, unintuitive, and not at all self-explanatory.
This commit replaces that system with a UI data struct directly in the
IDProperty. If it's not used, the only cost is of a NULL pointer. Beyond
storing the description, name, and RNA subtype, derived structs are used
to store type specific UI data like min and max.
Note that this means that addons using (abusing) the `_RNA_UI` custom
property will have to be changed. A few places in the addons repository
will be changed after this commit with D9919.
**Before**
Before, first the _RNA_UI subgroup is retrieved the _RNA_UI group,
then the subgroup for the original property, then specific UI data
is accessed like any other IDProperty.
```
prop = rna_idprop_ui_prop_get(idproperties_owner, "prop_name", create=True)
prop["min"] = 1.0
```
**After**
After, the `id_properties_ui` function for RNA structs returns a python
object specifically for managing an IDProperty's UI data.
```
ui_data = idproperties_owner.id_properties_ui("prop_name")
ui_data.update(min=1.0)
```
In addition to `update`, there are now other functions:
- `as_dict`: Returns a dictionary of the property's UI data.
- `clear`: Removes the property's UI data.
- `update_from`: Copy UI data between properties,
even if they have different owners.
Differential Revision: https://developer.blender.org/D9697
2021-08-27 08:27:24 -05:00
|
|
|
if (property == nullptr || !id_property_type_matches_socket(socket, *property)) {
|
2021-04-29 10:46:55 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2020-12-14 18:44:04 +11:00
|
|
|
|
2021-04-29 10:46:55 -05:00
|
|
|
char socket_id_esc[sizeof(socket.identifier) * 2];
|
|
|
|
|
BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc));
|
2020-12-14 18:44:04 +11:00
|
|
|
|
2021-04-29 10:46:55 -05:00
|
|
|
char rna_path[sizeof(socket_id_esc) + 4];
|
|
|
|
|
BLI_snprintf(rna_path, ARRAY_SIZE(rna_path), "[\"%s\"]", socket_id_esc);
|
2021-01-13 08:13:57 -06:00
|
|
|
|
2022-11-08 19:09:28 +01:00
|
|
|
uiLayout *row = uiLayoutRow(layout, true);
|
|
|
|
|
uiLayoutSetPropDecorate(row, true);
|
|
|
|
|
|
2021-04-29 10:46:55 -05:00
|
|
|
/* Use #uiItemPointerR to draw pointer properties because #uiItemR would not have enough
|
|
|
|
|
* information about what type of ID to select for editing the values. This is because
|
|
|
|
|
* pointer IDProperties contain no information about their type. */
|
|
|
|
|
switch (socket.type) {
|
|
|
|
|
case SOCK_OBJECT: {
|
2022-11-08 19:09:28 +01:00
|
|
|
uiItemPointerR(row, md_ptr, rna_path, bmain_ptr, "objects", socket.name, ICON_OBJECT_DATA);
|
2021-04-29 10:46:55 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SOCK_COLLECTION: {
|
2022-11-08 19:09:28 +01:00
|
|
|
uiItemPointerR(
|
|
|
|
|
row, md_ptr, rna_path, bmain_ptr, "collections", socket.name, ICON_OUTLINER_COLLECTION);
|
2021-04-29 10:46:55 -05:00
|
|
|
break;
|
2021-01-13 08:13:57 -06:00
|
|
|
}
|
2021-05-27 11:06:08 -04:00
|
|
|
case SOCK_MATERIAL: {
|
2022-11-08 19:09:28 +01:00
|
|
|
uiItemPointerR(row, md_ptr, rna_path, bmain_ptr, "materials", socket.name, ICON_MATERIAL);
|
2021-05-27 11:06:08 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SOCK_TEXTURE: {
|
2022-11-08 19:09:28 +01:00
|
|
|
uiItemPointerR(row, md_ptr, rna_path, bmain_ptr, "textures", socket.name, ICON_TEXTURE);
|
2021-05-27 11:06:08 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2021-10-14 14:18:24 +01:00
|
|
|
case SOCK_IMAGE: {
|
2022-11-08 19:09:28 +01:00
|
|
|
uiItemPointerR(row, md_ptr, rna_path, bmain_ptr, "images", socket.name, ICON_IMAGE);
|
2021-10-14 14:18:24 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2021-09-16 20:49:10 -05:00
|
|
|
default: {
|
2021-09-28 13:22:52 -05:00
|
|
|
if (input_has_attribute_toggle(*nmd->node_group, socket_index)) {
|
2022-11-08 19:09:28 +01:00
|
|
|
add_attribute_search_or_value_buttons(C, row, *nmd, md_ptr, socket);
|
2021-09-16 20:49:10 -05:00
|
|
|
}
|
|
|
|
|
else {
|
2021-10-21 13:54:48 -05:00
|
|
|
uiItemR(row, md_ptr, rna_path, 0, socket.name, ICON_NONE);
|
2021-09-16 20:49:10 -05:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
2023-01-20 17:41:34 -06:00
|
|
|
if (!input_has_attribute_toggle(*nmd->node_group, socket_index)) {
|
|
|
|
|
uiItemL(row, "", ICON_BLANK1);
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-11-05 11:19:12 -05:00
|
|
|
static void draw_property_for_output_socket(const bContext &C,
|
|
|
|
|
uiLayout *layout,
|
2021-10-21 13:54:48 -05:00
|
|
|
const NodesModifierData &nmd,
|
2021-09-27 15:33:48 +02:00
|
|
|
PointerRNA *md_ptr,
|
|
|
|
|
const bNodeSocket &socket)
|
|
|
|
|
{
|
|
|
|
|
char socket_id_esc[sizeof(socket.identifier) * 2];
|
|
|
|
|
BLI_str_escape(socket_id_esc, socket.identifier, sizeof(socket_id_esc));
|
|
|
|
|
const std::string rna_path_attribute_name = "[\"" + StringRef(socket_id_esc) +
|
|
|
|
|
attribute_name_suffix + "\"]";
|
|
|
|
|
|
2021-10-21 13:54:48 -05:00
|
|
|
uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
|
|
|
|
|
uiLayout *name_row = uiLayoutRow(split, false);
|
|
|
|
|
uiLayoutSetAlignment(name_row, UI_LAYOUT_ALIGN_RIGHT);
|
|
|
|
|
uiItemL(name_row, socket.name, ICON_NONE);
|
|
|
|
|
|
|
|
|
|
uiLayout *row = uiLayoutRow(split, true);
|
2021-11-05 11:19:12 -05:00
|
|
|
add_attribute_search_button(C, row, nmd, md_ptr, rna_path_attribute_name, socket, true);
|
2021-09-27 15:33:48 +02:00
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
static void panel_draw(const bContext *C, Panel *panel)
|
|
|
|
|
{
|
|
|
|
|
uiLayout *layout = panel->layout;
|
2021-01-13 08:13:57 -06:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
|
|
|
|
|
NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
|
|
|
|
|
|
|
|
|
|
uiLayoutSetPropSep(layout, true);
|
2021-10-21 13:54:48 -05:00
|
|
|
/* Decorators are added manually for supported properties because the
|
|
|
|
|
* attribute/value toggle requires a manually built layout anyway. */
|
|
|
|
|
uiLayoutSetPropDecorate(layout, false);
|
2020-12-02 13:25:25 +01:00
|
|
|
|
|
|
|
|
uiTemplateID(layout,
|
|
|
|
|
C,
|
|
|
|
|
ptr,
|
|
|
|
|
"node_group",
|
|
|
|
|
"node.new_geometry_node_group_assign",
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
|
|
|
|
0,
|
|
|
|
|
false,
|
|
|
|
|
nullptr);
|
|
|
|
|
|
|
|
|
|
if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
|
2021-01-13 08:13:57 -06:00
|
|
|
PointerRNA bmain_ptr;
|
|
|
|
|
RNA_main_pointer_create(bmain, &bmain_ptr);
|
|
|
|
|
|
2021-09-28 12:05:42 -05:00
|
|
|
int socket_index;
|
|
|
|
|
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &nmd->node_group->inputs, socket_index) {
|
2023-02-11 16:11:10 +01:00
|
|
|
if (!(socket->flag & SOCK_HIDE_IN_MODIFIER)) {
|
|
|
|
|
draw_property_for_socket(*C, layout, nmd, &bmain_ptr, ptr, *socket, socket_index);
|
|
|
|
|
}
|
2021-09-27 15:33:48 +02:00
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2021-07-22 17:53:35 -04:00
|
|
|
/* Draw node warnings. */
|
2022-09-13 08:44:26 +02:00
|
|
|
GeoTreeLog *tree_log = get_root_tree_log(*nmd);
|
|
|
|
|
if (tree_log != nullptr) {
|
|
|
|
|
tree_log->ensure_node_warnings();
|
|
|
|
|
for (const NodeWarning &warning : tree_log->all_warnings) {
|
|
|
|
|
if (warning.type != NodeWarningType::Info) {
|
|
|
|
|
uiItemL(layout, warning.message.c_str(), ICON_ERROR);
|
2021-07-22 17:53:35 -04:00
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
}
|
2021-07-22 17:53:35 -04:00
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
modifier_panel_end(layout, ptr);
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-05 11:19:12 -05:00
|
|
|
static void output_attribute_panel_draw(const bContext *C, Panel *panel)
|
2021-09-27 13:04:58 -05:00
|
|
|
{
|
|
|
|
|
uiLayout *layout = panel->layout;
|
|
|
|
|
|
|
|
|
|
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
|
|
|
|
|
NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
|
|
|
|
|
|
|
|
|
|
uiLayoutSetPropSep(layout, true);
|
|
|
|
|
uiLayoutSetPropDecorate(layout, true);
|
|
|
|
|
|
2021-10-27 08:54:24 -05:00
|
|
|
bool has_output_attribute = false;
|
2021-09-27 13:04:58 -05:00
|
|
|
if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
|
|
|
|
|
LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->outputs) {
|
|
|
|
|
if (socket_type_has_attribute_toggle(*socket)) {
|
2021-10-27 08:54:24 -05:00
|
|
|
has_output_attribute = true;
|
2021-11-05 11:19:12 -05:00
|
|
|
draw_property_for_output_socket(*C, layout, *nmd, ptr, *socket);
|
2021-09-27 13:04:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-27 08:54:24 -05:00
|
|
|
if (!has_output_attribute) {
|
2021-11-02 17:20:24 +01:00
|
|
|
uiItemL(layout, TIP_("No group output attributes connected"), ICON_INFO);
|
2021-10-27 08:54:24 -05:00
|
|
|
}
|
2021-09-27 13:04:58 -05:00
|
|
|
}
|
|
|
|
|
|
2022-10-03 17:37:25 -05:00
|
|
|
static void internal_dependencies_panel_draw(const bContext * /*C*/, Panel *panel)
|
2022-04-21 15:10:07 +02:00
|
|
|
{
|
|
|
|
|
uiLayout *layout = panel->layout;
|
|
|
|
|
|
|
|
|
|
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
|
|
|
|
|
NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
|
|
|
|
|
|
2022-09-13 08:44:26 +02:00
|
|
|
GeoTreeLog *tree_log = get_root_tree_log(*nmd);
|
|
|
|
|
if (tree_log == nullptr) {
|
2022-04-21 15:10:07 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
|
|
|
|
|
tree_log->ensure_used_named_attributes();
|
2022-09-17 12:08:43 +02:00
|
|
|
const Map<StringRefNull, NamedAttributeUsage> &usage_by_attribute =
|
2022-09-13 08:44:26 +02:00
|
|
|
tree_log->used_named_attributes;
|
2022-04-21 15:10:07 +02:00
|
|
|
|
|
|
|
|
if (usage_by_attribute.is_empty()) {
|
|
|
|
|
uiItemL(layout, IFACE_("No named attributes used"), ICON_INFO);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-25 16:00:43 +02:00
|
|
|
struct NameWithUsage {
|
|
|
|
|
StringRefNull name;
|
2022-09-13 08:44:26 +02:00
|
|
|
NamedAttributeUsage usage;
|
2022-04-25 16:00:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Vector<NameWithUsage> sorted_used_attribute;
|
2022-04-21 15:10:07 +02:00
|
|
|
for (auto &&item : usage_by_attribute.items()) {
|
|
|
|
|
sorted_used_attribute.append({item.key, item.value});
|
|
|
|
|
}
|
2022-04-25 16:00:43 +02:00
|
|
|
std::sort(sorted_used_attribute.begin(),
|
|
|
|
|
sorted_used_attribute.end(),
|
|
|
|
|
[](const NameWithUsage &a, const NameWithUsage &b) {
|
|
|
|
|
return BLI_strcasecmp_natural(a.name.c_str(), b.name.c_str()) <= 0;
|
|
|
|
|
});
|
2022-04-21 15:10:07 +02:00
|
|
|
|
2022-04-25 16:00:43 +02:00
|
|
|
for (const NameWithUsage &attribute : sorted_used_attribute) {
|
|
|
|
|
const StringRefNull attribute_name = attribute.name;
|
2022-09-13 08:44:26 +02:00
|
|
|
const NamedAttributeUsage usage = attribute.usage;
|
2022-04-21 15:10:07 +02:00
|
|
|
|
|
|
|
|
/* #uiLayoutRowWithHeading doesn't seem to work in this case. */
|
|
|
|
|
uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
|
|
|
|
|
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
Vector<std::string> usages;
|
2022-09-13 08:44:26 +02:00
|
|
|
if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) {
|
2022-04-21 15:10:07 +02:00
|
|
|
usages.append(TIP_("Read"));
|
|
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) {
|
2022-04-21 15:10:07 +02:00
|
|
|
usages.append(TIP_("Write"));
|
|
|
|
|
}
|
2022-09-13 08:44:26 +02:00
|
|
|
if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) {
|
2022-04-21 15:10:07 +02:00
|
|
|
usages.append(TIP_("Remove"));
|
|
|
|
|
}
|
|
|
|
|
for (const int i : usages.index_range()) {
|
|
|
|
|
ss << usages[i];
|
|
|
|
|
if (i < usages.size() - 1) {
|
|
|
|
|
ss << ", ";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiLayout *row = uiLayoutRow(split, false);
|
|
|
|
|
uiLayoutSetAlignment(row, UI_LAYOUT_ALIGN_RIGHT);
|
|
|
|
|
uiLayoutSetActive(row, false);
|
|
|
|
|
uiItemL(row, ss.str().c_str(), ICON_NONE);
|
|
|
|
|
|
|
|
|
|
row = uiLayoutRow(split, false);
|
|
|
|
|
uiItemL(row, attribute_name.c_str(), ICON_NONE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
static void panelRegister(ARegionType *region_type)
|
|
|
|
|
{
|
2021-09-27 13:04:58 -05:00
|
|
|
PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
|
|
|
|
|
modifier_subpanel_register(region_type,
|
|
|
|
|
"output_attributes",
|
|
|
|
|
N_("Output Attributes"),
|
|
|
|
|
nullptr,
|
|
|
|
|
output_attribute_panel_draw,
|
|
|
|
|
panel_type);
|
2022-04-21 15:10:07 +02:00
|
|
|
modifier_subpanel_register(region_type,
|
2022-04-26 16:58:53 +02:00
|
|
|
"internal_dependencies",
|
|
|
|
|
N_("Internal Dependencies"),
|
2022-04-21 15:10:07 +02:00
|
|
|
nullptr,
|
2022-04-26 16:58:53 +02:00
|
|
|
internal_dependencies_panel_draw,
|
2022-04-21 15:10:07 +02:00
|
|
|
panel_type);
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2022-10-03 17:37:25 -05:00
|
|
|
static void blendWrite(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
|
2020-12-02 13:25:25 +01:00
|
|
|
{
|
|
|
|
|
const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
|
2022-05-16 16:00:00 +02:00
|
|
|
|
|
|
|
|
BLO_write_struct(writer, NodesModifierData, nmd);
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
if (nmd->settings.properties != nullptr) {
|
2023-01-20 17:36:07 -06:00
|
|
|
Map<IDProperty *, IDPropertyUIDataBool *> boolean_props;
|
2023-01-23 15:06:55 -06:00
|
|
|
if (!BLO_write_is_undo(writer)) {
|
|
|
|
|
/* Boolean properties are added automatically for boolean node group inputs. Integer
|
|
|
|
|
* properties are automatically converted to boolean sockets where applicable as well.
|
|
|
|
|
* However, boolean properties will crash old versions of Blender, so convert them to integer
|
|
|
|
|
* properties for writing. The actual value is stored in the same variable for both types */
|
|
|
|
|
LISTBASE_FOREACH (IDProperty *, prop, &nmd->settings.properties->data.group) {
|
|
|
|
|
if (prop->type == IDP_BOOLEAN) {
|
|
|
|
|
boolean_props.add_new(prop, reinterpret_cast<IDPropertyUIDataBool *>(prop->ui_data));
|
|
|
|
|
prop->type = IDP_INT;
|
|
|
|
|
prop->ui_data = nullptr;
|
|
|
|
|
}
|
2023-01-20 17:36:07 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
/* Note that the property settings are based on the socket type info
|
|
|
|
|
* and don't necessarily need to be written, but we can't just free them. */
|
|
|
|
|
IDP_BlendWrite(writer, nmd->settings.properties);
|
2023-01-20 17:36:07 -06:00
|
|
|
|
2023-01-23 15:06:55 -06:00
|
|
|
if (!BLO_write_is_undo(writer)) {
|
|
|
|
|
LISTBASE_FOREACH (IDProperty *, prop, &nmd->settings.properties->data.group) {
|
|
|
|
|
if (prop->type == IDP_INT) {
|
|
|
|
|
if (IDPropertyUIDataBool **ui_data = boolean_props.lookup_ptr(prop)) {
|
|
|
|
|
prop->type = IDP_BOOLEAN;
|
|
|
|
|
if (ui_data) {
|
|
|
|
|
prop->ui_data = reinterpret_cast<IDPropertyUIData *>(*ui_data);
|
|
|
|
|
}
|
2023-01-20 17:36:07 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void blendRead(BlendDataReader *reader, ModifierData *md)
|
|
|
|
|
{
|
|
|
|
|
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
2022-04-28 08:39:30 -05:00
|
|
|
if (nmd->node_group == nullptr) {
|
|
|
|
|
nmd->settings.properties = nullptr;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLO_read_data_address(reader, &nmd->settings.properties);
|
|
|
|
|
IDP_BlendDataRead(reader, &nmd->settings.properties);
|
|
|
|
|
}
|
2021-07-07 11:20:19 +02:00
|
|
|
nmd->runtime_eval_log = nullptr;
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void copyData(const ModifierData *md, ModifierData *target, const int flag)
|
|
|
|
|
{
|
|
|
|
|
const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
|
|
|
|
|
NodesModifierData *tnmd = reinterpret_cast<NodesModifierData *>(target);
|
|
|
|
|
|
|
|
|
|
BKE_modifier_copydata_generic(md, target, flag);
|
|
|
|
|
|
2021-07-07 11:20:19 +02:00
|
|
|
tnmd->runtime_eval_log = nullptr;
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
if (nmd->settings.properties != nullptr) {
|
|
|
|
|
tnmd->settings.properties = IDP_CopyProperty_ex(nmd->settings.properties, flag);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void freeData(ModifierData *md)
|
|
|
|
|
{
|
|
|
|
|
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
|
|
|
|
|
if (nmd->settings.properties != nullptr) {
|
|
|
|
|
IDP_FreeProperty_ex(nmd->settings.properties, false);
|
|
|
|
|
nmd->settings.properties = nullptr;
|
|
|
|
|
}
|
2021-07-07 11:20:19 +02:00
|
|
|
|
|
|
|
|
clear_runtime_data(nmd);
|
2020-12-02 13:25:25 +01:00
|
|
|
}
|
|
|
|
|
|
2022-10-03 17:37:25 -05:00
|
|
|
static void requiredDataMask(ModifierData * /*md*/, CustomData_MeshMasks *r_cddata_masks)
|
2020-12-14 15:28:24 +01:00
|
|
|
{
|
|
|
|
|
/* We don't know what the node tree will need. If there are vertex groups, it is likely that the
|
|
|
|
|
* node tree wants to access them. */
|
|
|
|
|
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
|
2021-03-31 16:25:23 +02:00
|
|
|
r_cddata_masks->vmask |= CD_MASK_PROP_ALL;
|
2020-12-14 15:28:24 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-02 13:25:25 +01:00
|
|
|
ModifierTypeInfo modifierType_Nodes = {
|
2023-01-16 12:41:11 +11:00
|
|
|
/*name*/ N_("GeometryNodes"),
|
|
|
|
|
/*structName*/ "NodesModifierData",
|
|
|
|
|
/*structSize*/ sizeof(NodesModifierData),
|
|
|
|
|
/*srna*/ &RNA_NodesModifier,
|
|
|
|
|
/*type*/ eModifierTypeType_Constructive,
|
|
|
|
|
/*flags*/
|
Geometry Nodes: Support modifier on curve objects
With this commit, curve objects support the geometry nodes modifier.
Curves objects now evaluate to `CurveEval` unless there was a previous
implicit conversion (tessellating modifiers, mesh modifiers, or the
settings in the curve "Geometry" panel). In the new code, curves are
only considered to be the wire edges-- any generated surface is a mesh
instead, stored in the evaluated geometry set.
The consolidation of concepts mentioned above allows remove a lot of
code that had to do with maintaining the `DispList` type temporarily
for modifiers and rendering. Instead, render engines see a separate
object for the mesh from the mesh geometry component, and when the
curve object evaluates to a curve, the `CurveEval` is always used for
drawing wire edges.
However, currently the `DispList` type is still maintained and used as
an intermediate step in implicit mesh conversion. In the future, more
uses of it could be changed to use `CurveEval` and `Mesh` instead.
This is mostly not changed behavior, it is just a formalization of
existing logic after recent fixes for 2.8 versions last year and two
years ago. Also, in the future more functionality can be converted
to nodes, removing cases of implicit conversions. For more discussion
on that topic, see T89676.
The `use_fill_deform` option is removed. It has not worked properly
since 2.62, and the choice for filling a curve before or after
deformation will work much better and be clearer with a node system.
Applying the geometry nodes modifier to generate a curve is not
implemented with this commit, so applying the modifier won't work
at all. This is a separate technical challenge, and should be solved
in a separate step.
Differential Revision: https://developer.blender.org/D11597
2021-09-11 13:54:40 -05:00
|
|
|
static_cast<ModifierTypeFlag>(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs |
|
|
|
|
|
eModifierTypeFlag_SupportsEditmode |
|
|
|
|
|
eModifierTypeFlag_EnableInEditmode |
|
|
|
|
|
eModifierTypeFlag_SupportsMapping),
|
2023-01-16 12:41:11 +11:00
|
|
|
/*icon*/ ICON_GEOMETRY_NODES,
|
|
|
|
|
|
|
|
|
|
/*copyData*/ copyData,
|
|
|
|
|
|
|
|
|
|
/*deformVerts*/ nullptr,
|
|
|
|
|
/*deformMatrices*/ nullptr,
|
|
|
|
|
/*deformVertsEM*/ nullptr,
|
|
|
|
|
/*deformMatricesEM*/ nullptr,
|
|
|
|
|
/*modifyMesh*/ modifyMesh,
|
|
|
|
|
/*modifyGeometrySet*/ modifyGeometrySet,
|
|
|
|
|
|
|
|
|
|
/*initData*/ initData,
|
|
|
|
|
/*requiredDataMask*/ requiredDataMask,
|
|
|
|
|
/*freeData*/ freeData,
|
|
|
|
|
/*isDisabled*/ isDisabled,
|
|
|
|
|
/*updateDepsgraph*/ updateDepsgraph,
|
|
|
|
|
/*dependsOnTime*/ dependsOnTime,
|
|
|
|
|
/*dependsOnNormals*/ nullptr,
|
|
|
|
|
/*foreachIDLink*/ foreachIDLink,
|
|
|
|
|
/*foreachTexLink*/ foreachTexLink,
|
|
|
|
|
/*freeRuntimeData*/ nullptr,
|
|
|
|
|
/*panelRegister*/ panelRegister,
|
|
|
|
|
/*blendWrite*/ blendWrite,
|
|
|
|
|
/*blendRead*/ blendRead,
|
2020-12-02 13:25:25 +01:00
|
|
|
};
|