#include "StdAfx.h" #include "Terrain.h" #include "TerrainTextureMgr.h" #include "EditableBaseObj.h" #include "TerrainMaterial.h" #include "ObjectsManager.h" #include "LightsManager.h" #include "Vegetation.h" #include #include #include "utility.h" #define MAP_NO m_MapNO /** *
功能说明:添加节点到可渲染几何体集 *
可访问性:global *
注 释: * @param pObject[in] 待加入节点 * @param pVisible[in] 可渲染几何体集 * @return 无 */ void Global_AddNodeToVisiblaArray( NiAVObject *pObject, NiVisibleArray *pVisible ) { if (NiIsKindOf(NiGeometry, pObject)) { NiGeometry *pGeometry = NiDynamicCast( NiGeometry, pObject ); pVisible->Add( *pGeometry ); } else if ( NiIsKindOf(NiNode, pObject)) { NiNode *pNode = NiDynamicCast( NiNode, pObject ); for ( unsigned int i = 0; i < pNode->GetArrayCount(); i++ ) { NiAVObject *pChild = pNode->GetAt(i); Global_AddNodeToVisiblaArray( pChild, pVisible ); } } } void Global_CalculateNormal( const NiPoint3& v0, const NiPoint3& v1, const NiPoint3& v2, NiPoint3& vPt0, NiPoint3& vPt1 ) {} CTerrain::CTerrain(void) : m_pVertices(0), m_pNormals(0), m_pTexset0(0), m_pTexset1(0), m_pVertexClr(0) , m_pChunks(0),m_pGrids(0), m_spBlendTexture(0), m_MapNO(0) { #ifndef CODE_INGAME m_pObjectsMgr = new CObjectsManager( this ); m_pLightsMgr = new CLightsManager( this ); m_NpcCreatorManager.SetTerrain(this); m_pAreaMgr = new CAreaManager( this ); m_iLastChangedChunk = 0; m_bSimpleRender = false; m_bWaterScene = false; m_fImageFrameCount = 30.0f; m_fPreTime = 0.0f; m_fWaterCaustics_Size = 0.005f; m_fWaterCaustics_XOffset = 0.125f; m_fWaterCaustics_YOffset = 0.1f; m_fWaterCausticsFactor = 1.0f; #endif m_spTerrainRoot = NiNew NiNode(); // m_spPhyxRoot = NiNew NiNode(); //m_spCollisionRoot = NiNew NiNode(); } CTerrain::~CTerrain(void) { Destroy(); m_spTerrainRoot = 0; } /// 创建地形 bool CTerrain::Create( int iChunkX, int iChunkY, const char *pszBaseTex, DWORD dwNumber) { LOG( " 创建Start\n\n\n" ); if ( !pszBaseTex ) { LOG( "基础材质不可为空!\n" ); return false; } TRY_BEGIN // @step0 创建Blend纹理 /*if ( !CreateBlendTexture() ) { LOG( "Blend纹理创建失败!\n" ); return false; }*/ if ( iChunkX > MAX_CHUNK || iChunkY > MAX_CHUNK ) { LOG( "地块超过最大数目!\n" ); return false; } m_MapNO = dwNumber; m_iChunkNumX = iChunkX, m_iChunkNumY = iChunkY; ////@step1 设定顶点数据 m_iVertexX = ( m_iChunkNumX*GRIDINCHUNK+1 ); m_iVertexY = ( m_iChunkNumY*GRIDINCHUNK+1 ); int iVertexNum = m_iVertexX * m_iVertexY; // 地形总顶点个数 m_pVertices = NiNew NiPoint3[iVertexNum]; m_pNormals = NiNew NiPoint3[iVertexNum]; m_pTexset0 = NiNew NiPoint2[iVertexNum]; m_pTexset1 = NiNew NiPoint2[iVertexNum]; m_pVertexClr= NiNew NiColorA[iVertexNum]; // 碰撞数据 //m_pCollisionVertices = NiNew NiPoint3[iVertexNum]; // 初始化所有顶点数据 int index = 0; for ( int i = 0; i < m_iVertexY; ++i ) { for ( int j = 0; j < m_iVertexX; ++j ) { m_pVertices[index] = NiPoint3( float(j*EDIT_UNIT), float(i*EDIT_UNIT), 0 ); m_pNormals[index] = NiPoint3( 0,0,1 ); m_pTexset0[index] = NiPoint2( float(j*0.1f), float(i*0.1f) ); //m_pTexset0[index] = NiPoint2( (float)j/m_iVertexX, (float)i/m_iVertexY ); m_pTexset1[index] = NiPoint2( float(j)/float(GRIDINCHUNK), float(i)/(float)GRIDINCHUNK ); //m_pTexset0[] = m_pTexset1[index]; //m_pTexset1[index] = NiPoint2( float(j)/(float)(m_iVertexX-1), float(i)/(float)(m_iVertexY-1) ); // changed by syz, 顶点色初始化为黑色 m_pVertexClr[index] = NiColorA(0,0,0,1); index++; } } ////@step2 设定Chunk数据 int iChunkNum = m_iChunkNumX * m_iChunkNumY; m_pChunks = new stChunk[iChunkNum]; index = 0; for ( int i = 0; i < m_iChunkNumY; ++i ) { for ( int j = 0; j < m_iChunkNumX; ++j ) { m_pChunks[index].pChunkMtl = new CTerrainMaterial( pszBaseTex, NULL, NULL, NULL ); if ( !m_pChunks[index].pChunkMtl->Create() ) { LOG1( "第%d个Chunk材质创建失败!\n", index ); return false; } int iMinIndex = (i*m_iVertexX + j) * GRIDINCHUNK; int iMaxIndex = ((i+1)*m_iVertexX + (j+1) ) * GRIDINCHUNK; //int iMinIndex = (i*m_iChunkNumX + j) * GRIDINCHUNK; //int iMaxIndex = ((i+1)*m_iChunkNumX + (j+1) ) * GRIDINCHUNK; m_pChunks[index].vPosMin = NiPoint2( m_pVertices[ iMinIndex ].x, m_pVertices[ iMinIndex ].y ); m_pChunks[index].vPosMax = NiPoint2( m_pVertices[ iMaxIndex ].x, m_pVertices[ iMaxIndex ].y ); // 分配chunk的可渲染数据 _BuildChunkData( j, i ); index++; } } //@step3 设定Grid数据 int iGridX = m_iChunkNumX * GRIDINCHUNK; int iGridY = m_iChunkNumY * GRIDINCHUNK; m_pGrids = new stGrid[ iGridX*iGridY ]; m_iTotalX = EDIT_UNIT * iGridX; m_iTotalY = EDIT_UNIT * iGridY; index = 0; for ( int i = 0; i < iGridY; ++i ) { //index += i*iGridX; for ( int j = 0; j < iGridX; ++j ) { // 设定chunk的Grid数据 /* 3|---|2 0|___|1 */ m_pGrids[index].iPointIndx[0] = i*m_iVertexX+j; m_pGrids[index].iPointIndx[1] = i*m_iVertexX+j+1; m_pGrids[index].iPointIndx[2] = (i+1)*m_iVertexX+j+1; m_pGrids[index].iPointIndx[3] = (i+1)*m_iVertexX+j; index++; } } //SetCollisionTexture( ); TRY_END_HANDLE( Destroy(); return false ) //CreatePointLight_Debug(); LOG( "创建结束 \n" ); //NiDelete[] m_pVertices; return true; } bool CTerrain::_BuildChunkData( int iIndexX, int iIndexY, bool bBuildGeometryData, bool bBuildMaterialData ) { TRY_BEGIN // assert索引 int iChunkIndx = iIndexY * m_iChunkNumX + iIndexX; assert( iChunkIndx >= 0 && iChunkIndx < m_iChunkNumX * m_iChunkNumY ); if (bBuildGeometryData) { CTerrain::stChunk::stGeomData& geomData = m_pChunks[iChunkIndx].geomData; // 顶点数 int iVertNum = (GRIDINCHUNK+1) * (GRIDINCHUNK+1); int iVertNum2 = 2*iVertNum; /// 计算总索引 geomData.pGlobalVertIndx = new DWORD[ iVertNum ]; int iOffsetX = iIndexX * GRIDINCHUNK; int iOffsetY = iIndexY * GRIDINCHUNK; int indx = 0; for ( int n = 0; n < GRIDINCHUNK+1; ++n ) { for ( int m = 0; m < GRIDINCHUNK+1; ++m ) { geomData.pGlobalVertIndx[indx++] = (n+iOffsetY)*m_iVertexX + (m+iOffsetX); } } // 分配渲染数据 NiPoint3* pVerts = NiNew NiPoint3[iVertNum]; NiPoint3* pNormals = NiNew NiPoint3[iVertNum]; NiPoint2* pTexCoords = NiNew NiPoint2[iVertNum2]; NiColorA* pColors = NiNew NiColorA[iVertNum]; for ( int n = 0; n < iVertNum; ++n ) { int indx = geomData.pGlobalVertIndx[n]; pVerts[n] = m_pVertices[ indx ]; pNormals[n] = m_pNormals[ indx ]; pTexCoords[n] = m_pTexset0[ indx ]; pTexCoords[iVertNum + n] = m_pTexset1[indx]; pColors[n] = m_pVertexClr[indx]; } // 重新设置 tex coord 1 的值。使其从 0~1 float fPixelSize = 1.0f / BLENDTEX_SIZE; float fHalfPixelSize = fPixelSize * 0.5f; indx = 0; for ( int n = 0; n < GRIDINCHUNK+1; ++n ) // 遍历行 { for ( int m = 0; m < GRIDINCHUNK+1; ++m, indx++ ) // 遍历列 { pTexCoords[iVertNum + indx].x = (float)m/(GRIDINCHUNK)*(1.0f-fPixelSize) + fHalfPixelSize; pTexCoords[iVertNum + indx].y = (float)n/(GRIDINCHUNK)*(1.0f-fPixelSize) + fHalfPixelSize; } } WORD *pConnect = NiAlloc( WORD, GRIDINCHUNK*GRIDINCHUNK * 2 * 3 ); indx = 0; for ( int n = 0; n < GRIDINCHUNK; ++n ) { for ( int m = 0; m < GRIDINCHUNK; ++m ) { pConnect[indx++] = n * (GRIDINCHUNK+1)+m; pConnect[indx++] = n * (GRIDINCHUNK+1)+m+1; pConnect[indx++] = (n+1) * (GRIDINCHUNK+1)+m+1; pConnect[indx++] = n * (GRIDINCHUNK+1)+m; pConnect[indx++] = (n+1) * (GRIDINCHUNK+1)+m+1; pConnect[indx++] = (n+1) * (GRIDINCHUNK+1)+m; } } // 生成几何数据 int iTriNum = GRIDINCHUNK*GRIDINCHUNK*2; NiTriShapeDynamicData *pData = NiNew NiTriShapeDynamicData( iVertNum, pVerts, pNormals, pColors, pTexCoords, 2, NiGeometryData::NBT_METHOD_NDL, iTriNum, pConnect, iVertNum, iTriNum ); geomData.pTriShape = NiNew NiTriShape( pData ); m_spTerrainRoot->AttachChild( geomData.pTriShape ); // 设置名字 char szName[16]; sprintf_s( szName, 16, "Chunk_%d", iChunkIndx ); geomData.pTriShape->SetName( szName ); //NiBound kBound; //kBound.ComputeFromData( iVertNum, pVerts ); //geomData.pTriShape->SetModelBound(kBound); } if (bBuildMaterialData) { CTerrain::stChunk::stGeomData& geomData = m_pChunks[iChunkIndx].geomData; // 设置纹理属性 NiTexturingProperty * pTexProp = NiNew NiTexturingProperty( "" ); pTexProp->SetApplyMode( NiTexturingProperty::APPLY_MODULATE ); // 设置ShaderMap CTerrainMaterial *pTerrainMtl = m_pChunks[iChunkIndx].pChunkMtl; geomData.pTriShape->SetShader( pTerrainMtl->GetShader() ); for ( int i = 0; i < pTerrainMtl->GetUsedLayerCount(); ++i ) { NiTexturingProperty::ShaderMap* pShaderMap = NiNew NiTexturingProperty::ShaderMap( pTerrainMtl->GetTexture(i), i ); pTexProp->SetShaderMap( i, pShaderMap ); } // 设置Blend纹理 NiTexturingProperty::ShaderMap* pShaderMap = NiNew NiTexturingProperty::ShaderMap( pTerrainMtl->GetBlendTexture(), 4 ); pTexProp->SetShaderMap( 4, pShaderMap ); // Shader map 5 用于CursorTexture [10/21/2009 hemeng] #ifndef CODE_INGAME // 设置Property纹理 只在编辑器中使用 pShaderMap = NiNew NiTexturingProperty::ShaderMap( pTerrainMtl->GetPropertyTexture(), 6 ); pTexProp->SetShaderMap( 6, pShaderMap ); #endif // add 设置水波shader map [10/21/2009 hemeng] pShaderMap = NiNew NiTexturingProperty::ShaderMap( NULL, 7); pTexProp->SetShaderMap(7, pShaderMap); // end of add [10/21/2009 hemeng] geomData.pTriShape->ApplyAndSetActiveMaterial( pTerrainMtl->GetMaterial() ); geomData.pTriShape->AttachProperty( pTexProp ); // 设置用户数据 //geomData.pTriShape->GetExtreData( "CursorPoint", pCursorPoint ); if ( NULL == geomData.pTriShape->GetExtraData( "ShowCollisionData") ) { NiPoint3 vPoint = NiPoint3::ZERO; NiFloatsExtraData *pCursorPoint = NiNew NiFloatsExtraData( 3, (float *)&vPoint.x ); geomData.pTriShape->AddExtraData( "CursorPoint", pCursorPoint ); NiFloatExtraData *pCursorRadius = NiNew NiFloatExtraData( .0f ); geomData.pTriShape->AddExtraData( "CursorRadius", pCursorRadius ); NiFloatExtraData *pShowCollisionData = NiNew NiFloatExtraData( .0f ); geomData.pTriShape->AddExtraData( "ShowCollisionData", pShowCollisionData ); } if ( NULL == geomData.pTriShape->GetExtraData("bShow")) { // add [6/11/2009 hemeng] // 显示/隐藏 地形 NiFloatExtraData *pShowHiddenTerrain = NiNew NiFloatExtraData(.0f); if(!geomData.pTriShape->AddExtraData( "bShow", pShowHiddenTerrain )) { NiMessageBox("Fail to find bShow","Error"); } } geomData.pTriShape->Update(0.0f); geomData.pTriShape->UpdateProperties(); geomData.pTriShape->UpdateEffects(); } TRY_END_RETURN( false ) return true; } /// 重新分配每个chunk顶点索引,取消优化 void CTerrain::ReorderVertexIndex() { // 遍历所有 chunk for (int i=0; iGetTriList(); int iIdx = 0; for ( int n = 0; n < GRIDINCHUNK; ++n ) { for ( int m = 0; m < GRIDINCHUNK; ++m ) { pConnect[iIdx++] = n * (GRIDINCHUNK+1)+m; pConnect[iIdx++] = n * (GRIDINCHUNK+1)+m+1; pConnect[iIdx++] = (n+1) * (GRIDINCHUNK+1)+m+1; pConnect[iIdx++] = n * (GRIDINCHUNK+1)+m; pConnect[iIdx++] = (n+1) * (GRIDINCHUNK+1)+m+1; pConnect[iIdx++] = (n+1) * (GRIDINCHUNK+1)+m; } } m_pChunks[i].geomData.pTriShape->SetActiveTriangleCount(GRIDINCHUNK*GRIDINCHUNK*2); m_pChunks[i].geomData.pTriShape->GetModelData()->MarkAsChanged( NiTriBasedGeomData::TRIANGLE_INDEX_MASK | NiTriBasedGeomData::TRIANGLE_COUNT_MASK); m_pChunks[i].geomData.pTriShape->Update(0.0f); } } /// 从高度图创建地形 bool CTerrain::CreateFromHeightmap( const char *pszFile, const char *pszBaseTex ) { return true; } /// 函数作废 bool CTerrain::CreateBlendTexture( bool bNeedInit ) { //NiTexture::FormatPrefs kPrefs; //kPrefs.m_ePixelLayout = NiTexture::FormatPrefs::TRUE_COLOR_32; //kPrefs.m_eMipMapped = NiTexture::FormatPrefs::NO; //NiPixelData *pPixelData = NiNew NiPixelData( BLEND_TEX_SIZE, BLEND_TEX_SIZE, NiPixelFormat::BGRA8888 ); //NiSourceTexture::SetDestroyAppDataFlag( false ); //m_spBlendTexture = NiSourceTexture::Create( pPixelData ); //m_spBlendTexture->SetStatic( false ); //NiSourceTexture::SetDestroyAppDataFlag( true ); //if ( !m_spBlendTexture ) return false; //if ( bNeedInit ) //{ // for ( int y = 0; y < BLEND_TEX_SIZE; ++y ) // { // for ( int x = 0; x < BLEND_TEX_SIZE; ++x ) // { // unsigned char *pPtr = ( *pPixelData )(x,y); // pPtr[0] = pPtr[1] = pPtr[2] = 0x00; //B,G,R // pPtr[3] = 0xff; //A // } // } //} //pPixelData->MarkAsChanged(); return true; } void CTerrain::Destroy() { #ifndef CODE_INGAME RemoveAllEntity(); SAFE_DELETE( m_pObjectsMgr ); SAFE_DELETE( m_pLightsMgr ); m_mapOverTopVertexs.clear(); #endif SAFE_DELETE_ARRAY( m_pVertices ); SAFE_DELETE_ARRAY( m_pNormals ); SAFE_DELETE_ARRAY( m_pVertexClr ); SAFE_DELETE_ARRAY( m_pTexset0 ); SAFE_DELETE_ARRAY( m_pTexset1 ); SAFE_DELETE_ARRAY( m_pChunks ); SAFE_DELETE_ARRAY( m_pGrids ); m_spBlendTexture = 0; m_spTerrainRoot = 0; // m_spPhyxRoot = 0; CTerrainTextureMgr::GetInstance()->ClearAll(); } void CTerrain::Update( double dTime, float fElapsedTime ) { //m_spTerrainRoot->Update( fElapsedTime ); //m_spTerrainRoot->UpdateEffects(); //m_spTerrainRoot->UpdateProperties(); // NiMessageBox("Update CTerrain","Message"); //test for CTerrain Update [10/22/2009 hemeng] } void CTerrain::_Update( double dTime, float fElapsedTime ) { int index = 0; for ( int i = 0; i < m_iChunkNumY; ++i ) { for ( int j = 0; j < m_iChunkNumX; ++j ) { NiTriShape *pTriShape = m_pChunks[index].geomData.pTriShape; if ( pTriShape ) { pTriShape->UpdateProperties(); pTriShape->UpdateEffects(); pTriShape->Update( .0f ); } } } } void CTerrain::BuilderVisibleSet( NiCamera * pCamera, NiVisibleArray *pVisible ) { NIASSERT(pCamera && pVisible); set< NiGeometry* >::iterator it1 = m_RenderableChunkset.begin(); for ( ; it1 != m_RenderableChunkset.end(); ++it1 ) { pVisible->Add( *(*it1) ); } } void CTerrain::Render( NiCamera *pCamera, NiCullingProcess *pCuller, NiVisibleArray *pVisible ) { // 确定活动相机 BuilderVisibleSet( pCamera, pVisible ); // 渲染 //NiDrawVisibleArray( pCamera, *pVisible ); NiDrawScene( pCamera, m_spTerrainRoot, *pCuller, pVisible ); pVisible->RemoveAll(); } /// 获得指定位置的Chunk索引 __forceinline int CTerrain::GetChunkIndex( const NiPoint3& vPos ) { static const float fUnit = 1.0f / ( EDIT_UNIT * GRIDINCHUNK ); //int x = (int)floor( vPos.x / float( EDIT_UNIT * GRIDINCHUNK ) ); //int y = (int)floor( vPos.y / float( EDIT_UNIT * GRIDINCHUNK ) ); int x = (int)floor( vPos.x * fUnit ); int y = (int)floor( vPos.y * fUnit ); int index = y*m_iChunkNumX+x; if ( x < 0 || y < 0 || index >= m_iChunkNumX*m_iChunkNumY ) return INVALID_CHUNK; return index; } int CTerrain::GetIndexInChunk(int iChunkID,const NiPoint3& kPoint) { unsigned short usVertCount = m_pChunks[iChunkID].geomData.pTriShape->GetVertexCount(); NiPoint3* pVertice = m_pChunks[iChunkID].geomData.pTriShape->GetVertices(); int iPointx = (int)(kPoint.x + 0.5); int iPointy = (int)(kPoint.y + 0.5); for (unsigned short i = 0; i < usVertCount; i++) { int ix = (int)(pVertice[i].x + 0.5); int iy = (int)(pVertice[i].y + 0.5); if(ix == iPointx && iy == iPointy) { return i; } } return -1; } void CTerrain::GetChunkIndex( const NiPoint3& vPos, set& chunkset ) { for ( int i = 0; i < m_iChunkNumY; ++i ) { for ( int j = 0; j < m_iChunkNumX; ++j ) { int index = i*m_iChunkNumX+j; NiPoint2 vMin = m_pChunks[index].vPosMin; NiPoint2 vMax = m_pChunks[index].vPosMax; if ( vPos.x >= vMin.x && vPos.x <= vMax.x && vPos.y >= vMin.y && vPos.y <= vMax.y ) { chunkset.insert( index ); } } } } /// 获得指定位置的Grid索引 int CTerrain::GetGridIndex( const NiPoint3& vPos ) { int x = (int)floor( vPos.x / float( EDIT_UNIT ) ); int y = (int)floor( vPos.y / float( EDIT_UNIT ) ); int index = y*m_iChunkNumX*GRIDINCHUNK+x; if ( x < 0 || y < 0 || index >= (m_iChunkNumX*GRIDINCHUNK)*(m_iChunkNumY*GRIDINCHUNK) ) return INVALID_GRID; return index; } /// 获取高度值(精确) float CTerrain::GetHeight( const NiPoint2& vPos ) { int iGridIndx = GetGridIndex( NiPoint3( vPos.x, vPos.y, 0 ) ); if ( iGridIndx == INVALID_GRID ) return .0f; int indexArray[4]; for ( int i = 0; i < 4; ++i ) { indexArray[i] = m_pGrids[iGridIndx].iPointIndx[i]; } float f1 = (vPos.y - m_pVertices[indexArray[0]].y) / (m_pVertices[indexArray[3]].y - m_pVertices[indexArray[0]].y); float f2 = f1; float fx1 = m_pVertices[indexArray[0]].z * ( 1 - f1 ) + f1 * m_pVertices[indexArray[3]].z; float fx2 = m_pVertices[indexArray[1]].z * ( 1 - f2 ) + f2 * m_pVertices[indexArray[2]].z; float f3 = (vPos.x - m_pVertices[indexArray[0]].x) / (m_pVertices[indexArray[1]].x - m_pVertices[indexArray[0]].x); float fHeight = fx1 * ( 1 - f3 ) + fx2 * f3; return fHeight; } /// 获取高度值(粗糙) float CTerrain::GetRawHeight( const NiPoint2& vPos ) { int iGridIndx = GetGridIndex( NiPoint3( vPos.x, vPos.y, 0 ) ); if ( iGridIndx == INVALID_GRID ) return .0f; float sum = .0f; for ( int i = 0; i < 4; ++i ) { int index = m_pGrids[iGridIndx].iPointIndx[i]; sum += m_pVertices[index].z; } return sum * 0.25f; } NiPoint2 CTerrain::GetTotalSize() { return NiPoint2((float)m_iTotalX, (float)m_iTotalY); } int CTerrain::GetVerticesInLine(int iPosX1, int iPosY1, int iPoxX2, int iPosY2, vector& verticesList, vector& verticesNewHeight) { int e, t, x, y, yi, tx, ty, dx, dy; float fStartHeight; float fEndHeight; float fBuffer; fStartHeight = GetVertexHeight(iPosX1, iPosY1); fEndHeight = GetVertexHeight(iPoxX2, iPosY2); x = iPosX1; y = iPosY1; yi = iPosY1; tx = abs(iPoxX2 - iPosX1); ty = abs(iPosY2 - iPosY1); if (tx > ty) { t = tx; e = 2*ty - tx; } else { t = ty; e = 2*tx - ty; } fBuffer = (fEndHeight - fStartHeight) / (t + 1); if (iPoxX2 >= iPosX1) { dx = 1; } else { dx = -1; } if (iPosY2 >= iPosY1) { dy = 1; } else { dy = -1; } for(int i = 1;i < t;i++) { if (tx >= ty) { x = x + dx; if (e >= 0) { y = y + dy; e = e - 2*tx; } e = e + 2*ty; } else { y = y + dy; if (e >= 0) { x = x + dx; e = e - 2*ty; } e = e + 2*tx; } int iIndex = y*(m_iChunkNumX*GRIDINCHUNK+1) + x; verticesList.push_back(iIndex); float fNewHeight = fStartHeight + i*fBuffer; verticesNewHeight.push_back(fNewHeight); /// 调整周围点的高度,使得地形平滑 float fTempHeight = GetVertexHeight(x+1, y); float fBuffer2 = abs(fBuffer); if (abs(fTempHeight - fNewHeight) > 2*fBuffer2) { iIndex = y*(m_iChunkNumX*GRIDINCHUNK+1) + x+1; verticesList.push_back(iIndex); verticesNewHeight.push_back(fNewHeight); } fTempHeight = GetVertexHeight(x-1, y); if (abs(fTempHeight - fNewHeight) > 2*fBuffer2) { iIndex = y*(m_iChunkNumX*GRIDINCHUNK+1) + x-1; verticesList.push_back(iIndex); verticesNewHeight.push_back(fNewHeight); } fTempHeight = GetVertexHeight(x, y+1); if (abs(fTempHeight - fNewHeight) > 2*fBuffer2) { iIndex = (y+1)*(m_iChunkNumX*GRIDINCHUNK+1) + x; verticesList.push_back(iIndex); verticesNewHeight.push_back(fNewHeight); } fTempHeight = GetVertexHeight(x, y-1); if (abs(fTempHeight - fNewHeight) > 2*fBuffer2) { iIndex = (y-1)*(m_iChunkNumX*GRIDINCHUNK+1) + x; verticesList.push_back(iIndex); verticesNewHeight.push_back(fNewHeight); } } return t-1; } /// 制造斜坡 int CTerrain::MakeIncline(int iPosX1, int iPosY1, int iPoxX2, int iPosY2, float fRadius, vector& verticesList, vector& verticesNewHeight) { //两点重合,直接返回 if (iPosX1 == iPoxX2 && iPosY1 == iPosY2) { return 0; } GetVerticesInLine(iPosX1, iPosY1, iPoxX2, iPosY2, verticesList, verticesNewHeight); float dx = 0.0f; float dy = 0.0f; float fNewX1 = iPosX1; float fNewY1 = iPosY1; float fNewX2 = iPoxX2; float fNewY2 = iPosY2; float fNewX3 = iPosX1; float fNewY3 = iPosY1; float fNewX4 = iPoxX2; float fNewY4 = iPosY2; // 构成的正方形,计算非常方便 if (iPosX1 == iPoxX2) { dx = 0.0f; dy = 1.0f; } else if (iPosY1 == iPosY2) { dx = 1.0f; dy = 0.0f; } else { float k = float(iPosY2-iPosY1)/(iPoxX2-iPosX1); k = -1/k; if (fabs(k) <= 1) { dx = 1.0f; dy = k; } else { dx = 1/k; dy = 1.0f; } } float fArea = sqrt( (fNewX1-iPosX1)*(fNewX1-iPosX1) + (fNewY1-iPosY1)*(fNewY1-iPosY1)); while (fArea < fRadius ) { fNewX1 += dx; fNewY1 += dy; fNewX2 += dx; fNewY2 += dy; GetVerticesInLine(fNewX1+0.5f, fNewY1+0.5f, fNewX2+0.5f, fNewY2+0.5f, verticesList, verticesNewHeight); fNewX3 -= dx; fNewY3 -= dy; fNewX4 -= dx; fNewY4 -= dy; GetVerticesInLine(fNewX3+0.5f, fNewY3+0.5f, fNewX4+0.5f, fNewY4+0.5f, verticesList, verticesNewHeight); fArea = sqrt( (fNewX1-iPosX1)*(fNewX1-iPosX1) + (fNewY1-iPosY1)*(fNewY1-iPosY1)); } return 0; } // 获取 X 方向 chunk 数 int CTerrain::GetChunkNumX() { return m_iChunkNumX; } // 获取 Y 方向 chunk 数 int CTerrain::GetChunkNumY() { return m_iChunkNumY; } // 获取与指定grid相距一定距离的grid, 距离单位同样为grid void CTerrain::GetGridArray( int iGrid, WORD usOffset, set& gridset ) { gridset.insert( iGrid ); int iGridX = m_iChunkNumX * GRIDINCHUNK; int iGridY = m_iChunkNumY * GRIDINCHUNK; int ix = iGrid % ( iGridX ); int iy = iGrid / ( iGridX ); int iYFrom = iy - usOffset; int iYTo = iy + usOffset; int iXFrom = ix - usOffset; int iXTo = ix + usOffset; for ( int y = iYFrom; y <= iYTo; ++y ) { if ( y >= 0 && y < GRIDINCHUNK*m_iChunkNumY ) { for ( int x = iXFrom; x <= iXTo; ++x ) { if ( x >= 0 && x < GRIDINCHUNK*m_iChunkNumX ) { gridset.insert( y* m_iChunkNumX*GRIDINCHUNK + x ); } } } } } ///获取与指定chunk相距一定距离的chunks void CTerrain::GetChunkArray( int iChunk, WORD usOffset, set& chunkset ) { chunkset.insert( iChunk ); int iy = iChunk / m_iChunkNumX; int ix = iChunk % m_iChunkNumX; int iYFrom = iy - usOffset; int iYTo = iy + usOffset; int iXFrom = ix - usOffset; int iXTo = ix + usOffset; for ( int y = iYFrom; y <= iYTo; ++y ) { if ( y >= 0 && y < m_iChunkNumY ) { for ( int x = iXFrom; x <= iXTo; ++x ) { if ( x >= 0 && x < m_iChunkNumX ) { chunkset.insert( y* m_iChunkNumX + x ); } } } } } // 查找矩形范围覆盖的所有网格点 void CTerrain::GetPointsFromRectangle( float fLB_x, float fLB_y, float fRT_x, float fRT_y, vector< vector >& vPointArray ) { // @1矩形不相交 if ( fRT_x < 0.0f || fRT_y < 0.0f || fLB_x > m_iTotalX || fLB_y > m_iTotalY ) return; // @2矩形全包含, 这种情况暂不处理 if ( fRT_x>= m_iTotalX && fRT_y >= m_iTotalY && fLB_x <= 0.0f && fLB_y <= 0.0f ) {return;} float fLBx = fLB_x; float fLBy = fLB_y; float fRTx = fRT_x; float fRTy = fRT_y; float fTemp_x, fTemp_y; // @3矩形修正 if ( fLBx < .0f ) fLBx = .0f; if ( fLBy < .0f ) fLBy = .0f; if ( fRTx > m_iTotalX ) fRTx = static_cast(m_iTotalX); if ( fRTy > m_iTotalY ) fRTy = static_cast(m_iTotalY); // @4处理一般情况 { // @4-1 计算各向跨度 int iMinGrid_x = (int)fLBx / EDIT_UNIT+1; int iMaxGrid_x = (int)fRTx / EDIT_UNIT; int iMinGrid_y = (int)fLBy / EDIT_UNIT+1; int iMaxGrid_y = (int)fRTy / EDIT_UNIT; // @4-2 最小行 { // 首列 vector vRowPt; NiPoint3 pB = NiPoint3( fLBx, fLBy, GetHeight( NiPoint2(fLBx, fLBy) ) ); vRowPt.push_back( pB ); for( int i = iMinGrid_x; i <= iMaxGrid_x; ++i ) { float x = static_cast( i * EDIT_UNIT ); float y = fLBy; float z = GetHeight( NiPoint2( x, y ) ); vRowPt.push_back( NiPoint3(x,y,z) ); fTemp_x = x; } // 末列 if ( !FLOATEQUALZERO( fTemp_x - fRTx ) ) vRowPt.push_back( NiPoint3( fRTx, fLBy, GetHeight( NiPoint2( fRTx, fLBy ) ) ) ); vPointArray.push_back( vRowPt ); } // @4-3中间格子 for ( int i = iMinGrid_y; i <= iMaxGrid_y; ++i ) { fTemp_y = static_cast( i * EDIT_UNIT ); // 首列 vector vRowPt; vRowPt.push_back( NiPoint3(fLBx, fTemp_y, GetHeight( NiPoint2(fLBx,fTemp_y))) ); for ( int j = iMinGrid_x; j <= iMaxGrid_x; ++j ) { int index = m_iVertexX*i+j; vRowPt.push_back( m_pVertices[index] ); fTemp_x = m_pVertices[index].x; } // 末列 if ( !FLOATEQUALZERO( fTemp_x - fRTx ) ) vRowPt.push_back( NiPoint3(fRTx, fTemp_y, GetHeight( NiPoint2(fRTx,fTemp_y))) ); vPointArray.push_back( vRowPt ); } // @4-4 最大行 if ( !FLOATEQUALZERO(fTemp_y - fRTy) ) { // 首列 vector vRowPt; vRowPt.push_back( NiPoint3(fLBx, fRTy, GetHeight( NiPoint2(fLBx, fRTy ))) ); for ( int i = iMinGrid_x; i <= iMaxGrid_x; ++i ) { float x = static_cast(i * EDIT_UNIT); float y = fRTy; float z = GetHeight( NiPoint2( x, y ) ); vRowPt.push_back( NiPoint3(x,y,z) ); fTemp_x = x; } // 末列 if ( !FLOATEQUALZERO( fTemp_x - fRTx ) ) vRowPt.push_back( NiPoint3( fRTx, fRTy, GetHeight( NiPoint2(fRTx,fRTy))) ); vPointArray.push_back( vRowPt ); } } } bool CTerrain::_BuildChunkNormalLine( int iIndexX, int iIndexY ) { // assert索引 int iChunkIndx = iIndexY * m_iChunkNumX + iIndexX; assert( iChunkIndx >= 0 && iChunkIndx < m_iChunkNumX * m_iChunkNumY ); CTerrain::stChunk::stGeomData& geomData = m_pChunks[iChunkIndx].geomData; // 顶点数 int iVertNum = (GRIDINCHUNK+1) * (GRIDINCHUNK+1); int iVertNum2 = 2*iVertNum; NiPoint3 *pVerts = NiNew NiPoint3[ iVertNum2 ]; NiColorA *pColors = NiNew NiColorA[ iVertNum2 ]; for ( int n = 0; n < iVertNum; ++n ) { int indx = geomData.pGlobalVertIndx[n]; pVerts[ 2*n ] = m_pVertices[indx]; pVerts[2*n+1] = m_pVertices[indx] + m_pNormals[n]; pColors[ 2*n ] = NiColorA( 0, 1, 0, 1 ); pColors[2*n+1] = NiColorA( 0, 1, 0, 1 ); } NiBool* bConnect = (NiBool*)NiMalloc( sizeof(NiBool)* iVertNum2 ); for ( int i = 0; i < iVertNum2; ++i ) { bConnect[i] = ( i%2 )? false : true; } geomData.pLine = NiNew NiLines( iVertNum2, pVerts, pColors, 0, 0, NiGeometryData::NBT_METHOD_NONE, bConnect ); //m_spTerrainRoot->AttachChild( geomData.pLine ); NiVertexColorProperty * pVCProp = NiNew NiVertexColorProperty; pVCProp->SetLightingMode( NiVertexColorProperty::LIGHTING_E ); pVCProp->SetSourceMode( NiVertexColorProperty::SOURCE_EMISSIVE ); geomData.pLine->AttachProperty( pVCProp ); geomData.pLine->Update(.0f); geomData.pLine->UpdateProperties(); geomData.pLine->UpdateEffects(); return true; } //------------------------------------------------------------------------------------------- void CTerrain::SetFog(bool bEnable, NiColor& kColor, float fDepth) { //for ( int i = 0; i < m_iChunkNumX * m_iChunkNumY; ++i ) //{ // NiFloatExtraData * pExtraData = (NiFloatExtraData*)m_pChunks[i].geomData.pTriShape->GetExtraData( "CursorRadius" ); // if (pExtraData) pExtraData->SetValue( fRadius ); //} } //------------------------------------------------------------------------------------------- void CTerrain::CreatePointLight_Debug() { NiPointLight *pPointLight = NiNew NiPointLight; m_spTerrainRoot->AttachChild( pPointLight ); pPointLight->AttachAffectedNode( m_spTerrainRoot ); pPointLight->SetDimmer(1.0f); pPointLight->SetAmbientColor( NiColor::BLACK ); pPointLight->SetDiffuseColor( NiColor( 0.8f, 0.8f, 0.8f ) ); pPointLight->SetSpecularColor( NiColor::BLACK ); pPointLight->SetConstantAttenuation(0.0f); pPointLight->SetLinearAttenuation(0.01f); pPointLight->SetQuadraticAttenuation(0.0f); pPointLight->SetWorldTranslate( NiPoint3( 0, 0, 100 ) ); m_spTerrainRoot->UpdateEffects(); } /*************************************************** * 这里是只在编辑器中使用,游戏中不使用的函数实现 ****************************************************/ #ifndef CODE_INGAME /// 保存blend纹理数据,仅供测试 函数作废 bool CTerrain::SaveBlendTexture( const char *pszFile ) { //if ( !m_spBlendTexture ) return false; //CImage image; //image.Create( BLEND_TEX_SIZE, BLEND_TEX_SIZE, 32, CImage::createAlphaChannel ); //NiPixelData *pPixelData = m_spBlendTexture->GetSourcePixelData(); //unsigned char *pPtr = (*pPixelData)( 0, 0 ); //unsigned char *pData = ( unsigned char *)image.GetBits(); //for ( int y = 0; y < BLEND_TEX_SIZE; y++) //{ // memcpy( pData, pPtr, BLEND_TEX_SIZE * 4 ); // pPtr = (*pPixelData)( 0, y); // pData += image.GetPitch(); //} //image.Save( pszFile ); return false; } //////////////////////////////////////////////////////////////////////////// void CTerrain::SetShowCollisonData( bool bShow ) { for ( int i = 0; i < m_iChunkNumX * m_iChunkNumY; ++i ) { NiFloatExtraData * pExtraData = ( NiFloatExtraData* )m_pChunks[i].geomData.pTriShape->GetExtraData( "ShowCollisionData" ); if (pExtraData) bShow ? pExtraData->SetValue( 1 ) : pExtraData->SetValue( 0 ); } } ////////////////////////////////////////////////////////////////////////// // add [6/11/2009 hemeng] void CTerrain::SetShowHiddenTerrain(bool bShow) { for ( int i = 0; i < m_iChunkNumX * m_iChunkNumY; i++ ) { NiFloatExtraData * pExtraData = ( NiFloatExtraData* )m_pChunks[i].geomData.pTriShape->GetExtraData( "bShow" ); if (pExtraData) bShow ? pExtraData->SetValue( 1 ) : pExtraData->SetValue( 0 ); } } void CTerrain::SetCursorRadius( float fRadius ) { for ( int i = 0; i < m_iChunkNumX * m_iChunkNumY; ++i ) { NiFloatExtraData * pExtraData = (NiFloatExtraData*)m_pChunks[i].geomData.pTriShape->GetExtraData( "CursorRadius" ); if (pExtraData) pExtraData->SetValue( fRadius ); } } void CTerrain::SetCursorPosition( const NiPoint3& vPoint ) { for ( int i = 0; i < m_iChunkNumX * m_iChunkNumY; ++i ) { NiFloatsExtraData * pExtraData = (NiFloatsExtraData*)m_pChunks[i].geomData.pTriShape->GetExtraData( "CursorPoint" ); if (pExtraData) pExtraData->SetArray( 3, (float*)&vPoint.x ); } } void CTerrain::SetCursorTexture( const char *pszTexFile ) { for ( int i = 0; i < m_iChunkNumX * m_iChunkNumY; ++i ) { NiTexturingProperty* pTexProp = (NiTexturingProperty *)m_pChunks[i].geomData.pTriShape->GetProperty( NiProperty::TEXTURING ); NiTexturingProperty::ShaderMap *pShaderMap = NiNew NiTexturingProperty::ShaderMap( CTerrainTextureMgr::GetInstance()->GetTexture( pszTexFile ), 5 ); pTexProp->SetShaderMap( 5, pShaderMap ); } } void CTerrain::SetCollisionTexture( ) { for ( int i = 0; i < m_iChunkNumX * m_iChunkNumY; ++i ) { NiTexturingProperty* pTexProp = (NiTexturingProperty *)m_pChunks[i].geomData.pTriShape->GetProperty( NiProperty::TEXTURING ); NiTexturingProperty::ShaderMap *pShaderMap = NiNew NiTexturingProperty::ShaderMap( m_pChunks[i].pChunkMtl->GetPropertyTexture(), 6 ); pTexProp->SetShaderMap( 6, pShaderMap ); } } void CTerrain::UpdateEntity(NiEntityInterface* pkEntityInterface, NiFixedString &pkPropertyName, EntityType kType) { if (kType == CTerrain::NPCCreator) { if (!m_NpcCreatorManager.IsExited(MAP_NO,pkEntityInterface)) { return; } m_NpcCreatorManager.UpdateNPCCreator(MAP_NO,pkEntityInterface, pkPropertyName); } else if (kType == CTerrain::REGION) { m_pAreaMgr->UpdateAreaPoint(pkEntityInterface, pkPropertyName); } else if(kType == CTerrain::OBJECT) { if ( !m_pObjectsMgr->IsExited(pkEntityInterface) ) { return; } m_pObjectsMgr->UpdateObject(pkEntityInterface, pkPropertyName); } else if(kType == CTerrain::LIGHT) { if ( !m_pLightsMgr->IsExited(pkEntityInterface) ) { return; } m_pLightsMgr->RemoveLight(pkEntityInterface); m_pLightsMgr->AddLight(pkEntityInterface); m_pLightsMgr->UpdateLight(pkEntityInterface, pkPropertyName); } } void CTerrain::AddEntity(NiEntityInterface* pkEntityInterface, EntityType kType) { if (kType == CTerrain::OBJECT) { } else if (kType == CTerrain::LIGHT) { m_pLightsMgr->AddLight(pkEntityInterface); } else if (kType == CTerrain::NPCCreator) { m_NpcCreatorManager.AddNPCCreator(MAP_NO,pkEntityInterface); } else if (kType == CTerrain::REGION) { unsigned int uiAreaID = m_pAreaMgr->CreateArea(1); //m_pAreaMgr->AddAreaPoint(uiAreaID, pkEntityInterface); m_pAreaMgr->AddAreaPoint(1, pkEntityInterface); } } void CTerrain::RemoveEntity(NiEntityInterface* pkEntityInterface, EntityType kType) { /// 调试信息 m_pObjectsMgr->PrintAll(); if (kType == CTerrain::OBJECT) { m_pObjectsMgr->RemoveObject(pkEntityInterface); } else if (kType == CTerrain::LIGHT) { m_pLightsMgr->RemoveLight(pkEntityInterface); } else if (kType == CTerrain::NPCCreator) { m_NpcCreatorManager.DelNPCCreator(MAP_NO,pkEntityInterface); } else if (kType == CTerrain::REGION) { m_pAreaMgr->DelAreaPoint(pkEntityInterface); } } void CTerrain::RemoveAllEntity() { m_pObjectsMgr->RemoveAllObjects(); m_pLightsMgr->RemoveAllLights(); } int CTerrain::GetCreateNPCRangeArray( const NiPoint3& vPos, WORD usOffset, int* pVerts) { int iVertNum = 0; //返回的顶点的数目 //若点不合法,直接返回 if (this->GetGridIndex(vPos)== -1) { return -1; } int iGridX = vPos.x/EDIT_UNIT; int iGridY = vPos.y/EDIT_UNIT; int iNumVertexX = m_iChunkNumX*GRIDINCHUNK+1; int iNumVertexY = m_iChunkNumY*GRIDINCHUNK+1; int iLeft = (iGridX-usOffset>0) ? (iGridX-usOffset) : 0; int iRight = (iGridX+usOffset+10) ? (iGridY-usOffset) : 0; int iUp = (iGridY+usOffset+1=iBottom; iY--) { int iX = iRight; pVerts[iVertNum++] = iY*iNumVertexX+iX; } for (int iX = iRight; iX>=iLeft; iX--) { int iY = iBottom; pVerts[iVertNum++] = iY*iNumVertexX+iX; } return iVertNum; } int CTerrain::GetCreateNPCRangeArrayM1( const NiPoint3& vPos, WORD usOffsetX, WORD usOffsetY, int* pVerts) { int iVertNum = 0; //返回的顶点的数目 //若点不合法,直接返回 if (this->GetGridIndex(vPos)== -1) { return -1; } int iGridX = vPos.x/EDIT_UNIT; int iGridY = vPos.y/EDIT_UNIT; int iNumVertexX = m_iChunkNumX*GRIDINCHUNK+1; int iNumVertexY = m_iChunkNumY*GRIDINCHUNK+1; int iLeft = (iGridX-usOffsetX>0) ? (iGridX-usOffsetX) : 0; int iRight = (iGridX+usOffsetX+10) ? (iGridY-usOffsetY) : 0; int iUp = (iGridY+usOffsetY+1=iBottom; iY--) { int iX = iRight; pVerts[iVertNum++] = iY*iNumVertexX+iX; } for (int iX = iRight; iX>=iLeft; iX--) { int iY = iBottom; pVerts[iVertNum++] = iY*iNumVertexX+iX; } return iVertNum; } void CTerrain::InitEntity(NiEntityInterface* pkEntityInterface, EntityType kType) { if (kType == CTerrain::OBJECT) { NiFixedString strPath; pkEntityInterface->GetPropertyData("NIF File Path", strPath); m_pObjectsMgr->InitObject(pkEntityInterface, strPath); } if (kType == CTerrain::NPCCreator) { m_NpcCreatorManager.InitNPCCreator(MAP_NO, pkEntityInterface); } if (kType == CTerrain::REGION) { m_pAreaMgr->InitAreaPoint(pkEntityInterface); } } void CTerrain::SlopeToCollisionBlock(int iBoundDegree,bool bRenderOnly) { // 临界高度差。如果一个tile内任意两顶点超过临界高度,认为该tile不可进入 float fBound = tan(iBoundDegree*3.1416/180.0) * EDIT_UNIT; m_mapOverTopVertexs.clear(); int iGridX = m_iChunkNumX * GRIDINCHUNK; int iGridY = m_iChunkNumY * GRIDINCHUNK; for (int i=0; ifBound || abs(fH0-fH2)>fBound || abs(fH0-fH3)>fBound || abs(fH1-fH2)>fBound || abs(fH1-fH3)>fBound || abs(fH2-fH3)>fBound) { if (bRenderOnly) { const NiPoint3 kTmpPoint = GetVertex(m_pGrids[i].iPointIndx[0]); int iChunkIndex = GetChunkIndex(kTmpPoint); set setPointIndx; map>::iterator mapIt = m_mapOverTopVertexs.find(iChunkIndex); if (mapIt == m_mapOverTopVertexs.end()) { for(int iGPIndex = 0; iGPIndex < 4; iGPIndex++) { setPointIndx.insert(m_pGrids[i].iPointIndx[iGPIndex]); } m_mapOverTopVertexs.insert(pair>(iChunkIndex,setPointIndx)); } else { for(int iGPIndex = 0; iGPIndex < 4; iGPIndex++) { mapIt->second.insert(m_pGrids[i].iPointIndx[iGPIndex]); } } } else { // 该 tile 不可进入 CopyLowFourBit(m_pGrids[i].iTerrainProperty, TP_BLOCK); // 显示设置 NiPoint3 vLeftBtm = m_pVertices[ m_pGrids[i].iPointIndx[0] ]; NiPoint3 vRightTop = m_pVertices[ m_pGrids[i].iPointIndx[2]]; int iChunkIndx = GetChunkIndex( ( vLeftBtm+vRightTop) * 0.5f ); stChunk& chunk = m_pChunks[iChunkIndx]; CTerrainMaterial *pMtl = chunk.pChunkMtl; int iSize = pMtl->GetBlendTexSize(); float fLeft = iSize * ( vLeftBtm.x - chunk.vPosMin.x ) / ( chunk.vPosMax.x - chunk.vPosMin.x ); float fRight = iSize * ( vRightTop.x - chunk.vPosMin.x ) / ( chunk.vPosMax.x - chunk.vPosMin.x ); float fBtm = iSize * ( vLeftBtm.y - chunk.vPosMin.y ) / ( chunk.vPosMax.y - chunk.vPosMin.y ); float fTop = iSize * ( vRightTop.y - chunk.vPosMin.y ) / ( chunk.vPosMax.y - chunk.vPosMin.y ); pMtl->SetTerrainPropertyA( NiRect( fLeft, fRight, fTop, fBtm ), TP_BLOCK ); } } } } void CTerrain::ClearAllCollisionBlock() { int iGridX = m_iChunkNumX * GRIDINCHUNK; int iGridY = m_iChunkNumY * GRIDINCHUNK; for (int i=0; iClearCollisionDataA(); } } void CTerrain::RebuildAllChunkData() { //m_spTerrainRoot->RemoveAllChildren(); //for (int i=0; iSetActiveMaterial(NiRenderer::GetRenderer()->GetDefaultMaterial()); m_pChunks[i].geomData.pTriShape->RemoveAllExtraData(); m_pChunks[i].geomData.pTriShape->RemoveProperty(NiTexturingProperty::GetType()); m_pChunks[i].geomData.pTriShape->UpdateProperties(); m_pChunks[i].geomData.pTriShape->UpdateEffects(); m_pChunks[i].geomData.pTriShape->Update(0.0f); } } else { int iChunkIndx = 0; for (int i=0; iSetApplyMode( NiTexturingProperty::APPLY_MODULATE ); //// 设置ShaderMap //CTerrainMaterial *pTerrainMtl = m_pChunks[iChunkIndx].pChunkMtl; //geomData.pTriShape->SetShader( pTerrainMtl->GetShader() ); //for ( int i = 0; i < pTerrainMtl->GetUsedLayerCount(); ++i ) //{ // NiTexturingProperty::ShaderMap* pShaderMap = NiNew NiTexturingProperty::ShaderMap( // pTerrainMtl->GetTexture(i), i ); // pTexProp->SetShaderMap( i, pShaderMap ); //} //// 设置Blend纹理 //NiTexturingProperty::ShaderMap* pShaderMap = NiNew NiTexturingProperty::ShaderMap( // pTerrainMtl->GetBlendTexture(), 4 ); //pTexProp->SetShaderMap( 4, pShaderMap ); //// 设置Property纹理 只在编辑器中使用 //pShaderMap = NiNew NiTexturingProperty::ShaderMap( // pTerrainMtl->GetPropertyTexture(), 6 ); //pTexProp->SetShaderMap( 6, pShaderMap ); //geomData.pTriShape->ApplyAndSetActiveMaterial( pTerrainMtl->GetMaterial() ); //geomData.pTriShape->AttachProperty( pTexProp ); //// 设置用户数据 //NiPoint3 vPoint = NiPoint3::ZERO; //NiFloatsExtraData *pCursorPoint = NiNew NiFloatsExtraData( 3, (float *)&vPoint.x ); //geomData.pTriShape->AddExtraData( "CursorPoint", pCursorPoint ); //NiFloatExtraData *pCursorRadius = NiNew NiFloatExtraData( .0f ); //geomData.pTriShape->AddExtraData( "CursorRadius", pCursorRadius ); //NiFloatExtraData *pShowCollisionData = NiNew NiFloatExtraData( .0f ); //geomData.pTriShape->AddExtraData( "ShowCollisionData", pShowCollisionData ); //geomData.pTriShape->Update(0.0f); //geomData.pTriShape->UpdateProperties(); //geomData.pTriShape->UpdateEffects(); } } } } bool CTerrain::CheckEmptyTextureLayer() { // 遍历每个 chunk for (int i=0; iGetUsedLayerCount(); for (int j=0; jm_strTexFiles[j].size()==0 || m_pChunks[i].pChunkMtl->m_pLayerTexture[j]==NULL) { char szTmp[256]; sprintf_s(szTmp, "chunk %d 有空纹理层。请修复后再做其他操作。", i); ::MessageBox(NULL, szTmp, "警告", MB_OK); return false; } } } return true; } int CTerrain::GetOverTopVertexByAngle(float fVisualAngle, float uiDistance) { int uiVertexNum = 0; //一次需要计算的点的数量 float fUnitHeight = 0.0f; //单位距离的高度,即角度的tan值 float fAngleSin = 0.0f; //角度的sin值 float fAngleCos = 0.0f; //角度的cos值 fVisualAngle *= (NI_TWO_PI / 360.0f); //将角度换算成弧度 NiSinCos(fVisualAngle, fAngleSin, fAngleCos); //计算出sin和cos的值 uiVertexNum = uiDistance * fAngleCos; fUnitHeight = fAngleSin / fAngleCos; m_mapOverTopVertexs.clear(); for ( int i = uiVertexNum; i < m_iVertexY; ++i ) { for ( int j = 0; j < m_iVertexX; ++j ) { float fCurrentHeight = GetVertexHeight(j, i); for ( int k = 1 ; k <= uiVertexNum; ++k) { if (GetVertexHeight(j, i-k) - fCurrentHeight > k*fUnitHeight) { int index = (i-k)*(m_iChunkNumX*GRIDINCHUNK+1)+j; int iChunkID = (i-k)*m_iChunkNumX+j; map>::iterator mapIt = m_mapOverTopVertexs.find(iChunkID); if (mapIt == m_mapOverTopVertexs.end()) { set setChunk; setChunk.insert(index); m_mapOverTopVertexs.insert(pair>(iChunkID,setChunk)); } else { mapIt->second.insert(index); } } } } } return 0; } int CTerrain::GetOverTopVertexByHeight(float fHeight) { m_mapOverTopVertexs.clear(); for ( int i = 0; i < m_iVertexY; ++i ) { for ( int j = 0; j < m_iVertexX; ++j ) { if (GetVertexHeight(j, i) > fHeight) { int index = i*(m_iChunkNumX*GRIDINCHUNK+1)+j; int iChunkIndex = i*m_iChunkNumX+j; map>::iterator mapIt = m_mapOverTopVertexs.find(iChunkIndex); if (mapIt == m_mapOverTopVertexs.end()) { set setChunk; setChunk.insert(index); m_mapOverTopVertexs.insert(pair>(iChunkIndex,setChunk)); } else { mapIt->second.insert(index); } } } } return 0; } unsigned int CTerrain::AddRegion(NiEntityInterface* pkEntityInterface, unsigned short usAreaType) { unsigned int uiAreaID = m_pAreaMgr->CreateArea(usAreaType); m_pAreaMgr->AddAreaPoint(uiAreaID, pkEntityInterface); return uiAreaID; } void CTerrain::AddRegionPoint(NiEntityInterface* pkEntityInterface, unsigned int niAreaID) { m_pAreaMgr->AddAreaPoint(niAreaID, pkEntityInterface); } //----------------------------------------------------------------- void CTerrain::GetGridCentersInTriangle(NiPoint3 kP0, NiPoint3 kP1, NiPoint3 kP2, vector &vertList) { // 1. 找出能包含三点的最小矩形区域 float fMinX = m_iChunkNumX * GRIDINCHUNK; float fMaxX = 0.0f; float fMinY = m_iChunkNumY * GRIDINCHUNK; float fMaxY = 0.0f; fMinX = min(fMinX, kP0.x); fMinX = min(fMinX, kP1.x); fMinX = min(fMinX, kP2.x); fMaxX = max(fMaxX, kP0.x); fMaxX = max(fMaxX, kP1.x); fMaxX = max(fMaxX, kP2.x); fMinY = min(fMinY, kP0.y); fMinY = min(fMinY, kP1.y); fMinY = min(fMinY, kP2.y); fMaxY = max(fMaxY, kP0.y); fMaxY = max(fMaxY, kP1.y); fMaxY = max(fMaxY, kP2.y); // 2. 遍历区域内所有顶点,判断其是否在三角型区域内. for (float fY=fMinY; fY<=fMaxY; fY+=1.0f) // 遍历行,Y 方向 { for (float fX=fMinX; fX<=fMaxX; fX+=1.0f)// 遍历列,X 方向 { NiPoint3 kVert(fX+0.5f, fY+0.5f, 0.0f); if (IsVertexInTriangle(kP0, kP1, kP2, kVert)) { vertList.push_back(kVert); } } } } int CTerrain::GetGridPropertyPercent(int iGridProperty) { int iPercent = 0; int iGridX = m_iChunkNumX * GRIDINCHUNK; int iGridY = m_iChunkNumY * GRIDINCHUNK; int iIndex = 0; for(int i = 0; i < iGridY; i++) { for(int j = 0; j < iGridX; j ++) { int iCurGridProperty = m_pGrids[iIndex++].iTerrainProperty; if(iCurGridProperty == iGridProperty) { iPercent ++; } } } float fPercent = (float)iPercent / (iGridX * iGridY); iPercent = fPercent * 100; return iPercent; } // add [5/31/2009 hemeng] bool CTerrain::IsHideChunk(int iChunkID) { unsigned short usVerticeCount = m_pChunks[iChunkID].geomData.pTriShape->GetVertexCount(); NiColorA* pVerticColor = m_pChunks[iChunkID].geomData.pTriShape->GetColors(); bool bHide = true; for (unsigned short usIndex = 0; usIndex < usVerticeCount; usIndex++) { if (pVerticColor[usIndex].a != 0.0f) { bHide = false; break; } } return bHide; } void CTerrain::UpdateWaterCausticsTex(float fAccumTime, NiSourceTexturePtr pTex) { if ( NULL == pTex ) return; if ( (fAccumTime - m_fPreTime) < (1.0f / m_fImageFrameCount) ) return; m_fPreTime = fAccumTime; int iChunkNum = m_iChunkNumX * m_iChunkNumY; for (int iChunkIndx = 0; iChunkIndx < iChunkNum; iChunkIndx++) { CTerrain::stChunk::stGeomData& geomData = m_pChunks[iChunkIndx].geomData; NiTexturingProperty * pTexProp = NULL; pTexProp = (NiTexturingProperty*)geomData.pTriShape->GetProperty(NiProperty::TEXTURING); /*NIASSERT(pTexProp);*/ if (NULL == pTexProp) { continue; } int iShaderMapCount = pTexProp->GetShaderMapCount(); if (pTex) { NiTexturingProperty::ShaderMap *pMap = pTexProp->GetShaderMap(7); if (!pMap) { pMap = NiNew NiTexturingProperty::ShaderMap(pTex,7); pTexProp->SetShaderMap(7, pMap); } if (pMap) { if (m_bWaterScene) { pMap->SetTexture(pTex); } else { pMap->SetTexture(NULL); } } } } float afCaustics[4] = { m_fWaterCaustics_Size, m_fWaterCaustics_Size, sinf(fAccumTime) * m_fWaterCaustics_XOffset, cosf(fAccumTime) * m_fWaterCaustics_YOffset }; float bShowWaterGaus = m_bWaterScene ? 1.0f : 0.0f ; NiShaderFactory::UpdateGlobalShaderConstant("g_bShowWaterCaustics", sizeof(float), &bShowWaterGaus); NiShaderFactory::UpdateGlobalShaderConstant("g_Caustics", sizeof(afCaustics), &afCaustics); NiShaderFactory::UpdateGlobalShaderConstant("g_fCausticsFactor", sizeof( float), &m_fWaterCausticsFactor); } void CTerrain::SetWaterScene( bool bWaterScene ) { m_bWaterScene = bWaterScene; } void CTerrain::SetImageFrameCount( float fImageFrameCount ) { m_fImageFrameCount = fImageFrameCount; if ( m_fImageFrameCount <= 0.0f ) m_fImageFrameCount = 30.0f; } void CTerrain::SetWaterSceneConfig(float fSize, float fXOffset, float fYOffset, float fFactor) { m_fWaterCaustics_Size = fSize; m_fWaterCaustics_XOffset = fXOffset; m_fWaterCaustics_YOffset = fYOffset; m_fWaterCausticsFactor = fFactor; } #endif // end #ifndef CODE_INGAME // 函数作废 //int CTerrain::CreateNPCRange(const NiPoint3& vPos, WORD usOffset, const NiFixedString& strNPCCreateName) //{ // //若范围框已经存在,则删除旧的 // NiAVObjectPtr pOldLine = m_spPhyxRoot->GetObjectByName(strNPCCreateName); // if (pOldLine != NULL) // { // m_spPhyxRoot->DetachChild(pOldLine); // } // // //若半径为-1,直接返回,删除原来的范围框 // if ((short)usOffset == -1) // { // return 0; // } // // int iVertNum = 8 * usOffset + 4; // int *pVertsIndex = (int *)NiMalloc( sizeof(int)* iVertNum ); // // NiPoint3 *pVerts = NiNew NiPoint3[ iVertNum ]; // NiColorA *pColors = NiNew NiColorA[ iVertNum ]; // NiBool* bConnect = (NiBool*)NiMalloc( sizeof(NiBool)* iVertNum ); // // //得到范围框所包含的点 // if (this->GetCreateNPCRangeArray(vPos, usOffset, pVertsIndex) == -1) // { // return 0; // } // // //填充颜色和链接顺序 // int index = 0; // for(index = 0; index < iVertNum; ++index) // { // int pointIndex = pVertsIndex[index]; // NiPoint3 tempPoint = m_pVertices[ pointIndex ]; // tempPoint.z += COLLISION_DATA_OFFSET; // pVerts[index] = tempPoint; // pColors[ index ] = NiColorA( 0, 1, 0, 1 ); // bConnect[ index ] = true; // } // // //生成新的范围框 // NiLinesPtr pLine = NiNew NiLines( iVertNum, pVerts, pColors, 0, 0, NiGeometryData::NBT_METHOD_NONE, bConnect ); // pLine->SetName(strNPCCreateName); // m_spPhyxRoot->AttachChild(pLine); // m_spTerrainRoot->AttachChild( m_spPhyxRoot ); // // NiVertexColorProperty * pVCProp = NiNew NiVertexColorProperty; // pVCProp->SetLightingMode( NiVertexColorProperty::LIGHTING_E ); // pVCProp->SetSourceMode( NiVertexColorProperty::SOURCE_EMISSIVE ); // pLine->AttachProperty( pVCProp ); // // pLine->Update(.0f); // pLine->UpdateProperties(); // pLine->UpdateEffects(); // // return 0; //} void CTerrain::GetGridPosInServer( const NiPoint3& vPos, int& iPosX, int& iPosY) { int x = (int)floor( vPos.x / float( EDIT_UNIT ) ); int y = (int)floor( vPos.y / float( EDIT_UNIT ) ); iPosX = x; iPosY = y; } CTerrain::stChunk* CTerrain::GetChunks() { return m_pChunks; }