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 + -
显示快捷键?