/** @file RiverManager.cpp
@brief
* Copyright (c) 2007,第九城市游戏研发中心
* All rights reserved.
*
* 当前版本:
* 作 者:和萌
* 完成日期:2008-
*
* 取代版本:
* 作 者:
* 完成日期:
*/
#include "StdAfx.h"
#include "RiverManager.h"
#ifndef CODE_INGAME
//----------------------------------------------------------------------------------------------------------
CRiverManager* CRiverManager::ms_pRiverMgr = NULL;
CRiverManager::CRiverManager()
{
m_RiverRegion = NULL;
m_fAlphaDet = 0.0f;
}
CRiverManager::~CRiverManager(void)
{
if (m_RiverRegion->pkRiverGeom != NULL)
{
m_RiverRegion->pkRiverGeom = NULL;
m_RiverRegion = NULL;
m_fAlphaDet = 0.0f;
}
}
void CRiverManager::Do_Dispos()
{
if (ms_pRiverMgr != NULL)
{
delete ms_pRiverMgr;
ms_pRiverMgr = NULL;
}
}
unsigned int CRiverManager::GetRiverVerticCount()
{
return m_RiverRegion->uiVertexCount;
}
//静态函数,获得水域管理静态指针
CRiverManager* CRiverManager::GetInstance()
{
if (NULL == ms_pRiverMgr)
{
ms_pRiverMgr = new CRiverManager();
}
return ms_pRiverMgr;
}
unsigned int CRiverManager::GetTrianglesCount()
{
return m_RiverRegion->uiTriCount;
}
stRiverRegion* CRiverManager::GetRiverData()
{
return m_RiverRegion;
}
//////////////////////////////////////////////////////////////////////////
//函数功能:新建河流区域到m_pRiverRegions
void CRiverManager::AddRiverRegion(float fHeight,NiColorA kColor,float fAlphaDet)
{
if (m_RiverRegion != NULL)
{
return;
}
m_RiverRegion = new stRiverRegion;
m_fAlphaDet = fAlphaDet;
m_RiverRegion->fRiverHeight = fHeight;
m_RiverRegion->kColor = kColor;
m_RiverRegion->uiVertexCount = 0;
m_RiverRegion->uiTriCount = 0;
m_RiverRegion->pkRiverGeom = NULL;
}
//////////////////////////////////////////////////////////////////////////
//函数功能:判断给定位置是否已经存在水域
//输入参数:在Terrain上的顶点索引
//返回参数:已存在则返回顶点索引,反之返回-1
bool CRiverManager::IsExistPos(DWORD terrainIndex)
{
if (m_RiverRegion->mVertex.count(terrainIndex) == 1)
{
return true;
}
else
{
return false;
}
}
//bool CRiverManager::_IsExistTri(unsigned int uiP0)
//{
// unsigned int index;
// unsigned int iTriCount = m_RiverRegion->uiTriCount;
// for (index=0; indexstTri[index];
// if (tempTri.uiP0 == uiP0 )
// {
// return true;
// }
// }
// return false;
//
//}
unsigned int CRiverManager::_GetIdFromTerrainIndex(DWORD dwTerrainIndex )
{
DWORD i;
for ( i = 0; i < m_RiverRegion->dwTerrainIndex.size(); i ++ )
{
if( m_RiverRegion->dwTerrainIndex[i] == dwTerrainIndex )
return i;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
//函数功能:根据给定高度重新设置顶点alpha
void CRiverManager::AdjustAlphaByHeight(CTerrain *pTerrain)
{
for ( unsigned int i = 0; i < m_RiverRegion->uiVertexCount; i++ )
{
NiPoint3 kPoint = pTerrain->GetVertex(m_RiverRegion->dwTerrainIndex[i]);
NiColorA kPosColor = m_RiverRegion->kColor;
//alpha渐变等级
//float detAlpha = 0.2f;
if (kPoint.z >= m_RiverRegion->fRiverHeight)
{
kPosColor.a = 0.0f;
}//end of if kPoint
else
if (kPoint.z < m_RiverRegion->fRiverHeight)
{
//计算递增量
//float fAlphaDet = abs(m_RiverRegion->fRiverHeight - kPoint.z) / min( m_fAlphaDet * 10, 10.0f);
float fAlpha = abs(m_RiverRegion->fRiverHeight - kPoint.z) * m_fAlphaDet;
kPosColor.a = min(fAlpha,1);
}//end of else if
m_RiverRegion->mVertex[m_RiverRegion->dwTerrainIndex[i]].kVertexClr = kPosColor;
}//end of for
}//end of AdjustAlphaByHeight
//////////////////////////////////////////////////////////////////////////
//函数功能:根据参数添加河流区域点
//输入参数:kPos 添加点的世界坐标,fRadius 笔刷半径, bAddTo 添加或删除点
void CRiverManager::EditRiverPoint(CTerrain *pTerrain, const NiPoint3& kPos, float fRadius, bool bAddTo)
{
DWORD scanline = pTerrain->GetChunkNumX() * GRIDINCHUNK + 1;
DWORD dwTotalVertixCount = scanline * (pTerrain->GetChunkNumY() * GRIDINCHUNK + 1);
int iRadiu = int(fRadius + 0.5);
int iX = (int)(kPos.x + 0.5);
int iY = (int)(kPos.y + 0.5);
int iRightX = iX + iRadiu;
int iRightY = iY + iRadiu;
int iLeftX = iX - iRadiu;
int iLeftY = iY - iRadiu;
vector< vector > vRetPoints;
pTerrain->GetPointsFromRectangle(iLeftX,iLeftY,iRightX,iRightY,vRetPoints);
if (vRetPoints.size() < 1 || vRetPoints[0].size() < 1)
{
return;
}
//生成条带
int nHeight = vRetPoints.size();
int nWidth = vRetPoints[0].size();
int nVertexCount = nHeight * nWidth;
if ( nVertexCount < 1 )
{
return;
}
DWORD dwVertexIndex;
stRiverPoint stVertex;
// 顶点
for ( int nY = 0; nY < nHeight; nY++ )
{
for ( int nX = 0; nX < nWidth; nX++ )
{
stVertex.kVertexClr = m_RiverRegion->kColor;
stVertex.kVertex = vRetPoints[nY][nX];
//获得点在terrain上的索引
dwVertexIndex = stVertex.kVertex.x + stVertex.kVertex.y * scanline;
//设置水高
stVertex.kVertex.z = m_RiverRegion->fRiverHeight;
if (dwVertexIndex > dwTotalVertixCount)
{
NiMessageBox("越界","error",0);
break;
}
//添加点
if (bAddTo == true)
{
_InsertRiverPoint(dwVertexIndex,stVertex);
}//end of bAddTo true
//删除点
//检查插入点:若存在则删除
else
{
_DeleteRiverPoint(dwVertexIndex);
}//end of IsExitPos
}//end of for nX
}//end of for nY
_BuildTriangles(pTerrain,1);
}
unsigned int CRiverManager::_BuildTriangles(CTerrain *pTerrain, int iRadiu)
{
if ( m_RiverRegion->uiVertexCount == 0 )
{
return 0;
}
//清空三角形连接列表
m_RiverRegion->stTri.clear();
DWORD scanline = pTerrain->GetChunkNumX() * GRIDINCHUNK + 1;
DWORD dwTotalVertexCount = scanline * (pTerrain->GetChunkNumY() * GRIDINCHUNK + 1);
DWORD dwVertexIndex;
///////////////////////////////////////////////////////////////////////////
// //添加顶点索引
for (unsigned int i = 0; i < m_RiverRegion->uiVertexCount; i++)
{
dwVertexIndex = m_RiverRegion->dwTerrainIndex[i];
stTriList stTri;
//此处并为检查加值是否存在于terrain上
//////////////////////////////////////////////////////////////////////////
// 3*------*2
// | |
// | |
// @------*
// 0 1
DWORD p[4] = {dwVertexIndex, dwVertexIndex+iRadiu, dwVertexIndex+(scanline*iRadiu)+iRadiu, dwVertexIndex+(scanline*iRadiu)};
bool temp[4] = {true,true,true,true};
//////////////////////////////////////////////////////////////////////////
//判断是否超出terrian范围,索引位置是否正确
// *横向越界没有检查
for (int j = 0; j < 4; j++)
{
//检查多边形各点是否存在于terrain上
if (p[j] > dwTotalVertexCount)
{
//NiMessageBox("多边形越界","error",0);
temp[j] = false;
}
//检查是否为右边界点
if (p[j] % scanline == (scanline-1))
{
temp[j] = false;
}
}
//////////////////////////////////////////////////////////////////////////
//多边形4顶点均满足以上2项,则添加多边形
if (temp[0] && temp[1] && temp[2] && temp[3])
{
//////////////////////////////////////////////////////////////////////////
// /*2
// / |
// / |
// @------*
// 0 1
//
// *------*
// | /
// | /
// |/
// @
//如果对角线点都在水域内则添加多边形
if ( IsExistPos(p[2]) == true )
{
if (IsExistPos(p[1]) == true)
{
stTri.uiP0 = _GetIdFromTerrainIndex(p[0]);
stTri.uiP1 = _GetIdFromTerrainIndex(p[1]);
stTri.uiP2 = _GetIdFromTerrainIndex(p[2]);
m_RiverRegion->stTri.push_back(stTri);
}
if (IsExistPos(p[3]) == true)
{
stTri.uiP0 = _GetIdFromTerrainIndex(p[0]);
stTri.uiP1 = _GetIdFromTerrainIndex(p[2]);
stTri.uiP2 = _GetIdFromTerrainIndex(p[3]);
m_RiverRegion->stTri.push_back(stTri);
}
}
//对角线不在水域内
//////////////////////////////////////////////////////////////////////////
// *
// | \
// | \
// @------*
else
{
//1 3点都存在
if (IsExistPos(p[1]) == true && IsExistPos(p[3]) == true)
{
stTri.uiP0 = _GetIdFromTerrainIndex(p[0]);
stTri.uiP1 = _GetIdFromTerrainIndex(p[1]);
stTri.uiP2 = _GetIdFromTerrainIndex(p[3]);
m_RiverRegion->stTri.push_back(stTri);
}
}
}
//当下对角线点不在水域中
//////////////////////////////////////////////////////////////////////////
// *----@
// \ |
// \ |
// \*
//
if (IsExistPos( dwVertexIndex-scanline-1 ) == false)
{
//左、下点均在水域中
if (IsExistPos(dwVertexIndex-1) == true && IsExistPos(dwVertexIndex-scanline) == true)
{
stTri.uiP0 = _GetIdFromTerrainIndex(dwVertexIndex-scanline);
stTri.uiP1 = _GetIdFromTerrainIndex(dwVertexIndex);
stTri.uiP2 = _GetIdFromTerrainIndex(dwVertexIndex-1);
m_RiverRegion->stTri.push_back(stTri);
}
}
}
m_RiverRegion->uiTriCount = m_RiverRegion->stTri.size();
return m_RiverRegion->uiTriCount;
}
//////////////////////////////////////////////////////////////////////////
//导出前优化水体几何
void CRiverManager::OptimizerRiverGeom(CTerrain *pTerrain)
{
////对terrainIndex进行排序
sort(m_RiverRegion->dwTerrainIndex.begin(),m_RiverRegion->dwTerrainIndex.end());
////删除alpha小于fAdjust的多余点
float fAdjust = 0.0f;
_OptimizeByAlpha(pTerrain,fAdjust);
_BuildTriangles(pTerrain,1);
BuildRiverRegionGem(pTerrain);
}
//////////////////////////////////////////////////////////////////////////
//函数功能:创建河流几何
//输入参数:河流结构
//返回参数:成功 true,失败 false
bool CRiverManager::BuildRiverRegionGem(CTerrain *pTerrain)
{
AdjustAlphaByHeight(pTerrain);
//////////////////////////////////////////////////////////////////////////
//注意:生成几何形NiTriShape中的顶点个数和多边形个数都不能大于unsigned short
// 65535个,否则在创建几何形时无法创建出所需的几何形
unsigned int uiVertNum = m_RiverRegion->uiVertexCount;
DWORD terrainIndex = 0;
if ( uiVertNum > 65535 )
{
NiMessageBox("顶点数越界","error",0);
return false;
}
// 分配渲染数据
NiPoint3* pkVerts = NiNew NiPoint3[uiVertNum];
NiPoint3* pkNormals = NiNew NiPoint3[uiVertNum];
NiColorA* pkColors = NiNew NiColorA[uiVertNum];
unsigned short* pTriList;
unsigned int uiTriCount = GetTrianglesCount();
if ( uiTriCount > 65535 )
{
NiMessageBox("三角形数越界","error",0);
return false;
}
pTriList = NiAlloc( unsigned short, uiTriCount * 3 );
for ( unsigned int n = 0; n < uiVertNum; n++ )
{
terrainIndex = m_RiverRegion->dwTerrainIndex[n];
pkVerts[n] = m_RiverRegion->mVertex[terrainIndex].kVertex;
pkNormals[n] = NiPoint3(0.0f,0.0f,1.0f);
pkColors[n] = m_RiverRegion->mVertex[terrainIndex].kVertexClr;
}
//////////////////////////////////////////////////////////////////////////
//连接三角形
DWORD TriIndex = 0;
for ( DWORD i = 0; i < uiTriCount; i ++ )
{
if ( TriIndex >= uiTriCount * 3 )
{
NiMessageBox("三角形个数越界","error",0);
return false;
}
pTriList[ TriIndex ++ ] = m_RiverRegion->stTri[i].uiP0;
pTriList[ TriIndex ++ ] = m_RiverRegion->stTri[i].uiP1;
pTriList[ TriIndex ++ ] = m_RiverRegion->stTri[i].uiP2;
}
// 生成几何数据
NiTriShapeDynamicData *pData = NiNew NiTriShapeDynamicData(
uiVertNum, pkVerts, pkNormals,
pkColors, 0, 1, NiGeometryData::NBT_METHOD_NONE,
uiTriCount, pTriList, uiVertNum, uiTriCount );
m_RiverRegion->pkRiverGeom = NiNew NiTriShape( pData );
// 设置名字
char szName[16] = "River";
m_RiverRegion->pkRiverGeom->SetName( szName );
NiVertexColorProperty * pVertexProp = NiNew NiVertexColorProperty;
pVertexProp->SetLightingMode( NiVertexColorProperty::LIGHTING_E );
pVertexProp->SetSourceMode( NiVertexColorProperty::SOURCE_EMISSIVE );
m_RiverRegion->pkRiverGeom->AttachProperty( pVertexProp );
//////设置alpha属性
NiAlphaProperty* pkAlphaProp = NiNew NiAlphaProperty();
pkAlphaProp->SetAlphaBlending(true);
pkAlphaProp->SetSrcBlendMode(NiAlphaProperty::ALPHA_SRCALPHA);
pkAlphaProp->SetDestBlendMode(NiAlphaProperty::ALPHA_INVSRCALPHA);
m_RiverRegion->pkRiverGeom->AttachProperty(pkAlphaProp);
//设置显示为网格,仅供测试
//NiWireframeProperty* pkWireframeProp = NiNew NiWireframeProperty();
//pkWireframeProp->SetWireframe(true);
//m_RiverRegion->pkRiverGeom->AttachProperty(pkWireframeProp);
m_RiverRegion->pkRiverGeom->UpdateProperties();
m_RiverRegion->pkRiverGeom->Update(0.0f);
m_RiverRegion->pkRiverGeom->UpdateEffects();
return true;
}
NiTriShapePtr CRiverManager::GetRiverGeom( )
{
return m_RiverRegion->pkRiverGeom;
}
bool CRiverManager::_InsertRiverPoint(DWORD terrainIndex,stRiverPoint stVertex)
{
//检查插入点:若不存在则插入
if (IsExistPos(terrainIndex) == true)
{
return false;
}//end of if IsExistPos
m_RiverRegion->dwTerrainIndex.push_back( terrainIndex );
m_RiverRegion->mVertex.insert( map::value_type( terrainIndex,stVertex ) );
//更新顶点数
m_RiverRegion->uiVertexCount = m_RiverRegion->mVertex.size();
return true;
}
bool CRiverManager::_DeleteRiverPoint(DWORD terrainIndex)
{
if (IsExistPos(terrainIndex) == false)
{
return false;
}
map::iterator pointIt = m_RiverRegion->mVertex.find(terrainIndex);
m_RiverRegion->mVertex.erase(pointIt);
vector::iterator itIndex = m_RiverRegion->dwTerrainIndex.begin();
itIndex +=_GetIdFromTerrainIndex( terrainIndex );
m_RiverRegion->dwTerrainIndex.erase(itIndex);
//更新顶点数
m_RiverRegion->uiVertexCount = m_RiverRegion->mVertex.size();
return true;
}
void CRiverManager::_OptimizeByAlpha(CTerrain *pTerrain,float fAdjust)
{
DWORD scanline = pTerrain->GetChunkNumX() * GRIDINCHUNK + 1;
vector vTerrainIndex = m_RiverRegion->dwTerrainIndex;
unsigned int uiVertexCount = vTerrainIndex.size();
for (unsigned int i = 0; i < uiVertexCount; i++)
{
DWORD dwTerrainIndex = vTerrainIndex[i];
//如果所指顶点已删除则跳过
if (IsExistPos(dwTerrainIndex) == false)
{
break;
}
//////////////////////////////////////////////////////////////////////////
// ----*---*
// | | |
// *---@---*
// | | |
// ----*----
//
//如果当前点对应地形范围内Z大于等于水面高度+0.5,则删除改点
NiPoint3 kVertex = m_RiverRegion->mVertex[dwTerrainIndex].kVertex;
DWORD dwIndex[5] = { dwTerrainIndex-scanline, dwTerrainIndex-1, dwTerrainIndex+1, dwTerrainIndex+scanline,dwTerrainIndex+scanline+1};
int iCount = 0;
bool bFlag = true;
//当前点下、左、右、上各点是否属于水域
for (int j = 0; j < 5; j++)
{
if(IsExistPos(dwIndex[j] ) == true)
iCount ++;
}
//如果是孤立点或只有一个相邻点,则删除改点
if (iCount <= 1)
{
_DeleteRiverPoint(dwTerrainIndex);
}
else
{
//如果有大于1个相邻点属于水域,则测试相邻点alpha,若满足优化要求则删除
for (int j = 0; j < 5; j++)
{
if (IsExistPos(dwIndex[j]) == true)
{
float fAlpha = m_RiverRegion->mVertex[dwIndex[j]].kVertexClr.a;
//Alpha是否为0
if (fAlpha > fAdjust)
{
bFlag = false;
}
}
}
if (bFlag == true)
{
_DeleteRiverPoint(dwTerrainIndex);
}
}
}
}
//end of RiverManager.cpp
#endif