172 lines
5.8 KiB
C++
172 lines
5.8 KiB
C++
#ifndef OPTIMIZE_SUBD_H
|
|
#define OPTIMIZE_SUBD_H
|
|
#pragma once
|
|
|
|
#include "optimize.h"
|
|
#include "studio.h"
|
|
|
|
// Maximum number of points that can be part of a subd quad.
|
|
// This includes the 4 interior points of the quad, plus the 1-ring neighborhood
|
|
#define MAX_SUBD_POINTS 32
|
|
|
|
#define MAX_SUBD_ONERING_POINTS (MAX_SUBD_POINTS + 4*5)
|
|
|
|
#define CORNER_WITH_SMOOTHBNDTANGENTS 2
|
|
|
|
namespace OptimizedModel
|
|
{
|
|
|
|
struct SubD_Face_t;
|
|
|
|
// minimal HalfEdge structure, embedded in a face (#halfedges = #vertexperface)
|
|
struct HalfEdge
|
|
{
|
|
HalfEdge *twin;
|
|
HalfEdge *sectorStart;
|
|
unsigned char localID; // local halfedge/vertex ID
|
|
SubD_Face_t *patch;
|
|
|
|
inline HalfEdge *NextInFace();
|
|
inline HalfEdge *PrevInFace();
|
|
inline HalfEdge *NextByHead();
|
|
inline HalfEdge *PrevByHead();
|
|
inline HalfEdge *NextByTail();
|
|
inline HalfEdge *PrevByTail();
|
|
|
|
inline unsigned short &BndEdge();
|
|
};
|
|
|
|
struct Orientation
|
|
{
|
|
uint8 u : 1;
|
|
uint8 v : 1;
|
|
uint8 uSet : 1;
|
|
uint8 vSet : 1;
|
|
|
|
void SetU( bool b )
|
|
{
|
|
Assert( !uSet );
|
|
u = b;
|
|
uSet = true;
|
|
}
|
|
|
|
void SetV( bool b )
|
|
{
|
|
Assert( !vSet );
|
|
v = b;
|
|
vSet = true;
|
|
}
|
|
|
|
Orientation() { uSet = vSet = false; }
|
|
};
|
|
|
|
struct SubD_Face_t
|
|
{
|
|
unsigned short patchID; // for building our 4 sets of watertight UVs
|
|
unsigned short vtxIDs[4];
|
|
|
|
unsigned short oneRing[MAX_SUBD_ONERING_POINTS];
|
|
unsigned short vtx1RingSize[4]; // Pre-calculated prefixes for the first 4 points
|
|
unsigned short vtx1RingCenterQuadOffset[4]; // start of inner quad vertices in vertex 1-ring
|
|
|
|
unsigned short valences[4]; // Valences for the first 4 points in current sector
|
|
unsigned short minOneRingIndex[4]; // Location in oneRing array to start applying stencil (determined by lowest position index)
|
|
|
|
unsigned short bndVtx[4]; // is vertex on the boundary?
|
|
unsigned short bndEdge[4]; // is associated edge on the boundary?
|
|
unsigned short cornerVtx[4]; // should a boundary-vertex be treated as a corner?
|
|
|
|
unsigned short nbCornerVtx[4]; // bitfield, for all on-edge neighbors record if corner vertices
|
|
|
|
unsigned short loopGapAngle[4];
|
|
|
|
unsigned short edgeBias[8];
|
|
|
|
unsigned short vUV0[4]; // Vert index for Interior TexCoord (for vtxIDs[0-3])
|
|
unsigned short vUV1[4]; // Vert index for Parametric V TexCoord (for vtxIDs[0-3])
|
|
unsigned short vUV2[4]; // Vert index for Parametric U TexCoord (for vtxIDs[0-3])
|
|
unsigned short vUV3[4]; // Vert index for Corner TexCoord (for vtxIDs[0-3])
|
|
|
|
HalfEdge halfEdges[4];
|
|
|
|
void SetEdgeBias(int localID, float f0, float f1)
|
|
{
|
|
if (halfEdges[localID].twin==NULL) return;
|
|
edgeBias[2*localID] = f0 * 32768.0f;
|
|
edgeBias[2*localID+1] = f1 * 32768.0f;
|
|
halfEdges[localID].twin->patch->edgeBias[ 2*halfEdges[localID].twin->localID+1 ] = (1.0f - f0) * 32768.0f;
|
|
halfEdges[localID].twin->patch->edgeBias[ 2*halfEdges[localID].twin->localID ] = (1.0f - f1) * 32768.0f;
|
|
}
|
|
};
|
|
|
|
inline HalfEdge *HalfEdge::NextInFace()
|
|
{
|
|
static int MOD4[8] = {0,1,2,3,0,1,2,3};
|
|
return &patch->halfEdges[MOD4[localID+1]];
|
|
}
|
|
inline HalfEdge *HalfEdge::PrevInFace()
|
|
{
|
|
static int MOD4[8] = {0,1,2,3,0,1,2,3};
|
|
return &patch->halfEdges[MOD4[localID+3]];
|
|
}
|
|
inline HalfEdge *HalfEdge::NextByHead() { return (twin==NULL)? NULL : twin->PrevInFace(); }
|
|
inline HalfEdge *HalfEdge::PrevByHead() { return NextInFace()->twin; }
|
|
inline HalfEdge *HalfEdge::NextByTail() { return PrevInFace()->twin; }
|
|
inline HalfEdge *HalfEdge::PrevByTail() { return (twin==NULL)? NULL : twin->NextInFace(); }
|
|
|
|
inline bool FaceIsRegular( SubD_Face_t *patch )
|
|
{
|
|
return ( patch->valences[0] == 4 && patch->valences[1] == 4 && patch->valences[2] == 4 && patch->valences[3] == 4 ) &&
|
|
( patch->bndVtx[0] == false && patch->bndVtx[1] == false && patch->bndVtx[2] == false && patch->bndVtx[3] == false ) &&
|
|
( patch->bndEdge[0] == false && patch->bndEdge[1] == false && patch->bndEdge[2] == false && patch->bndEdge[3] == false );
|
|
}
|
|
|
|
inline unsigned short &HalfEdge::BndEdge() { return patch->bndEdge[localID]; }
|
|
|
|
typedef CUtlVector<SubD_Face_t> SubD_FaceList_t;
|
|
typedef CUtlVector<Vertex_t> SubD_VertexList_t;
|
|
typedef const mstudio_meshvertexdata_t *SubD_VertexData_t;
|
|
|
|
class COptimizeSubDBuilder
|
|
{
|
|
public:
|
|
COptimizeSubDBuilder(SubD_FaceList_t& subDFaceList, const SubD_VertexList_t& vertexList, const SubD_VertexData_t &vertexData, bool bIsTagged, bool bMendVertices=true );
|
|
void ProcessPatches( bool bIsTagged, bool bMendVertices );
|
|
|
|
HalfEdge *FindTwin(HalfEdge &he);
|
|
void CheckForManifoldMesh( );
|
|
void BuildNeighborhoodInfo( );
|
|
|
|
void ComputeSectorStart( SubD_Face_t *quad, unsigned short k );
|
|
void ComputePerVertexInfo( SubD_Face_t *baseQuad, unsigned short baseLocalID );
|
|
void ComputeSectorAngle( SubD_Face_t *baseQuad, unsigned short baseLocalID );
|
|
void ComputeNbCorners( SubD_Face_t *baseQuad, unsigned short baseLocalID );
|
|
void ComputeSectorOneRing( SubD_Face_t *baseQuad, unsigned short baseLocalID );
|
|
unsigned short FindNeighborVertex( HalfEdge** ppOutMirrorEdge, const HalfEdge *pHalfEdge, int indexAlongEdge );
|
|
void ComputeNeighborTexcoords( SubD_Face_t *baseQuad );
|
|
void MendVertices( SubD_Face_t *quad, unsigned short baseLocalID );
|
|
void TagCreases();
|
|
|
|
private:
|
|
|
|
// Routines used for orienting faces for edge consistency
|
|
void RotateOnce( SubD_Face_t *pFace );
|
|
void RotateFace( SubD_Face_t *pFace, int nTimesToRotate );
|
|
int FaceEdgeIndex( SubD_Face_t *pFace, HalfEdge *pEdge );
|
|
void Propagate( CUtlVector<Orientation> & orientationArray, HalfEdge *pEdge, bool dir );
|
|
void ConsistentPatchOrientation();
|
|
void RemapIndices();
|
|
void SetMinOneRingIndices();
|
|
|
|
SubD_FaceList_t &m_faceList;
|
|
const SubD_VertexList_t &m_vtxList;
|
|
const SubD_VertexData_t &m_vtxData;
|
|
int m_numPatches;
|
|
CUtlVector<int> m_IndexRemapTable;
|
|
};
|
|
|
|
|
|
}; // namespace OptimizedModel
|
|
|
|
#endif // OPTIMIZE_SUBD_H
|