// EMERGENT GAME TECHNOLOGIES PROPRIETARY INFORMATION // // This software is supplied under the terms of a license agreement or // nondisclosure agreement with Emergent Game Technologies and may not // be copied or disclosed except in accordance with the terms of that // agreement. // // Copyright (c) 1996-2007 Emergent Game Technologies. // All Rights Reserved. // // Emergent Game Technologies, Chapel Hill, North Carolina 27517 // http://www.emergent.net // Precompiled Header #include "StdPluginsCppPCH.h" #include "MSelectionInteractionMode.h" #include "NiVirtualBoolBugWrapper.h" #include "MSettingsHelper.h" using namespace Emergent::Gamebryo::SceneDesigner::StdPluginsCpp; // 获取按键的状态 #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0) //--------------------------------------------------------------------------- MSelectionInteractionMode::MSelectionInteractionMode() : m_pkGizmo(NULL) { m_pkPickRecord = NiNew NiPick::Record(NULL); m_pkPickRecord->SetDistance(NI_INFINITY); m_pkPickRecord->SetIntersection(NiPoint3::ZERO); m_pkPickRecord->SetNormal(NiPoint3::ZERO); } //--------------------------------------------------------------------------- void MSelectionInteractionMode::RegisterSettings() { // register the settings of all the classes we inherit from __super::RegisterSettings(); SettingChangedHandler* pmHandler = new SettingChangedHandler(this, &MSelectionInteractionMode::OnSettingChanged); // convert this settings from a distance to a ratio float fScale = STANDARD_DISTANCE / m_fDefaultDistance; MSettingsHelper::GetStandardSetting(MSettingsHelper::GIZMO_SCALE, fScale, pmHandler); m_fDefaultDistance = STANDARD_DISTANCE / fScale; } //--------------------------------------------------------------------------- void MSelectionInteractionMode::OnSettingChanged(Object* pmSender, SettingChangedEventArgs* pmEventArgs) { String* strSetting = pmEventArgs->Name; SettingsCategory eCategory = pmEventArgs->Category; // if a setting we care about was changed, re-cache it if (MSettingsHelper::IsArgStandardSetting(pmEventArgs, MSettingsHelper::GIZMO_SCALE)) { Object* pmObj; pmObj = SettingsService->GetSettingsObject( strSetting, eCategory); __box float* pfVal = dynamic_cast<__box float*>(pmObj); if (pfVal != NULL) { m_fDefaultDistance = STANDARD_DISTANCE / *pfVal; } } } //--------------------------------------------------------------------------- void MSelectionInteractionMode::SetInteractionMode(Object* pmObject, EventArgs* mArgs) { MVerifyValidInstance; InteractionModeService->ActiveMode = this; } //--------------------------------------------------------------------------- void MSelectionInteractionMode::ValidateInteractionMode(Object* pmSender, UIState* pmState) { MVerifyValidInstance; pmState->Checked = (InteractionModeService->ActiveMode == this); } //--------------------------------------------------------------------------- void MSelectionInteractionMode::SetGizmoScale(NiCamera* pkCamera) { // figure out the gizmo's location NiPoint3 kCenter; SelectionService->SelectionCenter->ToNiPoint3(kCenter); m_pkGizmo->SetTranslate(kCenter); // figure out how large it needs to be if (pkCamera->GetViewFrustum().m_bOrtho) { NiFrustum pkFrustum = pkCamera->GetViewFrustum(); m_pkGizmo->SetScale((pkFrustum.m_fRight * 2.0f) / m_fDefaultDistance); } else { float fCamDistance = (kCenter - pkCamera->GetWorldTranslate()).Length(); if ((fCamDistance / m_fDefaultDistance) > 0.0f) { m_pkGizmo->SetScale((fCamDistance / m_fDefaultDistance) * pkCamera->GetViewFrustum().m_fRight * 2.0f); } else { m_pkGizmo->SetScale(1.0f); } } m_pkGizmo->Update(0.0f); } //--------------------------------------------------------------------------- void MSelectionInteractionMode::Do_Dispose(bool bDisposing) { NiDelete m_pkPickRecord; MDisposeRefObject(m_pkGizmo); MViewInteractionMode::Do_Dispose(bDisposing); } //--------------------------------------------------------------------------- String* MSelectionInteractionMode::get_Name() { return "GamebryoSelection"; } //--------------------------------------------------------------------------- bool MSelectionInteractionMode::Initialize() { MVerifyValidInstance; m_fDefaultDistance = STANDARD_DISTANCE; String* pmPath = String::Concat(MFramework::Instance->AppStartupPath, ".\\AppData\\select.nif"); NiStream kStream; const char* pcPath = MStringToCharPointer(pmPath); int iSuccess = NiVirtualBoolBugWrapper::NiStream_Load(kStream, pcPath); MFreeCharPointer(pcPath); if (iSuccess != 0) { m_pkGizmo = (NiNode*)kStream.GetObjectAt(0); MInitRefObject(m_pkGizmo); m_pkGizmo->UpdateProperties(); m_pkGizmo->UpdateEffects(); m_pkGizmo->Update(0.0f); } else { MessageService->AddMessage(MessageChannelType::Errors, "Failed to load scale gizmo file 'select.nif'"); return false; } return true; } //--------------------------------------------------------------------------- void MSelectionInteractionMode::RenderGizmo( MRenderingContext* pmRenderingContext) { MVerifyValidInstance; if ((m_pkGizmo) && (SelectionService->NumSelectedEntities > 0)) { NiEntityRenderingContext* pkContext = pmRenderingContext->GetRenderingContext(); NiCamera* pkCam = pkContext->m_pkCamera; //clear the z-buffer pkContext->m_pkRenderer->ClearBuffer(NULL, NiRenderer::CLEAR_ZBUFFER); SetGizmoScale(pkCam); NiDrawScene(pkCam, m_pkGizmo, *pkContext->m_pkCullingProcess); } } //--------------------------------------------------------------------------- void MSelectionInteractionMode::MouseDown(MouseButtonType eType, int iX, int iY) { MVerifyValidInstance; MViewInteractionMode::MouseDown(eType, iX, iY); if (eType == MouseButtonType::LeftButton) { 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); MEntity* pmPickedEntity; float fPickDistance = NI_INFINITY; if (MFramework::Instance->PickUtility->PerformPick( MFramework::Instance->Scene, kOrigin, kDir, false)) { const NiPick* pkPick = MFramework::Instance->PickUtility->GetNiPick(); const NiPick::Results& kPickResults = pkPick->GetResults(); NiPick::Record* pkPickRecord = kPickResults.GetAt(0); if (pkPickRecord) { if (pkPickRecord->GetDistance() < fPickDistance) { m_pkPickRecord->SetDistance(pkPickRecord->GetDistance()); m_pkPickRecord->SetIntersection( pkPickRecord->GetIntersection()); m_pkPickRecord->SetNormal(pkPickRecord->GetNormal()); fPickDistance = pkPickRecord->GetDistance(); NiAVObject* pkPickedObject = pkPickRecord->GetAVObject(); pmPickedEntity = MFramework::Instance->PickUtility ->GetEntityFromPickedObject(pkPickedObject); ////////////////////////////////////////////////////////////////////////// // 指向新的区域 unsigned int uiAreaID; NiBool bPropExist = pmPickedEntity->GetNiEntityInterface()->GetPropertyData("RegionID", uiAreaID); if (bPropExist) { MFramework::Instance->Scene->SetCurrentRegionID(uiAreaID); } ////////////////////////////////////////////////////////////////////////// if ( pmPickedEntity && String::Compare( pmPickedEntity->Name, "Terrain" ) == 0 ) { pmPickedEntity = NULL; } } } } MFramework::Instance->ProxyManager->UpdateProxyScales( MFramework::Instance->ViewportManager->ActiveViewport); if (MFramework::Instance->PickUtility->PerformPick( MFramework::Instance->ProxyManager->ProxyScene, kOrigin, kDir, false)) { const NiPick* pkPick = MFramework::Instance->PickUtility->GetNiPick(); const NiPick::Results& kPickResults = pkPick->GetResults(); NiPick::Record* pkPickRecord = kPickResults.GetAt(0); if (pkPickRecord) { if (pkPickRecord->GetDistance() < fPickDistance) { m_pkPickRecord->SetDistance(pkPickRecord->GetDistance()); m_pkPickRecord->SetIntersection( pkPickRecord->GetIntersection()); m_pkPickRecord->SetNormal(pkPickRecord->GetNormal()); fPickDistance = pkPickRecord->GetDistance(); NiAVObject* pkPickedProxy = pkPickRecord->GetAVObject(); MEntity* pmPickedProxy = MFramework::Instance->PickUtility ->GetEntityFromPickedObject(pkPickedProxy); if (pmPickedProxy != NULL && pmPickedProxy->HasProperty("Source Entity")) { MEntity* pmEntity = dynamic_cast( pmPickedProxy->GetPropertyData("Source Entity")); if (pmEntity != NULL) { if (MFramework::Instance->Scene->IsEntityInScene( pmEntity)) { pmPickedEntity = pmEntity; } } } } } } if (pmPickedEntity != NULL) { if (GetAsyncKeyState(VK_CONTROL) & 0x8000) { // first, check if the picked entity is already selected bool bAddSelection = true; MEntity* amSelection[] = SelectionService->GetSelectedEntities(); for (int i = 0; i < amSelection->Count; i++) { if (amSelection[i] == pmPickedEntity) { bAddSelection = false; break; } } if (bAddSelection) { SelectionService->AddEntityToSelection(pmPickedEntity); } } else if (GetAsyncKeyState(VK_MENU) & 0x8000) { // first check that the entity is in the selection bool bRemove = false; MEntity* amSelection[] = SelectionService->GetSelectedEntities(); for (int i = 0; i < amSelection->Count; i++) { if (amSelection[i] == pmPickedEntity) { bRemove = true; break; } } if (bRemove) { SelectionService->RemoveEntityFromSelection( pmPickedEntity); } } else { // check that the selection doesn't match the entity if ((SelectionService->NumSelectedEntities != 1) || (SelectionService->SelectedEntity != pmPickedEntity)) { SelectionService->SelectedEntity = pmPickedEntity; } } } // 修改如果按下ctrl时点中非物件,不取消已选物件 [12/11/2009 hemeng] else if (!KEY_DOWN(VK_CONTROL)) { SelectionService->SelectedEntity = NULL; } } } void MSelectionInteractionMode::MouseUp(MouseButtonType eType, int iX, int iY) { MViewInteractionMode::MouseUp(eType, iX, iY); if (eType == MouseButtonType::LeftButton) { //MFramework::Instance->ViewportManager->ActiveViewport->SetRectSelectRenderState(false); // 框选功能 [12/9/2009 hemeng] if (MFramework::Instance->Scene->GetRectSelectState()) { if ((m_iStartX != iX) && (m_iStartY != iY)) { int iStartX = min(m_iStartX, iX); int iStartY = min(m_iStartY, iY); int iEndX = max(m_iStartX, iX); int iEndY = max(m_iStartY, iY); if (!KEY_DOWN(VK_CONTROL)) { ms_pmSelectionService->ClearSelectedEntities(); } int iRectSelPrec = MFramework::Instance->Scene->GetRectSelectPrec(); for (int itX = iStartX ; itX < iEndX; itX += iRectSelPrec) { for (int itY = iStartY; itY < iEndY; itY += iRectSelPrec) { MEntity* pmEntity = MFramework::Instance->PickUtility->GetEntityFromViewCoordinates( MFramework::Instance->Scene,MFramework::Instance->ViewportManager->ActiveViewport,itX,itY); if (pmEntity) { if (ms_pmSelectionService->IsEntitySelected(pmEntity)) { continue; } else { ms_pmSelectionService->AddEntityToSelection(pmEntity); } } // 获取proxy [12/14/2009 hemeng] MFramework::Instance->ProxyManager->UpdateProxyScales( MFramework::Instance->ViewportManager->ActiveViewport); MEntity* pmProxy = MFramework::Instance->PickUtility->GetEntityFromViewCoordinates( MFramework::Instance->ProxyManager->ProxyScene,MFramework::Instance->ViewportManager->ActiveViewport,itX,itY); if (pmProxy) { // 从proxy获取entity [12/14/2009 hemeng] pmEntity = dynamic_cast( pmProxy->GetPropertyData("Source Entity")); if (pmEntity) { if (!ms_pmSelectionService->IsEntitySelected(pmEntity)) { ms_pmSelectionService->AddEntityToSelection(pmEntity); } } } } } } } } } void MSelectionInteractionMode::MouseMove(int iX, int iY) { MViewInteractionMode::MouseMove(iX, iY); int iStartX = min(m_iStartX, iX); int iStartY = min(m_iStartY, iY); int iLength = max(m_iStartX, iX); int iHeight = max(m_iStartY, iY); iLength = iLength - iStartX; iHeight = iHeight - iStartY; MFramework::Instance->ViewportManager->ActiveViewport->SetRectSelectData(m_bLeftDown,iStartX, iStartY,iLength,iHeight); } //---------------------------------------------------------------------------