16 template<
class IndexType,
int maxSize>
19 typedef std::vector<IndexType> IndexVector;
26 if (currentSize == -1) {
27 auto indexVector =
reinterpret_cast<IndexVector *
>(&data);
28 indexVector->~IndexVector();
35 static_assert(maxSize *
sizeof(IndexType) >=
sizeof(IndexVector),
"No room for index vector.");
37 if (currentSize == maxSize) {
40 IndexType temp[maxSize];
42 std::memcpy(temp, data, maxSize *
sizeof(IndexType));
44 auto indexVector =
reinterpret_cast<IndexVector *
>(&data);
45 new (indexVector) IndexVector();
46 indexVector->assign(temp, temp + maxSize);
49 if (currentSize == -1) {
50 auto indexVector =
reinterpret_cast<IndexVector *
>(&data);
51 indexVector->push_back(index);
53 data[currentSize++] = index;
60 if (currentSize == -1) {
61 auto indexVector =
reinterpret_cast<const IndexVector *
>(&data);
63 assert(i < indexVector->
size() &&
"Index out of range.");
65 return (*indexVector)[i];
74 if (currentSize == -1) {
75 auto indexVector =
reinterpret_cast<const IndexVector *
>(&data);
76 return indexVector->size();
83 IndexType data[maxSize];
85 int8_t currentSize = 0;
88 typedef AdjacencyList_T<int32_t, 8> AdjacencyList;
93 template<
class IndexType,
class AdjacencyListType,
bool quads>
94 void generateAdjacencyInfo(
const size_t numFaces,
const IndexType * indices,
const size_t positionOffset, std::vector<AdjacencyListType> & adjacencyList)
96 const size_t numIndicesPerFace = quads ? 5 : 4;
98 for (
size_t i = 0; i < numFaces; i++) {
99 const size_t baseIndex = i * numIndicesPerFace;
101 adjacencyList[indices[baseIndex] -
static_cast<IndexType
>(positionOffset)].push_back(
static_cast<IndexType
>(i));
102 adjacencyList[indices[baseIndex + 1] -
static_cast<IndexType
>(positionOffset)].push_back(
static_cast<IndexType
>(i));
103 adjacencyList[indices[baseIndex + 2] -
static_cast<IndexType
>(positionOffset)].push_back(
static_cast<IndexType
>(i));
106 adjacencyList[indices[baseIndex + 3] - positionOffset].push_back(
static_cast<int32_t
>(i));
114 template<
class PositionType,
class IndexType,
class NormalType,
bool quads>
115 void calculateFaceNormals(
const size_t numFaces,
const PositionType * positions,
const IndexType * indices, std::vector<NormalType> & faceNormals)
117 const size_t numIndicesPerFace = quads ? 5 : 4;
119 NormalType faceNormal;
120 PositionType leftLeg;
121 PositionType rightLeg;
124 for (
size_t i = 0; i < numFaces; i++) {
125 const size_t baseIndex = i * numIndicesPerFace;
127 leftLeg = positions[indices[baseIndex + 1]] - positions[indices[baseIndex]];
128 rightLeg = positions[indices[baseIndex + 2]] - positions[indices[baseIndex]];
130 faceNormal = cross(rightLeg, leftLeg);
132 faceNormal = normalize(faceNormal);
134 faceNormals[i] = faceNormal;
142 template<
class NormalType,
class AdjacencyListType>
143 void calculateSmoothVertexNormals(NormalType * normals,
const size_t numNormals,
const std::vector<NormalType> & faceNormals,
const size_t positionOffset,
const std::vector<AdjacencyListType> & adjacencyList)
145 for (
size_t i = positionOffset; i < numNormals; i++) {
146 NormalType faceNormal = NormalType(0, 0, 0);
148 const size_t adjacencyIndex = i - positionOffset;
149 const size_t numAdjacentFaces = adjacencyList[adjacencyIndex].size();
151 for (
size_t k = 0; k < numAdjacentFaces; k++) {
152 faceNormal = faceNormal + faceNormals[adjacencyList[adjacencyIndex][k]];
155 faceNormal = normalize(faceNormal);
157 normals[i] = faceNormal;
164 return 3.14159265358979323846;
171 template<
class NormalType,
class AdjacencyListType,
class IndexType>
172 void calculateFacetVertexNormals(
const std::vector<NormalType> & faceNormals,
const std::vector<AdjacencyListType> & adjacencyList,
const IndexType * indexes,
const float creaseAngle,
bool quads, NormalType * normals)
174 const size_t numIndicesPerFace = quads ? 5 : 4;
175 const size_t numVertexesPerFace = quads ? 4 : 3;
177 const float threshold = std::cos(std::max(0.0f, std::min(creaseAngle,
static_cast<float>(pi()))));
179 for (
size_t i = 0; i < faceNormals.size(); ++i) {
180 const NormalType & faceNormal = faceNormals[i];
182 for (
size_t j = 0; j < numIndicesPerFace - 1; ++j) {
183 const int currentIndex = indexes[i * numIndicesPerFace + j];
185 NormalType vertexNormal = faceNormal;
187 const AdjacencyListType & faceList = adjacencyList[currentIndex];
189 for (
size_t k = 0; k < faceList.size(); ++k) {
190 const NormalType & adjacentFaceNormal = faceNormals[faceList[k]];
192 if (
static_cast<size_t>(faceList[k]) != i && dot(adjacentFaceNormal, faceNormal) > threshold) {
193 vertexNormal = vertexNormal + adjacentFaceNormal;
197 vertexNormal = normalize(vertexNormal);
199 normals[i * numVertexesPerFace + j] = vertexNormal;
209 template<
class IndexType,
bool quads>
215 for (
size_t i = 0; i < numFaces; ++i) {
216 indexes[index++] = vertexIndex++;
217 indexes[index++] = vertexIndex++;
218 indexes[index++] = vertexIndex++;
221 indexes[index++] = vertexIndex++;
224 indexes[index++] = -1;
231 template<
class ValueType,
class IndexType>
232 void reindexValues(
const ValueType * inputValues,
const IndexType * indexes,
const size_t numFaces,
const size_t numIndexesPerFace, ValueType * outputValues)
236 for (
size_t i = 0; i < numFaces; ++i) {
237 for (
size_t j = 0; j < numIndexesPerFace - 1; ++j) {
238 outputValues[index++] = inputValues[indexes[i * numIndexesPerFace + j]];
247 template<
class NormalType>
250 for (
size_t i = 0; i < numNormals; ++i) {
251 if (normals[i] == NormalType(0, 0, 0) || normals[i][0] == std::numeric_limits<float>::quiet_NaN()) {
252 normals[i] = NormalType(0, 0, 1);
260 template<
class NormalType>
263 for (
size_t i = 0; i < numNormals; ++i) {
264 normals[i] = -normals[i];
272 template<
class AdjacencyListType>
273 void addExtrusionSeamFaces(
const size_t numFaces,
size_t segmentCount, std::vector<AdjacencyListType> & adjacencyList)
275 const size_t numSections = numFaces / segmentCount;
277 for (
size_t i = 0; i < numSections; ++i) {
278 const size_t firstSegmentIndex = i * (segmentCount + 1);
279 const size_t lastSegmentIndex = i * (segmentCount + 1) + segmentCount;
281 const size_t firstSegmentIndexNextRow = (i + 1) * (segmentCount + 1);
282 const size_t lastSegmentIndexNextRow = (i + 1) * (segmentCount + 1) + segmentCount;
284 adjacencyList[lastSegmentIndex].push_back(
static_cast<int32_t
>(i * segmentCount));
285 adjacencyList[firstSegmentIndex].push_back(
static_cast<int32_t
>(i * segmentCount + (segmentCount - 1)));
286 adjacencyList[lastSegmentIndexNextRow].push_back(
static_cast<int32_t
>(i * segmentCount));
287 adjacencyList[firstSegmentIndexNextRow].push_back(
static_cast<int32_t
>(i * segmentCount + (segmentCount - 1)));
291 template<
class AdjacencyListType>
292 void addTriangleExtrusionSeamFaces(
const size_t numFaces,
size_t segmentCount, std::vector<AdjacencyListType> & adjacencyList)
294 const size_t numSections = (numFaces / 2) / segmentCount;
295 const size_t facePerSectionCount = segmentCount * 2;
297 for (
size_t i = 0; i < numSections; ++i) {
298 const size_t firstSegmentIndex = i * (segmentCount + 1);
299 const size_t lastSegmentIndex = i * (segmentCount + 1) + segmentCount;
301 const size_t firstSegmentIndexNextRow = (i + 1) * (segmentCount + 1);
302 const size_t lastSegmentIndexNextRow = (i + 1) * (segmentCount + 1) + segmentCount;
304 adjacencyList[firstSegmentIndex].push_back(
static_cast<int32_t
>(i * facePerSectionCount + (facePerSectionCount - 2)));
306 adjacencyList[lastSegmentIndex].push_back(
static_cast<int32_t
>(i * facePerSectionCount));
307 adjacencyList[lastSegmentIndex].push_back(
static_cast<int32_t
>(i * facePerSectionCount + 1));
309 adjacencyList[firstSegmentIndexNextRow].push_back(
static_cast<int32_t
>(i * facePerSectionCount + (facePerSectionCount - 1)));
310 adjacencyList[firstSegmentIndexNextRow].push_back(
static_cast<int32_t
>(i * facePerSectionCount + (facePerSectionCount - 2)));
312 adjacencyList[lastSegmentIndexNextRow].push_back(
static_cast<int32_t
>(i * facePerSectionCount + 1));
319 template<
typename VectorType,
typename IndexType>
320 void generateNormals(VectorType * positions,
const size_t numVertexes, IndexType * indexes,
const size_t numIndexes,
bool quads,
bool flipNormals,
bool correctNormals, std::vector<VectorType> & normals)
322 if (!numIndexes)
return;
323 if (!numVertexes)
return;
325 normals.resize(numVertexes);
327 generateNormals(positions, normals.data(), numVertexes, indexes, numIndexes, flipNormals, correctNormals, quads);
333 template<
typename VectorType,
typename IndexType>
335 const VectorType * positions,
336 VectorType * normals,
337 const size_t numPositions,
338 const IndexType * indices,
339 const size_t numIndices,
343 size_t positionOffset)
345 const size_t numIndicesPerFace = quads ? 5u : 4u;
346 const size_t numFaces = numIndices / numIndicesPerFace;
347 const size_t numActualVertices = numPositions - positionOffset;
349 std::vector<VectorType> faceNormals(
static_cast<unsigned>(numFaces));
350 std::vector<AdjacencyList> adjacencyList(
static_cast<unsigned>(numActualVertices));
353 generateAdjacencyInfo<IndexType, AdjacencyList, true>(numFaces, indices, positionOffset, adjacencyList);
355 calculateFaceNormals<VectorType, IndexType, VectorType, true>(numFaces, positions, indices, faceNormals);
357 generateAdjacencyInfo<IndexType, AdjacencyList, false>(numFaces, indices, positionOffset, adjacencyList);
359 calculateFaceNormals<VectorType, IndexType, VectorType, false>(numFaces, positions, indices, faceNormals);
362 if (correctNormals) {
382 template<
typename VectorType,
typename IndexType>
383 void generateExtrusionNormals(VectorType * positions,
const size_t numVertexes, IndexType * indexes,
const size_t numIndexes,
int segmentCount,
bool quads,
bool flipNormals, std::vector<VectorType> & normals)
385 if (!numVertexes)
return;
386 if (!numIndexes)
return;
388 const int numIndicesPerFace = quads ? 5 : 4;
389 const int numVertices = numVertexes;
390 const int numFaces = numIndexes / numIndicesPerFace;
392 normals.resize(numVertices);
394 std::vector<VectorType> faceNormals(numVertices);
395 std::vector<AdjacencyList> adjacencyList(numVertices);
398 generateAdjacencyInfo<IndexType, AdjacencyList, true>(numFaces, indexes, 0, adjacencyList);
400 generateAdjacencyInfo<IndexType, AdjacencyList, false>(numFaces, indexes, 0, adjacencyList);
406 addTriangleExtrusionSeamFaces(numFaces, segmentCount, adjacencyList);
410 calculateFaceNormals<VectorType, IndexType, VectorType, true>(numFaces, positions, indexes, faceNormals);
412 calculateFaceNormals<VectorType, IndexType, VectorType, false>(numFaces, positions, indexes, faceNormals);
422 template<
typename VectorType,
typename IndexType,
typename Vector2Type>
423 void generateFacetNormals(
424 const VectorType * positions,
425 const size_t numPositions,
426 const IndexType * indexes,
427 const size_t numIndexes,
428 const Vector2Type * texCoords,
429 bool quads,
bool flipNormals,
bool correctNormals,
const float creaseAngle,
bool createExtrusionSeam,
const size_t segmentCount,
430 std::vector<VectorType> & outputPositions,
431 std::vector<VectorType> & outputNormals,
432 std::vector<IndexType> & outputIndexes,
433 std::vector<Vector2Type> * outputTexCoords)
435 if (!numPositions)
return;
436 if (!numIndexes)
return;
438 const size_t positionOffset = 0;
439 const size_t numIndicesPerFace = quads ? 5 : 4;
440 const size_t numVertexesPerFace = quads ? 4 : 3;
441 const size_t numFaces = numIndexes / numIndicesPerFace;
442 const size_t numActualVertices = numPositions - positionOffset;
444 std::vector<VectorType> faceNormals(numFaces);
445 std::vector<AdjacencyList> adjacencyList(numActualVertices);
448 generateAdjacencyInfo<IndexType, AdjacencyList, true>(numFaces, indexes, positionOffset, adjacencyList);
450 generateAdjacencyInfo<IndexType, AdjacencyList, false>(numFaces, indexes, positionOffset, adjacencyList);
453 if (createExtrusionSeam) {
457 addTriangleExtrusionSeamFaces(numFaces, segmentCount - 1, adjacencyList);
462 calculateFaceNormals<VectorType, IndexType, VectorType, true>(numFaces, positions, indexes, faceNormals);
464 calculateFaceNormals<VectorType, IndexType, VectorType, false>(numFaces, positions, indexes, faceNormals);
467 if (correctNormals) {
475 outputNormals.resize(numFaces * numVertexesPerFace);
476 outputPositions.resize(numFaces * numVertexesPerFace);
478 VectorType * normal = outputNormals.data();
479 VectorType * position = outputPositions.data();
483 reindexValues(positions, indexes, numFaces, numIndicesPerFace, position);
486 outputTexCoords->resize(numFaces * numVertexesPerFace);
488 reindexValues(texCoords, indexes, numFaces, numIndicesPerFace, outputTexCoords->data());
491 outputIndexes.resize(numFaces * numIndicesPerFace);
492 IndexType * newIndex = outputIndexes.data();
495 generateLinearIndexes<IndexType, true>(numFaces, newIndex);
497 generateLinearIndexes<IndexType, false>(numFaces, newIndex);
@ Geometry
Store entity vector fields (vector<vec3>, vector<vec2>, vector<int>, vector<float>).
void addExtrusionSeamFaces(const size_t numFaces, size_t segmentCount, std::vector< AdjacencyListType > &adjacencyList)
Adds the faces along the seam of an extrusion to the adjacency list of the seam vertexes.
void calculateFaceNormals(const size_t numFaces, const PositionType *positions, const IndexType *indices, std::vector< NormalType > &faceNormals)
Calculates face normals for the list of faces given.
void generateExtrusionNormals(VectorType *positions, const size_t numVertexes, IndexType *indexes, const size_t numIndexes, int segmentCount, bool quads, bool flipNormals, std::vector< VectorType > &normals)
Generate normals for an extrusion shape.
void generateAdjacencyInfo(const size_t numFaces, const IndexType *indices, const size_t positionOffset, std::vector< AdjacencyListType > &adjacencyList)
Generates vertex adjacency info for the list of faces given by indices.
void generateNormals(VectorType *positions, const size_t numVertexes, IndexType *indexes, const size_t numIndexes, bool quads, bool flipNormals, bool correctNormals, std::vector< VectorType > &normals)
Generate normals for the given shape.
void correctZeroLengthNormals(NormalType *normals, const size_t numNormals)
Corrects invalid normals (zero length) by setting them to the unit Z vector.
void calculateSmoothVertexNormals(NormalType *normals, const size_t numNormals, const std::vector< NormalType > &faceNormals, const size_t positionOffset, const std::vector< AdjacencyListType > &adjacencyList)
Calculates smooth vertex normals from the list of face normals and adjacency info given.
void generateLinearIndexes(const size_t numFaces, IndexType *indexes)
Generates a set of indexes from zero upwards for the amount of faces given.
void reverseNormalDirections(NormalType *normals, const size_t numNormals)
Reverse the set of normals given.
void reindexValues(const ValueType *inputValues, const IndexType *indexes, const size_t numFaces, const size_t numIndexesPerFace, ValueType *outputValues)
Reindexes the input values into the output values based on the index array given.
void calculateFacetVertexNormals(const std::vector< NormalType > &faceNormals, const std::vector< AdjacencyListType > &adjacencyList, const IndexType *indexes, const float creaseAngle, bool quads, NormalType *normals)
Calculates per vertex facet normals.
Contains all Cogs related functionality.
Utility class for storing the face indexes a vertex belongs to.
const IndexType & operator[](size_t i) const
Gets the index at the given location.
AdjacencyList_T()=default
Constructs a new list. Initial index count is 0.
size_t size() const
Gets the size of the index array. Does not correspond to the size of allocated memory.
void push_back(IndexType index)
Adds a new index value to the back of the index vector.