csgo-2018-source/utils/studiomdl/optimize_subd.h
2021-07-24 21:11:47 -07:00

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