UI: Configurable UI Font Weight #112454
|
@ -94,9 +94,8 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
|||
/* Make a copy to split faces if we use auto-smooth, otherwise not needed.
|
||||
* Also in edit mode do we need to make a copy, to ensure data layers like
|
||||
* UV are not empty. */
|
||||
if (mesh.is_editmode() ||
|
||||
(mesh.normals_domain() == BL::Mesh::normals_domain_CORNER &&
|
||||
subdivision_type == Mesh::SUBDIVISION_NONE))
|
||||
if (mesh.is_editmode() || (mesh.normals_domain() == BL::Mesh::normals_domain_CORNER &&
|
||||
subdivision_type == Mesh::SUBDIVISION_NONE))
|
||||
{
|
||||
BL::Depsgraph depsgraph(PointerRNA_NULL);
|
||||
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
|
||||
|
|
|
@ -4612,7 +4612,8 @@ def km_grease_pencil_edit(params):
|
|||
op_menu("VIEW3D_MT_edit_greasepencil_animation", {"type": 'I', "value": 'PRESS'}),
|
||||
# Cyclical set
|
||||
("grease_pencil.cyclical_set", {"type": 'F', "value": 'PRESS'}, {"properties": [("type", "CLOSE")]}),
|
||||
("grease_pencil.cyclical_set", {"type": 'C', "value": 'PRESS', "alt": True}, {"properties": [("type", "TOGGLE")]}),
|
||||
("grease_pencil.cyclical_set", {"type": 'C', "value": 'PRESS',
|
||||
"alt": True}, {"properties": [("type", "TOGGLE")]}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
|
|
@ -299,8 +299,8 @@ class EEVEE_NEXT_MATERIAL_PT_settings_surface(MaterialButtonsPanel, Panel):
|
|||
col.prop(mat, "use_backface_culling", text="Camera")
|
||||
col.prop(mat, "use_backface_culling_shadow", text="Shadow")
|
||||
|
||||
#TODO(fclem): Displacement option
|
||||
#TODO(fclem): Transparent shadow option
|
||||
# TODO(fclem): Displacement option
|
||||
# TODO(fclem): Transparent shadow option
|
||||
|
||||
col = layout.column()
|
||||
col.prop(mat, "surface_render_method", text="Render Method")
|
||||
|
|
|
@ -5817,7 +5817,7 @@ class VIEW3D_MT_edit_greasepencil_stroke(Menu):
|
|||
layout.operator("grease_pencil.stroke_simplify")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
||||
layout.operator_enum("grease_pencil.cyclical_set", "type")
|
||||
|
||||
|
||||
|
|
|
@ -28,10 +28,10 @@ class Drawing;
|
|||
class MeshFieldContext : public fn::FieldContext {
|
||||
private:
|
||||
const Mesh &mesh_;
|
||||
const eAttrDomain domain_;
|
||||
eAttrDomain domain_;
|
||||
|
||||
public:
|
||||
MeshFieldContext(const Mesh &mesh, const eAttrDomain domain);
|
||||
MeshFieldContext(const Mesh &mesh, eAttrDomain domain);
|
||||
const Mesh &mesh() const
|
||||
{
|
||||
return mesh_;
|
||||
|
@ -46,10 +46,10 @@ class MeshFieldContext : public fn::FieldContext {
|
|||
class CurvesFieldContext : public fn::FieldContext {
|
||||
private:
|
||||
const CurvesGeometry &curves_;
|
||||
const eAttrDomain domain_;
|
||||
eAttrDomain domain_;
|
||||
|
||||
public:
|
||||
CurvesFieldContext(const CurvesGeometry &curves, const eAttrDomain domain);
|
||||
CurvesFieldContext(const CurvesGeometry &curves, eAttrDomain domain);
|
||||
|
||||
const CurvesGeometry &curves() const
|
||||
{
|
||||
|
@ -91,8 +91,8 @@ class GreasePencilFieldContext : public fn::FieldContext {
|
|||
class GreasePencilLayerFieldContext : public fn::FieldContext {
|
||||
private:
|
||||
const GreasePencil &grease_pencil_;
|
||||
const eAttrDomain domain_;
|
||||
const int layer_index_;
|
||||
eAttrDomain domain_;
|
||||
int layer_index_;
|
||||
|
||||
public:
|
||||
GreasePencilLayerFieldContext(const GreasePencil &grease_pencil,
|
||||
|
@ -148,7 +148,7 @@ class GeometryFieldContext : public fn::FieldContext {
|
|||
*/
|
||||
const void *geometry_;
|
||||
const GeometryComponent::Type type_;
|
||||
const eAttrDomain domain_;
|
||||
eAttrDomain domain_;
|
||||
/**
|
||||
* Only used when the type is grease pencil and the domain is either points or curves
|
||||
* (not layers).
|
||||
|
@ -332,7 +332,7 @@ class IDAttributeFieldInput : public GeometryFieldInput {
|
|||
bool is_equal_to(const fn::FieldNode &other) const override;
|
||||
};
|
||||
|
||||
VArray<float3> curve_normals_varray(const CurvesGeometry &curves, const eAttrDomain domain);
|
||||
VArray<float3> curve_normals_varray(const CurvesGeometry &curves, eAttrDomain domain);
|
||||
|
||||
VArray<float3> mesh_normals_varray(const Mesh &mesh, const IndexMask &mask, eAttrDomain domain);
|
||||
|
||||
|
@ -363,7 +363,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
|
|||
std::string producer_name)
|
||||
: GeometryFieldInput(type, anonymous_id->user_name()),
|
||||
anonymous_id_(std::move(anonymous_id)),
|
||||
producer_name_(producer_name)
|
||||
producer_name_(std::move(producer_name))
|
||||
{
|
||||
category_ = Category::AnonymousAttribute;
|
||||
}
|
||||
|
@ -405,12 +405,12 @@ class CurveLengthFieldInput final : public CurvesFieldInput {
|
|||
|
||||
bool try_capture_field_on_geometry(GeometryComponent &component,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const eAttrDomain domain,
|
||||
eAttrDomain domain,
|
||||
const fn::GField &field);
|
||||
|
||||
bool try_capture_field_on_geometry(GeometryComponent &component,
|
||||
const AttributeIDRef &attribute_id,
|
||||
const eAttrDomain domain,
|
||||
eAttrDomain domain,
|
||||
const fn::Field<bool> &selection,
|
||||
const fn::GField &field);
|
||||
|
||||
|
|
|
@ -506,16 +506,10 @@ class LayerGroup : public ::GreasePencilLayerTreeGroup {
|
|||
Span<LayerGroup *> groups_for_write();
|
||||
|
||||
/**
|
||||
* Returns a pointer to the layer with \a name. If no such layer was found, returns nullptr.
|
||||
* Returns a pointer to the node with \a name. If no such node was found, returns nullptr.
|
||||
*/
|
||||
const Layer *find_layer_by_name(StringRefNull name) const;
|
||||
Layer *find_layer_by_name(StringRefNull name);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the group with \a name. If no such group was found, returns nullptr.
|
||||
*/
|
||||
const LayerGroup *find_group_by_name(StringRefNull name) const;
|
||||
LayerGroup *find_group_by_name(StringRefNull name);
|
||||
const TreeNode *find_node_by_name(StringRefNull name) const;
|
||||
TreeNode *find_node_by_name(StringRefNull name);
|
||||
|
||||
/**
|
||||
* Print the nodes. For debugging purposes.
|
||||
|
|
|
@ -553,19 +553,37 @@ inline void bNodeTree::ensure_interface_cache() const
|
|||
this->tree_interface.ensure_items_cache();
|
||||
}
|
||||
|
||||
inline blender::Span<bNodeTreeInterfaceSocket *> bNodeTree::interface_inputs() const
|
||||
inline blender::Span<bNodeTreeInterfaceSocket *> bNodeTree::interface_inputs()
|
||||
{
|
||||
BLI_assert(this->tree_interface.items_cache_is_available());
|
||||
return this->tree_interface.runtime->inputs_;
|
||||
}
|
||||
|
||||
inline blender::Span<bNodeTreeInterfaceSocket *> bNodeTree::interface_outputs() const
|
||||
inline blender::Span<const bNodeTreeInterfaceSocket *> bNodeTree::interface_inputs() const
|
||||
{
|
||||
BLI_assert(this->tree_interface.items_cache_is_available());
|
||||
return this->tree_interface.runtime->inputs_;
|
||||
}
|
||||
|
||||
inline blender::Span<bNodeTreeInterfaceSocket *> bNodeTree::interface_outputs()
|
||||
{
|
||||
BLI_assert(this->tree_interface.items_cache_is_available());
|
||||
return this->tree_interface.runtime->outputs_;
|
||||
}
|
||||
|
||||
inline blender::Span<bNodeTreeInterfaceItem *> bNodeTree::interface_items() const
|
||||
inline blender::Span<const bNodeTreeInterfaceSocket *> bNodeTree::interface_outputs() const
|
||||
{
|
||||
BLI_assert(this->tree_interface.items_cache_is_available());
|
||||
return this->tree_interface.runtime->outputs_;
|
||||
}
|
||||
|
||||
inline blender::Span<bNodeTreeInterfaceItem *> bNodeTree::interface_items()
|
||||
{
|
||||
BLI_assert(this->tree_interface.items_cache_is_available());
|
||||
return this->tree_interface.runtime->items_;
|
||||
}
|
||||
|
||||
inline blender::Span<const bNodeTreeInterfaceItem *> bNodeTree::interface_items() const
|
||||
{
|
||||
BLI_assert(this->tree_interface.items_cache_is_available());
|
||||
return this->tree_interface.runtime->items_;
|
||||
|
|
|
@ -128,8 +128,8 @@ class DynamicAttributesProvider {
|
|||
class CustomDataAttributeProvider final : public DynamicAttributesProvider {
|
||||
private:
|
||||
static constexpr uint64_t supported_types_mask = CD_MASK_PROP_ALL;
|
||||
const eAttrDomain domain_;
|
||||
const CustomDataAccessInfo custom_data_access_;
|
||||
eAttrDomain domain_;
|
||||
CustomDataAccessInfo custom_data_access_;
|
||||
|
||||
public:
|
||||
CustomDataAttributeProvider(const eAttrDomain domain,
|
||||
|
|
|
@ -103,8 +103,10 @@ static void grease_pencil_copy_data(Main * /*bmain*/,
|
|||
|
||||
/* Set active layer. */
|
||||
if (grease_pencil_src->has_active_layer()) {
|
||||
grease_pencil_dst->set_active_layer(
|
||||
grease_pencil_dst->find_layer_by_name(grease_pencil_src->active_layer->wrap().name()));
|
||||
bke::greasepencil::TreeNode *active_node = grease_pencil_dst->find_node_by_name(
|
||||
grease_pencil_src->active_layer->wrap().name());
|
||||
BLI_assert(active_node && active_node->is_layer());
|
||||
grease_pencil_dst->set_active_layer(&active_node->as_layer());
|
||||
}
|
||||
|
||||
CustomData_copy(&grease_pencil_src->layers_data,
|
||||
|
@ -1006,41 +1008,21 @@ Span<LayerGroup *> LayerGroup::groups_for_write()
|
|||
return this->runtime->layer_group_cache_.as_span();
|
||||
}
|
||||
|
||||
const Layer *LayerGroup::find_layer_by_name(const StringRefNull name) const
|
||||
const TreeNode *LayerGroup::find_node_by_name(const StringRefNull name) const
|
||||
{
|
||||
for (const Layer *layer : this->layers()) {
|
||||
if (StringRef(layer->name()) == StringRef(name)) {
|
||||
return layer;
|
||||
for (const TreeNode *node : this->nodes()) {
|
||||
if (StringRef(node->name()) == StringRef(name)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Layer *LayerGroup::find_layer_by_name(const StringRefNull name)
|
||||
TreeNode *LayerGroup::find_node_by_name(const StringRefNull name)
|
||||
{
|
||||
for (Layer *layer : this->layers_for_write()) {
|
||||
if (StringRef(layer->name()) == StringRef(name)) {
|
||||
return layer;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const LayerGroup *LayerGroup::find_group_by_name(StringRefNull name) const
|
||||
{
|
||||
for (const LayerGroup *group : this->groups()) {
|
||||
if (StringRef(group->name()) == StringRef(name)) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LayerGroup *LayerGroup::find_group_by_name(StringRefNull name)
|
||||
{
|
||||
for (LayerGroup *group : this->groups_for_write()) {
|
||||
if (StringRef(group->name()) == StringRef(name)) {
|
||||
return group;
|
||||
for (TreeNode *node : this->nodes_for_write()) {
|
||||
if (StringRef(node->name()) == StringRef(name)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -2391,28 +2373,16 @@ void GreasePencil::move_node_into(blender::bke::greasepencil::TreeNode &node,
|
|||
parent_group.add_node(node);
|
||||
}
|
||||
|
||||
const blender::bke::greasepencil::Layer *GreasePencil::find_layer_by_name(
|
||||
const blender::bke::greasepencil::TreeNode *GreasePencil::find_node_by_name(
|
||||
const blender::StringRefNull name) const
|
||||
{
|
||||
return this->root_group().find_layer_by_name(name);
|
||||
return this->root_group().find_node_by_name(name);
|
||||
}
|
||||
|
||||
blender::bke::greasepencil::Layer *GreasePencil::find_layer_by_name(
|
||||
blender::bke::greasepencil::TreeNode *GreasePencil::find_node_by_name(
|
||||
const blender::StringRefNull name)
|
||||
{
|
||||
return this->root_group().find_layer_by_name(name);
|
||||
}
|
||||
|
||||
const blender::bke::greasepencil::LayerGroup *GreasePencil::find_layer_group_by_name(
|
||||
blender::StringRefNull name) const
|
||||
{
|
||||
return this->root_group().find_group_by_name(name);
|
||||
}
|
||||
|
||||
blender::bke::greasepencil::LayerGroup *GreasePencil::find_layer_group_by_name(
|
||||
blender::StringRefNull name)
|
||||
{
|
||||
return this->root_group().find_group_by_name(name);
|
||||
return this->root_group().find_node_by_name(name);
|
||||
}
|
||||
|
||||
void GreasePencil::rename_node(blender::bke::greasepencil::TreeNode &node,
|
||||
|
|
|
@ -195,11 +195,11 @@ TEST(greasepencil, layer_tree_is_child_of)
|
|||
|
||||
EXPECT_FALSE(ex.grease_pencil.root_group().is_child_of(ex.grease_pencil.root_group()));
|
||||
|
||||
const LayerGroup &group1 = *ex.grease_pencil.find_layer_group_by_name("Group1");
|
||||
const LayerGroup &group2 = *ex.grease_pencil.find_layer_group_by_name("Group2");
|
||||
const Layer &layer1 = *ex.grease_pencil.find_layer_by_name("Layer1");
|
||||
const Layer &layer3 = *ex.grease_pencil.find_layer_by_name("Layer3");
|
||||
const Layer &layer5 = *ex.grease_pencil.find_layer_by_name("Layer5");
|
||||
const LayerGroup &group1 = ex.grease_pencil.find_node_by_name("Group1")->as_group();
|
||||
const LayerGroup &group2 = ex.grease_pencil.find_node_by_name("Group2")->as_group();
|
||||
const Layer &layer1 = ex.grease_pencil.find_node_by_name("Layer1")->as_layer();
|
||||
const Layer &layer3 = ex.grease_pencil.find_node_by_name("Layer3")->as_layer();
|
||||
const Layer &layer5 = ex.grease_pencil.find_node_by_name("Layer5")->as_layer();
|
||||
|
||||
EXPECT_TRUE(layer1.is_child_of(ex.grease_pencil.root_group()));
|
||||
EXPECT_TRUE(layer1.is_child_of(group1));
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
#include "BKE_node_runtime.hh"
|
||||
#include "BKE_node_tree_anonymous_attributes.hh"
|
||||
#include "BKE_node_tree_dot_export.hh"
|
||||
#include "BKE_node_tree_zones.hh"
|
||||
|
||||
#include "BLI_bit_group_vector.hh"
|
||||
#include "BLI_bit_span_ops.hh"
|
||||
|
||||
#include "BLI_resource_scope.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace blender::bke::anonymous_attribute_inferencing {
|
||||
|
@ -195,6 +197,21 @@ class bNodeTreeToDotOptionsForAnonymousAttributeInferencing : public bNodeTreeTo
|
|||
}
|
||||
};
|
||||
|
||||
static bool or_into_each_other(MutableBoundedBitSpan a, MutableBoundedBitSpan b)
|
||||
{
|
||||
if (bits::spans_equal(a, b)) {
|
||||
return false;
|
||||
}
|
||||
a |= b;
|
||||
b |= a;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool or_into_each_other(BitGroupVector<> &vec, const int64_t a, const int64_t b)
|
||||
{
|
||||
return or_into_each_other(vec[a], vec[b]);
|
||||
}
|
||||
|
||||
static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
|
||||
const bNodeTree &tree)
|
||||
{
|
||||
|
@ -204,6 +221,22 @@ static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
|
|||
ResourceScope scope;
|
||||
const Array<const aal::RelationsInNode *> relations_by_node = get_relations_by_node(tree, scope);
|
||||
|
||||
/* Repeat zones need some special behavior because they can propagate anonymous attributes from
|
||||
* right to left (from the repeat output to the repeat input node). */
|
||||
const bNodeTreeZones *zones = tree.zones();
|
||||
Vector<const bNodeTreeZone *> repeat_zones_to_consider;
|
||||
if (zones) {
|
||||
for (const std::unique_ptr<bNodeTreeZone> &zone : zones->zones) {
|
||||
if (ELEM(nullptr, zone->input_node, zone->output_node)) {
|
||||
continue;
|
||||
}
|
||||
if (zone->output_node->type != GEO_NODE_REPEAT_OUTPUT) {
|
||||
continue;
|
||||
}
|
||||
repeat_zones_to_consider.append(zone.get());
|
||||
}
|
||||
}
|
||||
|
||||
Vector<FieldSource> all_field_sources;
|
||||
Vector<GeometrySource> all_geometry_sources;
|
||||
|
||||
|
@ -300,44 +333,72 @@ static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
|
|||
|
||||
/* Inferencing pass from left to right to figure out where fields and geometries may be
|
||||
* propagated to. */
|
||||
for (const bNode *node : tree.toposort_left_to_right()) {
|
||||
for (const bNodeSocket *socket : node->input_sockets()) {
|
||||
if (!socket->is_available()) {
|
||||
continue;
|
||||
}
|
||||
const int dst_index = socket->index_in_tree();
|
||||
for (const bNodeLink *link : socket->directly_linked_links()) {
|
||||
if (link->is_used()) {
|
||||
const int src_index = link->fromsock->index_in_tree();
|
||||
propagated_fields_by_socket[dst_index] |= propagated_fields_by_socket[src_index];
|
||||
propagated_geometries_by_socket[dst_index] |= propagated_geometries_by_socket[src_index];
|
||||
available_fields_by_geometry_socket[dst_index] |=
|
||||
available_fields_by_geometry_socket[src_index];
|
||||
auto pass_left_to_right = [&]() {
|
||||
for (const bNode *node : tree.toposort_left_to_right()) {
|
||||
for (const bNodeSocket *socket : node->input_sockets()) {
|
||||
if (!socket->is_available()) {
|
||||
continue;
|
||||
}
|
||||
const int dst_index = socket->index_in_tree();
|
||||
for (const bNodeLink *link : socket->directly_linked_links()) {
|
||||
if (link->is_used()) {
|
||||
const int src_index = link->fromsock->index_in_tree();
|
||||
propagated_fields_by_socket[dst_index] |= propagated_fields_by_socket[src_index];
|
||||
propagated_geometries_by_socket[dst_index] |=
|
||||
propagated_geometries_by_socket[src_index];
|
||||
available_fields_by_geometry_socket[dst_index] |=
|
||||
available_fields_by_geometry_socket[src_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const aal::RelationsInNode &relations = *relations_by_node[node->index()];
|
||||
for (const aal::ReferenceRelation &relation : relations.reference_relations) {
|
||||
const bNodeSocket &from_socket = node->input_socket(relation.from_field_input);
|
||||
const bNodeSocket &to_socket = node->output_socket(relation.to_field_output);
|
||||
if (!from_socket.is_available() || !to_socket.is_available()) {
|
||||
continue;
|
||||
const aal::RelationsInNode &relations = *relations_by_node[node->index()];
|
||||
for (const aal::ReferenceRelation &relation : relations.reference_relations) {
|
||||
const bNodeSocket &from_socket = node->input_socket(relation.from_field_input);
|
||||
const bNodeSocket &to_socket = node->output_socket(relation.to_field_output);
|
||||
if (!from_socket.is_available() || !to_socket.is_available()) {
|
||||
continue;
|
||||
}
|
||||
const int src_index = from_socket.index_in_tree();
|
||||
const int dst_index = to_socket.index_in_tree();
|
||||
propagated_fields_by_socket[dst_index] |= propagated_fields_by_socket[src_index];
|
||||
}
|
||||
const int src_index = from_socket.index_in_tree();
|
||||
const int dst_index = to_socket.index_in_tree();
|
||||
propagated_fields_by_socket[dst_index] |= propagated_fields_by_socket[src_index];
|
||||
}
|
||||
for (const aal::PropagateRelation &relation : relations.propagate_relations) {
|
||||
const bNodeSocket &from_socket = node->input_socket(relation.from_geometry_input);
|
||||
const bNodeSocket &to_socket = node->output_socket(relation.to_geometry_output);
|
||||
if (!from_socket.is_available() || !to_socket.is_available()) {
|
||||
continue;
|
||||
for (const aal::PropagateRelation &relation : relations.propagate_relations) {
|
||||
const bNodeSocket &from_socket = node->input_socket(relation.from_geometry_input);
|
||||
const bNodeSocket &to_socket = node->output_socket(relation.to_geometry_output);
|
||||
if (!from_socket.is_available() || !to_socket.is_available()) {
|
||||
continue;
|
||||
}
|
||||
const int src_index = from_socket.index_in_tree();
|
||||
const int dst_index = to_socket.index_in_tree();
|
||||
propagated_geometries_by_socket[dst_index] |= propagated_geometries_by_socket[src_index];
|
||||
available_fields_by_geometry_socket[dst_index] |=
|
||||
available_fields_by_geometry_socket[src_index];
|
||||
}
|
||||
const int src_index = from_socket.index_in_tree();
|
||||
const int dst_index = to_socket.index_in_tree();
|
||||
propagated_geometries_by_socket[dst_index] |= propagated_geometries_by_socket[src_index];
|
||||
available_fields_by_geometry_socket[dst_index] |=
|
||||
available_fields_by_geometry_socket[src_index];
|
||||
}
|
||||
};
|
||||
|
||||
while (true) {
|
||||
pass_left_to_right();
|
||||
|
||||
/* Repeat zones may need multiple inference passes. That's because anonymous attributes
|
||||
* propagated to a repeat output node also come out of the corresponding repeat input node. */
|
||||
bool changed = false;
|
||||
for (const bNodeTreeZone *zone : repeat_zones_to_consider) {
|
||||
const auto &storage = *static_cast<const NodeGeometryRepeatOutput *>(
|
||||
zone->output_node->storage);
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const bNodeSocket &body_input_socket = zone->input_node->output_socket(i);
|
||||
const bNodeSocket &body_output_socket = zone->output_node->input_socket(i);
|
||||
const int in_index = body_input_socket.index_in_tree();
|
||||
const int out_index = body_output_socket.index_in_tree();
|
||||
|
||||
changed |= or_into_each_other(propagated_fields_by_socket, in_index, out_index);
|
||||
changed |= or_into_each_other(propagated_geometries_by_socket, in_index, out_index);
|
||||
changed |= or_into_each_other(available_fields_by_geometry_socket, in_index, out_index);
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -346,8 +407,8 @@ static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
|
|||
VectorSet<int> propagated_output_geometry_indices;
|
||||
aal::RelationsInNode tree_relations;
|
||||
|
||||
/* Create #PropagateRelation, #AvailableRelation and #ReferenceRelation for the tree based on the
|
||||
* propagated data from above. */
|
||||
/* Create #PropagateRelation, #AvailableRelation and #ReferenceRelation for the tree based on
|
||||
* the propagated data from above. */
|
||||
if (const bNode *group_output_node = tree.group_output_node()) {
|
||||
for (const bNodeSocket *socket : group_output_node->input_sockets().drop_back(1)) {
|
||||
if (socket->type == SOCK_GEOMETRY) {
|
||||
|
@ -410,38 +471,64 @@ static AnonymousAttributeInferencingResult analyse_anonymous_attribute_usages(
|
|||
|
||||
/* Inferencing pass from right to left to determine which anonymous attributes have to be
|
||||
* propagated to which geometry sockets. */
|
||||
for (const bNode *node : tree.toposort_right_to_left()) {
|
||||
for (const bNodeSocket *socket : node->output_sockets()) {
|
||||
if (!socket->is_available()) {
|
||||
continue;
|
||||
}
|
||||
const int dst_index = socket->index_in_tree();
|
||||
for (const bNodeLink *link : socket->directly_linked_links()) {
|
||||
if (link->is_used()) {
|
||||
const int src_index = link->tosock->index_in_tree();
|
||||
required_fields_by_geometry_socket[dst_index] |=
|
||||
required_fields_by_geometry_socket[src_index];
|
||||
propagate_to_output_by_geometry_socket[dst_index] |=
|
||||
propagate_to_output_by_geometry_socket[src_index];
|
||||
auto pass_right_to_left = [&]() {
|
||||
for (const bNode *node : tree.toposort_right_to_left()) {
|
||||
for (const bNodeSocket *socket : node->output_sockets()) {
|
||||
if (!socket->is_available()) {
|
||||
continue;
|
||||
}
|
||||
const int dst_index = socket->index_in_tree();
|
||||
for (const bNodeLink *link : socket->directly_linked_links()) {
|
||||
if (link->is_used()) {
|
||||
const int src_index = link->tosock->index_in_tree();
|
||||
required_fields_by_geometry_socket[dst_index] |=
|
||||
required_fields_by_geometry_socket[src_index];
|
||||
propagate_to_output_by_geometry_socket[dst_index] |=
|
||||
propagate_to_output_by_geometry_socket[src_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
const aal::RelationsInNode &relations = *relations_by_node[node->index()];
|
||||
for (const aal::PropagateRelation &relation : relations.propagate_relations) {
|
||||
const bNodeSocket &output_socket = node->output_socket(relation.to_geometry_output);
|
||||
const bNodeSocket &input_socket = node->input_socket(relation.from_geometry_input);
|
||||
const int src_index = output_socket.index_in_tree();
|
||||
const int dst_index = input_socket.index_in_tree();
|
||||
required_fields_by_geometry_socket[dst_index] |=
|
||||
required_fields_by_geometry_socket[src_index];
|
||||
propagate_to_output_by_geometry_socket[dst_index] |=
|
||||
propagate_to_output_by_geometry_socket[src_index];
|
||||
}
|
||||
for (const aal::EvalRelation &relation : relations.eval_relations) {
|
||||
const bNodeSocket &geometry_socket = node->input_socket(relation.geometry_input);
|
||||
const bNodeSocket &field_socket = node->input_socket(relation.field_input);
|
||||
required_fields_by_geometry_socket[geometry_socket.index_in_tree()] |=
|
||||
propagated_fields_by_socket[field_socket.index_in_tree()];
|
||||
}
|
||||
}
|
||||
const aal::RelationsInNode &relations = *relations_by_node[node->index()];
|
||||
for (const aal::PropagateRelation &relation : relations.propagate_relations) {
|
||||
const bNodeSocket &output_socket = node->output_socket(relation.to_geometry_output);
|
||||
const bNodeSocket &input_socket = node->input_socket(relation.from_geometry_input);
|
||||
const int src_index = output_socket.index_in_tree();
|
||||
const int dst_index = input_socket.index_in_tree();
|
||||
required_fields_by_geometry_socket[dst_index] |=
|
||||
required_fields_by_geometry_socket[src_index];
|
||||
propagate_to_output_by_geometry_socket[dst_index] |=
|
||||
propagate_to_output_by_geometry_socket[src_index];
|
||||
};
|
||||
|
||||
while (true) {
|
||||
pass_right_to_left();
|
||||
|
||||
/* Data required by a repeat input node will also be required by the repeat output node,
|
||||
* because that's where the data comes from after the first iteration. */
|
||||
bool changed = false;
|
||||
for (const bNodeTreeZone *zone : repeat_zones_to_consider) {
|
||||
const auto &storage = *static_cast<const NodeGeometryRepeatOutput *>(
|
||||
zone->output_node->storage);
|
||||
for (const int i : IndexRange(storage.items_num)) {
|
||||
const bNodeSocket &body_input_socket = zone->input_node->output_socket(i);
|
||||
const bNodeSocket &body_output_socket = zone->output_node->input_socket(i);
|
||||
const int in_index = body_input_socket.index_in_tree();
|
||||
const int out_index = body_output_socket.index_in_tree();
|
||||
|
||||
changed |= or_into_each_other(required_fields_by_geometry_socket, in_index, out_index);
|
||||
changed |= or_into_each_other(propagate_to_output_by_geometry_socket, in_index, out_index);
|
||||
}
|
||||
}
|
||||
for (const aal::EvalRelation &relation : relations.eval_relations) {
|
||||
const bNodeSocket &geometry_socket = node->input_socket(relation.geometry_input);
|
||||
const bNodeSocket &field_socket = node->input_socket(relation.field_input);
|
||||
required_fields_by_geometry_socket[geometry_socket.index_in_tree()] |=
|
||||
propagated_fields_by_socket[field_socket.index_in_tree()];
|
||||
if (!changed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -238,9 +238,23 @@ template<typename... BitSpanT> inline bool has_common_set_bits(const BitSpanT &.
|
|||
return any_set_expr([](const auto... x) { return (x & ...); }, args...);
|
||||
}
|
||||
|
||||
template<typename BitSpanT> inline bool any_bit_set(const BitSpanT &arg)
|
||||
{
|
||||
return has_common_set_bits(arg);
|
||||
}
|
||||
|
||||
template<typename BitSpanT, typename Fn> inline void foreach_1_index(const BitSpanT &data, Fn &&fn)
|
||||
{
|
||||
foreach_1_index_expr([](const BitInt x) { return x; }, fn, data);
|
||||
}
|
||||
|
||||
template<typename BitSpanT1, typename BitSpanT2>
|
||||
inline bool spans_equal(const BitSpanT1 &a, const BitSpanT2 &b)
|
||||
{
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
return !any_set_expr([](const BitInt a, const BitInt b) { return a ^ b; }, a, b);
|
||||
}
|
||||
|
||||
} // namespace blender::bits
|
||||
|
|
|
@ -216,7 +216,7 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out, bool keep_hidden
|
|||
|
||||
/* Save the original #BMEdge's so we can use them as examples. */
|
||||
Array<BMEdge *> old_edges(bm->totedge);
|
||||
std::copy(bm->etable, bm->etable + bm->totedge, old_edges.begin());
|
||||
std::copy_n(bm->etable, bm->totedge, old_edges.begin());
|
||||
|
||||
/* Reuse or make new #BMFace's, as the faces are identical to old ones or not.
|
||||
* If reusing, mark them as "keep". First find the maximum face length
|
||||
|
|
|
@ -479,7 +479,7 @@ struct PBVHBatches {
|
|||
face_no = convert_value<float3, short4>(args.face_normals[face_i]);
|
||||
last_face = face_i;
|
||||
}
|
||||
std::fill(data, data + 3, face_no);
|
||||
std::fill_n(data, 3, face_no);
|
||||
data += 3;
|
||||
}
|
||||
else {
|
||||
|
@ -738,7 +738,7 @@ struct PBVHBatches {
|
|||
fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
|
||||
}
|
||||
}
|
||||
std::fill(data, data + 3, fset_color);
|
||||
std::fill_n(data, 3, fset_color);
|
||||
data += 3;
|
||||
}
|
||||
}
|
||||
|
@ -893,7 +893,7 @@ struct PBVHBatches {
|
|||
data++;
|
||||
}
|
||||
else {
|
||||
std::fill(data, data + 3, convert_value<float3, short4>(f->no));
|
||||
std::fill_n(data, 3, convert_value<float3, short4>(f->no));
|
||||
data += 3;
|
||||
}
|
||||
}
|
||||
|
@ -933,7 +933,7 @@ struct PBVHBatches {
|
|||
/* Skip for the default color face set to render it white. */
|
||||
fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
|
||||
}
|
||||
std::fill(data, data + 3, fset_color);
|
||||
std::fill_n(data, 3, fset_color);
|
||||
data += 3;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -450,7 +450,7 @@ static void run_node_group_ui(bContext *C, wmOperator *op)
|
|||
|
||||
node_tree->ensure_interface_cache();
|
||||
int input_index = 0;
|
||||
for (bNodeTreeInterfaceSocket *io_socket : node_tree->interface_inputs()) {
|
||||
for (const bNodeTreeInterfaceSocket *io_socket : node_tree->interface_inputs()) {
|
||||
draw_property_for_socket(
|
||||
*node_tree, layout, op->properties, &bmain_ptr, op->ptr, *io_socket, input_index);
|
||||
++input_index;
|
||||
|
|
|
@ -459,7 +459,6 @@ static int grease_pencil_stroke_simplify_exec(bContext *C, wmOperator *op)
|
|||
if (curves.points_num() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ed::curves::has_anything_selected(curves)) {
|
||||
return;
|
||||
}
|
||||
|
@ -666,7 +665,6 @@ static int grease_pencil_dissolve_exec(bContext *C, wmOperator *op)
|
|||
if (curves.points_num() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ed::curves::has_anything_selected(curves)) {
|
||||
return;
|
||||
}
|
||||
|
@ -884,23 +882,20 @@ static int grease_pencil_cyclical_set_exec(bContext *C, wmOperator *op)
|
|||
grease_pencil.foreach_editable_drawing(
|
||||
scene->r.cfra, [&](int /*layer_index*/, bke::greasepencil::Drawing &drawing) {
|
||||
bke::CurvesGeometry &curves = drawing.strokes_for_write();
|
||||
if (curves.points_num() == 0) {
|
||||
return;
|
||||
}
|
||||
if (!ed::curves::has_anything_selected(curves)) {
|
||||
|
||||
if (mode == CyclicalMode::OPEN && !curves.attributes().contains("cyclic")) {
|
||||
/* Avoid creating unneeded attribute. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Return to stop from creating unneeded attribute. */
|
||||
if (mode == CyclicalMode::OPEN && !curves.attributes().contains("cyclic")) {
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask curve_selection = ed::curves::retrieve_selected_curves(curves, memory);
|
||||
if (curve_selection.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MutableSpan<bool> cyclic = curves.cyclic_for_write();
|
||||
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask curve_selection = ed::curves::retrieve_selected_curves(curves, memory);
|
||||
|
||||
switch (mode) {
|
||||
case CyclicalMode::CLOSE:
|
||||
index_mask::masked_fill(cyclic, true, curve_selection);
|
||||
|
@ -914,10 +909,11 @@ static int grease_pencil_cyclical_set_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
|
||||
/* Remove the attribute if it is empty. */
|
||||
if (mode != CyclicalMode::CLOSE &&
|
||||
!ed::curves::has_anything_selected(curves.cyclic(), curves.curves_range()))
|
||||
{
|
||||
curves.attributes_for_write().remove("cyclic");
|
||||
if (mode != CyclicalMode::CLOSE) {
|
||||
if (array_utils::booleans_mix_calc(curves.cyclic()) == array_utils::BooleanMix::AllFalse)
|
||||
{
|
||||
curves.attributes_for_write().remove("cyclic");
|
||||
}
|
||||
}
|
||||
|
||||
changed = true;
|
||||
|
|
|
@ -141,8 +141,8 @@ static int grease_pencil_layer_reorder_exec(bContext *C, wmOperator *op)
|
|||
op->ptr, "target_layer_name", nullptr, 0, &target_layer_name_length);
|
||||
const int reorder_location = RNA_enum_get(op->ptr, "location");
|
||||
|
||||
Layer *target_layer = grease_pencil.find_layer_by_name(target_layer_name);
|
||||
if (!target_layer) {
|
||||
TreeNode *target_node = grease_pencil.find_node_by_name(target_layer_name);
|
||||
if (!target_node || !target_node->is_layer()) {
|
||||
MEM_SAFE_FREE(target_layer_name);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
@ -152,13 +152,13 @@ static int grease_pencil_layer_reorder_exec(bContext *C, wmOperator *op)
|
|||
case LAYER_REORDER_ABOVE: {
|
||||
/* NOTE: The layers are stored from bottom to top, so inserting above (visually), means
|
||||
* inserting the link after the target. */
|
||||
grease_pencil.move_node_after(active_layer.as_node(), target_layer->as_node());
|
||||
grease_pencil.move_node_after(active_layer.as_node(), *target_node);
|
||||
break;
|
||||
}
|
||||
case LAYER_REORDER_BELOW: {
|
||||
/* NOTE: The layers are stored from bottom to top, so inserting below (visually), means
|
||||
* inserting the link before the target. */
|
||||
grease_pencil.move_node_before(active_layer.as_node(), target_layer->as_node());
|
||||
grease_pencil.move_node_before(active_layer.as_node(), *target_node);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -3107,18 +3107,19 @@ static bool ed_curves_select_pick(bContext &C, const int mval[2], const SelectPi
|
|||
for (Base *base : bases.slice(range)) {
|
||||
Curves &curves_id = *static_cast<Curves *>(base->object->data);
|
||||
bke::CurvesGeometry &curves = curves_id.geometry.wrap();
|
||||
if (ed::curves::has_anything_selected(curves)) {
|
||||
bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
|
||||
curves, selection_domain, CD_PROP_BOOL);
|
||||
ed::curves::fill_selection_false(selection.span);
|
||||
selection.finish();
|
||||
|
||||
deselected = true;
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
|
||||
* generic attribute for now. */
|
||||
DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &curves_id);
|
||||
if (!ed::curves::has_anything_selected(curves)) {
|
||||
continue;
|
||||
}
|
||||
bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
|
||||
curves, selection_domain, CD_PROP_BOOL);
|
||||
ed::curves::fill_selection_false(selection.span);
|
||||
selection.finish();
|
||||
|
||||
deselected = true;
|
||||
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
|
||||
* generic attribute for now. */
|
||||
DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &curves_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -3213,14 +3214,15 @@ static bool ed_grease_pencil_select_pick(bContext *C,
|
|||
threading::parallel_for(drawings.index_range(), 1L, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
bke::CurvesGeometry &curves = drawings[i]->geometry.wrap();
|
||||
if (ed::curves::has_anything_selected(curves)) {
|
||||
bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
|
||||
curves, selection_domain, CD_PROP_BOOL);
|
||||
ed::curves::fill_selection_false(selection.span);
|
||||
selection.finish();
|
||||
|
||||
deselected = true;
|
||||
if (!ed::curves::has_anything_selected(curves)) {
|
||||
continue;
|
||||
}
|
||||
bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
|
||||
curves, selection_domain, CD_PROP_BOOL);
|
||||
ed::curves::fill_selection_false(selection.span);
|
||||
selection.finish();
|
||||
|
||||
deselected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -637,7 +637,7 @@ static void createTransNlaData(bContext *C, TransInfo *t)
|
|||
static void recalcData_nla(TransInfo *t)
|
||||
{
|
||||
SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
|
||||
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
|
||||
/* For each strip we've got, perform some additional validation of the values
|
||||
|
|
|
@ -492,11 +492,8 @@ typedef struct GreasePencil {
|
|||
blender::bke::greasepencil::LayerGroup &parent_group);
|
||||
|
||||
/* Search functions. */
|
||||
const blender::bke::greasepencil::Layer *find_layer_by_name(blender::StringRefNull name) const;
|
||||
blender::bke::greasepencil::Layer *find_layer_by_name(blender::StringRefNull name);
|
||||
const blender::bke::greasepencil::LayerGroup *find_layer_group_by_name(
|
||||
blender::StringRefNull name) const;
|
||||
blender::bke::greasepencil::LayerGroup *find_layer_group_by_name(blender::StringRefNull name);
|
||||
const blender::bke::greasepencil::TreeNode *find_node_by_name(blender::StringRefNull name) const;
|
||||
blender::bke::greasepencil::TreeNode *find_node_by_name(blender::StringRefNull name);
|
||||
|
||||
void rename_node(blender::bke::greasepencil::TreeNode &node, blender::StringRefNull new_name);
|
||||
|
||||
|
|
|
@ -788,9 +788,12 @@ typedef struct bNodeTree {
|
|||
void ensure_interface_cache() const;
|
||||
|
||||
/* Cached interface item lists. */
|
||||
blender::Span<bNodeTreeInterfaceSocket *> interface_inputs() const;
|
||||
blender::Span<bNodeTreeInterfaceSocket *> interface_outputs() const;
|
||||
blender::Span<bNodeTreeInterfaceItem *> interface_items() const;
|
||||
blender::Span<bNodeTreeInterfaceSocket *> interface_inputs();
|
||||
blender::Span<const bNodeTreeInterfaceSocket *> interface_inputs() const;
|
||||
blender::Span<bNodeTreeInterfaceSocket *> interface_outputs();
|
||||
blender::Span<const bNodeTreeInterfaceSocket *> interface_outputs() const;
|
||||
blender::Span<bNodeTreeInterfaceItem *> interface_items();
|
||||
blender::Span<const bNodeTreeInterfaceItem *> interface_items() const;
|
||||
#endif
|
||||
} bNodeTree;
|
||||
|
||||
|
|
Loading…
Reference in New Issue