Avara3D 0.2.0
C++ API reference
IndexAccess.h
1//
2// IndexAccess.h
3// avara3d
4//
5// Created by Morgan Davis on 1/6/2026.
6// Copyright © 2026 Morgan K Davis. All rights reserved.
7//
8
9#ifndef AVARA3D_MESH_INDEXACCESS_H
10#define AVARA3D_MESH_INDEXACCESS_H
11
12#include <cstddef>
13#include <cstdint>
14#include <cstring>
15#include <optional>
16#include <span>
17#include <type_traits>
18#include <vector>
19
20#include "a3d/Assert.h"
21#include "a3d/mesh/IndexFormats.h"
22#include "a3d/mesh/MeshElement.h"
23#include "a3d/mesh/PrimitiveTopology.h"
24
25namespace a3d {
26
27 struct IndexStreamView {
28 const std::byte* base = nullptr;
29 uint32_t count = 0; // number of indices
30 IndexFormat format = IndexFormat::None;
31 };
32
33 struct IndexAccess {
34
35 static std::optional<IndexStreamView> GetIndexStreamView(const MeshElement& element);
36 static std::optional<IndexStreamView> GetIndexStreamView(const MeshElement& element,
37 IndexFormat expectedFormat);
38
39 // read as u32
40 static uint32_t ReadIndexU32(const IndexStreamView& v, uint32_t i);
41
42 // convenience: expand to U32 vector (useful for libs like VHACD, meshopt, etc.)
43 static void ExpandToU32(const IndexStreamView& v, std::vector<uint32_t>& out);
44
45 // expand indices to U32. if mesh is non-indexed, generate 0..vertexCount-1
46 // assumes triangles - vertexCount must be multiple of 3 for non-indexed
47 static void GetTrianglesU32(const MeshElement& element, std::vector<uint32_t>& out);
48
49 // triangle iteration - assumes triangles, 3 indices per face
50 template<class F>
51 static void ForEachTriangle(const MeshElement& element, F&& fn) {
52
53 A3D_ASSERT(element.topology() == PrimitiveTopology::Triangles);
54 if (element.topology() != PrimitiveTopology::Triangles) {
55 return;
56 }
57
58 auto vOpt = GetIndexStreamView(element);
59 if (vOpt) {
60 const auto v = *vOpt;
61
62 A3D_ASSERT((v.count % 3u) == 0u);
63 if ((v.count % 3u) != 0u) {
64 return; // release safety
65 }
66
67 for (uint32_t i = 0; (i + 2u) < v.count; i += 3u) {
68 const uint32_t a = ReadIndexU32(v, i + 0u);
69 const uint32_t b = ReadIndexU32(v, i + 1u);
70 const uint32_t c = ReadIndexU32(v, i + 2u);
71 fn(a, b, c);
72 }
73 return;
74 }
75
76 // non-indexed fallback: triangles are implicit (0,1,2), (3,4,5), ...
77 const uint32_t vcount = element.vertexCount();
78
79 A3D_ASSERT((vcount % 3u) == 0u);
80 if ((vcount % 3u) != 0u) {
81 return;
82 }
83
84 for (uint32_t i = 0; (i + 2u) < vcount; i += 3u) {
85 fn(i + 0u, i + 1u, i + 2u);
86 }
87 }
88 };
89
90}
91
92#endif // AVARA3D_MESH_INDEXACCESS_H