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

498 lines
14 KiB
C++

#include "stdafx.h"
#include "KPrimitive.h"
#include "KResource.h"
#include "KPrimitiveFXParticle.h"
#include "KViewport.h"
#include "KRenderDevice.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KFXBillboardPrimitive Implement
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
KCommonParticleIndexBuffer& KCommonParticleIndexBuffer::GetInstance()
{
static KCommonParticleIndexBuffer indexbuffer;
return indexbuffer;
}
int KFXBillboardPrimitive::s_nVertexStride = K3DVertexBuffer::CalcVertexStride(K3DFVF_SPRITE);
KFXBillboardPrimitive::KFXBillboardPrimitive()
{
m_type = KPRIMITIVE_FXBILLBOARD;
}
KFXBillboardPrimitive::~KFXBillboardPrimitive()
{
}
void KFXBillboardPrimitive::SetBillboardRes( KResFXBillboard *pRes )
{
m_spRes = pRes;
}
KResFXBillboard* KFXBillboardPrimitive::GetBillboardRes()
{
return m_spRes;
}
void KFXBillboardPrimitive::SetTransform( const K3DMatrix &transform )
{
m_matTransform = transform;
}
const K3DMatrix &KFXBillboardPrimitive::GetTransform()
{
return m_matTransform;
}
void KFXBillboardPrimitive::SetColor ( const KColor &color )
{
m_colSprite = color;
}
const KColor& KFXBillboardPrimitive::GetColor()
{
return m_colSprite;
}
/// Rendering source target rectangle.
void KFXBillboardPrimitive::SetUV( float _l, float _t, float _r, float _b )
{
l = _l; t = _t; r = _r; b = _b;
}
void KFXBillboardPrimitive::GetUV( float *_l, float *_t, float *_r, float *_b )
{
*_l = l; *_t = t; *_r = r; *_b = b;
}
void KFXBillboardPrimitive::SetFixedAxis( int nAxis )
{
m_nFixedAxis = nAxis;
}
void KFXBillboardPrimitive::SetAngle( float fAngle )
{
m_fAngle = fAngle;
}
void KFXBillboardPrimitive::Render( KViewportObject *viewport, class K3DRenderDevice *dev, bool bUseAccum )
{
_UpdateBillboard(viewport, dev);
dev->SetTexture( 0, m_spRes->GetTexture() );
dev->DrawTriangleStrip(K3DFVF_SPRITE, m_VtxBuf, 4, s_nVertexStride);
}
template< typename T > static inline T _min( const T& a, const T& b ) { return a < b ? a : b; }
void KFXBillboardPrimitive::_UpdateBillboard(KViewportObject* pViewport, K3DRenderDevice* pDev)
{
const K3DVertex* pVtx = m_spRes->GetVertices();
for ( int i = 0 ; i < 4; i++ )
{
K3DVectorTransform( m_VtxBuf[ i ].pos, pVtx[ i ], m_RootMat );
m_VtxBuf[i].diffuse = m_colSprite;
}
K3DMatrix matViewMatrix = *pViewport->GetViewMatrix();
static K3DVector vPos;
K3DMatrixGetPosVector(vPos, m_RootMat);
static float fHalfWidth, fHalfHeight;
static bool bSwapWidthHeight = false;
if ( fabsf( pVtx[ 0 ].x - pVtx[ 1 ].x ) < fabsf( pVtx[ 0 ].z - pVtx[ 1 ].z ) )
bSwapWidthHeight = true;
else
bSwapWidthHeight = false;
K3DVector vCenterOffset = ( m_VtxBuf[ 0 ].pos + m_VtxBuf[ 1 ].pos + m_VtxBuf[ 2 ].pos + m_VtxBuf[ 3 ].pos ) / 4.0f;
vCenterOffset = ( vPos - vCenterOffset ) * 2.0f;
vCenterOffset.y = fabsf( vCenterOffset.y ) >= fabsf( vCenterOffset.z ) ? vCenterOffset.y : vCenterOffset.z;
vCenterOffset.z = 0.0f;
fHalfWidth = K3DVectorLength( m_VtxBuf[ 0 ].pos - m_VtxBuf[ 1 ].pos );
fHalfHeight = min( K3DVectorLength( m_VtxBuf[ 1 ].pos - m_VtxBuf[ 3 ].pos ), K3DVectorLength( m_VtxBuf[ 1 ].pos - m_VtxBuf[ 2 ].pos ) );
if ( bSwapWidthHeight )
{
float fTemp = fHalfWidth;
fHalfWidth = fHalfHeight;
fHalfHeight = fTemp;
}
K3DVector vecLeft, vecRight, vecUp, vecDown, vecView;
if ( m_nFixedAxis == 2 )
{
vecRight = K3DVector( 1.0f, 0.0f, 0.0f );
vecUp = K3DVector( 0.0f, 0.0f, 1.0f );
K3DVectorTransformNormal( vecUp, vecUp, matViewMatrix );
K3DVectorCross( vecView, vecUp, vecRight );
vecLeft = -vecRight * fHalfWidth - vecRight * vCenterOffset.x;
vecRight = vecRight * fHalfWidth - vecRight * vCenterOffset.x;
vecDown = -vecUp * fHalfHeight - vecUp * vCenterOffset.y;
vecUp = vecUp * fHalfHeight - vecUp * vCenterOffset.y;
}
else
{
vecRight = K3DVector( 1.0f, 0.0f, 0.0f );
vecUp = K3DVector( 0.0f, 1.0f, 0.0f );
K3DVectorCross( vecView, vecUp, vecRight );
vecLeft = -vecRight * fHalfWidth - vecRight * vCenterOffset.x;
vecRight = vecRight * fHalfWidth - vecRight * vCenterOffset.x;
vecDown = -vecUp * fHalfHeight - vecUp * vCenterOffset.y;
vecUp = vecUp * fHalfHeight - vecUp * vCenterOffset.y;
}
K3DMatrix matRotate;
K3DMatrixRotationAxis( matRotate, vecView, m_fAngle );
K3DVectorTransformNormal( vecLeft, vecLeft, matRotate );
K3DVectorTransformNormal( vecRight, vecRight, matRotate );
K3DVectorTransformNormal( vecUp, vecUp, matRotate );
K3DVectorTransformNormal( vecDown, vecDown, matRotate );
K3DMatrixInverse( matViewMatrix, matViewMatrix );
matViewMatrix.SetPosVector( vPos );
m_VtxBuf[ 0 ].pos = vecLeft + vecDown;
m_VtxBuf[ 1 ].pos = vecLeft + vecUp;
m_VtxBuf[ 2 ].pos = vecRight + vecDown;
m_VtxBuf[ 3 ].pos = vecRight + vecUp;
for(int i = 0 ; i < 4; ++i)
{
K3DVectorTransform( m_VtxBuf[ i ].pos, m_VtxBuf[ i ].pos, matViewMatrix );
}
// Set UV
m_VtxBuf[0].texel.u = l; m_VtxBuf[0].texel.v = b;
m_VtxBuf[1].texel.u = l; m_VtxBuf[1].texel.v = t;
m_VtxBuf[2].texel.u = r; m_VtxBuf[2].texel.v = b;
m_VtxBuf[3].texel.u = r; m_VtxBuf[3].texel.v = t;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KFXParticlePrimitive Implement
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int KFXParticlePrimitive::s_nVertexStride = K3DVertexBuffer::CalcVertexStride(K3DFVF_SPRITE);
KFXParticlePrimitive::KFXParticlePrimitive()
{
m_type = KPRIMITIVE_FXPARTICLE;
m_pParticles = NULL;
m_nParticleCount = 0;
m_pVtxBuf = NULL;
m_pIdxBuf = NULL;
m_nDrawParticleCount = 0;
m_bIsAttachParent = false;
}
KFXParticlePrimitive::~KFXParticlePrimitive()
{
SAFE_DELETE_ARRAY(m_pParticles);
SAFE_DELETE_ARRAY(m_pVtxBuf);
}
void KFXParticlePrimitive::ResetParticleCount()
{
m_nDrawParticleCount = 0;
}
void KFXParticlePrimitive::SetParticleRes( KResFXParticle *pRes )
{
m_spRes = pRes;
}
KResFXParticle* KFXParticlePrimitive::GetParticleRes()
{
return m_spRes;
}
void KFXParticlePrimitive::SetParticleCount( int count )
{
SAFE_DELETE_ARRAY(m_pParticles);
SAFE_DELETE_ARRAY(m_pVtxBuf);
m_nParticleCount = count;
m_pParticles = new _PARTICLE[m_nParticleCount];
m_pVtxBuf = new K3DSPRITEVERTEX[m_nParticleCount * 4];
m_pIdxBuf = GetIndexbufferInstance().GetCommonIndexbuffer( m_nParticleCount );
}
void KFXParticlePrimitive::SetParticleInfo( int num, _PARTICLE& particle )
{
if( m_nParticleCount > num )
{
m_pParticles[num].pos = particle.pos;
m_pParticles[num].fWidth = particle.fWidth;
m_pParticles[num].fHeight = particle.fHeight;
m_pParticles[num].color = particle.color;
m_pParticles[num].l = particle.l;
m_pParticles[num].t = particle.t;
m_pParticles[num].r = particle.r;
m_pParticles[num].b = particle.b;
++m_nDrawParticleCount;
}
}
void KFXParticlePrimitive::GetParticleUV( int num, float *_l, float *_t, float *_r, float *_b )
{
*_l = m_pParticles[num].l; *_t = m_pParticles[num].t; *_r = m_pParticles[num].r; *_b = m_pParticles[num].b;
}
void KFXParticlePrimitive::NewParticle( int num )
{
m_pParticles[num].newparticle = true;
}
void KFXParticlePrimitive::SetAttachParent( bool bAttachParent )
{
m_bIsAttachParent = bAttachParent;
}
const KFXParticlePrimitive::_PARTICLE & KFXParticlePrimitive::GetParticle( int num )
{
return m_pParticles[num];
}
int KFXParticlePrimitive::GetMaxParticleCount()
{
return m_nParticleCount;
}
int KFXParticlePrimitive::GetDrawParticleCount()
{
return m_nDrawParticleCount;
}
void KFXParticlePrimitive::Render( KViewportObject *viewport, class K3DRenderDevice *dev, bool bUseAccum )
{
if(m_nDrawParticleCount > 0 && IsValidIndexBuffer() )
{
_UpdateParticle(viewport, dev);
dev->SetTexture( 0, m_spRes->GetTexture() );
dev->DrawTriangles( K3DFVF_SPRITE,m_pVtxBuf, m_nDrawParticleCount * 4, s_nVertexStride, m_pIdxBuf, m_nDrawParticleCount * 6);
}
}
static inline void K3DMatrixAddPosVector( K3DMatrix &mat, const K3DVector &v )
{
mat._41 += v.x; mat._42 += v.y; mat._43 += v.z;
}
static inline void K3DMatrixSubtractPosVector( K3DMatrix &mat, const K3DVector &v )
{
mat._41 -= v.x; mat._42 -= v.y; mat._43 -= v.z;
}
void KFXParticlePrimitive::_UpdateParticle(KViewportObject* pViewport, K3DRenderDevice* pDev)
{
static float l,t,r,b;
static float fWidth, fHeight;
static K3DVertex vPos;
K3DMatrix matBillboard = *pViewport->GetViewMatrix();
matBillboard._41 = matBillboard._42 = matBillboard._43 = 0.0f;
matBillboard._44 = 1.0f;
K3DMatrixInverse( matBillboard, matBillboard );
K3DVector vCamPos = K3DVector( 0.0f, 0.0f, 0.0f );
if( pViewport->IsLocalCoord() )
vCamPos = pViewport->GetBackUpViewCamera()->GetCamPos();
K3DMatrix matOriParent = m_RootMat;
K3DMatrixAddPosVector( matOriParent, vCamPos );
K3DMatrix matTrans;
for(int i = 0 ; i < m_nDrawParticleCount; ++i)
{
K3DMatrixTranslation( matTrans, m_pParticles[i].pos.x, m_pParticles[i].pos.y, m_pParticles[i].pos.z );
if( m_bIsAttachParent )
{
matTrans = matTrans * m_RootMat;
m_pParticles[i].matParent = matOriParent;
m_pParticles[i].newparticle = false;
}
else
{
if( m_pParticles[i].newparticle )
{
matTrans = matTrans * m_RootMat;
m_pParticles[i].matParent = matOriParent;
m_pParticles[i].newparticle = false;
}
else
{
K3DMatrix matParent = m_pParticles[i].matParent;
K3DMatrixSubtractPosVector( matParent, vCamPos );
matTrans = matTrans * matParent;
}
}
matBillboard._41 = matTrans._41;
matBillboard._42 = matTrans._42;
matBillboard._43 = matTrans._43;
// 원래는 * 0.5f 해줘야 함 (max size 대로 나오게)
fWidth = m_pParticles[i].fWidth;
fHeight = m_pParticles[i].fHeight;
l = m_pParticles[i].l; t = m_pParticles[i].t; r = m_pParticles[i].r; b = m_pParticles[i].b;
static const float MULTIPLYER[4][2] = { {-1.f, -1.f} , {1.f, -1.f}, {-1.f, 1.f }, {1.f, 1.f} };
// Position, Color
for(int j = 0; j < 4; ++j)
{
m_pVtxBuf[i * 4 + j].pos.x = MULTIPLYER[j][0] * fWidth;
m_pVtxBuf[i * 4 + j].pos.y = MULTIPLYER[j][1] * fHeight;
m_pVtxBuf[i * 4 + j].pos.z = 0.0f;
m_pVtxBuf[i * 4 + j].diffuse = m_pParticles[i].color;
K3DVectorTransform( m_pVtxBuf[i * 4 + j].pos, m_pVtxBuf[i * 4 + j].pos, matBillboard );
}
// UV 셋팅
m_pVtxBuf[i * 4 + 0].texel.u = l; m_pVtxBuf[i * 4 + 0].texel.v = b;
m_pVtxBuf[i * 4 + 1].texel.u = r; m_pVtxBuf[i * 4 + 1].texel.v = b;
m_pVtxBuf[i * 4 + 2].texel.u = l; m_pVtxBuf[i * 4 + 2].texel.v = t;
m_pVtxBuf[i * 4 + 3].texel.u = r; m_pVtxBuf[i * 4 + 3].texel.v = t;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KFXAfterImagePrimitive Implement
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
KFXAfterImagePrimitive::KFXAfterImagePrimitive()
{
m_type = KPRIMITIVE_FXAFTERIMAGE;
m_nDepth = 0;
m_nDrawCount = 0;
m_pVtx = NULL;
m_nCurPos = 0;
m_nVertexStride = K3DVertexBuffer::CalcVertexStride( K3DFVF_SPRITE );
m_bIsTrans = true;
K3DMatrixIdentity(m_Transform);
}
/// Delete two custom vertex's array.
KFXAfterImagePrimitive::~KFXAfterImagePrimitive()
{
Clear();
}
void KFXAfterImagePrimitive::Clear()
{
SAFE_DELETE_ARRAY(m_pVtx);
}
void KFXAfterImagePrimitive::SetTransform( const K3DMatrix &transform )
{
m_Transform = transform;
}
void KFXAfterImagePrimitive::SetTexture( K3DTexture *pTex )
{
m_spTex = pTex;
}
void KFXAfterImagePrimitive::Initialize ( int nDepth )
{
Clear();
m_nDepth = nDepth;
m_nDrawCount = 0;
m_nCurPos = 0;
m_pVtx = new K3DSPRITEVERTEX[nDepth * 2];
}
void KFXAfterImagePrimitive::ReserveVtx(int nCount)
{
nCount = nCount - ( m_nDepth - m_nCurPos );
if( nCount <= 0)
return;
m_nCurPos = max(0, m_nCurPos - nCount);
m_nDrawCount = max(0, m_nDrawCount - nCount);
memcpy( m_pVtx, &m_pVtx[nCount * 2], sizeof(K3DSPRITEVERTEX) * 2 * (m_nCurPos) );
}
void KFXAfterImagePrimitive::PopVertex(int nCount)
{
m_nCurPos = max(0, m_nCurPos - nCount);
m_nDrawCount = max(0, m_nDrawCount - nCount);
}
void KFXAfterImagePrimitive::PushVertex( const K3DSPRITEVERTEX &vtx1, const K3DSPRITEVERTEX &vtx2)
{
if ( m_nCurPos == m_nDepth )
{
memcpy( m_pVtx, &m_pVtx[2], sizeof(K3DSPRITEVERTEX)*2*(m_nDepth-1) );
m_nCurPos = m_nDepth-1;
}
m_pVtx[m_nCurPos*2] = vtx1;
m_pVtx[m_nCurPos*2+1] = vtx2;
++m_nCurPos;
if ( ++m_nDrawCount > m_nDepth )
m_nDrawCount = m_nDepth;
}
void KFXAfterImagePrimitive::UpdateVertex()
{
if ( m_nDrawCount > 1 )
{
for ( int i=0 ; i<m_nDrawCount ; ++i )
{
m_pVtx[i*2+0].texel.u = .0f;
m_pVtx[i*2+1].texel.u= 1.0f;
m_pVtx[i*2+0].texel.v = m_pVtx[i*2+1].texel.v= (float)i/(float)(m_nDrawCount-1);
m_pVtx[i*2+0].diffuse = m_pVtx[i*2+1].diffuse = KColor(255,255,255, unsigned char( 255.0f * m_fVisibility * (float)i/(float)(m_nDrawCount-1) ) );
}
}
}
void KFXAfterImagePrimitive::RemoveVertex()
{
m_nDrawCount = 0;
m_nCurPos = 0;
}
void KFXAfterImagePrimitive::Render( KViewportObject *viewport, class K3DRenderDevice *dev, bool bUseAccum )
{
if ( m_nDrawCount > 1 )
{
K3DMatrix world;
K3DMatrixMultiply(world, m_Transform, m_RootMat);
dev->SetTransform( K3DRenderDevice::TS_WORLD, &world );
dev->SetTexture( 0, m_spTex );
//임시로 컬모드 설정
int nOldCullMode = dev->GetCullMode();
dev->SetCullMode( K3DRenderDevice::KCM_NONE );
dev->DrawTriangleStrip( K3DFVF_SPRITE, m_pVtx, m_nDrawCount*2, m_nVertexStride );
dev->SetCullMode( nOldCullMode );
}
}
void KFXAfterImagePrimitive::SetMoveAdded(const K3DVertex & vMoveAdded)
{
if ( m_nDrawCount > 1 )
{
for ( int i=0 ; i<m_nDrawCount ; ++i )
{
m_pVtx[i*2].pos += vMoveAdded;
m_pVtx[i*2+1].pos += vMoveAdded;
}
}
}