// 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 "SceneDesignerFrameworkPCH.h" #include "MLightManager.h" #include "MFramework.h" #include "MUtility.h" #include "ServiceProvider.h" #include "NiLightProxyComponent.h" #include "MTimeStamp.h" #include "MTerrain.h" using namespace Emergent::Gamebryo::SceneDesigner::Framework; //--------------------------------------------------------------------------- void MLightManager::Init() { if (ms_pmThis == NULL) { ms_pmThis = new MLightManager(); } } //--------------------------------------------------------------------------- void MLightManager::Shutdown() { if (ms_pmThis != NULL) { ms_pmThis->Dispose(); ms_pmThis = NULL; } } //--------------------------------------------------------------------------- bool MLightManager::InstanceIsValid() { return (ms_pmThis != NULL); } //--------------------------------------------------------------------------- MLightManager* MLightManager::get_Instance() { return ms_pmThis; } //--------------------------------------------------------------------------- MLightManager::MLightManager() : m_bUseDefaultLights(true), m_bAddEntitiesToLights(true), m_bUpdateDefaultLights(false) { m_pmLights = new ArrayList(); __hook(&MEventManager::SceneClosing, MEventManager::Instance, &MLightManager::OnSceneClosing); __hook(&MEventManager::NewSceneLoaded, MEventManager::Instance, &MLightManager::OnNewSceneLoaded); __hook(&MEventManager::EntityAddedToScene, MEventManager::Instance, &MLightManager::OnEntityAddedToScene); __hook(&MEventManager::EntityRemovedFromScene, MEventManager::Instance, &MLightManager::OnEntityRemovedFromScene); __hook(&MEventManager::EntityPropertyChanged, MEventManager::Instance, &MLightManager::OnEntityPropertyChanged); __hook(&MEventManager::EntityComponentAdded, MEventManager::Instance, &MLightManager::OnEntityComponentAdded); __hook(&MEventManager::EntityComponentRemoved, MEventManager::Instance, &MLightManager::OnEntityComponentRemoved); } //--------------------------------------------------------------------------- void MLightManager::Do_Dispose(bool bDisposing) { if (bDisposing) { // For some reason, __unhook causes bogus compilation errors here. // Thus, some events are unhooked manually. __unhook(&MEventManager::SceneClosing, MEventManager::Instance, &MLightManager::OnSceneClosing); MEventManager::Instance->remove_NewSceneLoaded(new MEventManager::__Delegate_NewSceneLoaded(this, &MLightManager::OnNewSceneLoaded)); MEventManager::Instance->remove_EntityAddedToScene(new MEventManager::__Delegate_EntityAddedToScene(this, &MLightManager::OnEntityAddedToScene)); MEventManager::Instance->remove_EntityRemovedFromScene(new MEventManager::__Delegate_EntityRemovedFromScene(this, &MLightManager::OnEntityRemovedFromScene)); __unhook(&MEventManager::EntityPropertyChanged, MEventManager::Instance, &MLightManager::OnEntityPropertyChanged); __unhook(&MEventManager::EntityComponentAdded, MEventManager::Instance, &MLightManager::OnEntityComponentAdded); MEventManager::Instance->remove_EntityComponentRemoved(new MEventManager::__Delegate_EntityComponentRemoved(this, &MLightManager::OnEntityComponentRemoved)); if (m_amDefaultLights != NULL) { DisposeDefaultLights(); } } } //--------------------------------------------------------------------------- void MLightManager::Startup() { MVerifyValidInstance; CreateLightProxyHandler(); MProxyManager::Instance->AddProxyHandler(this); CreateDefaultLights(); RegisterForDefaultLightsSetting(); RegisterForAddEntitiesToLightsSetting(); } //--------------------------------------------------------------------------- MEntity* MLightManager::GetMasterProxyEntity(MEntity* pmEntity) { if (MLightManager::EntityIsLight(pmEntity)) { return m_pmMasterProxy; } return NULL; } //--------------------------------------------------------------------------- void MLightManager::RegisterForDefaultLightsSetting() { MVerifyValidInstance; SettingsService->RegisterSettingsObject(ms_strDefaultLightsSettingName, __box(UseDefaultLights), SettingsCategory::PerUser); SettingsService->SetChangedSettingHandler(ms_strDefaultLightsSettingName, SettingsCategory::PerUser, new SettingChangedHandler(this, &MLightManager::OnDefaultLightsSettingChanged)); OnDefaultLightsSettingChanged(NULL, NULL); OptionsService->AddOption(ms_strDefaultLightsOptionName, SettingsCategory::PerUser, ms_strDefaultLightsSettingName); OptionsService->SetHelpDescription(ms_strDefaultLightsOptionName, "Indicates whether or not default lights will affect scene entities " "when no other lights exist in the scene."); } //--------------------------------------------------------------------------- void MLightManager::RegisterForAddEntitiesToLightsSetting() { MVerifyValidInstance; SettingsService->RegisterSettingsObject( ms_strAddEntitiesToLightsSettingName, __box(m_bAddEntitiesToLights), SettingsCategory::PerUser); SettingsService->SetChangedSettingHandler( ms_strAddEntitiesToLightsSettingName, SettingsCategory::PerUser, new SettingChangedHandler(this, &MLightManager::OnAddEntitiesToLightsSettingChanged)); OnAddEntitiesToLightsSettingChanged(NULL, NULL); OptionsService->AddOption(ms_strAddEntitiesToLightsOptionName, SettingsCategory::PerUser, ms_strAddEntitiesToLightsSettingName); OptionsService->SetHelpDescription(ms_strAddEntitiesToLightsOptionName, "Indicates whether or not entities added to the scene will be " "automatically affected by all lights in the scene."); } //--------------------------------------------------------------------------- void MLightManager::OnDefaultLightsSettingChanged(Object* pmSender, SettingChangedEventArgs* pmEventArgs) { MVerifyValidInstance; __box bool* pbUseDefaultLights = dynamic_cast<__box bool*>( SettingsService->GetSettingsObject(ms_strDefaultLightsSettingName, SettingsCategory::PerUser)); if (pbUseDefaultLights != NULL) { UseDefaultLights = *pbUseDefaultLights; } } //--------------------------------------------------------------------------- void MLightManager::OnAddEntitiesToLightsSettingChanged(Object* pmSender, SettingChangedEventArgs* pmEventArgs) { MVerifyValidInstance; __box bool* pbAddEntitiesToLights = dynamic_cast<__box bool*>( SettingsService->GetSettingsObject( ms_strAddEntitiesToLightsSettingName, SettingsCategory::PerUser)); if (pbAddEntitiesToLights != NULL) { m_bAddEntitiesToLights = *pbAddEntitiesToLights; } } //--------------------------------------------------------------------------- void MLightManager::CreateLightProxyHandler() { m_pmMasterProxy = NULL; NiDefaultErrorHandlerPtr spErrors; NiUniqueID kTemplateID; MUtility::GuidToID(Guid::NewGuid(), kTemplateID); NiEntityInterfaceIPtr spDummyEntity = NULL; MUtility::GuidToID(Guid::NewGuid(), kTemplateID); NiEntityInterfaceIPtr spEntity = NiNew NiGeneralEntity("Light Proxy", kTemplateID, 2); bool bSuccess = NIBOOL_IS_TRUE(spEntity->AddComponent(NiNew NiLightProxyComponent(spDummyEntity, NULL))); if (bSuccess) { const char* pcAppStartupPath = MStringToCharPointer(MFramework::Instance->AppStartupPath); char acAbsGeomPath[NI_MAX_PATH]; size_t stSize = NiPath::ConvertToAbsolute(acAbsGeomPath, NI_MAX_PATH, ".\\AppData\\light.nif", pcAppStartupPath); NIASSERT(stSize > 0); bSuccess = NIBOOL_IS_TRUE(spEntity->AddComponent(NiNew NiSceneGraphComponent(acAbsGeomPath))); if (bSuccess) { m_pmMasterProxy = MEntityFactory::Instance->Get(spEntity); m_pmMasterProxy->SetPropertyData("Source Entity", NULL, false); } else { if (!spErrors) { spErrors = NiNew NiDefaultErrorHandler(2); } spErrors->ReportError("Error creating light proxy entity;" " light proxy geometry will not be shown.", NULL, NULL, NULL); } MFreeCharPointer(pcAppStartupPath); } else { if (!spErrors) { spErrors = NiNew NiDefaultErrorHandler(2); } spErrors->ReportError("Error creating light proxy entity; light " "proxy geometry will not be shown.", NULL, NULL, NULL); } if (spErrors) { MUtility::AddErrorInterfaceMessages(MessageChannelType::Errors, spErrors); } } //--------------------------------------------------------------------------- bool MLightManager::EntityIsLight(MEntity* pmEntity) { MAssert(pmEntity != NULL, "Null entity provided to function!"); NiAVObject* pkSceneRoot = pmEntity->GetSceneRootPointer(0); if (pkSceneRoot != NULL && NiIsKindOf(NiLight, pkSceneRoot)) { return true; } else { return false; } } //--------------------------------------------------------------------------- MEntity* MLightManager::GetSceneLights()[] { return static_cast(m_pmLights->ToArray(__typeof(MEntity))); } //--------------------------------------------------------------------------- int MLightManager::GetSceneLightsCount() { return m_pmLights->Count; } //--------------------------------------------------------------------------- void MLightManager::OnSceneClosing(MScene* pmScene) { MVerifyValidInstance; if (MFramework::Instance->Scene == pmScene) { m_pmLights->Clear(); ClearDefaultLightAffectedEntities(); } } //--------------------------------------------------------------------------- void MLightManager::OnNewSceneLoaded(MScene* pmScene) { MVerifyValidInstance; if (MFramework::Instance->Scene == pmScene) { CollectSceneLights(pmScene); if (m_pmLights->Count == 0 && UseDefaultLights) { // If there are no lights in the scene, make all scene entities // get affected by the default lights. AddEntitiesToDefaultLights(pmScene->GetEntities()); } } } //--------------------------------------------------------------------------- void MLightManager::OnEntityAddedToScene(MScene* pmScene, MEntity* pmEntity) { MVerifyValidInstance; // 记录时间戳 #ifdef _DEBUG MTimeStamp::Instance->AddTimeStamp(new String("Enter MLightManager::OnEntityAddedToScene")); #endif if (MFramework::Instance->Scene == pmScene) { ProcessAddedEntity(pmScene, pmEntity); } #ifdef _DEBUG MTimeStamp::Instance->AddTimeStamp(new String("Quit MLightManager::OnEntityAddedToScene")); #endif } //--------------------------------------------------------------------------- void MLightManager::OnEntityRemovedFromScene(MScene* pmScene, MEntity* pmEntity, bool bResolveDependencies) { MVerifyValidInstance; if (MFramework::Instance->Scene == pmScene) { ProcessRemovedEntity(pmScene, pmEntity); } } //--------------------------------------------------------------------------- void MLightManager::OnEntityPropertyChanged(MEntity* pmEntity, String* strPropertyName, unsigned int uiPropertyIndex, bool bInBatch) { MVerifyValidInstance; if (pmEntity->IsExternalAssetPath(strPropertyName, uiPropertyIndex)) //|| pmEntity->Name.Equals("")) { // Perform an initial update here to force the entity to load // the external asset. if (MFramework::Instance->Scene->IsEntityInScene(pmEntity)) { pmEntity->Update(MTimeManager::Instance->CurrentTime, MFramework::Instance->ExternalAssetManager); } else { MEntity* amDependentEntities[] = MFramework::Instance->Scene ->GetDependentEntities(pmEntity); for (int i = 0; i < amDependentEntities->Length; i++) { MEntity* pmDependentEntity = amDependentEntities[i]; if (MFramework::Instance->Scene->IsEntityInScene( pmDependentEntity)) { pmDependentEntity->Update( MTimeManager::Instance->CurrentTime, MFramework::Instance->ExternalAssetManager); } } } // Refresh each light's affected entities list so that it will // affect the new external asset. RefreshLightAffectedEntities(); } } //--------------------------------------------------------------------------- void MLightManager::OnEntityComponentAdded(MEntity* pmEntity, MComponent* pmComponent) { MVerifyValidInstance; if (MFramework::Instance->Scene->IsEntityInScene(pmEntity)) { if (pmComponent->HasProperty(ms_strAffectedEntitiesName)) { // Ensure that entity has been updated with new component. pmEntity->Update(MTimeManager::Instance->CurrentTime, MFramework::Instance->ExternalAssetManager); // Process the entity as if it has just been added to the scene. ProcessAddedEntity(MFramework::Instance->Scene, pmEntity); } else if (pmComponent->HasProperty(ms_strCastShadowsName)) { // Force the shadow generator to recreate itself (to properly // support undo functionality). Object* pbActive = pmComponent->GetPropertyData( ms_strCastShadowsName); pmComponent->SetPropertyData(ms_strCastShadowsName, __box(false), true); pmComponent->SetPropertyData(ms_strCastShadowsName, pbActive, true); } } } //--------------------------------------------------------------------------- void MLightManager::OnEntityComponentRemoved(MEntity* pmEntity, MComponent* pmComponent) { MVerifyValidInstance; if (MFramework::Instance->Scene->IsEntityInScene(pmEntity)) { if (pmComponent->HasProperty(ms_strAffectedEntitiesName)) { // Remove entity from light array. m_pmLights->Remove(pmEntity); // Remove all affected entities for the light. for (unsigned int ui = 0; ui < pmComponent->GetElementCount( ms_strAffectedEntitiesName); ui++) { pmComponent->SetPropertyData(ms_strAffectedEntitiesName, NULL, ui, true); } if (m_pmLights->Count == 0 && UseDefaultLights) { // If this light was the last light in the scene, make all // scene entities get affected by the default lights. AddEntitiesToDefaultLights( MFramework::Instance->Scene->GetEntities()); } } else if (pmComponent->HasProperty(ms_strCastShadowsName)) { // Disable shadow generator. pmComponent->SetPropertyData(ms_strCastShadowsName, __box(false), true); } } } //--------------------------------------------------------------------------- void MLightManager::RefreshLightAffectedEntities() { MVerifyValidInstance; if (m_bUseDefaultLights && m_pmLights->Count == 0) { for (int i = 0; i < m_amDefaultLights->Length; i++) { MEntity* pmDefaultLight = m_amDefaultLights[i]; unsigned int uiAffectedEntitiesCount = pmDefaultLight ->GetElementCount(ms_strAffectedEntitiesName); for (unsigned int ui = 0; ui < uiAffectedEntitiesCount; ui++) { MEntity* pkAffectedEntity = dynamic_cast( pmDefaultLight->GetPropertyData( ms_strAffectedEntitiesName, ui)); if (pkAffectedEntity != NULL) { pmDefaultLight->SetPropertyData( ms_strAffectedEntitiesName, NULL, ui, false); pmDefaultLight->SetPropertyData( ms_strAffectedEntitiesName, pkAffectedEntity, ui, false); break; } } } m_bUpdateDefaultLights = true; } else { for (int i = 0; i < m_pmLights->Count; i++) { MEntity* pmLight = dynamic_cast(m_pmLights->Item[i]); MAssert(pmLight != NULL, "Invalid light array!"); // Refresh affected entities. unsigned int uiAffectedEntitiesCount = pmLight->GetElementCount( ms_strAffectedEntitiesName); for (unsigned int ui = 0; ui < uiAffectedEntitiesCount; ui++) { MEntity* pkAffectedEntity = dynamic_cast( pmLight->GetPropertyData(ms_strAffectedEntitiesName, ui)); if (pkAffectedEntity != NULL) { pmLight->SetPropertyData(ms_strAffectedEntitiesName, NULL, ui, false); pmLight->SetPropertyData(ms_strAffectedEntitiesName, pkAffectedEntity, ui, false); break; } } // Force the shadow generator to recreate itself, if the light // has one. if (pmLight->HasProperty(ms_strCastShadowsName)) { Object* pbActive = pmLight->GetPropertyData( ms_strCastShadowsName); pmLight->SetPropertyData(ms_strCastShadowsName, __box(false), true); pmLight->SetPropertyData(ms_strCastShadowsName, pbActive, true); } pmLight->Update(0.0f, MFramework::Instance->ExternalAssetManager); } } } //--------------------------------------------------------------------------- bool MLightManager::get_UseDefaultLights() { MVerifyValidInstance; return m_bUseDefaultLights; } //--------------------------------------------------------------------------- void MLightManager::set_UseDefaultLights(bool bUseDefaultLights) { MVerifyValidInstance; if (m_bUseDefaultLights != bUseDefaultLights) { m_bUseDefaultLights = bUseDefaultLights; if (m_bUseDefaultLights) { if (m_pmLights->Count == 0) { // If there are no lights in the scene, make all scene // entities get affected by the default lights. AddEntitiesToDefaultLights(MFramework::Instance->Scene ->GetEntities()); } } else { ClearDefaultLightAffectedEntities(); } } } //--------------------------------------------------------------------------- void MLightManager::CreateDefaultLights() { MVerifyValidInstance; // MEntityFactory is explicitly not used to create default light entities // because they are entirely internal and will be disposed of manually. NiFixedString kDefaultLightName = "Default Light"; NiFixedString kRotationName = "Rotation"; NiUniqueID kTemplateID; MUtility::GuidToID(Guid::NewGuid(), kTemplateID); NiEntityInterface* pkDefaultLight = NiNew NiGeneralEntity( kDefaultLightName, kTemplateID, 2); pkDefaultLight->AddComponent(NiNew NiTransformationComponent()); pkDefaultLight->AddComponent(NiNew NiLightComponent( NiLightComponent::LT_DIRECTIONAL, 1.0f, NiColor::BLACK, NiColor::WHITE, NiColor::WHITE, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100, 100)); m_amDefaultLights = new MEntity*[2]; int iIndex = 0; NiMatrix3 kRotation( NiPoint3(0.44663f, 0.496292f, -0.744438f), NiPoint3(0.0f, -0.83205f, -0.5547f), NiPoint3(-0.894703f, 0.247764f, -0.371646f)); pkDefaultLight->SetPropertyData(kRotationName, kRotation, 0); m_amDefaultLights[iIndex++] = MEntityFactory::Instance->Get( pkDefaultLight); NiEntityInterface* pkDefaultLightClone = pkDefaultLight->Clone( kDefaultLightName, false); kRotation.SetCol(0, NiPoint3(-0.44663f, -0.496292f, 0.744438f)); kRotation.SetCol(1, NiPoint3(0.0f, 0.83205f, 0.5547f)); kRotation.SetCol(2, NiPoint3(-0.894703f, 0.247764f, -0.371646f)); pkDefaultLightClone->SetPropertyData(kRotationName, kRotation, 0); m_amDefaultLights[iIndex++] = MEntityFactory::Instance->Get( pkDefaultLightClone); m_bUpdateDefaultLights = true; } //--------------------------------------------------------------------------- void MLightManager::DisposeDefaultLights() { MVerifyValidInstance; MAssert(m_amDefaultLights != NULL, "Null default lights array!"); for (int i = 0; i < m_amDefaultLights->Length; i++) { m_amDefaultLights[i]->Dispose(); } } //--------------------------------------------------------------------------- void MLightManager::ClearDefaultLightAffectedEntities() { MVerifyValidInstance; MAssert(m_amDefaultLights != NULL, "Null default lights array!"); for (int i = 0; i < m_amDefaultLights->Length; i++) { MEntity* pmDefaultLight = m_amDefaultLights[i]; unsigned int uiAffectedEntitiesCount = pmDefaultLight ->GetElementCount(ms_strAffectedEntitiesName); for (unsigned int ui = 0; ui < uiAffectedEntitiesCount; ui++) { pmDefaultLight->SetPropertyData(ms_strAffectedEntitiesName, NULL, ui, false); } } m_bUpdateDefaultLights = true; } //--------------------------------------------------------------------------- void MLightManager::AddEntityToDefaultLights(MEntity* pmEntity) { MVerifyValidInstance; MAssert(pmEntity != NULL, "Null entity provided to function!"); MAssert(m_amDefaultLights != NULL, "Null default lights array!"); for (int i = 0; i < m_amDefaultLights->Length; i++) { MEntity* pmDefaultLight = m_amDefaultLights[i]; unsigned int uiAffectedEntitiesCount = pmDefaultLight ->GetElementCount(ms_strAffectedEntitiesName); pmDefaultLight->SetPropertyData(ms_strAffectedEntitiesName, pmEntity, uiAffectedEntitiesCount, false); } m_bUpdateDefaultLights = true; } //--------------------------------------------------------------------------- void MLightManager::AddEntitiesToDefaultLights(MEntity* amEntities[]) { MVerifyValidInstance; MAssert(amEntities != NULL, "Null array provided to function!"); MAssert(m_amDefaultLights != NULL, "Null default lights array!"); for (int i = 0; i < m_amDefaultLights->Length; i++) { MEntity* pmDefaultLight = m_amDefaultLights[i]; unsigned int uiIndex = pmDefaultLight->GetElementCount( ms_strAffectedEntitiesName); for (int j = 0; j < amEntities->Length; j++) { MEntity* pmEntity = amEntities[j]; if (!MCameraManager::EntityIsCamera(pmEntity)) { pmDefaultLight->SetPropertyData(ms_strAffectedEntitiesName, pmEntity, uiIndex++, false); } } } m_bUpdateDefaultLights = true; } //--------------------------------------------------------------------------- void MLightManager::RemoveEntityFromDefaultLights(MEntity* pmEntity) { MVerifyValidInstance; MAssert(pmEntity != NULL, "Null entity provided to function!"); MAssert(m_amDefaultLights != NULL, "Null default lights array!"); for (int i = 0; i < m_amDefaultLights->Length; i++) { MEntity* pmDefaultLight = m_amDefaultLights[i]; unsigned int uiAffectedEntitiesCount = pmDefaultLight ->GetElementCount(ms_strAffectedEntitiesName); for (unsigned int ui = 0; ui < uiAffectedEntitiesCount; ui++) { if (pmDefaultLight->GetPropertyData(ms_strAffectedEntitiesName, ui) == pmEntity) { pmDefaultLight->SetPropertyData(ms_strAffectedEntitiesName, NULL, ui, false); break; } } } m_bUpdateDefaultLights = true; } //--------------------------------------------------------------------------- void MLightManager::RemoveEntitiesFromDefaultLights(MEntity* amEntities[]) { MVerifyValidInstance; MAssert(amEntities != NULL, "Null array provided to function!"); MAssert(m_amDefaultLights != NULL, "Null default lights array!"); for (int i = 0; i < m_amDefaultLights->Length; i++) { MEntity* pmDefaultLight = m_amDefaultLights[i]; for (int j = 0; j < amEntities->Length; j++) { MEntity* pmEntity = amEntities[j]; unsigned int uiAffectedEntitiesCount = pmDefaultLight ->GetElementCount(ms_strAffectedEntitiesName); for (unsigned int ui = 0; ui < uiAffectedEntitiesCount; ui++) { if (pmDefaultLight->GetPropertyData(ms_strAffectedEntitiesName, ui) == pmEntity) { pmDefaultLight->SetPropertyData(ms_strAffectedEntitiesName, NULL, ui, false); break; } } } } m_bUpdateDefaultLights = true; } //--------------------------------------------------------------------------- void MLightManager::Update(float fTime) { MVerifyValidInstance; if (m_bUpdateDefaultLights) { for (int i = 0; i < m_amDefaultLights->Length; i++) { m_amDefaultLights[i]->Update(fTime, MFramework::Instance ->ExternalAssetManager); } m_bUpdateDefaultLights = false; } } //--------------------------------------------------------------------------- void MLightManager::CollectSceneLights(MScene* pmScene) { MVerifyValidInstance; MEntity* amAllEntitiesInScene[] = pmScene->GetEntities(); for (int i = 0; i < amAllEntitiesInScene->Length; i++) { MEntity* pmEntity = amAllEntitiesInScene[i]; if (EntityIsLight(pmEntity)) { m_pmLights->Add(pmEntity); } } } //--------------------------------------------------------------------------- void MLightManager::ProcessAddedEntity(MScene* pmScene, MEntity* pmEntity) { MVerifyValidInstance; MAssert(pmScene != NULL, "Null scene provided to function!"); MAssert(pmEntity != NULL, "Null entity provided to function!"); #ifdef _DEBUG MTimeStamp::Instance->AddTimeStamp(new String("Enter MLightManager::ProcessAddedEntity")); #endif if (EntityIsLight(pmEntity)) { if (m_pmLights->Count == 0 && UseDefaultLights) { // If there are currently no lights, remove all affected entities // from the default lights. ClearDefaultLightAffectedEntities(); } // Add entity to light array. m_pmLights->Add(pmEntity); // 对character_ambient不添加影响物件 [2/2/2010 hemeng] if(String::Compare(pmEntity->Name,"character_ambient") == 0) { return; } if (m_bAddEntitiesToLights) { MAssert(pmEntity->HasProperty(ms_strAffectedEntitiesName), "Light does not have affected entities property!"); // Remove all affected entities for the light. unsigned int uiAffectedEntitiesCount = pmEntity->GetElementCount( ms_strAffectedEntitiesName); for (unsigned int ui = 0; ui < uiAffectedEntitiesCount; ui++) { pmEntity->SetPropertyData(ms_strAffectedEntitiesName, NULL, ui, true); } // Add all scene entities as affected entities for the light. // 090119 modified by 和萌,仅添加距离灯光范围的物体到影响列表 MEntity* amSceneEntities[] = pmScene->GetEntities(); unsigned int uiIndex = 0; for (int i = 0; i < amSceneEntities->Length; i++) { MEntity* pmSceneEntity = amSceneEntities[i]; if (!EntityIsLight(pmSceneEntity) && !MCameraManager::EntityIsCamera(pmSceneEntity)) { // 判断灯光类型 String* strType = dynamic_cast(pmEntity->GetPropertyData( "Light Type")); if (strType->Equals(NiLightComponent::LT_POINT)) { float fLightScale; if (!pmEntity->GetNiEntityInterface()->GetPropertyData("Scale",fLightScale)) { NiMessageBox("获取灯光影响范围失败!","Error",0); continue; } bool bInLightBound = IsEntityInLightBound(pmEntity,pmSceneEntity); if (!bInLightBound) { continue; } } pmEntity->SetPropertyData(ms_strAffectedEntitiesName, pmSceneEntity, uiIndex++, true); } } } } else if (!MCameraManager::EntityIsCamera(pmEntity)) { if (m_pmLights->Count == 0 && UseDefaultLights) { // If there are no lights in the scene, the default lights should // affect the entity. AddEntityToDefaultLights(pmEntity); } else if (m_bAddEntitiesToLights) { // If lights exist in the scene, add this entity to the affected // entities lists for each light. for (int i = 0; i < m_pmLights->Count; i++) { MEntity* pmLight = dynamic_cast( m_pmLights->Item[i]); MAssert(pmLight != NULL, "Invalid light in array!"); // 如果灯光为preview或character_sun,character_ambient则不添加物件到其列表 if (String::Compare(pmLight->Name,"character_sun") == 0 || String::Compare(pmLight->Name,"preview") == 0 || String::Compare(pmLight->Name,"character_ambient") == 0 ) { continue; } // 判断 pmLight 是否应该影响 pmEntity // 090119 add by 和萌 // 判断灯光类型 String* strType = dynamic_cast(pmLight->GetPropertyData( "Light Type")); if (strType->Equals(NiLightComponent::LT_POINT)) { NiEntityInterface* pkLightInterface = pmLight->GetNiEntityInterface(); float fLightScale = 0.0f; if (!pkLightInterface->GetPropertyData("Scale",fLightScale)) { NiMessageBox("获取周围灯光影响范围失败!","Error",0); continue; } bool bInLightBound = IsEntityInLightBound(pmLight,pmEntity); // 计算灯光与物体的距离,如果大于LIGHTAFFECT_DISTANCE_POINT则不添加如影响列表 if (!bInLightBound) { continue; } } unsigned int uiAffectedEntitiesCount = pmLight ->GetElementCount(ms_strAffectedEntitiesName); unsigned int uiIndex; for (uiIndex = 0; uiIndex < uiAffectedEntitiesCount; uiIndex++) { if (pmLight->GetPropertyData(ms_strAffectedEntitiesName, uiIndex) == NULL) { break; } } pmLight->SetPropertyData(ms_strAffectedEntitiesName, pmEntity, uiIndex, true); } } } #ifdef _DEBUG MTimeStamp::Instance->AddTimeStamp(new String("Quit MLightManager::ProcessAddedEntity")); #endif } //--------------------------------------------------------------------------- void MLightManager::OptimizeAffectedLights(MEntity* pmEntity) { // 修改灯光优化方法 [3/29/2010 hemeng] if (MLightManager::EntityIsLight(pmEntity) || MCameraManager::EntityIsCamera(pmEntity)) { return; } static NiFixedString szTranslationName("Translation"); static NiFixedString szLightTypeName("Light Type"); static NiFixedString szAffectedEntitiesName("Affected Entities"); static NiFixedString szSceneRootName("Scene Root Pointer"); // 从所有灯光列表中清除当前物件 ArrayList* arrAffectLights = GetAffectLights(pmEntity); map mapLightInfo; for (int iIndex = 0; iIndex < arrAffectLights->Count; iIndex++) { MEntity* pmLight = dynamic_cast(arrAffectLights->Item[iIndex]); if (pmLight == NULL) { continue; } String* strType = dynamic_cast(pmLight->GetPropertyData( szLightTypeName)); if (!strType->Equals(NiLightComponent::LT_POINT)) { continue; } else { NiAVObject* pkLightRoot = pmLight->GetSceneRootPointer(0); NiObject* pkAVObj = NULL; if (!pmEntity->GetNiEntityInterface()->GetPropertyData("Scene Root Pointer", pkAVObj, 0)) { // 没有 scene root continue; } NiBound kBound = pmEntity->GetSceneRootPointer(0)->GetWorldBound(); NiPoint3 kLightPos = pkLightRoot->GetTranslate(); float fDistanceToBound = (kLightPos - kBound.GetCenter()).Length(); mapLightInfo.insert(pair(iIndex, fDistanceToBound)); } } if (mapLightInfo.size() <= 3) { return; } while (mapLightInfo.size() > 3) { size_t iIdex = 0; float fDist = 0; map::iterator mapIt = mapLightInfo.begin(); for (; mapIt != mapLightInfo.end(); mapIt ++) { if (mapIt->second > fDist) { iIdex = mapIt->first; fDist = mapIt->second; } } mapIt = mapLightInfo.find(iIdex); mapLightInfo.erase(mapIt); } for (int iIndex = 0; iIndex < arrAffectLights->Count; iIndex++) { MEntity* pmLight = dynamic_cast(arrAffectLights->Item[iIndex]); if (pmLight == NULL) { continue; } String* strType = dynamic_cast(pmLight->GetPropertyData( szLightTypeName)); if (!strType->Equals(NiLightComponent::LT_POINT)) { continue; } else { map::iterator mapIt = mapLightInfo.find(iIndex); if (mapIt == mapLightInfo.end()) { SetAffect(pmLight->Name, pmEntity, false); } } } arrAffectLights->Clear(); arrAffectLights = NULL; } //--------------------------------------------------------------------------- ArrayList* MLightManager::GetAffectLights(MEntity* pmEntity) { if (MLightManager::EntityIsLight(pmEntity) || MCameraManager::EntityIsCamera(pmEntity)) { return NULL; } // 所有影响 pmEntity 的灯光列表 ArrayList* pmAffectLights = new ArrayList(); // 遍历所有灯光 for (int i = 0; i < m_pmLights->Count; i++) { MEntity* pmLight = dynamic_cast( m_pmLights->Item[i]); MAssert(pmLight != NULL, "Invalid light in array!"); // 遍历该灯光影响的所有物件 unsigned int uiAffectedEntitiesCount = pmLight ->GetElementCount(ms_strAffectedEntitiesName); unsigned int uiIndex; for (uiIndex = 0; uiIndex < uiAffectedEntitiesCount; uiIndex++) { if (pmLight->GetPropertyData(ms_strAffectedEntitiesName, uiIndex) == pmEntity) { pmAffectLights->Add(pmLight); break; } } } return pmAffectLights; }; // 设置某灯光对某物件的影响关系 void MLightManager::SetAffect(String* strLight, MEntity* pmEntity, bool bAffect) { // 根据名称获取灯光 for (int i = 0; i < m_pmLights->Count; i++) { MEntity* pmLight = dynamic_cast( m_pmLights->Item[i]); MAssert(pmLight != NULL, "Invalid light in array!"); // 找到该灯光了 if (pmLight->Name->Equals(strLight)) { if (bAffect) // 添加到影响列表 { // 遍历该灯光影响的所有物件,如果与 unsigned int uiAffectedEntitiesCount = pmLight ->GetElementCount(ms_strAffectedEntitiesName); unsigned int uiIndex; for (uiIndex = 0; uiIndex < uiAffectedEntitiesCount; uiIndex++) { if (pmLight->GetPropertyData(ms_strAffectedEntitiesName, uiIndex) == pmEntity) // 已经在影响列表了 { return; } else if (pmLight->GetPropertyData(ms_strAffectedEntitiesName, uiIndex) == NULL) // { break; } } pmLight->SetPropertyData(ms_strAffectedEntitiesName, pmEntity, uiIndex, true); } else // 从影响列表中删除 { unsigned int uiAffectedEntitiesCount = pmLight ->GetElementCount(ms_strAffectedEntitiesName); unsigned int uiIndex; for (uiIndex = 0; uiIndex < uiAffectedEntitiesCount; uiIndex++) { if (pmLight->GetPropertyData(ms_strAffectedEntitiesName, uiIndex) == pmEntity) // 已经在影响列表了 { pmLight->SetPropertyData(ms_strAffectedEntitiesName, NULL, uiIndex, false); break; } } } pmEntity->Update(MTimeManager::Instance->CurrentTime, MFramework::Instance->ExternalAssetManager); pmLight->Update(MTimeManager::Instance->CurrentTime, MFramework::Instance->ExternalAssetManager); } } } //--------------------------------------------------------------------------- void MLightManager::ProcessRemovedEntity(MScene* pmScene, MEntity* pmEntity) { MVerifyValidInstance; if (EntityIsLight(pmEntity)) { // Remove from light array. m_pmLights->Remove(pmEntity); MAssert(pmEntity->HasProperty(ms_strAffectedEntitiesName), "Light does not have affected entities property!"); // Remove all affected entities for the light. for (unsigned int ui = 0; ui < pmEntity->GetElementCount( ms_strAffectedEntitiesName); ui++) { pmEntity->SetPropertyData(ms_strAffectedEntitiesName, NULL, ui, true); } // Disable the shadow generator, if there is one. if (pmEntity->HasProperty(ms_strCastShadowsName)) { pmEntity->SetPropertyData(ms_strCastShadowsName, __box(false), true); } if (m_pmLights->Count == 0 && UseDefaultLights) { // If this light was the last light in the scene, make all scene // entities get affected by the default lights. AddEntitiesToDefaultLights(pmScene->GetEntities()); } } else if (!MCameraManager::EntityIsCamera(pmEntity)) { if (m_pmLights->Count == 0 && UseDefaultLights) { // If there are no lights in the scene, remove the entity from the // default lights' affected entities lists. RemoveEntityFromDefaultLights(pmEntity); } else { // 将该 entity 从所有灯光列表中去除 // 该部分放到保存场景时候做 //for (int i = 0; i < m_pmLights->Count; i++) //{ // MEntity* pmLight = dynamic_cast(m_pmLights->Item[i]); // if (pmLight->GetPropertyData() // { // NiAVObject* pkSceneRoot = pmLight->GetSceneRootPointer(0); // if (pkSceneRoot != NULL && NiIsKindOf(NiLight, pkSceneRoot)) // { // NiLightPtr pkLight = NiDynamicCast(NiLight, pkSceneRoot); // return pkLight; // } // } //} } } // Update removed entity to ensure that affected nodes are updated. pmEntity->Update(MTimeManager::Instance->CurrentTime, MFramework::Instance->ExternalAssetManager); } //--------------------------------------------------------------------------- ISettingsService* MLightManager::get_SettingsService() { if (ms_pmSettingsService == NULL) { ms_pmSettingsService = MGetService(ISettingsService); MAssert(ms_pmSettingsService != NULL, "Settings service not found!"); } return ms_pmSettingsService; } //--------------------------------------------------------------------------- IOptionsService* MLightManager::get_OptionsService() { if (ms_pmOptionsService == NULL) { ms_pmOptionsService = MGetService(IOptionsService); MAssert(ms_pmOptionsService != NULL, "Options service not found!"); } return ms_pmOptionsService; } //--------------------------------------------------------------------------- NiLightPtr MLightManager::GetNiLight(String* strLightName) { for (int i = 0; i < m_pmLights->Count; i++) { MEntity* pmLight = dynamic_cast(m_pmLights->Item[i]); if (pmLight->Name->CompareTo(strLightName) == 0) { NiAVObject* pkSceneRoot = pmLight->GetSceneRootPointer(0); if (pkSceneRoot != NULL && NiIsKindOf(NiLight, pkSceneRoot)) { NiLightPtr pkLight = NiDynamicCast(NiLight, pkSceneRoot); return pkLight; } } } return NULL; } NiEntityInterface* MLightManager::GetLightEntity(String* strLightName) { for (int i = 0; i < m_pmLights->Count; i++) { MEntity* pmLight = dynamic_cast(m_pmLights->Item[i]); if (pmLight->Name->CompareTo(strLightName) == 0) { return pmLight->GetNiEntityInterface(); } } return NULL; } MEntity* MLightManager::GetLight(String* strLightName) { for (int i = 0; i < m_pmLights->Count; i++) { MEntity* pmLight = dynamic_cast(m_pmLights->Item[i]); if (pmLight->Name->CompareTo(strLightName) == 0) { return pmLight; } } return NULL; } //-------------------------------------------------------------------------------------------- bool MLightManager::IsEntityInLightBound(MEntity* pmLight,MEntity* pmEntity) { if (NULL == pmEntity || NULL == pmLight) { return false; } if (EntityIsLight(pmLight) == false || EntityIsLight(pmEntity) == true) { return false; } float fScale; pmLight->GetNiEntityInterface()->GetPropertyData("Scale",fScale); float fDistanceToBound = 0; NiAVObject* pkLightRoot = pmLight->GetSceneRootPointer(0); NiObject* pkAVObj = NULL; if (!pmEntity->GetNiEntityInterface()->GetPropertyData("Scene Root Pointer", pkAVObj, 0)) { // 没有 scene root return false; } NiBound kBound = pmEntity->GetSceneRootPointer(0)->GetWorldBound(); NiPoint3 kLightPos = pkLightRoot->GetTranslate(); fDistanceToBound = (kLightPos - kBound.GetCenter()).Length(); if (fDistanceToBound > ( kBound.GetRadius() + fScale) ) { return false; } /*fDistanceToBound = (fDistanceToBound > 0) ? fDistanceToBound : 0.0f;*/ else { return true; } } //------------------------------------------------------------------------------- void MLightManager::UpdateLightAffectBound(MEntity* pmEntity,NiFixedString strPropertyName) { if (NULL == pmEntity || strPropertyName == "") { return ; } if (EntityIsLight(pmEntity) == true) { _UpdateLightParam(pmEntity,strPropertyName); } else { _UpdateEntityAffectLight(pmEntity,strPropertyName); } } //---------------------------------------------------------------------------------------------- // 090309 add by 和萌 // 更新灯光参数 void MLightManager::_UpdateLightParam(MEntity* pmLight,NiFixedString strPropertyName) { if (EntityIsLight(pmLight) == false) { return ; } //针对移动、缩放和调整attenuation NiFixedString szTranslationName("Translation"); NiFixedString szAttenuationLinearName("Attenuation (Linear)"); NiFixedString szAttenuationQuadraticName("Attenuation (Quadratic)"); NiFixedString szAttenuationConstantName("Attenuation (Constant)"); NiFixedString szLightTypeName("Light Type"); // 仅针对点光源 String* strType = dynamic_cast(pmLight->GetPropertyData(szLightTypeName)); if (!strType->Equals(NiLightComponent::LT_POINT)) { return; } if (strPropertyName == "Scale") { if( _ModifyScale(pmLight,strPropertyName) < 0) { return; } } else if (strPropertyName == szAttenuationLinearName || strPropertyName == szAttenuationQuadraticName) { if( _ModifyAtten(pmLight,strPropertyName) < 0) { return ; } } else if (strPropertyName == szTranslationName) { } else { return; } // 灯光位置 NiPoint3 kTranslate; if (!pmLight->GetNiEntityInterface()->GetPropertyData(szTranslationName,kTranslate) ) { return; } // 记录周边9个chunk vector chunkList; for (int i=-1; i<=1; i++) { for (int j=-1; j<=1; j++) { NiPoint3 kPos = kTranslate + NiPoint3((float)i*GRIDINCHUNK, (float)j*GRIDINCHUNK, 0); int iChunkID = MFramework::Instance->Scene->Terrain->GetChunkIndex(kPos); if (iChunkID != -1) { chunkList.push_back(iChunkID); } } } // update light translation // Remove all affected entities for the light. MAssert(pmLight->HasProperty(ms_strAffectedEntitiesName), "Light does not have affected entities property!"); unsigned int uiAffectedEntitiesCount = pmLight->GetElementCount( ms_strAffectedEntitiesName); for (unsigned int ui = 0; ui < uiAffectedEntitiesCount; ui++) { pmLight->SetPropertyData(ms_strAffectedEntitiesName, NULL, ui, true); } MEntity* amChunksEntities[] = MChunkEntityManager::Instance->GetEntity(&chunkList); for (int i = 0; i < amChunksEntities->Length; i++) { MEntity* pmChunkEntity = amChunksEntities[i]; if (pmChunkEntity == NULL) { continue; } if (!EntityIsLight(pmChunkEntity) && !MCameraManager::EntityIsCamera(pmChunkEntity)) { bool bInLightBound = IsEntityInLightBound(pmLight,pmChunkEntity); if (!bInLightBound) { continue; } unsigned int uiCount = pmLight->GetElementCount(ms_strAffectedEntitiesName); unsigned int uiIndex; for (uiIndex = 0; uiIndex < uiCount; uiIndex++) { if (pmLight->GetPropertyData(ms_strAffectedEntitiesName, uiIndex) == NULL) { break; } } pmLight->SetPropertyData(ms_strAffectedEntitiesName, pmChunkEntity, uiIndex++, true); } } } //---------------------------------------------------------------------------------------------- float MLightManager::_ModifyScale(MEntity* pmLight,NiFixedString strPropertyName) { // 更新scale或dimmer需要重新计算衰减值 NiFixedString szScaleName("Scale"); NiFixedString szAttenuationLinearName("Attenuation (Linear)"); NiFixedString szAttenuationQuadraticName("Attenuation (Quadratic)"); NiFixedString szAttenuationConstantName("Attenuation (Constant)"); // 灯光影响范围 float fScale; float fDimmer = 1.0f; float fAtten = 0; // fFinalIntensity = fDimmer / (fConst + fLinear * fScal + fQuadratic * fScale * fScale) if (!pmLight->GetNiEntityInterface()->GetPropertyData(szScaleName,fScale)) { return -2; } /*if (!pmLight->GetNiEntityInterface()->GetPropertyData(szDimmerName,fDimmer)) { return -2; }*/ if (pmLight->Name->Contains("linear")) { fAtten = INVERSE_FINAL_INTENSITY * fDimmer / fScale; if (!pmLight->GetNiEntityInterface()->SetPropertyData(szAttenuationLinearName,fAtten)) { return -2; } } else if (pmLight->Name->Contains("quadratic")) { fAtten = INVERSE_FINAL_INTENSITY * fDimmer / (fScale * fScale); if (!pmLight->GetNiEntityInterface()->SetPropertyData(szAttenuationQuadraticName,fAtten)) { return -2; } } return fScale; } //---------------------------------------------------------------------------------------------- float MLightManager::_ModifyAtten(MEntity* pmLight,NiFixedString strPropertyName) { // 更新衰减值,需要重新计算scale NiFixedString szScaleName("Scale"); NiFixedString szAttenuationLinearName("Attenuation (Linear)"); NiFixedString szAttenuationQuadraticName("Attenuation (Quadratic)"); NiFixedString szAttenuationConstantName("Attenuation (Constant)"); /*NiFixedString szDimmerName("Dimmer");*/ float fScale = 0; float fDimmer = 1.0f; float fAtten; // 这里假设fFinalIntensity = 0.1f; // fFinalIntensity = fDimmer / (fConst + fLinear * fScal + fQuadratic * fScale * fScale) /*if (!pmLight->GetNiEntityInterface()->GetPropertyData(szDimmerName,fDimmer)) { return -2; }*/ if (pmLight->Name->Contains("linear")) { if (!pmLight->GetNiEntityInterface()->GetPropertyData(szAttenuationLinearName,fAtten)) { return -2; } if (fAtten < 0) { NiMessageBox("Attenuation should be larger than zero!","Error",0); return -2; } fScale = INVERSE_FINAL_INTENSITY * fDimmer / fAtten; } else if (pmLight->Name->Contains("quadratic")) { if (!pmLight->GetNiEntityInterface()->GetPropertyData(szAttenuationQuadraticName,fAtten)) { return -2; } if (fAtten < 0) { NiMessageBox("Attenuation should be larger than zero!","Error",0); return -2; } fScale = sqrt( INVERSE_FINAL_INTENSITY * fDimmer / fAtten); } // update properties if (!pmLight->GetNiEntityInterface()->SetPropertyData(szScaleName,fScale)) { return -2; } if (!pmLight->GetNiEntityInterface()->SetPropertyData(szAttenuationConstantName,0.0f)) { return -2; } if (!pmLight->GetNiEntityInterface()->SetPropertyData(szAttenuationQuadraticName,0.0f)) { return -2; } return fScale; } //---------------------------------------------------------------------------------------------- // 更新影响物件的灯光,仅用于非灯光 void MLightManager::_UpdateEntityAffectLight(MEntity* pmEntity,NiFixedString strPropertyName) { if (MCameraManager::EntityIsCamera(pmEntity) == true) { return ; } NiFixedString szTranslationName("Translation"); NiFixedString szScaleName("Scale"); NiFixedString szLightTypeName("Light Type"); if (strPropertyName != szTranslationName && strPropertyName != szScaleName ) { return; } NiPoint3 kTranslate; /*float fScale;*/ if (!pmEntity->GetNiEntityInterface()->GetPropertyData(szTranslationName,kTranslate) ) { return; } // 记录周边9个chunk vector chunkList; for (int i=-1; i<=1; i++) { for (int j=-1; j<=1; j++) { NiPoint3 kPos = kTranslate + NiPoint3((float)i*GRIDINCHUNK, (float)j*GRIDINCHUNK, 0); int iChunkID = MFramework::Instance->Scene->Terrain->GetChunkIndex(kPos); if (iChunkID != -1) { chunkList.push_back(iChunkID); } } } // 从所有灯光列表中清除当前物件 ArrayList* arrAffectLights = GetAffectLights(pmEntity); for (int iIndex = 0; iIndex < arrAffectLights->Count; iIndex++) { MEntity* pmLight = dynamic_cast(arrAffectLights->Item[iIndex]); if (pmLight == NULL) { continue; } String* strType = dynamic_cast(pmLight->GetPropertyData( szLightTypeName)); if (!strType->Equals(NiLightComponent::LT_POINT)) { continue; } SetAffect(pmLight->Name,pmEntity,false); // 灯光影响列表改变后,调用地形的更新灯光函数。将地形节点添加到影响列表中 } arrAffectLights->Clear(); arrAffectLights = NULL; // 遍历所有灯光,重新添加物件到可影响灯光 MEntity* amLights[] = GetSceneLights(); for (int i = 0; i < amLights->Length; i++) { MEntity* pmLight = amLights[i]; if (pmLight == NULL) { continue; } if (EntityIsLight(pmLight)) { String* strType = dynamic_cast(pmLight->GetPropertyData( szLightTypeName)); if (!strType->Equals(NiLightComponent::LT_POINT)) { continue; } bool bInLightBound = IsEntityInLightBound(pmLight,pmEntity); if (!bInLightBound) { continue; } unsigned int uiCount = pmLight->GetElementCount(ms_strAffectedEntitiesName); unsigned int uiIndex; for (uiIndex = 0; uiIndex < uiCount; uiIndex++) { if (pmLight->GetPropertyData(ms_strAffectedEntitiesName,uiIndex) == NULL) { break; } } pmLight->SetPropertyData(ms_strAffectedEntitiesName, pmEntity, uiIndex++, true); } } }