Refactoring: Corrections and unifications in mathematics vfont gizmos #107193

Closed
Iliya Katushenock wants to merge 19 commits from mod_moder/blender:tmp_fix_text_cursor_transform into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
20 changed files with 381 additions and 269 deletions
Showing only changes of commit 6a224e7949 - Show all commits

View File

@ -69,20 +69,25 @@ namespace blender::bke {
/**
* Cache of a mesh's loose edges, accessed with #Mesh::loose_edges(). *
*/
struct LooseEdgeCache {
struct LooseGeomCache {
/**
* A bitmap set to true for each loose edge, false if the edge is used by any face.
* Allocated only if there is at least one loose edge.
* A bitmap set to true for each loose element, false if the element is used by any face.
* Allocated only if there is at least one loose element.
*/
blender::BitVector<> is_loose_bits;
/**
* The number of loose edges. If zero, the #is_loose_bits shouldn't be accessed.
* The number of loose elements. If zero, the #is_loose_bits shouldn't be accessed.
* If less than zero, the cache has been accessed in an invalid way
* (i.e.directly instead of through #Mesh::loose_edges()).
*/
int count = -1;
};
struct LooseEdgeCache : public LooseGeomCache {
};
struct LooseVertCache : public LooseGeomCache {
};
struct MeshRuntime {
/* Evaluated mesh for objects which do not have effective modifiers.
* This mesh is used as a result of modifier stack evaluation.
@ -166,11 +171,12 @@ struct MeshRuntime {
mutable Vector<float3> vert_normals;
mutable Vector<float3> poly_normals;
/**
* A cache of data about the loose edges. Can be shared with other data-blocks with unchanged
* topology. Accessed with #Mesh::loose_edges().
*/
/** Cache of data about edges not used by faces. See #Mesh::loose_edges(). */
SharedCache<LooseEdgeCache> loose_edges_cache;
/** Cache of data about vertices not used by edges. See #Mesh::loose_verts(). */
SharedCache<LooseVertCache> loose_verts_cache;
/** Cache of data about vertices not used by faces. See #Mesh::loose_verts(). */
SharedCache<LooseVertCache> verts_no_face_cache;
/**
* A bit vector the size of the number of vertices, set to true for the center vertices of

View File

@ -1141,30 +1141,6 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
return tree;
}
static BitVector<> loose_verts_map_get(const Span<blender::int2> edges,
int verts_num,
int *r_loose_vert_num)
{
BitVector<> loose_verts_mask(verts_num, true);
int num_linked_verts = 0;
for (const int64_t i : edges.index_range()) {
const blender::int2 &edge = edges[i];
if (loose_verts_mask[edge[0]]) {
loose_verts_mask[edge[0]].reset();
num_linked_verts++;
}
if (loose_verts_mask[edge[1]]) {
loose_verts_mask[edge[1]].reset();
num_linked_verts++;
}
}
*r_loose_vert_num = verts_num - num_linked_verts;
return loose_verts_mask;
}
static BitVector<> looptri_no_hidden_map_get(const blender::OffsetIndices<int> polys,
const VArray<bool> &hide_poly,
const int looptri_len,
@ -1237,10 +1213,14 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
switch (bvh_cache_type) {
case BVHTREE_FROM_LOOSEVERTS: {
int mask_bits_act_len = -1;
const BitVector<> mask = loose_verts_map_get(edges, mesh->totvert, &mask_bits_act_len);
data->tree = bvhtree_from_mesh_verts_create_tree(
0.0f, tree_type, 6, positions, mesh->totvert, mask, mask_bits_act_len);
const blender::bke::LooseVertCache &loose_verts = mesh->loose_verts();
data->tree = bvhtree_from_mesh_verts_create_tree(0.0f,
tree_type,
6,
positions,
mesh->totvert,
loose_verts.is_loose_bits,
loose_verts.count);
break;
}
case BVHTREE_FROM_VERTS: {

View File

@ -237,7 +237,8 @@ struct ResultOffsets {
Array<int> profile_indices;
/** Whether any curve in the profile or curve input has only a single evaluated point. */
bool any_single_point_curve;
bool any_single_point_main;
bool any_single_point_profile;
};
static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool fill_caps)
{
@ -315,10 +316,8 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
}
}
},
[&]() {
result.any_single_point_curve = offsets_contain_single_point(main_offsets) ||
offsets_contain_single_point(profile_offsets);
});
[&]() { result.any_single_point_main = offsets_contain_single_point(main_offsets); },
[&]() { result.any_single_point_profile = offsets_contain_single_point(profile_offsets); });
return result;
}
@ -765,9 +764,13 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
positions.slice(info.vert_range));
});
if (!offsets.any_single_point_curve) {
/* If there are no single point curves, every curve combination will always have faces. */
mesh->loose_edges_tag_none();
if (!offsets.any_single_point_main) {
/* If there are no single point curves, every combination will have at least loose edges. */
mesh->tag_loose_verts_none();
if (!offsets.any_single_point_profile) {
/* If there are no single point profiles, every combination will have faces. */
mesh->loose_edges_tag_none();
}
}
SpanAttributeWriter<bool> sharp_edges;

View File

@ -190,29 +190,27 @@ void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
BLI_assert(r_values.size() == mesh.totvert);
const Span<int> corner_verts = mesh.corner_verts();
Array<bool> loose_verts(mesh.totvert, true);
r_values.fill(true);
for (const int corner : IndexRange(mesh.totloop)) {
const int point_index = corner_verts[corner];
loose_verts[point_index] = false;
if (!old_values[corner]) {
r_values[point_index] = false;
}
}
/* Deselect loose vertices without corners that are still selected from the 'true' default. */
/* The record fact says that the value is true.
* Writing to the array from different threads is okay because each thread sets the same value.
*/
threading::parallel_for(loose_verts.index_range(), 2048, [&](const IndexRange range) {
for (const int vert_index : range) {
if (loose_verts[vert_index]) {
r_values[vert_index] = false;
const bke::LooseVertCache &loose_verts = mesh.verts_no_face();
if (loose_verts.count > 0) {
const BitSpan bits = loose_verts.is_loose_bits;
threading::parallel_for(bits.index_range(), 2048, [&](const IndexRange range) {
for (const int vert_index : range) {
if (bits[vert_index]) {
r_values[vert_index] = false;
}
}
}
});
});
}
}
static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray &varray)
@ -754,20 +752,26 @@ static bool can_simple_adapt_for_single(const Mesh &mesh,
/* All other domains are always connected to points. */
return true;
case ATTR_DOMAIN_EDGE:
/* There may be loose vertices not connected to edges. */
return ELEM(to_domain, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
if (to_domain == ATTR_DOMAIN_POINT) {
return mesh.loose_verts().count == 0;
}
return true;
case ATTR_DOMAIN_FACE:
/* There may be loose vertices or edges not connected to faces. */
if (to_domain == ATTR_DOMAIN_POINT) {
return mesh.verts_no_face().count == 0;
}
if (to_domain == ATTR_DOMAIN_EDGE) {
return mesh.loose_edges().count == 0;
}
return to_domain == ATTR_DOMAIN_CORNER;
return true;
case ATTR_DOMAIN_CORNER:
/* Only faces are always connected to corners. */
if (to_domain == ATTR_DOMAIN_POINT) {
return mesh.verts_no_face().count == 0;
}
if (to_domain == ATTR_DOMAIN_EDGE) {
return mesh.loose_edges().count == 0;
}
return to_domain == ATTR_DOMAIN_FACE;
return true;
default:
BLI_assert_unreachable();
return false;

View File

@ -130,6 +130,8 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
* when the source is persistent and edits to the destination mesh don't affect the caches.
* Caches will be "un-shared" as necessary later on. */
mesh_dst->runtime->bounds_cache = mesh_src->runtime->bounds_cache;
mesh_dst->runtime->loose_verts_cache = mesh_src->runtime->loose_verts_cache;
mesh_dst->runtime->verts_no_face_cache = mesh_src->runtime->verts_no_face_cache;
mesh_dst->runtime->loose_edges_cache = mesh_src->runtime->loose_edges_cache;
mesh_dst->runtime->looptris_cache = mesh_src->runtime->looptris_cache;

View File

@ -106,32 +106,90 @@ MeshRuntime::~MeshRuntime()
}
}
static int reset_bits_and_count(MutableBitSpan bits, const Span<int> indices_to_reset)
{
int count = bits.size();
for (const int vert : indices_to_reset) {
if (bits[vert]) {
bits[vert].reset();
count--;
}
}
return count;
}
static void bit_vector_with_reset_bits_or_empty(const Span<int> indices_to_reset,
const int indexed_elems_num,
BitVector<> &r_bits,
int &r_count)
{
r_bits.resize(0);
r_bits.resize(indexed_elems_num, true);
r_count = reset_bits_and_count(r_bits, indices_to_reset);
if (r_count == 0) {
r_bits.clear_and_shrink();
}
}
/**
* If there are no loose edges and no loose vertices, all vertices are used by faces.
*/
static void try_tag_verts_no_face_none(const Mesh &mesh)
{
if (mesh.runtime->loose_edges_cache.is_cached() || mesh.loose_edges().count > 0) {
return;
}
if (mesh.runtime->loose_verts_cache.is_cached() || mesh.loose_verts().count > 0) {
return;
}
mesh.runtime->verts_no_face_cache.ensure([&](LooseVertCache &r_data) {
r_data.is_loose_bits.clear_and_shrink();
r_data.count = 0;
});
}
} // namespace blender::bke
const blender::bke::LooseVertCache &Mesh::loose_verts() const
{
using namespace blender::bke;
this->runtime->loose_verts_cache.ensure([&](LooseVertCache &r_data) {
const Span<int> verts = this->edges().cast<int>();
bit_vector_with_reset_bits_or_empty(verts, this->totvert, r_data.is_loose_bits, r_data.count);
});
return this->runtime->loose_verts_cache.data();
}
const blender::bke::LooseVertCache &Mesh::verts_no_face() const
{
using namespace blender::bke;
this->runtime->verts_no_face_cache.ensure([&](LooseVertCache &r_data) {
const Span<int> verts = this->corner_verts();
bit_vector_with_reset_bits_or_empty(verts, this->totvert, r_data.is_loose_bits, r_data.count);
});
return this->runtime->verts_no_face_cache.data();
}
const blender::bke::LooseEdgeCache &Mesh::loose_edges() const
{
using namespace blender::bke;
this->runtime->loose_edges_cache.ensure([&](LooseEdgeCache &r_data) {
blender::BitVector<> &loose_edges = r_data.is_loose_bits;
loose_edges.resize(0);
loose_edges.resize(this->totedge, true);
int count = this->totedge;
for (const int edge : this->corner_edges()) {
if (loose_edges[edge]) {
loose_edges[edge].reset();
count--;
}
}
if (count == 0) {
loose_edges.clear_and_shrink();
}
r_data.count = count;
const Span<int> edges = this->corner_edges();
bit_vector_with_reset_bits_or_empty(edges, this->totedge, r_data.is_loose_bits, r_data.count);
});
return this->runtime->loose_edges_cache.data();
}
void Mesh::tag_loose_verts_none() const
{
using namespace blender::bke;
this->runtime->loose_verts_cache.ensure([&](LooseVertCache &r_data) {
r_data.is_loose_bits.clear_and_shrink();
r_data.count = 0;
});
try_tag_verts_no_face_none(*this);
}
void Mesh::loose_edges_tag_none() const
{
using namespace blender::bke;
@ -139,6 +197,7 @@ void Mesh::loose_edges_tag_none() const
r_data.is_loose_bits.clear_and_shrink();
r_data.count = 0;
});
try_tag_verts_no_face_none(*this);
}
blender::Span<MLoopTri> Mesh::looptris() const
@ -219,6 +278,8 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
free_subdiv_ccg(*mesh->runtime);
mesh->runtime->bounds_cache.tag_dirty();
mesh->runtime->loose_edges_cache.tag_dirty();
mesh->runtime->loose_verts_cache.tag_dirty();
mesh->runtime->verts_no_face_cache.tag_dirty();
mesh->runtime->looptris_cache.tag_dirty();
mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink();
@ -237,6 +298,8 @@ void BKE_mesh_tag_edges_split(struct Mesh *mesh)
reset_normals(*mesh->runtime);
free_subdiv_ccg(*mesh->runtime);
mesh->runtime->loose_edges_cache.tag_dirty();
mesh->runtime->loose_verts_cache.tag_dirty();
mesh->runtime->verts_no_face_cache.tag_dirty();
mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
mesh->runtime->subsurf_optimal_display_edges.clear_and_shrink();
if (mesh->runtime->shrinkwrap_data) {

View File

@ -177,6 +177,9 @@ static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
return true;
}
#endif
if (storage->infinite_sharp_vertices_map == nullptr) {
return false;
}
const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index];
return BLI_BITMAP_TEST_BOOL(storage->infinite_sharp_vertices_map, vertex_index);
}
@ -264,7 +267,7 @@ static void free_user_data(const OpenSubdiv_Converter *converter)
ConverterStorage *user_data = static_cast<ConverterStorage *>(converter->user_data);
MEM_SAFE_FREE(user_data->loop_uv_indices);
MEM_freeN(user_data->manifold_vertex_index);
MEM_freeN(user_data->infinite_sharp_vertices_map);
MEM_SAFE_FREE(user_data->infinite_sharp_vertices_map);
MEM_freeN(user_data->manifold_vertex_index_reverse);
MEM_freeN(user_data->manifold_edge_index_reverse);
MEM_freeN(user_data);
@ -306,7 +309,7 @@ static void init_functions(OpenSubdiv_Converter *converter)
converter->freeUserData = free_user_data;
}
static void initialize_manifold_index_array(const BLI_bitmap *used_map,
static void initialize_manifold_index_array(const blender::BitSpan not_used_map,
const int num_elements,
int **r_indices,
int **r_indices_reverse,
@ -323,7 +326,7 @@ static void initialize_manifold_index_array(const BLI_bitmap *used_map,
}
int offset = 0;
for (int i = 0; i < num_elements; i++) {
if (BLI_BITMAP_TEST_BOOL(used_map, i)) {
if (not_used_map.is_empty() || !not_used_map[i]) {
if (indices != nullptr) {
indices[i] = i - offset;
}
@ -349,42 +352,35 @@ static void initialize_manifold_index_array(const BLI_bitmap *used_map,
static void initialize_manifold_indices(ConverterStorage *storage)
{
using namespace blender;
const Mesh *mesh = storage->mesh;
const blender::Span<blender::int2> edges = storage->edges;
const blender::OffsetIndices<int> polys = storage->polys;
const blender::Span<int> corner_verts = storage->corner_verts;
const blender::Span<int> corner_edges = storage->corner_edges;
/* Set bits of elements which are not loose. */
BLI_bitmap *vert_used_map = BLI_BITMAP_NEW(mesh->totvert, "vert used map");
BLI_bitmap *edge_used_map = BLI_BITMAP_NEW(mesh->totedge, "edge used map");
for (int poly_index = 0; poly_index < mesh->totpoly; poly_index++) {
for (const int corner : polys[poly_index]) {
BLI_BITMAP_ENABLE(vert_used_map, corner_verts[corner]);
BLI_BITMAP_ENABLE(edge_used_map, corner_edges[corner]);
}
}
initialize_manifold_index_array(vert_used_map,
const bke::LooseVertCache &loose_verts = mesh->verts_no_face();
const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
initialize_manifold_index_array(loose_verts.is_loose_bits,
mesh->totvert,
&storage->manifold_vertex_index,
&storage->manifold_vertex_index_reverse,
&storage->num_manifold_vertices);
initialize_manifold_index_array(edge_used_map,
initialize_manifold_index_array(loose_edges.is_loose_bits,
mesh->totedge,
nullptr,
&storage->manifold_edge_index_reverse,
&storage->num_manifold_edges);
/* Initialize infinite sharp mapping. */
storage->infinite_sharp_vertices_map = BLI_BITMAP_NEW(mesh->totvert, "vert used map");
for (int edge_index = 0; edge_index < mesh->totedge; edge_index++) {
if (!BLI_BITMAP_TEST_BOOL(edge_used_map, edge_index)) {
const blender::int2 &edge = edges[edge_index];
BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge[0]);
BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge[1]);
if (loose_edges.count > 0) {
const Span<int2> edges = storage->edges;
storage->infinite_sharp_vertices_map = BLI_BITMAP_NEW(mesh->totvert, "vert used map");
for (int edge_index = 0; edge_index < mesh->totedge; edge_index++) {
if (loose_edges.is_loose_bits[edge_index]) {
const int2 edge = edges[edge_index];
BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge[0]);
BLI_BITMAP_ENABLE(storage->infinite_sharp_vertices_map, edge[1]);
}
}
}
/* Free working variables. */
MEM_freeN(vert_used_map);
MEM_freeN(edge_used_map);
else {
storage->infinite_sharp_vertices_map = nullptr;
}
}
static void init_user_data(OpenSubdiv_Converter *converter,

View File

@ -217,7 +217,7 @@ template<typename T> struct DefaultHash<T *> {
template<typename T> uint64_t get_default_hash(const T &v)
{
return DefaultHash<T>{}(v);
return DefaultHash<std::decay_t<T>>{}(v);
}
template<typename T1, typename T2> uint64_t get_default_hash_2(const T1 &v1, const T2 &v2)

View File

@ -30,46 +30,32 @@
/** \name Update Loose Geometry
* \{ */
static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBufferCache *cache)
static void extract_set_bits(const blender::BitSpan bits, blender::MutableSpan<int> indices)
{
using namespace blender;
BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
const bke::LooseEdgeCache &loose_edges = mr->me->loose_edges();
if (loose_edges.count > 0) {
cache->loose_geom.edges.reinitialize(loose_edges.count);
int count = 0;
for (const int64_t i : loose_edges.is_loose_bits.index_range()) {
if (loose_edges.is_loose_bits[i]) {
cache->loose_geom.edges[count] = int(i);
count++;
}
}
}
/* Tag verts as not loose. */
for (const int2 &edge : mr->edges) {
BLI_BITMAP_ENABLE(lvert_map, edge[0]);
BLI_BITMAP_ENABLE(lvert_map, edge[1]);
}
int count = 0;
Array<int> loose_verts(mr->vert_len);
for (int v = 0; v < mr->vert_len; v++) {
if (!BLI_BITMAP_TEST(lvert_map, v)) {
loose_verts[count] = v;
for (const int64_t i : bits.index_range()) {
if (bits[i]) {
indices[count] = int(i);
count++;
}
}
if (count < mr->vert_len) {
cache->loose_geom.verts = loose_verts.as_span().take_front(count);
}
else {
cache->loose_geom.verts = std::move(loose_verts);
BLI_assert(count == indices.size());
}
static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBufferCache *cache)
{
using namespace blender;
const bke::LooseEdgeCache &loose_edges = mr->me->loose_edges();
if (loose_edges.count > 0) {
cache->loose_geom.edges.reinitialize(loose_edges.count);
extract_set_bits(loose_edges.is_loose_bits, cache->loose_geom.edges);
}
MEM_freeN(lvert_map);
const bke::LooseVertCache &loose_verts = mr->me->loose_verts();
if (loose_verts.count > 0) {
cache->loose_geom.verts.reinitialize(loose_verts.count);
extract_set_bits(loose_verts.is_loose_bits, cache->loose_geom.verts);
}
}
static void mesh_render_data_loose_verts_bm(const MeshRenderData *mr,

View File

@ -417,6 +417,7 @@ Mesh *create_cuboid_mesh(const float3 &size,
const float3 bounds = size * 0.5f;
mesh->bounds_set_eager({-bounds, bounds});
mesh->tag_loose_verts_none();
return mesh;
}

View File

@ -203,6 +203,7 @@ struct AllMeshesInfo {
/** True if we know that there are no loose edges in any of the input meshes. */
bool no_loose_edges_hint = false;
bool no_loose_verts_hint = false;
};
struct AllCurvesInfo {
@ -947,6 +948,10 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
info.order.begin(), info.order.end(), [](const Mesh *mesh) {
return mesh->runtime->loose_edges_cache.is_cached() && mesh->loose_edges().count == 0;
});
info.no_loose_verts_hint = std::all_of(
info.order.begin(), info.order.end(), [](const Mesh *mesh) {
return mesh->runtime->loose_verts_cache.is_cached() && mesh->loose_verts().count == 0;
});
return info;
}
@ -1155,6 +1160,9 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
if (all_meshes_info.no_loose_edges_hint) {
dst_mesh->loose_edges_tag_none();
}
if (all_meshes_info.no_loose_verts_hint) {
dst_mesh->tag_loose_verts_none();
}
}
/** \} */

View File

@ -27,6 +27,7 @@ namespace bke {
struct MeshRuntime;
class AttributeAccessor;
class MutableAttributeAccessor;
struct LooseVertCache;
struct LooseEdgeCache;
} // namespace bke
} // namespace blender
@ -302,6 +303,15 @@ typedef struct Mesh {
* Cached information about loose edges, calculated lazily when necessary.
*/
const blender::bke::LooseEdgeCache &loose_edges() const;
/**
* Cached information about vertices that aren't used by any edges.
*/
const blender::bke::LooseVertCache &loose_verts() const;
/**
* Cached information about vertices that aren't used by faces (but may be used by loose edges).
*/
const blender::bke::LooseVertCache &verts_no_face() const;
/**
* Explicitly set the cached number of loose edges to zero. This can improve performance
* later on, because finding loose edges lazily can be skipped entirely.
@ -310,6 +320,14 @@ typedef struct Mesh {
* cache dirty. If the mesh was changed first, the relevant dirty tags should be called first.
*/
void loose_edges_tag_none() const;
/**
* Set the number of verices not connected to edges to zero. Similar to #loose_edges_tag_none().
* There may still be vertices only used by loose edges though.
*
* \note If both #loose_edges_tag_none() and #tag_loose_verts_none() are called,
* all vertices are used by faces, so #verts_no_faces() will be tagged empty as well.
*/
void tag_loose_verts_none() const;
/**
* Normal direction of polygons, defined by positions and the winding direction of face corners.

View File

@ -154,6 +154,8 @@ struct GeometryNodeLazyFunctionGraphMapping {
Array<int> lf_input_index_for_output_bsocket_usage;
/* Indexed by #bNodeSocket::index_in_all_outputs. */
Array<int> lf_input_index_for_attribute_propagation_to_output;
/* Indexed by #bNodeSocket::index_in_tree. */
Array<int> lf_index_by_bsocket;
};
/**

View File

@ -551,6 +551,7 @@ static void duplicate_faces(GeometrySet &geometry_set,
}
}
new_mesh->tag_loose_verts_none();
new_mesh->loose_edges_tag_none();
copy_face_attributes_without_id(edge_mapping,

View File

@ -220,7 +220,7 @@ class HasNeighborFieldInput final : public bke::GeometryFieldInput {
uint64_t hash() const final
{
return get_default_hash_2(3984756934876, group_field_);
return get_default_hash_2(39847876, group_field_);
}
bool is_equal_to(const fn::FieldNode &other) const final

View File

@ -153,6 +153,8 @@ static Mesh *create_circle_mesh(const float radius,
std::iota(corner_verts.begin(), corner_verts.end(), 0);
std::iota(corner_edges.begin(), corner_edges.end(), 0);
mesh->loose_edges_tag_none();
}
else if (fill_type == GEO_NODE_MESH_CIRCLE_FILL_TRIANGLE_FAN) {
for (const int i : poly_offsets.index_range()) {
@ -170,6 +172,7 @@ static Mesh *create_circle_mesh(const float radius,
}
}
mesh->tag_loose_verts_none();
mesh->bounds_set_eager(calculate_bounds_circle(radius, verts_num));
return mesh;

View File

@ -723,6 +723,7 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
}
calculate_selection_outputs(config, attribute_outputs, mesh->attributes_for_write());
mesh->tag_loose_verts_none();
mesh->loose_edges_tag_none();
mesh->bounds_set_eager(calculate_bounds_cylinder(config));

View File

@ -149,6 +149,7 @@ Mesh *create_grid_mesh(const int verts_x,
calculate_uvs(mesh, positions, corner_verts, size_x, size_y, uv_map_id);
}
mesh->tag_loose_verts_none();
mesh->loose_edges_tag_none();
const float3 bounds = float3(size_x * 0.5f, size_y * 0.5f, 0.0f);

View File

@ -333,6 +333,7 @@ static Mesh *create_uv_sphere_mesh(const float radius,
}
});
mesh->tag_loose_verts_none();
mesh->loose_edges_tag_none();
mesh->bounds_set_eager(calculate_bounds_uv_sphere(radius, segments, rings));

View File

@ -69,10 +69,9 @@ static const CPPType *get_vector_type(const CPPType &type)
* lazy-function.
*/
static void lazy_function_interface_from_node(const bNode &node,
Vector<const bNodeSocket *> &r_used_inputs,
Vector<const bNodeSocket *> &r_used_outputs,
Vector<lf::Input> &r_inputs,
Vector<lf::Output> &r_outputs)
Vector<lf::Output> &r_outputs,
MutableSpan<int> r_lf_index_by_bsocket)
{
const bool is_muted = node.is_muted();
const lf::ValueUsage input_usage = lf::ValueUsage::Used;
@ -87,8 +86,8 @@ static void lazy_function_interface_from_node(const bNode &node,
if (socket->is_multi_input() && !is_muted) {
type = get_vector_type(*type);
}
r_inputs.append({socket->identifier, *type, input_usage});
r_used_inputs.append(socket);
r_lf_index_by_bsocket[socket->index_in_tree()] = r_inputs.append_and_get_index_as(
socket->identifier, *type, input_usage);
}
for (const bNodeSocket *socket : node.output_sockets()) {
if (!socket->is_available()) {
@ -98,8 +97,8 @@ static void lazy_function_interface_from_node(const bNode &node,
if (type == nullptr) {
continue;
}
r_outputs.append({socket->identifier, *type});
r_used_outputs.append(socket);
r_lf_index_by_bsocket[socket->index_in_tree()] = r_outputs.append_and_get_index_as(
socket->identifier, *type);
}
}
@ -121,10 +120,9 @@ class LazyFunctionForGeometryNode : public LazyFunction {
public:
LazyFunctionForGeometryNode(const bNode &node,
Vector<const bNodeSocket *> &r_used_inputs,
Vector<const bNodeSocket *> &r_used_outputs,
MutableSpan<int> r_lf_input_for_output_bsocket_usage,
MutableSpan<int> r_lf_input_for_attribute_propagation_to_output)
MutableSpan<int> r_lf_input_for_attribute_propagation_to_output,
MutableSpan<int> r_lf_index_by_bsocket)
: node_(node),
lf_input_for_output_bsocket_usage_(r_lf_input_for_output_bsocket_usage),
lf_input_for_attribute_propagation_to_output_(
@ -132,7 +130,7 @@ class LazyFunctionForGeometryNode : public LazyFunction {
{
BLI_assert(node.typeinfo->geometry_node_execute != nullptr);
debug_name_ = node.name;
lazy_function_interface_from_node(node, r_used_inputs, r_used_outputs, inputs_, outputs_);
lazy_function_interface_from_node(node, inputs_, outputs_, r_lf_index_by_bsocket);
const NodeDeclaration &node_decl = *node.declaration();
const aal::RelationsInNode *relations = node_decl.anonymous_attribute_relations();
@ -291,13 +289,11 @@ class LazyFunctionForRerouteNode : public LazyFunction {
*/
class LazyFunctionForUndefinedNode : public LazyFunction {
public:
LazyFunctionForUndefinedNode(const bNode &node, Vector<const bNodeSocket *> &r_used_outputs)
LazyFunctionForUndefinedNode(const bNode &node, MutableSpan<int> r_lf_index_by_bsocket)
{
debug_name_ = "Undefined";
Vector<const bNodeSocket *> dummy_used_inputs;
Vector<lf::Input> dummy_inputs;
lazy_function_interface_from_node(
node, dummy_used_inputs, r_used_outputs, dummy_inputs, outputs_);
lazy_function_interface_from_node(node, dummy_inputs, outputs_, r_lf_index_by_bsocket);
}
void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
@ -392,12 +388,10 @@ class LazyFunctionForMutedNode : public LazyFunction {
Array<int> input_by_output_index_;
public:
LazyFunctionForMutedNode(const bNode &node,
Vector<const bNodeSocket *> &r_used_inputs,
Vector<const bNodeSocket *> &r_used_outputs)
LazyFunctionForMutedNode(const bNode &node, MutableSpan<int> r_lf_index_by_bsocket)
{
debug_name_ = "Muted";
lazy_function_interface_from_node(node, r_used_inputs, r_used_outputs, inputs_, outputs_);
lazy_function_interface_from_node(node, inputs_, outputs_, r_lf_index_by_bsocket);
for (lf::Input &fn_input : inputs_) {
fn_input.usage = lf::ValueUsage::Maybe;
}
@ -409,8 +403,8 @@ class LazyFunctionForMutedNode : public LazyFunction {
input_by_output_index_.reinitialize(outputs_.size());
input_by_output_index_.fill(-1);
for (const bNodeLink &internal_link : node.internal_links()) {
const int input_i = r_used_inputs.first_index_of_try(internal_link.fromsock);
const int output_i = r_used_outputs.first_index_of_try(internal_link.tosock);
const int input_i = r_lf_index_by_bsocket[internal_link.fromsock->index_in_tree()];
const int output_i = r_lf_index_by_bsocket[internal_link.tosock->index_in_tree()];
if (ELEM(-1, input_i, output_i)) {
continue;
}
@ -516,13 +510,12 @@ class LazyFunctionForMultiFunctionNode : public LazyFunction {
public:
LazyFunctionForMultiFunctionNode(const bNode &node,
NodeMultiFunctions::Item fn_item,
Vector<const bNodeSocket *> &r_used_inputs,
Vector<const bNodeSocket *> &r_used_outputs)
MutableSpan<int> r_lf_index_by_bsocket)
: fn_item_(std::move(fn_item))
{
BLI_assert(fn_item_.fn != nullptr);
debug_name_ = node.name;
lazy_function_interface_from_node(node, r_used_inputs, r_used_outputs, inputs_, outputs_);
lazy_function_interface_from_node(node, inputs_, outputs_, r_lf_index_by_bsocket);
for (const lf::Input &fn_input : inputs_) {
input_types_.append(ValueOrFieldCPPType::get_from_self(*fn_input.type));
}
@ -587,17 +580,24 @@ class LazyFunctionForViewerNode : public LazyFunction {
bool use_field_input_ = true;
public:
LazyFunctionForViewerNode(const bNode &bnode, Vector<const bNodeSocket *> &r_used_inputs)
LazyFunctionForViewerNode(const bNode &bnode, MutableSpan<int> r_lf_index_by_bsocket)
: bnode_(bnode)
{
debug_name_ = "Viewer";
Vector<const bNodeSocket *> dummy_used_outputs;
lazy_function_interface_from_node(bnode, r_used_inputs, dummy_used_outputs, inputs_, outputs_);
const Span<const bNodeLink *> links = r_used_inputs[1]->directly_linked_links();
if (links.is_empty() || nodeIsDanglingReroute(&bnode.owner_tree(), links.first()->fromnode)) {
use_field_input_ = false;
r_used_inputs.pop_last();
inputs_.pop_last();
lazy_function_interface_from_node(bnode, inputs_, outputs_, r_lf_index_by_bsocket);
/* Remove field input if it is not used. */
for (const bNodeSocket *bsocket : bnode.input_sockets().drop_front(1)) {
if (!bsocket->is_available()) {
continue;
}
const Span<const bNodeLink *> links = bsocket->directly_linked_links();
if (links.is_empty() ||
nodeIsDanglingReroute(&bnode.owner_tree(), links.first()->fromnode)) {
use_field_input_ = false;
inputs_.pop_last();
r_lf_index_by_bsocket[bsocket->index_in_tree()] = -1;
}
}
}
@ -718,23 +718,27 @@ class LazyFunctionForGroupNode : public LazyFunction {
* For every output bsocket there is a corresponding boolean input that indicates whether the
* output is used.
*/
Map<int, int> lf_input_for_output_bsocket_usage_;
const Span<int> lf_input_for_output_bsocket_usage_;
/**
* For every geometry output that can propagate attributes from an input, there is an attribute
* set input. It indicates which attributes should be propagated to the output.
*/
Map<int, int> lf_input_for_attribute_propagation_to_output_;
const Span<int> lf_input_for_attribute_propagation_to_output_;
LazyFunctionForGroupNode(const bNode &group_node,
const GeometryNodesLazyFunctionGraphInfo &lf_graph_info)
: group_node_(group_node)
const GeometryNodesLazyFunctionGraphInfo &lf_graph_info,
MutableSpan<int> r_lf_input_for_output_bsocket_usage,
MutableSpan<int> r_lf_input_for_attribute_propagation_to_output,
MutableSpan<int> r_lf_index_by_bsocket)
: group_node_(group_node),
lf_input_for_output_bsocket_usage_(r_lf_input_for_output_bsocket_usage),
lf_input_for_attribute_propagation_to_output_(
r_lf_input_for_attribute_propagation_to_output)
{
debug_name_ = group_node.name;
allow_missing_requested_inputs_ = true;
Vector<const bNodeSocket *> tmp_inputs;
Vector<const bNodeSocket *> tmp_outputs;
lazy_function_interface_from_node(group_node, tmp_inputs, tmp_outputs, inputs_, outputs_);
lazy_function_interface_from_node(group_node, inputs_, outputs_, r_lf_index_by_bsocket);
has_many_nodes_ = lf_graph_info.num_inline_nodes_approximate > 1000;
@ -744,9 +748,8 @@ class LazyFunctionForGroupNode : public LazyFunction {
/* Add a boolean input for every output bsocket that indicates whether that socket is used. */
for (const int i : group_node.output_sockets().index_range()) {
lf_input_for_output_bsocket_usage_.add_new(
i,
graph_inputs.append_and_get_index(lf_graph_info.mapping.group_output_used_sockets[i]));
r_lf_input_for_output_bsocket_usage[group_node.output_socket(i).index_in_all_outputs()] =
graph_inputs.append_and_get_index(lf_graph_info.mapping.group_output_used_sockets[i]);
inputs_.append_as("Output is Used", CPPType::get<bool>(), lf::ValueUsage::Maybe);
}
graph_inputs.extend(lf_graph_info.mapping.group_output_used_sockets);
@ -758,7 +761,8 @@ class LazyFunctionForGroupNode : public LazyFunction {
const int lf_index = inputs_.append_and_get_index_as(
"Attribute Set", CPPType::get<bke::AnonymousAttributeSet>(), lf::ValueUsage::Maybe);
graph_inputs.append(lf_socket);
lf_input_for_attribute_propagation_to_output_.add(output_index, lf_index);
r_lf_input_for_attribute_propagation_to_output[group_node_.output_socket(output_index)
.index_in_all_outputs()] = lf_index;
}
Vector<const lf::InputSocket *> graph_outputs;
@ -842,20 +846,19 @@ class LazyFunctionForGroupNode : public LazyFunction {
if (i < group_node_.input_sockets().size()) {
return group_node_.input_socket(i).name;
}
for (const auto [bsocket_index, lf_socket_index] :
lf_input_for_output_bsocket_usage_.items()) {
if (i == lf_socket_index) {
std::stringstream ss;
ss << "'" << group_node_.output_socket(bsocket_index).name << "' output is used";
return ss.str();
for (const bNodeSocket *bsocket : group_node_.output_sockets()) {
{
const int lf_index = lf_input_for_output_bsocket_usage_[bsocket->index_in_all_outputs()];
if (i == lf_index) {
return StringRef("Use Output '") + bsocket->identifier + "'";
}
}
}
for (const auto [bsocket_index, lf_index] :
lf_input_for_attribute_propagation_to_output_.items()) {
if (i == lf_index) {
std::stringstream ss;
ss << "Propagate to '" << group_node_.output_socket(bsocket_index).name << "'";
return ss.str();
{
const int lf_index =
lf_input_for_attribute_propagation_to_output_[bsocket->index_in_all_outputs()];
if (i == lf_index) {
return StringRef("Propagate to '") + bsocket->identifier + "'";
}
}
}
return inputs_[i].debug_name;
@ -1238,6 +1241,8 @@ struct GeometryNodesLazyFunctionGraphBuilder {
mapping_->lf_input_index_for_attribute_propagation_to_output.reinitialize(
btree_.all_output_sockets().size());
mapping_->lf_input_index_for_attribute_propagation_to_output.fill(-1);
mapping_->lf_index_by_bsocket.reinitialize(btree_.all_sockets().size());
mapping_->lf_index_by_bsocket.fill(-1);
this->prepare_node_multi_functions();
this->build_group_input_node();
@ -1376,23 +1381,27 @@ struct GeometryNodesLazyFunctionGraphBuilder {
void handle_muted_node(const bNode &bnode)
{
Vector<const bNodeSocket *> used_inputs;
Vector<const bNodeSocket *> used_outputs;
auto lazy_function = std::make_unique<LazyFunctionForMutedNode>(
bnode, used_inputs, used_outputs);
auto lazy_function = std::make_unique<LazyFunctionForMutedNode>(bnode,
mapping_->lf_index_by_bsocket);
lf::Node &lf_node = lf_graph_->add_function(*lazy_function);
lf_graph_info_->functions.append(std::move(lazy_function));
for (const int i : used_inputs.index_range()) {
const bNodeSocket &bsocket = *used_inputs[i];
lf::InputSocket &lf_socket = lf_node.input(i);
input_socket_map_.add(&bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
for (const bNodeSocket *bsocket : bnode.input_sockets()) {
const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
if (lf_index == -1) {
continue;
}
lf::InputSocket &lf_socket = lf_node.input(lf_index);
input_socket_map_.add(bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
}
for (const int i : used_outputs.index_range()) {
const bNodeSocket &bsocket = *used_outputs[i];
lf::OutputSocket &lf_socket = lf_node.output(i);
output_socket_map_.add_new(&bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
for (const bNodeSocket *bsocket : bnode.output_sockets()) {
const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
if (lf_index == -1) {
continue;
}
lf::OutputSocket &lf_socket = lf_node.output(lf_index);
output_socket_map_.add_new(bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
}
}
@ -1467,7 +1476,12 @@ struct GeometryNodesLazyFunctionGraphBuilder {
return;
}
auto lazy_function = std::make_unique<LazyFunctionForGroupNode>(bnode, *group_lf_graph_info);
auto lazy_function = std::make_unique<LazyFunctionForGroupNode>(
bnode,
*group_lf_graph_info,
mapping_->lf_input_index_for_output_bsocket_usage,
mapping_->lf_input_index_for_attribute_propagation_to_output,
mapping_->lf_index_by_bsocket);
lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function);
for (const int i : bnode.input_sockets().index_range()) {
@ -1487,57 +1501,70 @@ struct GeometryNodesLazyFunctionGraphBuilder {
lf_graph_info_->num_inline_nodes_approximate +=
group_lf_graph_info->num_inline_nodes_approximate;
static const bool static_false = false;
for (const int i : lazy_function->lf_input_for_output_bsocket_usage_.values()) {
lf_node.input(i).set_default_value(&static_false);
socket_usage_inputs_.add(&lf_node.input(i));
}
/* Keep track of attribute set inputs that need to be populated later. */
for (const auto [output_index, lf_input_index] :
lazy_function->lf_input_for_attribute_propagation_to_output_.items()) {
attribute_set_propagation_map_.add(&bnode.output_socket(output_index),
&lf_node.input(lf_input_index));
for (const bNodeSocket *bsocket : bnode.output_sockets()) {
{
const int lf_input_index =
mapping_->lf_input_index_for_output_bsocket_usage[bsocket->index_in_all_outputs()];
if (lf_input_index != -1) {
lf::InputSocket &lf_input = lf_node.input(lf_input_index);
lf_input.set_default_value(&static_false);
socket_usage_inputs_.add(&lf_input);
}
}
{
/* Keep track of attribute set inputs that need to be populated later. */
const int lf_input_index = mapping_->lf_input_index_for_attribute_propagation_to_output
[bsocket->index_in_all_outputs()];
if (lf_input_index != -1) {
lf::InputSocket &lf_input = lf_node.input(lf_input_index);
attribute_set_propagation_map_.add(bsocket, &lf_input);
}
}
}
lf_graph_info_->functions.append(std::move(lazy_function));
}
void handle_geometry_node(const bNode &bnode)
{
Vector<const bNodeSocket *> used_inputs;
Vector<const bNodeSocket *> used_outputs;
auto lazy_function = std::make_unique<LazyFunctionForGeometryNode>(
bnode,
used_inputs,
used_outputs,
mapping_->lf_input_index_for_output_bsocket_usage,
mapping_->lf_input_index_for_attribute_propagation_to_output);
mapping_->lf_input_index_for_attribute_propagation_to_output,
mapping_->lf_index_by_bsocket);
lf::Node &lf_node = lf_graph_->add_function(*lazy_function);
for (const int i : used_inputs.index_range()) {
const bNodeSocket &bsocket = *used_inputs[i];
lf::InputSocket &lf_socket = lf_node.input(i);
for (const bNodeSocket *bsocket : bnode.input_sockets()) {
const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
if (lf_index == -1) {
continue;
}
lf::InputSocket &lf_socket = lf_node.input(lf_index);
if (bsocket.is_multi_input()) {
auto multi_input_lazy_function = std::make_unique<LazyFunctionForMultiInput>(bsocket);
if (bsocket->is_multi_input()) {
auto multi_input_lazy_function = std::make_unique<LazyFunctionForMultiInput>(*bsocket);
lf::Node &lf_multi_input_node = lf_graph_->add_function(*multi_input_lazy_function);
lf_graph_info_->functions.append(std::move(multi_input_lazy_function));
lf_graph_->add_link(lf_multi_input_node.output(0), lf_socket);
multi_input_socket_nodes_.add_new(&bsocket, &lf_multi_input_node);
multi_input_socket_nodes_.add_new(bsocket, &lf_multi_input_node);
for (lf::InputSocket *lf_multi_input_socket : lf_multi_input_node.inputs()) {
mapping_->bsockets_by_lf_socket_map.add(lf_multi_input_socket, &bsocket);
mapping_->bsockets_by_lf_socket_map.add(lf_multi_input_socket, bsocket);
const void *default_value = lf_multi_input_socket->type().default_value();
lf_multi_input_socket->set_default_value(default_value);
}
}
else {
input_socket_map_.add(&bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
input_socket_map_.add(bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
}
}
for (const int i : used_outputs.index_range()) {
const bNodeSocket &bsocket = *used_outputs[i];
lf::OutputSocket &lf_socket = lf_node.output(i);
output_socket_map_.add_new(&bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
for (const bNodeSocket *bsocket : bnode.output_sockets()) {
const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
if (lf_index == -1) {
continue;
}
lf::OutputSocket &lf_socket = lf_node.output(lf_index);
output_socket_map_.add_new(bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
}
for (const bNodeSocket *bsocket : bnode.output_sockets()) {
@ -1565,40 +1592,47 @@ struct GeometryNodesLazyFunctionGraphBuilder {
void handle_multi_function_node(const bNode &bnode, const NodeMultiFunctions::Item &fn_item)
{
Vector<const bNodeSocket *> used_inputs;
Vector<const bNodeSocket *> used_outputs;
auto lazy_function = std::make_unique<LazyFunctionForMultiFunctionNode>(
bnode, fn_item, used_inputs, used_outputs);
bnode, fn_item, mapping_->lf_index_by_bsocket);
lf::Node &lf_node = lf_graph_->add_function(*lazy_function);
lf_graph_info_->functions.append(std::move(lazy_function));
for (const int i : used_inputs.index_range()) {
const bNodeSocket &bsocket = *used_inputs[i];
BLI_assert(!bsocket.is_multi_input());
lf::InputSocket &lf_socket = lf_node.input(i);
input_socket_map_.add(&bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
for (const bNodeSocket *bsocket : bnode.input_sockets()) {
const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
if (lf_index == -1) {
continue;
}
BLI_assert(!bsocket->is_multi_input());
lf::InputSocket &lf_socket = lf_node.input(lf_index);
input_socket_map_.add(bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
}
for (const int i : used_outputs.index_range()) {
const bNodeSocket &bsocket = *used_outputs[i];
lf::OutputSocket &lf_socket = lf_node.output(i);
output_socket_map_.add(&bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
for (const bNodeSocket *bsocket : bnode.output_sockets()) {
const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
if (lf_index == -1) {
continue;
}
lf::OutputSocket &lf_socket = lf_node.output(lf_index);
output_socket_map_.add(bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
}
}
void handle_viewer_node(const bNode &bnode)
{
Vector<const bNodeSocket *> used_inputs;
auto lazy_function = std::make_unique<LazyFunctionForViewerNode>(bnode, used_inputs);
auto lazy_function = std::make_unique<LazyFunctionForViewerNode>(
bnode, mapping_->lf_index_by_bsocket);
lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function);
lf_graph_info_->functions.append(std::move(lazy_function));
for (const int i : used_inputs.index_range()) {
const bNodeSocket &bsocket = *used_inputs[i];
lf::InputSocket &lf_socket = lf_node.input(i);
input_socket_map_.add(&bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
for (const bNodeSocket *bsocket : bnode.input_sockets()) {
const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
if (lf_index == -1) {
continue;
}
lf::InputSocket &lf_socket = lf_node.input(lf_index);
input_socket_map_.add(bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
}
mapping_->viewer_node_map.add(&bnode, &lf_node);
@ -1631,16 +1665,16 @@ struct GeometryNodesLazyFunctionGraphBuilder {
void handle_undefined_node(const bNode &bnode)
{
Vector<const bNodeSocket *> used_outputs;
auto lazy_function = std::make_unique<LazyFunctionForUndefinedNode>(bnode, used_outputs);
auto lazy_function = std::make_unique<LazyFunctionForUndefinedNode>(
bnode, mapping_->lf_index_by_bsocket);
lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function);
lf_graph_info_->functions.append(std::move(lazy_function));
for (const int i : used_outputs.index_range()) {
const bNodeSocket &bsocket = *used_outputs[i];
lf::OutputSocket &lf_socket = lf_node.output(i);
output_socket_map_.add(&bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, &bsocket);
for (const bNodeSocket *bsocket : bnode.output_sockets()) {
const int lf_index = mapping_->lf_index_by_bsocket[bsocket->index_in_tree()];
lf::OutputSocket &lf_socket = lf_node.output(lf_index);
output_socket_map_.add(bsocket, &lf_socket);
mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket);
}
}
@ -2160,8 +2194,10 @@ struct GeometryNodesLazyFunctionGraphBuilder {
}
for (const bNodeSocket *output_bsocket : bnode.output_sockets()) {
const int output_index = output_bsocket->index();
const int lf_input_index = fn.lf_input_for_output_bsocket_usage_.lookup(output_index);
const int lf_input_index =
mapping_
->lf_input_index_for_output_bsocket_usage[output_bsocket->index_in_all_outputs()];
BLI_assert(lf_input_index >= 0);
lf::InputSocket &lf_socket = lf_group_node.input(lf_input_index);
if (lf::OutputSocket *lf_output_is_used =
socket_is_used_map_[output_bsocket->index_in_tree()]) {