field.cpp
来自「x3d_new.rar」· C++ 代码 · 共 472 行 · 第 1/2 页
CPP
472 行
#include "StdAfx.h"
#include "Field.h"
#include "xUtil.h"
#include "RiceIndices.h"
#include <stdlib.h>
#include <assert.h>
#include <algorithm>
#include <complex>
extern STileParam child_param[4] = {{0, 0}, {1, 0}, {0, 1}, {1, 1}};
extern STileParam neighbor_param[4] = {{1, 0}, {1, 1}, {0, 0}, {0, 1}};
CField::CField(void)
: m_bValid(false)
, m_byHeights(NULL)
, m_byMaxHeight(0)
, m_Tiles(NULL)
, m_TouchTiles(NULL)
, m_QuarterData(NULL)
, m_nFieldSize(0)
, m_nBorderSize(0)
, m_nMaxTilesNum(0)
, m_nMaxTouchNum(0)
, m_nHeightsNum(0)
{
}
CField::~CField(void)
{
if(m_bValid)
Destroy();
}
bool CField::Create(int nFieldSize)
{
assert(m_bValid == false);
m_nFieldSize = nFieldSize;
m_nBorderSize = m_nFieldSize + 1;
m_nHeightsNum = m_nBorderSize * m_nBorderSize;
// "高度"数据
m_byHeights = new unsigned char[m_nHeightsNum];
if(NULL == m_byHeights)return false;
memset(m_byHeights, 0, sizeof(m_byHeights[0]) * m_nHeightsNum);
// "四分标记"数据
m_QuarterData = new SQuarterData[m_nHeightsNum];
if(NULL == m_QuarterData)return false;
memset(m_QuarterData, 0, sizeof(m_QuarterData[0]) * m_nHeightsNum);
// 计算最大可能的"块"数
m_nMaxTilesNum = CalculateMaxTileNum(m_nFieldSize);
// "块"数组
m_Tiles = new STile[m_nMaxTilesNum];
if(NULL == m_Tiles)return false;
// "受影响的块"数组(因为子节点自己要加进去,所以要"+1")
m_nMaxTouchNum = CalculateMaxTouchNum(nFieldSize) + 1;
m_TouchTiles = new STile[m_nMaxTouchNum];
if(NULL == m_TouchTiles)return false;
m_bValid = true;
return true;
}
void CField::Destroy()
{
assert(m_bValid);
delete_ary(m_byHeights);
delete_ary(m_QuarterData);
delete_ary(m_Tiles);
delete_ary(m_TouchTiles);
m_bValid = false;
}
// 添加(划分)子节点时,影响的两个临节点
STileParam effect_neighbor[4] = {{2, 3}, {3, 0}, {1, 2}, {0, 1}};
void CField::UpdateQuarters(CCamera* pCamera, int nEyeshot, int nMaxTileSize)
{
assert(pCamera);
int nTilesNum = 0;
memset(m_QuarterData, 0, sizeof(m_QuarterData[0]) * m_nHeightsNum);
// 加入第一个"块"
STile tileNew(m_nFieldSize >> 1, m_nFieldSize >> 1, m_nFieldSize);
m_QuarterData[tileNew.m_cz * m_nBorderSize + tileNew.m_cx].m_uValue = 1; // 标记
m_Tiles[nTilesNum++] = tileNew;
// 开始分块
int nIndex = 0;
while(nIndex < nTilesNum)
{
STile tileChild;
for(int i = 0; i < 4; ++i)
{
// 子节点
m_Tiles[nIndex].GetChild(i, &tileChild);
if(!IsTileValid(&tileChild))continue;
// 片区为最小拆分单位
if(m_Tiles[nIndex].m_size < nMaxTileSize)
{
// 根据视距计算误差
int nDis = abs_int((int)pCamera->GetPosition()->x - tileChild.m_cx)
+ abs_int((int)pCamera->GetPosition()->y - GetHeight(tileChild.m_cx, tileChild.m_cz))
+ abs_int((int)pCamera->GetPosition()->z - tileChild.m_cz);;
nDis = max(nEyeshot, nDis);
int nTileError = (int)(GetTileError(&tileChild) * nEyeshot / (float)nDis);
if(nTileError <= 0)continue;
}
// *加入节点
m_Tiles[nTilesNum++] = tileChild;
// 检查、更新受影响的节点(父节点的临节点)
// 首先加入自己
int nTouchNum = 0;
m_TouchTiles[nTouchNum++] = tileChild;
STile touchParent; // 父节点
STile parentNeighbor; // 父节点的临节点(重复使用这一个)
int nTouchIndex = 0;
while(nTouchIndex < nTouchNum)
{
STile* pTileTouch = &m_TouchTiles[nTouchIndex];
m_QuarterData[pTileTouch->m_cz * m_nBorderSize + pTileTouch->m_cx].m_uValue = 1; // 标记
// 父节点
pTileTouch->GetParent(&touchParent);
if(!IsTileValid(&touchParent)) continue;
// 标记父节点分块状态
int nSection = touchParent.GetSection(pTileTouch);
m_QuarterData[touchParent.m_cz * m_nBorderSize + touchParent.m_cx].m_uFlag |= (1 << nSection);
// 临节点1
touchParent.GetNeighbor(effect_neighbor[nSection].value1, &parentNeighbor);
if(IsTileValid(&parentNeighbor)
&& 0 == m_QuarterData[parentNeighbor.m_cz * m_nBorderSize + parentNeighbor.m_cx].m_uValue)
{
// *加入节点
m_TouchTiles[nTouchNum++] = parentNeighbor;
}
// 临节点2
touchParent.GetNeighbor(effect_neighbor[nSection].value2, &parentNeighbor);
if(IsTileValid(&parentNeighbor)
&& 0 == m_QuarterData[parentNeighbor.m_cz * m_nBorderSize + parentNeighbor.m_cx].m_uValue)
{
// *加入节点
m_TouchTiles[nTouchNum++] = parentNeighbor;
}
++nTouchIndex;
}
}
++nIndex;
}
}
bool CField::GetPatchTiles(STile* pStartTile, STile** pTiles, int* pnTileCount)
{
assert(pStartTile);
assert(pTiles);
assert(pnTileCount);
(*pTiles) = m_Tiles;
(*pnTileCount) = 0;
// 存入第一个"块"
m_Tiles[(*pnTileCount)++] = *pStartTile;
// 逐层加入子节点
int nIndex = 0;
while(nIndex < (*pnTileCount))
{
STile& rtile = m_Tiles[nIndex];
const SQuarterData& rqd = GetQuarterData(rtile.m_cx, rtile.m_cz);
if(rqd.m_uFlag & (1 << 0)) rtile.GetChild(0, &m_Tiles[(*pnTileCount)++]); // 0
if(rqd.m_uFlag & (1 << 1)) rtile.GetChild(1, &m_Tiles[(*pnTileCount)++]); // 1
if(rqd.m_uFlag & (1 << 2)) rtile.GetChild(2, &m_Tiles[(*pnTileCount)++]); // 2
if(rqd.m_uFlag & (1 << 3)) rtile.GetChild(3, &m_Tiles[(*pnTileCount)++]); // 3
++nIndex;
}
return true;
}
/*
sx,sz ex,sz
-------
| \ | / |
-------
| / | \ |
-------
sx,ez ex,ez
*/
int CField::GetTileError(const STile* pTile)
{
int sx = pTile->m_cx - (pTile->m_size >> 1);
int sz = pTile->m_cz - (pTile->m_size >> 1);
int ex = sx + pTile->m_size;
int ez = sz + pTile->m_size;
int fAverage = 0;
int nError = 0;
fAverage = (GetHeight(sx, sz) + GetHeight(ex, sz)) >> 1;
nError = max(nError, abs_int(fAverage - GetHeight(pTile->m_cx, sz)));
fAverage = (GetHeight(ex, sz) + GetHeight(ex, ez)) >> 1;
nError = max(nError, abs_int(fAverage - GetHeight(ex, pTile->m_cz)));
fAverage = (GetHeight(ex, ez) + GetHeight(sx, ez)) >> 1;
nError = max(nError, abs_int(fAverage - GetHeight(pTile->m_cx, ez)));
fAverage = (GetHeight(sx, ez) + GetHeight(sx, sz)) >> 1;
nError = max(nError, abs_int(fAverage - GetHeight(sx, pTile->m_cz)));
fAverage = (GetHeight(sx, sz) + GetHeight(ex, ez)) >> 1;
nError = max(nError, abs_int(fAverage - GetHeight(pTile->m_cx, pTile->m_cz)));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?