UI: Asset Shelf (Experimental Feature) #104831
|
@ -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';
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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__ = ()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 {};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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++,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue