#include "StdPluginsCppPCH.h" //#include "MUpRiseTerrain.h" #include "MPainterMode.h" #include "MSettingsHelper.h" #include "NiTerrainComponent.h" #include "TerrainGridBaseRegion.h" #include "TerrainGridBaseRegionManager.h" //#include "MChangeTerrainVertexCommand.h" //#include "MTerrain.h" //#include "MBrushParameter.h" using namespace Emergent::Gamebryo::SceneDesigner::StdPluginsCpp; using namespace Emergent::Gamebryo::SceneDesigner::PluginAPI::StandardServices; using namespace Emergent::Gamebryo::SceneDesigner::Framework; using namespace SceneCore; bool SaveNodeToNif( NiAVObject * pNode, const char *pszFile ) { NiStream kStream; kStream.InsertObject( pNode ); return kStream.Save( pszFile ); } MPainterMode::MPainterMode() : m_bDraging( false ) ,m_pBrushParameter( NULL ) , m_pTerrainParameter( NULL ) , m_pSelectionRegion( NULL ) , m_iStartX( -1 ) , m_iStartY( -1 ) , m_iEndX( -1 ) , m_iEndY( -1 ) { m_terrainBrush.fValue = 0.0f; m_terrainBrush.fInRadius = 1.0f; m_terrainBrush.fOutRadius = 1.0f; m_terrainBrush.pcTexFile = ""; m_terrainBrush.ePainterType = MTerrain::PT_TERRAIN_VERTEX; m_pBrushParameter = new MBrushParameter(); m_pTerrainParameter = new MTerrainParameter(); //m_pTerrainModifier = new CTerrainModifier(); } void MPainterMode::Do_Dispose(bool bDisposing) { if ( m_pSelectionRegion ) { delete m_pSelectionRegion; m_pSelectionRegion = NULL; } if ( m_pBrushParameter) { delete m_pBrushParameter; m_pBrushParameter = NULL; } if ( m_pTerrainParameter) { delete m_pTerrainParameter; m_pTerrainParameter = NULL; } CTerrainModifier::UnInitialize(); __super::Do_Dispose( bDisposing ); } void MPainterMode::SetInteractionMode(Object* pmObject, EventArgs* mArgs) { MVerifyValidInstance; InteractionModeService->ActiveMode = this; ICommandPanelService* commandPanelService = MGetService(ICommandPanelService); Form* panel = commandPanelService->GetPanel("TerrainEditPanel"); if (panel != NULL) { commandPanelService->ShowPanel("TerrainEditPanel", true); } } void MPainterMode::ValidateInteractionMode(Object* pmSender, UIState* pmState) { MVerifyValidInstance; pmState->Checked = (InteractionModeService->ActiveMode == this); } void MPainterMode::RegisterSettings() { MVerifyValidInstance; SettingChangedHandler* pmHandler = new SettingChangedHandler(this, &MPainterMode::OnSettingChanged); MSettingsHelper::GetStandardSetting(MSettingsHelper::TERRAIN_BRUSH, *m_pBrushParameter,pmHandler); MSettingsHelper::GetStandardSetting(MSettingsHelper::TERRAIN_PARAM, *m_pTerrainParameter,pmHandler); } void MPainterMode::OnSettingChanged(Object* pmSender, SettingChangedEventArgs* pmEventArgs) { MVerifyValidInstance; String* strSetting = pmEventArgs->Name; if(strSetting->Equals( "TerrainBrush" )) { Object* pmObj; pmObj = SettingsService->GetSettingsObject(strSetting,pmEventArgs->Category); MBrushParameter* pcBrush = dynamic_cast(pmObj); if(pcBrush) { m_terrainBrush.fInRadius = pcBrush->get_InnerRadius(); m_terrainBrush.fOutRadius = pcBrush->get_OuterRadius(); m_terrainBrush.fValue = pcBrush->get_Value(); m_terrainBrush.pcTexFile = pcBrush->get_TexFile(); m_terrainBrush.ePainterType = pcBrush->get_PainterMode(); CTerrain* pTerrain = MFramework::Instance->Scene->Terrain; if ( pTerrain ) pTerrain->SetCursorRadius( m_terrainBrush.fOutRadius ); } } else if ( strSetting->Equals( "TerrainParam" ) ) { Object* pmObj; pmObj = SettingsService->GetSettingsObject(strSetting,pmEventArgs->Category); MTerrainParameter* pTerrainParam = dynamic_cast(pmObj); switch(pTerrainParam->get_Mode()) { case 0: /// 创建地形 MFramework::Instance->Scene->CreateTerrain(pTerrainParam->get_ChunkX(), pTerrainParam->get_ChunkY(), MStringToCharPointer(pTerrainParam->get_MaterialName()), m_terrainBrush.fOutRadius , pTerrainParam->get_MapNo()); break; /// 原来case 1 和 case 2 是保存地形和加载地形选项,现在已把这两个功能放到菜单项之中。 } } } String* MPainterMode::get_Name() { MVerifyValidInstance; return "UpRaiseTerrain"; } bool MPainterMode::Initialize() { return CTerrainModifier::Initialize(); } void MPainterMode::Update(float fTime) { MVerifyValidInstance; __super::Update( fTime ); } void MPainterMode::RenderGizmo(MRenderingContext* pmRenderingContext) { MVerifyValidInstance; if ( !m_pSelectionRegion ) return; NiDrawScene(pmRenderingContext->GetRenderingContext()->m_pkCamera, m_pSelectionRegion, *pmRenderingContext->GetRenderingContext()->m_pkCullingProcess); } void MPainterMode::MouseDown(MouseButtonType eType, int iX, int iY) { MVerifyValidInstance; __super::MouseDown( eType, iX, iY ); if (eType == MouseButtonType::LeftButton ) { // 鼠标按下时生成新的 command,弹起时执行该 command,将 command 放入 undo 栈中 if (m_terrainBrush.ePainterType == MTerrain::PT_TERRAIN_VERTEX) { m_pCurrentCommand = new CTerrainChangeVertexCommand(MFramework::Instance->Scene->Terrain); } else if(m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_TERRAIN_GRID_AREA) { // 如果在刷区域模式下按下鼠标,当前被编辑区域又为空,提示用户在区域面板中创建一个区域 CTerrainGridBaseRegion* pOnEditRegion = CTerrainGridBaseRegionManager::GetInstance()->GetOnEditRegion(); if (pOnEditRegion == NULL) { /*m_bDraging = false;*/ /*m_bLeftDown = false;*/ MessageBox::Show("请先在 Grid 区域 面板中创建一个区域并选择后再进行操作。"); return; } } } /*if ( eType == MouseButtonType::RightButton ) { NiTerrainComponent::GetTerrainInstance()->SaveToFile( "c:/Terrain1.TRr" ); } if ( eType == MouseButtonType::MiddleButton ) { NiTerrainComponent::CreateTerrain( "c:/Terrain1.trr" ); }*/ } void MPainterMode::MouseUp(MouseButtonType eType, int iX, int iY) { // iPainterType 0 - 调整高度 1 - 刷纹理 2 - 刷碰撞块 MVerifyValidInstance; if ( eType == MouseButtonType::LeftButton ) { if ( !m_bDraging ) { if (KEY_DOWN(VK_LCONTROL)) { NiPoint3 vTerrainPt; if ( !GetInterPtFromMousePos( iX, iY, vTerrainPt ) ) { m_iStartX = -1; m_iStartY = -1; m_iEndX = -1; m_iEndY = -1; } else { if (m_iStartX == -1 || m_iStartY == -1) { m_iStartX = vTerrainPt.x; m_iStartY = vTerrainPt.y; m_iEndX = -1; m_iEndY = -1; } else { if (m_iEndX == -1 || m_iEndY == -1) { m_iEndX = vTerrainPt.x; m_iEndY = vTerrainPt.y; } else { m_iStartX = vTerrainPt.x; m_iStartY = vTerrainPt.y; m_iEndX = -1; m_iEndY = -1; } } } CTerrainModifier::SetMousePos(m_iStartX, m_iStartY, m_iEndX, m_iEndY); } if(m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_TERRAIN_VERTEX) { _AdjustTerrain( iX, iY, false ); } else if ( m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_TERRAIN_MATERIAL) { _PaintTerrain( iX, iY, false ); } else if ( m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_TERRAIN_PROPERTY) { //删除模式 if ( KEY_DOWN(VK_LMENU) ) { SetTerrainProperty( iX, iY, false, true); } else { SetTerrainProperty( iX, iY, false, false ); } } //else if ( m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_WATER_SURFACE) //{ // if ( !MFramework::Instance->Scene->IsInitalRiver() ) // { // //NiMessageBox("请先创建水域","error",0); // return; // } // _AddWater( iX,iY,false); //} } if (m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_TERRAIN_VERTEX) { MFramework::Instance->Scene->ExecuteAdjustTerrainHeightCommand(m_pCurrentCommand); m_pCurrentCommand = NULL; } //if (m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_WATER_SURFACE) //{ // if ( !MFramework::Instance->Scene->IsInitalRiver() ) // { // //NiMessageBox("请先创建水域","error",0); // return; // } // _BuildWaterGeom( iX, iY ); //} m_bDraging = false; } //else if ( eType == MouseButtonType::RightButton ) //{ // if (m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_WATER_SURFACE) // { // if ( !MFramework::Instance->Scene->IsInitalRiver() ) // { // //NiMessageBox("请先创建水域","error",0); // return; // } // _DeleteWater(iX,iY,false); // _BuildWaterGeom(iX,iY); // } //} else if( eType == MouseButtonType::MiddleButton) { NiPoint3 vTerrainPt; if ( !GetInterPtFromMousePos( iX, iY, vTerrainPt ) ) { return; } int iCunkdID = MTerrain::Instance->GetTerrainChunkIndex(vTerrainPt); if (iCunkdID >= 0) { MTerrain::Instance->SetTerrainOnEditChunk(iCunkdID); } } // [11/24/2009 shiyazheng] 将场景 dirty 设为 true MFramework::Instance->Scene->Dirty = true; __super::MouseUp( eType, iX, iY ); } void MPainterMode::MouseMove(int iX, int iY) { MVerifyValidInstance; __super::MouseMove( iX, iY ); if ( Control::MouseButtons == MouseButtons::Left/*m_bLeftDown*/ ) m_bDraging = true; if ( m_bDraging ) //持续的拖拽 { if(m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_TERRAIN_VERTEX ) { _AdjustTerrain( iX, iY, true ); } else if (m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_TERRAIN_MATERIAL) { _PaintTerrain( iX, iY, true ); } else if (m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_TERRAIN_PROPERTY ) { if (KEY_DOWN(VK_LMENU)) { SetTerrainProperty( iX, iY, true, true ); } else { SetTerrainProperty( iX, iY, true, false ); } } else if(m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_TERRAIN_GRID_AREA) { _PaintGridBaseRegion(iX, iY); } else if(m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_REMOVE_ENTITY) { _PaintRemoveEntity(iX, iY); } //else if (m_terrainBrush.ePainterType == MTerrain::EPainterType::PT_WATER_SURFACE) //{ // if ( !MFramework::Instance->Scene->IsInitalRiver() ) // { // //NiMessageBox("请先创建水域","error",0); // return; // } // _AddWater( iX,iY,true); //} } AdjustSelectionRegion( iX, iY ); } void MPainterMode::AdjustSelectionRegion( int iX, int iY ) { //return; CTerrain *pTerrain = MFramework::Instance->Scene->Terrain; if ( !pTerrain ) return; NiPoint3 vTerrainPt; if ( !GetInterPtFromMousePos( iX, iY, vTerrainPt ) ) return; pTerrain->SetCursorPosition( vTerrainPt ); return; //vTerrainPt.x = 200.0f; //vTerrainPt.y = 200.0f; float fLeftX = vTerrainPt.x - m_terrainBrush.fOutRadius; float fRightX = vTerrainPt.x + m_terrainBrush.fOutRadius; float fLeftY = vTerrainPt.y - m_terrainBrush.fOutRadius; float fRightY = vTerrainPt.y + m_terrainBrush.fOutRadius; vector< vector< NiPoint3 > > vRetPoints; MFramework::Instance->Scene->Terrain->GetPointsFromRectangle( fLeftX, fLeftY, fRightX, fRightY, vRetPoints ); if ( vRetPoints.size() < 1 || vRetPoints[0].size() < 1 ) return; //生成条带 int nHeight = vRetPoints.size(); int nWidth = vRetPoints[0].size(); int nVertexCount = nHeight * nWidth; int nTriCount = ( nHeight - 1 ) * ( nWidth - 1 ) * 2; if ( nVertexCount < 1 || nTriCount < 1 ) return; NiPoint3 * pVertexBuf = NULL; NiPoint2 * pUVBuf = NULL; unsigned short * pTriList = NULL; bool bNeedRebuild = !m_pSelectionRegion || nVertexCount != m_pSelectionRegion->GetVertexCount(); if ( bNeedRebuild ) { pVertexBuf = NiNew NiPoint3[ nVertexCount ]; pUVBuf = NiNew NiPoint2[ nVertexCount ]; pTriList = NiAlloc( unsigned short, nTriCount * 3 ); } else { pVertexBuf = m_pSelectionRegion->GetVertices(); pUVBuf = m_pSelectionRegion->GetTextures(); pTriList = m_pSelectionRegion->GetTriList(); } float fInvRegionWidth = 1 / ( 2 * m_terrainBrush.fOutRadius ); // vertex && uv for ( int nY = 0; nY < nHeight; nY ++ ) { for ( int nX = 0; nX < nWidth; nX ++ ) { UINT nIndex = nY * nWidth + nX; pVertexBuf[ nIndex ] = vRetPoints[nY][nX]; NiPoint3 vDiff = pVertexBuf[nIndex] - vTerrainPt; pVertexBuf[nIndex].z += 0.04f; pUVBuf[ nIndex ].x = vDiff.Dot( NiPoint3::UNIT_X ) * fInvRegionWidth + 0.5f; pUVBuf[ nIndex ].y = vDiff.Dot( NiPoint3::UNIT_Y ) * fInvRegionWidth + 0.5f; } } // index for ( int nGridY = 0, nIndex = 0; nGridY < nHeight - 1; nGridY ++ ) { for ( int nGridX = 0; nGridX < nWidth - 1; nGridX ++ ) { pTriList[ nIndex++ ] = nGridY * nWidth + nGridX; pTriList[ nIndex++ ] = nGridY * nWidth + nGridX + 1; pTriList[ nIndex++ ] = (nGridY + 1) * nWidth + nGridX + 1; pTriList[ nIndex++ ] = nGridY * nWidth + nGridX; pTriList[ nIndex++ ] = ( nGridY + 1 ) * nWidth + nGridX + 1; pTriList[ nIndex++ ] = (nGridY + 1) * nWidth + nGridX; } } //生成mesh if ( bNeedRebuild ) { if ( m_pSelectionRegion ) { //NiTerrainComponent::GetTerrainInstance()->GetTerrainRootNode()->DetachChild( m_pSelectionRegion ); delete m_pSelectionRegion; } m_pSelectionRegion = NiNew NiTriShape( nVertexCount, pVertexBuf, NULL, NULL, pUVBuf, 1, NiGeometryData::NBT_METHOD_NONE, nTriCount, pTriList ); //m_pSelectionRegion->IncRefCount(); // property NiTexturingProperty * pTexProp = NiNew NiTexturingProperty( "./Data/circle.tga" ); pTexProp->SetApplyMode( NiTexturingProperty::APPLY_REPLACE ); m_pSelectionRegion->AttachProperty( pTexProp ); NiAlphaProperty * pAlphaProperty = NiNew NiAlphaProperty; pAlphaProperty->SetAlphaBlending( true ); m_pSelectionRegion->AttachProperty( pAlphaProperty ); NiVertexColorProperty * pVertexProp = NiNew NiVertexColorProperty; pVertexProp->SetLightingMode( NiVertexColorProperty::LIGHTING_E ); pVertexProp->SetSourceMode( NiVertexColorProperty::SOURCE_EMISSIVE ); m_pSelectionRegion->AttachProperty( pVertexProp ); //NiWireframeProperty * pWireProp = NiNew NiWireframeProperty; //pWireProp->SetWireframe( true ); //m_pSelectionRegion->AttachProperty( pWireProp ); NiMaterialProperty * pMaterialProp = NiNew NiMaterialProperty; pMaterialProp->SetAlpha( 1.0f ); pMaterialProp->SetAmbientColor( NiColor::WHITE ); pMaterialProp->SetEmittance( NiColor::WHITE ); pMaterialProp->SetDiffuseColor( NiColor::WHITE ); m_pSelectionRegion->AttachProperty( pMaterialProp ); NiZBufferProperty * pZBufferProp = NiNew NiZBufferProperty; pZBufferProp->SetZBufferTest( true ); pZBufferProp->SetZBufferWrite( false ); m_pSelectionRegion->AttachProperty( pZBufferProp ); m_pSelectionRegion->UpdateProperties(); //NiTerrainComponent::GetTerrainInstance()->GetTerrainRootNode()->AttachChild( m_pSelectionRegion ); } else // modify { m_pSelectionRegion->GetModelData()->MarkAsChanged( NiTriShapeData::TRIANGLE_INDEX_MASK | NiGeometryData::VERTEX_MASK | NiGeometryData::TEXTURE_MASK ); m_pSelectionRegion->SetActiveVertexCount( nVertexCount ); m_pSelectionRegion->SetActiveTriangleCount( nTriCount ); NiBound bound; bound.ComputeFromData( nVertexCount, pVertexBuf ); m_pSelectionRegion->SetModelBound( bound ); } m_pSelectionRegion->Update( 0.0f ); } bool MPainterMode::GetInterPtFromMousePos( int iX, int iY, NiPoint3& vInterPt ) { NiPoint3 kOrigin, kDir; NiViewMath::MouseToRay( (float)iX, (float)iY, MFramework::Instance->ViewportManager->ActiveViewport->Width, MFramework::Instance->ViewportManager->ActiveViewport->Height, MFramework::Instance->ViewportManager->ActiveViewport->GetNiCamera(), kOrigin, kDir); NiPick pickTerrain; pickTerrain.SetTarget( MFramework::Instance->Scene->Terrain->GetTerrainRootNode() ); pickTerrain.SetFrontOnly( true ); if ( !pickTerrain.PickObjects( kOrigin, kDir ) ) return false; const NiPick::Results& kPickResults = pickTerrain.GetResults(); NiPick::Record* pkPickRecord = kPickResults.GetAt(0); if ( !pkPickRecord ) return false; vInterPt = pkPickRecord->GetIntersection(); return true; } void MPainterMode::_AdjustTerrain( int iX, int iY, bool bDraging ) { if( !MFramework::Instance->Scene->Terrain ) return; NiPoint3 vTerrainPt; if ( !GetInterPtFromMousePos( iX, iY, vTerrainPt ) ) return; CTerrainModifier::AdjustHeight( MFramework::Instance->Scene->Terrain, vTerrainPt, m_terrainBrush.fValue, m_terrainBrush.fInRadius, m_terrainBrush.fOutRadius, !bDraging, m_pCurrentCommand); //if (KEY_DOWN(VK_RMENU)) //{ // CTerrainModifier::LoadTerrainHeight(MFramework::Instance->Scene->Terrain, "TerrainHeight.bmp", m_pCurrentCommand); //} //if(KEY_DOWN(VK_LMENU)) //{ // CTerrainModifier::ExportTerrainHeight(MFramework::Instance->Scene->Terrain, "TerrainHeight.bmp"); //} } void MPainterMode::_PaintTerrain( int iX, int iY, bool bDraging ) { if( !MFramework::Instance->Scene->Terrain ) return; NiPoint3 vTerrainPt; if ( !GetInterPtFromMousePos( iX, iY, vTerrainPt ) ) return; CTerrainModifier::PaintTerrain(MFramework::Instance->Scene->Terrain, MStringToCharPointer(m_terrainBrush.pcTexFile) , vTerrainPt, m_terrainBrush.fValue,m_terrainBrush.fInRadius, m_terrainBrush.fOutRadius, !bDraging ); } void MPainterMode::_PaintGridBaseRegion(int iX, int iY) { if( !MFramework::Instance->Scene->Terrain ) return; NiPoint3 vTerrainPt; if ( !GetInterPtFromMousePos( iX, iY, vTerrainPt ) ) return; bool bAdd = true; if (KEY_DOWN(VK_LSHIFT)) { bAdd = false; } CTerrainGridBaseRegionManager::PaintGridBaseRegion(MFramework::Instance->Scene->Terrain, vTerrainPt, m_terrainBrush.fOutRadius, bAdd); } void MPainterMode::_PaintRemoveEntity(int iX, int iY) { NiPoint3 kTerrainPt; if ( !GetInterPtFromMousePos( iX, iY, kTerrainPt ) ) return; int iChunkID = MTerrain::Instance->Terrain->GetChunkIndex(kTerrainPt); if (iChunkID < 0) { return; } MEntity* amEntities[] = MChunkEntityManager::Instance->GetEntity(iChunkID); for (int i=0; iCount; i++) { MEntity* pmEntity = amEntities[i]; NiAVObject* pkAvObj = pmEntity->GetSceneRootPointer(0); if (pkAvObj != NULL) { const NiPoint3& kPos = pkAvObj->GetWorldBound().GetCenter(); if ((kTerrainPt-kPos).Length() < m_terrainBrush.fOutRadius) { // 删除该模型 MFramework::Instance->Scene->RemoveEntity(pmEntity, true, true); } } } } void MPainterMode::SetTerrainProperty( int iX, int iY, bool bDraging, bool bDelete ) { if( !MFramework::Instance->Scene->Terrain ) return; NiPoint3 vTerrainPt; if ( !GetInterPtFromMousePos( iX, iY, vTerrainPt ) ) return; CTerrainModifier::SetTerrainSurfaceProperty( MFramework::Instance->Scene->Terrain, vTerrainPt, m_terrainBrush.fOutRadius, bDelete ); } //void MPainterMode::_AddWater(int iX, int iY, bool bDraging) //{ // if ( !MFramework::Instance->Scene->Terrain ) // { // return; // } // // NiPoint3 vTerrainPt; // if ( !GetInterPtFromMousePos( iX, iY,vTerrainPt) ) // { // return; // } // if (m_terrainBrush.fOutRadius > 1.0f) // { // CRiverManager::GetInstance()->EditRiverPoint(MFramework::Instance->Scene->Terrain, vTerrainPt,m_terrainBrush.fOutRadius,true); // } // else // { // NiMessageBox("请笔半径刷大于1","error",0); // } //} // //void MPainterMode::_DeleteWater(int iX, int iY,bool bDraging) //{ // if ( !MFramework::Instance->Scene->Terrain ) // { // return; // } // // NiPoint3 vTerrainPt; // if ( !GetInterPtFromMousePos( iX, iY,vTerrainPt) ) // { // return; // } // // CRiverManager::GetInstance()->EditRiverPoint(MFramework::Instance->Scene->Terrain, vTerrainPt,m_terrainBrush.fOutRadius,false); //} // //void MPainterMode::_BuildWaterGeom(int iX,int iY) //{ // if ( !MFramework::Instance->Scene->Terrain ) // { // return; // } // // NiPoint3 vTerrainPt; // if ( !GetInterPtFromMousePos( iX, iY,vTerrainPt) ) // { // return; // } // // CRiverManager::GetInstance()->BuildRiverRegionGem(MFramework::Instance->Scene->Terrain); //}