diff --git a/examples/14-shadowvolumes/shadowvolumes.cpp b/examples/14-shadowvolumes/shadowvolumes.cpp index 883105e5..4b2bab8e 100644 --- a/examples/14-shadowvolumes/shadowvolumes.cpp +++ b/examples/14-shadowvolumes/shadowvolumes.cpp @@ -12,6 +12,7 @@ using namespace std::tr1; #include #include #include +#include #include #include "entry/entry.h" #include "fpumath.h" @@ -700,7 +701,7 @@ struct Edge { bool m_faceReverseOrder[2]; uint8_t m_faceIndex; - float m_v0[3], m_v1[3]; + uint16_t m_i0, m_i1; }; struct Plane @@ -816,6 +817,67 @@ struct HalfEdges HalfEdge* m_endPtr; }; +struct WeldedVertex +{ + uint16_t m_v; + bool m_welded; +}; + +inline float sqLength(const float _a[3], const float _b[3]) +{ + const float xx = _a[0] - _b[0]; + const float yy = _a[1] - _b[1]; + const float zz = _a[2] - _b[2]; + return xx*xx + yy*yy + zz*zz; +} + +uint16_t weldVertices(WeldedVertex* _output, const bgfx::VertexDecl& _decl, const void* _data, uint16_t _num, float _epsilon) +{ + const uint32_t hashSize = bx::uint32_nextpow2(_num); + const uint32_t hashMask = hashSize-1; + const float epsilonSq = _epsilon*_epsilon; + + uint32_t numVertices = 0; + + const uint32_t size = sizeof(uint16_t)*(hashSize + _num); + uint16_t* hashTable = (uint16_t*)alloca(size); + memset(hashTable, 0xff, size); + + uint16_t* next = hashTable + hashSize; + + for (uint32_t ii = 0; ii < _num; ++ii) + { + float pos[4]; + vertexUnpack(pos, bgfx::Attrib::Position, _decl, _data, ii); + uint32_t hashValue = bx::hashMurmur2A(pos, 3*sizeof(float) ) & hashMask; + + uint16_t offset = hashTable[hashValue]; + for (; UINT16_MAX != offset; offset = next[offset]) + { + float test[4]; + vertexUnpack(test, bgfx::Attrib::Position, _decl, _data, _output[offset].m_v); + + if (sqLength(test, pos) < epsilonSq) + { + _output[ii].m_v = _output[offset].m_v; + _output[ii].m_welded = true; + break; + } + } + + if (UINT16_MAX == offset) + { + _output[ii].m_v = ii; + _output[ii].m_welded = false; + next[ii] = hashTable[hashValue]; + hashTable[hashValue] = ii; + numVertices++; + } + } + + return numVertices; +} + struct Group { Group() @@ -839,73 +901,66 @@ struct Group typedef struct { float f[6]; } f6_t; - struct EdgeComparator - { - bool operator()(const f6_t& _a, const f6_t& _b) const - { - const uint8_t t0 = 0 - | ( (_a.f[0] < _b.f[0]) << 5) - | ( (_a.f[1] < _b.f[1]) << 4) - | ( (_a.f[2] < _b.f[2]) << 3) - | ( (_a.f[3] < _b.f[3]) << 2) - | ( (_a.f[4] < _b.f[4]) << 1) - | ( (_a.f[5] < _b.f[5]) << 0) - ; - - const uint8_t t1 = 0 - | ( (_a.f[0] > _b.f[0]) << 5) - | ( (_a.f[1] > _b.f[1]) << 4) - | ( (_a.f[2] > _b.f[2]) << 3) - | ( (_a.f[3] > _b.f[3]) << 2) - | ( (_a.f[4] > _b.f[4]) << 1) - | ( (_a.f[5] > _b.f[5]) << 0) - ; - - return t0 > t1; - } - }; - struct EdgeAndPlane { - EdgeAndPlane(const float* _v0, const float* _v1) + EdgeAndPlane(uint16_t _i0, uint16_t _i1) : m_faceIndex(0) + , m_i0(_i0) + , m_i1(_i1) { - memcpy(m_v0, _v0, 3*sizeof(float) ); - memcpy(m_v1, _v1, 3*sizeof(float) ); } bool m_faceReverseOrder[2]; uint8_t m_faceIndex; - float m_v0[3], m_v1[3]; + uint16_t m_i0, m_i1; Plane m_plane[2]; }; - void fillStructures(uint16_t _stride) + void fillStructures(const bgfx::VertexDecl& _decl) { + uint16_t stride = _decl.getStride(); m_faces.clear(); m_halfEdges.destroy(); - //init halfedges + //Init halfedges. m_halfEdges.init(m_indices, m_numIndices); - //init faces and edges + //Init faces and edges. m_faces.reserve(m_numIndices/3); //1 face = 3 indices m_edges = (Edge*)malloc(m_numIndices * sizeof(Edge)); //1 triangle = 3 indices = 3 edges. m_edgePlanesUnalignedPtr = (Plane*)malloc(m_numIndices * sizeof(Plane) + 15); m_edgePlanes = (Plane*)bx::alignPtr(m_edgePlanesUnalignedPtr, 0, 16); - typedef std::map EdgeMap; + typedef std::map, EdgeAndPlane> EdgeMap; EdgeMap edgeMap; + //Get unique indices. + WeldedVertex* uniqueVertices = (WeldedVertex*)malloc(m_numVertices*sizeof(WeldedVertex) ); + ::weldVertices(uniqueVertices, _decl, m_vertices, m_numVertices, 0.0001f); + uint16_t* uniqueIndices = (uint16_t*)malloc(m_numIndices*sizeof(uint16_t) ); + for (uint32_t ii = 0; ii < m_numIndices; ++ii) + { + uint16_t index = m_indices[ii]; + if (uniqueVertices[index].m_welded) + { + uniqueIndices[ii] = uniqueVertices[index].m_v; + } + else + { + uniqueIndices[ii] = index; + } + } + free(uniqueVertices); + for (uint32_t ii = 0, size = m_numIndices/3; ii < size; ++ii) { const uint16_t* indices = &m_indices[ii*3]; const uint16_t i0 = indices[0]; const uint16_t i1 = indices[1]; const uint16_t i2 = indices[2]; - const float* v0 = (float*)&m_vertices[i0*_stride]; - const float* v1 = (float*)&m_vertices[i1*_stride]; - const float* v2 = (float*)&m_vertices[i2*_stride]; + const float* v0 = (float*)&m_vertices[i0*stride]; + const float* v1 = (float*)&m_vertices[i1*stride]; + const float* v2 = (float*)&m_vertices[i2*stride]; float plane[4]; planeNormal(plane, v0, v2, v1); @@ -917,23 +972,26 @@ struct Group memcpy(face.m_plane, plane, 4*sizeof(float) ); m_faces.push_back(face); - const float* triangleV[3][2] = + //Use unique indices for EdgeMap. + const uint16_t* uindices = &uniqueIndices[ii*3]; + const uint16_t ui0 = uindices[0]; + const uint16_t ui1 = uindices[1]; + const uint16_t ui2 = uindices[2]; + + const uint16_t triangleEdge[3][2] = { - {v0, v1}, - {v1, v2}, - {v2, v0}, + {ui0, ui1}, + {ui1, ui2}, + {ui2, ui0}, }; for (uint8_t jj = 0; jj < 3; ++jj) { - const float* v0 = triangleV[jj][0]; - const float* v1 = triangleV[jj][1]; - f6_t key; - f6_t keyInv; - memcpy(&key.f[0], v0, 3*sizeof(float) ); - memcpy(&key.f[3], v1, 3*sizeof(float) ); - memcpy(&keyInv.f[0], v1, 3*sizeof(float) ); - memcpy(&keyInv.f[3], v0, 3*sizeof(float) ); + const uint16_t ui0 = triangleEdge[jj][0]; + const uint16_t ui1 = triangleEdge[jj][1]; + + std::pair key = std::make_pair(ui0, ui1); + std::pair keyInv = std::make_pair(ui1, ui0); EdgeMap::iterator iter = edgeMap.find(keyInv); if (iter != edgeMap.end()) @@ -944,7 +1002,7 @@ struct Group } else { - std::pair result = edgeMap.insert(std::make_pair(key, EdgeAndPlane(v0, v1)) ); + std::pair result = edgeMap.insert(std::make_pair(key, EdgeAndPlane(ui0, ui1) ) ); EdgeAndPlane& ep = result.first->second; memcpy(ep.m_plane[ep.m_faceIndex].m_plane, plane, 4*sizeof(float) ); ep.m_faceReverseOrder[ep.m_faceIndex] = false; @@ -953,6 +1011,8 @@ struct Group } } + free(uniqueIndices); + uint32_t index = 0; for (EdgeMap::const_iterator iter = edgeMap.begin(), end = edgeMap.end(); iter != end; ++iter) { @@ -1128,10 +1188,9 @@ struct Mesh reader.close(); - uint16_t stride = m_decl.getStride(); for (GroupArray::iterator it = m_groups.begin(), itEnd = m_groups.end(); it != itEnd; ++it) { - it->fillStructures(stride); + it->fillStructures(m_decl); } } @@ -1585,10 +1644,12 @@ void shadowVolumeCreate(ShadowVolume& _shadowVolume int16_t k = res[jj] + res[jj+2]; if (k != 0) { - verticesSide[vsideI++] = VertexData(edges[ii+jj].m_v0, 0.0f, float(k)); - verticesSide[vsideI++] = VertexData(edges[ii+jj].m_v0, 1.0f, float(k)); - verticesSide[vsideI++] = VertexData(edges[ii+jj].m_v1, 0.0f, float(k)); - verticesSide[vsideI++] = VertexData(edges[ii+jj].m_v1, 1.0f, float(k)); + float* v0 = (float*)&vertices[edges[ii+jj].m_i0*_stride]; + float* v1 = (float*)&vertices[edges[ii+jj].m_i1*_stride]; + verticesSide[vsideI++] = VertexData(v0, 0.0f, float(k)); + verticesSide[vsideI++] = VertexData(v0, 1.0f, float(k)); + verticesSide[vsideI++] = VertexData(v1, 0.0f, float(k)); + verticesSide[vsideI++] = VertexData(v1, 1.0f, float(k)); k = _textureAsStencil ? 1 : k; uint16_t winding = uint16_t(k > 0); @@ -1620,10 +1681,12 @@ void shadowVolumeCreate(ShadowVolume& _shadowVolume if (k != 0) { - verticesSide[vsideI++] = VertexData(edge.m_v0, 0.0f, k); - verticesSide[vsideI++] = VertexData(edge.m_v0, 1.0f, k); - verticesSide[vsideI++] = VertexData(edge.m_v1, 0.0f, k); - verticesSide[vsideI++] = VertexData(edge.m_v1, 1.0f, k); + float* v0 = (float*)&vertices[edge.m_i0*_stride]; + float* v1 = (float*)&vertices[edge.m_i1*_stride]; + verticesSide[vsideI++] = VertexData(v0, 0.0f, k); + verticesSide[vsideI++] = VertexData(v0, 1.0f, k); + verticesSide[vsideI++] = VertexData(v1, 0.0f, k); + verticesSide[vsideI++] = VertexData(v1, 1.0f, k); k = _textureAsStencil ? 1 : k; uint16_t winding = uint16_t(k > 0);