Files
FC1/Cry3DEngine/StencilShadowConnectivity.h
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

805 lines
22 KiB
C++

//////////////////////////////////////////////////////////////////////
//
// CryEngine Source code
//
// File:StencilShadowConnectivity.h
// Declaration of class CStencilShadowConnectivity
//
// History:
// -:Created by Sergiy Migdalskiy <sergiy@crytek.de>
// 08/30/2002 include .cpp in header files, move to CryCommon, use in Cry3DEngine (Martin Mittring)
//
//////////////////////////////////////////////////////////////////////
// class CStencilShadowConnectivity
//
// This is pre-computed data for a model that's gonna cast stencil
// shadows, and whose vertices may change position ****, but the topology
// cannot change.
//
// Ok, to put it clear: for each model, you need one instance of this
// class initialized once. The model is allowed to deform, but is not
// allowed to change topology (add or remove faces as well as re-assign
// face vertices or even change face orientation).
//
// NOTE: The class is optimized for use with manifold geometry.
// This means you have to provide a model with unified normals and non-
// exploded triangles.
//
//
// IMPLEMENTATION NOTES should be in
// StencilShadowConnectivity.cpp
//
#pragma once
#ifndef _STENCIL_SHADOW_CONNECTIVITY_HDR_
#define _STENCIL_SHADOW_CONNECTIVITY_HDR_
#include <IEdgeConnectivityBuilder.h> // IStencilShadowConnectivity
// the empty connectivity info:
class CStencilShadowConnectivityNull:public IStencilShadowConnectivity
{
public:
//! don't forget to call Release for freeing the memory resources
virtual void Release( void ) {delete this;}
//! to keep the interface small and the access fast
//! /return pointer to the internal memory representation (only used within module 3DEngine)
const virtual CStencilShadowConnectivity *GetInternalRepresentation( void ) const {return NULL;}
//! for debugging and profiling
//! /param outVertexCount
//! /param outTriangleCount
virtual void GetStats( DWORD &outVertexCount, DWORD &outTriangleCount ) {outVertexCount = outTriangleCount = 0;}
//! Memorize the vertex buffer in this connectivity object. This is needed if a static object doesn't need this info
virtual void SetVertices(const Vec3d* pVertices, unsigned numVertices) {assert(0);}
//! Serializes this object to the given memory block; if it's NULL, only returns
//! the number of bytes required. If it's not NULL, returns the number of bytes written
//! (0 means error, insufficient space)
virtual unsigned Serialize (bool bSave, void* pStream, unsigned nSize, IMiniLog* pWarningLog = NULL)
{
return 0;
}
//! Calculates the size of this object
virtual void GetMemoryUsage (ICrySizer* pSizer) {}
#ifdef WIN32
//! /param szFilename filename with path (or relative) and extension
//! /return true=success, false otherwise
virtual bool DebugConnectivityInfo( const char *szFilename ){}
#endif
};
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
class CStencilShadowConnectivity : public IStencilShadowConnectivity
{
public:
//! number of vertices in the array referenced by the mesh
//! /return vertex count
unsigned numVertices() const
{
return m_numVertices;
}
//! number of edges in the array of edges
//! /return edge count
unsigned numEdges() const
{
return m_numEdges;
}
//! number of orphaned (open) edges
//! /return orphaned (open) count
virtual unsigned numOrphanEdges() const
{
return m_numOrphanEdges;
}
//! total number of faces
//! /return face count
unsigned numFaces ()const
{
return m_numFaces;
}
// -----------------
// This is the basic edge representation: two vertex indices.
// This is capable of being sorted.
struct BasicEdge
{
//! default constructor
BasicEdge () {}
//! constructor
//! /param nV0 start vertex index
//! /param nV1 end vertex index
BasicEdge (vindex nV0, vindex nV1)
{
m_nVertex[0] = nV0;
m_nVertex[1] = nV1;
}
//! start and end vertex index of the edge
vindex m_nVertex[2];
// alphabet sorting implementation
//! /param rEdge right side of the operator term
inline bool operator < (const BasicEdge& rEdge)const
{
if (m_nVertex[0] < rEdge.m_nVertex[0])
return true;
else
if (m_nVertex[0] == rEdge.m_nVertex[0])
return m_nVertex[1] < rEdge.m_nVertex[1];
else
return false;
}
//! get teh start or end vertex index
//! /param nIndex 0/1
inline unsigned operator [] (int nIndex)const
{
assert(nIndex==0 || nIndex==1);
return m_nVertex[nIndex];
}
//! copy the basic edge, designed for ancestors
//! /param beEdge
void setBasicEdge (const BasicEdge& beEdge)
{
m_nVertex[0] = beEdge.m_nVertex[0];
m_nVertex[1] = beEdge.m_nVertex[1];
}
};
// -----------------
// connection of the edge to the face: may contain, depending on the implementation,
// the face index, pointer to it, vertex, pointer to it
struct EdgeFace
{
//! default constructor
EdgeFace (){}
//! constructor
//! /param nFace face index
//! /param nVertex vertex index
EdgeFace (vindex nFace, vindex nVertex): m_nFace(nFace), m_nVertex(nVertex) {}
//! /return face index
inline vindex getFaceIndex ()const {return m_nFace;}
//! /return vertex index
inline vindex getVertexIndex() const {return m_nVertex;}
vindex m_nFace; //!< face index
vindex m_nVertex; //!< face vertex
};
// -----------------
// This is a primary connectivity edge data structure:
// the basic edge (start and end vertices, inherited from BasicEdge)
// and the opposite face edges
class Edge: public BasicEdge
{
//! this and opposite face 3rd vertex.
//! in "this" face, the edge goes CCW (natural) direction [0],
//! and in "opposite" face it goes CW (reverse) direction [1]
EdgeFace m_Face[2];
public:
//! default constructor
Edge () {}
//! constructor
//! /param be edge datastructure
//! /param ef0 in this triangle the edge goes CCW (natural) direction
//! /param ef1 in this triangle the edge goes CW (reverse) direction
Edge (const BasicEdge& be, const EdgeFace& ef0, const EdgeFace& ef1):
BasicEdge(be)
{
m_Face[0] = ef0;
m_Face[1] = ef1;
}
//! /param nFace 0/1
//! /return reference to the face data structure
const EdgeFace& getFace(int nFace) const
{
assert(nFace==0 || nFace==1);
return m_Face[nFace];
}
//! /param nFace 0/1
//! /param ef reference to the edge datastructure
void setFace (int nFace, const EdgeFace& ef)
{
assert(nFace==0 || nFace==1);
m_Face[nFace] = ef;
}
};
// -----------------
// orphan edge - an edge with only one face attached to it (boundary)
class OrphanEdge: public BasicEdge
{
EdgeFace m_Face; //!<
public:
//! default constructor
OrphanEdge () {}
// constructor
OrphanEdge (const BasicEdge& be, const EdgeFace& ef):
BasicEdge (be),
m_Face (ef)
{}
const EdgeFace& getFace()const {return m_Face;}
void setFace (const EdgeFace& ef) {m_Face = ef;}
};
// -----------------
// face - 3 vertices
class Face
{
public:
vindex m_nVertex[3]; //!<
//! default constructur
Face () {}
//! constructor
//! /param nV0 first vertex index
//! /param nV1 second vertex index
//! /param nV2 thired vertex index
Face (vindex nV0, vindex nV1, vindex nV2)
{
m_nVertex[0] = nV0;
m_nVertex[1] = nV1;
m_nVertex[2] = nV2;
}
//! get the index of one triangle vertex
//! /param nVtx 0/1/2
//! /return index of that triangle vertex
const vindex getVertex (int nVtx) const
{
assert(nVtx==0 || nVtx==1 || nVtx==2);
return m_nVertex[nVtx];
}
//! set the index of one triangle vertex
//! /param nVtx 0/1/2
//! /param nIndex index of the triangle vertex no <nVtx>
void setVertex (int nVtx, vindex nIndex)
{
assert(nVtx==0 || nVtx==1 || nVtx==2);
m_nVertex[nVtx] = nIndex;
}
};
// -----------------
//! /aparam nEdge 0..m_numEdges-1
//! /return the nEdge'th edge
const Edge& getEdge (int nEdge)const
{
assert(m_pEdges);
assert(nEdge>=0);
assert((unsigned)nEdge<m_numEdges);
return m_pEdges[nEdge];
}
// returns the nEdge's orphaned edge
//! /param nEdge 0..m_numOrphanEdges-1
//! /return
const OrphanEdge& getOrphanEdge(int nEdge)const
{
assert(m_pOrphanEdges);
assert(nEdge>=0);
assert((unsigned)nEdge<m_numOrphanEdges);
return m_pOrphanEdges[nEdge];
}
//! returns the nFace's face
//! /param 0..m_numFaces-1
//! /return reference to the face
const Face& getFace (int nFace) const
{
assert(m_pFaces);
assert(nFace>=0);
assert((unsigned)nFace<m_numFaces);
return m_pFaces[nFace];
}
// copies the array of referred faces into internal array
// this is specially optimized for faster cooperation with the Builder
// The number of faces is determined from the earlier given edges, so
// NOTE: becareful to call the SetOrphanEdges BEFORE THIS FUNCTION
// DO NOT call twice, this is only designed to be called once after construction
void SetFaces (const std::vector<Face>& arrFaces)
{
assert (!m_pFaces && m_numFaces <= arrFaces.size());
if (!arrFaces.empty())
{
m_pFaces = new Face[m_numFaces = arrFaces.size()];
for (unsigned i = 0; i < m_numFaces; ++i)
m_pFaces[i] = arrFaces[i];
}
}
// destruct the object (it's only constructed by the Builder)
// the virtual ensures that the function releases the object in the same module where it was allocated:
// because the VTable was also allocated in the same module
virtual void Release ()
{
assert(this);
// this is a counterpart to the new that's called within the
// CStencilShadowConnectivityBuilder::ConstructConnectivity() method
delete this;
}
const virtual CStencilShadowConnectivity *GetInternalRepresentation( void ) const
{
return(this);
}
// from IStencilShadowConnectivity
virtual bool DebugConnectivityInfo( const char *szFilename )
{
// used only for debugging
FILE *out=fopen(szFilename,"w");
if(!out)return(false);
fprintf(out,"%d Edges:\n",m_numEdges);
for(unsigned i=0;i<m_numEdges;i++)
{
fprintf(out," face={%d,%d}, vertex={%d,%d}\n",
(m_pEdges[i].getFace(0)).getFaceIndex(),
(m_pEdges[i].getFace(1)).getFaceIndex(),
m_pEdges[i].m_nVertex[0],
m_pEdges[i].m_nVertex[1]);
}
fprintf(out,"%d OrphanEdges:\n",m_numOrphanEdges);
for(unsigned i=0;i<m_numOrphanEdges;i++)
#if !defined(LINUX)
fprintf(out," face={%d}, vertex={%d,%d}\n",m_pOrphanEdges[i].getFace(),m_pOrphanEdges[i].m_nVertex[0],m_pOrphanEdges[i].m_nVertex[1]);
#else
fprintf(out,", vertex={%d,%d}\n",m_pOrphanEdges[i].m_nVertex[0],m_pOrphanEdges[i].m_nVertex[1]);//face info does not compile, no time to make it more correct here
#endif//LINUX
fprintf(out,"%d Vertices:\n",m_numVertices);
fprintf(out,"Faces:\n",m_numFaces);
for(unsigned i=0;i<m_numFaces;i++)
fprintf(out," vertex indices={%d,%d,%d}\n",m_pFaces[i].getVertex(0),m_pFaces[i].getVertex(1),m_pFaces[i].getVertex(2));
fclose(out);
return(true);
}
//! constructor, only makes an empty object that's good for deserializing only
CStencilShadowConnectivity ()
{
m_numEdges = m_numOrphanEdges = m_numVertices = m_numFaces = 0;
m_pOrphanEdges = NULL;
m_pFaces = NULL;
m_pEdges = NULL;
m_pPlanes = NULL;
m_pVertices = NULL;
}
struct Plane
{
Vec3d vNormal;
float fDistance;
Plane(){}
Plane (const Vec3d& v0, const Vec3d& v1, const Vec3d& v2)
{
vNormal = (v1-v0)^(v2-v0);
fDistance = (v0*vNormal);
}
float apply (const Vec3d& v)const
{
return vNormal * v - fDistance;
}
};
//! Calculates the size of this object
void GetMemoryUsage(ICrySizer* pSizer)
{
pSizer->AddObject(this,Serialize (true, NULL,0));
}
protected:
//! constructor is only called within 3DEngine
//! /param pEdges - array of nNumEdges edges
//! /param nNumEdges
CStencilShadowConnectivity( const std::vector<Edge>& arrEdges)
{
m_pOrphanEdges=NULL;
m_pFaces=NULL;
m_numOrphanEdges=0;
// find the max vertex index to put it into m_nVertices
m_numVertices = 0;
m_numFaces = 0;
for (std::vector<Edge>::const_iterator it = arrEdges.begin(); it != arrEdges.end(); ++it)
{
UseBasicEdge (*it);
UseEdgeFace (it->getFace(0));
UseEdgeFace (it->getFace(1));
}
m_numEdges = arrEdges.size();
if(m_numEdges)
{
m_pEdges = new Edge[m_numEdges];
for (unsigned i = 0; i < m_numEdges; ++i)
m_pEdges[i] = arrEdges[i];
}
else
m_pEdges=0;
m_pPlanes = NULL;
m_pVertices = NULL;
}
void SetPlanes (const Plane* pPlanes, unsigned numPlanes)
{
if (m_pPlanes)
delete [] m_pPlanes;
if (pPlanes)
{
assert (numPlanes >= m_numFaces);
m_pPlanes = new Plane[m_numFaces];
memcpy (m_pPlanes, pPlanes, sizeof(Plane) * m_numFaces);
}
else
m_pPlanes = NULL;
}
void SetVertices(const Vec3d* pVertices, unsigned numVertices)
{
if (m_pVertices)
delete[]m_pVertices;
if (pVertices)
{
assert (numVertices >= m_numVertices);
m_pVertices = new Vec3d[m_numVertices];
memcpy (m_pVertices, pVertices, sizeof(Vec3d)*m_numVertices);
}
else
m_pVertices = NULL;
}
// remaps all vertex indices and memorizes the passed "new" vertex array (in new indexation)
void SetRemapVertices (const vindex*pMap, unsigned numMapEntries, const Vec3d* pNewVertices, unsigned numNewVertices)
{
if (m_pVertices)
delete[]m_pVertices;
assert (pNewVertices);
// we collected information about the vertices before . The number of used vertices is in
// m_numVertices. We assume the passed new vertex map can not make this number larger, because
// its sole purpose is optimization of number of vertex indices used (for storing the vertex info inside)
assert (numNewVertices <= m_numVertices);
m_numVertices = numNewVertices;
m_pVertices = new Vec3d[numNewVertices];
memcpy (m_pVertices, pNewVertices, sizeof(Vec3d)*numNewVertices);
remapVertexIndices (pMap, numMapEntries);
}
// can be destructed only from within Release()
virtual ~CStencilShadowConnectivity(void)
{
if (m_pEdges) delete[] m_pEdges;
if (m_pOrphanEdges) delete[] m_pOrphanEdges;
if (m_pFaces) delete[] m_pFaces;
if (m_pPlanes) delete[] m_pPlanes;
if (m_pVertices) delete[] m_pVertices;
}
// makes sure that the given vertex index fits into the range 0..m_nVertices
// by expanding (increasing) m_nVertices
void UseVertex(vindex nVertex)
{
if (nVertex >= m_numVertices)
m_numVertices = nVertex + 1;
}
// makes sure that the given face index fits into the range 0..m_nFaces
// by expanding (increasing) m_nFaces
void UseFace (vindex nFace)
{
if (nFace >= m_numFaces)
m_numFaces = nFace + 1;
}
// copies the list of orphaned edges into internal array
// this is specially optimized for faster cooperation with the Builder
// DO NOT call twice, this is only designed to be called once after construction
typedef std::map<BasicEdge, EdgeFace> OrphanEdgeMap;
// copies the list of orphaned edges into internal array
// this is specially optimized for faster cooperation with the Builder
// DO NOT call twice, this is only designed to be called once after construction
void SetOrphanEdges (const OrphanEdgeMap& mapOrphanEdge)
{
m_numOrphanEdges = mapOrphanEdge.size();
m_pOrphanEdges = new OrphanEdge[m_numOrphanEdges];
OrphanEdge* pEdge = m_pOrphanEdges;
// copy the content of the orphan edge map into the array
for (OrphanEdgeMap::const_iterator it = mapOrphanEdge.begin(); it != mapOrphanEdge.end(); ++it)
{
pEdge->setBasicEdge (it->first);
pEdge->setFace (it->second);
UseBasicEdge (*pEdge);
UseEdgeFace (pEdge->getFace());
++pEdge;
}
}
// makes sure that the vertices/faces referenced by the edge are in account by the m_numFaces and m_numVertices
void UseBasicEdge (const BasicEdge& beEdge)
{
UseVertex(beEdge[0]);
UseVertex(beEdge[1]);
}
// makes sure that the vertices/faces referenced by the edge are in account by the m_numFaces and m_numVertices
void UseEdgeFace (const EdgeFace& efEdge)
{
UseFace (efEdge.getFaceIndex());
UseVertex(efEdge.getVertexIndex());
}
//! for debugging and profiling
//! /param outVertexCount
//! /param outTriangleCount
virtual void GetStats( DWORD &outVertexCount, DWORD &outTriangleCount )
{
outVertexCount=m_numVertices;
outTriangleCount=m_numFaces;
}
public:
// the version of the stream
enum {g_nSerialVersion = 2};
//! Deserializes this object. Returns the number of bytes read. 0 means error
//! pWarningLog is used to put warnings about deserialized connectivity
unsigned Deserialize (void *pStream, unsigned nSize, IMiniLog* pWarningLog = NULL)
{
unsigned* pHeader = (unsigned*)pStream;
if (nSize < 5 * sizeof(unsigned))
return 0; // we should have the header in place
if (*(pHeader++) != g_nSerialVersion) // version is incompatible
return 0;
m_numEdges = *(pHeader++);
m_numOrphanEdges = *(pHeader++);
m_numVertices = *(pHeader++);
m_numFaces = *(pHeader++);
unsigned numPlanes = *(pHeader++);
assert (numPlanes == 0 || numPlanes == m_numFaces);
unsigned numVertices = *(pHeader++);
assert (numVertices == 0 || numVertices == m_numVertices);
unsigned nRequiredSize =
sizeof(unsigned) +
sizeof(m_numEdges) + m_numEdges * sizeof(Edge) +
sizeof(m_numOrphanEdges) + m_numOrphanEdges * sizeof(OrphanEdge) +
sizeof(m_numVertices) +
sizeof(m_numFaces) + m_numFaces * sizeof(Face) +
sizeof(numPlanes) + numPlanes * sizeof(Plane)+
sizeof(numVertices) + numVertices * sizeof(Vec3d);
if(m_pEdges) delete[] m_pEdges;
if(m_pOrphanEdges) delete[] m_pOrphanEdges;
if(m_pFaces) delete[] m_pFaces;
if(m_pPlanes) delete[] m_pPlanes;
if (m_pVertices) delete []m_pVertices;
if (nSize < nRequiredSize)
{
m_pEdges = NULL;
m_pOrphanEdges = NULL;
m_pFaces = NULL;
m_numEdges = 0;
m_numOrphanEdges = 0;
m_numVertices = 0;
m_numFaces = 0;
// incompatible stream
return 0;
}
m_pEdges = new Edge [m_numEdges];
m_pOrphanEdges = new OrphanEdge [m_numOrphanEdges];
m_pFaces = new Face [m_numFaces];
m_pPlanes = numPlanes?new Plane[numPlanes]:NULL;
m_pVertices = numVertices?new Vec3d[numVertices]:NULL;
Edge* pEdgeData = (Edge*)pHeader;
memcpy (m_pEdges, pEdgeData, m_numEdges*sizeof(Edge));
OrphanEdge* pOrphanEdgeData = (OrphanEdge*)(pEdgeData + m_numEdges);
memcpy (m_pOrphanEdges, pOrphanEdgeData, m_numOrphanEdges*sizeof(OrphanEdge));
Face* pFaceData = (Face*)(pOrphanEdgeData + m_numOrphanEdges);
memcpy (m_pFaces, pFaceData, m_numFaces * sizeof(Face));
Plane* pPlanes = (Plane*)(pFaceData+m_numFaces);
if (numPlanes)
memcpy (m_pPlanes, pPlanes, numPlanes* sizeof(Plane));
Vec3d* pVertices = (Vec3d*)(pPlanes + numPlanes);
if (numVertices)
memcpy (m_pVertices, pVertices, sizeof(Vec3d)*numVertices);
#if !defined(LINUX)
if (m_numOrphanEdges && pWarningLog)
pWarningLog->LogWarning("Connectivity warning: there are %d open edges (%d closed, %d faces, %d planes, %d vertices)", m_numOrphanEdges, m_numEdges, m_numFaces, numPlanes, numVertices);
#endif
return nRequiredSize;
}
//! Serializes this object to the given memory block; if it's NULL, only returns
//! the number of bytes required. If it's not NULL, returns the number of bytes written
//! (0 means error, insufficient space)
unsigned Serialize (bool bSave, void* pStream, unsigned nSize, IMiniLog* pWarningLog = NULL)
{
if (!bSave)
return Deserialize (pStream, nSize, pWarningLog);
// calculate the required size of the buffer
unsigned
numPlanes = m_pPlanes?m_numFaces:0,
numVertices = m_pVertices?m_numVertices:0,
nRequiredSize =
sizeof(unsigned) +
sizeof(m_numEdges) + m_numEdges * sizeof(Edge) +
sizeof(m_numOrphanEdges) + m_numOrphanEdges * sizeof(OrphanEdge) +
sizeof(m_numVertices) +
sizeof(m_numFaces) + m_numFaces * sizeof(Face) +
sizeof(numPlanes) + numPlanes * sizeof(Plane)+
sizeof(numVertices) + numVertices * sizeof(Vec3d);
if (pStream)
{
if (nSize < nRequiredSize)
return 0; // insufficient space in the pStream buffer
unsigned* pHeader = (unsigned*)pStream;
*(pHeader++) = g_nSerialVersion; // version of the stream
*(pHeader++) = m_numEdges;
*(pHeader++) = m_numOrphanEdges;
*(pHeader++) = m_numVertices;
*(pHeader++) = m_numFaces;
*(pHeader++) = numPlanes;
*(pHeader++) = numVertices;
Edge* pEdgeData = (Edge*)pHeader;
memcpy (pEdgeData, m_pEdges, m_numEdges*sizeof(Edge));
OrphanEdge* pOrphanEdgeData = (OrphanEdge*)(pEdgeData + m_numEdges);
memcpy (pOrphanEdgeData, m_pOrphanEdges, m_numOrphanEdges*sizeof(OrphanEdge));
Face* pFaceData = (Face*)(pOrphanEdgeData + m_numOrphanEdges);
memcpy (pFaceData, m_pFaces, m_numFaces * sizeof(Face));
Plane* pPlanes = (Plane*)(pFaceData+m_numFaces);
if (m_pPlanes)
memcpy (pPlanes, m_pPlanes, numPlanes * sizeof(Plane));
Vec3d* pVertices = (Vec3d*)(pPlanes+numPlanes);
if (m_pVertices)
memcpy (pVertices, m_pVertices, numVertices * sizeof(Vec3d));
}
return nRequiredSize;
}
// the plane equation, x*n+d == 0
bool hasPlanes() const {return m_pPlanes != NULL;}
const Plane&getPlane (unsigned i)const {assert(i<m_numFaces && m_pPlanes);return m_pPlanes[i];}
const Vec3d* getVertices() const {return m_pVertices;}
bool IsStandalone() const {return m_pPlanes != NULL && m_pVertices!= NULL;}
void remapVertexIndices(const vindex*pMap, unsigned nMapSize)
{
unsigned i;
#define REMAP(X) assert((X) < nMapSize);\
(X) = pMap[X];\
assert ((vindex)(X) != (vindex)-1 && (X) < m_numVertices)
for(i=0;i<m_numEdges;i++)
{
REMAP(m_pEdges[i].m_nVertex[0]);
REMAP(m_pEdges[i].m_nVertex[1]);
}
for(i=0;i<m_numOrphanEdges;i++)
{
REMAP(m_pOrphanEdges[i].m_nVertex[0]);
REMAP(m_pOrphanEdges[i].m_nVertex[1]);
}
for(i=0;i<m_numFaces;i++)
{
REMAP(m_pFaces[i].m_nVertex[0]);
REMAP(m_pFaces[i].m_nVertex[1]);
REMAP(m_pFaces[i].m_nVertex[2]);
}
#undef REMAP
}
private:
friend class CStencilShadowConnectivityBuilder;
friend class CStencilShadowStaticConnectivityBuilder;
// the array of normal edges (with two adjacent faces)
unsigned m_numEdges; //!<
Edge* m_pEdges; //!<
// the array of orphaned edges (with only one face attached)
unsigned m_numOrphanEdges; //!<
OrphanEdge* m_pOrphanEdges; //!<
private:
// number of vertices in the array referenced by the mesh
unsigned m_numVertices; //!<
// the faces
unsigned m_numFaces; //!< number of faces in the array referenced by the mesh
Face* m_pFaces; //!<
Plane* m_pPlanes; //!< if not NULL, then use these normals instead of computing them on the fly; 1 face - 1 normal
Vec3d* m_pVertices;
};
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
#endif // _STENCIL_SHADOW_CONNECTIVITY_HDR_