Merge branch 'blender-v3.0-release'
This commit is contained in:
commit
bdf6665e3a
|
@ -921,6 +921,10 @@ static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
|
|||
/* Release the mesh from the geometry set again. */
|
||||
if (geometry_set.has<MeshComponent>()) {
|
||||
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
if (mesh_component.get_for_read() != input_mesh) {
|
||||
/* Make sure the mesh component actually owns the mesh before taking over ownership. */
|
||||
mesh_component.ensure_owns_direct_data();
|
||||
}
|
||||
mesh_output = mesh_component.release();
|
||||
}
|
||||
|
||||
|
|
|
@ -568,15 +568,15 @@ class GeometryNodesEvaluator {
|
|||
}
|
||||
/* Count the number of potential users for this socket. */
|
||||
socket.foreach_target_socket(
|
||||
[&, this](const DInputSocket target_socket) {
|
||||
[&, this](const DInputSocket target_socket,
|
||||
const DOutputSocket::TargetSocketPathInfo &UNUSED(path_info)) {
|
||||
const DNode target_node = target_socket.node();
|
||||
if (!this->node_states_.contains_as(target_node)) {
|
||||
/* The target node is not computed because it is not computed to the output. */
|
||||
return;
|
||||
}
|
||||
output_state.potential_users += 1;
|
||||
},
|
||||
{});
|
||||
});
|
||||
if (output_state.potential_users == 0) {
|
||||
/* If it does not have any potential users, it is unused. It might become required again in
|
||||
* `schedule_initial_nodes`. */
|
||||
|
@ -1257,43 +1257,61 @@ class GeometryNodesEvaluator {
|
|||
{
|
||||
BLI_assert(value_to_forward.get() != nullptr);
|
||||
|
||||
Vector<DSocket> sockets_to_log_to;
|
||||
sockets_to_log_to.append(from_socket);
|
||||
|
||||
Vector<DInputSocket> to_sockets;
|
||||
auto handle_target_socket_fn = [&, this](const DInputSocket to_socket) {
|
||||
if (this->should_forward_to_socket(to_socket)) {
|
||||
to_sockets.append(to_socket);
|
||||
}
|
||||
};
|
||||
auto handle_skipped_socket_fn = [&](const DSocket socket) {
|
||||
sockets_to_log_to.append(socket);
|
||||
};
|
||||
from_socket.foreach_target_socket(handle_target_socket_fn, handle_skipped_socket_fn);
|
||||
|
||||
LinearAllocator<> &allocator = local_allocators_.local();
|
||||
|
||||
const CPPType &from_type = *value_to_forward.type();
|
||||
Vector<DInputSocket> to_sockets_same_type;
|
||||
for (const DInputSocket &to_socket : to_sockets) {
|
||||
const CPPType &to_type = *get_socket_cpp_type(to_socket);
|
||||
if (from_type == to_type) {
|
||||
/* All target sockets that do not need a conversion will be handled afterwards. */
|
||||
to_sockets_same_type.append(to_socket);
|
||||
/* Multi input socket values are logged once all values are available. */
|
||||
if (!to_socket->is_multi_input_socket()) {
|
||||
sockets_to_log_to.append(to_socket);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
this->forward_to_socket_with_different_type(
|
||||
allocator, value_to_forward, from_socket, to_socket, to_type);
|
||||
}
|
||||
|
||||
this->log_socket_value(sockets_to_log_to, value_to_forward);
|
||||
Vector<DSocket> log_original_value_sockets;
|
||||
Vector<DInputSocket> forward_original_value_sockets;
|
||||
log_original_value_sockets.append(from_socket);
|
||||
|
||||
from_socket.foreach_target_socket(
|
||||
[&](const DInputSocket to_socket, const DOutputSocket::TargetSocketPathInfo &path_info) {
|
||||
if (!this->should_forward_to_socket(to_socket)) {
|
||||
return;
|
||||
}
|
||||
BLI_assert(to_socket == path_info.sockets.last());
|
||||
GMutablePointer current_value = value_to_forward;
|
||||
for (const DSocket &next_socket : path_info.sockets) {
|
||||
const DNode next_node = next_socket.node();
|
||||
const bool is_last_socket = to_socket == next_socket;
|
||||
const bool do_conversion_if_necessary = is_last_socket ||
|
||||
next_node->is_group_output_node() ||
|
||||
(next_node->is_group_node() &&
|
||||
!next_node->is_muted());
|
||||
if (do_conversion_if_necessary) {
|
||||
const CPPType &next_type = *get_socket_cpp_type(next_socket);
|
||||
if (*current_value.type() != next_type) {
|
||||
void *buffer = allocator.allocate(next_type.size(), next_type.alignment());
|
||||
this->convert_value(*current_value.type(), next_type, current_value.get(), buffer);
|
||||
if (current_value.get() != value_to_forward.get()) {
|
||||
current_value.destruct();
|
||||
}
|
||||
current_value = {next_type, buffer};
|
||||
}
|
||||
}
|
||||
if (current_value.get() == value_to_forward.get()) {
|
||||
/* Log the original value at the current socket. */
|
||||
log_original_value_sockets.append(next_socket);
|
||||
}
|
||||
else {
|
||||
/* Multi-input sockets are logged when all values are available. */
|
||||
if (!(next_socket->is_input() && next_socket->as_input().is_multi_input_socket())) {
|
||||
/* Log the converted value at the socket. */
|
||||
this->log_socket_value({next_socket}, current_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (current_value.get() == value_to_forward.get()) {
|
||||
/* The value has not been converted, so forward the original value. */
|
||||
forward_original_value_sockets.append(to_socket);
|
||||
}
|
||||
else {
|
||||
/* The value has been converted. */
|
||||
this->add_value_to_input_socket(to_socket, from_socket, current_value);
|
||||
}
|
||||
});
|
||||
this->log_socket_value(log_original_value_sockets, value_to_forward);
|
||||
this->forward_to_sockets_with_same_type(
|
||||
allocator, to_sockets_same_type, value_to_forward, from_socket);
|
||||
allocator, forward_original_value_sockets, value_to_forward, from_socket);
|
||||
}
|
||||
|
||||
bool should_forward_to_socket(const DInputSocket socket)
|
||||
|
@ -1312,27 +1330,6 @@ class GeometryNodesEvaluator {
|
|||
return target_input_state.usage != ValueUsage::Unused;
|
||||
}
|
||||
|
||||
void forward_to_socket_with_different_type(LinearAllocator<> &allocator,
|
||||
const GPointer value_to_forward,
|
||||
const DOutputSocket from_socket,
|
||||
const DInputSocket to_socket,
|
||||
const CPPType &to_type)
|
||||
{
|
||||
const CPPType &from_type = *value_to_forward.type();
|
||||
|
||||
/* Allocate a buffer for the converted value. */
|
||||
void *buffer = allocator.allocate(to_type.size(), to_type.alignment());
|
||||
GMutablePointer value{to_type, buffer};
|
||||
|
||||
this->convert_value(from_type, to_type, value_to_forward.get(), buffer);
|
||||
|
||||
/* Multi input socket values are logged once all values are available. */
|
||||
if (!to_socket->is_multi_input_socket()) {
|
||||
this->log_socket_value({to_socket}, value);
|
||||
}
|
||||
this->add_value_to_input_socket(to_socket, from_socket, value);
|
||||
}
|
||||
|
||||
void forward_to_sockets_with_same_type(LinearAllocator<> &allocator,
|
||||
Span<DInputSocket> to_sockets,
|
||||
GMutablePointer value_to_forward,
|
||||
|
|
|
@ -158,8 +158,19 @@ class DOutputSocket : public DSocket {
|
|||
DInputSocket get_corresponding_group_node_input() const;
|
||||
DInputSocket get_active_corresponding_group_output_socket() const;
|
||||
|
||||
void foreach_target_socket(FunctionRef<void(DInputSocket)> target_fn,
|
||||
FunctionRef<void(DSocket)> skipped_fn) const;
|
||||
struct TargetSocketPathInfo {
|
||||
/** All sockets on the path from the current to the final target sockets, excluding `this`. */
|
||||
Vector<DSocket, 16> sockets;
|
||||
};
|
||||
|
||||
using ForeachTargetSocketFn =
|
||||
FunctionRef<void(DInputSocket, const TargetSocketPathInfo &path_info)>;
|
||||
|
||||
void foreach_target_socket(ForeachTargetSocketFn target_fn) const;
|
||||
|
||||
private:
|
||||
void foreach_target_socket(ForeachTargetSocketFn target_fn,
|
||||
TargetSocketPathInfo &path_info) const;
|
||||
};
|
||||
|
||||
class DerivedNodeTree {
|
||||
|
|
|
@ -231,45 +231,90 @@ void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> origin_fn) c
|
|||
|
||||
/* Calls `target_fn` for every "real" target socket. "Real" means that reroutes, muted nodes
|
||||
* and node groups are handled by this function. Target sockets are on the nodes that use the value
|
||||
* from this socket. The `skipped_fn` function is called for sockets that have been skipped during
|
||||
* the search for target sockets (e.g. reroutes). */
|
||||
void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> target_fn,
|
||||
FunctionRef<void(DSocket)> skipped_fn) const
|
||||
* from this socket. */
|
||||
void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn) const
|
||||
{
|
||||
for (const SocketRef *skipped_socket : socket_ref_->logically_linked_skipped_sockets()) {
|
||||
skipped_fn.call_safe({context_, skipped_socket});
|
||||
}
|
||||
for (const InputSocketRef *linked_socket : socket_ref_->as_output().logically_linked_sockets()) {
|
||||
const NodeRef &linked_node = linked_socket->node();
|
||||
DInputSocket linked_dsocket{context_, linked_socket};
|
||||
TargetSocketPathInfo path_info;
|
||||
this->foreach_target_socket(target_fn, path_info);
|
||||
}
|
||||
|
||||
if (linked_node.is_group_output_node()) {
|
||||
void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
|
||||
TargetSocketPathInfo &path_info) const
|
||||
{
|
||||
for (const LinkRef *link : socket_ref_->as_output().directly_linked_links()) {
|
||||
if (link->is_muted()) {
|
||||
continue;
|
||||
}
|
||||
const DInputSocket &linked_socket{context_, &link->to()};
|
||||
if (!linked_socket->is_available()) {
|
||||
continue;
|
||||
}
|
||||
const DNode linked_node = linked_socket.node();
|
||||
if (linked_node->is_reroute_node()) {
|
||||
const DInputSocket reroute_input = linked_socket;
|
||||
const DOutputSocket reroute_output = linked_node.output(0);
|
||||
path_info.sockets.append(reroute_input);
|
||||
path_info.sockets.append(reroute_output);
|
||||
reroute_output.foreach_target_socket(target_fn, path_info);
|
||||
path_info.sockets.pop_last();
|
||||
path_info.sockets.pop_last();
|
||||
}
|
||||
else if (linked_node->is_muted()) {
|
||||
for (const InternalLinkRef *internal_link : linked_node->internal_links()) {
|
||||
if (&internal_link->from() != linked_socket.socket_ref()) {
|
||||
continue;
|
||||
}
|
||||
/* The internal link only forwards the first incoming link. */
|
||||
if (linked_socket->is_multi_input_socket()) {
|
||||
if (linked_socket->directly_linked_links()[0] == link) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const DInputSocket mute_input = linked_socket;
|
||||
const DOutputSocket mute_output{context_, &internal_link->to()};
|
||||
path_info.sockets.append(mute_input);
|
||||
path_info.sockets.append(mute_output);
|
||||
mute_output.foreach_target_socket(target_fn, path_info);
|
||||
path_info.sockets.pop_last();
|
||||
path_info.sockets.pop_last();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (linked_node->is_group_output_node()) {
|
||||
if (context_->is_root()) {
|
||||
/* This is a group output in the root node group. */
|
||||
target_fn(linked_dsocket);
|
||||
path_info.sockets.append(linked_socket);
|
||||
target_fn(linked_socket, path_info);
|
||||
path_info.sockets.pop_last();
|
||||
}
|
||||
else {
|
||||
/* Follow the links going out of the group node in the parent node group. */
|
||||
DOutputSocket socket_in_parent_group =
|
||||
linked_dsocket.get_corresponding_group_node_output();
|
||||
skipped_fn.call_safe(linked_dsocket);
|
||||
skipped_fn.call_safe(socket_in_parent_group);
|
||||
socket_in_parent_group.foreach_target_socket(target_fn, skipped_fn);
|
||||
const DOutputSocket socket_in_parent_group =
|
||||
linked_socket.get_corresponding_group_node_output();
|
||||
path_info.sockets.append(linked_socket);
|
||||
path_info.sockets.append(socket_in_parent_group);
|
||||
socket_in_parent_group.foreach_target_socket(target_fn, path_info);
|
||||
path_info.sockets.pop_last();
|
||||
path_info.sockets.pop_last();
|
||||
}
|
||||
}
|
||||
else if (linked_node.is_group_node()) {
|
||||
else if (linked_node->is_group_node()) {
|
||||
/* Follow the links within the nested node group. */
|
||||
Vector<DOutputSocket> sockets_in_group =
|
||||
linked_dsocket.get_corresponding_group_input_sockets();
|
||||
skipped_fn.call_safe(linked_dsocket);
|
||||
for (DOutputSocket socket_in_group : sockets_in_group) {
|
||||
skipped_fn.call_safe(socket_in_group);
|
||||
socket_in_group.foreach_target_socket(target_fn, skipped_fn);
|
||||
path_info.sockets.append(linked_socket);
|
||||
const Vector<DOutputSocket> sockets_in_group =
|
||||
linked_socket.get_corresponding_group_input_sockets();
|
||||
for (const DOutputSocket &socket_in_group : sockets_in_group) {
|
||||
path_info.sockets.append(socket_in_group);
|
||||
socket_in_group.foreach_target_socket(target_fn, path_info);
|
||||
path_info.sockets.pop_last();
|
||||
}
|
||||
path_info.sockets.pop_last();
|
||||
}
|
||||
else {
|
||||
/* The normal case: just use the linked input socket as target. */
|
||||
target_fn(linked_dsocket);
|
||||
path_info.sockets.append(linked_socket);
|
||||
target_fn(linked_socket, path_info);
|
||||
path_info.sockets.pop_last();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue