Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
| Show First 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | static void expand_mesh(Mesh &mesh, | ||||
| if (loop_expand != 0) { | if (loop_expand != 0) { | ||||
| CustomData_duplicate_referenced_layers(&mesh.ldata, mesh.totloop); | CustomData_duplicate_referenced_layers(&mesh.ldata, mesh.totloop); | ||||
| mesh.totloop += loop_expand; | mesh.totloop += loop_expand; | ||||
| CustomData_realloc(&mesh.ldata, mesh.totloop); | CustomData_realloc(&mesh.ldata, mesh.totloop); | ||||
| } | } | ||||
| BKE_mesh_update_customdata_pointers(&mesh, false); | BKE_mesh_update_customdata_pointers(&mesh, false); | ||||
| } | } | ||||
| static CustomData &get_customdata(Mesh &mesh, const AttributeDomain domain) | |||||
| { | |||||
| switch (domain) { | |||||
| case ATTR_DOMAIN_POINT: | |||||
| return mesh.vdata; | |||||
| case ATTR_DOMAIN_EDGE: | |||||
| return mesh.edata; | |||||
| case ATTR_DOMAIN_FACE: | |||||
| return mesh.pdata; | |||||
| case ATTR_DOMAIN_CORNER: | |||||
| return mesh.ldata; | |||||
| default: | |||||
| BLI_assert_unreachable(); | |||||
| return mesh.vdata; | |||||
| } | |||||
| } | |||||
| static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const AttributeDomain domain) | |||||
| { | |||||
| MeshComponent component; | |||||
| component.replace(&mesh, GeometryOwnershipType::ReadOnly); | |||||
| CustomData &custom_data = get_customdata(mesh, domain); | |||||
| if (int *orig_indices = static_cast<int *>(CustomData_get_layer(&custom_data, CD_ORIGINDEX))) { | |||||
| return {orig_indices, component.attribute_domain_size(domain)}; | |||||
| } | |||||
| return {}; | |||||
| } | |||||
| static MEdge new_edge(const int v1, const int v2) | static MEdge new_edge(const int v1, const int v2) | ||||
| { | { | ||||
| MEdge edge; | MEdge edge; | ||||
| edge.v1 = v1; | edge.v1 = v1; | ||||
| edge.v2 = v2; | edge.v2 = v2; | ||||
| edge.flag = (ME_EDGEDRAW | ME_EDGERENDER); | edge.flag = (ME_EDGEDRAW | ME_EDGERENDER); | ||||
| return edge; | return edge; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | devirtualize_varray(offsets, [&](const auto offsets) { | ||||
| threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) { | threading::parallel_for(selection.index_range(), 1024, [&](const IndexRange range) { | ||||
| for (const int i : range) { | for (const int i : range) { | ||||
| const float3 offset = offsets[selection[i]]; | const float3 offset = offsets[selection[i]]; | ||||
| add_v3_v3(new_verts[i].co, offset); | add_v3_v3(new_verts[i].co, offset); | ||||
| } | } | ||||
| }); | }); | ||||
| }); | }); | ||||
| MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT); | |||||
| if (!vert_orig_indices.is_empty()) { | |||||
JacquesLucke: Technically this check is not necessary I think. | |||||
| vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE); | |||||
| } | |||||
| if (attribute_outputs.top_id) { | if (attribute_outputs.top_id) { | ||||
| save_selection_as_attribute( | save_selection_as_attribute( | ||||
| component, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range); | component, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range); | ||||
| } | } | ||||
| if (attribute_outputs.side_id) { | if (attribute_outputs.side_id) { | ||||
| save_selection_as_attribute( | save_selection_as_attribute( | ||||
| component, attribute_outputs.side_id.get(), ATTR_DOMAIN_EDGE, new_edge_range); | component, attribute_outputs.side_id.get(), ATTR_DOMAIN_EDGE, new_edge_range); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 307 Lines • ▼ Show 20 Lines | static void extrude_mesh_edges(MeshComponent &component, | ||||
| else { | else { | ||||
| threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) { | threading::parallel_for(new_verts.index_range(), 1024, [&](const IndexRange range) { | ||||
| for (const int i : range) { | for (const int i : range) { | ||||
| add_v3_v3(new_verts[i].co, vert_offsets[new_vert_indices[i]]); | add_v3_v3(new_verts[i].co, vert_offsets[new_vert_indices[i]]); | ||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT); | |||||
| if (!vert_orig_indices.is_empty()) { | |||||
| vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE); | |||||
| } | |||||
| MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE); | |||||
| if (!edge_orig_indices.is_empty()) { | |||||
| edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE); | |||||
| edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE); | |||||
| } | |||||
| if (attribute_outputs.top_id) { | if (attribute_outputs.top_id) { | ||||
| save_selection_as_attribute( | save_selection_as_attribute( | ||||
| component, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range); | component, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range); | ||||
| } | } | ||||
| if (attribute_outputs.side_id) { | if (attribute_outputs.side_id) { | ||||
| save_selection_as_attribute( | save_selection_as_attribute( | ||||
| component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, new_poly_range); | component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, new_poly_range); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 352 Lines • ▼ Show 20 Lines | threading::parallel_for( | ||||
| const int i_new = new_vert_indices.index_of_try(i_orig); | const int i_new = new_vert_indices.index_of_try(i_orig); | ||||
| const float3 offset = vert_offsets[i_orig]; | const float3 offset = vert_offsets[i_orig]; | ||||
| MVert &vert = mesh_verts(mesh)[(i_new == -1) ? i_orig : new_vert_range[i_new]]; | MVert &vert = mesh_verts(mesh)[(i_new == -1) ? i_orig : new_vert_range[i_new]]; | ||||
| add_v3_v3(vert.co, offset); | add_v3_v3(vert.co, offset); | ||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT); | |||||
| if (!vert_orig_indices.is_empty()) { | |||||
| vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE); | |||||
| } | |||||
| MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE); | |||||
| if (!edge_orig_indices.is_empty()) { | |||||
| edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE); | |||||
| edge_orig_indices.slice(new_inner_edge_range).fill(ORIGINDEX_NONE); | |||||
| edge_orig_indices.slice(boundary_edge_range).fill(ORIGINDEX_NONE); | |||||
| } | |||||
| MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE); | |||||
| if (!poly_orig_indices.is_empty()) { | |||||
| poly_orig_indices.slice(side_poly_range).fill(ORIGINDEX_NONE); | |||||
| } | |||||
| if (attribute_outputs.top_id) { | if (attribute_outputs.top_id) { | ||||
| save_selection_as_attribute( | save_selection_as_attribute( | ||||
| component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection); | component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection); | ||||
| } | } | ||||
| if (attribute_outputs.side_id) { | if (attribute_outputs.side_id) { | ||||
| save_selection_as_attribute( | save_selection_as_attribute( | ||||
| component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range); | component, attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE, side_poly_range); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 233 Lines • ▼ Show 20 Lines | threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) { | ||||
| for (const int i_selection : range) { | for (const int i_selection : range) { | ||||
| const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection); | const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection); | ||||
| for (MVert &vert : new_verts.slice(poly_corner_range)) { | for (MVert &vert : new_verts.slice(poly_corner_range)) { | ||||
| add_v3_v3(vert.co, poly_offset[poly_selection[i_selection]]); | add_v3_v3(vert.co, poly_offset[poly_selection[i_selection]]); | ||||
| } | } | ||||
| } | } | ||||
| }); | }); | ||||
| MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT); | |||||
| if (!vert_orig_indices.is_empty()) { | |||||
| vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE); | |||||
| } | |||||
| MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE); | |||||
| if (!edge_orig_indices.is_empty()) { | |||||
| edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE); | |||||
| edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE); | |||||
| } | |||||
| MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE); | |||||
| if (!poly_orig_indices.is_empty()) { | |||||
| poly_orig_indices.slice(side_poly_range).fill(ORIGINDEX_NONE); | |||||
| } | |||||
| /* Finally update each extruded polygon's loops to point to the new edges and vertices. | /* Finally update each extruded polygon's loops to point to the new edges and vertices. | ||||
| * This must be done last, because they were used to find original indices for attribute | * This must be done last, because they were used to find original indices for attribute | ||||
| * interpolation before. Alternatively an original index array could be built for each domain. */ | * interpolation before. Alternatively an original index array could be built for each domain. */ | ||||
| threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) { | threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) { | ||||
| for (const int i_selection : range) { | for (const int i_selection : range) { | ||||
| const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection); | const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection); | ||||
| const MPoly &poly = polys[poly_selection[i_selection]]; | const MPoly &poly = polys[poly_selection[i_selection]]; | ||||
| ▲ Show 20 Lines • Show All 107 Lines • Show Last 20 Lines | |||||
Technically this check is not necessary I think.