913{
914 u_segs = std::max(u_segs, 1U);
915 v_segs = std::max(v_segs, 1U);
916
917 std::vector<Kakshya::MeshVertex> verts;
918 std::vector<uint32_t> indices;
919 verts.reserve(uint32_t((u_segs + 1) * (v_segs + 1)));
920 indices.reserve(uint32_t(u_segs * v_segs * 6));
921
922 constexpr float eps = 1e-4F;
923
924 for (uint32_t row = 0; row <= v_segs; ++row) {
925 const float fv = static_cast<float>(row) / static_cast<float>(v_segs);
926 for (uint32_t col = 0; col <= u_segs; ++col) {
927 const float fu = static_cast<float>(col) / static_cast<float>(u_segs);
928
929 const glm::vec3 p = fn(fu, fv);
930 const glm::vec3 pu = fn(fu + eps, fv) - fn(fu - eps, fv);
931 const glm::vec3 pv = fn(fu, fv + eps) - fn(fu, fv - eps);
932 const glm::vec3 n = glm::normalize(glm::cross(pu, pv));
933
934 verts.push_back({
935 .position = p,
936 .uv = { fu, 1.0F - fv },
937 .normal = n,
938 });
939 }
940 }
941
942 const uint32_t stride = u_segs + 1;
943 for (uint32_t row = 0; row < v_segs; ++row) {
944 for (uint32_t col = 0; col < u_segs; ++col) {
945 const uint32_t
a = row * stride + col;
946 const uint32_t
b =
a + 1;
947 const uint32_t c =
a + stride;
948 const uint32_t d = c + 1;
949 indices.insert(indices.end(), { a, b, c, b, d, c });
950 }
951 }
952
953 auto data = Kakshya::MeshData::empty();
954 Kakshya::MeshInsertion ins(data.vertex_variant, data.index_variant);
955 ins.insert_flat(
956 std::span<const uint8_t>(reinterpret_cast<const uint8_t*>(verts.data()),
957 verts.size() * sizeof(Kakshya::MeshVertex)),
958 std::span<const uint32_t>(indices),
959 Kakshya::VertexLayout::for_meshes(sizeof(Kakshya::MeshVertex)));
960 data.layout = Kakshya::VertexLayout::for_meshes(sizeof(Kakshya::MeshVertex));
961 data.layout.vertex_count = static_cast<uint32_t>(verts.size());
962
963 return data;
964}