//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======// // // Purpose: // //=============================================================================// #ifndef MAPFACE_H #define MAPFACE_H #ifdef _WIN32 #pragma once #endif #pragma warning(push, 1) #pragma warning(disable:4701 4702 4530) #include #pragma warning(pop) #include "hammer_mathlib.h" #include "MapAtom.h" #include "DispManager.h" #include "mathlib/Vector4d.h" #include "UtlVector.h" #include "Color.h" #include "smoothinggroupmgr.h" #include "detailobjects.h" class CCheckFaceInfo; class IEditorTexture; class CRender; class CRender3D; class CChunkFile; class CSaveInfo; class IMaterial; class CMapWorld; struct MapFaceRender_t; class CMeshBuilder; class IMesh; struct LoadFace_t; enum EditorRenderMode_t; enum ChunkFileResult_t; #define DEFAULT_TEXTURE_SCALE 0.25 #define DEFAULT_LIGHTMAP_SCALE 16 #define SMOOTHING_GROUP_MAX_COUNT 32 #define SMOOTHING_GROUP_DEFAULT 0 // // Flags for CMapFace::CopyFrom. // #define COPY_FACE_PLANE 0x00000001 // Copies only the face's plane. Used for carving. #define COPY_FACE_POINTS 0x00000002 // Copies the face's points and plane. // // Used for storing the extrema of a face. Each element of the Extents_t array // contains a point that represents a local extreme along a particular dimension. // enum { EXTENTS_XMIN = 0, EXTENTS_XMAX, EXTENTS_YMIN, EXTENTS_YMAX, EXTENTS_ZMIN, EXTENTS_ZMAX, NUM_EXTENTS_DIMS, }; typedef Vector Extents_t[NUM_EXTENTS_DIMS]; struct PLANE { Vector normal; float dist; Vector planepts[3]; }; typedef struct { int numpoints; Vector *p; // variable sized } winding_t; enum FaceOrientation_t { FACE_ORIENTATION_FLOOR = 0, FACE_ORIENTATION_CEILING, FACE_ORIENTATION_NORTH_WALL, FACE_ORIENTATION_SOUTH_WALL, FACE_ORIENTATION_EAST_WALL, FACE_ORIENTATION_WEST_WALL, FACE_ORIENTATION_INVALID }; // // Both an enumeration and bitflags. Used as bitflags when querying a face for its texture // alignment because it could be world aligned and face aligned at the same time. // enum TextureAlignment_t { TEXTURE_ALIGN_NONE = 0x0000, TEXTURE_ALIGN_WORLD = 0x0001, TEXTURE_ALIGN_FACE = 0x0002, TEXTURE_ALIGN_QUAKE = 0x0004 }; enum TextureJustification_t { TEXTURE_JUSTIFY_NONE = 0, TEXTURE_JUSTIFY_TOP, TEXTURE_JUSTIFY_BOTTOM, TEXTURE_JUSTIFY_LEFT, TEXTURE_JUSTIFY_CENTER, TEXTURE_JUSTIFY_RIGHT, TEXTURE_JUSTIFY_FIT, TEXTURE_JUSTIFY_MAX }; #define INIT_TEXTURE_FORCE 0x0001 #define INIT_TEXTURE_AXES 0x0002 #define INIT_TEXTURE_ROTATION 0x0004 #define INIT_TEXTURE_SHIFT 0x0008 #define INIT_TEXTURE_SCALE 0x0010 #define INIT_TEXTURE_ALL (INIT_TEXTURE_AXES | INIT_TEXTURE_ROTATION | INIT_TEXTURE_SHIFT | INIT_TEXTURE_SCALE) // // Flags for CreateFace. // #define CREATE_FACE_PRESERVE_PLANE 0x0001 // Hack to prevent plane from being recalculated while building a solid from its planes. #define CREATE_FACE_CLIPPING 0x0002 // // Serialized data structure. Do not modify! // struct TEXTURE_21 { char texture[MAX_PATH]; float rotate; float shift[2]; float scale[2]; BYTE smooth; BYTE material; DWORD q2surface; DWORD q2contents; DWORD q2value; }; // // Post 2.1 explicit texture U/V axes were added. // // Serialized data structure. Do not modify! // struct TEXTURE_33 { char texture[MAX_PATH]; float UAxis[4]; // Must remain float[4] for RMF serialization. float VAxis[4]; // Must remain float[4] for RMF serialization. float rotate; float scale[2]; BYTE smooth; BYTE material; DWORD q2surface; DWORD q2contents; int nLightmapScale; }; struct TEXTURE { char texture[MAX_PATH]; Vector4D UAxis; Vector4D VAxis; float rotate; float scale[2]; BYTE smooth; BYTE material; DWORD q2surface; DWORD q2contents; int nLightmapScale; TEXTURE& operator=( TEXTURE const& src ) { // necessary since operator= is private for UAxis memcpy( this, &src, sizeof(TEXTURE) ); return *this; } }; #define FACE_FLAGS_NOSHADOW 1 #define FACE_FLAGS_NODRAW_IN_LPREVIEW 2 class CMapFace : public CMapAtom { public: CMapFace(void); ~CMapFace(void); // If bRescaleTextureCoordinates is true, then it will rescale and reoffset the texture coordinates // so that the texture is in the same apparent spot as the old texture (if they are different sizes). void SetTexture(const char *pszNewTex, bool bRescaleTextureCoordinates = false); void SetTexture(IEditorTexture *pTexture, bool bRescaleTextureCoordinates = false); void GetTextureName(char *pszName) const; inline IEditorTexture *GetTexture(void) const; // Renders opaque faces static void AddFaceToQueue( CMapFace* pMapFace, IEditorTexture* pTexture, EditorRenderMode_t renderMode, bool selected, SelectionState_t faceSelectionState ); static void PushFaceQueue( void ); static void PopFaceQueue( void ); static void RenderOpaqueFaces( CRender3D* pRender ); // // Serialization. // ChunkFileResult_t LoadVMF(CChunkFile *pFile); ChunkFileResult_t SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo); int SerializeRMF(std::fstream&, BOOL); int SerializeMAP(std::fstream&, BOOL); BOOL CheckFace(CCheckFaceInfo* = NULL); BOOL Fix(void); float GetNormalDistance(Vector& fPoint); inline int GetPointCount(void); inline void GetPoint(Vector& Point, int nPoint); inline void GetLightmapCoord( Vector2D & LightmapCoord, int nIndex ); inline void SetLightmapCoord( const Vector2D &LightmapCoord, int nIndex ); inline void GetTexCoord( Vector2D & TexCoord, int nTexCoord ); // Texture alignment. void GetCenter(Vector& Center); FaceOrientation_t GetOrientation(void) const; void RotateTextureAxes(float fDegrees); void InitializeTextureAxes(TextureAlignment_t eAlignment, DWORD dwFlags); void JustifyTexture(TextureJustification_t eJustification); void JustifyTextureUsingExtents(TextureJustification_t eJustification, Extents_t Extents); void GetFaceBounds(Vector& pfMins, Vector& pfMaxs) const; void GetFaceExtents(Extents_t Extents) const; void GetTextureExtents(Extents_t Extents, Vector2D & TopLeft, Vector2D & BottomRight) const; int GetTextureAlignment(void) const; void GetFaceTextureExtents(Vector2D & TopLeft, Vector2D & BottomRight) const; void CalcTextureCoordAtPoint( const Vector& pt, Vector2D & texCoord ); void CalcLightmapCoordAtPoint( const Vector& pt, Vector2D & lightCoord ); // Returns the max lightmap size for this face int MaxLightmapSize() const; void NormalizeTextureShifts(void); BOOL IsTextureAxisValid(void) const; inline void SetCordonFace( bool bCordonFace ); inline bool IsCordonFace() const; // Old code for setting up texture axes. Needed for backwards compatibility. void InitializeQuakeStyleTextureAxes(Vector4D& UAxis, Vector4D& VAxis); void CreateFace(Vector *pPoints, int nPoints, bool bIsCordonFace = false); void CreateFace(winding_t *w, int nFlags = 0); CMapFace *CopyFrom(const CMapFace *pFrom, DWORD dwFlags = COPY_FACE_POINTS, bool bUpdateDependencies = true ); size_t AllocatePoints(int nPoints); void OnUndoRedo(); void CalcPlane(void); void CalcPlaneFromFacePoints(void); void CalcTextureCoords(); void OffsetTexture(const Vector &Delta); void SetTextureCoords(int nPoint, float u, float v); struct TangentSpaceAxes_t { Vector tangent; Vector binormal; }; void CalcTangentSpaceAxes( void ); bool AllocTangentSpaceAxes( int count ); void FreeTangentSpaceAxes( void ); void Render2D(CRender2D *pRender); void Render3D(CRender3D *pRender); void Render3DGrid(CRender3D *pRender); void RenderVertices(CRender *pRender); void OnAddToWorld(CMapWorld *pWorld); void OnRemoveFromWorld(void); static void SetShowSelection(bool bShowSelection); inline void SetRenderAlpha(unsigned char uchAlpha) { m_uchAlpha = uchAlpha; } // HACK: should be in CMapAtom inline void GetFaceNormal( Vector& normal ); bool TraceLine(Vector &HitPos, Vector &HitNormal, Vector const &Start, Vector const &End); bool TraceLineInside( Vector &HitPos, Vector &HitNormal, Vector const &Start, Vector const &End, bool bNoDisp = false ); inline void SetDisp( EditDispHandle_t handle, bool bDestroyPrevious = true ); inline EditDispHandle_t GetDisp( void ); inline bool HasDisp( void ) const; bool ShouldRenderLast(); void GetDownVector( int index, Vector& downVect ); bool GetRender2DBox( Vector& boundMin, Vector& boundMax ); bool GetCullBox( Vector& boundMin, Vector& boundMax ); size_t GetDataSize( void ); inline int GetFaceID(void); inline void SetFaceID(int nFaceID); // Smoothing group. int SmoothingGroupCount( void ); void AddSmoothingGroup( int iGroup ); void RemoveSmoothingGroup( int iGroup ); bool InSmoothingGroup( int iGroup ); // Indicates this guy should be unlit void RenderUnlit( bool enable ); // (begin serialized information TEXTURE texture; // Texture info. Vector *Points; // Array of face points, dynamically allocated. int nPoints; // The number of points in the array. // end serialized information) PLANE plane; int m_nFaceFlags; // FACE_FLAGS_xx void DoTransform(const VMatrix &matrix); virtual void AddShadowingTriangles( CUtlVector &tri_list ); DetailObjects *m_pDetailObjects; protected: void ComputeColor( CRender3D* pRender, bool bRenderAsSelected, SelectionState_t faceSelectionState, bool ignoreLighting, Color &pColor ); void DrawFace( Color &pColor, EditorRenderMode_t mode ); void RenderGridIfCloseEnough( CRender3D* pRender ); void RenderTextureAxes( CRender3D* pRender ); // Adds a face's vertices to the meshbuilder void AddFaceVertices( CMeshBuilder &builder, CRender3D* pRender, bool bRenderSelected, SelectionState_t faceSelectionState ); // render texture axes static void RenderTextureAxes( CRender3D* pRender, int nCount, CMapFace **ppFaces ); static void RenderGridsIfCloseEnough( CRender3D* pRender, int nCount, CMapFace **ppFaces ); static void Render3DGrids( CRender3D* pRender, int nCount, CMapFace **ppFaces ); static void RenderWireframeFaces( CRender3D* pRender, int nCount, MapFaceRender_t **ppFaces ); static void RenderFacesBatch( CMeshBuilder &MeshBuilder, IMesh* pMesh, CRender3D* pRender, MapFaceRender_t **ppFaces, int nFaceCount, int nVertexCount, int nIndexCount, bool bWireframe ); static void RenderFaces( CRender3D* pRender, int nCount, MapFaceRender_t **ppFaces ); void RenderFace3D( CRender3D* pRender, EditorRenderMode_t renderMode, bool renderSelected, SelectionState_t faceSelectionState ); // // Serialization (chunk handlers). // static ChunkFileResult_t LoadDispInfoCallback(CChunkFile *pFile, CMapFace *pFace); static ChunkFileResult_t LoadKeyCallback(const char *szKey, const char *szValue, LoadFace_t *pLoadFace); unsigned char m_uchAlpha; // HACK: should be in CMapAtom int m_nFaceID; // The unique ID of this face in the world. IEditorTexture *m_pTexture; // Texture that is applied to this face. static IEditorTexture *m_pLightmapGrid; // Lightmap grid texture for use in viewing lightmap scales. EditDispHandle_t m_DispHandle; // Displacement map applied to this face, NULL if none. static bool m_bShowFaceSelection; // Whether to render faces with a special color when they are selected. Vector2D *m_pTextureCoords; // An array of texture coordinates, one per face point. Vector2D *m_pLightmapCoords; // An array of lightmap coordinates, one per face point. bool m_bIsCordonFace : 1; // should this be affected by lighting? bool m_bIgnoreLighting : 1; TangentSpaceAxes_t *m_pTangentAxes; unsigned int m_fSmoothingGroups; // 32-bits representing 32 smoothing groups void UpdateFaceFlags( void ); // sniff face flags from texture }; //----------------------------------------------------------------------------- // Purpose: Returns the unique ID of this face. //----------------------------------------------------------------------------- inline int CMapFace::GetFaceID(void) { return(m_nFaceID); } //----------------------------------------------------------------------------- // Purpose: // Input : TexCoord - // nTexCoord - //----------------------------------------------------------------------------- inline void CMapFace::GetLightmapCoord( Vector2D& LightmapCoord, int nIndex ) { Assert( nIndex < nPoints ); LightmapCoord[0] = m_pLightmapCoords[nIndex][0]; LightmapCoord[1] = m_pLightmapCoords[nIndex][1]; } //----------------------------------------------------------------------------- // Purpose: // Input : &LightmapCoord - // nIndex - // Output : inline void //----------------------------------------------------------------------------- inline void CMapFace::SetLightmapCoord( const Vector2D &LightmapCoord, int nIndex ) { Assert( nIndex < nPoints ); m_pLightmapCoords[nIndex][0] = LightmapCoord[0]; m_pLightmapCoords[nIndex][1] = LightmapCoord[1]; } //----------------------------------------------------------------------------- // Purpose: // Input : TexCoord - // nTexCoord - //----------------------------------------------------------------------------- inline void CMapFace::GetTexCoord( Vector2D& TexCoord, int nTexCoord ) { Assert( nTexCoord < nPoints ); TexCoord[0] = m_pTextureCoords[nTexCoord][0]; TexCoord[1] = m_pTextureCoords[nTexCoord][1]; } //----------------------------------------------------------------------------- // Purpose: Returns a pointer to the texture that is applied to this face, NULL if none. //----------------------------------------------------------------------------- inline IEditorTexture *CMapFace::GetTexture(void) const { return(m_pTexture); } //----------------------------------------------------------------------------- // Purpose: Returns the number of vertices that define this face. //----------------------------------------------------------------------------- inline int CMapFace::GetPointCount(void) { return(nPoints); } //----------------------------------------------------------------------------- // Purpose: Retrieves a point on this face by its index. // Input : Point - Receives point coordinates. // nPoint - Index of point to retrieve. //----------------------------------------------------------------------------- inline void CMapFace::GetPoint(Vector& Point, int nPoint) { Assert(nPoint < nPoints); Point = Points[nPoint]; } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- inline void CMapFace::GetFaceNormal( Vector& normal ) { normal = plane.normal; } //----------------------------------------------------------------------------- // Purpose: Sets the unique ID of this face. //----------------------------------------------------------------------------- inline void CMapFace::SetFaceID(int nID) { m_nFaceID = nID; } //----------------------------------------------------------------------------- // Purpose: Attaches a displacement surface to this face. // Input : handle - Displacement surface handle of surface attached to this face //----------------------------------------------------------------------------- inline void CMapFace::SetDisp( EditDispHandle_t handle, bool bDestroyPrevious ) { if ( ( m_DispHandle != EDITDISPHANDLE_INVALID ) && bDestroyPrevious ) { // destroy old handle EditDispMgr()->Destroy( m_DispHandle ); } Assert( ( handle == EDITDISPHANDLE_INVALID ) || ( EditDispMgr()->GetDisp( handle ) != NULL ) ); m_DispHandle = handle; } //----------------------------------------------------------------------------- // Purpose: Returns the displacement surface applied to this face, // DISPHANDLE_INVALID if none. //----------------------------------------------------------------------------- inline EditDispHandle_t CMapFace::GetDisp( void ) { return m_DispHandle; } //----------------------------------------------------------------------------- // Purpose: Returns true if this face has a displacement surface, false if not. //----------------------------------------------------------------------------- inline bool CMapFace::HasDisp( void ) const { return ( m_DispHandle != EDITDISPHANDLE_INVALID ); } //----------------------------------------------------------------------------- // Whether this face belongs to a cordon brush. //----------------------------------------------------------------------------- inline void CMapFace::SetCordonFace( bool bCordonFace ) { m_bIsCordonFace = bCordonFace; } inline bool CMapFace::IsCordonFace() const { return m_bIsCordonFace; } //----------------------------------------------------------------------------- // Defines a container class for a list of face pointers. //----------------------------------------------------------------------------- class CMapFaceList : public CUtlVector { public: inline CMapFaceList(void) {} inline CMapFaceList(CMapFaceList const &other); inline CMapFaceList &CMapFaceList::operator =(CMapFaceList const &other); inline int FindFaceID(int nFaceID); void Intersect(CMapFaceList &IntersectWith, CMapFaceList &In, CMapFaceList &Out); }; //----------------------------------------------------------------------------- // Purpose: Copy constructor. //----------------------------------------------------------------------------- CMapFaceList::CMapFaceList(CMapFaceList const &other) { *this = other; } //----------------------------------------------------------------------------- // Purpose: Assignment operator for copying face lists. // Input : other - //----------------------------------------------------------------------------- CMapFaceList &CMapFaceList::operator =(CMapFaceList const &other) { AddVectorToTail(other); return *this; } //----------------------------------------------------------------------------- // Purpose: Searches the list for a face with the given ID. // Input : nFaceID - Numeric face ID to search for. // Output : Index of found element, -1 if none. //----------------------------------------------------------------------------- int CMapFaceList::FindFaceID(int nFaceID) { for (int i = 0; i < Count(); i++) { if ((Element(i) != NULL) && (Element(i)->GetFaceID() == nFaceID)) { return(i); } } return(-1); } //----------------------------------------------------------------------------- // Defines a container class for a list of face IDs. //----------------------------------------------------------------------------- class CMapFaceIDList : public CUtlVector { public: inline CMapFaceIDList(void) {} inline CMapFaceIDList(CMapFaceIDList const &other); inline CMapFaceIDList &CMapFaceIDList::operator =(CMapFaceIDList const &other); void Intersect(CMapFaceIDList &IntersectWith, CMapFaceIDList &In, CMapFaceIDList &Out); }; //----------------------------------------------------------------------------- // Purpose: Copy constructor. //----------------------------------------------------------------------------- CMapFaceIDList::CMapFaceIDList(CMapFaceIDList const &other) { *this = other; } //----------------------------------------------------------------------------- // Purpose: Assignment operator for copying face ID lists. // Input : other - //----------------------------------------------------------------------------- CMapFaceIDList &CMapFaceIDList::operator =(CMapFaceIDList const &other) { AddVectorToTail(other); return *this; } #endif // MAPFACE_H