diff options
Diffstat (limited to 'externals/g3dlite/G3D/MeshAlg.h')
| -rw-r--r-- | externals/g3dlite/G3D/MeshAlg.h | 683 |
1 files changed, 0 insertions, 683 deletions
diff --git a/externals/g3dlite/G3D/MeshAlg.h b/externals/g3dlite/G3D/MeshAlg.h deleted file mode 100644 index 1decea10105..00000000000 --- a/externals/g3dlite/G3D/MeshAlg.h +++ /dev/null @@ -1,683 +0,0 @@ -/** - @file MeshAlg.h - - Indexed Mesh algorithms. - - @maintainer Morgan McGuire, http://graphics.cs.williams.edu - - @created 2003-09-14 - @edited 2010-01-18 -*/ - -#ifndef G3D_MeshAlg_h -#define G3D_MeshAlg_h - -#include "G3D/platform.h" -#include "G3D/Array.h" -#include "G3D/Vector3.h" -#include "G3D/CoordinateFrame.h" -#include "G3D/SmallArray.h" -#include "G3D/constants.h" -#include "G3D/Image1.h" - -#ifdef G3D_WIN32 -// Turn off "conditional expression is constant" warning; MSVC generates this -// for debug assertions in inlined methods. -#pragma warning (disable : 4127) -#endif - -namespace G3D { - -/** - Indexed <B>mesh alg</B>orithms. You have to build your own mesh class. - <P> - No mesh class is provided with G3D because there isn't an "ideal" - mesh format-- one application needs keyframed animation, another - skeletal animation, a third texture coordinates, a fourth - cannot precompute information, etc. Instead of compromising, this - class implements the hard parts of mesh computation and you can write - your own ideal mesh class on top of it. - - \sa G3D::ArticulatedModel, G3D::IFSModel - */ -class MeshAlg { -public: - - /** \deprecated */ - typedef PrimitiveType Primitive; - - /** Adjacency information for a vertex. - Does not contain the vertex position or normal, - which are stored in the MeshAlg::Geometry object. - <CODE>Vertex</CODE>s must be stored in an array - parallel to (indexed in the same way as) - MeshAlg::Geometry::vertexArray. - */ - class Vertex { - public: - Vertex() {} - - /** - Array of edges adjacent to this vertex. - Let e = edgeIndex[i]. - edge[(e >= 0) ? e : ~e].vertexIndex[0] == this - vertex index. - - Edges may be listed multiple times if they are - degenerate. - */ - SmallArray<int, 6> edgeIndex; - - /** - Returns true if e or ~e is in the edgeIndex list. - */ - inline bool inEdge(int e) const { - return edgeIndex.contains(~e) || edgeIndex.contains(e); - } - - /** - Array of faces containing this vertex. Faces - may be listed multiple times if they are degenerate. - */ - SmallArray<int, 6> faceIndex; - - inline bool inFace(int f) const { - debugAssert(f >= 0); - return faceIndex.contains(f); - } - }; - - - /** - Oriented, indexed triangle. - */ - class Face { - public: - Face(); - - /** - Used by Edge::faceIndex to indicate a missing face. - This is a large negative value. - */ - static const int NONE; - - - /** - Vertices in the face in counter-clockwise order. - Degenerate faces may include the same vertex multiple times. - */ - int vertexIndex[3]; - - inline bool containsVertex(int v) const { - return contains(vertexIndex, 3, v); - } - - /** - Edge indices in counter-clockwise order. Edges are - undirected, so it is important to know which way - each edge is pointing in a face. This is encoded - using negative indices. - - If <CODE>edgeIndex[i] >= 0</CODE> then this face - contains the directed edge - between vertex indices - <CODE>edgeArray[face.edgeIndex[i]].vertexIndex[0]</CODE> - and - <CODE>edgeArray[face.edgeIndex[i]].vertexIndex[1]</CODE>. - - If <CODE>edgeIndex[i] < 0</CODE> then - <CODE>~edgeIndex[i]</CODE> (i.e. the two's - complement of) is used and this face contains the directed - edge between vertex indices - <CODE>edgeArray[~face.edgeIndex[i]].vertexIndex[0]</CODE> - and - <CODE>edgeArray[~face.edgeIndex[i]].vertexIndex[1]</CODE>. - - Degenerate faces may include the same edge multiple times. - */ - // Temporarily takes on the value Face::NONE during adjacency - // computation to indicate an edge that has not yet been assigned. - int edgeIndex[3]; - - inline bool containsEdge(int e) const { - if (e < 0) { - e = ~e; - } - return contains(edgeIndex, 3, e) || contains(edgeIndex, 3, ~e); - } - - /** Contains the forward edge e if e >= 0 and the backward edge - ~e otherwise. */ - inline bool containsDirectedEdge(int e) const { - return contains(edgeIndex, 3, e); - } - }; - - - /** Oriented, indexed edge */ - class Edge { - public: - Edge(); - - /** Degenerate edges may include the same vertex times. */ - int vertexIndex[2]; - - inline bool containsVertex(int v) const { - return contains(vertexIndex, 2, v); - } - - /** - The edge is directed <B>forward</B> in face 0 - <B>backward</B> in face 1. Face index of MeshAlg::Face::NONE - indicates a boundary (a.k.a. crack, broken) edge. - */ - int faceIndex[2]; - - /** Returns true if f is contained in the faceIndex array in either slot. - To see if it is forward in that face, just check edge.faceIndex[0] == f.*/ - inline bool inFace(int f) const { - return contains(faceIndex, 2, f); - } - - /** - Returns true if either faceIndex is NONE. - */ - inline bool boundary() const { - return (faceIndex[0] == Face::NONE) || - (faceIndex[1] == Face::NONE); - } - - /** - Returns the reversed edge. - */ - inline Edge reverse() const { - Edge e; - e.vertexIndex[0] = vertexIndex[1]; - e.vertexIndex[1] = vertexIndex[0]; - e.faceIndex[0] = faceIndex[1]; - e.faceIndex[1] = faceIndex[0]; - return e; - } - }; - - - /** - Convenient for passing around the per-vertex data that changes under - animation. The faces and edges are needed to interpret - these values. - */ - class Geometry { - public: - /** Vertex positions */ - Array<Vector3> vertexArray; - - /** Vertex normals */ - Array<Vector3> normalArray; - - /** - Assignment is optimized using SSE. - */ - Geometry& operator=(const Geometry& src); - - void clear() { - vertexArray.clear(); - normalArray.clear(); - } - }; - - /** - Given a set of vertices and a set of indices for traversing them - to create triangles, computes other mesh properties. - - <B>Colocated vertices are treated as separate.</B> To have - colocated vertices collapsed (necessary for many algorithms, - like shadowing), weld the mesh before computing adjacency. - - <I>Recent change: In version 6.00, colocated vertices were automatically - welded by this routine and degenerate faces and edges were removed. That - is no longer the case.</I> - - Where two faces meet, there are two opposite directed edges. These - are collapsed into a single bidirectional edge in the edgeArray. - If four faces meet exactly at the same edge, that edge will appear - twice in the array, and so on. If an edge is a boundary of the mesh - (i.e. if the edge has only one adjacent face) it will appear in the - array with one face index set to MeshAlg::Face::NONE. - - @param vertexGeometry %Vertex positions to use when deciding colocation. - @param indexArray Order to traverse vertices to make triangles - @param faceArray <I>Output</I> - @param edgeArray <I>Output</I>. Sorted so that boundary edges are at the end of the array. - @param vertexArray <I>Output</I> - */ - static void computeAdjacency( - const Array<Vector3>& vertexGeometry, - const Array<int>& indexArray, - Array<Face>& faceArray, - Array<Edge>& edgeArray, - Array<Vertex>& vertexArray); - - /** - @deprecated Use the other version of computeAdjacency, which takes Array<Vertex>. - @param facesAdjacentToVertex <I>Output</I> adjacentFaceArray[v] is an array of - indices for faces touching vertex index v - */ - static void computeAdjacency( - const Array<Vector3>& vertexArray, - const Array<int>& indexArray, - Array<Face>& faceArray, - Array<Edge>& edgeArray, - Array< Array<int> >& facesAdjacentToVertex); - - /** - Computes some basic mesh statistics including: min, max mean and median, - edge lengths; and min, mean, median, and max face area. - - @param vertexArray %Vertex positions to use when deciding colocation. - @param indexArray Order to traverse vertices to make triangles - @param minEdgeLength Minimum edge length - @param meanEdgeLength Mean edge length - @param medianEdgeLength Median edge length - @param maxEdgeLength Max edge length - @param minFaceArea Minimum face area - @param meanFaceArea Mean face area - @param medianFaceArea Median face area - @param maxFaceArea Max face area - */ - static void computeAreaStatistics( - const Array<Vector3>& vertexArray, - const Array<int>& indexArray, - double& minEdgeLength, - double& meanEdgeLength, - double& medianEdgeLength, - double& maxEdgeLength, - double& minFaceArea, - double& meanFaceArea, - double& medianFaceArea, - double& maxFaceArea); - -private: - - /** Helper for weldAdjacency */ - static void weldBoundaryEdges( - Array<Face>& faceArray, - Array<Edge>& edgeArray, - Array<Vertex>& vertexArray); - -public: - - /** - Computes tangent and binormal vectors, - which provide a (mostly) consistent - parameterization over the surface for - effects like bump mapping. In the resulting coordinate frame, - T = x (varies with texture s coordinate), B = y (varies with negative texture t coordinate), - and N = z for a right-handed coordinate frame. If a billboard is vertical on the screen - in view of the camera, the tangent space matches the camera's coordinate frame. - - The vertex, texCoord, tangent, and binormal - arrays are parallel arrays. - - The resulting tangent and binormal might not be exactly - perpendicular to each other. They are guaranteed to - be perpendicular to the normal. - - @cite Max McGuire - */ - static void computeTangentSpaceBasis( - const Array<Vector3>& vertexArray, - const Array<Vector2>& texCoordArray, - const Array<Vector3>& vertexNormalArray, - const Array<Face>& faceArray, - Array<Vector3>& tangent, - Array<Vector3>& binormal); - - /** @deprecated */ - static void computeNormals( - const Array<Vector3>& vertexArray, - const Array<Face>& faceArray, - const Array< Array<int> >& adjacentFaceArray, - Array<Vector3>& vertexNormalArray, - Array<Vector3>& faceNormalArray); - - /** - Vertex normals are weighted by the area of adjacent faces. - Nelson Max showed this is superior to uniform weighting for - general meshes in jgt. - - @param vertexNormalArray Output. Unit length - @param faceNormalArray Output. Degenerate faces produce zero magnitude normals. Unit length - @see weld - */ - static void computeNormals( - const Array<Vector3>& vertexGeometry, - const Array<Face>& faceArray, - const Array<Vertex>& vertexArray, - Array<Vector3>& vertexNormalArray, - Array<Vector3>& faceNormalArray); - - /** Computes unit length normals in place using the other computeNormals methods. - If you already have a face array use another method; it will be faster. - @see weld*/ - static void computeNormals( - Geometry& geometry, - const Array<int>& indexArray); - - /** - Computes face normals only. Significantly faster (especially if - normalize is false) than computeNormals. - @see weld - */ - static void computeFaceNormals( - const Array<Vector3>& vertexArray, - const Array<Face>& faceArray, - Array<Vector3>& faceNormals, - bool normalize = true); - - /** - Classifies each face as a backface or a front face relative - to the observer point P (which is at infinity when P.w = 0). - A face with normal exactly perpendicular to the observer vector - may be classified as either a front or a back face arbitrarily. - */ - static void identifyBackfaces( - const Array<Vector3>& vertexArray, - const Array<Face>& faceArray, - const Vector4& P, - Array<bool>& backface); - - /** A faster version of identifyBackfaces for the case where - face normals have already been computed */ - static void identifyBackfaces( - const Array<Vector3>& vertexArray, - const Array<Face>& faceArray, - const Vector4& P, - Array<bool>& backface, - const Array<Vector3>& faceNormals); - - /** - Welds nearby and colocated elements of the <I>oldVertexArray</I> together so that - <I>newVertexArray</I> contains no vertices within <I>radius</I> of one another. - Every vertex in newVertexPositions also appears in oldVertexPositions. - This is useful for downsampling meshes and welding cracks created by artist errors - or numerical imprecision. - - The two integer arrays map indices back and forth between the arrays according to: - <PRE> - oldVertexArray[toOld[ni]] == newVertexArray[ni] - oldVertexArray[oi] == newVertexArray[toNew[ni]] - </PRE> - - Note that newVertexPositions is never longer than oldVertexPositions - and is shorter when vertices are welded. - - Welding with a large radius will effectively compute a lower level of detail for - the mesh. - - The welding method runs in roughly linear time in the length of oldVertexArray-- - a uniform spatial grid is used to achieve nearly constant time vertex collapses - for uniformly distributed vertices. - - It is sometimes desirable to keep the original vertex ordering but - identify the unique vertices. The following code computes - array canonical s.t. canonical[v] = first occurance of - a vertex near oldVertexPositions[v] in oldVertexPositions. - - <PRE> - Array<int> canonical(oldVertexPositions.size()), toNew, toOld; - computeWeld(oldVertexPositions, Array<Vector3>(), toNew, toOld, radius); - for (int v = 0; v < canonical.size(); ++v) { - canonical[v] = toOld[toNew[v]]; - } - </PRE> - - See also G3D::MeshAlg::weldAdjacency. - - @cite The method is that described as the 'Grouper' in Baum, Mann, Smith, and Winget, - Making Radiosity Usable: Automatic Preprocessing and Meshing Techniques for - the Generation of Accurate Radiosity Solutions, Computer Graphics vol 25, no 4, July 1991. - - @deprecated Use weld. - */ - static void computeWeld( - const Array<Vector3>& oldVertexPositions, - Array<Vector3>& newVertexPositions, - Array<int>& toNew, - Array<int>& toOld, - double radius = fuzzyEpsilon); - - /** - Modifies the face, edge, and vertex arrays in place so that - colocated (within radius) vertices are treated as identical. - Note that the vertexArray and corresponding geometry will - contain elements that are no longer used. In the vertexArray, - these elements are initialized to MeshAlg::Vertex() but not - removed (because removal would change the indexing). - - This is a good preprocessing step for algorithms that are only - concerned with the shape of a mesh (e.g. cartoon rendering, fur, shadows) - and not the indexing of the vertices. - - Use this method when you have already computed adjacency information - and want to collapse colocated vertices within that data without - disturbing the actual mesh vertices or indexing scheme. - - If you have not computed adjacency already, use MeshAlg::computeWeld - instead and compute adjacency information after welding. - - @deprecated Use weld. - - @param faceArray Mutated in place. Size is maintained (degenerate - faces are <b>not</B> removed). - @param edgeArray Mutated in place. May shrink if boundary edges - are welded together. - @param vertexArray Mutated in place. Size is maintained (duplicate - vertices contain no adjacency info). - */ - static void weldAdjacency( - const Array<Vector3>& originalGeometry, - Array<Face>& faceArray, - Array<Edge>& edgeArray, - Array<Vertex>& vertexArray, - double radius = fuzzyEpsilon); - - - /** - Counts the number of edges (in an edge array returned from - MeshAlg::computeAdjacency) that have only one adjacent face. - */ - static int countBoundaryEdges(const Array<Edge>& edgeArray); - - - /** - Generates an array of integers from start to start + n - 1 that have run numbers - in series then omit the next skip before the next run. Useful for turning - a triangle list into an indexed face set. - - Example: - <PRE> - createIndexArray(10, x); - // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - - createIndexArray(5, x, 2); - // x = [2, 3, 4, 5, 6, 7] - - createIndexArray(6, x, 0, 2, 1); - // x = [0, 1, 3, 4, 6, 7] - </PRE> - */ - static void createIndexArray( - int n, - Array<int>& array, - int start = 0, - int run = 1, - int skip = 0); - - /** - Computes a conservative, near-optimal axis aligned bounding box and sphere. - - @cite The bounding sphere uses the method from J. Ritter. An effcient bounding sphere. In Andrew S. Glassner, editor, Graphics Gems. Academic Press, Boston, MA, 1990. - - */ - static void computeBounds(const Array<Vector3>& vertex, class AABox& box, class Sphere& sphere); - - /** Computes bounds for a subset of the vertices. It is ok if vertices appear more than once in the index array. */ - static void computeBounds(const Array<Vector3>& vertex, const Array<int>& index, class AABox& box, class Sphere& sphere); - - /** - In debug mode, asserts that the adjacency references between the - face, edge, and vertex array are consistent. - */ - static void debugCheckConsistency( - const Array<Face>& faceArray, - const Array<Edge>& edgeArray, - const Array<Vertex>& vertexArray); - - /** - Generates a unit square in the X-Z plane composed of a grid of wCells x hCells - squares and then transforms it by xform. - - @param vertex Output vertices - @param texCoord Output texture coordinates - @param index Output triangle list indices - @param textureScale Lower-right texture coordinate - @param spaceCentered If true, the coordinates generated are centered at the origin before the transformation. - @param twoSided If true, matching top and bottom planes are generated. - \param elevation If non-NULL, values from this image are used as elevations. Apply an \a xform to adjust the scale - */ - static void generateGrid( - Array<Vector3>& vertex, - Array<Vector2>& texCoord, - Array<int>& index, - int wCells = 10, - int hCells = 10, - const Vector2& textureScale = Vector2(1,1), - bool spaceCentered = true, - bool twoSided = true, - const CoordinateFrame& xform = CoordinateFrame(), - const Image1::Ref& elevation = NULL); - - /** Converts quadlist (QUADS), - triangle fan (TRIANGLE_FAN), - tristrip(TRIANGLE_STRIP), and quadstrip (QUAD_STRIP) indices into - triangle list (TRIANGLES) indices and appends them to outIndices. */ - template<class IndexType> - static void toIndexedTriList( - const Array<IndexType>& inIndices, - MeshAlg::Primitive inType, - Array<IndexType>& outIndices) { - - debugAssert( - inType == PrimitiveType::TRIANGLE_STRIP || - inType == PrimitiveType::TRIANGLE_FAN || - inType == PrimitiveType::QUADS || - inType == PrimitiveType::QUAD_STRIP); - - const int inSize = inIndices.size(); - - switch(inType) { - case PrimitiveType::TRIANGLE_FAN: - { - debugAssert(inSize >= 3); - - int N = outIndices.size(); - outIndices.resize(N + (inSize - 2) * 3); - - for (IndexType i = 1, outIndex = N; i <= (inSize - 2); ++i, outIndex += 3) { - outIndices[outIndex] = inIndices[0]; - outIndices[outIndex + 1] = inIndices[i]; - outIndices[outIndex + 2] = inIndices[i + 1]; - } - - break; - } - - case PrimitiveType::TRIANGLE_STRIP: - { - debugAssert(inSize >= 3); - - int N = outIndices.size(); - outIndices.resize(N + (inSize - 2) * 3); - - bool atEven = false; - for (IndexType i = 0, outIndex = N; i <= (inSize - 2); ++i, outIndex += 3) { - if (atEven) { - outIndices[outIndex] = inIndices[i + 1]; - outIndices[outIndex + 1] = inIndices[i]; - outIndices[outIndex + 2] = inIndices[i + 2]; - atEven = false; - } else { - outIndices[outIndex] = inIndices[i]; - outIndices[outIndex + 1] = inIndices[i + 1]; - outIndices[outIndex + 2] = inIndices[i + 2]; - atEven = true; - } - } - - break; - } - - case PrimitiveType::QUADS: - { - debugAssert(inIndices.size() >= 4); - - int N = outIndices.size(); - outIndices.resize(N + (inSize / 4) * 3); - - for (IndexType i = 0, outIndex = N; i <= (inSize - 4); i += 4, outIndex += 6) { - outIndices[outIndex] = inIndices[i]; - outIndices[outIndex + 1] = inIndices[i + 1]; - outIndices[outIndex + 2] = inIndices[i + 3]; - outIndices[outIndex + 3] = inIndices[i + 1]; - outIndices[outIndex + 4] = inIndices[i + 2]; - outIndices[outIndex + 5] = inIndices[i + 3]; - } - - break; - } - - case PrimitiveType::QUAD_STRIP: - { - debugAssert(inIndices.size() >= 4); - - int N = outIndices.size(); - outIndices.resize(N + (inSize - 2) * 3); - - for (IndexType i = 0, outIndex = N; i <= (inSize - 2); i += 2, outIndex += 6) { - outIndices[outIndex] = inIndices[i]; - outIndices[outIndex + 1] = inIndices[i + 1]; - outIndices[outIndex + 2] = inIndices[i + 2]; - outIndices[outIndex + 3] = inIndices[i + 2]; - outIndices[outIndex + 4] = inIndices[i + 1]; - outIndices[outIndex + 5] = inIndices[i + 3]; - } - break; - } - default: - alwaysAssertM(false, "Illegal argument"); - } - } - -protected: - - /** - Helper for computeAdjacency. If a directed edge with index e already - exists from i0 to i1 then e is returned. If a directed edge with index e - already exists from i1 to i0, ~e is returned (the complement) and - edgeArray[e] is set to f. Otherwise, a new edge is created from i0 to i1 - with first face index f and its index is returned. - - @param vertexArray Vertex positions to use when deciding colocation. - - @param area Area of face f. When multiple edges of the same direction - are found between the same vertices (usually because of degenerate edges) - the face with larger area is kept in the edge table. - */ - static int findEdgeIndex( - const Array<Vector3>& vertexArray, - Array<Edge>& geometricEdgeArray, - int i0, int i1, int f, double area); -}; -} -#endif - |
