Refactoring: Corrections and unifications in mathematics vfont gizmos #107193
|
@ -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
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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 ¶ms, 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()]) {
|
||||
|
|
Loading…
Reference in New Issue