// 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 #include "stdafx.h" #include #include #include "PickController.h" static void RecursiveSetKeep(NiAVObject* pkObject); //--------------------------------------------------------------------------- PickController::PickController() { m_kGroundPick.SetPickType(NiPick::FIND_ALL); // FIND_FIRST m_kGroundPick.SetSortType(NiPick::SORT); // NO_SORT m_kGroundPick.SetIntersectType(NiPick::TRIANGLE_INTERSECT); // Assumes model coordinates have already been transformed to world m_kGroundPick.SetCoordinateType(NiPick::MODEL_COORDINATES); m_kGroundPick.SetFrontOnly(false); m_kGroundPick.SetObserveAppCullFlag(false); m_kGroundPick.SetReturnTexture(false); m_kGroundPick.SetReturnNormal(false); m_kGroundPick.SetReturnSmoothNormal(false); m_kGroundPick.SetReturnColor(false); } //--------------------------------------------------------------------------- PickController::~PickController() { m_kWalkables.RemoveAll(); } //--------------------------------------------------------------------------- bool PickController::HasWalkables() { if (m_kWalkables.GetEffectiveSize()) return true; else return false; } //--------------------------------------------------------------------------- bool PickController::Initialize(NiScene* pkSceneRoot) { FindAllWalkables(pkSceneRoot, m_kWalkables); if (m_kWalkables.GetEffectiveSize() == 0) return false; m_kGroundPick.SetTarget(NULL); return true; } //--------------------------------------------------------------------------- bool PickController::GetHeight(NiPoint3& kLoc, float &fHeight) { unsigned int uiNumOfPickables = m_kWalkables.GetSize(); bool bSuccess = false; bool bHit = false; m_kGroundPick.ClearResultsArray(); // The artist is allow to tag geometry as "walkable" or "non-walkable" // They are also allowed to tag a node. To support this, a map of // geometry to tagged node is created (kGeomToProxyMap). NiTMap kGeomToProxyMap; for (unsigned int ui=0; ui < uiNumOfPickables; ui++) { NiAVObject* pkObject = m_kWalkables.GetAt(ui); if (!pkObject) continue; m_kGroundPick.SetTarget(pkObject); if (m_kGroundPick.PickObjects(kLoc, -NiPoint3::UNIT_Z, true)) { bHit = true; const NiPick::Results& kResults = m_kGroundPick.GetResults(); unsigned int uiRecCount = kResults.GetSize(); for(unsigned int uiRec = 0; uiRec < uiRecCount; uiRec++) { NiPick::Record* pkRecord = kResults.GetAt(uiRec); NiAVObject* pkObj = pkRecord->GetAVObject(); NiAVObject* pkProxy; if (!kGeomToProxyMap.GetAt(pkObj, pkProxy)) { kGeomToProxyMap.SetAt(pkObj, pkObject); } } } } if (bHit) { NiPick::Record* pkRecord = m_kGroundPick.GetResults().GetAt(0); if (pkRecord) { NiAVObject* pkObjOrig = pkRecord->GetAVObject(); NiAVObject* pkObj; if (!kGeomToProxyMap.GetAt(pkObjOrig, pkObj)) { NIASSERT(!"Object wasn't registered!"); pkObj = pkObjOrig; } const char c = pkObj->GetName()[0]; // Could be a "walkable" or a "non-walkable". Check the first // letter to verify the object is a true "walkable". if (c=='w' || c=='W') { const NiTransform kTrans = pkObj->GetWorldTransform(); NiPoint3 kWorldIntersection = kTrans * pkRecord->GetIntersection(); fHeight = kWorldIntersection.z; bSuccess = true; } } } return bSuccess; } //--------------------------------------------------------------------------- bool PickController::GetIntersection(const NiPoint3& kStart, const NiPoint3& kDir, NiPoint3& kLoc) { if (m_kGroundPick.PickObjects(kStart, kDir)) { NiPick::Record* pkRecord = m_kGroundPick.GetResults().GetAt(0); if (pkRecord) { kLoc = pkRecord->GetIntersection(); return true; } } return false; } //--------------------------------------------------------------------------- void PickController::FindAllWalkables(NiScene* pkSceneRoot, NiTObjectArray& kWalkables) { // Find walkable and non-walkable terrain unsigned int uiEntities = pkSceneRoot->GetEntityCount(); unsigned int uiIndex; for(uiIndex=0; uiIndex < uiEntities; uiIndex++) { NiEntityInterface* pkEntity = pkSceneRoot->GetEntityAt(uiIndex); NiObject* pkObject; if (!pkEntity->GetPropertyData("Scene Root Pointer", pkObject)) continue; if (!NiIsKindOf(NiAVObject, pkObject)) continue; FindWalkables(kWalkables, (NiAVObject*)pkObject); } } //--------------------------------------------------------------------------- void PickController::FindWalkables(NiTObjectArray& kWalkables, NiAVObject* pkObject) { // Could be a walkable, check name const char* pkName = pkObject->GetName(); if (pkName) { if (NiStricmp(pkName, "walkable") == 0) { kWalkables.Add(pkObject); RecursiveSetKeep(pkObject); pkObject->SetAppCulled(true); return; } else if (NiStricmp(pkName, "non-walkable") == 0) { kWalkables.Add(pkObject); RecursiveSetKeep(pkObject); pkObject->SetAppCulled(true); return; } } if (NiIsKindOf(NiNode, pkObject)) { NiNode* pkNode = (NiNode*)pkObject; const unsigned int uiSize = pkNode->GetArrayCount(); for (unsigned int uiI = 0; uiI < uiSize; uiI++) { NiAVObject* pkChild = pkNode->GetAt(uiI); if (pkChild) { FindWalkables(kWalkables, pkChild); } } } } //--------------------------------------------------------------------------- void PickController::ToggleDisplayWalkables() { unsigned int uiWalkables = m_kWalkables.GetSize(); for (unsigned int ui=0; ui < uiWalkables; ui++) { NiAVObject* pkObject = m_kWalkables.GetAt(ui); if (!pkObject) continue; pkObject->SetAppCulled(!pkObject->GetAppCulled()); } } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // A utility function to set keep flags on all of the walkable geometry so // that they can be picked against after precaching. //--------------------------------------------------------------------------- void RecursiveSetKeep(NiAVObject* pkObject) { if (NiIsKindOf(NiNode, pkObject)) { // Recurse to children NiNode* pkNode = (NiNode*)pkObject; unsigned int uiChildCount = pkNode->GetArrayCount(); for (unsigned int i = 0; i < uiChildCount; i++) { NiAVObject* pkChild = pkNode->GetAt(i); if (pkChild) RecursiveSetKeep(pkChild); } } else if (NiIsKindOf(NiGeometry, pkObject)) { NiGeometry* pkGeom = (NiGeometry*)pkObject; pkGeom->GetModelData()->SetKeepFlags(NiGeometryData::KEEP_ALL); } } //---------------------------------------------------------------------------