#include "stdafx.h" #include "KRenderDeviceDX.h" #include "SEnvPrimitive.h" #include "K3DTypes.h" #include "KSeqModel.h" #include "K3DCamera.h" #include "KResourceManager.h" #include "KRenderObjectEtc.h" #include #include #include "TerrainPrimitive.h" #include "SDebug_Util.h" #include "SGameWorld.h" #include "SCommandSystem.h" #include #include "SGameSky.h" #include "SGameWeather.h" #include "SGameWeatherService.h" #include "LuaVM.h" #include #include "SGameMilesSoundMgr.h" #include "SGameAvatarEx.h" #include "SMessage.h" #include "SGameMessage.h" namespace env_fx { class CParticleCollisionStrategy : public env_fx::ICollisionStrategy { public: CParticleCollisionStrategy( SGame* pGame ) : m_pGame( pGame ) { assert( pGame && "Collision strategy must have a game instance" ); } virtual ~CParticleCollisionStrategy() { m_pGame = 0; } bool GetCollidePosition( float* out, float x, float y, float z ) { float fTerrainHeight; WORD wTile; bool bFound = m_pGame->GetHeight( x, y, fTerrainHeight, wTile ); if( bFound ) { out[ 0 ] = x; out[ 1 ] = y; out[ 2 ] = fTerrainHeight; } else { out[ 0 ] = x; out[ 1 ] = y; out[ 2 ] = -FLT_MAX; } return bFound; } bool GetCollideNormal( float* out_x, float* out_y, float* out_z, float x, float y, float z ) { K3DVector _out( 0, 0, 0 ); K3DVector _1, _2, _3; m_pGame->GetTerrainTriangle( x, y, _1, _2, _3 ); K3DVectorCross( _out, _3 - _1, _2 - _1 ); *out_x = _out.x; *out_y = _out.y; *out_z = _out.z; return true; } private: SGame* m_pGame; }; } SGameWeatherService::SGameWeatherService( SGame* pGame, SCommandSystem* pCommandSystem, SGameSky* pSky, SGameMilesSoundMgr* pSound, float fPrecipitationFactor ) : m_pGame ( pGame ) , m_pCommandSystem ( pCommandSystem ) , m_pSkyCtx ( pSky ) , m_pSoundMgr ( pSound ) , m_pCurrentState ( 0 ) , m_dwTime ( 0 ) , m_pRenderDevice ( 0 ) , m_pInfo ( 0 ) , m_pCollisionStrategy ( 0 ) , m_vCameraPosition ( 0, 0, 0 ) , m_vTargetPosition ( 0, 0, 0 ) , m_bActivity ( true ) , m_fQualityFactor ( 1.0f ) , m_fPrecipitationFactor( fPrecipitationFactor ) , m_bInDoor ( false ) { assert( m_pGame && m_pSkyCtx && m_pSoundMgr && "there is null context in weather service" ); m_pCollisionStrategy = new env_fx::CParticleCollisionStrategy( pGame ); K3DMatrixIdentity( m_mView ); } SGameWeatherService::~SGameWeatherService() { env_fx::util::wipe_seq( m_ctWeathers ); SAFE_DELETE( m_pInfo ); SAFE_DELETE( m_pCollisionStrategy ); } void SGameWeatherService::Init( K3DRenderDeviceDX* pDevice, K3DIndexBuffer* pIndexBuf ) { m_pRenderDevice = pDevice; } void SGameWeatherService::Process( DWORD dwTime ) { if( this->IsActive() ) { m_dwTime = dwTime; for( WeatherStateVector::iterator it = m_ctWeathers.begin(); it != m_ctWeathers.end(); ) { IGameWeatherState* pState = *it; if( pState ) { pState->Process( m_dwTime ); } if( !pState || pState->IsGarbage() ) { // garbages... if( m_pCurrentState == pState ) m_pCurrentState = 0; it = m_ctWeathers.erase( it ); SAFE_DELETE( pState ); } else { ++it; } } } } void SGameWeatherService::Render( KViewportObject* pViewport ) { if( this->IsActive() ) { WeatherStateVector::iterator it = m_ctWeathers.begin(), itend = m_ctWeathers.end(); for( ; it != itend; ++it ) { IGameWeatherState* pState = *it; if( pState ) pState->Render( pViewport ); } } } int SGameWeatherService::GetState() const { if( m_pCurrentState ) return m_pCurrentState->GetState(); return IGameWeatherState::WS_NONE; } void SGameWeatherService::SetPosition( const K3DVector& vCameraPos, const K3DVector& vTargetPos ) { m_vCameraPosition = vCameraPos; m_vTargetPosition = vTargetPos; } void SGameWeatherService::SetViewMatrix( const K3DMatrix& mView ) { m_mView = mView; } DWORD SGameWeatherService::GetFadingTime() const { return IsFading() ? m_dwTime : 0; } void SGameWeatherService::ChangeInOut( bool bInDoor ) { m_bInDoor = bInDoor; } void SGameWeatherService::ChangeState( int nThemeID, float fPrecipitationFactor, float fQualityFactor, bool bFader ) { if( nThemeID < IGameWeatherState::WS_FINE || nThemeID >= IGameWeatherState::WS_NONE ) return; if( m_pCurrentState && m_pCurrentState->GetState() == nThemeID && m_fPrecipitationFactor == fPrecipitationFactor && m_fQualityFactor == fQualityFactor ) return; m_bFader = bFader; m_fPrecipitationFactor = fPrecipitationFactor; m_fQualityFactor = fQualityFactor; // LOAD SCRIPT RESOURCE std::string script_name = KFileManager::Instance().CreateTemporaryFileFromResource( "weather_script.lua" ); if( script_name.length() > 0 ) { LUA()->LoadScript( script_name.c_str() ); KFileManager::Instance().DeleteTemporaryFile( "weather_script.lua" ); } std::string function_call; XStringUtil::Format( function_call, "change_weather_theme( %d )", nThemeID ); LUA()->RunString( function_call.c_str() ); #ifdef DISTANCE_VIEW // LOAD SCRIPT RESOURCE script_name = KFileManager::Instance().CreateTemporaryFileFromResource( "skybox_script2.lua" ); // script_name = KFileManager::Instance().CreateTemporaryFileFromResource( "skybox_script.lua" ); if( script_name.length() > 0 ) { LUA()->LoadScript( script_name.c_str() ); // KFileManager::Instance().DeleteTemporaryFile( "skybox_script.lua" ); KFileManager::Instance().DeleteTemporaryFile( "skybox_script2.lua" ); } XStringUtil::Format( function_call, "change_skybox_theme_sky( %d )", nThemeID ); LUA()->RunString( function_call.c_str() ); //script_name = KFileManager::Instance().CreateTemporaryFileFromResource( "skybox_script.lua" ); //if( script_name.length() > 0 ) //{ // LUA()->LoadScript( script_name.c_str() ); // KFileManager::Instance().DeleteTemporaryFile( "skybox_script.lua" ); //} //XStringUtil::Format( function_call, "change_skybox_theme( %d )", nThemeID ); //LUA()->RunString( function_call.c_str() ); #endif #ifdef CLOUD_LUA int k=0; // 지역아이디에 따라 날씨를 바꿔준다 int l=0; #endif } //void SGameWeatherService::ChangeCapacityFactor( float fCapacityFactor ) //{ // m_fCapacityFactor = fCapacityFactor; // if( m_pCurrentState ) // ChangeState( m_pCurrentState->GetState(), GetPrecipitationFactor(), true ); //} void SGameWeatherService::ChangeQuality( float fQualityFactor ) { if( m_pCurrentState ) ChangeState( m_pCurrentState->GetState(), m_fPrecipitationFactor, fQualityFactor, true ); } void SGameWeatherService::SetTheme( env_fx::SWeatherInfo* pInfo ) { if( !pInfo ) return; if( m_pCurrentState ) m_pCurrentState->OnLeave(); if( pInfo->m_nThemeID < 0 && pInfo->m_nThemeID >= IGameWeatherState::WS_NONE ) return; SAFE_DELETE( m_pInfo ); m_pInfo = pInfo; m_pCurrentState = _AppendWeatherState( static_cast< IGameWeatherState::EState >( pInfo->m_nThemeID ) ); if( m_pCurrentState ) m_pCurrentState->OnEnter(); } IGameWeatherState* SGameWeatherService::_AppendWeatherState( IGameWeatherState::EState nState ) { IGameWeatherState* pNewState = 0; switch( nState ) { case IGameWeatherState::WS_FINE: pNewState = new SGameFineState( this ); break; case IGameWeatherState::WS_CLOUDY: pNewState = new SGameCloudyState( this ); break; case IGameWeatherState::WS_FOGGY: pNewState = new SGameFoggyState( this ); break; case IGameWeatherState::WS_RAINY: pNewState = new SGameRainyState( this ); break; case IGameWeatherState::WS_SNOWY: pNewState = new SGameSnowyState( this ); break; default: break; } if( pNewState ) m_ctWeathers.push_back( pNewState ); return pNewState; } void SGameWeatherService::ActivateThunder( bool bActivity ) { m_pSkyCtx->SetThunderEnable( bActivity ); if( bActivity ) { std::string function_call; XStringUtil::Format( function_call, "get_thunder_attribute()" ); LUA()->RunString( function_call.c_str() ); } } void SGameWeatherService::ActivateLightning( bool bActivity ) { m_pSkyCtx->SetLightningEnable( bActivity ); if( bActivity ) { std::string function_call; XStringUtil::Format( function_call, "get_lightning_attribute()" ); LUA()->RunString( function_call.c_str() ); } } // =================================================================== // SGameFineState // =================================================================== void SGameFineState::OnEnter() { } void SGameFineState::OnLeave() { m_bIsGarbage = true; } // =================================================================== // SGameCloudyState // =================================================================== void SGameCloudyState::OnEnter() { } void SGameCloudyState::OnLeave() { m_bIsGarbage = true; } // =================================================================== // SGameFoggyState // =================================================================== void SGameFoggyState::OnEnter() { } void SGameFoggyState::OnLeave() { m_bIsGarbage = true; } // =================================================================== // SGameRainyState // =================================================================== void SGameRainyState::Process( DWORD dwTime ) { if( !m_pService->IsInDoor() && m_pEmitter ) { if( m_pEmitter->isActive() ) { if( m_pService->m_pCommandSystem ) { SGameAvatarEx* localAvatar = m_pService->m_pCommandSystem->GetLocalPlayer(); if( localAvatar && localAvatar->GetArClient() ) { ArMoveVector& move = localAvatar->GetArClient()->GetMyPos(); float speed = (float)localAvatar->getMovingSpeed(); static K3DVector prevPosition = m_pService->m_vTargetPosition; K3DVector moveDirection( m_pService->m_vTargetPosition.x - prevPosition.x, m_pService->m_vTargetPosition.y - prevPosition.y, 0.0f ); K3DVectorNormalize( moveDirection, moveDirection ); mVestige = moveDirection * ( speed / m_pEmitter->getAttribute().particle_velocity ); prevPosition = m_pService->m_vTargetPosition; } } m_pEmitter->locate( m_pService->m_vTargetPosition, m_pService->m_vTargetPosition ); m_pEmitter->process( dwTime ); if( m_pAdditiveEmitter && m_pAdditiveEmitter->isActive() ) { m_pAdditiveEmitter->locate( m_pService->m_vTargetPosition, m_pService->m_vTargetPosition ); m_pAdditiveEmitter->process( dwTime ); } } else { SAFE_DELETE( m_pEmitter ); SAFE_DELETE( m_pAdditiveEmitter ); m_bIsGarbage = true; } } } void SGameRainyState::Render( KViewportObject* pViewport ) { if( !m_pService->IsInDoor() ) { if( m_pEmitter && m_pEmitter->isActive() ) m_pEmitter->render( pViewport ); if( m_pAdditiveEmitter && m_pAdditiveEmitter->isActive() ) m_pAdditiveEmitter->render( pViewport ); } } void SGameRainyState::OnEnter() { if( 0 == m_pEmitter ) { if( m_pService->m_pInfo->m_pWeatherAttr ) { env_fx::SWeatherAttr* attribute = m_pService->m_pInfo->m_pWeatherAttr; typedef env_fx::ZAxisBillboardTextureResource< env_fx::K3DVERTEX_WEATHER, env_fx::K3DINDEX_WEATHER > zaxis_billboard_resource_t; typedef env_fx::NX3Resource nx3_resource_t; env_fx::particle_op_unit_t* initor = new env_fx::particle_op_unit_t(); env_fx::particle_op_unit_t* action = new env_fx::particle_op_unit_t(); env_fx::particle_bundle_t* bundle = new env_fx::particle_bundle_t( initor, action ); env_fx::particle_resource_t* resource = 0; if( attribute->resource_type == env_fx::SWeatherAttr::NX3 ) resource = new nx3_resource_t( attribute->resource ); else resource = new zaxis_billboard_resource_t( attribute->resource, m_pService->m_pRenderDevice, mVestige ); initor->append( new env_fx::LifeFixedInitor( attribute->particle_life ) ); initor->append( new env_fx::VelocityFixedInitor( attribute->particle_direction.min * attribute->particle_velocity ) ); initor->append( new env_fx::RotationInitor( attribute->rotation_unit, attribute->rotation_speed ) ); initor->append( new env_fx::PositionFixedDistributionInitor( attribute->area_width, attribute->hori_density, attribute->area_height / 2 ) ); initor->append( new env_fx::VisibilityFixedInitor( 1.0f ) ); initor->append( new env_fx::ColorFixedInitor( K3DColor( 0xc4ffffff ) ) ); initor->append( new env_fx::SizeFixedInitor( attribute->particle_width, attribute->particle_height ) ); action->append( new env_fx::LifeDecreaseAction() ); action->append( new env_fx::VelocityAction() ); action->append( new env_fx::VelocityReactiveAction( m_pService->m_vTargetPosition ) ); //action->append( new env_fx::RotationAction() ); // sonador 1.1.19 파티클 스왑 오류 수정 action->append( new env_fx::PositionSwapAction( attribute->area_width / 2, attribute->area_width / 2 ) ); action->append( new env_fx::VisibilityFadeInOutAction( attribute->destroy_duration ) ); action->append( new env_fx::VisibilityFadeInOutOffsetAdditiveAction( attribute->area_width, attribute->area_width * 0.05f ) ); m_pEmitter = new weather_system_t( bundle, resource ); m_pEmitter->initialize( *attribute, m_pService->GetPrecipitationFactor() ); // additive if( m_pEmitter && attribute->linked_attr ) { SAFE_DELETE( m_pAdditiveEmitter ); attribute = attribute->linked_attr; env_fx::particle_op_unit_t* initor = new env_fx::particle_op_unit_t(); env_fx::particle_op_unit_t* action = new env_fx::particle_op_unit_t(); env_fx::particle_bundle_t* bundle = new env_fx::particle_bundle_t( initor, action ); env_fx::particle_resource_t* resource = 0; if( attribute->resource_type == env_fx::SWeatherAttr::NX3 ) resource = new nx3_resource_t( attribute->resource ); else resource = new zaxis_billboard_resource_t( attribute->resource, m_pService->m_pRenderDevice, mVestige ); initor->append( new env_fx::LifeFixedInitor( attribute->particle_life ) ); initor->append( new env_fx::PositionNormalFixedDistributionOnTerrainInitor( m_pService->m_pCollisionStrategy, attribute->area_width, attribute->hori_density, m_pService->m_vTargetPosition ) ); initor->append( new env_fx::VisibilityFixedInitor( 1.0f ) ); initor->append( new env_fx::ColorFixedInitor( K3DColor( 0xffffffff ) ) ); action->append( new env_fx::LifeDecreaseAction() ); action->append( new env_fx::VelocityReactiveAction( m_pService->m_vTargetPosition ) ); action->append( new env_fx::VisibilityFadeInOutOffsetAdditiveAction( attribute->area_width, attribute->area_width * 0.05f ) ); m_pAdditiveEmitter = new weather_system_t( bundle, resource ); m_pAdditiveEmitter->initialize( *attribute, m_pService->GetPrecipitationFactor() ); } } } if( m_pEmitter ) m_pEmitter->activate( m_pService->GetFadingTime(), true ); if( m_pAdditiveEmitter ) m_pAdditiveEmitter->activate( m_pService->GetFadingTime(), true ); // control sky context if( m_pService->m_pSkyCtx ) m_pService->m_pSkyCtx->SetSkyType( m_pService->m_pInfo->m_nSkyType ); } void SGameRainyState::OnLeave() { if( m_pEmitter ) m_pEmitter->activate( m_pService->GetFadingTime(), false ); if( m_pAdditiveEmitter ) m_pAdditiveEmitter->activate( m_pService->GetFadingTime(), false ); } // =================================================================== // SGameSnowState // =================================================================== void SGameSnowyState::Process( DWORD dwTime ) { if( !m_pService->IsInDoor() && m_pEmitter ) { if( m_pEmitter->isActive() ) { m_pEmitter->locate( m_pService->m_vTargetPosition, m_pService->m_vTargetPosition ); m_pEmitter->process( dwTime ); } else { SAFE_DELETE( m_pEmitter ); m_bIsGarbage = true; } } } void SGameSnowyState::Render( KViewportObject* pViewport ) { if( !m_pService->IsInDoor() && m_pEmitter && m_pEmitter->isActive() ) m_pEmitter->render( pViewport ); } void SGameSnowyState::OnEnter() { if( 0 == m_pEmitter ) { typedef env_fx::BillboardTextureResource< env_fx::K3DVERTEX_WEATHER, env_fx::K3DINDEX_WEATHER > resource_t; env_fx::particle_op_unit_t* initor = new env_fx::particle_op_unit_t(); env_fx::particle_op_unit_t* action = new env_fx::particle_op_unit_t(); env_fx::particle_bundle_t* bundle = new env_fx::particle_bundle_t( initor, action ); resource_t* resource = new resource_t( m_pService->m_pInfo->m_pWeatherAttr->resource, m_pService->m_pRenderDevice ); initor->append( new env_fx::LifeFixedInitor( m_pService->m_pInfo->m_pWeatherAttr->particle_life ) ); initor->append( new env_fx::VelocityFixedInitor( m_pService->m_pInfo->m_pWeatherAttr->particle_direction.min * m_pService->m_pInfo->m_pWeatherAttr->particle_velocity ) ); initor->append( new env_fx::RotationInitor( m_pService->m_pInfo->m_pWeatherAttr->rotation_unit, m_pService->m_pInfo->m_pWeatherAttr->rotation_speed ) ); initor->append( new env_fx::PositionFixedDistributionInitor( m_pService->m_pInfo->m_pWeatherAttr->area_width, m_pService->m_pInfo->m_pWeatherAttr->hori_density, m_pService->m_pInfo->m_pWeatherAttr->area_height / 2 ) ); initor->append( new env_fx::VisibilityFixedInitor( 1.0f ) ); initor->append( new env_fx::ColorFixedInitor( K3DColor( 0xffffffff ) ) ); initor->append( new env_fx::SizeFixedInitor( m_pService->m_pInfo->m_pWeatherAttr->particle_width, m_pService->m_pInfo->m_pWeatherAttr->particle_height ) ); action->append( new env_fx::LifeDecreaseAction() ); action->append( new env_fx::VelocityAction() ); action->append( new env_fx::VelocityReactiveAction( m_pService->m_vTargetPosition ) ); action->append( new env_fx::RotationAction() ); action->append( new env_fx::PositionSwapAction( m_pService->m_pInfo->m_pWeatherAttr->area_width / 2, m_pService->m_pInfo->m_pWeatherAttr->area_width / 2 ) ); action->append( new env_fx::VisibilityFadeInOutAction( m_pService->m_pInfo->m_pWeatherAttr->destroy_duration ) ); action->append( new env_fx::VisibilityFadeInOutOffsetAdditiveAction( m_pService->m_pInfo->m_pWeatherAttr->area_width, m_pService->m_pInfo->m_pWeatherAttr->area_width * 0.05f ) ); m_pEmitter = new weather_system_t( bundle, resource ); m_pEmitter->initialize( *m_pService->m_pInfo->m_pWeatherAttr, m_pService->GetPrecipitationFactor() ); } if( m_pService->m_pInfo ) { m_pEmitter->activate( m_pService->GetFadingTime(), true ); } // control sky context if( m_pService->m_pSkyCtx ) m_pService->m_pSkyCtx->SetSkyType( m_pService->m_pInfo->m_nSkyType ); } void SGameSnowyState::OnLeave() { if( m_pEmitter ) m_pEmitter->activate( m_pService->GetFadingTime(), false ); }