UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
56 changed files with 2575 additions and 1527 deletions
Showing only changes of commit 801b01ba01 - Show all commits

5
extern/xdnd/xdnd.c vendored
View File

@ -464,8 +464,9 @@ static char *concat_string_list (char **t, int *bytes)
break;
if (!(t[n][0]))
break;
strcpy (s + l, t[n]);
l += strlen (t[n]) + 1;
int t_size = strlen (t[n]) + 1;
memcpy (s + l, t[n], t_size);
l += t_size;
}
*bytes = l;
s[l] = '\0';

View File

@ -270,10 +270,11 @@ void *GHOST_DropTargetWin32::getDropDataAsString(IDataObject *p_data_object)
if (p_data_object->QueryGetData(&fmtetc) == S_OK) {
if (p_data_object->GetData(&fmtetc, &stgmed) == S_OK) {
char *str = (char *)::GlobalLock(stgmed.hGlobal);
int str_size = ::strlen(str) + 1;
tmp_string = (char *)::malloc(::strlen(str) + 1);
tmp_string = (char *)::malloc(str_size);
if (tmp_string) {
::strcpy(tmp_string, str);
::memcpy(tmp_string, str, str_size);
}
/* Free memory. */
::GlobalUnlock(stgmed.hGlobal);

View File

@ -566,7 +566,7 @@ def _name_convention_attribute_remove(attributes, name):
class Mesh(bpy_types.ID):
__slots__ = ()
def from_pydata(self, vertices, edges, faces):
def from_pydata(self, vertices, edges, faces, shade_flat=True):
"""
Make a mesh from a list of vertices/edges/faces
Until we have a nicer way to make geometry, use this.
@ -623,6 +623,9 @@ class Mesh(bpy_types.ID):
self.polygons.foreach_set("loop_start", loop_starts)
self.polygons.foreach_set("vertices", vertex_indices)
if shade_flat:
self.shade_flat()
if edges_len or faces_len:
self.update(
# Needed to either:
@ -663,6 +666,22 @@ class Mesh(bpy_types.ID):
def edge_creases_remove(self):
_name_convention_attribute_remove(self.attributes, "crease_edge")
def shade_flat(self):
"""
Render and display faces uniform, using face normals,
setting the "sharp_face" attribute true for every face
"""
sharp_faces = _name_convention_attribute_ensure(self.attributes, "sharp_face", 'FACE', 'BOOLEAN')
for value in sharp_faces.data:
value.value = True
def shade_smooth(self):
"""
Render and display faces smooth, using interpolated vertex normals,
removing the "sharp_face" attribute
"""
_name_convention_attribute_remove(self.attributes, "sharp_face")
class MeshEdge(StructRNA):
__slots__ = ()

View File

@ -246,6 +246,7 @@ class AddTorus(Operator, object_utils.AddObjectHelper):
mesh.vertices.foreach_set("co", verts_loc)
mesh.polygons.foreach_set("loop_start", range(0, nbr_loops, 4))
mesh.loops.foreach_set("vertex_index", faces)
mesh.shade_flat()
if self.generate_uvs:
add_uvs(mesh, self.minor_segments, self.major_segments)

View File

@ -31,7 +31,7 @@ def draw_ui_list(
context,
class_name="UI_UL_list",
*,
unique_id="",
unique_id,
list_path,
active_index_path,
insertion_operators=True,
@ -48,7 +48,7 @@ def draw_ui_list(
:type context: :class:`Context`
:arg class_name: Name of the UIList class to draw. The default is the UIList class that ships with Blender.
:type class_name: str
:arg unique_id: Optional identifier, in case wanting to draw multiple unique copies of a list.
:arg unique_id: Unique identifier to differentiate this from other UI lists.
:type unique_id: str
:arg list_path: Data path of the list relative to context, eg. "object.vertex_groups".
:type list_path: str

View File

@ -87,8 +87,12 @@ class SPREADSHEET_HT_header(bpy.types.Header):
layout.label(text="Invalid id")
elif ctx.type == 'MODIFIER':
layout.label(text=ctx.modifier_name, icon='MODIFIER')
elif ctx.type == 'NODE':
layout.label(text=ctx.node_name, icon='NODE')
elif ctx.type == 'GROUP_NODE':
layout.label(text=ctx.ui_name, icon='NODE')
elif ctx.type == 'SIMULATION_ZONE':
layout.label(text="Simulation Zone")
elif ctx.type == 'VIEWER_NODE':
layout.label(text=ctx.ui_name)
def draw_spreadsheet_viewer_path_icon(self, layout, space, icon='RIGHTARROW_THIN'):
layout.prop(space, "display_viewer_path_collapsed", icon_only=True, emboss=False, icon=icon)

View File

@ -3068,8 +3068,8 @@ class VIEW3D_MT_object_convert(Menu):
def draw(self, context):
layout = self.layout
ob = context.active_object
if ob and ob.type == 'GPENCIL' and context.gpencil_data:
if ob and ob.type == 'GPENCIL' and context.gpencil_data and not context.preferences.experimental.use_grease_pencil_version3:
layout.operator_enum("gpencil.convert", "type")
else:
layout.operator_enum("object.convert", "target")

View File

@ -18,8 +18,9 @@ class MyPanel(bpy.types.Panel):
draw_ui_list(
layout,
context,
list_context_path="scene.my_list",
active_index_context_path="scene.my_list_active_index"
list_path="scene.my_list",
active_index_path="scene.my_list_active_index",
unique_id="my_list_id",
)

View File

@ -59,4 +59,23 @@ class NodeGroupComputeContext : public ComputeContext {
void print_current_in_line(std::ostream &stream) const override;
};
class SimulationZoneComputeContext : public ComputeContext {
private:
static constexpr const char *s_static_type = "SIMULATION_ZONE";
int32_t output_node_id_;
public:
SimulationZoneComputeContext(const ComputeContext *parent, int output_node_id);
SimulationZoneComputeContext(const ComputeContext *parent, const bNode &node);
int32_t output_node_id() const
{
return output_node_id_;
}
private:
void print_current_in_line(std::ostream &stream) const override;
};
} // namespace blender::bke

View File

@ -33,8 +33,8 @@ struct RelationsInNode;
}
namespace aal = anonymous_attribute_lifetime;
} // namespace blender::nodes
namespace blender::bke::node_tree_zones {
class TreeZones;
namespace blender::bke {
class bNodeTreeZones;
}
namespace blender::bke::anonymous_attribute_inferencing {
struct AnonymousAttributeInferencingResult;
@ -149,7 +149,7 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
mutable std::atomic<int> allow_use_dirty_topology_cache = 0;
CacheMutex tree_zones_cache_mutex;
std::unique_ptr<node_tree_zones::TreeZones> tree_zones;
std::unique_ptr<bNodeTreeZones> tree_zones;
/** Only valid when #topology_cache_is_dirty is false. */
Vector<bNodeLink *> links;

View File

@ -12,10 +12,13 @@
#include "BLI_vector.hh"
namespace blender::bke::node_tree_zones {
namespace blender::bke {
struct TreeZone {
TreeZones *owner = nullptr;
class bNodeTreeZones;
class bNodeTreeZone {
public:
bNodeTreeZones *owner = nullptr;
/** Index of the zone in the array of all zones in a node tree. */
int index = -1;
/** Zero for top level zones, one for a nested zone, and so on. */
@ -25,22 +28,22 @@ struct TreeZone {
/** Output node of the zone. */
const bNode *output_node = nullptr;
/** Direct parent of the zone. If this is null, this is a top level zone. */
TreeZone *parent_zone = nullptr;
bNodeTreeZone *parent_zone = nullptr;
/** Direct children zones. Does not contain recursively nested zones. */
Vector<TreeZone *> child_zones;
Vector<bNodeTreeZone *> child_zones;
/** Direct children nodes excluding nodes that belong to child zones. */
Vector<const bNode *> child_nodes;
/** Links that enter the zone through the zone border. */
Vector<const bNodeLink *> border_links;
bool contains_node_recursively(const bNode &node) const;
bool contains_zone_recursively(const TreeZone &other_zone) const;
bool contains_zone_recursively(const bNodeTreeZone &other_zone) const;
};
class TreeZones {
class bNodeTreeZones {
public:
Vector<std::unique_ptr<TreeZone>> zones;
Vector<TreeZone *> root_zones;
Vector<std::unique_ptr<bNodeTreeZone>> zones;
Vector<bNodeTreeZone *> root_zones;
Vector<const bNode *> nodes_outside_zones;
/**
* Zone index by node. Nodes that are in no zone, are not included. Nodes that are at the border
@ -52,9 +55,26 @@ class TreeZones {
* Get the deepest zone that a socket is in. Note that the inputs of a Simulation Input node are
* in a different zone than its output sockets.
*/
const TreeZone *get_zone_by_socket(const bNodeSocket &socket) const;
const bNodeTreeZone *get_zone_by_socket(const bNodeSocket &socket) const;
/**
* Get the deepest zone that the node is in. Note that the e.g. Simulation Input and Output nodes
* are considered to be inside of the zone they create.
*/
const bNodeTreeZone *get_zone_by_node(const int32_t node_id) const;
/**
* Get a sorted list of zones that the node is in. First comes the root zone and last the most
* nested zone. For nodes that are at the root level, the returned list is empty.
*/
Vector<const bNodeTreeZone *> get_zone_stack_for_node(const int32_t node_id) const;
};
const TreeZones *get_tree_zones(const bNodeTree &tree);
const bNodeTreeZones *get_tree_zones(const bNodeTree &tree);
} // namespace blender::bke::node_tree_zones
} // namespace blender::bke
inline const blender::bke::bNodeTreeZones *bNodeTree::zones() const
{
return blender::bke::get_tree_zones(*this);
}

View File

@ -50,7 +50,9 @@ void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const struct IDRemapper *
ViewerPathElem *BKE_viewer_path_elem_new(ViewerPathElemType type);
IDViewerPathElem *BKE_viewer_path_elem_new_id(void);
ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier(void);
NodeViewerPathElem *BKE_viewer_path_elem_new_node(void);
GroupNodeViewerPathElem *BKE_viewer_path_elem_new_group_node(void);
SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone(void);
ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node(void);
ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src);
bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b);
void BKE_viewer_path_elem_free(ViewerPathElem *elem);

View File

@ -2,6 +2,8 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_string.h"
#include "BKE_action.h"
#include "DNA_action_types.h"
@ -53,10 +55,10 @@ TEST(action_groups, ReconstructGroupsWithReordering)
bActionGroup groupB = {nullptr};
bActionGroup groupC = {nullptr};
bActionGroup groupD = {nullptr};
strcpy(groupA.name, "groupA");
strcpy(groupB.name, "groupB");
strcpy(groupC.name, "groupC");
strcpy(groupD.name, "groupD");
STRNCPY(groupA.name, "groupA");
STRNCPY(groupB.name, "groupB");
STRNCPY(groupC.name, "groupC");
STRNCPY(groupD.name, "groupD");
BLI_addtail(&action.groups, &groupA);
BLI_addtail(&action.groups, &groupB);

View File

@ -703,7 +703,7 @@ bool bone_autoside_name(
{
uint len;
char basename[MAXBONENAME] = "";
char extension[5] = "";
const char *extension = NULL;
len = strlen(name);
if (len == 0) {
@ -723,18 +723,18 @@ bool bone_autoside_name(
/* z-axis - vertical (top/bottom) */
if (IS_EQF(head, 0.0f)) {
if (tail < 0) {
strcpy(extension, "Bot");
extension = "Bot";
}
else if (tail > 0) {
strcpy(extension, "Top");
extension = "Top";
}
}
else {
if (head < 0) {
strcpy(extension, "Bot");
extension = "Bot";
}
else {
strcpy(extension, "Top");
extension = "Top";
}
}
}
@ -742,18 +742,18 @@ bool bone_autoside_name(
/* y-axis - depth (front/back) */
if (IS_EQF(head, 0.0f)) {
if (tail < 0) {
strcpy(extension, "Fr");
extension = "Fr";
}
else if (tail > 0) {
strcpy(extension, "Bk");
extension = "Bk";
}
}
else {
if (head < 0) {
strcpy(extension, "Fr");
extension = "Fr";
}
else {
strcpy(extension, "Bk");
extension = "Bk";
}
}
}
@ -761,19 +761,19 @@ bool bone_autoside_name(
/* x-axis - horizontal (left/right) */
if (IS_EQF(head, 0.0f)) {
if (tail < 0) {
strcpy(extension, "R");
extension = "R";
}
else if (tail > 0) {
strcpy(extension, "L");
extension = "L";
}
}
else {
if (head < 0) {
strcpy(extension, "R");
extension = "R";
/* XXX Shouldn't this be simple else, as for z and y axes? */
}
else if (head > 0) {
strcpy(extension, "L");
extension = "L";
}
}
}
@ -782,7 +782,7 @@ bool bone_autoside_name(
* - truncate if there is an extension and it wouldn't be able to fit
* - otherwise, just append to end
*/
if (extension[0]) {
if (extension) {
bool changed = true;
while (changed) { /* remove extensions */

View File

@ -62,4 +62,30 @@ void NodeGroupComputeContext::print_current_in_line(std::ostream &stream) const
stream << "Node ID: " << node_id_;
}
SimulationZoneComputeContext::SimulationZoneComputeContext(const ComputeContext *parent,
const int32_t output_node_id)
: ComputeContext(s_static_type, parent), output_node_id_(output_node_id)
{
/* Mix static type and node id into a single buffer so that only a single call to #mix_in is
* necessary. */
const int type_size = strlen(s_static_type);
const int buffer_size = type_size + 1 + sizeof(int32_t);
DynamicStackBuffer<64, 8> buffer_owner(buffer_size, 8);
char *buffer = static_cast<char *>(buffer_owner.buffer());
memcpy(buffer, s_static_type, type_size + 1);
memcpy(buffer + type_size + 1, &output_node_id_, sizeof(int32_t));
hash_.mix_in(buffer, buffer_size);
}
SimulationZoneComputeContext::SimulationZoneComputeContext(const ComputeContext *parent,
const bNode &node)
: SimulationZoneComputeContext(parent, node.identifier)
{
}
void SimulationZoneComputeContext::print_current_in_line(std::ostream &stream) const
{
stream << "Simulation Zone ID: " << output_node_id_;
}
} // namespace blender::bke

View File

@ -11,9 +11,9 @@
#include "BLI_task.hh"
#include "BLI_timeit.hh"
namespace blender::bke::node_tree_zones {
namespace blender::bke {
static void update_zone_depths(TreeZone &zone)
static void update_zone_depths(bNodeTreeZone &zone)
{
if (zone.depth >= 0) {
return;
@ -26,12 +26,14 @@ static void update_zone_depths(TreeZone &zone)
zone.depth = zone.parent_zone->depth + 1;
}
static Vector<std::unique_ptr<TreeZone>> find_zone_nodes(
const bNodeTree &tree, TreeZones &owner, Map<const bNode *, TreeZone *> &r_zone_by_inout_node)
static Vector<std::unique_ptr<bNodeTreeZone>> find_zone_nodes(
const bNodeTree &tree,
bNodeTreeZones &owner,
Map<const bNode *, bNodeTreeZone *> &r_zone_by_inout_node)
{
Vector<std::unique_ptr<TreeZone>> zones;
Vector<std::unique_ptr<bNodeTreeZone>> zones;
for (const bNode *node : tree.nodes_by_type("GeometryNodeSimulationOutput")) {
auto zone = std::make_unique<TreeZone>();
auto zone = std::make_unique<bNodeTreeZone>();
zone->owner = &owner;
zone->index = zones.size();
zone->output_node = node;
@ -41,7 +43,7 @@ static Vector<std::unique_ptr<TreeZone>> find_zone_nodes(
for (const bNode *node : tree.nodes_by_type("GeometryNodeSimulationInput")) {
const auto &storage = *static_cast<NodeGeometrySimulationInput *>(node->storage);
if (const bNode *sim_output_node = tree.node_by_id(storage.output_node_id)) {
if (TreeZone *zone = r_zone_by_inout_node.lookup_default(sim_output_node, nullptr)) {
if (bNodeTreeZone *zone = r_zone_by_inout_node.lookup_default(sim_output_node, nullptr)) {
zone->input_node = node;
r_zone_by_inout_node.add(node, zone);
}
@ -51,18 +53,18 @@ static Vector<std::unique_ptr<TreeZone>> find_zone_nodes(
}
struct ZoneRelation {
TreeZone *parent;
TreeZone *child;
bNodeTreeZone *parent;
bNodeTreeZone *child;
};
static Vector<ZoneRelation> get_direct_zone_relations(
const Span<std::unique_ptr<TreeZone>> all_zones,
const Span<std::unique_ptr<bNodeTreeZone>> all_zones,
const BitGroupVector<> &depend_on_input_flag_array)
{
Vector<ZoneRelation> zone_relations;
/* Gather all relations, even the transitive once. */
for (const std::unique_ptr<TreeZone> &zone : all_zones) {
for (const std::unique_ptr<bNodeTreeZone> &zone : all_zones) {
const int zone_i = zone->index;
for (const bNode *node : {zone->output_node}) {
if (node == nullptr) {
@ -108,18 +110,18 @@ static Vector<ZoneRelation> get_direct_zone_relations(
}
static void update_zone_per_node(const Span<const bNode *> all_nodes,
const Span<std::unique_ptr<TreeZone>> all_zones,
const Span<std::unique_ptr<bNodeTreeZone>> all_zones,
const BitGroupVector<> &depend_on_input_flag_array,
const Map<const bNode *, TreeZone *> &zone_by_inout_node,
const Map<const bNode *, bNodeTreeZone *> &zone_by_inout_node,
Map<int, int> &r_zone_by_node_id,
Vector<const bNode *> &r_node_outside_zones)
{
for (const int node_i : all_nodes.index_range()) {
const bNode &node = *all_nodes[node_i];
const BoundedBitSpan depend_on_input_flags = depend_on_input_flag_array[node_i];
TreeZone *parent_zone = nullptr;
bNodeTreeZone *parent_zone = nullptr;
bits::foreach_1_index(depend_on_input_flags, [&](const int parent_zone_i) {
TreeZone *zone = all_zones[parent_zone_i].get();
bNodeTreeZone *zone = all_zones[parent_zone_i].get();
if (ELEM(&node, zone->input_node, zone->output_node)) {
return;
}
@ -136,12 +138,12 @@ static void update_zone_per_node(const Span<const bNode *> all_nodes,
r_zone_by_node_id.add(node.identifier, parent_zone->index);
}
}
for (const MapItem<const bNode *, TreeZone *> item : zone_by_inout_node.items()) {
for (const MapItem<const bNode *, bNodeTreeZone *> item : zone_by_inout_node.items()) {
r_zone_by_node_id.add_overwrite(item.key->identifier, item.value->index);
}
}
static void update_zone_border_links(const bNodeTree &tree, TreeZones &tree_zones)
static void update_zone_border_links(const bNodeTree &tree, bNodeTreeZones &tree_zones)
{
for (const bNodeLink *link : tree.all_links()) {
if (!link->is_available()) {
@ -150,28 +152,30 @@ static void update_zone_border_links(const bNodeTree &tree, TreeZones &tree_zone
if (link->is_muted()) {
continue;
}
TreeZone *from_zone = const_cast<TreeZone *>(tree_zones.get_zone_by_socket(*link->fromsock));
TreeZone *to_zone = const_cast<TreeZone *>(tree_zones.get_zone_by_socket(*link->tosock));
bNodeTreeZone *from_zone = const_cast<bNodeTreeZone *>(
tree_zones.get_zone_by_socket(*link->fromsock));
bNodeTreeZone *to_zone = const_cast<bNodeTreeZone *>(
tree_zones.get_zone_by_socket(*link->tosock));
if (from_zone == to_zone) {
continue;
}
BLI_assert(from_zone == nullptr || from_zone->contains_zone_recursively(*to_zone));
for (TreeZone *zone = to_zone; zone != from_zone; zone = zone->parent_zone) {
for (bNodeTreeZone *zone = to_zone; zone != from_zone; zone = zone->parent_zone) {
zone->border_links.append(link);
}
}
}
static std::unique_ptr<TreeZones> discover_tree_zones(const bNodeTree &tree)
static std::unique_ptr<bNodeTreeZones> discover_tree_zones(const bNodeTree &tree)
{
if (tree.has_available_link_cycle()) {
return {};
}
std::unique_ptr<TreeZones> tree_zones = std::make_unique<TreeZones>();
std::unique_ptr<bNodeTreeZones> tree_zones = std::make_unique<bNodeTreeZones>();
const Span<const bNode *> all_nodes = tree.all_nodes();
Map<const bNode *, TreeZone *> zone_by_inout_node;
Map<const bNode *, bNodeTreeZone *> zone_by_inout_node;
tree_zones->zones = find_zone_nodes(tree, *tree_zones, zone_by_inout_node);
const int zones_num = tree_zones->zones.size();
@ -203,13 +207,13 @@ static std::unique_ptr<TreeZones> discover_tree_zones(const bNodeTree &tree)
}
}
if (node->type == GEO_NODE_SIMULATION_INPUT) {
if (const TreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) {
if (const bNodeTreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) {
/* Now entering a zone, so set the corresponding bit. */
depend_on_input_flags[zone->index].set();
}
}
else if (node->type == GEO_NODE_SIMULATION_OUTPUT) {
if (const TreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) {
if (const bNodeTreeZone *zone = zone_by_inout_node.lookup_default(node, nullptr)) {
/* The output is implicitly linked to the input, so also propagate the bits from there. */
if (const bNode *zone_input_node = zone->input_node) {
const int input_node_i = zone_input_node->index();
@ -239,11 +243,11 @@ static std::unique_ptr<TreeZones> discover_tree_zones(const bNodeTree &tree)
}
/* Update depths. */
for (std::unique_ptr<TreeZone> &zone : tree_zones->zones) {
for (std::unique_ptr<bNodeTreeZone> &zone : tree_zones->zones) {
update_zone_depths(*zone);
}
for (std::unique_ptr<TreeZone> &zone : tree_zones->zones) {
for (std::unique_ptr<bNodeTreeZone> &zone : tree_zones->zones) {
if (zone->depth == 0) {
tree_zones->root_zones.append(zone.get());
}
@ -262,7 +266,7 @@ static std::unique_ptr<TreeZones> discover_tree_zones(const bNodeTree &tree)
if (zone_i == -1) {
continue;
}
const TreeZone &zone = *tree_zones->zones[zone_i];
const bNodeTreeZone &zone = *tree_zones->zones[zone_i];
if (ELEM(node, zone.input_node, zone.output_node)) {
continue;
}
@ -274,21 +278,21 @@ static std::unique_ptr<TreeZones> discover_tree_zones(const bNodeTree &tree)
return tree_zones;
}
const TreeZones *get_tree_zones(const bNodeTree &tree)
const bNodeTreeZones *get_tree_zones(const bNodeTree &tree)
{
tree.runtime->tree_zones_cache_mutex.ensure(
[&]() { tree.runtime->tree_zones = discover_tree_zones(tree); });
return tree.runtime->tree_zones.get();
}
bool TreeZone::contains_node_recursively(const bNode &node) const
bool bNodeTreeZone::contains_node_recursively(const bNode &node) const
{
const TreeZones *zones = this->owner;
const bNodeTreeZones *zones = this->owner;
const int zone_i = zones->zone_by_node_id.lookup_default(node.identifier, -1);
if (zone_i == -1) {
return false;
}
for (const TreeZone *zone = zones->zones[zone_i].get(); zone; zone = zone->parent_zone) {
for (const bNodeTreeZone *zone = zones->zones[zone_i].get(); zone; zone = zone->parent_zone) {
if (zone == this) {
return true;
}
@ -296,9 +300,9 @@ bool TreeZone::contains_node_recursively(const bNode &node) const
return false;
}
bool TreeZone::contains_zone_recursively(const TreeZone &other_zone) const
bool bNodeTreeZone::contains_zone_recursively(const bNodeTreeZone &other_zone) const
{
for (const TreeZone *zone = other_zone.parent_zone; zone; zone = zone->parent_zone) {
for (const bNodeTreeZone *zone = other_zone.parent_zone; zone; zone = zone->parent_zone) {
if (zone == this) {
return true;
}
@ -306,25 +310,47 @@ bool TreeZone::contains_zone_recursively(const TreeZone &other_zone) const
return false;
}
const TreeZone *TreeZones::get_zone_by_socket(const bNodeSocket &socket) const
const bNodeTreeZone *bNodeTreeZones::get_zone_by_socket(const bNodeSocket &socket) const
{
const bNode &node = socket.owner_node();
const int zone_i = this->zone_by_node_id.lookup_default(node.identifier, -1);
const bNodeTreeZone *zone = this->get_zone_by_node(node.identifier);
if (zone == nullptr) {
return zone;
}
if (zone->input_node == &node) {
if (socket.is_input()) {
return zone->parent_zone;
}
}
if (zone->output_node == &node) {
if (socket.is_output()) {
return zone->parent_zone;
}
}
return zone;
}
const bNodeTreeZone *bNodeTreeZones::get_zone_by_node(const int32_t node_id) const
{
const int zone_i = this->zone_by_node_id.lookup_default(node_id, -1);
if (zone_i == -1) {
return nullptr;
}
const TreeZone &zone = *this->zones[zone_i];
if (zone.input_node == &node) {
if (socket.is_input()) {
return zone.parent_zone;
}
}
if (zone.output_node == &node) {
if (socket.is_output()) {
return zone.parent_zone;
}
}
return &zone;
return this->zones[zone_i].get();
}
} // namespace blender::bke::node_tree_zones
Vector<const bNodeTreeZone *> bNodeTreeZones::get_zone_stack_for_node(const int node_id) const
{
const bNodeTreeZone *zone = this->get_zone_by_node(node_id);
if (zone == nullptr) {
return {};
}
Vector<const bNodeTreeZone *> zone_stack;
for (; zone; zone = zone->parent_zone) {
zone_stack.append(zone);
}
std::reverse(zone_stack.begin(), zone_stack.end());
return zone_stack;
}
} // namespace blender::bke

View File

@ -73,13 +73,23 @@ void BKE_viewer_path_blend_write(BlendWriter *writer, const ViewerPath *viewer_p
BLO_write_string(writer, typed_elem->modifier_name);
break;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
const auto *typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
BLO_write_struct(writer, NodeViewerPathElem, typed_elem);
BLO_write_string(writer, typed_elem->node_name);
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto *typed_elem = reinterpret_cast<GroupNodeViewerPathElem *>(elem);
BLO_write_struct(writer, GroupNodeViewerPathElem, typed_elem);
break;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto *typed_elem = reinterpret_cast<SimulationZoneViewerPathElem *>(elem);
BLO_write_struct(writer, SimulationZoneViewerPathElem, typed_elem);
break;
}
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
const auto *typed_elem = reinterpret_cast<ViewerNodeViewerPathElem *>(elem);
BLO_write_struct(writer, ViewerNodeViewerPathElem, typed_elem);
break;
}
}
BLO_write_string(writer, elem->ui_name);
}
}
@ -87,7 +97,11 @@ void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer
{
BLO_read_list(reader, &viewer_path->path);
LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) {
BLO_read_data_address(reader, &elem->ui_name);
switch (ViewerPathElemType(elem->type)) {
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
case VIEWER_PATH_ELEM_TYPE_ID: {
break;
}
@ -96,11 +110,6 @@ void BKE_viewer_path_blend_read_data(BlendDataReader *reader, ViewerPath *viewer
BLO_read_data_address(reader, &typed_elem->modifier_name);
break;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
auto *typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
BLO_read_data_address(reader, &typed_elem->node_name);
break;
}
}
}
}
@ -115,7 +124,9 @@ void BKE_viewer_path_blend_read_lib(BlendLibReader *reader, ID *self_id, ViewerP
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
case VIEWER_PATH_ELEM_TYPE_NODE: {
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
break;
}
}
@ -132,7 +143,9 @@ void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_p
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
case VIEWER_PATH_ELEM_TYPE_NODE: {
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
break;
}
}
@ -149,30 +162,39 @@ void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const IDRemapper *mapping
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
case VIEWER_PATH_ELEM_TYPE_NODE: {
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
break;
}
}
}
}
template<typename T> static T *make_elem(const ViewerPathElemType type)
{
T *elem = MEM_cnew<T>(__func__);
elem->base.type = type;
return elem;
}
ViewerPathElem *BKE_viewer_path_elem_new(const ViewerPathElemType type)
{
switch (type) {
case VIEWER_PATH_ELEM_TYPE_ID: {
IDViewerPathElem *elem = MEM_cnew<IDViewerPathElem>(__func__);
elem->base.type = type;
return &elem->base;
return &make_elem<IDViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
ModifierViewerPathElem *elem = MEM_cnew<ModifierViewerPathElem>(__func__);
elem->base.type = type;
return &elem->base;
return &make_elem<ModifierViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
NodeViewerPathElem *elem = MEM_cnew<NodeViewerPathElem>(__func__);
elem->base.type = type;
return &elem->base;
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
return &make_elem<GroupNodeViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
return &make_elem<SimulationZoneViewerPathElem>(type)->base;
}
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
return &make_elem<ViewerNodeViewerPathElem>(type)->base;
}
}
BLI_assert_unreachable();
@ -190,15 +212,30 @@ ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier()
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_MODIFIER));
}
NodeViewerPathElem *BKE_viewer_path_elem_new_node()
GroupNodeViewerPathElem *BKE_viewer_path_elem_new_group_node()
{
return reinterpret_cast<NodeViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_NODE));
return reinterpret_cast<GroupNodeViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_GROUP_NODE));
}
SimulationZoneViewerPathElem *BKE_viewer_path_elem_new_simulation_zone()
{
return reinterpret_cast<SimulationZoneViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE));
}
ViewerNodeViewerPathElem *BKE_viewer_path_elem_new_viewer_node()
{
return reinterpret_cast<ViewerNodeViewerPathElem *>(
BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_VIEWER_NODE));
}
ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
{
ViewerPathElem *dst = BKE_viewer_path_elem_new(ViewerPathElemType(src->type));
if (src->ui_name) {
dst->ui_name = BLI_strdup(src->ui_name);
}
switch (ViewerPathElemType(src->type)) {
case VIEWER_PATH_ELEM_TYPE_ID: {
const auto *old_elem = reinterpret_cast<const IDViewerPathElem *>(src);
@ -214,13 +251,22 @@ ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src)
}
break;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
const auto *old_elem = reinterpret_cast<const NodeViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<NodeViewerPathElem *>(dst);
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto *old_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<GroupNodeViewerPathElem *>(dst);
new_elem->node_id = old_elem->node_id;
break;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto *old_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<SimulationZoneViewerPathElem *>(dst);
new_elem->sim_output_node_id = old_elem->sim_output_node_id;
break;
}
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
const auto *old_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(src);
auto *new_elem = reinterpret_cast<ViewerNodeViewerPathElem *>(dst);
new_elem->node_id = old_elem->node_id;
if (old_elem->node_name != nullptr) {
new_elem->node_name = BLI_strdup(old_elem->node_name);
}
break;
}
}
@ -243,9 +289,19 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b
const auto *b_elem = reinterpret_cast<const ModifierViewerPathElem *>(b);
return StringRef(a_elem->modifier_name) == StringRef(b_elem->modifier_name);
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
const auto *a_elem = reinterpret_cast<const NodeViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const NodeViewerPathElem *>(b);
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto *a_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const GroupNodeViewerPathElem *>(b);
return a_elem->node_id == b_elem->node_id;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto *a_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const SimulationZoneViewerPathElem *>(b);
return a_elem->sim_output_node_id == b_elem->sim_output_node_id;
}
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
const auto *a_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(a);
const auto *b_elem = reinterpret_cast<const ViewerNodeViewerPathElem *>(b);
return a_elem->node_id == b_elem->node_id;
}
}
@ -255,7 +311,10 @@ bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b
void BKE_viewer_path_elem_free(ViewerPathElem *elem)
{
switch (ViewerPathElemType(elem->type)) {
case VIEWER_PATH_ELEM_TYPE_ID: {
case VIEWER_PATH_ELEM_TYPE_ID:
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE: {
break;
}
case VIEWER_PATH_ELEM_TYPE_MODIFIER: {
@ -263,11 +322,9 @@ void BKE_viewer_path_elem_free(ViewerPathElem *elem)
MEM_SAFE_FREE(typed_elem->modifier_name);
break;
}
case VIEWER_PATH_ELEM_TYPE_NODE: {
auto *typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem);
MEM_SAFE_FREE(typed_elem->node_name);
break;
}
}
if (elem->ui_name) {
MEM_freeN(elem->ui_name);
}
MEM_freeN(elem);
}

View File

@ -599,7 +599,8 @@ template<typename T> class MutableSpan {
constexpr T &operator[](const int64_t index) const
{
BLI_assert(index < this->size());
BLI_assert(index >= 0);
BLI_assert(index < size_);
return data_[index];
}

View File

@ -196,8 +196,8 @@ static int path_normalize_impl(char *path, bool check_blend_relative_prefix)
/* NOTE(@ideasman42):
* `memmove(start, eind, strlen(eind) + 1);`
* is the same as
* `strcpy(start, eind);`
* except `strcpy` should not be used because there is overlap,
* `BLI_strncpy(start, eind, ...);`
* except string-copy should not be used because there is overlap,
* so use `memmove` 's slightly more obscure syntax. */
/* Inline replacement:

View File

@ -825,10 +825,10 @@ bool BLI_rcti_clamp(rcti *rect, const rcti *rect_bounds, int r_xy[2])
bool BLI_rctf_compare(const rctf *rect_a, const rctf *rect_b, const float limit)
{
if (fabsf(rect_a->xmin - rect_b->xmin) < limit) {
if (fabsf(rect_a->xmax - rect_b->xmax) < limit) {
if (fabsf(rect_a->ymin - rect_b->ymin) < limit) {
if (fabsf(rect_a->ymax - rect_b->ymax) < limit) {
if (fabsf(rect_a->xmin - rect_b->xmin) <= limit) {
if (fabsf(rect_a->xmax - rect_b->xmax) <= limit) {
if (fabsf(rect_a->ymin - rect_b->ymin) <= limit) {
if (fabsf(rect_a->ymax - rect_b->ymax) <= limit) {
return true;
}
}

View File

@ -133,14 +133,14 @@ size_t BLI_string_flip_side_name(char *name_dst,
BLI_string_debug_size(name_dst, name_dst_maxncpy);
size_t len;
char *prefix = alloca(name_dst_maxncpy); /* The part before the facing */
char *suffix = alloca(name_dst_maxncpy); /* The part after the facing */
char *replace = alloca(name_dst_maxncpy); /* The replacement string */
char *number = alloca(name_dst_maxncpy); /* The number extension string */
char *prefix = alloca(name_dst_maxncpy); /* The part before the facing */
char *suffix = alloca(name_dst_maxncpy); /* The part after the facing */
char *number = alloca(name_dst_maxncpy); /* The number extension string */
const char *replace = NULL;
char *index = NULL;
bool is_set = false;
*prefix = *suffix = *replace = *number = '\0';
*prefix = *suffix = *number = '\0';
/* always copy the name, since this can be called with an uninitialized string */
len = BLI_strncpy_rlen(name_dst, name_src, name_dst_maxncpy);
@ -169,19 +169,19 @@ size_t BLI_string_flip_side_name(char *name_dst,
switch (name_dst[len - 1]) {
case 'l':
prefix[len - 1] = 0;
strcpy(replace, "r");
replace = "r";
break;
case 'r':
prefix[len - 1] = 0;
strcpy(replace, "l");
replace = "l";
break;
case 'L':
prefix[len - 1] = 0;
strcpy(replace, "R");
replace = "R";
break;
case 'R':
prefix[len - 1] = 0;
strcpy(replace, "L");
replace = "L";
break;
default:
is_set = false;
@ -193,22 +193,22 @@ size_t BLI_string_flip_side_name(char *name_dst,
is_set = true;
switch (name_dst[0]) {
case 'l':
strcpy(replace, "r");
replace = "r";
BLI_strncpy(suffix, name_dst + 1, name_dst_maxncpy);
prefix[0] = 0;
break;
case 'r':
strcpy(replace, "l");
replace = "l";
BLI_strncpy(suffix, name_dst + 1, name_dst_maxncpy);
prefix[0] = 0;
break;
case 'L':
strcpy(replace, "R");
replace = "R";
BLI_strncpy(suffix, name_dst + 1, name_dst_maxncpy);
prefix[0] = 0;
break;
case 'R':
strcpy(replace, "L");
replace = "L";
BLI_strncpy(suffix, name_dst + 1, name_dst_maxncpy);
prefix[0] = 0;
break;
@ -222,10 +222,10 @@ size_t BLI_string_flip_side_name(char *name_dst,
if (((index = BLI_strcasestr(prefix, "right")) == prefix) || (index == prefix + len - 5)) {
is_set = true;
if (index[0] == 'r') {
strcpy(replace, "left");
replace = "left";
}
else {
strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
replace = (index[1] == 'I' ? "LEFT" : "Left");
}
*index = 0;
BLI_strncpy(suffix, index + 5, name_dst_maxncpy);
@ -233,10 +233,10 @@ size_t BLI_string_flip_side_name(char *name_dst,
else if (((index = BLI_strcasestr(prefix, "left")) == prefix) || (index == prefix + len - 4)) {
is_set = true;
if (index[0] == 'l') {
strcpy(replace, "right");
replace = "right";
}
else {
strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
replace = (index[1] == 'E' ? "RIGHT" : "Right");
}
*index = 0;
BLI_strncpy(suffix, index + 4, name_dst_maxncpy);
@ -244,7 +244,7 @@ size_t BLI_string_flip_side_name(char *name_dst,
}
return BLI_snprintf_rlen(
name_dst, name_dst_maxncpy, "%s%s%s%s", prefix, replace, suffix, number);
name_dst, name_dst_maxncpy, "%s%s%s%s", prefix, replace ? replace : "", suffix, number);
}
/* Unique name utils. */

View File

@ -36,17 +36,6 @@
/* -------------------------------------------------------------------- */
/* Utility functions */
static int path_ensure_slash(char *path)
{
int len = strlen(path);
if (len == 0 || path[len - 1] != SEP) {
path[len] = SEP;
path[len + 1] = '\0';
return len + 1;
}
return len;
}
static bool path_test_extension(const char *filepath, const char *ext)
{
const size_t a = strlen(filepath);
@ -81,6 +70,25 @@ static const char *path_basename(const char *path)
return filename ? filename + 1 : path;
}
static bool path_join(char *filepath,
size_t filepath_maxncpy,
const char *dirpath,
const char *filename)
{
int dirpath_len = strlen(dirpath);
if (dirpath_len && dirpath[dirpath_len - 1] == SEP) {
dirpath_len--;
}
const int filename_len = strlen(filename);
if (dirpath_len + 1 + filename_len + 1 > filepath_maxncpy) {
return false;
}
memcpy(filepath, dirpath, dirpath_len);
filepath[dirpath_len] = SEP;
memcpy(filepath + dirpath_len + 1, filename, filename_len + 1);
return true;
}
/* -------------------------------------------------------------------- */
/* Write a PNG from RGBA pixels */
@ -392,8 +400,6 @@ static bool icondir_to_png(const char *path_src, const char *file_dst)
DIR *dir;
const struct dirent *fname;
char filepath[1024];
char *filename;
int path_str_len;
int found = 0, fail = 0;
struct IconMergeContext context;
@ -411,15 +417,12 @@ static bool icondir_to_png(const char *path_src, const char *file_dst)
return false;
}
strcpy(filepath, path_src);
path_str_len = path_ensure_slash(filepath);
filename = &filepath[path_str_len];
while ((fname = readdir(dir)) != NULL) {
if (path_test_extension(fname->d_name, ".dat")) {
strcpy(filename, fname->d_name);
if (!path_join(filepath, sizeof(filepath), path_src, fname->d_name)) {
printf("%s: path is too long (%s, %s)\n", __func__, path_src, fname->d_name);
return false;
}
if (icon_merge(&context, filepath, &pixels_canvas, &canvas_w, &canvas_h)) {
found++;
}

View File

@ -41,11 +41,6 @@ struct SnapObjectHitDepth {
float depth;
float co[3];
float no[3];
int index;
struct Object *ob_eval;
float obmat[4][4];
/* needed to tell which ray-cast this was part of,
* the same object may be part of many ray-casts when dupli's are used. */
@ -58,12 +53,12 @@ struct SnapObjectParams {
eSnapTargetOP snap_target_select;
/* Geometry for snapping in edit mode. */
eSnapEditType edit_mode_type;
/* Break nearest face snapping into steps to improve transformations across U-shaped targets. */
short face_nearest_steps;
/* snap to the closest element, use when using more than one snap type */
bool use_occlusion_test : 1;
/* exclude back facing geometry from snapping */
bool use_backface_culling : 1;
/* Break nearest face snapping into steps to improve transformations across U-shaped targets. */
short face_nearest_steps;
/* Enable to force nearest face snapping to snap to target the source was initially near. */
bool keep_on_same_target : 1;
};

View File

@ -37,7 +37,8 @@ Object *parse_object_only(const ViewerPath &viewer_path);
struct ViewerPathForGeometryNodesViewer {
Object *object;
blender::StringRefNull modifier_name;
blender::Vector<int32_t> group_node_ids;
/* Contains only group node and simulation zone elements. */
blender::Vector<const ViewerPathElem *> node_path;
int32_t viewer_node_id;
};
@ -65,7 +66,6 @@ bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed
* Checks if the node referenced by the viewer and its entire context is still active, i.e. some
* editor is showing it.
*/
bool is_active_geometry_nodes_viewer(const bContext &C,
const ViewerPathForGeometryNodesViewer &parsed_viewer_path);
bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer_path);
} // namespace blender::ed::viewer_path

View File

@ -20,11 +20,7 @@ static void validate_viewer_paths(bContext &C, WorkSpace &workspace)
return;
}
const std::optional<blender::ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path =
blender::ed::viewer_path::parse_geometry_nodes_viewer(workspace.viewer_path);
if (parsed_path.has_value() &&
blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, *parsed_path))
{
if (blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, workspace.viewer_path)) {
/* The current viewer path is still valid and active. */
return;
}

View File

@ -94,8 +94,8 @@
#include <fmt/format.h>
namespace geo_log = blender::nodes::geo_eval_log;
using blender::bke::node_tree_zones::TreeZone;
using blender::bke::node_tree_zones::TreeZones;
using blender::bke::bNodeTreeZone;
using blender::bke::bNodeTreeZones;
/**
* This is passed to many functions which draw the node editor.
@ -113,7 +113,7 @@ struct TreeDrawContext {
* Geometry nodes logs various data during execution. The logged data that corresponds to the
* currently drawn node tree can be retrieved from the log below.
*/
geo_log::GeoTreeLog *geo_tree_log = nullptr;
blender::Map<const bNodeTreeZone *, geo_log::GeoTreeLog *> geo_log_by_zone;
/**
* True if there is an active realtime compositor using the node tree, false otherwise.
*/
@ -1068,8 +1068,8 @@ static void create_inspection_string_for_geometry_socket(std::stringstream &ss,
}
}
static std::optional<std::string> create_socket_inspection_string(TreeDrawContext &tree_draw_ctx,
const bNodeSocket &socket)
static std::optional<std::string> create_socket_inspection_string(
geo_log::GeoTreeLog &geo_tree_log, const bNodeSocket &socket)
{
using namespace blender::nodes::geo_eval_log;
@ -1077,8 +1077,8 @@ static std::optional<std::string> create_socket_inspection_string(TreeDrawContex
return std::nullopt;
}
tree_draw_ctx.geo_tree_log->ensure_socket_values();
ValueLog *value_log = tree_draw_ctx.geo_tree_log->find_socket_value_log(socket);
geo_tree_log.ensure_socket_values();
ValueLog *value_log = geo_tree_log.find_socket_value_log(socket);
std::stringstream ss;
if (const geo_log::GenericValueLog *generic_value_log =
dynamic_cast<const geo_log::GenericValueLog *>(value_log))
@ -1131,7 +1131,8 @@ static char *node_socket_get_tooltip(const SpaceNode *snode,
TreeDrawContext tree_draw_ctx;
if (snode != nullptr) {
if (ntree.type == NTREE_GEOMETRY) {
tree_draw_ctx.geo_tree_log = geo_log::GeoModifierLog::get_tree_log_for_node_editor(*snode);
tree_draw_ctx.geo_log_by_zone =
geo_log::GeoModifierLog::get_tree_log_by_zone_for_node_editor(*snode);
}
}
@ -1144,13 +1145,22 @@ static char *node_socket_get_tooltip(const SpaceNode *snode,
}
}
if (ntree.type == NTREE_GEOMETRY && tree_draw_ctx.geo_tree_log != nullptr) {
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
const bNodeTreeZones *zones = ntree.zones();
if (!zones) {
return nullptr;
}
const bNodeTreeZone *zone = zones->get_zone_by_socket(socket);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}();
if (ntree.type == NTREE_GEOMETRY && geo_tree_log != nullptr) {
if (!output.str().empty()) {
output << ".\n\n";
}
std::optional<std::string> socket_inspection_str = create_socket_inspection_string(
tree_draw_ctx, socket);
*geo_tree_log, socket);
if (socket_inspection_str.has_value()) {
output << *socket_inspection_str;
}
@ -1738,9 +1748,18 @@ static void node_add_error_message_button(const TreeDrawContext &tree_draw_ctx,
return;
}
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
const bNodeTreeZones *zones = node.owner_tree().zones();
if (!zones) {
return nullptr;
}
const bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}();
Span<geo_log::NodeWarning> warnings;
if (tree_draw_ctx.geo_tree_log) {
geo_log::GeoNodeLog *node_log = tree_draw_ctx.geo_tree_log->nodes.lookup_ptr(node.identifier);
if (geo_tree_log) {
geo_log::GeoNodeLog *node_log = geo_tree_log->nodes.lookup_ptr(node.identifier);
if (node_log != nullptr) {
warnings = node_log->warnings;
}
@ -1778,7 +1797,15 @@ static void node_add_error_message_button(const TreeDrawContext &tree_draw_ctx,
static std::optional<std::chrono::nanoseconds> node_get_execution_time(
const TreeDrawContext &tree_draw_ctx, const bNodeTree &ntree, const bNode &node)
{
const geo_log::GeoTreeLog *tree_log = tree_draw_ctx.geo_tree_log;
geo_log::GeoTreeLog *tree_log = [&]() -> geo_log::GeoTreeLog * {
const bNodeTreeZones *zones = ntree.zones();
if (!zones) {
return nullptr;
}
const bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}();
if (tree_log == nullptr) {
return std::nullopt;
}
@ -1936,7 +1963,15 @@ static NodeExtraInfoRow row_from_used_named_attribute(
static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(
TreeDrawContext &tree_draw_ctx, const bNode &node)
{
if (tree_draw_ctx.geo_tree_log == nullptr) {
geo_log::GeoTreeLog *geo_tree_log = [&]() -> geo_log::GeoTreeLog * {
const bNodeTreeZones *zones = node.owner_tree().zones();
if (!zones) {
return nullptr;
}
const bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}();
if (geo_tree_log == nullptr) {
return std::nullopt;
}
if (ELEM(node.type,
@ -1953,8 +1988,8 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(
}
}
}
tree_draw_ctx.geo_tree_log->ensure_used_named_attributes();
geo_log::GeoNodeLog *node_log = tree_draw_ctx.geo_tree_log->nodes.lookup_ptr(node.identifier);
geo_tree_log->ensure_used_named_attributes();
geo_log::GeoNodeLog *node_log = geo_tree_log->nodes.lookup_ptr(node.identifier);
if (node_log == nullptr) {
return std::nullopt;
}
@ -1998,7 +2033,16 @@ static Vector<NodeExtraInfoRow> node_get_extra_info(TreeDrawContext &tree_draw_c
}
if (snode.edittree->type == NTREE_GEOMETRY) {
if (geo_log::GeoTreeLog *tree_log = tree_draw_ctx.geo_tree_log) {
geo_log::GeoTreeLog *tree_log = [&]() -> geo_log::GeoTreeLog * {
const bNodeTreeZones *tree_zones = node.owner_tree().zones();
if (!tree_zones) {
return nullptr;
}
const bNodeTreeZone *zone = tree_zones->get_zone_by_node(node.identifier);
return tree_draw_ctx.geo_log_by_zone.lookup_default(zone, nullptr);
}();
if (tree_log) {
tree_log->ensure_debug_messages();
const geo_log::GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node.identifier);
if (node_log != nullptr) {
@ -3053,8 +3097,8 @@ static void add_rect_corner_positions(Vector<float2> &positions, const rctf &rec
}
static void find_bounds_by_zone_recursive(const SpaceNode &snode,
const TreeZone &zone,
const Span<std::unique_ptr<TreeZone>> all_zones,
const bNodeTreeZone &zone,
const Span<std::unique_ptr<bNodeTreeZone>> all_zones,
MutableSpan<Vector<float2>> r_bounds_by_zone)
{
const float node_padding = UI_UNIT_X;
@ -3066,7 +3110,7 @@ static void find_bounds_by_zone_recursive(const SpaceNode &snode,
}
Vector<float2> possible_bounds;
for (const TreeZone *child_zone : zone.child_zones) {
for (const bNodeTreeZone *child_zone : zone.child_zones) {
find_bounds_by_zone_recursive(snode, *child_zone, all_zones, r_bounds_by_zone);
const Span<float2> child_bounds = r_bounds_by_zone[child_zone->index];
for (const float2 &pos : child_bounds) {
@ -3126,7 +3170,7 @@ static void node_draw_zones(TreeDrawContext & /*tree_draw_ctx*/,
const SpaceNode &snode,
const bNodeTree &ntree)
{
const TreeZones *zones = bke::node_tree_zones::get_tree_zones(ntree);
const bNodeTreeZones *zones = ntree.zones();
if (zones == nullptr) {
return;
}
@ -3135,7 +3179,7 @@ static void node_draw_zones(TreeDrawContext & /*tree_draw_ctx*/,
Array<bke::CurvesGeometry> fillet_curve_by_zone(zones->zones.size());
for (const int zone_i : zones->zones.index_range()) {
const TreeZone &zone = *zones->zones[zone_i];
const bNodeTreeZone &zone = *zones->zones[zone_i];
find_bounds_by_zone_recursive(snode, zone, zones->zones, bounds_by_zone);
const Span<float2> boundary_positions = bounds_by_zone[zone_i];
@ -3368,10 +3412,11 @@ static void draw_nodetree(const bContext &C,
TreeDrawContext tree_draw_ctx;
if (ntree.type == NTREE_GEOMETRY) {
tree_draw_ctx.geo_tree_log = geo_log::GeoModifierLog::get_tree_log_for_node_editor(*snode);
if (tree_draw_ctx.geo_tree_log != nullptr) {
tree_draw_ctx.geo_tree_log->ensure_node_warnings();
tree_draw_ctx.geo_tree_log->ensure_node_run_time();
tree_draw_ctx.geo_log_by_zone = geo_log::GeoModifierLog::get_tree_log_by_zone_for_node_editor(
*snode);
for (geo_log::GeoTreeLog *log : tree_draw_ctx.geo_log_by_zone.values()) {
log->ensure_node_warnings();
log->ensure_node_run_time();
}
const WorkSpace *workspace = CTX_wm_workspace(&C);
tree_draw_ctx.active_geometry_nodes_viewer = viewer_path::find_geometry_nodes_viewer(

View File

@ -18,6 +18,7 @@
#include "BKE_context.h"
#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_node_tree_zones.hh"
#include "BKE_object.h"
#include "RNA_access.h"
@ -69,23 +70,33 @@ static Vector<const GeometryAttributeInfo *> get_attribute_info_from_context(
BLI_assert_unreachable();
return {};
}
GeoTreeLog *tree_log = GeoModifierLog::get_tree_log_for_node_editor(*snode);
if (tree_log == nullptr) {
const bke::bNodeTreeZones *tree_zones = node_tree->zones();
if (!tree_zones) {
return {};
}
tree_log->ensure_socket_values();
const Map<const bke::bNodeTreeZone *, GeoTreeLog *> log_by_zone =
GeoModifierLog::get_tree_log_by_zone_for_node_editor(*snode);
/* For the attribute input node, collect attribute information from all nodes in the group. */
if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE) {
tree_log->ensure_existing_attributes();
Vector<const GeometryAttributeInfo *> attributes;
for (const GeometryAttributeInfo *attribute : tree_log->existing_attributes) {
if (bke::allow_procedural_attribute_access(attribute->name)) {
attributes.append(attribute);
for (GeoTreeLog *tree_log : log_by_zone.values()) {
tree_log->ensure_socket_values();
tree_log->ensure_existing_attributes();
for (const GeometryAttributeInfo *attribute : tree_log->existing_attributes) {
if (bke::allow_procedural_attribute_access(attribute->name)) {
attributes.append(attribute);
}
}
}
return attributes;
}
const bke::bNodeTreeZone *zone = tree_zones->get_zone_by_node(node->identifier);
GeoTreeLog *tree_log = log_by_zone.lookup_default(zone, nullptr);
if (!tree_log) {
return {};
}
tree_log->ensure_socket_values();
GeoNodeLog *node_log = tree_log->nodes.lookup_ptr(node->identifier);
if (node_log == nullptr) {
return {};

View File

@ -57,6 +57,7 @@ set(SRC
tree/tree_element_driver.cc
tree/tree_element_gpencil_layer.cc
tree/tree_element_id.cc
tree/tree_element_id_armature.cc
tree/tree_element_id_collection.cc
tree/tree_element_id_curve.cc
tree/tree_element_id_gpencil_legacy.cc
@ -84,6 +85,7 @@ set(SRC
tree/tree_element_driver.hh
tree/tree_element_gpencil_layer.hh
tree/tree_element_id.hh
tree/tree_element_id_armature.hh
tree/tree_element_id_collection.hh
tree/tree_element_id_curve.hh
tree/tree_element_id_gpencil_legacy.hh

View File

@ -218,25 +218,6 @@ bool outliner_requires_rebuild_on_select_or_active_change(const SpaceOutliner *s
return exclude_flags & (SO_FILTER_OB_STATE_SELECTED | SO_FILTER_OB_STATE_ACTIVE);
}
/* special handling of hierarchical non-lib data */
static void outliner_add_bone(SpaceOutliner *space_outliner,
ListBase *lb,
ID *id,
Bone *curBone,
TreeElement *parent,
int *a)
{
TreeElement *te = outliner_add_element(space_outliner, lb, id, parent, TSE_BONE, *a);
(*a)++;
te->name = curBone->name;
te->directdata = curBone;
LISTBASE_FOREACH (Bone *, child_bone, &curBone->childbase) {
outliner_add_bone(space_outliner, &te->subtree, id, child_bone, te, a);
}
}
#ifdef WITH_FREESTYLE
static void outliner_add_line_styles(SpaceOutliner *space_outliner,
ListBase *lb,
@ -558,6 +539,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
case ID_LS:
case ID_GD_LEGACY:
case ID_GR:
case ID_AR:
BLI_assert_msg(0, "ID type expected to be expanded through new tree-element design");
break;
case ID_OB: {
@ -626,55 +608,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
/* bAction *act = (bAction *)id; */
break;
}
case ID_AR: {
bArmature *arm = (bArmature *)id;
if (outliner_animdata_test(arm->adt)) {
outliner_add_element(space_outliner, &te->subtree, arm, te, TSE_ANIM_DATA, 0);
}
if (arm->edbo) {
int a = 0;
LISTBASE_FOREACH_INDEX (EditBone *, ebone, arm->edbo, a) {
TreeElement *ten = outliner_add_element(
space_outliner, &te->subtree, id, te, TSE_EBONE, a);
ten->directdata = ebone;
ten->name = ebone->name;
ebone->temp.p = ten;
}
/* make hierarchy */
TreeElement *ten = arm->edbo->first ?
static_cast<TreeElement *>(((EditBone *)arm->edbo->first)->temp.p) :
nullptr;
while (ten) {
TreeElement *nten = ten->next, *par;
EditBone *ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&te->subtree, ten);
par = static_cast<TreeElement *>(ebone->parent->temp.p);
BLI_addtail(&par->subtree, ten);
ten->parent = par;
}
ten = nten;
}
}
else {
/* do not extend Armature when we have posemode */
tselem = TREESTORE(te->parent);
if (TSE_IS_REAL_ID(tselem) && GS(tselem->id->name) == ID_OB &&
((Object *)tselem->id)->mode & OB_MODE_POSE)
{
/* pass */
}
else {
int a = 0;
LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
outliner_add_bone(space_outliner, &te->subtree, id, bone, te, &a);
}
}
}
break;
}
case ID_CV: {
Curves *curves = (Curves *)id;
if (outliner_animdata_test(curves->adt)) {

View File

@ -20,6 +20,7 @@
#include "../outliner_intern.hh"
#include "common.hh"
#include "tree_element_id_armature.hh"
#include "tree_element_id_collection.hh"
#include "tree_element_id_curve.hh"
#include "tree_element_id_gpencil_legacy.hh"
@ -60,6 +61,8 @@ std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_t
return std::make_unique<TreeElementIDGPLegacy>(legacy_te, (bGPdata &)id);
case ID_GR:
return std::make_unique<TreeElementIDCollection>(legacy_te, (Collection &)id);
case ID_AR:
return std::make_unique<TreeElementIDArmature>(legacy_te, (bArmature &)id);
case ID_OB:
case ID_MA:
case ID_LT:
@ -85,7 +88,6 @@ std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_t
case ID_VF:
case ID_TXT:
case ID_SO:
case ID_AR:
case ID_AC:
case ID_PAL:
case ID_PC:

View File

@ -0,0 +1,110 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spoutliner
*/
#include "DNA_ID.h"
#include "DNA_armature_types.h"
#include "DNA_listBase.h"
#include "DNA_object_types.h"
#include "DNA_outliner_types.h"
#include "BLI_listbase.h"
#include "BKE_armature.h"
#include "../outliner_intern.hh"
#include "tree_element_id_armature.hh"
namespace blender::ed::outliner {
TreeElementIDArmature::TreeElementIDArmature(TreeElement &legacy_te, bArmature &arm)
: TreeElementID(legacy_te, arm.id), arm_(arm)
{
}
void TreeElementIDArmature::expand(SpaceOutliner &space_outliner) const
{
expand_animation_data(space_outliner, arm_.adt);
if (arm_.edbo) {
expandEditBones(space_outliner);
}
else {
/* do not extend Armature when we have posemode */
TreeStoreElem *tselem = TREESTORE(legacy_te_.parent);
if (TSE_IS_REAL_ID(tselem) && GS(tselem->id->name) == ID_OB &&
((Object *)tselem->id)->mode & OB_MODE_POSE)
{
/* pass */
}
else {
expandBones(space_outliner);
}
}
}
bool TreeElementIDArmature::isExpandValid() const
{
return true;
}
void TreeElementIDArmature::expandEditBones(SpaceOutliner &space_outiner) const
{
int a = 0;
LISTBASE_FOREACH_INDEX (EditBone *, ebone, arm_.edbo, a) {
TreeElement *ten = outliner_add_element(
&space_outiner, &legacy_te_.subtree, &arm_.id, &legacy_te_, TSE_EBONE, a);
ten->directdata = ebone;
ten->name = ebone->name;
ebone->temp.p = ten;
}
/* make hierarchy */
TreeElement *ten = arm_.edbo->first ?
static_cast<TreeElement *>(((EditBone *)arm_.edbo->first)->temp.p) :
nullptr;
while (ten) {
TreeElement *nten = ten->next, *par;
EditBone *ebone = (EditBone *)ten->directdata;
if (ebone->parent) {
BLI_remlink(&legacy_te_.subtree, ten);
par = static_cast<TreeElement *>(ebone->parent->temp.p);
BLI_addtail(&par->subtree, ten);
ten->parent = par;
}
ten = nten;
}
}
/* special handling of hierarchical non-lib data */
static void outliner_add_bone(SpaceOutliner *space_outliner,
ListBase *lb,
ID *id,
Bone *curBone,
TreeElement *parent,
int *a)
{
TreeElement *te = outliner_add_element(space_outliner, lb, id, parent, TSE_BONE, *a);
(*a)++;
te->name = curBone->name;
te->directdata = curBone;
LISTBASE_FOREACH (Bone *, child_bone, &curBone->childbase) {
outliner_add_bone(space_outliner, &te->subtree, id, child_bone, te, a);
}
}
void TreeElementIDArmature::expandBones(SpaceOutliner &space_outliner) const
{
int a = 0;
LISTBASE_FOREACH (Bone *, bone, &arm_.bonebase) {
outliner_add_bone(&space_outliner, &legacy_te_.subtree, &arm_.id, bone, &legacy_te_, &a);
}
}
} // namespace blender::ed::outliner

View File

@ -0,0 +1,33 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spoutliner
*/
#pragma once
#include "tree_element_id.hh"
struct Bone;
struct EditBone;
struct bArmature;
namespace blender::ed::outliner {
class TreeElementIDArmature final : public TreeElementID {
bArmature &arm_;
public:
TreeElementIDArmature(TreeElement &legacy_te, bArmature &arm);
void expand(SpaceOutliner &) const override;
bool isExpandValid() const override;
private:
void expandEditBones(SpaceOutliner &) const;
void expandBones(SpaceOutliner &) const;
};
} // namespace blender::ed::outliner

View File

@ -215,23 +215,12 @@ static eSnapMode iter_snap_objects(SnapObjectContext *sctx, IterSnapObjsCallback
/* Store all ray-hits
* Support for storing all depths, not just the first (ray-cast 'all'). */
static SnapObjectHitDepth *hit_depth_create(const float depth,
const float co[3],
const float no[3],
int index,
Object *ob_eval,
const float obmat[4][4],
uint ob_uuid)
static SnapObjectHitDepth *hit_depth_create(const float depth, const float co[3], uint ob_uuid)
{
SnapObjectHitDepth *hit = MEM_new<SnapObjectHitDepth>(__func__);
hit->depth = depth;
copy_v3_v3(hit->co, co);
copy_v3_v3(hit->no, no);
hit->index = index;
hit->ob_eval = ob_eval;
copy_m4_m4(hit->obmat, (float(*)[4])obmat);
hit->ob_uuid = ob_uuid;
return hit;
@ -259,20 +248,14 @@ void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRay
data->raycast_callback(data->bvhdata, index, ray, hit);
if (hit->index != -1) {
/* Get all values in world-space. */
float location[3], normal[3];
float location[3];
float depth;
/* World-space location. */
mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co);
depth = (hit->dist + data->len_diff) / data->local_scale;
/* World-space normal. */
copy_v3_v3(normal, hit->no);
mul_m3_v3((float(*)[3])data->timat, normal);
normalize_v3(normal);
SnapObjectHitDepth *hit_item = hit_depth_create(
depth, location, normal, hit->index, data->ob_eval, data->obmat, data->ob_uuid);
SnapObjectHitDepth *hit_item = hit_depth_create(depth, location, data->ob_uuid);
BLI_addtail(data->hit_list, hit_item);
}
}
@ -1732,7 +1715,7 @@ eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
mval,
init_co,
prev_co,
square_f(*dist_px),
dist_px ? square_f(*dist_px) : FLT_MAX,
nullptr,
use_occlusion_test))
{

View File

@ -10,44 +10,7 @@
#define MAX_CLIPPLANE_LEN 3
/* -------------------------------------------------------------------- */
/** \name Internal Data Types
* \{ */
/** #SnapObjectContext.editmesh_caches */
struct SnapData_EditMesh {
/* Verts, Edges. */
BVHTree *bvhtree[2];
bool cached[2];
/* BVH tree from #BMEditMesh.looptris. */
BVHTreeFromEditMesh treedata_editmesh;
blender::bke::MeshRuntime *mesh_runtime;
float min[3], max[3];
void clear()
{
for (int i = 0; i < ARRAY_SIZE(this->bvhtree); i++) {
if (!this->cached[i]) {
BLI_bvhtree_free(this->bvhtree[i]);
}
this->bvhtree[i] = nullptr;
}
free_bvhtree_from_editmesh(&this->treedata_editmesh);
}
~SnapData_EditMesh()
{
this->clear();
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("SnapData_EditMesh")
#endif
};
/** \} */
struct SnapData_EditMesh;
struct SnapObjectContext {
struct Scene *scene;
@ -123,17 +86,14 @@ struct RayCastAll_Data {
BVHTree_RayCastCallback raycast_callback;
const float (*obmat)[4];
const float (*timat)[3];
float len_diff;
float local_scale;
Object *ob_eval;
uint ob_uuid;
/* output data */
ListBase *hit_list;
bool retval;
};
struct Nearest2dUserData;
@ -222,6 +182,29 @@ bool nearest_world_tree(SnapObjectContext *sctx,
/* transform_snap_object_editmesh.cc */
struct SnapData_EditMesh {
/* Verts, Edges. */
BVHTree *bvhtree[2];
bool cached[2];
/* BVH tree from #BMEditMesh.looptris. */
BVHTreeFromEditMesh treedata_editmesh;
blender::bke::MeshRuntime *mesh_runtime;
float min[3], max[3];
void clear();
~SnapData_EditMesh()
{
this->clear();
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("SnapData_EditMesh")
#endif
};
eSnapMode snap_object_editmesh(SnapObjectContext *sctx,
Object *ob_eval,
ID *id,

View File

@ -25,6 +25,17 @@
/** \name Snap Object Data
* \{ */
void SnapData_EditMesh::clear()
{
for (int i = 0; i < ARRAY_SIZE(this->bvhtree); i++) {
if (!this->cached[i]) {
BLI_bvhtree_free(this->bvhtree[i]);
}
this->bvhtree[i] = nullptr;
}
free_bvhtree_from_editmesh(&this->treedata_editmesh);
}
/**
* Calculate the minimum and maximum coordinates of the box that encompasses this mesh.
*/
@ -257,7 +268,6 @@ static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
static bool raycastEditMesh(SnapData_EditMesh *sod,
SnapObjectContext *sctx,
Object *ob_eval,
BMEditMesh *em,
const float obmat[4][4],
const uint ob_index,
@ -316,23 +326,18 @@ static bool raycastEditMesh(SnapData_EditMesh *sod,
return retval;
}
float timat[3][3]; /* transpose inverse matrix for normals */
transpose_m3_m4(timat, imat);
if (r_hit_list) {
RayCastAll_Data data;
data.bvhdata = treedata;
data.raycast_callback = treedata->raycast_callback;
data.obmat = obmat;
data.timat = timat;
data.len_diff = len_diff;
data.local_scale = local_scale;
data.ob_eval = ob_eval;
data.ob_uuid = ob_index;
data.hit_list = r_hit_list;
data.retval = retval;
void *hit_last_prev = data.hit_list->last;
BLI_bvhtree_ray_cast_all(treedata->tree,
ray_start_local,
ray_normal_local,
@ -341,7 +346,7 @@ static bool raycastEditMesh(SnapData_EditMesh *sod,
raycast_all_cb,
&data);
retval = data.retval;
retval = hit_last_prev != data.hit_list->last;
}
else {
BVHTreeRayHit hit{};
@ -369,7 +374,7 @@ static bool raycastEditMesh(SnapData_EditMesh *sod,
if (r_no) {
copy_v3_v3(r_no, hit.no);
mul_m3_v3(timat, r_no);
mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}
@ -759,7 +764,6 @@ eSnapMode snap_object_editmesh(SnapObjectContext *sctx,
if (snap_mode_used & SCE_SNAP_MODE_FACE) {
if (raycastEditMesh(sod,
sctx,
ob_eval,
em,
obmat,
sctx->runtime.object_index++,

View File

@ -156,9 +156,6 @@ static bool raycastMesh(SnapObjectContext *sctx,
return retval;
}
float timat[3][3]; /* transpose inverse matrix for normals */
transpose_m3_m4(timat, imat);
BLI_assert(treedata.raycast_callback != nullptr);
if (r_hit_list) {
RayCastAll_Data data;
@ -166,18 +163,16 @@ static bool raycastMesh(SnapObjectContext *sctx,
data.bvhdata = &treedata;
data.raycast_callback = treedata.raycast_callback;
data.obmat = obmat;
data.timat = timat;
data.len_diff = len_diff;
data.local_scale = local_scale;
data.ob_eval = ob_eval;
data.ob_uuid = ob_index;
data.hit_list = r_hit_list;
data.retval = retval;
void *hit_last_prev = data.hit_list->last;
BLI_bvhtree_ray_cast_all(
treedata.tree, ray_start_local, ray_normal_local, 0.0f, *ray_depth, raycast_all_cb, &data);
retval = data.retval;
retval = hit_last_prev != data.hit_list->last;
}
else {
BVHTreeRayHit hit{};
@ -205,7 +200,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
if (r_no) {
copy_v3_v3(r_no, hit.no);
mul_m3_v3(timat, r_no);
mul_transposed_mat3_m4_v3(imat, r_no);
normalize_v3(r_no);
}

View File

@ -8,6 +8,7 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_node_runtime.hh"
#include "BKE_node_tree_zones.hh"
#include "BKE_workspace.h"
#include "BLI_listbase.h"
@ -22,6 +23,9 @@
namespace blender::ed::viewer_path {
using bke::bNodeTreeZone;
using bke::bNodeTreeZones;
static void viewer_path_for_geometry_node(const SpaceNode &snode,
const bNode &node,
ViewerPath &r_dst)
@ -55,27 +59,57 @@ static void viewer_path_for_geometry_node(const SpaceNode &snode,
modifier = nmd;
}
}
if (modifier != nullptr) {
ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier();
modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name);
BLI_addtail(&r_dst.path, modifier_elem);
if (modifier == nullptr) {
return;
}
ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier();
modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name);
BLI_addtail(&r_dst.path, modifier_elem);
Vector<const bNodeTreePath *, 16> tree_path = snode.treepath;
for (const int i : tree_path.index_range().drop_back(1)) {
bNodeTree *tree = tree_path[i]->nodetree;
/* The tree path contains the name of the node but not its ID. */
const bNode *node = nodeFindNodebyName(tree_path[i]->nodetree, tree_path[i + 1]->node_name);
const char *node_name = tree_path[i + 1]->node_name;
const bNode *node = nodeFindNodebyName(tree, node_name);
/* The name in the tree path should match a group node in the tree. */
BLI_assert(node != nullptr);
NodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_node();
tree->ensure_topology_cache();
const bNodeTreeZones *tree_zones = tree->zones();
if (!tree_zones) {
return;
}
const Vector<const bNodeTreeZone *> zone_stack = tree_zones->get_zone_stack_for_node(
node->identifier);
for (const bNodeTreeZone *zone : zone_stack) {
SimulationZoneViewerPathElem *node_elem = BKE_viewer_path_elem_new_simulation_zone();
node_elem->sim_output_node_id = zone->output_node->identifier;
BLI_addtail(&r_dst.path, node_elem);
}
GroupNodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_group_node();
node_elem->node_id = node->identifier;
node_elem->node_name = BLI_strdup(node->name);
node_elem->base.ui_name = BLI_strdup(node->name);
BLI_addtail(&r_dst.path, node_elem);
}
NodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_node();
snode.edittree->ensure_topology_cache();
const bNodeTreeZones *tree_zones = snode.edittree->zones();
if (!tree_zones) {
return;
}
const Vector<const bNodeTreeZone *> zone_stack = tree_zones->get_zone_stack_for_node(
node.identifier);
for (const bNodeTreeZone *zone : zone_stack) {
SimulationZoneViewerPathElem *node_elem = BKE_viewer_path_elem_new_simulation_zone();
node_elem->sim_output_node_id = zone->output_node->identifier;
BLI_addtail(&r_dst.path, node_elem);
}
ViewerNodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_viewer_node();
viewer_node_elem->node_id = node.identifier;
viewer_node_elem->node_name = BLI_strdup(node.name);
viewer_node_elem->base.ui_name = BLI_strdup(node.name);
BLI_addtail(&r_dst.path, viewer_node_elem);
}
@ -185,16 +219,21 @@ std::optional<ViewerPathForGeometryNodesViewer> parse_geometry_nodes_viewer(
return std::nullopt;
}
remaining_elems = remaining_elems.drop_front(1);
Vector<int32_t> node_ids;
for (const ViewerPathElem *elem : remaining_elems) {
if (elem->type != VIEWER_PATH_ELEM_TYPE_NODE) {
Vector<const ViewerPathElem *> node_path;
for (const ViewerPathElem *elem : remaining_elems.drop_back(1)) {
if (!ELEM(elem->type, VIEWER_PATH_ELEM_TYPE_GROUP_NODE, VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE))
{
return std::nullopt;
}
const int32_t node_id = reinterpret_cast<const NodeViewerPathElem *>(elem)->node_id;
node_ids.append(node_id);
node_path.append(elem);
}
const int32_t viewer_node_id = node_ids.pop_last();
return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_ids, viewer_node_id};
const ViewerPathElem *last_elem = remaining_elems.last();
if (last_elem->type != VIEWER_PATH_ELEM_TYPE_VIEWER_NODE) {
return std::nullopt;
}
const int32_t viewer_node_id =
reinterpret_cast<const ViewerNodeViewerPathElem *>(last_elem)->node_id;
return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_path, viewer_node_id};
}
bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
@ -217,81 +256,73 @@ bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed
return false;
}
const bNodeTree *ngroup = modifier->node_group;
ngroup->ensure_topology_cache();
for (const int32_t group_node_id : parsed_viewer_path.group_node_ids) {
const bNode *group_node = nullptr;
for (const bNode *node : ngroup->group_nodes()) {
if (node->identifier != group_node_id) {
continue;
const bNodeTreeZone *zone = nullptr;
for (const ViewerPathElem *path_elem : parsed_viewer_path.node_path) {
ngroup->ensure_topology_cache();
const bNodeTreeZones *tree_zones = ngroup->zones();
switch (path_elem->type) {
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto &typed_elem = *reinterpret_cast<const SimulationZoneViewerPathElem *>(
path_elem);
const bNodeTreeZone *next_zone = tree_zones->get_zone_by_node(
typed_elem.sim_output_node_id);
if (next_zone == nullptr) {
return false;
}
if (next_zone->parent_zone != zone) {
return false;
}
zone = next_zone;
break;
}
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto &typed_elem = *reinterpret_cast<const GroupNodeViewerPathElem *>(path_elem);
const bNode *group_node = ngroup->node_by_id(typed_elem.node_id);
if (group_node == nullptr) {
return false;
}
const bNodeTreeZone *parent_zone = tree_zones->get_zone_by_node(typed_elem.node_id);
if (parent_zone != zone) {
return false;
}
if (group_node->id == nullptr) {
return false;
}
ngroup = reinterpret_cast<const bNodeTree *>(group_node->id);
zone = nullptr;
break;
}
default: {
BLI_assert_unreachable();
}
group_node = node;
break;
}
if (group_node == nullptr) {
return false;
}
if (group_node->id == nullptr) {
return false;
}
ngroup = reinterpret_cast<const bNodeTree *>(group_node->id);
}
const bNode *viewer_node = nullptr;
for (const bNode *node : ngroup->nodes_by_type("GeometryNodeViewer")) {
if (node->identifier != parsed_viewer_path.viewer_node_id) {
continue;
}
viewer_node = node;
break;
}
const bNode *viewer_node = ngroup->node_by_id(parsed_viewer_path.viewer_node_id);
if (viewer_node == nullptr) {
return false;
}
return true;
}
static bool viewer_path_matches_node_editor_path(
const SpaceNode &snode, const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
{
Vector<const bNodeTreePath *, 16> tree_path = snode.treepath;
if (tree_path.size() != parsed_viewer_path.group_node_ids.size() + 1) {
const bNodeTreeZones *tree_zones = ngroup->zones();
if (tree_zones == nullptr) {
return false;
}
for (const int i : parsed_viewer_path.group_node_ids.index_range()) {
const bNode *node = tree_path[i]->nodetree->node_by_id(parsed_viewer_path.group_node_ids[i]);
if (!node) {
return false;
}
if (!STREQ(node->name, tree_path[i + 1]->node_name)) {
return false;
}
if (tree_zones->get_zone_by_node(viewer_node->identifier) != zone) {
return false;
}
return true;
}
bool is_active_geometry_nodes_viewer(const bContext &C,
const ViewerPathForGeometryNodesViewer &parsed_viewer_path)
bool is_active_geometry_nodes_viewer(const bContext &C, const ViewerPath &viewer_path)
{
const NodesModifierData *modifier = nullptr;
LISTBASE_FOREACH (const ModifierData *, md, &parsed_viewer_path.object->modifiers) {
if (md->name != parsed_viewer_path.modifier_name) {
continue;
}
if (md->type != eModifierType_Nodes) {
return false;
}
if ((md->mode & eModifierMode_Realtime) == 0) {
return false;
}
modifier = reinterpret_cast<const NodesModifierData *>(md);
break;
}
if (modifier == nullptr) {
if (BLI_listbase_is_empty(&viewer_path.path)) {
return false;
}
if (modifier->node_group == nullptr) {
const ViewerPathElem *last_elem = static_cast<ViewerPathElem *>(viewer_path.path.last);
if (last_elem->type != VIEWER_PATH_ELEM_TYPE_VIEWER_NODE) {
return false;
}
const bool modifier_is_active = modifier->modifier.flag & eModifierFlag_Active;
const int32_t viewer_node_id =
reinterpret_cast<const ViewerNodeViewerPathElem *>(last_elem)->node_id;
const Main *bmain = CTX_data_main(&C);
const wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
@ -315,30 +346,26 @@ bool is_active_geometry_nodes_viewer(const bContext &C,
continue;
}
const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl);
if (!modifier_is_active) {
if (!(snode.flag & SNODE_PIN)) {
/* Node tree has to be pinned when the modifier is not active. */
continue;
}
}
if (snode.id != &parsed_viewer_path.object->id) {
if (snode.edittree == nullptr) {
continue;
}
if (snode.nodetree != modifier->node_group) {
if (snode.edittree->type != NTREE_GEOMETRY) {
continue;
}
if (!viewer_path_matches_node_editor_path(snode, parsed_viewer_path)) {
continue;
}
const bNodeTree *ngroup = snode.edittree;
ngroup->ensure_topology_cache();
const bNode *viewer_node = ngroup->node_by_id(parsed_viewer_path.viewer_node_id);
snode.edittree->ensure_topology_cache();
const bNode *viewer_node = snode.edittree->node_by_id(viewer_node_id);
if (viewer_node == nullptr) {
continue;
}
if (!(viewer_node->flag & NODE_DO_OUTPUT)) {
continue;
}
ViewerPath tmp_viewer_path{};
BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&tmp_viewer_path); });
viewer_path_for_geometry_node(snode, *viewer_node, tmp_viewer_path);
if (!BKE_viewer_path_equal(&viewer_path, &tmp_viewer_path)) {
continue;
}
return true;
}
}

View File

@ -1855,7 +1855,7 @@ static float pack_islands_scale_margin(const Span<PackIsland *> islands,
rotate_inside_square(slow_aabbs, islands, params, scale, margin, r_phis, &extent);
}
if (!memcmp(&extent, &fast_extent, sizeof(rctf))) {
if (BLI_rctf_compare(&extent, &fast_extent, 0.0f)) {
/* The fast packer was the best so far. Lets just use the fast packer for everything. */
slow_aabbs = slow_aabbs.take_front(locked_island_count);
extent = locked_bounds;

View File

@ -109,6 +109,11 @@ class MTLUniformBuf;
/* MTLBuffer allocation wrapper. */
class MTLBuffer {
public:
/* NOTE: ListBase API is not used due to cutsom destructor operation required to release
* Metal objective C buffer resource. */
gpu::MTLBuffer *next, *prev;
private:
/* Metal resource. */
id<MTLBuffer> metal_buffer_;
@ -179,6 +184,8 @@ class MTLBuffer {
/* Safety check to ensure buffers are not used after free. */
void debug_ensure_used();
MEM_CXX_CLASS_ALLOC_FUNCS("MTLBuffer");
};
/* View into part of an MTLBuffer. */
@ -335,6 +342,8 @@ class MTLSafeFreeList {
}
}
}
MEM_CXX_CLASS_ALLOC_FUNCS("MTLSafeFreeList");
};
/* MTLBuffer pools. */
@ -364,7 +373,7 @@ class MTLBufferPool {
#endif
/* Metal resources. */
bool ensure_initialised_ = false;
bool initialized_ = false;
id<MTLDevice> device_ = nil;
/* The buffer selection aims to pick a buffer which meets the minimum size requirements.
@ -391,7 +400,10 @@ class MTLBufferPool {
std::mutex buffer_pool_lock_;
blender::Map<MTLBufferResourceOptions, MTLBufferPoolOrderedList *> buffer_pools_;
blender::Vector<gpu::MTLBuffer *> allocations_;
/* Linked list to track all existing allocations. Prioritizing fast insert/deletion. */
gpu::MTLBuffer *allocations_list_base_;
uint allocations_list_size_;
/* Maintain a queue of all MTLSafeFreeList's that have been released
* by the GPU and are ready to have their buffers re-inserted into the
@ -434,6 +446,11 @@ class MTLBufferPool {
void ensure_buffer_pool(MTLResourceOptions options);
void insert_buffer_into_pool(MTLResourceOptions options, gpu::MTLBuffer *buffer);
void free();
/* Allocations list. */
void allocations_list_insert(gpu::MTLBuffer *buffer);
void allocations_list_delete(gpu::MTLBuffer *buffer);
void allocations_list_delete_all();
};
/* Scratch buffers are circular-buffers used for temporary data within the current frame.
@ -494,6 +511,8 @@ class MTLScratchBufferManager {
* This call will perform a partial flush of the buffer starting from
* the last offset the data was flushed from, to the current offset. */
void flush_active_scratch_buffer();
MEM_CXX_CLASS_ALLOC_FUNCS("MTLBufferPool");
};
/** \} */

View File

@ -27,9 +27,9 @@ namespace blender::gpu {
void MTLBufferPool::init(id<MTLDevice> mtl_device)
{
if (!ensure_initialised_) {
if (!initialized_) {
BLI_assert(mtl_device);
ensure_initialised_ = true;
initialized_ = true;
device_ = mtl_device;
#if MTL_DEBUG_MEMORY_STATISTICS == 1
@ -41,6 +41,10 @@ void MTLBufferPool::init(id<MTLDevice> mtl_device)
/* Track pool allocation size. */
allocations_in_pool_ = 0;
/* Live allocations list. */
allocations_list_base_ = nullptr;
allocations_list_size_ = 0;
/* Free pools -- Create initial safe free pool */
BLI_assert(current_free_list_ == nullptr);
this->begin_new_safe_list();
@ -55,17 +59,29 @@ MTLBufferPool::~MTLBufferPool()
void MTLBufferPool::free()
{
buffer_pool_lock_.lock();
for (auto buffer : allocations_) {
BLI_assert(buffer);
delete buffer;
}
allocations_.clear();
/* Delete all existing allocations. */
allocations_list_delete_all();
/* Release safe free lists. */
for (int safe_pool_free_index = 0; safe_pool_free_index < completed_safelist_queue_.size();
safe_pool_free_index++)
{
delete completed_safelist_queue_[safe_pool_free_index];
}
completed_safelist_queue_.clear();
if (current_free_list_ != nullptr) {
delete current_free_list_;
current_free_list_ = nullptr;
}
/* Clear and release memory pools. */
for (std::multiset<blender::gpu::MTLBufferHandle, blender::gpu::CompareMTLBuffer> *buffer_pool :
buffer_pools_.values())
{
delete buffer_pool;
}
buffer_pools_.clear();
buffer_pool_lock_.unlock();
}
@ -156,10 +172,7 @@ gpu::MTLBuffer *MTLBufferPool::allocate_aligned(uint64_t size,
new_buffer = new gpu::MTLBuffer(device_, size, options, alignment);
/* Track allocation in context. */
allocations_.append(new_buffer);
#if MTL_DEBUG_MEMORY_STATISTICS == 1
total_allocation_bytes_ += aligned_alloc_size;
#endif
allocations_list_insert(new_buffer);
}
else {
/* Re-use suitable buffer. */
@ -290,6 +303,7 @@ void MTLBufferPool::update_memory_pools()
* animation.
* If memory is continually used, then we do not want to free this memory as it will be
* re-allocated during a short time period. */
const time_t time_now = std::time(nullptr);
for (auto buffer_pool_list : buffer_pools_.items()) {
MTLBufferPoolOrderedList *pool_allocations = buffer_pool_list.value;
@ -324,12 +338,13 @@ void MTLBufferPool::update_memory_pools()
if (time_passed > deletion_time_threshold_s) {
/* Delete allocation. */
delete handle.buffer;
/* Remove buffer from global allocations list and release resource. */
allocations_list_delete(handle.buffer);
/* Remove buffer from pool and update pool statistics. */
pool_iterator = pool_allocations->erase(pool_iterator);
allocations_in_pool_ -= handle.buffer_size;
#if MTL_DEBUG_MEMORY_STATISTICS == 1
total_allocation_bytes_ -= handle.buffer_size;
buffers_in_pool_--;
#endif
continue;
@ -344,7 +359,7 @@ void MTLBufferPool::update_memory_pools()
uint framealloc = (uint)per_frame_allocation_count_;
printf(" Allocations in frame: %u\n", framealloc);
printf(" Total Buffers allocated: %u\n", (uint)allocations_.size());
printf(" Total Buffers allocated: %u\n", allocations_list_size_);
printf(" Total Memory allocated: %u MB\n", (uint)total_allocation_bytes_ / (1024 * 1024));
uint allocs = (uint)(allocations_in_pool_) / 1024 / 2024;
@ -454,6 +469,80 @@ void MTLBufferPool::insert_buffer_into_pool(MTLResourceOptions options, gpu::MTL
#endif
}
void MTLBufferPool::allocations_list_insert(gpu::MTLBuffer *buffer)
{
/* NOTE: Function should only be called while buffer_pool_lock_ is acquired. */
BLI_assert(initialized_);
BLI_assert(buffer != nullptr);
/* Insert buffer at base of allocations list. */
gpu::MTLBuffer *current_head = allocations_list_base_;
buffer->next = current_head;
buffer->prev = nullptr;
if (current_head != nullptr) {
current_head->prev = buffer;
}
allocations_list_base_ = buffer;
allocations_list_size_++;
#if MTL_DEBUG_MEMORY_STATISTICS == 1
total_allocation_bytes_ += buffer->get_size();
#endif
}
void MTLBufferPool::allocations_list_delete(gpu::MTLBuffer *buffer)
{
/* NOTE: Function should only be called while buffer_pool_lock_ is acquired. */
/* Remove a buffer link in the allocations chain. */
BLI_assert(initialized_);
BLI_assert(buffer != nullptr);
BLI_assert(allocations_list_size_ >= 1);
gpu::MTLBuffer *next = buffer->next;
gpu::MTLBuffer *prev = buffer->prev;
if (prev != nullptr) {
BLI_assert(prev->next == buffer);
prev->next = next;
}
if (next != nullptr) {
BLI_assert(next->prev == buffer);
next->prev = prev;
}
if (allocations_list_base_ == buffer) {
allocations_list_base_ = next;
BLI_assert(prev == nullptr);
}
allocations_list_size_--;
#if MTL_DEBUG_MEMORY_STATISTICS == 1
total_allocation_bytes_ -= buffer->get_size();
#endif
/* Delete buffer. */
delete buffer;
}
void MTLBufferPool::allocations_list_delete_all()
{
gpu::MTLBuffer *current = allocations_list_base_;
while (current != nullptr) {
gpu::MTLBuffer *next = current->next;
delete current;
current = next;
}
allocations_list_size_ = 0;
allocations_list_base_ = nullptr;
#if MTL_DEBUG_MEMORY_STATISTICS == 1
total_allocation_bytes_ = 0;
#endif
}
MTLSafeFreeList::MTLSafeFreeList()
{
reference_count_ = 1;
@ -566,6 +655,9 @@ MTLBuffer::MTLBuffer(id<MTLDevice> mtl_device,
else {
data_ = nullptr;
}
/* Linked resources. */
next = prev = nullptr;
}
MTLBuffer::MTLBuffer(id<MTLBuffer> external_buffer)
@ -585,6 +677,9 @@ MTLBuffer::MTLBuffer(id<MTLBuffer> external_buffer)
this->set_usage_size(size_);
data_ = [metal_buffer_ contents];
in_use_ = true;
/* Linked resources. */
next = prev = nullptr;
}
gpu::MTLBuffer::~MTLBuffer()

View File

@ -31,6 +31,10 @@ class bNodeTreeRuntime;
class bNodeRuntime;
class bNodeSocketRuntime;
} // namespace blender::bke
namespace blender::bke {
class bNodeTreeZones;
class bNodeTreeZone;
} // namespace blender::bke
using NodeDeclarationHandle = blender::nodes::NodeDeclaration;
using SocketDeclarationHandle = blender::nodes::SocketDeclaration;
using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime;
@ -677,6 +681,8 @@ typedef struct bNodeTree {
blender::Span<const bNodePanel *> panels() const;
blender::MutableSpan<bNodePanel *> panels_for_write();
/** Zones in the node tree. Currently there are only simulation zones in geometry nodes. */
const blender::bke::bNodeTreeZones *zones() const;
#endif
} bNodeTree;

View File

@ -12,13 +12,16 @@ struct ID;
typedef enum ViewerPathElemType {
VIEWER_PATH_ELEM_TYPE_ID = 0,
VIEWER_PATH_ELEM_TYPE_MODIFIER = 1,
VIEWER_PATH_ELEM_TYPE_NODE = 2,
VIEWER_PATH_ELEM_TYPE_GROUP_NODE = 2,
VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE = 3,
VIEWER_PATH_ELEM_TYPE_VIEWER_NODE = 4,
} ViewerPathElemType;
typedef struct ViewerPathElem {
struct ViewerPathElem *next, *prev;
int type;
char _pad[4];
char *ui_name;
} ViewerPathElem;
typedef struct IDViewerPathElem {
@ -31,18 +34,26 @@ typedef struct ModifierViewerPathElem {
char *modifier_name;
} ModifierViewerPathElem;
typedef struct NodeViewerPathElem {
typedef struct GroupNodeViewerPathElem {
ViewerPathElem base;
int32_t node_id;
char _pad1[4];
} GroupNodeViewerPathElem;
/**
* The name of the node with the identifier. Not used to lookup nodes, only for display
* in the UI. Still stored here to avoid looking up the name for every redraw.
*/
char *node_name;
} NodeViewerPathElem;
typedef struct SimulationZoneViewerPathElem {
ViewerPathElem base;
int32_t sim_output_node_id;
char _pad1[4];
} SimulationZoneViewerPathElem;
typedef struct ViewerNodeViewerPathElem {
ViewerPathElem base;
int32_t node_id;
char _pad1[4];
} ViewerNodeViewerPathElem;
typedef struct ViewerPath {
/** List of #ViewerPathElem. */

View File

@ -1422,8 +1422,20 @@ static char *rna_def_property_set_func(
}
else {
rna_clamp_value_range(f, prop);
/* C++ may require casting to an enum type. */
fprintf(f, "#ifdef __cplusplus\n");
fprintf(f,
/* If #rna_clamp_value() adds an expression like `CLAMPIS(...)` (instead of an
lvalue), #decltype() yields a reference, so that has to be removed.*/
" data->%s = %s(std::remove_reference_t<decltype(data->%s)>)",
dp->dnaname,
(dp->booleannegative) ? "!" : "",
dp->dnaname);
rna_clamp_value(f, prop, 0);
fprintf(f, "#else\n");
fprintf(f, " data->%s = %s", dp->dnaname, (dp->booleannegative) ? "!" : "");
rna_clamp_value(f, prop, 0);
fprintf(f, "#endif\n");
}
}

View File

@ -526,7 +526,7 @@ static int rna_find_sdna_member(SDNA *sdna,
return 0;
}
static int rna_validate_identifier(const char *identifier, char *error, bool property)
static bool rna_validate_identifier(const char *identifier, bool property, const char **r_error)
{
int a = 0;
@ -548,15 +548,15 @@ static int rna_validate_identifier(const char *identifier, char *error, bool pro
};
if (!isalpha(identifier[0])) {
strcpy(error, "first character failed isalpha() check");
return 0;
*r_error = "first character failed isalpha() check";
return false;
}
for (a = 0; identifier[a]; a++) {
if (DefRNA.preprocess && property) {
if (isalpha(identifier[a]) && isupper(identifier[a])) {
strcpy(error, "property names must contain lower case characters only");
return 0;
*r_error = "property names must contain lower case characters only";
return false;
}
}
@ -565,20 +565,20 @@ static int rna_validate_identifier(const char *identifier, char *error, bool pro
}
if (identifier[a] == ' ') {
strcpy(error, "spaces are not okay in identifier names");
return 0;
*r_error = "spaces are not okay in identifier names";
return false;
}
if (isalnum(identifier[a]) == 0) {
strcpy(error, "one of the characters failed an isalnum() check and is not an underscore");
return 0;
*r_error = "one of the characters failed an isalnum() check and is not an underscore";
return false;
}
}
for (a = 0; kwlist[a]; a++) {
if (STREQ(identifier, kwlist[a])) {
strcpy(error, "this keyword is reserved by Python");
return 0;
*r_error = "this keyword is reserved by Python";
return false;
}
}
@ -594,13 +594,13 @@ static int rna_validate_identifier(const char *identifier, char *error, bool pro
for (a = 0; kwlist_prop[a]; a++) {
if (STREQ(identifier, kwlist_prop[a])) {
strcpy(error, "this keyword is reserved by Python");
return 0;
*r_error = "this keyword is reserved by Python";
return false;
}
}
}
return 1;
return true;
}
void RNA_identifier_sanitize(char *identifier, int property)
@ -907,9 +907,9 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN
PropertyRNA *prop;
if (DefRNA.preprocess) {
char error[512];
const char *error = NULL;
if (rna_validate_identifier(identifier, error, false) == 0) {
if (!rna_validate_identifier(identifier, false, &error)) {
CLOG_ERROR(&LOG, "struct identifier \"%s\" error - %s", identifier, error);
DefRNA.error = true;
}
@ -1269,9 +1269,9 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
PropertyRNA *prop;
if (DefRNA.preprocess) {
char error[512];
const char *error = NULL;
if (rna_validate_identifier(identifier, error, true) == 0) {
if (!rna_validate_identifier(identifier, true, &error)) {
CLOG_ERROR(
&LOG, "property identifier \"%s.%s\" - %s", CONTAINER_RNA_ID(cont), identifier, error);
DefRNA.error = true;
@ -1290,8 +1290,8 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_,
}
else {
#ifndef NDEBUG
char error[512];
if (rna_validate_identifier(identifier, error, true) == 0) {
const char *error = NULL;
if (!rna_validate_identifier(identifier, true, &error)) {
CLOG_ERROR(&LOG,
"runtime property identifier \"%s.%s\" - %s",
CONTAINER_RNA_ID(cont),
@ -3477,8 +3477,8 @@ void RNA_def_property_collection_funcs(PropertyRNA *prop,
void RNA_def_property_srna(PropertyRNA *prop, const char *type)
{
char error[512];
if (rna_validate_identifier(type, error, false) == 0) {
const char *error = NULL;
if (!rna_validate_identifier(type, false, &error)) {
CLOG_ERROR(&LOG, "struct identifier \"%s\" error - %s", type, error);
DefRNA.error = true;
return;
@ -4247,9 +4247,8 @@ static FunctionRNA *rna_def_function(StructRNA *srna, const char *identifier)
FunctionDefRNA *dfunc;
if (DefRNA.preprocess) {
char error[512];
if (rna_validate_identifier(identifier, error, false) == 0) {
const char *error = NULL;
if (!rna_validate_identifier(identifier, false, &error)) {
CLOG_ERROR(&LOG, "function identifier \"%s\" - %s", identifier, error);
DefRNA.error = true;
}

View File

@ -1357,7 +1357,7 @@ static int rna_MaterialSlot_name_length(PointerRNA *ptr)
return 0;
}
static void rna_MaterialSlot_name_get(PointerRNA *ptr, char *str)
static void rna_MaterialSlot_name_get(PointerRNA *ptr, char *value)
{
Object *ob = reinterpret_cast<Object *>(ptr->owner_id);
Material *ma;
@ -1366,10 +1366,10 @@ static void rna_MaterialSlot_name_get(PointerRNA *ptr, char *str)
ma = BKE_object_material_get(ob, index + 1);
if (ma) {
strcpy(str, ma->id.name + 2);
strcpy(value, ma->id.name + 2);
}
else {
str[0] = '\0';
value[0] = '\0';
}
}

View File

@ -30,6 +30,8 @@
#include "rna_internal.h" /* own include */
#define MESH_DM_INFO_STR_MAX 16384
static const EnumPropertyItem space_items[] = {
{CONSTRAINT_SPACE_WORLD, "WORLD", 0, "World Space", "The most global space in Blender"},
{CONSTRAINT_SPACE_POSE,
@ -763,7 +765,7 @@ void rna_Object_me_eval_info(
if (me_eval) {
ret = BKE_mesh_debug_info(me_eval);
if (ret) {
strcpy(result, ret);
BLI_strncpy(result, ret, MESH_DM_INFO_STR_MAX);
MEM_freeN(ret);
}
}
@ -1329,7 +1331,8 @@ void RNA_api_object(StructRNA *srna)
"(only needed if current Context's depsgraph is not suitable)");
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_RNAPTR);
/* weak!, no way to return dynamic string type */
parm = RNA_def_string(func, "result", nullptr, 16384, "", "Requested information");
parm = RNA_def_string(
func, "result", nullptr, MESH_DM_INFO_STR_MAX, "", "Requested information");
RNA_def_parameter_flags(
parm, PROP_THICK_WRAP, ParameterFlag(0)); /* needed for string return value */
RNA_def_function_output(func, parm);

View File

@ -1168,7 +1168,7 @@ static void rna_ParticleSystem_active_particle_target_index_set(struct PointerRN
}
}
static void rna_ParticleTarget_name_get(PointerRNA *ptr, char *str)
static void rna_ParticleTarget_name_get(PointerRNA *ptr, char *value)
{
ParticleTarget *pt = ptr->data;
@ -1185,28 +1185,28 @@ static void rna_ParticleTarget_name_get(PointerRNA *ptr, char *str)
if (psys) {
if (pt->ob) {
BLI_sprintf(str, "%s: %s", pt->ob->id.name + 2, psys->name);
BLI_sprintf(value, "%s: %s", pt->ob->id.name + 2, psys->name);
}
else {
strcpy(str, psys->name);
strcpy(value, psys->name);
}
}
else {
strcpy(str, TIP_("Invalid target!"));
strcpy(value, TIP_("Invalid target!"));
}
}
else {
strcpy(str, TIP_("Invalid target!"));
strcpy(value, TIP_("Invalid target!"));
}
}
static int rna_ParticleTarget_name_length(PointerRNA *ptr)
{
char tstr[MAX_ID_NAME + MAX_ID_NAME + 64];
char tvalue[MAX_ID_NAME + MAX_ID_NAME + 64];
rna_ParticleTarget_name_get(ptr, tstr);
rna_ParticleTarget_name_get(ptr, tvalue);
return strlen(tstr);
return strlen(tvalue);
}
static int particle_id_check(const PointerRNA *ptr)
@ -1304,7 +1304,7 @@ static void rna_ParticleDupliWeight_active_index_set(struct PointerRNA *ptr, int
}
}
static void rna_ParticleDupliWeight_name_get(PointerRNA *ptr, char *str)
static void rna_ParticleDupliWeight_name_get(PointerRNA *ptr, char *value)
{
ParticleSettings *part = (ParticleSettings *)ptr->owner_id;
psys_find_group_weights(part);
@ -1312,20 +1312,20 @@ static void rna_ParticleDupliWeight_name_get(PointerRNA *ptr, char *str)
ParticleDupliWeight *dw = ptr->data;
if (dw->ob) {
BLI_sprintf(str, "%s: %i", dw->ob->id.name + 2, dw->count);
BLI_sprintf(value, "%s: %i", dw->ob->id.name + 2, dw->count);
}
else {
strcpy(str, "No object");
strcpy(value, "No object");
}
}
static int rna_ParticleDupliWeight_name_length(PointerRNA *ptr)
{
char tstr[MAX_ID_NAME + 64];
char tvalue[MAX_ID_NAME + 64];
rna_ParticleDupliWeight_name_get(ptr, tstr);
rna_ParticleDupliWeight_name_get(ptr, tvalue);
return strlen(tstr);
return strlen(tvalue);
}
static const EnumPropertyItem *rna_Particle_type_itemf(bContext *UNUSED(C),

View File

@ -3347,8 +3347,12 @@ static StructRNA *rna_viewer_path_elem_refine(PointerRNA *ptr)
return &RNA_IDViewerPathElem;
case VIEWER_PATH_ELEM_TYPE_MODIFIER:
return &RNA_ModifierViewerPathElem;
case VIEWER_PATH_ELEM_TYPE_NODE:
return &RNA_NodeViewerPathElem;
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE:
return &RNA_GroupNodeViewerPathElem;
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE:
return &RNA_SimulationZoneViewerPathElem;
case VIEWER_PATH_ELEM_TYPE_VIEWER_NODE:
return &RNA_ViewerNodeViewerPathElem;
}
BLI_assert_unreachable();
return nullptr;
@ -8070,7 +8074,9 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
static const EnumPropertyItem viewer_path_elem_type_items[] = {
{VIEWER_PATH_ELEM_TYPE_ID, "ID", ICON_NONE, "ID", ""},
{VIEWER_PATH_ELEM_TYPE_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""},
{VIEWER_PATH_ELEM_TYPE_NODE, "NODE", ICON_NONE, "Node", ""},
{VIEWER_PATH_ELEM_TYPE_GROUP_NODE, "GROUP_NODE", ICON_NONE, "Group Node", ""},
{VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE, "SIMULATION_ZONE", ICON_NONE, "Simulation Zone", ""},
{VIEWER_PATH_ELEM_TYPE_VIEWER_NODE, "VIEWER_NODE", ICON_NONE, "Viewer Node", ""},
{0, nullptr, 0, nullptr, nullptr},
};
@ -8087,6 +8093,11 @@ static void rna_def_viewer_path_elem(BlenderRNA *brna)
RNA_def_property_enum_items(prop, viewer_path_elem_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of the path element");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "ui_name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(
prop, "UI Name", "Name that can be displayed in the UI for this element");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_id_viewer_path_elem(BlenderRNA *brna)
@ -8111,15 +8122,37 @@ static void rna_def_modifier_viewer_path_elem(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Modifier Name", "");
}
static void rna_def_node_viewer_path_elem(BlenderRNA *brna)
static void rna_def_group_node_viewer_path_elem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "NodeViewerPathElem", "ViewerPathElem");
srna = RNA_def_struct(brna, "GroupNodeViewerPathElem", "ViewerPathElem");
prop = RNA_def_property(srna, "node_name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Node Name", "");
prop = RNA_def_property(srna, "node_id", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "Node ID", "");
}
static void rna_def_simulation_zone_viewer_path_elem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "SimulationZoneViewerPathElem", "ViewerPathElem");
prop = RNA_def_property(srna, "sim_output_node_id", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "Simulation Output Node ID", "");
}
static void rna_def_viewer_node_viewer_path_elem(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "ViewerNodeViewerPathElem", "ViewerPathElem");
prop = RNA_def_property(srna, "node_id", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "Node ID", "");
}
static void rna_def_viewer_path(BlenderRNA *brna)
@ -8130,7 +8163,9 @@ static void rna_def_viewer_path(BlenderRNA *brna)
rna_def_viewer_path_elem(brna);
rna_def_id_viewer_path_elem(brna);
rna_def_modifier_viewer_path_elem(brna);
rna_def_node_viewer_path_elem(brna);
rna_def_group_node_viewer_path_elem(brna);
rna_def_simulation_zone_viewer_path_elem(brna);
rna_def_viewer_node_viewer_path_elem(brna);
srna = RNA_def_struct(brna, "ViewerPath", nullptr);
RNA_def_struct_ui_text(srna, "Viewer Path", "Path to data that is viewed");

View File

@ -349,15 +349,15 @@ static int rna_TextureSlot_name_length(PointerRNA *ptr)
return 0;
}
static void rna_TextureSlot_name_get(PointerRNA *ptr, char *str)
static void rna_TextureSlot_name_get(PointerRNA *ptr, char *value)
{
MTex *mtex = ptr->data;
if (mtex->tex) {
strcpy(str, mtex->tex->id.name + 2);
strcpy(value, mtex->tex->id.name + 2);
}
else {
str[0] = '\0';
value[0] = '\0';
}
}

View File

@ -266,7 +266,7 @@ static StructRNA *rna_Panel_register(Main *bmain,
RNA_pointer_create(nullptr, &RNA_Panel, &dummy_panel, &dummy_panel_ptr);
/* We have to set default context! Else we get a void string... */
strcpy(dummy_pt.translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
STRNCPY(dummy_pt.translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
/* validate the python class */
if (validate(&dummy_panel_ptr, data, have_function) != 0) {
@ -286,7 +286,7 @@ static StructRNA *rna_Panel_register(Main *bmain,
if ((1 << dummy_pt.region_type) & RGN_TYPE_HAS_CATEGORY_MASK) {
if (dummy_pt.category[0] == '\0') {
/* Use a fallback, otherwise an empty value will draw the panel in every category. */
strcpy(dummy_pt.category, PNL_CATEGORY_FALLBACK);
STRNCPY(dummy_pt.category, PNL_CATEGORY_FALLBACK);
# ifndef NDEBUG
printf("%s '%s' misses category, please update the script\n", error_prefix, dummy_pt.idname);
# endif
@ -989,7 +989,7 @@ static StructRNA *rna_Menu_register(Main *bmain,
RNA_pointer_create(nullptr, &RNA_Menu, &dummy_menu, &dummy_menu_ptr);
/* We have to set default context! Else we get a void string... */
strcpy(dummy_mt.translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
STRNCPY(dummy_mt.translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
/* validate the python class */
if (validate(&dummy_menu_ptr, data, have_function) != 0) {

View File

@ -6,8 +6,6 @@
* \ingroup modifiers
*/
#define DNA_DEPRECATED_ALLOW
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
@ -297,7 +295,7 @@ static void compute_interpolated_polys(const Mesh *mesh,
}
if (0 < in_count && in_count < poly_src.size()) {
/* Ring search starting at a vertex which is not included in the mask. */
int last_corner_vert = corner_verts[start];
int last_corner_vert = poly_verts_src[start];
bool v_loop_in_mask_last = vertex_mask[last_corner_vert];
for (const int j : poly_verts_src.index_range()) {
const int corner_vert = poly_verts_src[(start + 1 + j) % poly_src.size()];

View File

@ -424,25 +424,6 @@ void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
namespace blender {
static const lf::FunctionNode *find_viewer_lf_node(const bNode &viewer_bnode)
{
if (const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
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;
}
static const lf::FunctionNode *find_group_lf_node(const bNode &group_bnode)
{
if (const nodes::GeometryNodesLazyFunctionGraphInfo *lf_graph_info =
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;
}
static void find_side_effect_nodes_for_viewer_path(
const ViewerPath &viewer_path,
const NodesModifierData &nmd,
@ -464,45 +445,101 @@ static void find_side_effect_nodes_for_viewer_path(
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
/* Write side effect nodes to a new map and only if everything succeeds, move the nodes to the
* caller. This is easier than changing r_side_effect_nodes directly and then undoing changes in
* case of errors. */
MultiValueMap<ComputeContextHash, const lf::FunctionNode *> local_side_effect_nodes;
const bNodeTree *group = nmd.node_group;
Stack<const bNode *> group_node_stack;
for (const int32_t group_node_id : parsed_path->group_node_ids) {
const bNode *found_node = group->node_by_id(group_node_id);
if (found_node == nullptr) {
const bke::bNodeTreeZone *zone = nullptr;
for (const ViewerPathElem *elem : parsed_path->node_path) {
const bke::bNodeTreeZones *tree_zones = group->zones();
if (tree_zones == nullptr) {
return;
}
if (found_node->id == nullptr) {
const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*group);
if (lf_graph_info == nullptr) {
return;
}
if (found_node->is_muted()) {
return;
switch (elem->type) {
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto &typed_elem = *reinterpret_cast<const SimulationZoneViewerPathElem *>(elem);
const bke::bNodeTreeZone *next_zone = tree_zones->get_zone_by_node(
typed_elem.sim_output_node_id);
if (next_zone == nullptr) {
return;
}
if (next_zone->parent_zone != zone) {
return;
}
const lf::FunctionNode *lf_zone_node = lf_graph_info->mapping.zone_node_map.lookup_default(
next_zone, nullptr);
if (lf_zone_node == nullptr) {
return;
}
local_side_effect_nodes.add(compute_context_builder.hash(), lf_zone_node);
compute_context_builder.push<bke::SimulationZoneComputeContext>(*next_zone->output_node);
zone = next_zone;
break;
}
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto &typed_elem = *reinterpret_cast<const GroupNodeViewerPathElem *>(elem);
const bNode *node = group->node_by_id(typed_elem.node_id);
if (node == nullptr) {
return;
}
if (node->id == nullptr) {
return;
}
if (node->is_muted()) {
return;
}
if (zone != tree_zones->get_zone_by_node(node->identifier)) {
return;
}
const lf::FunctionNode *lf_group_node =
lf_graph_info->mapping.group_node_map.lookup_default(node, nullptr);
if (lf_group_node == nullptr) {
return;
}
local_side_effect_nodes.add(compute_context_builder.hash(), lf_group_node);
compute_context_builder.push<bke::NodeGroupComputeContext>(*node);
group = reinterpret_cast<const bNodeTree *>(node->id);
zone = nullptr;
break;
}
default: {
BLI_assert_unreachable();
return;
}
}
group_node_stack.push(found_node);
group = reinterpret_cast<bNodeTree *>(found_node->id);
compute_context_builder.push<bke::NodeGroupComputeContext>(*found_node);
}
const bNode *found_viewer_node = group->node_by_id(parsed_path->viewer_node_id);
if (found_viewer_node == nullptr) {
return;
}
const lf::FunctionNode *lf_viewer_node = find_viewer_lf_node(*found_viewer_node);
const auto *lf_graph_info = nodes::ensure_geometry_nodes_lazy_function_graph(*group);
if (lf_graph_info == nullptr) {
return;
}
const bke::bNodeTreeZones *tree_zones = group->zones();
if (tree_zones == nullptr) {
return;
}
if (tree_zones->get_zone_by_node(found_viewer_node->identifier) != zone) {
return;
}
const lf::FunctionNode *lf_viewer_node = lf_graph_info->mapping.viewer_node_map.lookup_default(
found_viewer_node, nullptr);
if (lf_viewer_node == nullptr) {
return;
}
local_side_effect_nodes.add(compute_context_builder.hash(), lf_viewer_node);
/* Not only mark the viewer node as having side effects, but also all group nodes it is contained
* in. */
r_side_effect_nodes.add_non_duplicates(compute_context_builder.hash(), lf_viewer_node);
compute_context_builder.pop();
while (!compute_context_builder.is_empty()) {
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);
compute_context_builder.pop();
/* Successfully found all compute contexts for the viewer. */
for (const auto item : local_side_effect_nodes.items()) {
r_side_effect_nodes.add_multiple(item.key, item.value);
}
}
@ -550,11 +587,11 @@ static void find_socket_log_contexts(const NodesModifierData &nmd,
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<ComputeContextHash> hash =
geo_log::GeoModifierLog::get_compute_context_hash_for_node_editor(
snode, nmd.modifier.name))
{
r_socket_log_contexts.add(*hash);
const Map<const bke::bNodeTreeZone *, ComputeContextHash> hash_by_zone =
geo_log::GeoModifierLog::get_context_hash_by_zone_for_node_editor(snode,
nmd.modifier.name);
for (const ComputeContextHash &hash : hash_by_zone.values()) {
r_socket_log_contexts.add(hash);
}
}
}

View File

@ -28,6 +28,7 @@
#include "BLI_compute_context.hh"
#include "BKE_node_tree_zones.hh"
#include "BKE_simulation_state.hh"
struct Object;
@ -175,7 +176,7 @@ struct GeometryNodeLazyFunctionGraphMapping {
*/
Map<const bNode *, const lf::FunctionNode *> group_node_map;
Map<const bNode *, const lf::FunctionNode *> viewer_node_map;
Map<const bNode *, const lf::FunctionNode *> sim_output_node_map;
Map<const bke::bNodeTreeZone *, const lf::FunctionNode *> zone_node_map;
/* Indexed by #bNodeSocket::index_in_all_outputs. */
Array<int> lf_input_index_for_output_bsocket_usage;
@ -190,29 +191,9 @@ struct GeometryNodeLazyFunctionGraphMapping {
*/
struct GeometryNodesLazyFunctionGraphInfo {
/**
* Allocator used for many things contained in this struct.
* Contains resources that need to be freed when the graph is not needed anymore.
*/
LinearAllocator<> allocator;
/**
* Many nodes are implemented as multi-functions. So this contains a mapping from nodes to their
* corresponding multi-functions.
*/
std::unique_ptr<NodeMultiFunctions> node_multi_functions;
/**
* Many lazy-functions are build for the lazy-function graph. Since the graph does not own them,
* we have to keep track of them separately.
*/
Vector<std::unique_ptr<LazyFunction>> functions;
/**
* Debug info that has to be destructed when the graph is not used anymore.
*/
Vector<std::unique_ptr<lf::DummyDebugInfo>> dummy_debug_infos_;
/**
* Many sockets have default values. Since those are not owned by the lazy-function graph, we
* have to keep track of them separately. This only owns the values, the memory is owned by the
* allocator above.
*/
Vector<GMutablePointer> values_to_destruct;
ResourceScope scope;
/**
* The actual lazy-function graph.
*/
@ -226,9 +207,6 @@ struct GeometryNodesLazyFunctionGraphInfo {
* This can be used as a simple heuristic for the complexity of the node group.
*/
int num_inline_nodes_approximate = 0;
GeometryNodesLazyFunctionGraphInfo();
~GeometryNodesLazyFunctionGraphInfo();
};
/**

View File

@ -37,6 +37,7 @@
#include "BKE_attribute.h"
#include "BKE_geometry_set.hh"
#include "BKE_node_tree_zones.hh"
#include "BKE_viewer_path.h"
#include "FN_field.hh"
@ -333,9 +334,11 @@ class GeoModifierLog {
/**
* Utility accessor to logged data.
*/
static std::optional<ComputeContextHash> get_compute_context_hash_for_node_editor(
const SpaceNode &snode, StringRefNull modifier_name);
static GeoTreeLog *get_tree_log_for_node_editor(const SpaceNode &snode);
static Map<const bke::bNodeTreeZone *, ComputeContextHash>
get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name);
static Map<const bke::bNodeTreeZone *, GeoTreeLog *> get_tree_log_by_zone_for_node_editor(
const SpaceNode &snode);
static const ViewerNodeLog *find_viewer_node_log_for_path(const ViewerPath &viewer_path);
};

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,8 @@
namespace blender::nodes::geo_eval_log {
using bke::bNodeTreeZone;
using bke::bNodeTreeZones;
using fn::FieldInput;
using fn::FieldInputs;
@ -518,46 +520,82 @@ static std::optional<ObjectAndModifier> get_modifier_for_node_editor(const Space
return ObjectAndModifier{object, used_modifier};
}
std::optional<ComputeContextHash> GeoModifierLog::get_compute_context_hash_for_node_editor(
const SpaceNode &snode, const StringRefNull modifier_name)
static void find_tree_zone_hash_recursive(
const bNodeTreeZone &zone,
ComputeContextBuilder &compute_context_builder,
Map<const bNodeTreeZone *, ComputeContextHash> &r_hash_by_zone)
{
Vector<const bNodeTreePath *> tree_path = snode.treepath;
if (tree_path.is_empty()) {
return std::nullopt;
compute_context_builder.push<bke::SimulationZoneComputeContext>(*zone.output_node);
r_hash_by_zone.add_new(&zone, compute_context_builder.hash());
for (const bNodeTreeZone *child_zone : zone.child_zones) {
find_tree_zone_hash_recursive(*child_zone, compute_context_builder, r_hash_by_zone);
}
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::ModifierComputeContext>(modifier_name);
for (const int i : tree_path.index_range().drop_back(1)) {
/* The tree path contains the name of the node but not its ID. */
const bNode *node = nodeFindNodebyName(tree_path[i]->nodetree, tree_path[i + 1]->node_name);
if (node == nullptr) {
/* The current tree path is invalid, probably because some parent group node has been
* deleted. */
return std::nullopt;
}
compute_context_builder.push<bke::NodeGroupComputeContext>(*node);
}
return compute_context_builder.hash();
compute_context_builder.pop();
}
GeoTreeLog *GeoModifierLog::get_tree_log_for_node_editor(const SpaceNode &snode)
Map<const bNodeTreeZone *, ComputeContextHash> GeoModifierLog::
get_context_hash_by_zone_for_node_editor(const SpaceNode &snode, StringRefNull modifier_name)
{
const Vector<const bNodeTreePath *> tree_path = snode.treepath;
if (tree_path.is_empty()) {
return {};
}
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::ModifierComputeContext>(modifier_name);
for (const int i : tree_path.index_range().drop_back(1)) {
bNodeTree *tree = tree_path[i]->nodetree;
const char *group_node_name = tree_path[i + 1]->node_name;
const bNode *group_node = nodeFindNodebyName(tree, group_node_name);
if (group_node == nullptr) {
return {};
}
const bNodeTreeZones *tree_zones = tree->zones();
if (tree_zones == nullptr) {
return {};
}
const Vector<const bNodeTreeZone *> zone_stack = tree_zones->get_zone_stack_for_node(
group_node->identifier);
for (const bNodeTreeZone *zone : zone_stack) {
compute_context_builder.push<bke::SimulationZoneComputeContext>(*zone->output_node);
}
compute_context_builder.push<bke::NodeGroupComputeContext>(*group_node);
}
const bNodeTreeZones *tree_zones = snode.edittree->zones();
if (tree_zones == nullptr) {
return {};
}
Map<const bNodeTreeZone *, ComputeContextHash> hash_by_zone;
hash_by_zone.add_new(nullptr, compute_context_builder.hash());
for (const bNodeTreeZone *zone : tree_zones->root_zones) {
find_tree_zone_hash_recursive(*zone, compute_context_builder, hash_by_zone);
}
return hash_by_zone;
}
Map<const bNodeTreeZone *, GeoTreeLog *> GeoModifierLog::get_tree_log_by_zone_for_node_editor(
const SpaceNode &snode)
{
std::optional<ObjectAndModifier> object_and_modifier = get_modifier_for_node_editor(snode);
if (!object_and_modifier) {
return nullptr;
return {};
}
GeoModifierLog *modifier_log = static_cast<GeoModifierLog *>(
object_and_modifier->nmd->runtime_eval_log);
if (modifier_log == nullptr) {
return nullptr;
return {};
}
if (const std::optional<ComputeContextHash> hash =
GeoModifierLog::get_compute_context_hash_for_node_editor(
snode, object_and_modifier->nmd->modifier.name))
{
return &modifier_log->get_tree_log(*hash);
const Map<const bNodeTreeZone *, ComputeContextHash> hash_by_zone =
GeoModifierLog::get_context_hash_by_zone_for_node_editor(
snode, object_and_modifier->nmd->modifier.name);
Map<const bNodeTreeZone *, GeoTreeLog *> log_by_zone;
for (const auto item : hash_by_zone.items()) {
GeoTreeLog &tree_log = modifier_log->get_tree_log(item.value);
log_by_zone.add(item.key, &tree_log);
}
return nullptr;
return log_by_zone;
}
const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerPath &viewer_path)
@ -587,8 +625,24 @@ const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerP
ComputeContextBuilder compute_context_builder;
compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name);
for (const int32_t group_node_id : parsed_path->group_node_ids) {
compute_context_builder.push<bke::NodeGroupComputeContext>(group_node_id);
for (const ViewerPathElem *elem : parsed_path->node_path) {
switch (elem->type) {
case VIEWER_PATH_ELEM_TYPE_GROUP_NODE: {
const auto &typed_elem = *reinterpret_cast<const GroupNodeViewerPathElem *>(elem);
compute_context_builder.push<bke::NodeGroupComputeContext>(typed_elem.node_id);
break;
}
case VIEWER_PATH_ELEM_TYPE_SIMULATION_ZONE: {
const auto &typed_elem = *reinterpret_cast<const SimulationZoneViewerPathElem *>(elem);
compute_context_builder.push<bke::SimulationZoneComputeContext>(
typed_elem.sim_output_node_id);
break;
}
default: {
BLI_assert_unreachable();
break;
}
}
}
const ComputeContextHash context_hash = compute_context_builder.hash();
nodes::geo_eval_log::GeoTreeLog &tree_log = modifier_log->get_tree_log(context_hash);