📄 wmlterrainpage.cpp
字号:
//----------------------------------------------------------------------------
void TerrainPage::SimplifyVertices (const Vector3f& rkModelEye,
const Vector3f& rkModelDir, bool bCloseAssumption)
{
unsigned int usQueue, usBlock;
if ( m_usFront < m_usRear )
{
for (usQueue = m_usFront; usQueue < m_usRear; usQueue++)
{
usBlock = m_ausQueue[usQueue];
if ( m_akBlock[usBlock].GetVisible() )
{
m_akBlock[usBlock].SimplifyVertices(this,rkModelEye,
rkModelDir,m_fWorldTolerance,bCloseAssumption);
}
}
}
else
{
for (usQueue = m_usFront; usQueue < m_usQueueQuantity; usQueue++)
{
usBlock = m_ausQueue[usQueue];
if ( m_akBlock[usBlock].GetVisible() )
{
m_akBlock[usBlock].SimplifyVertices(this,rkModelEye,
rkModelDir,m_fWorldTolerance,bCloseAssumption);
}
}
for (usQueue = 0; usQueue < m_usRear; usQueue++)
{
usBlock = m_ausQueue[usQueue];
if ( m_akBlock[usBlock].GetVisible() )
{
m_akBlock[usBlock].SimplifyVertices(this,rkModelEye,
rkModelDir,m_fWorldTolerance,bCloseAssumption);
}
}
}
}
//----------------------------------------------------------------------------
void TerrainPage::Simplify (Renderer* pkRenderer, const Vector3f& rkModelEye,
const Vector3f& rkModelDir, bool bCloseAssumption)
{
if ( m_fWorldTolerance == -1.0f )
SetPixelTolerance(pkRenderer,m_fPixelTolerance);
SimplifyBlocks(pkRenderer->GetCamera(),rkModelEye,rkModelDir,
bCloseAssumption);
SimplifyVertices(rkModelEye,rkModelDir,bCloseAssumption);
m_bNeedsTessellation = true;
}
//----------------------------------------------------------------------------
void TerrainPage::Render (TerrainBlock& rkBlock)
{
unsigned short usOrigin = rkBlock.GetX() + m_usSize*rkBlock.GetY();
unsigned short usTwoStride = 2*rkBlock.GetStride();
unsigned short usTwoStrideTimesSize = usTwoStride*m_usSize;
unsigned short usIndex[5] =
{
usOrigin,
usOrigin + usTwoStride,
usOrigin + rkBlock.GetStride()*(m_usSize + 1),
usOrigin + usTwoStrideTimesSize,
usOrigin + usTwoStrideTimesSize + usTwoStride
};
if ( rkBlock.GetEven() )
{
RenderTriangle(usIndex[0],usIndex[3],usIndex[1]);
RenderTriangle(usIndex[4],usIndex[1],usIndex[3]);
}
else
{
RenderTriangle(usIndex[1],usIndex[0],usIndex[4]);
RenderTriangle(usIndex[3],usIndex[4],usIndex[0]);
}
}
//----------------------------------------------------------------------------
void TerrainPage::RenderTriangle (unsigned short usT, unsigned short usL,
unsigned short usR)
{
// determine if triangle is leaf or interior
bool bInterior;
if ( usR > usT )
{
if ( usL > usT )
bInterior = (usR - usT > 1);
else
bInterior = (usT - usL > 1);
}
else
{
if ( usL > usT )
bInterior = (usL - usT > 1);
else
bInterior = (usT - usR > 1);
}
if ( bInterior )
{
// Triangle is part of internal block and can be subdivided. M is
// the midpoint of edge <L,R>.
unsigned short usM = ((usL + usR) >> 1);
if ( m_akTVertex[usM].GetEnabled() )
{
RenderTriangle(usM,usT,usL);
RenderTriangle(usM,usR,usT);
return;
}
}
// pack the vertex data
assert( m_iVertexQuantity < m_usSize*m_usSize );
unsigned char ucX, ucY;
if ( m_ausLookup[usT] == (unsigned short)(~0) )
{
ucX = usT % m_usSize;
ucY = usT / m_usSize;
m_akVertex[m_iVertexQuantity].X() = GetX(ucX);
m_akVertex[m_iVertexQuantity].Y() = GetY(ucY);
m_akVertex[m_iVertexQuantity].Z() = GetHeight(usT);
m_akTexture[m_iVertexQuantity].X() = GetTexture(ucX);
m_akTexture[m_iVertexQuantity].Y() = GetTexture(ucY);
m_ausLookup[usT] = m_iVertexQuantity++;
}
if ( m_ausLookup[usR] == (unsigned short)(~0) )
{
ucX = usR % m_usSize;
ucY = usR / m_usSize;
m_akVertex[m_iVertexQuantity].X() = GetX(ucX);
m_akVertex[m_iVertexQuantity].Y() = GetY(ucY);
m_akVertex[m_iVertexQuantity].Z() = GetHeight(usR);
m_akTexture[m_iVertexQuantity].X() = GetTexture(ucX);
m_akTexture[m_iVertexQuantity].Y() = GetTexture(ucY);
m_ausLookup[usR] = m_iVertexQuantity++;
}
if ( m_ausLookup[usL] == (unsigned short)(~0) )
{
ucX = usL % m_usSize;
ucY = usL / m_usSize;
m_akVertex[m_iVertexQuantity].X() = GetX(ucX);
m_akVertex[m_iVertexQuantity].Y() = GetY(ucY);
m_akVertex[m_iVertexQuantity].Z() = GetHeight(usL);
m_akTexture[m_iVertexQuantity].X() = GetTexture(ucX);
m_akTexture[m_iVertexQuantity].Y() = GetTexture(ucY);
m_ausLookup[usL] = m_iVertexQuantity++;
}
// add triangle to connectivity array
assert( m_iTriangleQuantity < 2*(m_usSize-1)*(m_usSize-1) );
assert( m_iConnectLength < 6*(m_usSize-1)*(m_usSize-1) );
m_aiConnect[m_iConnectLength++] = m_ausLookup[usT];
m_aiConnect[m_iConnectLength++] = m_ausLookup[usR];
m_aiConnect[m_iConnectLength++] = m_ausLookup[usL];
m_iTriangleQuantity++;
}
//----------------------------------------------------------------------------
void TerrainPage::RenderBlocks ()
{
// reset dynamic quantities
memset(m_ausLookup,0xFF,m_usSize*m_usSize*sizeof(unsigned short));
m_iVertexQuantity = 0;
m_iTriangleQuantity = 0;
m_iConnectLength = 0;
unsigned short usQueue;
if ( m_usFront < m_usRear )
{
for (usQueue = m_usFront; usQueue < m_usRear; usQueue++)
{
TerrainBlock& rkBlock = m_akBlock[m_ausQueue[usQueue]];
if ( rkBlock.GetVisible() )
Render(rkBlock);
}
}
else
{
for (usQueue = m_usFront; usQueue < m_usQueueQuantity; usQueue++)
{
TerrainBlock& rkBlock = m_akBlock[m_ausQueue[usQueue]];
if ( rkBlock.GetVisible() )
Render(rkBlock);
}
for (usQueue = 0; usQueue < m_usRear; usQueue++)
{
TerrainBlock& rkBlock = m_akBlock[m_ausQueue[usQueue]];
if ( rkBlock.GetVisible() )
Render(rkBlock);
}
}
}
//----------------------------------------------------------------------------
void TerrainPage::StitchLR (TerrainPage* pkRight)
{
// 'this' is left page, 'pkRight' is right page
assert( pkRight->m_usSize == m_usSize );
unsigned short usR = m_usSize;
for (unsigned short usY = 1; usY < m_usSizeM1; usY++, usR += m_usSize)
{
unsigned short usL = m_usSizeM1 + usR;
TerrainVertex* pkLVertex = &m_akTVertex[usL];
TerrainVertex* pkRVertex = &pkRight->m_akTVertex[usR];
pkRVertex->SetDependent(0,pkLVertex);
pkLVertex->SetDependent(1,pkRVertex);
}
}
//----------------------------------------------------------------------------
void TerrainPage::StitchTB (TerrainPage* pkBottom)
{
// 'this' is top page, 'pkBottom' is bottom page
assert( pkBottom->m_usSize == m_usSize );
unsigned short usOffset = m_usSize*m_usSizeM1;
for (unsigned short usB = 1; usB < m_usSizeM1; usB++)
{
unsigned short usT = usB + usOffset;
TerrainVertex* pkTVertex = &m_akTVertex[usT];
TerrainVertex* pkBVertex = &pkBottom->m_akTVertex[usB];
pkBVertex->SetDependent(1,pkTVertex);
pkTVertex->SetDependent(0,pkBVertex);
}
}
//----------------------------------------------------------------------------
void TerrainPage::UnstitchLR (TerrainPage* pkRight)
{
// 'this' is left page, 'pkRight' is right page
assert( pkRight->m_usSize == m_usSize );
unsigned short usR = m_usSize; // y = 1
for (unsigned short usY = 1; usY < m_usSizeM1; usY++, usR += m_usSize)
{
unsigned short usL = m_usSizeM1 + usR;
TerrainVertex* pkLVertex = &m_akTVertex[usL];
TerrainVertex* pkRVertex = &pkRight->m_akTVertex[usR];
pkRVertex->SetDependent(0,NULL);
pkLVertex->SetDependent(1,NULL);
}
}
//----------------------------------------------------------------------------
void TerrainPage::UnstitchTB (TerrainPage* pkBottom)
{
// 'this' is top page, 'pBottom' is bottom page
assert( pkBottom->m_usSize == m_usSize );
unsigned short usOffset = m_usSize*m_usSizeM1;
for (unsigned short usB = 1; usB < m_usSizeM1; usB++)
{
unsigned short usT = usB + usOffset;
TerrainVertex* pkTVertex = &m_akTVertex[usT];
TerrainVertex* pkBVertex = &pkBottom->m_akTVertex[usB];
pkBVertex->SetDependent(1,NULL);
pkTVertex->SetDependent(0,NULL);
}
}
//----------------------------------------------------------------------------
void TerrainPage::Draw (Renderer& rkRenderer)
{
if ( m_bNeedsTessellation )
{
m_bNeedsTessellation = false;
RenderBlocks();
}
// It is possible (but not likely) that blocks are not culled, but the
// camera is positioned so that no triangles are visible. For example,
// this can occur if you are below the terrain mesh and looking down.
if ( m_iTriangleQuantity > 0 )
TriMesh::Draw(rkRenderer);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// streaming
//----------------------------------------------------------------------------
Object* TerrainPage::Factory (Stream& rkStream)
{
TerrainPage* pkObject = new TerrainPage;
Stream::Link* pkLink = new Stream::Link(pkObject);
pkObject->Load(rkStream,pkLink);
return pkObject;
}
//----------------------------------------------------------------------------
void TerrainPage::Load (Stream& rkStream, Stream::Link* pkLink)
{
TriMesh::Load(rkStream,pkLink);
// native data
StreamRead(rkStream,m_usSize);
unsigned short usQuantity = m_usSize*m_usSize;
m_ausHeight = new unsigned short[usQuantity];
StreamRead(rkStream,m_ausHeight,usQuantity);
StreamRead(rkStream,m_kOrigin);
StreamRead(rkStream,m_fMinElevation);
StreamRead(rkStream,m_fMaxElevation);
StreamRead(rkStream,m_fSpacing);
InitializeDerivedData();
}
//----------------------------------------------------------------------------
void TerrainPage::Link (Stream& rkStream, Stream::Link* pkLink)
{
TriMesh::Link(rkStream,pkLink);
}
//----------------------------------------------------------------------------
bool TerrainPage::Register (Stream& rkStream)
{
return TriMesh::Register(rkStream);
}
//----------------------------------------------------------------------------
void TerrainPage::Save (Stream& rkStream)
{
// The vertex and triangle quantities are dynamically varied during the
// simplification. Write the maximum quantities to disk, then reset to
// the current dynamic values.
int iSaveVQ = m_iVertexQuantity;
int iSaveTQ = m_iTriangleQuantity;
int iSize = (int)m_usSize, iSizeM1 = iSize-1;
m_iVertexQuantity = iSize*iSize;
m_iTriangleQuantity = 2*iSizeM1*iSizeM1;
TriMesh::Save(rkStream);
m_iVertexQuantity = iSaveVQ;
m_iTriangleQuantity = iSaveTQ;
// native data
StreamWrite(rkStream,m_usSize);
StreamWrite(rkStream,m_ausHeight,m_usSize*m_usSize);
StreamWrite(rkStream,m_kOrigin);
StreamWrite(rkStream,m_fMinElevation);
StreamWrite(rkStream,m_fMaxElevation);
StreamWrite(rkStream,m_fSpacing);
}
//----------------------------------------------------------------------------
StringTree* TerrainPage::SaveStrings ()
{
// TO DO. Finish implementation.
StringTree* pkTree = new StringTree(1,0,1,0);
pkTree->SetString(0,MakeString(&ms_kRTTI,GetName()));
pkTree->SetChild(0,TriMesh::SaveStrings());
return pkTree;
}
//----------------------------------------------------------------------------
int TerrainPage::GetMemoryUsed () const
{
// The vertex and triangle quantities are dynamically varied during the
// simplification. Count the maximum quantities, then reset to the
// current dynamic values. The typecast to integer references is to
// circumvent the 'const' of this function. In effect, however, the
// function is 'const' since the quantities are restored.
int& riVQ = (int&)m_iVertexQuantity;
int& riTQ = (int&)m_iTriangleQuantity;
int iSaveVQ = riVQ;
int iSaveTQ = riTQ;
int iSize = (int)m_usSize, iSizeM1 = iSize-1;
riVQ = iSize*iSize;
riTQ = 2*iSizeM1*iSizeM1;
int iBaseSize = sizeof(TerrainPage) - sizeof(TriMesh);
int iDynaSize =
m_iVertexQuantity*sizeof(m_ausHeight[0]) +
m_iVertexQuantity*sizeof(m_ausLookup[0]) +
m_iVertexQuantity*sizeof(m_akTVertex[0]) +
m_usBlockQuantity*sizeof(m_akBlock[0]) +
m_usQueueQuantity*sizeof(m_ausQueue[0]);
int iTotalSize = iBaseSize + iDynaSize + TriMesh::GetMemoryUsed();
riVQ = iSaveVQ;
riTQ = iSaveTQ;
return iTotalSize;
}
//----------------------------------------------------------------------------
int TerrainPage::GetDiskUsed () const
{
// The vertex and triangle quantities are dynamically varied during the
// simplification. Count the maximum quantities, then reset to the
// current dynamic values. The typecast to integer references is to
// circumvent the 'const' of this function. In effect, however, the
// function is 'const' since the quantities are restored.
int& riVQ = (int&)m_iVertexQuantity;
int& riTQ = (int&)m_iTriangleQuantity;
int iSaveVQ = riVQ;
int iSaveTQ = riTQ;
int iSize = (int)m_usSize, iSizeM1 = iSize-1;
riVQ = iSize*iSize;
riTQ = 2*iSizeM1*iSizeM1;
int iDiskUsed = TriMesh::GetDiskUsed() +
sizeof(m_usSize) +
riVQ*sizeof(m_ausHeight[0]) +
sizeof(m_kOrigin) +
sizeof(m_fMinElevation) +
sizeof(m_fMaxElevation) +
sizeof(m_fSpacing);
riVQ = iSaveVQ;
riTQ = iSaveTQ;
return iDiskUsed;
}
//----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -