Files
2026-06-01 12:46:52 +02:00

403 lines
10 KiB
C++

// HEADERS -------------------------------------------------------
// foward include
#include "stdafx.h"
//#include <vector>
#include <queue>
#include <deque>
#include "KRenderDeviceDX.h"
#include "SEnvPrimitive.h"
#include "KViewport.h"
#include "KRenderObject.h"
// header
#include "SGameLightning.h"
#include <kfile/KFileManager.h>
#include <toolkit/XStringUtil.h>
#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() );
}
}