|
|
#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
|