Exists so the kernel has an oracle: identical spans, spec and view must produce identical bytes on both paths. Secondarily a route for a caller with no compute queue available. Not a general geometry utility, and not intended for per-frame use at scale.
871{
872 auto result = layout;
875
876 MillOffsets off;
877 if (!offsets_from(layout, off)) {
878 return result;
879 }
880
881 std::vector<uint32_t> prefix;
882 build_prefix(runs, prefix);
883 const uint32_t
total = prefix.empty() ? 0U : prefix.back();
885 return result;
886 }
887
889 result.vertex_count =
total;
890
891 const HostRecords rec {
892 .src =
reinterpret_cast<const uint32_t*
>(
src.data()),
893 .
dst =
reinterpret_cast<uint32_t*
>(
dst.data()),
895 };
896
897 const bool world_plane = spec.
ribbon == MillSpec::Ribbon::WorldPlane;
899
900 for (size_t r = 0; r < runs.size(); ++r) {
901 const auto&
run = runs[r];
902 const uint32_t emitted = prefix[r + 1] - prefix[r];
903 const uint32_t base = prefix[r];
904 const uint32_t voff =
run.vertex_offset;
905
906 for (uint32_t local = 0; local < emitted; ++local) {
907 const uint32_t
out = base + local;
908
909 if (
run.topology == PrimitiveTopology::TRIANGLE_LIST) {
910 rec.copy_vertex(
out, voff + local);
911 continue;
912 }
913
914 if (
run.topology == PrimitiveTopology::TRIANGLE_STRIP
915 ||
run.topology == PrimitiveTopology::TRIANGLE_FAN) {
916 const uint32_t tri = local / 3U;
917 const uint32_t c = local - tri * 3U;
919 uint32_t b1 = tri + 1U;
920 uint32_t b2 = tri + 2U;
921 if (
run.topology == PrimitiveTopology::TRIANGLE_STRIP) {
923 if ((tri & 1U) == 1U) {
925 }
926 }
927 const uint32_t pick = c == 0
U ?
a : (c == 1U ? b1 : b2);
928 rec.copy_vertex(
out, voff + pick);
929 continue;
930 }
931
932 const uint32_t corner = local % 6U;
933 const uint32_t quad = local / 6U;
934
935 if (
run.topology == PrimitiveTopology::POINT_LIST) {
936 const uint32_t s = voff + quad;
937 const glm::vec3 p = rec.read_pos(s, off.position);
940
941 glm::vec3 rx;
942 glm::vec3 ry;
943 if (world_plane) {
944 rx = glm::vec3(
h, 0.0F, 0.0F);
945 ry = glm::vec3(0.0F,
h, 0.0F);
946 } else {
947 const glm::vec3 n = host_view_normal(p, view.
eye);
948 const glm::vec3 up = std::abs(n.y) < 0.99F
949 ? glm::vec3(0.0F, 1.0F, 0.0F)
950 : glm::
vec3(1.0F, 0.0F, 0.0F);
951 rx = glm::normalize(glm::cross(up, n)) *
h;
952 ry = glm::normalize(glm::cross(n, rx)) *
h;
953 }
954
955 glm::vec3 o;
957 switch (corner) {
958 case 1:
959 o = rx - ry;
961 break;
962 case 2:
963 case 4:
964 o = rx + ry;
966 break;
967 case 5:
968 o = -rx + ry;
970 break;
971 default:
972 o = -rx - ry;
974 break;
975 }
976
977 rec.copy_vertex(
out, s);
978 rec.write_pos(
out, off.position, p + o);
980 rec.write_uv(
out, off.uv,
uv);
981 }
982 continue;
983 }
984
985 const uint32_t s0 =
run.topology == PrimitiveTopology::LINE_LIST
986 ? voff + quad * 2U
987 : voff + quad;
988 const uint32_t s1 = s0 + 1U;
989
990 const glm::vec3 p0 = rec.read_pos(s0, off.position);
991 const glm::vec3 p1 = rec.read_pos(s1, off.position);
992 const glm::vec3 d = p1 - p0;
993
994 if (glm::length(d) < 1e-6F) {
995 rec.write_pos(
out, off.position, p0);
996 continue;
997 }
998
1003
1004 const glm::vec3 e0 = host_side_at(
1005 p0, d, view.
eye, h0, world_plane);
1006 const glm::vec3 e1 = host_side_at(
1007 p1, d, view.
eye, h1, world_plane);
1008
1009 glm::vec3 pos;
1010 uint32_t pick = s0;
1012 switch (corner) {
1013 case 1:
1014 pos = p0 + e0;
1015 uv = { 0.0F, 0.0F };
1016 break;
1017 case 2:
1018 case 4:
1019 pos = p1 + e1;
1020 pick = s1;
1021 uv = { 1.0F, 0.0F };
1022 break;
1023 case 5:
1024 pos = p1 - e1;
1025 pick = s1;
1026 uv = { 1.0F, 1.0F };
1027 break;
1028 default:
1029 pos = p0 - e0;
1030 uv = { 0.0F, 1.0F };
1031 break;
1032 }
1033
1034 rec.copy_vertex(
out, pick);
1035 rec.write_pos(
out, off.position, pos);
1037 rec.write_uv(
out, off.uv,
uv);
1038 }
1039 }
1040 }
1041
1042 return result;
1043}
std::vector< float > * out
uint32_t stride_bytes
Total bytes per vertex (stride in Vulkan terms) e.g., 3 floats (position) + 3 floats (normal) = 24 by...
uint32_t vertex_count
Total number of vertices in this buffer.
bool synthesize_uv
Write 0..1 across each ribbon and quad rather than copying source.
float fallback_extent
Extent used when the layout carries no scalar attribute.
float width_scale
World units of total ribbon width per unit of a vertex's scalar.
bool use_vertex_extent
Take ribbon width and point size from each vertex's own scalar (LineVertex::thickness,...
float point_scale
World units per unit of a vertex's own size, on point spans.