123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "math/mMath.h"
- #include "core/color.h"
- #include "console/console.h"
- #include "collision/optimizedPolyList.h"
- #include "materials/baseMatInstance.h"
- #include "materials/materialDefinition.h"
- //----------------------------------------------------------------------------
- OptimizedPolyList::OptimizedPolyList()
- {
- VECTOR_SET_ASSOCIATION(mPoints);
- VECTOR_SET_ASSOCIATION(mNormals);
- VECTOR_SET_ASSOCIATION(mUV0s);
- VECTOR_SET_ASSOCIATION(mUV1s);
- VECTOR_SET_ASSOCIATION(mVertexList);
- VECTOR_SET_ASSOCIATION(mIndexList);
- VECTOR_SET_ASSOCIATION(mPlaneList);
- VECTOR_SET_ASSOCIATION(mPolyList);
- mIndexList.reserve(100);
- mCurrObject = NULL;
- mBaseMatrix = MatrixF::Identity;
- mMatrix = MatrixF::Identity;
- mTransformMatrix = MatrixF::Identity;
- mScale.set(1.0f, 1.0f, 1.0f);
- mPlaneTransformer.setIdentity();
- mInterestNormalRegistered = false;
- }
- OptimizedPolyList::~OptimizedPolyList()
- {
- mPoints.clear();
- mNormals.clear();
- mUV0s.clear();
- mUV1s.clear();
- mVertexList.clear();
- mIndexList.clear();
- mPlaneList.clear();
- mPolyList.clear();
- }
- //----------------------------------------------------------------------------
- void OptimizedPolyList::clear()
- {
- mPoints.clear();
- mNormals.clear();
- mUV0s.clear();
- mUV1s.clear();
- mVertexList.clear();
- mIndexList.clear();
- mPlaneList.clear();
- mPolyList.clear();
- }
- //----------------------------------------------------------------------------
- U32 OptimizedPolyList::insertPoint(const Point3F& point)
- {
- S32 retIdx = -1;
- // Apply the transform
- Point3F transPoint = point;
- transPoint *= mScale;
- mMatrix.mulP(transPoint);
- for (U32 i = 0; i < mPoints.size(); i++)
- {
- if (mPoints[i].equal(transPoint))
- {
- retIdx = i;
- break;
- }
- }
- if (retIdx == -1)
- {
- retIdx = mPoints.size();
- mPoints.push_back(transPoint);
- }
- return (U32)retIdx;
- }
- U32 OptimizedPolyList::insertNormal(const Point3F& normal)
- {
- S32 retIdx = -1;
- // Apply the transform
- Point3F transNormal;
- mMatrix.mulV( normal, &transNormal );
- for (U32 i = 0; i < mNormals.size(); i++)
- {
- if (mNormals[i].equal(transNormal))
- {
- retIdx = i;
- break;
- }
- }
- if (retIdx == -1)
- {
- retIdx = mNormals.size();
- mNormals.push_back(transNormal);
- }
- return (U32)retIdx;
- }
- U32 OptimizedPolyList::insertUV0(const Point2F& uv)
- {
- S32 retIdx = -1;
- for (U32 i = 0; i < mUV0s.size(); i++)
- {
- if (mUV0s[i].equal(uv))
- {
- retIdx = i;
- break;
- }
- }
- if (retIdx == -1)
- {
- retIdx = mUV0s.size();
- mUV0s.push_back(uv);
- }
- return (U32)retIdx;
- }
- U32 OptimizedPolyList::insertUV1(const Point2F& uv)
- {
- S32 retIdx = -1;
- for (U32 i = 0; i < mUV1s.size(); i++)
- {
- if (mUV1s[i].equal(uv))
- {
- retIdx = i;
- break;
- }
- }
- if (retIdx == -1)
- {
- retIdx = mUV1s.size();
- mUV1s.push_back(uv);
- }
- return (U32)retIdx;
- }
- U32 OptimizedPolyList::insertPlane(const PlaneF& plane)
- {
- S32 retIdx = -1;
- // Apply the transform
- PlaneF transPlane;
- mPlaneTransformer.transform(plane, transPlane);
- for (U32 i = 0; i < mPlaneList.size(); i++)
- {
- if (mPlaneList[i].equal(transPlane) &&
- mFabs( mPlaneList[i].d - transPlane.d ) < POINT_EPSILON)
- {
- retIdx = i;
- break;
- }
- }
- if (retIdx == -1)
- {
- retIdx = mPlaneList.size();
- mPlaneList.push_back(transPlane);
- }
- return (U32)retIdx;
- }
- U32 OptimizedPolyList::insertMaterial(BaseMatInstance* baseMat)
- {
- S32 retIdx = -1;
- if ( !baseMat )
- return retIdx;
- Material* mat = dynamic_cast<Material*>(baseMat->getMaterial());
- for (U32 i = 0; i < mMaterialList.size(); i++)
- {
- Material* testMat = dynamic_cast<Material*>(mMaterialList[i]->getMaterial());
- if (mat && testMat)
- {
- if (testMat == mat)
- {
- retIdx = i;
- break;
- }
- }
- else if (mMaterialList[i] == baseMat)
- {
- retIdx = i;
- break;
- }
- }
- if (retIdx == -1)
- {
- retIdx = mMaterialList.size();
- mMaterialList.push_back(baseMat);
- }
- return (U32)retIdx;
- }
- U32 OptimizedPolyList::insertVertex(const Point3F& point, const Point3F& normal,
- const Point2F& uv0, const Point2F& uv1)
- {
- VertIndex vert;
- vert.vertIdx = insertPoint(point);
- vert.normalIdx = insertNormal(normal);
- vert.uv0Idx = insertUV0(uv0);
- vert.uv1Idx = insertUV1(uv1);
- return mVertexList.push_back_unique(vert);
- }
- U32 OptimizedPolyList::addPoint(const Point3F& p)
- {
- return insertVertex(p);
- }
- U32 OptimizedPolyList::addPlane(const PlaneF& plane)
- {
- return insertPlane(plane);
- }
- //----------------------------------------------------------------------------
- void OptimizedPolyList::begin(BaseMatInstance* material, U32 surfaceKey)
- {
- mPolyList.increment();
- Poly& poly = mPolyList.last();
- poly.material = insertMaterial(material);
- poly.vertexStart = mIndexList.size();
- poly.surfaceKey = surfaceKey;
- poly.type = TriangleFan;
- poly.object = mCurrObject;
- }
- void OptimizedPolyList::begin(BaseMatInstance* material, U32 surfaceKey, PolyType type)
- {
- begin(material, surfaceKey);
- // Set the type
- mPolyList.last().type = type;
- }
- //----------------------------------------------------------------------------
- void OptimizedPolyList::plane(U32 v1, U32 v2, U32 v3)
- {
- /*
- AssertFatal(v1 < mPoints.size() && v2 < mPoints.size() && v3 < mPoints.size(),
- "OptimizedPolyList::plane(): Vertex indices are larger than vertex list size");
- mPolyList.last().plane = addPlane(PlaneF(mPoints[v1], mPoints[v2], mPoints[v3]));
- */
- mPolyList.last().plane = addPlane( PlaneF( mPoints[mVertexList[v1].vertIdx], mPoints[mVertexList[v2].vertIdx], mPoints[mVertexList[v3].vertIdx] ) );
- }
- void OptimizedPolyList::plane(const PlaneF& p)
- {
- mPolyList.last().plane = addPlane(p);
- }
- void OptimizedPolyList::plane(const U32 index)
- {
- AssertFatal(index < mPlaneList.size(), "Out of bounds index!");
- mPolyList.last().plane = index;
- }
- const PlaneF& OptimizedPolyList::getIndexedPlane(const U32 index)
- {
- AssertFatal(index < mPlaneList.size(), "Out of bounds index!");
- return mPlaneList[index];
- }
- //----------------------------------------------------------------------------
- void OptimizedPolyList::vertex(U32 vi)
- {
- mIndexList.push_back(vi);
- }
- void OptimizedPolyList::vertex(const Point3F& p)
- {
- mIndexList.push_back(addPoint(p));
- }
- void OptimizedPolyList::vertex(const Point3F& p,
- const Point3F& normal,
- const Point2F& uv0,
- const Point2F& uv1)
- {
- mIndexList.push_back(insertVertex(p, normal, uv0, uv1));
- }
- //----------------------------------------------------------------------------
- bool OptimizedPolyList::isEmpty() const
- {
- return !mPolyList.size();
- }
- void OptimizedPolyList::end()
- {
- Poly& poly = mPolyList.last();
- poly.vertexCount = mIndexList.size() - poly.vertexStart;
- }
- //----------------------------------------------------------------------------
- Polyhedron OptimizedPolyList::toPolyhedron() const
- {
- Polyhedron polyhedron;
- // Add the points, but filter out duplicates.
- Vector< S32 > pointRemap;
- pointRemap.setSize( mPoints.size() );
- pointRemap.fill( -1 );
- const U32 numPoints = mPoints.size();
- for( U32 i = 0; i < numPoints; ++ i )
- {
- bool isDuplicate = false;
- for( U32 npoint = 0; npoint < polyhedron.mPointList.size(); ++ npoint )
- {
- if( npoint == i )
- continue;
- if( !polyhedron.mPointList[ npoint ].equal( mPoints[ i ] ) )
- continue;
- pointRemap[ i ] = npoint;
- isDuplicate = true;
- }
- if( !isDuplicate )
- {
- pointRemap[ i ] = polyhedron.mPointList.size();
- polyhedron.mPointList.push_back( mPoints[ i ] );
- }
- }
- // Go through the polys and add all their edges and planes.
- // We will consolidate edges in a second pass.
- const U32 numPolys = mPolyList.size();
- for( U32 i = 0; i < numPolys; ++ i )
- {
- const Poly& poly = mPolyList[ i ];
- // Add the plane.
- const U32 polyIndex = polyhedron.mPlaneList.size();
- polyhedron.mPlaneList.push_back( mPlaneList[ poly.plane ] );
- // Account for polyhedrons expecting planes to
- // face inwards.
- polyhedron.mPlaneList.last().invert();
- // Gather remapped indices according to the
- // current polygon type.
- Vector< U32 > indexList;
- switch( poly.type )
- {
- case TriangleFan:
- AssertFatal( false, "TriangleFan conversion not implemented" );
- case TriangleStrip:
- AssertFatal( false, "TriangleStrip conversion not implemented" );
- case TriangleList:
- {
- Vector< Polyhedron::Edge > tempEdges;
- // Loop over the triangles and gather all unshared edges
- // in tempEdges. These are the exterior edges of the polygon.
- for( U32 n = poly.vertexStart; n < poly.vertexStart + poly.vertexCount; n += 3 )
- {
- U32 indices[ 3 ];
- // Get the remapped indices of the three vertices.
- indices[ 0 ] = pointRemap[ mVertexList[ mIndexList[ n + 0 ] ].vertIdx ];
- indices[ 1 ] = pointRemap[ mVertexList[ mIndexList[ n + 1 ] ].vertIdx ];
- indices[ 2 ] = pointRemap[ mVertexList[ mIndexList[ n + 2 ] ].vertIdx ];
- // Loop over the three edges.
- for( U32 d = 0; d < 3; ++ d )
- {
- U32 index1 = indices[ d ];
- U32 index2 = indices[ ( d + 1 ) % 3 ];
- // See if this edge is already in the list. If so,
- // it's a shared edge and thus an interior one. Remove
- // it.
- bool isShared = false;
- for( U32 nedge = 0; nedge < tempEdges.size(); ++ nedge )
- {
- Polyhedron::Edge& edge = tempEdges[ nedge ];
- if( ( edge.vertex[ 0 ] == index1 && edge.vertex[ 1 ] == index2 ) ||
- ( edge.vertex[ 0 ] == index2 && edge.vertex[ 1 ] == index1 ) )
- {
- tempEdges.erase( nedge );
- isShared = true;
- break;
- }
- }
- // If it wasn't in the list, add a new edge.
- if( !isShared )
- tempEdges.push_back(
- Polyhedron::Edge( -1, -1, index1, index2 )
- );
- }
- }
- // Walk the edges and gather consecutive indices.
- U32 currentEdge = 0;
- for( U32 n = 0; n < tempEdges.size(); ++ n )
- {
- // Add first vertex of edge.
- indexList.push_back( tempEdges[ currentEdge ].vertex[ 0 ] );
- // Find edge that begins at second vertex.
- for( U32 nedge = 0; nedge < tempEdges.size(); ++ nedge )
- {
- if( nedge == currentEdge )
- continue;
- if( tempEdges[ nedge ].vertex[ 0 ] == tempEdges[ currentEdge ].vertex[ 1 ] )
- {
- currentEdge = nedge;
- break;
- }
- }
- }
- }
- }
- // Create edges from the indices. Indices are CCW ordered and
- // we want CW order, so step everything in reverse.
- U32 lastIndex = 0;
- for( S32 n = indexList.size() - 1; n >= 0; -- n )
- {
- polyhedron.mEdgeList.push_back(
- Polyhedron::Edge(
- polyIndex, 0, // face1 filled later
- indexList[ lastIndex ], indexList[ n ]
- )
- );
- lastIndex = n;
- }
- }
- // Finally, consolidate the edge list by merging all edges that
- // are shared by polygons.
- for( U32 i = 0; i < polyhedron.mEdgeList.size(); ++ i )
- {
- Polyhedron::Edge& edge = polyhedron.mEdgeList[ i ];
- // Find the corresponding duplicate edge, if any, and merge
- // it into our current edge.
- for( U32 n = i + 1; n < polyhedron.mEdgeList.size(); ++ n )
- {
- const Polyhedron::Edge& thisEdge = polyhedron.mEdgeList[ n ];
- if( ( thisEdge.vertex[ 0 ] == edge.vertex[ 1 ] &&
- thisEdge.vertex[ 1 ] == edge.vertex[ 0 ] ) ||
- ( thisEdge.vertex[ 0 ] == edge.vertex[ 0 ] &&
- thisEdge.vertex[ 1 ] == edge.vertex[ 1 ] ) )
- {
- edge.face[ 1 ] = thisEdge.face[ 0 ];
- polyhedron.mEdgeList.erase( n );
- break;
- }
- }
- }
- return polyhedron;
- }
|