26 b.add_input<
decl::Bool>(
N_(
"Selection")).default_value(
true).supports_field().hide_value();
28 b.add_input<
decl::Float>(
N_(
"Offset Scale")).default_value(1.0f).supports_field();
29 b.add_input<
decl::Bool>(
N_(
"Individual")).default_value(
true);
39 uiItemR(layout,
ptr,
"mode", 0,
"", ICON_NONE);
72 component.attributes_for_write()->lookup_or_add_for_write_span<
bool>(
id, domain);
80 attribute.span.fill_indices(selection,
true);
116 const int vert_expand,
117 const int edge_expand,
118 const int poly_expand,
119 const int loop_expand)
121 if (vert_expand != 0) {
130 if (edge_expand != 0) {
135 if (poly_expand != 0) {
140 if (loop_expand != 0) {
170 return {orig_indices, attributes.
domain_size(domain)};
214 for (const int i : range) {
215 dst[i] = src[mask[i]];
224 template<
typename T,
typename GetMixIndicesFn>
228 attribute_math::DefaultPropatationMixer<T> mixer{dst.slice(range)};
230 for (const int i_src : get_mix_indices_fn(range[i_dst])) {
231 mixer.mix_in(i_dst, src[i_src]);
240 const int vert_offset = 0)
244 vert_to_edge_map[edges[i].v1 - vert_offset].append(i);
245 vert_to_edge_map[edges[i].v2 - vert_offset].append(i);
247 return vert_to_edge_map;
261 evaluator.add(offset_field);
262 evaluator.set_selection(selection_field);
263 evaluator.evaluate();
264 const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
272 const IndexRange new_vert_range{orig_vert_size, selection.
size()};
273 const IndexRange new_edge_range{orig_edge_size, selection.
size()};
278 for (
const int i_selection : selection.
index_range()) {
279 new_edges[i_selection] =
new_loose_edge(selection[i_selection], new_vert_range[i_selection]);
291 using T = decltype(dummy);
292 MutableSpan<T> data = attribute.span.typed<T>();
293 switch (attribute.domain) {
294 case ATTR_DOMAIN_POINT: {
296 copy_with_mask(data.slice(new_vert_range), data.as_span(), selection);
299 case ATTR_DOMAIN_EDGE: {
301 copy_with_mixing(data.slice(new_edge_range), data.as_span(), [&](const int i) {
302 return vert_to_edge_map[selection[i]].as_span();
307 BLI_assert_unreachable();
317 for (const int i : range) {
318 const float3 offset = offsets[selection[i]];
319 add_v3_v3(new_verts[i].co, offset);
327 if (attribute_outputs.top_id) {
331 if (attribute_outputs.side_id) {
346 const MPoly &poly = polys[i_poly];
348 polys_of_edge[loop.e].append(i_poly);
352 return polys_of_edge;
357 const int vert_connected_to_poly_1,
358 const int vert_connected_to_poly_2,
359 const int vert_across_from_poly_1,
360 const int vert_across_from_poly_2,
361 const int edge_connected_to_poly,
362 const int connecting_edge_1,
363 const int edge_across_from_poly,
364 const int connecting_edge_2)
367 bool start_with_connecting_edge =
true;
368 for (
const MLoop &loop : other_poly_loops) {
369 if (loop.e == edge_connected_to_poly) {
370 start_with_connecting_edge = loop.v == vert_connected_to_poly_1;
374 if (start_with_connecting_edge) {
375 new_loops[0].v = vert_connected_to_poly_1;
376 new_loops[0].e = connecting_edge_1;
377 new_loops[1].v = vert_across_from_poly_1;
378 new_loops[1].e = edge_across_from_poly;
379 new_loops[2].v = vert_across_from_poly_2;
380 new_loops[2].e = connecting_edge_2;
381 new_loops[3].v = vert_connected_to_poly_2;
382 new_loops[3].e = edge_connected_to_poly;
385 new_loops[0].v = vert_connected_to_poly_1;
386 new_loops[0].e = edge_connected_to_poly;
387 new_loops[1].v = vert_connected_to_poly_2;
388 new_loops[1].e = connecting_edge_2;
389 new_loops[2].v = vert_across_from_poly_2;
390 new_loops[2].e = edge_across_from_poly;
391 new_loops[3].v = vert_across_from_poly_1;
392 new_loops[3].e = connecting_edge_1;
399 static_assert(is_same_any_v<T, int, int64_t>);
403 for (
const T i_edge : edge_indices) {
405 vert_indices.
add(edge.v1);
406 vert_indices.
add(edge.v2);
424 edge_evaluator.set_selection(selection_field);
425 edge_evaluator.add(offset_field);
426 edge_evaluator.evaluate();
427 const IndexMask edge_selection = edge_evaluator.get_evaluated_selection_as_mask();
441 for (
const int i_edge : edge_selection) {
442 const MEdge &edge = orig_edges[i_edge];
444 mixer.mix_in(edge.v1,
offset);
445 mixer.mix_in(edge.v2,
offset);
452 const IndexRange new_vert_range{orig_vert_size, new_vert_indices.
size()};
454 const IndexRange connect_edge_range{orig_edges.
size(), new_vert_range.size()};
460 const IndexRange new_loop_range{orig_loop_size, new_poly_range.
size() * 4};
463 new_vert_range.
size(),
464 connect_edge_range.size() + duplicate_edge_range.
size(),
465 new_poly_range.size(),
466 new_loop_range.size());
477 connect_edges[i] =
new_edge(new_vert_indices[i], new_vert_range[i]);
482 const int i_new_vert_1 = new_vert_indices.
index_of(orig_edge.
v1);
483 const int i_new_vert_2 = new_vert_indices.
index_of(orig_edge.
v2);
488 new_polys[i] =
new_poly(new_loop_range[i * 4], 4);
492 const int orig_edge_index = edge_selection[i];
495 const int new_vert_1 = duplicate_edge.
v1;
496 const int new_vert_2 = duplicate_edge.
v2;
497 const int extrude_index_1 = new_vert_1 - orig_vert_size;
498 const int extrude_index_2 = new_vert_2 - orig_vert_size;
500 Span<int> connected_polys = edge_to_poly_map[orig_edge_index];
506 if (connected_polys.
size() == 1) {
507 const MPoly &connected_poly = polys[connected_polys.
first()];
511 new_loops.
slice(4 * i, 4),
512 new_vert_indices[extrude_index_1],
513 new_vert_indices[extrude_index_2],
517 connect_edge_range[extrude_index_1],
518 duplicate_edge_range[i],
519 connect_edge_range[extrude_index_2]);
538 using T = decltype(dummy);
539 MutableSpan<T> data = attribute.span.typed<T>();
540 switch (attribute.domain) {
541 case ATTR_DOMAIN_POINT: {
543 copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices);
546 case ATTR_DOMAIN_EDGE: {
548 MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range);
549 copy_with_mask(duplicate_data, data.as_span(), edge_selection);
552 MutableSpan<T> connect_data = data.slice(connect_edge_range);
553 copy_with_mixing(connect_data, duplicate_data.as_span(), [&](const int i_new_vert) {
554 return new_vert_to_duplicate_edge_map[i_new_vert].as_span();
558 case ATTR_DOMAIN_FACE: {
561 copy_with_mixing(data.slice(new_poly_range), data.as_span(), [&](const int i) {
562 return edge_to_poly_map[edge_selection[i]].as_span();
567 case ATTR_DOMAIN_CORNER: {
570 MutableSpan<T> new_data = data.slice(new_loop_range);
571 threading::parallel_for(edge_selection.index_range(), 256, [&](const IndexRange range) {
572 for (const int i_edge_selection : range) {
573 const int orig_edge_index = edge_selection[i_edge_selection];
575 Span<int> connected_polys = edge_to_poly_map[orig_edge_index];
576 if (connected_polys.is_empty()) {
579 new_data.slice(4 * i_edge_selection, 4).fill(T());
585 Array<T> side_poly_corner_data(2);
586 attribute_math::DefaultPropatationMixer<T> mixer{side_poly_corner_data};
588 const MEdge &duplicate_edge = duplicate_edges[i_edge_selection];
589 const int new_vert_1 = duplicate_edge.v1;
590 const int new_vert_2 = duplicate_edge.v2;
591 const int orig_vert_1 = new_vert_indices[new_vert_1 - orig_vert_size];
592 const int orig_vert_2 = new_vert_indices[new_vert_2 - orig_vert_size];
596 for (const int i_connected_poly : connected_polys.index_range()) {
597 const MPoly &connected_poly = polys[connected_polys[i_connected_poly]];
598 for (const int i_loop :
599 IndexRange(connected_poly.loopstart, connected_poly.totloop)) {
600 const MLoop &loop = loops[i_loop];
601 if (loop.v == orig_vert_1) {
602 mixer.mix_in(0, data[i_loop]);
604 if (loop.v == orig_vert_2) {
605 mixer.mix_in(1, data[i_loop]);
615 for (const int i : IndexRange(4 * i_edge_selection, 4)) {
616 if (ELEM(new_loops[i].v, new_vert_1, orig_vert_1)) {
617 new_data[i] = side_poly_corner_data.first();
619 else if (ELEM(new_loops[i].v, new_vert_2, orig_vert_2)) {
620 new_data[i] = side_poly_corner_data.last();
628 BLI_assert_unreachable();
636 if (edge_offsets.is_single()) {
637 const float3 offset = edge_offsets.get_internal_single();
639 for (const int i : range) {
640 add_v3_v3(new_verts[i].co, offset);
646 for (const int i : range) {
647 add_v3_v3(new_verts[i].co, vert_offsets[new_vert_indices[i]]);
657 edge_orig_indices.slice(duplicate_edge_range).fill(
ORIGINDEX_NONE);
659 if (attribute_outputs.top_id) {
663 if (attribute_outputs.side_id) {
688 poly_evaluator.set_selection(selection_field);
689 poly_evaluator.add(offset_field);
690 poly_evaluator.evaluate();
691 const IndexMask poly_selection = poly_evaluator.get_evaluated_selection_as_mask();
698 for (
const int i_poly : poly_selection) {
699 poly_selection_array[i_poly] =
true;
709 for (
const int i_poly : poly_selection) {
710 const MPoly &poly = orig_polys[i_poly];
713 mixer.mix_in(loop.v,
offset);
726 for (
const int i_poly : poly_selection) {
727 const MPoly &poly = orig_polys[i_poly];
729 all_selected_verts.
add(loop.v);
744 for (
const int i_edge : orig_edges.
index_range()) {
745 Span<int> polys = edge_to_poly_map[i_edge];
747 int i_selected_poly = -1;
748 int deselected_poly_count = 0;
749 int selected_poly_count = 0;
750 for (
const int i_other_poly : polys) {
751 if (poly_selection_array[i_other_poly]) {
752 selected_poly_count++;
753 i_selected_poly = i_other_poly;
756 deselected_poly_count++;
760 if (selected_poly_count == 1) {
763 boundary_edge_indices.
add_new(i_edge);
764 edge_extruded_face_indices.
append(i_selected_poly);
766 else if (selected_poly_count > 1) {
768 if (deselected_poly_count > 0) {
770 new_inner_edge_indices.
add_new(i_edge);
775 inner_edge_indices.
append(i_edge);
783 const int extruded_vert_size = new_vert_indices.
size();
786 for (
const int i_edge : new_inner_edge_indices) {
788 new_vert_indices.
add(edge.v1);
789 new_vert_indices.
add(edge.v2);
793 const IndexRange new_vert_range{orig_vert_size, new_vert_indices.
size()};
795 const IndexRange connect_edge_range{orig_edges.
size(), extruded_vert_size};
797 const IndexRange boundary_edge_range = connect_edge_range.
after(boundary_edge_indices.
size());
799 const IndexRange new_inner_edge_range = boundary_edge_range.
after(new_inner_edge_indices.
size());
803 const IndexRange side_loop_range{orig_loops.
size(), side_poly_range.size() * 4};
806 new_vert_range.
size(),
807 connect_edge_range.size() + boundary_edge_range.
size() + new_inner_edge_range.
size(),
808 side_poly_range.size(),
809 side_loop_range.size());
822 connect_edges[i] =
new_edge(new_vert_indices[i], new_vert_range[i]);
827 const MEdge &orig_edge = edges[boundary_edge_indices[i]];
828 const int i_new_vert_1 = new_vert_indices.
index_of(orig_edge.
v1);
829 const int i_new_vert_2 = new_vert_indices.
index_of(orig_edge.
v2);
830 boundary_edges[i] =
new_edge(new_vert_range[i_new_vert_1], new_vert_range[i_new_vert_2]);
834 for (
const int i : new_inner_edge_indices.
index_range()) {
835 const MEdge &orig_edge = edges[new_inner_edge_indices[i]];
836 const int i_new_vert_1 = new_vert_indices.
index_of(orig_edge.
v1);
837 const int i_new_vert_2 = new_vert_indices.
index_of(orig_edge.
v2);
838 new_inner_edges[i] =
new_edge(new_vert_range[i_new_vert_1], new_vert_range[i_new_vert_2]);
843 new_polys[i] =
new_poly(side_loop_range[i * 4], 4);
847 for (
const int i : inner_edge_indices) {
848 MEdge &edge = edges[i];
849 const int i_new_vert_1 = new_vert_indices.
index_of_try(edge.v1);
850 const int i_new_vert_2 = new_vert_indices.
index_of_try(edge.v2);
851 if (i_new_vert_1 != -1) {
852 edge.v1 = new_vert_range[i_new_vert_1];
854 if (i_new_vert_2 != -1) {
855 edge.v2 = new_vert_range[i_new_vert_2];
860 for (
const int i_poly : poly_selection) {
861 const MPoly &poly = polys[i_poly];
863 const int i_new_vert = new_vert_indices.
index_of_try(loop.v);
864 if (i_new_vert != -1) {
865 loop.v = new_vert_range[i_new_vert];
867 const int i_boundary_edge = boundary_edge_indices.
index_of_try(loop.e);
868 if (i_boundary_edge != -1) {
869 loop.e = boundary_edge_range[i_boundary_edge];
873 const int i_new_inner_edge = new_inner_edge_indices.
index_of_try(loop.e);
874 if (i_new_inner_edge != -1) {
875 loop.e = new_inner_edge_range[i_new_inner_edge];
881 for (
const int i : boundary_edge_indices.
index_range()) {
882 const MEdge &boundary_edge = boundary_edges[i];
883 const int new_vert_1 = boundary_edge.
v1;
884 const int new_vert_2 = boundary_edge.
v2;
885 const int extrude_index_1 = new_vert_1 - orig_vert_size;
886 const int extrude_index_2 = new_vert_2 - orig_vert_size;
888 const MPoly &extrude_poly = polys[edge_extruded_face_indices[i]];
891 new_loops.
slice(4 * i, 4),
894 new_vert_indices[extrude_index_1],
895 new_vert_indices[extrude_index_2],
896 boundary_edge_range[i],
897 connect_edge_range[extrude_index_1],
898 boundary_edge_indices[i],
899 connect_edge_range[extrude_index_2]);
906 new_vert_range.size(), boundary_edges, orig_vert_size);
918 using T = decltype(dummy);
919 MutableSpan<T> data = attribute.span.typed<T>();
920 switch (attribute.domain) {
921 case ATTR_DOMAIN_POINT: {
923 copy_with_indices(data.slice(new_vert_range), data.as_span(), new_vert_indices);
926 case ATTR_DOMAIN_EDGE: {
928 MutableSpan<T> boundary_data = data.slice(boundary_edge_range);
929 copy_with_indices(boundary_data, data.as_span(), boundary_edge_indices);
932 MutableSpan<T> new_inner_data = data.slice(new_inner_edge_range);
933 copy_with_indices(new_inner_data, data.as_span(), new_inner_edge_indices);
936 MutableSpan<T> connect_data = data.slice(connect_edge_range);
937 copy_with_mixing(connect_data, boundary_data.as_span(), [&](const int i) {
938 return new_vert_to_duplicate_edge_map[i].as_span();
942 case ATTR_DOMAIN_FACE: {
946 data.slice(side_poly_range), data.as_span(), edge_extruded_face_indices);
949 case ATTR_DOMAIN_CORNER: {
951 MutableSpan<T> new_data = data.slice(side_loop_range);
952 threading::parallel_for(
953 boundary_edge_indices.index_range(), 256, [&](const IndexRange range) {
954 for (const int i_boundary_edge : range) {
955 const MPoly &poly = polys[edge_extruded_face_indices[i_boundary_edge]];
957 const MEdge &boundary_edge = boundary_edges[i_boundary_edge];
958 const int new_vert_1 = boundary_edge.v1;
959 const int new_vert_2 = boundary_edge.v2;
960 const int orig_vert_1 = new_vert_indices[new_vert_1 - orig_vert_size];
961 const int orig_vert_2 = new_vert_indices[new_vert_2 - orig_vert_size];
970 for (const int i_loop : IndexRange(poly.loopstart, poly.totloop)) {
971 if (loops[i_loop].v == new_vert_1) {
972 data_1 = data[i_loop];
974 if (loops[i_loop].v == new_vert_2) {
975 data_2 = data[i_loop];
982 for (const int i : IndexRange(4 * i_boundary_edge, 4)) {
983 if (ELEM(new_loops[i].v, new_vert_1, orig_vert_1)) {
984 new_data[i] = data_1;
986 else if (ELEM(new_loops[i].v, new_vert_2, orig_vert_2)) {
987 new_data[i] = data_2;
995 BLI_assert_unreachable();
1006 if (poly_offsets.is_single()) {
1007 const float3 offset = poly_offsets.get_internal_single();
1010 for (const int i_orig : all_selected_verts.as_span().slice(range)) {
1011 const int i_new = new_vert_indices.index_of_try(i_orig);
1012 MVert &vert = mesh_verts(mesh)[(i_new == -1) ? i_orig : new_vert_range[i_new]];
1013 add_v3_v3(vert.co, offset);
1019 IndexRange(all_selected_verts.size()), 1024, [&](
const IndexRange range) {
1020 for (const int i_orig : all_selected_verts.as_span().slice(range)) {
1021 const int i_new = new_vert_indices.index_of_try(i_orig);
1022 const float3 offset = vert_offsets[i_orig];
1023 MVert &vert = mesh_verts(mesh)[(i_new == -1) ? i_orig : new_vert_range[i_new]];
1024 add_v3_v3(vert.co, offset);
1033 edge_orig_indices.slice(connect_edge_range).fill(
ORIGINDEX_NONE);
1034 edge_orig_indices.slice(new_inner_edge_range).fill(
ORIGINDEX_NONE);
1035 edge_orig_indices.slice(boundary_edge_range).fill(
ORIGINDEX_NONE);
1040 if (attribute_outputs.top_id) {
1044 if (attribute_outputs.side_id) {
1055 const int offset = offsets[index];
1056 const int next_offset = offsets[index + 1];
1076 poly_evaluator.set_selection(selection_field);
1077 poly_evaluator.add_with_destination(offset_field, poly_offset.
as_mutable_span());
1078 poly_evaluator.evaluate();
1079 const IndexMask poly_selection = poly_evaluator.get_evaluated_selection_as_mask();
1084 int extrude_corner_size = 0;
1086 for (
const int i_selection : poly_selection.
index_range()) {
1087 const MPoly &poly = orig_polys[poly_selection[i_selection]];
1088 index_offsets[i_selection] = extrude_corner_size;
1089 extrude_corner_size += poly.
totloop;
1091 index_offsets.
last() = extrude_corner_size;
1093 const IndexRange new_vert_range{orig_vert_size, extrude_corner_size};
1095 const IndexRange connect_edge_range{orig_edge_size, extrude_corner_size};
1097 const IndexRange duplicate_edge_range = connect_edge_range.
after(extrude_corner_size);
1100 const IndexRange side_loop_range{orig_loops.
size(), side_poly_range.size() * 4};
1103 new_vert_range.
size(),
1104 connect_edge_range.size() + duplicate_edge_range.
size(),
1105 side_poly_range.size(),
1106 side_loop_range.size());
1120 for (const int i_selection : range) {
1121 const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection);
1123 const MPoly &poly = polys[poly_selection[i_selection]];
1124 Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
1126 for (const int i : IndexRange(poly.totloop)) {
1127 const int i_next = (i == poly.totloop - 1) ? 0 : i + 1;
1128 const MLoop &orig_loop = poly_loops[i];
1129 const MLoop &orig_loop_next = poly_loops[i_next];
1131 const int i_extrude = poly_corner_range[i];
1132 const int i_extrude_next = poly_corner_range[i_next];
1134 const int i_duplicate_edge = duplicate_edge_range[i_extrude];
1135 const int new_vert = new_vert_range[i_extrude];
1136 const int new_vert_next = new_vert_range[i_extrude_next];
1138 const int orig_edge = orig_loop.e;
1140 const int orig_vert = orig_loop.v;
1141 const int orig_vert_next = orig_loop_next.v;
1143 duplicate_edges[i_extrude] = new_edge(new_vert, new_vert_next);
1145 new_polys[i_extrude] = new_poly(side_loop_range[i_extrude * 4], 4);
1147 MutableSpan<MLoop> side_loops = loops.slice(side_loop_range[i_extrude * 4], 4);
1148 side_loops[0].v = new_vert_next;
1149 side_loops[0].e = i_duplicate_edge;
1150 side_loops[1].v = new_vert;
1151 side_loops[1].e = connect_edge_range[i_extrude];
1152 side_loops[2].v = orig_vert;
1153 side_loops[2].e = orig_edge;
1154 side_loops[3].v = orig_vert_next;
1155 side_loops[3].e = connect_edge_range[i_extrude_next];
1157 connect_edges[i_extrude] = new_edge(orig_vert, new_vert);
1172 using T = decltype(dummy);
1173 MutableSpan<T> data = attribute.span.typed<T>();
1174 switch (attribute.domain) {
1175 case ATTR_DOMAIN_POINT: {
1177 MutableSpan<T> new_data = data.slice(new_vert_range);
1179 threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) {
1180 for (const int i_selection : range) {
1181 const MPoly &poly = polys[poly_selection[i_selection]];
1182 Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
1184 const int corner_offset = index_offsets[i_selection];
1185 for (const int i : poly_loops.index_range()) {
1186 const int orig_index = poly_loops[i].v;
1187 new_data[corner_offset + i] = data[orig_index];
1193 case ATTR_DOMAIN_EDGE: {
1194 MutableSpan<T> duplicate_data = data.slice(duplicate_edge_range);
1195 MutableSpan<T> connect_data = data.slice(connect_edge_range);
1197 threading::parallel_for(poly_selection.index_range(), 512, [&](const IndexRange range) {
1198 for (const int i_selection : range) {
1199 const MPoly &poly = polys[poly_selection[i_selection]];
1200 Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
1202 const IndexRange poly_corner_range = selected_corner_range(index_offsets,
1206 for (const int i : poly_loops.index_range()) {
1207 const int orig_index = poly_loops[i].e;
1208 duplicate_data[poly_corner_range[i]] = data[orig_index];
1213 for (const int i : poly_loops.index_range()) {
1214 const int i_loop_prev = (i == 0) ? poly.totloop - 1 : i - 1;
1215 const int orig_index = poly_loops[i].e;
1216 const int orig_index_prev = poly_loops[i_loop_prev].e;
1217 if constexpr (std::is_same_v<T, bool>) {
1219 connect_data[poly_corner_range[i]] = data[orig_index] || data[orig_index_prev];
1222 connect_data[poly_corner_range[i]] = attribute_math::mix2(
1223 0.5f, data[orig_index], data[orig_index_prev]);
1230 case ATTR_DOMAIN_FACE: {
1232 MutableSpan<T> new_data = data.slice(side_poly_range);
1233 threading::parallel_for(poly_selection.index_range(), 1024, [&](const IndexRange range) {
1234 for (const int i_selection : range) {
1235 const int poly_index = poly_selection[i_selection];
1236 const IndexRange poly_corner_range = selected_corner_range(index_offsets,
1238 new_data.slice(poly_corner_range).fill(data[poly_index]);
1243 case ATTR_DOMAIN_CORNER: {
1246 MutableSpan<T> new_data = data.slice(side_loop_range);
1247 threading::parallel_for(poly_selection.index_range(), 256, [&](const IndexRange range) {
1248 for (const int i_selection : range) {
1249 const MPoly &poly = polys[poly_selection[i_selection]];
1250 Span<T> poly_loop_data = data.slice(poly.loopstart, poly.totloop);
1251 const IndexRange poly_corner_range = selected_corner_range(index_offsets,
1254 for (const int i : IndexRange(poly.totloop)) {
1255 const int i_next = (i == poly.totloop - 1) ? 0 : i + 1;
1256 const int i_extrude = poly_corner_range[i];
1258 MutableSpan<T> side_loop_data = new_data.slice(i_extrude * 4, 4);
1263 side_loop_data[0] = poly_loop_data[i_next];
1264 side_loop_data[1] = poly_loop_data[i];
1265 side_loop_data[2] = poly_loop_data[i];
1266 side_loop_data[3] = poly_loop_data[i_next];
1273 BLI_assert_unreachable();
1283 for (const int i_selection : range) {
1284 const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection);
1285 for (MVert &vert : new_verts.slice(poly_corner_range)) {
1286 add_v3_v3(vert.co, poly_offset[poly_selection[i_selection]]);
1295 edge_orig_indices.slice(connect_edge_range).fill(
ORIGINDEX_NONE);
1296 edge_orig_indices.slice(duplicate_edge_range).fill(
ORIGINDEX_NONE);
1305 for (const int i_selection : range) {
1306 const IndexRange poly_corner_range = selected_corner_range(index_offsets, i_selection);
1308 const MPoly &poly = polys[poly_selection[i_selection]];
1309 MutableSpan<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
1311 for (const int i : IndexRange(poly.totloop)) {
1312 MLoop &loop = poly_loops[i];
1313 loop.v = new_vert_range[poly_corner_range[i]];
1314 loop.e = duplicate_edge_range[poly_corner_range[i]];
1319 if (attribute_outputs.top_id) {
1323 if (attribute_outputs.side_id) {
1346 std::shared_ptr<FieldOperation> multiply_op = std::make_shared<FieldOperation>(
1347 FieldOperation(multiply_fn, {std::move(offset_field), std::move(scale_field)}));
1351 if (
params.output_is_required(
"Top")) {
1354 if (
params.output_is_required(
"Side")) {
1359 params.extract_input<
bool>(
"Individual");
1372 if (extrude_individual) {
1386 params.set_output(
"Mesh", std::move(geometry_set));
1387 if (attribute_outputs.
top_id) {
1389 AnonymousAttributeFieldInput::Create<bool>(
1390 std::move(attribute_outputs.
top_id),
params.attribute_producer_name()));
1392 if (attribute_outputs.
side_id) {
1393 params.set_output(
"Side",
1394 AnonymousAttributeFieldInput::Create<bool>(
1395 std::move(attribute_outputs.
side_id),
params.attribute_producer_name()));
void * CustomData_get_layer(const struct CustomData *data, int type)
void CustomData_realloc(struct CustomData *data, int totelem)
void * CustomData_duplicate_referenced_layer(struct CustomData *data, int type, int totelem)
void CustomData_duplicate_referenced_layers(CustomData *data, int totelem)
@ GEO_COMPONENT_TYPE_MESH
bool BKE_mesh_is_valid(struct Mesh *me)
void BKE_mesh_update_customdata_pointers(struct Mesh *me, bool do_ensure_tess_cd)
void BKE_mesh_runtime_clear_cache(struct Mesh *mesh)
This function clears runtime cache of the given mesh.
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
#define NODE_STORAGE_FUNCS(StorageT)
#define GEO_NODE_EXTRUDE_MESH
void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available)
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
#define NODE_CLASS_GEOMETRY
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
void nodeRegisterType(struct bNodeType *ntype)
#define BLI_assert_unreachable()
static uint8 component(Color32 c, uint i)
GeometryNodeExtrudeMeshMode
@ GEO_NODE_EXTRUDE_MESH_FACES
@ GEO_NODE_EXTRUDE_MESH_VERTICES
@ GEO_NODE_EXTRUDE_MESH_EDGES
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
const T & last(const int64_t n=0) const
void reinitialize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
Span< int64_t > indices() const
IndexRange index_range() const
IndexRange as_range() const
constexpr int64_t size() const
constexpr IndexRange after(int64_t n) const
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr IndexRange index_range() const
constexpr Span slice(int64_t start, int64_t size) const
constexpr const T & first() const
constexpr int64_t size() const
constexpr IndexRange index_range() const
Span< Key > as_span() const
int64_t index_of(const Key &key) const
void reserve(const int64_t n)
void add_new(const Key &key)
int64_t index_of_try(const Key &key) const
IndexRange index_range() const
void append(const T &value)
int domain_size(const eAttrDomain domain) const
bool for_all(const AttributeForeachCallback fn) const
GSpanAttributeWriter lookup_or_add_for_write_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefault())
SyclQueue void void * src
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
ccl_gpu_kernel_postfix int ccl_global int * indices
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
typename DefaultPropatationMixerStruct< T >::type DefaultPropatationMixer
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
AttributeAccessor mesh_attributes(const Mesh &mesh)
OwnedAnonymousAttributeID< true > StrongAnonymousAttributeID
static void duplicate_edges(GeometrySet &geometry_set, const Field< int > &count_field, const Field< bool > &selection_field, const IndexAttributes &attribute_outputs)
static VectorSet< int > vert_indices_from_edges(const Mesh &mesh, const Span< T > edge_indices)
static MutableSpan< MLoop > mesh_loops(Mesh &mesh)
static CustomData & get_customdata(Mesh &mesh, const eAttrDomain domain)
static void node_declare(NodeDeclarationBuilder &b)
static MutableSpan< MEdge > mesh_edges(Mesh &mesh)
static Span< MLoop > mesh_loops(const Mesh &mesh)
static Span< MPoly > mesh_polys(const Mesh &mesh)
static void save_selection_as_attribute(MeshComponent &component, const AnonymousAttributeID *id, const eAttrDomain domain, const IndexMask selection)
static MEdge new_loose_edge(const int v1, const int v2)
void copy_with_mixing(MutableSpan< T > dst, Span< T > src, GetMixIndicesFn get_mix_indices_fn)
static void fill_quad_consistent_direction(Span< MLoop > other_poly_loops, MutableSpan< MLoop > new_loops, const int vert_connected_to_poly_1, const int vert_connected_to_poly_2, const int vert_across_from_poly_1, const int vert_across_from_poly_2, const int edge_connected_to_poly, const int connecting_edge_1, const int edge_across_from_poly, const int connecting_edge_2)
static void extrude_mesh_vertices(MeshComponent &component, const Field< bool > &selection_field, const Field< float3 > &offset_field, const AttributeOutputs &attribute_outputs)
static Array< Vector< int, 2 > > mesh_calculate_polys_of_edge(const Mesh &mesh)
static IndexRange selected_corner_range(Span< int > offsets, const int index)
void copy_with_indices(MutableSpan< T > dst, Span< T > src, Span< int > indices)
static void expand_mesh(Mesh &mesh, const int vert_expand, const int edge_expand, const int poly_expand, const int loop_expand)
static MutableSpan< MPoly > mesh_polys(Mesh &mesh)
static MutableSpan< MVert > mesh_verts(Mesh &mesh)
static void extrude_mesh_edges(MeshComponent &component, const Field< bool > &selection_field, const Field< float3 > &offset_field, const AttributeOutputs &attribute_outputs)
static void node_update(bNodeTree *ntree, bNode *node)
static Array< Vector< int > > create_vert_to_edge_map(const int vert_size, Span< MEdge > edges, const int vert_offset=0)
static MutableSpan< int > get_orig_index_layer(Mesh &mesh, const eAttrDomain domain)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
void copy_with_mask(MutableSpan< T > dst, Span< T > src, IndexMask mask)
static void node_geo_exec(GeoNodeExecParams params)
static void extrude_mesh_face_regions(MeshComponent &component, const Field< bool > &selection_field, const Field< float3 > &offset_field, const AttributeOutputs &attribute_outputs)
static MPoly new_poly(const int loopstart, const int totloop)
static void extrude_individual_mesh_faces(MeshComponent &component, const Field< bool > &selection_field, const Field< float3 > &offset_field, const AttributeOutputs &attribute_outputs)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static MEdge new_edge(const int v1, const int v2)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
void devirtualize_varray(const VArray< T > &varray, const Func &func, bool enable=true)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
void register_node_type_geo_extrude_mesh()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
void node_free_standard_storage(bNode *node)
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
void modify_geometry_sets(ForeachSubGeometryCallback callback)
NodeGeometryExecFunction geometry_node_execute
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
NodeDeclareFunction declare
StrongAnonymousAttributeID top_id
StrongAnonymousAttributeID side_id