/** @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