#include "StdAfx.h" #include "LightManager.h" #include "Player.h" #include "ObjectManager.h" #include "Map/Chunk.h" #define TERRAIN_LIGHT_SIGN 'LGHT' #define TERRAIN_LIGHT_VERSION 1 bool CTerrainLight::Load(NiFile* pkFile) { pkFile->Read(&m_kPosition, sizeof(NiPoint3)); pkFile->Read(&m_fInnerRadius, sizeof(float)); pkFile->Read(&m_fOuterRadius, sizeof(float)); NiBool bGlobal; pkFile->Read(&bGlobal, sizeof(NiBool)); m_bGlobal = NIBOOL_IS_TRUE(bGlobal); CLightManager* pkLightManager = CLightManager::Get(); if(pkLightManager->GetVersion() < MakeVersion(1, 0)) { unsigned int uiNumLightColor = 4; pkFile->Read(m_akColors, sizeof(CDayNightColor)*uiNumLightColor); m_akColors[FOG_COLOR] = m_akColors[AMBIENT_COLOR]; } else pkFile->Read(m_akColors, sizeof(m_akColors)); unsigned int uiNameLen; pkFile->Read(&uiNameLen, sizeof(unsigned int)); NIASSERT(uiNameLen < 1024); if( uiNameLen > 0 ) { char acString[1024]; pkFile->Read(acString, uiNameLen); acString[uiNameLen] = '\0'; } return true; } NiColor CTerrainLight::GetColor(unsigned int uiColor, unsigned int uiHour, unsigned int uiMinute) const { NIASSERT( uiColor < NUM_LIGHT_COLOR ); return m_akColors[uiColor].GetColor(uiHour, uiMinute); } CLightManager* CLightManager::ms_This = NULL; CLightManager::CLightManager() { NIASSERT( ms_This == NULL ); ms_This = this; m_DirLight = NiNew NiDirectionalLight; NiMatrix3 kMat; kMat.MakeIdentity(); NiPoint3 kDir = LIGHT_DIR; kDir.Unitize(); kMat.SetCol(0, kDir); m_DirLight->SetRotate(kMat); m_DirLight->Update(0.f); ResetColors(); } CLightManager::~CLightManager() { Unload(); ms_This = NULL; } void CLightManager::CalcLightWeights(const NiPoint3& pos) { NIASSERT(m_akLightList.GetSize() > 0); int iMaxLight = int(m_akLightList.GetSize()) - 1; m_akLightList.GetAt(iMaxLight)->SetWeight(1.f); CTerrainLight* pkLight; for(int i = iMaxLight - 1; i >= 0; i--) { pkLight = m_akLightList.GetAt(i); NiPoint3 kDiff = pos - pkLight->GetPosition(); float fDist = kDiff.Length(); if( fDist <= pkLight->GetInnerRadius() ) { // we're in a sky, zero out the rest pkLight->SetWeight(1.f); for(int j = i + 1; j < (int)m_akLightList.GetSize(); j++) m_akLightList.GetAt(j)->SetWeight(0.f); } else if(fDist < pkLight->GetOuterRadius()) { // we're in an outer area, scale down the other weights float r = (fDist - pkLight->GetInnerRadius())/(pkLight->GetOuterRadius() - pkLight->GetInnerRadius()); pkLight->SetWeight(1.0f - r); for(int j = i + 1; j < (int)m_akLightList.GetSize(); j++) m_akLightList.GetAt(j)->SetWeight(m_akLightList.GetAt(j)->GetWeight() * r); } else { pkLight->SetWeight(0.f); } } } void CLightManager::Update(float dt) { if(m_akLightList.GetSize() == 0) return; CPlayer* pkPlayer = ObjectMgr->GetLocalPlayer(); if( pkPlayer == NULL ) return; CalcLightWeights(pkPlayer->GetPosition()); SYSTEMTIME st; GetLocalTime(&st); unsigned int uiHour = st.wHour; unsigned int uiMinute = st.wMinute; //白天黑夜循环是6小时 //其中白天占5个小时, 黑夜占1个小时 uiHour %= 6; if(uiHour >= 1) { //白天 //每25分钟相当于1小时 unsigned int uiTotalMinute = (uiHour - 1)*60 + uiMinute; uiHour = 6 + uiTotalMinute / 25; uiMinute = int( float(uiTotalMinute % 25) * (60.f/25.f) ); } else { //黑夜 //每5分钟相当于1小时 uiHour = 18 + uiMinute / 5; uiMinute = (uiMinute % 5) * 12 + 6; } if(uiHour >= 24) uiHour -= 24; if(uiMinute >= 60) uiMinute -= 60; // //测试用, 快速走完一天 // //{ // static float s_fHour = 12.f; // static float s_fMinute = 0.f; // s_fMinute += 0.5f; // if( s_fMinute >= 60.f ) // { // s_fMinute = 0.f; // s_fHour += 1.f; // if( s_fHour >= 24.f ) // s_fHour = 0.f; // } // uiHour = (unsigned int)s_fHour; // uiMinute = (unsigned int)s_fMinute; //} memset(&m_akColors, 0, sizeof(m_akColors)); for( unsigned int i = 0; i < m_akLightList.GetSize(); i++ ) { if( m_akLightList.GetAt(i)->GetWeight() > 0.f ) { // now calculate the color rows for( int j = 0; j < NUM_LIGHT_COLOR; j++ ) { m_akColors[j] += m_akLightList.GetAt(i)->GetColor(j, uiHour, uiMinute) * m_akLightList.GetAt(i)->GetWeight(); m_akColors[j].Clamp(); } } } m_DirLight->SetAmbientColor(GetAmbientColor()); m_DirLight->SetDiffuseColor(GetDiffuseColor()); } void CLightManager::ApplyDirLight(NiNode* pkObject) { // m_DirLight->AttachAffectedNode(pkObject); } void CLightManager::DetachDirLight(NiNode* pkObject) { m_DirLight->DetachAffectedNode(pkObject); } bool CLightManager::Load(const NiFixedString& kMapName) { Unload(); char acFilename[NI_MAX_PATH]; NiSprintf(acFilename, NI_MAX_PATH, "Data\\World\\Maps\\%s\\%s.lit", (const char*)kMapName, (const char*)kMapName); NiFile* pkFile = NiFile::GetFile(acFilename, NiFile::READ_ONLY); if( !pkFile || !(*pkFile) ) { NiDelete pkFile; return false; } int iSign; pkFile->Read(&iSign, sizeof(int)); pkFile->Read(&m_uiVersion, sizeof(unsigned int)); NIASSERT(iSign == TERRAIN_LIGHT_SIGN); unsigned int uiSize; pkFile->Read(&uiSize, sizeof(unsigned int)); m_akLightList.SetSize( uiSize ); CTerrainLight* pkLight; for( unsigned int i = 0; i < uiSize; i++ ) { pkLight = NiNew CTerrainLight(); pkLight->Load( pkFile ); m_akLightList.SetAt(i, pkLight); } NiDelete pkFile; return true; } void CLightManager::Unload() { for( unsigned int ui = 0; ui < m_akLightList.GetSize(); ui++ ) { NiDelete m_akLightList.GetAt(ui); } m_akLightList.SetSize(0); ResetColors(); } void CLightManager::ResetColors() { m_DirLight->SetAmbientColor(NiColor::WHITE); m_DirLight->SetDiffuseColor(NiColor::WHITE); m_DirLight->SetSpecularColor(NiColor::WHITE); for( int i = 0; i < NUM_LIGHT_COLOR; i++ ) { m_akColors[i] = DEFAULT_COLOR; } }