Cogs.Core
IndexConversion.cpp
1#include "IndexConversion.h"
2
3// Cogs.js (EMSCRIPTEN) cannot use binary libraries from ZipMan, so it needs to compile all from sources, Libtess2 in this case
4// When built from source, tesselator.h is inside the "Include" folder in Libtess2 source tree (added as a project search path)
5// Using ZipMan binaries, it is located at "xxx/include/libtess2/tesselator.h" with "xxx/include" in the search path
6#ifdef EMSCRIPTEN
7 #include "tesselator.h"
8#else
9 #include "libtess2/tesselator.h"
10#endif
11
12#include "Resources/Mesh.h"
13
14namespace Cogs {
15 // Wraps a position-index pair to be able to sort/reindex by tesselator and
16 // get original index back.
18 {
19 glm::vec3 position;
20 int32_t index = 0;
21 };
22}
23
24void Cogs::Core::tesselate(const glm::vec3* contours,
25 const size_t count,
26 const size_t stride,
27 std::vector<uint32_t>& triangleIndexes,
28 uint32_t base) {
29 const int polySize = 3;
30 TESStesselator* tess = tessNewTess(nullptr);
31
32 tessAddContour(tess, polySize, contours, static_cast<int>(stride), static_cast<int>(count));
33
34 if (!tessTesselate(tess, TESS_WINDING_POSITIVE, TESS_POLYGONS, 3, 3, nullptr)) {
35 return;
36 }
37
38 const int elementCount = tessGetElementCount(tess);
39 const auto elements = tessGetElements(tess);
40 const auto indexes = tessGetVertexIndices(tess);
41
42 triangleIndexes.reserve(base + elementCount * polySize);
43
44 for (int i = 0; i < elementCount; ++i) {
45 const auto poly = &elements[i * polySize];
46
47 bool valid = true;
48 uint32_t polyIndexes[polySize];
49
50 for (int j = 0; j < polySize; ++j) {
51 const TESSindex index = indexes[poly[j]];
52
53 valid &= (index >= 0) && ((size_t)index < count);
54
55 polyIndexes[j] = base + static_cast<uint32_t>(index);
56 }
57
58 if (valid) {
59 triangleIndexes.insert(triangleIndexes.end(), std::begin(polyIndexes), std::end(polyIndexes));
60 }
61 }
62
63 tessDeleteTess(tess);
64}
65
66std::vector<int32_t> Cogs::Core::tesselatePolygons(std::vector<int32_t> & inputIndexes, Mesh * mesh)
67{
68 if (inputIndexes.size()) {
69 std::vector<uint32_t> indexes;
70 size_t currentIndex = 0;
71
72 auto addPolygon = [&](size_t base, size_t numVertexes)
73 {
74 auto [data, count, stride] = mesh->getPositionStream();
75
76 std::vector<IndexedPosition> positions(numVertexes);
77
78 for (size_t i = 0; i < numVertexes; ++i) {
79 const uint32_t index = inputIndexes[base + i];
80 assert(index < count && "Vertex index out of bounds.");
81 positions[i].index = index;
82 positions[i].position = *reinterpret_cast<glm::vec3 *>(data + index * stride);
83 }
84
85 std::vector<uint32_t> positionIndexes;
86 tesselate(reinterpret_cast<const glm::vec3 *>(positions.data()), numVertexes, sizeof(IndexedPosition), positionIndexes);
87
88 for (size_t i = 0; i < positionIndexes.size(); ++i) {
89 indexes.push_back(positions[positionIndexes[i]].index);
90 }
91
92 currentIndex = indexes.size();
93 };
94
95 size_t idx = 0;
96 while (idx < inputIndexes.size()) {
97 const size_t base = idx;
98
99 while (inputIndexes[idx++] != -1 && idx < inputIndexes.size()) {}
100
101 size_t numVertexes = idx - base - 1;
102
103 addPolygon(base, numVertexes);
104 }
105
106 std::vector<int32_t> output((indexes.size() / 3) * 4);
107
108 for (size_t i = 0; i < indexes.size() / 3; ++i) {
109 output[i * 4 + 0] = indexes[i * 3 + 0];
110 output[i * 4 + 1] = indexes[i * 3 + 1];
111 output[i * 4 + 2] = indexes[i * 3 + 2];
112 output[i * 4 + 3] = -1;
113 }
114
115 return output;
116 }
117
118 return std::vector<int32_t>();
119}
120
121void Cogs::Core::reindex(const std::vector<int32_t> & inputIndexes, Mesh * mesh, bool isLine)
122{
123 if (inputIndexes.size()) {
124 std::vector<uint32_t> indexes;
125 size_t currentIndex = 0;
126
127 if (!isLine) {
128
129 auto addTriangle = [&](size_t base)
130 {
131 indexes.resize(indexes.size() + 3);
132 indexes[currentIndex++] = inputIndexes[base];
133 indexes[currentIndex++] = inputIndexes[base + 1];
134 indexes[currentIndex++] = inputIndexes[base + 2];
135 };
136
137 auto addQuad = [&](size_t base)
138 {
139 indexes.resize(indexes.size() + 6);
140 indexes[currentIndex++] = inputIndexes[base];
141 indexes[currentIndex++] = inputIndexes[base + 1];
142 indexes[currentIndex++] = inputIndexes[base + 2];
143
144 indexes[currentIndex++] = inputIndexes[base];
145 indexes[currentIndex++] = inputIndexes[base + 2];
146 indexes[currentIndex++] = inputIndexes[base + 3];
147 };
148
149 auto addPolygon = [&](size_t base, size_t numVertexes)
150 {
151 auto [data, count, stride] = mesh->getPositionStream();
152
153 std::vector<IndexedPosition> positions(numVertexes);
154
155 for (size_t i = 0; i < numVertexes; ++i) {
156 const uint32_t index = inputIndexes[base + i];
157 assert(index < count && "Vertex index out of bounds.");
158 positions[i].index = index;
159 positions[i].position = *reinterpret_cast<glm::vec3 *>(data + index * stride);
160 }
161
162 std::vector<uint32_t> positionIndexes;
163 tesselate(reinterpret_cast<const glm::vec3 *>(positions.data()), numVertexes, sizeof(IndexedPosition), positionIndexes);
164
165 for (size_t i = 0; i < positionIndexes.size(); ++i) {
166 indexes.push_back(positions[positionIndexes[i]].index);
167 }
168
169 currentIndex = indexes.size();
170 };
171
172 size_t idx = 0;
173 while (idx < inputIndexes.size()) {
174 const size_t base = idx;
175
176 while (inputIndexes[idx++] != -1 && idx < inputIndexes.size()) {}
177
178 size_t numVertexes = idx - base - 1;
179
180 if (numVertexes == 3) {
181 addTriangle(base);
182 } else if (numVertexes == 4) {
183 addQuad(base);
184 } else {
185 addPolygon(base, numVertexes);
186 }
187 }
188 } else {
189 for (size_t i = 0; i < inputIndexes.size() - 1; ++i) {
190 if (inputIndexes[i] != -1 && inputIndexes[i + 1] != -1) {
191 indexes.push_back(inputIndexes[i]);
192 indexes.push_back(inputIndexes[i + 1]);
193 }
194 }
195
196 mesh->primitiveType = PrimitiveType::LineList;
197 }
198
199 mesh->setIndexData(indexes.data(), indexes.size());
200 }
201}
Contains all Cogs related functionality.
Definition: FieldSetter.h:23