Geometry Nodes: reorganize panels in modifier #117170

Merged
Jacques Lucke merged 6 commits from JacquesLucke/blender:panel-reorganization into main 2024-01-17 13:40:38 +01:00
15 changed files with 285 additions and 30 deletions
Showing only changes of commit e6900a718d - Show all commits

View File

@ -928,7 +928,8 @@ class NODE_PT_node_tree_interface(Panel):
if 'OUTPUT' in active_item.in_out:
layout.prop(active_item, "attribute_domain")
layout.prop(active_item, "default_attribute_name")
active_item.draw(context, layout)
if hasattr(active_item, 'draw'):
active_item.draw(context, layout)
if active_item.item_type == 'PANEL':
layout.prop(active_item, "description")

View File

@ -29,7 +29,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 10
#define BLENDER_FILE_SUBVERSION 11
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@ -406,8 +406,22 @@ GVArray AttributeFieldInput::get_varray_for_context(const GeometryFieldContext &
GVArray AttributeExistsFieldInput::get_varray_for_context(const bke::GeometryFieldContext &context,
const IndexMask & /*mask*/) const
{
const AttrDomain domain = context.domain();
if (context.type() == GeometryComponent::Type::GreasePencil) {
const AttributeAccessor layer_attributes = context.grease_pencil()->attributes();
if (context.domain() == AttrDomain::Layer) {
const bool exists = layer_attributes.contains(name_);
const int domain_size = layer_attributes.domain_size(AttrDomain::Layer);
return VArray<bool>::ForSingle(exists, domain_size);
}
const greasepencil::Drawing *drawing = context.grease_pencil_layer_drawing();
const AttributeAccessor curve_attributes = drawing->strokes().attributes();
const bool exists = layer_attributes.contains(name_) || curve_attributes.contains(name_);
const int domain_size = curve_attributes.domain_size(domain);
return VArray<bool>::ForSingle(exists, domain_size);
}
const bool exists = context.attributes()->contains(name_);
const int domain_size = context.attributes()->domain_size(context.domain());
const int domain_size = context.attributes()->domain_size(domain);
return VArray<bool>::ForSingle(exists, domain_size);
}
@ -752,7 +766,8 @@ bool try_capture_field_on_geometry(GeometryComponent &component,
const fn::Field<bool> &selection,
const fn::GField &field)
{
if (component.type() == GeometryComponent::Type::GreasePencil &&
const GeometryComponent::Type component_type = component.type();
if (component_type == GeometryComponent::Type::GreasePencil &&
ELEM(domain, AttrDomain::Point, AttrDomain::Curve))
{
/* Capture the field on every layer individually. */
@ -784,6 +799,10 @@ bool try_capture_field_on_geometry(GeometryComponent &component,
});
return any_success;
}
if (component_type == GeometryComponent::Type::GreasePencil && domain != AttrDomain::Layer) {
/* The remaining code only handles the layer domain for grease pencil geometries. */
return false;
}
MutableAttributeAccessor attributes = *component.attributes_for_write();
const GeometryFieldContext field_context{component, domain};

View File

@ -476,6 +476,7 @@ static void write_node_socket_interface(BlendWriter *writer, const bNodeSocket *
static bNodeSocket *make_socket(bNodeTree *ntree,
const eNodeSocketInOut in_out,
const StringRef idname,
const StringRef name,
const StringRef identifier)
{
@ -501,6 +502,59 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
return sock;
}
/* Include the subtype suffix for old socket idnames. */
static StringRef get_legacy_socket_subtype_idname(StringRef idname, const void *socket_data)
{
if (idname == "NodeSocketFloat") {
const bNodeSocketValueFloat &float_data = *static_cast<const bNodeSocketValueFloat *>(
socket_data);
switch (float_data.subtype) {
case PROP_UNSIGNED:
return "NodeSocketFloatUnsigned";
case PROP_PERCENTAGE:
return "NodeSocketFloatPercentage";
case PROP_FACTOR:
return "NodeSocketFloatFactor";
case PROP_ANGLE:
return "NodeSocketFloatAngle";
case PROP_TIME:
return "NodeSocketFloatTime";
case PROP_TIME_ABSOLUTE:
return "NodeSocketFloatTimeAbsolute";
case PROP_DISTANCE:
return "NodeSocketFloatDistance";
}
}
if (idname == "NodeSocketInt") {
const bNodeSocketValueInt &int_data = *static_cast<const bNodeSocketValueInt *>(socket_data);
switch (int_data.subtype) {
case PROP_UNSIGNED:
return "NodeSocketIntUnsigned";
case PROP_PERCENTAGE:
return "NodeSocketIntPercentage";
case PROP_FACTOR:
return "NodeSocketIntFactor";
}
}
if (idname == "NodeSocketVector") {
const bNodeSocketValueVector &vector_data = *static_cast<const bNodeSocketValueVector *>(
socket_data);
switch (vector_data.subtype) {
case PROP_TRANSLATION:
return "NodeSocketVectorTranslation";
case PROP_DIRECTION:
return "NodeSocketVectorDirection";
case PROP_VELOCITY:
return "NodeSocketVectorVelocity";
case PROP_ACCELERATION:
return "NodeSocketVectorAcceleration";
case PROP_EULER:
return "NodeSocketVectorEuler";
}
}
return idname;
}
/**
* Socket interface reconstruction for forward compatibility.
* To enable previous Blender versions to read the new interface DNA data,
@ -516,7 +570,11 @@ static void construct_interface_as_legacy_sockets(bNodeTree *ntree)
auto make_legacy_socket = [&](const bNodeTreeInterfaceSocket &socket,
eNodeSocketInOut in_out) -> bNodeSocket * {
bNodeSocket *iosock = make_socket(
ntree, in_out, socket.socket_type, socket.name ? socket.name : "", socket.identifier);
ntree,
in_out,
get_legacy_socket_subtype_idname(socket.socket_type, socket.socket_data),
socket.name ? socket.name : "",
socket.identifier);
if (!iosock) {
return nullptr;
}

View File

@ -1386,6 +1386,36 @@ static void version_geometry_nodes_use_rotation_socket(bNodeTree &ntree)
}
}
}
/* Find the base socket name for an idname that may include a subtype. */
static blender::StringRef legacy_socket_idname_to_socket_type(blender::StringRef idname)
{
using string_pair = std::pair<const char *, const char *>;
static const string_pair subtypes_map[] = {{"NodeSocketFloatUnsigned", "NodeSocketFloat"},
{"NodeSocketFloatPercentage", "NodeSocketFloat"},
{"NodeSocketFloatFactor", "NodeSocketFloat"},
{"NodeSocketFloatAngle", "NodeSocketFloat"},
{"NodeSocketFloatTime", "NodeSocketFloat"},
{"NodeSocketFloatTimeAbsolute", "NodeSocketFloat"},
{"NodeSocketFloatDistance", "NodeSocketFloat"},
{"NodeSocketIntUnsigned", "NodeSocketInt"},
{"NodeSocketIntPercentage", "NodeSocketInt"},
{"NodeSocketIntFactor", "NodeSocketInt"},
{"NodeSocketVectorTranslation", "NodeSocketVector"},
{"NodeSocketVectorDirection", "NodeSocketVector"},
{"NodeSocketVectorVelocity", "NodeSocketVector"},
{"NodeSocketVectorAcceleration", "NodeSocketVector"},
{"NodeSocketVectorEuler", "NodeSocketVector"},
{"NodeSocketVectorXYZ", "NodeSocketVector"}};
for (const string_pair &pair : subtypes_map) {
if (pair.first == idname) {
return pair.second;
}
}
/* Unchanged socket idname. */
return idname;
}
static bNodeTreeInterfaceItem *legacy_socket_move_to_interface(bNodeSocket &legacy_socket,
const eNodeSocketInOut in_out)
{
@ -1396,7 +1426,10 @@ static bNodeTreeInterfaceItem *legacy_socket_move_to_interface(bNodeSocket &lega
new_socket->name = BLI_strdup(legacy_socket.name);
new_socket->identifier = BLI_strdup(legacy_socket.identifier);
new_socket->description = BLI_strdup(legacy_socket.description);
new_socket->socket_type = BLI_strdup(legacy_socket.idname);
/* If the socket idname includes a subtype (e.g. "NodeSocketFloatFactor") this will convert it to
* the base type name ("NodeSocketFloat"). */
new_socket->socket_type = BLI_strdup(
legacy_socket_idname_to_socket_type(legacy_socket.idname).data());
new_socket->flag = (in_out == SOCK_IN ? NODE_INTERFACE_SOCKET_INPUT :
NODE_INTERFACE_SOCKET_OUTPUT);
SET_FLAG_FROM_TEST(
@ -1444,6 +1477,28 @@ static void versioning_convert_node_tree_socket_lists_to_interface(bNodeTree *nt
}
}
/**
* Original node tree interface conversion in did not convert socket idnames with subtype suffixes
* to correct socket base types (see #versioning_convert_node_tree_socket_lists_to_interface).
*/
static void versioning_fix_socket_subtype_idnames(bNodeTree *ntree)
{
bNodeTreeInterface &tree_interface = ntree->tree_interface;
tree_interface.foreach_item([](bNodeTreeInterfaceItem &item) -> bool {
if (item.item_type == NODE_INTERFACE_SOCKET) {
bNodeTreeInterfaceSocket &socket = reinterpret_cast<bNodeTreeInterfaceSocket &>(item);
blender::StringRef corrected_socket_type = legacy_socket_idname_to_socket_type(
socket.socket_type);
if (socket.socket_type != corrected_socket_type) {
MEM_freeN(socket.socket_type);
socket.socket_type = BLI_strdup(corrected_socket_type.data());
}
}
return true;
});
}
/* Convert coat inputs on the Principled BSDF. */
static void version_principled_bsdf_coat(bNodeTree *ntree)
{
@ -2577,6 +2632,14 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
if (MAIN_VERSION_FILE_ATLEAST(bmain, 400, 20) && !MAIN_VERSION_FILE_ATLEAST(bmain, 401, 11)) {
/* Convert old socket lists into new interface items. */
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
versioning_fix_socket_subtype_idnames(ntree);
}
FOREACH_NODETREE_END;
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.

View File

@ -1636,24 +1636,13 @@ const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
return ss->cache->view_normal;
}
static float frontface(const Brush *br,
const float3 &sculpt_normal,
const float3 &no,
const float3 &fno)
static float frontface(const Brush &brush, const float3 &view_normal, const float3 &normal)
{
using namespace blender;
if (!(br->flag & BRUSH_FRONTFACE)) {
if (!(brush.flag & BRUSH_FRONTFACE)) {
return 1.0f;
}
float dot;
if (no) {
dot = math::dot(no, sculpt_normal);
}
else {
dot = math::dot(fno, sculpt_normal);
}
return dot > 0.0f ? dot : 0.0f;
return std::max(math::dot(normal, view_normal), 0.0f);
}
#if 0
@ -2400,7 +2389,7 @@ float SCULPT_brush_strength_factor(
/* Falloff curve. */
avg *= BKE_brush_curve_strength(brush, final_len, cache->radius);
avg *= frontface(brush, cache->view_normal, vno, fno);
avg *= frontface(*brush, cache->view_normal, vno ? vno : fno);
/* Paint mask. */
avg *= 1.0f - mask;
@ -2435,7 +2424,7 @@ void SCULPT_brush_strength_color(
/* Falloff curve. */
const float falloff = BKE_brush_curve_strength(brush, final_len, cache->radius) *
frontface(brush, cache->view_normal, vno, fno);
frontface(*brush, cache->view_normal, vno ? vno : fno);
/* Paint mask. */
const float paint_mask = 1.0f - mask;

View File

@ -325,6 +325,13 @@ static StructRNA *rna_KeyingSetInfo_register(Main *bmain,
/* check if we have registered this info before, and remove it */
ksi = ANIM_keyingset_info_find_name(dummy_ksi.idname);
if (ksi) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_ksi.idname);
StructRNA *srna = ksi->rna_ext.srna;
if (!(srna && rna_KeyingSetInfo_unregister(bmain, srna))) {
BKE_reportf(reports,

View File

@ -991,6 +991,13 @@ static StructRNA *rna_NodeTree_register(Main *bmain,
/* check if we have registered this tree type before, and remove it */
nt = ntreeTypeFind(dummy_nt.idname);
if (nt) {
BKE_reportf(reports,
RPT_INFO,
"Registering node tree class: '%s', bl_idname '%s' has been registered before, "
"unregistering previous",
identifier,
dummy_nt.idname);
/* NOTE: unlike most types `nt->rna_ext.srna` doesn't need to be checked for nullptr. */
if (!rna_NodeTree_unregister(bmain, nt->rna_ext.srna)) {
BKE_reportf(reports,
@ -1663,6 +1670,13 @@ static bNodeType *rna_Node_register_base(Main *bmain,
return nullptr;
}
BKE_reportf(reports,
RPT_INFO,
"Registering node class: '%s', bl_idname '%s' has been registered before, "
"unregistering previous",
identifier,
dummy_nt.idname);
/* NOTE: unlike most types `nt->rna_ext.srna` doesn't need to be checked for nullptr. */
if (!rna_Node_unregister(bmain, nt->rna_ext.srna)) {
BKE_reportf(reports,

View File

@ -348,6 +348,13 @@ static StructRNA *rna_RenderEngine_register(Main *bmain,
et = static_cast<RenderEngineType *>(
BLI_findstring(&R_engines, dummy_et.idname, offsetof(RenderEngineType, idname)));
if (et) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_et.idname);
StructRNA *srna = et->rna_ext.srna;
if (!(srna && rna_RenderEngine_unregister(bmain, srna))) {
BKE_reportf(reports,

View File

@ -315,6 +315,12 @@ static StructRNA *rna_Panel_register(Main *bmain,
PanelType *pt_next = pt->next;
StructRNA *srna = pt->rna_ext.srna;
if (srna) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_pt.idname);
if (!rna_Panel_unregister(bmain, srna)) {
BKE_reportf(reports,
RPT_ERROR,
@ -721,6 +727,13 @@ static StructRNA *rna_UIList_register(Main *bmain,
/* Check if we have registered this UI-list type before, and remove it. */
ult = WM_uilisttype_find(dummy_ult.idname, true);
if (ult) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_ult.idname);
StructRNA *srna = ult->rna_ext.srna;
if (!(srna && rna_UIList_unregister(bmain, srna))) {
BKE_reportf(reports,
@ -852,6 +865,13 @@ static StructRNA *rna_Header_register(Main *bmain,
ht = static_cast<HeaderType *>(
BLI_findstring(&art->headertypes, dummy_ht.idname, offsetof(HeaderType, idname)));
if (ht) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_ht.idname);
StructRNA *srna = ht->rna_ext.srna;
if (!(srna && rna_Header_unregister(bmain, srna))) {
BKE_reportf(reports,
@ -1002,6 +1022,13 @@ static StructRNA *rna_Menu_register(Main *bmain,
/* check if we have registered this menu type before, and remove it */
mt = WM_menutype_find(dummy_mt.idname, true);
if (mt) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_mt.idname);
StructRNA *srna = mt->rna_ext.srna;
if (!(srna && rna_Menu_unregister(bmain, srna))) {
BKE_reportf(reports,
@ -1207,6 +1234,12 @@ static StructRNA *rna_AssetShelf_register(Main *bmain,
LISTBASE_FOREACH (AssetShelfType *, iter_shelf_type, &space_type->asset_shelf_types) {
if (STREQ(iter_shelf_type->idname, dummy_shelf_type.idname)) {
if (iter_shelf_type->rna_ext.srna) {
BKE_reportf(reports,
RPT_INFO,
"Registering asset shelf class: '%s' has been registered before, "
"unregistering previous",
dummy_shelf_type.idname);
rna_AssetShelf_unregister(bmain, iter_shelf_type->rna_ext.srna);
}
break;

View File

@ -82,6 +82,13 @@ static StructRNA *rna_USDHook_register(Main *bmain,
/* check if we have registered this hook before, and remove it */
hook = USD_find_hook_name(dummy_hook.idname);
if (hook) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_hook.idname);
StructRNA *srna = hook->rna_ext.srna;
if (!rna_USDHook_unregister(bmain, srna)) {
BKE_reportf(reports,

View File

@ -1059,6 +1059,13 @@ static StructRNA *rna_AddonPref_register(Main *bmain,
/* Check if we have registered this add-on preference type before, and remove it. */
apt = BKE_addon_pref_type_find(dummy_addon.module, true);
if (apt) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_apt.idname);
StructRNA *srna = apt->rna_ext.srna;
if (!(srna && rna_AddonPref_unregister(bmain, srna))) {
BKE_reportf(reports,

View File

@ -1185,6 +1185,13 @@ static StructRNA *rna_wmKeyConfigPref_register(Main *bmain,
/* check if we have registered this keyconf-prefs type before, and remove it */
kpt_rt = BKE_keyconfig_pref_type_find(dummy_kpt.idname, true);
if (kpt_rt) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_kpt.idname);
StructRNA *srna = kpt_rt->rna_ext.srna;
if (!(srna && rna_wmKeyConfigPref_unregister(bmain, srna))) {
BKE_reportf(reports,
@ -1530,6 +1537,13 @@ static StructRNA *rna_Operator_register(Main *bmain,
{
wmOperatorType *ot = WM_operatortype_find(dummy_ot.idname, true);
if (ot) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_ot.idname);
StructRNA *srna = ot->rna_ext.srna;
if (!(srna && rna_Operator_unregister(bmain, srna))) {
BKE_reportf(reports,
@ -1700,6 +1714,13 @@ static StructRNA *rna_MacroOperator_register(Main *bmain,
{
wmOperatorType *ot = WM_operatortype_find(dummy_ot.idname, true);
if (ot) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_ot.idname);
StructRNA *srna = ot->rna_ext.srna;
if (!(srna && rna_Operator_unregister(bmain, srna))) {
BKE_reportf(reports,

View File

@ -460,6 +460,13 @@ static StructRNA *rna_Gizmo_register(Main *bmain,
{
const wmGizmoType *gzt = WM_gizmotype_find(dummy_gt.idname, true);
if (gzt) {
BKE_reportf(reports,
RPT_INFO,
"%s '%s', bl_idname '%s' has been registered before, unregistering previous",
error_prefix,
identifier,
dummy_gt.idname);
StructRNA *srna = gzt->rna_ext.srna;
if (!(srna && rna_Gizmo_unregister(bmain, srna))) {
BKE_reportf(reports,

View File

@ -14,7 +14,25 @@ import bpy
args = None
type_info = {
base_idname = {
"VALUE": "NodeSocketFloat",
"INT": "NodeSocketInt",
"BOOLEAN": "NodeSocketBool",
"ROTATION": "NodeSocketRotation",
"VECTOR": "NodeSocketVector",
"RGBA": "NodeSocketColor",
"STRING": "NodeSocketString",
"SHADER": "NodeSocketShader",
"OBJECT": "NodeSocketObject",
"IMAGE": "NodeSocketImage",
"GEOMETRY": "NodeSocketGeometry",
"COLLECTION": "NodeSocketCollection",
"TEXTURE": "NodeSocketTexture",
"MATERIAL": "NodeSocketMaterial",
}
subtype_idname = {
("VALUE", "NONE"): "NodeSocketFloat",
("VALUE", "UNSIGNED"): "NodeSocketFloatUnsigned",
("VALUE", "PERCENTAGE"): "NodeSocketFloatPercentage",
@ -63,8 +81,12 @@ class SocketSpec():
external_links: int = 1
@property
def idname(self):
return type_info[(self.type, self.subtype)]
def base_idname(self):
return base_idname[self.type]
@property
def subtype_idname(self):
return subtype_idname[(self.type, self.subtype)]
class AbstractNodeGroupInterfaceTest(unittest.TestCase):
@ -95,7 +117,7 @@ class AbstractNodeGroupInterfaceTest(unittest.TestCase):
# Examine the interface item.
self.assertEqual(item.name, spec.name)
self.assertEqual(item.bl_socket_idname, spec.idname)
self.assertEqual(item.bl_socket_idname, spec.base_idname)
self.assertEqual(item.identifier, spec.identifier)
# Types that have subtypes.
@ -134,7 +156,7 @@ class AbstractNodeGroupInterfaceTest(unittest.TestCase):
socket = next(s for s in node.inputs if s.identifier == spec.identifier)
self.assertIsNotNone(socket, f"Could not find socket for group input identifier {spec.identifier}")
self.assertEqual(socket.name, spec.name)
self.assertEqual(socket.bl_idname, spec.idname)
self.assertEqual(socket.bl_idname, spec.subtype_idname)
self.assertEqual(socket.type, spec.type)
self.assertEqual(socket.hide_value, spec.hide_value)
if test_links:
@ -147,7 +169,7 @@ class AbstractNodeGroupInterfaceTest(unittest.TestCase):
self.assertIsNotNone(
socket, f"Could not find group input socket for group input identifier {spec.identifier}")
self.assertEqual(socket.name, spec.name)
self.assertEqual(socket.bl_idname, spec.idname)
self.assertEqual(socket.bl_idname, spec.subtype_idname)
self.assertEqual(socket.type, spec.type)
self.assertEqual(socket.hide_value, spec.hide_value)
if test_links:
@ -158,7 +180,7 @@ class AbstractNodeGroupInterfaceTest(unittest.TestCase):
socket = next(s for s in node.outputs if s.identifier == spec.identifier)
self.assertIsNotNone(socket, f"Could not find socket for group output identifier {spec.identifier}")
self.assertEqual(socket.name, spec.name)
self.assertEqual(socket.bl_idname, spec.idname)
self.assertEqual(socket.bl_idname, spec.subtype_idname)
self.assertEqual(socket.type, spec.type)
self.assertEqual(socket.hide_value, spec.hide_value)
if test_links:
@ -171,7 +193,7 @@ class AbstractNodeGroupInterfaceTest(unittest.TestCase):
self.assertIsNotNone(
socket, f"Could not find group output socket for group output identifier {spec.identifier}")
self.assertEqual(socket.name, spec.name)
self.assertEqual(socket.bl_idname, spec.idname)
self.assertEqual(socket.bl_idname, spec.subtype_idname)
self.assertEqual(socket.type, spec.type)
self.assertEqual(socket.hide_value, spec.hide_value)
if test_links: