⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 roamsphere.cpp

📁 大型多人在线游戏开发,该书光盘上附带的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		if(nOppositeVertex == 65535)
			return false;
		pTriangleVertex = CVertex::Array[nTriangleVertex];
		pOppositeVertex = CVertex::Array[nOppositeVertex];
		memcpy(pOppositeVertex, pTriangleVertex, sizeof(CVertex));
		if(m_pSurfaceMap)
			m_pSurfaceMap->GetTextureCoordinates(pOppositeVertex->m_vPosition, pOpposite->GetTriangleFace(), pOppositeVertex->m_fTexCoord[2], pOppositeVertex->m_fTexCoord[3]);
	}

	// Now create two new triangles for the split
	static CROAMTriangle *pNewTriangle[2];
	pNewTriangle[0] = new CROAMTriangle;
	pNewTriangle[1] = new CROAMTriangle;

	// Split the first one from pTriangle
	pTriangle->SetPriorityWait(0);
	pNewTriangle[0]->m_nFlags = pTriangle->m_nFlags;
	pNewTriangle[0]->InsertAfter(pTriangle);
	//m_llTriangle[pTriangle->GetTriangleFace()].AddTail(pNewTriangle[0]);
	pNewTriangle[0]->SetVertices(pTriangle->m_nVertex[2], nTriangleVertex, pTriangle->m_nVertex[1]);
	pTriangle->SetVertices(pTriangle->m_nVertex[1], nTriangleVertex, pTriangle->m_nVertex[0]);
	pNewTriangle[0]->SetEdges(pOpposite, pTriangle, pTriangle->m_pEdge[1]);
	pTriangle->m_pEdge[1]->ReplaceEdge(pTriangle, pNewTriangle[0]);
	pTriangle->SetEdges(pNewTriangle[0], pNewTriangle[1], pTriangle->m_pEdge[0]);
	if(pNewTriangle[0]->m_pEdge[2]->m_pEdge[2] == pNewTriangle[0])
		pNewTriangle[0]->CopyPriorityInfo(pNewTriangle[0]->m_pEdge[2]);
	else
		UpdateTriangleOffset(pNewTriangle[0]);
	if(pTriangle->m_pEdge[2]->m_pEdge[2] == pTriangle)
		pTriangle->CopyPriorityInfo(pTriangle->m_pEdge[2]);
	else
		UpdateTriangleOffset(pTriangle);

	// Split the second one from pOpposite
	pOpposite->SetPriorityWait(0);
	pNewTriangle[1]->m_nFlags = pOpposite->m_nFlags;
	pNewTriangle[1]->InsertAfter(pOpposite);
	//m_llTriangle[pOpposite->GetTriangleFace()].AddTail(pNewTriangle[1]);
	pNewTriangle[1]->SetVertices(pOpposite->m_nVertex[2], nOppositeVertex, pOpposite->m_nVertex[1]);
	pOpposite->SetVertices(pOpposite->m_nVertex[1], nOppositeVertex, pOpposite->m_nVertex[0]);
	pNewTriangle[1]->SetEdges(pTriangle, pOpposite, pOpposite->m_pEdge[1]);
	pOpposite->m_pEdge[1]->ReplaceEdge(pOpposite, pNewTriangle[1]);
	pOpposite->SetEdges(pNewTriangle[1], pNewTriangle[0], pOpposite->m_pEdge[0]);
	if(pNewTriangle[1]->m_pEdge[2]->m_pEdge[2] == pNewTriangle[1])
		pNewTriangle[1]->CopyPriorityInfo(pNewTriangle[1]->m_pEdge[2]);
	else
		UpdateTriangleOffset(pNewTriangle[1]);
	if(pOpposite->m_pEdge[2]->m_pEdge[2] == pOpposite)
		pOpposite->CopyPriorityInfo(pOpposite->m_pEdge[2]);
	else
		UpdateTriangleOffset(pOpposite);

	// Calculate the new vertex's normal vector
#define SPLIT_NORMAL	// Updates the normal of all vertices affected by the split
#ifdef SPLIT_NORMAL
	pTriangle->UpdateVertexNormals();
	pOpposite->UpdateVertexNormals();
#else
	pTriangleVertex->m_vNormal = pTriangle->GetNormal() + pOpposite->GetNormal() + pNewTriangle[0]->GetNormal() + pNewTriangle[1]->GetNormal();
	CVertex::Array.UpdateElement(nTriangleVertex);
	if(nTriangleVertex != nOppositeVertex)
	{
		pOppositeVertex->m_vNormal = pTriangleVertex->m_vNormal;
		CVertex::Array.UpdateElement(nOppositeVertex);
	}
#endif

	// Set up parent pointers
	pNewTriangle[0]->m_pParent = pTriangle;
	pNewTriangle[1]->m_pParent = pOpposite;

	// If either of the original triangles was part of a diamond, it has been destroyed.
	if(pTriangle->m_pDiamond)
		delete pTriangle->m_pDiamond;
	if(pOpposite->m_pDiamond)
		delete pOpposite->m_pDiamond;

	// A new diamond must be created with the 4 new triangles.
	m_llDiamond.AddTail(new CROAMDiamond(pTriangle, pOpposite, pNewTriangle[0], pNewTriangle[1]));
	m_nTriangles += 2;
	return true;
}

void CROAMSphere::Merge(CROAMDiamond *pDiamond)
{
	// First, get the vertex all the triangles share and the parent triangles that the children will be merged into
	unsigned short nVertex = pDiamond->m_pParent[0]->m_nVertex[1];
	unsigned short nOpposite = pDiamond->m_pParent[1]->m_nVertex[1];
	CVertex *pVertex = CVertex::Array[nVertex];

	// Loop twice to merge two child triangles into their parents
	for(int i=0; i<2; i++)
	{
		// Start by updating the parent's vertices and edges, then deleting the child
		CROAMTriangle *pParent = pDiamond->m_pParent[i];
		CROAMTriangle *pChild = pDiamond->m_pChild[i];
		pParent->SetVertices(pParent->m_nVertex[2], pParent->m_nVertex[0], pChild->m_nVertex[0]);
		pParent->SetEdges(pParent->m_pEdge[2], pChild->m_pEdge[2], pDiamond->m_pParent[1-i]);
		pChild->m_pEdge[2]->ReplaceEdge(pChild, pParent);
		delete pChild;

		// Then update the priority information
		if(i == 0)
		{
			CVector v = pParent->Vertex(0)->m_vPosition.Midpoint(pParent->Vertex(2)->m_vPosition);
			pParent->m_vMidpoint = v;
			float fHeight = (float)v.Magnitude();
			pParent->m_fOffset = (float)pVertex->m_vPosition.Magnitude() - fHeight;
		}
		else
			pParent->CopyPriorityInfo(pParent->m_pEdge[2]);

		// Then see if the merged parent forms a new diamond
		CROAMTriangle *p[4];
		pParent->m_pDiamond = NULL;
		p[0] = pParent;
		p[1] = p[0]->m_pEdge[0];
		p[2] = p[1]->m_pEdge[0];
		p[3] = p[2]->m_pEdge[0];
		if(p[3]->m_pEdge[0] == p[0])
		{
			// If it does, make sure parents and children match up
			if(p[1]->m_pParent == p[0] && p[3]->m_pParent == p[2])
				m_llDiamond.AddTail(new CROAMDiamond(p[0], p[2], p[1], p[3]));
			if(p[2]->m_pParent == p[1] && p[0]->m_pParent == p[3])
				m_llDiamond.AddTail(new CROAMDiamond(p[1], p[3], p[2], p[0]));
		}
	}
#define MERGE_NORMAL	// Updates the normal of all vertices affected by the merge
#ifdef MERGE_NORMAL
	pDiamond->m_pParent[0]->UpdateVertexNormals();
	pDiamond->m_pParent[1]->UpdateVertexNormals();
#endif
	pDiamond->m_pParent[0] = pDiamond->m_pParent[1] = NULL;
	pDiamond->m_pChild[0] = pDiamond->m_pChild[1] = NULL;
	delete pDiamond;
	CVertex::Array.UnlockElement(nVertex);
	if(nOpposite != nVertex)
		CVertex::Array.UnlockElement(nOpposite);
	m_nTriangles -= 2;
}

void CROAMSphere::Init(CHeightMap *pHeightMap, CSurfaceMap *pSurfaceMap)
{
	// Build a fresh cube and set up the initial vertices/triangles
	m_pHeightMap = pHeightMap;
	m_pSurfaceMap = pSurfaceMap;
	BuildCube();

	int nFace, i;
	for(nFace=0; nFace<6; nFace++)
	{
		for(CROAMTriangle *pTriangle=m_llTriangle[nFace].GetHead(); pTriangle->IsInList(); pTriangle = pTriangle->GetNext())
		{
			for(i=0; i<3; i++)
			{
				pTriangle->Vertex(i)->m_vPosition.Normalize();
				float fHeight = m_pHeightMap->GetHeightNormalized(pTriangle->Vertex(i)->m_vPosition);
				pTriangle->Vertex(i)->m_vPosition *= fHeight;
				if(m_pSurfaceMap)
				{
					m_pSurfaceMap->GetRawTextureCoordinates(pTriangle->Vertex(i)->m_vPosition, fHeight, pTriangle->Vertex(i)->m_fTexCoord[0], pTriangle->Vertex(i)->m_fTexCoord[1]);
					m_pSurfaceMap->GetTextureCoordinates(pTriangle->Vertex(i)->m_vPosition, nFace, pTriangle->Vertex(i)->m_fTexCoord[2], pTriangle->Vertex(i)->m_fTexCoord[3]);
				}
			}
			UpdateTriangleOffset(pTriangle);
		}
	}
}

void CROAMSphere::Update(CVector vPosition, CVector vHeading, float fHorizon, float fMaxError)
{
	m_fMaxError = fMaxError;
	const float fHalfError = m_fMaxError * 0.5f;
	const float fTwiceError = m_fMaxError * 2.0f;
	float fPriority;

	// Go through the list of diamonds, merging where necessary
	CROAMDiamond *pDiamond, *pOld;
	for(pDiamond=m_llDiamond.GetHead(); pDiamond->IsInList(); pDiamond = pDiamond->GetNext())
	{
		if(pDiamond->GetPriorityWait())
			pDiamond->SetPriorityWait(pDiamond->GetPriorityWait()-1);
		else
		{
			fPriority = pDiamond->GetPriority(vPosition, vHeading, fHorizon);
			if(fPriority < m_fMaxError)
			{
				pOld = pDiamond;
				pDiamond = pDiamond->GetPrevious();
				Merge(pOld);
			}
			else
			{
				pDiamond->SetPriorityWait(fPriority >= fTwiceError ? 2 : 1);
			}
		}
	}

	// Go through the list of triangles, splitting where necessary
	for(int nFace=0; nFace<6; nFace++)
	{
		for(CROAMTriangle *pTriangle=m_llTriangle[nFace].GetHead(); pTriangle->IsInList(); pTriangle = pTriangle->GetNext())
		{
			if(pTriangle->GetPriorityWait())
				pTriangle->SetPriorityWait(pTriangle->GetPriorityWait()-1);
			else
			{
				fPriority = pTriangle->GetPriority(vPosition, vHeading, fHorizon);
				if(fPriority >= m_fMaxError)
 					Split(pTriangle);
				else
				{
					pTriangle->SetPriorityWait(fPriority < DELTA ? 3 : fPriority < fHalfError ? 2 : 1);
				}
			}
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -