libs/core/src/eu/core/geom.extract.cc
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "eu/core/geom.h" | ||
| 2 | |||
| 3 | #include "eu/assert/assert.h" | ||
| 4 | #include "eu/base/cint.h" | ||
| 5 | |||
| 6 | #include "eu/core/geom.extract.h" | ||
| 7 | #include "eu/core/vertex_layout.h" | ||
| 8 | |||
| 9 | #include <numeric> | ||
| 10 | |||
| 11 | namespace eu::core | ||
| 12 | { | ||
| 13 | |||
| 14 | using ByteBuffer = std::vector<char>; | ||
| 15 | |||
| 16 | ✗ | std::vector<u32> compile_indices(const Geom& geom) | |
| 17 | { | ||
| 18 | ✗ | std::vector<u32> indices; | |
| 19 | ✗ | const auto push = [&indices](const u32 i) | |
| 20 | { | ||
| 21 | ✗ | indices.emplace_back(i); | |
| 22 | ✗ | }; | |
| 23 | ✗ | for (const auto& f: geom.faces) | |
| 24 | { | ||
| 25 | ✗ | push(f.a); | |
| 26 | ✗ | push(f.b); | |
| 27 | ✗ | push(f.c); | |
| 28 | } | ||
| 29 | ✗ | return indices; | |
| 30 | ✗ | } | |
| 31 | |||
| 32 | ✗ | void push_float(ByteBuffer* vv, float f) | |
| 33 | { | ||
| 34 | // todo(Gustav): is this safe? | ||
| 35 | union | ||
| 36 | { | ||
| 37 | float f; | ||
| 38 | char bytes[4]; | ||
| 39 | ✗ | } convert {}; | |
| 40 | |||
| 41 | ✗ | convert.f = f; | |
| 42 | ✗ | for (int byte_index = 0; byte_index < 4; byte_index += 1) | |
| 43 | { | ||
| 44 | ✗ | vv->emplace_back(convert.bytes[byte_index]); | |
| 45 | } | ||
| 46 | ✗ | } | |
| 47 | |||
| 48 | ✗ | void push2(ByteBuffer* vv, const v2& p) | |
| 49 | { | ||
| 50 | ✗ | push_float(vv, p.x); | |
| 51 | ✗ | push_float(vv, p.y); | |
| 52 | ✗ | } | |
| 53 | |||
| 54 | ✗ | void push3(ByteBuffer* vv, const v3& p) | |
| 55 | { | ||
| 56 | ✗ | push_float(vv, p.x); | |
| 57 | ✗ | push_float(vv, p.y); | |
| 58 | ✗ | push_float(vv, p.z); | |
| 59 | ✗ | } | |
| 60 | |||
| 61 | ✗ | void push4(ByteBuffer* vv, const v4& p) | |
| 62 | { | ||
| 63 | ✗ | push_float(vv, p.x); | |
| 64 | ✗ | push_float(vv, p.y); | |
| 65 | ✗ | push_float(vv, p.z); | |
| 66 | ✗ | push_float(vv, p.w); | |
| 67 | ✗ | } | |
| 68 | |||
| 69 | struct BufferData | ||
| 70 | { | ||
| 71 | using PerVertex = void (*)(ByteBuffer*, const Vertex&); | ||
| 72 | |||
| 73 | std::vector<ExtractedAttribute> attributes; | ||
| 74 | std::vector<PerVertex> per_vertex; | ||
| 75 | }; | ||
| 76 | |||
| 77 | ✗ | ExtractedGeom extract_geom(const Geom& geom, const CompiledGeomVertexAttributes& layout) | |
| 78 | { | ||
| 79 | ✗ | const auto indices = compile_indices(geom); | |
| 80 | |||
| 81 | ✗ | const BufferData attribute_descriptions = [&]() | |
| 82 | { | ||
| 83 | ✗ | auto data = BufferData{}; | |
| 84 | ✗ | data.attributes.reserve(layout.elements.size()); | |
| 85 | ✗ | data.per_vertex.reserve(layout.elements.size()); | |
| 86 | |||
| 87 | ✗ | for (const auto& element: layout.elements) | |
| 88 | { | ||
| 89 | ✗ | switch (element.type) | |
| 90 | { | ||
| 91 | #define MAP(VT, PROP, COUNT) \ | ||
| 92 | case VT: \ | ||
| 93 | data.attributes.emplace_back(ExtractedAttribute{ExtractedAttributeType::Float, COUNT, sizeof(float) * (COUNT)}); \ | ||
| 94 | data.per_vertex.emplace_back([](ByteBuffer* vertices, const Vertex& vertex) { push##COUNT(vertices, PROP); }); \ | ||
| 95 | break | ||
| 96 | ✗ | MAP(VertexType::position2xy, (v2{vertex.position.x, vertex.position.y}), 2); | |
| 97 | ✗ | MAP(VertexType::position2xz, (v2{vertex.position.x, vertex.position.z}), 2); | |
| 98 | ✗ | MAP(VertexType::position3, vertex.position, 3); | |
| 99 | ✗ | MAP(VertexType::normal3, vertex.normal, 3); | |
| 100 | ✗ | MAP(VertexType::color3, vertex.color, 3); | |
| 101 | ✗ | MAP(VertexType::color4, v4(vertex.color, 1.0f), 4); | |
| 102 | ✗ | MAP(VertexType::texture2, vertex.uv, 2); | |
| 103 | #undef MAP | ||
| 104 | ✗ | case VertexType::instance_transform: | |
| 105 | ✗ | DIE("can't use instance types for extraction"); | |
| 106 | ✗ | break; // todo(Gustav): should something else be done here? | |
| 107 | ✗ | default: DIE("Invalid buffer type"); break; | |
| 108 | } | ||
| 109 | } | ||
| 110 | ✗ | return data; | |
| 111 | ✗ | }(); | |
| 112 | |||
| 113 | ✗ | const std::size_t bytes_per_vertex = std::accumulate( | |
| 114 | attribute_descriptions.attributes.begin(), | ||
| 115 | attribute_descriptions.attributes.end(), | ||
| 116 | static_cast<std::size_t>(0), | ||
| 117 | ✗ | [](std::size_t s, const ExtractedAttribute& d) -> std::size_t { return s + d.size; } | |
| 118 | ✗ | ); | |
| 119 | ✗ | const auto vertices = [&]() | |
| 120 | { | ||
| 121 | ✗ | auto verts = ByteBuffer{}; | |
| 122 | ✗ | verts.reserve(geom.vertices.size() * bytes_per_vertex); | |
| 123 | ✗ | for (const auto& vertex: geom.vertices) | |
| 124 | { | ||
| 125 | ✗ | for (const auto& per_vertex: attribute_descriptions.per_vertex) | |
| 126 | { | ||
| 127 | ✗ | per_vertex(&verts, vertex); | |
| 128 | } | ||
| 129 | } | ||
| 130 | ✗ | return verts; | |
| 131 | ✗ | }(); | |
| 132 | |||
| 133 | ✗ | const auto face_size = static_cast<i32>(geom.faces.size()); | |
| 134 | |||
| 135 | ✗ | return {vertices, bytes_per_vertex, attribute_descriptions.attributes, indices, face_size}; | |
| 136 | ✗ | } | |
| 137 | |||
| 138 | } // namespace eu::core | ||
| 139 |