//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: This module defines the CPowerInfo class, which contains a 
//          whole bunch of precalculated data for each displacement power.
//          It holds data that indicates how to tesselate, how to access
//          neighbor displacements, etc.
//
// $NoKeywords: $
//=============================================================================//

#ifndef DISP_POWERINFO_H
#define DISP_POWERINFO_H
#ifdef _WIN32
#pragma once
#endif


#include "disp_vertindex.h"
#include "bspfile.h"


#define NUM_POWERINFOS				(MAX_MAP_DISP_POWER+1)


struct DispNodeInfo_t
{
	enum
	{
		// Indicates if any children at all have triangles
		CHILDREN_HAVE_TRIANGLES = 0x1
	};


	// Indicates which tesselation indices are associated with a node
	unsigned short	m_FirstTesselationIndex;
	unsigned char	m_Count;
	unsigned char	m_Flags;
};


// ------------------------------------------------------------------------ //
// CTesselateWindings are used to tell what order a node needs to visit
// vertices while tesselating.
// ------------------------------------------------------------------------ //
class CTesselateVert
{
public:
				CTesselateVert( CVertIndex const &index, int iNode );

	CVertIndex	m_Index;
	int			m_iNode;	// Which node this vert is a part of (-1 on left, right, up, and down).
};


class CTesselateWinding
{
public:
	CTesselateVert	*m_Verts;
	int				m_nVerts;	// (includes the last vert)
};


class CVertDependency
{
public:
	
	// Returns false if there is no dependency stored here.
	bool		IsValid()	{ return m_iVert.x != -1; }


public:
			
	// The vert index is in the same power as the source displacement.
	// It is also wrapped, so for example, on the middle of the right edge
	// of a 3x3, it will have a dependency on the 3x3's root node (1,1), and it
	// will have another (1,1) entry that references a neighbor.
	CVertIndex	m_iVert;

	// This is -1 if the vert exists inside the source displacement.
	// It is one of the NEIGHBOREDGE_ codes above if it reaches into a neighbor.
	int			m_iNeighbor;
};


// Precalculated data about displacement vertices.
class CVertInfo
{
public:
					CVertInfo();

	// These are the vertices that this vertex depends on (vertices that must be 
	// active for this vert to exist).
	CVertDependency	m_Dependencies[2];

	// These are the vertices that have this vert in their m_Dependencies.
	enum			{ NUM_REVERSE_DEPENDENCIES=4 };
	CVertDependency	m_ReverseDependencies[NUM_REVERSE_DEPENDENCIES];

	int				m_iNodeLevel;		// -1 if this is not a node. Otherwise, the recursion level
										// of this node (root node = 1).
	CVertIndex		m_iParent;			// x=-1 if this is a not a node or if it's the root node.
};


class CTwoUShorts
{
public:
	unsigned short	m_Values[2];
};


class CFourVerts
{
public:
	CVertIndex		m_Verts[4];
};


// Used for referencing triangles in the fully-tesselated displacement by index.
class CTriInfo
{
public:
	unsigned short	m_Indices[3];
};


// Precalculated data for displacements of a certain power.
class CPowerInfo
{
public:
						CPowerInfo( 
							CVertInfo *pVertInfo, 
							CFourVerts *pSideVerts,
							CFourVerts *pChildVerts,
							CFourVerts *pSideVertCorners,
							CTwoUShorts *pErrorEdges,
							CTriInfo *pTriInfos );

	int					GetPower() const		{ return m_Power; }
	int					GetSideLength() const	{ return m_SideLength; }
	const CVertIndex&	GetRootNode() const		{ return m_RootNode; }
	int					GetMidPoint() const		{ return m_MidPoint; } // Half the edge length.

	// Get at the tri list.
	int					GetNumTriInfos() const		{ return m_nTriInfos; }
	const CTriInfo*		GetTriInfo( int i ) const	{ return &m_pTriInfos[i]; }

	// Get the number of vertices in a displacement of this power.
	int					GetNumVerts() const			{ return m_MaxVerts; }
	
	// Return a corner point index. Indexed by the CORNER_ defines.
	const CVertIndex&	GetCornerPointIndex( int iCorner ) const;


public:

	CVertInfo			*m_pVertInfo;
	CFourVerts			*m_pSideVerts;	// The 4 side verts for each node.
	CFourVerts			*m_pChildVerts;	// The 4 children for each node.
	CFourVerts			*m_pSideVertCorners;
	CTwoUShorts			*m_pErrorEdges;			// These are the edges
												// that are used to measure the screenspace
												// error with respect to each vert.

	CTriInfo			*m_pTriInfos;
	int					m_nTriInfos;
	
	int					m_Power;

	CVertIndex			m_RootNode;
	int					m_SideLength;
	int					m_SideLengthM1;			// Side length minus 1.
	int					m_MidPoint;				// Side length / 2.
	int					m_MaxVerts;				// m_SideLength * m_SideLength
	int					m_NodeCount;			// total # of nodes, including children

	// Precalculated increments if you're using a bit vector to represent nodes.
	// Starting at level 0 of the tree, this stores the increment between the nodes at this
	// level. Vectors holding node data are stored in preorder traversal, and these
	// increments tell the number of elements between nodes at each level.
	int					m_NodeIndexIncrements[MAX_MAP_DISP_POWER];

	CVertIndex			m_EdgeStartVerts[4];
	CVertIndex			m_EdgeIncrements[4];

	CVertIndex			m_NeighborStartVerts[4][4];	// [side][orientation]
	CVertIndex			m_NeighborIncrements[4][4];	// [side][orientation]


private:
	friend void InitPowerInfo( CPowerInfo *pInfo, int iMaxPower );

	CVertIndex			m_CornerPointIndices[4];
};


// ----------------------------------------------------------------------------- //
// Globals.
// ----------------------------------------------------------------------------- //

// Indexed by the TWINDING_ enums.
extern CTesselateWinding	g_TWinding;


// ----------------------------------------------------------------------------- //
// Functions.
// ----------------------------------------------------------------------------- //

// Valid indices are MIN_MAP_DISP_POWER through (and including) MAX_MAP_DISP_POWER.
const CPowerInfo* GetPowerInfo( int iPower );


#endif // DISP_POWERINFO_H
