// 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-2008 Emergent Game Technologies. // All Rights Reserved. // // Emergent Game Technologies, Calabasas, CA 91302 // http://www.emergent.net // 从 GB2.6 移植到 2.3 #include "stdafx.h" #include "NiLightMapUtility.h" #ifndef CODE_INGAME #include #include "NiLightMapMaterial.h" #include "NiGeometry.h" // Do not inline - there is a static SDM object cration in NiLightMapMaterial.h that we do not // want to recreate each time NiLightMapUtility.h is included. bool NiLightMapUtility::IsLightMapMesh(NiGeometry* pkGeom) { return NiIsKindOf(NiLightMapMaterial, pkGeom->GetActiveMaterial()); } //----------------------------------------------------------------------------------------------- NiString NiLightMapUtility::GenerateLightMapName( NiAVObject* pkObject, unsigned int uiTraversalID) { NiString kMeshName(pkObject->GetName()); kMeshName.Replace(" ", ""); kMeshName.Replace(":", "_"); //if (kMeshName.Length() > 10) // kMeshName = kMeshName.GetSubstring(0,10); return NiString::FromInt(uiTraversalID) + NiString("_") + kMeshName; } //----------------------------------------------------------------------------------------------- class LoadLightMapFunctor : public NiVisitLightMapMeshFunctor { public: NiString m_kLightMapDirectory; NiString m_kExtension; bool m_bSuccess; LoadLightMapFunctor(NiString kLightMapDirectory, NiString kExtension) { m_kLightMapDirectory = kLightMapDirectory; m_kExtension = kExtension; m_bSuccess = true; } virtual bool operator() ( NiGeometry* pkGeom, NiLightMapMeshProperties kProps) { char pcFilename[NI_MAX_PATH]; NiSprintf( pcFilename, NI_MAX_PATH, "%s/%s_%s.%s", (const char *)m_kLightMapDirectory, kProps.m_pcEntityDirectory, kProps.m_pcLightMapFilename, (const char *)m_kExtension); NiPath::Standardize(pcFilename); if (!NiLightMapUtility::LoadLightMap(pkGeom, pcFilename)) { NILOG("ERROR: failed to load light map %s\n", pcFilename); m_bSuccess = false; } return false; } }; //----------------------------------------------------------------------------------------------- class DeactivateLightFunctor : public NiVisitLightMapLightFunctor { public: DeactivateLightFunctor() { } virtual bool operator() ( NiLight* pkLight, NiLightMapLightProperties kProps = NiLightMapLightProperties()) { if (kProps.m_bGenerateRuntimeLight) { if(kProps.m_pkLightComponent) { NiLightMapUtility::RemoveLightMapEntities(kProps.m_pkLightComponent); } else { NiLightMapUtility::RemoveLightMapNodes(pkLight); } } else { if(kProps.m_pkLightComponent) { kProps.m_pkLightComponent->RemoveAllAffectedEntities(); } else { pkLight->SetSwitch(false); } } return false; } }; //----------------------------------------------------------------------------------------------- bool NiLightMapUtility::LoadLightMap(NiGeometry* pkGeom, const char* pcFilename) { NIASSERT(pkGeom); NiTexturingProperty* pTexProp = (NiTexturingProperty *) pkGeom->GetProperty(NiProperty::TEXTURING); NIASSERT(pTexProp); NiTexturingPropertyPtr pkNewTexProp = (NiTexturingProperty*)pTexProp->Clone(); NiTexturePtr spTexture = NiSourceTexture::Create(pcFilename); if (spTexture) { NIASSERT(pkNewTexProp->GetShaderMap(0)); pkNewTexProp->GetShaderMap(0)->SetTexture(spTexture); pkGeom->RemoveProperty(NiProperty::TEXTURING); pkGeom->AttachProperty(pkNewTexProp); pkGeom->UpdateProperties(); pkGeom->SetMaterialNeedsUpdate(true); pkGeom->SetDefaultMaterialNeedsUpdateFlag(true); return true; } else { return false; } } //----------------------------------------------------------------------------------------------- /*bool NiLightMapUtility::LoadLightMaps(NiNode* pkSceneGraph, NiString kLightMapDirectory) { LoadLightMapFunctor kLoadMap(kLightMapDirectory); VisitLightMapMeshes(pkSceneGraph, kLoadMap, ""); DeactivateLightFunctor kDeactivateLight; VisitLightMapLights(pkSceneGraph, kDeactivateLight); return kLoadMap.m_bSuccess; }*/ //----------------------------------------------------------------------------------------------- bool NiLightMapUtility::LoadLightMaps( NiScene* pkScene, NiString kLightMapDirectory, NiString kExtension) { LoadLightMapFunctor kLoadMap(kLightMapDirectory, kExtension); VisitLightMapMeshes(pkScene, kLoadMap); DeactivateLightFunctor kDeactivateLight; VisitLightMapLights(pkScene, kDeactivateLight); return kLoadMap.m_bSuccess; } //----------------------------------------------------------------------------------------------- bool NiLightMapUtility::VisitLightMapMeshes( const char* pcGSAFilename, NiVisitLightMapMeshFunctor &kFunctor) { NiEntityStreamingAscii kStream; if (!kStream.Load(pcGSAFilename)) { NILOG("Failed: Loading file name %s", pcGSAFilename); return false; } if (kStream.GetSceneCount() < 1) { NILOG("Failed: Obtaining a Scene", "Failed"); return false; } NiScenePtr spEntityScene = kStream.GetSceneAt(0); NiExternalAssetManagerPtr spInterface = NiNew NiExternalAssetManager; spInterface->SetAssetFactory(NiFactories::GetAssetFactory()); NiDefaultErrorHandlerPtr spManager = NiNew NiDefaultErrorHandler; spEntityScene->Update(0.0f, spManager, spInterface); VisitLightMapMeshes(spEntityScene, kFunctor); return true; } //----------------------------------------------------------------------------------------------- bool NiLightMapUtility::VisitLightMapMeshes( NiScene* pkScene, NiVisitLightMapMeshFunctor &kFunctor) { unsigned int uiCount = pkScene->GetEntityCount(); for(unsigned int uiEntity=0; uiEntity < uiCount; uiEntity++) { NiEntityInterface* pkEntity = pkScene->GetEntityAt(uiEntity); VisitLightMapMeshes(pkEntity, kFunctor); } return true; } //----------------------------------------------------------------------------------------------- bool NiLightMapUtility::VisitLightMapMeshes( NiEntityInterface* pkEntity, NiVisitLightMapMeshFunctor &kFunctor) { unsigned int uiSceneRootCount; NiFixedString kSceneRootPointer = "Scene Root Pointer"; NIASSERT(pkEntity); // If an entity has a scene graph, visit all the meshes in that graph if (pkEntity->GetElementCount(kSceneRootPointer, uiSceneRootCount)) { for (unsigned int ui = 0; ui < uiSceneRootCount; ui++) { NiObject* pkObject; if (pkEntity->GetPropertyData( kSceneRootPointer, pkObject, ui)) { NiNode* pkNode = NiDynamicCast(NiNode, pkObject); if (pkNode) { VisitLightMapMeshes( pkNode, kFunctor, pkEntity); } } } } return true; } //----------------------------------------------------------------------------------------------- struct GetMeshLightMapInfoFunctor { NiVisitLightMapMeshFunctor* m_pkCallbackFunctor; NiEntityInterface* m_pkEntity; unsigned int m_iTraversalID; GetMeshLightMapInfoFunctor( NiVisitLightMapMeshFunctor* pkCallbackFunctor, NiEntityInterface* pkEntity): m_pkCallbackFunctor(pkCallbackFunctor) { m_iTraversalID = 0; m_pkEntity = pkEntity; } bool operator() (NiAVObject* pkObject) { NiGeometry* pkGeom = NiDynamicCast(NiGeometry, pkObject); if (pkGeom && (NiLightMapUtility::IsLightMapMesh(pkGeom)) && !pkGeom->GetAppCulled()) { NiString kEntityID = ""; if (m_pkEntity) { kEntityID = m_pkEntity->GetName(); kEntityID.Replace(",",""); kEntityID.Replace(":", ""); } NiString kFileName = NiLightMapUtility::GenerateLightMapName( pkGeom, m_iTraversalID++); NiLightMapMeshProperties kProps; kProps.m_pcEntityDirectory = m_pkEntity->GetName();//kEntityID; kProps.m_pcLightMapFilename = kFileName; kProps.m_pkEntity = m_pkEntity; (*m_pkCallbackFunctor)(pkGeom, kProps); } return false; } }; //----------------------------------------------------------------------------------------------- bool NiLightMapUtility::VisitLightMapMeshes( NiNode* pkNode, NiVisitLightMapMeshFunctor &kFunctor, NiEntityInterface* pkEntity) { GetMeshLightMapInfoFunctor kGetInfoFunctor( &kFunctor, pkEntity); NiTNodeTraversal::DepthFirst_AllObjects(pkNode, kGetInfoFunctor); return true; } //----------------------------------------------------------------------------------------------- bool NiLightMapUtility::VisitLightMapLights( const char* pcGSAFilename, NiVisitLightMapLightFunctor &kFunctor) { NiEntityStreamingAscii kStream; if (!kStream.Load(pcGSAFilename)) { NILOG("Failed: Loading file name %s", pcGSAFilename); return false; } if (kStream.GetSceneCount() < 1) { NILOG("Failed: Obtaining a Scene", "Failed"); return false; } NiScenePtr spEntityScene = kStream.GetSceneAt(0); NiExternalAssetManagerPtr spAsset = NiNew NiExternalAssetManager; spAsset->SetAssetFactory(NiFactories::GetAssetFactory()); NiDefaultErrorHandlerPtr spError = NiNew NiDefaultErrorHandler; spEntityScene->Update(0.0f, spError, spAsset); unsigned int uiCount = spEntityScene->GetEntityCount(); for (unsigned int uiEntity = 0; uiEntity < uiCount; uiEntity++) { NiEntityInterface* pkEntity = spEntityScene->GetEntityAt(uiEntity); pkEntity->Update(NULL, 0.0, spError, spAsset); } VisitLightMapLights(spEntityScene, kFunctor); return true; } //----------------------------------------------------------------------------------------------- bool NiLightMapUtility::VisitLightMapLights( NiScene* pkScene, NiVisitLightMapLightFunctor &kFunctor) { unsigned int uiCount = pkScene->GetEntityCount(); for(unsigned int uiEntity=0; uiEntity < uiCount; uiEntity++) { NiEntityInterface* pkEntity = pkScene->GetEntityAt(uiEntity); VisitLightMapLights(pkEntity, kFunctor); } return true; } //----------------------------------------------------------------------------------------------- bool NiLightMapUtility::VisitLightMapLights( NiEntityInterface* pkEntity, NiVisitLightMapLightFunctor &kFunctor) { unsigned int uiSceneRootCount; bool bGenerateLightMaps = false; NIASSERT(pkEntity); // If an entity has a scene graph, visit all the meshes in that graph if (pkEntity->GetElementCount("Scene Root Pointer", uiSceneRootCount) && pkEntity->GetPropertyData("Generate Light Maps", bGenerateLightMaps)) { NiLightMapLightProperties kProps; pkEntity->GetPropertyData("Generate Runtime Light", kProps.m_bGenerateRuntimeLight); pkEntity->GetPropertyData("Area Light Radius", kProps.m_fAreaLightRadius); pkEntity->GetPropertyData("Area Light Samples", kProps.m_iAreaLightSamples); NiString kEntityID = pkEntity->GetName(); kEntityID.Replace(",",""); kEntityID.Replace(":", ""); kProps.m_pcEntityID = kEntityID; NiFixedString kLightString("NiLightComponent"); for (unsigned int ui = 0; ui < pkEntity->GetComponentCount(); ui++) { NiEntityComponentInterface* pkComponent = pkEntity->GetComponentAt(ui); NiFixedString kString = pkComponent->GetClassName(); if (kString == kLightString) { kProps.m_pkLightComponent = (NiLightComponent*)pkComponent; break; } } if (bGenerateLightMaps) { for (unsigned int ui = 0; ui < uiSceneRootCount; ui++) { NiObject* pkObject; if (pkEntity->GetPropertyData( "Scene Root Pointer", pkObject, ui)) { NiLight* pkLight = NiDynamicCast(NiLight, pkObject); NIASSERT(pkLight); kFunctor(pkLight, kProps); } } } } return true; } //----------------------------------------------------------------------------------------------- /*struct GetLightFunctor { NiVisitLightMapLightFunctor &m_kCallbackFunctor; GetLightFunctor(NiVisitLightMapLightFunctor &kCallbackFunctor): m_kCallbackFunctor(kCallbackFunctor) { } bool operator() (NiAVObject* pkObject) { NiLight* pkLight = NiDynamicCast(NiLight, pkObject); if (pkLight) m_kCallbackFunctor(pkLight); return false; } }; //----------------------------------------------------------------------------------------------- bool NiLightMapUtility::VisitLightMapLights( NiNode* pkNode, NiVisitLightMapLightFunctor &kFunctor, bool bVisitAllLights) { GetLightFunctor kGetLightFunctor(kFunctor); NiTNodeTraversal::DepthFirst_AllObjects(pkNode, kGetLightFunctor); return true; }*/ //----------------------------------------------------------------------------------------------- int NiLightMapUtility::GetLightMapUVSetIndex(NiGeometry* pkGeom) { if (!NiLightMapUtility::IsLightMapMesh(pkGeom)) { return -1; } else { NiTexturingProperty* pkTexProp = (NiTexturingProperty*)pkGeom->GetProperty(NiProperty::TEXTURING); NIASSERT(pkTexProp); NiTexturingProperty::ShaderMap* pkShaderMap = pkTexProp->GetShaderMap(0); NIASSERT(pkShaderMap); return pkShaderMap->GetTextureIndex(); } } //----------------------------------------------------------------------------------------------- struct DetermineNodeTypeFunctor { bool m_HasLightMapMesh; bool m_HasStandardMesh; DetermineNodeTypeFunctor() { m_HasLightMapMesh = false; m_HasStandardMesh = false; } bool operator() (NiAVObject* pkObject) { NiGeometry* pkGeom = NiDynamicCast(NiGeometry, pkObject); if (pkGeom) { if (NiLightMapUtility::IsLightMapMesh(pkGeom)) m_HasLightMapMesh = true; else m_HasStandardMesh = true; } return false; } }; //----------------------------------------------------------------------------------------------- void NiLightMapUtility::RemoveLightMapNodes(NiLight* pkLight) { const NiNodeList& kNodeList = pkLight->GetAffectedNodeList(); NiTPointerList kRemoveList; NiTListIterator kIter = kNodeList.GetHeadPos(); while (kIter) { NiNode* pkNode = kNodeList.GetNext(kIter); DetermineNodeTypeFunctor kFunctor; NiTNodeTraversal::DepthFirst_AllObjects(pkNode, kFunctor); if (kFunctor.m_HasLightMapMesh) { kRemoveList.AddHead(pkNode); if (kFunctor.m_HasStandardMesh) { NILOG("WARNING: Found use of both LightMapMaterial and StandardMaterial in " "node \"%s\"; Light map lights will not affect this node at runtime.", (const char *)pkNode->GetName()); } } } kIter = kRemoveList.GetHeadPos(); while (kIter) { NiNode* pkNode = kRemoveList.GetNext(kIter); pkLight->DetachAffectedNode(pkNode); pkNode->UpdateEffects(); } } //----------------------------------------------------------------------------------------------- void NiLightMapUtility::RemoveLightMapEntities(NiLightComponent* pkComponent) { NiTPointerList kRemoveList; for (unsigned int ui = 0; ui < pkComponent->GetAffectedEntitiesCount(); ui++) { NiEntityInterface* pkEntity = pkComponent->GetAffectedEntityAt(ui); NiNode* pkNode = GetSceneGraphNode(pkEntity); DetermineNodeTypeFunctor kFunctor; NiTNodeTraversal::DepthFirst_AllObjects(pkNode, kFunctor); if (kFunctor.m_HasLightMapMesh) { kRemoveList.AddHead(pkEntity); if (kFunctor.m_HasStandardMesh) { NILOG("WARNING: Found use of both LightMapMaterial and StandardMaterial in " "node \"%s\"; Light map lights will not affect this node at runtime.", (const char *)pkNode->GetName()); } } } NiTListIterator kIter = kRemoveList.GetHeadPos(); while (kIter) { NiEntityInterface* pkEntity = kRemoveList.GetNext(kIter); pkComponent->RemoveAffectedEntity(pkEntity); } } //----------------------------------------------------------------------------------------------- NiNode* NiLightMapUtility::GetSceneGraphNode(NiEntityInterface* pkEntity) { NiObject* pkNode = NULL; pkEntity->GetPropertyData("Scene Root Pointer", pkNode, 0); return NiDynamicCast(NiNode, pkNode); } #endif // CODE_INGAME