// HEADERS ------------------------------------------------------- // foward include #include "stdafx.h" //#include #include #include #include "KRenderDeviceDX.h" #include "SEnvPrimitive.h" #include "KViewport.h" #include "KRenderObject.h" // header #include "SGameLightning.h" #include #include #include "KResourceManager.h" // namespaces ---------------------------------------------------- using namespace env_fx; // SLightningThread ---------------------------------------------- SLightningThread::SLightningThread() : m_dwTime_msec_ ( 0 ) , m_dwBirthTime_msec_ ( 0 ) , m_vPosition ( 0, 0, 0 ) , m_bAlive ( false ) , m_nGeomIndex ( -1 ) { } SLightningThread::~SLightningThread() { } void SLightningThread::Process( DWORD dwTime_msec_, const SLightningAttr& Attr ) { if( m_dwTime_msec_ == 0 ) { m_dwTime_msec_ = dwTime_msec_; } DWORD dwTimeDiff_msec_ = dwTime_msec_ - m_dwBirthTime_msec_; m_dwTime_msec_ = dwTime_msec_; if( dwTimeDiff_msec_ < Attr.dwLife_msec_ ) { // twinkling float ftheta = K3D_PI * Attr.nTwinklingCount * (float)( dwTimeDiff_msec_ ) / (float)Attr.dwLife_msec_; float fwave = sinf( ftheta ); fwave = fabs( fwave ); m_dwDiffuse = Attr.dwColor; m_dwDiffuse.a = (unsigned char)( fwave * 255.0f ); } else if( dwTimeDiff_msec_ >= Attr.dwLife_msec_ && dwTimeDiff_msec_ < ( Attr.dwLife_msec_ + Attr.dwFadeOut_msec_ ) ) { // fade out if( Attr.dwFadeOut_msec_ > 0 ) { DWORD dwFadeoutDiff_msec_ = dwTimeDiff_msec_ - Attr.dwLife_msec_; float fFadeoutFactor = 1.0f - (float)dwFadeoutDiff_msec_ / (float)Attr.dwFadeOut_msec_; fFadeoutFactor = ::max( ::min( 1.0f, fFadeoutFactor ), 0.0f ); m_dwDiffuse = Attr.dwColor; m_dwDiffuse.a = (unsigned char)( fFadeoutFactor * 255.0f ); } else { m_dwDiffuse.a = (unsigned char)0; } } else { // die this->SetAlive( false ); } } void SLightningThread::Primitive( const SLightningAttr& Attr , K3DSPRITEVERTEX* pVtx , const K3DVector& vCameraPosition ) { K3DVector vNewNormal = vCameraPosition - m_vPosition; vNewNormal.z = 0; K3DVectorNormalize( vNewNormal, vNewNormal ); K3DMatrix mBill = util::GetRotationMatrixByNormal( K3DVector( 0, 1, 0 ), vNewNormal ); float fHalfWidth = Attr.fWidth / 2.0f; float fHalfHeight = Attr.fHeight / 2.0f; K3DVector vLocal[ 4 ] = { K3DVector( -fHalfWidth, 0, 0 ), K3DVector( fHalfWidth, 0, 0 ), K3DVector( -fHalfWidth, 0, -Attr.fHeight ), K3DVector( fHalfWidth, 0, -Attr.fHeight ) }; for( int i = 0; i < 4; ++i ) { K3DVectorTransform( vLocal[ i ], vLocal[ i ], mBill ); } pVtx[ 0 ].pos = m_vPosition + vLocal[ 0 ]; pVtx[ 1 ].pos = m_vPosition + vLocal[ 1 ]; pVtx[ 2 ].pos = m_vPosition + vLocal[ 2 ]; pVtx[ 3 ].pos = m_vPosition + vLocal[ 3 ]; pVtx[ 0 ].diffuse = m_dwDiffuse; pVtx[ 1 ].diffuse = m_dwDiffuse; pVtx[ 2 ].diffuse = m_dwDiffuse; pVtx[ 3 ].diffuse = m_dwDiffuse; } void SLightningThread::SetAlive( bool bAlive ) { m_bAlive = bAlive; } bool SLightningThread::IsActive( const SLightningAttr& Attr ) const { return ( ( m_dwBirthTime_msec_ + Attr.dwLife_msec_ ) > m_dwTime_msec_ ) ? true : false; } void SLightningThread::SetPosition( const K3DVector& vPosition ) { m_vPosition = vPosition; } void SLightningThread::SetBirthTime( DWORD dwBirthTime_msec_ ) { m_dwBirthTime_msec_ = dwBirthTime_msec_; } // SGameLightning ---------------------------------------------- SGameLightning::SGameLightning( int nMaxLightning ) : m_dwTime_msec_ ( 0 ) , m_dwTimeDiff_msec_ ( 0 ) , m_dwTimeBirth_msec_ ( 0 ) , m_bAlive ( true ) , m_vPosition ( 0, 0, 0 ) , m_nMaxLightning ( nMaxLightning ) , m_pmParent ( 0 ) , m_pRenderDevice ( 0 ) , m_pPrimitive ( 0 ) , m_spTexture ( 0 ) , m_pMtrl ( 0 ) , m_pVtx ( 0 ) , m_pIdx ( 0 ) { m_ctLightningThreads.reserve( m_nMaxLightning ); K3DMatrixIdentity( m_mWorld ); K3DMatrixIdentity( m_mBillboard ); } SGameLightning::~SGameLightning() { SAFE_DELETE( m_pPrimitive ); SAFE_DELETE( m_pMtrl ); SAFE_DELETE_ARRAY( m_pVtx ); SAFE_DELETE_ARRAY( m_pIdx ); util::wipe_seq( m_ctLightningThreads ); } void SGameLightning::Init( K3DRenderDevice* pDevice ) { this->SetRenderDevice( pDevice ); this->initGeometry(); this->createLightningThread(); } void SGameLightning::Process( DWORD dwTime_msec_ ) { if( m_dwTime_msec_ == 0 ) { this->SetTime( dwTime_msec_ ); return; } this->SetTime( dwTime_msec_ ); K3DSPRITEVERTEX* pVtx = m_pVtx; int nThreadSize = (int)m_ctLightningThreads.size(); //K3DVector vBill( m_Attribute.fWidth / 2.0f, 0, 0 ); //K3DVectorTransform( vBill, vBill, m_mBillboard ); if( !m_ctLightningThreads.empty() ) { SWeatherLightningPrimitive* primitive = static_cast< SWeatherLightningPrimitive* >( m_pPrimitive ); primitive->ResetGeometryCount(); std::sort( m_ctLightningThreads.begin(), m_ctLightningThreads.end(), env_fx::_private::SSortThreadsByGeomIndex() ); for( int n = 0; n < nThreadSize; ++n ) { SLightningThread* pThread = m_ctLightningThreads[ n ]; if( pThread && pThread->IsAlive() ) { pThread->Process( m_dwTime_msec_, m_Attribute ); int geom_index = pThread->GetGeomIndex(); SWeatherLightningPrimitive::SGeometryInfo& geom_info = primitive->GetGeometryInfoAt( geom_index ); pThread->Primitive( m_Attribute, pVtx, K3DVector( 0, 0, 0 ) ); geom_info.IncreasePrimitiveCount(); pVtx += 4; } } } //m_pPrimitive->SetVertexCnt( nPrimCount * 4 ); } void SGameLightning::Render( KViewportObject* pViewport ) { if( m_pPrimitive && m_pPrimitive->GetVertexCnt() > 0 ) { pViewport->Register( m_pPrimitive, KRenderObject::RENDEREFX_WEATHER ); } } void SGameLightning::Emit( const K3DVector& vPosition ) { if( vPosition.Magnitude() < m_Attribute.fVisibleDistance ) return; LightningThreadVector::const_iterator iDeadThread = std::find_if( m_ctLightningThreads.begin(), m_ctLightningThreads.end(), _private::SFindDeadThread() ); if( iDeadThread != m_ctLightningThreads.end() ) { size_t geom_size = static_cast< SWeatherLightningPrimitive* >( m_pPrimitive )->GetGeometrySize(); if( geom_size > 0 ) { int geom_index = rand() % geom_size; (*iDeadThread)->SetGeomIndex( geom_index ); (*iDeadThread)->SetAlive( true ); (*iDeadThread)->SetPosition( vPosition ); (*iDeadThread)->SetBirthTime( m_dwTime_msec_ ); } } } void SGameLightning::SetRenderDevice( K3DRenderDevice* pDevice ) { m_pRenderDevice = pDevice; } void SGameLightning::SetBillboardMatrix( const K3DMatrix& mBillboard ) { m_mBillboard = mBillboard; } void SGameLightning::SetCameraPosition( const K3DVector& vCamPos ) { m_vCamPos = vCamPos; } void SGameLightning::SetTime( DWORD dwTime_msec_ ) { m_dwTime_msec_ = dwTime_msec_; //if( m_dwTimeBirth_msec_ + m_Attribute.dwLife_msec_ <= m_dwTime_msec_ ) // m_bAlive = false; //else // m_bAlive = true; } void SGameLightning::SetTexture( K3DTexture* pTexture ) { m_spTexture = pTexture; } void SGameLightning::SetAttribute( const SLightningAttr& Attr ) { m_Attribute = Attr; if( !m_Attribute.strTextures.empty() ) { NX3LoadPack loadpack; loadpack.Init(); size_t size = m_Attribute.strTextures.size(); for( size_t n = 0; n < size; ++n ) { K3DTextureSPtr spTexture; spTexture = KTextureManager::GetManager()->GetTexture( m_Attribute.strTextures.at( n ).c_str(), &loadpack, true, KTextureManager::GetManager()->GetMipMapBiasLevel() ); assert( m_spTexture && "Lightning texture not loaded!!" ); if( m_pPrimitive ) { SWeatherLightningPrimitive::SGeometryInfo info; info.texture = spTexture; static_cast< SWeatherLightningPrimitive* >( m_pPrimitive )->AddGeometryInfo( info ); } } } } void SGameLightning::SetPosition( const K3DVector& vPosition ) { m_vPosition = vPosition; } void SGameLightning::SetParentMatrix( K3DMatrix* pmParent ) { m_pmParent = pmParent; m_pPrimitive->SetTransform( m_pmParent, m_pmParent ); } const env_fx::SLightningAttr& SGameLightning::GetAttribute() const { return m_Attribute; } void SGameLightning::initGeometry() { if( m_pRenderDevice ) { srand( 0 ); // vertex buffer m_pVtx = new K3DSPRITEVERTEX[ m_nMaxLightning * 4 ]; for( int n = 0; n < m_nMaxLightning; ++n ) { m_pVtx[ 4 * n + 0 ].pos = K3DVector( 0, 0, 0 ); m_pVtx[ 4 * n + 0 ].texel = K3DTexel( 0, 0 ); m_pVtx[ 4 * n + 0 ].diffuse = KColor( 255, 255, 255, 255 ); m_pVtx[ 4 * n + 1 ].pos = K3DVector( 0, 0, 0 ); m_pVtx[ 4 * n + 1 ].texel = K3DTexel( 1, 0 ); m_pVtx[ 4 * n + 1 ].diffuse = KColor( 255, 255, 255, 255 ); m_pVtx[ 4 * n + 2 ].pos = K3DVector( 0, 0, 0 ); m_pVtx[ 4 * n + 2 ].texel = K3DTexel( 0, 1 ); m_pVtx[ 4 * n + 2 ].diffuse = KColor( 255, 255, 255, 255 ); m_pVtx[ 4 * n + 3 ].pos = K3DVector( 0, 0, 0 ); m_pVtx[ 4 * n + 3 ].texel = K3DTexel( 1, 1 ); m_pVtx[ 4 * n + 3 ].diffuse = KColor( 255, 255, 255, 255 ); } // index buffer m_pIdx = new WORD[ m_nMaxLightning * 6 ]; for( int n = 0; n < m_nMaxLightning; ++n ) { m_pIdx[ 6 * n + 0 ] = 4 * n + 2; m_pIdx[ 6 * n + 1 ] = 4 * n + 1; m_pIdx[ 6 * n + 2 ] = 4 * n + 0; m_pIdx[ 6 * n + 3 ] = 4 * n + 2; m_pIdx[ 6 * n + 4 ] = 4 * n + 3; m_pIdx[ 6 * n + 5 ] = 4 * n + 1; } m_pPrimitive = new SWeatherLightningPrimitive(); if( m_pPrimitive ) { m_pMtrl = new K3DMaterial; m_pMtrl->SetAmbient( K3DColor( 1.f, 1.f, 1.f, 1.f ) ); m_pMtrl->SetDiffuse( K3DColor( 1.f, 1.f, 1.f, 1.f ) ); m_pMtrl->SetSpecular( K3DColor( 0.f, 0.f, 0.f, 1.f ) ); m_pMtrl->SetSpecularPower( 1.0f ); K3DMatrix mParent; K3DMatrixIdentity( mParent ); m_pPrimitive->SetBlendMode( K3DMaterial::MBM_ADDITIVE ); m_pPrimitive->SetMaterial( m_pMtrl ); m_pPrimitive->SetTransparent( true ); m_pPrimitive->SetTransform( &m_mWorld, &mParent ); m_pPrimitive->SetTexture( 0, m_spTexture ); m_pPrimitive->SetCommonVertex( m_pVtx ); m_pPrimitive->SetCommonIndexed( m_pIdx ); m_pPrimitive->SetVertexFmt( K3DFVF_SPRITE ); m_pPrimitive->SetVertexStride( sizeof( K3DSPRITEVERTEX ) ); } } } void SGameLightning::createLightningThread() { for( int n = 0; n < m_nMaxLightning; ++n ) { m_ctLightningThreads.push_back( new SLightningThread() ); } }